pair-mode 0.2.1 → 0.3.3
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/.claude-plugin/plugin.json +12 -0
- package/.codex-plugin/plugin.json +29 -0
- package/README.md +79 -0
- package/assets/syntax/clojure.yaml +36 -0
- package/assets/syntax/cmake.yaml +41 -0
- package/assets/syntax/crystal.yaml +71 -0
- package/assets/syntax/csharp.yaml +51 -0
- package/assets/syntax/dart.yaml +45 -0
- package/assets/syntax/elm.yaml +38 -0
- package/assets/syntax/erb.yaml +42 -0
- package/assets/syntax/erlang.yaml +45 -0
- package/assets/syntax/fsharp.yaml +48 -0
- package/assets/syntax/graphql.yaml +47 -0
- package/assets/syntax/groovy.yaml +111 -0
- package/assets/syntax/haml.yaml +16 -0
- package/assets/syntax/haskell.yaml +52 -0
- package/assets/syntax/ini.yaml +23 -0
- package/assets/syntax/java.yaml +36 -0
- package/assets/syntax/julia.yaml +56 -0
- package/assets/syntax/kotlin.yaml +65 -0
- package/assets/syntax/makefile.yaml +37 -0
- package/assets/syntax/nginx.yaml +22 -0
- package/assets/syntax/nim.yaml +27 -0
- package/assets/syntax/nix.yaml +32 -0
- package/assets/syntax/objc.yaml +60 -0
- package/assets/syntax/ocaml.yaml +43 -0
- package/assets/syntax/perl.yaml +58 -0
- package/assets/syntax/php.yaml +60 -0
- package/assets/syntax/r.yaml +30 -0
- package/assets/syntax/scala.yaml +32 -0
- package/assets/syntax/svelte.yaml +27 -0
- package/assets/syntax/swift.yaml +102 -0
- package/assets/syntax/vue.yaml +63 -0
- package/assets/syntax/xml.yaml +37 -0
- package/assets/syntax/zig.yaml +52 -0
- package/dist/claude-code.js +461 -149
- package/dist/cli.js +1490 -476
- package/dist/codex.js +461 -149
- package/dist/opencode.js +453 -142
- package/dist/pair-tui.js +172 -26
- package/dist/pi.js +508 -155
- package/hooks/codex.json +17 -0
- package/hooks/hooks.json +16 -0
- package/package.json +8 -3
- package/skills/toggle/SKILL.md +24 -0
package/dist/pi.js
CHANGED
|
@@ -7363,11 +7363,72 @@ var require_dist = __commonJS({
|
|
|
7363
7363
|
// src/core/state/state.ts
|
|
7364
7364
|
import { createHash } from "node:crypto";
|
|
7365
7365
|
import { homedir } from "node:os";
|
|
7366
|
-
import { join, dirname, basename } from "node:path";
|
|
7367
|
-
import { existsSync, realpathSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
|
7366
|
+
import { join as join2, dirname, basename } from "node:path";
|
|
7367
|
+
import { existsSync, realpathSync, mkdirSync, writeFileSync, unlinkSync as unlinkSync2 } from "node:fs";
|
|
7368
|
+
|
|
7369
|
+
// src/helpers/isRecord.ts
|
|
7370
|
+
function isRecord(value) {
|
|
7371
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7372
|
+
}
|
|
7373
|
+
|
|
7374
|
+
// src/helpers/readFileOrEmpty.ts
|
|
7375
|
+
import { readFileSync } from "node:fs";
|
|
7376
|
+
function readFileOrEmpty(path) {
|
|
7377
|
+
try {
|
|
7378
|
+
return readFileSync(path, "utf-8");
|
|
7379
|
+
} catch {
|
|
7380
|
+
return "";
|
|
7381
|
+
}
|
|
7382
|
+
}
|
|
7383
|
+
|
|
7384
|
+
// src/helpers/removeQuietly.ts
|
|
7385
|
+
import { unlinkSync } from "node:fs";
|
|
7386
|
+
function removeQuietly(path) {
|
|
7387
|
+
try {
|
|
7388
|
+
unlinkSync(path);
|
|
7389
|
+
} catch {
|
|
7390
|
+
}
|
|
7391
|
+
}
|
|
7392
|
+
|
|
7393
|
+
// src/helpers/resolvesOnPath.ts
|
|
7394
|
+
import { spawnSync } from "node:child_process";
|
|
7395
|
+
var defaultResolvesOnPath = (command) => {
|
|
7396
|
+
const result = spawnSync("which", [command], { stdio: "ignore" });
|
|
7397
|
+
return result.status === 0;
|
|
7398
|
+
};
|
|
7399
|
+
|
|
7400
|
+
// src/helpers/resultFilePath.ts
|
|
7401
|
+
import { randomBytes } from "node:crypto";
|
|
7402
|
+
import { tmpdir } from "node:os";
|
|
7403
|
+
import { join } from "node:path";
|
|
7404
|
+
var NAME_BYTES = 6;
|
|
7405
|
+
function resultFilePath() {
|
|
7406
|
+
const name = `pair-result-${randomBytes(NAME_BYTES).toString("hex")}.json`;
|
|
7407
|
+
return join(tmpdir(), name);
|
|
7408
|
+
}
|
|
7409
|
+
|
|
7410
|
+
// src/helpers/spawn.ts
|
|
7411
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
7412
|
+
var defaultSpawn = (command, args) => {
|
|
7413
|
+
const result = spawnSync2(command, args, { stdio: ["ignore", "ignore", "pipe"] });
|
|
7414
|
+
const stderr = result.stderr ? result.stderr.toString("utf-8") : result.error?.message ?? "";
|
|
7415
|
+
return { status: result.status, stderr };
|
|
7416
|
+
};
|
|
7417
|
+
|
|
7418
|
+
// src/helpers/splitLines.ts
|
|
7419
|
+
function splitLines(text) {
|
|
7420
|
+
const lines = text.split("\n");
|
|
7421
|
+
const last = lines.at(-1);
|
|
7422
|
+
if (last === "") {
|
|
7423
|
+
lines.pop();
|
|
7424
|
+
}
|
|
7425
|
+
return lines;
|
|
7426
|
+
}
|
|
7427
|
+
|
|
7428
|
+
// src/core/state/state.ts
|
|
7368
7429
|
function stateDir() {
|
|
7369
|
-
const base = process.env["XDG_STATE_HOME"] ||
|
|
7370
|
-
return
|
|
7430
|
+
const base = process.env["XDG_STATE_HOME"] || join2(homedir(), ".local", "state");
|
|
7431
|
+
return join2(base, "pair-mode");
|
|
7371
7432
|
}
|
|
7372
7433
|
function realpathLenient(path) {
|
|
7373
7434
|
try {
|
|
@@ -7377,7 +7438,7 @@ function realpathLenient(path) {
|
|
|
7377
7438
|
if (parent === path) {
|
|
7378
7439
|
return path;
|
|
7379
7440
|
}
|
|
7380
|
-
return
|
|
7441
|
+
return join2(realpathLenient(parent), basename(path));
|
|
7381
7442
|
}
|
|
7382
7443
|
}
|
|
7383
7444
|
var DIGEST_LENGTH = 16;
|
|
@@ -7386,16 +7447,23 @@ function digestFor(directory) {
|
|
|
7386
7447
|
return createHash("sha1").update(real).digest("hex").slice(0, DIGEST_LENGTH);
|
|
7387
7448
|
}
|
|
7388
7449
|
function flagPath(directory) {
|
|
7389
|
-
return
|
|
7450
|
+
return join2(stateDir(), `${digestFor(directory)}.on`);
|
|
7390
7451
|
}
|
|
7391
7452
|
function sessionsDir() {
|
|
7392
|
-
return
|
|
7453
|
+
return join2(stateDir(), "sessions");
|
|
7454
|
+
}
|
|
7455
|
+
var OWNER_ONLY_DIR = 448;
|
|
7456
|
+
var OWNER_ONLY_FILE = 384;
|
|
7457
|
+
function makeSessionsDir() {
|
|
7458
|
+
const path = sessionsDir();
|
|
7459
|
+
mkdirSync(path, { recursive: true, mode: OWNER_ONLY_DIR });
|
|
7460
|
+
return path;
|
|
7393
7461
|
}
|
|
7394
7462
|
function sessionSocketPath(directory) {
|
|
7395
|
-
return
|
|
7463
|
+
return join2(sessionsDir(), `${digestFor(directory)}.sock`);
|
|
7396
7464
|
}
|
|
7397
7465
|
function sessionUrlPath(directory) {
|
|
7398
|
-
return
|
|
7466
|
+
return join2(sessionsDir(), `${digestFor(directory)}.url`);
|
|
7399
7467
|
}
|
|
7400
7468
|
function findSessionSocket(filePath) {
|
|
7401
7469
|
let current = dirname(realpathLenient(filePath));
|
|
@@ -7411,7 +7479,13 @@ function findSessionSocket(filePath) {
|
|
|
7411
7479
|
current = parent;
|
|
7412
7480
|
}
|
|
7413
7481
|
}
|
|
7414
|
-
function
|
|
7482
|
+
function sessionFlagState(key) {
|
|
7483
|
+
if (existsSync(sessionKeyOptOutPath(key))) {
|
|
7484
|
+
return "off";
|
|
7485
|
+
}
|
|
7486
|
+
return existsSync(sessionKeyFlagPath(key)) ? "on" : "unset";
|
|
7487
|
+
}
|
|
7488
|
+
function directoryEnabled(filePath) {
|
|
7415
7489
|
let current = dirname(realpathLenient(filePath));
|
|
7416
7490
|
while (true) {
|
|
7417
7491
|
if (existsSync(flagPath(current))) {
|
|
@@ -7424,6 +7498,29 @@ function isEnabled(filePath) {
|
|
|
7424
7498
|
current = parent;
|
|
7425
7499
|
}
|
|
7426
7500
|
}
|
|
7501
|
+
function isEnabled(filePath, key) {
|
|
7502
|
+
if (key !== void 0) {
|
|
7503
|
+
const state = sessionFlagState(key);
|
|
7504
|
+
if (state !== "unset") {
|
|
7505
|
+
return state === "on";
|
|
7506
|
+
}
|
|
7507
|
+
}
|
|
7508
|
+
return directoryEnabled(filePath);
|
|
7509
|
+
}
|
|
7510
|
+
function enableSession(key) {
|
|
7511
|
+
const path = sessionKeyFlagPath(key);
|
|
7512
|
+
makeSessionsDir();
|
|
7513
|
+
removeQuietly(sessionKeyOptOutPath(key));
|
|
7514
|
+
writeFileSync(path, "", { mode: OWNER_ONLY_FILE });
|
|
7515
|
+
return path;
|
|
7516
|
+
}
|
|
7517
|
+
function optOutSession(key) {
|
|
7518
|
+
const path = sessionKeyOptOutPath(key);
|
|
7519
|
+
makeSessionsDir();
|
|
7520
|
+
removeQuietly(sessionKeyFlagPath(key));
|
|
7521
|
+
writeFileSync(path, "", { mode: OWNER_ONLY_FILE });
|
|
7522
|
+
return path;
|
|
7523
|
+
}
|
|
7427
7524
|
function enable(directory) {
|
|
7428
7525
|
const path = flagPath(directory);
|
|
7429
7526
|
mkdirSync(dirname(path), { recursive: true });
|
|
@@ -7435,13 +7532,34 @@ function disable(directory) {
|
|
|
7435
7532
|
if (!existsSync(path)) {
|
|
7436
7533
|
return false;
|
|
7437
7534
|
}
|
|
7438
|
-
|
|
7535
|
+
unlinkSync2(path);
|
|
7439
7536
|
return true;
|
|
7440
7537
|
}
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
return
|
|
7538
|
+
var SESSION_KEY_LENGTH = 8;
|
|
7539
|
+
function sessionKey(agentSessionId) {
|
|
7540
|
+
const digest = createHash("sha1").update(agentSessionId).digest("hex");
|
|
7541
|
+
return `s-${digest.slice(0, SESSION_KEY_LENGTH)}`;
|
|
7542
|
+
}
|
|
7543
|
+
function watchUrlPath(directory, key) {
|
|
7544
|
+
return key ? sessionKeyUrlPath(key) : sessionUrlPath(directory);
|
|
7545
|
+
}
|
|
7546
|
+
function keyFor(agentSessionId) {
|
|
7547
|
+
return agentSessionId === void 0 || agentSessionId === "" ? void 0 : sessionKey(agentSessionId);
|
|
7548
|
+
}
|
|
7549
|
+
function sessionKeyPath(key, extension) {
|
|
7550
|
+
return join2(sessionsDir(), `${key}${extension}`);
|
|
7551
|
+
}
|
|
7552
|
+
function sessionKeySocketPath(key) {
|
|
7553
|
+
return sessionKeyPath(key, ".sock");
|
|
7554
|
+
}
|
|
7555
|
+
function sessionKeyFlagPath(key) {
|
|
7556
|
+
return sessionKeyPath(key, ".on");
|
|
7557
|
+
}
|
|
7558
|
+
function sessionKeyOptOutPath(key) {
|
|
7559
|
+
return sessionKeyPath(key, ".off");
|
|
7560
|
+
}
|
|
7561
|
+
function sessionKeyUrlPath(key) {
|
|
7562
|
+
return sessionKeyPath(key, ".url");
|
|
7445
7563
|
}
|
|
7446
7564
|
|
|
7447
7565
|
// src/core/simulate/simulate.ts
|
|
@@ -7488,7 +7606,7 @@ function applyEdit(text, edit) {
|
|
|
7488
7606
|
}
|
|
7489
7607
|
return replaceFirst(text, old, next);
|
|
7490
7608
|
}
|
|
7491
|
-
function simulate(tool, input, readFile) {
|
|
7609
|
+
function simulate(tool, input, readFile, sessionId) {
|
|
7492
7610
|
if (!isRecord(input)) {
|
|
7493
7611
|
return null;
|
|
7494
7612
|
}
|
|
@@ -7500,7 +7618,7 @@ function simulate(tool, input, readFile) {
|
|
|
7500
7618
|
const content = input["content"];
|
|
7501
7619
|
const after = typeof content === "string" ? content : "";
|
|
7502
7620
|
const before = readFile(filePath);
|
|
7503
|
-
return { tool, filePath, before, after };
|
|
7621
|
+
return { tool, filePath, before, after, sessionId };
|
|
7504
7622
|
}
|
|
7505
7623
|
if (tool === "Edit" || tool === "MultiEdit") {
|
|
7506
7624
|
const editsRaw = input["edits"];
|
|
@@ -7515,71 +7633,19 @@ function simulate(tool, input, readFile) {
|
|
|
7515
7633
|
if (after === null) {
|
|
7516
7634
|
return null;
|
|
7517
7635
|
}
|
|
7518
|
-
return { tool, filePath, before, after };
|
|
7636
|
+
return { tool, filePath, before, after, sessionId };
|
|
7519
7637
|
}
|
|
7520
7638
|
return null;
|
|
7521
7639
|
}
|
|
7522
7640
|
|
|
7523
7641
|
// src/cli/toggle.ts
|
|
7524
7642
|
import { existsSync as existsSync2, readFileSync as readFileSync2, unlinkSync as unlinkSync3 } from "node:fs";
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
function readFileOrEmpty(path) {
|
|
7529
|
-
try {
|
|
7530
|
-
return readFileSync(path, "utf-8");
|
|
7531
|
-
} catch {
|
|
7532
|
-
return "";
|
|
7533
|
-
}
|
|
7534
|
-
}
|
|
7535
|
-
|
|
7536
|
-
// src/helpers/removeQuietly.ts
|
|
7537
|
-
import { unlinkSync as unlinkSync2 } from "node:fs";
|
|
7538
|
-
function removeQuietly(path) {
|
|
7539
|
-
try {
|
|
7540
|
-
unlinkSync2(path);
|
|
7541
|
-
} catch {
|
|
7542
|
-
}
|
|
7643
|
+
import { join as join3 } from "node:path";
|
|
7644
|
+
function statusProbe(directory) {
|
|
7645
|
+
return join3(directory, ".pair-mode-status-probe");
|
|
7543
7646
|
}
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
import { spawnSync } from "node:child_process";
|
|
7547
|
-
var defaultResolvesOnPath = (command) => {
|
|
7548
|
-
const result = spawnSync("which", [command], { stdio: "ignore" });
|
|
7549
|
-
return result.status === 0;
|
|
7550
|
-
};
|
|
7551
|
-
|
|
7552
|
-
// src/helpers/resultFilePath.ts
|
|
7553
|
-
import { randomBytes } from "node:crypto";
|
|
7554
|
-
import { tmpdir } from "node:os";
|
|
7555
|
-
import { join as join2 } from "node:path";
|
|
7556
|
-
var NAME_BYTES = 6;
|
|
7557
|
-
function resultFilePath() {
|
|
7558
|
-
const name = `pair-result-${randomBytes(NAME_BYTES).toString("hex")}.json`;
|
|
7559
|
-
return join2(tmpdir(), name);
|
|
7560
|
-
}
|
|
7561
|
-
|
|
7562
|
-
// src/helpers/spawn.ts
|
|
7563
|
-
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
7564
|
-
var defaultSpawn = (command, args) => {
|
|
7565
|
-
const result = spawnSync2(command, args, { stdio: ["ignore", "ignore", "pipe"] });
|
|
7566
|
-
const stderr = result.stderr ? result.stderr.toString("utf-8") : result.error?.message ?? "";
|
|
7567
|
-
return { status: result.status, stderr };
|
|
7568
|
-
};
|
|
7569
|
-
|
|
7570
|
-
// src/helpers/splitLines.ts
|
|
7571
|
-
function splitLines(text) {
|
|
7572
|
-
const lines = text.split("\n");
|
|
7573
|
-
const last = lines.at(-1);
|
|
7574
|
-
if (last === "") {
|
|
7575
|
-
lines.pop();
|
|
7576
|
-
}
|
|
7577
|
-
return lines;
|
|
7578
|
-
}
|
|
7579
|
-
|
|
7580
|
-
// src/cli/toggle.ts
|
|
7581
|
-
function readLink(directory) {
|
|
7582
|
-
const path = sessionUrlPath(directory);
|
|
7647
|
+
function readLink(directory, key) {
|
|
7648
|
+
const path = watchUrlPath(directory, key);
|
|
7583
7649
|
if (!existsSync2(path)) {
|
|
7584
7650
|
return null;
|
|
7585
7651
|
}
|
|
@@ -7593,8 +7659,8 @@ function readLink(directory) {
|
|
|
7593
7659
|
}
|
|
7594
7660
|
return null;
|
|
7595
7661
|
}
|
|
7596
|
-
function stopLink(directory) {
|
|
7597
|
-
const link = readLink(directory);
|
|
7662
|
+
function stopLink(directory, key) {
|
|
7663
|
+
const link = readLink(directory, key);
|
|
7598
7664
|
if (link === null) {
|
|
7599
7665
|
return false;
|
|
7600
7666
|
}
|
|
@@ -7603,24 +7669,37 @@ function stopLink(directory) {
|
|
|
7603
7669
|
} catch {
|
|
7604
7670
|
}
|
|
7605
7671
|
try {
|
|
7606
|
-
unlinkSync3(
|
|
7672
|
+
unlinkSync3(watchUrlPath(directory, key));
|
|
7607
7673
|
} catch {
|
|
7608
7674
|
}
|
|
7609
7675
|
return true;
|
|
7610
7676
|
}
|
|
7611
|
-
function
|
|
7612
|
-
|
|
7613
|
-
return `pair mode ON for ${directory}`;
|
|
7677
|
+
function onHeadline(directory, key) {
|
|
7678
|
+
return key ? `pair mode ON \xB7 ${key} \xB7 ${directory}` : `pair mode ON for ${directory}`;
|
|
7614
7679
|
}
|
|
7615
|
-
function
|
|
7680
|
+
function pairOn(directory, key) {
|
|
7681
|
+
if (key) {
|
|
7682
|
+
enableSession(key);
|
|
7683
|
+
} else {
|
|
7684
|
+
enable(directory);
|
|
7685
|
+
}
|
|
7686
|
+
return onHeadline(directory, key);
|
|
7687
|
+
}
|
|
7688
|
+
function pairOff(directory, key) {
|
|
7689
|
+
if (key) {
|
|
7690
|
+
optOutSession(key);
|
|
7691
|
+
const stopped2 = stopLink(directory, key);
|
|
7692
|
+
return stopped2 ? `pair mode OFF \xB7 ${key} (web watcher stopped)` : `pair mode OFF \xB7 ${key}`;
|
|
7693
|
+
}
|
|
7616
7694
|
disable(directory);
|
|
7617
7695
|
const stopped = stopLink(directory);
|
|
7618
7696
|
return stopped ? `pair mode OFF for ${directory} (web watcher stopped)` : `pair mode OFF for ${directory}`;
|
|
7619
7697
|
}
|
|
7620
|
-
function pairStatus(directory) {
|
|
7621
|
-
const on =
|
|
7622
|
-
const link = readLink(directory);
|
|
7623
|
-
const
|
|
7698
|
+
function pairStatus(directory, key) {
|
|
7699
|
+
const on = isEnabled(statusProbe(directory), key);
|
|
7700
|
+
const link = readLink(directory, key);
|
|
7701
|
+
const scope = key ? `${key} \xB7 ${directory}` : directory;
|
|
7702
|
+
const state = `pair mode ${on ? "ON" : "OFF"} for ${scope}`;
|
|
7624
7703
|
return link === null ? state : `${state}
|
|
7625
7704
|
${link.url}`;
|
|
7626
7705
|
}
|
|
@@ -8049,7 +8128,7 @@ function parseNoteResult(text) {
|
|
|
8049
8128
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
8050
8129
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, rmSync } from "node:fs";
|
|
8051
8130
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
8052
|
-
import { join as
|
|
8131
|
+
import { join as join9 } from "node:path";
|
|
8053
8132
|
|
|
8054
8133
|
// src/core/render/render.ts
|
|
8055
8134
|
var HEADER_LEAD = [
|
|
@@ -8089,56 +8168,299 @@ function renderInline(input) {
|
|
|
8089
8168
|
// src/editors/micro.ts
|
|
8090
8169
|
var import_yaml = __toESM(require_dist(), 1);
|
|
8091
8170
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
8092
|
-
import { join as
|
|
8171
|
+
import { join as join5 } from "node:path";
|
|
8093
8172
|
|
|
8094
8173
|
// src/editors/languages.ts
|
|
8095
|
-
import {
|
|
8096
|
-
|
|
8174
|
+
import { openSync, readSync, closeSync } from "node:fs";
|
|
8175
|
+
import { basename as basename2, extname } from "node:path";
|
|
8176
|
+
var EXTENSIONS = {
|
|
8097
8177
|
".go": "go",
|
|
8098
8178
|
".rb": "ruby",
|
|
8099
8179
|
".rake": "ruby",
|
|
8180
|
+
".gemspec": "ruby",
|
|
8181
|
+
".ru": "ruby",
|
|
8182
|
+
".erb": "erb",
|
|
8183
|
+
".haml": "haml",
|
|
8100
8184
|
".ts": "typescript",
|
|
8101
|
-
".
|
|
8185
|
+
".mts": "typescript",
|
|
8186
|
+
".cts": "typescript",
|
|
8187
|
+
".tsx": "tsx",
|
|
8102
8188
|
".js": "javascript",
|
|
8103
|
-
".jsx": "javascript",
|
|
8104
8189
|
".mjs": "javascript",
|
|
8105
|
-
".
|
|
8190
|
+
".cjs": "javascript",
|
|
8191
|
+
".jsx": "jsx",
|
|
8192
|
+
".vue": "vue",
|
|
8193
|
+
".svelte": "svelte",
|
|
8194
|
+
".astro": "astro",
|
|
8195
|
+
".py": "python",
|
|
8196
|
+
".pyi": "python",
|
|
8106
8197
|
".ex": "elixir",
|
|
8107
8198
|
".exs": "elixir",
|
|
8199
|
+
".heex": "elixir",
|
|
8200
|
+
".erl": "erlang",
|
|
8201
|
+
".hrl": "erlang",
|
|
8108
8202
|
".rs": "rust",
|
|
8109
|
-
".sh": "
|
|
8110
|
-
".bash": "
|
|
8111
|
-
".
|
|
8203
|
+
".sh": "shellscript",
|
|
8204
|
+
".bash": "shellscript",
|
|
8205
|
+
".ksh": "shellscript",
|
|
8112
8206
|
".zsh": "zsh",
|
|
8207
|
+
".fish": "fish",
|
|
8208
|
+
".ps1": "powershell",
|
|
8209
|
+
".psm1": "powershell",
|
|
8210
|
+
".bat": "bat",
|
|
8211
|
+
".cmd": "bat",
|
|
8113
8212
|
".sql": "sql",
|
|
8114
8213
|
".json": "json",
|
|
8214
|
+
".jsonc": "jsonc",
|
|
8215
|
+
".json5": "json5",
|
|
8115
8216
|
".tf": "terraform",
|
|
8217
|
+
".tfvars": "terraform",
|
|
8218
|
+
".hcl": "hcl",
|
|
8116
8219
|
".proto": "proto",
|
|
8117
|
-
".dockerfile": "
|
|
8220
|
+
".dockerfile": "docker",
|
|
8118
8221
|
".toml": "toml",
|
|
8119
8222
|
".yaml": "yaml",
|
|
8120
8223
|
".yml": "yaml",
|
|
8224
|
+
".ini": "ini",
|
|
8225
|
+
".cfg": "ini",
|
|
8226
|
+
".properties": "properties",
|
|
8227
|
+
".env": "dotenv",
|
|
8121
8228
|
".md": "markdown",
|
|
8229
|
+
".markdown": "markdown",
|
|
8230
|
+
".mdx": "mdx",
|
|
8122
8231
|
".css": "css",
|
|
8232
|
+
".scss": "scss",
|
|
8233
|
+
".sass": "sass",
|
|
8234
|
+
".less": "less",
|
|
8235
|
+
".styl": "stylus",
|
|
8123
8236
|
".html": "html",
|
|
8124
|
-
".
|
|
8237
|
+
".htm": "html",
|
|
8238
|
+
".xml": "xml",
|
|
8239
|
+
".xsl": "xml",
|
|
8240
|
+
".svg": "xml",
|
|
8125
8241
|
".lua": "lua",
|
|
8126
8242
|
".c": "c",
|
|
8127
|
-
".h": "c"
|
|
8243
|
+
".h": "c",
|
|
8244
|
+
".cc": "cpp",
|
|
8245
|
+
".cpp": "cpp",
|
|
8246
|
+
".cxx": "cpp",
|
|
8247
|
+
".hpp": "cpp",
|
|
8248
|
+
".hh": "cpp",
|
|
8249
|
+
".cs": "csharp",
|
|
8250
|
+
".java": "java",
|
|
8251
|
+
".kt": "kotlin",
|
|
8252
|
+
".kts": "kotlin",
|
|
8253
|
+
".swift": "swift",
|
|
8254
|
+
".m": "objective-c",
|
|
8255
|
+
".mm": "objective-c",
|
|
8256
|
+
".php": "php",
|
|
8257
|
+
".pl": "perl",
|
|
8258
|
+
".pm": "perl",
|
|
8259
|
+
".scala": "scala",
|
|
8260
|
+
".sc": "scala",
|
|
8261
|
+
".clj": "clojure",
|
|
8262
|
+
".cljs": "clojure",
|
|
8263
|
+
".cljc": "clojure",
|
|
8264
|
+
".hs": "haskell",
|
|
8265
|
+
".nix": "nix",
|
|
8266
|
+
".r": "r",
|
|
8267
|
+
".jl": "julia",
|
|
8268
|
+
".zig": "zig",
|
|
8269
|
+
".nim": "nim",
|
|
8270
|
+
".dart": "dart",
|
|
8271
|
+
".groovy": "groovy",
|
|
8272
|
+
".gradle": "groovy",
|
|
8273
|
+
".cr": "crystal",
|
|
8274
|
+
".ml": "ocaml",
|
|
8275
|
+
".mli": "ocaml",
|
|
8276
|
+
".fs": "fsharp",
|
|
8277
|
+
".fsx": "fsharp",
|
|
8278
|
+
".elm": "elm",
|
|
8279
|
+
".graphql": "graphql",
|
|
8280
|
+
".gql": "graphql",
|
|
8281
|
+
".prisma": "prisma",
|
|
8282
|
+
".sol": "solidity",
|
|
8283
|
+
".vim": "viml",
|
|
8284
|
+
".diff": "diff",
|
|
8285
|
+
".patch": "diff",
|
|
8286
|
+
".tex": "latex",
|
|
8287
|
+
".wgsl": "wgsl",
|
|
8288
|
+
".glsl": "glsl",
|
|
8289
|
+
".cue": "cue"
|
|
8290
|
+
};
|
|
8291
|
+
var FILENAMES = {
|
|
8292
|
+
gemfile: "ruby",
|
|
8293
|
+
rakefile: "ruby",
|
|
8294
|
+
capfile: "ruby",
|
|
8295
|
+
vagrantfile: "ruby",
|
|
8296
|
+
guardfile: "ruby",
|
|
8297
|
+
podfile: "ruby",
|
|
8298
|
+
fastfile: "ruby",
|
|
8299
|
+
appfile: "ruby",
|
|
8300
|
+
brewfile: "ruby",
|
|
8301
|
+
"config.ru": "ruby",
|
|
8302
|
+
dockerfile: "docker",
|
|
8303
|
+
containerfile: "docker",
|
|
8304
|
+
makefile: "make",
|
|
8305
|
+
gnumakefile: "make",
|
|
8306
|
+
"cmakelists.txt": "cmake",
|
|
8307
|
+
"cargo.lock": "toml",
|
|
8308
|
+
"gemfile.lock": "toml",
|
|
8309
|
+
".babelrc": "json",
|
|
8310
|
+
".eslintrc": "json",
|
|
8311
|
+
".prettierrc": "json",
|
|
8312
|
+
".env": "dotenv",
|
|
8313
|
+
".gitconfig": "ini",
|
|
8314
|
+
".editorconfig": "ini",
|
|
8315
|
+
"nginx.conf": "nginx",
|
|
8316
|
+
"pnpm-workspace.yaml": "yaml"
|
|
8128
8317
|
};
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8318
|
+
var SHEBANGS = [
|
|
8319
|
+
{ pattern: /^#!.*\/(env\s+)?ruby(\s|$)/, id: "ruby" },
|
|
8320
|
+
{ pattern: /^#!.*\/(env\s+)?python[\d.]*(\s|$)/, id: "python" },
|
|
8321
|
+
{ pattern: /^#!.*\/(env\s+)?(node|bun|deno)(\s|$)/, id: "javascript" },
|
|
8322
|
+
{ pattern: /^#!.*\/(env\s+)?(bash|sh|ksh|dash)(\s|$)/, id: "shellscript" },
|
|
8323
|
+
{ pattern: /^#!.*\/(env\s+)?zsh(\s|$)/, id: "zsh" },
|
|
8324
|
+
{ pattern: /^#!.*\/(env\s+)?fish(\s|$)/, id: "fish" },
|
|
8325
|
+
{ pattern: /^#!.*\/(env\s+)?perl(\s|$)/, id: "perl" },
|
|
8326
|
+
{ pattern: /^#!.*\/(env\s+)?php(\s|$)/, id: "php" },
|
|
8327
|
+
{ pattern: /^#!.*\/(env\s+)?(elixir|iex)(\s|$)/, id: "elixir" },
|
|
8328
|
+
{ pattern: /^#!.*\/(env\s+)?lua(\s|$)/, id: "lua" },
|
|
8329
|
+
{ pattern: /^#!.*\/(env\s+)?Rscript(\s|$)/, id: "r" },
|
|
8330
|
+
{ pattern: /^#!.*\/(env\s+)?pwsh(\s|$)/, id: "powershell" }
|
|
8331
|
+
];
|
|
8332
|
+
var FIRST_LINE_BYTES = 256;
|
|
8333
|
+
function firstLine(sourcePath) {
|
|
8334
|
+
let handle = null;
|
|
8335
|
+
try {
|
|
8336
|
+
handle = openSync(sourcePath, "r");
|
|
8337
|
+
const buffer = Buffer.alloc(FIRST_LINE_BYTES);
|
|
8338
|
+
const read = readSync(handle, buffer, 0, FIRST_LINE_BYTES, 0);
|
|
8339
|
+
const text = buffer.toString("utf-8", 0, read);
|
|
8340
|
+
const newline = text.indexOf("\n");
|
|
8341
|
+
return newline === -1 ? text : text.slice(0, newline);
|
|
8342
|
+
} catch {
|
|
8343
|
+
return null;
|
|
8344
|
+
} finally {
|
|
8345
|
+
if (handle !== null) {
|
|
8346
|
+
try {
|
|
8347
|
+
closeSync(handle);
|
|
8348
|
+
} catch {
|
|
8349
|
+
}
|
|
8350
|
+
}
|
|
8351
|
+
}
|
|
8352
|
+
}
|
|
8353
|
+
function shebangLanguage(sourcePath) {
|
|
8354
|
+
const line = firstLine(sourcePath);
|
|
8355
|
+
if (line === null || !line.startsWith("#!")) {
|
|
8356
|
+
return null;
|
|
8357
|
+
}
|
|
8358
|
+
return SHEBANGS.find((rule) => rule.pattern.test(line))?.id ?? null;
|
|
8359
|
+
}
|
|
8360
|
+
function detectLanguage(sourcePath) {
|
|
8361
|
+
const name = basename2(sourcePath).toLowerCase();
|
|
8362
|
+
const ext = extname(name);
|
|
8363
|
+
if (ext !== "" && EXTENSIONS[ext] !== void 0) {
|
|
8364
|
+
return EXTENSIONS[ext];
|
|
8365
|
+
}
|
|
8366
|
+
if (FILENAMES[name] !== void 0) {
|
|
8367
|
+
return FILENAMES[name];
|
|
8368
|
+
}
|
|
8369
|
+
return shebangLanguage(sourcePath);
|
|
8370
|
+
}
|
|
8371
|
+
var MICRO_SYNTAX = {
|
|
8372
|
+
c: "c",
|
|
8373
|
+
clojure: "clojure",
|
|
8374
|
+
cmake: "cmake",
|
|
8375
|
+
crystal: "crystal",
|
|
8376
|
+
csharp: "csharp",
|
|
8377
|
+
css: "css",
|
|
8378
|
+
dart: "dart",
|
|
8379
|
+
docker: "dockerfile",
|
|
8380
|
+
elixir: "elixir",
|
|
8381
|
+
elm: "elm",
|
|
8382
|
+
erb: "erb",
|
|
8383
|
+
erlang: "erlang",
|
|
8384
|
+
fish: "fish",
|
|
8385
|
+
fsharp: "fsharp",
|
|
8386
|
+
go: "go",
|
|
8387
|
+
graphql: "graphql",
|
|
8388
|
+
groovy: "groovy",
|
|
8389
|
+
haml: "haml",
|
|
8390
|
+
haskell: "haskell",
|
|
8391
|
+
html: "html",
|
|
8392
|
+
ini: "ini",
|
|
8393
|
+
java: "java",
|
|
8394
|
+
javascript: "javascript",
|
|
8395
|
+
json: "json",
|
|
8396
|
+
julia: "julia",
|
|
8397
|
+
kotlin: "kotlin",
|
|
8398
|
+
lua: "lua",
|
|
8399
|
+
make: "makefile",
|
|
8400
|
+
markdown: "markdown",
|
|
8401
|
+
nginx: "nginx",
|
|
8402
|
+
nim: "nim",
|
|
8403
|
+
nix: "nix",
|
|
8404
|
+
"objective-c": "objc",
|
|
8405
|
+
ocaml: "ocaml",
|
|
8406
|
+
perl: "perl",
|
|
8407
|
+
php: "php",
|
|
8408
|
+
proto: "proto",
|
|
8409
|
+
python: "python3",
|
|
8410
|
+
r: "r",
|
|
8411
|
+
ruby: "ruby",
|
|
8412
|
+
rust: "rust",
|
|
8413
|
+
scala: "scala",
|
|
8414
|
+
shellscript: "sh",
|
|
8415
|
+
sql: "sql",
|
|
8416
|
+
svelte: "svelte",
|
|
8417
|
+
swift: "swift",
|
|
8418
|
+
terraform: "terraform",
|
|
8419
|
+
toml: "toml",
|
|
8420
|
+
typescript: "typescript",
|
|
8421
|
+
vue: "vue",
|
|
8422
|
+
xml: "xml",
|
|
8423
|
+
yaml: "yaml",
|
|
8424
|
+
zig: "zig",
|
|
8425
|
+
zsh: "zsh"
|
|
8426
|
+
};
|
|
8427
|
+
var VIM_FILETYPES = {
|
|
8428
|
+
shellscript: "sh",
|
|
8429
|
+
docker: "dockerfile",
|
|
8430
|
+
csharp: "cs",
|
|
8431
|
+
"objective-c": "objc",
|
|
8432
|
+
bat: "dosbatch",
|
|
8433
|
+
viml: "vim",
|
|
8434
|
+
mdx: "markdown",
|
|
8435
|
+
jsx: "javascriptreact",
|
|
8436
|
+
tsx: "typescriptreact",
|
|
8437
|
+
dotenv: "sh",
|
|
8438
|
+
properties: "jproperties",
|
|
8439
|
+
stylus: "stylus"
|
|
8440
|
+
};
|
|
8441
|
+
function microSyntaxName(sourcePath) {
|
|
8442
|
+
const id = detectLanguage(sourcePath);
|
|
8443
|
+
if (id === null) {
|
|
8444
|
+
return null;
|
|
8445
|
+
}
|
|
8446
|
+
return MICRO_SYNTAX[id] ?? null;
|
|
8447
|
+
}
|
|
8448
|
+
function vimFiletype(sourcePath) {
|
|
8449
|
+
const id = detectLanguage(sourcePath);
|
|
8450
|
+
if (id === null) {
|
|
8451
|
+
return null;
|
|
8452
|
+
}
|
|
8453
|
+
return VIM_FILETYPES[id] ?? id;
|
|
8132
8454
|
}
|
|
8133
8455
|
|
|
8134
8456
|
// src/editors/syntax-cache.ts
|
|
8135
8457
|
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
8136
|
-
import { dirname as dirname2, join as
|
|
8458
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
8137
8459
|
import { fileURLToPath } from "node:url";
|
|
8138
8460
|
function defaultAssetsDir() {
|
|
8139
8461
|
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
8140
8462
|
while (true) {
|
|
8141
|
-
const candidate =
|
|
8463
|
+
const candidate = join4(dir, "assets", "syntax");
|
|
8142
8464
|
if (existsSync3(candidate)) {
|
|
8143
8465
|
return candidate;
|
|
8144
8466
|
}
|
|
@@ -8153,7 +8475,7 @@ function syntaxSource(lang, assetsDir = defaultAssetsDir()) {
|
|
|
8153
8475
|
if (assetsDir === null) {
|
|
8154
8476
|
return null;
|
|
8155
8477
|
}
|
|
8156
|
-
const path =
|
|
8478
|
+
const path = join4(assetsDir, `${lang}.yaml`);
|
|
8157
8479
|
if (!existsSync3(path)) {
|
|
8158
8480
|
return null;
|
|
8159
8481
|
}
|
|
@@ -8190,7 +8512,7 @@ function bandRules() {
|
|
|
8190
8512
|
];
|
|
8191
8513
|
}
|
|
8192
8514
|
function writeColorScheme(configDir, theme) {
|
|
8193
|
-
const dir =
|
|
8515
|
+
const dir = join5(configDir, "colorschemes");
|
|
8194
8516
|
mkdirSync2(dir, { recursive: true });
|
|
8195
8517
|
const text = `include "monokai"
|
|
8196
8518
|
|
|
@@ -8198,7 +8520,7 @@ color-link pairadd "#d7ffd7,${theme.add}"
|
|
|
8198
8520
|
color-link pairdel "#ffd7d7,${theme.del}"
|
|
8199
8521
|
color-link pairskip "#6a6a6a,${theme.fold}"
|
|
8200
8522
|
`;
|
|
8201
|
-
writeFileSync2(
|
|
8523
|
+
writeFileSync2(join5(dir, "pair.micro"), text, "utf-8");
|
|
8202
8524
|
}
|
|
8203
8525
|
function syntaxText(lang, source) {
|
|
8204
8526
|
const parsed = (0, import_yaml.parse)(source);
|
|
@@ -8214,7 +8536,7 @@ function syntaxText(lang, source) {
|
|
|
8214
8536
|
return (0, import_yaml.stringify)(file, { lineWidth: 0 });
|
|
8215
8537
|
}
|
|
8216
8538
|
function writeSyntax(configDir, sourcePath) {
|
|
8217
|
-
const lang =
|
|
8539
|
+
const lang = microSyntaxName(sourcePath);
|
|
8218
8540
|
if (lang === null) {
|
|
8219
8541
|
return;
|
|
8220
8542
|
}
|
|
@@ -8226,9 +8548,9 @@ function writeSyntax(configDir, sourcePath) {
|
|
|
8226
8548
|
if (text === null) {
|
|
8227
8549
|
return;
|
|
8228
8550
|
}
|
|
8229
|
-
const dir =
|
|
8551
|
+
const dir = join5(configDir, "syntax");
|
|
8230
8552
|
mkdirSync2(dir, { recursive: true });
|
|
8231
|
-
writeFileSync2(
|
|
8553
|
+
writeFileSync2(join5(dir, `pair-${lang}.yaml`), text, "utf-8");
|
|
8232
8554
|
}
|
|
8233
8555
|
function createMicroEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
8234
8556
|
return {
|
|
@@ -8241,7 +8563,7 @@ function createMicroEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8241
8563
|
return ["# F3 moves between panes. Ctrl+W or F2 sends and closes."];
|
|
8242
8564
|
},
|
|
8243
8565
|
bufferSuffix(sourcePath) {
|
|
8244
|
-
const lang =
|
|
8566
|
+
const lang = microSyntaxName(sourcePath);
|
|
8245
8567
|
if (lang === null) {
|
|
8246
8568
|
return ".diff";
|
|
8247
8569
|
}
|
|
@@ -8250,12 +8572,12 @@ function createMicroEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8250
8572
|
prepare(context) {
|
|
8251
8573
|
mkdirSync2(context.configDir, { recursive: true });
|
|
8252
8574
|
writeFileSync2(
|
|
8253
|
-
|
|
8575
|
+
join5(context.configDir, "bindings.json"),
|
|
8254
8576
|
JSON.stringify(MICRO_BINDINGS, null, 2),
|
|
8255
8577
|
"utf-8"
|
|
8256
8578
|
);
|
|
8257
8579
|
writeFileSync2(
|
|
8258
|
-
|
|
8580
|
+
join5(context.configDir, "settings.json"),
|
|
8259
8581
|
JSON.stringify(MICRO_SETTINGS, null, 2),
|
|
8260
8582
|
"utf-8"
|
|
8261
8583
|
);
|
|
@@ -8279,16 +8601,6 @@ function isHexColor(value) {
|
|
|
8279
8601
|
}
|
|
8280
8602
|
|
|
8281
8603
|
// src/editors/vim.ts
|
|
8282
|
-
var VIM_FILETYPE_OVERRIDES = {
|
|
8283
|
-
python3: "python"
|
|
8284
|
-
};
|
|
8285
|
-
function vimFiletype(sourcePath) {
|
|
8286
|
-
const lang = syntaxName(sourcePath);
|
|
8287
|
-
if (lang === null) {
|
|
8288
|
-
return null;
|
|
8289
|
-
}
|
|
8290
|
-
return VIM_FILETYPE_OVERRIDES[lang] ?? lang;
|
|
8291
|
-
}
|
|
8292
8604
|
function safeThemeColor(value) {
|
|
8293
8605
|
if (!isHexColor(value)) {
|
|
8294
8606
|
throw new Error(`invalid theme colour for vim highlight: ${value}`);
|
|
@@ -8343,7 +8655,7 @@ function vimEditor(name, resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8343
8655
|
|
|
8344
8656
|
// src/editors/nano.ts
|
|
8345
8657
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
8346
|
-
import { join as
|
|
8658
|
+
import { join as join6 } from "node:path";
|
|
8347
8659
|
function safeThemeColor2(value) {
|
|
8348
8660
|
if (!isHexColor(value)) {
|
|
8349
8661
|
throw new Error(`invalid theme colour for nano rcfile: ${value}`);
|
|
@@ -8355,7 +8667,7 @@ function writeNanorc(configDir, theme) {
|
|
|
8355
8667
|
color ,${safeThemeColor2(theme.del)} "^\u258C\u258C-"
|
|
8356
8668
|
color ,${safeThemeColor2(theme.fold)} "^\u22EF"
|
|
8357
8669
|
`;
|
|
8358
|
-
const path =
|
|
8670
|
+
const path = join6(configDir, "pair.nanorc");
|
|
8359
8671
|
writeFileSync3(path, text, "utf-8");
|
|
8360
8672
|
return path;
|
|
8361
8673
|
}
|
|
@@ -8385,12 +8697,12 @@ function createNanoEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8385
8697
|
|
|
8386
8698
|
// src/editors/pair.ts
|
|
8387
8699
|
import { existsSync as existsSync5 } from "node:fs";
|
|
8388
|
-
import { dirname as dirname4, extname as extname3, join as
|
|
8700
|
+
import { dirname as dirname4, extname as extname3, join as join8 } from "node:path";
|
|
8389
8701
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
8390
8702
|
|
|
8391
8703
|
// src/core/config/config.ts
|
|
8392
8704
|
import { homedir as homedir2 } from "node:os";
|
|
8393
|
-
import { join as
|
|
8705
|
+
import { join as join7, dirname as dirname3 } from "node:path";
|
|
8394
8706
|
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "node:fs";
|
|
8395
8707
|
var EDITOR_NAMES = ["auto", "pair", "micro", "nvim", "vim", "nano"];
|
|
8396
8708
|
var MULTIPLEXER_NAMES = ["auto", "zellij", "tmux", "none"];
|
|
@@ -8417,8 +8729,8 @@ var DEFAULT_CONFIG = {
|
|
|
8417
8729
|
syntax: true
|
|
8418
8730
|
};
|
|
8419
8731
|
function configPath(homeDir) {
|
|
8420
|
-
const base = process.env["XDG_CONFIG_HOME"] ||
|
|
8421
|
-
return
|
|
8732
|
+
const base = process.env["XDG_CONFIG_HOME"] || join7(homeDir ?? homedir2(), ".config");
|
|
8733
|
+
return join7(base, "pair-mode", "config.json");
|
|
8422
8734
|
}
|
|
8423
8735
|
function isEditorName(value) {
|
|
8424
8736
|
return typeof value === "string" && EDITOR_NAMES.includes(value);
|
|
@@ -8725,7 +9037,7 @@ function paintLayout(layout) {
|
|
|
8725
9037
|
// src/editors/pair.ts
|
|
8726
9038
|
var defaultResolveTuiEntry = () => {
|
|
8727
9039
|
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
8728
|
-
return
|
|
9040
|
+
return join8(here, "pair-tui.js");
|
|
8729
9041
|
};
|
|
8730
9042
|
var defaultCheckBundleExists = existsSync5;
|
|
8731
9043
|
function createPairEditor(resolveTuiEntry = defaultResolveTuiEntry, checkBundleExists = defaultCheckBundleExists) {
|
|
@@ -8891,9 +9203,9 @@ function createTmuxMultiplexer(spawn = defaultSpawn, resolvesOnPath = defaultRes
|
|
|
8891
9203
|
}
|
|
8892
9204
|
|
|
8893
9205
|
// src/multiplexers/tty.ts
|
|
8894
|
-
import { openSync, closeSync } from "node:fs";
|
|
9206
|
+
import { openSync as openSync2, closeSync as closeSync2 } from "node:fs";
|
|
8895
9207
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
8896
|
-
var defaultOpen = () =>
|
|
9208
|
+
var defaultOpen = () => openSync2("/dev/tty", "r+");
|
|
8897
9209
|
var defaultRunner = (command, args, fd) => {
|
|
8898
9210
|
const result = spawnSync3(command, args, { stdio: [fd, fd, fd] });
|
|
8899
9211
|
const detail = result.status === 0 ? "" : String(result.error?.message ?? result.stderr ?? "");
|
|
@@ -8901,7 +9213,7 @@ var defaultRunner = (command, args, fd) => {
|
|
|
8901
9213
|
};
|
|
8902
9214
|
function closeQuietly(fd) {
|
|
8903
9215
|
try {
|
|
8904
|
-
|
|
9216
|
+
closeSync2(fd);
|
|
8905
9217
|
} catch {
|
|
8906
9218
|
}
|
|
8907
9219
|
}
|
|
@@ -8965,7 +9277,7 @@ function splitCommand(value) {
|
|
|
8965
9277
|
}
|
|
8966
9278
|
function tempFile(prefix, suffix, content) {
|
|
8967
9279
|
const name = `${prefix}${randomBytes3(NAME_BYTES2).toString("hex")}${suffix}`;
|
|
8968
|
-
const path =
|
|
9280
|
+
const path = join9(tmpdir2(), name);
|
|
8969
9281
|
writeFileSync5(path, content, "utf-8");
|
|
8970
9282
|
return path;
|
|
8971
9283
|
}
|
|
@@ -8976,7 +9288,7 @@ function removeTreeQuietly(path) {
|
|
|
8976
9288
|
}
|
|
8977
9289
|
}
|
|
8978
9290
|
function reviewConfigDir() {
|
|
8979
|
-
return
|
|
9291
|
+
return join9(stateDir(), "editor", randomBytes3(NAME_BYTES2).toString("hex"));
|
|
8980
9292
|
}
|
|
8981
9293
|
function withEnvPrefix(argv, env) {
|
|
8982
9294
|
const assignments = Object.entries(env).map(([key, value]) => `${key}=${value}`);
|
|
@@ -9056,6 +9368,7 @@ function createPaneTransport(deps = {}) {
|
|
|
9056
9368
|
|
|
9057
9369
|
// src/transports/session/client.ts
|
|
9058
9370
|
import { createConnection } from "node:net";
|
|
9371
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
9059
9372
|
|
|
9060
9373
|
// src/transports/session/wire.ts
|
|
9061
9374
|
var CLIENT_KINDS = ["tui", "web"];
|
|
@@ -9070,11 +9383,11 @@ function createLineReader() {
|
|
|
9070
9383
|
return parts.filter((line) => line.trim() !== "");
|
|
9071
9384
|
};
|
|
9072
9385
|
}
|
|
9073
|
-
function
|
|
9386
|
+
function isString2(value) {
|
|
9074
9387
|
return typeof value === "string";
|
|
9075
9388
|
}
|
|
9076
9389
|
function isClientKind(value) {
|
|
9077
|
-
return
|
|
9390
|
+
return isString2(value) && CLIENT_KINDS.includes(value);
|
|
9078
9391
|
}
|
|
9079
9392
|
function isQuestion(value) {
|
|
9080
9393
|
if (!isRecord(value)) {
|
|
@@ -9082,16 +9395,16 @@ function isQuestion(value) {
|
|
|
9082
9395
|
}
|
|
9083
9396
|
const line = value["line"];
|
|
9084
9397
|
const lineOk = line === null || typeof line === "number";
|
|
9085
|
-
return lineOk &&
|
|
9398
|
+
return lineOk && isString2(value["code"]) && isString2(value["text"]);
|
|
9086
9399
|
}
|
|
9087
9400
|
function isQuestionList(value) {
|
|
9088
9401
|
return Array.isArray(value) && value.every(isQuestion);
|
|
9089
9402
|
}
|
|
9090
9403
|
function toSubmit(raw) {
|
|
9091
|
-
if (!
|
|
9404
|
+
if (!isString2(raw["tool"]) || !isString2(raw["path"])) {
|
|
9092
9405
|
return null;
|
|
9093
9406
|
}
|
|
9094
|
-
if (!
|
|
9407
|
+
if (!isString2(raw["before"]) || !isString2(raw["after"])) {
|
|
9095
9408
|
return null;
|
|
9096
9409
|
}
|
|
9097
9410
|
return {
|
|
@@ -9107,7 +9420,7 @@ function toAttach(raw) {
|
|
|
9107
9420
|
}
|
|
9108
9421
|
function toReview(raw) {
|
|
9109
9422
|
const submit = toSubmit({ ...raw, type: "submit" });
|
|
9110
|
-
if (submit === null || !
|
|
9423
|
+
if (submit === null || !isString2(raw["id"])) {
|
|
9111
9424
|
return null;
|
|
9112
9425
|
}
|
|
9113
9426
|
return {
|
|
@@ -9120,13 +9433,31 @@ function toReview(raw) {
|
|
|
9120
9433
|
};
|
|
9121
9434
|
}
|
|
9122
9435
|
function toVerdict(raw) {
|
|
9123
|
-
if (!
|
|
9436
|
+
if (!isString2(raw["id"]) || !isQuestionList(raw["questions"])) {
|
|
9124
9437
|
return null;
|
|
9125
9438
|
}
|
|
9126
9439
|
return { type: "verdict", id: raw["id"], questions: raw["questions"] };
|
|
9127
9440
|
}
|
|
9128
9441
|
function toCancel(raw) {
|
|
9129
|
-
return
|
|
9442
|
+
return isString2(raw["id"]) ? { type: "cancel", id: raw["id"] } : null;
|
|
9443
|
+
}
|
|
9444
|
+
function isNumber(value) {
|
|
9445
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
9446
|
+
}
|
|
9447
|
+
function toState(raw) {
|
|
9448
|
+
const lastAttachAt = raw["lastAttachAt"];
|
|
9449
|
+
if (lastAttachAt !== null && !isString2(lastAttachAt)) {
|
|
9450
|
+
return null;
|
|
9451
|
+
}
|
|
9452
|
+
if (!isNumber(raw["clientCount"]) || !isNumber(raw["waitingDepth"])) {
|
|
9453
|
+
return null;
|
|
9454
|
+
}
|
|
9455
|
+
return {
|
|
9456
|
+
type: "state",
|
|
9457
|
+
clientCount: raw["clientCount"],
|
|
9458
|
+
waitingDepth: raw["waitingDepth"],
|
|
9459
|
+
lastAttachAt
|
|
9460
|
+
};
|
|
9130
9461
|
}
|
|
9131
9462
|
function decodeLine(line) {
|
|
9132
9463
|
let parsed;
|
|
@@ -9154,11 +9485,18 @@ function decodeLine(line) {
|
|
|
9154
9485
|
if (type === "cancel") {
|
|
9155
9486
|
return toCancel(parsed);
|
|
9156
9487
|
}
|
|
9488
|
+
if (type === "status") {
|
|
9489
|
+
return { type: "status" };
|
|
9490
|
+
}
|
|
9491
|
+
if (type === "state") {
|
|
9492
|
+
return toState(parsed);
|
|
9493
|
+
}
|
|
9157
9494
|
return null;
|
|
9158
9495
|
}
|
|
9159
9496
|
|
|
9160
9497
|
// src/transports/session/client.ts
|
|
9161
9498
|
var MS_PER_SECOND = 1e3;
|
|
9499
|
+
var NO_WATCHER = "no pair-mode watcher attached";
|
|
9162
9500
|
function failOpen(detail) {
|
|
9163
9501
|
return { reviewed: false, detail };
|
|
9164
9502
|
}
|
|
@@ -9191,7 +9529,7 @@ function requestReview(request, options) {
|
|
|
9191
9529
|
let lastError = "";
|
|
9192
9530
|
socket.on("error", (error) => {
|
|
9193
9531
|
if (isConnectionRefused(error)) {
|
|
9194
|
-
settle(failOpen(
|
|
9532
|
+
settle(failOpen(NO_WATCHER));
|
|
9195
9533
|
return;
|
|
9196
9534
|
}
|
|
9197
9535
|
lastError = error instanceof Error ? error.message : String(error);
|
|
@@ -9221,15 +9559,27 @@ function requestReview(request, options) {
|
|
|
9221
9559
|
});
|
|
9222
9560
|
});
|
|
9223
9561
|
}
|
|
9224
|
-
function reviewInSession(request, config, socketPath) {
|
|
9225
|
-
const
|
|
9226
|
-
if (
|
|
9227
|
-
return
|
|
9562
|
+
async function reviewInSession(request, config, socketPath) {
|
|
9563
|
+
const timeoutMs = config.session.timeout * MS_PER_SECOND;
|
|
9564
|
+
if (socketPath !== void 0) {
|
|
9565
|
+
return await requestReview(request, { socketPath, timeoutMs });
|
|
9228
9566
|
}
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9567
|
+
const key = keyFor(request.sessionId);
|
|
9568
|
+
const sessionPath = key === void 0 ? null : sessionKeySocketPath(key);
|
|
9569
|
+
if (sessionPath !== null && existsSync6(sessionPath)) {
|
|
9570
|
+
const outcome = await requestReview(request, { socketPath: sessionPath, timeoutMs });
|
|
9571
|
+
if (outcome.reviewed) {
|
|
9572
|
+
return outcome;
|
|
9573
|
+
}
|
|
9574
|
+
if (outcome.detail !== NO_WATCHER) {
|
|
9575
|
+
return outcome;
|
|
9576
|
+
}
|
|
9577
|
+
}
|
|
9578
|
+
const directoryPath = findSessionSocket(request.filePath);
|
|
9579
|
+
if (directoryPath === null) {
|
|
9580
|
+
return failOpen(NO_WATCHER);
|
|
9581
|
+
}
|
|
9582
|
+
return await requestReview(request, { socketPath: directoryPath, timeoutMs });
|
|
9233
9583
|
}
|
|
9234
9584
|
function createSessionTransport(socketPath) {
|
|
9235
9585
|
return {
|
|
@@ -9250,7 +9600,8 @@ async function runPair(request, config, deps = {}) {
|
|
|
9250
9600
|
if (request.before === request.after) {
|
|
9251
9601
|
return { decision: "allow", reviewed: false };
|
|
9252
9602
|
}
|
|
9253
|
-
|
|
9603
|
+
const key = keyFor(request.sessionId);
|
|
9604
|
+
if (!isEnabled(request.filePath, key)) {
|
|
9254
9605
|
return { decision: "allow", reviewed: false };
|
|
9255
9606
|
}
|
|
9256
9607
|
const transport = deps.transport ?? resolveTransport(config, deps);
|
|
@@ -9308,10 +9659,12 @@ async function handleToolCall(event, runPair2 = runPair) {
|
|
|
9308
9659
|
if (call === null) {
|
|
9309
9660
|
return { block: false };
|
|
9310
9661
|
}
|
|
9311
|
-
|
|
9662
|
+
const sessionId = event.sessionId === "" ? void 0 : event.sessionId;
|
|
9663
|
+
const key = keyFor(sessionId);
|
|
9664
|
+
if (!isEnabled(call.filePath, key)) {
|
|
9312
9665
|
return { block: false };
|
|
9313
9666
|
}
|
|
9314
|
-
const request = simulate(call.tool, call.input, readFileOrEmpty);
|
|
9667
|
+
const request = simulate(call.tool, call.input, readFileOrEmpty, sessionId);
|
|
9315
9668
|
if (request === null) {
|
|
9316
9669
|
return { block: false };
|
|
9317
9670
|
}
|