octomux 1.0.30 → 1.0.32

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.
Files changed (65) hide show
  1. package/README.md +50 -14
  2. package/bin/octomux.js +33 -2
  3. package/cli/dist/client.js +15 -0
  4. package/cli/dist/commands/add-agent.js +9 -0
  5. package/cli/dist/commands/create-task.js +4 -0
  6. package/cli/dist/commands/team.js +60 -0
  7. package/cli/dist/index.js +2 -0
  8. package/dist/assets/{AgentEditor-C-55HShP.js → AgentEditor-bmu3IToQ.js} +1 -1
  9. package/dist/assets/ChatPage-DoNLt9yc.js +2 -0
  10. package/dist/assets/{IntegrationsPage-ChleYO1n.js → IntegrationsPage-D3iTxzhN.js} +1 -1
  11. package/dist/assets/ReviewDetailPage-DxCK8Zq4.js +1 -0
  12. package/dist/assets/{SetupPage-Cdr8AEDl.js → SetupPage-CJYmbm6K.js} +1 -1
  13. package/dist/assets/SkillEditor-BXV-a19B.js +1 -0
  14. package/dist/assets/{WorkspaceDetailPage-BA4KkTu6.js → WorkspaceDetailPage-Cns6VZKt.js} +1 -1
  15. package/dist/assets/WorkspacesPage-DI_Ilx7o.js +1 -0
  16. package/dist/assets/index-D2mLE9DX.css +1 -0
  17. package/dist/assets/index-DKTtIYvz.js +35 -0
  18. package/dist/index.html +6 -3
  19. package/dist-server/{agents-7NORWYDI.js → agents-XWAPBJ6K.js} +1 -1
  20. package/dist-server/chunk-34KJHQCF.js +1 -0
  21. package/dist-server/chunk-5XTSTJXV.js +2 -0
  22. package/dist-server/{chunk-RGKFIAYK.js → chunk-6WY5EP6F.js} +1 -1
  23. package/dist-server/chunk-72XPVTY6.js +16 -0
  24. package/dist-server/chunk-BYZCD2AS.js +16 -0
  25. package/dist-server/{chunk-UZUF5CZR.js → chunk-F5R6D6FU.js} +1 -1
  26. package/dist-server/chunk-G45FZHCE.js +1 -0
  27. package/dist-server/chunk-GAXJZSQT.js +2 -0
  28. package/dist-server/chunk-O2SQP4SR.js +1 -0
  29. package/dist-server/{chunk-WFZH7745.js → chunk-PBZCZYAH.js} +1 -1
  30. package/dist-server/chunk-RB2T3IO7.js +49 -0
  31. package/dist-server/{chunk-6RXAD73K.js → chunk-RHMOEXMR.js} +29 -8
  32. package/dist-server/chunk-YMZYMBMF.js +23 -0
  33. package/dist-server/{chunk-GBD6IX6H.js → chunk-YUNRZQSW.js} +1 -1
  34. package/dist-server/claude-code-FPRNRVIA.js +1 -0
  35. package/dist-server/harnesses-ZAGCSSES.js +1 -0
  36. package/dist-server/hook-settings-BSWHE3FL.js +1 -0
  37. package/dist-server/index.js +101 -124
  38. package/dist-server/{preflight-7M4CZVOF.js → preflight-KHWEEL74.js} +1 -1
  39. package/dist-server/{publish-review-7GG3AEZI.js → publish-review-TFPK32KX.js} +1 -1
  40. package/dist-server/{settings-EYM2VUM7.js → settings-2RRBPIQP.js} +1 -1
  41. package/dist-server/setup-status-LKN6RF2T.js +1 -0
  42. package/dist-server/startup.js +1 -1
  43. package/dist-server/store-VYXJD5ZW.js +1 -0
  44. package/dist-server/teams-QXITPB5J.js +22 -0
  45. package/package.json +19 -3
  46. package/scripts/build-tmux.sh +226 -0
  47. package/scripts/postinstall.sh +2 -2
  48. package/scripts/verify-mobile-terminal-scroll.ts +212 -0
  49. package/skills/review-orchestrator/SKILL.md +14 -1
  50. package/dist/assets/ChatPage-2n4U1InI.js +0 -2
  51. package/dist/assets/ReviewDetailPage-DgrEGANy.js +0 -1
  52. package/dist/assets/SkillEditor-Br3LMps4.js +0 -1
  53. package/dist/assets/WorkspacesPage-CEmv-ObL.js +0 -1
  54. package/dist/assets/index-CghBwA2d.js +0 -35
  55. package/dist/assets/index-D1KcUNra.css +0 -1
  56. package/dist-server/chunk-5TX2AE6V.js +0 -2
  57. package/dist-server/chunk-JJNLZ7U4.js +0 -2
  58. package/dist-server/chunk-PE6WB7WG.js +0 -36
  59. package/dist-server/chunk-WSL26W3H.js +0 -16
  60. package/dist-server/chunk-XMCSUNYM.js +0 -1
  61. package/dist-server/claude-code-H6WHSYXB.js +0 -1
  62. package/dist-server/harnesses-DH3SOF4F.js +0 -1
  63. package/dist-server/hook-settings-ENUKEL6E.js +0 -1
  64. package/dist-server/setup-status-SRJSWBUH.js +0 -1
  65. package/dist-server/store-6VCU4ZDL.js +0 -1
package/README.md CHANGED
@@ -14,12 +14,14 @@ npm install -g octomux && octomux init && cd your-repo && octomux start
14
14
 
15
15
  Open [http://localhost:7777](http://localhost:7777) — describe a task in the composer, pick **Claude Code** or **Cursor**, and watch agents work in place.
16
16
 
17
+ ![octomux demo](assets/demo.gif)
18
+
17
19
  ## From prompt to merged PR
18
20
 
19
21
  Three phases, one window:
20
22
 
21
- - **01 — Dispatch.** Type a task. Pick Claude Code or Cursor. Hit go. The composer takes plain English, Jira links, or GitHub issue URLs. Drop a second agent on the same branch with one click.
22
- - **02 — Watch.** See every agent work, live. Each task streams its own view — files the agent is editing, the diff as it grows, terminal output as it runs. When an agent needs permission, the prompt lands in your inbox so you don't have to babysit every pane.
23
+ - **01 — Dispatch.** Type a task. Pick Claude Code or Cursor. Hit go. The composer takes plain English, Jira links, or GitHub issue URLs. Drop a second agent on the same branch with one click — or paste a whole list and **bulk-create** a worktree, branch, and agent for each.
24
+ - **02 — Watch.** See every agent work, live. Each task streams its own view — files the agent is editing, the diff as it grows, terminal output as it runs. The **Monitor** view tiles every running agent into one grid so you can scan the whole fleet at a glance. When an agent needs permission, the prompt lands in your inbox so you don't have to babysit every pane.
23
25
  - **03 — Review & Ship.** Diff review in the same window. File tree, per-file reviewed state, inline comments. Hit **Ship** and the PR auto-links to the task — closes itself when the PR merges.
24
26
 
25
27
  Code never leaves your laptop. No telemetry, no cloud sync. Crash, reboot, close the lid — `octomux start` restores every task, branch, and session.
@@ -37,12 +39,16 @@ Code never leaves your laptop. No telemetry, no cloud sync. Crash, reboot, close
37
39
  ## Features
38
40
 
39
41
  - **Sessions inbox** — every permission prompt and question lands in one place; reply once, agents keep going. Tab title shows `(N) octomux` when something needs you.
40
- - **Command center** — kanban for backlog → done; drag status, archive, workflow from draft → ship.
42
+ - **Command center** — kanban for backlog → done; drag status, archive, workflow from draft → ship. Empty board? A first-run guide shows you where to start.
43
+ - **Monitor grid** — every running agent tiled into one auto-sized grid; scan the whole fleet's activity (active / idle / waiting) without opening each task.
44
+ - **Bulk dispatch** — paste a list of prompts or a GitHub issue list and spin up one task — worktree, branch, agent — per line in a single shot.
41
45
  - **In-app diff review** — compare to `main`, mark files reviewed, queue inline comments, open lazygit in-editor.
42
46
  - **Dual harnesses** — run **Claude Code** (`claude`) or **Cursor** (`cursor-agent`) per task; mix agents on one task via **Add agent**.
43
47
  - **Worktrees keep agents off each other** — each task gets its own git worktree and `agents/<task-id>` branch; five agents can edit `auth.ts` at the same time without conflicts on your main tree.
44
48
  - **Live task view** — see every agent work in real time: files edited, diff growing, terminal output streaming via xterm.js. Attach the same session from the CLI if you prefer.
45
49
  - **Agents that dispatch agents** — `/create-task`, `/list-tasks`, `/send-agent-message` skills work inside any Claude Code window; recursive dispatch from inside an agent.
50
+ - **Agent teams** — reusable crews defined as code in `<repo>/.octomux/team.yaml`: a lead spawns workers from a roster, each with its own model. Run on demand (`octomux team run`) or on a cron schedule.
51
+ - **Per-task model** — pin any task or added agent to a specific model (`--model claude-opus-4-8`); mix models across a fleet so the right one lands on each job.
46
52
  - **Integrations** — Jira wiring plus orchestrator skills for GitHub / auto-review intake.
47
53
  - **CLI ↔ dashboard parity** — `octomux create-task`, `send-message`, `resume-task` — same tasks the UI shows.
48
54
  - **Reboot-proof** — WAL SQLite + preserved worktrees across restarts.
@@ -104,16 +110,17 @@ DISPATCH → BRANCH → CODE → INBOX → REVIEW → MERGE
104
110
 
105
111
  ## CLI
106
112
 
107
- | Command | Description |
108
- | ------------------------------------ | -------------------------------------------------------- |
109
- | `octomux start` | Dashboard at `:7777` |
110
- | `octomux init` | Defaults wizard (Jira, base branch, harness prefs) |
111
- | `octomux create-task` | New task (`--harness cursor` optional) |
112
- | `octomux list-tasks` / `get-task` | Inspect tasks |
113
- | `octomux close-task` / `delete-task` | Stop or fully remove |
114
- | `octomux resume-task` | Resume a closed task |
115
- | `octomux add-agent` | Another agent window |
116
- | `octomux send-message` | Message a running agent — course-correct without restart |
113
+ | Command | Description |
114
+ | ---------------------------------------- | -------------------------------------------------------- |
115
+ | `octomux start` | Dashboard at `:7777` |
116
+ | `octomux init` | Defaults wizard (Jira, base branch, harness prefs) |
117
+ | `octomux create-task` | New task (`--harness cursor` optional) |
118
+ | `octomux list-tasks` / `get-task` | Inspect tasks |
119
+ | `octomux close-task` / `delete-task` | Stop or fully remove |
120
+ | `octomux resume-task` | Resume a closed task |
121
+ | `octomux add-agent` | Another agent window (`--skeleton`, `--model` optional) |
122
+ | `octomux send-message` | Message a running agent — course-correct without restart |
123
+ | `octomux team run` / `schedule` / `list` | Run or schedule an agent crew from `.octomux/team.yaml` |
117
124
 
118
125
  ## Architecture
119
126
 
@@ -148,11 +155,13 @@ flowchart LR
148
155
 
149
156
  ## Requirements
150
157
 
151
- - macOS (ARM64 or x64), Node.js 20+
158
+ - macOS (ARM64 or x64), Node.js 20+ (24 LTS recommended)
152
159
  - `tmux`, `git`
153
160
  - At least one harness: **Claude Code** (`claude`) and/or **Cursor CLI** (`cursor-agent`)
154
161
  - Recommended: `lazygit`, `neovim`
155
162
 
163
+ > First run flags only the deps you're actually missing — install what the setup banner asks for and you're good. Jira and other integrations are configured later from the in-app **Integrations** page.
164
+
156
165
  ## Configuration
157
166
 
158
167
  | Variable / flag | Purpose |
@@ -162,6 +171,33 @@ flowchart LR
162
171
  | `OCTOMUX_DB_PATH` | Override task DB path |
163
172
  | `OCTOMUX_GITHUB_LOGIN` | Reviewer-request polling account |
164
173
 
174
+ ## Remote access over Tailscale
175
+
176
+ octomux binds to `127.0.0.1` by default — reachable only from the host machine. To view
177
+ and control sessions from your other devices (phone, second laptop), put them on a
178
+ [Tailscale](https://tailscale.com) tailnet and enable remote mode:
179
+
180
+ 1. Install Tailscale on the host and each device; run `tailscale up` on each. Enable
181
+ MagicDNS so the host is reachable by name.
182
+ 2. Start octomux in remote mode:
183
+ ```bash
184
+ octomux start --bind 0.0.0.0
185
+ # or: OCTOMUX_BIND=0.0.0.0 octomux start
186
+ ```
187
+ On first start a random access token is generated and its file path is logged
188
+ (`~/.octomux/data/remote-token`). Override it with `OCTOMUX_REMOTE_TOKEN=<secret>`.
189
+ 3. (Optional) Restrict the accepted `Host` header to your tailnet name:
190
+ `OCTOMUX_ALLOWED_HOSTS=mybox.your-tailnet.ts.net`. The `100.64.0.0/10` tailnet IP range
191
+ is accepted automatically.
192
+ 4. From a device on the tailnet, open `http://<host-magicdns-name>:7777` and sign in once
193
+ with the token. Local (loopback) access never requires the token.
194
+
195
+ **Security notes:** only devices on your tailnet can reach the port; the token is a second
196
+ factor so a single compromised tailnet device cannot silently drive your agents. Binding
197
+ `0.0.0.0` also exposes the port on any other LAN the host is on — the token gates those out,
198
+ and you can add a host firewall rule limiting port 7777 to the `100.64.0.0/10` range for
199
+ belt-and-suspenders. For HTTPS, front octomux with `tailscale serve`.
200
+
165
201
  ## FAQ
166
202
 
167
203
  **What's the difference between octomux and just running tmux + Claude Code?**
package/bin/octomux.js CHANGED
@@ -3,6 +3,7 @@
3
3
  import { execFileSync, exec as execCb } from 'child_process';
4
4
  import { readFileSync, existsSync, mkdirSync, readdirSync, cpSync, rmSync } from 'fs';
5
5
  import { fileURLToPath } from 'url';
6
+ import { createRequire } from 'module';
6
7
  import path from 'path';
7
8
  import os from 'os';
8
9
 
@@ -26,6 +27,24 @@ if (command === 'start') {
26
27
  await import('../cli/dist/index.js');
27
28
  }
28
29
 
30
+ // ─── tmux binary resolver ────────────────────────────────────────────────────
31
+ // Mirrors the resolution logic in server/tmux-bin.ts (kept in sync manually).
32
+ // Uses createRequire so the optional CJS package can be loaded from ESM context.
33
+
34
+ const _require = createRequire(import.meta.url);
35
+
36
+ function resolveTmuxBin() {
37
+ if (process.env.OCTOMUX_TMUX_BIN) return process.env.OCTOMUX_TMUX_BIN;
38
+ try {
39
+ const pkg = `@octomux/tmux-${process.platform}-${process.arch}`;
40
+ const { tmuxBin } = _require(pkg);
41
+ if (tmuxBin) return tmuxBin;
42
+ } catch {
43
+ /* not installed yet — fall back to PATH */
44
+ }
45
+ return 'tmux';
46
+ }
47
+
29
48
  // ─── start command ───────────────────────────────────────────────────────────
30
49
 
31
50
  async function runStart(startArgs) {
@@ -37,6 +56,9 @@ async function runStart(startArgs) {
37
56
  if (startArgs[i] === '--port' && startArgs[i + 1]) {
38
57
  port = parseInt(startArgs[i + 1], 10);
39
58
  i++;
59
+ } else if (startArgs[i] === '--bind' && startArgs[i + 1]) {
60
+ process.env.OCTOMUX_BIND = startArgs[i + 1];
61
+ i++;
40
62
  } else if (startArgs[i] === '--no-open') {
41
63
  autoOpen = false;
42
64
  }
@@ -58,8 +80,16 @@ async function runStart(startArgs) {
58
80
  // Preflight: warn about missing tools (install from dashboard Setup — no blocking exit)
59
81
  const { warnBinary, checkNeovimVersion } = await import('../dist-server/startup.js');
60
82
 
83
+ const resolvedTmux = resolveTmuxBin();
61
84
  const preflight = [
62
- { cmd: 'tmux', checkArgs: ['-V'], brewPkg: 'tmux' },
85
+ {
86
+ cmd: resolvedTmux,
87
+ checkArgs: ['-V'],
88
+ name: 'tmux',
89
+ // No brewPkg — tmux is bundled via @octomux/tmux-<platform>-<arch>.
90
+ // If the bundled package isn't available and PATH tmux is also missing,
91
+ // the bundled binary isn't available for this platform/arch and PATH tmux is also missing.
92
+ },
63
93
  { cmd: 'git', checkArgs: ['--version'], brewPkg: 'git' },
64
94
  {
65
95
  cmd: 'claude',
@@ -82,7 +112,8 @@ async function runStart(startArgs) {
82
112
  }
83
113
 
84
114
  checkNeovimVersion();
85
- console.log('Open Setup in the dashboard to install dependencies and configure defaults.\n');
115
+ console.log('Open Setup in the dashboard to install dependencies and configure defaults.');
116
+ console.log('Tip: use --bind 0.0.0.0 to enable remote access over Tailscale.\n');
86
117
 
87
118
  // Start server
88
119
  process.env.NODE_ENV = 'production';
@@ -135,5 +135,20 @@ export function createClient(serverUrl) {
135
135
  getTaskRefs(taskId) {
136
136
  return request(baseUrl, `/tasks/${encodeURIComponent(taskId)}/refs`);
137
137
  },
138
+ teamRun(data) {
139
+ return request(baseUrl, '/teams/run', {
140
+ method: 'POST',
141
+ body: JSON.stringify(data),
142
+ });
143
+ },
144
+ teamSchedule(data) {
145
+ return request(baseUrl, '/teams/schedule', {
146
+ method: 'POST',
147
+ body: JSON.stringify(data),
148
+ });
149
+ },
150
+ listTeams() {
151
+ return request(baseUrl, '/teams');
152
+ },
138
153
  };
139
154
  }
@@ -8,6 +8,9 @@ export function registerAddAgent(program) {
8
8
  .requiredOption('-p, --prompt <prompt>', 'initial prompt for the new agent')
9
9
  .option('-a, --agent <agent-type>', 'Claude Code agent type (e.g. code-reviewer)')
10
10
  .option('-l, --label <label>', 'label for the new agent (default: server-assigned "Agent N")')
11
+ .option('--model <id>', 'per-agent model override (e.g. claude-opus-4-8, claude-sonnet-4-6)')
12
+ .option('--skeleton <name>', 'role skeleton to load from <repo>/.octomux/agents/<name>.md')
13
+ .option('--notify-agent <agent-id>', 'agent ID to notify when this agent finishes')
11
14
  .action(async (opts, cmd) => {
12
15
  const { client, json } = getContext(cmd);
13
16
  const payload = {
@@ -17,6 +20,12 @@ export function registerAddAgent(program) {
17
20
  payload.agent = opts.agent;
18
21
  if (opts.label)
19
22
  payload.label = opts.label;
23
+ if (opts.model)
24
+ payload.model = opts.model;
25
+ if (opts.skeleton)
26
+ payload.skeleton = opts.skeleton;
27
+ if (opts.notifyAgent)
28
+ payload.notify_agent_id = opts.notifyAgent;
20
29
  const agent = await client.addAgent(opts.task, payload);
21
30
  if (json) {
22
31
  outputJson(agent);
@@ -64,6 +64,8 @@ export function registerCreateTask(program) {
64
64
  .option('--fork-from <task-id>', 'fork from an existing new-mode task (sets base_branch to agents/<id>)')
65
65
  .option('--draft', 'create as draft without starting')
66
66
  .option('--harness <id>', 'coding agent (harness id): claude-code | cursor (default: server setting)')
67
+ .option('--model <id>', 'per-task model override (e.g. claude-opus-4-8, claude-sonnet-4-6)')
68
+ .option('--notify-task <id>', 'task ID to notify when this task finishes')
67
69
  .action(async (opts, cmd) => {
68
70
  const { client, json } = getContext(cmd);
69
71
  const mode = opts.mode;
@@ -136,6 +138,8 @@ export function registerCreateTask(program) {
136
138
  run_mode: mode,
137
139
  worktree_path: opts.worktreePath,
138
140
  ...(opts.harness ? { harness_id: opts.harness } : {}),
141
+ ...(opts.model ? { model: opts.model } : {}),
142
+ ...(opts.notifyTask ? { notify_task_id: opts.notifyTask } : {}),
139
143
  });
140
144
  if (json) {
141
145
  outputJson(task);
@@ -0,0 +1,60 @@
1
+ import chalk from 'chalk';
2
+ import { getContext } from '../action.js';
3
+ import { outputJson, success, label, heading } from '../format.js';
4
+ async function runTeamRun(name, opts, cmd) {
5
+ const { client, json } = getContext(cmd);
6
+ const repoPath = opts.repo ?? process.cwd();
7
+ const result = await client.teamRun({ name, repo_path: repoPath });
8
+ if (json) {
9
+ outputJson(result);
10
+ return;
11
+ }
12
+ success(`Started team run: ${name}`);
13
+ console.log(label('Lead task', result.task_id));
14
+ }
15
+ async function runTeamSchedule(name, opts, cmd) {
16
+ const { client, json } = getContext(cmd);
17
+ const repoPath = opts.repo ?? process.cwd();
18
+ await client.teamSchedule({ name, repo_path: repoPath, cron: opts.cron });
19
+ if (json) {
20
+ outputJson({ ok: true });
21
+ return;
22
+ }
23
+ success(`Scheduled team: ${name}`);
24
+ console.log(label('Cron', opts.cron));
25
+ console.log(label('Repo', repoPath));
26
+ }
27
+ async function runTeamList(opts, cmd) {
28
+ const { client, json } = getContext(cmd);
29
+ const schedules = await client.listTeams();
30
+ if (json) {
31
+ outputJson(schedules);
32
+ return;
33
+ }
34
+ if (!schedules || schedules.length === 0) {
35
+ console.log(chalk.dim('No team schedules configured.'));
36
+ return;
37
+ }
38
+ heading('Team Schedules');
39
+ for (const s of schedules) {
40
+ console.log(` ${chalk.bold(s.name)} ${chalk.dim(s.cron)} last: ${s.last_run_at ?? chalk.dim('never')}`);
41
+ }
42
+ }
43
+ export function registerTeam(program) {
44
+ const team = program.command('team').description('Manage reusable agent desk teams');
45
+ team
46
+ .command('run <name>')
47
+ .description('Run a team immediately from .octomux/team.yaml')
48
+ .option('-r, --repo <path>', 'path to the target repo (default: cwd)')
49
+ .action((name, opts, cmd) => runTeamRun(name, opts, cmd));
50
+ team
51
+ .command('schedule <name>')
52
+ .description('Upsert a cron schedule for a team')
53
+ .requiredOption('--cron <expr>', 'cron expression, e.g. "0 7 * * *"')
54
+ .option('-r, --repo <path>', 'path to the target repo (default: cwd)')
55
+ .action((name, opts, cmd) => runTeamSchedule(name, opts, cmd));
56
+ team
57
+ .command('list')
58
+ .description('List configured team schedules')
59
+ .action((opts, cmd) => runTeamList(opts, cmd));
60
+ }
package/cli/dist/index.js CHANGED
@@ -28,6 +28,7 @@ import { registerHooksInstall } from './commands/hooks-install.js';
28
28
  import { registerHooksList } from './commands/hooks-list.js';
29
29
  import { registerListIntegrations } from './commands/list-integrations.js';
30
30
  import { registerInit } from './commands/init.js';
31
+ import { registerTeam } from './commands/team.js';
31
32
  const program = new Command();
32
33
  program
33
34
  .name('octomux')
@@ -61,6 +62,7 @@ registerHooksInstall(program);
61
62
  registerHooksList(program);
62
63
  registerListIntegrations(program);
63
64
  registerInit(program);
65
+ registerTeam(program);
64
66
  program.hook('preAction', (thisCommand) => {
65
67
  const opts = thisCommand.optsWithGlobals();
66
68
  const client = createClient(opts.serverUrl);
@@ -1 +1 @@
1
- import{b as a,j as e}from"./vendor-react-Dd26lTa7.js";import{j as m,s as f}from"./index-CghBwA2d.js";import{c as E,b as R}from"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";function $(){const{name:t}=E(),u=R(),[l,d]=a.useState(""),[c,v]=a.useState(""),[h,x]=a.useState(!1),[j,b]=a.useState(!0),[p,N]=a.useState(null),[o,g]=a.useState(!1),i=a.useRef(""),n=l!==i.current;a.useEffect(()=>{if(!t)return;let s=!1;return m.getAgent(t).then(r=>{s||(d(r.content),v(r.defaultContent),x(r.isCustom),i.current=r.content)}).catch(r=>{s||N(r.message)}).finally(()=>{s||b(!1)}),()=>{s=!0}},[t]);const C=a.useCallback(async()=>{if(!(!t||!n||o)){g(!0);try{await m.saveAgent(t,l),i.current=l,x(!0),f("success","SAVED",`Agent "${t}" saved`)}catch(s){f("error","ERROR",s instanceof Error?s.message:"Failed to save")}finally{g(!1)}}},[t,l,n,o]),y=a.useCallback(async()=>{if(t&&window.confirm(`Reset "${t}" to default? Your customizations will be lost.`))try{await m.resetAgent(t),d(c),i.current=c,x(!1),f("success","RESET",`Agent "${t}" reset to default`)}catch(s){f("error","ERROR",s instanceof Error?s.message:"Failed to reset")}},[t,c]),w=a.useCallback(()=>{n&&!window.confirm("You have unsaved changes. Discard them?")||u("/settings")},[n,u]);return j?e.jsx("div",{className:"flex h-full items-center justify-center",children:e.jsx("span",{className:"text-[#6a6a6a]",children:"Loading..."})}):p?e.jsxs("div",{className:"flex h-full flex-col items-center justify-center gap-3",children:[e.jsx("p",{className:"text-red-400",children:p}),e.jsx("button",{onClick:()=>u("/settings"),className:"text-xs text-[#3B82F6] hover:underline",children:"Back to Settings"})]}):e.jsxs("div",{className:"flex h-full flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-[#2f2f2f] px-6 py-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{onClick:w,className:"text-sm text-[#6a6a6a] hover:text-white",children:"←"}),e.jsx("span",{className:"font-mono text-lg font-bold",children:t}),h&&e.jsx("span",{className:"text-xs text-[#FFB800]",children:"custom"}),n&&e.jsx("span",{className:"text-xs text-[#FFB800]",children:"unsaved"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[h&&c&&e.jsx("button",{onClick:y,className:"px-3 py-2 text-xs text-red-400 hover:text-red-300",children:"Reset to Default"}),e.jsx("button",{onClick:C,disabled:!n||o,className:"bg-[#3B82F6] px-4 py-2 text-xs text-white disabled:opacity-50",children:o?"Saving...":"Save"})]})]}),e.jsx("div",{className:"flex-1 p-6",children:e.jsx("textarea",{value:l,onChange:s=>d(s.target.value),className:"h-full min-h-[500px] w-full resize-none border border-[#2f2f2f] bg-[#0A0A0A] p-4 font-mono text-sm leading-relaxed text-white outline-none focus:border-[#3B82F6]",spellCheck:!1})})]})}export{$ as default};
1
+ import{b as a,j as e}from"./vendor-react-Dd26lTa7.js";import{p as m,x as f}from"./index-DKTtIYvz.js";import{c as E,b as R}from"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";function $(){const{name:t}=E(),u=R(),[l,d]=a.useState(""),[c,v]=a.useState(""),[h,x]=a.useState(!1),[b,j]=a.useState(!0),[p,N]=a.useState(null),[o,g]=a.useState(!1),i=a.useRef(""),n=l!==i.current;a.useEffect(()=>{if(!t)return;let s=!1;return m.getAgent(t).then(r=>{s||(d(r.content),v(r.defaultContent),x(r.isCustom),i.current=r.content)}).catch(r=>{s||N(r.message)}).finally(()=>{s||j(!1)}),()=>{s=!0}},[t]);const C=a.useCallback(async()=>{if(!(!t||!n||o)){g(!0);try{await m.saveAgent(t,l),i.current=l,x(!0),f("success","SAVED",`Agent "${t}" saved`)}catch(s){f("error","ERROR",s instanceof Error?s.message:"Failed to save")}finally{g(!1)}}},[t,l,n,o]),y=a.useCallback(async()=>{if(t&&window.confirm(`Reset "${t}" to default? Your customizations will be lost.`))try{await m.resetAgent(t),d(c),i.current=c,x(!1),f("success","RESET",`Agent "${t}" reset to default`)}catch(s){f("error","ERROR",s instanceof Error?s.message:"Failed to reset")}},[t,c]),w=a.useCallback(()=>{n&&!window.confirm("You have unsaved changes. Discard them?")||u("/settings")},[n,u]);return b?e.jsx("div",{className:"flex h-full items-center justify-center",children:e.jsx("span",{className:"text-[#6a6a6a]",children:"Loading..."})}):p?e.jsxs("div",{className:"flex h-full flex-col items-center justify-center gap-3",children:[e.jsx("p",{className:"text-red-400",children:p}),e.jsx("button",{onClick:()=>u("/settings"),className:"text-xs text-[#3B82F6] hover:underline",children:"Back to Settings"})]}):e.jsxs("div",{className:"flex h-full flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-[#2f2f2f] px-6 py-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{onClick:w,className:"text-sm text-[#6a6a6a] hover:text-white",children:"←"}),e.jsx("span",{className:"font-mono text-lg font-bold",children:t}),h&&e.jsx("span",{className:"text-xs text-[#FFB800]",children:"custom"}),n&&e.jsx("span",{className:"text-xs text-[#FFB800]",children:"unsaved"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[h&&c&&e.jsx("button",{onClick:y,className:"px-3 py-2 text-xs text-red-400 hover:text-red-300",children:"Reset to Default"}),e.jsx("button",{onClick:C,disabled:!n||o,className:"bg-[#3B82F6] px-4 py-2 text-xs text-white disabled:opacity-50",children:o?"Saving...":"Save"})]})]}),e.jsx("div",{className:"flex-1 p-6",children:e.jsx("textarea",{value:l,onChange:s=>d(s.target.value),className:"h-full min-h-[500px] w-full resize-none border border-[#2f2f2f] bg-[#0A0A0A] p-4 font-mono text-sm leading-relaxed text-white outline-none focus:border-[#3B82F6]",spellCheck:!1})})]})}export{$ as default};
@@ -0,0 +1,2 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-DKTtIYvz.js","assets/vendor-react-Dd26lTa7.js","assets/vendor-router-yJbofmar.js","assets/vendor-ui-ChI1tM4e.js","assets/vendor-xterm-DvXGiZvM.js","assets/vendor-xterm-DYP7pi_n.css","assets/vendor-monaco-CdNyTACs.js","assets/index-D2mLE9DX.css"])))=>i.map(i=>d[i]);
2
+ import{_ as c}from"./index-DKTtIYvz.js";import{b as r,j as e}from"./vendor-react-Dd26lTa7.js";import{c as m}from"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";const d=r.lazy(()=>c(()=>import("./index-DKTtIYvz.js").then(t=>t.o),__vite__mapDeps([0,1,2,3,4,5,6,7])).then(t=>({default:t.TerminalView})));function j(){const{id:t}=m(),[s,i]=r.useState(null),[l,o]=r.useState(null);return r.useEffect(()=>{if(!t)return;let n=!1;return fetch(`/api/chats/${t}`).then(a=>a.ok?a.json():Promise.reject(new Error(`${a.status}`))).then(a=>{n||i(a)}).catch(a=>{n||o(a.message)}),()=>{n=!0}},[t]),l?e.jsxs("div",{className:"flex h-full items-center justify-center text-[#6a6a6a]",children:["Chat not found (",l,")"]}):s?e.jsxs("div",{className:"octomux-agent-session flex h-full min-h-0 flex-col overflow-hidden",children:[e.jsxs("div",{className:"flex shrink-0 items-center gap-2 border-b border-border px-4 py-2 md:gap-3 md:px-6 md:py-3",children:[e.jsx("span",{className:"text-[10px] font-bold uppercase tracking-wider text-[#6a6a6a]",children:"// CHAT"}),e.jsx("span",{className:"text-sm font-medium text-white",children:s.label}),s.agent&&e.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] font-mono",style:{backgroundColor:"rgba(245, 158, 11, 0.12)",borderColor:"rgba(245, 158, 11, 0.4)",color:"#F59E0B"},title:`Running as agent: ${s.agent}`,children:["🤖 ",s.agent]}),s.status==="running"&&e.jsx("span",{className:"h-2 w-2 animate-pulse bg-[#22C55E]"})]}),e.jsx("div",{className:"min-h-0 flex-1",children:e.jsx(r.Suspense,{fallback:e.jsx("div",{className:"flex h-full items-center justify-center text-[#6a6a6a]",children:"Loading terminal..."}),children:e.jsx(d,{wsUrl:`/ws/terminal/chat/${s.id}`,visible:!0})})})]}):e.jsx("div",{className:"flex h-full items-center justify-center text-[#6a6a6a]",children:"Loading..."})}export{j as default};
@@ -1 +1 @@
1
- import{b as r,j as e}from"./vendor-react-Dd26lTa7.js";import{a as B,j as u,g as $,S as J,R as H,s as O,h as X}from"./index-CghBwA2d.js";import"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";function Z({content:s,label:o="More information",className:m}){const x=r.useId(),[g,c]=r.useState(!1);return e.jsxs("span",{className:`relative inline-flex ${m??""}`,children:[e.jsx("button",{type:"button","aria-label":o,"aria-describedby":g?x:void 0,className:"focus-ring flex size-4 items-center justify-center rounded-full border border-glass-edge text-[10px] font-semibold leading-none text-[#8a8a8a] transition-colors hover:border-[#60a5fa] hover:text-[#60a5fa]",onMouseEnter:()=>c(!0),onMouseLeave:()=>c(!1),onFocus:()=>c(!0),onBlur:()=>c(!1),children:"i"}),g&&e.jsx("span",{role:"tooltip",id:x,className:"absolute left-1/2 top-full z-50 mt-1.5 w-64 -translate-x-1/2 rounded-md border border-glass-edge bg-popover px-3 py-2 text-xs leading-relaxed text-[#d4d4dc] shadow-lg",children:s})]})}const ee=[{key:"backlog",label:"Backlog"},{key:"planned",label:"Planned"},{key:"in_progress",label:"In Progress"},{key:"human_review",label:"Human Review"},{key:"pr",label:"PR"},{key:"done",label:"Done"}],F={background:"rgba(255,255,255,0.06)",border:"1px solid rgba(255,255,255,0.12)",borderRadius:6,color:"#e2e2e7",fontSize:13,padding:"6px 10px",width:"100%",outline:"none"},A={display:"block",fontSize:11,fontWeight:600,color:"#8a8a8a",textTransform:"uppercase",letterSpacing:"0.05em",marginBottom:4};function q({initial:s,onSubmit:o,onCancel:m,submitLabel:x="Save",nameInitial:g=""}){const[c,i]=r.useState(g),[d,h]=r.useState((s==null?void 0:s.base_url)??""),[b,N]=r.useState((s==null?void 0:s.email)??""),[y,P]=r.useState((s==null?void 0:s.api_token)??""),[C,w]=r.useState((s==null?void 0:s.default_project)??""),[R,I]=r.useState((s==null?void 0:s.status_map)??{}),[p,E]=r.useState(!1),[_,f]=r.useState(null);async function L(l){if(l.preventDefault(),f(null),!c.trim()){f("Name is required");return}if(!d.trim()){f("Base URL is required");return}if(!b.trim()){f("Email is required");return}if(!y.trim()){f("API token is required");return}E(!0);try{await o({base_url:d.trim(),email:b.trim(),api_token:y,default_project:C.trim()||void 0,status_map:R},c.trim())}catch(T){f(T instanceof Error?T.message:"Failed to save")}finally{E(!1)}}return e.jsxs("form",{onSubmit:L,style:{display:"flex",flexDirection:"column",gap:16},children:[e.jsxs("div",{children:[e.jsx("label",{style:A,children:"Instance name"}),e.jsx("input",{style:F,value:c,onChange:l=>i(l.target.value),placeholder:"e.g. My Jira",required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{style:A,children:"Base URL"}),e.jsx("input",{style:F,type:"url",value:d,onChange:l=>h(l.target.value),placeholder:"https://acme.atlassian.net",required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{style:A,children:"Email"}),e.jsx("input",{style:F,type:"email",value:b,onChange:l=>N(l.target.value),placeholder:"you@company.com",required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{style:A,children:"API Token"}),e.jsx("input",{style:F,type:"password",value:y,onChange:l=>P(l.target.value),placeholder:y==="••••"?"Leave as-is to keep stored token":"Atlassian API token",autoComplete:"off"}),e.jsxs("p",{style:{fontSize:11,color:"#8a8a8a",marginTop:4},children:["Generate at Atlassian account settings → Security → API tokens. Use"," ",e.jsxs("code",{style:{fontFamily:"monospace"},children:["$","{env:MY_VAR}"]})," to read from an environment variable."]})]}),e.jsxs("div",{children:[e.jsx("label",{style:A,children:"Default project key (optional)"}),e.jsx("input",{style:F,value:C,onChange:l=>w(l.target.value),placeholder:"e.g. PROJ"})]}),e.jsxs("div",{children:[e.jsx("label",{style:{...A,marginBottom:8},children:"Workflow → Jira transition ID map"}),e.jsx("p",{style:{fontSize:11,color:"#8a8a8a",marginBottom:8},children:"Map each octomux workflow status to a Jira transition ID (numeric). Leave blank to skip."}),e.jsx("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:8},children:ee.map(({key:l,label:T})=>e.jsxs("div",{children:[e.jsx("label",{style:{...A,marginBottom:2},children:T}),e.jsx("input",{style:F,value:R[l]??"",onChange:D=>I(n=>{const j={...n};return D.target.value?j[l]=D.target.value:delete j[l],j}),placeholder:"Transition ID"})]},l))})]}),_&&e.jsx("p",{style:{fontSize:12,color:"#f87171",margin:0},children:_}),e.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",paddingTop:4},children:[e.jsx("button",{type:"button",onClick:m,disabled:p,style:{padding:"6px 14px",borderRadius:6,border:"1px solid rgba(255,255,255,0.15)",background:"transparent",color:"#b5b5bd",fontSize:13,cursor:"pointer"},children:"Cancel"}),e.jsx("button",{type:"submit",disabled:p,style:{padding:"6px 14px",borderRadius:6,border:"none",background:p?"rgba(59,130,246,0.5)":"#3b82f6",color:"white",fontSize:13,cursor:p?"not-allowed":"pointer"},children:p?"Saving…":x})]})]})}function te(s){const o=s.config;return{base_url:String(o.base_url??""),email:String(o.email??""),api_token:String(o.api_token??""),default_project:o.default_project?String(o.default_project):void 0,status_map:o.status_map??{}}}const se=[{key:"backlog",label:"Backlog"},{key:"planned",label:"Planned"},{key:"in_progress",label:"In Progress"},{key:"human_review",label:"Human Review"},{key:"pr",label:"PR"},{key:"done",label:"Done"}];function G({initial:s,prefillTeams:o,onSubmit:m,onCancel:x,submitLabel:g="Save",nameInitial:c=""}){const[i,d]=r.useState(c),[h,b]=r.useState((s==null?void 0:s.api_key)??""),[N,y]=r.useState((s==null?void 0:s.default_team_key)??""),[P,C]=r.useState((s==null?void 0:s.status_map_by_team)??{}),[w,R]=r.useState(o??[]),[I,p]=r.useState(!1),[E,_]=r.useState(null),[f,L]=r.useState(!1);async function l(){_(null),p(!0);try{const n=await u.prefillLinear(h);R(n.teams),C(n.status_map_by_team),!N&&n.default_team_suggestion&&y(n.default_team_suggestion)}catch(n){_(n.message)}finally{p(!1)}}function T(n,j,k){C(v=>{const z={...v[n]??{}};return k?z[j]=k:delete z[j],{...v,[n]:z}})}async function D(n){n.preventDefault(),L(!0);try{await m({api_key:h.trim(),default_team_key:N.trim()||void 0,status_map_by_team:P},i.trim()||"Linear")}finally{L(!1)}}return e.jsxs("form",{onSubmit:D,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"linear-name",className:"mb-1 block text-xs text-[#b5b5bd]",children:"Integration name"}),e.jsx("input",{id:"linear-name",type:"text",value:i,onChange:n=>d(n.target.value),placeholder:"Linear",className:"w-full border border-glass-edge bg-[#0B0C0F] px-3 py-2 text-sm text-white outline-none focus:border-[#3B82F6]"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"linear-api-key",className:"mb-1 block text-xs text-[#b5b5bd]",children:"API key"}),e.jsx("input",{id:"linear-api-key",type:"password",value:h,onChange:n=>b(n.target.value),placeholder:"lin_api_...",className:"w-full border border-glass-edge bg-[#0B0C0F] px-3 py-2 font-mono text-sm text-white outline-none focus:border-[#3B82F6]"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(B,{type:"button",size:"sm",variant:"outline",disabled:!h||I,onClick:l,children:I?"Connecting…":"Connect & auto-detect teams"}),E&&e.jsx("span",{className:"text-xs text-red-400",children:E})]}),w.length>0&&e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-xs text-[#b5b5bd]",children:"Default team"}),e.jsx("select",{value:N,onChange:n=>y(n.target.value),className:"w-full border border-glass-edge bg-[#0B0C0F] px-3 py-2 text-sm text-white outline-none focus:border-[#3B82F6]",children:w.map(n=>e.jsxs("option",{value:n.key,children:[n.name," (",n.key,")"]},n.key))})]}),w.map(n=>{const j=P[n.key]??{};return e.jsxs("details",{open:n.key===N,children:[e.jsxs("summary",{className:"cursor-pointer py-1 text-sm text-white",children:[n.name," (",n.key,")"]}),e.jsx("div",{className:"mt-2 space-y-2 pl-3",children:se.map(k=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-32 text-xs text-[#b5b5bd]",children:k.label}),e.jsxs("select",{value:j[k.key]??"",onChange:v=>T(n.key,k.key,v.target.value||void 0),className:"flex-1 border border-glass-edge bg-[#0B0C0F] px-2 py-1 text-xs text-white outline-none focus:border-[#3B82F6]",children:[e.jsx("option",{value:"",children:"— unmapped —"}),n.states.map(v=>e.jsx("option",{value:v.id,children:v.name},v.id))]})]},k.key))})]},n.key)})]}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(B,{type:"button",size:"sm",variant:"outline",onClick:x,children:"Cancel"}),e.jsx(B,{type:"submit",size:"sm",disabled:f||!h,children:f?"Saving…":g})]})]})}function ae(s){return s.config}function Y(s){return s==="jira"?"J":s==="linear"?"L":s.charAt(0).toUpperCase()}const K={"jira-status":{label:"jira-status hook",tooltip:"Runs when a task’s workflow column changes and transitions the linked Jira issue via the status→transition-ID map in ~/.octomux/hooks. Needs JIRA_BASE_URL, JIRA_EMAIL and JIRA_TOKEN. This is an alternative to the Jira API integration’s automatic transitions — use one or the other to avoid double-firing."}};function U(s){var o;return((o=K[s])==null?void 0:o.label)??s}function ne({integration:s,onEdit:o,onDelete:m,onToggle:x,onTest:g,testResult:c,testing:i}){return e.jsxs("div",{className:"flex items-center justify-between py-3",style:H,"data-testid":`integration-row-${s.id}`,children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex size-8 items-center justify-center rounded-lg bg-primary/20 text-sm font-bold text-primary",children:Y(s.kind)}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:s.name}),e.jsx("p",{className:"text-xs capitalize text-muted-soft",children:s.kind})]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[c&&e.jsxs("span",{className:"text-xs",style:{color:c.ok?"var(--color-success)":"var(--destructive)"},children:[c.ok?"✓":"✗"," ",c.message]}),e.jsx("button",{type:"button",className:"focus-ring text-xs text-muted-soft transition-colors hover:text-foreground",onClick:g,disabled:i,children:i?"Testing…":"Test"}),e.jsx("button",{type:"button",className:"focus-ring text-xs text-muted-soft transition-colors hover:text-foreground",onClick:o,children:"Edit"}),e.jsx("button",{type:"button",className:"focus-ring text-xs text-destructive transition-colors hover:text-destructive/80",onClick:m,children:"Delete"}),e.jsx(X,{checked:s.enabled,onChange:x})]})]})}function M({title:s,onClose:o,children:m}){return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm",onClick:x=>{x.target===x.currentTarget&&o()},children:e.jsxs("div",{className:"relative max-h-[90vh] w-full max-w-lg overflow-y-auto rounded-2xl border border-glass-edge bg-popover p-6",children:[e.jsxs("div",{className:"mb-5 flex items-center justify-between",children:[e.jsx("h2",{className:"text-sm font-semibold text-foreground",children:s}),e.jsx("button",{type:"button",onClick:o,className:"text-muted-soft hover:text-foreground","aria-label":"Close",children:"✕"})]}),m]})})}function ue(){const[s,o]=r.useState([]),[m,x]=r.useState([]),[g,c]=r.useState(!0),[i,d]=r.useState(null),[h,b]=r.useState(null),[N,y]=r.useState({}),[P,C]=r.useState({}),[w,R]=r.useState([]),[I,p]=r.useState(null),[E,_]=r.useState(""),[f,L]=r.useState(!1),l=r.useCallback(async()=>{try{const[t,a,S,W]=await Promise.all([u.listProviders(),u.listIntegrations(),u.listHookTemplates().catch(()=>[]),u.getSettings().catch(()=>null)]);o(t),x(a),R(S),W&&_(W.defaultTracker??"")}catch{}finally{c(!1)}},[]);async function T(t){p(t);try{await u.installHookTemplate(t),O("success","HOOKS",`Installed ${U(t)}`),l()}catch(a){O("error","HOOKS",a instanceof Error?a.message:"Install failed")}finally{p(null)}}async function D(t){_(t),L(!0);try{await u.updateSettings({defaultTracker:t||void 0}),O("success","INTEGRATIONS","Primary tracker saved")}catch(a){O("error","INTEGRATIONS",a instanceof Error?a.message:"Save failed")}finally{L(!1)}}r.useEffect(()=>{l()},[l]);async function n(t,a){await u.createIntegration("jira",a,t),d(null),l()}async function j(t,a,S){await u.updateIntegration(t,{name:S,config:a}),d(null),l()}async function k(t,a){await u.createIntegration("linear",a,t),d(null),l()}async function v(t,a,S){await u.updateIntegration(t,{name:S,config:a}),d(null),l()}async function z(t){await u.deleteIntegration(t),b(null),l()}async function V(t,a){await u.updateIntegration(t,{enabled:a}),l()}async function Q(t){C(a=>({...a,[t]:!0}));try{const a=await u.testIntegration(t);y(S=>({...S,[t]:a}))}catch(a){y(S=>({...S,[t]:{ok:!1,message:a instanceof Error?a.message:"Test failed"}}))}finally{C(a=>({...a,[t]:!1}))}}return g?e.jsx($,{title:"Integrations",description:"Connect Octomux to external systems",children:e.jsx("p",{className:"text-sm text-muted-soft",children:"Loading integrations…"})}):e.jsxs(e.Fragment,{children:[e.jsxs($,{title:"Integrations",description:"Workflow column changes fire to enabled integrations",children:[e.jsx(J,{id:"providers",title:"Available providers",children:s.length===0?e.jsx("p",{className:"py-2 text-xs text-muted-soft",children:"No providers registered."}):s.map(t=>e.jsxs("div",{className:"flex items-center justify-between py-3",style:H,children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex size-8 items-center justify-center rounded-lg bg-primary/20 text-sm font-bold text-primary",children:Y(t.kind)}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:t.displayName}),e.jsxs("p",{className:"text-xs text-muted-soft",children:["Events: ",t.events.join(", ")]})]})]}),e.jsxs(B,{size:"sm",onClick:()=>{t.kind==="jira"?d({kind:"create-jira"}):t.kind==="linear"&&d({kind:"create-linear"})},children:["Add ",t.displayName]})]},t.kind))}),e.jsx(J,{id:"configured",title:"Configured",count:m.length,children:m.length===0?e.jsx("p",{className:"py-2 text-xs text-muted-soft",children:"No integrations configured. Add one above."}):m.map(t=>e.jsx(ne,{integration:t,onEdit:()=>{t.kind==="jira"?d({kind:"edit-jira",integration:t}):t.kind==="linear"&&d({kind:"edit-linear",integration:t})},onDelete:()=>b(t.id),onToggle:a=>void V(t.id,a),onTest:()=>void Q(t.id),testResult:N[t.id]??null,testing:P[t.id]??!1},t.id))}),e.jsx(J,{id:"primary-tracker",title:"Primary tracker",children:e.jsxs("div",{className:"flex items-center justify-between py-3",style:H,"data-testid":"primary-tracker-row",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"Default tracker for new tasks"}),e.jsx("p",{className:"text-xs text-muted-soft",children:"Used by the create-task flow when more than one tracker is configured."})]}),e.jsxs("select",{value:E,disabled:f,onChange:t=>void D(t.target.value),className:"border border-glass-edge bg-[#0B0C0F] px-3 py-2 text-sm text-white outline-none focus:border-[#3B82F6]","data-testid":"primary-tracker-select","aria-label":"Primary tracker",children:[e.jsx("option",{value:"",children:"— none —"}),e.jsx("option",{value:"linear",children:"Linear"}),e.jsx("option",{value:"jira",children:"Jira"})]})]})}),e.jsx(J,{id:"workflow-hooks",title:"Workflow hooks",children:w.length===0?e.jsx("p",{className:"py-2 text-xs text-muted-soft",children:"No hook templates available."}):w.map(t=>{var a;return e.jsxs("div",{className:"flex items-center justify-between py-3",style:H,"data-testid":`hook-template-${t.id}`,children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:U(t.id)}),((a=K[t.id])==null?void 0:a.tooltip)&&e.jsx(Z,{content:K[t.id].tooltip,label:`About ${U(t.id)}`})]}),t.installed?e.jsx("span",{className:"text-xs font-medium text-[#22C55E]",children:"Installed"}):e.jsx(B,{size:"sm",variant:"outline",disabled:I===t.id,onClick:()=>void T(t.id),"data-testid":`hook-install-${t.id}`,children:I===t.id?"Installing…":"Install"})]},t.id)})})]}),(i==null?void 0:i.kind)==="create-jira"&&e.jsx(M,{title:"Add Jira integration",onClose:()=>d(null),children:e.jsx(q,{onSubmit:n,onCancel:()=>d(null),submitLabel:"Create"})}),(i==null?void 0:i.kind)==="edit-jira"&&e.jsx(M,{title:"Edit Jira integration",onClose:()=>d(null),children:e.jsx(q,{initial:te(i.integration),nameInitial:i.integration.name,onSubmit:(t,a)=>j(i.integration.id,t,a),onCancel:()=>d(null),submitLabel:"Save changes"})}),(i==null?void 0:i.kind)==="create-linear"&&e.jsx(M,{title:"Add Linear integration",onClose:()=>d(null),children:e.jsx(G,{onSubmit:k,onCancel:()=>d(null),submitLabel:"Create"})}),(i==null?void 0:i.kind)==="edit-linear"&&e.jsx(M,{title:"Edit Linear integration",onClose:()=>d(null),children:e.jsx(G,{initial:ae(i.integration),nameInitial:i.integration.name,onSubmit:(t,a)=>v(i.integration.id,t,a),onCancel:()=>d(null),submitLabel:"Save changes"})}),h&&e.jsxs(M,{title:"Delete integration",onClose:()=>b(null),children:[e.jsx("p",{className:"mb-4 text-sm text-muted-foreground",children:"Are you sure you want to delete this integration? This action cannot be undone."}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(B,{variant:"outline",size:"sm",onClick:()=>b(null),children:"Cancel"}),e.jsx(B,{variant:"destructive",size:"sm",onClick:()=>void z(h),children:"Delete"})]})]})]})}export{ue as default};
1
+ import{b as r,j as e}from"./vendor-react-Dd26lTa7.js";import{a as B,p as u,m as $,S as J,R as H,x as O,n as X}from"./index-DKTtIYvz.js";import"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";function Z({content:s,label:o="More information",className:m}){const x=r.useId(),[g,c]=r.useState(!1);return e.jsxs("span",{className:`relative inline-flex ${m??""}`,children:[e.jsx("button",{type:"button","aria-label":o,"aria-describedby":g?x:void 0,className:"focus-ring flex size-4 items-center justify-center rounded-full border border-glass-edge text-[10px] font-semibold leading-none text-[#8a8a8a] transition-colors hover:border-[#60a5fa] hover:text-[#60a5fa]",onMouseEnter:()=>c(!0),onMouseLeave:()=>c(!1),onFocus:()=>c(!0),onBlur:()=>c(!1),children:"i"}),g&&e.jsx("span",{role:"tooltip",id:x,className:"absolute left-1/2 top-full z-50 mt-1.5 w-64 -translate-x-1/2 rounded-md border border-glass-edge bg-popover px-3 py-2 text-xs leading-relaxed text-[#d4d4dc] shadow-lg",children:s})]})}const ee=[{key:"backlog",label:"Backlog"},{key:"planned",label:"Planned"},{key:"in_progress",label:"In Progress"},{key:"human_review",label:"Human Review"},{key:"pr",label:"PR"},{key:"done",label:"Done"}],F={background:"rgba(255,255,255,0.06)",border:"1px solid rgba(255,255,255,0.12)",borderRadius:6,color:"#e2e2e7",fontSize:13,padding:"6px 10px",width:"100%",outline:"none"},A={display:"block",fontSize:11,fontWeight:600,color:"#8a8a8a",textTransform:"uppercase",letterSpacing:"0.05em",marginBottom:4};function q({initial:s,onSubmit:o,onCancel:m,submitLabel:x="Save",nameInitial:g=""}){const[c,i]=r.useState(g),[d,h]=r.useState((s==null?void 0:s.base_url)??""),[b,N]=r.useState((s==null?void 0:s.email)??""),[y,P]=r.useState((s==null?void 0:s.api_token)??""),[C,w]=r.useState((s==null?void 0:s.default_project)??""),[R,I]=r.useState((s==null?void 0:s.status_map)??{}),[p,E]=r.useState(!1),[_,f]=r.useState(null);async function L(l){if(l.preventDefault(),f(null),!c.trim()){f("Name is required");return}if(!d.trim()){f("Base URL is required");return}if(!b.trim()){f("Email is required");return}if(!y.trim()){f("API token is required");return}E(!0);try{await o({base_url:d.trim(),email:b.trim(),api_token:y,default_project:C.trim()||void 0,status_map:R},c.trim())}catch(T){f(T instanceof Error?T.message:"Failed to save")}finally{E(!1)}}return e.jsxs("form",{onSubmit:L,style:{display:"flex",flexDirection:"column",gap:16},children:[e.jsxs("div",{children:[e.jsx("label",{style:A,children:"Instance name"}),e.jsx("input",{style:F,value:c,onChange:l=>i(l.target.value),placeholder:"e.g. My Jira",required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{style:A,children:"Base URL"}),e.jsx("input",{style:F,type:"url",value:d,onChange:l=>h(l.target.value),placeholder:"https://acme.atlassian.net",required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{style:A,children:"Email"}),e.jsx("input",{style:F,type:"email",value:b,onChange:l=>N(l.target.value),placeholder:"you@company.com",required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{style:A,children:"API Token"}),e.jsx("input",{style:F,type:"password",value:y,onChange:l=>P(l.target.value),placeholder:y==="••••"?"Leave as-is to keep stored token":"Atlassian API token",autoComplete:"off"}),e.jsxs("p",{style:{fontSize:11,color:"#8a8a8a",marginTop:4},children:["Generate at Atlassian account settings → Security → API tokens. Use"," ",e.jsxs("code",{style:{fontFamily:"monospace"},children:["$","{env:MY_VAR}"]})," to read from an environment variable."]})]}),e.jsxs("div",{children:[e.jsx("label",{style:A,children:"Default project key (optional)"}),e.jsx("input",{style:F,value:C,onChange:l=>w(l.target.value),placeholder:"e.g. PROJ"})]}),e.jsxs("div",{children:[e.jsx("label",{style:{...A,marginBottom:8},children:"Workflow → Jira transition ID map"}),e.jsx("p",{style:{fontSize:11,color:"#8a8a8a",marginBottom:8},children:"Map each octomux workflow status to a Jira transition ID (numeric). Leave blank to skip."}),e.jsx("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:8},children:ee.map(({key:l,label:T})=>e.jsxs("div",{children:[e.jsx("label",{style:{...A,marginBottom:2},children:T}),e.jsx("input",{style:F,value:R[l]??"",onChange:D=>I(n=>{const j={...n};return D.target.value?j[l]=D.target.value:delete j[l],j}),placeholder:"Transition ID"})]},l))})]}),_&&e.jsx("p",{style:{fontSize:12,color:"#f87171",margin:0},children:_}),e.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",paddingTop:4},children:[e.jsx("button",{type:"button",onClick:m,disabled:p,style:{padding:"6px 14px",borderRadius:6,border:"1px solid rgba(255,255,255,0.15)",background:"transparent",color:"#b5b5bd",fontSize:13,cursor:"pointer"},children:"Cancel"}),e.jsx("button",{type:"submit",disabled:p,style:{padding:"6px 14px",borderRadius:6,border:"none",background:p?"rgba(59,130,246,0.5)":"#3b82f6",color:"white",fontSize:13,cursor:p?"not-allowed":"pointer"},children:p?"Saving…":x})]})]})}function te(s){const o=s.config;return{base_url:String(o.base_url??""),email:String(o.email??""),api_token:String(o.api_token??""),default_project:o.default_project?String(o.default_project):void 0,status_map:o.status_map??{}}}const se=[{key:"backlog",label:"Backlog"},{key:"planned",label:"Planned"},{key:"in_progress",label:"In Progress"},{key:"human_review",label:"Human Review"},{key:"pr",label:"PR"},{key:"done",label:"Done"}];function G({initial:s,prefillTeams:o,onSubmit:m,onCancel:x,submitLabel:g="Save",nameInitial:c=""}){const[i,d]=r.useState(c),[h,b]=r.useState((s==null?void 0:s.api_key)??""),[N,y]=r.useState((s==null?void 0:s.default_team_key)??""),[P,C]=r.useState((s==null?void 0:s.status_map_by_team)??{}),[w,R]=r.useState(o??[]),[I,p]=r.useState(!1),[E,_]=r.useState(null),[f,L]=r.useState(!1);async function l(){_(null),p(!0);try{const n=await u.prefillLinear(h);R(n.teams),C(n.status_map_by_team),!N&&n.default_team_suggestion&&y(n.default_team_suggestion)}catch(n){_(n.message)}finally{p(!1)}}function T(n,j,k){C(v=>{const z={...v[n]??{}};return k?z[j]=k:delete z[j],{...v,[n]:z}})}async function D(n){n.preventDefault(),L(!0);try{await m({api_key:h.trim(),default_team_key:N.trim()||void 0,status_map_by_team:P},i.trim()||"Linear")}finally{L(!1)}}return e.jsxs("form",{onSubmit:D,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"linear-name",className:"mb-1 block text-xs text-[#b5b5bd]",children:"Integration name"}),e.jsx("input",{id:"linear-name",type:"text",value:i,onChange:n=>d(n.target.value),placeholder:"Linear",className:"w-full border border-glass-edge bg-[#0B0C0F] px-3 py-2 text-sm text-white outline-none focus:border-[#3B82F6]"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"linear-api-key",className:"mb-1 block text-xs text-[#b5b5bd]",children:"API key"}),e.jsx("input",{id:"linear-api-key",type:"password",value:h,onChange:n=>b(n.target.value),placeholder:"lin_api_...",className:"w-full border border-glass-edge bg-[#0B0C0F] px-3 py-2 font-mono text-sm text-white outline-none focus:border-[#3B82F6]"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(B,{type:"button",size:"sm",variant:"outline",disabled:!h||I,onClick:l,children:I?"Connecting…":"Connect & auto-detect teams"}),E&&e.jsx("span",{className:"text-xs text-red-400",children:E})]}),w.length>0&&e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-xs text-[#b5b5bd]",children:"Default team"}),e.jsx("select",{value:N,onChange:n=>y(n.target.value),className:"w-full border border-glass-edge bg-[#0B0C0F] px-3 py-2 text-sm text-white outline-none focus:border-[#3B82F6]",children:w.map(n=>e.jsxs("option",{value:n.key,children:[n.name," (",n.key,")"]},n.key))})]}),w.map(n=>{const j=P[n.key]??{};return e.jsxs("details",{open:n.key===N,children:[e.jsxs("summary",{className:"cursor-pointer py-1 text-sm text-white",children:[n.name," (",n.key,")"]}),e.jsx("div",{className:"mt-2 space-y-2 pl-3",children:se.map(k=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-32 text-xs text-[#b5b5bd]",children:k.label}),e.jsxs("select",{value:j[k.key]??"",onChange:v=>T(n.key,k.key,v.target.value||void 0),className:"flex-1 border border-glass-edge bg-[#0B0C0F] px-2 py-1 text-xs text-white outline-none focus:border-[#3B82F6]",children:[e.jsx("option",{value:"",children:"— unmapped —"}),n.states.map(v=>e.jsx("option",{value:v.id,children:v.name},v.id))]})]},k.key))})]},n.key)})]}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(B,{type:"button",size:"sm",variant:"outline",onClick:x,children:"Cancel"}),e.jsx(B,{type:"submit",size:"sm",disabled:f||!h,children:f?"Saving…":g})]})]})}function ae(s){return s.config}function Y(s){return s==="jira"?"J":s==="linear"?"L":s.charAt(0).toUpperCase()}const K={"jira-status":{label:"jira-status hook",tooltip:"Runs when a task’s workflow column changes and transitions the linked Jira issue via the status→transition-ID map in ~/.octomux/hooks. Needs JIRA_BASE_URL, JIRA_EMAIL and JIRA_TOKEN. This is an alternative to the Jira API integration’s automatic transitions — use one or the other to avoid double-firing."}};function U(s){var o;return((o=K[s])==null?void 0:o.label)??s}function ne({integration:s,onEdit:o,onDelete:m,onToggle:x,onTest:g,testResult:c,testing:i}){return e.jsxs("div",{className:"flex items-center justify-between py-3",style:H,"data-testid":`integration-row-${s.id}`,children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex size-8 items-center justify-center rounded-lg bg-primary/20 text-sm font-bold text-primary",children:Y(s.kind)}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:s.name}),e.jsx("p",{className:"text-xs capitalize text-muted-soft",children:s.kind})]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[c&&e.jsxs("span",{className:"text-xs",style:{color:c.ok?"var(--color-success)":"var(--destructive)"},children:[c.ok?"✓":"✗"," ",c.message]}),e.jsx("button",{type:"button",className:"focus-ring text-xs text-muted-soft transition-colors hover:text-foreground",onClick:g,disabled:i,children:i?"Testing…":"Test"}),e.jsx("button",{type:"button",className:"focus-ring text-xs text-muted-soft transition-colors hover:text-foreground",onClick:o,children:"Edit"}),e.jsx("button",{type:"button",className:"focus-ring text-xs text-destructive transition-colors hover:text-destructive/80",onClick:m,children:"Delete"}),e.jsx(X,{checked:s.enabled,onChange:x})]})]})}function M({title:s,onClose:o,children:m}){return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm",onClick:x=>{x.target===x.currentTarget&&o()},children:e.jsxs("div",{className:"relative max-h-[90vh] w-full max-w-lg overflow-y-auto rounded-2xl border border-glass-edge bg-popover p-6",children:[e.jsxs("div",{className:"mb-5 flex items-center justify-between",children:[e.jsx("h2",{className:"text-sm font-semibold text-foreground",children:s}),e.jsx("button",{type:"button",onClick:o,className:"text-muted-soft hover:text-foreground","aria-label":"Close",children:"✕"})]}),m]})})}function ue(){const[s,o]=r.useState([]),[m,x]=r.useState([]),[g,c]=r.useState(!0),[i,d]=r.useState(null),[h,b]=r.useState(null),[N,y]=r.useState({}),[P,C]=r.useState({}),[w,R]=r.useState([]),[I,p]=r.useState(null),[E,_]=r.useState(""),[f,L]=r.useState(!1),l=r.useCallback(async()=>{try{const[t,a,S,W]=await Promise.all([u.listProviders(),u.listIntegrations(),u.listHookTemplates().catch(()=>[]),u.getSettings().catch(()=>null)]);o(t),x(a),R(S),W&&_(W.defaultTracker??"")}catch{}finally{c(!1)}},[]);async function T(t){p(t);try{await u.installHookTemplate(t),O("success","HOOKS",`Installed ${U(t)}`),l()}catch(a){O("error","HOOKS",a instanceof Error?a.message:"Install failed")}finally{p(null)}}async function D(t){_(t),L(!0);try{await u.updateSettings({defaultTracker:t||void 0}),O("success","INTEGRATIONS","Primary tracker saved")}catch(a){O("error","INTEGRATIONS",a instanceof Error?a.message:"Save failed")}finally{L(!1)}}r.useEffect(()=>{l()},[l]);async function n(t,a){await u.createIntegration("jira",a,t),d(null),l()}async function j(t,a,S){await u.updateIntegration(t,{name:S,config:a}),d(null),l()}async function k(t,a){await u.createIntegration("linear",a,t),d(null),l()}async function v(t,a,S){await u.updateIntegration(t,{name:S,config:a}),d(null),l()}async function z(t){await u.deleteIntegration(t),b(null),l()}async function V(t,a){await u.updateIntegration(t,{enabled:a}),l()}async function Q(t){C(a=>({...a,[t]:!0}));try{const a=await u.testIntegration(t);y(S=>({...S,[t]:a}))}catch(a){y(S=>({...S,[t]:{ok:!1,message:a instanceof Error?a.message:"Test failed"}}))}finally{C(a=>({...a,[t]:!1}))}}return g?e.jsx($,{title:"Integrations",description:"Connect Octomux to external systems",children:e.jsx("p",{className:"text-sm text-muted-soft",children:"Loading integrations…"})}):e.jsxs(e.Fragment,{children:[e.jsxs($,{title:"Integrations",description:"Workflow column changes fire to enabled integrations",children:[e.jsx(J,{id:"providers",title:"Available providers",children:s.length===0?e.jsx("p",{className:"py-2 text-xs text-muted-soft",children:"No providers registered."}):s.map(t=>e.jsxs("div",{className:"flex items-center justify-between py-3",style:H,children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex size-8 items-center justify-center rounded-lg bg-primary/20 text-sm font-bold text-primary",children:Y(t.kind)}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:t.displayName}),e.jsxs("p",{className:"text-xs text-muted-soft",children:["Events: ",t.events.join(", ")]})]})]}),e.jsxs(B,{size:"sm",onClick:()=>{t.kind==="jira"?d({kind:"create-jira"}):t.kind==="linear"&&d({kind:"create-linear"})},children:["Add ",t.displayName]})]},t.kind))}),e.jsx(J,{id:"configured",title:"Configured",count:m.length,children:m.length===0?e.jsx("p",{className:"py-2 text-xs text-muted-soft",children:"No integrations configured. Add one above."}):m.map(t=>e.jsx(ne,{integration:t,onEdit:()=>{t.kind==="jira"?d({kind:"edit-jira",integration:t}):t.kind==="linear"&&d({kind:"edit-linear",integration:t})},onDelete:()=>b(t.id),onToggle:a=>void V(t.id,a),onTest:()=>void Q(t.id),testResult:N[t.id]??null,testing:P[t.id]??!1},t.id))}),e.jsx(J,{id:"primary-tracker",title:"Primary tracker",children:e.jsxs("div",{className:"flex items-center justify-between py-3",style:H,"data-testid":"primary-tracker-row",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:"Default tracker for new tasks"}),e.jsx("p",{className:"text-xs text-muted-soft",children:"Used by the create-task flow when more than one tracker is configured."})]}),e.jsxs("select",{value:E,disabled:f,onChange:t=>void D(t.target.value),className:"border border-glass-edge bg-[#0B0C0F] px-3 py-2 text-sm text-white outline-none focus:border-[#3B82F6]","data-testid":"primary-tracker-select","aria-label":"Primary tracker",children:[e.jsx("option",{value:"",children:"— none —"}),e.jsx("option",{value:"linear",children:"Linear"}),e.jsx("option",{value:"jira",children:"Jira"})]})]})}),e.jsx(J,{id:"workflow-hooks",title:"Workflow hooks",children:w.length===0?e.jsx("p",{className:"py-2 text-xs text-muted-soft",children:"No hook templates available."}):w.map(t=>{var a;return e.jsxs("div",{className:"flex items-center justify-between py-3",style:H,"data-testid":`hook-template-${t.id}`,children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("p",{className:"text-sm font-medium text-foreground",children:U(t.id)}),((a=K[t.id])==null?void 0:a.tooltip)&&e.jsx(Z,{content:K[t.id].tooltip,label:`About ${U(t.id)}`})]}),t.installed?e.jsx("span",{className:"text-xs font-medium text-[#22C55E]",children:"Installed"}):e.jsx(B,{size:"sm",variant:"outline",disabled:I===t.id,onClick:()=>void T(t.id),"data-testid":`hook-install-${t.id}`,children:I===t.id?"Installing…":"Install"})]},t.id)})})]}),(i==null?void 0:i.kind)==="create-jira"&&e.jsx(M,{title:"Add Jira integration",onClose:()=>d(null),children:e.jsx(q,{onSubmit:n,onCancel:()=>d(null),submitLabel:"Create"})}),(i==null?void 0:i.kind)==="edit-jira"&&e.jsx(M,{title:"Edit Jira integration",onClose:()=>d(null),children:e.jsx(q,{initial:te(i.integration),nameInitial:i.integration.name,onSubmit:(t,a)=>j(i.integration.id,t,a),onCancel:()=>d(null),submitLabel:"Save changes"})}),(i==null?void 0:i.kind)==="create-linear"&&e.jsx(M,{title:"Add Linear integration",onClose:()=>d(null),children:e.jsx(G,{onSubmit:k,onCancel:()=>d(null),submitLabel:"Create"})}),(i==null?void 0:i.kind)==="edit-linear"&&e.jsx(M,{title:"Edit Linear integration",onClose:()=>d(null),children:e.jsx(G,{initial:ae(i.integration),nameInitial:i.integration.name,onSubmit:(t,a)=>v(i.integration.id,t,a),onCancel:()=>d(null),submitLabel:"Save changes"})}),h&&e.jsxs(M,{title:"Delete integration",onClose:()=>b(null),children:[e.jsx("p",{className:"mb-4 text-sm text-muted-foreground",children:"Are you sure you want to delete this integration? This action cannot be undone."}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(B,{variant:"outline",size:"sm",onClick:()=>b(null),children:"Cancel"}),e.jsx(B,{variant:"destructive",size:"sm",onClick:()=>void z(h),children:"Delete"})]})]})]})}export{ue as default};
@@ -0,0 +1 @@
1
+ import{b as r,j as e}from"./vendor-react-Dd26lTa7.js";import{w as te,C as q,r as y,B as I,q as K,b as J,e as se,f as ae,t as ne,s as re,D as le,a as D,d as ie,p as F,z as _,y as U,A as oe,u as de,T as ce,k as ue,g as me,h as xe,i as fe,j as pe,c as he}from"./index-DKTtIYvz.js";import{c as ge,b as ve}from"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";function we(t){var g;const s=t.status.toLowerCase().replace(/_/g," ").trim(),a=((g=t.notes??t.reason)==null?void 0:g.trim())||null;let l="neutral",o=t.status;return["compliant","fully","full","satisfied","addressed","met","yes","complete","done"].some(n=>s===n||s.startsWith(n))?(l="positive",o="Met"):["partially","partial","part"].some(n=>s===n||s.startsWith(n))?(l="partial",o="Partial"):["non-compliant","non compliant","not","failed","missing","unmet","no"].some(n=>s===n||s.startsWith(n))&&s!=="no ticket"?(l="negative",o="Not met"):["no ticket","no_ticket","n/a","na","none"].some(n=>s.includes(n))&&(l="neutral",o="N/A"),{ticket:t.ticket,label:o,tone:l,detail:a}}function be(t){switch(t){case"positive":return"text-emerald-400";case"partial":return"text-amber-400";case"negative":return"text-destructive";default:return"text-muted-foreground"}}function je(t){switch(t){case"positive":return"✓";case"partial":return"~";case"negative":return"✗";default:return"·"}}const Y="octomux:review:walkthrough-expanded";function ye(){if(typeof window>"u")return!0;try{const t=localStorage.getItem(Y);if(t!==null)return t==="true"}catch{}return!0}function Ne({walkthrough:t}){var v;const s=t.global??{},[a,l]=r.useState(ye);r.useEffect(()=>{try{localStorage.setItem(Y,String(a))}catch{}},[a]);const o=r.useCallback(()=>l(u=>!u),[]),g=r.useMemo(()=>(s.ticket_compliance??[]).map(we),[s.ticket_compliance]),n=((v=s.key_review_points)==null?void 0:v.filter(Boolean))??[],f=s.security_concerns!=null&&s.security_concerns!=="";if(!(s.summary||s.type||s.risk||s.effort!==void 0||s.relevant_tests||f||n.length>0||g.length>0))return null;const m=te(s.risk);return e.jsxs("section",{"data-testid":"walkthrough-panel","data-expanded":a?"true":"false",className:"border-b border-glass-edge bg-glass-l1",children:[e.jsxs("button",{type:"button",onClick:o,className:"focus-ring flex w-full items-start gap-2 px-4 py-2.5 text-left hover:bg-glass-l2/30","aria-expanded":a,"aria-label":a?"Collapse walkthrough":"Expand walkthrough",children:[e.jsx(q,{"aria-hidden":!0,className:y("mt-0.5 size-4 shrink-0 text-muted-foreground transition-transform",!a&&"-rotate-90")}),e.jsxs("div",{className:"min-w-0 flex-1 space-y-2",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsx("span",{className:"text-xs font-semibold text-foreground",children:"Walkthrough"}),s.type&&e.jsx(I,{variant:"outline",className:"text-[10px]",children:s.type}),s.risk&&e.jsxs(I,{variant:"outline",className:y("text-[10px]",m),children:["risk: ",s.risk]}),s.effort!==void 0&&e.jsxs(I,{variant:"outline",className:"text-[10px]",children:["effort ",s.effort,"/5"]}),s.relevant_tests&&e.jsxs(I,{variant:"outline",className:y("text-[10px]",s.relevant_tests==="no"&&"border-amber-500/40 text-amber-400"),children:["tests: ",s.relevant_tests]}),f&&e.jsx(I,{variant:"destructive",className:"text-[10px]",children:"security"}),!a&&n.length>0&&e.jsxs("span",{className:"text-[10px] text-muted-foreground",children:["· ",n.length," focus ",n.length===1?"area":"areas"]})]}),!a&&s.summary&&e.jsx("p",{className:"line-clamp-2 text-xs leading-relaxed text-muted-foreground",children:s.summary})]}),e.jsx("span",{className:"shrink-0 pt-0.5 text-[10px] text-muted-foreground",children:a?"Collapse":"Expand"})]}),a&&e.jsxs("div",{"data-testid":"walkthrough-panel-body",className:"max-h-[min(280px,40vh)] space-y-3 overflow-y-auto border-t border-glass-edge/60 px-4 pb-3 pt-2",children:[s.summary&&e.jsx("p",{className:"max-w-4xl text-sm leading-relaxed text-foreground",children:s.summary}),f&&e.jsx("p",{className:"rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:s.security_concerns}),n.length>0&&e.jsxs("div",{"data-testid":"walkthrough-key-points",children:[e.jsx("h3",{className:"mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground",children:"Where to focus"}),e.jsx("ul",{className:"space-y-1.5 text-sm text-foreground",children:n.map(u=>e.jsxs("li",{className:"flex gap-2 leading-snug",children:[e.jsx("span",{className:"mt-1.5 size-1 shrink-0 rounded-full bg-primary","aria-hidden":!0}),e.jsx("span",{children:u})]},u))})]}),g.length>0&&e.jsxs("div",{"data-testid":"walkthrough-tickets",children:[e.jsx("h3",{className:"mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground",children:"Tickets"}),e.jsx("ul",{className:"space-y-2",children:g.map(u=>e.jsxs("li",{className:"rounded-lg border border-glass-edge bg-glass-l2/40 px-3 py-2",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs",children:[e.jsx("span",{className:"font-mono font-medium text-foreground",children:u.ticket}),e.jsxs("span",{className:y("font-medium",be(u.tone)),children:[u.label," ",je(u.tone)]})]}),u.detail&&e.jsx("p",{className:"mt-1 text-xs leading-relaxed text-muted-foreground",children:u.detail})]},u.ticket))})]})]})]})}function Q({done:t,total:s,className:a,"data-testid":l}){const o=s>0?Math.min(100,Math.round(t/s*100)):0;return e.jsx("div",{"data-testid":l,className:y("h-1.5 w-full overflow-hidden rounded-full bg-glass-l2",a),role:"progressbar","aria-valuenow":t,"aria-valuemin":0,"aria-valuemax":s,"aria-label":`${t} of ${s} files reviewed`,children:e.jsx("div",{className:"h-full rounded-full bg-primary transition-[width] duration-300",style:{width:`${o}%`}})})}function ke(t){const s=new Map;for(const a of t){const l=s.get(a.file_path)??{open:0,stale:0,hasSerious:!1};a.status==="stale"?l.stale+=1:a.status!=="rejected"&&a.status!=="published"&&!a.auto_resolved_at&&(l.open+=1,(a.severity==="critical"||a.severity==="issue")&&(l.hasSerious=!0)),s.set(a.file_path,l)}return s}function Ce(t){const s=t.lastIndexOf("/");return s===-1?t:t.slice(s+1)}function Re(t,s){return t.filter(a=>s.has(a.path)).length}function Se({file:t,selected:s,counts:a,reviewedFiles:l,onToggleReviewed:o,onSelect:g}){const n=(a==null?void 0:a.open)??0,f=(a==null?void 0:a.stale)??0,x=!!(a!=null&&a.hasSerious),m=l.has(t.path);return e.jsxs("li",{"data-testid":`review-file-row-${t.path}`,"data-selected":s?"true":void 0,"data-reviewed":m?"true":"false",className:y("flex items-start gap-2 px-2 py-1 text-left text-xs","data-[reviewed=true]:opacity-60"),role:"treeitem","aria-selected":s,children:[e.jsx("input",{type:"checkbox",checked:m,"data-testid":`review-toggle-${t.path}`,"aria-label":m?`Unmark ${t.path} reviewed`:`Mark ${t.path} reviewed`,onClick:v=>v.stopPropagation(),onChange:v=>{v.stopPropagation(),o(t.path,m)},className:"mt-1.5 h-3.5 w-3.5 shrink-0 cursor-pointer"}),e.jsxs("button",{type:"button",onClick:()=>g(t.path),className:y(ae,"min-w-0 flex-1 flex-col items-stretch gap-0.5 py-1.5",s&&se),tabIndex:s?0:-1,title:t.path,children:[e.jsxs("span",{className:"flex min-w-0 items-center gap-2",children:[e.jsx("code",{className:"min-w-0 flex-1 truncate font-mono text-foreground",children:Ce(t.path)}),t.label&&e.jsx(I,{variant:"outline",className:"shrink-0 px-1 text-[10px]",children:t.label})]}),t.summary&&e.jsx(J,{text:t.summary,lines:2,clampChars:120,className:"text-[10px] leading-snug text-muted-foreground"})]}),(n>0||f>0)&&e.jsxs("div",{className:"flex shrink-0 flex-col items-end gap-1 pt-1",children:[n>0&&e.jsx("span",{"data-testid":`comment-count-${t.path}`,"data-tone":x?"serious":"muted",className:y("inline-flex min-w-[1.25rem] items-center justify-center rounded-full px-1.5 py-0.5 text-[10px] font-medium",x?"bg-destructive/20 text-destructive":"bg-glass-l2 text-muted-foreground"),children:n}),f>0&&e.jsxs("span",{"data-testid":`stale-count-${t.path}`,className:"inline-flex items-center rounded-full bg-warning/15 px-1.5 py-0.5 text-[10px] font-medium text-warning",children:["stale: ",f]})]})]})}function _e({files:t,walkthrough:s,comments:a,selectedPath:l,reviewedFiles:o,onToggleReviewed:g,onSelect:n}){const f=r.useMemo(()=>K(t,s),[t,s]),x=r.useMemo(()=>ke(a),[a]),[m,v]=r.useState(new Set),u=r.useMemo(()=>{let d=0;for(const c of x.values())d+=c.open;return d},[x]);function P(d){v(c=>{const p=new Set(c);return p.has(d)?p.delete(d):p.add(d),p})}const E=r.useCallback(d=>{if(!["ArrowDown","ArrowUp","j","k"].includes(d.key))return;const c=f.flatMap(T=>T.files.map(M=>M.path));if(c.length===0)return;const p=l?c.indexOf(l):-1,b=d.key==="ArrowDown"||d.key==="j"?1:-1,N=p===-1?0:(p+b+c.length)%c.length,k=c[N];k&&(d.preventDefault(),n(k))},[f,l,n]);return f.length===0?e.jsx("div",{className:"p-4 text-xs text-muted-foreground","data-testid":"review-file-tree-empty",children:"No files in diff"}):e.jsxs("div",{className:"flex h-full min-h-0 flex-col",children:[e.jsxs("header",{className:"shrink-0 space-y-2 border-b border-glass-edge px-3 py-2.5",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:"Files"}),e.jsxs("span",{className:"font-mono text-[10px] text-muted-foreground",children:[o.size,"/",t.length]})]}),e.jsx(Q,{done:o.size,total:t.length,"data-testid":"review-file-tree-progress"}),u>0&&e.jsxs("p",{className:"text-[10px] text-muted-foreground",children:[u," open comment",u===1?"":"s"," in tree"]})]}),e.jsx("nav",{"data-testid":"review-file-tree",role:"tree",className:"min-h-0 flex-1 overflow-y-auto",onKeyDown:E,children:f.map(d=>{const c=!m.has(d.name),p=Re(d.files,o);return e.jsxs("section",{role:"group","data-testid":`review-file-group-${d.name}`,className:"border-b border-glass-edge/60",children:[e.jsxs("button",{type:"button",onClick:()=>P(d.name),className:"flex w-full items-center gap-2 overflow-hidden px-3 py-2 text-left text-xs font-semibold hover:bg-glass-l2/40","aria-expanded":c,role:"treeitem",title:d.name,children:[e.jsx(q,{"aria-hidden":!0,className:y("size-3.5 shrink-0",c?"transition-transform":"-rotate-90 transition-transform")}),e.jsx("span",{className:"min-w-0 flex-1 truncate",children:d.name}),e.jsxs("span",{className:"shrink-0 font-mono text-[10px] font-normal text-muted-foreground",children:[p,"/",d.files.length]})]}),c&&d.summary&&e.jsx("div",{className:"px-3 pb-1.5",children:e.jsx(J,{text:d.summary,lines:2,clampChars:120,className:"text-[11px] leading-snug text-muted-foreground"})}),c&&e.jsx("ul",{children:d.files.map(b=>e.jsx(Se,{file:b,selected:l===b.path,counts:x.get(b.path),reviewedFiles:o,onToggleReviewed:g,onSelect:n},b.path))})]},d.name)})})]})}function V(t){const s=t.lastIndexOf("/");return s===-1?t:t.slice(s+1)}function Ee({groups:t,selectedPath:s}){const a=r.useMemo(()=>s?ne(t,s):null,[t,s]),l=!!(a!=null&&a.file.summary||a!=null&&a.group.summary);return s?l?e.jsxs("aside",{"data-testid":"review-context-strip",className:"max-h-52 space-y-3 overflow-y-auto border-b border-glass-edge bg-glass-l1/80 px-4 py-3",children:[a.group.summary&&e.jsxs("div",{"data-testid":"review-context-group",children:[e.jsx("h3",{className:"mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground",children:a.group.name}),e.jsx("p",{className:"text-xs leading-relaxed text-foreground",children:a.group.summary})]}),a.file.summary&&e.jsxs("div",{"data-testid":"review-context-file",children:[e.jsxs("div",{className:"mb-1 flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"font-mono text-[11px] font-medium text-foreground",title:s,children:V(s)}),a.file.label&&e.jsx(I,{variant:"outline",className:"px-1 text-[10px]",children:a.file.label})]}),e.jsx("p",{className:"text-xs leading-relaxed text-foreground",children:a.file.summary})]})]}):e.jsxs("div",{"data-testid":"review-context-strip",className:"border-b border-glass-edge bg-glass-l1/50 px-4 py-2 text-[11px] text-muted-foreground",children:[e.jsx("span",{className:"font-mono text-foreground",children:V(s)}),e.jsx("span",{className:"ml-2",children:"— no walkthrough notes for this file"})]}):e.jsx("div",{"data-testid":"review-context-strip",className:"border-b border-glass-edge bg-glass-l1/50 px-4 py-2 text-[11px] text-muted-foreground",children:"Select a file to read its review notes"})}const Te=[{value:"COMMENT",label:"Comment"},{value:"APPROVE",label:"Approve"},{value:"REQUEST_CHANGES",label:"Request changes"}];function Ie({taskId:t,prTitle:s,prNumber:a,prUrl:l,acceptedCount:o,draftCount:g,staleCount:n,reviewedDone:f,reviewedTotal:x,totalCommentsCount:m,showCommentsPanel:v,onToggleCommentsPanel:u,isRunning:P,onPublished:E,onReRun:d,onDeleted:c}){const[p,b]=r.useState("COMMENT"),[N,k]=r.useState(!1),[T,M]=r.useState(!1),[O,C]=r.useState(!1),R=re(s);async function z(){if(o!==0){k(!0);try{await F.publishReview(t,{verdict:p}),_.success("Review published to GitHub"),E()}catch(w){_.error(`Publish failed: ${w.message}`)}finally{k(!1)}}}async function $(){M(!0);try{await F.requestReReview(t),_.success("Re-review started"),d()}catch(w){_.error(`Re-run failed: ${w.message}`)}finally{M(!1)}}async function A(){try{await F.deleteTask(t),_.success("Review deleted"),c==null||c()}catch(w){throw _.error(`Delete failed: ${w.message}`),w}}return e.jsxs("div",{className:"sticky top-0 z-10 border-b border-glass-edge bg-glass-l2 backdrop-blur-sm",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-x-3 gap-y-2 px-4 py-2 sm:px-6",children:[e.jsxs("div",{className:"flex min-w-0 flex-1 basis-[min(100%,280px)] items-center gap-2",children:[e.jsx("span",{className:"truncate text-sm font-semibold",title:R,children:R}),a!=null&&e.jsxs("span",{className:"shrink-0 font-mono text-xs text-muted-foreground",children:["#",a]}),l&&e.jsx("a",{href:l,target:"_blank",rel:"noreferrer",className:"shrink-0 text-xs text-primary hover:underline",children:"GitHub"})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs",children:[o>0&&e.jsxs("span",{className:y(le),children:[o," accepted"]}),g>0&&e.jsxs("span",{className:"inline-flex items-center rounded-md border border-glass-edge bg-glass-l1 px-2 py-0.5 font-mono text-[11px] text-muted-foreground",children:[g," drafts"]}),n>0&&e.jsxs("span",{className:"inline-flex items-center rounded-md border border-warning/40 bg-warning/15 px-2 py-0.5 font-mono text-[11px] text-warning",children:[n," stale"]})]}),e.jsxs("div",{className:"ml-auto flex flex-wrap items-center justify-end gap-2",children:[e.jsxs(D,{variant:"outline",size:"sm","data-testid":"comments-toggle","data-active":v?"true":void 0,className:v?"border-primary/40 bg-primary/15 text-primary":void 0,onClick:u,children:["Comments (",m,")"]}),e.jsx(D,{variant:"outline",size:"sm",onClick:$,disabled:P||T,children:T?"Starting…":P?"Running…":"Re-run review"}),e.jsx("select",{value:p,onChange:w=>b(w.target.value),className:"h-8 rounded-lg border border-glass-edge bg-glass-l1 px-2 text-xs text-foreground outline-none focus:border-ring","aria-label":"Review verdict",children:Te.map(w=>e.jsx("option",{value:w.value,children:w.label},w.value))}),e.jsx(D,{size:"sm",onClick:z,disabled:o===0||N,children:N?"Publishing…":"Publish review"}),e.jsx(D,{variant:"ghost",size:"sm",className:"text-muted-foreground hover:text-destructive","data-testid":"review-delete-btn",onClick:()=>C(!0),children:"Delete"})]})]}),e.jsx(ie,{open:O,onOpenChange:C,reviewLabel:R,onConfirm:A}),x>0&&e.jsxs("div",{className:"flex items-center gap-3 border-t border-glass-edge/50 px-4 pb-2 pt-1.5 sm:px-6","data-testid":"pr-review-progress",children:[e.jsx(Q,{done:f,total:x,className:"max-w-xs flex-1"}),e.jsxs("span",{className:"shrink-0 font-mono text-[11px] text-muted-foreground",children:[f,"/",x," files reviewed"]})]})]})}function De({taskId:t,currentSha:s,onRefresh:a}){const[l,o]=r.useState(null),[g,n]=r.useState(!1);if(r.useEffect(()=>U(x=>{const m=x;!m.payload.taskId||m.payload.taskId!==t||(m.type==="review:head-advanced"&&m.payload.newHeadSha&&o(m.payload.newHeadSha),m.type==="review:drafts-ready"&&(o(null),a()))}),[t,a]),r.useEffect(()=>{l&&l===s&&o(null)},[l,s]),!l)return null;async function f(){n(!0);try{await F.requestReReview(t),_.success("Incremental re-review started")}catch(x){_.error(`Re-run failed: ${x.message}`)}finally{n(!1)}}return e.jsxs("div",{className:"flex items-center gap-3 bg-yellow-900/30 border-b border-yellow-600 px-6 py-2 text-sm text-yellow-300",children:[e.jsxs("span",{children:["PR head advanced to ",e.jsx("code",{className:"font-mono text-xs",children:l.slice(0,8)})]}),e.jsx(D,{variant:"outline",size:"xs",onClick:f,disabled:g,className:"border-yellow-600 text-yellow-300 hover:bg-yellow-900/50",children:g?"Starting…":"Re-run incremental review"}),e.jsx(D,{variant:"ghost",size:"xs",onClick:()=>o(null),className:"ml-auto text-yellow-400",children:"Dismiss"})]})}const X="octomux:review:comments-panel-open";function Fe(){if(typeof window>"u")return!1;try{const t=localStorage.getItem(X);if(t!==null)return t==="true"}catch{}return window.innerWidth>=1440}function Be(){var H;const{id:t}=ge(),s=ve(),[a,l]=r.useState(null),[o,g]=r.useState(null),[n,f]=r.useState([]),[x,m]=r.useState(null),[v,u]=r.useState(Fe),[P,E]=r.useState(!1),d=r.useRef(null);r.useEffect(()=>{try{localStorage.setItem(X,String(v))}catch{}},[v]);const c=r.useCallback(()=>{t&&F.getReviewDetail(t).then(l).catch(i=>g(i.message))},[t]);r.useEffect(()=>{c()},[c]),r.useEffect(()=>{if(t)return U(i=>{const h=i;!("taskId"in h.payload)||h.payload.taskId!==t||(h.type==="review:drafts-ready"||h.type==="review:published")&&c()})},[t,c]);const p=oe(t),[b,N]=r.useState(new Set),k=r.useCallback(async(i,h)=>{N(S=>{const j=new Set(S);return h?j.delete(i):j.add(i),j});try{h?await F.unmarkReviewed(t,i):await F.markReviewed(t,i)}catch{N(S=>{const j=new Set(S);return h?j.add(i):j.delete(i),j})}},[t]),T=r.useRef(!1),M=r.useCallback(i=>{if(T.current)return;T.current=!0;const h=new Set;for(const S of i.files)S.reviewed&&h.add(S.path);N(h)},[]),O=r.useMemo(()=>new Set(n),[n]),C=r.useMemo(()=>{var h;const i=(h=a==null?void 0:a.latest_run)==null?void 0:h.walkthrough;if(!i)return null;try{return JSON.parse(i)}catch{return null}},[a]),R=r.useMemo(()=>K(n,C),[n,C]),z=r.useMemo(()=>de(R),[R]),$=r.useCallback(i=>{var h;m(i),(h=d.current)==null||h.scrollToFile(i),E(!1)},[]),A=r.useCallback((i,h,S,j)=>{var L;m(i),(L=d.current)==null||L.revealLineInFile(i,h,S),p.setFocusedId(j),u(!1),window.setTimeout(()=>{p.focusedId===j&&p.setFocusedId(null)},1600)},[p]);if(o)return e.jsx("div",{className:"p-4 text-red-500 md:p-6",children:o});if(!a)return e.jsx("div",{className:"p-4 text-sm text-muted-foreground md:p-6",children:"Loading…"});const w=a.comments.filter(i=>i.status==="draft").length,Z=a.comments.filter(i=>i.status==="accepted").length,ee=a.comments.filter(i=>i.status==="stale").length,B=((H=a.latest_run)==null?void 0:H.status)==="running"||a.all_runs.some(i=>i.status==="running"),W=e.jsx(_e,{files:n,walkthrough:C,comments:a.comments,selectedPath:x,reviewedFiles:b,onToggleReviewed:k,onSelect:$}),G=e.jsx(he,{agents:[],filesInDiff:O,rangeIsBase:!0,onJumpTo:A,onClose:()=>u(!1),className:"h-full w-full max-w-none lg:w-80"});return e.jsx(ce.Provider,{value:p,children:e.jsxs("div",{className:"flex h-full min-h-0 flex-col",children:[e.jsx(De,{taskId:t,currentSha:a.task.pr_head_sha,onRefresh:c}),e.jsx(Ie,{taskId:t,prTitle:a.task.title,prNumber:a.task.pr_number,prUrl:a.task.pr_url??void 0,acceptedCount:Z,draftCount:w,staleCount:ee,reviewedDone:b.size,reviewedTotal:n.length,totalCommentsCount:p.byId.size,showCommentsPanel:v,onToggleCommentsPanel:()=>u(i=>!i),isRunning:B,onPublished:c,onReRun:c,onDeleted:()=>s("/reviews")}),C&&e.jsx(Ne,{walkthrough:C}),e.jsx(Ee,{groups:R,selectedPath:x}),e.jsxs("div",{className:"flex min-h-0 flex-1",children:[e.jsx("aside",{"data-testid":"review-file-tree-pane",className:"glass-chrome hidden w-[320px] shrink-0 flex-col overflow-hidden border-r border-glass-edge lg:flex",children:W}),e.jsxs("div",{className:"flex min-h-0 min-w-0 flex-1 flex-col",children:[e.jsxs("div",{className:"flex items-center gap-2 border-b border-glass-edge px-4 py-2 lg:hidden",children:[e.jsxs(D,{type:"button",size:"sm",variant:"outline","data-testid":"review-mobile-files-button",onClick:()=>E(!0),children:["Files",n.length>0?` (${n.length})`:""]}),x?e.jsx("span",{className:"min-w-0 truncate font-mono text-[11px] text-muted-foreground",children:x}):null]}),e.jsx(ue,{taskId:t,isRunning:B,range:{kind:"base"},listRef:d,enableComments:!0,onFilesChange:f,onSelectionChange:m,onSummaryLoaded:M,onToggleReviewed:k,hideFileTree:!0,fileOrder:z,groups:R})]}),v?e.jsx("div",{className:"hidden shrink-0 lg:flex",children:G}):null]}),v?e.jsxs("div",{className:"fixed inset-0 z-50 flex lg:hidden","data-testid":"review-mobile-comments-overlay",children:[e.jsx("button",{type:"button",className:"absolute inset-0 bg-black/60","aria-label":"Close comments",onClick:()=>u(!1)}),e.jsx("div",{className:"relative ml-auto h-full w-full max-w-sm",children:G})]}):null,e.jsx(me,{open:P,onOpenChange:E,children:e.jsxs(xe,{className:"flex max-h-[min(85dvh,100dvh)] flex-col gap-0 overflow-hidden p-0 sm:max-w-md",showCloseButton:!0,children:[e.jsx(fe,{className:"border-b border-glass-edge px-4 py-3",children:e.jsx(pe,{children:"Changed files"})}),e.jsx("div",{className:"min-h-0 flex-1 overflow-auto",children:W})]})})]})})}export{Be as default};
@@ -1 +1 @@
1
- import{b as r,j as e}from"./vendor-react-Dd26lTa7.js";import{j as u,P as C,a as g,S,f as B,s as l,R as E}from"./index-CghBwA2d.js";import{L as b}from"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";const F=["required","recommended","optional"],D={required:"Required",recommended:"Recommended",optional:"Optional"};function O(s){switch(s){case"ok":return"Ready";case"missing":return"Missing";case"outdated":return"Outdated";case"unconfigured":return"Not configured";case"optional_missing":return"Optional";default:return s}}function A(s){switch(s){case"ok":return"text-[#22C55E]";case"missing":case"outdated":return"text-red-400";case"unconfigured":return"text-[#FFB800]";default:return"text-[#8a8a8a]"}}function I({item:s,installing:x,onInstall:i}){const d=x===s.id;return e.jsxs("div",{className:"flex flex-col gap-2 py-3 sm:flex-row sm:items-start sm:justify-between",style:E,children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"text-sm font-medium text-white",children:s.label}),e.jsx("span",{className:`text-xs font-medium ${A(s.status)}`,children:O(s.status)}),s.version&&e.jsx("span",{className:"truncate font-mono text-xs text-[#8a8a8a]",children:s.version})]}),s.detail&&e.jsx("p",{className:"mt-1 text-xs text-[#b5b5bd]",children:s.detail})]}),e.jsxs("div",{className:"flex shrink-0 flex-wrap items-center gap-2",children:[s.install&&s.status!=="ok"&&e.jsx(g,{type:"button",size:"sm",variant:"outline",disabled:d,onClick:()=>i(s.install.id),"data-testid":`setup-install-${s.id}`,children:d?"Installing…":s.install.label}),s.configureUrl&&e.jsx(b,{to:s.configureUrl,className:"focus-ring rounded-md border border-glass-edge px-3 py-1.5 text-xs text-[#60a5fa] hover:bg-glass-l1",children:"Configure"}),s.docsUrl&&e.jsx("a",{href:s.docsUrl,target:"_blank",rel:"noreferrer",className:"focus-ring rounded-md px-2 py-1.5 text-xs text-[#8a8a8a] hover:text-white",children:"Docs"})]})]})}function T({initial:s,onSaved:x}){const[i,d]=r.useState(s.defaultBaseBranch??""),[m,f]=r.useState(s.deleteGraceHours??6),[c,p]=r.useState(!1),h=async()=>{p(!0);try{await u.updateSettings({defaultBaseBranch:i.trim()||void 0,deleteGraceHours:m}),l("success","DEFAULTS","Task defaults saved"),x()}catch(n){l("error","ERROR",n.message)}finally{p(!1)}};return e.jsxs("div",{className:"space-y-3 pt-2",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"setup-default-branch",className:"mb-1 block text-xs text-[#b5b5bd]",children:"Default base branch"}),e.jsx("input",{id:"setup-default-branch",type:"text",value:i,onChange:n=>d(n.target.value),placeholder:"main",className:"w-full border border-glass-edge bg-[#0B0C0F] px-3 py-2 font-mono text-sm text-white outline-none focus:border-[#3B82F6]","data-testid":"setup-default-branch"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-xs text-[#b5b5bd]",children:"Hours before deleted tasks are permanently removed"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"number",min:0,step:1,value:m,onChange:n=>f(Math.max(0,Number(n.target.value)||0)),className:"w-32 border border-glass-edge bg-[#0B0C0F] px-3 py-2 font-mono text-sm text-white outline-none focus:border-[#3B82F6]","data-testid":"setup-delete-grace-hours"}),e.jsx("span",{className:"text-xs text-[#8a8a8a]",children:"default 6"})]})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(g,{type:"button",size:"sm",disabled:c,onClick:h,"data-testid":"setup-save-defaults",children:c?"Saving…":"Save defaults"})})]})}function q(){const[s,x]=r.useState(null),[i,d]=r.useState(null),[m,f]=r.useState(!0),[c,p]=r.useState(null),[h,n]=r.useState(null),[y,j]=r.useState(!1),o=r.useCallback(async()=>{f(!0),p(null);try{const[t,a]=await Promise.all([u.getSettings(),u.getSetupStatus()]);d(t),x(a)}catch(t){p(t.message)}finally{f(!1)}},[]);r.useEffect(()=>{o()},[o]);const w=async t=>{n(t);try{const a=await u.setupInstall(t);l(a.ok?"success":"error","SETUP",a.message),await o()}catch(a){l("error","SETUP",a.message)}finally{n(null)}},N=async()=>{j(!0);try{const t=await u.applyRecommendedDefaults();d(t),l("success","DEFAULTS","Applied recommended defaults"),await o()}catch(t){l("error","ERROR",t.message)}finally{j(!1)}},R=async()=>{try{await u.updateSettings({onboardingCompletedAt:new Date().toISOString()}),l("success","SETUP","Setup reminder dismissed"),await o()}catch(t){l("error","ERROR",t.message)}},k=t=>(s==null?void 0:s.items.filter(a=>a.category===t&&a.id!=="defaults"))??[];return e.jsxs("div",{className:"flex h-full flex-col",children:[e.jsx(C,{variant:"glass",title:"Setup",description:"Install dependencies, configure defaults, and connect integrations",actions:e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(g,{type:"button",size:"sm",variant:"outline",disabled:y,onClick:N,"data-testid":"setup-apply-recommended",children:y?"Applying…":"Apply recommended defaults"}),e.jsx(g,{type:"button",size:"sm",variant:"ghost",onClick:R,children:"Dismiss reminders"})]})}),e.jsx("div",{className:"min-h-0 flex-1 overflow-auto px-6 py-6",children:e.jsxs("div",{className:"mx-auto max-w-3xl space-y-6",children:[m&&e.jsx("div",{className:"space-y-2",children:[1,2,3].map(t=>e.jsx("div",{className:"h-14 animate-pulse border border-glass-edge bg-glass-l1"},t))}),c&&e.jsxs("div",{className:"border border-red-400/30 bg-red-400/5 px-4 py-3 text-sm text-red-400",children:[c,e.jsx("button",{type:"button",className:"ml-3 text-[#3B82F6]",onClick:o,children:"Retry"})]}),!m&&!c&&s&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{"data-testid":"setup-summary",className:s.summary.ready?"border border-[#22C55E]/30 bg-[#22C55E]/5 px-4 py-3 text-sm text-[#22C55E]":"border border-[#FFB800]/30 bg-[#FFB800]/5 px-4 py-3 text-sm text-[#FFB800]",children:[s.summary.ready?"Core dependencies are ready. Optional items can be configured below.":`${s.summary.blockerCount} required item(s) still need attention before tasks can run reliably.`,s.hasBrew&&s.platform==="darwin"&&e.jsx("span",{className:"mt-1 block text-xs opacity-80",children:"Homebrew installs are available from this page."})]}),F.map(t=>{const a=k(t);return a.length===0?null:e.jsx(S,{id:`setup-${t}`,title:D[t],children:a.map(v=>e.jsx(I,{item:v,installing:h,onInstall:w},v.id))},t)}),e.jsxs(S,{id:"setup-defaults",title:"Task defaults",children:[e.jsx(B,{label:"Defaults for new tasks",description:"Base branch and trash retention for new tasks",lastRow:!0,children:e.jsx("span",{})}),i&&e.jsx(T,{initial:i,onSaved:o})]}),e.jsxs("p",{className:"text-center text-xs text-[#8a8a8a]",children:["More options in"," ",e.jsx(b,{to:"/settings",className:"text-[#60a5fa] hover:underline",children:"Settings"})," ","and"," ",e.jsx(b,{to:"/integrations",className:"text-[#60a5fa] hover:underline",children:"Integrations"}),"."]})]})]})})]})}export{q as default};
1
+ import{b as r,j as e}from"./vendor-react-Dd26lTa7.js";import{p as u,P as C,a as g,S,l as B,x as l,R as E}from"./index-DKTtIYvz.js";import{L as b}from"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";const F=["required","recommended","optional"],D={required:"Required",recommended:"Recommended",optional:"Optional"};function O(s){switch(s){case"ok":return"Ready";case"missing":return"Missing";case"outdated":return"Outdated";case"unconfigured":return"Not configured";case"optional_missing":return"Optional";default:return s}}function A(s){switch(s){case"ok":return"text-[#22C55E]";case"missing":case"outdated":return"text-red-400";case"unconfigured":return"text-[#FFB800]";default:return"text-[#8a8a8a]"}}function I({item:s,installing:x,onInstall:i}){const d=x===s.id;return e.jsxs("div",{className:"flex flex-col gap-2 py-3 sm:flex-row sm:items-start sm:justify-between",style:E,children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"text-sm font-medium text-white",children:s.label}),e.jsx("span",{className:`text-xs font-medium ${A(s.status)}`,children:O(s.status)}),s.version&&e.jsx("span",{className:"truncate font-mono text-xs text-[#8a8a8a]",children:s.version})]}),s.detail&&e.jsx("p",{className:"mt-1 text-xs text-[#b5b5bd]",children:s.detail})]}),e.jsxs("div",{className:"flex shrink-0 flex-wrap items-center gap-2",children:[s.install&&s.status!=="ok"&&e.jsx(g,{type:"button",size:"sm",variant:"outline",disabled:d,onClick:()=>i(s.install.id),"data-testid":`setup-install-${s.id}`,children:d?"Installing…":s.install.label}),s.configureUrl&&e.jsx(b,{to:s.configureUrl,className:"focus-ring rounded-md border border-glass-edge px-3 py-1.5 text-xs text-[#60a5fa] hover:bg-glass-l1",children:"Configure"}),s.docsUrl&&e.jsx("a",{href:s.docsUrl,target:"_blank",rel:"noreferrer",className:"focus-ring rounded-md px-2 py-1.5 text-xs text-[#8a8a8a] hover:text-white",children:"Docs"})]})]})}function T({initial:s,onSaved:x}){const[i,d]=r.useState(s.defaultBaseBranch??""),[m,f]=r.useState(s.deleteGraceHours??6),[c,p]=r.useState(!1),h=async()=>{p(!0);try{await u.updateSettings({defaultBaseBranch:i.trim()||void 0,deleteGraceHours:m}),l("success","DEFAULTS","Task defaults saved"),x()}catch(n){l("error","ERROR",n.message)}finally{p(!1)}};return e.jsxs("div",{className:"space-y-3 pt-2",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"setup-default-branch",className:"mb-1 block text-xs text-[#b5b5bd]",children:"Default base branch"}),e.jsx("input",{id:"setup-default-branch",type:"text",value:i,onChange:n=>d(n.target.value),placeholder:"main",className:"w-full border border-glass-edge bg-[#0B0C0F] px-3 py-2 font-mono text-sm text-white outline-none focus:border-[#3B82F6]","data-testid":"setup-default-branch"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-xs text-[#b5b5bd]",children:"Hours before deleted tasks are permanently removed"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"number",min:0,step:1,value:m,onChange:n=>f(Math.max(0,Number(n.target.value)||0)),className:"w-32 border border-glass-edge bg-[#0B0C0F] px-3 py-2 font-mono text-sm text-white outline-none focus:border-[#3B82F6]","data-testid":"setup-delete-grace-hours"}),e.jsx("span",{className:"text-xs text-[#8a8a8a]",children:"default 6"})]})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(g,{type:"button",size:"sm",disabled:c,onClick:h,"data-testid":"setup-save-defaults",children:c?"Saving…":"Save defaults"})})]})}function q(){const[s,x]=r.useState(null),[i,d]=r.useState(null),[m,f]=r.useState(!0),[c,p]=r.useState(null),[h,n]=r.useState(null),[y,j]=r.useState(!1),o=r.useCallback(async()=>{f(!0),p(null);try{const[t,a]=await Promise.all([u.getSettings(),u.getSetupStatus()]);d(t),x(a)}catch(t){p(t.message)}finally{f(!1)}},[]);r.useEffect(()=>{o()},[o]);const w=async t=>{n(t);try{const a=await u.setupInstall(t);l(a.ok?"success":"error","SETUP",a.message),await o()}catch(a){l("error","SETUP",a.message)}finally{n(null)}},N=async()=>{j(!0);try{const t=await u.applyRecommendedDefaults();d(t),l("success","DEFAULTS","Applied recommended defaults"),await o()}catch(t){l("error","ERROR",t.message)}finally{j(!1)}},R=async()=>{try{await u.updateSettings({onboardingCompletedAt:new Date().toISOString()}),l("success","SETUP","Setup reminder dismissed"),await o()}catch(t){l("error","ERROR",t.message)}},k=t=>(s==null?void 0:s.items.filter(a=>a.category===t&&a.id!=="defaults"))??[];return e.jsxs("div",{className:"flex h-full flex-col",children:[e.jsx(C,{variant:"glass",title:"Setup",description:"Install dependencies, configure defaults, and connect integrations",actions:e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(g,{type:"button",size:"sm",variant:"outline",disabled:y,onClick:N,"data-testid":"setup-apply-recommended",children:y?"Applying…":"Apply recommended defaults"}),e.jsx(g,{type:"button",size:"sm",variant:"ghost",onClick:R,children:"Dismiss reminders"})]})}),e.jsx("div",{className:"min-h-0 flex-1 overflow-auto px-6 py-6",children:e.jsxs("div",{className:"mx-auto max-w-3xl space-y-6",children:[m&&e.jsx("div",{className:"space-y-2",children:[1,2,3].map(t=>e.jsx("div",{className:"h-14 animate-pulse border border-glass-edge bg-glass-l1"},t))}),c&&e.jsxs("div",{className:"border border-red-400/30 bg-red-400/5 px-4 py-3 text-sm text-red-400",children:[c,e.jsx("button",{type:"button",className:"ml-3 text-[#3B82F6]",onClick:o,children:"Retry"})]}),!m&&!c&&s&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{"data-testid":"setup-summary",className:s.summary.ready?"border border-[#22C55E]/30 bg-[#22C55E]/5 px-4 py-3 text-sm text-[#22C55E]":"border border-[#FFB800]/30 bg-[#FFB800]/5 px-4 py-3 text-sm text-[#FFB800]",children:[s.summary.ready?"Core dependencies are ready. Optional items can be configured below.":`${s.summary.blockerCount} required item(s) still need attention before tasks can run reliably.`,s.hasBrew&&s.platform==="darwin"&&e.jsx("span",{className:"mt-1 block text-xs opacity-80",children:"Homebrew installs are available from this page."})]}),F.map(t=>{const a=k(t);return a.length===0?null:e.jsx(S,{id:`setup-${t}`,title:D[t],children:a.map(v=>e.jsx(I,{item:v,installing:h,onInstall:w},v.id))},t)}),e.jsxs(S,{id:"setup-defaults",title:"Task defaults",children:[e.jsx(B,{label:"Defaults for new tasks",description:"Base branch and trash retention for new tasks",lastRow:!0,children:e.jsx("span",{})}),i&&e.jsx(T,{initial:i,onSaved:o})]}),e.jsxs("p",{className:"text-center text-xs text-[#8a8a8a]",children:["More options in"," ",e.jsx(b,{to:"/settings",className:"text-[#60a5fa] hover:underline",children:"Settings"})," ","and"," ",e.jsx(b,{to:"/integrations",className:"text-[#60a5fa] hover:underline",children:"Integrations"}),"."]})]})]})})]})}export{q as default};
@@ -0,0 +1 @@
1
+ import{b as s,j as e}from"./vendor-react-Dd26lTa7.js";import{p as x,z as u}from"./index-DKTtIYvz.js";import{c as b,b as j}from"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";function B(){const{name:a}=b(),i=j(),[r,o]=s.useState(""),[m,h]=s.useState(!0),[f,p]=s.useState(null),[l,d]=s.useState(!1),c=s.useRef(""),n=r!==c.current;s.useEffect(()=>{a&&x.getSkill(a).then(t=>{o(t.content),c.current=t.content}).catch(t=>p(t.message)).finally(()=>h(!1))},[a]);const g=s.useCallback(async()=>{if(!(!a||!n||l)){d(!0);try{await x.updateSkill(a,{content:r}),c.current=r,u.success("Skill saved")}catch(t){u.error(t instanceof Error?t.message:"Failed to save skill")}finally{d(!1)}}},[a,r,n,l]),v=s.useCallback(()=>{n&&!window.confirm("You have unsaved changes. Discard them?")||i("/settings")},[n,i]);return m?e.jsx("div",{className:"flex h-full items-center justify-center",children:e.jsx("span",{className:"text-[#6a6a6a]",children:"Loading..."})}):f?e.jsxs("div",{className:"flex h-full flex-col items-center justify-center gap-3",children:[e.jsx("p",{className:"text-red-400",children:f}),e.jsx("button",{onClick:()=>i("/settings"),className:"text-xs text-[#3B82F6] hover:underline",children:"Back to Settings"})]}):e.jsxs("div",{className:"flex h-full flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-[#2f2f2f] px-6 py-4",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{onClick:v,className:"text-sm text-[#6a6a6a] hover:text-white",children:"←"}),e.jsx("span",{className:"font-mono text-lg font-bold",children:a}),n&&e.jsx("span",{className:"text-xs text-[#FFB800]",children:"unsaved"})]}),e.jsx("button",{onClick:g,disabled:!n||l,className:"bg-[#3B82F6] px-4 py-2 text-xs text-white disabled:opacity-50",children:l?"Saving...":"Save"})]}),e.jsx("div",{className:"flex-1 p-6",children:e.jsx("textarea",{value:r,onChange:t=>o(t.target.value),className:"h-full min-h-[500px] w-full resize-none border border-[#2f2f2f] bg-[#0A0A0A] p-4 font-mono text-sm leading-relaxed text-white outline-none focus:border-[#3B82F6]",spellCheck:!1})})]})}export{B as default};
@@ -1 +1 @@
1
- import{b as n,j as e}from"./vendor-react-Dd26lTa7.js";import{j as x,a as m}from"./index-CghBwA2d.js";import{c as N,b as y}from"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";const _={new:"new",existing:"existing",none:"none",scratch:"scratch"};function C(s){if(!s)return"—";const a=s.split("/").filter(Boolean);return a[a.length-1]||s}function u(s){if(!s)return"—";const a=new Date(s.replace(" ","T")+"Z");return Number.isNaN(a.getTime())?s:a.toLocaleString()}function O(){const{id:s}=N(),a=y(),[t,h]=n.useState(null),[i,c]=n.useState(null),[f,l]=n.useState(!1),d=n.useCallback(async()=>{if(s){c(null);try{const o=await x.getWorktree(s);h(o)}catch(o){c(o.message)}}},[s]);n.useEffect(()=>{d()},[d]);const k=n.useCallback(()=>{if(!t)return;const o=new URLSearchParams;t.worktree.repo_path&&o.set("repo",t.worktree.repo_path),o.set("mode","existing"),t.worktree.path&&o.set("worktree_path",t.worktree.path),a(`/?${o.toString()}`)},[t,a]),w=n.useCallback(async()=>{if(!t)return;const g=t.worktree.mode==="existing"||t.worktree.mode==="none"?"Forget this workspace? The filesystem directory will be left untouched; only the Octomux record is removed.":"Remove this workspace? This deletes the worktree directory and branch from disk.";if(window.confirm(g)){l(!0);try{await x.deleteWorktree(t.worktree.id),a("/workspaces")}catch(j){c(j.message),l(!1)}}},[t,a]);if(i&&!t)return e.jsx("div",{className:"h-full overflow-auto",children:e.jsxs("div",{className:"mx-auto max-w-4xl px-4 py-6 text-sm text-destructive",children:["Failed to load workspace: ",i]})});if(!t)return e.jsx("div",{className:"h-full overflow-auto",children:e.jsx("div",{className:"mx-auto max-w-4xl px-4 py-6 text-sm text-[#8a8a8a]",children:"Loading…"})});const r=t.worktree,v=r.status==="available"&&t.active_task===null&&!f,b=r.mode==="existing"||r.mode==="none";return e.jsx("div",{className:"h-full overflow-auto",children:e.jsxs("div",{className:"mx-auto max-w-4xl px-4 py-6",children:[e.jsx("button",{onClick:()=>a("/workspaces"),className:"mb-3 text-xs text-[#8a8a8a] hover:text-foreground",children:"← All workspaces"}),e.jsxs("div",{className:"mb-6 flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"min-w-0 flex flex-col gap-1.5",children:[e.jsxs("h1",{className:"font-display text-[28px] font-bold leading-tight",children:[C(r.repo_path),r.branch?e.jsx("span",{className:"ml-3 font-mono text-lg text-[#a0a0a0]",children:r.branch}):null]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs text-[#8a8a8a]",children:[e.jsx("span",{className:"inline-flex items-center px-1.5 py-0.5",style:{fontSize:10,background:"#1a1a1a",border:"1px solid #2f2f2f",color:"#a0a0a0"},children:_[r.mode]}),e.jsx("span",{className:r.status==="in_use"?"text-[#22C55E]":"",children:r.status})]}),e.jsx("div",{className:"mt-1 break-all font-mono text-xs text-[#8a8a8a]",children:r.path})]}),e.jsxs("div",{className:"flex shrink-0 flex-col items-end gap-2",children:[r.status==="available"&&e.jsx(m,{size:"sm",onClick:k,"data-testid":"new-task-on-workspace",children:"New task on this workspace"}),v&&e.jsx(m,{size:"sm",variant:"outline",onClick:w,"data-testid":"remove-workspace",children:b?"Forget workspace":"Remove workspace"})]})]}),i&&e.jsx("div",{className:"mb-4 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:i}),e.jsxs("section",{className:"mb-6",children:[e.jsx("h2",{className:"mb-2 text-xs font-bold uppercase tracking-wider text-[#8a8a8a]",children:"Active task"}),t.active_task?e.jsx(p,{task:t.active_task,onClick:()=>a(`/tasks/${t.active_task.id}`)}):e.jsx("div",{className:"rounded-md border border-border bg-card p-4 text-sm text-[#8a8a8a]",children:"No active task."})]}),e.jsxs("section",{children:[e.jsxs("h2",{className:"mb-2 text-xs font-bold uppercase tracking-wider text-[#8a8a8a]",children:["History (",t.history.length,")"]}),t.history.length===0?e.jsx("div",{className:"rounded-md border border-border bg-card p-4 text-sm text-[#8a8a8a]",children:"No past tasks."}):e.jsx("div",{className:"flex flex-col gap-2",children:t.history.map(o=>e.jsx(p,{task:o,onClick:()=>a(`/tasks/${o.id}`)},o.id))})]}),e.jsxs("div",{className:"mt-6 text-[10px] text-[#6a6a6a]",children:["Created ",u(r.created_at)," · Last used ",u(r.last_used_at)]})]})})}function p({task:s,onClick:a}){return e.jsxs("button",{type:"button",onClick:a,"data-testid":`workspace-task-${s.id}`,className:"flex w-full items-center justify-between gap-3 rounded-md border border-border bg-card px-3 py-2 text-left hover:bg-[#141414]",children:[e.jsx("div",{className:"min-w-0 flex-1 truncate text-sm text-foreground",children:s.title}),e.jsx("div",{className:"shrink-0 text-xs text-[#8a8a8a]",children:s.runtime_state})]})}export{O as default};
1
+ import{b as n,j as e}from"./vendor-react-Dd26lTa7.js";import{p as x,a as m}from"./index-DKTtIYvz.js";import{c as N,b as y}from"./vendor-router-yJbofmar.js";import"./vendor-ui-ChI1tM4e.js";import"./vendor-xterm-DvXGiZvM.js";import"./vendor-monaco-CdNyTACs.js";const _={new:"new",existing:"existing",none:"none",scratch:"scratch"};function C(s){if(!s)return"—";const a=s.split("/").filter(Boolean);return a[a.length-1]||s}function u(s){if(!s)return"—";const a=new Date(s.replace(" ","T")+"Z");return Number.isNaN(a.getTime())?s:a.toLocaleString()}function O(){const{id:s}=N(),a=y(),[t,h]=n.useState(null),[i,c]=n.useState(null),[f,l]=n.useState(!1),d=n.useCallback(async()=>{if(s){c(null);try{const o=await x.getWorktree(s);h(o)}catch(o){c(o.message)}}},[s]);n.useEffect(()=>{d()},[d]);const k=n.useCallback(()=>{if(!t)return;const o=new URLSearchParams;t.worktree.repo_path&&o.set("repo",t.worktree.repo_path),o.set("mode","existing"),t.worktree.path&&o.set("worktree_path",t.worktree.path),a(`/?${o.toString()}`)},[t,a]),w=n.useCallback(async()=>{if(!t)return;const g=t.worktree.mode==="existing"||t.worktree.mode==="none"?"Forget this workspace? The filesystem directory will be left untouched; only the Octomux record is removed.":"Remove this workspace? This deletes the worktree directory and branch from disk.";if(window.confirm(g)){l(!0);try{await x.deleteWorktree(t.worktree.id),a("/workspaces")}catch(j){c(j.message),l(!1)}}},[t,a]);if(i&&!t)return e.jsx("div",{className:"h-full overflow-auto",children:e.jsxs("div",{className:"mx-auto max-w-4xl px-4 py-6 text-sm text-destructive",children:["Failed to load workspace: ",i]})});if(!t)return e.jsx("div",{className:"h-full overflow-auto",children:e.jsx("div",{className:"mx-auto max-w-4xl px-4 py-6 text-sm text-[#8a8a8a]",children:"Loading…"})});const r=t.worktree,v=r.status==="available"&&t.active_task===null&&!f,b=r.mode==="existing"||r.mode==="none";return e.jsx("div",{className:"h-full overflow-auto",children:e.jsxs("div",{className:"mx-auto max-w-4xl px-4 py-6",children:[e.jsx("button",{onClick:()=>a("/workspaces"),className:"mb-3 text-xs text-[#8a8a8a] hover:text-foreground",children:"← All workspaces"}),e.jsxs("div",{className:"mb-6 flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"min-w-0 flex flex-col gap-1.5",children:[e.jsxs("h1",{className:"font-display text-[28px] font-bold leading-tight",children:[C(r.repo_path),r.branch?e.jsx("span",{className:"ml-3 font-mono text-lg text-[#a0a0a0]",children:r.branch}):null]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs text-[#8a8a8a]",children:[e.jsx("span",{className:"inline-flex items-center px-1.5 py-0.5",style:{fontSize:10,background:"#1a1a1a",border:"1px solid #2f2f2f",color:"#a0a0a0"},children:_[r.mode]}),e.jsx("span",{className:r.status==="in_use"?"text-[#22C55E]":"",children:r.status})]}),e.jsx("div",{className:"mt-1 break-all font-mono text-xs text-[#8a8a8a]",children:r.path})]}),e.jsxs("div",{className:"flex shrink-0 flex-col items-end gap-2",children:[r.status==="available"&&e.jsx(m,{size:"sm",onClick:k,"data-testid":"new-task-on-workspace",children:"New task on this workspace"}),v&&e.jsx(m,{size:"sm",variant:"outline",onClick:w,"data-testid":"remove-workspace",children:b?"Forget workspace":"Remove workspace"})]})]}),i&&e.jsx("div",{className:"mb-4 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:i}),e.jsxs("section",{className:"mb-6",children:[e.jsx("h2",{className:"mb-2 text-xs font-bold uppercase tracking-wider text-[#8a8a8a]",children:"Active task"}),t.active_task?e.jsx(p,{task:t.active_task,onClick:()=>a(`/tasks/${t.active_task.id}`)}):e.jsx("div",{className:"rounded-md border border-border bg-card p-4 text-sm text-[#8a8a8a]",children:"No active task."})]}),e.jsxs("section",{children:[e.jsxs("h2",{className:"mb-2 text-xs font-bold uppercase tracking-wider text-[#8a8a8a]",children:["History (",t.history.length,")"]}),t.history.length===0?e.jsx("div",{className:"rounded-md border border-border bg-card p-4 text-sm text-[#8a8a8a]",children:"No past tasks."}):e.jsx("div",{className:"flex flex-col gap-2",children:t.history.map(o=>e.jsx(p,{task:o,onClick:()=>a(`/tasks/${o.id}`)},o.id))})]}),e.jsxs("div",{className:"mt-6 text-[10px] text-[#6a6a6a]",children:["Created ",u(r.created_at)," · Last used ",u(r.last_used_at)]})]})})}function p({task:s,onClick:a}){return e.jsxs("button",{type:"button",onClick:a,"data-testid":`workspace-task-${s.id}`,className:"flex w-full items-center justify-between gap-3 rounded-md border border-border bg-card px-3 py-2 text-left hover:bg-[#141414]",children:[e.jsx("div",{className:"min-w-0 flex-1 truncate text-sm text-foreground",children:s.title}),e.jsx("div",{className:"shrink-0 text-xs text-[#8a8a8a]",children:s.runtime_state})]})}export{O as default};