pair-mode 0.3.0 → 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 +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +66 -9
- 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/package.json +4 -4
- package/skills/toggle/SKILL.md +24 -0
- package/commands/pair.md +0 -18
- package/skills/pair/SKILL.md +0 -20
package/dist/opencode.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,13 +7447,13 @@ 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");
|
|
7393
7454
|
}
|
|
7394
7455
|
function sessionSocketPath(directory) {
|
|
7395
|
-
return
|
|
7456
|
+
return join2(sessionsDir(), `${digestFor(directory)}.sock`);
|
|
7396
7457
|
}
|
|
7397
7458
|
function findSessionSocket(filePath) {
|
|
7398
7459
|
let current = dirname(realpathLenient(filePath));
|
|
@@ -7408,7 +7469,13 @@ function findSessionSocket(filePath) {
|
|
|
7408
7469
|
current = parent;
|
|
7409
7470
|
}
|
|
7410
7471
|
}
|
|
7411
|
-
function
|
|
7472
|
+
function sessionFlagState(key) {
|
|
7473
|
+
if (existsSync(sessionKeyOptOutPath(key))) {
|
|
7474
|
+
return "off";
|
|
7475
|
+
}
|
|
7476
|
+
return existsSync(sessionKeyFlagPath(key)) ? "on" : "unset";
|
|
7477
|
+
}
|
|
7478
|
+
function directoryEnabled(filePath) {
|
|
7412
7479
|
let current = dirname(realpathLenient(filePath));
|
|
7413
7480
|
while (true) {
|
|
7414
7481
|
if (existsSync(flagPath(current))) {
|
|
@@ -7421,10 +7488,34 @@ function isEnabled(filePath) {
|
|
|
7421
7488
|
current = parent;
|
|
7422
7489
|
}
|
|
7423
7490
|
}
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7491
|
+
function isEnabled(filePath, key) {
|
|
7492
|
+
if (key !== void 0) {
|
|
7493
|
+
const state = sessionFlagState(key);
|
|
7494
|
+
if (state !== "unset") {
|
|
7495
|
+
return state === "on";
|
|
7496
|
+
}
|
|
7497
|
+
}
|
|
7498
|
+
return directoryEnabled(filePath);
|
|
7499
|
+
}
|
|
7500
|
+
var SESSION_KEY_LENGTH = 8;
|
|
7501
|
+
function sessionKey(agentSessionId) {
|
|
7502
|
+
const digest = createHash("sha1").update(agentSessionId).digest("hex");
|
|
7503
|
+
return `s-${digest.slice(0, SESSION_KEY_LENGTH)}`;
|
|
7504
|
+
}
|
|
7505
|
+
function keyFor(agentSessionId) {
|
|
7506
|
+
return agentSessionId === void 0 || agentSessionId === "" ? void 0 : sessionKey(agentSessionId);
|
|
7507
|
+
}
|
|
7508
|
+
function sessionKeyPath(key, extension) {
|
|
7509
|
+
return join2(sessionsDir(), `${key}${extension}`);
|
|
7510
|
+
}
|
|
7511
|
+
function sessionKeySocketPath(key) {
|
|
7512
|
+
return sessionKeyPath(key, ".sock");
|
|
7513
|
+
}
|
|
7514
|
+
function sessionKeyFlagPath(key) {
|
|
7515
|
+
return sessionKeyPath(key, ".on");
|
|
7516
|
+
}
|
|
7517
|
+
function sessionKeyOptOutPath(key) {
|
|
7518
|
+
return sessionKeyPath(key, ".off");
|
|
7428
7519
|
}
|
|
7429
7520
|
|
|
7430
7521
|
// src/core/simulate/simulate.ts
|
|
@@ -7471,7 +7562,7 @@ function applyEdit(text, edit) {
|
|
|
7471
7562
|
}
|
|
7472
7563
|
return replaceFirst(text, old, next);
|
|
7473
7564
|
}
|
|
7474
|
-
function simulate(tool, input, readFile) {
|
|
7565
|
+
function simulate(tool, input, readFile, sessionId) {
|
|
7475
7566
|
if (!isRecord(input)) {
|
|
7476
7567
|
return null;
|
|
7477
7568
|
}
|
|
@@ -7483,7 +7574,7 @@ function simulate(tool, input, readFile) {
|
|
|
7483
7574
|
const content = input["content"];
|
|
7484
7575
|
const after = typeof content === "string" ? content : "";
|
|
7485
7576
|
const before = readFile(filePath);
|
|
7486
|
-
return { tool, filePath, before, after };
|
|
7577
|
+
return { tool, filePath, before, after, sessionId };
|
|
7487
7578
|
}
|
|
7488
7579
|
if (tool === "Edit" || tool === "MultiEdit") {
|
|
7489
7580
|
const editsRaw = input["edits"];
|
|
@@ -7498,7 +7589,7 @@ function simulate(tool, input, readFile) {
|
|
|
7498
7589
|
if (after === null) {
|
|
7499
7590
|
return null;
|
|
7500
7591
|
}
|
|
7501
|
-
return { tool, filePath, before, after };
|
|
7592
|
+
return { tool, filePath, before, after, sessionId };
|
|
7502
7593
|
}
|
|
7503
7594
|
return null;
|
|
7504
7595
|
}
|
|
@@ -7929,16 +8020,6 @@ import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, rmSync
|
|
|
7929
8020
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
7930
8021
|
import { join as join8 } from "node:path";
|
|
7931
8022
|
|
|
7932
|
-
// src/helpers/splitLines.ts
|
|
7933
|
-
function splitLines(text) {
|
|
7934
|
-
const lines = text.split("\n");
|
|
7935
|
-
const last = lines.at(-1);
|
|
7936
|
-
if (last === "") {
|
|
7937
|
-
lines.pop();
|
|
7938
|
-
}
|
|
7939
|
-
return lines;
|
|
7940
|
-
}
|
|
7941
|
-
|
|
7942
8023
|
// src/core/render/render.ts
|
|
7943
8024
|
var HEADER_LEAD = [
|
|
7944
8025
|
"# PAIR MODE. Left pane is the current file. Right pane is the proposal.",
|
|
@@ -7977,56 +8058,299 @@ function renderInline(input) {
|
|
|
7977
8058
|
// src/editors/micro.ts
|
|
7978
8059
|
var import_yaml = __toESM(require_dist(), 1);
|
|
7979
8060
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7980
|
-
import { join as
|
|
8061
|
+
import { join as join4 } from "node:path";
|
|
7981
8062
|
|
|
7982
8063
|
// src/editors/languages.ts
|
|
7983
|
-
import {
|
|
7984
|
-
|
|
8064
|
+
import { openSync, readSync, closeSync } from "node:fs";
|
|
8065
|
+
import { basename as basename2, extname } from "node:path";
|
|
8066
|
+
var EXTENSIONS = {
|
|
7985
8067
|
".go": "go",
|
|
7986
8068
|
".rb": "ruby",
|
|
7987
8069
|
".rake": "ruby",
|
|
8070
|
+
".gemspec": "ruby",
|
|
8071
|
+
".ru": "ruby",
|
|
8072
|
+
".erb": "erb",
|
|
8073
|
+
".haml": "haml",
|
|
7988
8074
|
".ts": "typescript",
|
|
7989
|
-
".
|
|
8075
|
+
".mts": "typescript",
|
|
8076
|
+
".cts": "typescript",
|
|
8077
|
+
".tsx": "tsx",
|
|
7990
8078
|
".js": "javascript",
|
|
7991
|
-
".jsx": "javascript",
|
|
7992
8079
|
".mjs": "javascript",
|
|
7993
|
-
".
|
|
8080
|
+
".cjs": "javascript",
|
|
8081
|
+
".jsx": "jsx",
|
|
8082
|
+
".vue": "vue",
|
|
8083
|
+
".svelte": "svelte",
|
|
8084
|
+
".astro": "astro",
|
|
8085
|
+
".py": "python",
|
|
8086
|
+
".pyi": "python",
|
|
7994
8087
|
".ex": "elixir",
|
|
7995
8088
|
".exs": "elixir",
|
|
8089
|
+
".heex": "elixir",
|
|
8090
|
+
".erl": "erlang",
|
|
8091
|
+
".hrl": "erlang",
|
|
7996
8092
|
".rs": "rust",
|
|
7997
|
-
".sh": "
|
|
7998
|
-
".bash": "
|
|
7999
|
-
".
|
|
8093
|
+
".sh": "shellscript",
|
|
8094
|
+
".bash": "shellscript",
|
|
8095
|
+
".ksh": "shellscript",
|
|
8000
8096
|
".zsh": "zsh",
|
|
8097
|
+
".fish": "fish",
|
|
8098
|
+
".ps1": "powershell",
|
|
8099
|
+
".psm1": "powershell",
|
|
8100
|
+
".bat": "bat",
|
|
8101
|
+
".cmd": "bat",
|
|
8001
8102
|
".sql": "sql",
|
|
8002
8103
|
".json": "json",
|
|
8104
|
+
".jsonc": "jsonc",
|
|
8105
|
+
".json5": "json5",
|
|
8003
8106
|
".tf": "terraform",
|
|
8107
|
+
".tfvars": "terraform",
|
|
8108
|
+
".hcl": "hcl",
|
|
8004
8109
|
".proto": "proto",
|
|
8005
|
-
".dockerfile": "
|
|
8110
|
+
".dockerfile": "docker",
|
|
8006
8111
|
".toml": "toml",
|
|
8007
8112
|
".yaml": "yaml",
|
|
8008
8113
|
".yml": "yaml",
|
|
8114
|
+
".ini": "ini",
|
|
8115
|
+
".cfg": "ini",
|
|
8116
|
+
".properties": "properties",
|
|
8117
|
+
".env": "dotenv",
|
|
8009
8118
|
".md": "markdown",
|
|
8119
|
+
".markdown": "markdown",
|
|
8120
|
+
".mdx": "mdx",
|
|
8010
8121
|
".css": "css",
|
|
8122
|
+
".scss": "scss",
|
|
8123
|
+
".sass": "sass",
|
|
8124
|
+
".less": "less",
|
|
8125
|
+
".styl": "stylus",
|
|
8011
8126
|
".html": "html",
|
|
8012
|
-
".
|
|
8127
|
+
".htm": "html",
|
|
8128
|
+
".xml": "xml",
|
|
8129
|
+
".xsl": "xml",
|
|
8130
|
+
".svg": "xml",
|
|
8013
8131
|
".lua": "lua",
|
|
8014
8132
|
".c": "c",
|
|
8015
|
-
".h": "c"
|
|
8133
|
+
".h": "c",
|
|
8134
|
+
".cc": "cpp",
|
|
8135
|
+
".cpp": "cpp",
|
|
8136
|
+
".cxx": "cpp",
|
|
8137
|
+
".hpp": "cpp",
|
|
8138
|
+
".hh": "cpp",
|
|
8139
|
+
".cs": "csharp",
|
|
8140
|
+
".java": "java",
|
|
8141
|
+
".kt": "kotlin",
|
|
8142
|
+
".kts": "kotlin",
|
|
8143
|
+
".swift": "swift",
|
|
8144
|
+
".m": "objective-c",
|
|
8145
|
+
".mm": "objective-c",
|
|
8146
|
+
".php": "php",
|
|
8147
|
+
".pl": "perl",
|
|
8148
|
+
".pm": "perl",
|
|
8149
|
+
".scala": "scala",
|
|
8150
|
+
".sc": "scala",
|
|
8151
|
+
".clj": "clojure",
|
|
8152
|
+
".cljs": "clojure",
|
|
8153
|
+
".cljc": "clojure",
|
|
8154
|
+
".hs": "haskell",
|
|
8155
|
+
".nix": "nix",
|
|
8156
|
+
".r": "r",
|
|
8157
|
+
".jl": "julia",
|
|
8158
|
+
".zig": "zig",
|
|
8159
|
+
".nim": "nim",
|
|
8160
|
+
".dart": "dart",
|
|
8161
|
+
".groovy": "groovy",
|
|
8162
|
+
".gradle": "groovy",
|
|
8163
|
+
".cr": "crystal",
|
|
8164
|
+
".ml": "ocaml",
|
|
8165
|
+
".mli": "ocaml",
|
|
8166
|
+
".fs": "fsharp",
|
|
8167
|
+
".fsx": "fsharp",
|
|
8168
|
+
".elm": "elm",
|
|
8169
|
+
".graphql": "graphql",
|
|
8170
|
+
".gql": "graphql",
|
|
8171
|
+
".prisma": "prisma",
|
|
8172
|
+
".sol": "solidity",
|
|
8173
|
+
".vim": "viml",
|
|
8174
|
+
".diff": "diff",
|
|
8175
|
+
".patch": "diff",
|
|
8176
|
+
".tex": "latex",
|
|
8177
|
+
".wgsl": "wgsl",
|
|
8178
|
+
".glsl": "glsl",
|
|
8179
|
+
".cue": "cue"
|
|
8180
|
+
};
|
|
8181
|
+
var FILENAMES = {
|
|
8182
|
+
gemfile: "ruby",
|
|
8183
|
+
rakefile: "ruby",
|
|
8184
|
+
capfile: "ruby",
|
|
8185
|
+
vagrantfile: "ruby",
|
|
8186
|
+
guardfile: "ruby",
|
|
8187
|
+
podfile: "ruby",
|
|
8188
|
+
fastfile: "ruby",
|
|
8189
|
+
appfile: "ruby",
|
|
8190
|
+
brewfile: "ruby",
|
|
8191
|
+
"config.ru": "ruby",
|
|
8192
|
+
dockerfile: "docker",
|
|
8193
|
+
containerfile: "docker",
|
|
8194
|
+
makefile: "make",
|
|
8195
|
+
gnumakefile: "make",
|
|
8196
|
+
"cmakelists.txt": "cmake",
|
|
8197
|
+
"cargo.lock": "toml",
|
|
8198
|
+
"gemfile.lock": "toml",
|
|
8199
|
+
".babelrc": "json",
|
|
8200
|
+
".eslintrc": "json",
|
|
8201
|
+
".prettierrc": "json",
|
|
8202
|
+
".env": "dotenv",
|
|
8203
|
+
".gitconfig": "ini",
|
|
8204
|
+
".editorconfig": "ini",
|
|
8205
|
+
"nginx.conf": "nginx",
|
|
8206
|
+
"pnpm-workspace.yaml": "yaml"
|
|
8207
|
+
};
|
|
8208
|
+
var SHEBANGS = [
|
|
8209
|
+
{ pattern: /^#!.*\/(env\s+)?ruby(\s|$)/, id: "ruby" },
|
|
8210
|
+
{ pattern: /^#!.*\/(env\s+)?python[\d.]*(\s|$)/, id: "python" },
|
|
8211
|
+
{ pattern: /^#!.*\/(env\s+)?(node|bun|deno)(\s|$)/, id: "javascript" },
|
|
8212
|
+
{ pattern: /^#!.*\/(env\s+)?(bash|sh|ksh|dash)(\s|$)/, id: "shellscript" },
|
|
8213
|
+
{ pattern: /^#!.*\/(env\s+)?zsh(\s|$)/, id: "zsh" },
|
|
8214
|
+
{ pattern: /^#!.*\/(env\s+)?fish(\s|$)/, id: "fish" },
|
|
8215
|
+
{ pattern: /^#!.*\/(env\s+)?perl(\s|$)/, id: "perl" },
|
|
8216
|
+
{ pattern: /^#!.*\/(env\s+)?php(\s|$)/, id: "php" },
|
|
8217
|
+
{ pattern: /^#!.*\/(env\s+)?(elixir|iex)(\s|$)/, id: "elixir" },
|
|
8218
|
+
{ pattern: /^#!.*\/(env\s+)?lua(\s|$)/, id: "lua" },
|
|
8219
|
+
{ pattern: /^#!.*\/(env\s+)?Rscript(\s|$)/, id: "r" },
|
|
8220
|
+
{ pattern: /^#!.*\/(env\s+)?pwsh(\s|$)/, id: "powershell" }
|
|
8221
|
+
];
|
|
8222
|
+
var FIRST_LINE_BYTES = 256;
|
|
8223
|
+
function firstLine(sourcePath) {
|
|
8224
|
+
let handle = null;
|
|
8225
|
+
try {
|
|
8226
|
+
handle = openSync(sourcePath, "r");
|
|
8227
|
+
const buffer = Buffer.alloc(FIRST_LINE_BYTES);
|
|
8228
|
+
const read = readSync(handle, buffer, 0, FIRST_LINE_BYTES, 0);
|
|
8229
|
+
const text = buffer.toString("utf-8", 0, read);
|
|
8230
|
+
const newline = text.indexOf("\n");
|
|
8231
|
+
return newline === -1 ? text : text.slice(0, newline);
|
|
8232
|
+
} catch {
|
|
8233
|
+
return null;
|
|
8234
|
+
} finally {
|
|
8235
|
+
if (handle !== null) {
|
|
8236
|
+
try {
|
|
8237
|
+
closeSync(handle);
|
|
8238
|
+
} catch {
|
|
8239
|
+
}
|
|
8240
|
+
}
|
|
8241
|
+
}
|
|
8242
|
+
}
|
|
8243
|
+
function shebangLanguage(sourcePath) {
|
|
8244
|
+
const line = firstLine(sourcePath);
|
|
8245
|
+
if (line === null || !line.startsWith("#!")) {
|
|
8246
|
+
return null;
|
|
8247
|
+
}
|
|
8248
|
+
return SHEBANGS.find((rule) => rule.pattern.test(line))?.id ?? null;
|
|
8249
|
+
}
|
|
8250
|
+
function detectLanguage(sourcePath) {
|
|
8251
|
+
const name = basename2(sourcePath).toLowerCase();
|
|
8252
|
+
const ext = extname(name);
|
|
8253
|
+
if (ext !== "" && EXTENSIONS[ext] !== void 0) {
|
|
8254
|
+
return EXTENSIONS[ext];
|
|
8255
|
+
}
|
|
8256
|
+
if (FILENAMES[name] !== void 0) {
|
|
8257
|
+
return FILENAMES[name];
|
|
8258
|
+
}
|
|
8259
|
+
return shebangLanguage(sourcePath);
|
|
8260
|
+
}
|
|
8261
|
+
var MICRO_SYNTAX = {
|
|
8262
|
+
c: "c",
|
|
8263
|
+
clojure: "clojure",
|
|
8264
|
+
cmake: "cmake",
|
|
8265
|
+
crystal: "crystal",
|
|
8266
|
+
csharp: "csharp",
|
|
8267
|
+
css: "css",
|
|
8268
|
+
dart: "dart",
|
|
8269
|
+
docker: "dockerfile",
|
|
8270
|
+
elixir: "elixir",
|
|
8271
|
+
elm: "elm",
|
|
8272
|
+
erb: "erb",
|
|
8273
|
+
erlang: "erlang",
|
|
8274
|
+
fish: "fish",
|
|
8275
|
+
fsharp: "fsharp",
|
|
8276
|
+
go: "go",
|
|
8277
|
+
graphql: "graphql",
|
|
8278
|
+
groovy: "groovy",
|
|
8279
|
+
haml: "haml",
|
|
8280
|
+
haskell: "haskell",
|
|
8281
|
+
html: "html",
|
|
8282
|
+
ini: "ini",
|
|
8283
|
+
java: "java",
|
|
8284
|
+
javascript: "javascript",
|
|
8285
|
+
json: "json",
|
|
8286
|
+
julia: "julia",
|
|
8287
|
+
kotlin: "kotlin",
|
|
8288
|
+
lua: "lua",
|
|
8289
|
+
make: "makefile",
|
|
8290
|
+
markdown: "markdown",
|
|
8291
|
+
nginx: "nginx",
|
|
8292
|
+
nim: "nim",
|
|
8293
|
+
nix: "nix",
|
|
8294
|
+
"objective-c": "objc",
|
|
8295
|
+
ocaml: "ocaml",
|
|
8296
|
+
perl: "perl",
|
|
8297
|
+
php: "php",
|
|
8298
|
+
proto: "proto",
|
|
8299
|
+
python: "python3",
|
|
8300
|
+
r: "r",
|
|
8301
|
+
ruby: "ruby",
|
|
8302
|
+
rust: "rust",
|
|
8303
|
+
scala: "scala",
|
|
8304
|
+
shellscript: "sh",
|
|
8305
|
+
sql: "sql",
|
|
8306
|
+
svelte: "svelte",
|
|
8307
|
+
swift: "swift",
|
|
8308
|
+
terraform: "terraform",
|
|
8309
|
+
toml: "toml",
|
|
8310
|
+
typescript: "typescript",
|
|
8311
|
+
vue: "vue",
|
|
8312
|
+
xml: "xml",
|
|
8313
|
+
yaml: "yaml",
|
|
8314
|
+
zig: "zig",
|
|
8315
|
+
zsh: "zsh"
|
|
8016
8316
|
};
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8317
|
+
var VIM_FILETYPES = {
|
|
8318
|
+
shellscript: "sh",
|
|
8319
|
+
docker: "dockerfile",
|
|
8320
|
+
csharp: "cs",
|
|
8321
|
+
"objective-c": "objc",
|
|
8322
|
+
bat: "dosbatch",
|
|
8323
|
+
viml: "vim",
|
|
8324
|
+
mdx: "markdown",
|
|
8325
|
+
jsx: "javascriptreact",
|
|
8326
|
+
tsx: "typescriptreact",
|
|
8327
|
+
dotenv: "sh",
|
|
8328
|
+
properties: "jproperties",
|
|
8329
|
+
stylus: "stylus"
|
|
8330
|
+
};
|
|
8331
|
+
function microSyntaxName(sourcePath) {
|
|
8332
|
+
const id = detectLanguage(sourcePath);
|
|
8333
|
+
if (id === null) {
|
|
8334
|
+
return null;
|
|
8335
|
+
}
|
|
8336
|
+
return MICRO_SYNTAX[id] ?? null;
|
|
8337
|
+
}
|
|
8338
|
+
function vimFiletype(sourcePath) {
|
|
8339
|
+
const id = detectLanguage(sourcePath);
|
|
8340
|
+
if (id === null) {
|
|
8341
|
+
return null;
|
|
8342
|
+
}
|
|
8343
|
+
return VIM_FILETYPES[id] ?? id;
|
|
8020
8344
|
}
|
|
8021
8345
|
|
|
8022
8346
|
// src/editors/syntax-cache.ts
|
|
8023
|
-
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
8024
|
-
import { dirname as dirname2, join as
|
|
8347
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
8348
|
+
import { dirname as dirname2, join as join3 } from "node:path";
|
|
8025
8349
|
import { fileURLToPath } from "node:url";
|
|
8026
8350
|
function defaultAssetsDir() {
|
|
8027
8351
|
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
8028
8352
|
while (true) {
|
|
8029
|
-
const candidate =
|
|
8353
|
+
const candidate = join3(dir, "assets", "syntax");
|
|
8030
8354
|
if (existsSync2(candidate)) {
|
|
8031
8355
|
return candidate;
|
|
8032
8356
|
}
|
|
@@ -8041,20 +8365,13 @@ function syntaxSource(lang, assetsDir = defaultAssetsDir()) {
|
|
|
8041
8365
|
if (assetsDir === null) {
|
|
8042
8366
|
return null;
|
|
8043
8367
|
}
|
|
8044
|
-
const path =
|
|
8368
|
+
const path = join3(assetsDir, `${lang}.yaml`);
|
|
8045
8369
|
if (!existsSync2(path)) {
|
|
8046
8370
|
return null;
|
|
8047
8371
|
}
|
|
8048
|
-
return
|
|
8372
|
+
return readFileSync2(path, "utf-8");
|
|
8049
8373
|
}
|
|
8050
8374
|
|
|
8051
|
-
// src/helpers/resolvesOnPath.ts
|
|
8052
|
-
import { spawnSync } from "node:child_process";
|
|
8053
|
-
var defaultResolvesOnPath = (command) => {
|
|
8054
|
-
const result = spawnSync("which", [command], { stdio: "ignore" });
|
|
8055
|
-
return result.status === 0;
|
|
8056
|
-
};
|
|
8057
|
-
|
|
8058
8375
|
// src/editors/micro.ts
|
|
8059
8376
|
var MICRO_BINDINGS = {
|
|
8060
8377
|
F2: "QuitAll",
|
|
@@ -8085,7 +8402,7 @@ function bandRules() {
|
|
|
8085
8402
|
];
|
|
8086
8403
|
}
|
|
8087
8404
|
function writeColorScheme(configDir, theme) {
|
|
8088
|
-
const dir =
|
|
8405
|
+
const dir = join4(configDir, "colorschemes");
|
|
8089
8406
|
mkdirSync2(dir, { recursive: true });
|
|
8090
8407
|
const text = `include "monokai"
|
|
8091
8408
|
|
|
@@ -8093,7 +8410,7 @@ color-link pairadd "#d7ffd7,${theme.add}"
|
|
|
8093
8410
|
color-link pairdel "#ffd7d7,${theme.del}"
|
|
8094
8411
|
color-link pairskip "#6a6a6a,${theme.fold}"
|
|
8095
8412
|
`;
|
|
8096
|
-
writeFileSync2(
|
|
8413
|
+
writeFileSync2(join4(dir, "pair.micro"), text, "utf-8");
|
|
8097
8414
|
}
|
|
8098
8415
|
function syntaxText(lang, source) {
|
|
8099
8416
|
const parsed = (0, import_yaml.parse)(source);
|
|
@@ -8109,7 +8426,7 @@ function syntaxText(lang, source) {
|
|
|
8109
8426
|
return (0, import_yaml.stringify)(file, { lineWidth: 0 });
|
|
8110
8427
|
}
|
|
8111
8428
|
function writeSyntax(configDir, sourcePath) {
|
|
8112
|
-
const lang =
|
|
8429
|
+
const lang = microSyntaxName(sourcePath);
|
|
8113
8430
|
if (lang === null) {
|
|
8114
8431
|
return;
|
|
8115
8432
|
}
|
|
@@ -8121,9 +8438,9 @@ function writeSyntax(configDir, sourcePath) {
|
|
|
8121
8438
|
if (text === null) {
|
|
8122
8439
|
return;
|
|
8123
8440
|
}
|
|
8124
|
-
const dir =
|
|
8441
|
+
const dir = join4(configDir, "syntax");
|
|
8125
8442
|
mkdirSync2(dir, { recursive: true });
|
|
8126
|
-
writeFileSync2(
|
|
8443
|
+
writeFileSync2(join4(dir, `pair-${lang}.yaml`), text, "utf-8");
|
|
8127
8444
|
}
|
|
8128
8445
|
function createMicroEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
8129
8446
|
return {
|
|
@@ -8136,7 +8453,7 @@ function createMicroEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8136
8453
|
return ["# F3 moves between panes. Ctrl+W or F2 sends and closes."];
|
|
8137
8454
|
},
|
|
8138
8455
|
bufferSuffix(sourcePath) {
|
|
8139
|
-
const lang =
|
|
8456
|
+
const lang = microSyntaxName(sourcePath);
|
|
8140
8457
|
if (lang === null) {
|
|
8141
8458
|
return ".diff";
|
|
8142
8459
|
}
|
|
@@ -8145,12 +8462,12 @@ function createMicroEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8145
8462
|
prepare(context) {
|
|
8146
8463
|
mkdirSync2(context.configDir, { recursive: true });
|
|
8147
8464
|
writeFileSync2(
|
|
8148
|
-
|
|
8465
|
+
join4(context.configDir, "bindings.json"),
|
|
8149
8466
|
JSON.stringify(MICRO_BINDINGS, null, 2),
|
|
8150
8467
|
"utf-8"
|
|
8151
8468
|
);
|
|
8152
8469
|
writeFileSync2(
|
|
8153
|
-
|
|
8470
|
+
join4(context.configDir, "settings.json"),
|
|
8154
8471
|
JSON.stringify(MICRO_SETTINGS, null, 2),
|
|
8155
8472
|
"utf-8"
|
|
8156
8473
|
);
|
|
@@ -8174,16 +8491,6 @@ function isHexColor(value) {
|
|
|
8174
8491
|
}
|
|
8175
8492
|
|
|
8176
8493
|
// src/editors/vim.ts
|
|
8177
|
-
var VIM_FILETYPE_OVERRIDES = {
|
|
8178
|
-
python3: "python"
|
|
8179
|
-
};
|
|
8180
|
-
function vimFiletype(sourcePath) {
|
|
8181
|
-
const lang = syntaxName(sourcePath);
|
|
8182
|
-
if (lang === null) {
|
|
8183
|
-
return null;
|
|
8184
|
-
}
|
|
8185
|
-
return VIM_FILETYPE_OVERRIDES[lang] ?? lang;
|
|
8186
|
-
}
|
|
8187
8494
|
function safeThemeColor(value) {
|
|
8188
8495
|
if (!isHexColor(value)) {
|
|
8189
8496
|
throw new Error(`invalid theme colour for vim highlight: ${value}`);
|
|
@@ -8238,7 +8545,7 @@ function vimEditor(name, resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8238
8545
|
|
|
8239
8546
|
// src/editors/nano.ts
|
|
8240
8547
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
8241
|
-
import { join as
|
|
8548
|
+
import { join as join5 } from "node:path";
|
|
8242
8549
|
function safeThemeColor2(value) {
|
|
8243
8550
|
if (!isHexColor(value)) {
|
|
8244
8551
|
throw new Error(`invalid theme colour for nano rcfile: ${value}`);
|
|
@@ -8250,7 +8557,7 @@ function writeNanorc(configDir, theme) {
|
|
|
8250
8557
|
color ,${safeThemeColor2(theme.del)} "^\u258C\u258C-"
|
|
8251
8558
|
color ,${safeThemeColor2(theme.fold)} "^\u22EF"
|
|
8252
8559
|
`;
|
|
8253
|
-
const path =
|
|
8560
|
+
const path = join5(configDir, "pair.nanorc");
|
|
8254
8561
|
writeFileSync3(path, text, "utf-8");
|
|
8255
8562
|
return path;
|
|
8256
8563
|
}
|
|
@@ -8280,13 +8587,13 @@ function createNanoEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8280
8587
|
|
|
8281
8588
|
// src/editors/pair.ts
|
|
8282
8589
|
import { existsSync as existsSync4 } from "node:fs";
|
|
8283
|
-
import { dirname as dirname4, extname as extname3, join as
|
|
8590
|
+
import { dirname as dirname4, extname as extname3, join as join7 } from "node:path";
|
|
8284
8591
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
8285
8592
|
|
|
8286
8593
|
// src/core/config/config.ts
|
|
8287
8594
|
import { homedir as homedir2 } from "node:os";
|
|
8288
|
-
import { join as
|
|
8289
|
-
import { existsSync as existsSync3, readFileSync as
|
|
8595
|
+
import { join as join6, dirname as dirname3 } from "node:path";
|
|
8596
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "node:fs";
|
|
8290
8597
|
var EDITOR_NAMES = ["auto", "pair", "micro", "nvim", "vim", "nano"];
|
|
8291
8598
|
var MULTIPLEXER_NAMES = ["auto", "zellij", "tmux", "none"];
|
|
8292
8599
|
var TRANSPORT_NAMES = ["pane", "session"];
|
|
@@ -8312,8 +8619,8 @@ var DEFAULT_CONFIG = {
|
|
|
8312
8619
|
syntax: true
|
|
8313
8620
|
};
|
|
8314
8621
|
function configPath(homeDir) {
|
|
8315
|
-
const base = process.env["XDG_CONFIG_HOME"] ||
|
|
8316
|
-
return
|
|
8622
|
+
const base = process.env["XDG_CONFIG_HOME"] || join6(homeDir ?? homedir2(), ".config");
|
|
8623
|
+
return join6(base, "pair-mode", "config.json");
|
|
8317
8624
|
}
|
|
8318
8625
|
function isEditorName(value) {
|
|
8319
8626
|
return typeof value === "string" && EDITOR_NAMES.includes(value);
|
|
@@ -8585,7 +8892,7 @@ function loadConfig(path) {
|
|
|
8585
8892
|
}
|
|
8586
8893
|
let text;
|
|
8587
8894
|
try {
|
|
8588
|
-
text =
|
|
8895
|
+
text = readFileSync3(target, "utf-8");
|
|
8589
8896
|
} catch (error) {
|
|
8590
8897
|
const message = error instanceof Error ? error.message : String(error);
|
|
8591
8898
|
return {
|
|
@@ -8620,7 +8927,7 @@ function paintLayout(layout) {
|
|
|
8620
8927
|
// src/editors/pair.ts
|
|
8621
8928
|
var defaultResolveTuiEntry = () => {
|
|
8622
8929
|
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
8623
|
-
return
|
|
8930
|
+
return join7(here, "pair-tui.js");
|
|
8624
8931
|
};
|
|
8625
8932
|
var defaultCheckBundleExists = existsSync4;
|
|
8626
8933
|
function createPairEditor(resolveTuiEntry = defaultResolveTuiEntry, checkBundleExists = defaultCheckBundleExists) {
|
|
@@ -8719,14 +9026,6 @@ function resolve(preference, resolvesOnPath = defaultResolvesOnPath, checkPairBu
|
|
|
8719
9026
|
return available ?? vimEditor("vim", resolvesOnPath);
|
|
8720
9027
|
}
|
|
8721
9028
|
|
|
8722
|
-
// src/helpers/spawn.ts
|
|
8723
|
-
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
8724
|
-
var defaultSpawn = (command, args) => {
|
|
8725
|
-
const result = spawnSync2(command, args, { stdio: ["ignore", "ignore", "pipe"] });
|
|
8726
|
-
const stderr = result.stderr ? result.stderr.toString("utf-8") : result.error?.message ?? "";
|
|
8727
|
-
return { status: result.status, stderr };
|
|
8728
|
-
};
|
|
8729
|
-
|
|
8730
9029
|
// src/multiplexers/zellij.ts
|
|
8731
9030
|
function createZellijMultiplexer(spawn = defaultSpawn, resolvesOnPath = defaultResolvesOnPath) {
|
|
8732
9031
|
return {
|
|
@@ -8756,7 +9055,7 @@ function createZellijMultiplexer(spawn = defaultSpawn, resolvesOnPath = defaultR
|
|
|
8756
9055
|
}
|
|
8757
9056
|
|
|
8758
9057
|
// src/multiplexers/tmux.ts
|
|
8759
|
-
import { randomBytes } from "node:crypto";
|
|
9058
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
8760
9059
|
var CHANNEL_BYTES = 8;
|
|
8761
9060
|
var SAFE_UNQUOTED = /^[A-Za-z0-9_\-./]+$/;
|
|
8762
9061
|
function shellQuote(value) {
|
|
@@ -8772,7 +9071,7 @@ function createTmuxMultiplexer(spawn = defaultSpawn, resolvesOnPath = defaultRes
|
|
|
8772
9071
|
return Boolean(process.env["TMUX"]) && resolvesOnPath("tmux");
|
|
8773
9072
|
},
|
|
8774
9073
|
run(argv, size) {
|
|
8775
|
-
const channel = `pair-${
|
|
9074
|
+
const channel = `pair-${randomBytes2(CHANNEL_BYTES).toString("hex")}`;
|
|
8776
9075
|
const inner = argv.map(shellQuote).join(" ");
|
|
8777
9076
|
const script = `stty -ixon 2>/dev/null; ${inner}; tmux wait-for -S ${channel}`;
|
|
8778
9077
|
const popup = spawn("tmux", [
|
|
@@ -8794,9 +9093,9 @@ function createTmuxMultiplexer(spawn = defaultSpawn, resolvesOnPath = defaultRes
|
|
|
8794
9093
|
}
|
|
8795
9094
|
|
|
8796
9095
|
// src/multiplexers/tty.ts
|
|
8797
|
-
import { openSync, closeSync } from "node:fs";
|
|
9096
|
+
import { openSync as openSync2, closeSync as closeSync2 } from "node:fs";
|
|
8798
9097
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
8799
|
-
var defaultOpen = () =>
|
|
9098
|
+
var defaultOpen = () => openSync2("/dev/tty", "r+");
|
|
8800
9099
|
var defaultRunner = (command, args, fd) => {
|
|
8801
9100
|
const result = spawnSync3(command, args, { stdio: [fd, fd, fd] });
|
|
8802
9101
|
const detail = result.status === 0 ? "" : String(result.error?.message ?? result.stderr ?? "");
|
|
@@ -8804,7 +9103,7 @@ var defaultRunner = (command, args, fd) => {
|
|
|
8804
9103
|
};
|
|
8805
9104
|
function closeQuietly(fd) {
|
|
8806
9105
|
try {
|
|
8807
|
-
|
|
9106
|
+
closeSync2(fd);
|
|
8808
9107
|
} catch {
|
|
8809
9108
|
}
|
|
8810
9109
|
}
|
|
@@ -8861,35 +9160,6 @@ function detect(preference, adapters = {}) {
|
|
|
8861
9160
|
return tty;
|
|
8862
9161
|
}
|
|
8863
9162
|
|
|
8864
|
-
// src/helpers/readFileOrEmpty.ts
|
|
8865
|
-
import { readFileSync as readFileSync3 } from "node:fs";
|
|
8866
|
-
function readFileOrEmpty(path) {
|
|
8867
|
-
try {
|
|
8868
|
-
return readFileSync3(path, "utf-8");
|
|
8869
|
-
} catch {
|
|
8870
|
-
return "";
|
|
8871
|
-
}
|
|
8872
|
-
}
|
|
8873
|
-
|
|
8874
|
-
// src/helpers/removeQuietly.ts
|
|
8875
|
-
import { unlinkSync as unlinkSync2 } from "node:fs";
|
|
8876
|
-
function removeQuietly(path) {
|
|
8877
|
-
try {
|
|
8878
|
-
unlinkSync2(path);
|
|
8879
|
-
} catch {
|
|
8880
|
-
}
|
|
8881
|
-
}
|
|
8882
|
-
|
|
8883
|
-
// src/helpers/resultFilePath.ts
|
|
8884
|
-
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
8885
|
-
import { tmpdir } from "node:os";
|
|
8886
|
-
import { join as join7 } from "node:path";
|
|
8887
|
-
var NAME_BYTES = 6;
|
|
8888
|
-
function resultFilePath() {
|
|
8889
|
-
const name = `pair-result-${randomBytes2(NAME_BYTES).toString("hex")}.json`;
|
|
8890
|
-
return join7(tmpdir(), name);
|
|
8891
|
-
}
|
|
8892
|
-
|
|
8893
9163
|
// src/transports/pane/pane.ts
|
|
8894
9164
|
var NAME_BYTES2 = 6;
|
|
8895
9165
|
function splitCommand(value) {
|
|
@@ -8988,6 +9258,7 @@ function createPaneTransport(deps = {}) {
|
|
|
8988
9258
|
|
|
8989
9259
|
// src/transports/session/client.ts
|
|
8990
9260
|
import { createConnection } from "node:net";
|
|
9261
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
8991
9262
|
|
|
8992
9263
|
// src/transports/session/wire.ts
|
|
8993
9264
|
var CLIENT_KINDS = ["tui", "web"];
|
|
@@ -9002,11 +9273,11 @@ function createLineReader() {
|
|
|
9002
9273
|
return parts.filter((line) => line.trim() !== "");
|
|
9003
9274
|
};
|
|
9004
9275
|
}
|
|
9005
|
-
function
|
|
9276
|
+
function isString2(value) {
|
|
9006
9277
|
return typeof value === "string";
|
|
9007
9278
|
}
|
|
9008
9279
|
function isClientKind(value) {
|
|
9009
|
-
return
|
|
9280
|
+
return isString2(value) && CLIENT_KINDS.includes(value);
|
|
9010
9281
|
}
|
|
9011
9282
|
function isQuestion(value) {
|
|
9012
9283
|
if (!isRecord(value)) {
|
|
@@ -9014,16 +9285,16 @@ function isQuestion(value) {
|
|
|
9014
9285
|
}
|
|
9015
9286
|
const line = value["line"];
|
|
9016
9287
|
const lineOk = line === null || typeof line === "number";
|
|
9017
|
-
return lineOk &&
|
|
9288
|
+
return lineOk && isString2(value["code"]) && isString2(value["text"]);
|
|
9018
9289
|
}
|
|
9019
9290
|
function isQuestionList(value) {
|
|
9020
9291
|
return Array.isArray(value) && value.every(isQuestion);
|
|
9021
9292
|
}
|
|
9022
9293
|
function toSubmit(raw) {
|
|
9023
|
-
if (!
|
|
9294
|
+
if (!isString2(raw["tool"]) || !isString2(raw["path"])) {
|
|
9024
9295
|
return null;
|
|
9025
9296
|
}
|
|
9026
|
-
if (!
|
|
9297
|
+
if (!isString2(raw["before"]) || !isString2(raw["after"])) {
|
|
9027
9298
|
return null;
|
|
9028
9299
|
}
|
|
9029
9300
|
return {
|
|
@@ -9039,7 +9310,7 @@ function toAttach(raw) {
|
|
|
9039
9310
|
}
|
|
9040
9311
|
function toReview(raw) {
|
|
9041
9312
|
const submit = toSubmit({ ...raw, type: "submit" });
|
|
9042
|
-
if (submit === null || !
|
|
9313
|
+
if (submit === null || !isString2(raw["id"])) {
|
|
9043
9314
|
return null;
|
|
9044
9315
|
}
|
|
9045
9316
|
return {
|
|
@@ -9052,13 +9323,31 @@ function toReview(raw) {
|
|
|
9052
9323
|
};
|
|
9053
9324
|
}
|
|
9054
9325
|
function toVerdict(raw) {
|
|
9055
|
-
if (!
|
|
9326
|
+
if (!isString2(raw["id"]) || !isQuestionList(raw["questions"])) {
|
|
9056
9327
|
return null;
|
|
9057
9328
|
}
|
|
9058
9329
|
return { type: "verdict", id: raw["id"], questions: raw["questions"] };
|
|
9059
9330
|
}
|
|
9060
9331
|
function toCancel(raw) {
|
|
9061
|
-
return
|
|
9332
|
+
return isString2(raw["id"]) ? { type: "cancel", id: raw["id"] } : null;
|
|
9333
|
+
}
|
|
9334
|
+
function isNumber(value) {
|
|
9335
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
9336
|
+
}
|
|
9337
|
+
function toState(raw) {
|
|
9338
|
+
const lastAttachAt = raw["lastAttachAt"];
|
|
9339
|
+
if (lastAttachAt !== null && !isString2(lastAttachAt)) {
|
|
9340
|
+
return null;
|
|
9341
|
+
}
|
|
9342
|
+
if (!isNumber(raw["clientCount"]) || !isNumber(raw["waitingDepth"])) {
|
|
9343
|
+
return null;
|
|
9344
|
+
}
|
|
9345
|
+
return {
|
|
9346
|
+
type: "state",
|
|
9347
|
+
clientCount: raw["clientCount"],
|
|
9348
|
+
waitingDepth: raw["waitingDepth"],
|
|
9349
|
+
lastAttachAt
|
|
9350
|
+
};
|
|
9062
9351
|
}
|
|
9063
9352
|
function decodeLine(line) {
|
|
9064
9353
|
let parsed;
|
|
@@ -9086,11 +9375,18 @@ function decodeLine(line) {
|
|
|
9086
9375
|
if (type === "cancel") {
|
|
9087
9376
|
return toCancel(parsed);
|
|
9088
9377
|
}
|
|
9378
|
+
if (type === "status") {
|
|
9379
|
+
return { type: "status" };
|
|
9380
|
+
}
|
|
9381
|
+
if (type === "state") {
|
|
9382
|
+
return toState(parsed);
|
|
9383
|
+
}
|
|
9089
9384
|
return null;
|
|
9090
9385
|
}
|
|
9091
9386
|
|
|
9092
9387
|
// src/transports/session/client.ts
|
|
9093
9388
|
var MS_PER_SECOND = 1e3;
|
|
9389
|
+
var NO_WATCHER = "no pair-mode watcher attached";
|
|
9094
9390
|
function failOpen(detail) {
|
|
9095
9391
|
return { reviewed: false, detail };
|
|
9096
9392
|
}
|
|
@@ -9123,7 +9419,7 @@ function requestReview(request, options) {
|
|
|
9123
9419
|
let lastError = "";
|
|
9124
9420
|
socket.on("error", (error) => {
|
|
9125
9421
|
if (isConnectionRefused(error)) {
|
|
9126
|
-
settle(failOpen(
|
|
9422
|
+
settle(failOpen(NO_WATCHER));
|
|
9127
9423
|
return;
|
|
9128
9424
|
}
|
|
9129
9425
|
lastError = error instanceof Error ? error.message : String(error);
|
|
@@ -9153,15 +9449,27 @@ function requestReview(request, options) {
|
|
|
9153
9449
|
});
|
|
9154
9450
|
});
|
|
9155
9451
|
}
|
|
9156
|
-
function reviewInSession(request, config, socketPath) {
|
|
9157
|
-
const
|
|
9158
|
-
if (
|
|
9159
|
-
return
|
|
9452
|
+
async function reviewInSession(request, config, socketPath) {
|
|
9453
|
+
const timeoutMs = config.session.timeout * MS_PER_SECOND;
|
|
9454
|
+
if (socketPath !== void 0) {
|
|
9455
|
+
return await requestReview(request, { socketPath, timeoutMs });
|
|
9160
9456
|
}
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
9457
|
+
const key = keyFor(request.sessionId);
|
|
9458
|
+
const sessionPath = key === void 0 ? null : sessionKeySocketPath(key);
|
|
9459
|
+
if (sessionPath !== null && existsSync5(sessionPath)) {
|
|
9460
|
+
const outcome = await requestReview(request, { socketPath: sessionPath, timeoutMs });
|
|
9461
|
+
if (outcome.reviewed) {
|
|
9462
|
+
return outcome;
|
|
9463
|
+
}
|
|
9464
|
+
if (outcome.detail !== NO_WATCHER) {
|
|
9465
|
+
return outcome;
|
|
9466
|
+
}
|
|
9467
|
+
}
|
|
9468
|
+
const directoryPath = findSessionSocket(request.filePath);
|
|
9469
|
+
if (directoryPath === null) {
|
|
9470
|
+
return failOpen(NO_WATCHER);
|
|
9471
|
+
}
|
|
9472
|
+
return await requestReview(request, { socketPath: directoryPath, timeoutMs });
|
|
9165
9473
|
}
|
|
9166
9474
|
function createSessionTransport(socketPath) {
|
|
9167
9475
|
return {
|
|
@@ -9182,7 +9490,8 @@ async function runPair(request, config, deps = {}) {
|
|
|
9182
9490
|
if (request.before === request.after) {
|
|
9183
9491
|
return { decision: "allow", reviewed: false };
|
|
9184
9492
|
}
|
|
9185
|
-
|
|
9493
|
+
const key = keyFor(request.sessionId);
|
|
9494
|
+
if (!isEnabled(request.filePath, key)) {
|
|
9186
9495
|
return { decision: "allow", reviewed: false };
|
|
9187
9496
|
}
|
|
9188
9497
|
const transport = deps.transport ?? resolveTransport(config, deps);
|
|
@@ -9236,10 +9545,12 @@ async function evaluate(input, output, runPair2) {
|
|
|
9236
9545
|
if (call === null) {
|
|
9237
9546
|
return null;
|
|
9238
9547
|
}
|
|
9239
|
-
|
|
9548
|
+
const sessionId = input.sessionID === "" ? void 0 : input.sessionID;
|
|
9549
|
+
const key = keyFor(sessionId);
|
|
9550
|
+
if (!isEnabled(call.filePath, key)) {
|
|
9240
9551
|
return null;
|
|
9241
9552
|
}
|
|
9242
|
-
const request = simulate(call.tool, call.input, readFileOrEmpty);
|
|
9553
|
+
const request = simulate(call.tool, call.input, readFileOrEmpty, sessionId);
|
|
9243
9554
|
if (request === null) {
|
|
9244
9555
|
return null;
|
|
9245
9556
|
}
|