tmux-ide 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -9
- package/bin/cli.js +1024 -519
- package/bin/cli.ts +63 -6
- package/bunfig.toml +4 -0
- package/package.json +18 -7
- package/packages/contracts/package.json +22 -0
- package/packages/contracts/src/__tests__/ide-config.test.ts +46 -0
- package/packages/contracts/src/__tests__/terminals.test.ts +87 -0
- package/packages/contracts/src/actions-contract.ts +310 -0
- package/packages/contracts/src/actions-errors.ts +41 -0
- package/packages/contracts/src/domain.ts +36 -0
- package/packages/contracts/src/ide-config.ts +170 -0
- package/packages/contracts/src/index.ts +24 -0
- package/packages/contracts/src/lib-internal/auth.ts +13 -0
- package/packages/contracts/src/lib-internal/hq.ts +38 -0
- package/packages/contracts/src/terminals.ts +116 -0
- package/packages/contracts/src/tmux.ts +60 -0
- package/packages/contracts/src/workspace.ts +67 -0
- package/packages/daemon/dist/agent-explain.d.ts +8 -1
- package/packages/daemon/dist/agent-explain.js +19 -3
- package/packages/daemon/dist/lib/tui-binary.d.ts +57 -0
- package/packages/daemon/dist/lib/tui-binary.js +130 -0
- package/packages/daemon/dist/widgets/explorer/breadcrumbs.d.ts +1 -1
- package/packages/daemon/dist/widgets/explorer/footer.d.ts +1 -1
- package/packages/daemon/dist/widgets/explorer/tree.d.ts +1 -1
- package/packages/daemon/dist/widgets/lib/help-overlay.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/agent-naming.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/config-tree.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/detect-panel.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/field-editor.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/footer.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/layout-picker.d.ts +1 -1
- package/packages/daemon/src/agent-explain.ts +298 -0
- package/packages/daemon/src/attach.ts +20 -0
- package/packages/daemon/src/bin.ts +4 -0
- package/packages/daemon/src/canonical.ts +7 -0
- package/packages/daemon/src/cli.ts +499 -0
- package/packages/daemon/src/command-center/actions/contract.ts +2 -0
- package/packages/daemon/src/command-center/actions/dispatcher.ts +137 -0
- package/packages/daemon/src/command-center/actions/errors.ts +105 -0
- package/packages/daemon/src/command-center/actions/handlers/_project-context.ts +30 -0
- package/packages/daemon/src/command-center/actions/handlers/_resolve-project.ts +78 -0
- package/packages/daemon/src/command-center/actions/handlers/app-set-remote-access.ts +118 -0
- package/packages/daemon/src/command-center/actions/handlers/config-actions.ts +113 -0
- package/packages/daemon/src/command-center/actions/handlers/daemon-shutdown.ts +38 -0
- package/packages/daemon/src/command-center/actions/handlers/project-activate.ts +30 -0
- package/packages/daemon/src/command-center/actions/handlers/project-launch.ts +70 -0
- package/packages/daemon/src/command-center/actions/handlers/project-open-terminal.ts +87 -0
- package/packages/daemon/src/command-center/actions/handlers/project-restart.ts +38 -0
- package/packages/daemon/src/command-center/actions/handlers/project-stop.ts +62 -0
- package/packages/daemon/src/command-center/actions/handlers/terminal-respawn.ts +119 -0
- package/packages/daemon/src/command-center/actions/handlers/terminal-stop.ts +35 -0
- package/packages/daemon/src/command-center/actions/registry.ts +149 -0
- package/packages/daemon/src/command-center/discovery.ts +96 -0
- package/packages/daemon/src/command-center/index.ts +31 -0
- package/packages/daemon/src/command-center/schemas.ts +85 -0
- package/packages/daemon/src/command-center/server.ts +1260 -0
- package/packages/daemon/src/command-center/ws-events.ts +316 -0
- package/packages/daemon/src/config.ts +549 -0
- package/packages/daemon/src/detect.ts +248 -0
- package/packages/daemon/src/doctor.ts +242 -0
- package/packages/daemon/src/embed.ts +5 -0
- package/packages/daemon/src/index.ts +12 -0
- package/packages/daemon/src/init.ts +211 -0
- package/packages/daemon/src/inspect.ts +178 -0
- package/packages/daemon/src/js-yaml.d.ts +10 -0
- package/packages/daemon/src/launch.ts +349 -0
- package/packages/daemon/src/lib/active-projects.ts +49 -0
- package/packages/daemon/src/lib/agent-discovery.ts +121 -0
- package/packages/daemon/src/lib/app-config.ts +427 -0
- package/packages/daemon/src/lib/app-settings.ts +53 -0
- package/packages/daemon/src/lib/auth/auth-service.ts +227 -0
- package/packages/daemon/src/lib/auth/middleware.ts +56 -0
- package/packages/daemon/src/lib/auth/types.ts +2 -0
- package/packages/daemon/src/lib/auth-token.ts +5 -0
- package/packages/daemon/src/lib/authorship.ts +280 -0
- package/packages/daemon/src/lib/canonical-daemon.ts +122 -0
- package/packages/daemon/src/lib/cli-action-bridge.ts +216 -0
- package/packages/daemon/src/lib/daemon-embed.ts +782 -0
- package/packages/daemon/src/lib/daemon-watchdog.ts +111 -0
- package/packages/daemon/src/lib/daemon.ts +79 -0
- package/packages/daemon/src/lib/dot-path.ts +17 -0
- package/packages/daemon/src/lib/errors.ts +67 -0
- package/packages/daemon/src/lib/filesystem-browser.ts +292 -0
- package/packages/daemon/src/lib/launch-plan.ts +90 -0
- package/packages/daemon/src/lib/log.ts +134 -0
- package/packages/daemon/src/lib/output.ts +76 -0
- package/packages/daemon/src/lib/project-init-runner.ts +150 -0
- package/packages/daemon/src/lib/project-inspect.ts +80 -0
- package/packages/daemon/src/lib/project-onboard.ts +149 -0
- package/packages/daemon/src/lib/project-probe.ts +92 -0
- package/packages/daemon/src/lib/project-registry.ts +296 -0
- package/packages/daemon/src/lib/session-monitor.ts +122 -0
- package/packages/daemon/src/lib/session-options.ts +100 -0
- package/packages/daemon/src/lib/shell.ts +8 -0
- package/packages/daemon/src/lib/sizes.ts +36 -0
- package/packages/daemon/src/lib/skill-sync.ts +155 -0
- package/packages/daemon/src/lib/slugify.ts +10 -0
- package/packages/daemon/src/lib/terminals-store.ts +125 -0
- package/packages/daemon/src/lib/tui-binary.ts +165 -0
- package/packages/daemon/src/lib/update-check.ts +298 -0
- package/packages/daemon/src/lib/update.ts +158 -0
- package/packages/daemon/src/lib/workspace-registry.ts +229 -0
- package/packages/daemon/src/lib/worktree.ts +289 -0
- package/packages/daemon/src/lib/yaml-io.ts +27 -0
- package/packages/daemon/src/ls.ts +40 -0
- package/packages/daemon/src/restart.ts +24 -0
- package/packages/daemon/src/restore.ts +514 -0
- package/packages/daemon/src/schemas/domain.ts +2 -0
- package/packages/daemon/src/schemas/filesystem.ts +34 -0
- package/packages/daemon/src/schemas/ide-config.ts +2 -0
- package/packages/daemon/src/schemas/index.ts +59 -0
- package/packages/daemon/src/schemas/inspect.ts +67 -0
- package/packages/daemon/src/schemas/registry.ts +55 -0
- package/packages/daemon/src/schemas/ws-events.ts +135 -0
- package/packages/daemon/src/send.ts +171 -0
- package/packages/daemon/src/server/README.md +15 -0
- package/packages/daemon/src/server/index.ts +74 -0
- package/packages/daemon/src/server/pty-bridge.ts +532 -0
- package/packages/daemon/src/server/standalone.ts +18 -0
- package/packages/daemon/src/server/ws-route.ts +483 -0
- package/packages/daemon/src/status.ts +59 -0
- package/packages/daemon/src/stop.ts +28 -0
- package/packages/daemon/src/terminal/NodePtyAdapter.ts +271 -0
- package/packages/daemon/src/terminal/PtyAdapter.ts +140 -0
- package/packages/daemon/src/terminal/README.md +92 -0
- package/packages/daemon/src/tui/chrome/cheatsheet.ts +260 -0
- package/packages/daemon/src/tui/chrome/chip.ts +30 -0
- package/packages/daemon/src/tui/chrome/events.ts +119 -0
- package/packages/daemon/src/tui/chrome/kitty-keys.ts +55 -0
- package/packages/daemon/src/tui/chrome/menu.ts +289 -0
- package/packages/daemon/src/tui/chrome/notify.ts +382 -0
- package/packages/daemon/src/tui/chrome/panels.ts +111 -0
- package/packages/daemon/src/tui/chrome/sidebar.ts +222 -0
- package/packages/daemon/src/tui/chrome/snapshot.ts +425 -0
- package/packages/daemon/src/tui/chrome/statusline.ts +595 -0
- package/packages/daemon/src/tui/chrome/updater.ts +510 -0
- package/packages/daemon/src/tui/chrome/welcome.ts +124 -0
- package/packages/daemon/src/tui/compiled.ts +121 -0
- package/packages/daemon/src/tui/detect/classify.ts +208 -0
- package/packages/daemon/src/tui/detect/manifest-loader.ts +193 -0
- package/packages/daemon/src/tui/detect/manifest.ts +199 -0
- package/packages/daemon/src/tui/detect/manifests.ts +354 -0
- package/packages/daemon/src/tui/detect/process-tree.ts +217 -0
- package/packages/daemon/src/tui/detect/snapshot.ts +70 -0
- package/packages/daemon/src/tui/integrations/claude.ts +176 -0
- package/packages/daemon/src/tui/integrations/offer.ts +145 -0
- package/packages/daemon/src/tui/main.ts +82 -0
- package/packages/daemon/src/tui/mirror/ack-writer.ts +77 -0
- package/packages/daemon/src/tui/mirror/agent-chip.ts +97 -0
- package/packages/daemon/src/tui/mirror/agent-rows.ts +133 -0
- package/packages/daemon/src/tui/mirror/app-state.ts +179 -0
- package/packages/daemon/src/tui/mirror/app.tsx +5265 -0
- package/packages/daemon/src/tui/mirror/blit.ts +186 -0
- package/packages/daemon/src/tui/mirror/control-client.ts +214 -0
- package/packages/daemon/src/tui/mirror/control.ts +97 -0
- package/packages/daemon/src/tui/mirror/dialog-model.ts +298 -0
- package/packages/daemon/src/tui/mirror/dialog-stack.ts +354 -0
- package/packages/daemon/src/tui/mirror/diff-model.ts +112 -0
- package/packages/daemon/src/tui/mirror/editor-buffer.ts +117 -0
- package/packages/daemon/src/tui/mirror/file-tree.ts +97 -0
- package/packages/daemon/src/tui/mirror/focus-border.ts +57 -0
- package/packages/daemon/src/tui/mirror/folder-picker.ts +124 -0
- package/packages/daemon/src/tui/mirror/home-model.ts +174 -0
- package/packages/daemon/src/tui/mirror/input-coalescer.ts +105 -0
- package/packages/daemon/src/tui/mirror/menu-model.ts +187 -0
- package/packages/daemon/src/tui/mirror/palette.ts +274 -0
- package/packages/daemon/src/tui/mirror/pane-mirror.ts +561 -0
- package/packages/daemon/src/tui/mirror/pane-surface.tsx +415 -0
- package/packages/daemon/src/tui/mirror/perf-tap.ts +160 -0
- package/packages/daemon/src/tui/mirror/resize-model.ts +85 -0
- package/packages/daemon/src/tui/mirror/scrollbar-model.ts +88 -0
- package/packages/daemon/src/tui/mirror/search-model.ts +70 -0
- package/packages/daemon/src/tui/mirror/selection.ts +262 -0
- package/packages/daemon/src/tui/mirror/session-mirror.ts +443 -0
- package/packages/daemon/src/tui/mirror/settings-model.ts +345 -0
- package/packages/daemon/src/tui/mirror/size-truth.ts +77 -0
- package/packages/daemon/src/tui/mirror/spans.ts +46 -0
- package/packages/daemon/src/tui/mirror/status-grammar.ts +32 -0
- package/packages/daemon/src/tui/team/CONTROL.md +50 -0
- package/packages/daemon/src/tui/team/entry.ts +38 -0
- package/packages/daemon/src/tui/team/fuzzy.ts +133 -0
- package/packages/daemon/src/tui/team/home.ts +170 -0
- package/packages/daemon/src/tui/team/index.tsx +1521 -0
- package/packages/daemon/src/tui/team/input.ts +34 -0
- package/packages/daemon/src/tui/team/keymap.ts +127 -0
- package/packages/daemon/src/tui/team/mouse.ts +29 -0
- package/packages/daemon/src/tui/team/nav.ts +31 -0
- package/packages/daemon/src/tui/team/preview.ts +34 -0
- package/packages/daemon/src/tui/team/projects.ts +191 -0
- package/packages/daemon/src/tui/team/report.ts +83 -0
- package/packages/daemon/src/tui/team/sessions.ts +433 -0
- package/packages/daemon/src/tui/team/tree.ts +62 -0
- package/packages/daemon/src/types.ts +13 -0
- package/packages/daemon/src/ui/index.ts +32 -0
- package/packages/daemon/src/ui/terminal/index.ts +9 -0
- package/packages/daemon/src/ui/types.ts +91 -0
- package/packages/daemon/src/ui/web/base.css +80 -0
- package/packages/daemon/src/ui/web/components/Box.tsx +59 -0
- package/packages/daemon/src/ui/web/components/Input.tsx +32 -0
- package/packages/daemon/src/ui/web/components/ScrollBox.tsx +60 -0
- package/packages/daemon/src/ui/web/components/Text.tsx +28 -0
- package/packages/daemon/src/ui/web/hooks.ts +106 -0
- package/packages/daemon/src/ui/web/index.ts +27 -0
- package/packages/daemon/src/ui/web/render.ts +77 -0
- package/packages/daemon/src/ui/web/utils/color.ts +27 -0
- package/packages/daemon/src/validate.ts +217 -0
- package/packages/daemon/src/widgets/changes/README.md +3 -0
- package/packages/daemon/src/widgets/changes/index.tsx +691 -0
- package/packages/daemon/src/widgets/config/README.md +3 -0
- package/packages/daemon/src/widgets/config/index.tsx +481 -0
- package/packages/daemon/src/widgets/explorer/README.md +3 -0
- package/packages/daemon/src/widgets/explorer/breadcrumbs.tsx +77 -0
- package/packages/daemon/src/widgets/explorer/footer.tsx +20 -0
- package/packages/daemon/src/widgets/explorer/header.tsx +23 -0
- package/packages/daemon/src/widgets/explorer/index.tsx +456 -0
- package/packages/daemon/src/widgets/explorer/tree-model.ts +103 -0
- package/packages/daemon/src/widgets/explorer/tree.tsx +165 -0
- package/packages/daemon/src/widgets/lib/config-model.ts +116 -0
- package/packages/daemon/src/widgets/lib/files.ts +88 -0
- package/packages/daemon/src/widgets/lib/git.ts +88 -0
- package/packages/daemon/src/widgets/lib/grammar.ts +126 -0
- package/packages/daemon/src/widgets/lib/help-overlay.tsx +101 -0
- package/packages/daemon/src/widgets/lib/pane-comms.ts +209 -0
- package/packages/daemon/src/widgets/lib/theme.ts +194 -0
- package/packages/daemon/src/widgets/lib/watcher.ts +132 -0
- package/packages/daemon/src/widgets/preview/README.md +3 -0
- package/packages/daemon/src/widgets/preview/index.tsx +416 -0
- package/packages/daemon/src/widgets/resolve.ts +121 -0
- package/packages/daemon/src/widgets/setup/README.md +3 -0
- package/packages/daemon/src/widgets/setup/agent-naming.tsx +112 -0
- package/packages/daemon/src/widgets/setup/config-tree.tsx +246 -0
- package/packages/daemon/src/widgets/setup/detect-panel.tsx +72 -0
- package/packages/daemon/src/widgets/setup/field-editor.tsx +265 -0
- package/packages/daemon/src/widgets/setup/footer.tsx +107 -0
- package/packages/daemon/src/widgets/setup/index.tsx +341 -0
- package/packages/daemon/src/widgets/setup/layout-picker.tsx +96 -0
- package/packages/daemon/src/widgets/setup/orchestrator-panel.tsx +200 -0
- package/packages/daemon/src/widgets/setup/review-panel.tsx +140 -0
- package/packages/daemon/src/widgets/setup/setup-model.ts +188 -0
- package/packages/daemon/src/widgets/sidebar/index.tsx +527 -0
- package/packages/tmux-bridge/package.json +22 -0
- package/packages/tmux-bridge/src/errors.ts +28 -0
- package/packages/tmux-bridge/src/index.ts +31 -0
- package/packages/tmux-bridge/src/monitor.ts +77 -0
- package/packages/tmux-bridge/src/panes.ts +136 -0
- package/packages/tmux-bridge/src/runner.test.ts +501 -0
- package/packages/tmux-bridge/src/runner.ts +91 -0
- package/packages/tmux-bridge/src/sessions.ts +126 -0
- package/packages/tmux-bridge/src/targeting.test.ts +107 -0
- package/packages/tmux-bridge/src/targeting.ts +90 -0
- package/scripts/build-tui.mjs +11 -4
- package/scripts/perf-mirror.mjs +313 -0
- package/scripts/postinstall.js +26 -2
- package/skill/SKILL.md +22 -0
- package/templates/AGENTS.md +14 -7
- package/templates/agent-team-monorepo.yml +8 -0
- package/templates/agent-team-nextjs.yml +8 -0
- package/templates/agent-team.yml +10 -0
- package/templates/convex.yml +2 -0
- package/templates/default.yml +11 -5
- package/templates/go.yml +4 -0
- package/templates/missions.yml +6 -0
- package/templates/nextjs.yml +4 -0
- package/templates/python.yml +4 -0
- package/templates/skills/backend.md +5 -12
- package/templates/skills/frontend.md +5 -12
- package/templates/skills/general-worker.md +5 -12
- package/templates/skills/researcher.md +7 -12
- package/templates/skills/reviewer.md +7 -16
- package/templates/vite.yml +4 -0
package/bin/cli.js
CHANGED
|
@@ -1628,7 +1628,7 @@ var init_manifest = __esm({
|
|
|
1628
1628
|
});
|
|
1629
1629
|
|
|
1630
1630
|
// packages/daemon/src/tui/detect/manifests.ts
|
|
1631
|
-
var BRAILLE_SPINNER, CLAUDE, CODEX, OPENCODE, GEMINI, AIDER, COPILOT, SHELL, BUNDLED_MANIFESTS;
|
|
1631
|
+
var BRAILLE_SPINNER, CLAUDE, CODEX, OPENCODE, GEMINI, AIDER, COPILOT, CURSOR, GOOSE, AMP, SHELL, BUNDLED_MANIFESTS;
|
|
1632
1632
|
var init_manifests = __esm({
|
|
1633
1633
|
"packages/daemon/src/tui/detect/manifests.ts"() {
|
|
1634
1634
|
"use strict";
|
|
@@ -1636,6 +1636,7 @@ var init_manifests = __esm({
|
|
|
1636
1636
|
CLAUDE = {
|
|
1637
1637
|
id: "claude",
|
|
1638
1638
|
commands: ["claude"],
|
|
1639
|
+
confidence: "tuned",
|
|
1639
1640
|
states: {
|
|
1640
1641
|
// Approval / confirmation prompts — Claude is waiting on the user.
|
|
1641
1642
|
// Claude's approval UI is a bordered box asking a "Do you want …?" question
|
|
@@ -1682,40 +1683,56 @@ var init_manifests = __esm({
|
|
|
1682
1683
|
};
|
|
1683
1684
|
CODEX = {
|
|
1684
1685
|
id: "codex",
|
|
1685
|
-
commands: ["codex"],
|
|
1686
|
+
commands: ["codex", "codex.exe"],
|
|
1687
|
+
confidence: "tuned",
|
|
1686
1688
|
states: {
|
|
1689
|
+
// TUNED against real captures (codex-cli v0.142.5, driven through a turn).
|
|
1690
|
+
// The command-approval dialog and the directory-trust prompt are the two
|
|
1691
|
+
// "blocked" screens. Codex's approval menu uses a "› 1." numbered arrow —
|
|
1692
|
+
// note the arrow is "›" (U+203A), NOT claude's "❯".
|
|
1687
1693
|
blocked: {
|
|
1688
1694
|
any: [
|
|
1689
|
-
//
|
|
1690
|
-
//
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
{ region: "bottom", contains: "
|
|
1694
|
-
|
|
1695
|
-
{ region: "bottom", contains: "
|
|
1695
|
+
// seen (command approval): "Would you like to run the following
|
|
1696
|
+
// command?" above a "$ <cmd>" preview and the numbered menu.
|
|
1697
|
+
{ region: "bottom", contains: "Would you like to run", caseInsensitive: true },
|
|
1698
|
+
// seen: the highlighted approval option "› 1. Yes, proceed".
|
|
1699
|
+
{ region: "bottom", contains: "Yes, proceed" },
|
|
1700
|
+
// seen: "3. No, and tell Codex what to do differently (esc)".
|
|
1701
|
+
{ region: "bottom", contains: "No, and tell Codex" },
|
|
1702
|
+
// seen: the confirm footer under the approval menu.
|
|
1703
|
+
{ region: "bottom", contains: "Press enter to confirm", caseInsensitive: true },
|
|
1704
|
+
// seen (directory-trust prompt on first launch in an untrusted dir):
|
|
1705
|
+
// "Do you trust the contents of this directory?" + "1. Yes, continue".
|
|
1706
|
+
{ region: "bottom", contains: "Do you trust the contents", caseInsensitive: true }
|
|
1696
1707
|
]
|
|
1697
1708
|
},
|
|
1698
1709
|
working: {
|
|
1699
1710
|
any: [
|
|
1700
|
-
//
|
|
1701
|
-
//
|
|
1702
|
-
// the
|
|
1711
|
+
// seen (verbatim): the working status line is
|
|
1712
|
+
// "• Working (6s • esc to interrupt)".
|
|
1713
|
+
// Both the "Working (" prefix and the shared "esc to interrupt" hint
|
|
1714
|
+
// are present for the whole turn.
|
|
1715
|
+
{ region: "bottom", regex: "Working \\(\\d" },
|
|
1703
1716
|
{ region: "bottom", contains: "esc to interrupt", caseInsensitive: true },
|
|
1704
1717
|
{ region: "bottom", regex: BRAILLE_SPINNER },
|
|
1705
1718
|
{ region: "title", regex: BRAILLE_SPINNER }
|
|
1706
1719
|
]
|
|
1707
1720
|
}
|
|
1708
|
-
// done: omitted. NOTE (seen, NOT used):
|
|
1709
|
-
//
|
|
1710
|
-
// "
|
|
1711
|
-
//
|
|
1721
|
+
// done: omitted. NOTE (seen, NOT used): a finished turn leaves the agent's
|
|
1722
|
+
// answer above the idle "›" input box (placeholder "Find and fix a bug in
|
|
1723
|
+
// @filename") and a "gpt-5.5 xhigh · <cwd>" status line; older builds also
|
|
1724
|
+
// showed "Goal achieved (5m)". None are working/blocked evidence, so codex
|
|
1725
|
+
// correctly falls through to idle and the classifier infers done.
|
|
1712
1726
|
}
|
|
1713
1727
|
};
|
|
1714
1728
|
OPENCODE = {
|
|
1715
1729
|
id: "opencode",
|
|
1716
|
-
commands: ["opencode"],
|
|
1730
|
+
commands: ["opencode", "opencode.exe"],
|
|
1731
|
+
confidence: "conservative",
|
|
1717
1732
|
states: {
|
|
1718
|
-
//
|
|
1733
|
+
// conservative — a live capture was attempted (opencode v1.17.10) but its
|
|
1734
|
+
// local auth DB errored ("no such column: name") and the TUI rendered
|
|
1735
|
+
// blank, so these stay best-effort. High-precision only.
|
|
1719
1736
|
blocked: {
|
|
1720
1737
|
any: [
|
|
1721
1738
|
{ region: "bottom", contains: "(y/n)", caseInsensitive: true },
|
|
@@ -1735,8 +1752,10 @@ var init_manifests = __esm({
|
|
|
1735
1752
|
GEMINI = {
|
|
1736
1753
|
id: "gemini",
|
|
1737
1754
|
commands: ["gemini"],
|
|
1755
|
+
confidence: "conservative",
|
|
1738
1756
|
states: {
|
|
1739
|
-
//
|
|
1757
|
+
// conservative — gemini-cli needs a Google account/API key to reach a
|
|
1758
|
+
// working state, so no live capture was taken. High-precision only.
|
|
1740
1759
|
blocked: {
|
|
1741
1760
|
any: [
|
|
1742
1761
|
{ region: "bottom", contains: "(y/n)", caseInsensitive: true },
|
|
@@ -1758,28 +1777,43 @@ var init_manifests = __esm({
|
|
|
1758
1777
|
AIDER = {
|
|
1759
1778
|
id: "aider",
|
|
1760
1779
|
commands: ["aider"],
|
|
1780
|
+
confidence: "tuned",
|
|
1761
1781
|
states: {
|
|
1762
|
-
//
|
|
1763
|
-
//
|
|
1782
|
+
// TUNED from aider's installed source (v0.86.2). Every confirmation renders
|
|
1783
|
+
// through `io.confirm_ask` (io.py), which appends the literal option string
|
|
1784
|
+
// " (Y)es/(N)o" (plus "/(A)ll/(S)kip all" or "/(D)on't ask again") and a
|
|
1785
|
+
// "[Yes]:"/"[No]:" default — so "(Y)es/(N)o" is aider's exact, universal
|
|
1786
|
+
// blocked marker. The specific questions below are verbatim from
|
|
1787
|
+
// base_coder.py / commands.py.
|
|
1764
1788
|
blocked: {
|
|
1765
1789
|
any: [
|
|
1766
1790
|
{ region: "bottom", contains: "(Y)es/(N)o", caseInsensitive: true },
|
|
1767
|
-
{ region: "bottom", contains: "
|
|
1768
|
-
{ region: "bottom", contains: "
|
|
1791
|
+
{ region: "bottom", contains: "Add file to the chat", caseInsensitive: true },
|
|
1792
|
+
{ region: "bottom", contains: "Allow edits to file", caseInsensitive: true },
|
|
1793
|
+
{ region: "bottom", contains: "Add command output to the chat", caseInsensitive: true },
|
|
1794
|
+
{ region: "bottom", contains: "Run pip install", caseInsensitive: true }
|
|
1769
1795
|
]
|
|
1770
1796
|
},
|
|
1771
|
-
//
|
|
1772
|
-
//
|
|
1797
|
+
// TUNED: while a turn runs aider shows a `WaitingSpinner` (waiting.py)
|
|
1798
|
+
// rendered as "[░█ ] Waiting for <model>" — the text is literally
|
|
1799
|
+
// "Waiting for LLM" or "Waiting for " + the model name (base_coder.py:1440).
|
|
1800
|
+
// aider's spinner uses a "░█" scanner, NOT braille, so "Waiting for " is the
|
|
1801
|
+
// real invariant; the braille probe is kept only as a harmless fallback.
|
|
1773
1802
|
working: {
|
|
1774
|
-
any: [
|
|
1803
|
+
any: [
|
|
1804
|
+
{ region: "bottom", contains: "Waiting for ", caseInsensitive: false },
|
|
1805
|
+
{ region: "bottom", regex: BRAILLE_SPINNER }
|
|
1806
|
+
]
|
|
1775
1807
|
}
|
|
1776
1808
|
}
|
|
1777
1809
|
};
|
|
1778
1810
|
COPILOT = {
|
|
1779
1811
|
id: "copilot",
|
|
1780
1812
|
commands: ["copilot", "github-copilot", "github-copilot-cli"],
|
|
1813
|
+
confidence: "conservative",
|
|
1781
1814
|
states: {
|
|
1782
|
-
//
|
|
1815
|
+
// conservative — github-copilot-cli needs a GitHub account, so no live
|
|
1816
|
+
// capture was taken. High-precision only.
|
|
1783
1817
|
blocked: {
|
|
1784
1818
|
any: [
|
|
1785
1819
|
{ region: "bottom", contains: "(y/n)", caseInsensitive: true },
|
|
@@ -1796,9 +1830,89 @@ var init_manifests = __esm({
|
|
|
1796
1830
|
}
|
|
1797
1831
|
}
|
|
1798
1832
|
};
|
|
1833
|
+
CURSOR = {
|
|
1834
|
+
id: "cursor",
|
|
1835
|
+
commands: ["cursor-agent", "cursor"],
|
|
1836
|
+
confidence: "conservative",
|
|
1837
|
+
states: {
|
|
1838
|
+
// conservative — cursor-agent (Cursor CLI) was launched live but sits on a
|
|
1839
|
+
// "Press any key to log in…" pre-auth screen without an account, so no
|
|
1840
|
+
// working/blocked turn could be captured. The pre-auth splash ("Cursor
|
|
1841
|
+
// Agent" / "Press any key to log in") is idle chrome and deliberately NOT
|
|
1842
|
+
// matched here. Markers below are high-precision guesses from public
|
|
1843
|
+
// knowledge of its approval/streaming UI. NOTE: cursor-agent runs under
|
|
1844
|
+
// `node`, so it resolves via the process-tree (argv0 basename), not the
|
|
1845
|
+
// pane's `current_command`.
|
|
1846
|
+
blocked: {
|
|
1847
|
+
any: [
|
|
1848
|
+
{ region: "bottom", contains: "Do you want", caseInsensitive: false },
|
|
1849
|
+
{ region: "bottom", contains: "Run this command", caseInsensitive: true },
|
|
1850
|
+
{ region: "bottom", contains: "Apply this edit", caseInsensitive: true },
|
|
1851
|
+
{ region: "bottom", contains: "(y/n)", caseInsensitive: true }
|
|
1852
|
+
]
|
|
1853
|
+
},
|
|
1854
|
+
working: {
|
|
1855
|
+
any: [
|
|
1856
|
+
{ region: "bottom", contains: "esc to interrupt", caseInsensitive: true },
|
|
1857
|
+
{ region: "bottom", regex: BRAILLE_SPINNER },
|
|
1858
|
+
{ region: "title", regex: BRAILLE_SPINNER }
|
|
1859
|
+
]
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
};
|
|
1863
|
+
GOOSE = {
|
|
1864
|
+
id: "goose",
|
|
1865
|
+
commands: ["goose"],
|
|
1866
|
+
confidence: "conservative",
|
|
1867
|
+
states: {
|
|
1868
|
+
// conservative — Block's goose CLI needs a configured provider, so no live
|
|
1869
|
+
// capture was taken. High-precision only; markers are best-effort from
|
|
1870
|
+
// public knowledge of its confirmation/streaming UI.
|
|
1871
|
+
blocked: {
|
|
1872
|
+
any: [
|
|
1873
|
+
{ region: "bottom", contains: "Do you want", caseInsensitive: false },
|
|
1874
|
+
{ region: "bottom", contains: "Allow this tool", caseInsensitive: true },
|
|
1875
|
+
{ region: "bottom", contains: "(y/n)", caseInsensitive: true },
|
|
1876
|
+
{ region: "bottom", contains: "[y/n]", caseInsensitive: true }
|
|
1877
|
+
]
|
|
1878
|
+
},
|
|
1879
|
+
working: {
|
|
1880
|
+
any: [
|
|
1881
|
+
{ region: "bottom", contains: "esc to interrupt", caseInsensitive: true },
|
|
1882
|
+
{ region: "bottom", regex: BRAILLE_SPINNER },
|
|
1883
|
+
{ region: "title", regex: BRAILLE_SPINNER }
|
|
1884
|
+
]
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1888
|
+
AMP = {
|
|
1889
|
+
id: "amp",
|
|
1890
|
+
commands: ["amp"],
|
|
1891
|
+
confidence: "conservative",
|
|
1892
|
+
states: {
|
|
1893
|
+
// conservative — Sourcegraph's amp CLI needs an account, so no live capture
|
|
1894
|
+
// was taken. High-precision only; markers are best-effort from public
|
|
1895
|
+
// knowledge of its approval/streaming UI.
|
|
1896
|
+
blocked: {
|
|
1897
|
+
any: [
|
|
1898
|
+
{ region: "bottom", contains: "Do you want", caseInsensitive: false },
|
|
1899
|
+
{ region: "bottom", contains: "Allow", caseInsensitive: false },
|
|
1900
|
+
{ region: "bottom", contains: "(y/n)", caseInsensitive: true }
|
|
1901
|
+
]
|
|
1902
|
+
},
|
|
1903
|
+
working: {
|
|
1904
|
+
any: [
|
|
1905
|
+
{ region: "bottom", contains: "esc to interrupt", caseInsensitive: true },
|
|
1906
|
+
{ region: "bottom", regex: BRAILLE_SPINNER },
|
|
1907
|
+
{ region: "title", regex: BRAILLE_SPINNER }
|
|
1908
|
+
]
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1799
1912
|
SHELL = {
|
|
1800
1913
|
id: "shell",
|
|
1801
1914
|
commands: ["bash", "zsh", "sh", "fish", "nu"],
|
|
1915
|
+
confidence: "conservative",
|
|
1802
1916
|
states: {
|
|
1803
1917
|
// Catch-all: a raw shell is almost always idle. We only flag an explicit
|
|
1804
1918
|
// interactive confirmation as blocked; "working" is unreliable to read
|
|
@@ -1818,6 +1932,9 @@ var init_manifests = __esm({
|
|
|
1818
1932
|
GEMINI,
|
|
1819
1933
|
AIDER,
|
|
1820
1934
|
COPILOT,
|
|
1935
|
+
CURSOR,
|
|
1936
|
+
GOOSE,
|
|
1937
|
+
AMP,
|
|
1821
1938
|
SHELL
|
|
1822
1939
|
];
|
|
1823
1940
|
}
|
|
@@ -1829,7 +1946,8 @@ __export(classify_exports, {
|
|
|
1829
1946
|
classifyInstant: () => classifyInstant,
|
|
1830
1947
|
classifyPaneCommand: () => classifyPaneCommand,
|
|
1831
1948
|
createStatusTracker: () => createStatusTracker,
|
|
1832
|
-
parseAuthority: () => parseAuthority
|
|
1949
|
+
parseAuthority: () => parseAuthority,
|
|
1950
|
+
parseAuthorityEpoch: () => parseAuthorityEpoch
|
|
1833
1951
|
});
|
|
1834
1952
|
function parseAuthority(raw, nowSec) {
|
|
1835
1953
|
if (!raw) return null;
|
|
@@ -1843,6 +1961,13 @@ function parseAuthority(raw, nowSec) {
|
|
|
1843
1961
|
}
|
|
1844
1962
|
return state;
|
|
1845
1963
|
}
|
|
1964
|
+
function parseAuthorityEpoch(raw) {
|
|
1965
|
+
if (!raw) return null;
|
|
1966
|
+
const sep2 = raw.lastIndexOf(":");
|
|
1967
|
+
if (sep2 === -1) return null;
|
|
1968
|
+
const epoch = Number(raw.slice(sep2 + 1));
|
|
1969
|
+
return Number.isFinite(epoch) ? epoch : null;
|
|
1970
|
+
}
|
|
1846
1971
|
function classifyInstant(snapshot, manifest) {
|
|
1847
1972
|
if (!manifest) return "unknown";
|
|
1848
1973
|
const { state } = evaluateManifest(snapshot, manifest);
|
|
@@ -2004,7 +2129,8 @@ function normalizeStates(m) {
|
|
|
2004
2129
|
if (m.states.blocked) states.blocked = m.states.blocked;
|
|
2005
2130
|
if (m.states.working) states.working = m.states.working;
|
|
2006
2131
|
if (m.states.done) states.done = m.states.done;
|
|
2007
|
-
|
|
2132
|
+
const confidence = m.confidence === "tuned" ? "tuned" : "conservative";
|
|
2133
|
+
return { id: m.id, commands: m.commands, states, confidence };
|
|
2008
2134
|
}
|
|
2009
2135
|
function warnOnce(path2, reason) {
|
|
2010
2136
|
if (warned.has(path2)) return;
|
|
@@ -2070,6 +2196,16 @@ function subtreeCommands(entries, rootPid, maxDepth = 6) {
|
|
|
2070
2196
|
walk(rootPid, 0);
|
|
2071
2197
|
return commands;
|
|
2072
2198
|
}
|
|
2199
|
+
function describeSubtree(entries, rootPid, limit = 8) {
|
|
2200
|
+
const seen = [];
|
|
2201
|
+
for (const command2 of subtreeCommands(entries, rootPid)) {
|
|
2202
|
+
for (const token of commandTokens(command2)) {
|
|
2203
|
+
if (!seen.includes(token)) seen.push(token);
|
|
2204
|
+
if (seen.length >= limit) return seen;
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
return seen;
|
|
2208
|
+
}
|
|
2073
2209
|
function readProcessTable() {
|
|
2074
2210
|
try {
|
|
2075
2211
|
const raw = execFileSync2("ps", ["-axo", "pid=,ppid=,command="], {
|
|
@@ -2159,6 +2295,7 @@ var init_snapshot = __esm({
|
|
|
2159
2295
|
var sessions_exports = {};
|
|
2160
2296
|
__export(sessions_exports, {
|
|
2161
2297
|
SIDEBAR_PANE_OPTION: () => SIDEBAR_PANE_OPTION,
|
|
2298
|
+
buildAgentEntry: () => buildAgentEntry,
|
|
2162
2299
|
excludeSidebarPanes: () => excludeSidebarPanes,
|
|
2163
2300
|
isListableSession: () => isListableSession,
|
|
2164
2301
|
listTeamSessions: () => listTeamSessions,
|
|
@@ -2166,6 +2303,22 @@ __export(sessions_exports, {
|
|
|
2166
2303
|
rollupWindows: () => rollupWindows
|
|
2167
2304
|
});
|
|
2168
2305
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
2306
|
+
function buildAgentEntry(input) {
|
|
2307
|
+
const { manifest, pane } = input;
|
|
2308
|
+
if (!manifest || manifest.id === "shell") return null;
|
|
2309
|
+
return {
|
|
2310
|
+
paneId: pane.id,
|
|
2311
|
+
windowIndex: pane.windowIndex,
|
|
2312
|
+
session: input.sessionName,
|
|
2313
|
+
kind: manifest.id,
|
|
2314
|
+
state: input.state,
|
|
2315
|
+
confidence: manifest.confidence ?? "conservative",
|
|
2316
|
+
since: input.since,
|
|
2317
|
+
title: pane.title,
|
|
2318
|
+
command: pane.cmd,
|
|
2319
|
+
dir: pane.dir
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2169
2322
|
function excludeSidebarPanes(panes) {
|
|
2170
2323
|
return panes.filter((pane) => !pane.sidebar);
|
|
2171
2324
|
}
|
|
@@ -2196,23 +2349,23 @@ function listTeamSessions(tracker, opts = {}) {
|
|
|
2196
2349
|
const panes = excludeSidebarPanes(panesBySession.get(name) ?? []);
|
|
2197
2350
|
const seen = opts.viewed === name;
|
|
2198
2351
|
const nowSec = Math.floor(Date.now() / 1e3);
|
|
2199
|
-
const
|
|
2352
|
+
const agents = [];
|
|
2200
2353
|
const statuses = panes.map((pane) => {
|
|
2201
2354
|
const authority = parseAuthority(pane.authority, nowSec);
|
|
2202
2355
|
let status2;
|
|
2203
2356
|
let manifest;
|
|
2357
|
+
let since = null;
|
|
2204
2358
|
if (authority !== null) {
|
|
2359
|
+
since = parseAuthorityEpoch(pane.authority);
|
|
2205
2360
|
if (authority === "done" && seen) {
|
|
2206
2361
|
ackDone(pane.id, nowSec);
|
|
2207
2362
|
status2 = "idle";
|
|
2208
2363
|
} else {
|
|
2209
2364
|
status2 = authority;
|
|
2210
2365
|
}
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
}).manifest;
|
|
2215
|
-
}
|
|
2366
|
+
manifest = resolveAgentCommand(pane.cmd, pane.pid, processTable, {
|
|
2367
|
+
hint: pane.hint
|
|
2368
|
+
}).manifest;
|
|
2216
2369
|
} else {
|
|
2217
2370
|
manifest = resolveAgentCommand(pane.cmd, pane.pid, processTable, {
|
|
2218
2371
|
hint: pane.hint
|
|
@@ -2226,6 +2379,8 @@ function listTeamSessions(tracker, opts = {}) {
|
|
|
2226
2379
|
agent: manifest && manifest.id !== "shell" ? manifest.id : null,
|
|
2227
2380
|
status: status2
|
|
2228
2381
|
});
|
|
2382
|
+
const entry = buildAgentEntry({ sessionName: name, pane, manifest, state: status2, since });
|
|
2383
|
+
if (entry) agents.push(entry);
|
|
2229
2384
|
return status2;
|
|
2230
2385
|
});
|
|
2231
2386
|
return {
|
|
@@ -2236,7 +2391,8 @@ function listTeamSessions(tracker, opts = {}) {
|
|
|
2236
2391
|
status: rollupStatus(statuses),
|
|
2237
2392
|
// `panes` and `statuses` are parallel (statuses = panes.map(...)), so
|
|
2238
2393
|
// the pure rollup can group each pane's window with its resolved status.
|
|
2239
|
-
windowList: rollupWindows(panes, statuses)
|
|
2394
|
+
windowList: rollupWindows(panes, statuses),
|
|
2395
|
+
agents
|
|
2240
2396
|
};
|
|
2241
2397
|
});
|
|
2242
2398
|
}
|
|
@@ -2245,9 +2401,11 @@ function collectPanes() {
|
|
|
2245
2401
|
"list-panes",
|
|
2246
2402
|
"-a",
|
|
2247
2403
|
"-F",
|
|
2248
|
-
// Window fields sit before pane_title so the (tab-safe)
|
|
2249
|
-
// trailing catch-all — window names don't contain tabs
|
|
2250
|
-
|
|
2404
|
+
// Window fields + pane_current_path sit before pane_title so the (tab-safe)
|
|
2405
|
+
// title stays the trailing catch-all — window names/paths don't contain tabs
|
|
2406
|
+
// in practice. pane_current_path rides this SAME list-panes call (no extra
|
|
2407
|
+
// tmux round-trip) so per-pane agent entries can carry a working dir.
|
|
2408
|
+
`#{session_name} #{pane_id} #{pane_pid} #{pane_current_command} #{@agent_state} #{@agent_hint} #{${SIDEBAR_PANE_OPTION}} #{window_index} #{window_name} #{window_active} #{pane_current_path} #{pane_title}`
|
|
2251
2409
|
]);
|
|
2252
2410
|
const bySession = /* @__PURE__ */ new Map();
|
|
2253
2411
|
for (const line of raw.split("\n").filter(Boolean)) {
|
|
@@ -2262,6 +2420,7 @@ function collectPanes() {
|
|
|
2262
2420
|
windowIndex = "0",
|
|
2263
2421
|
windowName = "",
|
|
2264
2422
|
windowActive = "0",
|
|
2423
|
+
dir = "",
|
|
2265
2424
|
...titleParts
|
|
2266
2425
|
] = line.split(" ");
|
|
2267
2426
|
if (!session) continue;
|
|
@@ -2276,6 +2435,7 @@ function collectPanes() {
|
|
|
2276
2435
|
windowIndex: Number(windowIndex) || 0,
|
|
2277
2436
|
windowName,
|
|
2278
2437
|
windowActive: windowActive === "1",
|
|
2438
|
+
dir,
|
|
2279
2439
|
title: titleParts.join(" ")
|
|
2280
2440
|
});
|
|
2281
2441
|
bySession.set(session, list);
|
|
@@ -2325,10 +2485,277 @@ var init_sessions2 = __esm({
|
|
|
2325
2485
|
}
|
|
2326
2486
|
});
|
|
2327
2487
|
|
|
2328
|
-
// packages/daemon/src/
|
|
2329
|
-
|
|
2330
|
-
|
|
2488
|
+
// packages/daemon/src/lib/update-check.ts
|
|
2489
|
+
var update_check_exports = {};
|
|
2490
|
+
__export(update_check_exports, {
|
|
2491
|
+
CHECK_INTERVAL_MS: () => CHECK_INTERVAL_MS,
|
|
2492
|
+
REGISTRY_URL: () => REGISTRY_URL,
|
|
2493
|
+
compareSemver: () => compareSemver,
|
|
2494
|
+
deriveStatus: () => deriveStatus,
|
|
2495
|
+
fetchLatestVersion: () => fetchLatestVersion,
|
|
2496
|
+
getCurrentVersion: () => getCurrentVersion,
|
|
2497
|
+
getUpdateStatus: () => getUpdateStatus,
|
|
2498
|
+
isNewer: () => isNewer,
|
|
2499
|
+
markUpdateNotified: () => markUpdateNotified,
|
|
2500
|
+
maybeCheckForUpdate: () => maybeCheckForUpdate,
|
|
2501
|
+
parseRegistryResponse: () => parseRegistryResponse,
|
|
2502
|
+
readUpdateCache: () => readUpdateCache,
|
|
2503
|
+
runUpdateCheck: () => runUpdateCheck,
|
|
2504
|
+
shouldCheck: () => shouldCheck,
|
|
2505
|
+
updateCachePath: () => updateCachePath,
|
|
2506
|
+
writeUpdateCache: () => writeUpdateCache
|
|
2507
|
+
});
|
|
2508
|
+
import { existsSync, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2509
|
+
import { homedir as homedir2 } from "node:os";
|
|
2510
|
+
import { dirname, join as join2 } from "node:path";
|
|
2331
2511
|
import { fileURLToPath } from "node:url";
|
|
2512
|
+
function parseSemver(version) {
|
|
2513
|
+
const core = version.trim().replace(/^v/i, "").split("+")[0] ?? "";
|
|
2514
|
+
const dash = core.indexOf("-");
|
|
2515
|
+
const main = dash === -1 ? core : core.slice(0, dash);
|
|
2516
|
+
const pre = dash === -1 ? "" : core.slice(dash + 1);
|
|
2517
|
+
const parts = main.split(".");
|
|
2518
|
+
const num = (i) => {
|
|
2519
|
+
const n = Number.parseInt(parts[i] ?? "", 10);
|
|
2520
|
+
return Number.isFinite(n) && n >= 0 ? n : 0;
|
|
2521
|
+
};
|
|
2522
|
+
return { nums: [num(0), num(1), num(2)], pre };
|
|
2523
|
+
}
|
|
2524
|
+
function compareSemver(a, b) {
|
|
2525
|
+
const pa = parseSemver(a);
|
|
2526
|
+
const pb = parseSemver(b);
|
|
2527
|
+
for (let i = 0; i < 3; i++) {
|
|
2528
|
+
if (pa.nums[i] !== pb.nums[i]) return pa.nums[i] < pb.nums[i] ? -1 : 1;
|
|
2529
|
+
}
|
|
2530
|
+
if (pa.pre === pb.pre) return 0;
|
|
2531
|
+
if (pa.pre === "") return 1;
|
|
2532
|
+
if (pb.pre === "") return -1;
|
|
2533
|
+
return pa.pre < pb.pre ? -1 : 1;
|
|
2534
|
+
}
|
|
2535
|
+
function isNewer(latest, current) {
|
|
2536
|
+
return compareSemver(latest, current) === 1;
|
|
2537
|
+
}
|
|
2538
|
+
function shouldCheck(lastCheckedAt, nowMs) {
|
|
2539
|
+
if (lastCheckedAt === null) return true;
|
|
2540
|
+
return nowMs - lastCheckedAt >= CHECK_INTERVAL_MS;
|
|
2541
|
+
}
|
|
2542
|
+
function parseRegistryResponse(json2) {
|
|
2543
|
+
try {
|
|
2544
|
+
const parsed = JSON.parse(json2);
|
|
2545
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
2546
|
+
const version = parsed.version;
|
|
2547
|
+
return typeof version === "string" && version.length > 0 ? version : null;
|
|
2548
|
+
} catch {
|
|
2549
|
+
return null;
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
function deriveStatus(latest, currentVersion) {
|
|
2553
|
+
return {
|
|
2554
|
+
latest,
|
|
2555
|
+
updateAvailable: latest !== null && isNewer(latest, currentVersion)
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2558
|
+
function updateCachePath() {
|
|
2559
|
+
const home = process.env.TMUX_IDE_HOME ?? join2(homedir2(), ".tmux-ide");
|
|
2560
|
+
return join2(home, "update-check.json");
|
|
2561
|
+
}
|
|
2562
|
+
function readUpdateCache() {
|
|
2563
|
+
const path2 = updateCachePath();
|
|
2564
|
+
if (!existsSync(path2)) return null;
|
|
2565
|
+
try {
|
|
2566
|
+
const parsed = JSON.parse(readFileSync3(path2, "utf-8"));
|
|
2567
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
2568
|
+
const obj = parsed;
|
|
2569
|
+
const lastCheckedAt = typeof obj.lastCheckedAt === "number" ? obj.lastCheckedAt : null;
|
|
2570
|
+
const latest = typeof obj.latest === "string" && obj.latest.length > 0 ? obj.latest : null;
|
|
2571
|
+
const notified = Array.isArray(obj.notified) ? obj.notified.filter((v) => typeof v === "string") : void 0;
|
|
2572
|
+
return { lastCheckedAt, latest, ...notified ? { notified } : {} };
|
|
2573
|
+
} catch {
|
|
2574
|
+
return null;
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
function writeUpdateCache(cache3) {
|
|
2578
|
+
const path2 = updateCachePath();
|
|
2579
|
+
try {
|
|
2580
|
+
mkdirSync(dirname(path2), { recursive: true });
|
|
2581
|
+
writeFileSync2(path2, JSON.stringify(cache3));
|
|
2582
|
+
} catch {
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
async function fetchLatestVersion(timeoutMs = 3e3) {
|
|
2586
|
+
const controller = new AbortController();
|
|
2587
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2588
|
+
try {
|
|
2589
|
+
const res = await fetch(REGISTRY_URL, { signal: controller.signal });
|
|
2590
|
+
if (!res.ok) return null;
|
|
2591
|
+
return parseRegistryResponse(await res.text());
|
|
2592
|
+
} catch {
|
|
2593
|
+
return null;
|
|
2594
|
+
} finally {
|
|
2595
|
+
clearTimeout(timer);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
function getCurrentVersion() {
|
|
2599
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
2600
|
+
const candidates = [
|
|
2601
|
+
join2(here, "../package.json"),
|
|
2602
|
+
// bundled bin/cli.js → repo root
|
|
2603
|
+
join2(here, "../../../../package.json")
|
|
2604
|
+
// dev src/lib → repo root
|
|
2605
|
+
];
|
|
2606
|
+
for (const candidate of candidates) {
|
|
2607
|
+
try {
|
|
2608
|
+
const parsed = JSON.parse(readFileSync3(candidate, "utf-8"));
|
|
2609
|
+
if (typeof parsed.version === "string" && parsed.version.length > 0) return parsed.version;
|
|
2610
|
+
} catch {
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
return "0.0.0";
|
|
2614
|
+
}
|
|
2615
|
+
function getUpdateStatus({
|
|
2616
|
+
currentVersion = getCurrentVersion()
|
|
2617
|
+
} = {}) {
|
|
2618
|
+
const cache3 = readUpdateCache();
|
|
2619
|
+
return deriveStatus(cache3?.latest ?? null, currentVersion);
|
|
2620
|
+
}
|
|
2621
|
+
async function runUpdateCheck({ now = Date.now() } = {}) {
|
|
2622
|
+
const cache3 = readUpdateCache();
|
|
2623
|
+
if (!shouldCheck(cache3?.lastCheckedAt ?? null, now)) return;
|
|
2624
|
+
const fetched = await fetchLatestVersion();
|
|
2625
|
+
writeUpdateCache({
|
|
2626
|
+
lastCheckedAt: now,
|
|
2627
|
+
latest: fetched ?? cache3?.latest ?? null,
|
|
2628
|
+
...cache3?.notified ? { notified: cache3.notified } : {}
|
|
2629
|
+
});
|
|
2630
|
+
}
|
|
2631
|
+
function maybeCheckForUpdate({
|
|
2632
|
+
enabled,
|
|
2633
|
+
now = Date.now(),
|
|
2634
|
+
currentVersion = getCurrentVersion()
|
|
2635
|
+
}) {
|
|
2636
|
+
if (!enabled) return { latest: null, updateAvailable: false };
|
|
2637
|
+
const status2 = getUpdateStatus({ now, currentVersion });
|
|
2638
|
+
void runUpdateCheck({ now }).catch(() => {
|
|
2639
|
+
});
|
|
2640
|
+
return status2;
|
|
2641
|
+
}
|
|
2642
|
+
function markUpdateNotified(version) {
|
|
2643
|
+
const cache3 = readUpdateCache() ?? { lastCheckedAt: null, latest: null };
|
|
2644
|
+
const notified = cache3.notified ?? [];
|
|
2645
|
+
if (notified.includes(version)) return false;
|
|
2646
|
+
writeUpdateCache({ ...cache3, notified: [...notified, version] });
|
|
2647
|
+
return true;
|
|
2648
|
+
}
|
|
2649
|
+
var REGISTRY_URL, CHECK_INTERVAL_MS;
|
|
2650
|
+
var init_update_check = __esm({
|
|
2651
|
+
"packages/daemon/src/lib/update-check.ts"() {
|
|
2652
|
+
"use strict";
|
|
2653
|
+
REGISTRY_URL = "https://registry.npmjs.org/tmux-ide/latest";
|
|
2654
|
+
CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
2655
|
+
}
|
|
2656
|
+
});
|
|
2657
|
+
|
|
2658
|
+
// packages/daemon/src/lib/tui-binary.ts
|
|
2659
|
+
var tui_binary_exports = {};
|
|
2660
|
+
__export(tui_binary_exports, {
|
|
2661
|
+
MIN_TUI_BINARY_BYTES: () => MIN_TUI_BINARY_BYTES,
|
|
2662
|
+
RELEASE_REPO: () => RELEASE_REPO,
|
|
2663
|
+
bunTargetForTag: () => bunTargetForTag,
|
|
2664
|
+
downloadTuiBinary: () => downloadTuiBinary,
|
|
2665
|
+
downloadedTuiPath: () => downloadedTuiPath,
|
|
2666
|
+
findDownloadedTui: () => findDownloadedTui,
|
|
2667
|
+
normalizeVersion: () => normalizeVersion,
|
|
2668
|
+
releaseAssetName: () => releaseAssetName,
|
|
2669
|
+
releaseAssetUrl: () => releaseAssetUrl,
|
|
2670
|
+
tuiPlatformTag: () => tuiPlatformTag,
|
|
2671
|
+
tuiStateHome: () => tuiStateHome
|
|
2672
|
+
});
|
|
2673
|
+
import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
2674
|
+
import { homedir as homedir3 } from "node:os";
|
|
2675
|
+
import { dirname as dirname2, join as join3 } from "node:path";
|
|
2676
|
+
import { gunzipSync } from "node:zlib";
|
|
2677
|
+
function tuiPlatformTag(platform = process.platform, arch = process.arch) {
|
|
2678
|
+
return SUPPORTED[`${platform}-${arch}`] ?? null;
|
|
2679
|
+
}
|
|
2680
|
+
function bunTargetForTag(tag) {
|
|
2681
|
+
return `bun-${tag}`;
|
|
2682
|
+
}
|
|
2683
|
+
function releaseAssetName(tag) {
|
|
2684
|
+
return `tmux-ide-tui-${tag}.gz`;
|
|
2685
|
+
}
|
|
2686
|
+
function normalizeVersion(version) {
|
|
2687
|
+
return version.startsWith("v") ? version.slice(1) : version;
|
|
2688
|
+
}
|
|
2689
|
+
function releaseAssetUrl(version, tag) {
|
|
2690
|
+
return `https://github.com/${RELEASE_REPO}/releases/download/v${normalizeVersion(version)}/${releaseAssetName(tag)}`;
|
|
2691
|
+
}
|
|
2692
|
+
function downloadedTuiPath(home, tag, version) {
|
|
2693
|
+
return join3(home, "bin", `tmux-ide-tui-${tag}-${normalizeVersion(version)}`);
|
|
2694
|
+
}
|
|
2695
|
+
function tuiStateHome() {
|
|
2696
|
+
return process.env.TMUX_IDE_HOME ?? join3(homedir3(), ".tmux-ide");
|
|
2697
|
+
}
|
|
2698
|
+
function findDownloadedTui(version = getCurrentVersion()) {
|
|
2699
|
+
const tag = tuiPlatformTag();
|
|
2700
|
+
if (!tag) return null;
|
|
2701
|
+
const path2 = downloadedTuiPath(tuiStateHome(), tag, version);
|
|
2702
|
+
return existsSync2(path2) ? path2 : null;
|
|
2703
|
+
}
|
|
2704
|
+
async function downloadTuiBinary(opts = {}) {
|
|
2705
|
+
const log = opts.log ?? (() => {
|
|
2706
|
+
});
|
|
2707
|
+
const version = normalizeVersion(opts.version ?? getCurrentVersion());
|
|
2708
|
+
const tag = tuiPlatformTag();
|
|
2709
|
+
if (!tag) {
|
|
2710
|
+
throw new Error(
|
|
2711
|
+
`no prebuilt TUI binary is published for ${process.platform}-${process.arch} \u2014 install bun (https://bun.sh) to run the TUI surfaces from source instead`
|
|
2712
|
+
);
|
|
2713
|
+
}
|
|
2714
|
+
const url = releaseAssetUrl(version, tag);
|
|
2715
|
+
const dest = downloadedTuiPath(tuiStateHome(), tag, version);
|
|
2716
|
+
mkdirSync2(dirname2(dest), { recursive: true });
|
|
2717
|
+
log(`downloading ${url}`);
|
|
2718
|
+
const res = await fetch(url);
|
|
2719
|
+
if (!res.ok) {
|
|
2720
|
+
throw new Error(
|
|
2721
|
+
`could not download the TUI binary (${url} \u2192 HTTP ${res.status} ${res.statusText}). Check that release v${version} exists and published its assets.`
|
|
2722
|
+
);
|
|
2723
|
+
}
|
|
2724
|
+
const gz = Buffer.from(await res.arrayBuffer());
|
|
2725
|
+
const bin = gunzipSync(gz);
|
|
2726
|
+
if (bin.byteLength < MIN_TUI_BINARY_BYTES) {
|
|
2727
|
+
throw new Error(
|
|
2728
|
+
`the downloaded TUI binary is only ${bin.byteLength} bytes (expected >10MB) \u2014 treating it as corrupt and leaving the previous binary (if any) in place`
|
|
2729
|
+
);
|
|
2730
|
+
}
|
|
2731
|
+
const tmp = `${dest}.${process.pid}.tmp`;
|
|
2732
|
+
writeFileSync3(tmp, bin, { mode: 493 });
|
|
2733
|
+
chmodSync(tmp, 493);
|
|
2734
|
+
renameSync(tmp, dest);
|
|
2735
|
+
const mb = (bin.byteLength / 1024 / 1024).toFixed(1);
|
|
2736
|
+
log(`installed ${dest} (${mb} MB)`);
|
|
2737
|
+
return { path: dest, bytes: bin.byteLength };
|
|
2738
|
+
}
|
|
2739
|
+
var RELEASE_REPO, MIN_TUI_BINARY_BYTES, SUPPORTED;
|
|
2740
|
+
var init_tui_binary = __esm({
|
|
2741
|
+
"packages/daemon/src/lib/tui-binary.ts"() {
|
|
2742
|
+
"use strict";
|
|
2743
|
+
init_update_check();
|
|
2744
|
+
RELEASE_REPO = "wavyrai/tmux-ide";
|
|
2745
|
+
MIN_TUI_BINARY_BYTES = 10 * 1024 * 1024;
|
|
2746
|
+
SUPPORTED = {
|
|
2747
|
+
"darwin-arm64": "darwin-arm64",
|
|
2748
|
+
"darwin-x64": "darwin-x64",
|
|
2749
|
+
"linux-x64": "linux-x64",
|
|
2750
|
+
"linux-arm64": "linux-arm64"
|
|
2751
|
+
};
|
|
2752
|
+
}
|
|
2753
|
+
});
|
|
2754
|
+
|
|
2755
|
+
// packages/daemon/src/tui/compiled.ts
|
|
2756
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
2757
|
+
import { dirname as dirname3, resolve as resolve4 } from "node:path";
|
|
2758
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
2332
2759
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
2333
2760
|
function resolveTuiLaunch(input) {
|
|
2334
2761
|
if (input.checkoutExists && input.bunAvailable) {
|
|
@@ -2340,30 +2767,30 @@ function resolveTuiLaunch(input) {
|
|
|
2340
2767
|
const reasons = [];
|
|
2341
2768
|
if (!input.checkoutExists) {
|
|
2342
2769
|
reasons.push(
|
|
2343
|
-
"the TUI widget sources are absent (
|
|
2770
|
+
"the TUI widget sources are absent (reinstall tmux-ide \u2014 releases since v2.6.1 ship them)"
|
|
2344
2771
|
);
|
|
2345
2772
|
}
|
|
2346
2773
|
if (!input.bunAvailable) {
|
|
2347
2774
|
reasons.push("the `bun` runtime is not installed (https://bun.sh)");
|
|
2348
2775
|
}
|
|
2349
2776
|
reasons.push(
|
|
2350
|
-
"no compiled `tmux-ide-tui` binary was found (build one with `pnpm build:tui`, or reinstall a release that ships it)"
|
|
2777
|
+
"no compiled `tmux-ide-tui` binary was found (build one with `pnpm build:tui`, download it with `tmux-ide update --tui-binary`, or reinstall a release that ships it)"
|
|
2351
2778
|
);
|
|
2352
2779
|
return { mode: "unavailable", reasons };
|
|
2353
2780
|
}
|
|
2354
2781
|
function findCompiledTui() {
|
|
2355
2782
|
const override = process.env.TMUX_IDE_TUI_BIN;
|
|
2356
|
-
if (override) return
|
|
2783
|
+
if (override) return existsSync3(override) ? override : null;
|
|
2357
2784
|
const anchors = [];
|
|
2358
|
-
if (process.argv[1]) anchors.push(
|
|
2785
|
+
if (process.argv[1]) anchors.push(dirname3(process.argv[1]));
|
|
2359
2786
|
anchors.push(__dirname);
|
|
2360
2787
|
for (const anchor of anchors) {
|
|
2361
2788
|
for (const rel of BINARY_RELS) {
|
|
2362
2789
|
const candidate = resolve4(anchor, rel);
|
|
2363
|
-
if (
|
|
2790
|
+
if (existsSync3(candidate)) return candidate;
|
|
2364
2791
|
}
|
|
2365
2792
|
}
|
|
2366
|
-
return
|
|
2793
|
+
return findDownloadedTui();
|
|
2367
2794
|
}
|
|
2368
2795
|
function isBunAvailable() {
|
|
2369
2796
|
try {
|
|
@@ -2377,7 +2804,8 @@ var __dirname, BINARY_RELS;
|
|
|
2377
2804
|
var init_compiled = __esm({
|
|
2378
2805
|
"packages/daemon/src/tui/compiled.ts"() {
|
|
2379
2806
|
"use strict";
|
|
2380
|
-
|
|
2807
|
+
init_tui_binary();
|
|
2808
|
+
__dirname = dirname3(fileURLToPath2(import.meta.url));
|
|
2381
2809
|
BINARY_RELS = [
|
|
2382
2810
|
"../packages/daemon/dist/tui/tmux-ide-tui",
|
|
2383
2811
|
"../../dist/tui/tmux-ide-tui",
|
|
@@ -2405,15 +2833,15 @@ __export(sidebar_exports, {
|
|
|
2405
2833
|
sidebarWidgetCommand: () => sidebarWidgetCommand,
|
|
2406
2834
|
sidebarWidgetScript: () => sidebarWidgetScript
|
|
2407
2835
|
});
|
|
2408
|
-
import { existsSync as
|
|
2409
|
-
import { dirname as
|
|
2410
|
-
import { fileURLToPath as
|
|
2836
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
2837
|
+
import { dirname as dirname4, resolve as resolve5 } from "node:path";
|
|
2838
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
2411
2839
|
function sidebarWidgetScript() {
|
|
2412
2840
|
const candidates = [
|
|
2413
2841
|
resolve5(__dirname2, "../../widgets/sidebar/index.tsx"),
|
|
2414
2842
|
resolve5(__dirname2, "../packages/daemon/src/widgets/sidebar/index.tsx")
|
|
2415
2843
|
];
|
|
2416
|
-
return candidates.find((p) =>
|
|
2844
|
+
return candidates.find((p) => existsSync4(p)) ?? candidates[0];
|
|
2417
2845
|
}
|
|
2418
2846
|
function sidebarWidgetCommand(scriptPath, session, dir, theme) {
|
|
2419
2847
|
const args = [`--session=${session}`, `--dir=${dir}`];
|
|
@@ -2422,7 +2850,7 @@ function sidebarWidgetCommand(scriptPath, session, dir, theme) {
|
|
|
2422
2850
|
surface: "sidebar",
|
|
2423
2851
|
scriptPath,
|
|
2424
2852
|
args,
|
|
2425
|
-
checkoutExists:
|
|
2853
|
+
checkoutExists: existsSync4(scriptPath),
|
|
2426
2854
|
bunAvailable: isBunAvailable(),
|
|
2427
2855
|
compiledBinary: findCompiledTui()
|
|
2428
2856
|
});
|
|
@@ -2501,7 +2929,7 @@ var init_sidebar = __esm({
|
|
|
2501
2929
|
init_shell();
|
|
2502
2930
|
init_sessions2();
|
|
2503
2931
|
init_compiled();
|
|
2504
|
-
__dirname2 =
|
|
2932
|
+
__dirname2 = dirname4(fileURLToPath3(import.meta.url));
|
|
2505
2933
|
SIDEBAR_KEY = "M-b";
|
|
2506
2934
|
DEFAULT_SIDEBAR_WIDTH = 30;
|
|
2507
2935
|
}
|
|
@@ -2514,12 +2942,12 @@ __export(resolve_exports, {
|
|
|
2514
2942
|
resolveWidgetCommand: () => resolveWidgetCommand,
|
|
2515
2943
|
resolveWidgetSpawn: () => resolveWidgetSpawn
|
|
2516
2944
|
});
|
|
2517
|
-
import { resolve as resolve6, dirname as
|
|
2518
|
-
import { existsSync as
|
|
2519
|
-
import { fileURLToPath as
|
|
2945
|
+
import { resolve as resolve6, dirname as dirname5 } from "node:path";
|
|
2946
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
2947
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
2520
2948
|
function widgetEntryPath(entry) {
|
|
2521
2949
|
const sibling = resolve6(__dirname3, entry);
|
|
2522
|
-
if (
|
|
2950
|
+
if (existsSync5(sibling)) return sibling;
|
|
2523
2951
|
return resolve6(__dirname3, "../packages/daemon/src/widgets", entry);
|
|
2524
2952
|
}
|
|
2525
2953
|
function widgetArgs(opts) {
|
|
@@ -2536,7 +2964,7 @@ function resolveWidgetCommand(type, opts) {
|
|
|
2536
2964
|
surface: type,
|
|
2537
2965
|
scriptPath,
|
|
2538
2966
|
args: widgetArgs(opts),
|
|
2539
|
-
checkoutExists:
|
|
2967
|
+
checkoutExists: existsSync5(scriptPath),
|
|
2540
2968
|
bunAvailable: isBunAvailable(),
|
|
2541
2969
|
compiledBinary: findCompiledTui()
|
|
2542
2970
|
});
|
|
@@ -2557,7 +2985,7 @@ function resolveWidgetSpawn(type, opts) {
|
|
|
2557
2985
|
surface: type,
|
|
2558
2986
|
scriptPath,
|
|
2559
2987
|
args: widgetArgs(opts),
|
|
2560
|
-
checkoutExists:
|
|
2988
|
+
checkoutExists: existsSync5(scriptPath),
|
|
2561
2989
|
bunAvailable: isBunAvailable(),
|
|
2562
2990
|
compiledBinary: findCompiledTui()
|
|
2563
2991
|
});
|
|
@@ -2573,7 +3001,7 @@ var init_resolve = __esm({
|
|
|
2573
3001
|
"use strict";
|
|
2574
3002
|
init_shell();
|
|
2575
3003
|
init_compiled();
|
|
2576
|
-
__dirname3 =
|
|
3004
|
+
__dirname3 = dirname5(fileURLToPath4(import.meta.url));
|
|
2577
3005
|
WIDGET_ENTRY_POINTS = {
|
|
2578
3006
|
explorer: "explorer/index.tsx",
|
|
2579
3007
|
changes: "changes/index.tsx",
|
|
@@ -2582,7 +3010,7 @@ var init_resolve = __esm({
|
|
|
2582
3010
|
config: "config/index.tsx",
|
|
2583
3011
|
sidebar: "sidebar/index.tsx"
|
|
2584
3012
|
};
|
|
2585
|
-
REPO_ROOT =
|
|
3013
|
+
REPO_ROOT = existsSync5(resolve6(__dirname3, "explorer/index.tsx")) ? resolve6(__dirname3, "../../../..") : resolve6(__dirname3, "..");
|
|
2586
3014
|
WIDGET_TYPES = Object.keys(WIDGET_ENTRY_POINTS);
|
|
2587
3015
|
}
|
|
2588
3016
|
});
|
|
@@ -2597,11 +3025,14 @@ __export(app_config_exports, {
|
|
|
2597
3025
|
appConfigPath: () => appConfigPath,
|
|
2598
3026
|
getAppConfig: () => getAppConfig,
|
|
2599
3027
|
loadAppConfig: () => loadAppConfig,
|
|
2600
|
-
|
|
3028
|
+
loadRawAppConfig: () => loadRawAppConfig,
|
|
3029
|
+
mergeConfigPatch: () => mergeConfigPatch,
|
|
3030
|
+
parseAppConfig: () => parseAppConfig,
|
|
3031
|
+
updateAppConfig: () => updateAppConfig
|
|
2601
3032
|
});
|
|
2602
|
-
import { existsSync as
|
|
2603
|
-
import { homedir as
|
|
2604
|
-
import { join as
|
|
3033
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
3034
|
+
import { homedir as homedir4 } from "node:os";
|
|
3035
|
+
import { dirname as dirname6, join as join4 } from "node:path";
|
|
2605
3036
|
function asObject(value) {
|
|
2606
3037
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2607
3038
|
}
|
|
@@ -2629,6 +3060,7 @@ function parseAppConfig(input) {
|
|
|
2629
3060
|
const welcome = asObject(root.welcome);
|
|
2630
3061
|
const integrations = asObject(root.integrations);
|
|
2631
3062
|
const worktrees = asObject(root.worktrees);
|
|
3063
|
+
const app = asObject(root.app);
|
|
2632
3064
|
return {
|
|
2633
3065
|
keys: {
|
|
2634
3066
|
popup: pickString(keys.popup, D.keys.popup),
|
|
@@ -2670,17 +3102,18 @@ function parseAppConfig(input) {
|
|
|
2670
3102
|
updates: { check: pickBool(updates.check, D.updates.check) },
|
|
2671
3103
|
welcome: { show: pickBool(welcome.show, D.welcome.show) },
|
|
2672
3104
|
integrations: { offer: pickBool(integrations.offer, D.integrations.offer) },
|
|
2673
|
-
worktrees: { dir: pickString(worktrees.dir, D.worktrees.dir) }
|
|
3105
|
+
worktrees: { dir: pickString(worktrees.dir, D.worktrees.dir) },
|
|
3106
|
+
app: { frontDoor: pickBool(app.frontDoor, D.app.frontDoor) }
|
|
2674
3107
|
};
|
|
2675
3108
|
}
|
|
2676
3109
|
function appConfigPath() {
|
|
2677
|
-
return process.env.TMUX_IDE_CONFIG ??
|
|
3110
|
+
return process.env.TMUX_IDE_CONFIG ?? join4(homedir4(), ".tmux-ide", "config.json");
|
|
2678
3111
|
}
|
|
2679
3112
|
function loadAppConfig() {
|
|
2680
3113
|
const path2 = appConfigPath();
|
|
2681
|
-
if (!
|
|
3114
|
+
if (!existsSync6(path2)) return parseAppConfig(void 0);
|
|
2682
3115
|
try {
|
|
2683
|
-
return parseAppConfig(JSON.parse(
|
|
3116
|
+
return parseAppConfig(JSON.parse(readFileSync4(path2, "utf-8")));
|
|
2684
3117
|
} catch {
|
|
2685
3118
|
return parseAppConfig(void 0);
|
|
2686
3119
|
}
|
|
@@ -2692,6 +3125,45 @@ function getAppConfig() {
|
|
|
2692
3125
|
function _resetForTests() {
|
|
2693
3126
|
cached = null;
|
|
2694
3127
|
}
|
|
3128
|
+
function loadRawAppConfig() {
|
|
3129
|
+
const path2 = appConfigPath();
|
|
3130
|
+
if (!existsSync6(path2)) return {};
|
|
3131
|
+
try {
|
|
3132
|
+
const parsed = JSON.parse(readFileSync4(path2, "utf-8"));
|
|
3133
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
3134
|
+
} catch {
|
|
3135
|
+
return {};
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
function isPlainObject(value) {
|
|
3139
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
3140
|
+
}
|
|
3141
|
+
function mergeConfigPatch(raw, patch) {
|
|
3142
|
+
const out = { ...raw };
|
|
3143
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
3144
|
+
if (value === void 0) {
|
|
3145
|
+
delete out[key];
|
|
3146
|
+
} else if (isPlainObject(value) && isPlainObject(out[key])) {
|
|
3147
|
+
out[key] = mergeConfigPatch(out[key], value);
|
|
3148
|
+
} else if (isPlainObject(value)) {
|
|
3149
|
+
out[key] = mergeConfigPatch({}, value);
|
|
3150
|
+
} else {
|
|
3151
|
+
out[key] = value;
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
return out;
|
|
3155
|
+
}
|
|
3156
|
+
function updateAppConfig(patch) {
|
|
3157
|
+
const path2 = appConfigPath();
|
|
3158
|
+
const merged = mergeConfigPatch(loadRawAppConfig(), patch);
|
|
3159
|
+
mkdirSync3(dirname6(path2), { recursive: true });
|
|
3160
|
+
const tmp = `${path2}.${process.pid}.${Date.now()}.tmp`;
|
|
3161
|
+
writeFileSync4(tmp, `${JSON.stringify(merged, null, 2)}
|
|
3162
|
+
`, "utf-8");
|
|
3163
|
+
renameSync2(tmp, path2);
|
|
3164
|
+
cached = null;
|
|
3165
|
+
return parseAppConfig(merged);
|
|
3166
|
+
}
|
|
2695
3167
|
var DEFAULT_APP_CONFIG, DEFAULT_THEME, DEFAULT_KEYS, cached;
|
|
2696
3168
|
var init_app_config = __esm({
|
|
2697
3169
|
"packages/daemon/src/lib/app-config.ts"() {
|
|
@@ -2724,7 +3196,8 @@ var init_app_config = __esm({
|
|
|
2724
3196
|
updates: { check: true },
|
|
2725
3197
|
welcome: { show: true },
|
|
2726
3198
|
integrations: { offer: true },
|
|
2727
|
-
worktrees: { dir: "" }
|
|
3199
|
+
worktrees: { dir: "" },
|
|
3200
|
+
app: { frontDoor: false }
|
|
2728
3201
|
};
|
|
2729
3202
|
DEFAULT_THEME = DEFAULT_APP_CONFIG.theme;
|
|
2730
3203
|
DEFAULT_KEYS = DEFAULT_APP_CONFIG.keys;
|
|
@@ -2733,9 +3206,9 @@ var init_app_config = __esm({
|
|
|
2733
3206
|
});
|
|
2734
3207
|
|
|
2735
3208
|
// packages/daemon/src/tui/team/keymap.ts
|
|
2736
|
-
import { existsSync as
|
|
2737
|
-
import { homedir as
|
|
2738
|
-
import { join as
|
|
3209
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
|
|
3210
|
+
import { homedir as homedir5 } from "node:os";
|
|
3211
|
+
import { join as join5 } from "node:path";
|
|
2739
3212
|
var ACTION_ORDER, DEFAULT_KEYMAP;
|
|
2740
3213
|
var init_keymap = __esm({
|
|
2741
3214
|
"packages/daemon/src/tui/team/keymap.ts"() {
|
|
@@ -3164,24 +3637,24 @@ __export(welcome_exports, {
|
|
|
3164
3637
|
welcomeMarkerPath: () => welcomeMarkerPath
|
|
3165
3638
|
});
|
|
3166
3639
|
import { spawn as spawn2 } from "node:child_process";
|
|
3167
|
-
import { existsSync as
|
|
3168
|
-
import { homedir as
|
|
3169
|
-
import { dirname as
|
|
3640
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3641
|
+
import { homedir as homedir6 } from "node:os";
|
|
3642
|
+
import { dirname as dirname7, join as join6 } from "node:path";
|
|
3170
3643
|
function renderKey2(tmuxKey) {
|
|
3171
3644
|
return tmuxKey.replace(/M-/g, "\u2325").replace(/C-/g, "^").replace(/S-/g, "\u21E7");
|
|
3172
3645
|
}
|
|
3173
3646
|
function welcomeMarkerPath() {
|
|
3174
|
-
const home = process.env.TMUX_IDE_HOME ??
|
|
3175
|
-
return
|
|
3647
|
+
const home = process.env.TMUX_IDE_HOME ?? join6(homedir6(), ".tmux-ide");
|
|
3648
|
+
return join6(home, "welcomed");
|
|
3176
3649
|
}
|
|
3177
3650
|
function shouldShowWelcome() {
|
|
3178
|
-
return !
|
|
3651
|
+
return !existsSync8(welcomeMarkerPath()) && getAppConfig().welcome.show;
|
|
3179
3652
|
}
|
|
3180
3653
|
function markWelcomed() {
|
|
3181
3654
|
const path2 = welcomeMarkerPath();
|
|
3182
3655
|
try {
|
|
3183
|
-
|
|
3184
|
-
|
|
3656
|
+
mkdirSync4(dirname7(path2), { recursive: true });
|
|
3657
|
+
writeFileSync5(path2, (/* @__PURE__ */ new Date()).toISOString());
|
|
3185
3658
|
} catch {
|
|
3186
3659
|
}
|
|
3187
3660
|
}
|
|
@@ -3241,20 +3714,20 @@ __export(claude_exports, {
|
|
|
3241
3714
|
uninstallClaudeIntegration: () => uninstallClaudeIntegration
|
|
3242
3715
|
});
|
|
3243
3716
|
import {
|
|
3244
|
-
chmodSync,
|
|
3717
|
+
chmodSync as chmodSync2,
|
|
3245
3718
|
copyFileSync,
|
|
3246
|
-
existsSync as
|
|
3247
|
-
mkdirSync as
|
|
3248
|
-
readFileSync as
|
|
3249
|
-
writeFileSync as
|
|
3719
|
+
existsSync as existsSync9,
|
|
3720
|
+
mkdirSync as mkdirSync5,
|
|
3721
|
+
readFileSync as readFileSync6,
|
|
3722
|
+
writeFileSync as writeFileSync6
|
|
3250
3723
|
} from "node:fs";
|
|
3251
|
-
import { homedir as
|
|
3252
|
-
import { dirname as
|
|
3724
|
+
import { homedir as homedir7 } from "node:os";
|
|
3725
|
+
import { dirname as dirname8, join as join7 } from "node:path";
|
|
3253
3726
|
function hookScriptPath() {
|
|
3254
|
-
return
|
|
3727
|
+
return join7(homedir7(), HOOK_SCRIPT_RELPATH);
|
|
3255
3728
|
}
|
|
3256
3729
|
function claudeSettingsPath() {
|
|
3257
|
-
return process.env.TMUX_IDE_CLAUDE_SETTINGS ??
|
|
3730
|
+
return process.env.TMUX_IDE_CLAUDE_SETTINGS ?? join7(homedir7(), ".claude", "settings.json");
|
|
3258
3731
|
}
|
|
3259
3732
|
function isOurs(group) {
|
|
3260
3733
|
return group.hooks?.some((h) => h.command?.includes(HOOK_SCRIPT_RELPATH)) ?? false;
|
|
@@ -3287,24 +3760,24 @@ function isInstalled(settings) {
|
|
|
3287
3760
|
return Object.values(settings.hooks ?? {}).some((groups) => groups.some(isOurs));
|
|
3288
3761
|
}
|
|
3289
3762
|
function readSettings(path2) {
|
|
3290
|
-
if (!
|
|
3763
|
+
if (!existsSync9(path2)) return {};
|
|
3291
3764
|
try {
|
|
3292
|
-
return JSON.parse(
|
|
3765
|
+
return JSON.parse(readFileSync6(path2, "utf8"));
|
|
3293
3766
|
} catch {
|
|
3294
3767
|
throw new Error(`${path2} is not valid JSON \u2014 fix or move it, then retry`);
|
|
3295
3768
|
}
|
|
3296
3769
|
}
|
|
3297
3770
|
function installClaudeIntegration() {
|
|
3298
3771
|
const script = hookScriptPath();
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3772
|
+
mkdirSync5(dirname8(script), { recursive: true });
|
|
3773
|
+
writeFileSync6(script, HOOK_SCRIPT, "utf8");
|
|
3774
|
+
chmodSync2(script, 493);
|
|
3302
3775
|
const settingsPath = claudeSettingsPath();
|
|
3303
|
-
|
|
3776
|
+
mkdirSync5(dirname8(settingsPath), { recursive: true });
|
|
3304
3777
|
const settings = readSettings(settingsPath);
|
|
3305
3778
|
const backup = `${settingsPath}.tmux-ide.bak`;
|
|
3306
|
-
if (
|
|
3307
|
-
|
|
3779
|
+
if (existsSync9(settingsPath) && !existsSync9(backup)) copyFileSync(settingsPath, backup);
|
|
3780
|
+
writeFileSync6(settingsPath, `${JSON.stringify(mergeHooks(settings, script), null, 2)}
|
|
3308
3781
|
`, "utf8");
|
|
3309
3782
|
return { scriptPath: script, settingsPath };
|
|
3310
3783
|
}
|
|
@@ -3313,7 +3786,7 @@ function uninstallClaudeIntegration() {
|
|
|
3313
3786
|
const settings = readSettings(settingsPath);
|
|
3314
3787
|
const wasInstalled = isInstalled(settings);
|
|
3315
3788
|
if (wasInstalled) {
|
|
3316
|
-
|
|
3789
|
+
writeFileSync6(settingsPath, `${JSON.stringify(removeHooks(settings), null, 2)}
|
|
3317
3790
|
`, "utf8");
|
|
3318
3791
|
}
|
|
3319
3792
|
return { settingsPath, wasInstalled };
|
|
@@ -3321,7 +3794,7 @@ function uninstallClaudeIntegration() {
|
|
|
3321
3794
|
function claudeIntegrationStatus() {
|
|
3322
3795
|
return {
|
|
3323
3796
|
installed: isInstalled(readSettings(claudeSettingsPath())),
|
|
3324
|
-
scriptExists:
|
|
3797
|
+
scriptExists: existsSync9(hookScriptPath())
|
|
3325
3798
|
};
|
|
3326
3799
|
}
|
|
3327
3800
|
var HOOK_SCRIPT_RELPATH, HOOK_SCRIPT, EVENT_STATES;
|
|
@@ -3360,12 +3833,12 @@ __export(offer_exports, {
|
|
|
3360
3833
|
shouldOfferIntegration: () => shouldOfferIntegration
|
|
3361
3834
|
});
|
|
3362
3835
|
import { execFileSync as execFileSync5, spawn as spawn3 } from "node:child_process";
|
|
3363
|
-
import { existsSync as
|
|
3364
|
-
import { homedir as
|
|
3365
|
-
import { dirname as
|
|
3836
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "node:fs";
|
|
3837
|
+
import { homedir as homedir8 } from "node:os";
|
|
3838
|
+
import { dirname as dirname9, join as join8 } from "node:path";
|
|
3366
3839
|
function integrationOfferMarkerPath() {
|
|
3367
|
-
const home = process.env.TMUX_IDE_HOME ??
|
|
3368
|
-
return
|
|
3840
|
+
const home = process.env.TMUX_IDE_HOME ?? join8(homedir8(), ".tmux-ide");
|
|
3841
|
+
return join8(home, "integration-offered");
|
|
3369
3842
|
}
|
|
3370
3843
|
function shouldOfferIntegration(input) {
|
|
3371
3844
|
return input.claudeOnPath && !input.integrationInstalled && !input.markerPresent && input.offerEnabled;
|
|
@@ -3373,8 +3846,8 @@ function shouldOfferIntegration(input) {
|
|
|
3373
3846
|
function markIntegrationOffered() {
|
|
3374
3847
|
const path2 = integrationOfferMarkerPath();
|
|
3375
3848
|
try {
|
|
3376
|
-
|
|
3377
|
-
|
|
3849
|
+
mkdirSync6(dirname9(path2), { recursive: true });
|
|
3850
|
+
writeFileSync7(path2, (/* @__PURE__ */ new Date()).toISOString());
|
|
3378
3851
|
} catch {
|
|
3379
3852
|
}
|
|
3380
3853
|
}
|
|
@@ -3399,7 +3872,7 @@ function maybeOfferIntegrationPopup() {
|
|
|
3399
3872
|
offer = shouldOfferIntegration({
|
|
3400
3873
|
claudeOnPath: claudeOnPath(),
|
|
3401
3874
|
integrationInstalled: status2.installed,
|
|
3402
|
-
markerPresent:
|
|
3875
|
+
markerPresent: existsSync10(integrationOfferMarkerPath()),
|
|
3403
3876
|
offerEnabled: getAppConfig().integrations.offer
|
|
3404
3877
|
});
|
|
3405
3878
|
} catch {
|
|
@@ -3455,176 +3928,6 @@ var init_kitty_keys = __esm({
|
|
|
3455
3928
|
}
|
|
3456
3929
|
});
|
|
3457
3930
|
|
|
3458
|
-
// packages/daemon/src/lib/update-check.ts
|
|
3459
|
-
var update_check_exports = {};
|
|
3460
|
-
__export(update_check_exports, {
|
|
3461
|
-
CHECK_INTERVAL_MS: () => CHECK_INTERVAL_MS,
|
|
3462
|
-
REGISTRY_URL: () => REGISTRY_URL,
|
|
3463
|
-
compareSemver: () => compareSemver,
|
|
3464
|
-
deriveStatus: () => deriveStatus,
|
|
3465
|
-
fetchLatestVersion: () => fetchLatestVersion,
|
|
3466
|
-
getCurrentVersion: () => getCurrentVersion,
|
|
3467
|
-
getUpdateStatus: () => getUpdateStatus,
|
|
3468
|
-
isNewer: () => isNewer,
|
|
3469
|
-
markUpdateNotified: () => markUpdateNotified,
|
|
3470
|
-
maybeCheckForUpdate: () => maybeCheckForUpdate,
|
|
3471
|
-
parseRegistryResponse: () => parseRegistryResponse,
|
|
3472
|
-
readUpdateCache: () => readUpdateCache,
|
|
3473
|
-
runUpdateCheck: () => runUpdateCheck,
|
|
3474
|
-
shouldCheck: () => shouldCheck,
|
|
3475
|
-
updateCachePath: () => updateCachePath,
|
|
3476
|
-
writeUpdateCache: () => writeUpdateCache
|
|
3477
|
-
});
|
|
3478
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3479
|
-
import { homedir as homedir7 } from "node:os";
|
|
3480
|
-
import { dirname as dirname7, join as join7 } from "node:path";
|
|
3481
|
-
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
3482
|
-
function parseSemver(version) {
|
|
3483
|
-
const core = version.trim().replace(/^v/i, "").split("+")[0] ?? "";
|
|
3484
|
-
const dash = core.indexOf("-");
|
|
3485
|
-
const main = dash === -1 ? core : core.slice(0, dash);
|
|
3486
|
-
const pre = dash === -1 ? "" : core.slice(dash + 1);
|
|
3487
|
-
const parts = main.split(".");
|
|
3488
|
-
const num = (i) => {
|
|
3489
|
-
const n = Number.parseInt(parts[i] ?? "", 10);
|
|
3490
|
-
return Number.isFinite(n) && n >= 0 ? n : 0;
|
|
3491
|
-
};
|
|
3492
|
-
return { nums: [num(0), num(1), num(2)], pre };
|
|
3493
|
-
}
|
|
3494
|
-
function compareSemver(a, b) {
|
|
3495
|
-
const pa = parseSemver(a);
|
|
3496
|
-
const pb = parseSemver(b);
|
|
3497
|
-
for (let i = 0; i < 3; i++) {
|
|
3498
|
-
if (pa.nums[i] !== pb.nums[i]) return pa.nums[i] < pb.nums[i] ? -1 : 1;
|
|
3499
|
-
}
|
|
3500
|
-
if (pa.pre === pb.pre) return 0;
|
|
3501
|
-
if (pa.pre === "") return 1;
|
|
3502
|
-
if (pb.pre === "") return -1;
|
|
3503
|
-
return pa.pre < pb.pre ? -1 : 1;
|
|
3504
|
-
}
|
|
3505
|
-
function isNewer(latest, current) {
|
|
3506
|
-
return compareSemver(latest, current) === 1;
|
|
3507
|
-
}
|
|
3508
|
-
function shouldCheck(lastCheckedAt, nowMs) {
|
|
3509
|
-
if (lastCheckedAt === null) return true;
|
|
3510
|
-
return nowMs - lastCheckedAt >= CHECK_INTERVAL_MS;
|
|
3511
|
-
}
|
|
3512
|
-
function parseRegistryResponse(json2) {
|
|
3513
|
-
try {
|
|
3514
|
-
const parsed = JSON.parse(json2);
|
|
3515
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
3516
|
-
const version = parsed.version;
|
|
3517
|
-
return typeof version === "string" && version.length > 0 ? version : null;
|
|
3518
|
-
} catch {
|
|
3519
|
-
return null;
|
|
3520
|
-
}
|
|
3521
|
-
}
|
|
3522
|
-
function deriveStatus(latest, currentVersion) {
|
|
3523
|
-
return {
|
|
3524
|
-
latest,
|
|
3525
|
-
updateAvailable: latest !== null && isNewer(latest, currentVersion)
|
|
3526
|
-
};
|
|
3527
|
-
}
|
|
3528
|
-
function updateCachePath() {
|
|
3529
|
-
const home = process.env.TMUX_IDE_HOME ?? join7(homedir7(), ".tmux-ide");
|
|
3530
|
-
return join7(home, "update-check.json");
|
|
3531
|
-
}
|
|
3532
|
-
function readUpdateCache() {
|
|
3533
|
-
const path2 = updateCachePath();
|
|
3534
|
-
if (!existsSync9(path2)) return null;
|
|
3535
|
-
try {
|
|
3536
|
-
const parsed = JSON.parse(readFileSync6(path2, "utf-8"));
|
|
3537
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
3538
|
-
const obj = parsed;
|
|
3539
|
-
const lastCheckedAt = typeof obj.lastCheckedAt === "number" ? obj.lastCheckedAt : null;
|
|
3540
|
-
const latest = typeof obj.latest === "string" && obj.latest.length > 0 ? obj.latest : null;
|
|
3541
|
-
const notified = Array.isArray(obj.notified) ? obj.notified.filter((v) => typeof v === "string") : void 0;
|
|
3542
|
-
return { lastCheckedAt, latest, ...notified ? { notified } : {} };
|
|
3543
|
-
} catch {
|
|
3544
|
-
return null;
|
|
3545
|
-
}
|
|
3546
|
-
}
|
|
3547
|
-
function writeUpdateCache(cache3) {
|
|
3548
|
-
const path2 = updateCachePath();
|
|
3549
|
-
try {
|
|
3550
|
-
mkdirSync4(dirname7(path2), { recursive: true });
|
|
3551
|
-
writeFileSync5(path2, JSON.stringify(cache3));
|
|
3552
|
-
} catch {
|
|
3553
|
-
}
|
|
3554
|
-
}
|
|
3555
|
-
async function fetchLatestVersion(timeoutMs = 3e3) {
|
|
3556
|
-
const controller = new AbortController();
|
|
3557
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3558
|
-
try {
|
|
3559
|
-
const res = await fetch(REGISTRY_URL, { signal: controller.signal });
|
|
3560
|
-
if (!res.ok) return null;
|
|
3561
|
-
return parseRegistryResponse(await res.text());
|
|
3562
|
-
} catch {
|
|
3563
|
-
return null;
|
|
3564
|
-
} finally {
|
|
3565
|
-
clearTimeout(timer);
|
|
3566
|
-
}
|
|
3567
|
-
}
|
|
3568
|
-
function getCurrentVersion() {
|
|
3569
|
-
const here = dirname7(fileURLToPath4(import.meta.url));
|
|
3570
|
-
const candidates = [
|
|
3571
|
-
join7(here, "../package.json"),
|
|
3572
|
-
// bundled bin/cli.js → repo root
|
|
3573
|
-
join7(here, "../../../../package.json")
|
|
3574
|
-
// dev src/lib → repo root
|
|
3575
|
-
];
|
|
3576
|
-
for (const candidate of candidates) {
|
|
3577
|
-
try {
|
|
3578
|
-
const parsed = JSON.parse(readFileSync6(candidate, "utf-8"));
|
|
3579
|
-
if (typeof parsed.version === "string" && parsed.version.length > 0) return parsed.version;
|
|
3580
|
-
} catch {
|
|
3581
|
-
}
|
|
3582
|
-
}
|
|
3583
|
-
return "0.0.0";
|
|
3584
|
-
}
|
|
3585
|
-
function getUpdateStatus({
|
|
3586
|
-
currentVersion = getCurrentVersion()
|
|
3587
|
-
} = {}) {
|
|
3588
|
-
const cache3 = readUpdateCache();
|
|
3589
|
-
return deriveStatus(cache3?.latest ?? null, currentVersion);
|
|
3590
|
-
}
|
|
3591
|
-
async function runUpdateCheck({ now = Date.now() } = {}) {
|
|
3592
|
-
const cache3 = readUpdateCache();
|
|
3593
|
-
if (!shouldCheck(cache3?.lastCheckedAt ?? null, now)) return;
|
|
3594
|
-
const fetched = await fetchLatestVersion();
|
|
3595
|
-
writeUpdateCache({
|
|
3596
|
-
lastCheckedAt: now,
|
|
3597
|
-
latest: fetched ?? cache3?.latest ?? null,
|
|
3598
|
-
...cache3?.notified ? { notified: cache3.notified } : {}
|
|
3599
|
-
});
|
|
3600
|
-
}
|
|
3601
|
-
function maybeCheckForUpdate({
|
|
3602
|
-
enabled,
|
|
3603
|
-
now = Date.now(),
|
|
3604
|
-
currentVersion = getCurrentVersion()
|
|
3605
|
-
}) {
|
|
3606
|
-
if (!enabled) return { latest: null, updateAvailable: false };
|
|
3607
|
-
const status2 = getUpdateStatus({ now, currentVersion });
|
|
3608
|
-
void runUpdateCheck({ now }).catch(() => {
|
|
3609
|
-
});
|
|
3610
|
-
return status2;
|
|
3611
|
-
}
|
|
3612
|
-
function markUpdateNotified(version) {
|
|
3613
|
-
const cache3 = readUpdateCache() ?? { lastCheckedAt: null, latest: null };
|
|
3614
|
-
const notified = cache3.notified ?? [];
|
|
3615
|
-
if (notified.includes(version)) return false;
|
|
3616
|
-
writeUpdateCache({ ...cache3, notified: [...notified, version] });
|
|
3617
|
-
return true;
|
|
3618
|
-
}
|
|
3619
|
-
var REGISTRY_URL, CHECK_INTERVAL_MS;
|
|
3620
|
-
var init_update_check = __esm({
|
|
3621
|
-
"packages/daemon/src/lib/update-check.ts"() {
|
|
3622
|
-
"use strict";
|
|
3623
|
-
REGISTRY_URL = "https://registry.npmjs.org/tmux-ide/latest";
|
|
3624
|
-
CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
3625
|
-
}
|
|
3626
|
-
});
|
|
3627
|
-
|
|
3628
3931
|
// packages/daemon/src/schemas/registry.ts
|
|
3629
3932
|
import { z as z9 } from "zod";
|
|
3630
3933
|
var RegisteredProjectSchemaZ, RegisterProjectRequestSchemaZ, InitProjectRequestSchemaZ, ProjectTemplateSchemaZ;
|
|
@@ -3663,7 +3966,7 @@ var init_registry = __esm({
|
|
|
3663
3966
|
|
|
3664
3967
|
// packages/daemon/src/lib/project-probe.ts
|
|
3665
3968
|
import { execFile } from "node:child_process";
|
|
3666
|
-
import { existsSync as
|
|
3969
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
3667
3970
|
import { basename as basename3, isAbsolute, resolve as resolve7 } from "node:path";
|
|
3668
3971
|
function sanitizeName(raw) {
|
|
3669
3972
|
return raw.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-9._-]/g, "").replace(/^-+|-+$/g, "");
|
|
@@ -3694,7 +3997,7 @@ var init_project_probe = __esm({
|
|
|
3694
3997
|
"use strict";
|
|
3695
3998
|
GIT_TIMEOUT_MS = 2e3;
|
|
3696
3999
|
realIo = {
|
|
3697
|
-
exists:
|
|
4000
|
+
exists: existsSync11,
|
|
3698
4001
|
runGit: (args, cwd) => new Promise((resolveResult) => {
|
|
3699
4002
|
execFile(
|
|
3700
4003
|
"git",
|
|
@@ -3715,9 +4018,9 @@ var init_project_probe = __esm({
|
|
|
3715
4018
|
|
|
3716
4019
|
// packages/daemon/src/lib/project-registry.ts
|
|
3717
4020
|
import { EventEmitter } from "node:events";
|
|
3718
|
-
import { existsSync as
|
|
3719
|
-
import { homedir as
|
|
3720
|
-
import { dirname as
|
|
4021
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync7, renameSync as renameSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
4022
|
+
import { homedir as homedir9 } from "node:os";
|
|
4023
|
+
import { dirname as dirname10, isAbsolute as isAbsolute2, join as join9, resolve as resolve8 } from "node:path";
|
|
3721
4024
|
import { z as z10 } from "zod";
|
|
3722
4025
|
function applyAction(state, action) {
|
|
3723
4026
|
switch (action.type) {
|
|
@@ -3749,14 +4052,14 @@ function buildRegisteredProject(probe, name, registeredAt) {
|
|
|
3749
4052
|
function registryDir() {
|
|
3750
4053
|
const override = process.env[REGISTRY_DIR_ENV];
|
|
3751
4054
|
if (override && override.length > 0) return override;
|
|
3752
|
-
return
|
|
4055
|
+
return join9(homedir9(), ".tmux-ide");
|
|
3753
4056
|
}
|
|
3754
4057
|
function registryPath() {
|
|
3755
|
-
return
|
|
4058
|
+
return join9(registryDir(), "projects.json");
|
|
3756
4059
|
}
|
|
3757
4060
|
function readDisk() {
|
|
3758
4061
|
const path2 = registryPath();
|
|
3759
|
-
if (!
|
|
4062
|
+
if (!existsSync12(path2)) return [];
|
|
3760
4063
|
const raw = readFileSync7(path2, "utf-8");
|
|
3761
4064
|
if (raw.trim().length === 0) return [];
|
|
3762
4065
|
let parsed;
|
|
@@ -3779,12 +4082,12 @@ function readDisk() {
|
|
|
3779
4082
|
}
|
|
3780
4083
|
function writeDisk(projects) {
|
|
3781
4084
|
const path2 = registryPath();
|
|
3782
|
-
const dir =
|
|
3783
|
-
|
|
4085
|
+
const dir = dirname10(path2);
|
|
4086
|
+
mkdirSync7(dir, { recursive: true });
|
|
3784
4087
|
const file = { version: 1, projects };
|
|
3785
4088
|
const tmpPath = `${path2}.tmp`;
|
|
3786
|
-
|
|
3787
|
-
|
|
4089
|
+
writeFileSync8(tmpPath, JSON.stringify(file, null, 2) + "\n");
|
|
4090
|
+
renameSync3(tmpPath, path2);
|
|
3788
4091
|
}
|
|
3789
4092
|
function ensureCache() {
|
|
3790
4093
|
if (cache2 !== null) return cache2;
|
|
@@ -3803,7 +4106,7 @@ function getProject(name) {
|
|
|
3803
4106
|
return ensureCache().find((p) => p.name === name) ?? null;
|
|
3804
4107
|
}
|
|
3805
4108
|
async function registerProject(input) {
|
|
3806
|
-
const exists = input.exists ??
|
|
4109
|
+
const exists = input.exists ?? existsSync12;
|
|
3807
4110
|
const absoluteDir = isAbsolute2(input.dir) ? input.dir : resolve8(input.dir);
|
|
3808
4111
|
if (!exists(absoluteDir)) {
|
|
3809
4112
|
throw new ProjectDirNotFoundError(absoluteDir);
|
|
@@ -4013,9 +4316,9 @@ __export(events_exports, {
|
|
|
4013
4316
|
formatEventLine: () => formatEventLine,
|
|
4014
4317
|
shouldRotate: () => shouldRotate
|
|
4015
4318
|
});
|
|
4016
|
-
import { appendFileSync, existsSync as
|
|
4017
|
-
import { homedir as
|
|
4018
|
-
import { join as
|
|
4319
|
+
import { appendFileSync, existsSync as existsSync13, mkdirSync as mkdirSync8, renameSync as renameSync4, statSync } from "node:fs";
|
|
4320
|
+
import { homedir as homedir10 } from "node:os";
|
|
4321
|
+
import { join as join10 } from "node:path";
|
|
4019
4322
|
function diffFleet(prev, next) {
|
|
4020
4323
|
const state = /* @__PURE__ */ new Map();
|
|
4021
4324
|
const events = [];
|
|
@@ -4042,15 +4345,15 @@ function formatEventLine(ev, paint = (_s, t) => t) {
|
|
|
4042
4345
|
return `${isoTime(ev.ts)} ${ev.session} ${from} \u2192 ${paint(ev.to, ev.to)}`;
|
|
4043
4346
|
}
|
|
4044
4347
|
function eventsPath() {
|
|
4045
|
-
return
|
|
4348
|
+
return join10(homedir10(), ".tmux-ide", "events.jsonl");
|
|
4046
4349
|
}
|
|
4047
4350
|
function appendEvents(events, now = () => (/* @__PURE__ */ new Date()).toISOString()) {
|
|
4048
4351
|
if (events.length === 0) return;
|
|
4049
4352
|
const path2 = eventsPath();
|
|
4050
4353
|
try {
|
|
4051
|
-
|
|
4052
|
-
if (
|
|
4053
|
-
|
|
4354
|
+
mkdirSync8(join10(homedir10(), ".tmux-ide"), { recursive: true });
|
|
4355
|
+
if (existsSync13(path2) && shouldRotate(statSync(path2).size)) {
|
|
4356
|
+
renameSync4(path2, `${path2}.1`);
|
|
4054
4357
|
}
|
|
4055
4358
|
const ts = now();
|
|
4056
4359
|
const lines = events.map((e) => `${JSON.stringify({ ts, ...e })}
|
|
@@ -4069,25 +4372,38 @@ var init_events = __esm({
|
|
|
4069
4372
|
|
|
4070
4373
|
// packages/daemon/src/tui/chrome/notify.ts
|
|
4071
4374
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
4072
|
-
|
|
4073
|
-
|
|
4375
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8 } from "node:fs";
|
|
4376
|
+
function statusPhrase(to) {
|
|
4377
|
+
return to === "blocked" ? "needs input" : "finished";
|
|
4378
|
+
}
|
|
4379
|
+
function notifyMessage(ev) {
|
|
4380
|
+
const agent = ev.agent && ev.agent.length > 0 ? ev.agent : "agent";
|
|
4381
|
+
const where = ev.location && ev.location.length > 0 ? ev.location : ev.session;
|
|
4382
|
+
const text = `${agent} ${ev.to} \xB7 ${where} \u2014 ${statusPhrase(ev.to)}`;
|
|
4383
|
+
return text.length > NOTIFY_MAX_LEN ? `${text.slice(0, NOTIFY_MAX_LEN - 1)}\u2026` : text;
|
|
4384
|
+
}
|
|
4385
|
+
function enabledStates(prefs) {
|
|
4386
|
+
const states = /* @__PURE__ */ new Set();
|
|
4387
|
+
if (prefs.onBlocked) states.add("blocked");
|
|
4388
|
+
if (prefs.onDone) states.add("done");
|
|
4389
|
+
return states;
|
|
4074
4390
|
}
|
|
4075
|
-
function decideNotifications(events, clients, lastNotified, nowMs) {
|
|
4391
|
+
function decideNotifications(events, clients, lastNotified, nowMs, states = NOTIFY_STATES) {
|
|
4076
4392
|
const nextLastNotified = new Map(lastNotified);
|
|
4077
4393
|
const toasts = [];
|
|
4078
4394
|
const system = [];
|
|
4079
4395
|
for (const ev of events) {
|
|
4080
|
-
if (!
|
|
4396
|
+
if (!states.has(ev.to)) continue;
|
|
4081
4397
|
const key = `${ev.session}:${ev.to}`;
|
|
4082
4398
|
const last = nextLastNotified.get(key);
|
|
4083
4399
|
if (last !== void 0 && nowMs - last < NOTIFY_DEBOUNCE_MS) continue;
|
|
4084
4400
|
nextLastNotified.set(key, nowMs);
|
|
4085
|
-
const message = notifyMessage(ev
|
|
4401
|
+
const message = notifyMessage(ev);
|
|
4086
4402
|
for (const c of clients) {
|
|
4087
4403
|
if (c.session === ev.session) continue;
|
|
4088
4404
|
toasts.push({ client: c.client, message });
|
|
4089
4405
|
}
|
|
4090
|
-
system.push({ message });
|
|
4406
|
+
system.push({ message, session: ev.session });
|
|
4091
4407
|
}
|
|
4092
4408
|
return { toasts, system, nextLastNotified };
|
|
4093
4409
|
}
|
|
@@ -4115,23 +4431,100 @@ function sendToasts(toasts) {
|
|
|
4115
4431
|
}
|
|
4116
4432
|
}
|
|
4117
4433
|
}
|
|
4118
|
-
function
|
|
4434
|
+
function hasTerminalNotifier() {
|
|
4435
|
+
try {
|
|
4436
|
+
execFileSync6("which", ["terminal-notifier"], { stdio: "ignore" });
|
|
4437
|
+
return true;
|
|
4438
|
+
} catch {
|
|
4439
|
+
return false;
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
function shellSingleQuote(value) {
|
|
4443
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
4444
|
+
}
|
|
4445
|
+
function terminalNotifierArgs(n) {
|
|
4446
|
+
return [
|
|
4447
|
+
"-title",
|
|
4448
|
+
"tmux-ide",
|
|
4449
|
+
"-message",
|
|
4450
|
+
n.message,
|
|
4451
|
+
"-execute",
|
|
4452
|
+
`tmux switch-client -t ${shellSingleQuote(n.session)}`
|
|
4453
|
+
];
|
|
4454
|
+
}
|
|
4455
|
+
function sendSystemNotification(n) {
|
|
4119
4456
|
if (process.platform !== "darwin") return;
|
|
4120
|
-
const escaped = message.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
4121
4457
|
try {
|
|
4458
|
+
if (hasTerminalNotifier()) {
|
|
4459
|
+
execFileSync6("terminal-notifier", terminalNotifierArgs(n), { stdio: "ignore" });
|
|
4460
|
+
return;
|
|
4461
|
+
}
|
|
4462
|
+
const escaped = n.message.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
4122
4463
|
execFileSync6("osascript", ["-e", `display notification "${escaped}" with title "tmux-ide"`], {
|
|
4123
4464
|
stdio: "ignore"
|
|
4124
4465
|
});
|
|
4125
4466
|
} catch {
|
|
4126
4467
|
}
|
|
4127
4468
|
}
|
|
4469
|
+
function asObject2(value) {
|
|
4470
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
4471
|
+
}
|
|
4472
|
+
function pickBool2(value, fallback) {
|
|
4473
|
+
return typeof value === "boolean" ? value : fallback;
|
|
4474
|
+
}
|
|
4475
|
+
function parseHHMM(value) {
|
|
4476
|
+
if (typeof value !== "string") return null;
|
|
4477
|
+
const m = /^(\d{2}):(\d{2})$/.exec(value.trim());
|
|
4478
|
+
if (!m) return null;
|
|
4479
|
+
const hours = Number(m[1]);
|
|
4480
|
+
const minutes = Number(m[2]);
|
|
4481
|
+
if (hours > 23 || minutes > 59) return null;
|
|
4482
|
+
return hours * 60 + minutes;
|
|
4483
|
+
}
|
|
4484
|
+
function inQuietHours(now, quiet) {
|
|
4485
|
+
if (!quiet) return false;
|
|
4486
|
+
const start2 = parseHHMM(quiet.start);
|
|
4487
|
+
const end = parseHHMM(quiet.end);
|
|
4488
|
+
if (start2 === null || end === null || start2 === end) return false;
|
|
4489
|
+
const nowMin = now.getHours() * 60 + now.getMinutes();
|
|
4490
|
+
return start2 < end ? nowMin >= start2 && nowMin < end : nowMin >= start2 || nowMin < end;
|
|
4491
|
+
}
|
|
4492
|
+
function parseQuietHours(value) {
|
|
4493
|
+
const o = asObject2(value);
|
|
4494
|
+
const start2 = typeof o.start === "string" ? o.start : null;
|
|
4495
|
+
const end = typeof o.end === "string" ? o.end : null;
|
|
4496
|
+
if (start2 === null || end === null) return null;
|
|
4497
|
+
if (parseHHMM(start2) === null || parseHHMM(end) === null) return null;
|
|
4498
|
+
return { start: start2, end };
|
|
4499
|
+
}
|
|
4500
|
+
function parseNotificationPrefs(rawConfig) {
|
|
4501
|
+
const base = parseAppConfig(rawConfig).notifications;
|
|
4502
|
+
const n = asObject2(asObject2(rawConfig).notifications);
|
|
4503
|
+
return {
|
|
4504
|
+
enabled: pickBool2(n.enabled, DEFAULT_NOTIFICATION_PREFS.enabled),
|
|
4505
|
+
toast: base.toast,
|
|
4506
|
+
macos: base.macos,
|
|
4507
|
+
onBlocked: pickBool2(n.onBlocked, DEFAULT_NOTIFICATION_PREFS.onBlocked),
|
|
4508
|
+
onDone: pickBool2(n.onDone, DEFAULT_NOTIFICATION_PREFS.onDone),
|
|
4509
|
+
quietHours: parseQuietHours(n.quietHours)
|
|
4510
|
+
};
|
|
4511
|
+
}
|
|
4128
4512
|
function applyKillSwitch(prefs, envValue) {
|
|
4129
|
-
return envValue === "0" ? { toast: false, macos: false } : prefs;
|
|
4513
|
+
return envValue === "0" ? { ...prefs, enabled: false, toast: false, macos: false } : prefs;
|
|
4514
|
+
}
|
|
4515
|
+
function readRawConfig() {
|
|
4516
|
+
const path2 = appConfigPath();
|
|
4517
|
+
if (!existsSync14(path2)) return void 0;
|
|
4518
|
+
try {
|
|
4519
|
+
return JSON.parse(readFileSync8(path2, "utf-8"));
|
|
4520
|
+
} catch {
|
|
4521
|
+
return void 0;
|
|
4522
|
+
}
|
|
4130
4523
|
}
|
|
4131
4524
|
function readNotificationPrefs() {
|
|
4132
|
-
return applyKillSwitch(
|
|
4525
|
+
return applyKillSwitch(parseNotificationPrefs(readRawConfig()), process.env.TMUX_IDE_NOTIFY);
|
|
4133
4526
|
}
|
|
4134
|
-
var NOTIFY_STATES, NOTIFY_DEBOUNCE_MS;
|
|
4527
|
+
var NOTIFY_STATES, NOTIFY_DEBOUNCE_MS, NOTIFY_MAX_LEN, DEFAULT_NOTIFICATION_PREFS;
|
|
4135
4528
|
var init_notify = __esm({
|
|
4136
4529
|
"packages/daemon/src/tui/chrome/notify.ts"() {
|
|
4137
4530
|
"use strict";
|
|
@@ -4139,13 +4532,22 @@ var init_notify = __esm({
|
|
|
4139
4532
|
init_app_config();
|
|
4140
4533
|
NOTIFY_STATES = /* @__PURE__ */ new Set(["blocked", "done"]);
|
|
4141
4534
|
NOTIFY_DEBOUNCE_MS = 3e4;
|
|
4535
|
+
NOTIFY_MAX_LEN = 120;
|
|
4536
|
+
DEFAULT_NOTIFICATION_PREFS = {
|
|
4537
|
+
enabled: true,
|
|
4538
|
+
toast: true,
|
|
4539
|
+
macos: false,
|
|
4540
|
+
onBlocked: true,
|
|
4541
|
+
onDone: true,
|
|
4542
|
+
quietHours: null
|
|
4543
|
+
};
|
|
4142
4544
|
}
|
|
4143
4545
|
});
|
|
4144
4546
|
|
|
4145
4547
|
// packages/daemon/src/tui/chrome/snapshot.ts
|
|
4146
|
-
import { existsSync as
|
|
4147
|
-
import { homedir as
|
|
4148
|
-
import { dirname as
|
|
4548
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync9, readFileSync as readFileSync9, renameSync as renameSync5, writeFileSync as writeFileSync9 } from "node:fs";
|
|
4549
|
+
import { homedir as homedir11 } from "node:os";
|
|
4550
|
+
import { dirname as dirname11, join as join11 } from "node:path";
|
|
4149
4551
|
import { z as z11 } from "zod";
|
|
4150
4552
|
function isBareShell(cmd) {
|
|
4151
4553
|
return /^-?(zsh|bash|sh|fish|dash|ksh|tcsh|csh|nu)$/.test(cmd.trim());
|
|
@@ -4260,29 +4662,29 @@ function collectFleetSnapshot(io = defaultIo) {
|
|
|
4260
4662
|
return buildSnapshot(rawPanes, rawSessions, io.processTable());
|
|
4261
4663
|
}
|
|
4262
4664
|
function snapshotPath() {
|
|
4263
|
-
return
|
|
4665
|
+
return join11(homedir11(), ".tmux-ide", "snapshot.json");
|
|
4264
4666
|
}
|
|
4265
4667
|
function writeSnapshot(snapshot) {
|
|
4266
4668
|
const path2 = snapshotPath();
|
|
4267
4669
|
try {
|
|
4268
|
-
|
|
4670
|
+
mkdirSync9(dirname11(path2), { recursive: true });
|
|
4269
4671
|
const tmp = `${path2}.tmp`;
|
|
4270
|
-
|
|
4271
|
-
if (
|
|
4672
|
+
writeFileSync9(tmp, JSON.stringify(snapshot, null, 2) + "\n");
|
|
4673
|
+
if (existsSync15(path2)) {
|
|
4272
4674
|
try {
|
|
4273
|
-
|
|
4675
|
+
renameSync5(path2, `${path2}.1`);
|
|
4274
4676
|
} catch {
|
|
4275
4677
|
}
|
|
4276
4678
|
}
|
|
4277
|
-
|
|
4679
|
+
renameSync5(tmp, path2);
|
|
4278
4680
|
} catch {
|
|
4279
4681
|
}
|
|
4280
4682
|
}
|
|
4281
4683
|
function readSnapshot() {
|
|
4282
4684
|
const path2 = snapshotPath();
|
|
4283
4685
|
try {
|
|
4284
|
-
if (!
|
|
4285
|
-
const raw =
|
|
4686
|
+
if (!existsSync15(path2)) return null;
|
|
4687
|
+
const raw = readFileSync9(path2, "utf-8");
|
|
4286
4688
|
if (raw.trim().length === 0) return null;
|
|
4287
4689
|
const result = FleetSnapshotSchemaZ.safeParse(JSON.parse(raw));
|
|
4288
4690
|
return result.success ? result.data : null;
|
|
@@ -4379,7 +4781,10 @@ __export(updater_exports, {
|
|
|
4379
4781
|
UPDATER_PID_OPTION: () => UPDATER_PID_OPTION,
|
|
4380
4782
|
UPDATER_SESSION: () => UPDATER_SESSION,
|
|
4381
4783
|
adoptedSessionsFrom: () => adoptedSessionsFrom,
|
|
4784
|
+
enrichEvents: () => enrichEvents,
|
|
4382
4785
|
listAdoptedSessions: () => listAdoptedSessions,
|
|
4786
|
+
paneLocation: () => paneLocation,
|
|
4787
|
+
pickRepresentativePane: () => pickRepresentativePane,
|
|
4383
4788
|
runUpdaterLoop: () => runUpdaterLoop,
|
|
4384
4789
|
runUpdaterTick: () => runUpdaterTick,
|
|
4385
4790
|
seedSessionStatus: () => seedSessionStatus,
|
|
@@ -4436,7 +4841,7 @@ function runUpdaterTick(deps2) {
|
|
|
4436
4841
|
for (const [name, status2] of state) deps2.prevState.set(name, status2);
|
|
4437
4842
|
if (events.length > 0) {
|
|
4438
4843
|
deps2.appendEvents(events);
|
|
4439
|
-
dispatchNotifications(deps2, events);
|
|
4844
|
+
dispatchNotifications(deps2, enrichEvents(events, panes, deps2.locatePane));
|
|
4440
4845
|
}
|
|
4441
4846
|
}
|
|
4442
4847
|
}
|
|
@@ -4452,16 +4857,54 @@ function writeChips(deps2, adopted, panes, theme) {
|
|
|
4452
4857
|
writeChip(pane.paneId, chip);
|
|
4453
4858
|
}
|
|
4454
4859
|
}
|
|
4860
|
+
function pickRepresentativePane(session, to, panes) {
|
|
4861
|
+
const matching = panes.filter((p) => p.sessionName === session && p.status === to);
|
|
4862
|
+
if (matching.length === 0) return null;
|
|
4863
|
+
return matching.find((p) => p.agent !== null) ?? matching[0];
|
|
4864
|
+
}
|
|
4865
|
+
function enrichEvents(events, panes, locate) {
|
|
4866
|
+
return events.map((ev) => {
|
|
4867
|
+
const notifiable = ev.to === "blocked" || ev.to === "done";
|
|
4868
|
+
const rep = notifiable ? pickRepresentativePane(ev.session, ev.to, panes) : null;
|
|
4869
|
+
return {
|
|
4870
|
+
...ev,
|
|
4871
|
+
agent: rep?.agent ?? null,
|
|
4872
|
+
location: rep && locate ? locate(rep.paneId) : ev.session
|
|
4873
|
+
};
|
|
4874
|
+
});
|
|
4875
|
+
}
|
|
4455
4876
|
function dispatchNotifications(deps2, events) {
|
|
4456
4877
|
const { listClients, lastNotified, now, prefs, sendToasts: toast, sendSystem } = deps2;
|
|
4457
4878
|
if (!listClients || !lastNotified || !now || !prefs) return;
|
|
4879
|
+
if (!prefs.enabled) return;
|
|
4458
4880
|
if (!prefs.toast && !prefs.macos) return;
|
|
4459
|
-
const
|
|
4881
|
+
const nowMs = now();
|
|
4882
|
+
const decision = decideNotifications(
|
|
4883
|
+
events,
|
|
4884
|
+
listClients(),
|
|
4885
|
+
lastNotified,
|
|
4886
|
+
nowMs,
|
|
4887
|
+
enabledStates(prefs)
|
|
4888
|
+
);
|
|
4460
4889
|
lastNotified.clear();
|
|
4461
4890
|
for (const [key, ts] of decision.nextLastNotified) lastNotified.set(key, ts);
|
|
4462
4891
|
if (prefs.toast && toast) toast(decision.toasts);
|
|
4463
|
-
if (prefs.macos && sendSystem) {
|
|
4464
|
-
for (const
|
|
4892
|
+
if (prefs.macos && sendSystem && !inQuietHours(new Date(nowMs), prefs.quietHours)) {
|
|
4893
|
+
for (const n of decision.system) sendSystem(n);
|
|
4894
|
+
}
|
|
4895
|
+
}
|
|
4896
|
+
function paneLocation(paneId) {
|
|
4897
|
+
try {
|
|
4898
|
+
const raw = runTmux([
|
|
4899
|
+
"display-message",
|
|
4900
|
+
"-p",
|
|
4901
|
+
"-t",
|
|
4902
|
+
paneId,
|
|
4903
|
+
"#{session_name}:#{window_index}.#{pane_index}"
|
|
4904
|
+
]).toString().trim();
|
|
4905
|
+
return raw || paneId;
|
|
4906
|
+
} catch {
|
|
4907
|
+
return paneId;
|
|
4465
4908
|
}
|
|
4466
4909
|
}
|
|
4467
4910
|
function dispatchUpdateToast(deps2, version) {
|
|
@@ -4553,6 +4996,7 @@ function runUpdaterLoop() {
|
|
|
4553
4996
|
prefs: readNotificationPrefs(),
|
|
4554
4997
|
sendToasts,
|
|
4555
4998
|
sendSystem: sendSystemNotification,
|
|
4999
|
+
locatePane: paneLocation,
|
|
4556
5000
|
maybeCheckForUpdate: () => maybeCheckForUpdate({ enabled: config2.updates.check }),
|
|
4557
5001
|
markUpdateNotified
|
|
4558
5002
|
});
|
|
@@ -4872,12 +5316,12 @@ __export(canonical_daemon_exports, {
|
|
|
4872
5316
|
warnOnDaemonVersionSkew: () => warnOnDaemonVersionSkew,
|
|
4873
5317
|
writeCanonicalDaemonInfo: () => writeCanonicalDaemonInfo
|
|
4874
5318
|
});
|
|
4875
|
-
import { existsSync as
|
|
4876
|
-
import { homedir as
|
|
4877
|
-
import { dirname as
|
|
5319
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync10, renameSync as renameSync6, rmSync, writeFileSync as writeFileSync10 } from "node:fs";
|
|
5320
|
+
import { homedir as homedir12 } from "node:os";
|
|
5321
|
+
import { dirname as dirname12, join as join12 } from "node:path";
|
|
4878
5322
|
function getCanonicalDaemonInfoPath() {
|
|
4879
|
-
const dir = process.env[DAEMON_INFO_DIR_ENV] ?? process.env[REGISTRY_DIR_ENV2] ??
|
|
4880
|
-
return
|
|
5323
|
+
const dir = process.env[DAEMON_INFO_DIR_ENV] ?? process.env[REGISTRY_DIR_ENV2] ?? join12(homedir12(), ".tmux-ide");
|
|
5324
|
+
return join12(dir, DAEMON_INFO_FILE);
|
|
4881
5325
|
}
|
|
4882
5326
|
function parseCanonicalDaemonInfo(raw) {
|
|
4883
5327
|
if (!raw || typeof raw !== "object") return null;
|
|
@@ -4900,7 +5344,7 @@ function parseCanonicalDaemonInfo(raw) {
|
|
|
4900
5344
|
}
|
|
4901
5345
|
function writeCanonicalDaemonInfo(info) {
|
|
4902
5346
|
const path2 = getCanonicalDaemonInfoPath();
|
|
4903
|
-
|
|
5347
|
+
mkdirSync10(dirname12(path2), { recursive: true });
|
|
4904
5348
|
const tmpPath = `${path2}.${process.pid}.${Date.now()}.tmp`;
|
|
4905
5349
|
const persisted = {
|
|
4906
5350
|
pid: info.pid,
|
|
@@ -4910,14 +5354,14 @@ function writeCanonicalDaemonInfo(info) {
|
|
|
4910
5354
|
bindHostname: info.bindHostname,
|
|
4911
5355
|
authToken: info.authToken
|
|
4912
5356
|
};
|
|
4913
|
-
|
|
4914
|
-
|
|
5357
|
+
writeFileSync10(tmpPath, JSON.stringify(persisted, null, 2) + "\n", "utf-8");
|
|
5358
|
+
renameSync6(tmpPath, path2);
|
|
4915
5359
|
}
|
|
4916
5360
|
function readCanonicalDaemonInfo() {
|
|
4917
5361
|
const path2 = getCanonicalDaemonInfoPath();
|
|
4918
|
-
if (!
|
|
5362
|
+
if (!existsSync16(path2)) return null;
|
|
4919
5363
|
try {
|
|
4920
|
-
return parseCanonicalDaemonInfo(JSON.parse(
|
|
5364
|
+
return parseCanonicalDaemonInfo(JSON.parse(readFileSync10(path2, "utf-8")));
|
|
4921
5365
|
} catch {
|
|
4922
5366
|
return null;
|
|
4923
5367
|
}
|
|
@@ -5207,13 +5651,13 @@ var init_launch = __esm({
|
|
|
5207
5651
|
|
|
5208
5652
|
// packages/daemon/src/detect.ts
|
|
5209
5653
|
import { resolve as resolve10, basename as basename4 } from "node:path";
|
|
5210
|
-
import { readFileSync as
|
|
5654
|
+
import { readFileSync as readFileSync11, existsSync as existsSync17 } from "node:fs";
|
|
5211
5655
|
function fileExists(dir, name) {
|
|
5212
|
-
return
|
|
5656
|
+
return existsSync17(resolve10(dir, name));
|
|
5213
5657
|
}
|
|
5214
5658
|
function readJson(dir, name) {
|
|
5215
5659
|
try {
|
|
5216
|
-
return JSON.parse(
|
|
5660
|
+
return JSON.parse(readFileSync11(resolve10(dir, name), "utf-8"));
|
|
5217
5661
|
} catch {
|
|
5218
5662
|
return null;
|
|
5219
5663
|
}
|
|
@@ -5275,7 +5719,7 @@ function detectStack(dir) {
|
|
|
5275
5719
|
detected.language = detected.language ?? "python";
|
|
5276
5720
|
detected.reasons.push('Detected Python from "pyproject.toml" or "requirements.txt".');
|
|
5277
5721
|
try {
|
|
5278
|
-
const pyproject =
|
|
5722
|
+
const pyproject = readFileSync11(resolve10(dir, "pyproject.toml"), "utf-8");
|
|
5279
5723
|
if (pyproject.includes("fastapi"))
|
|
5280
5724
|
pushFramework(detected, "fastapi", 'Found "fastapi" in pyproject.toml.');
|
|
5281
5725
|
else if (pyproject.includes("django"))
|
|
@@ -5422,28 +5866,28 @@ __export(skill_sync_exports, {
|
|
|
5422
5866
|
syncSkill: () => syncSkill,
|
|
5423
5867
|
versionMarker: () => versionMarker
|
|
5424
5868
|
});
|
|
5425
|
-
import { existsSync as
|
|
5426
|
-
import { homedir as
|
|
5427
|
-
import { dirname as
|
|
5869
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync12, readFileSync as readFileSync13, writeFileSync as writeFileSync12 } from "node:fs";
|
|
5870
|
+
import { homedir as homedir13 } from "node:os";
|
|
5871
|
+
import { dirname as dirname14, join as join14 } from "node:path";
|
|
5428
5872
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
5429
5873
|
function claudeDir() {
|
|
5430
|
-
return process.env.TMUX_IDE_CLAUDE_DIR ??
|
|
5874
|
+
return process.env.TMUX_IDE_CLAUDE_DIR ?? join14(homedir13(), ".claude");
|
|
5431
5875
|
}
|
|
5432
5876
|
function skillTargetDir() {
|
|
5433
|
-
return
|
|
5877
|
+
return join14(claudeDir(), "skills", "tmux-ide");
|
|
5434
5878
|
}
|
|
5435
5879
|
function skillTargetFile() {
|
|
5436
|
-
return
|
|
5880
|
+
return join14(skillTargetDir(), "SKILL.md");
|
|
5437
5881
|
}
|
|
5438
5882
|
function defaultSkillSource() {
|
|
5439
|
-
const here =
|
|
5883
|
+
const here = dirname14(fileURLToPath6(import.meta.url));
|
|
5440
5884
|
const candidates = [
|
|
5441
|
-
|
|
5885
|
+
join14(here, "../skill/SKILL.md"),
|
|
5442
5886
|
// bundled bin/cli.js → repo root
|
|
5443
|
-
|
|
5887
|
+
join14(here, "../../../../skill/SKILL.md")
|
|
5444
5888
|
// dev src/lib → repo root
|
|
5445
5889
|
];
|
|
5446
|
-
return candidates.find((c) =>
|
|
5890
|
+
return candidates.find((c) => existsSync19(c)) ?? candidates[0];
|
|
5447
5891
|
}
|
|
5448
5892
|
function versionMarker(version) {
|
|
5449
5893
|
return `<!-- tmux-ide-skill-version: ${version} -->`;
|
|
@@ -5457,10 +5901,10 @@ function rewriteVersionMarker(content, version) {
|
|
|
5457
5901
|
return content.replace(VERSION_MARKER_RE, versionMarker(version));
|
|
5458
5902
|
}
|
|
5459
5903
|
function installedSkillVersion(dir = skillTargetDir()) {
|
|
5460
|
-
const file =
|
|
5461
|
-
if (!
|
|
5904
|
+
const file = join14(dir, "SKILL.md");
|
|
5905
|
+
if (!existsSync19(file)) return null;
|
|
5462
5906
|
try {
|
|
5463
|
-
return parseSkillVersion(
|
|
5907
|
+
return parseSkillVersion(readFileSync13(file, "utf-8"));
|
|
5464
5908
|
} catch {
|
|
5465
5909
|
return null;
|
|
5466
5910
|
}
|
|
@@ -5469,15 +5913,15 @@ function syncSkill({
|
|
|
5469
5913
|
source = defaultSkillSource(),
|
|
5470
5914
|
version = getCurrentVersion()
|
|
5471
5915
|
} = {}) {
|
|
5472
|
-
const rendered = rewriteVersionMarker(
|
|
5916
|
+
const rendered = rewriteVersionMarker(readFileSync13(source, "utf-8"), version);
|
|
5473
5917
|
const dir = skillTargetDir();
|
|
5474
|
-
const target =
|
|
5475
|
-
const existing =
|
|
5918
|
+
const target = join14(dir, "SKILL.md");
|
|
5919
|
+
const existing = existsSync19(target) ? readFileSync13(target, "utf-8") : null;
|
|
5476
5920
|
if (existing === rendered) {
|
|
5477
5921
|
return { action: "unchanged", path: target, to: version };
|
|
5478
5922
|
}
|
|
5479
|
-
|
|
5480
|
-
|
|
5923
|
+
mkdirSync12(dir, { recursive: true });
|
|
5924
|
+
writeFileSync12(target, rendered, "utf-8");
|
|
5481
5925
|
if (existing === null) return { action: "installed", path: target, to: version };
|
|
5482
5926
|
return { action: "updated", path: target, from: parseSkillVersion(existing), to: version };
|
|
5483
5927
|
}
|
|
@@ -5678,8 +6122,8 @@ var init_PtyAdapter = __esm({
|
|
|
5678
6122
|
});
|
|
5679
6123
|
|
|
5680
6124
|
// packages/daemon/src/terminal/NodePtyAdapter.ts
|
|
5681
|
-
import { chmodSync as
|
|
5682
|
-
import { dirname as
|
|
6125
|
+
import { chmodSync as chmodSync3, existsSync as existsSync22, statSync as statSync2 } from "node:fs";
|
|
6126
|
+
import { dirname as dirname16, join as join15 } from "node:path";
|
|
5683
6127
|
import { createRequire } from "node:module";
|
|
5684
6128
|
import * as pty from "node-pty";
|
|
5685
6129
|
function candidateSpawnHelperPaths() {
|
|
@@ -5690,11 +6134,11 @@ function candidateSpawnHelperPaths() {
|
|
|
5690
6134
|
} catch {
|
|
5691
6135
|
return [];
|
|
5692
6136
|
}
|
|
5693
|
-
const pkgDir =
|
|
6137
|
+
const pkgDir = dirname16(pkgJsonPath);
|
|
5694
6138
|
return [
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
6139
|
+
join15(pkgDir, "build", "Release", "spawn-helper"),
|
|
6140
|
+
join15(pkgDir, "build", "Debug", "spawn-helper"),
|
|
6141
|
+
join15(pkgDir, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper")
|
|
5698
6142
|
];
|
|
5699
6143
|
}
|
|
5700
6144
|
function ensureNodePtySpawnHelperExecutable(options = {}) {
|
|
@@ -5702,9 +6146,9 @@ function ensureNodePtySpawnHelperExecutable(options = {}) {
|
|
|
5702
6146
|
if (!options.force && !options.explicitPath && helperEnsured) return;
|
|
5703
6147
|
const candidates = options.explicitPath ? [options.explicitPath] : candidateSpawnHelperPaths();
|
|
5704
6148
|
for (const candidate of candidates) {
|
|
5705
|
-
if (!
|
|
6149
|
+
if (!existsSync22(candidate)) continue;
|
|
5706
6150
|
try {
|
|
5707
|
-
|
|
6151
|
+
chmodSync3(candidate, 493);
|
|
5708
6152
|
} catch {
|
|
5709
6153
|
}
|
|
5710
6154
|
}
|
|
@@ -6691,9 +7135,9 @@ var init_pane_comms = __esm({
|
|
|
6691
7135
|
|
|
6692
7136
|
// packages/daemon/src/lib/workspace-registry.ts
|
|
6693
7137
|
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
6694
|
-
import { existsSync as
|
|
6695
|
-
import { homedir as
|
|
6696
|
-
import { dirname as
|
|
7138
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync13, readFileSync as readFileSync14, renameSync as renameSync8, writeFileSync as writeFileSync13 } from "node:fs";
|
|
7139
|
+
import { homedir as homedir14 } from "node:os";
|
|
7140
|
+
import { dirname as dirname17, join as join16 } from "node:path";
|
|
6697
7141
|
import { z as z12 } from "zod";
|
|
6698
7142
|
function getDefaultWorkspaceRegistry() {
|
|
6699
7143
|
if (!_default) _default = new WorkspaceRegistry();
|
|
@@ -6742,7 +7186,7 @@ var init_workspace_registry = __esm({
|
|
|
6742
7186
|
workspaces = [];
|
|
6743
7187
|
loaded = false;
|
|
6744
7188
|
constructor(options = {}) {
|
|
6745
|
-
this.dir = options.dir ?? process.env[REGISTRY_DIR_ENV3] ??
|
|
7189
|
+
this.dir = options.dir ?? process.env[REGISTRY_DIR_ENV3] ?? join16(homedir14(), ".tmux-ide");
|
|
6746
7190
|
this.listSessions = options.listSessions ?? defaultListSessions;
|
|
6747
7191
|
this.emitter.setMaxListeners(0);
|
|
6748
7192
|
}
|
|
@@ -6809,14 +7253,14 @@ var init_workspace_registry = __esm({
|
|
|
6809
7253
|
}
|
|
6810
7254
|
// ----------------- io -----------------
|
|
6811
7255
|
filePath() {
|
|
6812
|
-
return
|
|
7256
|
+
return join16(this.dir, "workspaces.json");
|
|
6813
7257
|
}
|
|
6814
7258
|
readDisk() {
|
|
6815
7259
|
const path2 = this.filePath();
|
|
6816
|
-
if (!
|
|
7260
|
+
if (!existsSync23(path2)) return [];
|
|
6817
7261
|
let parsed;
|
|
6818
7262
|
try {
|
|
6819
|
-
parsed = JSON.parse(
|
|
7263
|
+
parsed = JSON.parse(readFileSync14(path2, "utf-8"));
|
|
6820
7264
|
} catch {
|
|
6821
7265
|
return [];
|
|
6822
7266
|
}
|
|
@@ -6826,11 +7270,11 @@ var init_workspace_registry = __esm({
|
|
|
6826
7270
|
}
|
|
6827
7271
|
writeDisk() {
|
|
6828
7272
|
const path2 = this.filePath();
|
|
6829
|
-
|
|
7273
|
+
mkdirSync13(dirname17(path2), { recursive: true });
|
|
6830
7274
|
const file = { version: 1, workspaces: this.workspaces };
|
|
6831
7275
|
const tmp = `${path2}.tmp`;
|
|
6832
|
-
|
|
6833
|
-
|
|
7276
|
+
writeFileSync13(tmp, JSON.stringify(file, null, 2) + "\n");
|
|
7277
|
+
renameSync8(tmp, path2);
|
|
6834
7278
|
}
|
|
6835
7279
|
/** @internal Test-only: assert the registry is loaded. */
|
|
6836
7280
|
_isLoaded() {
|
|
@@ -7111,14 +7555,14 @@ var init_auth_token = __esm({
|
|
|
7111
7555
|
});
|
|
7112
7556
|
|
|
7113
7557
|
// packages/daemon/src/lib/app-settings.ts
|
|
7114
|
-
import { existsSync as
|
|
7115
|
-
import { dirname as
|
|
7116
|
-
import { homedir as
|
|
7558
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync15, renameSync as renameSync9, writeFileSync as writeFileSync14 } from "node:fs";
|
|
7559
|
+
import { dirname as dirname18, join as join17 } from "node:path";
|
|
7560
|
+
import { homedir as homedir15 } from "node:os";
|
|
7117
7561
|
function settingsDir() {
|
|
7118
|
-
return process.env.TMUX_IDE_SETTINGS_DIR ??
|
|
7562
|
+
return process.env.TMUX_IDE_SETTINGS_DIR ?? join17(homedir15(), ".tmux-ide");
|
|
7119
7563
|
}
|
|
7120
7564
|
function appSettingsPath() {
|
|
7121
|
-
return
|
|
7565
|
+
return join17(settingsDir(), "app-settings.json");
|
|
7122
7566
|
}
|
|
7123
7567
|
function normalizeSettings(value) {
|
|
7124
7568
|
if (!value || typeof value !== "object") return structuredClone(DEFAULT_SETTINGS);
|
|
@@ -7131,20 +7575,20 @@ function normalizeSettings(value) {
|
|
|
7131
7575
|
}
|
|
7132
7576
|
function readAppSettings() {
|
|
7133
7577
|
const path2 = appSettingsPath();
|
|
7134
|
-
if (!
|
|
7578
|
+
if (!existsSync24(path2)) return structuredClone(DEFAULT_SETTINGS);
|
|
7135
7579
|
try {
|
|
7136
|
-
return normalizeSettings(JSON.parse(
|
|
7580
|
+
return normalizeSettings(JSON.parse(readFileSync15(path2, "utf-8")));
|
|
7137
7581
|
} catch {
|
|
7138
7582
|
return structuredClone(DEFAULT_SETTINGS);
|
|
7139
7583
|
}
|
|
7140
7584
|
}
|
|
7141
7585
|
function writeAppSettings(next) {
|
|
7142
7586
|
const path2 = appSettingsPath();
|
|
7143
|
-
|
|
7587
|
+
mkdirSync14(dirname18(path2), { recursive: true });
|
|
7144
7588
|
const tmp = `${path2}.${process.pid}.${Date.now()}.tmp`;
|
|
7145
|
-
|
|
7589
|
+
writeFileSync14(tmp, `${JSON.stringify(normalizeSettings(next), null, 2)}
|
|
7146
7590
|
`, "utf-8");
|
|
7147
|
-
|
|
7591
|
+
renameSync9(tmp, path2);
|
|
7148
7592
|
}
|
|
7149
7593
|
var DEFAULT_SETTINGS;
|
|
7150
7594
|
var init_app_settings = __esm({
|
|
@@ -7332,16 +7776,16 @@ var init_active_projects = __esm({
|
|
|
7332
7776
|
|
|
7333
7777
|
// packages/daemon/src/send.ts
|
|
7334
7778
|
import { randomUUID } from "node:crypto";
|
|
7335
|
-
import { resolve as resolve17, join as
|
|
7336
|
-
import { existsSync as
|
|
7779
|
+
import { resolve as resolve17, join as join18 } from "node:path";
|
|
7780
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync15, writeFileSync as writeFileSync15 } from "node:fs";
|
|
7337
7781
|
function writeDispatchFile(dir, paneId, message) {
|
|
7338
7782
|
if (message.length <= LONG_MESSAGE_THRESHOLD) return null;
|
|
7339
|
-
const dispatchDir =
|
|
7340
|
-
if (!
|
|
7783
|
+
const dispatchDir = join18(dir, ".tasks", "dispatch");
|
|
7784
|
+
if (!existsSync25(dispatchDir)) mkdirSync15(dispatchDir, { recursive: true });
|
|
7341
7785
|
const paneSlug = paneId.replace("%", "");
|
|
7342
7786
|
const filename = `send-${paneSlug}-${Date.now()}-${randomUUID().slice(0, 8)}.md`;
|
|
7343
|
-
const filePath =
|
|
7344
|
-
|
|
7787
|
+
const filePath = join18(dispatchDir, filename);
|
|
7788
|
+
writeFileSync15(filePath, message);
|
|
7345
7789
|
return { filePath, triggerCmd: `Read and execute: .tasks/dispatch/${filename}` };
|
|
7346
7790
|
}
|
|
7347
7791
|
function resolvePane(panes, target) {
|
|
@@ -7585,19 +8029,19 @@ var init_schemas = __esm({
|
|
|
7585
8029
|
});
|
|
7586
8030
|
|
|
7587
8031
|
// packages/daemon/src/lib/terminals-store.ts
|
|
7588
|
-
import { existsSync as
|
|
7589
|
-
import { dirname as
|
|
8032
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync16, readFileSync as readFileSync16, renameSync as renameSync10, writeFileSync as writeFileSync16 } from "node:fs";
|
|
8033
|
+
import { dirname as dirname19, join as join19 } from "node:path";
|
|
7590
8034
|
function path(dir) {
|
|
7591
|
-
return
|
|
8035
|
+
return join19(dir, TERMINALS_FILE);
|
|
7592
8036
|
}
|
|
7593
8037
|
function ensureDir(dir) {
|
|
7594
|
-
|
|
8038
|
+
mkdirSync16(dirname19(path(dir)), { recursive: true });
|
|
7595
8039
|
}
|
|
7596
8040
|
function loadTerminals(dir) {
|
|
7597
8041
|
const file = path(dir);
|
|
7598
|
-
if (!
|
|
8042
|
+
if (!existsSync26(file)) return [];
|
|
7599
8043
|
try {
|
|
7600
|
-
const body =
|
|
8044
|
+
const body = readFileSync16(file, "utf-8");
|
|
7601
8045
|
const parsed = JSON.parse(body);
|
|
7602
8046
|
if (!parsed.terminals || !Array.isArray(parsed.terminals)) return [];
|
|
7603
8047
|
return parsed.terminals.filter((t) => isTerminal(t)).map((t) => ({ ...t }));
|
|
@@ -7614,8 +8058,8 @@ function writeAtomic(dir, terminals) {
|
|
|
7614
8058
|
ensureDir(dir);
|
|
7615
8059
|
const file = path(dir);
|
|
7616
8060
|
const tmp = `${file}.tmp`;
|
|
7617
|
-
|
|
7618
|
-
|
|
8061
|
+
writeFileSync16(tmp, JSON.stringify({ terminals }, null, 2) + "\n");
|
|
8062
|
+
renameSync10(tmp, file);
|
|
7619
8063
|
}
|
|
7620
8064
|
function upsertTerminal(dir, input) {
|
|
7621
8065
|
if (!SAFE_ID.test(input.id)) {
|
|
@@ -7676,9 +8120,9 @@ __export(auth_service_exports, {
|
|
|
7676
8120
|
AuthService: () => AuthService
|
|
7677
8121
|
});
|
|
7678
8122
|
import * as crypto2 from "node:crypto";
|
|
7679
|
-
import { readFileSync as
|
|
7680
|
-
import { join as
|
|
7681
|
-
import { homedir as
|
|
8123
|
+
import { readFileSync as readFileSync17, existsSync as existsSync27 } from "node:fs";
|
|
8124
|
+
import { join as join20 } from "node:path";
|
|
8125
|
+
import { homedir as homedir16 } from "node:os";
|
|
7682
8126
|
function base64url(buf) {
|
|
7683
8127
|
const b = typeof buf === "string" ? Buffer.from(buf) : buf;
|
|
7684
8128
|
return b.toString("base64url");
|
|
@@ -7820,10 +8264,10 @@ var init_auth_service = __esm({
|
|
|
7820
8264
|
}
|
|
7821
8265
|
checkSSHKeyAuthorization(userId, publicKey) {
|
|
7822
8266
|
try {
|
|
7823
|
-
const home = userId === process.env.USER ?
|
|
7824
|
-
const authKeysPath =
|
|
7825
|
-
if (!
|
|
7826
|
-
const authorizedKeys =
|
|
8267
|
+
const home = userId === process.env.USER ? homedir16() : `/home/${userId}`;
|
|
8268
|
+
const authKeysPath = join20(home, ".ssh", "authorized_keys");
|
|
8269
|
+
if (!existsSync27(authKeysPath)) return false;
|
|
8270
|
+
const authorizedKeys = readFileSync17(authKeysPath, "utf-8");
|
|
7827
8271
|
const parts = publicKey.trim().split(" ");
|
|
7828
8272
|
const keyData = parts.length > 1 ? parts[1] : parts[0];
|
|
7829
8273
|
return authorizedKeys.includes(keyData);
|
|
@@ -8221,11 +8665,11 @@ var init_project_context = __esm({
|
|
|
8221
8665
|
});
|
|
8222
8666
|
|
|
8223
8667
|
// packages/daemon/src/command-center/actions/handlers/config-actions.ts
|
|
8224
|
-
import { existsSync as
|
|
8225
|
-
import { join as
|
|
8668
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
8669
|
+
import { join as join21 } from "node:path";
|
|
8226
8670
|
function mutateConfigAction(input, deps2, fn) {
|
|
8227
8671
|
const context = resolveProjectContext(input, deps2);
|
|
8228
|
-
if (!
|
|
8672
|
+
if (!existsSync28(join21(context.dir, "ide.yml"))) {
|
|
8229
8673
|
throw new ActionError({
|
|
8230
8674
|
code: "ide_yml_missing",
|
|
8231
8675
|
message: "ide.yml was not found",
|
|
@@ -8648,8 +9092,8 @@ var init_inspect = __esm({
|
|
|
8648
9092
|
|
|
8649
9093
|
// packages/daemon/src/lib/filesystem-browser.ts
|
|
8650
9094
|
import { realpathSync, readdirSync as readdirSync3, statSync as statSync4 } from "node:fs";
|
|
8651
|
-
import { homedir as
|
|
8652
|
-
import { isAbsolute as isAbsolute3, join as
|
|
9095
|
+
import { homedir as homedir17 } from "node:os";
|
|
9096
|
+
import { isAbsolute as isAbsolute3, join as join22, resolve as resolve19, sep } from "node:path";
|
|
8653
9097
|
function isUnderRoot(canonical, root) {
|
|
8654
9098
|
if (canonical === root) return true;
|
|
8655
9099
|
const prefix = root.endsWith(sep) ? root : root + sep;
|
|
@@ -8678,7 +9122,7 @@ var init_filesystem_browser = __esm({
|
|
|
8678
9122
|
});
|
|
8679
9123
|
|
|
8680
9124
|
// packages/daemon/src/lib/project-inspect.ts
|
|
8681
|
-
import { existsSync as
|
|
9125
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
8682
9126
|
import { isAbsolute as isAbsolute4, resolve as resolve20 } from "node:path";
|
|
8683
9127
|
function narrowPackageManager(raw) {
|
|
8684
9128
|
if (!raw) return null;
|
|
@@ -8689,7 +9133,7 @@ function inferTestCommand(packageManager) {
|
|
|
8689
9133
|
return packageManager === "npm" ? "npm test" : `${packageManager} test`;
|
|
8690
9134
|
}
|
|
8691
9135
|
async function inspectProject(dir, io = {}) {
|
|
8692
|
-
const exists = io.exists ??
|
|
9136
|
+
const exists = io.exists ?? existsSync29;
|
|
8693
9137
|
const absoluteDir = isAbsolute4(dir) ? dir : resolve20(dir);
|
|
8694
9138
|
if (!exists(absoluteDir)) {
|
|
8695
9139
|
throw new InspectDirNotFoundError(absoluteDir);
|
|
@@ -8730,8 +9174,8 @@ var init_project_inspect = __esm({
|
|
|
8730
9174
|
|
|
8731
9175
|
// packages/daemon/src/lib/project-onboard.ts
|
|
8732
9176
|
import yaml2 from "js-yaml";
|
|
8733
|
-
import { existsSync as
|
|
8734
|
-
import { join as
|
|
9177
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
9178
|
+
import { join as join23 } from "node:path";
|
|
8735
9179
|
function composeIdeYmlConfig(input) {
|
|
8736
9180
|
if (!Number.isInteger(input.agents) || input.agents < 1 || input.agents > 3) {
|
|
8737
9181
|
throw new OnboardInvalidInputError(
|
|
@@ -8789,8 +9233,8 @@ function composeIdeYmlConfig(input) {
|
|
|
8789
9233
|
}
|
|
8790
9234
|
return config2;
|
|
8791
9235
|
}
|
|
8792
|
-
function assertNoExistingIdeYml(dir, exists =
|
|
8793
|
-
const path2 =
|
|
9236
|
+
function assertNoExistingIdeYml(dir, exists = existsSync30) {
|
|
9237
|
+
const path2 = join23(dir, "ide.yml");
|
|
8794
9238
|
if (exists(path2)) {
|
|
8795
9239
|
throw new OnboardConflictError(path2);
|
|
8796
9240
|
}
|
|
@@ -8825,23 +9269,23 @@ __export(server_exports, {
|
|
|
8825
9269
|
});
|
|
8826
9270
|
import { execFile as execFile2 } from "node:child_process";
|
|
8827
9271
|
import { promisify } from "node:util";
|
|
8828
|
-
import { existsSync as
|
|
8829
|
-
import { join as
|
|
9272
|
+
import { existsSync as existsSync31, readFileSync as readFileSync18, readdirSync as readdirSync4 } from "node:fs";
|
|
9273
|
+
import { join as join24, dirname as dirname20, basename as basename8 } from "node:path";
|
|
8830
9274
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
8831
9275
|
import { Hono } from "hono";
|
|
8832
9276
|
import { streamSSE } from "hono/streaming";
|
|
8833
9277
|
import { cors } from "hono/cors";
|
|
8834
9278
|
import { zValidator } from "@hono/zod-validator";
|
|
8835
9279
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
8836
|
-
import { homedir as
|
|
9280
|
+
import { homedir as homedir18 } from "node:os";
|
|
8837
9281
|
import { isAbsolute as isAbsolute5, resolve as pathResolve } from "node:path";
|
|
8838
9282
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
8839
9283
|
import { WebSocketServer } from "ws";
|
|
8840
9284
|
function resolvePackageVersion() {
|
|
8841
|
-
const candidates = [
|
|
9285
|
+
const candidates = [join24(__dirname5, "../../package.json"), join24(__dirname5, "../package.json")];
|
|
8842
9286
|
for (const candidate of candidates) {
|
|
8843
9287
|
try {
|
|
8844
|
-
const parsed = JSON.parse(
|
|
9288
|
+
const parsed = JSON.parse(readFileSync18(candidate, "utf-8"));
|
|
8845
9289
|
if (typeof parsed.version === "string") return parsed.version;
|
|
8846
9290
|
} catch {
|
|
8847
9291
|
}
|
|
@@ -8905,7 +9349,7 @@ function sandboxResolveDir(rawDir) {
|
|
|
8905
9349
|
if (trimmed.includes("\0")) {
|
|
8906
9350
|
return { error: "invalid-path", message: "Path contains a null byte", status: 400 };
|
|
8907
9351
|
}
|
|
8908
|
-
const home = process.env.TMUX_IDE_HOME_OVERRIDE && process.env.TMUX_IDE_HOME_OVERRIDE.trim().length > 0 ? process.env.TMUX_IDE_HOME_OVERRIDE :
|
|
9352
|
+
const home = process.env.TMUX_IDE_HOME_OVERRIDE && process.env.TMUX_IDE_HOME_OVERRIDE.trim().length > 0 ? process.env.TMUX_IDE_HOME_OVERRIDE : homedir18();
|
|
8909
9353
|
let candidate = trimmed;
|
|
8910
9354
|
if (candidate === "~") {
|
|
8911
9355
|
candidate = home;
|
|
@@ -9575,7 +10019,7 @@ function createApp(options = {}) {
|
|
|
9575
10019
|
if (!parsed.success) {
|
|
9576
10020
|
return c.json({ error: "Invalid request", details: parsed.error.issues }, 400);
|
|
9577
10021
|
}
|
|
9578
|
-
if (!
|
|
10022
|
+
if (!existsSync31(parsed.data.dir)) {
|
|
9579
10023
|
return c.json({ error: `Directory "${parsed.data.dir}" does not exist` }, 400);
|
|
9580
10024
|
}
|
|
9581
10025
|
const jobId = randomUUID3();
|
|
@@ -9681,9 +10125,9 @@ function createApp(options = {}) {
|
|
|
9681
10125
|
}
|
|
9682
10126
|
function listAvailableTemplates() {
|
|
9683
10127
|
const __filename = fileURLToPath8(import.meta.url);
|
|
9684
|
-
const __dir =
|
|
9685
|
-
const templatesDir =
|
|
9686
|
-
if (!
|
|
10128
|
+
const __dir = dirname20(__filename);
|
|
10129
|
+
const templatesDir = join24(__dir, "..", "..", "..", "..", "templates");
|
|
10130
|
+
if (!existsSync31(templatesDir)) return [];
|
|
9687
10131
|
const labels = {
|
|
9688
10132
|
default: { label: "Default", description: "Single Claude pane + dev/shell row" },
|
|
9689
10133
|
nextjs: {
|
|
@@ -9772,7 +10216,7 @@ var init_server = __esm({
|
|
|
9772
10216
|
init_filesystem_browser();
|
|
9773
10217
|
init_project_inspect();
|
|
9774
10218
|
init_project_onboard();
|
|
9775
|
-
__dirname5 =
|
|
10219
|
+
__dirname5 = dirname20(fileURLToPath8(import.meta.url));
|
|
9776
10220
|
pkgVersion = resolvePackageVersion();
|
|
9777
10221
|
projectStreamConnections = 0;
|
|
9778
10222
|
sseMetrics = {
|
|
@@ -10975,7 +11419,7 @@ var require_package = __commonJS({
|
|
|
10975
11419
|
"package.json"(exports, module) {
|
|
10976
11420
|
module.exports = {
|
|
10977
11421
|
name: "tmux-ide",
|
|
10978
|
-
version: "2.
|
|
11422
|
+
version: "2.7.0",
|
|
10979
11423
|
description: "Turn any project into a tmux-powered terminal IDE with a simple ide.yml",
|
|
10980
11424
|
type: "module",
|
|
10981
11425
|
bin: {
|
|
@@ -10987,7 +11431,13 @@ var require_package = __commonJS({
|
|
|
10987
11431
|
"skill",
|
|
10988
11432
|
"templates",
|
|
10989
11433
|
"packages/daemon/dist",
|
|
10990
|
-
"!packages/daemon/dist/tui"
|
|
11434
|
+
"!packages/daemon/dist/tui",
|
|
11435
|
+
"packages/daemon/src",
|
|
11436
|
+
"bunfig.toml",
|
|
11437
|
+
"packages/contracts/src",
|
|
11438
|
+
"packages/tmux-bridge/src",
|
|
11439
|
+
"packages/tmux-bridge/package.json",
|
|
11440
|
+
"packages/contracts/package.json"
|
|
10991
11441
|
],
|
|
10992
11442
|
scripts: {
|
|
10993
11443
|
build: "pnpm build:cli",
|
|
@@ -11034,16 +11484,15 @@ var require_package = __commonJS({
|
|
|
11034
11484
|
dependencies: {
|
|
11035
11485
|
"@hono/node-server": "^1.19.11",
|
|
11036
11486
|
"@hono/zod-validator": "^0.7.6",
|
|
11037
|
-
"@opentui/core": "^0.
|
|
11038
|
-
"@opentui/
|
|
11039
|
-
"@opentui/solid": "^0.1.88",
|
|
11487
|
+
"@opentui/core": "^0.4.3",
|
|
11488
|
+
"@opentui/solid": "^0.4.3",
|
|
11040
11489
|
"@parcel/watcher": "^2.5.6",
|
|
11041
11490
|
"@types/ws": "^8.18.1",
|
|
11042
11491
|
hono: "^4.12.8",
|
|
11043
11492
|
ignore: "^7.0.5",
|
|
11044
11493
|
"js-yaml": "^4.1.1",
|
|
11045
11494
|
"node-pty": "1.2.0-beta.12",
|
|
11046
|
-
"solid-js": "
|
|
11495
|
+
"solid-js": "1.9.12",
|
|
11047
11496
|
ws: "^8.20.0",
|
|
11048
11497
|
zod: "^4.3.6"
|
|
11049
11498
|
},
|
|
@@ -11052,7 +11501,10 @@ var require_package = __commonJS({
|
|
|
11052
11501
|
"@parcel/watcher",
|
|
11053
11502
|
"esbuild",
|
|
11054
11503
|
"node-pty"
|
|
11055
|
-
]
|
|
11504
|
+
],
|
|
11505
|
+
overrides: {
|
|
11506
|
+
zod: "^4.3.6"
|
|
11507
|
+
}
|
|
11056
11508
|
},
|
|
11057
11509
|
devDependencies: {
|
|
11058
11510
|
"@eslint/js": "^10.0.1",
|
|
@@ -11068,6 +11520,9 @@ var require_package = __commonJS({
|
|
|
11068
11520
|
turbo: "^2.3.3",
|
|
11069
11521
|
typescript: "^5.9.3",
|
|
11070
11522
|
vitest: "^4.1.0"
|
|
11523
|
+
},
|
|
11524
|
+
optionalDependencies: {
|
|
11525
|
+
"@opentui/core-darwin-arm64": "^0.4.3"
|
|
11071
11526
|
}
|
|
11072
11527
|
};
|
|
11073
11528
|
}
|
|
@@ -11098,7 +11553,10 @@ function toFleetJson(projects) {
|
|
|
11098
11553
|
active: w.active,
|
|
11099
11554
|
panes: w.panes,
|
|
11100
11555
|
status: w.status
|
|
11101
|
-
}))
|
|
11556
|
+
})),
|
|
11557
|
+
// A pre-agents TeamSession (older constructor/test) yields `[]` — the
|
|
11558
|
+
// contract always exposes the array.
|
|
11559
|
+
agents: s.agents ?? []
|
|
11102
11560
|
}))
|
|
11103
11561
|
}))
|
|
11104
11562
|
};
|
|
@@ -11180,6 +11638,7 @@ function buildReport(target) {
|
|
|
11180
11638
|
hint: info.hintRaw
|
|
11181
11639
|
});
|
|
11182
11640
|
const manifest = resolved2.manifest;
|
|
11641
|
+
const subtree = manifest ? [] : describeSubtree(table, info.pid);
|
|
11183
11642
|
const snapshot = { ...readPaneSnapshot(info.id), title: info.title };
|
|
11184
11643
|
const explained = manifest ? explain(snapshot, manifest) : {
|
|
11185
11644
|
state: null,
|
|
@@ -11201,7 +11660,9 @@ function buildReport(target) {
|
|
|
11201
11660
|
resolution: {
|
|
11202
11661
|
manifestId: manifest?.id ?? null,
|
|
11203
11662
|
matchedCommand: resolved2.matchedCommand,
|
|
11204
|
-
source: resolved2.source
|
|
11663
|
+
source: resolved2.source,
|
|
11664
|
+
confidence: manifest ? manifest.confidence ?? "conservative" : null,
|
|
11665
|
+
subtree
|
|
11205
11666
|
},
|
|
11206
11667
|
states: explained.checked,
|
|
11207
11668
|
winner: explained.state,
|
|
@@ -11237,10 +11698,16 @@ function renderReport(r, opts = {}) {
|
|
|
11237
11698
|
} else {
|
|
11238
11699
|
out.push(` ${label("hint")} ${dim4("(unset)")}`);
|
|
11239
11700
|
}
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
)
|
|
11701
|
+
if (r.resolution.manifestId) {
|
|
11702
|
+
const conf = r.resolution.confidence === "tuned" ? c("\x1B[32m", "tuned") : dim4(r.resolution.confidence ?? "conservative");
|
|
11703
|
+
out.push(
|
|
11704
|
+
` ${label("manifest")} ${r.resolution.manifestId} ${dim4(`via ${r.resolution.source}` + (r.resolution.matchedCommand ? ` "${r.resolution.matchedCommand}"` : ""))} [${conf}]`
|
|
11705
|
+
);
|
|
11706
|
+
} else {
|
|
11707
|
+
const saw = r.resolution.subtree.length > 0 ? r.resolution.subtree.join(", ") : r.pane.cmd || "(nothing)";
|
|
11708
|
+
out.push(` ${label("manifest")} ${dim4("none matched")} \u2014 ${dim4(`process-tree saw: ${saw}`)}`);
|
|
11709
|
+
out.push(` ${dim4("set `tmux set-option -p @agent_hint <agent>` to force one")}`);
|
|
11710
|
+
}
|
|
11244
11711
|
out.push("");
|
|
11245
11712
|
out.push(bold4(" state rules"));
|
|
11246
11713
|
if (r.states.length === 0) {
|
|
@@ -11314,7 +11781,7 @@ __export(worktree_exports, {
|
|
|
11314
11781
|
worktreeSessionName: () => worktreeSessionName
|
|
11315
11782
|
});
|
|
11316
11783
|
import { execFileSync as execFileSync13 } from "node:child_process";
|
|
11317
|
-
import { basename as basename9, dirname as
|
|
11784
|
+
import { basename as basename9, dirname as dirname21, isAbsolute as isAbsolute6, join as join25, resolve as resolve22 } from "node:path";
|
|
11318
11785
|
function sanitizeForTmux(part) {
|
|
11319
11786
|
return part.replace(/[.:/\s]+/g, "-");
|
|
11320
11787
|
}
|
|
@@ -11323,11 +11790,11 @@ function worktreeSessionName(project, branch) {
|
|
|
11323
11790
|
}
|
|
11324
11791
|
function defaultWorktreeBaseDir(repoDir) {
|
|
11325
11792
|
const abs = resolve22(repoDir);
|
|
11326
|
-
return
|
|
11793
|
+
return join25(dirname21(abs), `${basename9(abs)}-worktrees`);
|
|
11327
11794
|
}
|
|
11328
11795
|
function worktreePath(repoDir, branch, configuredDir) {
|
|
11329
11796
|
const base = configuredDir && configuredDir.length > 0 ? isAbsolute6(configuredDir) ? configuredDir : resolve22(repoDir, configuredDir) : defaultWorktreeBaseDir(repoDir);
|
|
11330
|
-
return
|
|
11797
|
+
return join25(base, branch);
|
|
11331
11798
|
}
|
|
11332
11799
|
function parseWorktreeList(porcelain) {
|
|
11333
11800
|
const entries = [];
|
|
@@ -11471,8 +11938,8 @@ __export(update_exports, {
|
|
|
11471
11938
|
runUpdate: () => runUpdate
|
|
11472
11939
|
});
|
|
11473
11940
|
import { execSync as execSync4 } from "node:child_process";
|
|
11474
|
-
import { existsSync as
|
|
11475
|
-
import { dirname as
|
|
11941
|
+
import { existsSync as existsSync32 } from "node:fs";
|
|
11942
|
+
import { dirname as dirname22, join as join26 } from "node:path";
|
|
11476
11943
|
function detectPackageManager(cliPath) {
|
|
11477
11944
|
const p = cliPath.toLowerCase();
|
|
11478
11945
|
if (/(^|\/)\.?bun(\/|$)/.test(p)) return "bun";
|
|
@@ -11518,8 +11985,8 @@ function renderPlan(plan, { current, latest, dryRun }) {
|
|
|
11518
11985
|
function findGitCheckoutRoot(startDir) {
|
|
11519
11986
|
let dir = startDir;
|
|
11520
11987
|
for (; ; ) {
|
|
11521
|
-
if (
|
|
11522
|
-
const parent =
|
|
11988
|
+
if (existsSync32(join26(dir, ".git"))) return dir;
|
|
11989
|
+
const parent = dirname22(dir);
|
|
11523
11990
|
if (parent === dir) return null;
|
|
11524
11991
|
dir = parent;
|
|
11525
11992
|
}
|
|
@@ -11651,65 +12118,68 @@ var init_server2 = __esm({
|
|
|
11651
12118
|
// bin/cli.ts
|
|
11652
12119
|
init_launch();
|
|
11653
12120
|
import { parseArgs } from "node:util";
|
|
11654
|
-
import { resolve as resolve23, dirname as
|
|
12121
|
+
import { resolve as resolve23, dirname as dirname23, join as join27 } from "node:path";
|
|
11655
12122
|
import { execFileSync as execFileSync14 } from "node:child_process";
|
|
11656
|
-
import { existsSync as
|
|
12123
|
+
import { existsSync as existsSync33 } from "node:fs";
|
|
11657
12124
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
11658
12125
|
|
|
11659
12126
|
// packages/daemon/src/tui/team/entry.ts
|
|
11660
|
-
function
|
|
11661
|
-
|
|
12127
|
+
function resolveEntry(opts) {
|
|
12128
|
+
if (opts.teamFlag) return "cockpit";
|
|
12129
|
+
if (opts.hasIdeYml) return "project";
|
|
12130
|
+
return opts.frontDoor ? "app" : "cockpit";
|
|
11662
12131
|
}
|
|
11663
12132
|
|
|
11664
12133
|
// bin/cli.ts
|
|
12134
|
+
init_app_config();
|
|
11665
12135
|
init_compiled();
|
|
11666
12136
|
|
|
11667
12137
|
// packages/daemon/src/init.ts
|
|
11668
12138
|
init_detect();
|
|
11669
12139
|
init_output();
|
|
11670
12140
|
import {
|
|
11671
|
-
existsSync as
|
|
11672
|
-
readFileSync as
|
|
11673
|
-
writeFileSync as
|
|
11674
|
-
renameSync as
|
|
11675
|
-
mkdirSync as
|
|
12141
|
+
existsSync as existsSync18,
|
|
12142
|
+
readFileSync as readFileSync12,
|
|
12143
|
+
writeFileSync as writeFileSync11,
|
|
12144
|
+
renameSync as renameSync7,
|
|
12145
|
+
mkdirSync as mkdirSync11,
|
|
11676
12146
|
readdirSync as readdirSync2,
|
|
11677
12147
|
copyFileSync as copyFileSync2
|
|
11678
12148
|
} from "node:fs";
|
|
11679
|
-
import { resolve as resolve11, join as
|
|
12149
|
+
import { resolve as resolve11, join as join13, basename as basename5, dirname as dirname13 } from "node:path";
|
|
11680
12150
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
11681
|
-
var __dirname4 =
|
|
12151
|
+
var __dirname4 = dirname13(fileURLToPath5(import.meta.url));
|
|
11682
12152
|
function copyTemplateSkills(targetDir) {
|
|
11683
12153
|
const created = [];
|
|
11684
12154
|
const templateSkillsDir = resolve11(__dirname4, "..", "..", "..", "templates", "skills");
|
|
11685
|
-
if (!
|
|
11686
|
-
|
|
12155
|
+
if (!existsSync18(templateSkillsDir)) return created;
|
|
12156
|
+
mkdirSync11(targetDir, { recursive: true });
|
|
11687
12157
|
for (const file of readdirSync2(templateSkillsDir)) {
|
|
11688
12158
|
if (!file.endsWith(".md")) continue;
|
|
11689
|
-
const destination =
|
|
11690
|
-
copyFileSync2(
|
|
12159
|
+
const destination = join13(targetDir, file);
|
|
12160
|
+
copyFileSync2(join13(templateSkillsDir, file), destination);
|
|
11691
12161
|
created.push(destination);
|
|
11692
12162
|
}
|
|
11693
12163
|
return created;
|
|
11694
12164
|
}
|
|
11695
12165
|
function scaffoldLibraryStubs(dir) {
|
|
11696
12166
|
const created = [];
|
|
11697
|
-
const libraryDir =
|
|
11698
|
-
if (!
|
|
11699
|
-
|
|
12167
|
+
const libraryDir = join13(dir, ".tmux-ide", "library");
|
|
12168
|
+
if (!existsSync18(libraryDir)) {
|
|
12169
|
+
mkdirSync11(libraryDir, { recursive: true });
|
|
11700
12170
|
created.push(libraryDir);
|
|
11701
12171
|
}
|
|
11702
|
-
const archPath =
|
|
11703
|
-
if (!
|
|
11704
|
-
|
|
12172
|
+
const archPath = join13(libraryDir, "architecture.md");
|
|
12173
|
+
if (!existsSync18(archPath)) {
|
|
12174
|
+
writeFileSync11(
|
|
11705
12175
|
archPath,
|
|
11706
12176
|
"# Architecture\n\n<!-- Describe your project's architecture here. This context is injected into agent dispatch prompts. -->\n"
|
|
11707
12177
|
);
|
|
11708
12178
|
created.push(archPath);
|
|
11709
12179
|
}
|
|
11710
|
-
const learningsPath =
|
|
11711
|
-
if (!
|
|
11712
|
-
|
|
12180
|
+
const learningsPath = join13(libraryDir, "learnings.md");
|
|
12181
|
+
if (!existsSync18(learningsPath)) {
|
|
12182
|
+
writeFileSync11(
|
|
11713
12183
|
learningsPath,
|
|
11714
12184
|
"# Learnings\n\n<!-- Task summaries are automatically appended here by the orchestrator. -->\n"
|
|
11715
12185
|
);
|
|
@@ -11719,13 +12189,13 @@ function scaffoldLibraryStubs(dir) {
|
|
|
11719
12189
|
}
|
|
11720
12190
|
function scaffoldValidationContract(dir) {
|
|
11721
12191
|
const created = [];
|
|
11722
|
-
const tasksDir =
|
|
11723
|
-
if (!
|
|
11724
|
-
|
|
12192
|
+
const tasksDir = join13(dir, ".tasks");
|
|
12193
|
+
if (!existsSync18(tasksDir)) {
|
|
12194
|
+
mkdirSync11(tasksDir, { recursive: true });
|
|
11725
12195
|
}
|
|
11726
|
-
const contractPath =
|
|
11727
|
-
if (!
|
|
11728
|
-
|
|
12196
|
+
const contractPath = join13(tasksDir, "validation-contract.md");
|
|
12197
|
+
if (!existsSync18(contractPath)) {
|
|
12198
|
+
writeFileSync11(
|
|
11729
12199
|
contractPath,
|
|
11730
12200
|
"# Validation Contract\n\n<!-- Define assertions that the validator agent will verify. Example: -->\n<!-- - VAL-001: All tests pass -->\n<!-- - VAL-002: No TypeScript errors -->\n<!-- - VAL-003: Lint passes with zero warnings -->\n"
|
|
11731
12201
|
);
|
|
@@ -11736,11 +12206,11 @@ function scaffoldValidationContract(dir) {
|
|
|
11736
12206
|
function scaffoldAgentsMd(dir, name) {
|
|
11737
12207
|
const created = [];
|
|
11738
12208
|
const agentsTemplatePath = resolve11(__dirname4, "..", "..", "..", "templates", "AGENTS.md");
|
|
11739
|
-
if (
|
|
11740
|
-
const agentsPath =
|
|
11741
|
-
if (!
|
|
11742
|
-
const content =
|
|
11743
|
-
|
|
12209
|
+
if (existsSync18(agentsTemplatePath)) {
|
|
12210
|
+
const agentsPath = join13(dir, "AGENTS.md");
|
|
12211
|
+
if (!existsSync18(agentsPath)) {
|
|
12212
|
+
const content = readFileSync12(agentsTemplatePath, "utf-8").replace(/{{name}}/g, name);
|
|
12213
|
+
writeFileSync11(agentsPath, content);
|
|
11744
12214
|
created.push(agentsPath);
|
|
11745
12215
|
}
|
|
11746
12216
|
}
|
|
@@ -11758,7 +12228,7 @@ function scaffoldTeamWorkspace(dir, name) {
|
|
|
11758
12228
|
}
|
|
11759
12229
|
function scaffoldMissionsWorkspace(dir, name) {
|
|
11760
12230
|
const created = [];
|
|
11761
|
-
const skillsDir =
|
|
12231
|
+
const skillsDir = join13(dir, ".tmux-ide", "skills");
|
|
11762
12232
|
created.push(...copyTemplateSkills(skillsDir));
|
|
11763
12233
|
created.push(...scaffoldTeamWorkspace(dir, name));
|
|
11764
12234
|
return created;
|
|
@@ -11769,30 +12239,30 @@ async function init({
|
|
|
11769
12239
|
} = {}) {
|
|
11770
12240
|
const dir = process.cwd();
|
|
11771
12241
|
const configPath = resolve11(dir, "ide.yml");
|
|
11772
|
-
if (
|
|
12242
|
+
if (existsSync18(configPath)) {
|
|
11773
12243
|
outputError("ide.yml already exists in this directory", "EXISTS");
|
|
11774
12244
|
}
|
|
11775
12245
|
if (template) {
|
|
11776
12246
|
const templatePath = resolve11(__dirname4, "..", "..", "..", "templates", `${template}.yml`);
|
|
11777
|
-
if (!
|
|
12247
|
+
if (!existsSync18(templatePath)) {
|
|
11778
12248
|
outputError(`Template "${template}" not found`, "NOT_FOUND");
|
|
11779
12249
|
}
|
|
11780
|
-
let content =
|
|
12250
|
+
let content = readFileSync12(templatePath, "utf-8");
|
|
11781
12251
|
const name2 = basename5(dir);
|
|
11782
12252
|
content = content.replace(/^name: .+/m, `name: ${name2}`);
|
|
11783
12253
|
const tmpPath = configPath + ".tmp";
|
|
11784
|
-
|
|
11785
|
-
|
|
12254
|
+
writeFileSync11(tmpPath, content);
|
|
12255
|
+
renameSync7(tmpPath, configPath);
|
|
11786
12256
|
let created;
|
|
11787
12257
|
if (template === "missions") {
|
|
11788
12258
|
created = scaffoldMissionsWorkspace(dir, name2);
|
|
11789
12259
|
} else if (isTeamTemplate(template)) {
|
|
11790
12260
|
created = [
|
|
11791
|
-
...copyTemplateSkills(
|
|
12261
|
+
...copyTemplateSkills(join13(dir, ".tmux-ide", "skills")),
|
|
11792
12262
|
...scaffoldTeamWorkspace(dir, name2)
|
|
11793
12263
|
];
|
|
11794
12264
|
} else {
|
|
11795
|
-
created = copyTemplateSkills(
|
|
12265
|
+
created = copyTemplateSkills(join13(dir, ".tmux-ide", "skills"));
|
|
11796
12266
|
}
|
|
11797
12267
|
if (json2) {
|
|
11798
12268
|
console.log(JSON.stringify({ created: true, template, name: name2, paths: created }));
|
|
@@ -11812,8 +12282,8 @@ async function init({
|
|
|
11812
12282
|
const config2 = suggestConfig(dir, detected);
|
|
11813
12283
|
const yaml3 = (await import("js-yaml")).default;
|
|
11814
12284
|
const tmpPath2 = configPath + ".tmp";
|
|
11815
|
-
|
|
11816
|
-
|
|
12285
|
+
writeFileSync11(tmpPath2, yaml3.dump(config2, { lineWidth: -1, noRefs: true, quotingType: '"' }));
|
|
12286
|
+
renameSync7(tmpPath2, configPath);
|
|
11817
12287
|
const desc = detected.frameworks.join(" + ");
|
|
11818
12288
|
if (json2) {
|
|
11819
12289
|
console.log(JSON.stringify({ created: true, detected: detected.frameworks, name }));
|
|
@@ -11824,11 +12294,11 @@ async function init({
|
|
|
11824
12294
|
}
|
|
11825
12295
|
} else {
|
|
11826
12296
|
const templatePath = resolve11(__dirname4, "..", "..", "..", "templates", "default.yml");
|
|
11827
|
-
let content =
|
|
12297
|
+
let content = readFileSync12(templatePath, "utf-8");
|
|
11828
12298
|
content = content.replace(/^name: .+/m, `name: ${name}`);
|
|
11829
12299
|
const tmpPath3 = configPath + ".tmp";
|
|
11830
|
-
|
|
11831
|
-
|
|
12300
|
+
writeFileSync11(tmpPath3, content);
|
|
12301
|
+
renameSync7(tmpPath3, configPath);
|
|
11832
12302
|
if (json2) {
|
|
11833
12303
|
console.log(JSON.stringify({ created: true, template: "default", name }));
|
|
11834
12304
|
} else {
|
|
@@ -11838,8 +12308,8 @@ async function init({
|
|
|
11838
12308
|
console.log("Edit it to configure your workspace, then run: tmux-ide");
|
|
11839
12309
|
}
|
|
11840
12310
|
}
|
|
11841
|
-
const skillsDir =
|
|
11842
|
-
if (!
|
|
12311
|
+
const skillsDir = join13(dir, ".tmux-ide", "skills");
|
|
12312
|
+
if (!existsSync18(skillsDir)) {
|
|
11843
12313
|
const created = copyTemplateSkills(skillsDir);
|
|
11844
12314
|
if (created.length > 0 && !json2) {
|
|
11845
12315
|
console.log("Copied built-in skill templates to .tmux-ide/skills/");
|
|
@@ -11927,8 +12397,8 @@ init_skill_sync();
|
|
|
11927
12397
|
init_agent_discovery();
|
|
11928
12398
|
init_compiled();
|
|
11929
12399
|
import { execSync as execSync3 } from "node:child_process";
|
|
11930
|
-
import { existsSync as
|
|
11931
|
-
import { resolve as resolve14, dirname as
|
|
12400
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
12401
|
+
import { resolve as resolve14, dirname as dirname15 } from "node:path";
|
|
11932
12402
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
11933
12403
|
function agentIntegrationRows(agents) {
|
|
11934
12404
|
return presentAgents(agents).map((agent) => {
|
|
@@ -11998,7 +12468,7 @@ async function doctor({
|
|
|
11998
12468
|
checks.push(
|
|
11999
12469
|
check("ide.yml exists", () => {
|
|
12000
12470
|
const path2 = resolve14(".", "ide.yml");
|
|
12001
|
-
if (!
|
|
12471
|
+
if (!existsSync20(path2)) throw new Error("not found in current directory");
|
|
12002
12472
|
return "found";
|
|
12003
12473
|
})
|
|
12004
12474
|
);
|
|
@@ -12006,11 +12476,11 @@ async function doctor({
|
|
|
12006
12476
|
check(
|
|
12007
12477
|
"TUI surfaces (cockpit / widgets)",
|
|
12008
12478
|
() => {
|
|
12009
|
-
const here =
|
|
12479
|
+
const here = dirname15(fileURLToPath7(import.meta.url));
|
|
12010
12480
|
const checkoutEntry = [
|
|
12011
12481
|
resolve14(here, "../packages/daemon/src/tui/team/index.tsx"),
|
|
12012
12482
|
resolve14(here, "tui/team/index.tsx")
|
|
12013
|
-
].find(
|
|
12483
|
+
].find(existsSync20);
|
|
12014
12484
|
const binary = findCompiledTui();
|
|
12015
12485
|
if (checkoutEntry && isBunAvailable()) return "dev checkout (bun)";
|
|
12016
12486
|
if (binary) return `compiled binary (${binary})`;
|
|
@@ -12113,11 +12583,11 @@ init_yaml_io();
|
|
|
12113
12583
|
init_src();
|
|
12114
12584
|
init_canonical_daemon();
|
|
12115
12585
|
import { resolve as resolve15 } from "node:path";
|
|
12116
|
-
import { existsSync as
|
|
12586
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
12117
12587
|
async function status(targetDir, { json: json2 } = {}) {
|
|
12118
12588
|
const dir = resolve15(targetDir ?? ".");
|
|
12119
12589
|
const { name: session } = getSessionName(dir);
|
|
12120
|
-
const configExists =
|
|
12590
|
+
const configExists = existsSync21(resolve15(dir, "ide.yml"));
|
|
12121
12591
|
const state = getSessionState(session);
|
|
12122
12592
|
const running = state.running;
|
|
12123
12593
|
let panes = [];
|
|
@@ -12569,7 +13039,9 @@ function reportPlan(plan, snapshot, { json: json2, dryRun, restored, launched, r
|
|
|
12569
13039
|
init_send();
|
|
12570
13040
|
init_errors2();
|
|
12571
13041
|
init_output();
|
|
12572
|
-
var __dirname6 =
|
|
13042
|
+
var __dirname6 = dirname23(fileURLToPath9(import.meta.url));
|
|
13043
|
+
var selfPath = fileURLToPath9(import.meta.url);
|
|
13044
|
+
var nodeCliPath = selfPath.endsWith(".js") ? selfPath : resolve23(__dirname6, "cli.js");
|
|
12573
13045
|
var { positionals, values } = parseArgs({
|
|
12574
13046
|
allowPositionals: true,
|
|
12575
13047
|
strict: false,
|
|
@@ -12647,6 +13119,7 @@ var knownCommands = /* @__PURE__ */ new Set([
|
|
|
12647
13119
|
"send",
|
|
12648
13120
|
"settings",
|
|
12649
13121
|
"team",
|
|
13122
|
+
"app",
|
|
12650
13123
|
"switcher",
|
|
12651
13124
|
"wait",
|
|
12652
13125
|
"events",
|
|
@@ -12707,6 +13180,7 @@ ${bold3("Usage:")}
|
|
|
12707
13180
|
${dim3("(--resume-agents revives claude conversations via claude --resume)")}
|
|
12708
13181
|
${cyan2("tmux-ide attach")} ${dim3("Reattach to a running session")}
|
|
12709
13182
|
${cyan2("tmux-ide team")} [--json] ${dim3("TUI over all tmux sessions (--json prints fleet state)")}
|
|
13183
|
+
${cyan2("tmux-ide app")} [session] ${dim3("Unified app: fleet home + live session mirror (bare = home)")}
|
|
12710
13184
|
${cyan2("tmux-ide switcher")} ${dim3("Compact session picker (opens in the M-p popup on adopted sessions)")}
|
|
12711
13185
|
${cyan2("tmux-ide wait agent-status")} <session> --status <s> [--timeout <ms>]
|
|
12712
13186
|
${dim3("Block until a session reaches a status (exit 0 match / 1 timeout)")}
|
|
@@ -12774,18 +13248,23 @@ function execBunWidget(surface, scriptPath, args, commandLabel, extraEnv = {}) {
|
|
|
12774
13248
|
surface,
|
|
12775
13249
|
scriptPath,
|
|
12776
13250
|
args,
|
|
12777
|
-
checkoutExists:
|
|
13251
|
+
checkoutExists: existsSync33(scriptPath),
|
|
12778
13252
|
bunAvailable: isBunAvailable(),
|
|
12779
13253
|
compiledBinary: findCompiledTui()
|
|
12780
13254
|
});
|
|
12781
13255
|
if (launch2.mode === "unavailable") {
|
|
12782
13256
|
throw new IdeError(
|
|
12783
13257
|
`\`tmux-ide ${commandLabel}\` is unavailable because ${launch2.reasons.join(" and ")}.
|
|
12784
|
-
|
|
13258
|
+
Install bun (https://bun.sh) \u2014 the TUI surfaces run on it. Sources ship with the npm package since v2.6.1.`,
|
|
12785
13259
|
{ code: "USAGE", exitCode: 1 }
|
|
12786
13260
|
);
|
|
12787
13261
|
}
|
|
12788
|
-
const env = {
|
|
13262
|
+
const env = {
|
|
13263
|
+
...process.env,
|
|
13264
|
+
TMUX_IDE_CWD: process.cwd(),
|
|
13265
|
+
TMUX_IDE_CLI: nodeCliPath,
|
|
13266
|
+
...extraEnv
|
|
13267
|
+
};
|
|
12789
13268
|
if (launch2.mode === "bun") {
|
|
12790
13269
|
execFileSync14(launch2.bin, launch2.argv, {
|
|
12791
13270
|
stdio: "inherit",
|
|
@@ -12803,9 +13282,13 @@ async function printFleetJson() {
|
|
|
12803
13282
|
console.log(JSON.stringify(toFleetJson2(listTeamProjects2(createStatusTracker2())), null, 2));
|
|
12804
13283
|
}
|
|
12805
13284
|
var teamScriptPath = resolve23(__dirname6, "../packages/daemon/src/tui/team/index.tsx");
|
|
13285
|
+
var appScriptPath = resolve23(__dirname6, "../packages/daemon/src/tui/mirror/app.tsx");
|
|
12806
13286
|
function launchTeamCockpit() {
|
|
12807
13287
|
execBunWidget("team", teamScriptPath, [], "team");
|
|
12808
13288
|
}
|
|
13289
|
+
function launchApp() {
|
|
13290
|
+
execBunWidget("app", appScriptPath, [], "app");
|
|
13291
|
+
}
|
|
12809
13292
|
try {
|
|
12810
13293
|
switch (command) {
|
|
12811
13294
|
case "start": {
|
|
@@ -12823,13 +13306,19 @@ try {
|
|
|
12823
13306
|
}
|
|
12824
13307
|
}
|
|
12825
13308
|
const targetDir = resolve23(startTargetDir || ".");
|
|
12826
|
-
const hasIdeYml =
|
|
12827
|
-
|
|
13309
|
+
const hasIdeYml = existsSync33(join27(targetDir, "ide.yml"));
|
|
13310
|
+
const entry = resolveEntry({
|
|
13311
|
+
hasIdeYml,
|
|
13312
|
+
teamFlag: values.team === true,
|
|
13313
|
+
frontDoor: loadAppConfig().app.frontDoor
|
|
13314
|
+
});
|
|
13315
|
+
if (entry !== "project") {
|
|
12828
13316
|
if (json) {
|
|
12829
13317
|
await printFleetJson();
|
|
12830
13318
|
break;
|
|
12831
13319
|
}
|
|
12832
|
-
|
|
13320
|
+
if (entry === "app") launchApp();
|
|
13321
|
+
else launchTeamCockpit();
|
|
12833
13322
|
break;
|
|
12834
13323
|
}
|
|
12835
13324
|
await launch(startTargetDir, { json });
|
|
@@ -12929,8 +13418,8 @@ try {
|
|
|
12929
13418
|
const messageStart = values.to ? 1 : 2;
|
|
12930
13419
|
let message = positionals.slice(messageStart).join(" ");
|
|
12931
13420
|
if (!message && !process.stdin.isTTY) {
|
|
12932
|
-
const { readFileSync:
|
|
12933
|
-
message =
|
|
13421
|
+
const { readFileSync: readFileSync19 } = await import("node:fs");
|
|
13422
|
+
message = readFileSync19(0, "utf-8").trim();
|
|
12934
13423
|
}
|
|
12935
13424
|
await send(null, { json, to: target, message, noEnter: values["no-enter"] });
|
|
12936
13425
|
break;
|
|
@@ -12955,6 +13444,12 @@ try {
|
|
|
12955
13444
|
launchTeamCockpit();
|
|
12956
13445
|
break;
|
|
12957
13446
|
}
|
|
13447
|
+
case "app": {
|
|
13448
|
+
const session = positionals[1];
|
|
13449
|
+
const appArgs = session ? [`--target=${session}`] : [];
|
|
13450
|
+
execBunWidget("app", appScriptPath, appArgs, "app");
|
|
13451
|
+
break;
|
|
13452
|
+
}
|
|
12958
13453
|
case "switcher": {
|
|
12959
13454
|
const clientArg = typeof values.client === "string" ? values.client : "";
|
|
12960
13455
|
execBunWidget("team", teamScriptPath, [], "switcher", { TMUX_IDE_PICKER_CLIENT: clientArg });
|
|
@@ -13047,10 +13542,10 @@ try {
|
|
|
13047
13542
|
}
|
|
13048
13543
|
}
|
|
13049
13544
|
case "events": {
|
|
13050
|
-
const { readFileSync:
|
|
13545
|
+
const { readFileSync: readFileSync19, existsSync: existsSync34, statSync: statSync5, openSync, readSync, closeSync } = await import("node:fs");
|
|
13051
13546
|
const { eventsPath: eventsPath2, formatEventLine: formatEventLine2 } = await Promise.resolve().then(() => (init_events(), events_exports));
|
|
13052
13547
|
const path2 = eventsPath2();
|
|
13053
|
-
if (!
|
|
13548
|
+
if (!existsSync34(path2)) {
|
|
13054
13549
|
console.log("no events yet \u2014 is a session adopted? (the chrome updater writes events)");
|
|
13055
13550
|
break;
|
|
13056
13551
|
}
|
|
@@ -13070,7 +13565,7 @@ try {
|
|
|
13070
13565
|
} catch {
|
|
13071
13566
|
}
|
|
13072
13567
|
};
|
|
13073
|
-
const allLines =
|
|
13568
|
+
const allLines = readFileSync19(path2, "utf8").split("\n").filter((l) => l.trim().length > 0);
|
|
13074
13569
|
for (const line of allLines.slice(-50)) printLine(line);
|
|
13075
13570
|
if (!values.follow) break;
|
|
13076
13571
|
let offset = statSync5(path2).size;
|
|
@@ -13477,7 +13972,7 @@ Known panels: ${POPUP_WIDGETS2.join(", ")}.`,
|
|
|
13477
13972
|
const mainPath = worktrees[0]?.path ?? repoDir;
|
|
13478
13973
|
const projectName = getSessionName2(mainPath).name;
|
|
13479
13974
|
async function openWorktreeSession(wtPath, name) {
|
|
13480
|
-
if (
|
|
13975
|
+
if (existsSync33(join27(wtPath, "ide.yml"))) {
|
|
13481
13976
|
await launch(wtPath, { attach: false, sessionName: name });
|
|
13482
13977
|
} else {
|
|
13483
13978
|
if (!hasSession2(name)) createDetachedSession2(name, wtPath);
|
|
@@ -13614,6 +14109,16 @@ Known panels: ${POPUP_WIDGETS2.join(", ")}.`,
|
|
|
13614
14109
|
break;
|
|
13615
14110
|
}
|
|
13616
14111
|
case "update": {
|
|
14112
|
+
if (values["tui-binary"] === true) {
|
|
14113
|
+
const { downloadTuiBinary: downloadTuiBinary2 } = await Promise.resolve().then(() => (init_tui_binary(), tui_binary_exports));
|
|
14114
|
+
const { path: path2 } = await downloadTuiBinary2({ log: (m) => console.error(m) });
|
|
14115
|
+
if (json) {
|
|
14116
|
+
console.log(JSON.stringify({ ok: true, path: path2 }, null, 2));
|
|
14117
|
+
} else {
|
|
14118
|
+
console.log(`TUI binary ready: ${path2}`);
|
|
14119
|
+
}
|
|
14120
|
+
break;
|
|
14121
|
+
}
|
|
13617
14122
|
const { runUpdate: runUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
13618
14123
|
const dryRun = values["dry-run"] === true;
|
|
13619
14124
|
const plan = runUpdate2({ cliDir: __dirname6, dryRun });
|