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/claude-code.js
CHANGED
|
@@ -7363,11 +7363,79 @@ 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/readPayload.ts
|
|
7385
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
7386
|
+
function readPayload() {
|
|
7387
|
+
const text = readFileSync2(0, "utf-8");
|
|
7388
|
+
return JSON.parse(text);
|
|
7389
|
+
}
|
|
7390
|
+
|
|
7391
|
+
// src/helpers/removeQuietly.ts
|
|
7392
|
+
import { unlinkSync } from "node:fs";
|
|
7393
|
+
function removeQuietly(path) {
|
|
7394
|
+
try {
|
|
7395
|
+
unlinkSync(path);
|
|
7396
|
+
} catch {
|
|
7397
|
+
}
|
|
7398
|
+
}
|
|
7399
|
+
|
|
7400
|
+
// src/helpers/resolvesOnPath.ts
|
|
7401
|
+
import { spawnSync } from "node:child_process";
|
|
7402
|
+
var defaultResolvesOnPath = (command) => {
|
|
7403
|
+
const result = spawnSync("which", [command], { stdio: "ignore" });
|
|
7404
|
+
return result.status === 0;
|
|
7405
|
+
};
|
|
7406
|
+
|
|
7407
|
+
// src/helpers/resultFilePath.ts
|
|
7408
|
+
import { randomBytes } from "node:crypto";
|
|
7409
|
+
import { tmpdir } from "node:os";
|
|
7410
|
+
import { join } from "node:path";
|
|
7411
|
+
var NAME_BYTES = 6;
|
|
7412
|
+
function resultFilePath() {
|
|
7413
|
+
const name = `pair-result-${randomBytes(NAME_BYTES).toString("hex")}.json`;
|
|
7414
|
+
return join(tmpdir(), name);
|
|
7415
|
+
}
|
|
7416
|
+
|
|
7417
|
+
// src/helpers/spawn.ts
|
|
7418
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
7419
|
+
var defaultSpawn = (command, args) => {
|
|
7420
|
+
const result = spawnSync2(command, args, { stdio: ["ignore", "ignore", "pipe"] });
|
|
7421
|
+
const stderr = result.stderr ? result.stderr.toString("utf-8") : result.error?.message ?? "";
|
|
7422
|
+
return { status: result.status, stderr };
|
|
7423
|
+
};
|
|
7424
|
+
|
|
7425
|
+
// src/helpers/splitLines.ts
|
|
7426
|
+
function splitLines(text) {
|
|
7427
|
+
const lines = text.split("\n");
|
|
7428
|
+
const last = lines.at(-1);
|
|
7429
|
+
if (last === "") {
|
|
7430
|
+
lines.pop();
|
|
7431
|
+
}
|
|
7432
|
+
return lines;
|
|
7433
|
+
}
|
|
7434
|
+
|
|
7435
|
+
// src/core/state/state.ts
|
|
7368
7436
|
function stateDir() {
|
|
7369
|
-
const base = process.env["XDG_STATE_HOME"] ||
|
|
7370
|
-
return
|
|
7437
|
+
const base = process.env["XDG_STATE_HOME"] || join2(homedir(), ".local", "state");
|
|
7438
|
+
return join2(base, "pair-mode");
|
|
7371
7439
|
}
|
|
7372
7440
|
function realpathLenient(path) {
|
|
7373
7441
|
try {
|
|
@@ -7377,7 +7445,7 @@ function realpathLenient(path) {
|
|
|
7377
7445
|
if (parent === path) {
|
|
7378
7446
|
return path;
|
|
7379
7447
|
}
|
|
7380
|
-
return
|
|
7448
|
+
return join2(realpathLenient(parent), basename(path));
|
|
7381
7449
|
}
|
|
7382
7450
|
}
|
|
7383
7451
|
var DIGEST_LENGTH = 16;
|
|
@@ -7386,13 +7454,13 @@ function digestFor(directory) {
|
|
|
7386
7454
|
return createHash("sha1").update(real).digest("hex").slice(0, DIGEST_LENGTH);
|
|
7387
7455
|
}
|
|
7388
7456
|
function flagPath(directory) {
|
|
7389
|
-
return
|
|
7457
|
+
return join2(stateDir(), `${digestFor(directory)}.on`);
|
|
7390
7458
|
}
|
|
7391
7459
|
function sessionsDir() {
|
|
7392
|
-
return
|
|
7460
|
+
return join2(stateDir(), "sessions");
|
|
7393
7461
|
}
|
|
7394
7462
|
function sessionSocketPath(directory) {
|
|
7395
|
-
return
|
|
7463
|
+
return join2(sessionsDir(), `${digestFor(directory)}.sock`);
|
|
7396
7464
|
}
|
|
7397
7465
|
function findSessionSocket(filePath) {
|
|
7398
7466
|
let current = dirname(realpathLenient(filePath));
|
|
@@ -7408,7 +7476,13 @@ function findSessionSocket(filePath) {
|
|
|
7408
7476
|
current = parent;
|
|
7409
7477
|
}
|
|
7410
7478
|
}
|
|
7411
|
-
function
|
|
7479
|
+
function sessionFlagState(key) {
|
|
7480
|
+
if (existsSync(sessionKeyOptOutPath(key))) {
|
|
7481
|
+
return "off";
|
|
7482
|
+
}
|
|
7483
|
+
return existsSync(sessionKeyFlagPath(key)) ? "on" : "unset";
|
|
7484
|
+
}
|
|
7485
|
+
function directoryEnabled(filePath) {
|
|
7412
7486
|
let current = dirname(realpathLenient(filePath));
|
|
7413
7487
|
while (true) {
|
|
7414
7488
|
if (existsSync(flagPath(current))) {
|
|
@@ -7421,10 +7495,34 @@ function isEnabled(filePath) {
|
|
|
7421
7495
|
current = parent;
|
|
7422
7496
|
}
|
|
7423
7497
|
}
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7498
|
+
function isEnabled(filePath, key) {
|
|
7499
|
+
if (key !== void 0) {
|
|
7500
|
+
const state = sessionFlagState(key);
|
|
7501
|
+
if (state !== "unset") {
|
|
7502
|
+
return state === "on";
|
|
7503
|
+
}
|
|
7504
|
+
}
|
|
7505
|
+
return directoryEnabled(filePath);
|
|
7506
|
+
}
|
|
7507
|
+
var SESSION_KEY_LENGTH = 8;
|
|
7508
|
+
function sessionKey(agentSessionId) {
|
|
7509
|
+
const digest = createHash("sha1").update(agentSessionId).digest("hex");
|
|
7510
|
+
return `s-${digest.slice(0, SESSION_KEY_LENGTH)}`;
|
|
7511
|
+
}
|
|
7512
|
+
function keyFor(agentSessionId) {
|
|
7513
|
+
return agentSessionId === void 0 || agentSessionId === "" ? void 0 : sessionKey(agentSessionId);
|
|
7514
|
+
}
|
|
7515
|
+
function sessionKeyPath(key, extension) {
|
|
7516
|
+
return join2(sessionsDir(), `${key}${extension}`);
|
|
7517
|
+
}
|
|
7518
|
+
function sessionKeySocketPath(key) {
|
|
7519
|
+
return sessionKeyPath(key, ".sock");
|
|
7520
|
+
}
|
|
7521
|
+
function sessionKeyFlagPath(key) {
|
|
7522
|
+
return sessionKeyPath(key, ".on");
|
|
7523
|
+
}
|
|
7524
|
+
function sessionKeyOptOutPath(key) {
|
|
7525
|
+
return sessionKeyPath(key, ".off");
|
|
7428
7526
|
}
|
|
7429
7527
|
|
|
7430
7528
|
// src/core/simulate/simulate.ts
|
|
@@ -7471,7 +7569,7 @@ function applyEdit(text, edit) {
|
|
|
7471
7569
|
}
|
|
7472
7570
|
return replaceFirst(text, old, next);
|
|
7473
7571
|
}
|
|
7474
|
-
function simulate(tool, input, readFile) {
|
|
7572
|
+
function simulate(tool, input, readFile, sessionId) {
|
|
7475
7573
|
if (!isRecord(input)) {
|
|
7476
7574
|
return null;
|
|
7477
7575
|
}
|
|
@@ -7483,7 +7581,7 @@ function simulate(tool, input, readFile) {
|
|
|
7483
7581
|
const content = input["content"];
|
|
7484
7582
|
const after = typeof content === "string" ? content : "";
|
|
7485
7583
|
const before = readFile(filePath);
|
|
7486
|
-
return { tool, filePath, before, after };
|
|
7584
|
+
return { tool, filePath, before, after, sessionId };
|
|
7487
7585
|
}
|
|
7488
7586
|
if (tool === "Edit" || tool === "MultiEdit") {
|
|
7489
7587
|
const editsRaw = input["edits"];
|
|
@@ -7498,7 +7596,7 @@ function simulate(tool, input, readFile) {
|
|
|
7498
7596
|
if (after === null) {
|
|
7499
7597
|
return null;
|
|
7500
7598
|
}
|
|
7501
|
-
return { tool, filePath, before, after };
|
|
7599
|
+
return { tool, filePath, before, after, sessionId };
|
|
7502
7600
|
}
|
|
7503
7601
|
return null;
|
|
7504
7602
|
}
|
|
@@ -7929,16 +8027,6 @@ import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, rmSync
|
|
|
7929
8027
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
7930
8028
|
import { join as join8 } from "node:path";
|
|
7931
8029
|
|
|
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
8030
|
// src/core/render/render.ts
|
|
7943
8031
|
var HEADER_LEAD = [
|
|
7944
8032
|
"# PAIR MODE. Left pane is the current file. Right pane is the proposal.",
|
|
@@ -7977,56 +8065,299 @@ function renderInline(input) {
|
|
|
7977
8065
|
// src/editors/micro.ts
|
|
7978
8066
|
var import_yaml = __toESM(require_dist(), 1);
|
|
7979
8067
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7980
|
-
import { join as
|
|
8068
|
+
import { join as join4 } from "node:path";
|
|
7981
8069
|
|
|
7982
8070
|
// src/editors/languages.ts
|
|
7983
|
-
import {
|
|
7984
|
-
|
|
8071
|
+
import { openSync, readSync, closeSync } from "node:fs";
|
|
8072
|
+
import { basename as basename2, extname } from "node:path";
|
|
8073
|
+
var EXTENSIONS = {
|
|
7985
8074
|
".go": "go",
|
|
7986
8075
|
".rb": "ruby",
|
|
7987
8076
|
".rake": "ruby",
|
|
8077
|
+
".gemspec": "ruby",
|
|
8078
|
+
".ru": "ruby",
|
|
8079
|
+
".erb": "erb",
|
|
8080
|
+
".haml": "haml",
|
|
7988
8081
|
".ts": "typescript",
|
|
7989
|
-
".
|
|
8082
|
+
".mts": "typescript",
|
|
8083
|
+
".cts": "typescript",
|
|
8084
|
+
".tsx": "tsx",
|
|
7990
8085
|
".js": "javascript",
|
|
7991
|
-
".jsx": "javascript",
|
|
7992
8086
|
".mjs": "javascript",
|
|
7993
|
-
".
|
|
8087
|
+
".cjs": "javascript",
|
|
8088
|
+
".jsx": "jsx",
|
|
8089
|
+
".vue": "vue",
|
|
8090
|
+
".svelte": "svelte",
|
|
8091
|
+
".astro": "astro",
|
|
8092
|
+
".py": "python",
|
|
8093
|
+
".pyi": "python",
|
|
7994
8094
|
".ex": "elixir",
|
|
7995
8095
|
".exs": "elixir",
|
|
8096
|
+
".heex": "elixir",
|
|
8097
|
+
".erl": "erlang",
|
|
8098
|
+
".hrl": "erlang",
|
|
7996
8099
|
".rs": "rust",
|
|
7997
|
-
".sh": "
|
|
7998
|
-
".bash": "
|
|
7999
|
-
".
|
|
8100
|
+
".sh": "shellscript",
|
|
8101
|
+
".bash": "shellscript",
|
|
8102
|
+
".ksh": "shellscript",
|
|
8000
8103
|
".zsh": "zsh",
|
|
8104
|
+
".fish": "fish",
|
|
8105
|
+
".ps1": "powershell",
|
|
8106
|
+
".psm1": "powershell",
|
|
8107
|
+
".bat": "bat",
|
|
8108
|
+
".cmd": "bat",
|
|
8001
8109
|
".sql": "sql",
|
|
8002
8110
|
".json": "json",
|
|
8111
|
+
".jsonc": "jsonc",
|
|
8112
|
+
".json5": "json5",
|
|
8003
8113
|
".tf": "terraform",
|
|
8114
|
+
".tfvars": "terraform",
|
|
8115
|
+
".hcl": "hcl",
|
|
8004
8116
|
".proto": "proto",
|
|
8005
|
-
".dockerfile": "
|
|
8117
|
+
".dockerfile": "docker",
|
|
8006
8118
|
".toml": "toml",
|
|
8007
8119
|
".yaml": "yaml",
|
|
8008
8120
|
".yml": "yaml",
|
|
8121
|
+
".ini": "ini",
|
|
8122
|
+
".cfg": "ini",
|
|
8123
|
+
".properties": "properties",
|
|
8124
|
+
".env": "dotenv",
|
|
8009
8125
|
".md": "markdown",
|
|
8126
|
+
".markdown": "markdown",
|
|
8127
|
+
".mdx": "mdx",
|
|
8010
8128
|
".css": "css",
|
|
8129
|
+
".scss": "scss",
|
|
8130
|
+
".sass": "sass",
|
|
8131
|
+
".less": "less",
|
|
8132
|
+
".styl": "stylus",
|
|
8011
8133
|
".html": "html",
|
|
8012
|
-
".
|
|
8134
|
+
".htm": "html",
|
|
8135
|
+
".xml": "xml",
|
|
8136
|
+
".xsl": "xml",
|
|
8137
|
+
".svg": "xml",
|
|
8013
8138
|
".lua": "lua",
|
|
8014
8139
|
".c": "c",
|
|
8015
|
-
".h": "c"
|
|
8140
|
+
".h": "c",
|
|
8141
|
+
".cc": "cpp",
|
|
8142
|
+
".cpp": "cpp",
|
|
8143
|
+
".cxx": "cpp",
|
|
8144
|
+
".hpp": "cpp",
|
|
8145
|
+
".hh": "cpp",
|
|
8146
|
+
".cs": "csharp",
|
|
8147
|
+
".java": "java",
|
|
8148
|
+
".kt": "kotlin",
|
|
8149
|
+
".kts": "kotlin",
|
|
8150
|
+
".swift": "swift",
|
|
8151
|
+
".m": "objective-c",
|
|
8152
|
+
".mm": "objective-c",
|
|
8153
|
+
".php": "php",
|
|
8154
|
+
".pl": "perl",
|
|
8155
|
+
".pm": "perl",
|
|
8156
|
+
".scala": "scala",
|
|
8157
|
+
".sc": "scala",
|
|
8158
|
+
".clj": "clojure",
|
|
8159
|
+
".cljs": "clojure",
|
|
8160
|
+
".cljc": "clojure",
|
|
8161
|
+
".hs": "haskell",
|
|
8162
|
+
".nix": "nix",
|
|
8163
|
+
".r": "r",
|
|
8164
|
+
".jl": "julia",
|
|
8165
|
+
".zig": "zig",
|
|
8166
|
+
".nim": "nim",
|
|
8167
|
+
".dart": "dart",
|
|
8168
|
+
".groovy": "groovy",
|
|
8169
|
+
".gradle": "groovy",
|
|
8170
|
+
".cr": "crystal",
|
|
8171
|
+
".ml": "ocaml",
|
|
8172
|
+
".mli": "ocaml",
|
|
8173
|
+
".fs": "fsharp",
|
|
8174
|
+
".fsx": "fsharp",
|
|
8175
|
+
".elm": "elm",
|
|
8176
|
+
".graphql": "graphql",
|
|
8177
|
+
".gql": "graphql",
|
|
8178
|
+
".prisma": "prisma",
|
|
8179
|
+
".sol": "solidity",
|
|
8180
|
+
".vim": "viml",
|
|
8181
|
+
".diff": "diff",
|
|
8182
|
+
".patch": "diff",
|
|
8183
|
+
".tex": "latex",
|
|
8184
|
+
".wgsl": "wgsl",
|
|
8185
|
+
".glsl": "glsl",
|
|
8186
|
+
".cue": "cue"
|
|
8187
|
+
};
|
|
8188
|
+
var FILENAMES = {
|
|
8189
|
+
gemfile: "ruby",
|
|
8190
|
+
rakefile: "ruby",
|
|
8191
|
+
capfile: "ruby",
|
|
8192
|
+
vagrantfile: "ruby",
|
|
8193
|
+
guardfile: "ruby",
|
|
8194
|
+
podfile: "ruby",
|
|
8195
|
+
fastfile: "ruby",
|
|
8196
|
+
appfile: "ruby",
|
|
8197
|
+
brewfile: "ruby",
|
|
8198
|
+
"config.ru": "ruby",
|
|
8199
|
+
dockerfile: "docker",
|
|
8200
|
+
containerfile: "docker",
|
|
8201
|
+
makefile: "make",
|
|
8202
|
+
gnumakefile: "make",
|
|
8203
|
+
"cmakelists.txt": "cmake",
|
|
8204
|
+
"cargo.lock": "toml",
|
|
8205
|
+
"gemfile.lock": "toml",
|
|
8206
|
+
".babelrc": "json",
|
|
8207
|
+
".eslintrc": "json",
|
|
8208
|
+
".prettierrc": "json",
|
|
8209
|
+
".env": "dotenv",
|
|
8210
|
+
".gitconfig": "ini",
|
|
8211
|
+
".editorconfig": "ini",
|
|
8212
|
+
"nginx.conf": "nginx",
|
|
8213
|
+
"pnpm-workspace.yaml": "yaml"
|
|
8214
|
+
};
|
|
8215
|
+
var SHEBANGS = [
|
|
8216
|
+
{ pattern: /^#!.*\/(env\s+)?ruby(\s|$)/, id: "ruby" },
|
|
8217
|
+
{ pattern: /^#!.*\/(env\s+)?python[\d.]*(\s|$)/, id: "python" },
|
|
8218
|
+
{ pattern: /^#!.*\/(env\s+)?(node|bun|deno)(\s|$)/, id: "javascript" },
|
|
8219
|
+
{ pattern: /^#!.*\/(env\s+)?(bash|sh|ksh|dash)(\s|$)/, id: "shellscript" },
|
|
8220
|
+
{ pattern: /^#!.*\/(env\s+)?zsh(\s|$)/, id: "zsh" },
|
|
8221
|
+
{ pattern: /^#!.*\/(env\s+)?fish(\s|$)/, id: "fish" },
|
|
8222
|
+
{ pattern: /^#!.*\/(env\s+)?perl(\s|$)/, id: "perl" },
|
|
8223
|
+
{ pattern: /^#!.*\/(env\s+)?php(\s|$)/, id: "php" },
|
|
8224
|
+
{ pattern: /^#!.*\/(env\s+)?(elixir|iex)(\s|$)/, id: "elixir" },
|
|
8225
|
+
{ pattern: /^#!.*\/(env\s+)?lua(\s|$)/, id: "lua" },
|
|
8226
|
+
{ pattern: /^#!.*\/(env\s+)?Rscript(\s|$)/, id: "r" },
|
|
8227
|
+
{ pattern: /^#!.*\/(env\s+)?pwsh(\s|$)/, id: "powershell" }
|
|
8228
|
+
];
|
|
8229
|
+
var FIRST_LINE_BYTES = 256;
|
|
8230
|
+
function firstLine(sourcePath) {
|
|
8231
|
+
let handle = null;
|
|
8232
|
+
try {
|
|
8233
|
+
handle = openSync(sourcePath, "r");
|
|
8234
|
+
const buffer = Buffer.alloc(FIRST_LINE_BYTES);
|
|
8235
|
+
const read = readSync(handle, buffer, 0, FIRST_LINE_BYTES, 0);
|
|
8236
|
+
const text = buffer.toString("utf-8", 0, read);
|
|
8237
|
+
const newline = text.indexOf("\n");
|
|
8238
|
+
return newline === -1 ? text : text.slice(0, newline);
|
|
8239
|
+
} catch {
|
|
8240
|
+
return null;
|
|
8241
|
+
} finally {
|
|
8242
|
+
if (handle !== null) {
|
|
8243
|
+
try {
|
|
8244
|
+
closeSync(handle);
|
|
8245
|
+
} catch {
|
|
8246
|
+
}
|
|
8247
|
+
}
|
|
8248
|
+
}
|
|
8249
|
+
}
|
|
8250
|
+
function shebangLanguage(sourcePath) {
|
|
8251
|
+
const line = firstLine(sourcePath);
|
|
8252
|
+
if (line === null || !line.startsWith("#!")) {
|
|
8253
|
+
return null;
|
|
8254
|
+
}
|
|
8255
|
+
return SHEBANGS.find((rule) => rule.pattern.test(line))?.id ?? null;
|
|
8256
|
+
}
|
|
8257
|
+
function detectLanguage(sourcePath) {
|
|
8258
|
+
const name = basename2(sourcePath).toLowerCase();
|
|
8259
|
+
const ext = extname(name);
|
|
8260
|
+
if (ext !== "" && EXTENSIONS[ext] !== void 0) {
|
|
8261
|
+
return EXTENSIONS[ext];
|
|
8262
|
+
}
|
|
8263
|
+
if (FILENAMES[name] !== void 0) {
|
|
8264
|
+
return FILENAMES[name];
|
|
8265
|
+
}
|
|
8266
|
+
return shebangLanguage(sourcePath);
|
|
8267
|
+
}
|
|
8268
|
+
var MICRO_SYNTAX = {
|
|
8269
|
+
c: "c",
|
|
8270
|
+
clojure: "clojure",
|
|
8271
|
+
cmake: "cmake",
|
|
8272
|
+
crystal: "crystal",
|
|
8273
|
+
csharp: "csharp",
|
|
8274
|
+
css: "css",
|
|
8275
|
+
dart: "dart",
|
|
8276
|
+
docker: "dockerfile",
|
|
8277
|
+
elixir: "elixir",
|
|
8278
|
+
elm: "elm",
|
|
8279
|
+
erb: "erb",
|
|
8280
|
+
erlang: "erlang",
|
|
8281
|
+
fish: "fish",
|
|
8282
|
+
fsharp: "fsharp",
|
|
8283
|
+
go: "go",
|
|
8284
|
+
graphql: "graphql",
|
|
8285
|
+
groovy: "groovy",
|
|
8286
|
+
haml: "haml",
|
|
8287
|
+
haskell: "haskell",
|
|
8288
|
+
html: "html",
|
|
8289
|
+
ini: "ini",
|
|
8290
|
+
java: "java",
|
|
8291
|
+
javascript: "javascript",
|
|
8292
|
+
json: "json",
|
|
8293
|
+
julia: "julia",
|
|
8294
|
+
kotlin: "kotlin",
|
|
8295
|
+
lua: "lua",
|
|
8296
|
+
make: "makefile",
|
|
8297
|
+
markdown: "markdown",
|
|
8298
|
+
nginx: "nginx",
|
|
8299
|
+
nim: "nim",
|
|
8300
|
+
nix: "nix",
|
|
8301
|
+
"objective-c": "objc",
|
|
8302
|
+
ocaml: "ocaml",
|
|
8303
|
+
perl: "perl",
|
|
8304
|
+
php: "php",
|
|
8305
|
+
proto: "proto",
|
|
8306
|
+
python: "python3",
|
|
8307
|
+
r: "r",
|
|
8308
|
+
ruby: "ruby",
|
|
8309
|
+
rust: "rust",
|
|
8310
|
+
scala: "scala",
|
|
8311
|
+
shellscript: "sh",
|
|
8312
|
+
sql: "sql",
|
|
8313
|
+
svelte: "svelte",
|
|
8314
|
+
swift: "swift",
|
|
8315
|
+
terraform: "terraform",
|
|
8316
|
+
toml: "toml",
|
|
8317
|
+
typescript: "typescript",
|
|
8318
|
+
vue: "vue",
|
|
8319
|
+
xml: "xml",
|
|
8320
|
+
yaml: "yaml",
|
|
8321
|
+
zig: "zig",
|
|
8322
|
+
zsh: "zsh"
|
|
8323
|
+
};
|
|
8324
|
+
var VIM_FILETYPES = {
|
|
8325
|
+
shellscript: "sh",
|
|
8326
|
+
docker: "dockerfile",
|
|
8327
|
+
csharp: "cs",
|
|
8328
|
+
"objective-c": "objc",
|
|
8329
|
+
bat: "dosbatch",
|
|
8330
|
+
viml: "vim",
|
|
8331
|
+
mdx: "markdown",
|
|
8332
|
+
jsx: "javascriptreact",
|
|
8333
|
+
tsx: "typescriptreact",
|
|
8334
|
+
dotenv: "sh",
|
|
8335
|
+
properties: "jproperties",
|
|
8336
|
+
stylus: "stylus"
|
|
8016
8337
|
};
|
|
8017
|
-
function
|
|
8018
|
-
const
|
|
8019
|
-
|
|
8338
|
+
function microSyntaxName(sourcePath) {
|
|
8339
|
+
const id = detectLanguage(sourcePath);
|
|
8340
|
+
if (id === null) {
|
|
8341
|
+
return null;
|
|
8342
|
+
}
|
|
8343
|
+
return MICRO_SYNTAX[id] ?? null;
|
|
8344
|
+
}
|
|
8345
|
+
function vimFiletype(sourcePath) {
|
|
8346
|
+
const id = detectLanguage(sourcePath);
|
|
8347
|
+
if (id === null) {
|
|
8348
|
+
return null;
|
|
8349
|
+
}
|
|
8350
|
+
return VIM_FILETYPES[id] ?? id;
|
|
8020
8351
|
}
|
|
8021
8352
|
|
|
8022
8353
|
// src/editors/syntax-cache.ts
|
|
8023
|
-
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
8024
|
-
import { dirname as dirname2, join as
|
|
8354
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
|
|
8355
|
+
import { dirname as dirname2, join as join3 } from "node:path";
|
|
8025
8356
|
import { fileURLToPath } from "node:url";
|
|
8026
8357
|
function defaultAssetsDir() {
|
|
8027
8358
|
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
8028
8359
|
while (true) {
|
|
8029
|
-
const candidate =
|
|
8360
|
+
const candidate = join3(dir, "assets", "syntax");
|
|
8030
8361
|
if (existsSync2(candidate)) {
|
|
8031
8362
|
return candidate;
|
|
8032
8363
|
}
|
|
@@ -8041,20 +8372,13 @@ function syntaxSource(lang, assetsDir = defaultAssetsDir()) {
|
|
|
8041
8372
|
if (assetsDir === null) {
|
|
8042
8373
|
return null;
|
|
8043
8374
|
}
|
|
8044
|
-
const path =
|
|
8375
|
+
const path = join3(assetsDir, `${lang}.yaml`);
|
|
8045
8376
|
if (!existsSync2(path)) {
|
|
8046
8377
|
return null;
|
|
8047
8378
|
}
|
|
8048
|
-
return
|
|
8379
|
+
return readFileSync3(path, "utf-8");
|
|
8049
8380
|
}
|
|
8050
8381
|
|
|
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
8382
|
// src/editors/micro.ts
|
|
8059
8383
|
var MICRO_BINDINGS = {
|
|
8060
8384
|
F2: "QuitAll",
|
|
@@ -8085,7 +8409,7 @@ function bandRules() {
|
|
|
8085
8409
|
];
|
|
8086
8410
|
}
|
|
8087
8411
|
function writeColorScheme(configDir, theme) {
|
|
8088
|
-
const dir =
|
|
8412
|
+
const dir = join4(configDir, "colorschemes");
|
|
8089
8413
|
mkdirSync2(dir, { recursive: true });
|
|
8090
8414
|
const text = `include "monokai"
|
|
8091
8415
|
|
|
@@ -8093,7 +8417,7 @@ color-link pairadd "#d7ffd7,${theme.add}"
|
|
|
8093
8417
|
color-link pairdel "#ffd7d7,${theme.del}"
|
|
8094
8418
|
color-link pairskip "#6a6a6a,${theme.fold}"
|
|
8095
8419
|
`;
|
|
8096
|
-
writeFileSync2(
|
|
8420
|
+
writeFileSync2(join4(dir, "pair.micro"), text, "utf-8");
|
|
8097
8421
|
}
|
|
8098
8422
|
function syntaxText(lang, source) {
|
|
8099
8423
|
const parsed = (0, import_yaml.parse)(source);
|
|
@@ -8109,7 +8433,7 @@ function syntaxText(lang, source) {
|
|
|
8109
8433
|
return (0, import_yaml.stringify)(file, { lineWidth: 0 });
|
|
8110
8434
|
}
|
|
8111
8435
|
function writeSyntax(configDir, sourcePath) {
|
|
8112
|
-
const lang =
|
|
8436
|
+
const lang = microSyntaxName(sourcePath);
|
|
8113
8437
|
if (lang === null) {
|
|
8114
8438
|
return;
|
|
8115
8439
|
}
|
|
@@ -8121,9 +8445,9 @@ function writeSyntax(configDir, sourcePath) {
|
|
|
8121
8445
|
if (text === null) {
|
|
8122
8446
|
return;
|
|
8123
8447
|
}
|
|
8124
|
-
const dir =
|
|
8448
|
+
const dir = join4(configDir, "syntax");
|
|
8125
8449
|
mkdirSync2(dir, { recursive: true });
|
|
8126
|
-
writeFileSync2(
|
|
8450
|
+
writeFileSync2(join4(dir, `pair-${lang}.yaml`), text, "utf-8");
|
|
8127
8451
|
}
|
|
8128
8452
|
function createMicroEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
8129
8453
|
return {
|
|
@@ -8136,7 +8460,7 @@ function createMicroEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8136
8460
|
return ["# F3 moves between panes. Ctrl+W or F2 sends and closes."];
|
|
8137
8461
|
},
|
|
8138
8462
|
bufferSuffix(sourcePath) {
|
|
8139
|
-
const lang =
|
|
8463
|
+
const lang = microSyntaxName(sourcePath);
|
|
8140
8464
|
if (lang === null) {
|
|
8141
8465
|
return ".diff";
|
|
8142
8466
|
}
|
|
@@ -8145,12 +8469,12 @@ function createMicroEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8145
8469
|
prepare(context) {
|
|
8146
8470
|
mkdirSync2(context.configDir, { recursive: true });
|
|
8147
8471
|
writeFileSync2(
|
|
8148
|
-
|
|
8472
|
+
join4(context.configDir, "bindings.json"),
|
|
8149
8473
|
JSON.stringify(MICRO_BINDINGS, null, 2),
|
|
8150
8474
|
"utf-8"
|
|
8151
8475
|
);
|
|
8152
8476
|
writeFileSync2(
|
|
8153
|
-
|
|
8477
|
+
join4(context.configDir, "settings.json"),
|
|
8154
8478
|
JSON.stringify(MICRO_SETTINGS, null, 2),
|
|
8155
8479
|
"utf-8"
|
|
8156
8480
|
);
|
|
@@ -8174,16 +8498,6 @@ function isHexColor(value) {
|
|
|
8174
8498
|
}
|
|
8175
8499
|
|
|
8176
8500
|
// 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
8501
|
function safeThemeColor(value) {
|
|
8188
8502
|
if (!isHexColor(value)) {
|
|
8189
8503
|
throw new Error(`invalid theme colour for vim highlight: ${value}`);
|
|
@@ -8238,7 +8552,7 @@ function vimEditor(name, resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8238
8552
|
|
|
8239
8553
|
// src/editors/nano.ts
|
|
8240
8554
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
8241
|
-
import { join as
|
|
8555
|
+
import { join as join5 } from "node:path";
|
|
8242
8556
|
function safeThemeColor2(value) {
|
|
8243
8557
|
if (!isHexColor(value)) {
|
|
8244
8558
|
throw new Error(`invalid theme colour for nano rcfile: ${value}`);
|
|
@@ -8250,7 +8564,7 @@ function writeNanorc(configDir, theme) {
|
|
|
8250
8564
|
color ,${safeThemeColor2(theme.del)} "^\u258C\u258C-"
|
|
8251
8565
|
color ,${safeThemeColor2(theme.fold)} "^\u22EF"
|
|
8252
8566
|
`;
|
|
8253
|
-
const path =
|
|
8567
|
+
const path = join5(configDir, "pair.nanorc");
|
|
8254
8568
|
writeFileSync3(path, text, "utf-8");
|
|
8255
8569
|
return path;
|
|
8256
8570
|
}
|
|
@@ -8280,13 +8594,13 @@ function createNanoEditor(resolvesOnPath = defaultResolvesOnPath) {
|
|
|
8280
8594
|
|
|
8281
8595
|
// src/editors/pair.ts
|
|
8282
8596
|
import { existsSync as existsSync4 } from "node:fs";
|
|
8283
|
-
import { dirname as dirname4, extname as extname3, join as
|
|
8597
|
+
import { dirname as dirname4, extname as extname3, join as join7 } from "node:path";
|
|
8284
8598
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
8285
8599
|
|
|
8286
8600
|
// src/core/config/config.ts
|
|
8287
8601
|
import { homedir as homedir2 } from "node:os";
|
|
8288
|
-
import { join as
|
|
8289
|
-
import { existsSync as existsSync3, readFileSync as
|
|
8602
|
+
import { join as join6, dirname as dirname3 } from "node:path";
|
|
8603
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "node:fs";
|
|
8290
8604
|
var EDITOR_NAMES = ["auto", "pair", "micro", "nvim", "vim", "nano"];
|
|
8291
8605
|
var MULTIPLEXER_NAMES = ["auto", "zellij", "tmux", "none"];
|
|
8292
8606
|
var TRANSPORT_NAMES = ["pane", "session"];
|
|
@@ -8312,8 +8626,8 @@ var DEFAULT_CONFIG = {
|
|
|
8312
8626
|
syntax: true
|
|
8313
8627
|
};
|
|
8314
8628
|
function configPath(homeDir) {
|
|
8315
|
-
const base = process.env["XDG_CONFIG_HOME"] ||
|
|
8316
|
-
return
|
|
8629
|
+
const base = process.env["XDG_CONFIG_HOME"] || join6(homeDir ?? homedir2(), ".config");
|
|
8630
|
+
return join6(base, "pair-mode", "config.json");
|
|
8317
8631
|
}
|
|
8318
8632
|
function isEditorName(value) {
|
|
8319
8633
|
return typeof value === "string" && EDITOR_NAMES.includes(value);
|
|
@@ -8585,7 +8899,7 @@ function loadConfig(path) {
|
|
|
8585
8899
|
}
|
|
8586
8900
|
let text;
|
|
8587
8901
|
try {
|
|
8588
|
-
text =
|
|
8902
|
+
text = readFileSync4(target, "utf-8");
|
|
8589
8903
|
} catch (error) {
|
|
8590
8904
|
const message = error instanceof Error ? error.message : String(error);
|
|
8591
8905
|
return {
|
|
@@ -8620,7 +8934,7 @@ function paintLayout(layout) {
|
|
|
8620
8934
|
// src/editors/pair.ts
|
|
8621
8935
|
var defaultResolveTuiEntry = () => {
|
|
8622
8936
|
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
8623
|
-
return
|
|
8937
|
+
return join7(here, "pair-tui.js");
|
|
8624
8938
|
};
|
|
8625
8939
|
var defaultCheckBundleExists = existsSync4;
|
|
8626
8940
|
function createPairEditor(resolveTuiEntry = defaultResolveTuiEntry, checkBundleExists = defaultCheckBundleExists) {
|
|
@@ -8719,14 +9033,6 @@ function resolve(preference, resolvesOnPath = defaultResolvesOnPath, checkPairBu
|
|
|
8719
9033
|
return available ?? vimEditor("vim", resolvesOnPath);
|
|
8720
9034
|
}
|
|
8721
9035
|
|
|
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
9036
|
// src/multiplexers/zellij.ts
|
|
8731
9037
|
function createZellijMultiplexer(spawn = defaultSpawn, resolvesOnPath = defaultResolvesOnPath) {
|
|
8732
9038
|
return {
|
|
@@ -8756,7 +9062,7 @@ function createZellijMultiplexer(spawn = defaultSpawn, resolvesOnPath = defaultR
|
|
|
8756
9062
|
}
|
|
8757
9063
|
|
|
8758
9064
|
// src/multiplexers/tmux.ts
|
|
8759
|
-
import { randomBytes } from "node:crypto";
|
|
9065
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
8760
9066
|
var CHANNEL_BYTES = 8;
|
|
8761
9067
|
var SAFE_UNQUOTED = /^[A-Za-z0-9_\-./]+$/;
|
|
8762
9068
|
function shellQuote(value) {
|
|
@@ -8772,7 +9078,7 @@ function createTmuxMultiplexer(spawn = defaultSpawn, resolvesOnPath = defaultRes
|
|
|
8772
9078
|
return Boolean(process.env["TMUX"]) && resolvesOnPath("tmux");
|
|
8773
9079
|
},
|
|
8774
9080
|
run(argv, size) {
|
|
8775
|
-
const channel = `pair-${
|
|
9081
|
+
const channel = `pair-${randomBytes2(CHANNEL_BYTES).toString("hex")}`;
|
|
8776
9082
|
const inner = argv.map(shellQuote).join(" ");
|
|
8777
9083
|
const script = `stty -ixon 2>/dev/null; ${inner}; tmux wait-for -S ${channel}`;
|
|
8778
9084
|
const popup = spawn("tmux", [
|
|
@@ -8794,9 +9100,9 @@ function createTmuxMultiplexer(spawn = defaultSpawn, resolvesOnPath = defaultRes
|
|
|
8794
9100
|
}
|
|
8795
9101
|
|
|
8796
9102
|
// src/multiplexers/tty.ts
|
|
8797
|
-
import { openSync, closeSync } from "node:fs";
|
|
9103
|
+
import { openSync as openSync2, closeSync as closeSync2 } from "node:fs";
|
|
8798
9104
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
8799
|
-
var defaultOpen = () =>
|
|
9105
|
+
var defaultOpen = () => openSync2("/dev/tty", "r+");
|
|
8800
9106
|
var defaultRunner = (command, args, fd) => {
|
|
8801
9107
|
const result = spawnSync3(command, args, { stdio: [fd, fd, fd] });
|
|
8802
9108
|
const detail = result.status === 0 ? "" : String(result.error?.message ?? result.stderr ?? "");
|
|
@@ -8804,7 +9110,7 @@ var defaultRunner = (command, args, fd) => {
|
|
|
8804
9110
|
};
|
|
8805
9111
|
function closeQuietly(fd) {
|
|
8806
9112
|
try {
|
|
8807
|
-
|
|
9113
|
+
closeSync2(fd);
|
|
8808
9114
|
} catch {
|
|
8809
9115
|
}
|
|
8810
9116
|
}
|
|
@@ -8861,42 +9167,6 @@ function detect(preference, adapters = {}) {
|
|
|
8861
9167
|
return tty;
|
|
8862
9168
|
}
|
|
8863
9169
|
|
|
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/readPayload.ts
|
|
8875
|
-
import { readFileSync as readFileSync4 } from "node:fs";
|
|
8876
|
-
function readPayload() {
|
|
8877
|
-
const text = readFileSync4(0, "utf-8");
|
|
8878
|
-
return JSON.parse(text);
|
|
8879
|
-
}
|
|
8880
|
-
|
|
8881
|
-
// src/helpers/removeQuietly.ts
|
|
8882
|
-
import { unlinkSync as unlinkSync2 } from "node:fs";
|
|
8883
|
-
function removeQuietly(path) {
|
|
8884
|
-
try {
|
|
8885
|
-
unlinkSync2(path);
|
|
8886
|
-
} catch {
|
|
8887
|
-
}
|
|
8888
|
-
}
|
|
8889
|
-
|
|
8890
|
-
// src/helpers/resultFilePath.ts
|
|
8891
|
-
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
8892
|
-
import { tmpdir } from "node:os";
|
|
8893
|
-
import { join as join7 } from "node:path";
|
|
8894
|
-
var NAME_BYTES = 6;
|
|
8895
|
-
function resultFilePath() {
|
|
8896
|
-
const name = `pair-result-${randomBytes2(NAME_BYTES).toString("hex")}.json`;
|
|
8897
|
-
return join7(tmpdir(), name);
|
|
8898
|
-
}
|
|
8899
|
-
|
|
8900
9170
|
// src/transports/pane/pane.ts
|
|
8901
9171
|
var NAME_BYTES2 = 6;
|
|
8902
9172
|
function splitCommand(value) {
|
|
@@ -8995,6 +9265,7 @@ function createPaneTransport(deps = {}) {
|
|
|
8995
9265
|
|
|
8996
9266
|
// src/transports/session/client.ts
|
|
8997
9267
|
import { createConnection } from "node:net";
|
|
9268
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
8998
9269
|
|
|
8999
9270
|
// src/transports/session/wire.ts
|
|
9000
9271
|
var CLIENT_KINDS = ["tui", "web"];
|
|
@@ -9009,11 +9280,11 @@ function createLineReader() {
|
|
|
9009
9280
|
return parts.filter((line) => line.trim() !== "");
|
|
9010
9281
|
};
|
|
9011
9282
|
}
|
|
9012
|
-
function
|
|
9283
|
+
function isString2(value) {
|
|
9013
9284
|
return typeof value === "string";
|
|
9014
9285
|
}
|
|
9015
9286
|
function isClientKind(value) {
|
|
9016
|
-
return
|
|
9287
|
+
return isString2(value) && CLIENT_KINDS.includes(value);
|
|
9017
9288
|
}
|
|
9018
9289
|
function isQuestion(value) {
|
|
9019
9290
|
if (!isRecord(value)) {
|
|
@@ -9021,16 +9292,16 @@ function isQuestion(value) {
|
|
|
9021
9292
|
}
|
|
9022
9293
|
const line = value["line"];
|
|
9023
9294
|
const lineOk = line === null || typeof line === "number";
|
|
9024
|
-
return lineOk &&
|
|
9295
|
+
return lineOk && isString2(value["code"]) && isString2(value["text"]);
|
|
9025
9296
|
}
|
|
9026
9297
|
function isQuestionList(value) {
|
|
9027
9298
|
return Array.isArray(value) && value.every(isQuestion);
|
|
9028
9299
|
}
|
|
9029
9300
|
function toSubmit(raw) {
|
|
9030
|
-
if (!
|
|
9301
|
+
if (!isString2(raw["tool"]) || !isString2(raw["path"])) {
|
|
9031
9302
|
return null;
|
|
9032
9303
|
}
|
|
9033
|
-
if (!
|
|
9304
|
+
if (!isString2(raw["before"]) || !isString2(raw["after"])) {
|
|
9034
9305
|
return null;
|
|
9035
9306
|
}
|
|
9036
9307
|
return {
|
|
@@ -9046,7 +9317,7 @@ function toAttach(raw) {
|
|
|
9046
9317
|
}
|
|
9047
9318
|
function toReview(raw) {
|
|
9048
9319
|
const submit = toSubmit({ ...raw, type: "submit" });
|
|
9049
|
-
if (submit === null || !
|
|
9320
|
+
if (submit === null || !isString2(raw["id"])) {
|
|
9050
9321
|
return null;
|
|
9051
9322
|
}
|
|
9052
9323
|
return {
|
|
@@ -9059,13 +9330,31 @@ function toReview(raw) {
|
|
|
9059
9330
|
};
|
|
9060
9331
|
}
|
|
9061
9332
|
function toVerdict(raw) {
|
|
9062
|
-
if (!
|
|
9333
|
+
if (!isString2(raw["id"]) || !isQuestionList(raw["questions"])) {
|
|
9063
9334
|
return null;
|
|
9064
9335
|
}
|
|
9065
9336
|
return { type: "verdict", id: raw["id"], questions: raw["questions"] };
|
|
9066
9337
|
}
|
|
9067
9338
|
function toCancel(raw) {
|
|
9068
|
-
return
|
|
9339
|
+
return isString2(raw["id"]) ? { type: "cancel", id: raw["id"] } : null;
|
|
9340
|
+
}
|
|
9341
|
+
function isNumber(value) {
|
|
9342
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
9343
|
+
}
|
|
9344
|
+
function toState(raw) {
|
|
9345
|
+
const lastAttachAt = raw["lastAttachAt"];
|
|
9346
|
+
if (lastAttachAt !== null && !isString2(lastAttachAt)) {
|
|
9347
|
+
return null;
|
|
9348
|
+
}
|
|
9349
|
+
if (!isNumber(raw["clientCount"]) || !isNumber(raw["waitingDepth"])) {
|
|
9350
|
+
return null;
|
|
9351
|
+
}
|
|
9352
|
+
return {
|
|
9353
|
+
type: "state",
|
|
9354
|
+
clientCount: raw["clientCount"],
|
|
9355
|
+
waitingDepth: raw["waitingDepth"],
|
|
9356
|
+
lastAttachAt
|
|
9357
|
+
};
|
|
9069
9358
|
}
|
|
9070
9359
|
function decodeLine(line) {
|
|
9071
9360
|
let parsed;
|
|
@@ -9093,11 +9382,18 @@ function decodeLine(line) {
|
|
|
9093
9382
|
if (type === "cancel") {
|
|
9094
9383
|
return toCancel(parsed);
|
|
9095
9384
|
}
|
|
9385
|
+
if (type === "status") {
|
|
9386
|
+
return { type: "status" };
|
|
9387
|
+
}
|
|
9388
|
+
if (type === "state") {
|
|
9389
|
+
return toState(parsed);
|
|
9390
|
+
}
|
|
9096
9391
|
return null;
|
|
9097
9392
|
}
|
|
9098
9393
|
|
|
9099
9394
|
// src/transports/session/client.ts
|
|
9100
9395
|
var MS_PER_SECOND = 1e3;
|
|
9396
|
+
var NO_WATCHER = "no pair-mode watcher attached";
|
|
9101
9397
|
function failOpen(detail) {
|
|
9102
9398
|
return { reviewed: false, detail };
|
|
9103
9399
|
}
|
|
@@ -9130,7 +9426,7 @@ function requestReview(request, options) {
|
|
|
9130
9426
|
let lastError = "";
|
|
9131
9427
|
socket.on("error", (error) => {
|
|
9132
9428
|
if (isConnectionRefused(error)) {
|
|
9133
|
-
settle(failOpen(
|
|
9429
|
+
settle(failOpen(NO_WATCHER));
|
|
9134
9430
|
return;
|
|
9135
9431
|
}
|
|
9136
9432
|
lastError = error instanceof Error ? error.message : String(error);
|
|
@@ -9160,15 +9456,27 @@ function requestReview(request, options) {
|
|
|
9160
9456
|
});
|
|
9161
9457
|
});
|
|
9162
9458
|
}
|
|
9163
|
-
function reviewInSession(request, config, socketPath) {
|
|
9164
|
-
const
|
|
9165
|
-
if (
|
|
9166
|
-
return
|
|
9459
|
+
async function reviewInSession(request, config, socketPath) {
|
|
9460
|
+
const timeoutMs = config.session.timeout * MS_PER_SECOND;
|
|
9461
|
+
if (socketPath !== void 0) {
|
|
9462
|
+
return await requestReview(request, { socketPath, timeoutMs });
|
|
9167
9463
|
}
|
|
9168
|
-
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
|
|
9464
|
+
const key = keyFor(request.sessionId);
|
|
9465
|
+
const sessionPath = key === void 0 ? null : sessionKeySocketPath(key);
|
|
9466
|
+
if (sessionPath !== null && existsSync5(sessionPath)) {
|
|
9467
|
+
const outcome = await requestReview(request, { socketPath: sessionPath, timeoutMs });
|
|
9468
|
+
if (outcome.reviewed) {
|
|
9469
|
+
return outcome;
|
|
9470
|
+
}
|
|
9471
|
+
if (outcome.detail !== NO_WATCHER) {
|
|
9472
|
+
return outcome;
|
|
9473
|
+
}
|
|
9474
|
+
}
|
|
9475
|
+
const directoryPath = findSessionSocket(request.filePath);
|
|
9476
|
+
if (directoryPath === null) {
|
|
9477
|
+
return failOpen(NO_WATCHER);
|
|
9478
|
+
}
|
|
9479
|
+
return await requestReview(request, { socketPath: directoryPath, timeoutMs });
|
|
9172
9480
|
}
|
|
9173
9481
|
function createSessionTransport(socketPath) {
|
|
9174
9482
|
return {
|
|
@@ -9189,7 +9497,8 @@ async function runPair(request, config, deps = {}) {
|
|
|
9189
9497
|
if (request.before === request.after) {
|
|
9190
9498
|
return { decision: "allow", reviewed: false };
|
|
9191
9499
|
}
|
|
9192
|
-
|
|
9500
|
+
const key = keyFor(request.sessionId);
|
|
9501
|
+
if (!isEnabled(request.filePath, key)) {
|
|
9193
9502
|
return { decision: "allow", reviewed: false };
|
|
9194
9503
|
}
|
|
9195
9504
|
const transport = deps.transport ?? resolveTransport(config, deps);
|
|
@@ -9245,15 +9554,18 @@ async function main(config) {
|
|
|
9245
9554
|
if (!isRecord(toolInput)) {
|
|
9246
9555
|
return 0;
|
|
9247
9556
|
}
|
|
9557
|
+
const rawSessionId = payload["session_id"];
|
|
9558
|
+
const sessionId = typeof rawSessionId === "string" ? rawSessionId : void 0;
|
|
9248
9559
|
const filePathValue = toolInput["file_path"];
|
|
9249
9560
|
const filePath = typeof filePathValue === "string" ? filePathValue : "";
|
|
9250
9561
|
if (filePath === "") {
|
|
9251
9562
|
return 0;
|
|
9252
9563
|
}
|
|
9253
|
-
|
|
9564
|
+
const key = keyFor(sessionId);
|
|
9565
|
+
if (!isEnabled(filePath, key)) {
|
|
9254
9566
|
return 0;
|
|
9255
9567
|
}
|
|
9256
|
-
const request = simulate(tool, toolInput, readFileOrEmpty);
|
|
9568
|
+
const request = simulate(tool, toolInput, readFileOrEmpty, sessionId);
|
|
9257
9569
|
if (request === null) {
|
|
9258
9570
|
trace("exit: could not simulate", config);
|
|
9259
9571
|
return 0;
|