vde-layout 0.0.3 → 0.0.5
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 +121 -176
- package/dist/index.js +201 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,211 +1,156 @@
|
|
|
1
1
|
# vde-layout
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
vde-layout is a CLI that reproduces tmux pane layouts from YAML presets. Define the panes you need once, then bring them back with a single command.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- Define layouts in YAML format
|
|
12
|
-
- Reproduce layouts with a single command
|
|
13
|
-
- Manage presets for different use cases
|
|
14
|
-
- Flexible pane settings (commands, working directories, environment variables, etc.)
|
|
15
|
-
- Freely combine horizontal and vertical splits
|
|
16
|
-
|
|
17
|
-
## Architecture
|
|
18
|
-
|
|
19
|
-
vde-layout follows a functional-core/imperative-shell approach:
|
|
20
|
-
|
|
21
|
-
- Functional Core compiles presets into immutable layout plans and deterministic tmux command sequences.
|
|
22
|
-
- CLI adapters reuse the same plan for dry-run and real execution, ensuring matching plan hashes.
|
|
23
|
-
- Plan Runner validates tmux prerequisites, applies each plan step, and reports structured diagnostics when a step fails.
|
|
24
|
-
|
|
25
|
-
This separation allows the Functional Core to remain pure and fully testable while the boundary layer coordinates I/O with tmux.
|
|
26
|
-
|
|
27
|
-
## Development Notes
|
|
28
|
-
|
|
29
|
-
- Runtime modules are authored in ESM with explicit `.ts` extensions, and `src/core/` exposes the canonical functional services directly.
|
|
30
|
-
- Boundary adapters (`src/cli`, `src/executor`, `src/tmux`) remain factory-based; avoid新たなクラス導入は避けてください。
|
|
31
|
-
- `npm run build` uses tsdown to emit ESM bundles into `dist/`. `npm test` automatically rebuilds before executing the Vitest suite.
|
|
32
|
-
- Run `npm run typecheck` to validate the TypeScript sources without emitting artifacts.
|
|
5
|
+
## Key Capabilities
|
|
6
|
+
- Keep reusable presets for development, monitoring, reviews, and more.
|
|
7
|
+
- Build nested horizontal/vertical splits with ratio-based sizing.
|
|
8
|
+
- Launch commands in each pane with custom working directories, environment variables, delays, and titles.
|
|
9
|
+
- Preview every tmux step in dry-run mode before you apply a preset.
|
|
10
|
+
- Switch between configuration files by flag or environment variables.
|
|
33
11
|
|
|
34
12
|
## Installation
|
|
35
|
-
|
|
36
13
|
```bash
|
|
37
14
|
npm install -g vde-layout
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
or
|
|
41
|
-
|
|
42
|
-
```bash
|
|
15
|
+
# or
|
|
43
16
|
pnpm add -g vde-layout
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
or
|
|
47
|
-
|
|
48
|
-
```bash
|
|
17
|
+
# or
|
|
49
18
|
bun add -g vde-layout
|
|
50
19
|
```
|
|
51
20
|
|
|
52
|
-
##
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
21
|
+
## Quick Start
|
|
22
|
+
1. Create a YAML file at `~/.config/vde/layout.yml` (or any supported location; see “Configuration Search Order”).
|
|
23
|
+
2. Paste a preset definition:
|
|
24
|
+
```yaml
|
|
25
|
+
presets:
|
|
26
|
+
web-dev:
|
|
27
|
+
name: Web Development
|
|
28
|
+
description: Editor, server, and logs
|
|
29
|
+
layout:
|
|
30
|
+
type: horizontal
|
|
31
|
+
ratio: [3, 2]
|
|
32
|
+
panes:
|
|
33
|
+
- name: editor
|
|
34
|
+
command: nvim
|
|
35
|
+
focus: true
|
|
36
|
+
- type: vertical
|
|
37
|
+
ratio: [7, 3]
|
|
38
|
+
panes:
|
|
39
|
+
- name: server
|
|
40
|
+
command: npm run dev
|
|
41
|
+
cwd: ~/projects/app
|
|
42
|
+
env:
|
|
43
|
+
NODE_ENV: development
|
|
44
|
+
- name: logs
|
|
45
|
+
command: tail -f logs/app.log
|
|
46
|
+
title: Logs
|
|
47
|
+
delay: 500
|
|
48
|
+
monitor:
|
|
49
|
+
name: Monitor
|
|
50
|
+
command: htop
|
|
51
|
+
```
|
|
52
|
+
3. Start tmux and run:
|
|
53
|
+
```bash
|
|
54
|
+
vde-layout web-dev
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## CLI Commands
|
|
58
|
+
- `vde-layout [preset]` – Apply the named preset. When omitted, vde-layout uses the `default` preset; if none exists it lists available presets and exits.
|
|
59
|
+
- `vde-layout list` – Show available presets with descriptions.
|
|
60
|
+
- `vde-layout dev --dry-run` – Display the tmux steps without executing them.
|
|
61
|
+
- `vde-layout dev --verbose` – Print informational logs, including resolved presets and plan details.
|
|
62
|
+
- `vde-layout dev --current-window` – Reuse the current tmux window after confirming that other panes can be closed.
|
|
63
|
+
- `vde-layout dev --new-window` – Force creation of a new tmux window even when presets or defaults request reuse.
|
|
64
|
+
- `vde-layout --config /path/to/layout.yml` – Load presets from a specific file.
|
|
65
|
+
- `vde-layout --help` – Show usage.
|
|
66
|
+
- `vde-layout --version` / `vde-layout -v` – Print package version (`-V` is kept for compatibility).
|
|
67
|
+
|
|
68
|
+
> **Note:** Applying a preset (without `--dry-run`) must be done inside an active tmux session.
|
|
69
|
+
|
|
70
|
+
## Configuration Search Order
|
|
71
|
+
When no `--config` flag is provided, vde-layout searches for configuration files in the following order:
|
|
72
|
+
1. `$VDE_CONFIG_PATH/layout.yml` (if `VDE_CONFIG_PATH` is set).
|
|
73
|
+
2. `$XDG_CONFIG_HOME/vde/layout.yml` or `~/.config/vde/layout.yml` when `XDG_CONFIG_HOME` is unset.
|
|
74
|
+
3. `<project-root>/.vde/layout.yml` (discovered by walking up from the current directory).
|
|
75
|
+
|
|
76
|
+
All existing files are merged, with project-specific definitions taking precedence over shared ones.
|
|
77
|
+
|
|
78
|
+
## Preset Structure
|
|
79
|
+
Each preset is an object under the `presets` key:
|
|
58
80
|
```yaml
|
|
59
81
|
presets:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
layout:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
panes:
|
|
68
|
-
- name: editor
|
|
69
|
-
command: nvim
|
|
70
|
-
focus: true
|
|
71
|
-
- type: vertical
|
|
72
|
-
ratio: [7, 3] # 70:30 ratio
|
|
73
|
-
panes:
|
|
74
|
-
- name: server
|
|
75
|
-
command: npm run dev
|
|
76
|
-
- name: logs
|
|
77
|
-
command: tail -f logs/app.log
|
|
78
|
-
|
|
79
|
-
# Simple 2-pane layout
|
|
80
|
-
simple:
|
|
81
|
-
name: Simple Layout
|
|
82
|
-
description: 2-pane configuration with editor and terminal
|
|
83
|
-
layout:
|
|
84
|
-
type: vertical
|
|
85
|
-
ratio: [7, 3] # 70:30 ratio
|
|
86
|
-
panes:
|
|
87
|
-
- name: editor
|
|
88
|
-
command: vim
|
|
89
|
-
- name: terminal
|
|
90
|
-
# Omitting command launches the default shell
|
|
91
|
-
|
|
92
|
-
# Single pane preset (without layout)
|
|
93
|
-
monitor:
|
|
94
|
-
name: System Monitor
|
|
95
|
-
description: System monitoring tool
|
|
96
|
-
command: htop
|
|
82
|
+
preset-key:
|
|
83
|
+
name: "Display Name" # required
|
|
84
|
+
description: "Summary" # optional
|
|
85
|
+
windowMode: new-window # optional; "new-window" (default) or "current-window"
|
|
86
|
+
layout: # optional; omit for single command presets
|
|
87
|
+
# see Layout Structure
|
|
88
|
+
command: "htop" # optional; used when layout is omitted
|
|
97
89
|
```
|
|
98
90
|
|
|
99
|
-
###
|
|
100
|
-
|
|
101
|
-
#### List Presets
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
vde-layout list
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
#### Execute a Preset
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
# Execute a specific preset
|
|
111
|
-
vde-layout dev
|
|
112
|
-
|
|
113
|
-
# Execute the default preset
|
|
114
|
-
vde-layout
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
#### Options
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
# dry-run mode (doesn't actually execute)
|
|
121
|
-
vde-layout dev --dry-run
|
|
122
|
-
|
|
123
|
-
# Show verbose logs
|
|
124
|
-
vde-layout dev --verbose
|
|
125
|
-
|
|
126
|
-
# Show help
|
|
127
|
-
vde-layout --help
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Configuration File Structure
|
|
131
|
-
|
|
132
|
-
### Presets
|
|
133
|
-
|
|
134
|
-
Each preset is defined as an object with the following fields:
|
|
135
|
-
|
|
136
|
-
```yaml
|
|
137
|
-
presets:
|
|
138
|
-
preset-name:
|
|
139
|
-
name: "Preset Name" # Required
|
|
140
|
-
description: "Description" # Optional
|
|
141
|
-
layout: # Optional (single pane when omitted)
|
|
142
|
-
# Layout definition
|
|
143
|
-
command: "Command" # Optional (only when layout is absent)
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### Layout Definition
|
|
147
|
-
|
|
148
|
-
Layouts define horizontal or vertical splits:
|
|
149
|
-
|
|
91
|
+
### Layout Structure
|
|
150
92
|
```yaml
|
|
151
93
|
layout:
|
|
152
|
-
type: horizontal
|
|
153
|
-
ratio: [3, 2]
|
|
154
|
-
panes:
|
|
155
|
-
- name: "
|
|
156
|
-
command: "
|
|
157
|
-
cwd: "~/project"
|
|
158
|
-
env:
|
|
159
|
-
|
|
160
|
-
focus: true
|
|
161
|
-
|
|
162
|
-
|
|
94
|
+
type: horizontal | vertical # required
|
|
95
|
+
ratio: [3, 2, ...] # required; positive numbers, auto-normalized
|
|
96
|
+
panes: # required
|
|
97
|
+
- name: "left" # required for terminal panes
|
|
98
|
+
command: "npm run start" # optional
|
|
99
|
+
cwd: "~/project" # optional
|
|
100
|
+
env: # optional
|
|
101
|
+
API_BASE_URL: http://localhost:3000
|
|
102
|
+
focus: true # optional; only one pane should be true
|
|
103
|
+
delay: 500 # optional; wait (ms) before running command
|
|
104
|
+
title: "Server" # optional; tmux pane title
|
|
105
|
+
- type: vertical # nested split
|
|
163
106
|
ratio: [1, 1]
|
|
164
107
|
panes:
|
|
165
|
-
- name: "
|
|
166
|
-
- name: "
|
|
108
|
+
- name: "tests"
|
|
109
|
+
- name: "shell"
|
|
167
110
|
```
|
|
168
111
|
|
|
169
|
-
###
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
- `[1, 1]` → `[50,
|
|
174
|
-
- `[2, 3]` → `[40, 60]` (40%, 60%)
|
|
175
|
-
- `[1, 2, 1]` → `[25, 50, 25]` (25%, 50%, 25%)
|
|
176
|
-
|
|
177
|
-
### Single Pane Presets
|
|
178
|
-
|
|
179
|
-
When layout is omitted, it operates as a single pane:
|
|
112
|
+
### Ratio Normalization
|
|
113
|
+
Ratios can be any set of positive integers. vde-layout normalizes them to percentages:
|
|
114
|
+
- `[1, 1]` → `[50, 50]`
|
|
115
|
+
- `[2, 3]` → `[40, 60]`
|
|
116
|
+
- `[1, 2, 1]` → `[25, 50, 25]`
|
|
180
117
|
|
|
118
|
+
### Single Command Presets
|
|
119
|
+
If you omit `layout`, the preset runs a single command in one pane (or opens the default shell when `command` is omitted):
|
|
181
120
|
```yaml
|
|
182
121
|
presets:
|
|
183
|
-
|
|
184
|
-
name:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
name: "Default Shell"
|
|
189
|
-
# Omitting command also launches the default shell
|
|
122
|
+
shell:
|
|
123
|
+
name: Default Shell
|
|
124
|
+
build:
|
|
125
|
+
name: Build Script
|
|
126
|
+
command: npm run build
|
|
190
127
|
```
|
|
191
128
|
|
|
192
|
-
###
|
|
129
|
+
### Window Mode Selection
|
|
130
|
+
- `defaults.windowMode` sets the default behavior for presets that omit `windowMode`. Allowed values are `new-window` (default) and `current-window`.
|
|
131
|
+
- Each preset may override the default by specifying its own `windowMode`.
|
|
132
|
+
- CLI flags (`--current-window` / `--new-window`) take highest precedence and override both presets and defaults.
|
|
133
|
+
- When `current-window` mode is used during an actual run, vde-layout prompts for confirmation before closing panes other than the pane running the command. Dry-run mode prints the intended closures without prompting.
|
|
193
134
|
|
|
194
|
-
The configuration file location can be changed using environment variables:
|
|
195
135
|
|
|
196
|
-
|
|
197
|
-
-
|
|
136
|
+
## Runtime Behavior
|
|
137
|
+
- Dry-run mode prints every tmux command and preserves the execution order you would see in a real run.
|
|
138
|
+
- Applying a preset creates (or reuses) a tmux window, splits panes according to the plan, sets environment variables, changes directories, and runs commands sequentially.
|
|
139
|
+
- If an error occurs (for example, a tmux command fails or the configuration is invalid), vde-layout returns a structured error with the failing step and guidance.
|
|
198
140
|
|
|
199
|
-
##
|
|
141
|
+
## Environment Variables
|
|
142
|
+
- `VDE_CONFIG_PATH` – Override the base directory for configuration files.
|
|
143
|
+
- `XDG_CONFIG_HOME` – XDG base directory root; defaults to `~/.config` when unset.
|
|
144
|
+
- `VDE_DEBUG=true` – Enable debug-level logs (includes stack traces).
|
|
145
|
+
- `VDE_VERBOSE=true` – Enable info-level logs without full debug output.
|
|
146
|
+
- `TMUX` – Automatically set by tmux. vde-layout checks this to ensure execution happens inside a session.
|
|
200
147
|
|
|
148
|
+
## Requirements
|
|
201
149
|
- Node.js 22 or higher
|
|
202
150
|
- tmux 2.0 or higher
|
|
203
|
-
- Must be executed within a tmux session
|
|
204
|
-
|
|
205
|
-
## License
|
|
206
|
-
|
|
207
|
-
MIT
|
|
208
151
|
|
|
209
152
|
## Contributing
|
|
153
|
+
Please submit bug reports and feature requests through [GitHub Issues](https://github.com/yuki-yano/vde-layout/issues).
|
|
210
154
|
|
|
211
|
-
|
|
155
|
+
## License
|
|
156
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,8 @@ import fs from "fs-extra";
|
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import os from "node:os";
|
|
10
10
|
import { z } from "zod";
|
|
11
|
+
import { createInterface } from "node:readline/promises";
|
|
12
|
+
import { stdin, stdout } from "node:process";
|
|
11
13
|
import { execa } from "execa";
|
|
12
14
|
import { createHash } from "node:crypto";
|
|
13
15
|
|
|
@@ -26,7 +28,8 @@ const ErrorCodes = {
|
|
|
26
28
|
NOT_IN_TMUX: "NOT_IN_TMUX",
|
|
27
29
|
TMUX_NOT_FOUND: "TMUX_NOT_FOUND",
|
|
28
30
|
TMUX_NOT_INSTALLED: "TMUX_NOT_INSTALLED",
|
|
29
|
-
UNSUPPORTED_TMUX_VERSION: "UNSUPPORTED_TMUX_VERSION"
|
|
31
|
+
UNSUPPORTED_TMUX_VERSION: "UNSUPPORTED_TMUX_VERSION",
|
|
32
|
+
USER_CANCELLED: "USER_CANCELLED"
|
|
30
33
|
};
|
|
31
34
|
const createBaseError = (name, message, code, details = {}) => {
|
|
32
35
|
const error = new Error(message);
|
|
@@ -78,6 +81,7 @@ const formatters = {
|
|
|
78
81
|
|
|
79
82
|
//#endregion
|
|
80
83
|
//#region src/models/schema.ts
|
|
84
|
+
const WindowModeSchema = z.enum(["new-window", "current-window"]);
|
|
81
85
|
const TerminalPaneSchema = z.object({
|
|
82
86
|
name: z.string().min(1),
|
|
83
87
|
command: z.string().optional(),
|
|
@@ -102,9 +106,13 @@ const PresetSchema = z.object({
|
|
|
102
106
|
name: z.string().min(1),
|
|
103
107
|
description: z.string().optional(),
|
|
104
108
|
layout: LayoutSchema.optional(),
|
|
105
|
-
command: z.string().optional()
|
|
109
|
+
command: z.string().optional(),
|
|
110
|
+
windowMode: WindowModeSchema.optional()
|
|
111
|
+
});
|
|
112
|
+
const ConfigSchema = z.object({
|
|
113
|
+
defaults: z.object({ windowMode: WindowModeSchema.optional() }).optional(),
|
|
114
|
+
presets: z.record(PresetSchema)
|
|
106
115
|
});
|
|
107
|
-
const ConfigSchema = z.object({ presets: z.record(PresetSchema) });
|
|
108
116
|
|
|
109
117
|
//#endregion
|
|
110
118
|
//#region src/config/validator.ts
|
|
@@ -231,7 +239,7 @@ const createConfigLoader = (options = {}) => {
|
|
|
231
239
|
const config = validateYAML(content);
|
|
232
240
|
mergedConfig = mergeConfigs(mergedConfig, config);
|
|
233
241
|
}
|
|
234
|
-
return mergedConfig;
|
|
242
|
+
return applyDefaults(mergedConfig);
|
|
235
243
|
};
|
|
236
244
|
return {
|
|
237
245
|
loadYAML: async () => {
|
|
@@ -290,10 +298,26 @@ const safeReadFile = async (filePath) => {
|
|
|
290
298
|
}
|
|
291
299
|
};
|
|
292
300
|
const mergeConfigs = (base, override) => {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
301
|
+
const mergedPresets = { ...base.presets };
|
|
302
|
+
for (const [presetKey, overridePreset] of Object.entries(override.presets)) {
|
|
303
|
+
const basePreset = base.presets[presetKey];
|
|
304
|
+
if (basePreset !== void 0 && basePreset.windowMode !== void 0 && overridePreset.windowMode !== void 0 && basePreset.windowMode !== overridePreset.windowMode) console.warn(`[vde-layout] Preset "${presetKey}" windowMode conflict: "${basePreset.windowMode}" overridden by "${overridePreset.windowMode}"`);
|
|
305
|
+
mergedPresets[presetKey] = overridePreset;
|
|
306
|
+
}
|
|
307
|
+
const baseDefaults = base.defaults;
|
|
308
|
+
const overrideDefaults = override.defaults;
|
|
309
|
+
if (baseDefaults?.windowMode !== void 0 && overrideDefaults?.windowMode !== void 0 && baseDefaults.windowMode !== overrideDefaults.windowMode) console.warn(`[vde-layout] defaults.windowMode conflict: "${baseDefaults.windowMode}" overridden by "${overrideDefaults.windowMode}"`);
|
|
310
|
+
const mergedDefaults = baseDefaults !== void 0 || overrideDefaults !== void 0 ? {
|
|
311
|
+
...baseDefaults ?? {},
|
|
312
|
+
...overrideDefaults ?? {}
|
|
313
|
+
} : void 0;
|
|
314
|
+
return mergedDefaults === void 0 ? { presets: mergedPresets } : {
|
|
315
|
+
defaults: mergedDefaults,
|
|
316
|
+
presets: mergedPresets
|
|
317
|
+
};
|
|
318
|
+
};
|
|
319
|
+
const applyDefaults = (config) => {
|
|
320
|
+
return config;
|
|
297
321
|
};
|
|
298
322
|
|
|
299
323
|
//#endregion
|
|
@@ -333,12 +357,16 @@ const createState = (options = {}) => {
|
|
|
333
357
|
if (typeof firstKey !== "string" || firstKey.length === 0) throw createConfigError("No presets defined", ErrorCodes.PRESET_NOT_FOUND);
|
|
334
358
|
return config.presets[firstKey];
|
|
335
359
|
};
|
|
360
|
+
const getDefaults = () => {
|
|
361
|
+
return ensureConfig().defaults;
|
|
362
|
+
};
|
|
336
363
|
return {
|
|
337
364
|
setConfigPath,
|
|
338
365
|
loadConfig,
|
|
339
366
|
getPreset,
|
|
340
367
|
listPresets,
|
|
341
|
-
getDefaultPreset
|
|
368
|
+
getDefaultPreset,
|
|
369
|
+
getDefaults
|
|
342
370
|
};
|
|
343
371
|
};
|
|
344
372
|
const createPresetManager = (options = {}) => {
|
|
@@ -348,7 +376,57 @@ const createPresetManager = (options = {}) => {
|
|
|
348
376
|
loadConfig: state.loadConfig,
|
|
349
377
|
getPreset: state.getPreset,
|
|
350
378
|
listPresets: state.listPresets,
|
|
351
|
-
getDefaultPreset: state.getDefaultPreset
|
|
379
|
+
getDefaultPreset: state.getDefaultPreset,
|
|
380
|
+
getDefaults: state.getDefaults
|
|
381
|
+
};
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region src/cli/window-mode.ts
|
|
386
|
+
const resolveWindowMode = ({ cli, preset, defaults }) => {
|
|
387
|
+
if (cli !== void 0) return {
|
|
388
|
+
mode: cli,
|
|
389
|
+
source: "cli"
|
|
390
|
+
};
|
|
391
|
+
if (preset !== void 0) return {
|
|
392
|
+
mode: preset,
|
|
393
|
+
source: "preset"
|
|
394
|
+
};
|
|
395
|
+
if (defaults !== void 0) return {
|
|
396
|
+
mode: defaults,
|
|
397
|
+
source: "defaults"
|
|
398
|
+
};
|
|
399
|
+
return {
|
|
400
|
+
mode: "new-window",
|
|
401
|
+
source: "fallback"
|
|
402
|
+
};
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
//#endregion
|
|
406
|
+
//#region src/cli/user-prompt.ts
|
|
407
|
+
const createPaneKillPrompter = (logger) => {
|
|
408
|
+
return async ({ panesToClose, dryRun }) => {
|
|
409
|
+
if (panesToClose.length === 0) return true;
|
|
410
|
+
const paneList = panesToClose.join(", ");
|
|
411
|
+
if (dryRun) {
|
|
412
|
+
logger.warn(`[DRY RUN] Would close panes: ${paneList}`);
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
logger.warn(`This operation will close the following panes: ${paneList}`);
|
|
416
|
+
if (stdin.isTTY !== true || stdout.isTTY !== true) {
|
|
417
|
+
logger.error("Cannot prompt for confirmation because the terminal is not interactive");
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
const rl = createInterface({
|
|
421
|
+
input: stdin,
|
|
422
|
+
output: stdout
|
|
423
|
+
});
|
|
424
|
+
try {
|
|
425
|
+
const normalized = (await rl.question("Continue? [y/N]: ")).trim().toLowerCase();
|
|
426
|
+
return normalized === "y" || normalized === "yes";
|
|
427
|
+
} finally {
|
|
428
|
+
await rl.close();
|
|
429
|
+
}
|
|
352
430
|
};
|
|
353
431
|
};
|
|
354
432
|
|
|
@@ -501,25 +579,66 @@ const isFunctionalCoreError = (value) => {
|
|
|
501
579
|
//#region src/executor/plan-runner.ts
|
|
502
580
|
const DOUBLE_QUOTE = "\"";
|
|
503
581
|
const ESCAPED_DOUBLE_QUOTE = "\\\"";
|
|
504
|
-
const executePlan = async ({ emission, executor, windowName }) => {
|
|
582
|
+
const executePlan = async ({ emission, executor, windowName, windowMode, onConfirmKill }) => {
|
|
505
583
|
const initialVirtualPaneId = emission.summary.initialPaneId;
|
|
506
584
|
if (typeof initialVirtualPaneId !== "string" || initialVirtualPaneId.length === 0) raiseExecutionError("INVALID_PLAN", {
|
|
507
585
|
message: "Plan emission is missing initial pane metadata",
|
|
508
586
|
path: "plan.initialPaneId"
|
|
509
587
|
});
|
|
510
588
|
const paneMap = /* @__PURE__ */ new Map();
|
|
511
|
-
const
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
589
|
+
const isDryRun = executor.isDryRun();
|
|
590
|
+
let initialPaneId;
|
|
591
|
+
if (windowMode === "current-window") {
|
|
592
|
+
const currentPaneId = await resolveCurrentPaneId({
|
|
593
|
+
executor,
|
|
594
|
+
contextPath: initialVirtualPaneId,
|
|
595
|
+
isDryRun
|
|
596
|
+
});
|
|
597
|
+
const panesToClose = (await listWindowPaneIds(executor, initialVirtualPaneId)).filter((paneId) => paneId !== currentPaneId);
|
|
598
|
+
if (panesToClose.length > 0) {
|
|
599
|
+
let confirmed = true;
|
|
600
|
+
if (onConfirmKill !== void 0) confirmed = await onConfirmKill({
|
|
601
|
+
panesToClose,
|
|
602
|
+
dryRun: isDryRun
|
|
603
|
+
});
|
|
604
|
+
if (confirmed !== true) throw createFunctionalError("execution", {
|
|
605
|
+
code: ErrorCodes.USER_CANCELLED,
|
|
606
|
+
message: "Aborted layout application for current window",
|
|
607
|
+
path: initialVirtualPaneId,
|
|
608
|
+
details: { panes: panesToClose }
|
|
609
|
+
});
|
|
610
|
+
await executeCommand(executor, [
|
|
611
|
+
"kill-pane",
|
|
612
|
+
"-a",
|
|
613
|
+
"-t",
|
|
614
|
+
currentPaneId
|
|
615
|
+
], {
|
|
616
|
+
code: ErrorCodes.TMUX_COMMAND_FAILED,
|
|
617
|
+
message: "Failed to close existing panes",
|
|
618
|
+
path: initialVirtualPaneId,
|
|
619
|
+
details: { command: [
|
|
620
|
+
"kill-pane",
|
|
621
|
+
"-a",
|
|
622
|
+
"-t",
|
|
623
|
+
currentPaneId
|
|
624
|
+
] }
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
initialPaneId = normalizePaneId(currentPaneId);
|
|
628
|
+
} else {
|
|
629
|
+
const newWindowCommand = [
|
|
630
|
+
"new-window",
|
|
631
|
+
"-P",
|
|
632
|
+
"-F",
|
|
633
|
+
"#{pane_id}"
|
|
634
|
+
];
|
|
635
|
+
if (typeof windowName === "string" && windowName.trim().length > 0) newWindowCommand.push("-n", windowName.trim());
|
|
636
|
+
initialPaneId = normalizePaneId(await executeCommand(executor, newWindowCommand, {
|
|
637
|
+
code: ErrorCodes.TMUX_COMMAND_FAILED,
|
|
638
|
+
message: "Failed to create tmux window",
|
|
639
|
+
path: initialVirtualPaneId
|
|
640
|
+
}));
|
|
641
|
+
}
|
|
523
642
|
registerPane(paneMap, initialVirtualPaneId, initialPaneId);
|
|
524
643
|
let executedSteps = 0;
|
|
525
644
|
for (const step of emission.steps) {
|
|
@@ -664,7 +783,27 @@ const executeCommand = async (executor, command, context) => {
|
|
|
664
783
|
});
|
|
665
784
|
}
|
|
666
785
|
};
|
|
667
|
-
const
|
|
786
|
+
const resolveCurrentPaneId = async ({ executor, contextPath, isDryRun }) => {
|
|
787
|
+
const envPaneId = process.env.TMUX_PANE;
|
|
788
|
+
if (typeof envPaneId === "string" && envPaneId.trim().length > 0) return normalizePaneId(envPaneId);
|
|
789
|
+
if (isDryRun) return "%0";
|
|
790
|
+
const paneId = (await executeCommand(executor, [
|
|
791
|
+
"display-message",
|
|
792
|
+
"-p",
|
|
793
|
+
"#{pane_id}"
|
|
794
|
+
], {
|
|
795
|
+
code: ErrorCodes.TMUX_COMMAND_FAILED,
|
|
796
|
+
message: "Failed to resolve current tmux pane",
|
|
797
|
+
path: contextPath
|
|
798
|
+
})).trim();
|
|
799
|
+
if (paneId.length === 0) throw createFunctionalError("execution", {
|
|
800
|
+
code: ErrorCodes.NOT_IN_TMUX_SESSION,
|
|
801
|
+
message: "Unable to determine current tmux pane",
|
|
802
|
+
path: contextPath
|
|
803
|
+
});
|
|
804
|
+
return normalizePaneId(paneId);
|
|
805
|
+
};
|
|
806
|
+
const listWindowPaneIds = async (executor, contextPath) => {
|
|
668
807
|
return (await executeCommand(executor, [
|
|
669
808
|
"list-panes",
|
|
670
809
|
"-F",
|
|
@@ -672,9 +811,12 @@ const listPaneIds = async (executor, step) => {
|
|
|
672
811
|
], {
|
|
673
812
|
code: ErrorCodes.TMUX_COMMAND_FAILED,
|
|
674
813
|
message: "Failed to list tmux panes",
|
|
675
|
-
path:
|
|
814
|
+
path: contextPath
|
|
676
815
|
})).split("\n").map((pane) => pane.trim()).filter((pane) => pane.length > 0);
|
|
677
816
|
};
|
|
817
|
+
const listPaneIds = async (executor, step) => {
|
|
818
|
+
return listWindowPaneIds(executor, step.id);
|
|
819
|
+
};
|
|
678
820
|
const findNewPaneId = (before, after) => {
|
|
679
821
|
const beforeSet = new Set(before);
|
|
680
822
|
return after.find((id) => !beforeSet.has(id));
|
|
@@ -1297,6 +1439,11 @@ const createCli = (options = {}) => {
|
|
|
1297
1439
|
const buildPresetSource = (presetName) => {
|
|
1298
1440
|
return typeof presetName === "string" && presetName.length > 0 ? `preset://${presetName}` : "preset://default";
|
|
1299
1441
|
};
|
|
1442
|
+
const determineCliWindowMode = (options$1) => {
|
|
1443
|
+
if (options$1.currentWindow === true && options$1.newWindow === true) throw new Error("Cannot use --current-window and --new-window at the same time");
|
|
1444
|
+
if (options$1.currentWindow === true) return "current-window";
|
|
1445
|
+
if (options$1.newWindow === true) return "new-window";
|
|
1446
|
+
};
|
|
1300
1447
|
const handleFunctionalError = (error) => {
|
|
1301
1448
|
const header = [`[${error.kind}]`, `[${error.code}]`];
|
|
1302
1449
|
if (typeof error.path === "string" && error.path.length > 0) header.push(`[${error.path}]`);
|
|
@@ -1361,6 +1508,19 @@ const createCli = (options = {}) => {
|
|
|
1361
1508
|
try {
|
|
1362
1509
|
await presetManager.loadConfig();
|
|
1363
1510
|
const preset = typeof presetName === "string" && presetName.length > 0 ? presetManager.getPreset(presetName) : presetManager.getDefaultPreset();
|
|
1511
|
+
const cliWindowMode = determineCliWindowMode({
|
|
1512
|
+
currentWindow: options$1.currentWindow,
|
|
1513
|
+
newWindow: options$1.newWindow
|
|
1514
|
+
});
|
|
1515
|
+
const defaults = presetManager.getDefaults();
|
|
1516
|
+
const windowModeResolution = resolveWindowMode({
|
|
1517
|
+
cli: cliWindowMode,
|
|
1518
|
+
preset: preset.windowMode,
|
|
1519
|
+
defaults: defaults?.windowMode
|
|
1520
|
+
});
|
|
1521
|
+
const windowMode = windowModeResolution.mode;
|
|
1522
|
+
logger.info(`Window mode: ${windowMode} (source: ${windowModeResolution.source})`);
|
|
1523
|
+
const confirmPaneClosure = createPaneKillPrompter(logger);
|
|
1364
1524
|
const tmuxEnv = process.env.TMUX;
|
|
1365
1525
|
if (!(typeof tmuxEnv === "string" && tmuxEnv.length > 0) && options$1.dryRun !== true) throw new Error("Must be run inside a tmux session");
|
|
1366
1526
|
const executor = createCommandExecutor({
|
|
@@ -1386,7 +1546,9 @@ const createCli = (options = {}) => {
|
|
|
1386
1546
|
const executionResult = await executePlan({
|
|
1387
1547
|
emission,
|
|
1388
1548
|
executor,
|
|
1389
|
-
windowName: preset.name ?? presetName ?? "vde-layout"
|
|
1549
|
+
windowName: preset.name ?? presetName ?? "vde-layout",
|
|
1550
|
+
windowMode,
|
|
1551
|
+
onConfirmKill: confirmPaneClosure
|
|
1390
1552
|
});
|
|
1391
1553
|
logger.info(`Executed ${executionResult.executedSteps} tmux steps`);
|
|
1392
1554
|
} catch (error) {
|
|
@@ -1399,10 +1561,13 @@ const createCli = (options = {}) => {
|
|
|
1399
1561
|
}
|
|
1400
1562
|
};
|
|
1401
1563
|
const setupProgram = () => {
|
|
1402
|
-
program.name("vde-layout").description("VDE (Vibrant Development Environment) Layout Manager - tmux pane layout management tool").version(version, "-
|
|
1403
|
-
program.option("
|
|
1564
|
+
program.name("vde-layout").description("VDE (Vibrant Development Environment) Layout Manager - tmux pane layout management tool").version(version, "-v, --version", "Show version").helpOption("-h, --help", "Show help");
|
|
1565
|
+
program.option("--verbose", "Show detailed logs", false);
|
|
1566
|
+
program.option("-V", "Show version (deprecated; use -v)");
|
|
1404
1567
|
program.option("--dry-run", "Display commands without executing", false);
|
|
1405
1568
|
program.option("--config <path>", "Path to configuration file");
|
|
1569
|
+
program.option("--current-window", "Use the current tmux window for layout (kills other panes)", false);
|
|
1570
|
+
program.option("--new-window", "Always create a new tmux window for layout", false);
|
|
1406
1571
|
program.command("list").description("List available presets").action(async () => {
|
|
1407
1572
|
await listPresets();
|
|
1408
1573
|
});
|
|
@@ -1413,13 +1578,19 @@ const createCli = (options = {}) => {
|
|
|
1413
1578
|
const opts = program.opts();
|
|
1414
1579
|
await executePreset(presetName, {
|
|
1415
1580
|
verbose: opts.verbose === true,
|
|
1416
|
-
dryRun: opts.dryRun === true
|
|
1581
|
+
dryRun: opts.dryRun === true,
|
|
1582
|
+
currentWindow: opts.currentWindow === true,
|
|
1583
|
+
newWindow: opts.newWindow === true
|
|
1417
1584
|
});
|
|
1418
1585
|
});
|
|
1419
1586
|
};
|
|
1420
1587
|
setupProgram();
|
|
1421
1588
|
const run = async (args = process.argv.slice(2)) => {
|
|
1422
|
-
|
|
1589
|
+
if (args.includes("-V")) {
|
|
1590
|
+
console.log(version);
|
|
1591
|
+
return;
|
|
1592
|
+
}
|
|
1593
|
+
const requestedVersion = args.some((arg) => arg === "--version" || arg === "-v");
|
|
1423
1594
|
const requestedHelp = args.includes("--help") || args.includes("-h");
|
|
1424
1595
|
try {
|
|
1425
1596
|
await program.parseAsync(args, { from: "user" });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["formatters: Record<string, (error: VDELayoutError) => string>","SplitPaneSchema: z.ZodType<unknown>","PaneSchema: z.ZodType<unknown>","path","candidates: string[]","mergedConfig: Config","yaml","paths: string[]","existing: string[]","loaderOptions: ConfigLoaderOptions","cachedConfig: Config | null","parseCommand","toCommandString","newWindowCommand: string[]","severityRank: Record<DiagnosticsSeverity, number>","findings: DiagnosticsFinding[]","path","parsedPreset: unknown","parsed: unknown","panes: PlanNode[]","focusPaneIds: string[]","terminalPaneIds: string[]","steps: CommandStep[]","current: PlanNode","KNOWN_ISSUES: ReadonlyArray<string>","functionalCore: FunctionalCoreBridge","defaultCompilePreset","defaultCreateLayoutPlan","defaultEmitPlan","logger: Logger","document: Record<string, unknown>","toYAML","options","compileResult: CompilePresetSuccess","planResult: CreateLayoutPlanSuccess","emission: PlanEmission"],"sources":["../src/utils/errors.ts","../src/models/schema.ts","../src/config/validator.ts","../src/config/loader.ts","../src/layout/preset.ts","../src/utils/logger.ts","../src/executor/real-executor.ts","../src/executor/dry-run-executor.ts","../src/core/errors.ts","../src/executor/plan-runner.ts","../src/core/diagnostics.ts","../src/core/compile.ts","../src/core/planner.ts","../src/core/emitter.ts","../src/cli.ts","../src/index.ts"],"sourcesContent":["export type VDELayoutError = Error & {\n readonly code: string\n readonly details: Readonly<Record<string, unknown>>\n}\n\nexport const ErrorCodes = {\n CONFIG_NOT_FOUND: \"CONFIG_NOT_FOUND\",\n CONFIG_PARSE_ERROR: \"CONFIG_PARSE_ERROR\",\n CONFIG_PERMISSION_ERROR: \"CONFIG_PERMISSION_ERROR\",\n INVALID_PRESET: \"INVALID_PRESET\",\n PRESET_NOT_FOUND: \"PRESET_NOT_FOUND\",\n INVALID_LAYOUT: \"INVALID_LAYOUT\",\n INVALID_PANE: \"INVALID_PANE\",\n TMUX_NOT_RUNNING: \"TMUX_NOT_RUNNING\",\n TMUX_COMMAND_FAILED: \"TMUX_COMMAND_FAILED\",\n NOT_IN_TMUX_SESSION: \"NOT_IN_TMUX_SESSION\",\n NOT_IN_TMUX: \"NOT_IN_TMUX\",\n TMUX_NOT_FOUND: \"TMUX_NOT_FOUND\",\n TMUX_NOT_INSTALLED: \"TMUX_NOT_INSTALLED\",\n UNSUPPORTED_TMUX_VERSION: \"UNSUPPORTED_TMUX_VERSION\",\n} as const\n\nconst createBaseError = (\n name: string,\n message: string,\n code: string,\n details: Readonly<Record<string, unknown>> = {},\n): VDELayoutError => {\n const error = new Error(message) as VDELayoutError\n error.name = name\n ;(error as { code: string }).code = code\n ;(error as { details: Readonly<Record<string, unknown>> }).details = details\n return error\n}\n\nexport const createConfigError = (\n message: string,\n code: string,\n details: Readonly<Record<string, unknown>> = {},\n): VDELayoutError => {\n return createBaseError(\"ConfigError\", message, code, details)\n}\n\nexport const createValidationError = (\n message: string,\n code: string,\n details: Readonly<Record<string, unknown>> = {},\n): VDELayoutError => {\n return createBaseError(\"ValidationError\", message, code, details)\n}\n\nexport const createTmuxError = (\n message: string,\n code: string,\n details: Readonly<Record<string, unknown>> = {},\n): VDELayoutError => {\n return createBaseError(\"TmuxError\", message, code, details)\n}\n\nexport const createEnvironmentError = (\n message: string,\n code: string,\n details: Readonly<Record<string, unknown>> = {},\n): VDELayoutError => {\n return createBaseError(\"EnvironmentError\", message, code, details)\n}\n\nexport const isVDELayoutError = (error: unknown): error is VDELayoutError => {\n if (typeof error !== \"object\" || error === null) {\n return false\n }\n\n if (!(\"code\" in error)) {\n return false\n }\n\n const { code } = error as { code?: unknown }\n if (typeof code !== \"string\") {\n return false\n }\n\n if (!(\"details\" in error)) {\n return false\n }\n\n return true\n}\n\nconst formatters: Record<string, (error: VDELayoutError) => string> = {\n [ErrorCodes.CONFIG_NOT_FOUND]: (error) => {\n const searchPaths = error.details.searchPaths\n if (!Array.isArray(searchPaths)) {\n return \"\"\n }\n\n const lines = [\"\", \"Searched in the following locations:\"]\n searchPaths.forEach((location) => lines.push(` - ${location}`))\n lines.push(\"\", \"To create a configuration file, run:\")\n lines.push(\" mkdir -p ~/.config/vde\")\n lines.push(' echo \"presets: {}\" > ~/.config/vde/layout.yml')\n return lines.join(\"\\n\")\n },\n [ErrorCodes.NOT_IN_TMUX_SESSION]: () => {\n return \"\\nThis command must be run inside a tmux session.\\nStart tmux first with: tmux\\n\"\n },\n [ErrorCodes.TMUX_NOT_INSTALLED]: () => {\n return (\n \"\\ntmux is required but not installed.\\n\" +\n \"Install tmux using your package manager:\\n\" +\n \" - macOS: brew install tmux\\n\" +\n \" - Ubuntu/Debian: sudo apt-get install tmux\\n\" +\n \" - Fedora: sudo dnf install tmux\\n\"\n )\n },\n [ErrorCodes.UNSUPPORTED_TMUX_VERSION]: (error) => {\n const requiredVersion = error.details.requiredVersion\n if (typeof requiredVersion !== \"string\") {\n return \"\"\n }\n return `\\nRequired tmux version: ${requiredVersion} or higher\\n`\n },\n}\n\nexport const formatError = (error: Error): string => {\n if (!isVDELayoutError(error)) {\n return `${error.name}: ${error.message}`\n }\n\n let message = `Error: ${error.message}`\n\n const formatter = formatters[error.code]\n if (formatter) {\n message += `\\n${formatter(error)}`\n }\n\n const commandDetail = error.details.command\n if (commandDetail !== undefined) {\n message += `\\nCommand: ${JSON.stringify(commandDetail)}`\n }\n\n const stderrDetail = error.details.stderr\n if (stderrDetail !== undefined) {\n message += `\\nstderr: ${String(stderrDetail)}`\n }\n\n const presetDetail = error.details.preset\n if (presetDetail !== undefined) {\n message += `\\npreset: ${String(presetDetail)}`\n }\n\n const nestedErrors = error.details.errors\n if (Array.isArray(nestedErrors) && nestedErrors.length > 0) {\n message += \"\\nValidation errors:\\n\"\n nestedErrors.forEach((item) => {\n message += ` - ${String(item)}\\n`\n })\n }\n\n return message\n}\n","import { z } from \"zod\"\n\n// Terminal pane schema\nconst TerminalPaneSchema = z\n .object({\n name: z.string().min(1),\n command: z.string().optional(),\n cwd: z.string().optional(),\n env: z.record(z.string()).optional(),\n delay: z.number().int().positive().optional(),\n title: z.string().optional(),\n focus: z.boolean().optional(),\n })\n .strict()\n\n// Split container schema (recursive)\nconst SplitPaneSchema: z.ZodType<unknown> = z.lazy(() =>\n z\n .object({\n type: z.enum([\"horizontal\", \"vertical\"]),\n ratio: z.array(z.number().positive()).min(1),\n panes: z.array(PaneSchema).min(1),\n })\n .strict()\n .refine((data) => data.ratio.length === data.panes.length, {\n message: \"Number of elements in ratio array does not match number of elements in panes array\",\n }),\n)\n\n// Recursive Pane schema definition\nexport const PaneSchema: z.ZodType<unknown> = z.lazy(() => z.union([SplitPaneSchema, TerminalPaneSchema]))\n\n// Layout schema definition\nexport const LayoutSchema = z\n .object({\n type: z.enum([\"horizontal\", \"vertical\"]),\n ratio: z.array(z.number().positive()).min(1),\n panes: z.array(PaneSchema).min(1),\n })\n .refine((data) => data.ratio.length === data.panes.length, {\n message: \"Number of elements in ratio array does not match number of elements in panes array\",\n })\n\n// Preset schema definition\nexport const PresetSchema = z.object({\n name: z.string().min(1),\n description: z.string().optional(),\n layout: LayoutSchema.optional(),\n command: z.string().optional(),\n})\n\n// Config schema definition\nexport const ConfigSchema = z.object({\n presets: z.record(PresetSchema),\n})\n\n// Validation result type\ntype ValidationResult<T> = {\n success: boolean\n data?: T\n error?: string\n}\n\n// Helper function to format Zod errors consistently\nconst formatValidationError = (error: z.ZodError): string => {\n const messages = error.errors.map((e) => {\n const path = e.path.join(\".\")\n const message = e.message\n\n // Customize error message for panes array element count check\n if (path === \"layout.panes\" && message.includes(\"at least 2 element\")) {\n return `${path}: panes array must have at least 2 elements`\n }\n\n return `${path}: ${message}`\n })\n\n return messages.join(\"\\n\")\n}\n\n// Config validation\nexport const validateConfig = (data: unknown): ValidationResult<z.infer<typeof ConfigSchema>> => {\n try {\n const parsed = ConfigSchema.parse(data)\n return { success: true, data: parsed }\n } catch (error) {\n if (error instanceof z.ZodError) {\n return { success: false, error: formatValidationError(error) }\n }\n return { success: false, error: String(error) }\n }\n}\n\n// Preset validation\nexport const validatePreset = (data: unknown): ValidationResult<z.infer<typeof PresetSchema>> => {\n try {\n const parsed = PresetSchema.parse(data)\n return { success: true, data: parsed }\n } catch (error) {\n if (error instanceof z.ZodError) {\n return { success: false, error: formatValidationError(error) }\n }\n return { success: false, error: String(error) }\n }\n}\n\n// Pane validation\nexport const validatePane = (data: unknown): ValidationResult<z.infer<typeof PaneSchema>> => {\n try {\n const parsed = PaneSchema.parse(data)\n return { success: true, data: parsed }\n } catch (error) {\n if (error instanceof z.ZodError) {\n return { success: false, error: formatValidationError(error) }\n }\n return { success: false, error: String(error) }\n }\n}\n","import * as YAML from \"yaml\"\nimport { z } from \"zod\"\nimport { ConfigSchema } from \"../models/schema.ts\"\nimport type { Config } from \"../models/types.ts\"\nimport { createValidationError, ErrorCodes, isVDELayoutError } from \"../utils/errors.ts\"\n\n/**\n * Parse YAML text into an object\n * @param yamlText - YAML text to parse\n * @returns Parsed object\n * @throws {ValidationError} When YAML parsing fails\n */\nconst parseYAML = (yamlText: string): unknown => {\n // Input validation\n if (!yamlText || typeof yamlText !== \"string\") {\n throw createValidationError(\"YAML text not provided\", ErrorCodes.CONFIG_PARSE_ERROR, {\n received: typeof yamlText,\n })\n }\n\n try {\n return YAML.parse(yamlText)\n } catch (error) {\n throw createValidationError(\"Failed to parse YAML\", ErrorCodes.CONFIG_PARSE_ERROR, {\n parseError: error instanceof Error ? error.message : String(error),\n yamlSnippet: yamlText.substring(0, 200),\n })\n }\n}\n\n/**\n * Validate basic configuration structure\n * @param parsed - Parsed YAML object\n * @throws {ValidationError} When structure is invalid\n */\nconst validateConfigStructure = (parsed: unknown): void => {\n // Check for empty YAML\n if (parsed === null || parsed === undefined || typeof parsed !== \"object\") {\n throw createValidationError(\"YAML is empty or invalid format\", ErrorCodes.CONFIG_PARSE_ERROR, {\n parsed: parsed,\n })\n }\n\n // Check for presets field existence\n const parsedObj = parsed as Record<string, unknown>\n if (!(\"presets\" in parsedObj) || parsedObj.presets === undefined || parsedObj.presets === null) {\n throw createValidationError(\"presets field is required\", ErrorCodes.INVALID_PRESET, {\n availableFields: Object.keys(parsedObj),\n })\n }\n\n // Check for empty presets\n const presetsObj = parsedObj.presets\n if (typeof presetsObj !== \"object\" || presetsObj === null || Object.keys(presetsObj).length === 0) {\n throw createValidationError(\"At least one preset is required\", ErrorCodes.INVALID_PRESET, {\n presets: presetsObj,\n })\n }\n}\n\n/**\n * Format Zod validation errors into user-friendly messages\n * @param error - Zod validation error\n * @returns Formatted error issues\n */\nconst formatZodErrors = (error: z.ZodError): Array<{ path: string; message: string; code: string }> => {\n return error.issues.map((issue) => {\n const path = issue.path.join(\".\")\n let message = issue.message\n\n // Custom error messages\n if (issue.code === \"invalid_type\") {\n if (issue.path.includes(\"command\") && issue.expected === \"string\") {\n message = \"command field must be a string\"\n } else if (issue.path.includes(\"workingDirectory\") && issue.expected === \"string\") {\n message = \"workingDirectory field must be a string\"\n } else if (issue.received === \"number\" && issue.expected === \"string\") {\n message = `${path} must be a string`\n } else if (issue.received === \"array\" && issue.expected === \"string\") {\n message = `${path} must be a string`\n }\n } else if (issue.code === \"invalid_union\") {\n // Detailed error messages for union types\n const unionIssue = issue as z.ZodIssue & { unionErrors?: z.ZodError[] }\n if (unionIssue.unionErrors !== undefined) {\n // When command is missing in terminal pane\n const terminalError = unionIssue.unionErrors.find(\n (e) => e.issues?.some((i) => i.path.includes(\"command\") && i.code === \"invalid_type\") === true,\n )\n if (terminalError !== undefined) {\n message = \"command field is required\"\n } else {\n // When panes is missing in split pane\n const splitError = unionIssue.unionErrors.find(\n (e) => e.issues?.some((i) => i.path.includes(\"panes\") && i.code === \"invalid_type\") === true,\n )\n if (splitError !== undefined) {\n message = \"panes field is required\"\n } else {\n message = 'Pane type must be \"terminal\" or \"split\"'\n }\n }\n } else {\n message = 'Pane type must be \"terminal\" or \"split\"'\n }\n } else if (issue.code === \"invalid_literal\") {\n if (issue.path.includes(\"direction\")) {\n message = 'direction must be \"horizontal\" or \"vertical\"'\n }\n } else if (issue.message.includes(\"required\")) {\n // Use the message as is\n message = issue.message\n } else if (issue.code === \"custom\" && issue.message.includes(\"ratio array\")) {\n message = issue.message\n } else if (issue.code === \"too_small\" && issue.message.includes(\"Array must contain at least\")) {\n // Minimum array elements error\n if (path.includes(\"panes\")) {\n message = \"panes array must contain at least 2 elements\"\n } else if (path.includes(\"ratio\")) {\n message = \"ratio array must contain at least 2 elements\"\n } else {\n message = issue.message\n }\n }\n\n return {\n path,\n message,\n code: issue.code,\n }\n })\n}\n\n/**\n * Validates YAML text and converts it to a type-safe Config object\n * @param yamlText - YAML text to validate\n * @returns Validated Config object\n * @throws {ValidationError} When YAML is invalid\n */\nexport const validateYAML = (yamlText: string): Config => {\n // Parse YAML\n const parsed = parseYAML(yamlText)\n\n // Validate basic structure\n validateConfigStructure(parsed)\n\n // Ratio sum validation removed - unnecessary due to automatic normalization\n\n // Validation with Zod schema\n try {\n const validated = ConfigSchema.parse(parsed)\n return validated\n } catch (error) {\n if (error instanceof z.ZodError) {\n const issues = formatZodErrors(error)\n\n // Use the first error message as the primary message\n const primaryMessage = issues.length > 0 && issues[0] ? issues[0].message : \"Configuration validation failed\"\n\n throw createValidationError(primaryMessage, ErrorCodes.CONFIG_PARSE_ERROR, {\n issues,\n rawErrors: error.issues,\n })\n }\n\n if (isVDELayoutError(error) && error.name === \"ValidationError\") {\n throw error\n }\n\n // Other errors\n throw createValidationError(\"Unexpected validation error occurred\", ErrorCodes.CONFIG_PARSE_ERROR, {\n error: error instanceof Error ? error.message : String(error),\n })\n }\n}\n","import fs from \"fs-extra\"\nimport path from \"path\"\nimport os from \"os\"\nimport * as yaml from \"yaml\"\nimport type { Config } from \"../models/types.ts\"\nimport { createConfigError, ErrorCodes } from \"../utils/errors.ts\"\nimport { validateYAML } from \"./validator.ts\"\n\nexport type ConfigLoaderOptions = {\n readonly configPaths?: string[]\n}\n\nexport type ConfigLoader = {\n readonly loadYAML: () => Promise<string>\n readonly loadConfig: () => Promise<Config>\n readonly findConfigFile: () => Promise<string | null>\n readonly getSearchPaths: () => string[]\n}\n\nexport const createConfigLoader = (options: ConfigLoaderOptions = {}): ConfigLoader => {\n const explicitConfigPaths = options.configPaths\n\n const computeCachedSearchPaths = (): string[] => {\n if (explicitConfigPaths && explicitConfigPaths.length > 0) {\n return [...explicitConfigPaths]\n }\n\n const candidates: string[] = []\n const projectCandidate = findProjectConfigCandidate()\n if (projectCandidate !== null) {\n candidates.push(projectCandidate)\n }\n\n candidates.push(...buildDefaultSearchPaths())\n\n return [...new Set(candidates)]\n }\n\n const loadConfig = async (): Promise<Config> => {\n if (explicitConfigPaths && explicitConfigPaths.length > 0) {\n const filePath = await findFirstExisting(explicitConfigPaths)\n if (filePath === null) {\n throw createConfigError(\"Configuration file not found\", ErrorCodes.CONFIG_NOT_FOUND, {\n searchPaths: explicitConfigPaths,\n })\n }\n\n const content = await safeReadFile(filePath)\n return validateYAML(content)\n }\n\n const searchPaths = computeCachedSearchPaths()\n const existingPaths = await filterExistingPaths(searchPaths)\n\n if (existingPaths.length === 0) {\n throw createConfigError(\"Configuration file not found\", ErrorCodes.CONFIG_NOT_FOUND, {\n searchPaths,\n })\n }\n\n const projectPath = findProjectConfigCandidate()\n const globalPaths = existingPaths.filter((filePath) => filePath !== projectPath)\n\n let mergedConfig: Config = { presets: {} }\n\n for (const globalPath of globalPaths) {\n const content = await safeReadFile(globalPath)\n const config = validateYAML(content)\n mergedConfig = mergeConfigs(mergedConfig, config)\n }\n\n if (projectPath !== null && (await fs.pathExists(projectPath))) {\n const content = await safeReadFile(projectPath)\n const config = validateYAML(content)\n mergedConfig = mergeConfigs(mergedConfig, config)\n }\n\n return mergedConfig\n }\n\n return {\n loadYAML: async (): Promise<string> => {\n const config = await loadConfig()\n return yaml.stringify(config)\n },\n loadConfig,\n findConfigFile: async (): Promise<string | null> => {\n const searchPaths =\n explicitConfigPaths && explicitConfigPaths.length > 0 ? [...explicitConfigPaths] : computeCachedSearchPaths()\n\n for (const searchPath of searchPaths) {\n if (await fs.pathExists(searchPath)) {\n return searchPath\n }\n }\n return null\n },\n getSearchPaths: (): string[] => computeCachedSearchPaths(),\n }\n}\n\nconst buildDefaultSearchPaths = (): string[] => {\n const paths: string[] = []\n\n const vdeConfigPath = process.env.VDE_CONFIG_PATH\n if (vdeConfigPath !== undefined) {\n paths.push(path.join(vdeConfigPath, \"layout.yml\"))\n }\n\n const homeDir = process.env.HOME ?? os.homedir()\n const xdgConfigHome = process.env.XDG_CONFIG_HOME ?? path.join(homeDir, \".config\")\n paths.push(path.join(xdgConfigHome, \"vde\", \"layout.yml\"))\n\n return [...new Set(paths)]\n}\n\nconst findProjectConfigCandidate = (): string | null => {\n let currentDir = process.cwd()\n const { root } = path.parse(currentDir)\n\n while (true) {\n const candidate = path.join(currentDir, \".vde\", \"layout.yml\")\n if (fs.existsSync(candidate)) {\n return candidate\n }\n\n if (currentDir === root) {\n break\n }\n\n const parent = path.dirname(currentDir)\n if (parent === currentDir) {\n break\n }\n\n currentDir = parent\n }\n\n return null\n}\n\nconst findFirstExisting = async (paths: ReadonlyArray<string>): Promise<string | null> => {\n for (const candidate of paths) {\n if (await fs.pathExists(candidate)) {\n return candidate\n }\n }\n return null\n}\n\nconst filterExistingPaths = async (paths: ReadonlyArray<string>): Promise<string[]> => {\n const existing: string[] = []\n for (const candidate of paths) {\n if (await fs.pathExists(candidate)) {\n existing.push(candidate)\n }\n }\n return existing\n}\n\nconst safeReadFile = async (filePath: string): Promise<string> => {\n try {\n return await fs.readFile(filePath, \"utf8\")\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n throw createConfigError(`Failed to read configuration file`, ErrorCodes.CONFIG_PERMISSION_ERROR, {\n filePath,\n error: errorMessage,\n })\n }\n}\n\nconst mergeConfigs = (base: Config, override: Config): Config => {\n return {\n presets: {\n ...base.presets,\n ...override.presets,\n },\n }\n}\n","import { createConfigLoader, type ConfigLoaderOptions } from \"../config/loader.ts\"\nimport { createConfigError, ErrorCodes } from \"../utils/errors.ts\"\nimport type { Config, Preset, PresetInfo } from \"../models/types.ts\"\nimport type { PresetManager } from \"../types/preset-manager.ts\"\n\ntype PresetState = {\n setConfigPath: (filePath: string) => void\n loadConfig: () => Promise<void>\n getPreset: (name: string) => Preset\n listPresets: () => PresetInfo[]\n getDefaultPreset: () => Preset\n}\n\nconst createState = (options: ConfigLoaderOptions = {}): PresetState => {\n let loaderOptions: ConfigLoaderOptions = options\n let cachedConfig: Config | null = null\n\n const setConfigPath = (filePath: string): void => {\n loaderOptions = { configPaths: [filePath] }\n cachedConfig = null\n }\n\n const loadConfig = async (): Promise<void> => {\n const loader = createConfigLoader(loaderOptions)\n cachedConfig = await loader.loadConfig()\n }\n\n const ensureConfig = (): Config => {\n if (cachedConfig === null) {\n throw createConfigError(\"Configuration not loaded\", ErrorCodes.CONFIG_NOT_FOUND)\n }\n return cachedConfig\n }\n\n const getPreset = (name: string): Preset => {\n const config = ensureConfig()\n const preset = config.presets[name]\n if (preset === undefined) {\n throw createConfigError(`Preset \"${name}\" not found`, ErrorCodes.PRESET_NOT_FOUND, {\n availablePresets: Object.keys(config.presets),\n })\n }\n return preset\n }\n\n const listPresets = (): PresetInfo[] => {\n if (cachedConfig === null) {\n return []\n }\n\n return Object.entries(cachedConfig.presets).map(([key, preset]) => ({\n key,\n name: preset.name,\n description: preset.description,\n }))\n }\n\n const getDefaultPreset = (): Preset => {\n const config = ensureConfig()\n\n if (config.presets.default !== undefined) {\n return config.presets.default\n }\n\n const firstKey = Object.keys(config.presets)[0]\n if (typeof firstKey !== \"string\" || firstKey.length === 0) {\n throw createConfigError(\"No presets defined\", ErrorCodes.PRESET_NOT_FOUND)\n }\n\n return config.presets[firstKey]!\n }\n\n return {\n setConfigPath,\n loadConfig,\n getPreset,\n listPresets,\n getDefaultPreset,\n }\n}\n\nexport const createPresetManager = (options: ConfigLoaderOptions = {}): PresetManager => {\n const state = createState(options)\n return {\n setConfigPath: state.setConfigPath,\n loadConfig: state.loadConfig,\n getPreset: state.getPreset,\n listPresets: state.listPresets,\n getDefaultPreset: state.getDefaultPreset,\n }\n}\n","import chalk from \"chalk\"\n\nexport enum LogLevel {\n ERROR = 0,\n WARN = 1,\n INFO = 2,\n DEBUG = 3,\n}\n\ntype LoggerOptions = {\n readonly level?: LogLevel\n readonly prefix?: string\n}\n\nexport type Logger = {\n readonly level: LogLevel\n readonly prefix: string\n error: (message: string, error?: Error) => void\n warn: (message: string) => void\n info: (message: string) => void\n debug: (message: string) => void\n success: (message: string) => void\n createChild: (suffix: string) => Logger\n}\n\nconst resolveDefaultLogLevel = (): LogLevel => {\n if (process.env.VDE_DEBUG === \"true\") {\n return LogLevel.DEBUG\n }\n if (process.env.VDE_VERBOSE === \"true\") {\n return LogLevel.INFO\n }\n return LogLevel.WARN\n}\n\nconst formatMessage = (prefix: string, message: string): string => {\n return prefix ? `${prefix} ${message}` : message\n}\n\nexport const createLogger = (options: LoggerOptions = {}): Logger => {\n const level = options.level ?? resolveDefaultLogLevel()\n const prefix = options.prefix ?? \"\"\n\n const build = (nextPrefix: string, nextLevel: LogLevel): Logger => {\n const resolvedPrefix = nextPrefix\n\n return {\n level: nextLevel,\n prefix: resolvedPrefix,\n error(message: string, error?: Error): void {\n if (nextLevel >= LogLevel.ERROR) {\n console.error(chalk.red(formatMessage(resolvedPrefix, `Error: ${message}`)))\n if (error && process.env.VDE_DEBUG === \"true\") {\n console.error(chalk.gray(error.stack))\n }\n }\n },\n warn(message: string): void {\n if (nextLevel >= LogLevel.WARN) {\n console.warn(chalk.yellow(formatMessage(resolvedPrefix, message)))\n }\n },\n info(message: string): void {\n if (nextLevel >= LogLevel.INFO) {\n console.log(formatMessage(resolvedPrefix, message))\n }\n },\n debug(message: string): void {\n if (nextLevel >= LogLevel.DEBUG) {\n console.log(chalk.gray(formatMessage(resolvedPrefix, `[DEBUG] ${message}`)))\n }\n },\n success(message: string): void {\n console.log(chalk.green(formatMessage(resolvedPrefix, message)))\n },\n createChild(suffix: string): Logger {\n const childPrefix = resolvedPrefix ? `${resolvedPrefix} ${suffix}` : suffix\n return build(childPrefix, nextLevel)\n },\n }\n }\n\n return build(prefix, level)\n}\n","import { execa } from \"execa\"\nimport { createTmuxError, ErrorCodes } from \"../utils/errors.ts\"\nimport type { CommandExecutor } from \"../types/command-executor.ts\"\nimport { createLogger, LogLevel } from \"../utils/logger.ts\"\n\ntype RealExecutorOptions = {\n readonly verbose?: boolean\n}\n\nconst parseCommand = (commandOrArgs: string | string[]): string[] => {\n return typeof commandOrArgs === \"string\"\n ? commandOrArgs\n .split(\" \")\n .filter((segment) => segment.length > 0)\n .slice(1)\n : commandOrArgs\n}\n\nconst toCommandString = (args: string[]): string => {\n return [\"tmux\", ...args].join(\" \")\n}\n\nexport const createRealExecutor = (options: RealExecutorOptions = {}): CommandExecutor => {\n const verbose = options.verbose ?? false\n const logger = createLogger({\n level: verbose ? LogLevel.INFO : LogLevel.WARN,\n prefix: \"[tmux]\",\n })\n\n const execute = async (commandOrArgs: string | string[]): Promise<string> => {\n const args = parseCommand(commandOrArgs)\n const commandString = toCommandString(args)\n\n logger.info(`Executing: ${commandString}`)\n\n try {\n const result = await execa(\"tmux\", args)\n return result.stdout\n } catch (error) {\n const execaError = error as { exitCode?: number; stderr?: string; message: string }\n\n throw createTmuxError(\"Failed to execute tmux command\", ErrorCodes.TMUX_COMMAND_FAILED, {\n command: commandString,\n exitCode: execaError.exitCode,\n stderr: execaError.stderr,\n })\n }\n }\n\n return {\n execute,\n async executeMany(commandsList: string[][]): Promise<void> {\n for (const args of commandsList) {\n await execute(args)\n }\n },\n isDryRun(): boolean {\n return false\n },\n logCommand(command: string): void {\n logger.info(`Executing: ${command}`)\n },\n }\n}\n","import type { CommandExecutor } from \"../types/command-executor.ts\"\nimport { createLogger, LogLevel } from \"../utils/logger.ts\"\n\ntype DryRunExecutorOptions = {\n readonly verbose?: boolean\n}\n\nconst parseCommand = (commandOrArgs: string | string[]): string[] => {\n return typeof commandOrArgs === \"string\"\n ? commandOrArgs\n .split(\" \")\n .filter((segment) => segment.length > 0)\n .slice(1)\n : commandOrArgs\n}\n\nconst toCommandString = (args: string[]): string => {\n return [\"tmux\", ...args].join(\" \")\n}\n\nexport const createDryRunExecutor = (options: DryRunExecutorOptions = {}): CommandExecutor => {\n const verbose = options.verbose ?? false\n const logger = createLogger({\n level: verbose ? LogLevel.INFO : LogLevel.WARN,\n prefix: \"[tmux] [DRY RUN]\",\n })\n\n const execute = async (commandOrArgs: string | string[]): Promise<string> => {\n const args = parseCommand(commandOrArgs)\n const commandString = toCommandString(args)\n logger.info(`Would execute: ${commandString}`)\n return \"\"\n }\n\n return {\n execute,\n async executeMany(commandsList: string[][]): Promise<void> {\n for (const args of commandsList) {\n await execute(args)\n }\n },\n isDryRun(): boolean {\n return true\n },\n logCommand(command: string): void {\n logger.info(`Would execute: ${command}`)\n },\n }\n}\n","type FunctionalCoreErrorKind = \"compile\" | \"plan\" | \"emit\" | \"execution\"\n\nexport type FunctionalCoreError = {\n readonly kind: FunctionalCoreErrorKind\n readonly code: string\n readonly message: string\n readonly source?: string\n readonly path?: string\n readonly details?: Readonly<Record<string, unknown>>\n}\n\nexport const createFunctionalError = (\n kind: FunctionalCoreErrorKind,\n error: {\n readonly code: string\n readonly message: string\n readonly source?: string\n readonly path?: string\n readonly details?: Readonly<Record<string, unknown>>\n },\n): FunctionalCoreError => ({\n kind,\n code: error.code,\n message: error.message,\n source: error.source,\n path: error.path,\n details: error.details,\n})\n\nexport const isFunctionalCoreError = (value: unknown): value is FunctionalCoreError => {\n if (typeof value !== \"object\" || value === null) {\n return false\n }\n const candidate = value as Partial<FunctionalCoreError>\n return (\n (candidate.kind === \"compile\" ||\n candidate.kind === \"plan\" ||\n candidate.kind === \"emit\" ||\n candidate.kind === \"execution\") &&\n typeof candidate.code === \"string\" &&\n typeof candidate.message === \"string\"\n )\n}\n","import type { CommandExecutor } from \"../types/command-executor.ts\"\nimport type { PlanEmission, CommandStep, EmittedTerminal } from \"../core/emitter.ts\"\nimport { ErrorCodes } from \"../utils/errors.ts\"\nimport { createFunctionalError } from \"../core/errors.ts\"\n\nconst DOUBLE_QUOTE = '\"'\nconst ESCAPED_DOUBLE_QUOTE = '\\\\\"'\n\ntype ExecutePlanInput = {\n readonly emission: PlanEmission\n readonly executor: CommandExecutor\n readonly windowName?: string\n}\n\ntype ExecutePlanSuccess = {\n readonly executedSteps: number\n}\n\nexport const executePlan = async ({\n emission,\n executor,\n windowName,\n}: ExecutePlanInput): Promise<ExecutePlanSuccess> => {\n const initialVirtualPaneId = emission.summary.initialPaneId\n if (typeof initialVirtualPaneId !== \"string\" || initialVirtualPaneId.length === 0) {\n raiseExecutionError(\"INVALID_PLAN\", {\n message: \"Plan emission is missing initial pane metadata\",\n path: \"plan.initialPaneId\",\n })\n }\n\n const paneMap = new Map<string, string>()\n\n const newWindowCommand: string[] = [\"new-window\", \"-P\", \"-F\", \"#{pane_id}\"]\n if (typeof windowName === \"string\" && windowName.trim().length > 0) {\n newWindowCommand.push(\"-n\", windowName.trim())\n }\n\n const initialPaneId = normalizePaneId(\n await executeCommand(executor, newWindowCommand, {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: \"Failed to create tmux window\",\n path: initialVirtualPaneId,\n }),\n )\n\n registerPane(paneMap, initialVirtualPaneId, initialPaneId)\n\n let executedSteps = 0\n\n for (const step of emission.steps) {\n if (step.kind === \"split\") {\n await executeSplitStep({ step, executor, paneMap })\n } else if (step.kind === \"focus\") {\n await executeFocusStep({ step, executor, paneMap })\n }\n executedSteps += 1\n }\n\n await executeTerminalCommands({ terminals: emission.terminals, executor, paneMap })\n\n const finalRealFocus = resolvePaneId(paneMap, emission.summary.focusPaneId)\n if (typeof finalRealFocus === \"string\" && finalRealFocus.length > 0) {\n await executeCommand(executor, [\"select-pane\", \"-t\", finalRealFocus], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: \"Failed to restore focus\",\n path: emission.summary.focusPaneId,\n })\n }\n\n return { executedSteps }\n}\n\nconst executeSplitStep = async ({\n step,\n executor,\n paneMap,\n}: {\n readonly step: CommandStep\n readonly executor: CommandExecutor\n readonly paneMap: Map<string, string>\n}): Promise<void> => {\n const targetVirtualId = ensureNonEmpty(step.targetPaneId, () =>\n raiseExecutionError(\"MISSING_TARGET\", {\n message: \"Split step missing target pane metadata\",\n path: step.id,\n }),\n )\n\n const targetRealId = ensureNonEmpty(resolvePaneId(paneMap, targetVirtualId), () =>\n raiseExecutionError(\"UNKNOWN_PANE\", {\n message: `Unknown target pane: ${targetVirtualId}`,\n path: step.id,\n }),\n )\n\n const panesBefore = await listPaneIds(executor, step)\n const splitCommand = replaceTarget(step.command, targetRealId)\n await executeCommand(executor, splitCommand, {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: `Failed to execute split step ${step.id}`,\n path: step.id,\n details: { command: splitCommand },\n })\n\n const panesAfter = await listPaneIds(executor, step)\n const newPaneId = ensureNonEmpty(findNewPaneId(panesBefore, panesAfter), () =>\n raiseExecutionError(\"UNKNOWN_PANE\", {\n message: \"Unable to determine newly created pane\",\n path: step.id,\n }),\n )\n\n const createdVirtualId = step.createdPaneId\n if (typeof createdVirtualId === \"string\" && createdVirtualId.length > 0) {\n registerPane(paneMap, createdVirtualId, newPaneId)\n }\n}\n\nconst executeFocusStep = async ({\n step,\n executor,\n paneMap,\n}: {\n readonly step: CommandStep\n readonly executor: CommandExecutor\n readonly paneMap: Map<string, string>\n}): Promise<void> => {\n const targetVirtualId = ensureNonEmpty(step.targetPaneId, () =>\n raiseExecutionError(\"MISSING_TARGET\", {\n message: \"Focus step missing target pane metadata\",\n path: step.id,\n }),\n )\n\n const targetRealId = ensureNonEmpty(resolvePaneId(paneMap, targetVirtualId), () =>\n raiseExecutionError(\"UNKNOWN_PANE\", {\n message: `Unknown focus pane: ${targetVirtualId}`,\n path: step.id,\n }),\n )\n\n const command = replaceTarget(step.command, targetRealId)\n await executeCommand(executor, command, {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: `Failed to execute focus step ${step.id}`,\n path: step.id,\n details: { command },\n })\n}\n\nconst executeTerminalCommands = async ({\n terminals,\n executor,\n paneMap,\n}: {\n readonly terminals: ReadonlyArray<EmittedTerminal>\n readonly executor: CommandExecutor\n readonly paneMap: Map<string, string>\n}): Promise<void> => {\n for (const terminal of terminals) {\n const realPaneId = ensureNonEmpty(resolvePaneId(paneMap, terminal.virtualPaneId), () =>\n raiseExecutionError(\"UNKNOWN_PANE\", {\n message: `Unknown terminal pane: ${terminal.virtualPaneId}`,\n path: terminal.virtualPaneId,\n }),\n )\n\n if (typeof terminal.cwd === \"string\" && terminal.cwd.length > 0) {\n const escapedCwd = terminal.cwd.split(DOUBLE_QUOTE).join(ESCAPED_DOUBLE_QUOTE)\n await executeCommand(executor, [\"send-keys\", \"-t\", realPaneId, `cd \"${escapedCwd}\"`, \"Enter\"], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: `Failed to change directory for pane ${terminal.virtualPaneId}`,\n path: terminal.virtualPaneId,\n details: { cwd: terminal.cwd },\n })\n }\n\n if (terminal.env !== undefined) {\n for (const [key, value] of Object.entries(terminal.env)) {\n const escaped = String(value).split(DOUBLE_QUOTE).join(ESCAPED_DOUBLE_QUOTE)\n await executeCommand(executor, [\"send-keys\", \"-t\", realPaneId, `export ${key}=\"${escaped}\"`, \"Enter\"], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: `Failed to set environment variable ${key}`,\n path: terminal.virtualPaneId,\n })\n }\n }\n\n if (typeof terminal.command === \"string\" && terminal.command.length > 0) {\n await executeCommand(executor, [\"send-keys\", \"-t\", realPaneId, terminal.command, \"Enter\"], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: `Failed to execute command for pane ${terminal.virtualPaneId}`,\n path: terminal.virtualPaneId,\n details: { command: terminal.command },\n })\n }\n }\n}\n\nconst executeCommand = async (\n executor: CommandExecutor,\n command: string[],\n context: {\n readonly code: string\n readonly message: string\n readonly path: string\n readonly details?: Record<string, unknown>\n },\n): Promise<string> => {\n try {\n return await executor.execute([...command])\n } catch (error) {\n if (error instanceof Error && \"code\" in error && \"message\" in error) {\n const candidate = error as { code?: string; message?: string; details?: Record<string, unknown> }\n throw createFunctionalError(\"execution\", {\n code: typeof candidate.code === \"string\" ? candidate.code : context.code,\n message: candidate.message ?? context.message,\n path: context.path,\n details: candidate.details ?? context.details,\n })\n }\n\n throw createFunctionalError(\"execution\", {\n code: context.code,\n message: context.message,\n path: context.path,\n details: context.details,\n })\n }\n}\n\nconst listPaneIds = async (executor: CommandExecutor, step: CommandStep): Promise<string[]> => {\n const output = await executeCommand(executor, [\"list-panes\", \"-F\", \"#{pane_id}\"], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: \"Failed to list tmux panes\",\n path: step.id,\n })\n\n return output\n .split(\"\\n\")\n .map((pane) => pane.trim())\n .filter((pane) => pane.length > 0)\n}\n\nconst findNewPaneId = (before: string[], after: string[]): string | undefined => {\n const beforeSet = new Set(before)\n return after.find((id) => !beforeSet.has(id))\n}\n\nconst replaceTarget = (command: ReadonlyArray<string>, realTarget: string): string[] => {\n const next = [...command]\n const targetIndex = next.findIndex((value, index) => value === \"-t\" && index + 1 < next.length)\n if (targetIndex >= 0) {\n next[targetIndex + 1] = realTarget\n return next\n }\n\n if (next.length > 0) {\n next[next.length - 1] = realTarget\n }\n return next\n}\n\nconst normalizePaneId = (raw: string): string => {\n const trimmed = raw.trim()\n return trimmed.length === 0 ? \"%0\" : trimmed\n}\n\nconst registerPane = (paneMap: Map<string, string>, virtualId: string, realId: string): void => {\n paneMap.set(virtualId, realId)\n}\n\nconst resolvePaneId = (paneMap: Map<string, string>, virtualId: string): string | undefined => {\n const direct = paneMap.get(virtualId)\n if (typeof direct === \"string\" && direct.length > 0) {\n return direct\n }\n\n let ancestor = virtualId\n while (ancestor.includes(\".\")) {\n ancestor = ancestor.slice(0, ancestor.lastIndexOf(\".\"))\n const candidate = paneMap.get(ancestor)\n if (typeof candidate === \"string\" && candidate.length > 0) {\n paneMap.set(virtualId, candidate)\n return candidate\n }\n }\n\n for (const [key, value] of paneMap.entries()) {\n if (key.startsWith(`${virtualId}.`)) {\n if (typeof value === \"string\" && value.length > 0) {\n paneMap.set(virtualId, value)\n return value\n }\n }\n }\n\n return undefined\n}\n\nconst ensureNonEmpty = <T extends string>(value: T | undefined, buildError: () => never): T => {\n if (value === undefined || value.length === 0) {\n return buildError()\n }\n return value\n}\n\nconst raiseExecutionError = (\n code: string,\n error: {\n readonly message: string\n readonly path: string\n readonly details?: Record<string, unknown>\n },\n): never => {\n throw createFunctionalError(\"execution\", {\n code,\n message: error.message,\n path: error.path,\n details: error.details,\n })\n}\n","import { parse } from \"yaml\"\n\nexport type DiagnosticsSeverity = \"high\" | \"medium\" | \"low\"\n\ntype DiagnosticsFinding = {\n readonly path: string\n readonly severity: DiagnosticsSeverity\n readonly description: string\n}\n\ntype DiagnosticsBacklogItem = {\n readonly id: string\n readonly severity: DiagnosticsSeverity\n readonly summary: string\n readonly actions: ReadonlyArray<string>\n}\n\nexport type DiagnosticsReport = {\n readonly findings: ReadonlyArray<DiagnosticsFinding>\n readonly nextSteps: ReadonlyArray<string>\n readonly backlog: ReadonlyArray<DiagnosticsBacklogItem>\n}\n\ntype DiagnosticsInput = {\n readonly presetDocument: string\n readonly knownIssues?: ReadonlyArray<string>\n}\n\nconst severityRank: Record<DiagnosticsSeverity, number> = {\n high: 3,\n medium: 2,\n low: 1,\n}\n\ntype FindingAccumulator = {\n add: (args: { path: string; severity: DiagnosticsSeverity; description: string; nextStep?: string }) => void\n readonly findings: DiagnosticsFinding[]\n readonly nextSteps: Set<string>\n readonly backlog: Map<string, DiagnosticsBacklogItem>\n}\n\nconst createAccumulator = (): FindingAccumulator => {\n const findings: DiagnosticsFinding[] = []\n const nextSteps = new Set<string>()\n const backlog = new Map<string, DiagnosticsBacklogItem>()\n\n return {\n findings,\n nextSteps,\n backlog,\n add: ({ path, severity, description, nextStep }): void => {\n findings.push({ path, severity, description })\n if (typeof nextStep === \"string\" && nextStep.length > 0) {\n nextSteps.add(nextStep)\n }\n\n const existing = backlog.get(path)\n const existingActions = new Set(existing?.actions ?? [])\n existingActions.add(description)\n if (typeof nextStep === \"string\" && nextStep.length > 0) {\n existingActions.add(nextStep)\n }\n\n const mergedSeverity = existing !== undefined ? maxSeverity(existing.severity, severity) : severity\n\n const summary =\n existing !== undefined && severityRank[existing.severity] >= severityRank[severity]\n ? existing.summary\n : description\n\n backlog.set(path, {\n id: path,\n severity: mergedSeverity,\n summary,\n actions: Array.from(existingActions),\n })\n },\n }\n}\n\nexport const runDiagnostics = (input: DiagnosticsInput): DiagnosticsReport => {\n const accumulator = createAccumulator()\n const knownIssues = input.knownIssues ?? []\n let parsedPreset: unknown\n\n try {\n parsedPreset = parse(input.presetDocument)\n } catch (error) {\n accumulator.add({\n path: \"presetDocument\",\n severity: \"high\",\n description: `プリセットYAMLの解析に失敗しました: ${(error as Error).message}`,\n nextStep: \"プリセットYAMLを構文チェックし、Functional Coreリライト前に整合性を確保する\",\n })\n return {\n findings: sortBySeverity(accumulator.findings),\n nextSteps: Array.from(accumulator.nextSteps),\n backlog: sortBacklog(accumulator.backlog),\n }\n }\n\n if (parsedPreset === null || typeof parsedPreset !== \"object\") {\n accumulator.add({\n path: \"preset\",\n severity: \"high\",\n description: \"プリセット定義がオブジェクト形式ではありません\",\n nextStep: \"プリセットYAMLをオブジェクト構造に整形し整合性を確保する\",\n })\n } else {\n const presetObject = parsedPreset as Record<string, unknown>\n checkFocusDuplications(presetObject, accumulator)\n collectLowPrioritySignals(presetObject, accumulator)\n }\n\n knownIssues.forEach((issue, index) => {\n const trimmed = issue.trim()\n if (trimmed.length === 0) {\n return\n }\n\n accumulator.add({\n path: `codebase.knownIssues[${index}]`,\n severity: \"medium\",\n description: trimmed,\n nextStep: `tmux依存や副作用をFunctional Core境界で切り離す: ${trimmed}`,\n })\n })\n\n return {\n findings: sortBySeverity(accumulator.findings),\n nextSteps: Array.from(accumulator.nextSteps),\n backlog: sortBacklog(accumulator.backlog),\n }\n}\n\nconst checkFocusDuplications = (preset: Record<string, unknown>, accumulator: FindingAccumulator): void => {\n const layout = preset.layout as unknown\n if (layout === undefined || layout === null) {\n return\n }\n\n const focusCount = countFocusFlags(layout)\n if (focusCount > 1) {\n accumulator.add({\n path: \"preset.layout\",\n severity: \"high\",\n description: \"複数のペインでfocus: trueが指定されています\",\n nextStep: \"focusは単一ペインに限定しPlan生成時に一貫するようFunctional Coreで制御する\",\n })\n }\n}\n\nconst collectLowPrioritySignals = (preset: Record<string, unknown>, accumulator: FindingAccumulator): void => {\n const layout = preset.layout as Record<string, unknown> | undefined | null\n if (layout === undefined || layout === null) {\n accumulator.add({\n path: \"preset.layout\",\n severity: \"low\",\n description: \"layout定義が存在しません(単一ペイン運用が前提)\",\n nextStep: \"単一ペイン前提でもPlan出力に影響しないことをFunctional Coreで確認する\",\n })\n return\n }\n\n if (!Array.isArray(layout.panes)) {\n accumulator.add({\n path: \"preset.layout.panes\",\n severity: \"low\",\n description: \"panes配列が存在しないか配列ではありません\",\n nextStep: \"レイアウト定義の構造を正規化し、Plan生成の入力契約を明示する\",\n })\n }\n}\n\nconst countFocusFlags = (node: unknown): number => {\n if (Array.isArray(node)) {\n return node.reduce((sum, child) => sum + countFocusFlags(child), 0)\n }\n\n if (node === null || typeof node !== \"object\") {\n return 0\n }\n\n const record = node as Record<string, unknown>\n const selfFocus = record.focus === true ? 1 : 0\n const childFocus = Array.isArray(record.panes)\n ? record.panes.reduce((sum, child) => sum + countFocusFlags(child), 0)\n : 0\n\n return selfFocus + childFocus\n}\n\nconst sortBySeverity = (findings: DiagnosticsFinding[]): DiagnosticsFinding[] => {\n return [...findings].sort((a, b) => severityRank[b.severity] - severityRank[a.severity])\n}\n\nconst sortBacklog = (backlog: Map<string, DiagnosticsBacklogItem>): DiagnosticsBacklogItem[] => {\n return [...backlog.values()].sort((a, b) => severityRank[b.severity] - severityRank[a.severity])\n}\n\nconst maxSeverity = (left: DiagnosticsSeverity, right: DiagnosticsSeverity): DiagnosticsSeverity => {\n return severityRank[left] >= severityRank[right] ? left : right\n}\n","import { parse } from \"yaml\"\nimport { createFunctionalError, type FunctionalCoreError } from \"./errors.ts\"\n\nexport type CompilePresetInput = {\n readonly document: string\n readonly source: string\n}\n\nexport type FunctionalTerminalPane = {\n readonly kind: \"terminal\"\n readonly name: string\n readonly command?: string\n readonly cwd?: string\n readonly env?: Readonly<Record<string, string>>\n readonly focus?: boolean\n readonly options?: Readonly<Record<string, unknown>>\n}\n\nexport type FunctionalSplitPane = {\n readonly kind: \"split\"\n readonly orientation: \"horizontal\" | \"vertical\"\n readonly ratio: ReadonlyArray<number>\n readonly panes: ReadonlyArray<FunctionalLayoutNode>\n}\n\nexport type FunctionalLayoutNode = FunctionalTerminalPane | FunctionalSplitPane\n\ntype FunctionalPresetMetadata = {\n readonly source: string\n}\n\nexport type FunctionalPreset = {\n readonly name: string\n readonly version: string\n readonly command?: string\n readonly layout?: FunctionalLayoutNode\n readonly metadata: FunctionalPresetMetadata\n}\n\nexport type CompilePresetSuccess = {\n readonly preset: FunctionalPreset\n}\n\nexport const compilePreset = ({ document, source }: CompilePresetInput): CompilePresetSuccess => {\n let parsed: unknown\n try {\n parsed = parse(document)\n } catch (error) {\n throw compileError(\"PRESET_PARSE_ERROR\", {\n source,\n message: `YAMLの解析に失敗しました: ${(error as Error).message}`,\n details: {\n reason: error instanceof Error ? error.message : String(error),\n },\n })\n }\n\n if (!isRecord(parsed)) {\n throw compileError(\"PRESET_INVALID_DOCUMENT\", {\n source,\n message: \"プリセット定義がオブジェクトではありません\",\n path: \"preset\",\n })\n }\n\n const name = typeof parsed.name === \"string\" && parsed.name.trim().length > 0 ? parsed.name : \"Unnamed preset\"\n\n const layout = parseLayoutNode(parsed.layout, {\n source,\n path: \"preset.layout\",\n })\n\n return {\n preset: {\n name,\n version: \"legacy\",\n command: typeof parsed.command === \"string\" ? parsed.command : undefined,\n layout: layout ?? undefined,\n metadata: { source },\n },\n }\n}\n\nconst parseLayoutNode = (\n node: unknown,\n context: { readonly source: string; readonly path: string },\n): FunctionalLayoutNode | null => {\n if (node === undefined || node === null) {\n return null\n }\n\n if (!isRecord(node)) {\n throw compileError(\"LAYOUT_INVALID_NODE\", {\n source: context.source,\n message: \"レイアウトノードの形式が不正です\",\n path: context.path,\n details: { node },\n })\n }\n\n if (typeof node.type === \"string\" && Array.isArray(node.panes)) {\n return parseSplitPane(node, context)\n }\n\n if (typeof node.name === \"string\") {\n return parseTerminalPane(node)\n }\n\n throw compileError(\"LAYOUT_INVALID_NODE\", {\n source: context.source,\n message: \"レイアウトノードの形式が不正です\",\n path: context.path,\n details: { node },\n })\n}\n\nconst parseSplitPane = (\n node: Record<string, unknown>,\n context: { readonly source: string; readonly path: string },\n): FunctionalSplitPane => {\n const orientation = node.type\n if (orientation !== \"horizontal\" && orientation !== \"vertical\") {\n throw compileError(\"LAYOUT_INVALID_ORIENTATION\", {\n source: context.source,\n message: \"layout.type は horizontal か vertical である必要があります\",\n path: `${context.path}.type`,\n details: { type: orientation },\n })\n }\n\n if (!Array.isArray(node.panes) || node.panes.length === 0) {\n throw compileError(\"LAYOUT_PANES_MISSING\", {\n source: context.source,\n message: \"panes 配列が存在しません\",\n path: `${context.path}.panes`,\n })\n }\n\n if (!Array.isArray(node.ratio) || node.ratio.length === 0) {\n throw compileError(\"LAYOUT_RATIO_MISSING\", {\n source: context.source,\n message: \"ratio 配列が存在しません\",\n path: `${context.path}.ratio`,\n })\n }\n\n if (node.ratio.length !== node.panes.length) {\n throw compileError(\"LAYOUT_RATIO_MISMATCH\", {\n source: context.source,\n message: \"ratio 配列と panes 配列の長さが一致しません\",\n path: context.path,\n details: {\n ratioLength: node.ratio.length,\n panesLength: node.panes.length,\n },\n })\n }\n\n const ratio = node.ratio.map((value, index) => {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n throw compileError(\"RATIO_INVALID_VALUE\", {\n source: context.source,\n message: \"ratio の値が正の数値ではありません\",\n path: `${context.path}.ratio[${index}]`,\n details: { value },\n })\n }\n return value\n })\n\n const panes = node.panes.map((child, index) =>\n parseLayoutNode(child, {\n source: context.source,\n path: `${context.path}.panes[${index}]`,\n }),\n )\n\n return {\n kind: \"split\",\n orientation,\n ratio,\n panes: panes.filter((pane): pane is FunctionalLayoutNode => pane !== null),\n }\n}\n\nconst parseTerminalPane = (node: Record<string, unknown>): FunctionalTerminalPane => {\n const name = typeof node.name === \"string\" ? node.name : \"\"\n const command = typeof node.command === \"string\" ? node.command : undefined\n const cwd = typeof node.cwd === \"string\" ? node.cwd : undefined\n const focus = node.focus === true ? true : undefined\n const env = normalizeEnv(node.env)\n\n const knownKeys = new Set([\"name\", \"command\", \"cwd\", \"env\", \"focus\", \"options\", \"title\", \"delay\"])\n const options = collectOptions(node, knownKeys)\n\n return {\n kind: \"terminal\",\n name,\n command,\n cwd,\n env,\n focus,\n options,\n }\n}\n\nconst normalizeEnv = (env: unknown): Readonly<Record<string, string>> | undefined => {\n if (!isRecord(env)) {\n return undefined\n }\n\n const entries = Object.entries(env).reduce<Record<string, string>>((accumulator, [key, value]) => {\n if (typeof value === \"string\") {\n accumulator[key] = value\n }\n return accumulator\n }, {})\n\n return Object.keys(entries).length > 0 ? entries : undefined\n}\n\nconst collectOptions = (\n node: Record<string, unknown>,\n excludedKeys: ReadonlySet<string>,\n): Readonly<Record<string, unknown>> | undefined => {\n const optionsEntries = Object.entries(node).filter(([key]) => !excludedKeys.has(key))\n if (optionsEntries.length === 0) {\n return undefined\n }\n\n return optionsEntries.reduce<Record<string, unknown>>((accumulator, [key, value]) => {\n accumulator[key] = value\n return accumulator\n }, {})\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null\n}\n\nconst compileError = (\n code: string,\n error: {\n readonly source?: string\n readonly message: string\n readonly path?: string\n readonly details?: Readonly<Record<string, unknown>>\n },\n): FunctionalCoreError => {\n return createFunctionalError(\"compile\", {\n code,\n message: error.message,\n source: error.source,\n path: error.path,\n details: error.details,\n })\n}\n","import type { FunctionalLayoutNode, FunctionalPreset, FunctionalSplitPane, FunctionalTerminalPane } from \"./compile.ts\"\nimport { createFunctionalError, type FunctionalCoreError } from \"./errors.ts\"\n\ntype CreateLayoutPlanInput = {\n readonly preset: FunctionalPreset\n}\n\ntype PlanTerminal = {\n readonly kind: \"terminal\"\n readonly id: string\n readonly name: string\n readonly command?: string\n readonly cwd?: string\n readonly env?: Readonly<Record<string, string>>\n readonly focus: boolean\n readonly options?: Readonly<Record<string, unknown>>\n}\n\ntype PlanSplit = {\n readonly kind: \"split\"\n readonly id: string\n readonly orientation: \"horizontal\" | \"vertical\"\n readonly ratio: ReadonlyArray<number>\n readonly panes: ReadonlyArray<PlanNode>\n}\n\nexport type PlanNode = PlanTerminal | PlanSplit\n\nexport type LayoutPlan = {\n readonly root: PlanNode\n readonly focusPaneId: string\n}\n\nexport type CreateLayoutPlanSuccess = {\n readonly plan: LayoutPlan\n}\n\nexport const createLayoutPlan = ({ preset }: CreateLayoutPlanInput): CreateLayoutPlanSuccess => {\n if (!preset.layout) {\n const terminal = createTerminalNode({\n id: \"root\",\n terminal: {\n kind: \"terminal\",\n name: preset.name,\n command: preset.command,\n },\n focusOverride: true,\n })\n\n return {\n plan: {\n root: terminal,\n focusPaneId: terminal.id,\n },\n }\n }\n\n const { node, focusPaneIds, terminalPaneIds } = buildLayoutNode(preset.layout, {\n parentId: \"root\",\n path: \"preset.layout\",\n source: preset.metadata.source,\n })\n\n if (focusPaneIds.length > 1) {\n throw planError(\"FOCUS_CONFLICT\", {\n message: \"複数のペインでfocusが指定されています\",\n path: \"preset.layout\",\n source: preset.metadata.source,\n details: { focusPaneIds },\n })\n }\n\n if (terminalPaneIds.length === 0) {\n throw planError(\"NO_TERMINAL_PANES\", {\n message: \"ターミナルペインが存在しません\",\n path: \"preset.layout\",\n source: preset.metadata.source,\n })\n }\n\n const focusPaneId = focusPaneIds[0] ?? terminalPaneIds[0]!\n const root = ensureFocus(node, focusPaneId)\n\n return {\n plan: {\n root,\n focusPaneId,\n },\n }\n}\n\ntype BuildResult = {\n readonly node: PlanNode\n readonly focusPaneIds: ReadonlyArray<string>\n readonly terminalPaneIds: ReadonlyArray<string>\n}\n\nconst buildLayoutNode = (\n node: FunctionalLayoutNode,\n context: { readonly parentId: string; readonly path: string; readonly source: string },\n): BuildResult => {\n if (node.kind === \"split\") {\n return buildSplitNode(node, context)\n }\n\n return {\n node: createTerminalNode({ id: context.parentId, terminal: node }),\n focusPaneIds: node.focus === true ? [context.parentId] : [],\n terminalPaneIds: [context.parentId],\n }\n}\n\nconst buildSplitNode = (\n node: FunctionalSplitPane,\n context: { readonly parentId: string; readonly path: string; readonly source: string },\n): BuildResult => {\n const ratio = normalizeRatio(node.ratio, context)\n\n const panes: PlanNode[] = []\n const focusPaneIds: string[] = []\n const terminalPaneIds: string[] = []\n\n for (let index = 0; index < node.panes.length; index += 1) {\n const childId = `${context.parentId}.${index}`\n const childContext = {\n parentId: childId,\n path: `${context.path}.panes[${index}]`,\n source: context.source,\n }\n\n const childResult = buildLayoutNode(node.panes[index]!, childContext)\n panes.push(childResult.node)\n focusPaneIds.push(...childResult.focusPaneIds)\n terminalPaneIds.push(...childResult.terminalPaneIds)\n }\n\n return {\n node: {\n kind: \"split\",\n id: context.parentId,\n orientation: node.orientation,\n ratio,\n panes,\n },\n focusPaneIds,\n terminalPaneIds,\n }\n}\n\nconst createTerminalNode = ({\n id,\n terminal,\n focusOverride,\n}: {\n readonly id: string\n readonly terminal: FunctionalTerminalPane\n readonly focusOverride?: boolean\n}): PlanTerminal => {\n return {\n kind: \"terminal\",\n id,\n name: terminal.name,\n command: terminal.command,\n cwd: terminal.cwd,\n env: terminal.env,\n options: terminal.options,\n focus: focusOverride === true ? true : terminal.focus === true,\n }\n}\n\nconst ensureFocus = (node: PlanNode, focusPaneId: string): PlanNode => {\n if (node.kind === \"terminal\") {\n return {\n ...node,\n focus: node.id === focusPaneId,\n }\n }\n\n return {\n ...node,\n panes: node.panes.map((pane) => ensureFocus(pane, focusPaneId)),\n }\n}\n\nconst normalizeRatio = (\n ratio: ReadonlyArray<number>,\n context: { readonly path: string; readonly source: string },\n): number[] => {\n const total = ratio.reduce((sum, value, index) => {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n throw planError(\"RATIO_INVALID_VALUE\", {\n message: \"ratio の値が非負の数値ではありません\",\n path: `${context.path}.ratio[${index}]`,\n source: context.source,\n details: { value },\n })\n }\n return sum + value\n }, 0)\n\n if (total === 0) {\n return ratio.map(() => 1 / ratio.length)\n }\n\n return ratio.map((value) => value / total)\n}\n\nconst planError = (\n code: string,\n error: {\n readonly message: string\n readonly source?: string\n readonly path?: string\n readonly details?: Readonly<Record<string, unknown>>\n },\n): FunctionalCoreError => {\n return createFunctionalError(\"plan\", {\n code,\n message: error.message,\n source: error.source,\n path: error.path,\n details: error.details,\n })\n}\n","import { createHash } from \"crypto\"\nimport type { LayoutPlan, PlanNode } from \"./planner.ts\"\n\ntype EmitPlanInput = {\n readonly plan: LayoutPlan\n}\n\ntype CommandStepKind = \"split\" | \"focus\"\n\nexport type CommandStep = {\n readonly id: string\n readonly kind: CommandStepKind\n readonly command: ReadonlyArray<string>\n readonly summary: string\n readonly targetPaneId?: string\n readonly createdPaneId?: string\n}\n\nexport type EmittedTerminal = {\n readonly virtualPaneId: string\n readonly command?: string\n readonly cwd?: string\n readonly env?: Readonly<Record<string, string>>\n readonly focus: boolean\n readonly name: string\n}\n\ntype PlanEmissionSummary = {\n readonly stepsCount: number\n readonly focusPaneId: string\n readonly initialPaneId: string\n}\n\nexport type PlanEmission = {\n readonly steps: ReadonlyArray<CommandStep>\n readonly summary: PlanEmissionSummary\n readonly terminals: ReadonlyArray<EmittedTerminal>\n readonly hash: string\n}\n\ntype SplitNode = Extract<PlanNode, { kind: \"split\" }>\n\nexport const emitPlan = ({ plan }: EmitPlanInput): PlanEmission => {\n const steps: CommandStep[] = []\n collectSplitSteps(plan.root, steps)\n\n steps.push({\n id: `${plan.focusPaneId}:focus`,\n kind: \"focus\",\n command: [\"select-pane\", \"-t\", plan.focusPaneId],\n summary: `select pane ${plan.focusPaneId}`,\n targetPaneId: plan.focusPaneId,\n })\n\n const hash = createPlanHash(plan, steps)\n const initialPaneId = determineInitialPaneId(plan.root)\n const terminals = collectTerminals(plan.root)\n\n return {\n steps,\n summary: {\n stepsCount: steps.length,\n focusPaneId: plan.focusPaneId,\n initialPaneId,\n },\n terminals,\n hash,\n }\n}\n\nconst collectSplitSteps = (node: PlanNode, steps: CommandStep[]): void => {\n if (node.kind === \"terminal\") {\n return\n }\n\n appendSplitSteps(node, steps)\n node.panes.forEach((pane) => collectSplitSteps(pane, steps))\n}\n\nconst appendSplitSteps = (node: SplitNode, steps: CommandStep[]): void => {\n const directionFlag = node.orientation === \"horizontal\" ? \"-h\" : \"-v\"\n\n for (let index = 1; index < node.panes.length; index += 1) {\n const remainingIncludingTarget = node.ratio.slice(index - 1).reduce((sum, value) => sum + value, 0)\n const remainingAfterTarget = node.ratio.slice(index).reduce((sum, value) => sum + value, 0)\n\n const desiredPercentage =\n remainingIncludingTarget === 0 ? 0 : (remainingAfterTarget / remainingIncludingTarget) * 100\n const percentage = Math.max(1, Math.round(desiredPercentage))\n const targetPaneId = node.panes[index - 1]?.id ?? node.id\n const createdPaneId = node.panes[index]?.id\n\n steps.push({\n id: `${node.id}:split:${index}`,\n kind: \"split\",\n command: [\"split-window\", directionFlag, \"-t\", targetPaneId, \"-p\", String(Math.min(percentage, 99))],\n summary: `split ${targetPaneId} (${directionFlag})`,\n targetPaneId,\n createdPaneId,\n })\n }\n}\n\nconst collectTerminals = (node: PlanNode): EmittedTerminal[] => {\n if (node.kind === \"terminal\") {\n return [\n {\n virtualPaneId: node.id,\n command: node.command,\n cwd: node.cwd,\n env: node.env,\n focus: node.focus,\n name: node.name,\n },\n ]\n }\n\n return node.panes.flatMap((pane) => collectTerminals(pane))\n}\n\nconst determineInitialPaneId = (node: PlanNode): string => {\n if (node.kind === \"terminal\") {\n return node.id\n }\n\n let current: PlanNode = node\n while (current.kind === \"split\") {\n current = current.panes[0]!\n }\n return current.id\n}\n\nconst createPlanHash = (plan: LayoutPlan, steps: ReadonlyArray<CommandStep>): string => {\n const digest = createHash(\"sha256\")\n const normalized = {\n focusPaneId: plan.focusPaneId,\n root: plan.root,\n steps,\n }\n digest.update(JSON.stringify(normalized))\n return digest.digest(\"hex\")\n}\n","import { Command } from \"commander\"\nimport chalk from \"chalk\"\nimport { stringify as toYAML } from \"yaml\"\nimport { createRequire } from \"module\"\nimport { createPresetManager } from \"./layout/preset.ts\"\nimport type { Preset, PresetInfo } from \"./models/types\"\nimport type { CommandExecutor } from \"./types/command-executor.ts\"\nimport type { PresetManager } from \"./types/preset-manager.ts\"\nimport { createRealExecutor, createDryRunExecutor } from \"./executor/index.ts\"\nimport { executePlan } from \"./executor/plan-runner.ts\"\nimport { createLogger, LogLevel, type Logger } from \"./utils/logger.ts\"\nimport {\n runDiagnostics,\n compilePreset as defaultCompilePreset,\n createLayoutPlan as defaultCreateLayoutPlan,\n emitPlan as defaultEmitPlan,\n} from \"./core/index.ts\"\nimport type {\n DiagnosticsReport,\n DiagnosticsSeverity,\n CompilePresetInput,\n PlanEmission,\n FunctionalCoreError,\n CompilePresetSuccess,\n CreateLayoutPlanSuccess,\n} from \"./core/index.ts\"\nimport { isFunctionalCoreError } from \"./core/index.ts\"\n\nconst KNOWN_ISSUES: ReadonlyArray<string> = [\n \"LayoutEngineがtmux依存とI/Oを同一クラスで扱っている\",\n \"dry-run実行と本番適用でPlan構造が共有されていない\",\n \"Loggerが境界層とFunctional Coreの責務を混在させている\",\n]\n\nconst formatSeverityTag = (severity: DiagnosticsSeverity): string => {\n switch (severity) {\n case \"high\":\n return chalk.red(\"[HIGH]\")\n case \"medium\":\n return chalk.yellow(\"[MEDIUM]\")\n case \"low\":\n default:\n return chalk.blue(\"[LOW]\")\n }\n}\n\nexport type FunctionalCoreBridge = {\n readonly compilePreset: (input: CompilePresetInput) => ReturnType<typeof defaultCompilePreset>\n readonly createLayoutPlan: (\n input: Parameters<typeof defaultCreateLayoutPlan>[0],\n ) => ReturnType<typeof defaultCreateLayoutPlan>\n readonly emitPlan: (input: Parameters<typeof defaultEmitPlan>[0]) => ReturnType<typeof defaultEmitPlan>\n}\n\nexport type CLIOptions = {\n readonly presetManager?: PresetManager\n readonly createCommandExecutor?: (options: { verbose: boolean; dryRun: boolean }) => CommandExecutor\n readonly functionalCore?: FunctionalCoreBridge\n}\n\nexport type CLI = {\n run(args?: string[]): Promise<void>\n}\n\nexport const createCli = (options: CLIOptions = {}): CLI => {\n const presetManager = options.presetManager ?? createPresetManager()\n const createCommandExecutor =\n options.createCommandExecutor ??\n ((opts: { verbose: boolean; dryRun: boolean }): CommandExecutor => {\n if (opts.dryRun) {\n return createDryRunExecutor({ verbose: opts.verbose })\n }\n return createRealExecutor({ verbose: opts.verbose })\n })\n\n const functionalCore: FunctionalCoreBridge =\n options.functionalCore ??\n ({\n compilePreset: defaultCompilePreset,\n createLayoutPlan: defaultCreateLayoutPlan,\n emitPlan: defaultEmitPlan,\n } as const)\n\n const program = new Command()\n const require = createRequire(import.meta.url)\n const { version } = require(\"../package.json\") as { version: string }\n let logger: Logger = createLogger()\n\n const renderDiagnosticsReport = (report: DiagnosticsReport): void => {\n console.log(chalk.bold(\"\\nFunctional Core Diagnostics\\n\"))\n\n if (report.backlog.length > 0) {\n console.log(chalk.bold(\"改善バックログ\"))\n report.backlog.forEach((item, index) => {\n const prefix = `${index + 1}. ${formatSeverityTag(item.severity)}`\n console.log(`${prefix} ${item.summary}`)\n item.actions.forEach((action) => {\n console.log(` - ${action}`)\n })\n })\n console.log(\"\")\n }\n\n if (report.findings.length > 0) {\n console.log(chalk.bold(\"診断結果\"))\n report.findings.forEach((finding) => {\n console.log(`${formatSeverityTag(finding.severity)} ${finding.path} :: ${finding.description}`)\n })\n console.log(\"\")\n }\n\n if (report.nextSteps.length > 0) {\n console.log(chalk.bold(\"次のアクション\"))\n report.nextSteps.forEach((step) => {\n console.log(` - ${step}`)\n })\n console.log(\"\")\n }\n }\n\n const renderDryRun = (emission: PlanEmission): void => {\n console.log(chalk.bold(\"\\nPlanned tmux steps (dry-run)\"))\n emission.steps.forEach((step, index) => {\n const commandString = step.command.join(\" \")\n console.log(` ${index + 1}. ${step.summary}: tmux ${commandString}`)\n })\n }\n\n const buildPresetDocument = (preset: Preset, presetName?: string): string => {\n const document: Record<string, unknown> = {\n name: preset.name ?? presetName ?? \"vde-layout\",\n command: preset.command,\n layout: preset.layout,\n }\n\n if (typeof preset.command !== \"string\" || preset.command.length === 0) {\n delete document.command\n }\n\n if (preset.layout === undefined || preset.layout === null) {\n delete document.layout\n }\n\n return toYAML(document)\n }\n\n const buildPresetSource = (presetName?: string): string => {\n return typeof presetName === \"string\" && presetName.length > 0 ? `preset://${presetName}` : \"preset://default\"\n }\n\n const handleFunctionalError = (error: FunctionalCoreError): never => {\n const header = [`[${error.kind}]`, `[${error.code}]`]\n if (typeof error.path === \"string\" && error.path.length > 0) {\n header.push(`[${error.path}]`)\n }\n\n const lines = [`${header.join(\" \")} ${error.message}`.trim()]\n\n if (typeof error.source === \"string\" && error.source.length > 0) {\n lines.push(`source: ${error.source}`)\n }\n\n const commandDetail = error.details?.command\n if (Array.isArray(commandDetail)) {\n const tmuxCommand = commandDetail.filter((segment): segment is string => typeof segment === \"string\")\n if (tmuxCommand.length > 0) {\n lines.push(`command: tmux ${tmuxCommand.join(\" \")}`)\n }\n } else if (typeof commandDetail === \"string\" && commandDetail.length > 0) {\n lines.push(`command: ${commandDetail}`)\n }\n\n const stderrDetail = error.details?.stderr\n if (typeof stderrDetail === \"string\" && stderrDetail.length > 0) {\n lines.push(`stderr: ${stderrDetail}`)\n } else if (stderrDetail !== undefined) {\n lines.push(`stderr: ${String(stderrDetail)}`)\n }\n\n logger.error(lines.join(\"\\n\"))\n process.exit(1)\n }\n\n const handleError = (error: unknown): never => {\n if (error instanceof Error) {\n logger.error(error.message, error)\n } else {\n logger.error(\"An unexpected error occurred\")\n }\n\n process.exit(1)\n }\n\n const handlePipelineFailure = (error: unknown): never => {\n if (isFunctionalCoreError(error)) {\n return handleFunctionalError(error)\n }\n return handleError(error)\n }\n\n const listPresets = async (): Promise<never> => {\n try {\n await presetManager.loadConfig()\n const presets = presetManager.listPresets()\n\n if (presets.length === 0) {\n logger.warn(\"No presets defined\")\n process.exit(0)\n }\n\n console.log(chalk.bold(\"Available presets:\\n\"))\n\n const maxKeyLength = Math.max(...presets.map((p) => p.key.length))\n\n presets.forEach((preset: PresetInfo) => {\n const paddedKey = preset.key.padEnd(maxKeyLength + 2)\n const description = preset.description ?? \"\"\n console.log(` ${chalk.cyan(paddedKey)} ${description}`)\n })\n\n process.exit(0)\n } catch (error) {\n return handleError(error)\n }\n }\n\n const diagnosePreset = async (presetName: string | undefined): Promise<never> => {\n try {\n await presetManager.loadConfig()\n const preset =\n typeof presetName === \"string\" && presetName.length > 0\n ? presetManager.getPreset(presetName)\n : presetManager.getDefaultPreset()\n\n const presetDocument = toYAML(preset ?? {})\n const report = runDiagnostics({\n presetDocument,\n knownIssues: KNOWN_ISSUES,\n })\n\n renderDiagnosticsReport(report)\n process.exit(0)\n } catch (error) {\n return handleError(error)\n }\n }\n\n const executePreset = async (\n presetName: string | undefined,\n options: { verbose: boolean; dryRun: boolean },\n ): Promise<never> => {\n try {\n await presetManager.loadConfig()\n\n const preset =\n typeof presetName === \"string\" && presetName.length > 0\n ? presetManager.getPreset(presetName)\n : presetManager.getDefaultPreset()\n\n const tmuxEnv = process.env.TMUX\n const insideTmux = typeof tmuxEnv === \"string\" && tmuxEnv.length > 0\n if (!insideTmux && options.dryRun !== true) {\n throw new Error(\"Must be run inside a tmux session\")\n }\n\n const executor = createCommandExecutor({\n verbose: options.verbose,\n dryRun: options.dryRun,\n })\n\n if (options.dryRun === true) {\n console.log(\"[DRY RUN] No actual commands will be executed\")\n }\n\n let compileResult: CompilePresetSuccess\n let planResult: CreateLayoutPlanSuccess\n let emission: PlanEmission\n\n try {\n compileResult = functionalCore.compilePreset({\n document: buildPresetDocument(preset, presetName),\n source: buildPresetSource(presetName),\n })\n planResult = functionalCore.createLayoutPlan({ preset: compileResult.preset })\n emission = functionalCore.emitPlan({ plan: planResult.plan })\n } catch (error) {\n return handlePipelineFailure(error)\n }\n\n if (options.dryRun === true) {\n renderDryRun(emission)\n } else {\n try {\n const executionResult = await executePlan({\n emission,\n executor,\n windowName: preset.name ?? presetName ?? \"vde-layout\",\n })\n logger.info(`Executed ${executionResult.executedSteps} tmux steps`)\n } catch (error) {\n return handlePipelineFailure(error)\n }\n }\n\n logger.success(`✓ Applied preset \"${preset.name}\"`)\n process.exit(0)\n } catch (error) {\n return handleError(error)\n }\n }\n\n const setupProgram = (): void => {\n program\n .name(\"vde-layout\")\n .description(\"VDE (Vibrant Development Environment) Layout Manager - tmux pane layout management tool\")\n .version(version, \"-V, --version\", \"Show version\")\n .helpOption(\"-h, --help\", \"Show help\")\n\n program.option(\"-v, --verbose\", \"Show detailed logs\", false)\n program.option(\"--dry-run\", \"Display commands without executing\", false)\n program.option(\"--config <path>\", \"Path to configuration file\")\n\n program\n .command(\"list\")\n .description(\"List available presets\")\n .action(async () => {\n await listPresets()\n })\n\n program\n .command(\"diagnose\")\n .description(\"Functional Coreリライトに向けた診断レポートを表示する\")\n .argument(\"[preset]\", 'Preset name (defaults to \"default\" preset when omitted)')\n .action(async (presetName?: string) => {\n await diagnosePreset(presetName)\n })\n\n program\n .argument(\"[preset]\", 'Preset name (defaults to \"default\" preset when omitted)')\n .action(async (presetName?: string) => {\n const opts = program.opts<{ verbose?: boolean; dryRun?: boolean }>()\n await executePreset(presetName, {\n verbose: opts.verbose === true,\n dryRun: opts.dryRun === true,\n })\n })\n }\n\n setupProgram()\n\n const run = async (args: string[] = process.argv.slice(2)): Promise<void> => {\n const requestedVersion = args.includes(\"--version\") || args.includes(\"-V\")\n const requestedHelp = args.includes(\"--help\") || args.includes(\"-h\")\n try {\n await program.parseAsync(args, { from: \"user\" })\n const opts = program.opts<{ verbose?: boolean; config?: string }>()\n\n if (requestedVersion || requestedHelp) {\n return\n }\n\n if (opts.verbose === true) {\n logger = createLogger({ level: LogLevel.INFO })\n } else {\n logger = createLogger()\n }\n\n if (\n typeof opts.config === \"string\" &&\n opts.config.length > 0 &&\n typeof presetManager.setConfigPath === \"function\"\n ) {\n presetManager.setConfigPath(opts.config)\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"Process exited\")) {\n throw error\n }\n handleError(error)\n }\n }\n\n return { run }\n}\n","#!/usr/bin/env node\nimport { createCli } from \"./cli.ts\"\n\n/**\n * Main entry point\n * Launches the CLI application\n */\nconst main = async (): Promise<void> => {\n const cli = createCli()\n try {\n // Pass arguments excluding the first two elements (node, script path) from process.argv\n await cli.run(process.argv.slice(2))\n } catch (error) {\n // Format and display error message appropriately\n if (error instanceof Error) {\n console.error(\"Error:\", error.message)\n\n // Also display stack trace in debug mode\n if (process.env.VDE_DEBUG === \"true\") {\n console.error(error.stack)\n }\n } else {\n console.error(\"An unexpected error occurred:\", String(error))\n }\n\n process.exit(1)\n }\n}\n\n// Execute immediately\nvoid main()\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["formatters: Record<string, (error: VDELayoutError) => string>","SplitPaneSchema: z.ZodType<unknown>","PaneSchema: z.ZodType<unknown>","path","candidates: string[]","mergedConfig: Config","yaml","paths: string[]","existing: string[]","mergedPresets: Config[\"presets\"]","loaderOptions: ConfigLoaderOptions","cachedConfig: Config | null","input","output","parseCommand","toCommandString","initialPaneId: string","newWindowCommand: string[]","severityRank: Record<DiagnosticsSeverity, number>","findings: DiagnosticsFinding[]","path","parsedPreset: unknown","parsed: unknown","panes: PlanNode[]","focusPaneIds: string[]","terminalPaneIds: string[]","steps: CommandStep[]","current: PlanNode","KNOWN_ISSUES: ReadonlyArray<string>","functionalCore: FunctionalCoreBridge","defaultCompilePreset","defaultCreateLayoutPlan","defaultEmitPlan","logger: Logger","document: Record<string, unknown>","toYAML","options","compileResult: CompilePresetSuccess","planResult: CreateLayoutPlanSuccess","emission: PlanEmission"],"sources":["../src/utils/errors.ts","../src/models/schema.ts","../src/config/validator.ts","../src/config/loader.ts","../src/layout/preset.ts","../src/cli/window-mode.ts","../src/cli/user-prompt.ts","../src/utils/logger.ts","../src/executor/real-executor.ts","../src/executor/dry-run-executor.ts","../src/core/errors.ts","../src/executor/plan-runner.ts","../src/core/diagnostics.ts","../src/core/compile.ts","../src/core/planner.ts","../src/core/emitter.ts","../src/cli.ts","../src/index.ts"],"sourcesContent":["export type VDELayoutError = Error & {\n readonly code: string\n readonly details: Readonly<Record<string, unknown>>\n}\n\nexport const ErrorCodes = {\n CONFIG_NOT_FOUND: \"CONFIG_NOT_FOUND\",\n CONFIG_PARSE_ERROR: \"CONFIG_PARSE_ERROR\",\n CONFIG_PERMISSION_ERROR: \"CONFIG_PERMISSION_ERROR\",\n INVALID_PRESET: \"INVALID_PRESET\",\n PRESET_NOT_FOUND: \"PRESET_NOT_FOUND\",\n INVALID_LAYOUT: \"INVALID_LAYOUT\",\n INVALID_PANE: \"INVALID_PANE\",\n TMUX_NOT_RUNNING: \"TMUX_NOT_RUNNING\",\n TMUX_COMMAND_FAILED: \"TMUX_COMMAND_FAILED\",\n NOT_IN_TMUX_SESSION: \"NOT_IN_TMUX_SESSION\",\n NOT_IN_TMUX: \"NOT_IN_TMUX\",\n TMUX_NOT_FOUND: \"TMUX_NOT_FOUND\",\n TMUX_NOT_INSTALLED: \"TMUX_NOT_INSTALLED\",\n UNSUPPORTED_TMUX_VERSION: \"UNSUPPORTED_TMUX_VERSION\",\n USER_CANCELLED: \"USER_CANCELLED\",\n} as const\n\nconst createBaseError = (\n name: string,\n message: string,\n code: string,\n details: Readonly<Record<string, unknown>> = {},\n): VDELayoutError => {\n const error = new Error(message) as VDELayoutError\n error.name = name\n ;(error as { code: string }).code = code\n ;(error as { details: Readonly<Record<string, unknown>> }).details = details\n return error\n}\n\nexport const createConfigError = (\n message: string,\n code: string,\n details: Readonly<Record<string, unknown>> = {},\n): VDELayoutError => {\n return createBaseError(\"ConfigError\", message, code, details)\n}\n\nexport const createValidationError = (\n message: string,\n code: string,\n details: Readonly<Record<string, unknown>> = {},\n): VDELayoutError => {\n return createBaseError(\"ValidationError\", message, code, details)\n}\n\nexport const createTmuxError = (\n message: string,\n code: string,\n details: Readonly<Record<string, unknown>> = {},\n): VDELayoutError => {\n return createBaseError(\"TmuxError\", message, code, details)\n}\n\nexport const createEnvironmentError = (\n message: string,\n code: string,\n details: Readonly<Record<string, unknown>> = {},\n): VDELayoutError => {\n return createBaseError(\"EnvironmentError\", message, code, details)\n}\n\nexport const isVDELayoutError = (error: unknown): error is VDELayoutError => {\n if (typeof error !== \"object\" || error === null) {\n return false\n }\n\n if (!(\"code\" in error)) {\n return false\n }\n\n const { code } = error as { code?: unknown }\n if (typeof code !== \"string\") {\n return false\n }\n\n if (!(\"details\" in error)) {\n return false\n }\n\n return true\n}\n\nconst formatters: Record<string, (error: VDELayoutError) => string> = {\n [ErrorCodes.CONFIG_NOT_FOUND]: (error) => {\n const searchPaths = error.details.searchPaths\n if (!Array.isArray(searchPaths)) {\n return \"\"\n }\n\n const lines = [\"\", \"Searched in the following locations:\"]\n searchPaths.forEach((location) => lines.push(` - ${location}`))\n lines.push(\"\", \"To create a configuration file, run:\")\n lines.push(\" mkdir -p ~/.config/vde\")\n lines.push(' echo \"presets: {}\" > ~/.config/vde/layout.yml')\n return lines.join(\"\\n\")\n },\n [ErrorCodes.NOT_IN_TMUX_SESSION]: () => {\n return \"\\nThis command must be run inside a tmux session.\\nStart tmux first with: tmux\\n\"\n },\n [ErrorCodes.TMUX_NOT_INSTALLED]: () => {\n return (\n \"\\ntmux is required but not installed.\\n\" +\n \"Install tmux using your package manager:\\n\" +\n \" - macOS: brew install tmux\\n\" +\n \" - Ubuntu/Debian: sudo apt-get install tmux\\n\" +\n \" - Fedora: sudo dnf install tmux\\n\"\n )\n },\n [ErrorCodes.UNSUPPORTED_TMUX_VERSION]: (error) => {\n const requiredVersion = error.details.requiredVersion\n if (typeof requiredVersion !== \"string\") {\n return \"\"\n }\n return `\\nRequired tmux version: ${requiredVersion} or higher\\n`\n },\n}\n\nexport const formatError = (error: Error): string => {\n if (!isVDELayoutError(error)) {\n return `${error.name}: ${error.message}`\n }\n\n let message = `Error: ${error.message}`\n\n const formatter = formatters[error.code]\n if (formatter) {\n message += `\\n${formatter(error)}`\n }\n\n const commandDetail = error.details.command\n if (commandDetail !== undefined) {\n message += `\\nCommand: ${JSON.stringify(commandDetail)}`\n }\n\n const stderrDetail = error.details.stderr\n if (stderrDetail !== undefined) {\n message += `\\nstderr: ${String(stderrDetail)}`\n }\n\n const presetDetail = error.details.preset\n if (presetDetail !== undefined) {\n message += `\\npreset: ${String(presetDetail)}`\n }\n\n const nestedErrors = error.details.errors\n if (Array.isArray(nestedErrors) && nestedErrors.length > 0) {\n message += \"\\nValidation errors:\\n\"\n nestedErrors.forEach((item) => {\n message += ` - ${String(item)}\\n`\n })\n }\n\n return message\n}\n","import { z } from \"zod\"\n\nexport const WindowModeSchema = z.enum([\"new-window\", \"current-window\"])\n\n// Terminal pane schema\nconst TerminalPaneSchema = z\n .object({\n name: z.string().min(1),\n command: z.string().optional(),\n cwd: z.string().optional(),\n env: z.record(z.string()).optional(),\n delay: z.number().int().positive().optional(),\n title: z.string().optional(),\n focus: z.boolean().optional(),\n })\n .strict()\n\n// Split container schema (recursive)\nconst SplitPaneSchema: z.ZodType<unknown> = z.lazy(() =>\n z\n .object({\n type: z.enum([\"horizontal\", \"vertical\"]),\n ratio: z.array(z.number().positive()).min(1),\n panes: z.array(PaneSchema).min(1),\n })\n .strict()\n .refine((data) => data.ratio.length === data.panes.length, {\n message: \"Number of elements in ratio array does not match number of elements in panes array\",\n }),\n)\n\n// Recursive Pane schema definition\nexport const PaneSchema: z.ZodType<unknown> = z.lazy(() => z.union([SplitPaneSchema, TerminalPaneSchema]))\n\n// Layout schema definition\nexport const LayoutSchema = z\n .object({\n type: z.enum([\"horizontal\", \"vertical\"]),\n ratio: z.array(z.number().positive()).min(1),\n panes: z.array(PaneSchema).min(1),\n })\n .refine((data) => data.ratio.length === data.panes.length, {\n message: \"Number of elements in ratio array does not match number of elements in panes array\",\n })\n\n// Preset schema definition\nexport const PresetSchema = z.object({\n name: z.string().min(1),\n description: z.string().optional(),\n layout: LayoutSchema.optional(),\n command: z.string().optional(),\n windowMode: WindowModeSchema.optional(),\n})\n\n// Config schema definition\nexport const ConfigSchema = z.object({\n defaults: z\n .object({\n windowMode: WindowModeSchema.optional(),\n })\n .optional(),\n presets: z.record(PresetSchema),\n})\n\n// Validation result type\ntype ValidationResult<T> = {\n success: boolean\n data?: T\n error?: string\n}\n\n// Helper function to format Zod errors consistently\nconst formatValidationError = (error: z.ZodError): string => {\n const messages = error.errors.map((e) => {\n const path = e.path.join(\".\")\n const message = e.message\n\n // Customize error message for panes array element count check\n if (path === \"layout.panes\" && message.includes(\"at least 2 element\")) {\n return `${path}: panes array must have at least 2 elements`\n }\n\n return `${path}: ${message}`\n })\n\n return messages.join(\"\\n\")\n}\n\n// Config validation\nexport const validateConfig = (data: unknown): ValidationResult<z.infer<typeof ConfigSchema>> => {\n try {\n const parsed = ConfigSchema.parse(data)\n return { success: true, data: parsed }\n } catch (error) {\n if (error instanceof z.ZodError) {\n return { success: false, error: formatValidationError(error) }\n }\n return { success: false, error: String(error) }\n }\n}\n\n// Preset validation\nexport const validatePreset = (data: unknown): ValidationResult<z.infer<typeof PresetSchema>> => {\n try {\n const parsed = PresetSchema.parse(data)\n return { success: true, data: parsed }\n } catch (error) {\n if (error instanceof z.ZodError) {\n return { success: false, error: formatValidationError(error) }\n }\n return { success: false, error: String(error) }\n }\n}\n\n// Pane validation\nexport const validatePane = (data: unknown): ValidationResult<z.infer<typeof PaneSchema>> => {\n try {\n const parsed = PaneSchema.parse(data)\n return { success: true, data: parsed }\n } catch (error) {\n if (error instanceof z.ZodError) {\n return { success: false, error: formatValidationError(error) }\n }\n return { success: false, error: String(error) }\n }\n}\n","import * as YAML from \"yaml\"\nimport { z } from \"zod\"\nimport { ConfigSchema } from \"../models/schema.ts\"\nimport type { Config } from \"../models/types.ts\"\nimport { createValidationError, ErrorCodes, isVDELayoutError } from \"../utils/errors.ts\"\n\n/**\n * Parse YAML text into an object\n * @param yamlText - YAML text to parse\n * @returns Parsed object\n * @throws {ValidationError} When YAML parsing fails\n */\nconst parseYAML = (yamlText: string): unknown => {\n // Input validation\n if (!yamlText || typeof yamlText !== \"string\") {\n throw createValidationError(\"YAML text not provided\", ErrorCodes.CONFIG_PARSE_ERROR, {\n received: typeof yamlText,\n })\n }\n\n try {\n return YAML.parse(yamlText)\n } catch (error) {\n throw createValidationError(\"Failed to parse YAML\", ErrorCodes.CONFIG_PARSE_ERROR, {\n parseError: error instanceof Error ? error.message : String(error),\n yamlSnippet: yamlText.substring(0, 200),\n })\n }\n}\n\n/**\n * Validate basic configuration structure\n * @param parsed - Parsed YAML object\n * @throws {ValidationError} When structure is invalid\n */\nconst validateConfigStructure = (parsed: unknown): void => {\n // Check for empty YAML\n if (parsed === null || parsed === undefined || typeof parsed !== \"object\") {\n throw createValidationError(\"YAML is empty or invalid format\", ErrorCodes.CONFIG_PARSE_ERROR, {\n parsed: parsed,\n })\n }\n\n // Check for presets field existence\n const parsedObj = parsed as Record<string, unknown>\n if (!(\"presets\" in parsedObj) || parsedObj.presets === undefined || parsedObj.presets === null) {\n throw createValidationError(\"presets field is required\", ErrorCodes.INVALID_PRESET, {\n availableFields: Object.keys(parsedObj),\n })\n }\n\n // Check for empty presets\n const presetsObj = parsedObj.presets\n if (typeof presetsObj !== \"object\" || presetsObj === null || Object.keys(presetsObj).length === 0) {\n throw createValidationError(\"At least one preset is required\", ErrorCodes.INVALID_PRESET, {\n presets: presetsObj,\n })\n }\n}\n\n/**\n * Format Zod validation errors into user-friendly messages\n * @param error - Zod validation error\n * @returns Formatted error issues\n */\nconst formatZodErrors = (error: z.ZodError): Array<{ path: string; message: string; code: string }> => {\n return error.issues.map((issue) => {\n const path = issue.path.join(\".\")\n let message = issue.message\n\n // Custom error messages\n if (issue.code === \"invalid_type\") {\n if (issue.path.includes(\"command\") && issue.expected === \"string\") {\n message = \"command field must be a string\"\n } else if (issue.path.includes(\"workingDirectory\") && issue.expected === \"string\") {\n message = \"workingDirectory field must be a string\"\n } else if (issue.received === \"number\" && issue.expected === \"string\") {\n message = `${path} must be a string`\n } else if (issue.received === \"array\" && issue.expected === \"string\") {\n message = `${path} must be a string`\n }\n } else if (issue.code === \"invalid_union\") {\n // Detailed error messages for union types\n const unionIssue = issue as z.ZodIssue & { unionErrors?: z.ZodError[] }\n if (unionIssue.unionErrors !== undefined) {\n // When command is missing in terminal pane\n const terminalError = unionIssue.unionErrors.find(\n (e) => e.issues?.some((i) => i.path.includes(\"command\") && i.code === \"invalid_type\") === true,\n )\n if (terminalError !== undefined) {\n message = \"command field is required\"\n } else {\n // When panes is missing in split pane\n const splitError = unionIssue.unionErrors.find(\n (e) => e.issues?.some((i) => i.path.includes(\"panes\") && i.code === \"invalid_type\") === true,\n )\n if (splitError !== undefined) {\n message = \"panes field is required\"\n } else {\n message = 'Pane type must be \"terminal\" or \"split\"'\n }\n }\n } else {\n message = 'Pane type must be \"terminal\" or \"split\"'\n }\n } else if (issue.code === \"invalid_literal\") {\n if (issue.path.includes(\"direction\")) {\n message = 'direction must be \"horizontal\" or \"vertical\"'\n }\n } else if (issue.message.includes(\"required\")) {\n // Use the message as is\n message = issue.message\n } else if (issue.code === \"custom\" && issue.message.includes(\"ratio array\")) {\n message = issue.message\n } else if (issue.code === \"too_small\" && issue.message.includes(\"Array must contain at least\")) {\n // Minimum array elements error\n if (path.includes(\"panes\")) {\n message = \"panes array must contain at least 2 elements\"\n } else if (path.includes(\"ratio\")) {\n message = \"ratio array must contain at least 2 elements\"\n } else {\n message = issue.message\n }\n }\n\n return {\n path,\n message,\n code: issue.code,\n }\n })\n}\n\n/**\n * Validates YAML text and converts it to a type-safe Config object\n * @param yamlText - YAML text to validate\n * @returns Validated Config object\n * @throws {ValidationError} When YAML is invalid\n */\nexport const validateYAML = (yamlText: string): Config => {\n // Parse YAML\n const parsed = parseYAML(yamlText)\n\n // Validate basic structure\n validateConfigStructure(parsed)\n\n // Ratio sum validation removed - unnecessary due to automatic normalization\n\n // Validation with Zod schema\n try {\n const validated = ConfigSchema.parse(parsed)\n return validated\n } catch (error) {\n if (error instanceof z.ZodError) {\n const issues = formatZodErrors(error)\n\n // Use the first error message as the primary message\n const primaryMessage = issues.length > 0 && issues[0] ? issues[0].message : \"Configuration validation failed\"\n\n throw createValidationError(primaryMessage, ErrorCodes.CONFIG_PARSE_ERROR, {\n issues,\n rawErrors: error.issues,\n })\n }\n\n if (isVDELayoutError(error) && error.name === \"ValidationError\") {\n throw error\n }\n\n // Other errors\n throw createValidationError(\"Unexpected validation error occurred\", ErrorCodes.CONFIG_PARSE_ERROR, {\n error: error instanceof Error ? error.message : String(error),\n })\n }\n}\n","import fs from \"fs-extra\"\nimport path from \"path\"\nimport os from \"os\"\nimport * as yaml from \"yaml\"\nimport type { Config } from \"../models/types.ts\"\nimport { createConfigError, ErrorCodes } from \"../utils/errors.ts\"\nimport { validateYAML } from \"./validator.ts\"\n\nexport type ConfigLoaderOptions = {\n readonly configPaths?: string[]\n}\n\nexport type ConfigLoader = {\n readonly loadYAML: () => Promise<string>\n readonly loadConfig: () => Promise<Config>\n readonly findConfigFile: () => Promise<string | null>\n readonly getSearchPaths: () => string[]\n}\n\nexport const createConfigLoader = (options: ConfigLoaderOptions = {}): ConfigLoader => {\n const explicitConfigPaths = options.configPaths\n\n const computeCachedSearchPaths = (): string[] => {\n if (explicitConfigPaths && explicitConfigPaths.length > 0) {\n return [...explicitConfigPaths]\n }\n\n const candidates: string[] = []\n const projectCandidate = findProjectConfigCandidate()\n if (projectCandidate !== null) {\n candidates.push(projectCandidate)\n }\n\n candidates.push(...buildDefaultSearchPaths())\n\n return [...new Set(candidates)]\n }\n\n const loadConfig = async (): Promise<Config> => {\n if (explicitConfigPaths && explicitConfigPaths.length > 0) {\n const filePath = await findFirstExisting(explicitConfigPaths)\n if (filePath === null) {\n throw createConfigError(\"Configuration file not found\", ErrorCodes.CONFIG_NOT_FOUND, {\n searchPaths: explicitConfigPaths,\n })\n }\n\n const content = await safeReadFile(filePath)\n return validateYAML(content)\n }\n\n const searchPaths = computeCachedSearchPaths()\n const existingPaths = await filterExistingPaths(searchPaths)\n\n if (existingPaths.length === 0) {\n throw createConfigError(\"Configuration file not found\", ErrorCodes.CONFIG_NOT_FOUND, {\n searchPaths,\n })\n }\n\n const projectPath = findProjectConfigCandidate()\n const globalPaths = existingPaths.filter((filePath) => filePath !== projectPath)\n\n let mergedConfig: Config = { presets: {} }\n\n for (const globalPath of globalPaths) {\n const content = await safeReadFile(globalPath)\n const config = validateYAML(content)\n mergedConfig = mergeConfigs(mergedConfig, config)\n }\n\n if (projectPath !== null && (await fs.pathExists(projectPath))) {\n const content = await safeReadFile(projectPath)\n const config = validateYAML(content)\n mergedConfig = mergeConfigs(mergedConfig, config)\n }\n\n return applyDefaults(mergedConfig)\n }\n\n return {\n loadYAML: async (): Promise<string> => {\n const config = await loadConfig()\n return yaml.stringify(config)\n },\n loadConfig,\n findConfigFile: async (): Promise<string | null> => {\n const searchPaths =\n explicitConfigPaths && explicitConfigPaths.length > 0 ? [...explicitConfigPaths] : computeCachedSearchPaths()\n\n for (const searchPath of searchPaths) {\n if (await fs.pathExists(searchPath)) {\n return searchPath\n }\n }\n return null\n },\n getSearchPaths: (): string[] => computeCachedSearchPaths(),\n }\n}\n\nconst buildDefaultSearchPaths = (): string[] => {\n const paths: string[] = []\n\n const vdeConfigPath = process.env.VDE_CONFIG_PATH\n if (vdeConfigPath !== undefined) {\n paths.push(path.join(vdeConfigPath, \"layout.yml\"))\n }\n\n const homeDir = process.env.HOME ?? os.homedir()\n const xdgConfigHome = process.env.XDG_CONFIG_HOME ?? path.join(homeDir, \".config\")\n paths.push(path.join(xdgConfigHome, \"vde\", \"layout.yml\"))\n\n return [...new Set(paths)]\n}\n\nconst findProjectConfigCandidate = (): string | null => {\n let currentDir = process.cwd()\n const { root } = path.parse(currentDir)\n\n while (true) {\n const candidate = path.join(currentDir, \".vde\", \"layout.yml\")\n if (fs.existsSync(candidate)) {\n return candidate\n }\n\n if (currentDir === root) {\n break\n }\n\n const parent = path.dirname(currentDir)\n if (parent === currentDir) {\n break\n }\n\n currentDir = parent\n }\n\n return null\n}\n\nconst findFirstExisting = async (paths: ReadonlyArray<string>): Promise<string | null> => {\n for (const candidate of paths) {\n if (await fs.pathExists(candidate)) {\n return candidate\n }\n }\n return null\n}\n\nconst filterExistingPaths = async (paths: ReadonlyArray<string>): Promise<string[]> => {\n const existing: string[] = []\n for (const candidate of paths) {\n if (await fs.pathExists(candidate)) {\n existing.push(candidate)\n }\n }\n return existing\n}\n\nconst safeReadFile = async (filePath: string): Promise<string> => {\n try {\n return await fs.readFile(filePath, \"utf8\")\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n throw createConfigError(`Failed to read configuration file`, ErrorCodes.CONFIG_PERMISSION_ERROR, {\n filePath,\n error: errorMessage,\n })\n }\n}\n\nconst mergeConfigs = (base: Config, override: Config): Config => {\n const mergedPresets: Config[\"presets\"] = { ...base.presets }\n\n for (const [presetKey, overridePreset] of Object.entries(override.presets)) {\n const basePreset = base.presets[presetKey]\n if (\n basePreset !== undefined &&\n basePreset.windowMode !== undefined &&\n overridePreset.windowMode !== undefined &&\n basePreset.windowMode !== overridePreset.windowMode\n ) {\n console.warn(\n `[vde-layout] Preset \"${presetKey}\" windowMode conflict: \"${basePreset.windowMode}\" overridden by \"${overridePreset.windowMode}\"`,\n )\n }\n mergedPresets[presetKey] = overridePreset\n }\n\n const baseDefaults = base.defaults\n const overrideDefaults = override.defaults\n\n if (\n baseDefaults?.windowMode !== undefined &&\n overrideDefaults?.windowMode !== undefined &&\n baseDefaults.windowMode !== overrideDefaults.windowMode\n ) {\n console.warn(\n `[vde-layout] defaults.windowMode conflict: \"${baseDefaults.windowMode}\" overridden by \"${overrideDefaults.windowMode}\"`,\n )\n }\n\n const mergedDefaults =\n baseDefaults !== undefined || overrideDefaults !== undefined\n ? {\n ...(baseDefaults ?? {}),\n ...(overrideDefaults ?? {}),\n }\n : undefined\n\n return mergedDefaults === undefined\n ? {\n presets: mergedPresets,\n }\n : {\n defaults: mergedDefaults,\n presets: mergedPresets,\n }\n}\n\nconst applyDefaults = (config: Config): Config => {\n return config\n}\n","import { createConfigLoader, type ConfigLoaderOptions } from \"../config/loader.ts\"\nimport { createConfigError, ErrorCodes } from \"../utils/errors.ts\"\nimport type { Config, Preset, PresetInfo } from \"../models/types.ts\"\nimport type { PresetManager } from \"../types/preset-manager.ts\"\n\ntype PresetState = {\n setConfigPath: (filePath: string) => void\n loadConfig: () => Promise<void>\n getPreset: (name: string) => Preset\n listPresets: () => PresetInfo[]\n getDefaultPreset: () => Preset\n getDefaults: () => Config[\"defaults\"] | undefined\n}\n\nconst createState = (options: ConfigLoaderOptions = {}): PresetState => {\n let loaderOptions: ConfigLoaderOptions = options\n let cachedConfig: Config | null = null\n\n const setConfigPath = (filePath: string): void => {\n loaderOptions = { configPaths: [filePath] }\n cachedConfig = null\n }\n\n const loadConfig = async (): Promise<void> => {\n const loader = createConfigLoader(loaderOptions)\n cachedConfig = await loader.loadConfig()\n }\n\n const ensureConfig = (): Config => {\n if (cachedConfig === null) {\n throw createConfigError(\"Configuration not loaded\", ErrorCodes.CONFIG_NOT_FOUND)\n }\n return cachedConfig\n }\n\n const getPreset = (name: string): Preset => {\n const config = ensureConfig()\n const preset = config.presets[name]\n if (preset === undefined) {\n throw createConfigError(`Preset \"${name}\" not found`, ErrorCodes.PRESET_NOT_FOUND, {\n availablePresets: Object.keys(config.presets),\n })\n }\n return preset\n }\n\n const listPresets = (): PresetInfo[] => {\n if (cachedConfig === null) {\n return []\n }\n\n return Object.entries(cachedConfig.presets).map(([key, preset]) => ({\n key,\n name: preset.name,\n description: preset.description,\n }))\n }\n\n const getDefaultPreset = (): Preset => {\n const config = ensureConfig()\n\n if (config.presets.default !== undefined) {\n return config.presets.default\n }\n\n const firstKey = Object.keys(config.presets)[0]\n if (typeof firstKey !== \"string\" || firstKey.length === 0) {\n throw createConfigError(\"No presets defined\", ErrorCodes.PRESET_NOT_FOUND)\n }\n\n return config.presets[firstKey]!\n }\n\n const getDefaults = (): Config[\"defaults\"] | undefined => {\n const config = ensureConfig()\n return config.defaults\n }\n\n return {\n setConfigPath,\n loadConfig,\n getPreset,\n listPresets,\n getDefaultPreset,\n getDefaults,\n }\n}\n\nexport const createPresetManager = (options: ConfigLoaderOptions = {}): PresetManager => {\n const state = createState(options)\n return {\n setConfigPath: state.setConfigPath,\n loadConfig: state.loadConfig,\n getPreset: state.getPreset,\n listPresets: state.listPresets,\n getDefaultPreset: state.getDefaultPreset,\n getDefaults: state.getDefaults,\n }\n}\n","import type { WindowMode } from \"../models/types.ts\"\n\nexport type WindowModeSource = {\n readonly cli?: WindowMode\n readonly preset?: WindowMode\n readonly defaults?: WindowMode\n}\n\nexport type WindowModeResolutionSource = \"cli\" | \"preset\" | \"defaults\" | \"fallback\"\n\nexport type WindowModeResolution = {\n readonly mode: WindowMode\n readonly source: WindowModeResolutionSource\n}\n\nexport const resolveWindowMode = ({ cli, preset, defaults }: WindowModeSource): WindowModeResolution => {\n if (cli !== undefined) {\n return { mode: cli, source: \"cli\" }\n }\n\n if (preset !== undefined) {\n return { mode: preset, source: \"preset\" }\n }\n\n if (defaults !== undefined) {\n return { mode: defaults, source: \"defaults\" }\n }\n\n return { mode: \"new-window\", source: \"fallback\" }\n}\n","import { createInterface } from \"node:readline/promises\"\nimport { stdin as input, stdout as output } from \"node:process\"\nimport type { Logger } from \"../utils/logger.ts\"\n\nexport type ConfirmPaneClosureContext = {\n readonly panesToClose: ReadonlyArray<string>\n readonly dryRun: boolean\n}\n\nexport type ConfirmPaneClosure = (context: ConfirmPaneClosureContext) => Promise<boolean>\n\nexport const createPaneKillPrompter = (logger: Logger): ConfirmPaneClosure => {\n return async ({ panesToClose, dryRun }: ConfirmPaneClosureContext): Promise<boolean> => {\n if (panesToClose.length === 0) {\n return true\n }\n\n const paneList = panesToClose.join(\", \")\n\n if (dryRun) {\n logger.warn(`[DRY RUN] Would close panes: ${paneList}`)\n return true\n }\n\n logger.warn(`This operation will close the following panes: ${paneList}`)\n\n if (input.isTTY !== true || output.isTTY !== true) {\n logger.error(\"Cannot prompt for confirmation because the terminal is not interactive\")\n return false\n }\n\n const rl = createInterface({ input, output })\n try {\n const answer = await rl.question(\"Continue? [y/N]: \")\n const normalized = answer.trim().toLowerCase()\n return normalized === \"y\" || normalized === \"yes\"\n } finally {\n await rl.close()\n }\n }\n}\n","import chalk from \"chalk\"\n\nexport enum LogLevel {\n ERROR = 0,\n WARN = 1,\n INFO = 2,\n DEBUG = 3,\n}\n\ntype LoggerOptions = {\n readonly level?: LogLevel\n readonly prefix?: string\n}\n\nexport type Logger = {\n readonly level: LogLevel\n readonly prefix: string\n error: (message: string, error?: Error) => void\n warn: (message: string) => void\n info: (message: string) => void\n debug: (message: string) => void\n success: (message: string) => void\n createChild: (suffix: string) => Logger\n}\n\nconst resolveDefaultLogLevel = (): LogLevel => {\n if (process.env.VDE_DEBUG === \"true\") {\n return LogLevel.DEBUG\n }\n if (process.env.VDE_VERBOSE === \"true\") {\n return LogLevel.INFO\n }\n return LogLevel.WARN\n}\n\nconst formatMessage = (prefix: string, message: string): string => {\n return prefix ? `${prefix} ${message}` : message\n}\n\nexport const createLogger = (options: LoggerOptions = {}): Logger => {\n const level = options.level ?? resolveDefaultLogLevel()\n const prefix = options.prefix ?? \"\"\n\n const build = (nextPrefix: string, nextLevel: LogLevel): Logger => {\n const resolvedPrefix = nextPrefix\n\n return {\n level: nextLevel,\n prefix: resolvedPrefix,\n error(message: string, error?: Error): void {\n if (nextLevel >= LogLevel.ERROR) {\n console.error(chalk.red(formatMessage(resolvedPrefix, `Error: ${message}`)))\n if (error && process.env.VDE_DEBUG === \"true\") {\n console.error(chalk.gray(error.stack))\n }\n }\n },\n warn(message: string): void {\n if (nextLevel >= LogLevel.WARN) {\n console.warn(chalk.yellow(formatMessage(resolvedPrefix, message)))\n }\n },\n info(message: string): void {\n if (nextLevel >= LogLevel.INFO) {\n console.log(formatMessage(resolvedPrefix, message))\n }\n },\n debug(message: string): void {\n if (nextLevel >= LogLevel.DEBUG) {\n console.log(chalk.gray(formatMessage(resolvedPrefix, `[DEBUG] ${message}`)))\n }\n },\n success(message: string): void {\n console.log(chalk.green(formatMessage(resolvedPrefix, message)))\n },\n createChild(suffix: string): Logger {\n const childPrefix = resolvedPrefix ? `${resolvedPrefix} ${suffix}` : suffix\n return build(childPrefix, nextLevel)\n },\n }\n }\n\n return build(prefix, level)\n}\n","import { execa } from \"execa\"\nimport { createTmuxError, ErrorCodes } from \"../utils/errors.ts\"\nimport type { CommandExecutor } from \"../types/command-executor.ts\"\nimport { createLogger, LogLevel } from \"../utils/logger.ts\"\n\ntype RealExecutorOptions = {\n readonly verbose?: boolean\n}\n\nconst parseCommand = (commandOrArgs: string | string[]): string[] => {\n return typeof commandOrArgs === \"string\"\n ? commandOrArgs\n .split(\" \")\n .filter((segment) => segment.length > 0)\n .slice(1)\n : commandOrArgs\n}\n\nconst toCommandString = (args: string[]): string => {\n return [\"tmux\", ...args].join(\" \")\n}\n\nexport const createRealExecutor = (options: RealExecutorOptions = {}): CommandExecutor => {\n const verbose = options.verbose ?? false\n const logger = createLogger({\n level: verbose ? LogLevel.INFO : LogLevel.WARN,\n prefix: \"[tmux]\",\n })\n\n const execute = async (commandOrArgs: string | string[]): Promise<string> => {\n const args = parseCommand(commandOrArgs)\n const commandString = toCommandString(args)\n\n logger.info(`Executing: ${commandString}`)\n\n try {\n const result = await execa(\"tmux\", args)\n return result.stdout\n } catch (error) {\n const execaError = error as { exitCode?: number; stderr?: string; message: string }\n\n throw createTmuxError(\"Failed to execute tmux command\", ErrorCodes.TMUX_COMMAND_FAILED, {\n command: commandString,\n exitCode: execaError.exitCode,\n stderr: execaError.stderr,\n })\n }\n }\n\n return {\n execute,\n async executeMany(commandsList: string[][]): Promise<void> {\n for (const args of commandsList) {\n await execute(args)\n }\n },\n isDryRun(): boolean {\n return false\n },\n logCommand(command: string): void {\n logger.info(`Executing: ${command}`)\n },\n }\n}\n","import type { CommandExecutor } from \"../types/command-executor.ts\"\nimport { createLogger, LogLevel } from \"../utils/logger.ts\"\n\ntype DryRunExecutorOptions = {\n readonly verbose?: boolean\n}\n\nconst parseCommand = (commandOrArgs: string | string[]): string[] => {\n return typeof commandOrArgs === \"string\"\n ? commandOrArgs\n .split(\" \")\n .filter((segment) => segment.length > 0)\n .slice(1)\n : commandOrArgs\n}\n\nconst toCommandString = (args: string[]): string => {\n return [\"tmux\", ...args].join(\" \")\n}\n\nexport const createDryRunExecutor = (options: DryRunExecutorOptions = {}): CommandExecutor => {\n const verbose = options.verbose ?? false\n const logger = createLogger({\n level: verbose ? LogLevel.INFO : LogLevel.WARN,\n prefix: \"[tmux] [DRY RUN]\",\n })\n\n const execute = async (commandOrArgs: string | string[]): Promise<string> => {\n const args = parseCommand(commandOrArgs)\n const commandString = toCommandString(args)\n logger.info(`Would execute: ${commandString}`)\n return \"\"\n }\n\n return {\n execute,\n async executeMany(commandsList: string[][]): Promise<void> {\n for (const args of commandsList) {\n await execute(args)\n }\n },\n isDryRun(): boolean {\n return true\n },\n logCommand(command: string): void {\n logger.info(`Would execute: ${command}`)\n },\n }\n}\n","type FunctionalCoreErrorKind = \"compile\" | \"plan\" | \"emit\" | \"execution\"\n\nexport type FunctionalCoreError = {\n readonly kind: FunctionalCoreErrorKind\n readonly code: string\n readonly message: string\n readonly source?: string\n readonly path?: string\n readonly details?: Readonly<Record<string, unknown>>\n}\n\nexport const createFunctionalError = (\n kind: FunctionalCoreErrorKind,\n error: {\n readonly code: string\n readonly message: string\n readonly source?: string\n readonly path?: string\n readonly details?: Readonly<Record<string, unknown>>\n },\n): FunctionalCoreError => ({\n kind,\n code: error.code,\n message: error.message,\n source: error.source,\n path: error.path,\n details: error.details,\n})\n\nexport const isFunctionalCoreError = (value: unknown): value is FunctionalCoreError => {\n if (typeof value !== \"object\" || value === null) {\n return false\n }\n const candidate = value as Partial<FunctionalCoreError>\n return (\n (candidate.kind === \"compile\" ||\n candidate.kind === \"plan\" ||\n candidate.kind === \"emit\" ||\n candidate.kind === \"execution\") &&\n typeof candidate.code === \"string\" &&\n typeof candidate.message === \"string\"\n )\n}\n","import type { CommandExecutor } from \"../types/command-executor.ts\"\nimport type { PlanEmission, CommandStep, EmittedTerminal } from \"../core/emitter.ts\"\nimport type { WindowMode } from \"../models/types.ts\"\nimport { ErrorCodes } from \"../utils/errors.ts\"\nimport { createFunctionalError } from \"../core/errors.ts\"\n\nconst DOUBLE_QUOTE = '\"'\nconst ESCAPED_DOUBLE_QUOTE = '\\\\\"'\n\ntype ConfirmPaneClosure = (context: { panesToClose: ReadonlyArray<string>; dryRun: boolean }) => Promise<boolean>\n\ntype ExecutePlanInput = {\n readonly emission: PlanEmission\n readonly executor: CommandExecutor\n readonly windowName?: string\n readonly windowMode: WindowMode\n readonly onConfirmKill?: ConfirmPaneClosure\n}\n\ntype ExecutePlanSuccess = {\n readonly executedSteps: number\n}\n\nexport const executePlan = async ({\n emission,\n executor,\n windowName,\n windowMode,\n onConfirmKill,\n}: ExecutePlanInput): Promise<ExecutePlanSuccess> => {\n const initialVirtualPaneId = emission.summary.initialPaneId\n if (typeof initialVirtualPaneId !== \"string\" || initialVirtualPaneId.length === 0) {\n raiseExecutionError(\"INVALID_PLAN\", {\n message: \"Plan emission is missing initial pane metadata\",\n path: \"plan.initialPaneId\",\n })\n }\n\n const paneMap = new Map<string, string>()\n\n const isDryRun = executor.isDryRun()\n\n let initialPaneId: string\n\n if (windowMode === \"current-window\") {\n const currentPaneId = await resolveCurrentPaneId({\n executor,\n contextPath: initialVirtualPaneId,\n isDryRun,\n })\n\n const panesInWindow = await listWindowPaneIds(executor, initialVirtualPaneId)\n const panesToClose = panesInWindow.filter((paneId) => paneId !== currentPaneId)\n\n if (panesToClose.length > 0) {\n let confirmed = true\n if (onConfirmKill !== undefined) {\n confirmed = await onConfirmKill({ panesToClose, dryRun: isDryRun })\n }\n\n if (confirmed !== true) {\n throw createFunctionalError(\"execution\", {\n code: ErrorCodes.USER_CANCELLED,\n message: \"Aborted layout application for current window\",\n path: initialVirtualPaneId,\n details: { panes: panesToClose },\n })\n }\n\n await executeCommand(executor, [\"kill-pane\", \"-a\", \"-t\", currentPaneId], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: \"Failed to close existing panes\",\n path: initialVirtualPaneId,\n details: { command: [\"kill-pane\", \"-a\", \"-t\", currentPaneId] },\n })\n }\n\n initialPaneId = normalizePaneId(currentPaneId)\n } else {\n const newWindowCommand: string[] = [\"new-window\", \"-P\", \"-F\", \"#{pane_id}\"]\n if (typeof windowName === \"string\" && windowName.trim().length > 0) {\n newWindowCommand.push(\"-n\", windowName.trim())\n }\n\n initialPaneId = normalizePaneId(\n await executeCommand(executor, newWindowCommand, {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: \"Failed to create tmux window\",\n path: initialVirtualPaneId,\n }),\n )\n }\n\n registerPane(paneMap, initialVirtualPaneId, initialPaneId)\n\n let executedSteps = 0\n\n for (const step of emission.steps) {\n if (step.kind === \"split\") {\n await executeSplitStep({ step, executor, paneMap })\n } else if (step.kind === \"focus\") {\n await executeFocusStep({ step, executor, paneMap })\n }\n executedSteps += 1\n }\n\n await executeTerminalCommands({ terminals: emission.terminals, executor, paneMap })\n\n const finalRealFocus = resolvePaneId(paneMap, emission.summary.focusPaneId)\n if (typeof finalRealFocus === \"string\" && finalRealFocus.length > 0) {\n await executeCommand(executor, [\"select-pane\", \"-t\", finalRealFocus], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: \"Failed to restore focus\",\n path: emission.summary.focusPaneId,\n })\n }\n\n return { executedSteps }\n}\n\nconst executeSplitStep = async ({\n step,\n executor,\n paneMap,\n}: {\n readonly step: CommandStep\n readonly executor: CommandExecutor\n readonly paneMap: Map<string, string>\n}): Promise<void> => {\n const targetVirtualId = ensureNonEmpty(step.targetPaneId, () =>\n raiseExecutionError(\"MISSING_TARGET\", {\n message: \"Split step missing target pane metadata\",\n path: step.id,\n }),\n )\n\n const targetRealId = ensureNonEmpty(resolvePaneId(paneMap, targetVirtualId), () =>\n raiseExecutionError(\"UNKNOWN_PANE\", {\n message: `Unknown target pane: ${targetVirtualId}`,\n path: step.id,\n }),\n )\n\n const panesBefore = await listPaneIds(executor, step)\n const splitCommand = replaceTarget(step.command, targetRealId)\n await executeCommand(executor, splitCommand, {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: `Failed to execute split step ${step.id}`,\n path: step.id,\n details: { command: splitCommand },\n })\n\n const panesAfter = await listPaneIds(executor, step)\n const newPaneId = ensureNonEmpty(findNewPaneId(panesBefore, panesAfter), () =>\n raiseExecutionError(\"UNKNOWN_PANE\", {\n message: \"Unable to determine newly created pane\",\n path: step.id,\n }),\n )\n\n const createdVirtualId = step.createdPaneId\n if (typeof createdVirtualId === \"string\" && createdVirtualId.length > 0) {\n registerPane(paneMap, createdVirtualId, newPaneId)\n }\n}\n\nconst executeFocusStep = async ({\n step,\n executor,\n paneMap,\n}: {\n readonly step: CommandStep\n readonly executor: CommandExecutor\n readonly paneMap: Map<string, string>\n}): Promise<void> => {\n const targetVirtualId = ensureNonEmpty(step.targetPaneId, () =>\n raiseExecutionError(\"MISSING_TARGET\", {\n message: \"Focus step missing target pane metadata\",\n path: step.id,\n }),\n )\n\n const targetRealId = ensureNonEmpty(resolvePaneId(paneMap, targetVirtualId), () =>\n raiseExecutionError(\"UNKNOWN_PANE\", {\n message: `Unknown focus pane: ${targetVirtualId}`,\n path: step.id,\n }),\n )\n\n const command = replaceTarget(step.command, targetRealId)\n await executeCommand(executor, command, {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: `Failed to execute focus step ${step.id}`,\n path: step.id,\n details: { command },\n })\n}\n\nconst executeTerminalCommands = async ({\n terminals,\n executor,\n paneMap,\n}: {\n readonly terminals: ReadonlyArray<EmittedTerminal>\n readonly executor: CommandExecutor\n readonly paneMap: Map<string, string>\n}): Promise<void> => {\n for (const terminal of terminals) {\n const realPaneId = ensureNonEmpty(resolvePaneId(paneMap, terminal.virtualPaneId), () =>\n raiseExecutionError(\"UNKNOWN_PANE\", {\n message: `Unknown terminal pane: ${terminal.virtualPaneId}`,\n path: terminal.virtualPaneId,\n }),\n )\n\n if (typeof terminal.cwd === \"string\" && terminal.cwd.length > 0) {\n const escapedCwd = terminal.cwd.split(DOUBLE_QUOTE).join(ESCAPED_DOUBLE_QUOTE)\n await executeCommand(executor, [\"send-keys\", \"-t\", realPaneId, `cd \"${escapedCwd}\"`, \"Enter\"], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: `Failed to change directory for pane ${terminal.virtualPaneId}`,\n path: terminal.virtualPaneId,\n details: { cwd: terminal.cwd },\n })\n }\n\n if (terminal.env !== undefined) {\n for (const [key, value] of Object.entries(terminal.env)) {\n const escaped = String(value).split(DOUBLE_QUOTE).join(ESCAPED_DOUBLE_QUOTE)\n await executeCommand(executor, [\"send-keys\", \"-t\", realPaneId, `export ${key}=\"${escaped}\"`, \"Enter\"], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: `Failed to set environment variable ${key}`,\n path: terminal.virtualPaneId,\n })\n }\n }\n\n if (typeof terminal.command === \"string\" && terminal.command.length > 0) {\n await executeCommand(executor, [\"send-keys\", \"-t\", realPaneId, terminal.command, \"Enter\"], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: `Failed to execute command for pane ${terminal.virtualPaneId}`,\n path: terminal.virtualPaneId,\n details: { command: terminal.command },\n })\n }\n }\n}\n\nconst executeCommand = async (\n executor: CommandExecutor,\n command: string[],\n context: {\n readonly code: string\n readonly message: string\n readonly path: string\n readonly details?: Record<string, unknown>\n },\n): Promise<string> => {\n try {\n return await executor.execute([...command])\n } catch (error) {\n if (error instanceof Error && \"code\" in error && \"message\" in error) {\n const candidate = error as { code?: string; message?: string; details?: Record<string, unknown> }\n throw createFunctionalError(\"execution\", {\n code: typeof candidate.code === \"string\" ? candidate.code : context.code,\n message: candidate.message ?? context.message,\n path: context.path,\n details: candidate.details ?? context.details,\n })\n }\n\n throw createFunctionalError(\"execution\", {\n code: context.code,\n message: context.message,\n path: context.path,\n details: context.details,\n })\n }\n}\n\nconst resolveCurrentPaneId = async ({\n executor,\n contextPath,\n isDryRun,\n}: {\n executor: CommandExecutor\n contextPath: string\n isDryRun: boolean\n}): Promise<string> => {\n const envPaneId = process.env.TMUX_PANE\n if (typeof envPaneId === \"string\" && envPaneId.trim().length > 0) {\n return normalizePaneId(envPaneId)\n }\n\n if (isDryRun) {\n return \"%0\"\n }\n\n const output = await executeCommand(executor, [\"display-message\", \"-p\", \"#{pane_id}\"], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: \"Failed to resolve current tmux pane\",\n path: contextPath,\n })\n\n const paneId = output.trim()\n if (paneId.length === 0) {\n throw createFunctionalError(\"execution\", {\n code: ErrorCodes.NOT_IN_TMUX_SESSION,\n message: \"Unable to determine current tmux pane\",\n path: contextPath,\n })\n }\n\n return normalizePaneId(paneId)\n}\n\nconst listWindowPaneIds = async (executor: CommandExecutor, contextPath: string): Promise<string[]> => {\n const output = await executeCommand(executor, [\"list-panes\", \"-F\", \"#{pane_id}\"], {\n code: ErrorCodes.TMUX_COMMAND_FAILED,\n message: \"Failed to list tmux panes\",\n path: contextPath,\n })\n\n return output\n .split(\"\\n\")\n .map((pane) => pane.trim())\n .filter((pane) => pane.length > 0)\n}\n\nconst listPaneIds = async (executor: CommandExecutor, step: CommandStep): Promise<string[]> => {\n return listWindowPaneIds(executor, step.id)\n}\n\nconst findNewPaneId = (before: string[], after: string[]): string | undefined => {\n const beforeSet = new Set(before)\n return after.find((id) => !beforeSet.has(id))\n}\n\nconst replaceTarget = (command: ReadonlyArray<string>, realTarget: string): string[] => {\n const next = [...command]\n const targetIndex = next.findIndex((value, index) => value === \"-t\" && index + 1 < next.length)\n if (targetIndex >= 0) {\n next[targetIndex + 1] = realTarget\n return next\n }\n\n if (next.length > 0) {\n next[next.length - 1] = realTarget\n }\n return next\n}\n\nconst normalizePaneId = (raw: string): string => {\n const trimmed = raw.trim()\n return trimmed.length === 0 ? \"%0\" : trimmed\n}\n\nconst registerPane = (paneMap: Map<string, string>, virtualId: string, realId: string): void => {\n paneMap.set(virtualId, realId)\n}\n\nconst resolvePaneId = (paneMap: Map<string, string>, virtualId: string): string | undefined => {\n const direct = paneMap.get(virtualId)\n if (typeof direct === \"string\" && direct.length > 0) {\n return direct\n }\n\n let ancestor = virtualId\n while (ancestor.includes(\".\")) {\n ancestor = ancestor.slice(0, ancestor.lastIndexOf(\".\"))\n const candidate = paneMap.get(ancestor)\n if (typeof candidate === \"string\" && candidate.length > 0) {\n paneMap.set(virtualId, candidate)\n return candidate\n }\n }\n\n for (const [key, value] of paneMap.entries()) {\n if (key.startsWith(`${virtualId}.`)) {\n if (typeof value === \"string\" && value.length > 0) {\n paneMap.set(virtualId, value)\n return value\n }\n }\n }\n\n return undefined\n}\n\nconst ensureNonEmpty = <T extends string>(value: T | undefined, buildError: () => never): T => {\n if (value === undefined || value.length === 0) {\n return buildError()\n }\n return value\n}\n\nconst raiseExecutionError = (\n code: string,\n error: {\n readonly message: string\n readonly path: string\n readonly details?: Record<string, unknown>\n },\n): never => {\n throw createFunctionalError(\"execution\", {\n code,\n message: error.message,\n path: error.path,\n details: error.details,\n })\n}\n","import { parse } from \"yaml\"\n\nexport type DiagnosticsSeverity = \"high\" | \"medium\" | \"low\"\n\ntype DiagnosticsFinding = {\n readonly path: string\n readonly severity: DiagnosticsSeverity\n readonly description: string\n}\n\ntype DiagnosticsBacklogItem = {\n readonly id: string\n readonly severity: DiagnosticsSeverity\n readonly summary: string\n readonly actions: ReadonlyArray<string>\n}\n\nexport type DiagnosticsReport = {\n readonly findings: ReadonlyArray<DiagnosticsFinding>\n readonly nextSteps: ReadonlyArray<string>\n readonly backlog: ReadonlyArray<DiagnosticsBacklogItem>\n}\n\ntype DiagnosticsInput = {\n readonly presetDocument: string\n readonly knownIssues?: ReadonlyArray<string>\n}\n\nconst severityRank: Record<DiagnosticsSeverity, number> = {\n high: 3,\n medium: 2,\n low: 1,\n}\n\ntype FindingAccumulator = {\n add: (args: { path: string; severity: DiagnosticsSeverity; description: string; nextStep?: string }) => void\n readonly findings: DiagnosticsFinding[]\n readonly nextSteps: Set<string>\n readonly backlog: Map<string, DiagnosticsBacklogItem>\n}\n\nconst createAccumulator = (): FindingAccumulator => {\n const findings: DiagnosticsFinding[] = []\n const nextSteps = new Set<string>()\n const backlog = new Map<string, DiagnosticsBacklogItem>()\n\n return {\n findings,\n nextSteps,\n backlog,\n add: ({ path, severity, description, nextStep }): void => {\n findings.push({ path, severity, description })\n if (typeof nextStep === \"string\" && nextStep.length > 0) {\n nextSteps.add(nextStep)\n }\n\n const existing = backlog.get(path)\n const existingActions = new Set(existing?.actions ?? [])\n existingActions.add(description)\n if (typeof nextStep === \"string\" && nextStep.length > 0) {\n existingActions.add(nextStep)\n }\n\n const mergedSeverity = existing !== undefined ? maxSeverity(existing.severity, severity) : severity\n\n const summary =\n existing !== undefined && severityRank[existing.severity] >= severityRank[severity]\n ? existing.summary\n : description\n\n backlog.set(path, {\n id: path,\n severity: mergedSeverity,\n summary,\n actions: Array.from(existingActions),\n })\n },\n }\n}\n\nexport const runDiagnostics = (input: DiagnosticsInput): DiagnosticsReport => {\n const accumulator = createAccumulator()\n const knownIssues = input.knownIssues ?? []\n let parsedPreset: unknown\n\n try {\n parsedPreset = parse(input.presetDocument)\n } catch (error) {\n accumulator.add({\n path: \"presetDocument\",\n severity: \"high\",\n description: `プリセットYAMLの解析に失敗しました: ${(error as Error).message}`,\n nextStep: \"プリセットYAMLを構文チェックし、Functional Coreリライト前に整合性を確保する\",\n })\n return {\n findings: sortBySeverity(accumulator.findings),\n nextSteps: Array.from(accumulator.nextSteps),\n backlog: sortBacklog(accumulator.backlog),\n }\n }\n\n if (parsedPreset === null || typeof parsedPreset !== \"object\") {\n accumulator.add({\n path: \"preset\",\n severity: \"high\",\n description: \"プリセット定義がオブジェクト形式ではありません\",\n nextStep: \"プリセットYAMLをオブジェクト構造に整形し整合性を確保する\",\n })\n } else {\n const presetObject = parsedPreset as Record<string, unknown>\n checkFocusDuplications(presetObject, accumulator)\n collectLowPrioritySignals(presetObject, accumulator)\n }\n\n knownIssues.forEach((issue, index) => {\n const trimmed = issue.trim()\n if (trimmed.length === 0) {\n return\n }\n\n accumulator.add({\n path: `codebase.knownIssues[${index}]`,\n severity: \"medium\",\n description: trimmed,\n nextStep: `tmux依存や副作用をFunctional Core境界で切り離す: ${trimmed}`,\n })\n })\n\n return {\n findings: sortBySeverity(accumulator.findings),\n nextSteps: Array.from(accumulator.nextSteps),\n backlog: sortBacklog(accumulator.backlog),\n }\n}\n\nconst checkFocusDuplications = (preset: Record<string, unknown>, accumulator: FindingAccumulator): void => {\n const layout = preset.layout as unknown\n if (layout === undefined || layout === null) {\n return\n }\n\n const focusCount = countFocusFlags(layout)\n if (focusCount > 1) {\n accumulator.add({\n path: \"preset.layout\",\n severity: \"high\",\n description: \"複数のペインでfocus: trueが指定されています\",\n nextStep: \"focusは単一ペインに限定しPlan生成時に一貫するようFunctional Coreで制御する\",\n })\n }\n}\n\nconst collectLowPrioritySignals = (preset: Record<string, unknown>, accumulator: FindingAccumulator): void => {\n const layout = preset.layout as Record<string, unknown> | undefined | null\n if (layout === undefined || layout === null) {\n accumulator.add({\n path: \"preset.layout\",\n severity: \"low\",\n description: \"layout定義が存在しません(単一ペイン運用が前提)\",\n nextStep: \"単一ペイン前提でもPlan出力に影響しないことをFunctional Coreで確認する\",\n })\n return\n }\n\n if (!Array.isArray(layout.panes)) {\n accumulator.add({\n path: \"preset.layout.panes\",\n severity: \"low\",\n description: \"panes配列が存在しないか配列ではありません\",\n nextStep: \"レイアウト定義の構造を正規化し、Plan生成の入力契約を明示する\",\n })\n }\n}\n\nconst countFocusFlags = (node: unknown): number => {\n if (Array.isArray(node)) {\n return node.reduce((sum, child) => sum + countFocusFlags(child), 0)\n }\n\n if (node === null || typeof node !== \"object\") {\n return 0\n }\n\n const record = node as Record<string, unknown>\n const selfFocus = record.focus === true ? 1 : 0\n const childFocus = Array.isArray(record.panes)\n ? record.panes.reduce((sum, child) => sum + countFocusFlags(child), 0)\n : 0\n\n return selfFocus + childFocus\n}\n\nconst sortBySeverity = (findings: DiagnosticsFinding[]): DiagnosticsFinding[] => {\n return [...findings].sort((a, b) => severityRank[b.severity] - severityRank[a.severity])\n}\n\nconst sortBacklog = (backlog: Map<string, DiagnosticsBacklogItem>): DiagnosticsBacklogItem[] => {\n return [...backlog.values()].sort((a, b) => severityRank[b.severity] - severityRank[a.severity])\n}\n\nconst maxSeverity = (left: DiagnosticsSeverity, right: DiagnosticsSeverity): DiagnosticsSeverity => {\n return severityRank[left] >= severityRank[right] ? left : right\n}\n","import { parse } from \"yaml\"\nimport { createFunctionalError, type FunctionalCoreError } from \"./errors.ts\"\n\nexport type CompilePresetInput = {\n readonly document: string\n readonly source: string\n}\n\nexport type FunctionalTerminalPane = {\n readonly kind: \"terminal\"\n readonly name: string\n readonly command?: string\n readonly cwd?: string\n readonly env?: Readonly<Record<string, string>>\n readonly focus?: boolean\n readonly options?: Readonly<Record<string, unknown>>\n}\n\nexport type FunctionalSplitPane = {\n readonly kind: \"split\"\n readonly orientation: \"horizontal\" | \"vertical\"\n readonly ratio: ReadonlyArray<number>\n readonly panes: ReadonlyArray<FunctionalLayoutNode>\n}\n\nexport type FunctionalLayoutNode = FunctionalTerminalPane | FunctionalSplitPane\n\ntype FunctionalPresetMetadata = {\n readonly source: string\n}\n\nexport type FunctionalPreset = {\n readonly name: string\n readonly version: string\n readonly command?: string\n readonly layout?: FunctionalLayoutNode\n readonly metadata: FunctionalPresetMetadata\n}\n\nexport type CompilePresetSuccess = {\n readonly preset: FunctionalPreset\n}\n\nexport const compilePreset = ({ document, source }: CompilePresetInput): CompilePresetSuccess => {\n let parsed: unknown\n try {\n parsed = parse(document)\n } catch (error) {\n throw compileError(\"PRESET_PARSE_ERROR\", {\n source,\n message: `YAMLの解析に失敗しました: ${(error as Error).message}`,\n details: {\n reason: error instanceof Error ? error.message : String(error),\n },\n })\n }\n\n if (!isRecord(parsed)) {\n throw compileError(\"PRESET_INVALID_DOCUMENT\", {\n source,\n message: \"プリセット定義がオブジェクトではありません\",\n path: \"preset\",\n })\n }\n\n const name = typeof parsed.name === \"string\" && parsed.name.trim().length > 0 ? parsed.name : \"Unnamed preset\"\n\n const layout = parseLayoutNode(parsed.layout, {\n source,\n path: \"preset.layout\",\n })\n\n return {\n preset: {\n name,\n version: \"legacy\",\n command: typeof parsed.command === \"string\" ? parsed.command : undefined,\n layout: layout ?? undefined,\n metadata: { source },\n },\n }\n}\n\nconst parseLayoutNode = (\n node: unknown,\n context: { readonly source: string; readonly path: string },\n): FunctionalLayoutNode | null => {\n if (node === undefined || node === null) {\n return null\n }\n\n if (!isRecord(node)) {\n throw compileError(\"LAYOUT_INVALID_NODE\", {\n source: context.source,\n message: \"レイアウトノードの形式が不正です\",\n path: context.path,\n details: { node },\n })\n }\n\n if (typeof node.type === \"string\" && Array.isArray(node.panes)) {\n return parseSplitPane(node, context)\n }\n\n if (typeof node.name === \"string\") {\n return parseTerminalPane(node)\n }\n\n throw compileError(\"LAYOUT_INVALID_NODE\", {\n source: context.source,\n message: \"レイアウトノードの形式が不正です\",\n path: context.path,\n details: { node },\n })\n}\n\nconst parseSplitPane = (\n node: Record<string, unknown>,\n context: { readonly source: string; readonly path: string },\n): FunctionalSplitPane => {\n const orientation = node.type\n if (orientation !== \"horizontal\" && orientation !== \"vertical\") {\n throw compileError(\"LAYOUT_INVALID_ORIENTATION\", {\n source: context.source,\n message: \"layout.type は horizontal か vertical である必要があります\",\n path: `${context.path}.type`,\n details: { type: orientation },\n })\n }\n\n if (!Array.isArray(node.panes) || node.panes.length === 0) {\n throw compileError(\"LAYOUT_PANES_MISSING\", {\n source: context.source,\n message: \"panes 配列が存在しません\",\n path: `${context.path}.panes`,\n })\n }\n\n if (!Array.isArray(node.ratio) || node.ratio.length === 0) {\n throw compileError(\"LAYOUT_RATIO_MISSING\", {\n source: context.source,\n message: \"ratio 配列が存在しません\",\n path: `${context.path}.ratio`,\n })\n }\n\n if (node.ratio.length !== node.panes.length) {\n throw compileError(\"LAYOUT_RATIO_MISMATCH\", {\n source: context.source,\n message: \"ratio 配列と panes 配列の長さが一致しません\",\n path: context.path,\n details: {\n ratioLength: node.ratio.length,\n panesLength: node.panes.length,\n },\n })\n }\n\n const ratio = node.ratio.map((value, index) => {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n throw compileError(\"RATIO_INVALID_VALUE\", {\n source: context.source,\n message: \"ratio の値が正の数値ではありません\",\n path: `${context.path}.ratio[${index}]`,\n details: { value },\n })\n }\n return value\n })\n\n const panes = node.panes.map((child, index) =>\n parseLayoutNode(child, {\n source: context.source,\n path: `${context.path}.panes[${index}]`,\n }),\n )\n\n return {\n kind: \"split\",\n orientation,\n ratio,\n panes: panes.filter((pane): pane is FunctionalLayoutNode => pane !== null),\n }\n}\n\nconst parseTerminalPane = (node: Record<string, unknown>): FunctionalTerminalPane => {\n const name = typeof node.name === \"string\" ? node.name : \"\"\n const command = typeof node.command === \"string\" ? node.command : undefined\n const cwd = typeof node.cwd === \"string\" ? node.cwd : undefined\n const focus = node.focus === true ? true : undefined\n const env = normalizeEnv(node.env)\n\n const knownKeys = new Set([\"name\", \"command\", \"cwd\", \"env\", \"focus\", \"options\", \"title\", \"delay\"])\n const options = collectOptions(node, knownKeys)\n\n return {\n kind: \"terminal\",\n name,\n command,\n cwd,\n env,\n focus,\n options,\n }\n}\n\nconst normalizeEnv = (env: unknown): Readonly<Record<string, string>> | undefined => {\n if (!isRecord(env)) {\n return undefined\n }\n\n const entries = Object.entries(env).reduce<Record<string, string>>((accumulator, [key, value]) => {\n if (typeof value === \"string\") {\n accumulator[key] = value\n }\n return accumulator\n }, {})\n\n return Object.keys(entries).length > 0 ? entries : undefined\n}\n\nconst collectOptions = (\n node: Record<string, unknown>,\n excludedKeys: ReadonlySet<string>,\n): Readonly<Record<string, unknown>> | undefined => {\n const optionsEntries = Object.entries(node).filter(([key]) => !excludedKeys.has(key))\n if (optionsEntries.length === 0) {\n return undefined\n }\n\n return optionsEntries.reduce<Record<string, unknown>>((accumulator, [key, value]) => {\n accumulator[key] = value\n return accumulator\n }, {})\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null\n}\n\nconst compileError = (\n code: string,\n error: {\n readonly source?: string\n readonly message: string\n readonly path?: string\n readonly details?: Readonly<Record<string, unknown>>\n },\n): FunctionalCoreError => {\n return createFunctionalError(\"compile\", {\n code,\n message: error.message,\n source: error.source,\n path: error.path,\n details: error.details,\n })\n}\n","import type { FunctionalLayoutNode, FunctionalPreset, FunctionalSplitPane, FunctionalTerminalPane } from \"./compile.ts\"\nimport { createFunctionalError, type FunctionalCoreError } from \"./errors.ts\"\n\ntype CreateLayoutPlanInput = {\n readonly preset: FunctionalPreset\n}\n\ntype PlanTerminal = {\n readonly kind: \"terminal\"\n readonly id: string\n readonly name: string\n readonly command?: string\n readonly cwd?: string\n readonly env?: Readonly<Record<string, string>>\n readonly focus: boolean\n readonly options?: Readonly<Record<string, unknown>>\n}\n\ntype PlanSplit = {\n readonly kind: \"split\"\n readonly id: string\n readonly orientation: \"horizontal\" | \"vertical\"\n readonly ratio: ReadonlyArray<number>\n readonly panes: ReadonlyArray<PlanNode>\n}\n\nexport type PlanNode = PlanTerminal | PlanSplit\n\nexport type LayoutPlan = {\n readonly root: PlanNode\n readonly focusPaneId: string\n}\n\nexport type CreateLayoutPlanSuccess = {\n readonly plan: LayoutPlan\n}\n\nexport const createLayoutPlan = ({ preset }: CreateLayoutPlanInput): CreateLayoutPlanSuccess => {\n if (!preset.layout) {\n const terminal = createTerminalNode({\n id: \"root\",\n terminal: {\n kind: \"terminal\",\n name: preset.name,\n command: preset.command,\n },\n focusOverride: true,\n })\n\n return {\n plan: {\n root: terminal,\n focusPaneId: terminal.id,\n },\n }\n }\n\n const { node, focusPaneIds, terminalPaneIds } = buildLayoutNode(preset.layout, {\n parentId: \"root\",\n path: \"preset.layout\",\n source: preset.metadata.source,\n })\n\n if (focusPaneIds.length > 1) {\n throw planError(\"FOCUS_CONFLICT\", {\n message: \"複数のペインでfocusが指定されています\",\n path: \"preset.layout\",\n source: preset.metadata.source,\n details: { focusPaneIds },\n })\n }\n\n if (terminalPaneIds.length === 0) {\n throw planError(\"NO_TERMINAL_PANES\", {\n message: \"ターミナルペインが存在しません\",\n path: \"preset.layout\",\n source: preset.metadata.source,\n })\n }\n\n const focusPaneId = focusPaneIds[0] ?? terminalPaneIds[0]!\n const root = ensureFocus(node, focusPaneId)\n\n return {\n plan: {\n root,\n focusPaneId,\n },\n }\n}\n\ntype BuildResult = {\n readonly node: PlanNode\n readonly focusPaneIds: ReadonlyArray<string>\n readonly terminalPaneIds: ReadonlyArray<string>\n}\n\nconst buildLayoutNode = (\n node: FunctionalLayoutNode,\n context: { readonly parentId: string; readonly path: string; readonly source: string },\n): BuildResult => {\n if (node.kind === \"split\") {\n return buildSplitNode(node, context)\n }\n\n return {\n node: createTerminalNode({ id: context.parentId, terminal: node }),\n focusPaneIds: node.focus === true ? [context.parentId] : [],\n terminalPaneIds: [context.parentId],\n }\n}\n\nconst buildSplitNode = (\n node: FunctionalSplitPane,\n context: { readonly parentId: string; readonly path: string; readonly source: string },\n): BuildResult => {\n const ratio = normalizeRatio(node.ratio, context)\n\n const panes: PlanNode[] = []\n const focusPaneIds: string[] = []\n const terminalPaneIds: string[] = []\n\n for (let index = 0; index < node.panes.length; index += 1) {\n const childId = `${context.parentId}.${index}`\n const childContext = {\n parentId: childId,\n path: `${context.path}.panes[${index}]`,\n source: context.source,\n }\n\n const childResult = buildLayoutNode(node.panes[index]!, childContext)\n panes.push(childResult.node)\n focusPaneIds.push(...childResult.focusPaneIds)\n terminalPaneIds.push(...childResult.terminalPaneIds)\n }\n\n return {\n node: {\n kind: \"split\",\n id: context.parentId,\n orientation: node.orientation,\n ratio,\n panes,\n },\n focusPaneIds,\n terminalPaneIds,\n }\n}\n\nconst createTerminalNode = ({\n id,\n terminal,\n focusOverride,\n}: {\n readonly id: string\n readonly terminal: FunctionalTerminalPane\n readonly focusOverride?: boolean\n}): PlanTerminal => {\n return {\n kind: \"terminal\",\n id,\n name: terminal.name,\n command: terminal.command,\n cwd: terminal.cwd,\n env: terminal.env,\n options: terminal.options,\n focus: focusOverride === true ? true : terminal.focus === true,\n }\n}\n\nconst ensureFocus = (node: PlanNode, focusPaneId: string): PlanNode => {\n if (node.kind === \"terminal\") {\n return {\n ...node,\n focus: node.id === focusPaneId,\n }\n }\n\n return {\n ...node,\n panes: node.panes.map((pane) => ensureFocus(pane, focusPaneId)),\n }\n}\n\nconst normalizeRatio = (\n ratio: ReadonlyArray<number>,\n context: { readonly path: string; readonly source: string },\n): number[] => {\n const total = ratio.reduce((sum, value, index) => {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n throw planError(\"RATIO_INVALID_VALUE\", {\n message: \"ratio の値が非負の数値ではありません\",\n path: `${context.path}.ratio[${index}]`,\n source: context.source,\n details: { value },\n })\n }\n return sum + value\n }, 0)\n\n if (total === 0) {\n return ratio.map(() => 1 / ratio.length)\n }\n\n return ratio.map((value) => value / total)\n}\n\nconst planError = (\n code: string,\n error: {\n readonly message: string\n readonly source?: string\n readonly path?: string\n readonly details?: Readonly<Record<string, unknown>>\n },\n): FunctionalCoreError => {\n return createFunctionalError(\"plan\", {\n code,\n message: error.message,\n source: error.source,\n path: error.path,\n details: error.details,\n })\n}\n","import { createHash } from \"crypto\"\nimport type { LayoutPlan, PlanNode } from \"./planner.ts\"\n\ntype EmitPlanInput = {\n readonly plan: LayoutPlan\n}\n\ntype CommandStepKind = \"split\" | \"focus\"\n\nexport type CommandStep = {\n readonly id: string\n readonly kind: CommandStepKind\n readonly command: ReadonlyArray<string>\n readonly summary: string\n readonly targetPaneId?: string\n readonly createdPaneId?: string\n}\n\nexport type EmittedTerminal = {\n readonly virtualPaneId: string\n readonly command?: string\n readonly cwd?: string\n readonly env?: Readonly<Record<string, string>>\n readonly focus: boolean\n readonly name: string\n}\n\ntype PlanEmissionSummary = {\n readonly stepsCount: number\n readonly focusPaneId: string\n readonly initialPaneId: string\n}\n\nexport type PlanEmission = {\n readonly steps: ReadonlyArray<CommandStep>\n readonly summary: PlanEmissionSummary\n readonly terminals: ReadonlyArray<EmittedTerminal>\n readonly hash: string\n}\n\ntype SplitNode = Extract<PlanNode, { kind: \"split\" }>\n\nexport const emitPlan = ({ plan }: EmitPlanInput): PlanEmission => {\n const steps: CommandStep[] = []\n collectSplitSteps(plan.root, steps)\n\n steps.push({\n id: `${plan.focusPaneId}:focus`,\n kind: \"focus\",\n command: [\"select-pane\", \"-t\", plan.focusPaneId],\n summary: `select pane ${plan.focusPaneId}`,\n targetPaneId: plan.focusPaneId,\n })\n\n const hash = createPlanHash(plan, steps)\n const initialPaneId = determineInitialPaneId(plan.root)\n const terminals = collectTerminals(plan.root)\n\n return {\n steps,\n summary: {\n stepsCount: steps.length,\n focusPaneId: plan.focusPaneId,\n initialPaneId,\n },\n terminals,\n hash,\n }\n}\n\nconst collectSplitSteps = (node: PlanNode, steps: CommandStep[]): void => {\n if (node.kind === \"terminal\") {\n return\n }\n\n appendSplitSteps(node, steps)\n node.panes.forEach((pane) => collectSplitSteps(pane, steps))\n}\n\nconst appendSplitSteps = (node: SplitNode, steps: CommandStep[]): void => {\n const directionFlag = node.orientation === \"horizontal\" ? \"-h\" : \"-v\"\n\n for (let index = 1; index < node.panes.length; index += 1) {\n const remainingIncludingTarget = node.ratio.slice(index - 1).reduce((sum, value) => sum + value, 0)\n const remainingAfterTarget = node.ratio.slice(index).reduce((sum, value) => sum + value, 0)\n\n const desiredPercentage =\n remainingIncludingTarget === 0 ? 0 : (remainingAfterTarget / remainingIncludingTarget) * 100\n const percentage = Math.max(1, Math.round(desiredPercentage))\n const targetPaneId = node.panes[index - 1]?.id ?? node.id\n const createdPaneId = node.panes[index]?.id\n\n steps.push({\n id: `${node.id}:split:${index}`,\n kind: \"split\",\n command: [\"split-window\", directionFlag, \"-t\", targetPaneId, \"-p\", String(Math.min(percentage, 99))],\n summary: `split ${targetPaneId} (${directionFlag})`,\n targetPaneId,\n createdPaneId,\n })\n }\n}\n\nconst collectTerminals = (node: PlanNode): EmittedTerminal[] => {\n if (node.kind === \"terminal\") {\n return [\n {\n virtualPaneId: node.id,\n command: node.command,\n cwd: node.cwd,\n env: node.env,\n focus: node.focus,\n name: node.name,\n },\n ]\n }\n\n return node.panes.flatMap((pane) => collectTerminals(pane))\n}\n\nconst determineInitialPaneId = (node: PlanNode): string => {\n if (node.kind === \"terminal\") {\n return node.id\n }\n\n let current: PlanNode = node\n while (current.kind === \"split\") {\n current = current.panes[0]!\n }\n return current.id\n}\n\nconst createPlanHash = (plan: LayoutPlan, steps: ReadonlyArray<CommandStep>): string => {\n const digest = createHash(\"sha256\")\n const normalized = {\n focusPaneId: plan.focusPaneId,\n root: plan.root,\n steps,\n }\n digest.update(JSON.stringify(normalized))\n return digest.digest(\"hex\")\n}\n","import { Command } from \"commander\"\nimport chalk from \"chalk\"\nimport { stringify as toYAML } from \"yaml\"\nimport { createRequire } from \"module\"\nimport { createPresetManager } from \"./layout/preset.ts\"\nimport { resolveWindowMode } from \"./cli/window-mode.ts\"\nimport { createPaneKillPrompter } from \"./cli/user-prompt.ts\"\nimport type { Preset, PresetInfo, WindowMode } from \"./models/types\"\nimport type { CommandExecutor } from \"./types/command-executor.ts\"\nimport type { PresetManager } from \"./types/preset-manager.ts\"\nimport { createRealExecutor, createDryRunExecutor } from \"./executor/index.ts\"\nimport { executePlan } from \"./executor/plan-runner.ts\"\nimport { createLogger, LogLevel, type Logger } from \"./utils/logger.ts\"\nimport {\n runDiagnostics,\n compilePreset as defaultCompilePreset,\n createLayoutPlan as defaultCreateLayoutPlan,\n emitPlan as defaultEmitPlan,\n} from \"./core/index.ts\"\nimport type {\n DiagnosticsReport,\n DiagnosticsSeverity,\n CompilePresetInput,\n PlanEmission,\n FunctionalCoreError,\n CompilePresetSuccess,\n CreateLayoutPlanSuccess,\n} from \"./core/index.ts\"\nimport { isFunctionalCoreError } from \"./core/index.ts\"\n\nconst KNOWN_ISSUES: ReadonlyArray<string> = [\n \"LayoutEngineがtmux依存とI/Oを同一クラスで扱っている\",\n \"dry-run実行と本番適用でPlan構造が共有されていない\",\n \"Loggerが境界層とFunctional Coreの責務を混在させている\",\n]\n\nconst formatSeverityTag = (severity: DiagnosticsSeverity): string => {\n switch (severity) {\n case \"high\":\n return chalk.red(\"[HIGH]\")\n case \"medium\":\n return chalk.yellow(\"[MEDIUM]\")\n case \"low\":\n default:\n return chalk.blue(\"[LOW]\")\n }\n}\n\nexport type FunctionalCoreBridge = {\n readonly compilePreset: (input: CompilePresetInput) => ReturnType<typeof defaultCompilePreset>\n readonly createLayoutPlan: (\n input: Parameters<typeof defaultCreateLayoutPlan>[0],\n ) => ReturnType<typeof defaultCreateLayoutPlan>\n readonly emitPlan: (input: Parameters<typeof defaultEmitPlan>[0]) => ReturnType<typeof defaultEmitPlan>\n}\n\nexport type CLIOptions = {\n readonly presetManager?: PresetManager\n readonly createCommandExecutor?: (options: { verbose: boolean; dryRun: boolean }) => CommandExecutor\n readonly functionalCore?: FunctionalCoreBridge\n}\n\nexport type CLI = {\n run(args?: string[]): Promise<void>\n}\n\nexport const createCli = (options: CLIOptions = {}): CLI => {\n const presetManager = options.presetManager ?? createPresetManager()\n const createCommandExecutor =\n options.createCommandExecutor ??\n ((opts: { verbose: boolean; dryRun: boolean }): CommandExecutor => {\n if (opts.dryRun) {\n return createDryRunExecutor({ verbose: opts.verbose })\n }\n return createRealExecutor({ verbose: opts.verbose })\n })\n\n const functionalCore: FunctionalCoreBridge =\n options.functionalCore ??\n ({\n compilePreset: defaultCompilePreset,\n createLayoutPlan: defaultCreateLayoutPlan,\n emitPlan: defaultEmitPlan,\n } as const)\n\n const program = new Command()\n const require = createRequire(import.meta.url)\n const { version } = require(\"../package.json\") as { version: string }\n let logger: Logger = createLogger()\n\n const renderDiagnosticsReport = (report: DiagnosticsReport): void => {\n console.log(chalk.bold(\"\\nFunctional Core Diagnostics\\n\"))\n\n if (report.backlog.length > 0) {\n console.log(chalk.bold(\"改善バックログ\"))\n report.backlog.forEach((item, index) => {\n const prefix = `${index + 1}. ${formatSeverityTag(item.severity)}`\n console.log(`${prefix} ${item.summary}`)\n item.actions.forEach((action) => {\n console.log(` - ${action}`)\n })\n })\n console.log(\"\")\n }\n\n if (report.findings.length > 0) {\n console.log(chalk.bold(\"診断結果\"))\n report.findings.forEach((finding) => {\n console.log(`${formatSeverityTag(finding.severity)} ${finding.path} :: ${finding.description}`)\n })\n console.log(\"\")\n }\n\n if (report.nextSteps.length > 0) {\n console.log(chalk.bold(\"次のアクション\"))\n report.nextSteps.forEach((step) => {\n console.log(` - ${step}`)\n })\n console.log(\"\")\n }\n }\n\n const renderDryRun = (emission: PlanEmission): void => {\n console.log(chalk.bold(\"\\nPlanned tmux steps (dry-run)\"))\n emission.steps.forEach((step, index) => {\n const commandString = step.command.join(\" \")\n console.log(` ${index + 1}. ${step.summary}: tmux ${commandString}`)\n })\n }\n\n const buildPresetDocument = (preset: Preset, presetName?: string): string => {\n const document: Record<string, unknown> = {\n name: preset.name ?? presetName ?? \"vde-layout\",\n command: preset.command,\n layout: preset.layout,\n }\n\n if (typeof preset.command !== \"string\" || preset.command.length === 0) {\n delete document.command\n }\n\n if (preset.layout === undefined || preset.layout === null) {\n delete document.layout\n }\n\n return toYAML(document)\n }\n\n const buildPresetSource = (presetName?: string): string => {\n return typeof presetName === \"string\" && presetName.length > 0 ? `preset://${presetName}` : \"preset://default\"\n }\n\n const determineCliWindowMode = (options: {\n currentWindow?: boolean\n newWindow?: boolean\n }): WindowMode | undefined => {\n if (options.currentWindow === true && options.newWindow === true) {\n throw new Error(\"Cannot use --current-window and --new-window at the same time\")\n }\n\n if (options.currentWindow === true) {\n return \"current-window\"\n }\n\n if (options.newWindow === true) {\n return \"new-window\"\n }\n\n return undefined\n }\n\n const handleFunctionalError = (error: FunctionalCoreError): never => {\n const header = [`[${error.kind}]`, `[${error.code}]`]\n if (typeof error.path === \"string\" && error.path.length > 0) {\n header.push(`[${error.path}]`)\n }\n\n const lines = [`${header.join(\" \")} ${error.message}`.trim()]\n\n if (typeof error.source === \"string\" && error.source.length > 0) {\n lines.push(`source: ${error.source}`)\n }\n\n const commandDetail = error.details?.command\n if (Array.isArray(commandDetail)) {\n const tmuxCommand = commandDetail.filter((segment): segment is string => typeof segment === \"string\")\n if (tmuxCommand.length > 0) {\n lines.push(`command: tmux ${tmuxCommand.join(\" \")}`)\n }\n } else if (typeof commandDetail === \"string\" && commandDetail.length > 0) {\n lines.push(`command: ${commandDetail}`)\n }\n\n const stderrDetail = error.details?.stderr\n if (typeof stderrDetail === \"string\" && stderrDetail.length > 0) {\n lines.push(`stderr: ${stderrDetail}`)\n } else if (stderrDetail !== undefined) {\n lines.push(`stderr: ${String(stderrDetail)}`)\n }\n\n logger.error(lines.join(\"\\n\"))\n process.exit(1)\n }\n\n const handleError = (error: unknown): never => {\n if (error instanceof Error) {\n logger.error(error.message, error)\n } else {\n logger.error(\"An unexpected error occurred\")\n }\n\n process.exit(1)\n }\n\n const handlePipelineFailure = (error: unknown): never => {\n if (isFunctionalCoreError(error)) {\n return handleFunctionalError(error)\n }\n return handleError(error)\n }\n\n const listPresets = async (): Promise<never> => {\n try {\n await presetManager.loadConfig()\n const presets = presetManager.listPresets()\n\n if (presets.length === 0) {\n logger.warn(\"No presets defined\")\n process.exit(0)\n }\n\n console.log(chalk.bold(\"Available presets:\\n\"))\n\n const maxKeyLength = Math.max(...presets.map((p) => p.key.length))\n\n presets.forEach((preset: PresetInfo) => {\n const paddedKey = preset.key.padEnd(maxKeyLength + 2)\n const description = preset.description ?? \"\"\n console.log(` ${chalk.cyan(paddedKey)} ${description}`)\n })\n\n process.exit(0)\n } catch (error) {\n return handleError(error)\n }\n }\n\n const diagnosePreset = async (presetName: string | undefined): Promise<never> => {\n try {\n await presetManager.loadConfig()\n const preset =\n typeof presetName === \"string\" && presetName.length > 0\n ? presetManager.getPreset(presetName)\n : presetManager.getDefaultPreset()\n\n const presetDocument = toYAML(preset ?? {})\n const report = runDiagnostics({\n presetDocument,\n knownIssues: KNOWN_ISSUES,\n })\n\n renderDiagnosticsReport(report)\n process.exit(0)\n } catch (error) {\n return handleError(error)\n }\n }\n\n const executePreset = async (\n presetName: string | undefined,\n options: { verbose: boolean; dryRun: boolean; currentWindow: boolean; newWindow: boolean },\n ): Promise<never> => {\n try {\n await presetManager.loadConfig()\n\n const preset =\n typeof presetName === \"string\" && presetName.length > 0\n ? presetManager.getPreset(presetName)\n : presetManager.getDefaultPreset()\n\n const cliWindowMode = determineCliWindowMode({\n currentWindow: options.currentWindow,\n newWindow: options.newWindow,\n })\n const defaults = presetManager.getDefaults()\n const windowModeResolution = resolveWindowMode({\n cli: cliWindowMode,\n preset: preset.windowMode,\n defaults: defaults?.windowMode,\n })\n const windowMode = windowModeResolution.mode\n logger.info(`Window mode: ${windowMode} (source: ${windowModeResolution.source})`)\n const confirmPaneClosure = createPaneKillPrompter(logger)\n\n const tmuxEnv = process.env.TMUX\n const insideTmux = typeof tmuxEnv === \"string\" && tmuxEnv.length > 0\n if (!insideTmux && options.dryRun !== true) {\n throw new Error(\"Must be run inside a tmux session\")\n }\n\n const executor = createCommandExecutor({\n verbose: options.verbose,\n dryRun: options.dryRun,\n })\n\n if (options.dryRun === true) {\n console.log(\"[DRY RUN] No actual commands will be executed\")\n }\n\n let compileResult: CompilePresetSuccess\n let planResult: CreateLayoutPlanSuccess\n let emission: PlanEmission\n\n try {\n compileResult = functionalCore.compilePreset({\n document: buildPresetDocument(preset, presetName),\n source: buildPresetSource(presetName),\n })\n planResult = functionalCore.createLayoutPlan({ preset: compileResult.preset })\n emission = functionalCore.emitPlan({ plan: planResult.plan })\n } catch (error) {\n return handlePipelineFailure(error)\n }\n\n if (options.dryRun === true) {\n renderDryRun(emission)\n } else {\n try {\n const executionResult = await executePlan({\n emission,\n executor,\n windowName: preset.name ?? presetName ?? \"vde-layout\",\n windowMode,\n onConfirmKill: confirmPaneClosure,\n })\n logger.info(`Executed ${executionResult.executedSteps} tmux steps`)\n } catch (error) {\n return handlePipelineFailure(error)\n }\n }\n\n logger.success(`✓ Applied preset \"${preset.name}\"`)\n process.exit(0)\n } catch (error) {\n return handleError(error)\n }\n }\n\n const setupProgram = (): void => {\n program\n .name(\"vde-layout\")\n .description(\"VDE (Vibrant Development Environment) Layout Manager - tmux pane layout management tool\")\n .version(version, \"-v, --version\", \"Show version\")\n .helpOption(\"-h, --help\", \"Show help\")\n\n program.option(\"--verbose\", \"Show detailed logs\", false)\n program.option(\"-V\", \"Show version (deprecated; use -v)\")\n program.option(\"--dry-run\", \"Display commands without executing\", false)\n program.option(\"--config <path>\", \"Path to configuration file\")\n program.option(\"--current-window\", \"Use the current tmux window for layout (kills other panes)\", false)\n program.option(\"--new-window\", \"Always create a new tmux window for layout\", false)\n\n program\n .command(\"list\")\n .description(\"List available presets\")\n .action(async () => {\n await listPresets()\n })\n\n program\n .command(\"diagnose\")\n .description(\"Functional Coreリライトに向けた診断レポートを表示する\")\n .argument(\"[preset]\", 'Preset name (defaults to \"default\" preset when omitted)')\n .action(async (presetName?: string) => {\n await diagnosePreset(presetName)\n })\n\n program\n .argument(\"[preset]\", 'Preset name (defaults to \"default\" preset when omitted)')\n .action(async (presetName?: string) => {\n const opts = program.opts<{\n verbose?: boolean\n dryRun?: boolean\n currentWindow?: boolean\n newWindow?: boolean\n }>()\n await executePreset(presetName, {\n verbose: opts.verbose === true,\n dryRun: opts.dryRun === true,\n currentWindow: opts.currentWindow === true,\n newWindow: opts.newWindow === true,\n })\n })\n }\n\n setupProgram()\n\n const run = async (args: string[] = process.argv.slice(2)): Promise<void> => {\n if (args.includes(\"-V\")) {\n console.log(version)\n return\n }\n\n const requestedVersion = args.some((arg) => arg === \"--version\" || arg === \"-v\")\n const requestedHelp = args.includes(\"--help\") || args.includes(\"-h\")\n try {\n await program.parseAsync(args, { from: \"user\" })\n const opts = program.opts<{\n verbose?: boolean\n config?: string\n V?: boolean\n currentWindow?: boolean\n newWindow?: boolean\n }>()\n\n if (requestedVersion || requestedHelp) {\n return\n }\n\n if (opts.verbose === true) {\n logger = createLogger({ level: LogLevel.INFO })\n } else {\n logger = createLogger()\n }\n\n if (\n typeof opts.config === \"string\" &&\n opts.config.length > 0 &&\n typeof presetManager.setConfigPath === \"function\"\n ) {\n presetManager.setConfigPath(opts.config)\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"Process exited\")) {\n throw error\n }\n handleError(error)\n }\n }\n\n return { run }\n}\n","#!/usr/bin/env node\nimport { createCli } from \"./cli.ts\"\n\n/**\n * Main entry point\n * Launches the CLI application\n */\nconst main = async (): Promise<void> => {\n const cli = createCli()\n try {\n // Pass arguments excluding the first two elements (node, script path) from process.argv\n await cli.run(process.argv.slice(2))\n } catch (error) {\n // Format and display error message appropriately\n if (error instanceof Error) {\n console.error(\"Error:\", error.message)\n\n // Also display stack trace in debug mode\n if (process.env.VDE_DEBUG === \"true\") {\n console.error(error.stack)\n }\n } else {\n console.error(\"An unexpected error occurred:\", String(error))\n }\n\n process.exit(1)\n }\n}\n\n// Execute immediately\nvoid main()\n"],"mappings":"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"}
|