tmux-ide 2.9.15 → 2.9.16
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 +1 -1
- package/bin/cli.js +460 -142
- package/package.json +2 -1
- package/packages/contracts/src/tmux-server-scope.ts +54 -0
- package/packages/core/src/terminal-replica.ts +32 -10
- package/packages/daemon/dist/command-center/daemon-fleet-facts-observer.js +8 -1
- package/packages/daemon/dist/command-center/tmux-servers.js +46 -10
- package/packages/daemon/dist/lib/session-favicon.js +152 -0
- package/packages/daemon/dist/lib/skill-sync.js +3 -3
- package/packages/daemon/dist/lib/tmux-server-owner.js +16 -3
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Info.plist +2 -2
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/MacOS/tmux-ide-notifier +0 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Resources/Assets.car +0 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/_CodeSignature/CodeResources +2 -2
- package/packages/daemon/dist/open-browser.js +47 -3
- package/packages/daemon/dist/terminal/pane-stream/pane-stream-websocket.js +12 -0
- package/packages/daemon/dist/terminal/session-runtime/terminal-delivery-hub.js +16 -0
- package/packages/daemon/src/command-center/daemon-fleet-facts-observer.ts +9 -1
- package/packages/daemon/src/command-center/tmux-servers.ts +55 -11
- package/packages/daemon/src/lib/session-favicon.ts +185 -0
- package/packages/daemon/src/lib/skill-sync.ts +3 -3
- package/packages/daemon/src/lib/tmux-server-owner.ts +35 -6
- package/packages/daemon/src/open-browser.ts +88 -3
- package/packages/daemon/src/terminal/pane-stream/pane-stream-websocket.ts +12 -0
- package/packages/daemon/src/terminal/session-runtime/terminal-delivery-hub.ts +25 -0
- package/skill/SKILL.md +6 -1
package/bin/cli.js
CHANGED
|
@@ -7432,14 +7432,18 @@ var init_terminal_projection = __esm({
|
|
|
7432
7432
|
var tmux_server_scope_exports = {};
|
|
7433
7433
|
__export(tmux_server_scope_exports, {
|
|
7434
7434
|
TMUX_SERVERS_API_PATH: () => TMUX_SERVERS_API_PATH,
|
|
7435
|
+
TMUX_SERVER_SESSION_FAVICON_MAX_BYTES: () => TMUX_SERVER_SESSION_FAVICON_MAX_BYTES,
|
|
7435
7436
|
TmuxServerDescriptorSchemaZ: () => TmuxServerDescriptorSchemaZ,
|
|
7436
7437
|
TmuxServerGenerationSchemaZ: () => TmuxServerGenerationSchemaZ,
|
|
7437
7438
|
TmuxServerIdSchemaZ: () => TmuxServerIdSchemaZ,
|
|
7438
7439
|
TmuxServerPaneTargetSchemaZ: () => TmuxServerPaneTargetSchemaZ,
|
|
7439
7440
|
TmuxServerRegistrationRequestSchemaZ: () => TmuxServerRegistrationRequestSchemaZ,
|
|
7440
7441
|
TmuxServerScopeSchemaZ: () => TmuxServerScopeSchemaZ,
|
|
7442
|
+
TmuxServerSessionFaviconMimeSchemaZ: () => TmuxServerSessionFaviconMimeSchemaZ,
|
|
7443
|
+
TmuxServerSessionFaviconSchemaZ: () => TmuxServerSessionFaviconSchemaZ,
|
|
7441
7444
|
TmuxServerSessionTargetSchemaZ: () => TmuxServerSessionTargetSchemaZ,
|
|
7442
7445
|
TmuxServerSessionsResourceSchemaZ: () => TmuxServerSessionsResourceSchemaZ,
|
|
7446
|
+
TmuxServerSessionsResourceV2SchemaZ: () => TmuxServerSessionsResourceV2SchemaZ,
|
|
7443
7447
|
TmuxServerWindowTargetSchemaZ: () => TmuxServerWindowTargetSchemaZ,
|
|
7444
7448
|
TmuxServersResourceSchemaZ: () => TmuxServersResourceSchemaZ,
|
|
7445
7449
|
isTmuxServerPaneStreamPath: () => isTmuxServerPaneStreamPath,
|
|
@@ -7474,7 +7478,11 @@ function isTmuxServerPaneStreamPath(path2) {
|
|
|
7474
7478
|
if (!match) return false;
|
|
7475
7479
|
return TmuxServerScopeSchemaZ.safeParse({ serverId: match[1], generation: match[2] }).success;
|
|
7476
7480
|
}
|
|
7477
|
-
|
|
7481
|
+
function base64DecodedLength(data) {
|
|
7482
|
+
const padding = data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0;
|
|
7483
|
+
return data.length / 4 * 3 - padding;
|
|
7484
|
+
}
|
|
7485
|
+
var descriptorShape, TmuxServerDescriptorSchemaZ, TMUX_SERVERS_API_PATH, TmuxServersResourceSchemaZ, TmuxServerSessionTargetSchemaZ, TmuxServerWindowTargetSchemaZ, TmuxServerPaneTargetSchemaZ, TmuxServerSessionsResourceSchemaZ, TMUX_SERVER_SESSION_FAVICON_MAX_BYTES, TmuxServerSessionFaviconMimeSchemaZ, TmuxServerSessionFaviconSchemaZ, TmuxServerSessionsResourceV2SchemaZ, TmuxServerRegistrationRequestSchemaZ;
|
|
7478
7486
|
var init_tmux_server_scope = __esm({
|
|
7479
7487
|
"packages/contracts/src/tmux-server-scope.ts"() {
|
|
7480
7488
|
"use strict";
|
|
@@ -7537,6 +7545,37 @@ var init_tmux_server_scope = __esm({
|
|
|
7537
7545
|
}).strict()
|
|
7538
7546
|
)
|
|
7539
7547
|
}).strict())();
|
|
7548
|
+
TMUX_SERVER_SESSION_FAVICON_MAX_BYTES = /* @__PURE__ */ (() => 32768)();
|
|
7549
|
+
TmuxServerSessionFaviconMimeSchemaZ = /* @__PURE__ */ (() => z47.enum([
|
|
7550
|
+
"image/png",
|
|
7551
|
+
"image/svg+xml",
|
|
7552
|
+
"image/x-icon",
|
|
7553
|
+
"image/jpeg",
|
|
7554
|
+
"image/webp",
|
|
7555
|
+
"image/gif"
|
|
7556
|
+
]))();
|
|
7557
|
+
TmuxServerSessionFaviconSchemaZ = /* @__PURE__ */ (() => z47.object({
|
|
7558
|
+
mime: TmuxServerSessionFaviconMimeSchemaZ,
|
|
7559
|
+
data: z47.string().regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u).refine(
|
|
7560
|
+
(data) => base64DecodedLength(data) <= TMUX_SERVER_SESSION_FAVICON_MAX_BYTES,
|
|
7561
|
+
"favicon exceeds 32 KiB"
|
|
7562
|
+
)
|
|
7563
|
+
}).strict())();
|
|
7564
|
+
TmuxServerSessionsResourceV2SchemaZ = /* @__PURE__ */ (() => z47.object({
|
|
7565
|
+
version: z47.literal(2),
|
|
7566
|
+
server: TmuxServerScopeSchemaZ,
|
|
7567
|
+
sessions: z47.array(
|
|
7568
|
+
z47.object({
|
|
7569
|
+
liveSessionId: WorkspaceCatalogLiveSessionIdSchemaZ,
|
|
7570
|
+
sessionName: z47.string().min(1).max(160),
|
|
7571
|
+
workspaceName: z47.string().min(1).max(160).nullable(),
|
|
7572
|
+
paneCount: z47.number().int().nonnegative(),
|
|
7573
|
+
windowCount: z47.number().int().min(1),
|
|
7574
|
+
lastActivity: z47.number().int().nonnegative().nullable(),
|
|
7575
|
+
favicon: TmuxServerSessionFaviconSchemaZ.nullable()
|
|
7576
|
+
}).strict()
|
|
7577
|
+
)
|
|
7578
|
+
}).strict())();
|
|
7540
7579
|
TmuxServerRegistrationRequestSchemaZ = /* @__PURE__ */ (() => z47.object({
|
|
7541
7580
|
label: descriptorShape.label.max(128),
|
|
7542
7581
|
selector: z47.discriminatedUnion("kind", [
|
|
@@ -13043,7 +13082,7 @@ var require_package = __commonJS({
|
|
|
13043
13082
|
"package.json"(exports, module) {
|
|
13044
13083
|
module.exports = {
|
|
13045
13084
|
name: "tmux-ide",
|
|
13046
|
-
version: "2.9.
|
|
13085
|
+
version: "2.9.16",
|
|
13047
13086
|
description: "The open-source workspace for coding agents: run Claude Code, Codex and other agents in tmux with live status",
|
|
13048
13087
|
type: "module",
|
|
13049
13088
|
bin: {
|
|
@@ -13113,6 +13152,7 @@ var require_package = __commonJS({
|
|
|
13113
13152
|
postinstall: "node scripts/postinstall.js",
|
|
13114
13153
|
docs: "turbo run dev --filter=@tmux-ide/docs",
|
|
13115
13154
|
"demo:tui": "bun --preload @opentui/solid/preload docs/scripts/render-tui-demo.tsx",
|
|
13155
|
+
"demo:themes": "bun --preload @opentui/solid/preload docs/scripts/render-theme-gallery.tsx && node docs/scripts/rasterize-theme-gallery.mjs",
|
|
13116
13156
|
"demo:font": "node docs/scripts/tui-demo-font/build.mjs",
|
|
13117
13157
|
"readme:media": "node docs/scripts/readme-media.mjs",
|
|
13118
13158
|
"test:tui-renderer": "bun test --preload @opentui/solid/preload --preload ./packages/daemon/test-support/opentui-renderer-preload.ts ./packages/daemon/src/tui/mirror/automatic-contrast-renderer.test.tsx ./packages/daemon/src/tui/mirror/pane-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/native-grid-projection-renderer.test.tsx ./packages/daemon/src/tui/mirror/widget-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/missions-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/recipes-gallery-renderer.test.tsx ./packages/daemon/src/tui/mirror/shell-chrome-renderer.test.tsx ./packages/daemon/src/tui/mirror/sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/home-files-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/changes-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/activity-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/files/session-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-terminal-workspace-renderer.test.tsx ./packages/daemon/src/tui/mirror/testing/styled-frame-oracle.test.tsx ./packages/daemon/src/tui/mirror/runtime/terminal-transient-frame-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/terminal-draw-failure-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-view-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-root-error-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-backpressure-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-demand-cadence-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/files-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/changes-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/missions-activity-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/dialogs-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/optional-feature-registry-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/palette-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/pane-scoped-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/rich-preview/feature.test.ts ./packages/daemon/src/tui/mirror/runtime/rich-preview-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/application-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/pane-frame-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-chrome-view.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-window-strip-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-dock-dual-host-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/agent-terminal-canvas-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/command-palette-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/opentui-insertion-stability-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-home-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-header-polish-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-roster-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-flow-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/guided-tour-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-sidebar-catalog-renderer.test.tsx ./packages/daemon/src/tui/mirror/ui/ui-renderer.test.tsx ./packages/daemon/src/tui/mirror/ui/pane-interaction-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-machine-sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-add-machine-dialog-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-new-agent-dialog-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-switcher-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-palette-preview-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-palette-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-session-actions-renderer.test.tsx ./packages/daemon/src/tui/mirror/ui/agent-team-renderer.test.tsx ./scripts/solid-conditional-props.test.tsx",
|
|
@@ -39850,7 +39890,7 @@ function createNativeTmuxSessionOpener(options) {
|
|
|
39850
39890
|
options.assertOpen();
|
|
39851
39891
|
if (disposed) throw new Error("Session admission is retired");
|
|
39852
39892
|
};
|
|
39853
|
-
const
|
|
39893
|
+
const open5 = async (liveSessionId, observed) => {
|
|
39854
39894
|
assertOpen();
|
|
39855
39895
|
const records = await options.run([
|
|
39856
39896
|
"list-sessions",
|
|
@@ -39912,7 +39952,7 @@ function createNativeTmuxSessionOpener(options) {
|
|
|
39912
39952
|
const previous = pending.get(liveSessionId);
|
|
39913
39953
|
if (previous) return previous;
|
|
39914
39954
|
if (pending.size >= 16) throw new Error("Session admission capacity reached");
|
|
39915
|
-
const operation = tail.then(() =>
|
|
39955
|
+
const operation = tail.then(() => open5(liveSessionId)).finally(() => pending.delete(liveSessionId));
|
|
39916
39956
|
pending.set(liveSessionId, operation);
|
|
39917
39957
|
tail = operation.catch(() => {
|
|
39918
39958
|
});
|
|
@@ -39925,7 +39965,7 @@ function createNativeTmuxSessionOpener(options) {
|
|
|
39925
39965
|
if (pending.size >= 16) throw new Error("Session admission capacity reached");
|
|
39926
39966
|
const key2 = randomUUID23();
|
|
39927
39967
|
const operation = tail.then(async () => {
|
|
39928
|
-
const result2 = await
|
|
39968
|
+
const result2 = await open5(liveSessionId, observed);
|
|
39929
39969
|
if (!result2.semanticPaneId) throw new Error("Agent admission returned no target");
|
|
39930
39970
|
return { ...result2, semanticPaneId: result2.semanticPaneId };
|
|
39931
39971
|
}).finally(() => pending.delete(key2));
|
|
@@ -44563,8 +44603,13 @@ async function applyTerminalReplicaUpdateCooperatively(current, update, options)
|
|
|
44563
44603
|
}
|
|
44564
44604
|
const authenticated = options.authenticatedFrameHash;
|
|
44565
44605
|
const frameStart = readProfileClock(options.instrumentation);
|
|
44566
|
-
const
|
|
44567
|
-
|
|
44606
|
+
const reuseAuthenticated = Boolean(authenticated && /^[0-9a-f]{16}$/u.test(authenticated));
|
|
44607
|
+
if (!reuseAuthenticated) {
|
|
44608
|
+
await primeTerminalReplicaRowsHashCooperatively(snapshot3.grid, yieldControl);
|
|
44609
|
+
await primeTerminalReplicaRowsHashCooperatively(snapshot3.history, yieldControl);
|
|
44610
|
+
}
|
|
44611
|
+
const frameHash = reuseAuthenticated ? authenticated : await hashCanonicalTerminalValueCooperatively(
|
|
44612
|
+
terminalReplicaFrameIdentity({ ...admitted, snapshot: snapshot3 }),
|
|
44568
44613
|
yieldControl,
|
|
44569
44614
|
// Bound frame hashing without scheduling a task per few cells.
|
|
44570
44615
|
32 * 1024
|
|
@@ -44841,10 +44886,20 @@ function resolveFrameHash(update, options, profile) {
|
|
|
44841
44886
|
return authenticated;
|
|
44842
44887
|
}
|
|
44843
44888
|
const started = readProfileClock(options.instrumentation);
|
|
44844
|
-
const hash = hashStable(update);
|
|
44889
|
+
const hash = hashStable(terminalReplicaFrameIdentity(update));
|
|
44845
44890
|
addProfileDuration(profile, "updateHash", started, options.instrumentation);
|
|
44846
44891
|
return hash;
|
|
44847
44892
|
}
|
|
44893
|
+
function terminalReplicaFrameIdentity(update) {
|
|
44894
|
+
if (update.type !== "terminal.seed") return update;
|
|
44895
|
+
const { grid, history, ...rest } = update.snapshot;
|
|
44896
|
+
return [
|
|
44897
|
+
"terminal-replica-frame-v2",
|
|
44898
|
+
{ ...update, snapshot: rest },
|
|
44899
|
+
hashTerminalReplicaRows(grid),
|
|
44900
|
+
hashTerminalReplicaRows(history)
|
|
44901
|
+
];
|
|
44902
|
+
}
|
|
44848
44903
|
function readProfileClock(instrumentation) {
|
|
44849
44904
|
if (!instrumentation) return void 0;
|
|
44850
44905
|
try {
|
|
@@ -62237,6 +62292,14 @@ function joinBytes(chunks) {
|
|
|
62237
62292
|
}
|
|
62238
62293
|
return joined;
|
|
62239
62294
|
}
|
|
62295
|
+
function logDeliveryFault(client, reason, cause) {
|
|
62296
|
+
logger.info("terminal-delivery", "fault sent to client", {
|
|
62297
|
+
reason,
|
|
62298
|
+
...cause ? { cause } : {},
|
|
62299
|
+
pane: client.paneId,
|
|
62300
|
+
workspace: client.deliveryWorkspaceName
|
|
62301
|
+
});
|
|
62302
|
+
}
|
|
62240
62303
|
var MAX_CANONICAL_REVISIONS, MAX_RAW_JOURNAL_BYTES, MAX_REPRESENTATION_CACHE_ENTRIES, MAX_REPRESENTATION_CACHE_BYTES, MAX_CLIENTS, MAX_PANES, MAX_PENDING_CANONICAL_CELLS, MAX_CONNECTIONS, BACKGROUND_CADENCE_MS, DeferredProjectionEncoding, DeferredSeedEncoding, ExactSemanticRepresentationSelectionError, TerminalDeliveryRepresentationSelectionError, TerminalDeliveryPreaccountLimitError, SessionRuntimeTerminalDeliveryHub;
|
|
62241
62304
|
var init_terminal_delivery_hub = __esm({
|
|
62242
62305
|
"packages/daemon/src/terminal/session-runtime/terminal-delivery-hub.ts"() {
|
|
@@ -62245,6 +62308,7 @@ var init_terminal_delivery_hub = __esm({
|
|
|
62245
62308
|
init_src2();
|
|
62246
62309
|
init_src3();
|
|
62247
62310
|
init_stock_capture_fidelity();
|
|
62311
|
+
init_log();
|
|
62248
62312
|
init_native_seed_backing();
|
|
62249
62313
|
init_src2();
|
|
62250
62314
|
init_src3();
|
|
@@ -62426,6 +62490,11 @@ var init_terminal_delivery_hub = __esm({
|
|
|
62426
62490
|
};
|
|
62427
62491
|
} catch (error) {
|
|
62428
62492
|
if (!(error instanceof StockCaptureTabUnavailableError)) throw error;
|
|
62493
|
+
logDeliveryFault(
|
|
62494
|
+
{ paneId: semanticPaneId3, deliveryWorkspaceName: address },
|
|
62495
|
+
"source-closed",
|
|
62496
|
+
"capture-unavailable"
|
|
62497
|
+
);
|
|
62429
62498
|
await accept({
|
|
62430
62499
|
type: "terminal.delivery.fault",
|
|
62431
62500
|
reason: "source-closed",
|
|
@@ -62584,6 +62653,7 @@ var init_terminal_delivery_hub = __esm({
|
|
|
62584
62653
|
this.#cancelEncoding(client);
|
|
62585
62654
|
client.outgoing.length = 0;
|
|
62586
62655
|
client.inFlight = null;
|
|
62656
|
+
logDeliveryFault(client, "source-closed", "source-restarted");
|
|
62587
62657
|
this.#enqueue(client, {
|
|
62588
62658
|
type: "terminal.delivery.fault",
|
|
62589
62659
|
reason: "source-closed",
|
|
@@ -63571,6 +63641,7 @@ var init_terminal_delivery_hub = __esm({
|
|
|
63571
63641
|
this.#recordDeliveryStatus(client, this.#panes.get(client.paneId));
|
|
63572
63642
|
}
|
|
63573
63643
|
#fault(client, reason, message, selectionObservation = null) {
|
|
63644
|
+
logDeliveryFault(client, reason);
|
|
63574
63645
|
if (this.#observability.enabled)
|
|
63575
63646
|
try {
|
|
63576
63647
|
const atMicros = this.#observability.nowMicros();
|
|
@@ -72667,6 +72738,7 @@ var init_pane_stream_websocket = __esm({
|
|
|
72667
72738
|
init_src2();
|
|
72668
72739
|
init_src2();
|
|
72669
72740
|
init_src2();
|
|
72741
|
+
init_log();
|
|
72670
72742
|
init_src2();
|
|
72671
72743
|
init_admission_util();
|
|
72672
72744
|
init_registry2();
|
|
@@ -73175,6 +73247,11 @@ var init_pane_stream_websocket = __esm({
|
|
|
73175
73247
|
this.#open = false;
|
|
73176
73248
|
this.#cancelDeadline();
|
|
73177
73249
|
const socket = this.#socket;
|
|
73250
|
+
logger.info("pane-stream", "admission closed", {
|
|
73251
|
+
code: code2,
|
|
73252
|
+
reason,
|
|
73253
|
+
hostClientId: this.hostClientId
|
|
73254
|
+
});
|
|
73178
73255
|
this.#detach();
|
|
73179
73256
|
this.#onRelease(this);
|
|
73180
73257
|
if (socket) safeCloseSocket(socket, code2, reason);
|
|
@@ -73426,6 +73503,12 @@ var init_pane_stream_websocket = __esm({
|
|
|
73426
73503
|
close(code2 = 1e3, reason = "stream-closed") {
|
|
73427
73504
|
if (this.#closed) return;
|
|
73428
73505
|
this.#recordDiagnosticLifecycle("pane-stream-terminal", code2, reason);
|
|
73506
|
+
logger.info("pane-stream", "stream closed", {
|
|
73507
|
+
code: code2,
|
|
73508
|
+
reason,
|
|
73509
|
+
session: this.#descriptor.sessionName,
|
|
73510
|
+
clientId: this.#clientId
|
|
73511
|
+
});
|
|
73429
73512
|
this.#closed = true;
|
|
73430
73513
|
for (const demand of this.#surfaceDemands.values()) demand.close();
|
|
73431
73514
|
this.#surfaceDemands.clear();
|
|
@@ -75719,7 +75802,8 @@ function createNativeTmuxServerCatalog(workspaceRegistry, run, assertOpen = () =
|
|
|
75719
75802
|
"list-panes",
|
|
75720
75803
|
"-a",
|
|
75721
75804
|
"-F",
|
|
75722
|
-
|
|
75805
|
+
// session_path stays last: tmux rejects tabs in session names but not in paths.
|
|
75806
|
+
"#{pid} #{session_id} #{session_created} #{session_name} #{pane_id} #{window_id} #{session_activity} #{session_path}"
|
|
75723
75807
|
].map(shellEscape).join(" ")
|
|
75724
75808
|
],
|
|
75725
75809
|
AbortSignal.timeout(2e3)
|
|
@@ -75728,17 +75812,21 @@ function createNativeTmuxServerCatalog(workspaceRegistry, run, assertOpen = () =
|
|
|
75728
75812
|
const rows = /* @__PURE__ */ new Map();
|
|
75729
75813
|
const lines = raw.trim() === "tmux-ide-empty-catalog-v1" ? [] : raw.trim().split("\n");
|
|
75730
75814
|
for (const line of lines) {
|
|
75731
|
-
const [pid, id2, created, name, pane,
|
|
75732
|
-
|
|
75815
|
+
const [pid, id2, created, name, pane, window2, activity, ...pathParts] = line.split(" ");
|
|
75816
|
+
const dir = pathParts.join(" ");
|
|
75817
|
+
if (!pid || !/^\d+$/.test(pid) || !id2 || !/^\$\d+$/.test(id2) || !created || !/^\d+$/.test(created) || !name || !pane || !/^%\d+$/.test(pane) || !window2 || !/^@\d+$/.test(window2) || !dir)
|
|
75733
75818
|
throw new Error("Invalid native server catalog");
|
|
75734
75819
|
if (!isVisibleFleetSession(name)) continue;
|
|
75735
75820
|
const liveSessionId = liveSessionIdForNativeIdentity(pid, id2, created);
|
|
75736
75821
|
const row = rows.get(liveSessionId) ?? {
|
|
75737
75822
|
summary: { liveSessionId, sessionName: name, paneCount: 0 },
|
|
75738
75823
|
panes: /* @__PURE__ */ new Set(),
|
|
75739
|
-
|
|
75824
|
+
windows: /* @__PURE__ */ new Set(),
|
|
75825
|
+
dir,
|
|
75826
|
+
activity: activity && /^\d+$/.test(activity) ? Number(activity) : null
|
|
75740
75827
|
};
|
|
75741
75828
|
row.panes.add(pane);
|
|
75829
|
+
row.windows.add(window2);
|
|
75742
75830
|
rows.set(liveSessionId, row);
|
|
75743
75831
|
}
|
|
75744
75832
|
const names = new Set([...rows.values()].map(({ summary }) => summary.sessionName));
|
|
@@ -75753,7 +75841,13 @@ function createNativeTmuxServerCatalog(workspaceRegistry, run, assertOpen = () =
|
|
|
75753
75841
|
projectDir: dir,
|
|
75754
75842
|
persistence: "volatile"
|
|
75755
75843
|
});
|
|
75756
|
-
return [...rows.values()].map(({ summary, panes }) => ({
|
|
75844
|
+
return [...rows.values()].map(({ summary, panes, windows, dir, activity }) => ({
|
|
75845
|
+
...summary,
|
|
75846
|
+
paneCount: panes.size,
|
|
75847
|
+
windowCount: windows.size,
|
|
75848
|
+
lastActivity: activity,
|
|
75849
|
+
sessionPath: dir
|
|
75850
|
+
}));
|
|
75757
75851
|
};
|
|
75758
75852
|
}
|
|
75759
75853
|
async function createNativeTmuxServerOwner(options) {
|
|
@@ -78728,7 +78822,7 @@ function createSharedFleetFactsReaders(run, isAbsentServer = () => false) {
|
|
|
78728
78822
|
}
|
|
78729
78823
|
};
|
|
78730
78824
|
}
|
|
78731
|
-
var DaemonFleetFactsObserver, SESSION_COMPOSITION_TMUX_ARGS, FLEET_FACTS_TMUX_ARGS;
|
|
78825
|
+
var DaemonFleetFactsObserver, FLEET_FACTS_POLL_MS, SESSION_COMPOSITION_TMUX_ARGS, FLEET_FACTS_TMUX_ARGS;
|
|
78732
78826
|
var init_daemon_fleet_facts_observer = __esm({
|
|
78733
78827
|
"packages/daemon/src/command-center/daemon-fleet-facts-observer.ts"() {
|
|
78734
78828
|
"use strict";
|
|
@@ -78763,7 +78857,7 @@ var init_daemon_fleet_facts_observer = __esm({
|
|
|
78763
78857
|
#diagnosticActiveOperations = 0;
|
|
78764
78858
|
constructor(options) {
|
|
78765
78859
|
this.#options = options;
|
|
78766
|
-
this.#intervalMs = options.intervalMs ??
|
|
78860
|
+
this.#intervalMs = options.intervalMs ?? FLEET_FACTS_POLL_MS;
|
|
78767
78861
|
this.#setTimer = options.setTimer ?? ((callback, delayMs) => {
|
|
78768
78862
|
const timer = setTimeout(callback, delayMs);
|
|
78769
78863
|
timer.unref?.();
|
|
@@ -79101,6 +79195,7 @@ var init_daemon_fleet_facts_observer = __esm({
|
|
|
79101
79195
|
return this.#refs.has(demand) && (captured.get(demand) ?? 0) === (this.#demandEpochs.get(demand) ?? 0);
|
|
79102
79196
|
}
|
|
79103
79197
|
};
|
|
79198
|
+
FLEET_FACTS_POLL_MS = 500;
|
|
79104
79199
|
SESSION_COMPOSITION_TMUX_ARGS = [
|
|
79105
79200
|
"list-panes",
|
|
79106
79201
|
"-a",
|
|
@@ -84761,6 +84856,145 @@ var init_tmux_server_editor_context = __esm({
|
|
|
84761
84856
|
}
|
|
84762
84857
|
});
|
|
84763
84858
|
|
|
84859
|
+
// packages/daemon/src/lib/session-favicon.ts
|
|
84860
|
+
import { constants as constants16 } from "node:fs";
|
|
84861
|
+
import { lstat as lstat4, open as open4 } from "node:fs/promises";
|
|
84862
|
+
import { extname, isAbsolute as isAbsolute24, join as join41 } from "node:path";
|
|
84863
|
+
async function lstatOrNull(io, path2) {
|
|
84864
|
+
try {
|
|
84865
|
+
return await io.lstat(path2);
|
|
84866
|
+
} catch {
|
|
84867
|
+
return null;
|
|
84868
|
+
}
|
|
84869
|
+
}
|
|
84870
|
+
function createSessionFaviconResolver(options = {}) {
|
|
84871
|
+
const io = options.io ?? defaultSessionFaviconIo;
|
|
84872
|
+
const now = options.now ?? Date.now;
|
|
84873
|
+
const missTtlMs = options.missTtlMs ?? 3e4;
|
|
84874
|
+
const maxEntries = options.maxEntries ?? 256;
|
|
84875
|
+
const cache3 = /* @__PURE__ */ new Map();
|
|
84876
|
+
const remember = (sessionPath, entry) => {
|
|
84877
|
+
cache3.delete(sessionPath);
|
|
84878
|
+
cache3.set(sessionPath, entry);
|
|
84879
|
+
while (cache3.size > maxEntries) cache3.delete(cache3.keys().next().value);
|
|
84880
|
+
};
|
|
84881
|
+
const scan = async (sessionPath) => {
|
|
84882
|
+
const directories = /* @__PURE__ */ new Map();
|
|
84883
|
+
for (const candidate of SESSION_FAVICON_CANDIDATES) {
|
|
84884
|
+
const mime = MIME_BY_EXTENSION[extname(candidate)];
|
|
84885
|
+
if (!mime) continue;
|
|
84886
|
+
const slash = candidate.lastIndexOf("/");
|
|
84887
|
+
if (slash >= 0) {
|
|
84888
|
+
const parts = candidate.slice(0, slash).split("/");
|
|
84889
|
+
let real = true;
|
|
84890
|
+
for (let index = 1; index <= parts.length && real; index += 1) {
|
|
84891
|
+
const directory2 = parts.slice(0, index).join("/");
|
|
84892
|
+
let known = directories.get(directory2);
|
|
84893
|
+
if (known === void 0) {
|
|
84894
|
+
const stats2 = await lstatOrNull(io, join41(sessionPath, directory2));
|
|
84895
|
+
known = stats2 !== null && stats2.isDirectory() && !stats2.isSymbolicLink();
|
|
84896
|
+
directories.set(directory2, known);
|
|
84897
|
+
}
|
|
84898
|
+
real = known;
|
|
84899
|
+
}
|
|
84900
|
+
if (!real) continue;
|
|
84901
|
+
}
|
|
84902
|
+
const file = join41(sessionPath, candidate);
|
|
84903
|
+
const stats = await lstatOrNull(io, file);
|
|
84904
|
+
if (!stats || !stats.isFile() || stats.size > TMUX_SERVER_SESSION_FAVICON_MAX_BYTES) continue;
|
|
84905
|
+
const bytes = await io.readNoFollow(file, TMUX_SERVER_SESSION_FAVICON_MAX_BYTES);
|
|
84906
|
+
if (!bytes) continue;
|
|
84907
|
+
return {
|
|
84908
|
+
kind: "hit",
|
|
84909
|
+
file,
|
|
84910
|
+
mtimeMs: stats.mtimeMs,
|
|
84911
|
+
size: stats.size,
|
|
84912
|
+
favicon: { mime, data: bytes.toString("base64"), size: bytes.byteLength }
|
|
84913
|
+
};
|
|
84914
|
+
}
|
|
84915
|
+
return { kind: "miss", at: now() };
|
|
84916
|
+
};
|
|
84917
|
+
return async (sessionPath) => {
|
|
84918
|
+
if (!sessionPath || !isAbsolute24(sessionPath) || sessionPath.includes("\0")) return null;
|
|
84919
|
+
const cached2 = cache3.get(sessionPath);
|
|
84920
|
+
if (cached2?.kind === "miss" && now() - cached2.at < missTtlMs) {
|
|
84921
|
+
remember(sessionPath, cached2);
|
|
84922
|
+
return null;
|
|
84923
|
+
}
|
|
84924
|
+
if (cached2?.kind === "hit") {
|
|
84925
|
+
const stats = await lstatOrNull(io, cached2.file);
|
|
84926
|
+
if (stats && stats.isFile() && stats.mtimeMs === cached2.mtimeMs && stats.size === cached2.size) {
|
|
84927
|
+
remember(sessionPath, cached2);
|
|
84928
|
+
return cached2.favicon;
|
|
84929
|
+
}
|
|
84930
|
+
}
|
|
84931
|
+
const entry = await scan(sessionPath);
|
|
84932
|
+
remember(sessionPath, entry);
|
|
84933
|
+
return entry.kind === "hit" ? entry.favicon : null;
|
|
84934
|
+
};
|
|
84935
|
+
}
|
|
84936
|
+
var SESSION_FAVICON_CANDIDATES, MIME_BY_EXTENSION, defaultSessionFaviconIo;
|
|
84937
|
+
var init_session_favicon = __esm({
|
|
84938
|
+
"packages/daemon/src/lib/session-favicon.ts"() {
|
|
84939
|
+
"use strict";
|
|
84940
|
+
init_src2();
|
|
84941
|
+
SESSION_FAVICON_CANDIDATES = [
|
|
84942
|
+
"favicon.svg",
|
|
84943
|
+
"favicon.png",
|
|
84944
|
+
"favicon.ico",
|
|
84945
|
+
"public/favicon.svg",
|
|
84946
|
+
"public/favicon.png",
|
|
84947
|
+
"public/favicon.ico",
|
|
84948
|
+
"app/icon.svg",
|
|
84949
|
+
"app/icon.png",
|
|
84950
|
+
"app/favicon.ico",
|
|
84951
|
+
"src/app/icon.svg",
|
|
84952
|
+
"src/app/icon.png",
|
|
84953
|
+
"src/app/favicon.ico",
|
|
84954
|
+
"static/favicon.svg",
|
|
84955
|
+
"static/favicon.png",
|
|
84956
|
+
"static/favicon.ico",
|
|
84957
|
+
"assets/favicon.svg",
|
|
84958
|
+
"assets/favicon.png",
|
|
84959
|
+
"assets/favicon.ico",
|
|
84960
|
+
"apple-touch-icon.png",
|
|
84961
|
+
"public/apple-touch-icon.png",
|
|
84962
|
+
"icon.svg",
|
|
84963
|
+
"icon.png"
|
|
84964
|
+
];
|
|
84965
|
+
MIME_BY_EXTENSION = {
|
|
84966
|
+
".png": "image/png",
|
|
84967
|
+
".svg": "image/svg+xml",
|
|
84968
|
+
".ico": "image/x-icon",
|
|
84969
|
+
".jpg": "image/jpeg",
|
|
84970
|
+
".jpeg": "image/jpeg",
|
|
84971
|
+
".webp": "image/webp",
|
|
84972
|
+
".gif": "image/gif"
|
|
84973
|
+
};
|
|
84974
|
+
defaultSessionFaviconIo = {
|
|
84975
|
+
lstat: (path2) => lstat4(path2),
|
|
84976
|
+
readNoFollow: async (path2, maxBytes) => {
|
|
84977
|
+
let handle;
|
|
84978
|
+
try {
|
|
84979
|
+
handle = await open4(path2, constants16.O_RDONLY | constants16.O_NOFOLLOW | constants16.O_NONBLOCK);
|
|
84980
|
+
} catch {
|
|
84981
|
+
return null;
|
|
84982
|
+
}
|
|
84983
|
+
try {
|
|
84984
|
+
const stats = await handle.stat();
|
|
84985
|
+
if (!stats.isFile() || stats.size > maxBytes) return null;
|
|
84986
|
+
const bytes = await handle.readFile();
|
|
84987
|
+
return bytes.byteLength > maxBytes ? null : bytes;
|
|
84988
|
+
} catch {
|
|
84989
|
+
return null;
|
|
84990
|
+
} finally {
|
|
84991
|
+
await handle.close().catch(() => void 0);
|
|
84992
|
+
}
|
|
84993
|
+
}
|
|
84994
|
+
};
|
|
84995
|
+
}
|
|
84996
|
+
});
|
|
84997
|
+
|
|
84764
84998
|
// packages/daemon/src/command-center/pane-stream-issue.ts
|
|
84765
84999
|
function issueError(code2, reason, retryable = false) {
|
|
84766
85000
|
return PaneStreamIssueResultSchemaZ.parse({
|
|
@@ -85019,6 +85253,7 @@ function failure(c, error) {
|
|
|
85019
85253
|
}
|
|
85020
85254
|
function mountTmuxServerRoutes(app, options) {
|
|
85021
85255
|
const base2 = TMUX_SERVERS_API_PATH;
|
|
85256
|
+
const resolveSessionFavicon = options.resolveSessionFavicon ?? createSessionFaviconResolver();
|
|
85022
85257
|
const authorize = async (c, next) => {
|
|
85023
85258
|
c.header("Cache-Control", "no-store");
|
|
85024
85259
|
if (!ownerBearerMatches(c.req.header("Authorization"), options.ownerToken))
|
|
@@ -85191,19 +85426,54 @@ function mountTmuxServerRoutes(app, options) {
|
|
|
85191
85426
|
`${scoped}/sessions`,
|
|
85192
85427
|
route(async (c) => {
|
|
85193
85428
|
const server = scope2(c);
|
|
85429
|
+
const v2 = c.req.query("version") === "2";
|
|
85430
|
+
const { rows, favicons } = await options.owners.withOwner(server, async (owner) => {
|
|
85431
|
+
const sessions = await owner.catalog();
|
|
85432
|
+
const workspaces = owner.workspaceRegistry.list();
|
|
85433
|
+
const rows2 = sessions.map((session) => {
|
|
85434
|
+
const aliases = workspaces.filter(
|
|
85435
|
+
(workspace) => workspace.sessionName === session.sessionName
|
|
85436
|
+
);
|
|
85437
|
+
return { session, workspaceName: aliases.length === 1 ? aliases[0].name : null };
|
|
85438
|
+
});
|
|
85439
|
+
const favicons2 = v2 ? await Promise.all(
|
|
85440
|
+
sessions.map(
|
|
85441
|
+
(session) => resolveSessionFavicon(session.sessionPath).catch(() => null)
|
|
85442
|
+
)
|
|
85443
|
+
) : [];
|
|
85444
|
+
return { rows: rows2, favicons: favicons2 };
|
|
85445
|
+
});
|
|
85446
|
+
if (!v2)
|
|
85447
|
+
return c.json(
|
|
85448
|
+
TmuxServerSessionsResourceSchemaZ.parse({
|
|
85449
|
+
version: 1,
|
|
85450
|
+
server,
|
|
85451
|
+
sessions: rows.map(({ session, workspaceName }) => ({
|
|
85452
|
+
liveSessionId: session.liveSessionId,
|
|
85453
|
+
sessionName: session.sessionName,
|
|
85454
|
+
paneCount: session.paneCount,
|
|
85455
|
+
workspaceName
|
|
85456
|
+
}))
|
|
85457
|
+
})
|
|
85458
|
+
);
|
|
85459
|
+
let budget2 = SESSIONS_RESOURCE_FAVICON_BUDGET_BYTES;
|
|
85194
85460
|
return c.json(
|
|
85195
|
-
|
|
85196
|
-
version:
|
|
85461
|
+
TmuxServerSessionsResourceV2SchemaZ.parse({
|
|
85462
|
+
version: 2,
|
|
85197
85463
|
server,
|
|
85198
|
-
sessions:
|
|
85199
|
-
const
|
|
85200
|
-
const
|
|
85201
|
-
|
|
85202
|
-
|
|
85203
|
-
|
|
85204
|
-
|
|
85205
|
-
|
|
85206
|
-
|
|
85464
|
+
sessions: rows.map(({ session, workspaceName }, index) => {
|
|
85465
|
+
const found = favicons[index] ?? null;
|
|
85466
|
+
const favicon = found && found.size <= budget2 ? found : null;
|
|
85467
|
+
if (favicon) budget2 -= favicon.size;
|
|
85468
|
+
return {
|
|
85469
|
+
liveSessionId: session.liveSessionId,
|
|
85470
|
+
sessionName: session.sessionName,
|
|
85471
|
+
workspaceName,
|
|
85472
|
+
paneCount: session.paneCount,
|
|
85473
|
+
windowCount: session.windowCount,
|
|
85474
|
+
lastActivity: session.lastActivity,
|
|
85475
|
+
favicon: favicon ? { mime: favicon.mime, data: favicon.data } : null
|
|
85476
|
+
};
|
|
85207
85477
|
})
|
|
85208
85478
|
})
|
|
85209
85479
|
);
|
|
@@ -85469,7 +85739,7 @@ function mountTmuxServerRoutes(app, options) {
|
|
|
85469
85739
|
})
|
|
85470
85740
|
);
|
|
85471
85741
|
}
|
|
85472
|
-
var registrationSchema, workspaceSchema;
|
|
85742
|
+
var SESSIONS_RESOURCE_FAVICON_BUDGET_BYTES, registrationSchema, workspaceSchema;
|
|
85473
85743
|
var init_tmux_servers = __esm({
|
|
85474
85744
|
"packages/daemon/src/command-center/tmux-servers.ts"() {
|
|
85475
85745
|
"use strict";
|
|
@@ -85484,11 +85754,13 @@ var init_tmux_servers = __esm({
|
|
|
85484
85754
|
init_fleet_catalog2();
|
|
85485
85755
|
init_src2();
|
|
85486
85756
|
init_tmux_server_owners();
|
|
85757
|
+
init_session_favicon();
|
|
85487
85758
|
init_workspace_multiplexer_verbs();
|
|
85488
85759
|
init_workspace_pane_creation2();
|
|
85489
85760
|
init_owner_authority();
|
|
85490
85761
|
init_pane_stream_issue();
|
|
85491
85762
|
init_terminal_runtime_inventory2();
|
|
85763
|
+
SESSIONS_RESOURCE_FAVICON_BUDGET_BYTES = 512 * 1024;
|
|
85492
85764
|
registrationSchema = TmuxServerRegistrationSchemaZ.omit({ serverId: true }).strict();
|
|
85493
85765
|
workspaceSchema = z125.string().min(1).max(160).refine((value) => !/[\0\r\n]/u.test(value));
|
|
85494
85766
|
}
|
|
@@ -85665,9 +85937,9 @@ import {
|
|
|
85665
85937
|
writeFileSync as writeFileSync22,
|
|
85666
85938
|
watch
|
|
85667
85939
|
} from "node:fs";
|
|
85668
|
-
import { basename as basename15, dirname as dirname33, join as
|
|
85940
|
+
import { basename as basename15, dirname as dirname33, join as join42 } from "node:path";
|
|
85669
85941
|
function savedMachinesPath() {
|
|
85670
|
-
return runtimeOwnedPath(
|
|
85942
|
+
return runtimeOwnedPath(join42(resolveRuntimeNamespace().registryDir, "machines.json"));
|
|
85671
85943
|
}
|
|
85672
85944
|
function loadSavedMachines(path2 = savedMachinesPath()) {
|
|
85673
85945
|
let fd;
|
|
@@ -85986,9 +86258,9 @@ import {
|
|
|
85986
86258
|
writeFileSync as writeFileSync23
|
|
85987
86259
|
} from "node:fs";
|
|
85988
86260
|
import { randomUUID as randomUUID43 } from "node:crypto";
|
|
85989
|
-
import { dirname as dirname34, join as
|
|
86261
|
+
import { dirname as dirname34, join as join43 } from "node:path";
|
|
85990
86262
|
function fleetClientStatePath() {
|
|
85991
|
-
return runtimeOwnedPath(
|
|
86263
|
+
return runtimeOwnedPath(join43(resolveRuntimeNamespace().registryDir, "fleet-view.json"));
|
|
85992
86264
|
}
|
|
85993
86265
|
function loadFleetClientState(path2 = fleetClientStatePath()) {
|
|
85994
86266
|
let fd;
|
|
@@ -86221,14 +86493,14 @@ var init_schemas = __esm({
|
|
|
86221
86493
|
import { createHash as createHash28 } from "node:crypto";
|
|
86222
86494
|
import { realpathSync as realpathSync21 } from "node:fs";
|
|
86223
86495
|
import { existsSync as existsSync28, mkdirSync as mkdirSync27, readFileSync as readFileSync29, renameSync as renameSync17, writeFileSync as writeFileSync24 } from "node:fs";
|
|
86224
|
-
import { dirname as dirname35, join as
|
|
86496
|
+
import { dirname as dirname35, join as join44 } from "node:path";
|
|
86225
86497
|
function path(dir) {
|
|
86226
86498
|
const namespace = resolveRuntimeNamespace();
|
|
86227
86499
|
if (namespace.development) {
|
|
86228
86500
|
const identity4 = createHash28("sha256").update(realpathSync21(dir)).digest("hex");
|
|
86229
|
-
return runtimeOwnedPath(
|
|
86501
|
+
return runtimeOwnedPath(join44(namespace.stateHome, "projects", identity4, "terminals.json"));
|
|
86230
86502
|
}
|
|
86231
|
-
return
|
|
86503
|
+
return join44(dir, TERMINALS_FILE);
|
|
86232
86504
|
}
|
|
86233
86505
|
function ensureDir(dir) {
|
|
86234
86506
|
mkdirSync27(dirname35(path(dir)), { recursive: true });
|
|
@@ -86319,7 +86591,7 @@ __export(auth_service_exports, {
|
|
|
86319
86591
|
});
|
|
86320
86592
|
import * as crypto2 from "node:crypto";
|
|
86321
86593
|
import { readFileSync as readFileSync30, existsSync as existsSync29 } from "node:fs";
|
|
86322
|
-
import { join as
|
|
86594
|
+
import { join as join45 } from "node:path";
|
|
86323
86595
|
import { homedir as homedir5 } from "node:os";
|
|
86324
86596
|
function base64url(buf) {
|
|
86325
86597
|
const b = typeof buf === "string" ? Buffer.from(buf) : buf;
|
|
@@ -86465,7 +86737,7 @@ var init_auth_service = __esm({
|
|
|
86465
86737
|
if (resolveRuntimeNamespace().development) return false;
|
|
86466
86738
|
try {
|
|
86467
86739
|
const home = userId === process.env.USER ? homedir5() : `/home/${userId}`;
|
|
86468
|
-
const authKeysPath =
|
|
86740
|
+
const authKeysPath = join45(home, ".ssh", "authorized_keys");
|
|
86469
86741
|
if (!existsSync29(authKeysPath)) return false;
|
|
86470
86742
|
const authorizedKeys = readFileSync30(authKeysPath, "utf-8");
|
|
86471
86743
|
const parts = publicKey.trim().split(" ");
|
|
@@ -89491,7 +89763,7 @@ var init_inspect = __esm({
|
|
|
89491
89763
|
// packages/daemon/src/lib/filesystem-browser.ts
|
|
89492
89764
|
import { realpathSync as realpathSync22, readdirSync as readdirSync6, statSync as statSync19 } from "node:fs";
|
|
89493
89765
|
import { homedir as homedir6 } from "node:os";
|
|
89494
|
-
import { isAbsolute as
|
|
89766
|
+
import { isAbsolute as isAbsolute25, join as join46, resolve as resolve32, sep as sep11 } from "node:path";
|
|
89495
89767
|
function isUnderRoot(canonical, root) {
|
|
89496
89768
|
if (canonical === root) return true;
|
|
89497
89769
|
const prefix = root.endsWith(sep11) ? root : root + sep11;
|
|
@@ -89735,7 +90007,7 @@ var init_detect = __esm({
|
|
|
89735
90007
|
|
|
89736
90008
|
// packages/daemon/src/lib/project-inspect.ts
|
|
89737
90009
|
import { existsSync as existsSync32 } from "node:fs";
|
|
89738
|
-
import { isAbsolute as
|
|
90010
|
+
import { isAbsolute as isAbsolute26, resolve as resolve34 } from "node:path";
|
|
89739
90011
|
function narrowPackageManager(raw) {
|
|
89740
90012
|
if (!raw) return null;
|
|
89741
90013
|
return KNOWN_PACKAGE_MANAGERS.has(raw) ? raw : null;
|
|
@@ -89746,7 +90018,7 @@ function inferTestCommand(packageManager) {
|
|
|
89746
90018
|
}
|
|
89747
90019
|
async function inspectProject(dir, io = {}) {
|
|
89748
90020
|
const exists = io.exists ?? existsSync32;
|
|
89749
|
-
const absoluteDir =
|
|
90021
|
+
const absoluteDir = isAbsolute26(dir) ? dir : resolve34(dir);
|
|
89750
90022
|
if (!exists(absoluteDir)) {
|
|
89751
90023
|
throw new InspectDirNotFoundError(absoluteDir);
|
|
89752
90024
|
}
|
|
@@ -90606,7 +90878,7 @@ var init_workspace_changes_git = __esm({
|
|
|
90606
90878
|
// packages/daemon/src/command-center/resources/workspace-changes-authority.ts
|
|
90607
90879
|
import { spawnSync } from "node:child_process";
|
|
90608
90880
|
import { readFileSync as readFileSync33, realpathSync as realpathSync24, statSync as statSync20 } from "node:fs";
|
|
90609
|
-
import { basename as basename18, isAbsolute as
|
|
90881
|
+
import { basename as basename18, isAbsolute as isAbsolute27, relative as relative8, resolve as resolvePath2 } from "node:path";
|
|
90610
90882
|
function runGit(args, cwd) {
|
|
90611
90883
|
const result2 = spawnSync("git", args, {
|
|
90612
90884
|
cwd,
|
|
@@ -90650,7 +90922,7 @@ function confineToWorkspace(realRoot, repoRoot, gitPath) {
|
|
|
90650
90922
|
if (gitPath.length === 0 || gitPath.includes("\0")) return null;
|
|
90651
90923
|
const abs = resolvePath2(repoRoot, gitPath);
|
|
90652
90924
|
const rel = relative8(realRoot, abs);
|
|
90653
|
-
if (rel.length === 0 || rel.startsWith("..") ||
|
|
90925
|
+
if (rel.length === 0 || rel.startsWith("..") || isAbsolute27(rel)) return null;
|
|
90654
90926
|
const display = rel.split(/[\\/]+/u).join("/");
|
|
90655
90927
|
return WorkspaceRelativeDisplayPathSchemaZ.safeParse(display).success ? display : null;
|
|
90656
90928
|
}
|
|
@@ -92878,9 +93150,9 @@ import {
|
|
|
92878
93150
|
rmSync as rmSync5,
|
|
92879
93151
|
writeFileSync as writeFileSync25
|
|
92880
93152
|
} from "node:fs";
|
|
92881
|
-
import { join as
|
|
93153
|
+
import { join as join47 } from "node:path";
|
|
92882
93154
|
function assetRoot() {
|
|
92883
|
-
return runtimeOwnedPath(
|
|
93155
|
+
return runtimeOwnedPath(join47(stateHome(), ASSET_DIRECTORY));
|
|
92884
93156
|
}
|
|
92885
93157
|
function ensureAssetRoot() {
|
|
92886
93158
|
const root = assetRoot();
|
|
@@ -92900,8 +93172,8 @@ function safeName2(name) {
|
|
|
92900
93172
|
}
|
|
92901
93173
|
function assetPaths(root, assetId) {
|
|
92902
93174
|
return {
|
|
92903
|
-
data:
|
|
92904
|
-
metadata:
|
|
93175
|
+
data: join47(root, `${assetId}.bin`),
|
|
93176
|
+
metadata: join47(root, `${assetId}.json`)
|
|
92905
93177
|
};
|
|
92906
93178
|
}
|
|
92907
93179
|
function parseMetadata(raw) {
|
|
@@ -92926,7 +93198,7 @@ function parseMetadata(raw) {
|
|
|
92926
93198
|
}
|
|
92927
93199
|
function pruneAssets(root, now = Date.now()) {
|
|
92928
93200
|
const metadataFiles = readdirSync8(root).filter((name) => /^[0-9a-f]{64}\.json$/u.test(name)).map((name) => {
|
|
92929
|
-
const path2 =
|
|
93201
|
+
const path2 = join47(root, name);
|
|
92930
93202
|
try {
|
|
92931
93203
|
const stat3 = lstatSync14(path2);
|
|
92932
93204
|
return stat3.isFile() && !stat3.isSymbolicLink() ? { name, mtimeMs: stat3.mtimeMs } : null;
|
|
@@ -92937,8 +93209,8 @@ function pruneAssets(root, now = Date.now()) {
|
|
|
92937
93209
|
for (const [index, entry] of metadataFiles.entries()) {
|
|
92938
93210
|
if (index < MAX_ASSET_FILES && now - entry.mtimeMs <= WIDGET_ASSET_RETENTION_MS) continue;
|
|
92939
93211
|
const assetId = entry.name.slice(0, -".json".length);
|
|
92940
|
-
rmSync5(
|
|
92941
|
-
rmSync5(
|
|
93212
|
+
rmSync5(join47(root, `${assetId}.json`), { force: true });
|
|
93213
|
+
rmSync5(join47(root, `${assetId}.bin`), { force: true });
|
|
92942
93214
|
}
|
|
92943
93215
|
}
|
|
92944
93216
|
function publishWidgetAsset(bytes, options) {
|
|
@@ -92967,11 +93239,11 @@ function publishWidgetAsset(bytes, options) {
|
|
|
92967
93239
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
92968
93240
|
};
|
|
92969
93241
|
if (!existsSync33(paths.data)) {
|
|
92970
|
-
const temporary =
|
|
93242
|
+
const temporary = join47(root, `.${assetId}.${randomUUID45()}.bin`);
|
|
92971
93243
|
writeFileSync25(temporary, bytes, { mode: 384, flag: "wx" });
|
|
92972
93244
|
renameSync18(temporary, paths.data);
|
|
92973
93245
|
}
|
|
92974
|
-
const metadataTemporary =
|
|
93246
|
+
const metadataTemporary = join47(root, `.${assetId}.${randomUUID45()}.json`);
|
|
92975
93247
|
writeFileSync25(metadataTemporary, `${JSON.stringify(metadata)}
|
|
92976
93248
|
`, { mode: 384, flag: "wx" });
|
|
92977
93249
|
renameSync18(metadataTemporary, paths.metadata);
|
|
@@ -93033,7 +93305,7 @@ __export(server_exports2, {
|
|
|
93033
93305
|
import { execFile as execFile14 } from "node:child_process";
|
|
93034
93306
|
import { promisify as promisify4 } from "node:util";
|
|
93035
93307
|
import { existsSync as existsSync34, readdirSync as readdirSync9 } from "node:fs";
|
|
93036
|
-
import { join as
|
|
93308
|
+
import { join as join48, dirname as dirname38, basename as basename19 } from "node:path";
|
|
93037
93309
|
import { fileURLToPath as fileURLToPath10 } from "node:url";
|
|
93038
93310
|
import { Hono as Hono3 } from "hono";
|
|
93039
93311
|
import { streamSSE as streamSSE3 } from "hono/streaming";
|
|
@@ -93042,7 +93314,7 @@ import { zValidator } from "@hono/zod-validator";
|
|
|
93042
93314
|
import { z as z130 } from "zod";
|
|
93043
93315
|
import { realpathSync as realpathSync25 } from "node:fs";
|
|
93044
93316
|
import { homedir as homedir7 } from "node:os";
|
|
93045
|
-
import { isAbsolute as
|
|
93317
|
+
import { isAbsolute as isAbsolute28, resolve as pathResolve } from "node:path";
|
|
93046
93318
|
import { randomUUID as randomUUID46 } from "node:crypto";
|
|
93047
93319
|
import { WebSocketServer as WebSocketServer4 } from "ws";
|
|
93048
93320
|
function bearerToken(authHeader) {
|
|
@@ -93148,7 +93420,7 @@ function sandboxResolveDir(rawDir) {
|
|
|
93148
93420
|
} else if (candidate.startsWith("~/")) {
|
|
93149
93421
|
candidate = `${home.replace(/\/+$/, "")}/${candidate.slice(2)}`;
|
|
93150
93422
|
}
|
|
93151
|
-
if (!
|
|
93423
|
+
if (!isAbsolute28(candidate)) {
|
|
93152
93424
|
return { error: "invalid-path", message: "Path must be absolute", status: 400 };
|
|
93153
93425
|
}
|
|
93154
93426
|
const resolved2 = pathResolve(candidate);
|
|
@@ -94285,7 +94557,7 @@ function listAvailableTemplates() {
|
|
|
94285
94557
|
const __filename = fileURLToPath10(import.meta.url);
|
|
94286
94558
|
const __dir = dirname38(__filename);
|
|
94287
94559
|
const configuredTemplatesDir = process.env.TMUX_IDE_TEMPLATES_DIR;
|
|
94288
|
-
const templatesDir = configuredTemplatesDir &&
|
|
94560
|
+
const templatesDir = configuredTemplatesDir && isAbsolute28(configuredTemplatesDir) ? configuredTemplatesDir : join48(__dir, "..", "..", "..", "..", "templates");
|
|
94289
94561
|
if (!existsSync34(templatesDir)) return [];
|
|
94290
94562
|
const labels = {
|
|
94291
94563
|
default: { label: "Default", description: "Single Claude pane + dev/shell row" },
|
|
@@ -94482,7 +94754,7 @@ var init_types = __esm({
|
|
|
94482
94754
|
});
|
|
94483
94755
|
|
|
94484
94756
|
// packages/daemon/src/lib/daemon-embed.ts
|
|
94485
|
-
import { dirname as dirname39, join as
|
|
94757
|
+
import { dirname as dirname39, join as join49 } from "node:path";
|
|
94486
94758
|
import { execFileSync as execFileSync21 } from "node:child_process";
|
|
94487
94759
|
import { randomBytes as randomBytes9, randomUUID as randomUUID47 } from "node:crypto";
|
|
94488
94760
|
import { createWriteStream } from "node:fs";
|
|
@@ -95158,7 +95430,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
95158
95430
|
execFileSync21(tmuxAuthority.executablePath, ["-V"], { encoding: "utf8", timeout: 3e3 })
|
|
95159
95431
|
);
|
|
95160
95432
|
const readTeamMemberships = createClaudeTeamMembershipReader(
|
|
95161
|
-
|
|
95433
|
+
join49(resolveRuntimeNamespace().claudeDir, "teams")
|
|
95162
95434
|
);
|
|
95163
95435
|
const catalogTmuxRunner = createPinnedWorkspaceTmuxRunner(tmuxAuthority);
|
|
95164
95436
|
const initialTmuxProof = captureTmuxServerProof(catalogTmuxRunner);
|
|
@@ -96825,7 +97097,7 @@ __export(development_owner_exports, {
|
|
|
96825
97097
|
verifyManagedDevelopmentAdmission: () => verifyManagedDevelopmentAdmission
|
|
96826
97098
|
});
|
|
96827
97099
|
import { realpathSync as realpathSync26, writeFileSync as writeFileSync26 } from "node:fs";
|
|
96828
|
-
import { join as
|
|
97100
|
+
import { join as join50 } from "node:path";
|
|
96829
97101
|
async function claimManagedDevelopmentLaunch(instance, attempt) {
|
|
96830
97102
|
if (!/^[a-f0-9-]{36}$/u.test(attempt)) throw new Error("Invalid development launch attempt");
|
|
96831
97103
|
const owner = readDevelopmentOwner(instance);
|
|
@@ -96833,7 +97105,7 @@ async function claimManagedDevelopmentLaunch(instance, attempt) {
|
|
|
96833
97105
|
throw new Error("A live or unknown managed owner is protected");
|
|
96834
97106
|
requireDevelopmentNotSuspended(instance);
|
|
96835
97107
|
writeFileSync26(
|
|
96836
|
-
|
|
97108
|
+
join50(instance.root, `launch-${attempt}.json`),
|
|
96837
97109
|
JSON.stringify({ version: 1, attempt, pid: process.pid }),
|
|
96838
97110
|
{ flag: "wx", mode: 384 }
|
|
96839
97111
|
);
|
|
@@ -96842,7 +97114,7 @@ async function claimManagedDevelopmentLaunch(instance, attempt) {
|
|
|
96842
97114
|
function verifyManagedDevelopmentAdmission(instance, attempt, expected) {
|
|
96843
97115
|
requireDevelopmentNotSuspended(instance);
|
|
96844
97116
|
const current = readPrivateDevelopmentRecord(
|
|
96845
|
-
|
|
97117
|
+
join50(instance.root, "startup.json")
|
|
96846
97118
|
);
|
|
96847
97119
|
if (!current || current.attempt !== attempt || current.attempt !== expected.attempt || current.generation !== expected.generation || current.manifestHash !== expected.manifestHash)
|
|
96848
97120
|
throw new Error("Managed owner admission changed before startup");
|
|
@@ -96853,7 +97125,7 @@ async function runManagedDevelopmentOwner() {
|
|
|
96853
97125
|
if (!instance) throw new Error("Managed development owner requires a development namespace");
|
|
96854
97126
|
const identity4 = await readDevelopmentIdentity(instance);
|
|
96855
97127
|
const attempt = process.env.TMUX_IDE_DEVELOPMENT_ATTEMPT;
|
|
96856
|
-
const pending = readPrivateDevelopmentRecord(
|
|
97128
|
+
const pending = readPrivateDevelopmentRecord(join50(instance.root, "startup.json"));
|
|
96857
97129
|
const build = readDevelopmentBuild(instance);
|
|
96858
97130
|
if (!identity4 || identity4.capability !== namespace.cleanupToken || !attempt || pending?.attempt !== attempt || pending.generation !== build.generation || pending.manifestHash !== process.env.TMUX_IDE_DEVELOPMENT_BUILD_HASH)
|
|
96859
97131
|
throw new Error("Development launch admission does not match owner");
|
|
@@ -96863,7 +97135,7 @@ async function runManagedDevelopmentOwner() {
|
|
|
96863
97135
|
if (!incarnation) throw new Error("Cannot establish managed owner incarnation");
|
|
96864
97136
|
await claimManagedDevelopmentLaunch(instance, attempt);
|
|
96865
97137
|
verifyManagedDevelopmentAdmission(instance, attempt, pending);
|
|
96866
|
-
const log = createBoundedDevelopmentLog(
|
|
97138
|
+
const log = createBoundedDevelopmentLog(join50(instance.root, "logs/owner.log"));
|
|
96867
97139
|
const originalOut = process.stdout.write;
|
|
96868
97140
|
const originalErr = process.stderr.write;
|
|
96869
97141
|
const writer = ((chunk, encodingOrCallback, callback) => {
|
|
@@ -96880,7 +97152,7 @@ async function runManagedDevelopmentOwner() {
|
|
|
96880
97152
|
json: true,
|
|
96881
97153
|
expectedVersion: build.packageVersion,
|
|
96882
97154
|
onOwnedReady: () => {
|
|
96883
|
-
writeDevelopmentRecord(
|
|
97155
|
+
writeDevelopmentRecord(join50(instance.root, "owner.json"), {
|
|
96884
97156
|
version: 1,
|
|
96885
97157
|
attempt,
|
|
96886
97158
|
pid: process.pid,
|
|
@@ -96927,7 +97199,7 @@ import {
|
|
|
96927
97199
|
readdirSync as readdirSync10,
|
|
96928
97200
|
copyFileSync as copyFileSync2
|
|
96929
97201
|
} from "node:fs";
|
|
96930
|
-
import { resolve as resolve35, join as
|
|
97202
|
+
import { resolve as resolve35, join as join51, basename as basename20, dirname as dirname40 } from "node:path";
|
|
96931
97203
|
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
96932
97204
|
function copyTemplateSkills(targetDir) {
|
|
96933
97205
|
const created = [];
|
|
@@ -96936,20 +97208,20 @@ function copyTemplateSkills(targetDir) {
|
|
|
96936
97208
|
mkdirSync29(targetDir, { recursive: true });
|
|
96937
97209
|
for (const file of readdirSync10(templateSkillsDir)) {
|
|
96938
97210
|
if (!file.endsWith(".md")) continue;
|
|
96939
|
-
const destination =
|
|
96940
|
-
copyFileSync2(
|
|
97211
|
+
const destination = join51(targetDir, file);
|
|
97212
|
+
copyFileSync2(join51(templateSkillsDir, file), destination);
|
|
96941
97213
|
created.push(destination);
|
|
96942
97214
|
}
|
|
96943
97215
|
return created;
|
|
96944
97216
|
}
|
|
96945
97217
|
function scaffoldLibraryStubs(dir) {
|
|
96946
97218
|
const created = [];
|
|
96947
|
-
const libraryDir =
|
|
97219
|
+
const libraryDir = join51(dir, ".tmux-ide", "library");
|
|
96948
97220
|
if (!existsSync35(libraryDir)) {
|
|
96949
97221
|
mkdirSync29(libraryDir, { recursive: true });
|
|
96950
97222
|
created.push(libraryDir);
|
|
96951
97223
|
}
|
|
96952
|
-
const archPath =
|
|
97224
|
+
const archPath = join51(libraryDir, "architecture.md");
|
|
96953
97225
|
if (!existsSync35(archPath)) {
|
|
96954
97226
|
writeFileSync27(
|
|
96955
97227
|
archPath,
|
|
@@ -96957,7 +97229,7 @@ function scaffoldLibraryStubs(dir) {
|
|
|
96957
97229
|
);
|
|
96958
97230
|
created.push(archPath);
|
|
96959
97231
|
}
|
|
96960
|
-
const learningsPath =
|
|
97232
|
+
const learningsPath = join51(libraryDir, "learnings.md");
|
|
96961
97233
|
if (!existsSync35(learningsPath)) {
|
|
96962
97234
|
writeFileSync27(
|
|
96963
97235
|
learningsPath,
|
|
@@ -96969,11 +97241,11 @@ function scaffoldLibraryStubs(dir) {
|
|
|
96969
97241
|
}
|
|
96970
97242
|
function scaffoldValidationContract(dir) {
|
|
96971
97243
|
const created = [];
|
|
96972
|
-
const tasksDir =
|
|
97244
|
+
const tasksDir = join51(dir, ".tasks");
|
|
96973
97245
|
if (!existsSync35(tasksDir)) {
|
|
96974
97246
|
mkdirSync29(tasksDir, { recursive: true });
|
|
96975
97247
|
}
|
|
96976
|
-
const contractPath =
|
|
97248
|
+
const contractPath = join51(tasksDir, "validation-contract.md");
|
|
96977
97249
|
if (!existsSync35(contractPath)) {
|
|
96978
97250
|
writeFileSync27(
|
|
96979
97251
|
contractPath,
|
|
@@ -96987,7 +97259,7 @@ function scaffoldAgentsMd(dir, name) {
|
|
|
96987
97259
|
const created = [];
|
|
96988
97260
|
const agentsTemplatePath = resolve35(__dirname4, "..", "..", "..", "templates", "AGENTS.md");
|
|
96989
97261
|
if (existsSync35(agentsTemplatePath)) {
|
|
96990
|
-
const agentsPath =
|
|
97262
|
+
const agentsPath = join51(dir, "AGENTS.md");
|
|
96991
97263
|
if (!existsSync35(agentsPath)) {
|
|
96992
97264
|
const content = readFileSync35(agentsTemplatePath, "utf-8").replace(/{{name}}/g, name);
|
|
96993
97265
|
writeFileSync27(agentsPath, content);
|
|
@@ -97008,7 +97280,7 @@ function scaffoldTeamWorkspace(dir, name) {
|
|
|
97008
97280
|
}
|
|
97009
97281
|
function scaffoldMissionsWorkspace(dir, name) {
|
|
97010
97282
|
const created = [];
|
|
97011
|
-
const skillsDir =
|
|
97283
|
+
const skillsDir = join51(dir, ".tmux-ide", "skills");
|
|
97012
97284
|
created.push(...copyTemplateSkills(skillsDir));
|
|
97013
97285
|
created.push(...scaffoldTeamWorkspace(dir, name));
|
|
97014
97286
|
return created;
|
|
@@ -97040,11 +97312,11 @@ async function init({
|
|
|
97040
97312
|
created = scaffoldMissionsWorkspace(dir, name2);
|
|
97041
97313
|
} else if (isTeamTemplate(template)) {
|
|
97042
97314
|
created = [
|
|
97043
|
-
...copyTemplateSkills(
|
|
97315
|
+
...copyTemplateSkills(join51(dir, ".tmux-ide", "skills")),
|
|
97044
97316
|
...scaffoldTeamWorkspace(dir, name2)
|
|
97045
97317
|
];
|
|
97046
97318
|
} else {
|
|
97047
|
-
created = copyTemplateSkills(
|
|
97319
|
+
created = copyTemplateSkills(join51(dir, ".tmux-ide", "skills"));
|
|
97048
97320
|
}
|
|
97049
97321
|
if (json3) {
|
|
97050
97322
|
console.log(JSON.stringify({ created: true, template, name: name2, paths: created }));
|
|
@@ -97086,7 +97358,7 @@ async function init({
|
|
|
97086
97358
|
console.log("Edit it to configure your workspace, then run: tmux-ide");
|
|
97087
97359
|
}
|
|
97088
97360
|
}
|
|
97089
|
-
const skillsDir =
|
|
97361
|
+
const skillsDir = join51(dir, ".tmux-ide", "skills");
|
|
97090
97362
|
if (!existsSync35(skillsDir)) {
|
|
97091
97363
|
const created = copyTemplateSkills(skillsDir);
|
|
97092
97364
|
if (created.length > 0 && !json3) {
|
|
@@ -97141,19 +97413,21 @@ var init_stop = __esm({
|
|
|
97141
97413
|
// packages/daemon/src/open-browser.ts
|
|
97142
97414
|
var open_browser_exports = {};
|
|
97143
97415
|
__export(open_browser_exports, {
|
|
97416
|
+
NO_NATIVE_CONTROLS_NOTICE: () => NO_NATIVE_CONTROLS_NOTICE,
|
|
97144
97417
|
createBrowserPane: () => createBrowserPane,
|
|
97418
|
+
nativeControlsNotice: () => nativeControlsNotice,
|
|
97145
97419
|
openBrowser: () => openBrowser,
|
|
97146
97420
|
resolveTerminalBrowser: () => resolveTerminalBrowser,
|
|
97147
97421
|
validateBrowserOpen: () => validateBrowserOpen
|
|
97148
97422
|
});
|
|
97149
|
-
import { accessSync as accessSync10, constants as
|
|
97150
|
-
import { delimiter as delimiter4, isAbsolute as
|
|
97423
|
+
import { accessSync as accessSync10, constants as constants17, realpathSync as realpathSync27, statSync as statSync21 } from "node:fs";
|
|
97424
|
+
import { delimiter as delimiter4, isAbsolute as isAbsolute29, join as join52, resolve as resolve37 } from "node:path";
|
|
97151
97425
|
import { homedir as homedir8 } from "node:os";
|
|
97152
97426
|
function resolveTerminalBrowser(environment = process.env, platform2 = process.platform) {
|
|
97153
97427
|
const configured = environment.TMUX_IDE_TERMINAL_BROWSER_BIN;
|
|
97154
97428
|
const home = environment.HOME ?? homedir8();
|
|
97155
|
-
const bundled = platform2 === "darwin" &&
|
|
97156
|
-
|
|
97429
|
+
const bundled = platform2 === "darwin" && isAbsolute29(home) ? [
|
|
97430
|
+
join52(
|
|
97157
97431
|
home,
|
|
97158
97432
|
"Library",
|
|
97159
97433
|
"Application Support",
|
|
@@ -97168,12 +97442,12 @@ function resolveTerminalBrowser(environment = process.env, platform2 = process.p
|
|
|
97168
97442
|
] : [];
|
|
97169
97443
|
const candidates = configured ? [configured] : [
|
|
97170
97444
|
...bundled,
|
|
97171
|
-
...(environment.PATH ?? "").split(delimiter4).filter(
|
|
97445
|
+
...(environment.PATH ?? "").split(delimiter4).filter(isAbsolute29).map((dir) => join52(dir, "terminal-browser"))
|
|
97172
97446
|
];
|
|
97173
97447
|
for (const candidate of candidates) {
|
|
97174
97448
|
try {
|
|
97175
|
-
if (!
|
|
97176
|
-
accessSync10(candidate,
|
|
97449
|
+
if (!isAbsolute29(candidate)) continue;
|
|
97450
|
+
accessSync10(candidate, constants17.X_OK);
|
|
97177
97451
|
const path2 = realpathSync27(candidate);
|
|
97178
97452
|
if (statSync21(path2).isFile()) return path2;
|
|
97179
97453
|
} catch {
|
|
@@ -97218,6 +97492,26 @@ function validateBrowserOpen(url, options) {
|
|
|
97218
97492
|
exitCode: 2
|
|
97219
97493
|
});
|
|
97220
97494
|
}
|
|
97495
|
+
function isBundledBrowser(executable) {
|
|
97496
|
+
return /\/[^/]+\.app\/Contents\/Resources\/browser\//u.test(executable);
|
|
97497
|
+
}
|
|
97498
|
+
async function nativeControlsNotice(run, pane, executable, wait = {}) {
|
|
97499
|
+
if (isBundledBrowser(executable)) return null;
|
|
97500
|
+
const sleep3 = wait.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
97501
|
+
const now = wait.now ?? Date.now;
|
|
97502
|
+
const deadline = now() + STANDALONE_WAIT_MS;
|
|
97503
|
+
for (; ; ) {
|
|
97504
|
+
let control;
|
|
97505
|
+
try {
|
|
97506
|
+
control = run(["display-message", "-p", "-t", pane, "#{@tmux_ide_browser_control}"]).trim();
|
|
97507
|
+
} catch {
|
|
97508
|
+
return null;
|
|
97509
|
+
}
|
|
97510
|
+
if (control) return null;
|
|
97511
|
+
if (now() >= deadline) return NO_NATIVE_CONTROLS_NOTICE;
|
|
97512
|
+
await sleep3(250);
|
|
97513
|
+
}
|
|
97514
|
+
}
|
|
97221
97515
|
function createBrowserPane(run, executable, url, options, environment, cwd, namespace) {
|
|
97222
97516
|
validateBrowserOpen(url, options);
|
|
97223
97517
|
const inheritedPane = /^%\d+$/u.test(environment.TMUX_PANE ?? "") ? environment.TMUX_PANE : void 0;
|
|
@@ -97289,9 +97583,21 @@ function createBrowserPane(run, executable, url, options, environment, cwd, name
|
|
|
97289
97583
|
});
|
|
97290
97584
|
return { pane, session: createdSession, window: createdWindow, status: "created" };
|
|
97291
97585
|
}
|
|
97292
|
-
function openBrowser(url, options = {}) {
|
|
97586
|
+
async function openBrowser(url, options = {}, dependencies = {}) {
|
|
97293
97587
|
validateBrowserOpen(url, options);
|
|
97294
|
-
const executable = resolveTerminalBrowser();
|
|
97588
|
+
const executable = (dependencies.executable ?? resolveTerminalBrowser)();
|
|
97589
|
+
const { result: result2, run } = (dependencies.create ?? createPinnedBrowserPane)(
|
|
97590
|
+
executable,
|
|
97591
|
+
url,
|
|
97592
|
+
options
|
|
97593
|
+
);
|
|
97594
|
+
const message = await nativeControlsNotice(run, result2.pane, executable, dependencies.wait);
|
|
97595
|
+
if (message)
|
|
97596
|
+
(dependencies.notice ?? ((line) => process.stderr.write(`${line}
|
|
97597
|
+
`)))(message);
|
|
97598
|
+
return result2;
|
|
97599
|
+
}
|
|
97600
|
+
function createPinnedBrowserPane(executable, url, options) {
|
|
97295
97601
|
try {
|
|
97296
97602
|
const namespace = { ...runtimeNamespaceEnvironment(resolveRuntimeNamespace()) };
|
|
97297
97603
|
const authority2 = resolveWorkspacePaneTmuxAuthority();
|
|
@@ -97299,7 +97605,16 @@ function openBrowser(url, options = {}) {
|
|
|
97299
97605
|
const run = createPinnedWorkspaceTmuxRunner(authority2, {
|
|
97300
97606
|
timeoutMs: 1e4
|
|
97301
97607
|
});
|
|
97302
|
-
|
|
97608
|
+
const result2 = createBrowserPane(
|
|
97609
|
+
run,
|
|
97610
|
+
executable,
|
|
97611
|
+
url,
|
|
97612
|
+
options,
|
|
97613
|
+
process.env,
|
|
97614
|
+
process.cwd(),
|
|
97615
|
+
namespace
|
|
97616
|
+
);
|
|
97617
|
+
return { result: result2, run };
|
|
97303
97618
|
} catch (error) {
|
|
97304
97619
|
if (error instanceof IdeError) throw error;
|
|
97305
97620
|
throw new IdeError(
|
|
@@ -97311,12 +97626,15 @@ function openBrowser(url, options = {}) {
|
|
|
97311
97626
|
);
|
|
97312
97627
|
}
|
|
97313
97628
|
}
|
|
97629
|
+
var NO_NATIVE_CONTROLS_NOTICE, STANDALONE_WAIT_MS;
|
|
97314
97630
|
var init_open_browser = __esm({
|
|
97315
97631
|
"packages/daemon/src/open-browser.ts"() {
|
|
97316
97632
|
"use strict";
|
|
97317
97633
|
init_errors2();
|
|
97318
97634
|
init_runtime_namespace();
|
|
97319
97635
|
init_workspace_pane_creation2();
|
|
97636
|
+
NO_NATIVE_CONTROLS_NOTICE = "This browser has no tmux-ide controls; install the native app for back/forward/reload.";
|
|
97637
|
+
STANDALONE_WAIT_MS = 2e3;
|
|
97320
97638
|
}
|
|
97321
97639
|
});
|
|
97322
97640
|
|
|
@@ -97475,7 +97793,7 @@ var init_daemon_service_manager = __esm({
|
|
|
97475
97793
|
|
|
97476
97794
|
// packages/daemon/src/lib/daemon-service-plan.ts
|
|
97477
97795
|
import { createHash as createHash34 } from "node:crypto";
|
|
97478
|
-
import { isAbsolute as
|
|
97796
|
+
import { isAbsolute as isAbsolute30, join as join53 } from "node:path";
|
|
97479
97797
|
function safeValue(value, name) {
|
|
97480
97798
|
if (!value || [...value].some((char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127))
|
|
97481
97799
|
throw new TypeError(`${name} must be nonempty and contain no control characters`);
|
|
@@ -97483,7 +97801,7 @@ function safeValue(value, name) {
|
|
|
97483
97801
|
}
|
|
97484
97802
|
function absolute(value, name) {
|
|
97485
97803
|
safeValue(value, name);
|
|
97486
|
-
if (!
|
|
97804
|
+
if (!isAbsolute30(value)) throw new TypeError(`${name} must be an absolute path`);
|
|
97487
97805
|
return value;
|
|
97488
97806
|
}
|
|
97489
97807
|
function xml(value) {
|
|
@@ -97507,8 +97825,8 @@ function planDaemonService(options) {
|
|
|
97507
97825
|
const executable = absolute(options.executable, "Stable CLI executable");
|
|
97508
97826
|
const identity4 = createHash34("sha256").update(absolute(namespace.daemonInfoDir, "Daemon state directory")).digest("hex").slice(0, 24);
|
|
97509
97827
|
const supervisionId = `tmux-ide.${identity4}`;
|
|
97510
|
-
const stdoutPath =
|
|
97511
|
-
const stderrPath =
|
|
97828
|
+
const stdoutPath = join53(namespace.daemonInfoDir, "service.stdout.log");
|
|
97829
|
+
const stderrPath = join53(namespace.daemonInfoDir, "service.stderr.log");
|
|
97512
97830
|
const environment = {
|
|
97513
97831
|
HOME: home,
|
|
97514
97832
|
PATH: safeValue(options.path, "Service PATH"),
|
|
@@ -97525,7 +97843,7 @@ function planDaemonService(options) {
|
|
|
97525
97843
|
const shared = {
|
|
97526
97844
|
supervisionId,
|
|
97527
97845
|
executable,
|
|
97528
|
-
recordPath:
|
|
97846
|
+
recordPath: join53(namespace.daemonInfoDir, "service.json"),
|
|
97529
97847
|
stdoutPath,
|
|
97530
97848
|
stderrPath
|
|
97531
97849
|
};
|
|
@@ -97536,7 +97854,7 @@ function planDaemonService(options) {
|
|
|
97536
97854
|
...shared,
|
|
97537
97855
|
manager: "launchd",
|
|
97538
97856
|
target: `gui/${options.uid}/${label4}`,
|
|
97539
|
-
unitPath:
|
|
97857
|
+
unitPath: join53(home, "Library", "LaunchAgents", `${label4}.plist`),
|
|
97540
97858
|
contents: `<?xml version="1.0" encoding="UTF-8"?>
|
|
97541
97859
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
97542
97860
|
<plist version="1.0"><dict>
|
|
@@ -97555,14 +97873,14 @@ function planDaemonService(options) {
|
|
|
97555
97873
|
`
|
|
97556
97874
|
});
|
|
97557
97875
|
}
|
|
97558
|
-
const configHome = absolute(options.configHome ??
|
|
97876
|
+
const configHome = absolute(options.configHome ?? join53(home, ".config"), "Config directory");
|
|
97559
97877
|
const target = `${supervisionId}.service`;
|
|
97560
97878
|
const workingDirectory = `${home.replace(/%/gu, "%%")}/.`;
|
|
97561
97879
|
return Object.freeze({
|
|
97562
97880
|
...shared,
|
|
97563
97881
|
manager: "systemd",
|
|
97564
97882
|
target,
|
|
97565
|
-
unitPath:
|
|
97883
|
+
unitPath: join53(configHome, "systemd", "user", target),
|
|
97566
97884
|
contents: `[Unit]
|
|
97567
97885
|
Description=tmux-ide canonical user daemon
|
|
97568
97886
|
StartLimitIntervalSec=60
|
|
@@ -97600,7 +97918,7 @@ __export(daemon_service_exports, {
|
|
|
97600
97918
|
});
|
|
97601
97919
|
import {
|
|
97602
97920
|
accessSync as accessSync11,
|
|
97603
|
-
constants as
|
|
97921
|
+
constants as constants18,
|
|
97604
97922
|
openSync as openSync11,
|
|
97605
97923
|
closeSync as closeSync11,
|
|
97606
97924
|
fstatSync as fstatSync9,
|
|
@@ -97614,7 +97932,7 @@ import {
|
|
|
97614
97932
|
linkSync as linkSync4
|
|
97615
97933
|
} from "node:fs";
|
|
97616
97934
|
import { randomUUID as randomUUID48 } from "node:crypto";
|
|
97617
|
-
import { dirname as dirname41, join as
|
|
97935
|
+
import { dirname as dirname41, join as join54 } from "node:path";
|
|
97618
97936
|
import { homedir as homedir9 } from "node:os";
|
|
97619
97937
|
import { z as z131 } from "zod";
|
|
97620
97938
|
function defaults() {
|
|
@@ -97634,7 +97952,7 @@ function defaults() {
|
|
|
97634
97952
|
reserve: reserveCanonicalDaemonSupervision,
|
|
97635
97953
|
release: releaseCanonicalDaemonSupervision,
|
|
97636
97954
|
probe: probeCanonicalDaemonIdentity,
|
|
97637
|
-
recordPath:
|
|
97955
|
+
recordPath: join54(dirname41(getCanonicalDaemonInfoPath()), "service.json"),
|
|
97638
97956
|
waitMs: 3e4
|
|
97639
97957
|
};
|
|
97640
97958
|
}
|
|
@@ -97644,7 +97962,7 @@ function refused(message) {
|
|
|
97644
97962
|
function ownedFile(path2) {
|
|
97645
97963
|
let descriptor;
|
|
97646
97964
|
try {
|
|
97647
|
-
descriptor = openSync11(path2,
|
|
97965
|
+
descriptor = openSync11(path2, constants18.O_RDONLY | constants18.O_NOFOLLOW | constants18.O_NONBLOCK);
|
|
97648
97966
|
const stat3 = fstatSync9(descriptor);
|
|
97649
97967
|
if (!stat3.isFile() || stat3.uid !== process.getuid?.() || (stat3.mode & 18) !== 0 || stat3.size > 128 * 1024)
|
|
97650
97968
|
refused(`Service file is not a bounded, user-owned regular file: ${path2}`);
|
|
@@ -97737,7 +98055,7 @@ async function manageDaemonService(action, executable, deps2 = defaults()) {
|
|
|
97737
98055
|
if (record2 && !boundTo(deps2.inspect(), plan.supervisionId) && !(record2.removing && action === "remove" && deps2.inspect().status === "missing"))
|
|
97738
98056
|
refused("Service reservation is missing or belongs to another owner");
|
|
97739
98057
|
if (!record2) {
|
|
97740
|
-
accessSync11(plan.executable,
|
|
98058
|
+
accessSync11(plan.executable, constants18.X_OK);
|
|
97741
98059
|
deps2.reserve(plan.supervisionId);
|
|
97742
98060
|
}
|
|
97743
98061
|
const lock = `${plan.recordPath}.lock`;
|
|
@@ -98353,23 +98671,23 @@ __export(skill_sync_exports, {
|
|
|
98353
98671
|
versionMarker: () => versionMarker
|
|
98354
98672
|
});
|
|
98355
98673
|
import { existsSync as existsSync36, mkdirSync as mkdirSync31, readFileSync as readFileSync37, writeFileSync as writeFileSync29 } from "node:fs";
|
|
98356
|
-
import { dirname as dirname42, join as
|
|
98674
|
+
import { dirname as dirname42, join as join55 } from "node:path";
|
|
98357
98675
|
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
98358
98676
|
function claudeDir() {
|
|
98359
98677
|
return resolveRuntimeNamespace().claudeDir;
|
|
98360
98678
|
}
|
|
98361
98679
|
function skillTargetDir() {
|
|
98362
|
-
return runtimeOwnedPath(
|
|
98680
|
+
return runtimeOwnedPath(join55(claudeDir(), "skills", "tmux-ide"));
|
|
98363
98681
|
}
|
|
98364
98682
|
function skillTargetFile() {
|
|
98365
|
-
return
|
|
98683
|
+
return join55(skillTargetDir(), "SKILL.md");
|
|
98366
98684
|
}
|
|
98367
98685
|
function defaultSkillSource() {
|
|
98368
98686
|
const here = dirname42(fileURLToPath12(import.meta.url));
|
|
98369
98687
|
const candidates = [
|
|
98370
|
-
|
|
98688
|
+
join55(here, "../skill/SKILL.md"),
|
|
98371
98689
|
// bundled bin/cli.js → repo root
|
|
98372
|
-
|
|
98690
|
+
join55(here, "../../../../skill/SKILL.md")
|
|
98373
98691
|
// dev src/lib → repo root
|
|
98374
98692
|
];
|
|
98375
98693
|
return candidates.find((c) => existsSync36(c)) ?? candidates[0];
|
|
@@ -98386,7 +98704,7 @@ function rewriteVersionMarker(content, version) {
|
|
|
98386
98704
|
return content.replace(VERSION_MARKER_RE, versionMarker(version));
|
|
98387
98705
|
}
|
|
98388
98706
|
function installedSkillVersion(dir = skillTargetDir()) {
|
|
98389
|
-
const file =
|
|
98707
|
+
const file = join55(dir, "SKILL.md");
|
|
98390
98708
|
if (!existsSync36(file)) return null;
|
|
98391
98709
|
try {
|
|
98392
98710
|
return parseSkillVersion(readFileSync37(file, "utf-8"));
|
|
@@ -98402,7 +98720,7 @@ function syncSkill({
|
|
|
98402
98720
|
throw new Error("Automatic skill sync is disabled in development instances");
|
|
98403
98721
|
const rendered = rewriteVersionMarker(readFileSync37(source, "utf-8"), version);
|
|
98404
98722
|
const dir = skillTargetDir();
|
|
98405
|
-
const target =
|
|
98723
|
+
const target = join55(dir, "SKILL.md");
|
|
98406
98724
|
const existing = existsSync36(target) ? readFileSync37(target, "utf-8") : null;
|
|
98407
98725
|
if (existing === rendered) {
|
|
98408
98726
|
return { action: "unchanged", path: target, to: version };
|
|
@@ -98435,7 +98753,7 @@ __export(doctor_exports, {
|
|
|
98435
98753
|
workspaceConfigRow: () => workspaceConfigRow
|
|
98436
98754
|
});
|
|
98437
98755
|
import { execSync as execSync3, execFileSync as execFileSync22 } from "node:child_process";
|
|
98438
|
-
import { accessSync as accessSync12, constants as
|
|
98756
|
+
import { accessSync as accessSync12, constants as constants19, existsSync as existsSync37 } from "node:fs";
|
|
98439
98757
|
import { resolve as resolve39, dirname as dirname43 } from "node:path";
|
|
98440
98758
|
import { fileURLToPath as fileURLToPath13 } from "node:url";
|
|
98441
98759
|
function agentIntegrationRows(agents) {
|
|
@@ -98650,7 +98968,7 @@ async function doctor({
|
|
|
98650
98968
|
}
|
|
98651
98969
|
let writable = false;
|
|
98652
98970
|
try {
|
|
98653
|
-
accessSync12(probe,
|
|
98971
|
+
accessSync12(probe, constants19.W_OK);
|
|
98654
98972
|
writable = true;
|
|
98655
98973
|
} catch {
|
|
98656
98974
|
}
|
|
@@ -101212,11 +101530,11 @@ __export(pane_team_exports, {
|
|
|
101212
101530
|
assignPaneTeam: () => assignPaneTeam
|
|
101213
101531
|
});
|
|
101214
101532
|
import { execFileSync as execFileSync25 } from "node:child_process";
|
|
101215
|
-
import { isAbsolute as
|
|
101533
|
+
import { isAbsolute as isAbsolute31 } from "node:path";
|
|
101216
101534
|
function assignPaneTeam(options, run = (args) => execFileSync25("tmux", args, { encoding: "utf8", timeout: 5e3 })) {
|
|
101217
101535
|
if (!/^%\d+$/u.test(options.paneId)) throw new Error("Use an exact pane ID such as %3");
|
|
101218
101536
|
if (options.socketPath && options.socketName) throw new Error("Choose one tmux socket selector");
|
|
101219
|
-
if (options.socketPath && !
|
|
101537
|
+
if (options.socketPath && !isAbsolute31(options.socketPath))
|
|
101220
101538
|
throw new Error("Socket path must be absolute");
|
|
101221
101539
|
if (options.socketName && !/^[a-zA-Z0-9_.-]+$/u.test(options.socketName))
|
|
101222
101540
|
throw new Error("Invalid socket name");
|
|
@@ -101453,9 +101771,9 @@ import {
|
|
|
101453
101771
|
unlinkSync as unlinkSync10,
|
|
101454
101772
|
writeFileSync as writeFileSync30,
|
|
101455
101773
|
accessSync as accessSync13,
|
|
101456
|
-
constants as
|
|
101774
|
+
constants as constants20
|
|
101457
101775
|
} from "node:fs";
|
|
101458
|
-
import { basename as basename21, delimiter as delimiter5, dirname as dirname45, join as
|
|
101776
|
+
import { basename as basename21, delimiter as delimiter5, dirname as dirname45, join as join56 } from "node:path";
|
|
101459
101777
|
function isOptOut(value) {
|
|
101460
101778
|
if (value === false || value === 0) return true;
|
|
101461
101779
|
return typeof value === "string" && /^\s*(0|false|off|no)\s*$/iu.test(value);
|
|
@@ -101503,8 +101821,8 @@ function agentTeamsPaths() {
|
|
|
101503
101821
|
function claudeOnPath2(path2 = process.env.PATH ?? "") {
|
|
101504
101822
|
return path2.split(delimiter5).filter(Boolean).some((dir) => {
|
|
101505
101823
|
try {
|
|
101506
|
-
accessSync13(
|
|
101507
|
-
return statSync23(
|
|
101824
|
+
accessSync13(join56(dir, "claude"), constants20.X_OK);
|
|
101825
|
+
return statSync23(join56(dir, "claude")).isFile();
|
|
101508
101826
|
} catch {
|
|
101509
101827
|
return false;
|
|
101510
101828
|
}
|
|
@@ -101529,7 +101847,7 @@ function existingBackup(settingsPath) {
|
|
|
101529
101847
|
const prefix = `${basename21(settingsPath)}${BACKUP_INFIX}`;
|
|
101530
101848
|
try {
|
|
101531
101849
|
const found = readdirSync11(dir).find((name) => name.startsWith(prefix));
|
|
101532
|
-
return found ?
|
|
101850
|
+
return found ? join56(dir, found) : null;
|
|
101533
101851
|
} catch {
|
|
101534
101852
|
return null;
|
|
101535
101853
|
}
|
|
@@ -101545,7 +101863,7 @@ function writeSettings(path2, settings, exists) {
|
|
|
101545
101863
|
copyFileSync3(path2, backup);
|
|
101546
101864
|
}
|
|
101547
101865
|
}
|
|
101548
|
-
const temporary =
|
|
101866
|
+
const temporary = join56(dirname45(path2), `.${basename21(path2)}.tmux-ide-${process.pid}.tmp`);
|
|
101549
101867
|
try {
|
|
101550
101868
|
writeFileSync30(temporary, `${JSON.stringify(settings, null, 2)}
|
|
101551
101869
|
`, { mode: 384 });
|
|
@@ -101686,7 +102004,7 @@ __export(worktree_exports, {
|
|
|
101686
102004
|
worktreeSessionName: () => worktreeSessionName
|
|
101687
102005
|
});
|
|
101688
102006
|
import { execFileSync as execFileSync26 } from "node:child_process";
|
|
101689
|
-
import { basename as basename22, dirname as dirname46, isAbsolute as
|
|
102007
|
+
import { basename as basename22, dirname as dirname46, isAbsolute as isAbsolute32, join as join57, resolve as resolve43 } from "node:path";
|
|
101690
102008
|
function sanitizeForTmux(part) {
|
|
101691
102009
|
return part.replace(/[.:/\s]+/g, "-");
|
|
101692
102010
|
}
|
|
@@ -101695,11 +102013,11 @@ function worktreeSessionName(project, branch) {
|
|
|
101695
102013
|
}
|
|
101696
102014
|
function defaultWorktreeBaseDir(repoDir) {
|
|
101697
102015
|
const abs = resolve43(repoDir);
|
|
101698
|
-
return
|
|
102016
|
+
return join57(dirname46(abs), `${basename22(abs)}-worktrees`);
|
|
101699
102017
|
}
|
|
101700
102018
|
function worktreePath(repoDir, branch, configuredDir) {
|
|
101701
|
-
const base2 = configuredDir && configuredDir.length > 0 ?
|
|
101702
|
-
return
|
|
102019
|
+
const base2 = configuredDir && configuredDir.length > 0 ? isAbsolute32(configuredDir) ? configuredDir : resolve43(repoDir, configuredDir) : defaultWorktreeBaseDir(repoDir);
|
|
102020
|
+
return join57(base2, branch);
|
|
101703
102021
|
}
|
|
101704
102022
|
function parseWorktreeList(porcelain) {
|
|
101705
102023
|
const entries = [];
|
|
@@ -101834,7 +102152,7 @@ var init_worktree = __esm({
|
|
|
101834
102152
|
|
|
101835
102153
|
// packages/daemon/src/lib/managed-installer-update.ts
|
|
101836
102154
|
import { mkdtempSync, readFileSync as readFileSync40, realpathSync as realpathSync29, rmSync as rmSync7 } from "node:fs";
|
|
101837
|
-
import { dirname as dirname47, join as
|
|
102155
|
+
import { dirname as dirname47, join as join58 } from "node:path";
|
|
101838
102156
|
import { tmpdir } from "node:os";
|
|
101839
102157
|
import { execFileSync as execFileSync27 } from "node:child_process";
|
|
101840
102158
|
function managedInstallerPrefix(cliPath) {
|
|
@@ -101843,16 +102161,16 @@ function managedInstallerPrefix(cliPath) {
|
|
|
101843
102161
|
);
|
|
101844
102162
|
if (!match) return null;
|
|
101845
102163
|
const prefix = match[1] || "/";
|
|
101846
|
-
const root =
|
|
101847
|
-
const release =
|
|
102164
|
+
const root = join58(prefix, "share/tmux-ide");
|
|
102165
|
+
const release = join58(root, "releases", match[2]);
|
|
101848
102166
|
try {
|
|
101849
|
-
if (realpathSync29(
|
|
102167
|
+
if (realpathSync29(join58(root, "current")) !== release) return null;
|
|
101850
102168
|
if (realpathSync29(release) !== release) return null;
|
|
101851
|
-
if (readFileSync40(
|
|
101852
|
-
if (readFileSync40(
|
|
101853
|
-
if (!readFileSync40(
|
|
102169
|
+
if (readFileSync40(join58(root, "installer-v1"), "utf8") !== "1\n") return null;
|
|
102170
|
+
if (readFileSync40(join58(release, ".installer-release-v1"), "utf8") !== "1\n") return null;
|
|
102171
|
+
if (!readFileSync40(join58(prefix, "bin/tmux-ide"), "utf8").split("\n").includes("# tmux-ide universal installer v1"))
|
|
101854
102172
|
return null;
|
|
101855
|
-
if (JSON.parse(readFileSync40(
|
|
102173
|
+
if (JSON.parse(readFileSync40(join58(dirname47(cliPath), "package.json"), "utf8")).name !== "tmux-ide")
|
|
101856
102174
|
return null;
|
|
101857
102175
|
return prefix;
|
|
101858
102176
|
} catch {
|
|
@@ -101860,8 +102178,8 @@ function managedInstallerPrefix(cliPath) {
|
|
|
101860
102178
|
}
|
|
101861
102179
|
}
|
|
101862
102180
|
function runManagedInstallerUpdate(prefix, channel, json3, execute2 = execFileSync27) {
|
|
101863
|
-
const temporary = mkdtempSync(
|
|
101864
|
-
const script =
|
|
102181
|
+
const temporary = mkdtempSync(join58(tmpdir(), "tmux-ide-update-"));
|
|
102182
|
+
const script = join58(temporary, "install.sh");
|
|
101865
102183
|
try {
|
|
101866
102184
|
execute2(
|
|
101867
102185
|
"curl",
|
|
@@ -101904,7 +102222,7 @@ var init_managed_installer_update = __esm({
|
|
|
101904
102222
|
|
|
101905
102223
|
// packages/daemon/src/lib/install-origin.ts
|
|
101906
102224
|
import { existsSync as existsSync39, readFileSync as readFileSync41, realpathSync as realpathSync30 } from "node:fs";
|
|
101907
|
-
import { dirname as dirname48, join as
|
|
102225
|
+
import { dirname as dirname48, join as join59 } from "node:path";
|
|
101908
102226
|
import { fileURLToPath as fileURLToPath14 } from "node:url";
|
|
101909
102227
|
function detectPackageManager(path2) {
|
|
101910
102228
|
if (/\/share\/tmux-ide\/releases\/install-[^/]+\/npm\/lib\/node_modules\/tmux-ide\/bin$/.test(path2))
|
|
@@ -101921,9 +102239,9 @@ function findGitCheckoutRoot(startDir) {
|
|
|
101921
102239
|
let dir = startDir;
|
|
101922
102240
|
for (; ; ) {
|
|
101923
102241
|
if (dir.endsWith("/node_modules")) return null;
|
|
101924
|
-
if (existsSync39(
|
|
102242
|
+
if (existsSync39(join59(dir, ".git"))) {
|
|
101925
102243
|
try {
|
|
101926
|
-
if (JSON.parse(readFileSync41(
|
|
102244
|
+
if (JSON.parse(readFileSync41(join59(dir, "package.json"), "utf8")).name === "tmux-ide")
|
|
101927
102245
|
return dir;
|
|
101928
102246
|
} catch {
|
|
101929
102247
|
}
|
|
@@ -101944,7 +102262,7 @@ function installOrigin(cliDir = dirname48(fileURLToPath14(import.meta.url))) {
|
|
|
101944
102262
|
let detected2 = detectPackageManager(path2);
|
|
101945
102263
|
if (detected2 === "npm" || detected2 === "pnpm" || detected2 === "bun") {
|
|
101946
102264
|
try {
|
|
101947
|
-
if (JSON.parse(readFileSync41(
|
|
102265
|
+
if (JSON.parse(readFileSync41(join59(path2, "../package.json"), "utf8")).name !== "tmux-ide")
|
|
101948
102266
|
detected2 = "unknown";
|
|
101949
102267
|
} catch {
|
|
101950
102268
|
detected2 = "unknown";
|
|
@@ -101970,7 +102288,7 @@ __export(update_exports, {
|
|
|
101970
102288
|
runUpdate: () => runUpdate
|
|
101971
102289
|
});
|
|
101972
102290
|
import { realpathSync as realpathSync31 } from "node:fs";
|
|
101973
|
-
import { dirname as dirname49, join as
|
|
102291
|
+
import { dirname as dirname49, join as join60 } from "node:path";
|
|
101974
102292
|
import { execFileSync as execFileSync28 } from "node:child_process";
|
|
101975
102293
|
function planUpdate(input) {
|
|
101976
102294
|
const current = input.currentVersion ?? getCurrentVersion();
|
|
@@ -102060,7 +102378,7 @@ function runUpdate({ cliDir, dryRun, json: json3 = false }, dependencies = {}) {
|
|
|
102060
102378
|
plan.executable === "bun" ? ["pm", "bin", "-g"] : ["root", "-g"]
|
|
102061
102379
|
).trim();
|
|
102062
102380
|
if (!root.startsWith("/")) throw new Error("invalid manager path");
|
|
102063
|
-
const target = plan.executable === "bun" ? dirname49(realpathSync31(
|
|
102381
|
+
const target = plan.executable === "bun" ? dirname49(realpathSync31(join60(root, "tmux-ide"))) : realpathSync31(join60(root, "tmux-ide", "bin"));
|
|
102064
102382
|
if (target !== source.path) throw new Error("different installation");
|
|
102065
102383
|
} catch {
|
|
102066
102384
|
plan = {
|
|
@@ -102122,9 +102440,9 @@ __export(pane_widget_exports, {
|
|
|
102122
102440
|
paneWidgetId: () => paneWidgetId,
|
|
102123
102441
|
paneWidgetIdForFile: () => paneWidgetIdForFile
|
|
102124
102442
|
});
|
|
102125
|
-
import { basename as basename23, extname } from "node:path";
|
|
102443
|
+
import { basename as basename23, extname as extname2 } from "node:path";
|
|
102126
102444
|
function imageMediaTypeFor(fileName) {
|
|
102127
|
-
return IMAGE_MEDIA_BY_EXTENSION.get(
|
|
102445
|
+
return IMAGE_MEDIA_BY_EXTENSION.get(extname2(fileName).toLowerCase()) ?? null;
|
|
102128
102446
|
}
|
|
102129
102447
|
function buildMarkdownAnnouncement(text2, title) {
|
|
102130
102448
|
if (text2.trim().length === 0) {
|
|
@@ -102190,7 +102508,7 @@ function paneWidgetId(value) {
|
|
|
102190
102508
|
);
|
|
102191
102509
|
}
|
|
102192
102510
|
function paneWidgetIdForFile(fileName) {
|
|
102193
|
-
const extension =
|
|
102511
|
+
const extension = extname2(fileName).toLowerCase();
|
|
102194
102512
|
if ([".md", ".markdown"].includes(extension)) return "markdown";
|
|
102195
102513
|
if (IMAGE_MEDIA_BY_EXTENSION.has(extension)) return "image";
|
|
102196
102514
|
if (extension === ".json") return "card";
|
|
@@ -102337,7 +102655,7 @@ var init_server3 = __esm({
|
|
|
102337
102655
|
init_src();
|
|
102338
102656
|
init_tmux_client_execution();
|
|
102339
102657
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
102340
|
-
import { resolve as resolve44, dirname as dirname50, join as
|
|
102658
|
+
import { resolve as resolve44, dirname as dirname50, join as join61 } from "node:path";
|
|
102341
102659
|
import { execFileSync as execFileSync29 } from "node:child_process";
|
|
102342
102660
|
import { appendFileSync as appendFileSync2, existsSync as existsSync40, mkdirSync as mkdirSync33, writeFileSync as writeFileSync31 } from "node:fs";
|
|
102343
102661
|
import { fileURLToPath as fileURLToPath15 } from "node:url";
|
|
@@ -102678,9 +102996,9 @@ Install bun (https://bun.sh) \u2014 the TUI surfaces run on it. Sources ship wit
|
|
|
102678
102996
|
let automaticDiagnosticLog;
|
|
102679
102997
|
if (surface === "app" && !process.env.TMUX_IDE_TUI_PERF_LOG && !process.env.TMUX_IDE_TUI_LOG) {
|
|
102680
102998
|
try {
|
|
102681
|
-
const logDirectory =
|
|
102999
|
+
const logDirectory = join61(stateHome(), "logs");
|
|
102682
103000
|
mkdirSync33(logDirectory, { recursive: true, mode: 448 });
|
|
102683
|
-
automaticDiagnosticLog =
|
|
103001
|
+
automaticDiagnosticLog = join61(logDirectory, "tui-latest.jsonl");
|
|
102684
103002
|
writeFileSync31(
|
|
102685
103003
|
automaticDiagnosticLog,
|
|
102686
103004
|
`${JSON.stringify({
|
|
@@ -103052,7 +103370,7 @@ try {
|
|
|
103052
103370
|
exitCode: 2
|
|
103053
103371
|
});
|
|
103054
103372
|
const { openBrowser: openBrowser2 } = await Promise.resolve().then(() => (init_open_browser(), open_browser_exports));
|
|
103055
|
-
const result2 = openBrowser2(positionals[1], {
|
|
103373
|
+
const result2 = await openBrowser2(positionals[1], {
|
|
103056
103374
|
session: values.session,
|
|
103057
103375
|
pane: values.pane,
|
|
103058
103376
|
split: values.split,
|