context-mode 2.0.0-next.6 → 2.0.0-next.8

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/cli.mjs CHANGED
@@ -88,7 +88,7 @@ var require_src = __commonJS({
88
88
  // src/entries/cli.ts
89
89
  import { spawn as spawn2 } from "node:child_process";
90
90
  import { readFileSync as readFileSync5, realpathSync as realpathSync5 } from "node:fs";
91
- import path7 from "node:path";
91
+ import path8 from "node:path";
92
92
  import { fileURLToPath as fileURLToPath2 } from "node:url";
93
93
 
94
94
  // src/core/contracts/constants.ts
@@ -240,7 +240,6 @@ var PLAIN_OUTPUT_ENV = Object.freeze({ NO_COLOR: "1", FORCE_COLOR: "0" });
240
240
  var HOST_SESSION_ENV = Object.freeze({ "claude-code": "CLAUDE_CODE_SESSION_ID" });
241
241
  var NODE_MIN = "24.15.0";
242
242
  var DATA_ROOT = "~/.context-mode";
243
- var HOST_CONFIG_DIR_NAME = ".claude";
244
243
  var HOST_PLUGINS_DIR_NAME = "plugins";
245
244
  var INSTALLED_PLUGINS_FILE = "installed_plugins.json";
246
245
  var MCP_HINT_EVERY_DEFAULT = 10;
@@ -280,7 +279,7 @@ var EDIT_PATH_KEYS = Object.freeze(["file_path", "path"]);
280
279
  var AGENT_ARG = "--agent";
281
280
  var STATS_COLUMNS = Object.freeze(["Scope", "Produced", "Returned", "Saved", "Reduction %"]);
282
281
  var PURGE_SCOPES = Object.freeze(["session", "source", "project"]);
283
- var DOCTOR_CHECK_ORDER = Object.freeze(["D1", "D2", "D3", "D4", "D5", "D5b", "D6", "D7", "D8", "D9", "D10"]);
282
+ var DOCTOR_CHECK_ORDER = Object.freeze(["D1", "D2", "D3", "D4", "D5", "D5b", "D6", "D7", "D8", "D9", "D10", "D11"]);
284
283
  var DOCTOR_LABEL = Object.freeze({
285
284
  D1: "version",
286
285
  D2: "node",
@@ -292,7 +291,8 @@ var DOCTOR_LABEL = Object.freeze({
292
291
  D7: "project and worktree",
293
292
  D8: "context.db",
294
293
  D9: "index",
295
- D10: "enforcement mode"
294
+ D10: "enforcement mode",
295
+ D11: "shell"
296
296
  });
297
297
  var REPORT_TRUNCATED_LINE = `(report truncated at ${REPORT_CAP} B; run ctx_doctor again after the first fix)`;
298
298
  var D2_NODE_FIX = `install Node ${NODE_MIN} or later`;
@@ -315,6 +315,8 @@ var GIT_HEAD_SHA_ARGS = Object.freeze(["rev-parse", "HEAD"]);
315
315
  var UPGRADE_GIT_CHECKOUT_AGENTS = Object.freeze(["pi", "opencode"]);
316
316
  var GIT_NO_PROMPT_ENV = Object.freeze({ GIT_TERMINAL_PROMPT: "0" });
317
317
  var GIT_NO_CRLF_ENV = Object.freeze({ GIT_CONFIG_COUNT: "1", GIT_CONFIG_KEY_0: "core.autocrlf", GIT_CONFIG_VALUE_0: "false" });
318
+ var WIN_SHELL_LANGS = Object.freeze(["shell", "bash", "sh"]);
319
+ var GIT_BASH_RELATIVE = Object.freeze([["..", "bin", "bash.exe"], ["..", "..", "bin", "bash.exe"]]);
318
320
  var OPS_SPLIT_FILES = Object.freeze([
319
321
  "doctor-env.ts",
320
322
  "doctor-config.ts",
@@ -331,10 +333,10 @@ var OPS_SPLIT_FILES = Object.freeze([
331
333
  var HOOK_HOST_FILE = Object.freeze({
332
334
  "claude-code": { root: "plugin", file: ["hooks", "claude-code.json"], key: ["hooks"], shape: "nested", timeoutKey: "timeout", matcher: true },
333
335
  codex: { root: "home", file: [".codex", "hooks.json"], key: ["hooks"], shape: "nested", timeoutKey: "timeout", matcher: true },
334
- gemini: { root: "home", file: [".gemini", "settings.json"], key: ["hooks"], shape: "nested", timeoutKey: "timeout", matcher: false },
335
- qwen: { root: "home", file: [".qwen", "settings.json"], key: ["hooks"], shape: "nested", timeoutKey: "timeout", matcher: true },
336
+ gemini: { root: "plugin", file: ["hooks", "hooks.json"], key: ["hooks"], shape: "nested", timeoutKey: "timeout", matcher: false },
337
+ qwen: { root: "plugin", file: ["hooks", "qwen.json"], key: ["hooks"], shape: "nested", timeoutKey: "timeout", matcher: true },
336
338
  "copilot-cli": { root: "home", file: [".copilot", "hooks", "context-mode.json"], key: ["hooks"], shape: "flat", timeoutKey: "timeoutSec", matcher: false },
337
- vscode: { root: "project", file: [".github", "hooks", "context-mode.json"], key: ["hooks"], shape: "flat", timeoutKey: "timeout", matcher: false },
339
+ vscode: { root: "home", file: [".copilot", "hooks", "context-mode-vscode.json"], key: ["hooks"], shape: "flat", timeoutKey: "timeout", matcher: false },
338
340
  kiro: { root: "home", file: [".kiro", "hooks", "context-mode.json"], key: ["hooks"], shape: "kiro", timeoutKey: "timeout", matcher: false },
339
341
  zcode: { root: "home", file: [".zcode", "cli", "config.json"], key: ["hooks", "events"], shape: "zcode", timeoutKey: "timeoutMs", matcher: true },
340
342
  pi: null,
@@ -388,6 +390,13 @@ var V1_HOOKS_DIR_NAME = "hooks";
388
390
  var SETTINGS_FILE = "settings.json";
389
391
  var CLAUDE_USER_CONFIG_FILE = ".claude.json";
390
392
  var HOOKS_JSON_FILE = "hooks.json";
393
+ var CLAUDE_CONFIG_DIR_ENV = "CLAUDE_CONFIG_DIR";
394
+ var COPILOT_HOME_ENV = "COPILOT_HOME";
395
+ var KIRO_HOME_ENV = "KIRO_HOME";
396
+ var OPENCODE_CONFIG_DIR_ENV = "OPENCODE_CONFIG_DIR";
397
+ var APPDATA_ENV = "APPDATA";
398
+ var VSCODE_USER_DIR_SEGMENTS = Object.freeze(["Code", "User"]);
399
+ var XDG_CONFIG_HOME_ENV = "XDG_CONFIG_HOME";
391
400
  var CONFIG_TOML_FILE = "config.toml";
392
401
  var CONFIG_JSON_FILE = "config.json";
393
402
  var ZCODE_CLI_DIR = "cli";
@@ -402,6 +411,7 @@ var KIRO_AGENT_NAME_KEY = "name";
402
411
  var KIRO_STEERING_FILE = Object.freeze(["steering", "KIRO.md"]);
403
412
  var PI_AGENT_DIR = "agent";
404
413
  var OPENCODE_CONFIG_FILES = Object.freeze(["opencode.jsonc", "opencode.json"]);
414
+ var OPENCODE_BASE_CONFIG_FILE = "opencode.json";
405
415
  var MCP_SERVERS_KEY = "mcpServers";
406
416
  var HOOKS_KEY = "hooks";
407
417
  var STATUS_LINE_KEY = "statusLine";
@@ -417,6 +427,8 @@ var ZCODE_EVENTS_KEY = "events";
417
427
  var PI_ROLE = "custom";
418
428
  var PI_PACKAGE_SOURCE_KEY = "source";
419
429
  var V1_PATH_SEPS = Object.freeze(["/", "\\"]);
430
+ var HOST_SEP_TOKEN = "${/}";
431
+ var HOOK_SCRIPT_SEPS = Object.freeze([...V1_PATH_SEPS, HOST_SEP_TOKEN]);
420
432
  var V1_REASON = Object.freeze({
421
433
  hook: "old context-mode hook entry: command contains context-mode and an old script name or context-mode hook",
422
434
  cacheHealHook: "old context-mode cache-heal SessionStart hook entry",
@@ -440,13 +452,20 @@ var V1_REASON = Object.freeze({
440
452
  });
441
453
  var UPGRADE_REPORT_ONLY_REASONS = Object.freeze([V1_REASON.statusLine, V1_REASON.vscodeMcp, V1_REASON.dataDirShared, V1_REASON.tmpFile, V1_REASON.kiroSteering]);
442
454
  var OPENCODE_TOOL_PREFIX = SERVER_KEY + "_";
455
+ var ATOMIC_RENAME_RETRIES = 5;
456
+ var ATOMIC_RENAME_DELAY_MS = 50;
457
+ var ATOMIC_RENAME_BUSY_CODES = ["EPERM", "EBUSY", "EACCES"];
458
+ var ATOMIC_TMP_PREFIX = ".";
459
+ var ATOMIC_TMP_MARK = ".cm-tmp-";
443
460
  var JSON_INDENT_UNIT = " ";
444
461
  var ZCODE_MCP_FEATURE_KEY = Object.freeze(["features", "mcp"]);
445
462
  var CODEX_OMIT_TOOLS_FROM_FIELD = "omit_tools_from";
446
463
  var CODEX_OMIT_DEFERRED = Object.freeze(["deferred"]);
464
+ var CODEX_APPROVAL_MODE_FIELD = "default_tools_approval_mode";
465
+ var CODEX_APPROVAL_APPROVE = "approve";
447
466
  var OWN_MCP_ENTRY = Object.freeze({
448
- codex: { file: [".codex", "config.toml"], key: ["mcp_servers", SERVER_KEY], fields: { [CODEX_OMIT_TOOLS_FROM_FIELD]: CODEX_OMIT_DEFERRED } },
449
- vscode: { file: [".vscode", "mcp.json"], key: ["servers", SERVER_KEY] },
467
+ codex: { file: [".codex", "config.toml"], key: ["mcp_servers", SERVER_KEY], fields: { [CODEX_OMIT_TOOLS_FROM_FIELD]: CODEX_OMIT_DEFERRED, [CODEX_APPROVAL_MODE_FIELD]: CODEX_APPROVAL_APPROVE } },
468
+ vscode: { file: [VSCODE_MCP_FILE], key: ["servers", SERVER_KEY] },
450
469
  kiro: { file: [".kiro", "settings", "mcp.json"], key: ["mcpServers", SERVER_KEY] },
451
470
  zcode: {
452
471
  file: [".zcode", "cli", "config.json"],
@@ -816,8 +835,14 @@ var VSCODE_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostTool
816
835
  var MCP_PREFIX2 = "mcp_";
817
836
  var MCP_SEP2 = "_";
818
837
  var SESSION_START_NEW = "new";
819
- var SHELL_TOOL_NAME = "run_in_terminal";
820
- var NATIVE_TO_CANONICAL4 = { [SHELL_TOOL_NAME]: "Bash" };
838
+ var SHELL_TOOL_NAMES = Object.freeze(["run_in_terminal", "runTerminalCommand", "bash", "powershell"]);
839
+ var READ_TOOL_NAMES = Object.freeze(["read_file", "view"]);
840
+ var WEBFETCH_TOOL_NAMES = Object.freeze(["fetch_webpage", "web_fetch"]);
841
+ var NATIVE_TO_CANONICAL4 = Object.fromEntries([
842
+ ...SHELL_TOOL_NAMES.map((n3) => [n3, "Bash"]),
843
+ ...READ_TOOL_NAMES.map((n3) => [n3, "Read"]),
844
+ ...WEBFETCH_TOOL_NAMES.map((n3) => [n3, "WebFetch"])
845
+ ]);
821
846
  function canonicalName4(name) {
822
847
  if (name.startsWith(TOOL_NAME_PREFIX6)) return name.slice(TOOL_NAME_PREFIX6.length);
823
848
  if (Object.hasOwn(NATIVE_TO_CANONICAL4, name)) return NATIVE_TO_CANONICAL4[name];
@@ -827,14 +852,88 @@ function canonicalName4(name) {
827
852
  if (sep <= 0 || sep === rest.length - 1) return name;
828
853
  return "mcp:" + rest.slice(0, sep) + ":" + rest.slice(sep + MCP_SEP2.length);
829
854
  }
855
+ var isNum = (v) => typeof v === "number" && Number.isFinite(v);
856
+ function policyInput(name, canonical, input) {
857
+ if (canonical === "Read" && READ_TOOL_NAMES.includes(name)) {
858
+ const out2 = { ...input };
859
+ if (name === "read_file") {
860
+ if (typeof input.filePath === "string") out2.file_path = input.filePath;
861
+ if (isNum(input.startLine)) out2.offset = input.startLine;
862
+ if (isNum(input.startLine) && isNum(input.endLine) && input.endLine >= input.startLine) out2.limit = input.endLine - input.startLine + 1;
863
+ } else if (Array.isArray(input.view_range) && isNum(input.view_range[0])) {
864
+ out2.offset = input.view_range[0];
865
+ const end = input.view_range[1];
866
+ if (isNum(end) && end >= input.view_range[0]) out2.limit = end - input.view_range[0] + 1;
867
+ }
868
+ return out2;
869
+ }
870
+ if (canonical === "WebFetch" && name === "fetch_webpage" && Array.isArray(input.urls) && typeof input.urls[0] === "string") {
871
+ return { ...input, url: input.urls[0] };
872
+ }
873
+ return input;
874
+ }
830
875
  function readResult4(resp) {
831
876
  const text2 = resp === void 0 ? "" : typeof resp === "string" ? resp : JSON.stringify(resp);
832
877
  const isError = typeof resp === "object" && resp !== null && resp.is_error === true;
833
878
  return { isError, bytes: Buffer.byteLength(text2), text: text2 };
834
879
  }
880
+ var CAMEL_EVENTS = {
881
+ sessionStart: "SessionStart",
882
+ userPromptSubmitted: "UserPromptSubmit",
883
+ preToolUse: "PreToolUse",
884
+ postToolUse: "PostToolUse",
885
+ preCompact: "PreCompact"
886
+ };
887
+ var EVENT_BY_KEY2 = [
888
+ ["toolResult", "postToolUse"],
889
+ ["toolName", "preToolUse"],
890
+ ["prompt", "userPromptSubmitted"],
891
+ ["source", "sessionStart"],
892
+ ["trigger", "preCompact"]
893
+ ];
894
+ var SESSION_SOURCES = { new: "startup", startup: "startup", resume: "resume" };
895
+ var RESULT_SUCCESS2 = "success";
896
+ function isRecord2(v) {
897
+ return typeof v === "object" && v !== null && !Array.isArray(v);
898
+ }
899
+ function readArgs2(v) {
900
+ if (isRecord2(v)) return v;
901
+ if (typeof v !== "string") return {};
902
+ try {
903
+ const parsed = JSON.parse(v);
904
+ return isRecord2(parsed) ? parsed : {};
905
+ } catch {
906
+ return {};
907
+ }
908
+ }
909
+ function readCamelResult(v) {
910
+ const r2 = isRecord2(v) ? v : {};
911
+ const text2 = typeof r2.textResultForLlm === "string" ? r2.textResultForLlm : "";
912
+ return { isError: typeof r2.resultType === "string" && r2.resultType !== RESULT_SUCCESS2, bytes: Buffer.byteLength(text2), text: text2 };
913
+ }
914
+ function decodeCamel(p3, name) {
915
+ const event = typeof name === "string" ? CAMEL_EVENTS[name] ?? VSCODE_EVENTS.find((e) => e === name) : void 0;
916
+ if (event === void 0) throw new Error("vscode: unknown hook event " + String(name));
917
+ const ev = { event, agent: "vscode", sessionId: String(p3.sessionId ?? ""), cwd: String(p3.cwd ?? "") };
918
+ if (event === "SessionStart" && typeof p3.source === "string" && SESSION_SOURCES[p3.source] !== void 0) ev.source = SESSION_SOURCES[p3.source];
919
+ if (event === "UserPromptSubmit" && typeof p3.prompt === "string") ev.prompt = p3.prompt;
920
+ if (event === "PreToolUse" || event === "PostToolUse") {
921
+ const toolName = String(p3.toolName ?? "");
922
+ const canonical = canonicalName4(toolName);
923
+ ev.tool = { name: toolName, canonicalName: canonical, input: policyInput(toolName, canonical, readArgs2(p3.toolArgs)) };
924
+ }
925
+ if (event === "PostToolUse") ev.result = readCamelResult(p3.toolResult);
926
+ return ev;
927
+ }
835
928
  function decode6(raw) {
836
929
  if (typeof raw !== "object" || raw === null || Array.isArray(raw)) throw new Error("vscode: hook payload is not a JSON object");
837
930
  const p3 = raw;
931
+ if (p3.hookEventName !== void 0) return decodeCamel(p3, p3.hookEventName);
932
+ if (p3.hook_event_name === void 0) {
933
+ const byKey = EVENT_BY_KEY2.find(([key]) => Object.hasOwn(p3, key))?.[1];
934
+ if (byKey === void 0) throw new Error("vscode: missing required field hook_event_name");
935
+ return decodeCamel(p3, byKey);
936
+ }
838
937
  const event = VSCODE_EVENTS.find((e) => e === p3.hook_event_name);
839
938
  if (event === void 0) throw new Error("vscode: unknown hook event " + String(p3.hook_event_name));
840
939
  const ev = { event, agent: "vscode", sessionId: String(p3.session_id ?? ""), cwd: String(p3.cwd ?? "") };
@@ -842,8 +941,9 @@ function decode6(raw) {
842
941
  if (event === "UserPromptSubmit" && typeof p3.prompt === "string") ev.prompt = p3.prompt;
843
942
  if (event === "PreToolUse" || event === "PostToolUse") {
844
943
  const name = String(p3.tool_name ?? "");
845
- const input = typeof p3.tool_input === "object" && p3.tool_input !== null && !Array.isArray(p3.tool_input) ? p3.tool_input : {};
846
- ev.tool = { name, canonicalName: canonicalName4(name), input };
944
+ const input = isRecord2(p3.tool_input) ? p3.tool_input : {};
945
+ const canonical = canonicalName4(name);
946
+ ev.tool = { name, canonicalName: canonical, input: policyInput(name, canonical, input) };
847
947
  }
848
948
  if (event === "PostToolUse") ev.result = readResult4(p3.tool_response);
849
949
  return ev;
@@ -861,12 +961,14 @@ var KIRO_EVENTS = {
861
961
  PromptSubmit: "UserPromptSubmit",
862
962
  userPromptSubmit: "UserPromptSubmit",
863
963
  PreToolUse: "PreToolUse",
864
- PostToolUse: "PostToolUse"
964
+ preToolUse: "PreToolUse",
965
+ PostToolUse: "PostToolUse",
966
+ postToolUse: "PostToolUse"
865
967
  };
866
968
  var PROMPT_ENV = "USER_PROMPT";
867
969
  var MCP_PREFIX3 = "mcp_";
868
- var SHELL_TOOL_NAME2 = "execute_bash";
869
- var NATIVE_TO_CANONICAL5 = { [SHELL_TOOL_NAME2]: "Bash" };
970
+ var SHELL_TOOL_NAMES2 = Object.freeze(["execute_bash", "execute_pwsh", "shell"]);
971
+ var NATIVE_TO_CANONICAL5 = Object.fromEntries(SHELL_TOOL_NAMES2.map((n3) => [n3, "Bash"]));
870
972
  var MCP_SEP3 = "_";
871
973
  var KIRO_SOURCES = { startup: "startup", resume: "resume", clear: "clear", compact: "compact" };
872
974
  function canonicalName5(name) {
@@ -1007,8 +1109,8 @@ var OPENCODE_EVENTS = {
1007
1109
  compaction: "PreCompact",
1008
1110
  "step-finish": "Usage"
1009
1111
  };
1010
- var SHELL_TOOL_NAME3 = "bash";
1011
- var NATIVE_TO_CANONICAL7 = { webfetch: "WebFetch", [SHELL_TOOL_NAME3]: "Bash" };
1112
+ var SHELL_TOOL_NAME = "bash";
1113
+ var NATIVE_TO_CANONICAL7 = { webfetch: "WebFetch", [SHELL_TOOL_NAME]: "Bash" };
1012
1114
  function toCanonicalTool(name) {
1013
1115
  if (name.startsWith(OWN_WIRE_PREFIX)) return name.slice(OWN_WIRE_PREFIX.length);
1014
1116
  return Object.prototype.hasOwnProperty.call(NATIVE_TO_CANONICAL7, name) ? NATIVE_TO_CANONICAL7[name] : name;
@@ -1128,8 +1230,8 @@ var ADAPTERS = Object.freeze([
1128
1230
  hookTimeoutMs: HOOK_TIMEOUT_MS,
1129
1231
  denyChannel: "deny-reason",
1130
1232
  hookChannel: { kind: "package", path: "hooks/qwen.json" },
1131
- skillChannel: { kind: "home-dir", path: ".qwen/skills" },
1132
- // ADR-0020
1233
+ skillChannel: { kind: "package", path: "skills" },
1234
+ // ADR-0020, D-HQ-SKILLS-3: qwen loads <extension>/skills, shared with gemini
1133
1235
  decode: decode4,
1134
1236
  encode: encode4
1135
1237
  },
@@ -1157,7 +1259,8 @@ var ADAPTERS = Object.freeze([
1157
1259
  projectSource: "arg:workspaceFolder",
1158
1260
  toolNamePrefix: TOOL_NAME_PREFIX6,
1159
1261
  // PreCompact sets the pending flag (ADR-0009 §6, DEVIATIONS D-M3-A4-1).
1160
- nativeTools: { shell: [SHELL_TOOL_NAME] },
1262
+ nativeTools: { shell: [...SHELL_TOOL_NAMES], read: [...READ_TOOL_NAMES], webfetch: [...WEBFETCH_TOOL_NAMES] },
1263
+ // D-HF-VSCODE-PROJECT-1, D-N7-VSCODE-TOOLS-1
1161
1264
  execReadOnlyHint: false,
1162
1265
  eventMap: { ...CLAUDE_EVENTS, PreCompact: "PreCompact" },
1163
1266
  compactDelivery: "pending-flag",
@@ -1165,8 +1268,8 @@ var ADAPTERS = Object.freeze([
1165
1268
  hookTimeoutMs: HOOK_TIMEOUT_MS,
1166
1269
  denyChannel: "deny-reason",
1167
1270
  hookChannel: { kind: "home-file", path: ".copilot/hooks/context-mode-vscode.json" },
1168
- skillChannel: { kind: "home-dir", path: ".copilot/skills" },
1169
- // ADR-0020
1271
+ skillChannel: { kind: "home-dir", path: ".agents/skills" },
1272
+ // ADR-0020, D-HQ-COPILOT-NAMES-3: Copilot CLI owns ~/.copilot/skills
1170
1273
  decode: decode6,
1171
1274
  encode: encode6
1172
1275
  },
@@ -1175,9 +1278,9 @@ var ADAPTERS = Object.freeze([
1175
1278
  installMode: "mcp-entry",
1176
1279
  projectSource: "arg:--agent+cwd",
1177
1280
  toolNamePrefix: TOOL_NAME_PREFIX7,
1178
- nativeTools: { shell: [SHELL_TOOL_NAME2] },
1281
+ nativeTools: { shell: [...SHELL_TOOL_NAMES2] },
1179
1282
  execReadOnlyHint: false,
1180
- // D-HF-KIRO-SHELL-1
1283
+ // D-HF-KIRO-SHELL-1, D-N7-KIRO-1
1181
1284
  eventMap: { SessionStart: "SessionStart", UserPromptSubmit: "UserPromptSubmit", PreToolUse: "PreToolUse", PostToolUse: "PostToolUse" },
1182
1285
  compactDelivery: "none",
1183
1286
  compactSummary: "none",
@@ -1190,7 +1293,7 @@ var ADAPTERS = Object.freeze([
1190
1293
  encode: encode7
1191
1294
  },
1192
1295
  {
1193
- // toolNamePrefix and nativeTools unverified until T-ZC (DECISIONS-r9 R3, R4: Claude names).
1296
+ // toolNamePrefix is the documented ZCode name mcp__<server>__<tool> (D-N7-ZCODE-NAMES-1); nativeTools are Claude names.
1194
1297
  id: "zcode",
1195
1298
  installMode: "hooks+mcp",
1196
1299
  projectSource: "spawn-cwd",
@@ -1232,7 +1335,7 @@ var ADAPTERS = Object.freeze([
1232
1335
  installMode: "in-process",
1233
1336
  projectSource: "spawn-cwd",
1234
1337
  toolNamePrefix: TOOL_NAME_PREFIX10,
1235
- nativeTools: { shell: [SHELL_TOOL_NAME3] },
1338
+ nativeTools: { shell: [SHELL_TOOL_NAME] },
1236
1339
  execReadOnlyHint: false,
1237
1340
  // D-HF-OPENCODE-SHELL-1
1238
1341
  // Usage: step-finish cost row (DEVIATIONS D-M5-arch-2).
@@ -1462,11 +1565,11 @@ Examples:
1462
1565
  };
1463
1566
 
1464
1567
  // src/cli/commands.ts
1465
- import { spawnSync as spawnSync2 } from "node:child_process";
1568
+ import { spawnSync as spawnSync3 } from "node:child_process";
1466
1569
  import { createHash as createHash2 } from "node:crypto";
1467
- import { existsSync as existsSync7, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
1570
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "node:fs";
1468
1571
  import os from "node:os";
1469
- import path6 from "node:path";
1572
+ import path7 from "node:path";
1470
1573
 
1471
1574
  // node_modules/@clack/prompts/dist/index.mjs
1472
1575
  var dist_exports = {};
@@ -1756,17 +1859,17 @@ var wrapWord = (rows, word, columns) => {
1756
1859
  };
1757
1860
  var stringVisibleTrimSpacesRight = (string) => {
1758
1861
  const words = string.split(" ");
1759
- let last = words.length;
1760
- while (last) {
1761
- if (dist_default2(words[last - 1])) {
1862
+ let last2 = words.length;
1863
+ while (last2) {
1864
+ if (dist_default2(words[last2 - 1])) {
1762
1865
  break;
1763
1866
  }
1764
- last--;
1867
+ last2--;
1765
1868
  }
1766
- if (last === words.length) {
1869
+ if (last2 === words.length) {
1767
1870
  return string;
1768
1871
  }
1769
- return words.slice(0, last).join(" ") + words.slice(last).join("");
1872
+ return words.slice(0, last2).join(" ") + words.slice(last2).join("");
1770
1873
  };
1771
1874
  var exec = (string, columns, options = {}) => {
1772
1875
  if (options.trim !== false && string.trim() === "") {
@@ -4283,14 +4386,8 @@ ${i2}
4283
4386
  }
4284
4387
  }).prompt();
4285
4388
 
4286
- // src/setup/registry.ts
4287
- import path2 from "node:path";
4288
-
4289
- // src/core/ops/doctor-config.ts
4290
- import { join as join6 } from "node:path";
4291
-
4292
4389
  // src/core/project/config-dir.ts
4293
- import { join as join2 } from "node:path";
4390
+ import { join as join2, posix, win32 } from "node:path";
4294
4391
 
4295
4392
  // src/core/contracts/errors.ts
4296
4393
  var ERROR_TEXT = Object.freeze({
@@ -4300,6 +4397,8 @@ var ERROR_TEXT = Object.freeze({
4300
4397
  NO_PROJECT: "Project source <kind> is missing. Fix: run ctx_doctor.",
4301
4398
  UNKNOWN_FIELD: 'Unknown field "<f>". Fix: use "queries".',
4302
4399
  TIMEOUT: "Timed out after <ms> ms. Fix: pass background: true.",
4400
+ NO_GIT_BASH: "Git Bash not found. Fix: install Git for Windows.",
4401
+ // D-VT-WINBASH-1
4303
4402
  NO_RUNTIME: "No <lang> runtime on PATH. Fix: install it or pick another language.",
4304
4403
  FETCH_FAILED: "Fetch failed: <code>. Fix: check the URL or proxy.",
4305
4404
  SSRF: "Blocked private address <host>. Fix: use a public URL.",
@@ -4362,294 +4461,2200 @@ var CtxError = class extends Error {
4362
4461
 
4363
4462
  // src/core/project/config-dir.ts
4364
4463
  var { mkdirSync, realpathSync } = process.getBuiltinModule("node:fs");
4464
+ function homeDirOf(env, platform = process.platform) {
4465
+ const set2 = (v) => v !== void 0 && v !== "";
4466
+ if (platform === "win32") {
4467
+ if (set2(env.USERPROFILE)) return env.USERPROFILE;
4468
+ if (set2(env.HOMEDRIVE) && set2(env.HOMEPATH)) return env.HOMEDRIVE + env.HOMEPATH;
4469
+ return set2(env.HOME) ? env.HOME : null;
4470
+ }
4471
+ if (set2(env.HOME)) return env.HOME;
4472
+ return set2(env.USERPROFILE) ? env.USERPROFILE : null;
4473
+ }
4474
+ function copilotDirOf(env, home) {
4475
+ const dir = env[COPILOT_HOME_ENV];
4476
+ return dir !== void 0 && dir !== "" ? dir : join2(home, ...AGENT_HOME_DIR["copilot-cli"]);
4477
+ }
4478
+ function kiroDirOf(env, home, platform = process.platform) {
4479
+ const p3 = platform === "win32" ? win32 : posix;
4480
+ const fallback = p3.join(home, ...AGENT_HOME_DIR.kiro);
4481
+ const dir = env[KIRO_HOME_ENV];
4482
+ if (dir === void 0 || dir === "" || !p3.isAbsolute(dir)) return fallback;
4483
+ if (platform === "win32" && p3.parse(dir).root.length < 2) return fallback;
4484
+ const abs = p3.resolve(dir);
4485
+ if (p3.dirname(abs) === abs) return fallback;
4486
+ const up = p3.relative(abs, p3.resolve(home));
4487
+ if (!p3.isAbsolute(up) && up.split(p3.sep)[0] !== "..") return fallback;
4488
+ return dir;
4489
+ }
4490
+ function claudeDirOf(env, home) {
4491
+ const dir = env[CLAUDE_CONFIG_DIR_ENV];
4492
+ return dir !== void 0 && dir !== "" ? dir : join2(home, ...AGENT_HOME_DIR["claude-code"]);
4493
+ }
4494
+ function opencodeDirOf(env, home) {
4495
+ const own2 = env[OPENCODE_CONFIG_DIR_ENV];
4496
+ if (own2 !== void 0 && own2 !== "") return own2;
4497
+ const xdg = env[XDG_CONFIG_HOME_ENV];
4498
+ if (xdg !== void 0 && xdg !== "") return join2(xdg, AGENT_HOME_DIR.opencode[AGENT_HOME_DIR.opencode.length - 1]);
4499
+ return join2(home, ...AGENT_HOME_DIR.opencode);
4500
+ }
4501
+ function vscodeUserDirOf(env, home, platform = process.platform) {
4502
+ const set2 = (v) => v !== void 0 && v !== "";
4503
+ const p3 = platform === "win32" ? win32 : posix;
4504
+ if (platform === "win32") return p3.join(set2(env[APPDATA_ENV]) ? env[APPDATA_ENV] : p3.join(home, "AppData", "Roaming"), ...VSCODE_USER_DIR_SEGMENTS);
4505
+ if (platform === "darwin") return p3.join(home, "Library", "Application Support", ...VSCODE_USER_DIR_SEGMENTS);
4506
+ return p3.join(set2(env[XDG_CONFIG_HOME_ENV]) ? env[XDG_CONFIG_HOME_ENV] : p3.join(home, ".config"), ...VSCODE_USER_DIR_SEGMENTS);
4507
+ }
4508
+ function ownMcpFileOf(agent, file, env, home) {
4509
+ if (agent === "kiro") return join2(kiroDirOf(env, home), ...file.slice(1));
4510
+ return agent === "vscode" ? join2(vscodeUserDirOf(env, home), ...file) : join2(home, ...file);
4511
+ }
4512
+
4513
+ // src/setup/registry.ts
4514
+ import path3 from "node:path";
4515
+
4516
+ // src/core/ops/doctor-config.ts
4517
+ import { join as join6 } from "node:path";
4365
4518
 
4366
4519
  // src/core/ops/detect-v1.ts
4367
- import { existsSync as existsSync2, opendirSync, readdirSync as readdirSync2, readFileSync } from "node:fs";
4520
+ import { existsSync as existsSync3, opendirSync, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "node:fs";
4368
4521
  import { tmpdir } from "node:os";
4369
- import { join as join3 } from "node:path";
4370
- var isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
4371
- var keyPath = (...parts) => parts.join(".");
4372
- var finding = (file, path8, reason) => ({ file, path: path8, reason });
4373
- function stripJsonc(text2) {
4374
- let out2 = "";
4375
- let inStr = false;
4376
- let esc = false;
4377
- for (let i2 = 0; i2 < text2.length; i2++) {
4378
- const c3 = text2[i2];
4379
- if (inStr) {
4380
- out2 += c3;
4381
- if (esc) esc = false;
4382
- else if (c3 === "\\") esc = true;
4383
- else if (c3 === '"') inStr = false;
4384
- continue;
4385
- }
4386
- if (c3 === '"') {
4387
- inStr = true;
4388
- out2 += c3;
4389
- continue;
4390
- }
4391
- if (c3 === "/" && text2[i2 + 1] === "/") {
4392
- while (i2 < text2.length && text2[i2] !== "\n") i2++;
4393
- out2 += "\n";
4394
- continue;
4395
- }
4396
- if (c3 === "/" && text2[i2 + 1] === "*") {
4397
- const end = text2.indexOf("*/", i2 + 2);
4398
- i2 = end === -1 ? text2.length : end + 1;
4399
- continue;
4400
- }
4401
- if (c3 === ",") {
4402
- let j2 = i2 + 1;
4403
- while (j2 < text2.length && " \r\n".includes(text2[j2])) j2++;
4404
- if (text2[j2] === "}" || text2[j2] === "]") continue;
4522
+ import { join as join4 } from "node:path";
4523
+
4524
+ // src/core/ops/host-config.ts
4525
+ import { existsSync as existsSync2, readFileSync } from "node:fs";
4526
+ import { dirname as dirname2, join as join3 } from "node:path";
4527
+
4528
+ // node_modules/eslint-visitor-keys/lib/visitor-keys.js
4529
+ var KEYS2 = {
4530
+ ArrayExpression: ["elements"],
4531
+ ArrayPattern: ["elements"],
4532
+ ArrowFunctionExpression: ["params", "body"],
4533
+ AssignmentExpression: ["left", "right"],
4534
+ AssignmentPattern: ["left", "right"],
4535
+ AwaitExpression: ["argument"],
4536
+ BinaryExpression: ["left", "right"],
4537
+ BlockStatement: ["body"],
4538
+ BreakStatement: ["label"],
4539
+ CallExpression: ["callee", "arguments"],
4540
+ CatchClause: ["param", "body"],
4541
+ ChainExpression: ["expression"],
4542
+ ClassBody: ["body"],
4543
+ ClassDeclaration: ["id", "superClass", "body"],
4544
+ ClassExpression: ["id", "superClass", "body"],
4545
+ ConditionalExpression: ["test", "consequent", "alternate"],
4546
+ ContinueStatement: ["label"],
4547
+ DebuggerStatement: [],
4548
+ DoWhileStatement: ["body", "test"],
4549
+ EmptyStatement: [],
4550
+ ExperimentalRestProperty: ["argument"],
4551
+ ExperimentalSpreadProperty: ["argument"],
4552
+ ExportAllDeclaration: ["exported", "source", "attributes"],
4553
+ ExportDefaultDeclaration: ["declaration"],
4554
+ ExportNamedDeclaration: [
4555
+ "declaration",
4556
+ "specifiers",
4557
+ "source",
4558
+ "attributes"
4559
+ ],
4560
+ ExportSpecifier: ["local", "exported"],
4561
+ ExpressionStatement: ["expression"],
4562
+ ForInStatement: ["left", "right", "body"],
4563
+ ForOfStatement: ["left", "right", "body"],
4564
+ ForStatement: ["init", "test", "update", "body"],
4565
+ FunctionDeclaration: ["id", "params", "body"],
4566
+ FunctionExpression: ["id", "params", "body"],
4567
+ Identifier: [],
4568
+ IfStatement: ["test", "consequent", "alternate"],
4569
+ ImportAttribute: ["key", "value"],
4570
+ ImportDeclaration: ["specifiers", "source", "attributes"],
4571
+ ImportDefaultSpecifier: ["local"],
4572
+ ImportExpression: ["source", "options"],
4573
+ ImportNamespaceSpecifier: ["local"],
4574
+ ImportSpecifier: ["imported", "local"],
4575
+ JSXAttribute: ["name", "value"],
4576
+ JSXClosingElement: ["name"],
4577
+ JSXClosingFragment: [],
4578
+ JSXElement: ["openingElement", "children", "closingElement"],
4579
+ JSXEmptyExpression: [],
4580
+ JSXExpressionContainer: ["expression"],
4581
+ JSXFragment: ["openingFragment", "children", "closingFragment"],
4582
+ JSXIdentifier: [],
4583
+ JSXMemberExpression: ["object", "property"],
4584
+ JSXNamespacedName: ["namespace", "name"],
4585
+ JSXOpeningElement: ["name", "attributes"],
4586
+ JSXOpeningFragment: [],
4587
+ JSXSpreadAttribute: ["argument"],
4588
+ JSXSpreadChild: ["expression"],
4589
+ JSXText: [],
4590
+ LabeledStatement: ["label", "body"],
4591
+ Literal: [],
4592
+ LogicalExpression: ["left", "right"],
4593
+ MemberExpression: ["object", "property"],
4594
+ MetaProperty: ["meta", "property"],
4595
+ MethodDefinition: ["key", "value"],
4596
+ NewExpression: ["callee", "arguments"],
4597
+ ObjectExpression: ["properties"],
4598
+ ObjectPattern: ["properties"],
4599
+ PrivateIdentifier: [],
4600
+ Program: ["body"],
4601
+ Property: ["key", "value"],
4602
+ PropertyDefinition: ["key", "value"],
4603
+ RestElement: ["argument"],
4604
+ ReturnStatement: ["argument"],
4605
+ SequenceExpression: ["expressions"],
4606
+ SpreadElement: ["argument"],
4607
+ StaticBlock: ["body"],
4608
+ Super: [],
4609
+ SwitchCase: ["test", "consequent"],
4610
+ SwitchStatement: ["discriminant", "cases"],
4611
+ TaggedTemplateExpression: ["tag", "quasi"],
4612
+ TemplateElement: [],
4613
+ TemplateLiteral: ["quasis", "expressions"],
4614
+ ThisExpression: [],
4615
+ ThrowStatement: ["argument"],
4616
+ TryStatement: ["block", "handler", "finalizer"],
4617
+ UnaryExpression: ["argument"],
4618
+ UpdateExpression: ["argument"],
4619
+ VariableDeclaration: ["declarations"],
4620
+ VariableDeclarator: ["id", "init"],
4621
+ WhileStatement: ["test", "body"],
4622
+ WithStatement: ["object", "body"],
4623
+ YieldExpression: ["argument"]
4624
+ };
4625
+ var NODE_TYPES = Object.keys(KEYS2);
4626
+ for (const type of NODE_TYPES) {
4627
+ Object.freeze(KEYS2[type]);
4628
+ }
4629
+ Object.freeze(KEYS2);
4630
+ var visitor_keys_default = KEYS2;
4631
+
4632
+ // node_modules/eslint-visitor-keys/lib/index.js
4633
+ function unionWith(additionalKeys) {
4634
+ const retv = (
4635
+ /** @type {{ [type: string]: ReadonlyArray<string> }} */
4636
+ Object.assign({}, visitor_keys_default)
4637
+ );
4638
+ for (const type of Object.keys(additionalKeys)) {
4639
+ if (Object.hasOwn(retv, type)) {
4640
+ const keys = new Set(additionalKeys[type]);
4641
+ for (const key of retv[type]) {
4642
+ keys.add(key);
4643
+ }
4644
+ retv[type] = Object.freeze(Array.from(keys));
4645
+ } else {
4646
+ retv[type] = Object.freeze(Array.from(additionalKeys[type]));
4405
4647
  }
4406
- out2 += c3;
4407
4648
  }
4408
- return out2;
4649
+ return Object.freeze(retv);
4409
4650
  }
4410
- function readJson(file) {
4411
- try {
4412
- return JSON.parse(stripJsonc(readFileSync(file, "utf8")));
4413
- } catch {
4414
- return void 0;
4415
- }
4651
+
4652
+ // node_modules/toml-eslint-parser/lib/index.mjs
4653
+ function last(arr) {
4654
+ return arr[arr.length - 1] ?? null;
4416
4655
  }
4417
- function readText(file) {
4418
- try {
4419
- return readFileSync(file, "utf8");
4420
- } catch {
4421
- return "";
4422
- }
4656
+ function toKeyName(node) {
4657
+ return node.type === "TOMLBare" ? node.name : node.value;
4423
4658
  }
4424
- var listOf = (v) => Array.isArray(v) ? v : [];
4425
- var commandOf = (v) => isObj(v) && typeof v.command === "string" ? v.command : null;
4426
- function nestedCommands(doc) {
4427
- const out2 = [];
4428
- if (!isObj(doc) || !isObj(doc[HOOKS_KEY])) return out2;
4429
- for (const [event, groups] of Object.entries(doc[HOOKS_KEY])) {
4430
- listOf(groups).forEach((group2, i2) => {
4431
- if (!isObj(group2)) return;
4432
- listOf(group2[HOOKS_KEY]).forEach((inner, j2) => {
4433
- const command = commandOf(inner);
4434
- if (command !== null) out2.push({ path: keyPath(HOOKS_KEY, event, i2, HOOKS_KEY, j2), command });
4435
- });
4436
- });
4659
+ var TOMLVerImpl = class {
4660
+ constructor(major, minor) {
4661
+ this.major = major;
4662
+ this.minor = minor;
4437
4663
  }
4438
- return out2;
4664
+ lt(major, minor) {
4665
+ return this.major < major || this.major === major && this.minor < minor;
4666
+ }
4667
+ gte(major, minor) {
4668
+ return this.major > major || this.major === major && this.minor >= minor;
4669
+ }
4670
+ };
4671
+ var TOML_VERSION_1_0 = new TOMLVerImpl(1, 0);
4672
+ var TOML_VERSION_1_1 = new TOMLVerImpl(1, 1);
4673
+ var DEFAULT_TOML_VERSION = TOML_VERSION_1_1;
4674
+ var SUPPORTED_TOML_VERSIONS = {
4675
+ "1.0": TOML_VERSION_1_0,
4676
+ "1.0.0": TOML_VERSION_1_0,
4677
+ "1.1": TOML_VERSION_1_1,
4678
+ "1.1.0": TOML_VERSION_1_1,
4679
+ latest: TOML_VERSION_1_1,
4680
+ next: TOML_VERSION_1_1
4681
+ };
4682
+ function getTOMLVer(v) {
4683
+ return v && SUPPORTED_TOML_VERSIONS[v] || DEFAULT_TOML_VERSION;
4684
+ }
4685
+ var MESSAGES = {
4686
+ "unterminated-string": "Unterminated string constant",
4687
+ "unterminated-table-key": "Unterminated table-key",
4688
+ "unterminated-array": "Unterminated array",
4689
+ "unterminated-inline-table": "Unterminated inline table",
4690
+ "missing-key": "Empty bare keys are not allowed",
4691
+ "missing-newline": "Must be a newline",
4692
+ "missing-equals-sign": "Expected equal (=) token",
4693
+ "missing-value": "Unspecified values are invalid",
4694
+ "missing-comma": "Expected comma (,) token",
4695
+ "dupe-keys": "Defining a key multiple times is invalid",
4696
+ "unexpected-char": "Unexpected character",
4697
+ "unexpected-token": "Unexpected token",
4698
+ "invalid-control-character": "Control characters (codes < 0x1f and 0x7f) are not allowed",
4699
+ "invalid-comment-character": "Invalid code point {{cp}} within comments",
4700
+ "invalid-key-value-newline": "The key, equals sign, and value must be on the same line",
4701
+ "invalid-inline-table-newline": "No newlines are allowed between the curly braces unless they are valid within a value",
4702
+ "invalid-underscore": "Underscores are allowed between digits",
4703
+ "invalid-space": "Unexpected spaces",
4704
+ "invalid-three-quotes": "Three or more quotes are not permitted",
4705
+ "invalid-date": "Unexpected invalid date",
4706
+ "invalid-time": "Unexpected invalid time",
4707
+ "invalid-leading-zero": "Leading zeros are not allowed",
4708
+ "invalid-trailing-comma-in-inline-table": "Trailing comma is not permitted in an inline table",
4709
+ "invalid-char-in-escape-sequence": "Invalid character in escape sequence",
4710
+ "invalid-consecutive-dots-in-key": "Consecutive dots are not permitted in keys",
4711
+ "invalid-code-point": "Invalid code point {{cp}}",
4712
+ "invalid-trailing-dot-in-key": "Keys cannot end with a dot",
4713
+ "invalid-leading-dot-in-key": "Keys cannot start with a dot"
4714
+ };
4715
+ function getMessage(code, data) {
4716
+ if (data) return MESSAGES[code].replace(/\{\{(.*?)\}\}/gu, (_2, name$2) => {
4717
+ if (name$2 in data) return data[name$2];
4718
+ return `{{${name$2}}}`;
4719
+ });
4720
+ return MESSAGES[code];
4439
4721
  }
4440
- function flatCommands(events2, prefix) {
4441
- const out2 = [];
4442
- if (!isObj(events2)) return out2;
4443
- for (const [event, entries] of Object.entries(events2)) {
4444
- listOf(entries).forEach((entry2, i2) => {
4445
- const command = commandOf(entry2);
4446
- if (command !== null) out2.push({ path: keyPath(...prefix, event, i2), command });
4447
- });
4722
+ var ParseError = class extends SyntaxError {
4723
+ /**
4724
+ * Initialize this ParseError instance.
4725
+ *
4726
+ */
4727
+ constructor(code, offset, line, column, data) {
4728
+ super(getMessage(code, data));
4729
+ this.index = offset;
4730
+ this.lineNumber = line;
4731
+ this.column = column;
4448
4732
  }
4449
- return out2;
4733
+ };
4734
+ var CodePoint = {
4735
+ EOF: -1,
4736
+ NULL: 0,
4737
+ SOH: 1,
4738
+ BACKSPACE: 8,
4739
+ TABULATION: 9,
4740
+ LINE_FEED: 10,
4741
+ FORM_FEED: 12,
4742
+ CARRIAGE_RETURN: 13,
4743
+ ESCAPE: 27,
4744
+ SO: 14,
4745
+ US: 31,
4746
+ SPACE: 32,
4747
+ QUOTATION_MARK: 34,
4748
+ HASH: 35,
4749
+ SINGLE_QUOTE: 39,
4750
+ PLUS_SIGN: 43,
4751
+ COMMA: 44,
4752
+ DASH: 45,
4753
+ DOT: 46,
4754
+ DIGIT_0: 48,
4755
+ DIGIT_1: 49,
4756
+ DIGIT_2: 50,
4757
+ DIGIT_3: 51,
4758
+ DIGIT_7: 55,
4759
+ DIGIT_9: 57,
4760
+ COLON: 58,
4761
+ EQUALS_SIGN: 61,
4762
+ LATIN_CAPITAL_A: 65,
4763
+ LATIN_CAPITAL_E: 69,
4764
+ LATIN_CAPITAL_F: 70,
4765
+ LATIN_CAPITAL_T: 84,
4766
+ LATIN_CAPITAL_U: 85,
4767
+ LATIN_CAPITAL_Z: 90,
4768
+ LEFT_BRACKET: 91,
4769
+ BACKSLASH: 92,
4770
+ RIGHT_BRACKET: 93,
4771
+ UNDERSCORE: 95,
4772
+ LATIN_SMALL_A: 97,
4773
+ LATIN_SMALL_B: 98,
4774
+ LATIN_SMALL_E: 101,
4775
+ LATIN_SMALL_F: 102,
4776
+ LATIN_SMALL_I: 105,
4777
+ LATIN_SMALL_L: 108,
4778
+ LATIN_SMALL_N: 110,
4779
+ LATIN_SMALL_O: 111,
4780
+ LATIN_SMALL_R: 114,
4781
+ LATIN_SMALL_S: 115,
4782
+ LATIN_SMALL_T: 116,
4783
+ LATIN_SMALL_U: 117,
4784
+ LATIN_SMALL_X: 120,
4785
+ LATIN_SMALL_Z: 122,
4786
+ LEFT_BRACE: 123,
4787
+ RIGHT_BRACE: 125,
4788
+ TILDE: 126,
4789
+ DELETE: 127,
4790
+ PAD: 128,
4791
+ SUPERSCRIPT_TWO: 178,
4792
+ SUPERSCRIPT_THREE: 179,
4793
+ SUPERSCRIPT_ONE: 185,
4794
+ VULGAR_FRACTION_ONE_QUARTER: 188,
4795
+ VULGAR_FRACTION_THREE_QUARTERS: 190,
4796
+ LATIN_CAPITAL_LETTER_A_WITH_GRAVE: 192,
4797
+ LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS: 214,
4798
+ LATIN_CAPITAL_LETTER_O_WITH_STROKE: 216,
4799
+ LATIN_SMALL_LETTER_O_WITH_DIAERESIS: 246,
4800
+ LATIN_SMALL_LETTER_O_WITH_STROKE: 248,
4801
+ GREEK_SMALL_REVERSED_DOTTED_LUNATE_SIGMA_SYMBOL: 891,
4802
+ GREEK_CAPITAL_LETTER_YOT: 895,
4803
+ CP_1FFF: 8191,
4804
+ ZERO_WIDTH_NON_JOINER: 8204,
4805
+ ZERO_WIDTH_JOINER: 8205,
4806
+ UNDERTIE: 8255,
4807
+ CHARACTER_TIE: 8256,
4808
+ SUPERSCRIPT_ZERO: 8304,
4809
+ CP_218F: 8591,
4810
+ CIRCLED_DIGIT_ONE: 9312,
4811
+ NEGATIVE_CIRCLED_DIGIT_ZERO: 9471,
4812
+ GLAGOLITIC_CAPITAL_LETTER_AZU: 11264,
4813
+ CP_2FEF: 12271,
4814
+ IDEOGRAPHIC_COMMA: 12289,
4815
+ CP_D7FF: 55295,
4816
+ CP_E000: 57344,
4817
+ CJK_COMPATIBILITY_IDEOGRAPH_F900: 63744,
4818
+ ARABIC_LIGATURE_SALAAMUHU_ALAYNAA: 64975,
4819
+ ARABIC_LIGATURE_SALLA_USED_AS_KORANIC_STOP_SIGN_ISOLATED_FORM: 65008,
4820
+ REPLACEMENT_CHARACTER: 65533,
4821
+ LINEAR_B_SYLLABLE_B008_A: 65536,
4822
+ CP_EFFFF: 983039,
4823
+ CP_10FFFF: 1114111
4824
+ };
4825
+ function isControl(cp) {
4826
+ return cp >= CodePoint.NULL && cp <= CodePoint.US;
4450
4827
  }
4451
- var isV1Hook = (cmd) => cmd.includes(SERVER_KEY) && (V1_SCRIPT_NAMES.some((name) => cmd.includes(name)) || cmd.includes(V1_HOOK_COMMAND));
4452
- var isCodexScript = (cmd) => cmd.includes(V1_SCRIPT_EXT) && V1_PATH_SEPS.some((sep) => cmd.includes(V1_CODEX_HOOKS_DIR.join(sep) + sep));
4453
- function dataDir(dir, reason, out2) {
4454
- if (existsSync2(dir)) out2.push(finding(dir, "", reason));
4828
+ function isWhitespace(cp) {
4829
+ return cp === CodePoint.TABULATION || cp === CodePoint.SPACE;
4455
4830
  }
4456
- function mcpEntry(file, doc, out2) {
4457
- if (isObj(doc) && isObj(doc[MCP_SERVERS_KEY]) && Object.hasOwn(doc[MCP_SERVERS_KEY], SERVER_KEY)) {
4458
- out2.push(finding(file, keyPath(MCP_SERVERS_KEY, SERVER_KEY), V1_REASON.mcpEntry));
4459
- }
4831
+ function isEOL(cp) {
4832
+ return cp === CodePoint.LINE_FEED || cp === CodePoint.CARRIAGE_RETURN;
4460
4833
  }
4461
- function claudeShapeSettings(agentHome, out2) {
4462
- const file = join3(agentHome, SETTINGS_FILE);
4463
- const doc = readJson(file);
4464
- for (const c3 of nestedCommands(doc)) {
4465
- if (c3.command.includes(V1_CACHE_HEAL_NAME)) out2.push(finding(file, c3.path, V1_REASON.cacheHealHook));
4466
- else if (isV1Hook(c3.command)) out2.push(finding(file, c3.path, V1_REASON.hook));
4467
- }
4468
- const status = isObj(doc) ? commandOf(doc[STATUS_LINE_KEY]) : null;
4469
- if (status !== null && status.includes(V1_STATUSLINE_COMMAND)) {
4470
- out2.push(finding(file, STATUS_LINE_KEY, V1_REASON.statusLine));
4471
- }
4472
- mcpEntry(file, doc, out2);
4834
+ function isUpperLetter(cp) {
4835
+ return cp >= CodePoint.LATIN_CAPITAL_A && cp <= CodePoint.LATIN_CAPITAL_Z;
4473
4836
  }
4474
- function v1HookFile(file, out2) {
4475
- const doc = readJson(file);
4476
- const cmds = isObj(doc) ? flatCommands(doc[HOOKS_KEY], [HOOKS_KEY]) : [];
4477
- if (cmds.some((c3) => c3.command.includes(V1_HOOK_COMMAND))) out2.push(finding(file, "", V1_REASON.hookFile));
4837
+ function isLowerLetter(cp) {
4838
+ return cp >= CodePoint.LATIN_SMALL_A && cp <= CodePoint.LATIN_SMALL_Z;
4478
4839
  }
4479
- function scanClaudeCode(home, agentHome, out2) {
4480
- claudeShapeSettings(agentHome, out2);
4481
- for (const ext of V1_CACHE_HEAL_EXTS) {
4482
- const file = join3(agentHome, V1_HOOKS_DIR_NAME, V1_CACHE_HEAL_NAME + ext);
4483
- if (existsSync2(file)) out2.push(finding(file, "", V1_REASON.cacheHealFile));
4484
- }
4485
- const userFile = join3(home, CLAUDE_USER_CONFIG_FILE);
4486
- mcpEntry(userFile, readJson(userFile), out2);
4487
- dataDir(join3(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
4840
+ function isLetter(cp) {
4841
+ return isLowerLetter(cp) || isUpperLetter(cp);
4488
4842
  }
4489
- function scanCodex(agentHome, out2) {
4490
- const hooksFile = join3(agentHome, HOOKS_JSON_FILE);
4491
- for (const c3 of nestedCommands(readJson(hooksFile))) {
4492
- if (c3.command.includes(V1_CODEX_HOOK_COMMAND) || isCodexScript(c3.command)) {
4493
- out2.push(finding(hooksFile, c3.path, V1_REASON.codexHook));
4494
- }
4495
- }
4496
- const tomlFile = join3(agentHome, CONFIG_TOML_FILE);
4497
- for (const line of readText(tomlFile).split("\n")) {
4498
- const header = line.trim();
4499
- if (header.startsWith(V1_TOML_SECTION_PREFIX)) out2.push(finding(tomlFile, header, V1_REASON.codexToml));
4500
- }
4501
- dataDir(join3(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
4843
+ function isDigit(cp) {
4844
+ return cp >= CodePoint.DIGIT_0 && cp <= CodePoint.DIGIT_9;
4502
4845
  }
4503
- function scanGemini(agentHome, out2) {
4504
- const file = join3(agentHome, SETTINGS_FILE);
4505
- for (const c3 of nestedCommands(readJson(file))) {
4506
- if (c3.command.includes(SERVER_KEY)) out2.push(finding(file, c3.path, V1_REASON.hook));
4846
+ function isHexDig(cp) {
4847
+ return isDigit(cp) || cp >= CodePoint.LATIN_SMALL_A && cp <= CodePoint.LATIN_SMALL_F || cp >= CodePoint.LATIN_CAPITAL_A && cp <= CodePoint.LATIN_CAPITAL_F;
4848
+ }
4849
+ function isOctalDig(cp) {
4850
+ return cp >= CodePoint.DIGIT_0 && cp <= CodePoint.DIGIT_7;
4851
+ }
4852
+ function isUnicodeScalarValue(cp) {
4853
+ return cp >= 0 && cp <= 55295 || cp >= 57344 && cp <= 1114111;
4854
+ }
4855
+ function sortedLastIndex(array, value) {
4856
+ let low = 0;
4857
+ let high = array.length;
4858
+ while (low < high) {
4859
+ const mid = low + high >>> 1;
4860
+ const val = array[mid];
4861
+ if (val === value) return mid + 1;
4862
+ if (val < value) low = mid + 1;
4863
+ else high = mid;
4507
4864
  }
4508
- dataDir(join3(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDirShared, out2);
4865
+ return low;
4509
4866
  }
4510
- function scanVscode(agentHome, project, out2) {
4511
- if (project !== void 0) {
4512
- v1HookFile(join3(project, GITHUB_DIR_NAME, V1_HOOKS_DIR_NAME, OWN_HOOK_FILE), out2);
4513
- const mcpFile = join3(project, VSCODE_DIR_NAME, VSCODE_MCP_FILE);
4514
- const doc = readJson(mcpFile);
4515
- const servers = isObj(doc) && isObj(doc[VSCODE_MCP_SERVERS_KEY]) ? doc[VSCODE_MCP_SERVERS_KEY] : {};
4516
- const entry2 = Object.hasOwn(servers, SERVER_KEY) ? servers[SERVER_KEY] : void 0;
4517
- if (isObj(entry2) && (entry2.command === V1_BIN_COMMAND || listOf(entry2.args).some((a2) => a2 === V1_BIN_COMMAND))) {
4518
- out2.push(finding(mcpFile, keyPath(VSCODE_MCP_SERVERS_KEY, SERVER_KEY), V1_REASON.vscodeMcp));
4867
+ var Locations = class {
4868
+ constructor() {
4869
+ this.offsets = [];
4870
+ }
4871
+ addOffset(offset) {
4872
+ for (let i2 = this.offsets.length - 1; i2 >= 0; i2--) {
4873
+ const element = this.offsets[i2];
4874
+ if (element === offset) return;
4875
+ if (element < offset) break;
4519
4876
  }
4520
- dataDir(join3(project, GITHUB_DIR_NAME, V1_DATA_DIR_NAME, V1_SESSIONS_DIR_NAME), V1_REASON.dataDir, out2);
4877
+ this.offsets.push(offset);
4521
4878
  }
4522
- dataDir(join3(agentHome, V1_DATA_DIR_NAME, V1_SESSIONS_DIR_NAME), V1_REASON.dataDir, out2);
4523
- }
4524
- function jsonFiles(dir) {
4525
- try {
4526
- return readdirSync2(dir).filter((name) => name.endsWith(KIRO_AGENT_FILE_EXT)).sort();
4527
- } catch {
4528
- return [];
4879
+ /**
4880
+ * Calculate the location of the given index.
4881
+ * @param index The index to calculate their location.
4882
+ * @returns The location of the index.
4883
+ */
4884
+ getLocFromIndex(offset) {
4885
+ const line = sortedLastIndex(this.offsets, offset) + 1;
4886
+ return {
4887
+ line,
4888
+ column: offset - (line === 1 ? 0 : this.offsets[line - 2])
4889
+ };
4529
4890
  }
4530
- }
4531
- function scanKiro(agentHome, project, out2) {
4532
- const agentsDir = join3(agentHome, KIRO_AGENTS_DIR);
4533
- const defaultFile = join3(agentHome, ...KIRO_AGENT_FILE);
4534
- for (const name of jsonFiles(agentsDir)) {
4535
- const file = join3(agentsDir, name);
4536
- const doc = readJson(file);
4537
- if (isObj(doc) && doc[KIRO_AGENT_NAME_KEY] === SERVER_KEY) {
4538
- out2.push(finding(file, "", V1_REASON.kiroAgentFile));
4539
- continue;
4891
+ };
4892
+ var CodePointIterator = class {
4893
+ /**
4894
+ * Initialize this char iterator.
4895
+ */
4896
+ constructor(text2) {
4897
+ this.locs = new Locations();
4898
+ this.lastCodePoint = CodePoint.NULL;
4899
+ this.start = -1;
4900
+ this.end = 0;
4901
+ this.text = text2;
4902
+ }
4903
+ next() {
4904
+ if (this.lastCodePoint === CodePoint.EOF) return CodePoint.EOF;
4905
+ return this.lastCodePoint = this.moveAt(this.end);
4906
+ }
4907
+ getLocFromIndex(index) {
4908
+ return this.locs.getLocFromIndex(index);
4909
+ }
4910
+ eat(cp) {
4911
+ if (this.text.codePointAt(this.end) === cp) {
4912
+ this.next();
4913
+ return true;
4540
4914
  }
4541
- if (file !== defaultFile) continue;
4542
- for (const c3 of isObj(doc) ? flatCommands(doc[HOOKS_KEY], [HOOKS_KEY]) : []) {
4543
- if (isV1Hook(c3.command)) out2.push(finding(file, c3.path, V1_REASON.kiroHook));
4915
+ return false;
4916
+ }
4917
+ moveAt(offset) {
4918
+ this.start = this.end = offset;
4919
+ const cp = this.text.codePointAt(this.start) ?? CodePoint.EOF;
4920
+ if (cp === CodePoint.EOF) {
4921
+ this.end = this.start;
4922
+ return cp;
4544
4923
  }
4924
+ this.end += cp >= 65536 ? 2 : 1;
4925
+ if (cp === CodePoint.LINE_FEED) this.locs.addOffset(this.end);
4926
+ else if (cp === CodePoint.CARRIAGE_RETURN) {
4927
+ if (this.text.codePointAt(this.end) === CodePoint.LINE_FEED) {
4928
+ this.end++;
4929
+ this.locs.addOffset(this.end);
4930
+ }
4931
+ return CodePoint.LINE_FEED;
4932
+ }
4933
+ return cp;
4545
4934
  }
4546
- const steeringDocs = [join3(agentHome, ...KIRO_STEERING_FILE)];
4547
- if (project !== void 0) steeringDocs.push(join3(project, ...AGENT_HOME_DIR.kiro, ...KIRO_STEERING_FILE));
4548
- for (const file of steeringDocs) {
4549
- if (existsSync2(file)) out2.push(finding(file, "", V1_REASON.kiroSteering));
4935
+ };
4936
+ var HAS_BIGINT = typeof BigInt !== "undefined";
4937
+ var RADIX_PREFIXES = {
4938
+ 16: "0x",
4939
+ 10: "",
4940
+ 8: "0o",
4941
+ 2: "0b"
4942
+ };
4943
+ var ESCAPES_1_0 = {
4944
+ [CodePoint.QUOTATION_MARK]: CodePoint.QUOTATION_MARK,
4945
+ [CodePoint.BACKSLASH]: CodePoint.BACKSLASH,
4946
+ [CodePoint.LATIN_SMALL_B]: CodePoint.BACKSPACE,
4947
+ [CodePoint.LATIN_SMALL_F]: CodePoint.FORM_FEED,
4948
+ [CodePoint.LATIN_SMALL_N]: CodePoint.LINE_FEED,
4949
+ [CodePoint.LATIN_SMALL_R]: CodePoint.CARRIAGE_RETURN,
4950
+ [CodePoint.LATIN_SMALL_T]: CodePoint.TABULATION
4951
+ };
4952
+ var ESCAPES_LATEST = {
4953
+ ...ESCAPES_1_0,
4954
+ [CodePoint.LATIN_SMALL_E]: CodePoint.ESCAPE
4955
+ };
4956
+ var Tokenizer = class {
4957
+ /**
4958
+ * Initialize this tokenizer.
4959
+ */
4960
+ constructor(text2, parserOptions) {
4961
+ this.backCode = false;
4962
+ this.lastCodePoint = CodePoint.NULL;
4963
+ this.state = "DATA";
4964
+ this.token = null;
4965
+ this.tokenStart = -1;
4966
+ this.valuesEnabled = false;
4967
+ this.text = text2;
4968
+ this.parserOptions = parserOptions || {};
4969
+ this.codePointIterator = new CodePointIterator(text2);
4970
+ this.tomlVersion = getTOMLVer(this.parserOptions.tomlVersion);
4971
+ this.ESCAPES = this.tomlVersion.gte(1, 1) ? ESCAPES_LATEST : ESCAPES_1_0;
4972
+ }
4973
+ get start() {
4974
+ return this.codePointIterator.start;
4975
+ }
4976
+ get end() {
4977
+ return this.codePointIterator.end;
4978
+ }
4979
+ getLocFromIndex(index) {
4980
+ return this.codePointIterator.getLocFromIndex(index);
4550
4981
  }
4551
- dataDir(join3(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
4552
- }
4553
- function scanPi(piAgentDir, agentHome, out2) {
4554
- const file = join3(piAgentDir, SETTINGS_FILE);
4555
- const doc = readJson(file);
4556
- listOf(isObj(doc) ? doc[PI_PACKAGES_KEY] : void 0).forEach((pkg, i2) => {
4557
- const spec = isObj(pkg) ? pkg[PI_PACKAGE_SOURCE_KEY] : pkg;
4558
- if (spec === V1_PI_PACKAGE) out2.push(finding(file, keyPath(PI_PACKAGES_KEY, i2), V1_REASON.piNpm));
4559
- });
4560
- dataDir(join3(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
4561
- }
4562
- function scanOpencode(agentHome, out2) {
4563
- for (const name of OPENCODE_CONFIG_FILES) {
4564
- const file = join3(agentHome, name);
4565
- const doc = readJson(file);
4566
- if (!isObj(doc) || !Array.isArray(doc[OPENCODE_PLUGIN_KEY])) continue;
4567
- doc[OPENCODE_PLUGIN_KEY].forEach((spec, i2) => {
4568
- if (spec === V1_OPENCODE_PLUGIN_SPEC) out2.push(finding(file, keyPath(OPENCODE_PLUGIN_KEY, i2), V1_REASON.opencodePlugin));
4569
- });
4570
- return;
4982
+ /**
4983
+ * Report an invalid character error.
4984
+ */
4985
+ reportParseError(code, data) {
4986
+ const offset = this.codePointIterator.start;
4987
+ const loc = this.codePointIterator.getLocFromIndex(offset);
4988
+ throw new ParseError(code, offset, loc.line, loc.column, data);
4571
4989
  }
4572
- }
4573
- function scanZcode(agentHome, out2) {
4574
- const configFile = join3(agentHome, ZCODE_CLI_DIR, CONFIG_JSON_FILE);
4575
- const config = readJson(configFile);
4576
- const events2 = isObj(config) && isObj(config[HOOKS_KEY]) ? config[HOOKS_KEY][ZCODE_EVENTS_KEY] : void 0;
4577
- for (const c3 of flatCommands(events2, [HOOKS_KEY, ZCODE_EVENTS_KEY])) {
4578
- if (c3.command.includes(V1_HOOK_COMMAND)) out2.push(finding(configFile, c3.path, V1_REASON.zcodeHook));
4990
+ /**
4991
+ * Get the next token.
4992
+ */
4993
+ nextToken() {
4994
+ let token = this.token;
4995
+ if (token != null) {
4996
+ this.token = null;
4997
+ return token;
4998
+ }
4999
+ let cp = this.lastCodePoint;
5000
+ while (cp !== CodePoint.EOF && !this.token) {
5001
+ cp = this.nextCode();
5002
+ const nextState = this[this.state](cp);
5003
+ if (!nextState) throw new Error(`Unknown error: pre state=${this.state}`);
5004
+ this.state = nextState;
5005
+ }
5006
+ token = this.token;
5007
+ this.token = null;
5008
+ return token;
4579
5009
  }
4580
- const hooksFile = join3(agentHome, ZCODE_CLI_DIR, HOOKS_JSON_FILE);
4581
- for (const c3 of nestedCommands(readJson(hooksFile))) {
4582
- if (c3.command.includes(V1_HOOK_COMMAND)) out2.push(finding(hooksFile, c3.path, V1_REASON.zcodeHook));
5010
+ /**
5011
+ * Get the next code point.
5012
+ */
5013
+ nextCode() {
5014
+ if (this.lastCodePoint === CodePoint.EOF) return CodePoint.EOF;
5015
+ if (this.backCode) {
5016
+ this.backCode = false;
5017
+ return this.lastCodePoint;
5018
+ }
5019
+ return this.lastCodePoint = this.codePointIterator.next();
4583
5020
  }
4584
- }
4585
- function firstTmpMatch(dir) {
4586
- let handle;
4587
- try {
4588
- handle = opendirSync(dir);
4589
- } catch {
4590
- return null;
5021
+ /**
5022
+ * Eat the next code point.
5023
+ */
5024
+ eatCode(cp) {
5025
+ if (this.lastCodePoint === CodePoint.EOF) return false;
5026
+ if (this.backCode) {
5027
+ if (this.lastCodePoint === cp) {
5028
+ this.backCode = false;
5029
+ return true;
5030
+ }
5031
+ return false;
5032
+ }
5033
+ return this.codePointIterator.eat(cp);
4591
5034
  }
4592
- try {
4593
- for (let e = handle.readSync(); e !== null; e = handle.readSync()) {
4594
- if (e.name.startsWith(V1_TMP_PREFIX)) return e.name;
5035
+ /**
5036
+ * Moves the character position to the given position.
5037
+ */
5038
+ moveAt(loc) {
5039
+ if (this.backCode) this.backCode = false;
5040
+ this.lastCodePoint = this.codePointIterator.moveAt(loc);
5041
+ }
5042
+ /**
5043
+ * Back the current code point as the given state.
5044
+ */
5045
+ back(state) {
5046
+ this.backCode = true;
5047
+ return state;
5048
+ }
5049
+ punctuatorToken() {
5050
+ this.startToken();
5051
+ this.endToken("Punctuator", "end");
5052
+ }
5053
+ startToken() {
5054
+ this.tokenStart = this.codePointIterator.start;
5055
+ }
5056
+ /**
5057
+ * Commit the current token.
5058
+ */
5059
+ endToken(type, pos, option1, option2) {
5060
+ const { tokenStart } = this;
5061
+ const end = this.codePointIterator[pos];
5062
+ const range = [tokenStart, end];
5063
+ const loc = {
5064
+ start: this.codePointIterator.getLocFromIndex(tokenStart),
5065
+ end: this.codePointIterator.getLocFromIndex(end)
5066
+ };
5067
+ if (type === "Block") this.token = {
5068
+ type,
5069
+ value: this.text.slice(tokenStart + 1, end),
5070
+ range,
5071
+ loc
5072
+ };
5073
+ else {
5074
+ let token;
5075
+ const value = this.text.slice(tokenStart, end);
5076
+ if (type === "BasicString" || type === "LiteralString" || type === "MultiLineBasicString" || type === "MultiLineLiteralString") token = {
5077
+ type,
5078
+ value,
5079
+ string: option1,
5080
+ range,
5081
+ loc
5082
+ };
5083
+ else if (type === "Integer") {
5084
+ const text2 = option1;
5085
+ token = {
5086
+ type,
5087
+ value,
5088
+ number: parseInt(text2, option2),
5089
+ bigint: HAS_BIGINT ? BigInt(RADIX_PREFIXES[option2] + text2) : null,
5090
+ range,
5091
+ loc
5092
+ };
5093
+ } else if (type === "Float") token = {
5094
+ type,
5095
+ value,
5096
+ number: option1,
5097
+ range,
5098
+ loc
5099
+ };
5100
+ else if (type === "Boolean") token = {
5101
+ type,
5102
+ value,
5103
+ boolean: option1,
5104
+ range,
5105
+ loc
5106
+ };
5107
+ else if (type === "LocalDate" || type === "LocalTime" || type === "LocalDateTime" || type === "OffsetDateTime") token = {
5108
+ type,
5109
+ value,
5110
+ date: option1,
5111
+ range,
5112
+ loc
5113
+ };
5114
+ else token = {
5115
+ type,
5116
+ value,
5117
+ range,
5118
+ loc
5119
+ };
5120
+ this.token = token;
4595
5121
  }
4596
- return null;
4597
- } catch {
4598
- return null;
4599
- } finally {
4600
- handle.closeSync();
4601
5122
  }
5123
+ DATA(cp) {
5124
+ while (isWhitespace(cp) || isEOL(cp)) cp = this.nextCode();
5125
+ if (cp === CodePoint.HASH) {
5126
+ this.startToken();
5127
+ return "COMMENT";
5128
+ }
5129
+ if (cp === CodePoint.QUOTATION_MARK) {
5130
+ this.startToken();
5131
+ return "BASIC_STRING";
5132
+ }
5133
+ if (cp === CodePoint.SINGLE_QUOTE) {
5134
+ this.startToken();
5135
+ return "LITERAL_STRING";
5136
+ }
5137
+ if (cp === CodePoint.DOT || cp === CodePoint.EQUALS_SIGN || cp === CodePoint.LEFT_BRACKET || cp === CodePoint.RIGHT_BRACKET || cp === CodePoint.LEFT_BRACE || cp === CodePoint.RIGHT_BRACE || cp === CodePoint.COMMA) {
5138
+ this.punctuatorToken();
5139
+ return "DATA";
5140
+ }
5141
+ if (this.valuesEnabled) {
5142
+ if (cp === CodePoint.DASH || cp === CodePoint.PLUS_SIGN) {
5143
+ this.startToken();
5144
+ return "SIGN";
5145
+ }
5146
+ if (cp === CodePoint.LATIN_SMALL_N || cp === CodePoint.LATIN_SMALL_I) {
5147
+ this.startToken();
5148
+ return this.back("NAN_OR_INF");
5149
+ }
5150
+ if (isDigit(cp)) {
5151
+ this.startToken();
5152
+ return this.back("NUMBER");
5153
+ }
5154
+ if (cp === CodePoint.LATIN_SMALL_T || cp === CodePoint.LATIN_SMALL_F) {
5155
+ this.startToken();
5156
+ return this.back("BOOLEAN");
5157
+ }
5158
+ } else if (isUnquotedKeyChar(cp, this.tomlVersion)) {
5159
+ this.startToken();
5160
+ return "BARE";
5161
+ }
5162
+ if (cp === CodePoint.EOF) return "DATA";
5163
+ return this.reportParseError("unexpected-char");
5164
+ }
5165
+ COMMENT(cp) {
5166
+ const processCommentChar = this.tomlVersion.gte(1, 1) ? (c3) => {
5167
+ if (!isNonEOL(c3)) this.reportParseError("invalid-comment-character", { cp: JSON.stringify(String.fromCodePoint(c3)).slice(1, -1) });
5168
+ } : (c3) => {
5169
+ if (isControlOtherThanTab(c3)) this.reportParseErrorControlChar();
5170
+ };
5171
+ while (!isEOL(cp) && cp !== CodePoint.EOF) {
5172
+ processCommentChar(cp);
5173
+ cp = this.nextCode();
5174
+ }
5175
+ this.endToken("Block", "start");
5176
+ return "DATA";
5177
+ }
5178
+ BARE(cp) {
5179
+ while (isUnquotedKeyChar(cp, this.tomlVersion)) cp = this.nextCode();
5180
+ this.endToken("Bare", "start");
5181
+ return this.back("DATA");
5182
+ }
5183
+ BASIC_STRING(cp) {
5184
+ if (cp === CodePoint.QUOTATION_MARK) {
5185
+ cp = this.nextCode();
5186
+ if (cp === CodePoint.QUOTATION_MARK) return "MULTI_LINE_BASIC_STRING";
5187
+ this.endToken("BasicString", "start", "");
5188
+ return this.back("DATA");
5189
+ }
5190
+ const out2 = [];
5191
+ while (cp !== CodePoint.QUOTATION_MARK && cp !== CodePoint.EOF && cp !== CodePoint.LINE_FEED) {
5192
+ if (isControlOtherThanTab(cp)) return this.reportParseErrorControlChar();
5193
+ if (cp === CodePoint.BACKSLASH) {
5194
+ cp = this.nextCode();
5195
+ const ecp = this.ESCAPES[cp];
5196
+ if (ecp) {
5197
+ out2.push(ecp);
5198
+ cp = this.nextCode();
5199
+ continue;
5200
+ } else if (cp === CodePoint.LATIN_SMALL_U) {
5201
+ const code = this.parseUnicode(4);
5202
+ out2.push(code);
5203
+ cp = this.nextCode();
5204
+ continue;
5205
+ } else if (cp === CodePoint.LATIN_CAPITAL_U) {
5206
+ const code = this.parseUnicode(8);
5207
+ out2.push(code);
5208
+ cp = this.nextCode();
5209
+ continue;
5210
+ } else if (cp === CodePoint.LATIN_SMALL_X && this.tomlVersion.gte(1, 1)) {
5211
+ const code = this.parseUnicode(2);
5212
+ out2.push(code);
5213
+ cp = this.nextCode();
5214
+ continue;
5215
+ }
5216
+ return this.reportParseError("invalid-char-in-escape-sequence");
5217
+ }
5218
+ out2.push(cp);
5219
+ cp = this.nextCode();
5220
+ }
5221
+ if (cp !== CodePoint.QUOTATION_MARK) return this.reportParseError("unterminated-string");
5222
+ this.endToken("BasicString", "end", String.fromCodePoint(...out2));
5223
+ return "DATA";
5224
+ }
5225
+ MULTI_LINE_BASIC_STRING(cp) {
5226
+ const out2 = [];
5227
+ if (cp === CodePoint.LINE_FEED) cp = this.nextCode();
5228
+ while (cp !== CodePoint.EOF) {
5229
+ if (cp !== CodePoint.LINE_FEED && isControlOtherThanTab(cp)) return this.reportParseErrorControlChar();
5230
+ if (cp === CodePoint.QUOTATION_MARK) {
5231
+ const startPos = this.codePointIterator.start;
5232
+ if (this.eatCode(CodePoint.QUOTATION_MARK) && this.eatCode(CodePoint.QUOTATION_MARK)) {
5233
+ if (this.eatCode(CodePoint.QUOTATION_MARK)) {
5234
+ out2.push(CodePoint.QUOTATION_MARK);
5235
+ if (this.eatCode(CodePoint.QUOTATION_MARK)) {
5236
+ out2.push(CodePoint.QUOTATION_MARK);
5237
+ if (this.eatCode(CodePoint.QUOTATION_MARK)) {
5238
+ this.moveAt(startPos);
5239
+ return this.reportParseError("invalid-three-quotes");
5240
+ }
5241
+ }
5242
+ }
5243
+ this.endToken("MultiLineBasicString", "end", String.fromCodePoint(...out2));
5244
+ return "DATA";
5245
+ }
5246
+ this.moveAt(startPos);
5247
+ }
5248
+ if (cp === CodePoint.BACKSLASH) {
5249
+ cp = this.nextCode();
5250
+ const ecp = this.ESCAPES[cp];
5251
+ if (ecp) {
5252
+ out2.push(ecp);
5253
+ cp = this.nextCode();
5254
+ continue;
5255
+ } else if (cp === CodePoint.LATIN_SMALL_U) {
5256
+ const code = this.parseUnicode(4);
5257
+ out2.push(code);
5258
+ cp = this.nextCode();
5259
+ continue;
5260
+ } else if (cp === CodePoint.LATIN_CAPITAL_U) {
5261
+ const code = this.parseUnicode(8);
5262
+ out2.push(code);
5263
+ cp = this.nextCode();
5264
+ continue;
5265
+ } else if (cp === CodePoint.LATIN_SMALL_X && this.tomlVersion.gte(1, 1)) {
5266
+ const code = this.parseUnicode(2);
5267
+ out2.push(code);
5268
+ cp = this.nextCode();
5269
+ continue;
5270
+ } else if (cp === CodePoint.LINE_FEED) {
5271
+ cp = this.nextCode();
5272
+ while (isWhitespace(cp) || cp === CodePoint.LINE_FEED) cp = this.nextCode();
5273
+ continue;
5274
+ } else if (isWhitespace(cp)) {
5275
+ let valid = true;
5276
+ const startPos = this.codePointIterator.start;
5277
+ let nextCp;
5278
+ while ((nextCp = this.nextCode()) !== CodePoint.EOF) {
5279
+ if (nextCp === CodePoint.LINE_FEED) break;
5280
+ if (!isWhitespace(nextCp)) {
5281
+ this.moveAt(startPos);
5282
+ valid = false;
5283
+ break;
5284
+ }
5285
+ }
5286
+ if (valid) {
5287
+ cp = this.nextCode();
5288
+ while (isWhitespace(cp) || cp === CodePoint.LINE_FEED) cp = this.nextCode();
5289
+ continue;
5290
+ }
5291
+ }
5292
+ return this.reportParseError("invalid-char-in-escape-sequence");
5293
+ }
5294
+ out2.push(cp);
5295
+ cp = this.nextCode();
5296
+ }
5297
+ return this.reportParseError("unterminated-string");
5298
+ }
5299
+ LITERAL_STRING(cp) {
5300
+ if (cp === CodePoint.SINGLE_QUOTE) {
5301
+ cp = this.nextCode();
5302
+ if (cp === CodePoint.SINGLE_QUOTE) return "MULTI_LINE_LITERAL_STRING";
5303
+ this.endToken("LiteralString", "start", "");
5304
+ return this.back("DATA");
5305
+ }
5306
+ const out2 = [];
5307
+ while (cp !== CodePoint.SINGLE_QUOTE && cp !== CodePoint.EOF && cp !== CodePoint.LINE_FEED) {
5308
+ if (isControlOtherThanTab(cp)) return this.reportParseErrorControlChar();
5309
+ out2.push(cp);
5310
+ cp = this.nextCode();
5311
+ }
5312
+ if (cp !== CodePoint.SINGLE_QUOTE) return this.reportParseError("unterminated-string");
5313
+ this.endToken("LiteralString", "end", String.fromCodePoint(...out2));
5314
+ return "DATA";
5315
+ }
5316
+ MULTI_LINE_LITERAL_STRING(cp) {
5317
+ const out2 = [];
5318
+ if (cp === CodePoint.LINE_FEED) cp = this.nextCode();
5319
+ while (cp !== CodePoint.EOF) {
5320
+ if (cp !== CodePoint.LINE_FEED && isControlOtherThanTab(cp)) return this.reportParseErrorControlChar();
5321
+ if (cp === CodePoint.SINGLE_QUOTE) {
5322
+ const startPos = this.codePointIterator.start;
5323
+ if (this.eatCode(CodePoint.SINGLE_QUOTE) && this.eatCode(CodePoint.SINGLE_QUOTE)) {
5324
+ if (this.eatCode(CodePoint.SINGLE_QUOTE)) {
5325
+ out2.push(CodePoint.SINGLE_QUOTE);
5326
+ if (this.eatCode(CodePoint.SINGLE_QUOTE)) {
5327
+ out2.push(CodePoint.SINGLE_QUOTE);
5328
+ if (this.eatCode(CodePoint.SINGLE_QUOTE)) {
5329
+ this.moveAt(startPos);
5330
+ return this.reportParseError("invalid-three-quotes");
5331
+ }
5332
+ }
5333
+ }
5334
+ this.endToken("MultiLineLiteralString", "end", String.fromCodePoint(...out2));
5335
+ return "DATA";
5336
+ }
5337
+ this.moveAt(startPos);
5338
+ }
5339
+ out2.push(cp);
5340
+ cp = this.nextCode();
5341
+ }
5342
+ return this.reportParseError("unterminated-string");
5343
+ }
5344
+ SIGN(cp) {
5345
+ if (cp === CodePoint.LATIN_SMALL_N || cp === CodePoint.LATIN_SMALL_I) return this.back("NAN_OR_INF");
5346
+ if (isDigit(cp)) return this.back("NUMBER");
5347
+ return this.reportParseError("unexpected-char");
5348
+ }
5349
+ NAN_OR_INF(cp) {
5350
+ if (cp === CodePoint.LATIN_SMALL_N) {
5351
+ const startPos = this.codePointIterator.start;
5352
+ if (this.eatCode(CodePoint.LATIN_SMALL_A) && this.eatCode(CodePoint.LATIN_SMALL_N)) {
5353
+ this.endToken("Float", "end", NaN);
5354
+ return "DATA";
5355
+ }
5356
+ this.moveAt(startPos);
5357
+ } else if (cp === CodePoint.LATIN_SMALL_I) {
5358
+ const startPos = this.codePointIterator.start;
5359
+ if (this.eatCode(CodePoint.LATIN_SMALL_N) && this.eatCode(CodePoint.LATIN_SMALL_F)) {
5360
+ this.endToken("Float", "end", this.text[this.tokenStart] === "-" ? -Infinity : Infinity);
5361
+ return "DATA";
5362
+ }
5363
+ this.moveAt(startPos);
5364
+ }
5365
+ return this.reportParseError("unexpected-char");
5366
+ }
5367
+ NUMBER(cp) {
5368
+ const start = this.text[this.tokenStart];
5369
+ const sign = start === "+" ? CodePoint.PLUS_SIGN : start === "-" ? CodePoint.DASH : CodePoint.NULL;
5370
+ if (cp === CodePoint.DIGIT_0) {
5371
+ if (sign === CodePoint.NULL) {
5372
+ const startPos = this.codePointIterator.start;
5373
+ const nextCp$1 = this.nextCode();
5374
+ if (isDigit(nextCp$1)) {
5375
+ const nextNextCp = this.nextCode();
5376
+ if (nextNextCp === CodePoint.COLON) {
5377
+ this.data = {
5378
+ hasDate: false,
5379
+ year: 0,
5380
+ month: 0,
5381
+ day: 0,
5382
+ hour: Number(String.fromCodePoint(CodePoint.DIGIT_0, nextCp$1)),
5383
+ minute: 0,
5384
+ second: 0
5385
+ };
5386
+ return "TIME_MINUTE";
5387
+ }
5388
+ if (isDigit(nextNextCp)) {
5389
+ const nextNextNextCp = this.nextCode();
5390
+ if (isDigit(nextNextNextCp) && this.eatCode(CodePoint.DASH)) {
5391
+ this.data = {
5392
+ hasDate: true,
5393
+ year: Number(String.fromCodePoint(CodePoint.DIGIT_0, nextCp$1, nextNextCp, nextNextNextCp)),
5394
+ month: 0,
5395
+ day: 0,
5396
+ hour: 0,
5397
+ minute: 0,
5398
+ second: 0
5399
+ };
5400
+ return "DATE_MONTH";
5401
+ }
5402
+ }
5403
+ this.moveAt(startPos);
5404
+ return this.reportParseError("invalid-leading-zero");
5405
+ }
5406
+ this.moveAt(startPos);
5407
+ }
5408
+ cp = this.nextCode();
5409
+ if (cp === CodePoint.LATIN_SMALL_X || cp === CodePoint.LATIN_SMALL_O || cp === CodePoint.LATIN_SMALL_B) {
5410
+ if (sign !== CodePoint.NULL) return this.reportParseError("unexpected-char");
5411
+ return cp === CodePoint.LATIN_SMALL_X ? "HEX" : cp === CodePoint.LATIN_SMALL_O ? "OCTAL" : "BINARY";
5412
+ }
5413
+ if (cp === CodePoint.LATIN_SMALL_E || cp === CodePoint.LATIN_CAPITAL_E) {
5414
+ this.data = {
5415
+ minus: sign === CodePoint.DASH,
5416
+ left: [CodePoint.DIGIT_0]
5417
+ };
5418
+ return "EXPONENT_RIGHT";
5419
+ }
5420
+ if (cp === CodePoint.DOT) {
5421
+ this.data = {
5422
+ minus: sign === CodePoint.DASH,
5423
+ absInt: [CodePoint.DIGIT_0]
5424
+ };
5425
+ return "FRACTIONAL_RIGHT";
5426
+ }
5427
+ this.endToken("Integer", "start", "0", 10);
5428
+ return this.back("DATA");
5429
+ }
5430
+ const { out: out2, nextCp, hasUnderscore } = this.parseDigits(cp, isDigit);
5431
+ if (nextCp === CodePoint.DASH && sign === CodePoint.NULL && !hasUnderscore && out2.length === 4) {
5432
+ this.data = {
5433
+ hasDate: true,
5434
+ year: Number(String.fromCodePoint(...out2)),
5435
+ month: 0,
5436
+ day: 0,
5437
+ hour: 0,
5438
+ minute: 0,
5439
+ second: 0
5440
+ };
5441
+ return "DATE_MONTH";
5442
+ }
5443
+ if (nextCp === CodePoint.COLON && sign === CodePoint.NULL && !hasUnderscore && out2.length === 2) {
5444
+ this.data = {
5445
+ hasDate: false,
5446
+ year: 0,
5447
+ month: 0,
5448
+ day: 0,
5449
+ hour: Number(String.fromCodePoint(...out2)),
5450
+ minute: 0,
5451
+ second: 0
5452
+ };
5453
+ return "TIME_MINUTE";
5454
+ }
5455
+ if (nextCp === CodePoint.LATIN_SMALL_E || nextCp === CodePoint.LATIN_CAPITAL_E) {
5456
+ this.data = {
5457
+ minus: sign === CodePoint.DASH,
5458
+ left: out2
5459
+ };
5460
+ return "EXPONENT_RIGHT";
5461
+ }
5462
+ if (nextCp === CodePoint.DOT) {
5463
+ this.data = {
5464
+ minus: sign === CodePoint.DASH,
5465
+ absInt: out2
5466
+ };
5467
+ return "FRACTIONAL_RIGHT";
5468
+ }
5469
+ this.endToken("Integer", "start", sign === CodePoint.DASH ? String.fromCodePoint(CodePoint.DASH, ...out2) : String.fromCodePoint(...out2), 10);
5470
+ return this.back("DATA");
5471
+ }
5472
+ HEX(cp) {
5473
+ const { out: out2 } = this.parseDigits(cp, isHexDig);
5474
+ this.endToken("Integer", "start", String.fromCodePoint(...out2), 16);
5475
+ return this.back("DATA");
5476
+ }
5477
+ OCTAL(cp) {
5478
+ const { out: out2 } = this.parseDigits(cp, isOctalDig);
5479
+ this.endToken("Integer", "start", String.fromCodePoint(...out2), 8);
5480
+ return this.back("DATA");
5481
+ }
5482
+ BINARY(cp) {
5483
+ const { out: out2 } = this.parseDigits(cp, (c3) => c3 === CodePoint.DIGIT_0 || c3 === CodePoint.DIGIT_1);
5484
+ this.endToken("Integer", "start", String.fromCodePoint(...out2), 2);
5485
+ return this.back("DATA");
5486
+ }
5487
+ FRACTIONAL_RIGHT(cp) {
5488
+ const { minus, absInt } = this.data;
5489
+ const { out: out2, nextCp } = this.parseDigits(cp, isDigit);
5490
+ const absNum = [
5491
+ ...absInt,
5492
+ CodePoint.DOT,
5493
+ ...out2
5494
+ ];
5495
+ if (nextCp === CodePoint.LATIN_SMALL_E || nextCp === CodePoint.LATIN_CAPITAL_E) {
5496
+ this.data = {
5497
+ minus,
5498
+ left: absNum
5499
+ };
5500
+ return "EXPONENT_RIGHT";
5501
+ }
5502
+ const value = Number(minus ? String.fromCodePoint(CodePoint.DASH, ...absNum) : String.fromCodePoint(...absNum));
5503
+ this.endToken("Float", "start", value);
5504
+ return this.back("DATA");
5505
+ }
5506
+ EXPONENT_RIGHT(cp) {
5507
+ const { left, minus: leftMinus } = this.data;
5508
+ let minus = false;
5509
+ if (cp === CodePoint.DASH || cp === CodePoint.PLUS_SIGN) {
5510
+ minus = cp === CodePoint.DASH;
5511
+ cp = this.nextCode();
5512
+ }
5513
+ const { out: out2 } = this.parseDigits(cp, isDigit);
5514
+ const right = out2;
5515
+ if (minus) right.unshift(CodePoint.DASH);
5516
+ const value = Number(leftMinus ? String.fromCodePoint(CodePoint.DASH, ...left, CodePoint.LATIN_SMALL_E, ...right) : String.fromCodePoint(...left, CodePoint.LATIN_SMALL_E, ...right));
5517
+ this.endToken("Float", "start", value);
5518
+ return this.back("DATA");
5519
+ }
5520
+ BOOLEAN(cp) {
5521
+ if (cp === CodePoint.LATIN_SMALL_T) {
5522
+ const startPos = this.codePointIterator.start;
5523
+ if (this.eatCode(CodePoint.LATIN_SMALL_R) && this.eatCode(CodePoint.LATIN_SMALL_U) && this.eatCode(CodePoint.LATIN_SMALL_E)) {
5524
+ this.endToken("Boolean", "end", true);
5525
+ return "DATA";
5526
+ }
5527
+ this.moveAt(startPos);
5528
+ } else if (cp === CodePoint.LATIN_SMALL_F) {
5529
+ const startPos = this.codePointIterator.start;
5530
+ if (this.eatCode(CodePoint.LATIN_SMALL_A) && this.eatCode(CodePoint.LATIN_SMALL_L) && this.eatCode(CodePoint.LATIN_SMALL_S) && this.eatCode(CodePoint.LATIN_SMALL_E)) {
5531
+ this.endToken("Boolean", "end", false);
5532
+ return "DATA";
5533
+ }
5534
+ this.moveAt(startPos);
5535
+ }
5536
+ return this.reportParseError("unexpected-char");
5537
+ }
5538
+ DATE_MONTH(cp) {
5539
+ const start = this.codePointIterator.start;
5540
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5541
+ cp = this.nextCode();
5542
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5543
+ cp = this.nextCode();
5544
+ if (cp !== CodePoint.DASH) return this.reportParseError("unexpected-char");
5545
+ const end = this.codePointIterator.start;
5546
+ const data = this.data;
5547
+ data.month = Number(this.text.slice(start, end));
5548
+ return "DATE_DAY";
5549
+ }
5550
+ DATE_DAY(cp) {
5551
+ const start = this.codePointIterator.start;
5552
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5553
+ cp = this.nextCode();
5554
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5555
+ const end = this.codePointIterator.end;
5556
+ const data = this.data;
5557
+ data.day = Number(this.text.slice(start, end));
5558
+ if (!isValidDate(data.year, data.month, data.day)) return this.reportParseError("invalid-date");
5559
+ cp = this.nextCode();
5560
+ if (cp === CodePoint.LATIN_CAPITAL_T || cp === CodePoint.LATIN_SMALL_T) return "TIME_HOUR";
5561
+ if (cp === CodePoint.SPACE) {
5562
+ const startPos = this.codePointIterator.start;
5563
+ if (isDigit(this.nextCode()) && isDigit(this.nextCode())) {
5564
+ this.moveAt(startPos);
5565
+ return "TIME_HOUR";
5566
+ }
5567
+ this.moveAt(startPos);
5568
+ }
5569
+ const dateValue = getDateFromDateTimeData(data, "");
5570
+ this.endToken("LocalDate", "start", dateValue);
5571
+ return this.back("DATA");
5572
+ }
5573
+ TIME_HOUR(cp) {
5574
+ const start = this.codePointIterator.start;
5575
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5576
+ cp = this.nextCode();
5577
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5578
+ cp = this.nextCode();
5579
+ if (cp !== CodePoint.COLON) return this.reportParseError("unexpected-char");
5580
+ const end = this.codePointIterator.start;
5581
+ const data = this.data;
5582
+ data.hour = Number(this.text.slice(start, end));
5583
+ return "TIME_MINUTE";
5584
+ }
5585
+ TIME_MINUTE(cp) {
5586
+ const start = this.codePointIterator.start;
5587
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5588
+ cp = this.nextCode();
5589
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5590
+ const end = this.codePointIterator.end;
5591
+ const data = this.data;
5592
+ data.minute = Number(this.text.slice(start, end));
5593
+ cp = this.nextCode();
5594
+ if (cp === CodePoint.COLON) return "TIME_SECOND";
5595
+ if (this.tomlVersion.lt(1, 1)) return this.reportParseError("unexpected-char");
5596
+ if (!isValidTime(data.hour, data.minute, data.second)) return this.reportParseError("invalid-time");
5597
+ return this.processTimeEnd(cp, data);
5598
+ }
5599
+ TIME_SECOND(cp) {
5600
+ const start = this.codePointIterator.start;
5601
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5602
+ cp = this.nextCode();
5603
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5604
+ const end = this.codePointIterator.end;
5605
+ const data = this.data;
5606
+ data.second = Number(this.text.slice(start, end));
5607
+ if (!isValidTime(data.hour, data.minute, data.second)) return this.reportParseError("invalid-time");
5608
+ cp = this.nextCode();
5609
+ if (cp === CodePoint.DOT) return "TIME_SEC_FRAC";
5610
+ return this.processTimeEnd(cp, data);
5611
+ }
5612
+ TIME_SEC_FRAC(cp) {
5613
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5614
+ const start = this.codePointIterator.start;
5615
+ while (isDigit(cp)) cp = this.nextCode();
5616
+ const end = this.codePointIterator.start;
5617
+ const data = this.data;
5618
+ data.frac = this.text.slice(start, end);
5619
+ return this.processTimeEnd(cp, data);
5620
+ }
5621
+ processTimeEnd(cp, data) {
5622
+ if (data.hasDate) {
5623
+ if (cp === CodePoint.DASH || cp === CodePoint.PLUS_SIGN) {
5624
+ data.offsetSign = cp;
5625
+ return "TIME_OFFSET";
5626
+ }
5627
+ if (cp === CodePoint.LATIN_CAPITAL_Z || cp === CodePoint.LATIN_SMALL_Z) {
5628
+ const dateValue$2 = getDateFromDateTimeData(data, "Z");
5629
+ this.endToken("OffsetDateTime", "end", dateValue$2);
5630
+ return "DATA";
5631
+ }
5632
+ const dateValue$1 = getDateFromDateTimeData(data, "");
5633
+ this.endToken("LocalDateTime", "start", dateValue$1);
5634
+ return this.back("DATA");
5635
+ }
5636
+ const dateValue = getDateFromDateTimeData(data, "");
5637
+ this.endToken("LocalTime", "start", dateValue);
5638
+ return this.back("DATA");
5639
+ }
5640
+ TIME_OFFSET(cp) {
5641
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5642
+ const hourStart = this.codePointIterator.start;
5643
+ cp = this.nextCode();
5644
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5645
+ cp = this.nextCode();
5646
+ if (cp !== CodePoint.COLON) return this.reportParseError("unexpected-char");
5647
+ const hourEnd = this.codePointIterator.start;
5648
+ cp = this.nextCode();
5649
+ const minuteStart = this.codePointIterator.start;
5650
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5651
+ cp = this.nextCode();
5652
+ if (!isDigit(cp)) return this.reportParseError("unexpected-char");
5653
+ const minuteEnd = this.codePointIterator.end;
5654
+ const hour = Number(this.text.slice(hourStart, hourEnd));
5655
+ const minute = Number(this.text.slice(minuteStart, minuteEnd));
5656
+ if (!isValidTime(hour, minute, 0)) return this.reportParseError("invalid-time");
5657
+ const data = this.data;
5658
+ const dateValue = getDateFromDateTimeData(data, `${String.fromCodePoint(data.offsetSign)}${padStart(hour, 2)}:${padStart(minute, 2)}`);
5659
+ this.endToken("OffsetDateTime", "end", dateValue);
5660
+ return "DATA";
5661
+ }
5662
+ parseDigits(cp, checkDigit) {
5663
+ if (cp === CodePoint.UNDERSCORE) return this.reportParseError("invalid-underscore");
5664
+ if (!checkDigit(cp)) return this.reportParseError("unexpected-char");
5665
+ const out2 = [];
5666
+ let before = CodePoint.NULL;
5667
+ let hasUnderscore = false;
5668
+ while (checkDigit(cp) || cp === CodePoint.UNDERSCORE) {
5669
+ if (cp === CodePoint.UNDERSCORE) {
5670
+ hasUnderscore = true;
5671
+ if (before === CodePoint.UNDERSCORE) return this.reportParseError("invalid-underscore");
5672
+ } else out2.push(cp);
5673
+ before = cp;
5674
+ cp = this.nextCode();
5675
+ }
5676
+ if (before === CodePoint.UNDERSCORE) return this.reportParseError("invalid-underscore");
5677
+ return {
5678
+ out: out2,
5679
+ nextCp: cp,
5680
+ hasUnderscore
5681
+ };
5682
+ }
5683
+ parseUnicode(count) {
5684
+ const startLoc = this.codePointIterator.start;
5685
+ const start = this.codePointIterator.end;
5686
+ let charCount = 0;
5687
+ let cp;
5688
+ while ((cp = this.nextCode()) !== CodePoint.EOF) {
5689
+ if (!isHexDig(cp)) {
5690
+ this.moveAt(startLoc);
5691
+ return this.reportParseError("invalid-char-in-escape-sequence");
5692
+ }
5693
+ charCount++;
5694
+ if (charCount >= count) break;
5695
+ }
5696
+ const end = this.codePointIterator.end;
5697
+ const code = this.text.slice(start, end);
5698
+ const codePoint = parseInt(code, 16);
5699
+ if (!isUnicodeScalarValue(codePoint)) return this.reportParseError("invalid-code-point", { cp: code });
5700
+ return codePoint;
5701
+ }
5702
+ reportParseErrorControlChar() {
5703
+ return this.reportParseError("invalid-control-character");
5704
+ }
5705
+ };
5706
+ function isUnquotedKeyChar(cp, tomlVersion) {
5707
+ if (isLetter(cp) || isDigit(cp) || cp === CodePoint.UNDERSCORE || cp === CodePoint.DASH) return true;
5708
+ if (tomlVersion.lt(1, 1)) return false;
5709
+ return false;
4602
5710
  }
4603
- function scanAll(home, tmp, out2) {
4604
- const root = join3(home, DATA_ROOT.slice(1));
4605
- for (const name of V1_DATA_ROOT_ENTRIES) dataDir(join3(root, name), V1_REASON.dataRoot, out2);
4606
- if (firstTmpMatch(tmp) !== null) out2.push(finding(tmp, V1_TMP_PREFIX + "*", V1_REASON.tmpFile));
5711
+ function isControlOtherThanTab(cp) {
5712
+ return isControl(cp) && cp !== CodePoint.TABULATION || cp === CodePoint.DELETE;
4607
5713
  }
4608
- function detectV1(agent, home, scope = {}) {
4609
- const out2 = [];
4610
- const project = scope.project;
4611
- const agentHome = join3(home, ...AGENT_HOME_DIR[agent]);
4612
- switch (agent) {
4613
- case "claude-code":
4614
- scanClaudeCode(home, agentHome, out2);
4615
- break;
4616
- case "codex":
4617
- scanCodex(agentHome, out2);
4618
- break;
4619
- case "gemini":
4620
- scanGemini(agentHome, out2);
4621
- break;
4622
- case "qwen":
4623
- claudeShapeSettings(agentHome, out2);
4624
- dataDir(join3(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
4625
- break;
4626
- case "copilot-cli":
4627
- v1HookFile(join3(agentHome, V1_HOOKS_DIR_NAME, OWN_HOOK_FILE), out2);
4628
- dataDir(join3(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
4629
- break;
4630
- case "vscode":
4631
- scanVscode(agentHome, project, out2);
4632
- break;
4633
- case "kiro":
4634
- scanKiro(agentHome, project, out2);
4635
- break;
4636
- case "pi":
4637
- scanPi(scope.piAgentDir ?? join3(agentHome, PI_AGENT_DIR), agentHome, out2);
4638
- break;
4639
- case "opencode":
4640
- scanOpencode(agentHome, out2);
4641
- break;
4642
- case "zcode":
4643
- scanZcode(agentHome, out2);
4644
- break;
5714
+ function isNonEOL(cp) {
5715
+ return cp === CodePoint.TABULATION || CodePoint.SPACE <= cp && cp <= CodePoint.TILDE || isNonAscii(cp);
5716
+ }
5717
+ function isNonAscii(cp) {
5718
+ return CodePoint.PAD <= cp && cp <= CodePoint.CP_D7FF || CodePoint.CP_E000 <= cp && cp <= CodePoint.CP_10FFFF;
5719
+ }
5720
+ function isValidDate(y2, m3, d) {
5721
+ if (y2 >= 0 && m3 <= 12 && m3 >= 1 && d >= 1) return d <= (m3 === 2 ? y2 & 3 || !(y2 % 25) && y2 & 15 ? 28 : 29 : 30 + (m3 + (m3 >> 3) & 1));
5722
+ return false;
5723
+ }
5724
+ function isValidTime(h2, m3, s) {
5725
+ if (h2 >= 24 || h2 < 0 || m3 > 59 || m3 < 0 || s > 60 || s < 0) return false;
5726
+ return true;
5727
+ }
5728
+ function getDateFromDateTimeData(data, timeZone) {
5729
+ const year = padStart(data.year, 4);
5730
+ const month = data.month ? padStart(data.month, 2) : "01";
5731
+ const day = data.day ? padStart(data.day, 2) : "01";
5732
+ const hour = padStart(data.hour, 2);
5733
+ const minute = padStart(data.minute, 2);
5734
+ const second = padStart(data.second, 2);
5735
+ const textDate = `${year}-${month}-${day}`;
5736
+ const frac = data.frac ? `.${data.frac}` : "";
5737
+ const dateValue = /* @__PURE__ */ new Date(`${textDate}T${hour}:${minute}:${second}${frac}${timeZone}`);
5738
+ if (!isNaN(dateValue.getTime()) || data.second !== 60) return dateValue;
5739
+ return /* @__PURE__ */ new Date(`${textDate}T${hour}:${minute}:59${frac}${timeZone}`);
5740
+ }
5741
+ function padStart(num, maxLength) {
5742
+ return String(num).padStart(maxLength, "0");
5743
+ }
5744
+ var VALUE_KIND_VALUE = Symbol("VALUE_KIND_VALUE");
5745
+ var VALUE_KIND_INTERMEDIATE = Symbol("VALUE_KIND_INTERMEDIATE");
5746
+ var KeysResolver = class {
5747
+ constructor(ctx) {
5748
+ this.rootKeys = /* @__PURE__ */ new Map();
5749
+ this.tables = [];
5750
+ this.ctx = ctx;
5751
+ }
5752
+ applyResolveKeyForTable(node) {
5753
+ let keys = this.rootKeys;
5754
+ const peekKeyIndex = node.key.keys.length - 1;
5755
+ for (let index = 0; index < peekKeyIndex; index++) {
5756
+ const keyNode = node.key.keys[index];
5757
+ const keyName = toKeyName(keyNode);
5758
+ node.resolvedKey.push(keyName);
5759
+ let keyStore = keys.get(keyName);
5760
+ if (!keyStore) {
5761
+ keyStore = {
5762
+ node: keyNode,
5763
+ keys: /* @__PURE__ */ new Map()
5764
+ };
5765
+ keys.set(keyName, keyStore);
5766
+ } else if (keyStore.table === "array") {
5767
+ const peekIndex = keyStore.peekIndex;
5768
+ node.resolvedKey.push(peekIndex);
5769
+ keyStore = keyStore.keys.get(peekIndex);
5770
+ }
5771
+ keys = keyStore.keys;
5772
+ }
5773
+ const lastKeyNode = node.key.keys[peekKeyIndex];
5774
+ const lastKeyName = toKeyName(lastKeyNode);
5775
+ node.resolvedKey.push(lastKeyName);
5776
+ const lastKeyStore = keys.get(lastKeyName);
5777
+ if (!lastKeyStore) if (node.kind === "array") {
5778
+ node.resolvedKey.push(0);
5779
+ const newKeyStore = {
5780
+ node: lastKeyNode,
5781
+ keys: /* @__PURE__ */ new Map()
5782
+ };
5783
+ keys.set(lastKeyName, {
5784
+ table: node.kind,
5785
+ node: lastKeyNode,
5786
+ keys: /* @__PURE__ */ new Map([[0, newKeyStore]]),
5787
+ peekIndex: 0
5788
+ });
5789
+ this.tables.push({
5790
+ node,
5791
+ keys: newKeyStore.keys
5792
+ });
5793
+ } else {
5794
+ const newKeyStore = {
5795
+ table: node.kind,
5796
+ node: lastKeyNode,
5797
+ keys: /* @__PURE__ */ new Map()
5798
+ };
5799
+ keys.set(lastKeyName, newKeyStore);
5800
+ this.tables.push({
5801
+ node,
5802
+ keys: newKeyStore.keys
5803
+ });
5804
+ }
5805
+ else if (!lastKeyStore.table) if (node.kind === "array") this.ctx.reportParseError("dupe-keys", lastKeyNode);
5806
+ else {
5807
+ const transformKey = {
5808
+ table: node.kind,
5809
+ node: lastKeyNode,
5810
+ keys: lastKeyStore.keys
5811
+ };
5812
+ keys.set(lastKeyName, transformKey);
5813
+ this.tables.push({
5814
+ node,
5815
+ keys: transformKey.keys
5816
+ });
5817
+ }
5818
+ else if (lastKeyStore.table === "array") if (node.kind === "array") {
5819
+ const newKeyStore = {
5820
+ node: lastKeyNode,
5821
+ keys: /* @__PURE__ */ new Map()
5822
+ };
5823
+ const newIndex = lastKeyStore.peekIndex + 1;
5824
+ node.resolvedKey.push(newIndex);
5825
+ lastKeyStore.keys.set(newIndex, newKeyStore);
5826
+ lastKeyStore.peekIndex = newIndex;
5827
+ this.tables.push({
5828
+ node,
5829
+ keys: newKeyStore.keys
5830
+ });
5831
+ } else this.ctx.reportParseError("dupe-keys", lastKeyNode);
5832
+ else this.ctx.reportParseError("dupe-keys", lastKeyNode);
5833
+ }
5834
+ verifyDuplicateKeys(node) {
5835
+ for (const body of node.body) if (body.type === "TOMLKeyValue") verifyDuplicateKeysForKeyValue(this.ctx, this.rootKeys, body);
5836
+ for (const { node: tableNode, keys } of this.tables) for (const body of tableNode.body) verifyDuplicateKeysForKeyValue(this.ctx, keys, body);
5837
+ }
5838
+ };
5839
+ function verifyDuplicateKeysForKeyValue(ctx, defineKeys, node) {
5840
+ let keys = defineKeys;
5841
+ const lastKey = last(node.key.keys);
5842
+ for (const keyNode of node.key.keys) {
5843
+ const key = toKeyName(keyNode);
5844
+ let defineKey = keys.get(key);
5845
+ if (defineKey) {
5846
+ if (defineKey.value === VALUE_KIND_VALUE) ctx.reportParseError("dupe-keys", getAfterNode(keyNode, defineKey.node));
5847
+ else if (lastKey === keyNode) ctx.reportParseError("dupe-keys", getAfterNode(keyNode, defineKey.node));
5848
+ else if (defineKey.table) ctx.reportParseError("dupe-keys", getAfterNode(keyNode, defineKey.node));
5849
+ defineKey.value = VALUE_KIND_INTERMEDIATE;
5850
+ } else {
5851
+ if (lastKey === keyNode) defineKey = {
5852
+ value: VALUE_KIND_VALUE,
5853
+ node: keyNode,
5854
+ keys: /* @__PURE__ */ new Map()
5855
+ };
5856
+ else defineKey = {
5857
+ value: VALUE_KIND_INTERMEDIATE,
5858
+ node: keyNode,
5859
+ keys: /* @__PURE__ */ new Map()
5860
+ };
5861
+ keys.set(key, defineKey);
5862
+ }
5863
+ keys = defineKey.keys;
5864
+ }
5865
+ if (node.value.type === "TOMLInlineTable") verifyDuplicateKeysForInlineTable(ctx, keys, node.value);
5866
+ else if (node.value.type === "TOMLArray") verifyDuplicateKeysForArray(ctx, keys, node.value);
5867
+ }
5868
+ function verifyDuplicateKeysForInlineTable(ctx, defineKeys, node) {
5869
+ for (const body of node.body) verifyDuplicateKeysForKeyValue(ctx, defineKeys, body);
5870
+ }
5871
+ function verifyDuplicateKeysForArray(ctx, defineKeys, node) {
5872
+ const keys = defineKeys;
5873
+ for (let index = 0; index < node.elements.length; index++) {
5874
+ const element = node.elements[index];
5875
+ let defineKey = keys.get(index);
5876
+ if (defineKey) ctx.reportParseError("dupe-keys", getAfterNode(element, defineKey.node));
5877
+ else {
5878
+ defineKey = {
5879
+ value: VALUE_KIND_VALUE,
5880
+ node: element,
5881
+ keys: /* @__PURE__ */ new Map()
5882
+ };
5883
+ defineKeys.set(index, defineKey);
5884
+ if (element.type === "TOMLInlineTable") verifyDuplicateKeysForInlineTable(ctx, defineKey.keys, element);
5885
+ else if (element.type === "TOMLArray") verifyDuplicateKeysForArray(ctx, defineKey.keys, element);
5886
+ }
5887
+ }
5888
+ }
5889
+ function getAfterNode(a2, b3) {
5890
+ return a2.range[0] <= b3.range[0] ? b3 : a2;
5891
+ }
5892
+ var Context = class {
5893
+ constructor(data) {
5894
+ this.tokens = [];
5895
+ this.comments = [];
5896
+ this.back = null;
5897
+ this.stateStack = [];
5898
+ this.needNewLine = false;
5899
+ this.needSameLine = false;
5900
+ this.currToken = null;
5901
+ this.prevToken = null;
5902
+ this.valueContainerStack = [];
5903
+ this.tokenizer = new Tokenizer(data.text, data.parserOptions);
5904
+ this.topLevelTable = data.topLevelTable;
5905
+ this.table = data.topLevelTable;
5906
+ this.keysResolver = new KeysResolver(this);
5907
+ }
5908
+ /**
5909
+ * Get the next token.
5910
+ */
5911
+ nextToken(option) {
5912
+ this.prevToken = this.currToken;
5913
+ if (this.back) {
5914
+ this.currToken = this.back;
5915
+ this.back = null;
5916
+ } else this.currToken = this._nextTokenFromTokenizer(option);
5917
+ if ((this.needNewLine || this.needSameLine || option?.needSameLine) && this.prevToken && this.currToken) if (this.prevToken.loc.end.line === this.currToken.loc.start.line) {
5918
+ if (this.needNewLine) return this.reportParseError("missing-newline", this.currToken);
5919
+ } else {
5920
+ const needSameLine = this.needSameLine || option?.needSameLine;
5921
+ if (needSameLine) return this.reportParseError(needSameLine, this.currToken);
5922
+ }
5923
+ this.needNewLine = false;
5924
+ this.needSameLine = false;
5925
+ return this.currToken;
5926
+ }
5927
+ _nextTokenFromTokenizer(option) {
5928
+ const valuesEnabled = this.tokenizer.valuesEnabled;
5929
+ if (option?.valuesEnabled) this.tokenizer.valuesEnabled = option.valuesEnabled;
5930
+ let token = this.tokenizer.nextToken();
5931
+ while (token && token.type === "Block") {
5932
+ this.comments.push(token);
5933
+ token = this.tokenizer.nextToken();
5934
+ }
5935
+ if (token) this.tokens.push(token);
5936
+ this.tokenizer.valuesEnabled = valuesEnabled;
5937
+ return token;
5938
+ }
5939
+ backToken() {
5940
+ if (this.back) throw new Error("Illegal state");
5941
+ this.back = this.currToken;
5942
+ this.currToken = this.prevToken;
5943
+ }
5944
+ addValueContainer(valueContainer) {
5945
+ this.valueContainerStack.push(valueContainer);
5946
+ this.tokenizer.valuesEnabled = true;
5947
+ }
5948
+ consumeValueContainer() {
5949
+ const valueContainer = this.valueContainerStack.pop();
5950
+ this.tokenizer.valuesEnabled = this.valueContainerStack.length > 0;
5951
+ return valueContainer;
5952
+ }
5953
+ applyResolveKeyForTable(node) {
5954
+ this.keysResolver.applyResolveKeyForTable(node);
5955
+ }
5956
+ verifyDuplicateKeys() {
5957
+ this.keysResolver.verifyDuplicateKeys(this.topLevelTable);
5958
+ }
5959
+ /**
5960
+ * Report an invalid token error.
5961
+ */
5962
+ reportParseError(code, token) {
5963
+ let offset, line, column;
5964
+ if (token) {
5965
+ offset = token.range[0];
5966
+ line = token.loc.start.line;
5967
+ column = token.loc.start.column;
5968
+ } else {
5969
+ offset = this.tokenizer.start;
5970
+ const startPos = this.tokenizer.getLocFromIndex(offset);
5971
+ line = startPos.line;
5972
+ column = startPos.column;
5973
+ }
5974
+ throw new ParseError(code, offset, line, column);
5975
+ }
5976
+ };
5977
+ var STATE_FOR_ERROR = { VALUE: "missing-value" };
5978
+ var STRING_VALUE_STYLE_MAP = {
5979
+ BasicString: "basic",
5980
+ MultiLineBasicString: "basic",
5981
+ LiteralString: "literal",
5982
+ MultiLineLiteralString: "literal"
5983
+ };
5984
+ var STRING_KEY_STYLE_MAP = {
5985
+ BasicString: "basic",
5986
+ LiteralString: "literal"
5987
+ };
5988
+ var DATETIME_VALUE_KIND_MAP = {
5989
+ OffsetDateTime: "offset-date-time",
5990
+ LocalDateTime: "local-date-time",
5991
+ LocalDate: "local-date",
5992
+ LocalTime: "local-time"
5993
+ };
5994
+ var TOMLParser = class {
5995
+ /**
5996
+ * Initialize this parser.
5997
+ */
5998
+ constructor(text2, parserOptions) {
5999
+ this.text = text2;
6000
+ this.parserOptions = parserOptions || {};
6001
+ this.tomlVersion = getTOMLVer(this.parserOptions.tomlVersion);
6002
+ }
6003
+ /**
6004
+ * Parse TOML
6005
+ */
6006
+ parse() {
6007
+ const ast = {
6008
+ type: "Program",
6009
+ body: [],
6010
+ sourceType: "module",
6011
+ tokens: [],
6012
+ comments: [],
6013
+ parent: null,
6014
+ range: [0, 0],
6015
+ loc: {
6016
+ start: {
6017
+ line: 1,
6018
+ column: 0
6019
+ },
6020
+ end: {
6021
+ line: 1,
6022
+ column: 0
6023
+ }
6024
+ }
6025
+ };
6026
+ const node = {
6027
+ type: "TOMLTopLevelTable",
6028
+ body: [],
6029
+ parent: ast,
6030
+ range: cloneRange(ast.range),
6031
+ loc: cloneLoc(ast.loc)
6032
+ };
6033
+ ast.body = [node];
6034
+ const ctx = new Context({
6035
+ text: this.text,
6036
+ parserOptions: this.parserOptions,
6037
+ topLevelTable: node
6038
+ });
6039
+ let token = ctx.nextToken();
6040
+ if (token) {
6041
+ node.range[0] = token.range[0];
6042
+ node.loc.start = clonePos(token.loc.start);
6043
+ while (token) {
6044
+ const state$1 = ctx.stateStack.pop() || "TABLE";
6045
+ ctx.stateStack.push(...this[state$1](token, ctx));
6046
+ token = ctx.nextToken();
6047
+ }
6048
+ const state = ctx.stateStack.pop() || "TABLE";
6049
+ if (state in STATE_FOR_ERROR) return ctx.reportParseError(STATE_FOR_ERROR[state], null);
6050
+ if (ctx.table.type === "TOMLTable") applyEndLoc(ctx.table, last(ctx.table.body));
6051
+ applyEndLoc(node, last(node.body));
6052
+ }
6053
+ ctx.verifyDuplicateKeys();
6054
+ ast.tokens = ctx.tokens;
6055
+ ast.comments = ctx.comments;
6056
+ const endOffset = ctx.tokenizer.end;
6057
+ const endPos = ctx.tokenizer.getLocFromIndex(endOffset);
6058
+ ast.range[1] = endOffset;
6059
+ ast.loc.end = {
6060
+ line: endPos.line,
6061
+ column: endPos.column
6062
+ };
6063
+ return ast;
6064
+ }
6065
+ TABLE(token, ctx) {
6066
+ if (isBare(token) || isString(token)) return this.processKeyValue(token, ctx.table, ctx);
6067
+ if (isLeftBracket(token)) return this.processTable(token, ctx.topLevelTable, ctx);
6068
+ return ctx.reportParseError("unexpected-token", token);
6069
+ }
6070
+ VALUE(token, ctx) {
6071
+ if (isString(token) || isMultiLineString(token)) return this.processStringValue(token, ctx);
6072
+ if (isNumber(token)) return this.processNumberValue(token, ctx);
6073
+ if (isBoolean(token)) return this.processBooleanValue(token, ctx);
6074
+ if (isDateTime(token)) return this.processDateTimeValue(token, ctx);
6075
+ if (isLeftBracket(token)) return this.processArray(token, ctx);
6076
+ if (isLeftBrace(token)) return this.processInlineTable(token, ctx);
6077
+ return ctx.reportParseError("unexpected-token", token);
6078
+ }
6079
+ processTable(token, topLevelTableNode, ctx) {
6080
+ const tableNode = {
6081
+ type: "TOMLTable",
6082
+ kind: "standard",
6083
+ key: null,
6084
+ resolvedKey: [],
6085
+ body: [],
6086
+ parent: topLevelTableNode,
6087
+ range: cloneRange(token.range),
6088
+ loc: cloneLoc(token.loc)
6089
+ };
6090
+ if (ctx.table.type === "TOMLTable") applyEndLoc(ctx.table, last(ctx.table.body));
6091
+ topLevelTableNode.body.push(tableNode);
6092
+ ctx.table = tableNode;
6093
+ let targetToken = ctx.nextToken({ needSameLine: "invalid-key-value-newline" });
6094
+ if (isLeftBracket(targetToken)) {
6095
+ if (token.range[1] < targetToken.range[0]) return ctx.reportParseError("invalid-space", targetToken);
6096
+ tableNode.kind = "array";
6097
+ targetToken = ctx.nextToken({ needSameLine: "invalid-key-value-newline" });
6098
+ }
6099
+ if (isRightBracket(targetToken)) return ctx.reportParseError("missing-key", targetToken);
6100
+ if (!targetToken) return ctx.reportParseError("unterminated-table-key", null);
6101
+ targetToken = this.processKeyNode(targetToken, tableNode, ctx).nextToken;
6102
+ if (!isRightBracket(targetToken)) return ctx.reportParseError("unterminated-table-key", targetToken);
6103
+ if (tableNode.kind === "array") {
6104
+ const rightBracket = targetToken;
6105
+ targetToken = ctx.nextToken({ needSameLine: "invalid-key-value-newline" });
6106
+ if (!isRightBracket(targetToken)) return ctx.reportParseError("unterminated-table-key", targetToken);
6107
+ if (rightBracket.range[1] < targetToken.range[0]) return ctx.reportParseError("invalid-space", targetToken);
6108
+ }
6109
+ applyEndLoc(tableNode, targetToken);
6110
+ ctx.applyResolveKeyForTable(tableNode);
6111
+ ctx.needNewLine = true;
6112
+ return [];
6113
+ }
6114
+ processKeyValue(token, tableNode, ctx) {
6115
+ const keyValueNode = {
6116
+ type: "TOMLKeyValue",
6117
+ key: null,
6118
+ value: null,
6119
+ parent: tableNode,
6120
+ range: cloneRange(token.range),
6121
+ loc: cloneLoc(token.loc)
6122
+ };
6123
+ tableNode.body.push(keyValueNode);
6124
+ const { nextToken: targetToken } = this.processKeyNode(token, keyValueNode, ctx);
6125
+ if (!isEq(targetToken)) return ctx.reportParseError("missing-equals-sign", targetToken);
6126
+ ctx.addValueContainer({
6127
+ parent: keyValueNode,
6128
+ set: (valNode) => {
6129
+ keyValueNode.value = valNode;
6130
+ applyEndLoc(keyValueNode, valNode);
6131
+ ctx.needNewLine = true;
6132
+ return [];
6133
+ }
6134
+ });
6135
+ ctx.needSameLine = "invalid-key-value-newline";
6136
+ return ["VALUE"];
6137
+ }
6138
+ processKeyNode(token, parent, ctx) {
6139
+ if (isDot(token)) ctx.reportParseError("invalid-leading-dot-in-key", token);
6140
+ const keyNode = {
6141
+ type: "TOMLKey",
6142
+ keys: [],
6143
+ parent,
6144
+ range: cloneRange(token.range),
6145
+ loc: cloneLoc(token.loc)
6146
+ };
6147
+ parent.key = keyNode;
6148
+ let targetToken = token;
6149
+ let dotToken = null;
6150
+ do {
6151
+ if (isBare(targetToken)) this.processBareKey(targetToken, keyNode);
6152
+ else if (isString(targetToken)) this.processStringKey(targetToken, keyNode);
6153
+ else break;
6154
+ dotToken = null;
6155
+ targetToken = ctx.nextToken({ needSameLine: "invalid-key-value-newline" });
6156
+ if (!isDot(targetToken)) break;
6157
+ dotToken = targetToken;
6158
+ targetToken = ctx.nextToken({ needSameLine: "invalid-key-value-newline" });
6159
+ } while (targetToken);
6160
+ if (dotToken) ctx.reportParseError(isDot(targetToken) ? "invalid-consecutive-dots-in-key" : "invalid-trailing-dot-in-key", dotToken);
6161
+ applyEndLoc(keyNode, last(keyNode.keys));
6162
+ return {
6163
+ keyNode,
6164
+ nextToken: targetToken
6165
+ };
6166
+ }
6167
+ processBareKey(token, keyNode) {
6168
+ const node = {
6169
+ type: "TOMLBare",
6170
+ name: token.value,
6171
+ parent: keyNode,
6172
+ range: cloneRange(token.range),
6173
+ loc: cloneLoc(token.loc)
6174
+ };
6175
+ keyNode.keys.push(node);
6176
+ }
6177
+ processStringKey(token, keyNode) {
6178
+ const node = {
6179
+ type: "TOMLQuoted",
6180
+ kind: "string",
6181
+ value: token.string,
6182
+ style: STRING_KEY_STYLE_MAP[token.type],
6183
+ multiline: false,
6184
+ parent: keyNode,
6185
+ range: cloneRange(token.range),
6186
+ loc: cloneLoc(token.loc)
6187
+ };
6188
+ keyNode.keys.push(node);
6189
+ }
6190
+ processStringValue(token, ctx) {
6191
+ const valueContainer = ctx.consumeValueContainer();
6192
+ const node = {
6193
+ type: "TOMLValue",
6194
+ kind: "string",
6195
+ value: token.string,
6196
+ style: STRING_VALUE_STYLE_MAP[token.type],
6197
+ multiline: isMultiLineString(token),
6198
+ parent: valueContainer.parent,
6199
+ range: cloneRange(token.range),
6200
+ loc: cloneLoc(token.loc)
6201
+ };
6202
+ return valueContainer.set(node);
6203
+ }
6204
+ processNumberValue(token, ctx) {
6205
+ const valueContainer = ctx.consumeValueContainer();
6206
+ const text2 = this.text;
6207
+ const [startRange, endRange] = token.range;
6208
+ let numberString = null;
6209
+ const getNumberText = () => {
6210
+ return numberString ?? (numberString = text2.slice(startRange, endRange).replace(/_/g, ""));
6211
+ };
6212
+ let node;
6213
+ if (token.type === "Integer") node = {
6214
+ type: "TOMLValue",
6215
+ kind: "integer",
6216
+ value: token.number,
6217
+ bigint: token.bigint,
6218
+ get number() {
6219
+ return getNumberText();
6220
+ },
6221
+ parent: valueContainer.parent,
6222
+ range: cloneRange(token.range),
6223
+ loc: cloneLoc(token.loc)
6224
+ };
6225
+ else node = {
6226
+ type: "TOMLValue",
6227
+ kind: "float",
6228
+ value: token.number,
6229
+ get number() {
6230
+ return getNumberText();
6231
+ },
6232
+ parent: valueContainer.parent,
6233
+ range: cloneRange(token.range),
6234
+ loc: cloneLoc(token.loc)
6235
+ };
6236
+ return valueContainer.set(node);
6237
+ }
6238
+ processBooleanValue(token, ctx) {
6239
+ const valueContainer = ctx.consumeValueContainer();
6240
+ const node = {
6241
+ type: "TOMLValue",
6242
+ kind: "boolean",
6243
+ value: token.boolean,
6244
+ parent: valueContainer.parent,
6245
+ range: cloneRange(token.range),
6246
+ loc: cloneLoc(token.loc)
6247
+ };
6248
+ return valueContainer.set(node);
6249
+ }
6250
+ processDateTimeValue(token, ctx) {
6251
+ const valueContainer = ctx.consumeValueContainer();
6252
+ const node = {
6253
+ type: "TOMLValue",
6254
+ kind: DATETIME_VALUE_KIND_MAP[token.type],
6255
+ value: token.date,
6256
+ datetime: token.value,
6257
+ parent: valueContainer.parent,
6258
+ range: cloneRange(token.range),
6259
+ loc: cloneLoc(token.loc)
6260
+ };
6261
+ return valueContainer.set(node);
6262
+ }
6263
+ processArray(token, ctx) {
6264
+ const valueContainer = ctx.consumeValueContainer();
6265
+ const node = {
6266
+ type: "TOMLArray",
6267
+ elements: [],
6268
+ parent: valueContainer.parent,
6269
+ range: cloneRange(token.range),
6270
+ loc: cloneLoc(token.loc)
6271
+ };
6272
+ const nextToken = ctx.nextToken({ valuesEnabled: true });
6273
+ if (isRightBracket(nextToken)) {
6274
+ applyEndLoc(node, nextToken);
6275
+ return valueContainer.set(node);
6276
+ }
6277
+ ctx.backToken();
6278
+ return this.processArrayValue(node, valueContainer, ctx);
6279
+ }
6280
+ processArrayValue(node, valueContainer, ctx) {
6281
+ ctx.addValueContainer({
6282
+ parent: node,
6283
+ set: (valNode) => {
6284
+ node.elements.push(valNode);
6285
+ let nextToken = ctx.nextToken({ valuesEnabled: true });
6286
+ const hasComma = isComma(nextToken);
6287
+ if (hasComma) nextToken = ctx.nextToken({ valuesEnabled: true });
6288
+ if (isRightBracket(nextToken)) {
6289
+ applyEndLoc(node, nextToken);
6290
+ return valueContainer.set(node);
6291
+ }
6292
+ if (hasComma) {
6293
+ ctx.backToken();
6294
+ return this.processArrayValue(node, valueContainer, ctx);
6295
+ }
6296
+ return ctx.reportParseError(nextToken ? "missing-comma" : "unterminated-array", nextToken);
6297
+ }
6298
+ });
6299
+ return ["VALUE"];
6300
+ }
6301
+ processInlineTable(token, ctx) {
6302
+ const valueContainer = ctx.consumeValueContainer();
6303
+ const node = {
6304
+ type: "TOMLInlineTable",
6305
+ body: [],
6306
+ parent: valueContainer.parent,
6307
+ range: cloneRange(token.range),
6308
+ loc: cloneLoc(token.loc)
6309
+ };
6310
+ const needSameLine = this.tomlVersion.gte(1, 1) ? void 0 : "invalid-inline-table-newline";
6311
+ const nextToken = ctx.nextToken({ needSameLine });
6312
+ if (nextToken) {
6313
+ if (isBare(nextToken) || isString(nextToken)) return this.processInlineTableKeyValue(nextToken, node, valueContainer, ctx);
6314
+ if (isRightBrace(nextToken)) {
6315
+ applyEndLoc(node, nextToken);
6316
+ return valueContainer.set(node);
6317
+ }
6318
+ }
6319
+ return ctx.reportParseError("unexpected-token", nextToken);
6320
+ }
6321
+ processInlineTableKeyValue(token, inlineTableNode, valueContainer, ctx) {
6322
+ const keyValueNode = {
6323
+ type: "TOMLKeyValue",
6324
+ key: null,
6325
+ value: null,
6326
+ parent: inlineTableNode,
6327
+ range: cloneRange(token.range),
6328
+ loc: cloneLoc(token.loc)
6329
+ };
6330
+ inlineTableNode.body.push(keyValueNode);
6331
+ const { nextToken: targetToken } = this.processKeyNode(token, keyValueNode, ctx);
6332
+ if (!isEq(targetToken)) return ctx.reportParseError("missing-equals-sign", targetToken);
6333
+ const needSameLine = this.tomlVersion.gte(1, 1) ? void 0 : "invalid-inline-table-newline";
6334
+ ctx.addValueContainer({
6335
+ parent: keyValueNode,
6336
+ set: (valNode) => {
6337
+ keyValueNode.value = valNode;
6338
+ applyEndLoc(keyValueNode, valNode);
6339
+ let nextToken = ctx.nextToken({ needSameLine });
6340
+ if (isComma(nextToken)) {
6341
+ nextToken = ctx.nextToken({ needSameLine });
6342
+ if (nextToken && (isBare(nextToken) || isString(nextToken))) return this.processInlineTableKeyValue(nextToken, inlineTableNode, valueContainer, ctx);
6343
+ if (isRightBrace(nextToken)) {
6344
+ if (this.tomlVersion.lt(1, 1)) return ctx.reportParseError("invalid-trailing-comma-in-inline-table", nextToken);
6345
+ } else return ctx.reportParseError(nextToken ? "unexpected-token" : "unterminated-inline-table", nextToken);
6346
+ }
6347
+ if (isRightBrace(nextToken)) {
6348
+ applyEndLoc(inlineTableNode, nextToken);
6349
+ return valueContainer.set(inlineTableNode);
6350
+ }
6351
+ return ctx.reportParseError(nextToken ? "missing-comma" : "unterminated-inline-table", nextToken);
6352
+ }
6353
+ });
6354
+ ctx.needSameLine = "invalid-key-value-newline";
6355
+ return ["VALUE"];
6356
+ }
6357
+ };
6358
+ function isDot(token) {
6359
+ return isPunctuator(token) && token.value === ".";
6360
+ }
6361
+ function isEq(token) {
6362
+ return isPunctuator(token) && token.value === "=";
6363
+ }
6364
+ function isLeftBracket(token) {
6365
+ return isPunctuator(token) && token.value === "[";
6366
+ }
6367
+ function isRightBracket(token) {
6368
+ return isPunctuator(token) && token.value === "]";
6369
+ }
6370
+ function isLeftBrace(token) {
6371
+ return isPunctuator(token) && token.value === "{";
6372
+ }
6373
+ function isRightBrace(token) {
6374
+ return isPunctuator(token) && token.value === "}";
6375
+ }
6376
+ function isComma(token) {
6377
+ return isPunctuator(token) && token.value === ",";
6378
+ }
6379
+ function isPunctuator(token) {
6380
+ return Boolean(token && token.type === "Punctuator");
6381
+ }
6382
+ function isBare(token) {
6383
+ return token.type === "Bare";
6384
+ }
6385
+ function isString(token) {
6386
+ return token.type === "BasicString" || token.type === "LiteralString";
6387
+ }
6388
+ function isMultiLineString(token) {
6389
+ return token.type === "MultiLineBasicString" || token.type === "MultiLineLiteralString";
6390
+ }
6391
+ function isNumber(token) {
6392
+ return token.type === "Integer" || token.type === "Float";
6393
+ }
6394
+ function isBoolean(token) {
6395
+ return token.type === "Boolean";
6396
+ }
6397
+ function isDateTime(token) {
6398
+ return token.type === "OffsetDateTime" || token.type === "LocalDateTime" || token.type === "LocalDate" || token.type === "LocalTime";
6399
+ }
6400
+ function applyEndLoc(node, child) {
6401
+ if (child) {
6402
+ node.range[1] = child.range[1];
6403
+ node.loc.end = clonePos(child.loc.end);
6404
+ }
6405
+ }
6406
+ function cloneRange(range) {
6407
+ return [range[0], range[1]];
6408
+ }
6409
+ function cloneLoc(loc) {
6410
+ return {
6411
+ start: clonePos(loc.start),
6412
+ end: clonePos(loc.end)
6413
+ };
6414
+ }
6415
+ function clonePos(pos) {
6416
+ return {
6417
+ line: pos.line,
6418
+ column: pos.column
6419
+ };
6420
+ }
6421
+ var tomlKeys = {
6422
+ Program: ["body"],
6423
+ TOMLTopLevelTable: ["body"],
6424
+ TOMLTable: ["key", "body"],
6425
+ TOMLKeyValue: ["key", "value"],
6426
+ TOMLKey: ["keys"],
6427
+ TOMLArray: ["elements"],
6428
+ TOMLInlineTable: ["body"],
6429
+ TOMLBare: [],
6430
+ TOMLQuoted: [],
6431
+ TOMLValue: []
6432
+ };
6433
+ var KEYS3 = unionWith(tomlKeys);
6434
+ function parseForESLint(code, options) {
6435
+ return {
6436
+ ast: new TOMLParser(code, options).parse(),
6437
+ visitorKeys: KEYS3,
6438
+ services: { isTOML: true }
6439
+ };
6440
+ }
6441
+ var getStaticTOMLValue = generateConvertTOMLValue((node) => node.value);
6442
+ function generateConvertTOMLValue(convertValue) {
6443
+ function resolveValue(node, baseTable) {
6444
+ return resolver[node.type](node, baseTable);
6445
+ }
6446
+ const resolver = {
6447
+ Program(node, baseTable = {}) {
6448
+ return resolveValue(node.body[0], baseTable);
6449
+ },
6450
+ TOMLTopLevelTable(node, baseTable = {}) {
6451
+ for (const body of node.body) resolveValue(body, baseTable);
6452
+ return baseTable;
6453
+ },
6454
+ TOMLKeyValue(node, baseTable = {}) {
6455
+ const value = resolveValue(node.value);
6456
+ set(baseTable, resolveValue(node.key), value);
6457
+ return baseTable;
6458
+ },
6459
+ TOMLTable(node, baseTable = {}) {
6460
+ const table2 = getTable(baseTable, resolveValue(node.key), node.kind === "array");
6461
+ for (const body of node.body) resolveValue(body, table2);
6462
+ return baseTable;
6463
+ },
6464
+ TOMLArray(node) {
6465
+ return node.elements.map((e) => resolveValue(e));
6466
+ },
6467
+ TOMLInlineTable(node) {
6468
+ const table2 = {};
6469
+ for (const body of node.body) resolveValue(body, table2);
6470
+ return table2;
6471
+ },
6472
+ TOMLKey(node) {
6473
+ return node.keys.map((key) => resolveValue(key));
6474
+ },
6475
+ TOMLBare(node) {
6476
+ return node.name;
6477
+ },
6478
+ TOMLQuoted(node) {
6479
+ return node.value;
6480
+ },
6481
+ TOMLValue(node) {
6482
+ return convertValue(node);
6483
+ }
6484
+ };
6485
+ return (node) => resolveValue(node);
6486
+ }
6487
+ function getTable(baseTable, keys, array) {
6488
+ let target = baseTable;
6489
+ for (let index = 0; index < keys.length - 1; index++) {
6490
+ const key = keys[index];
6491
+ target = getNextTargetFromKey(target, key);
6492
+ }
6493
+ const lastKey = last(keys);
6494
+ const lastTarget = target[lastKey];
6495
+ if (lastTarget == null) {
6496
+ const tableValue$1 = {};
6497
+ target[lastKey] = array ? [tableValue$1] : tableValue$1;
6498
+ return tableValue$1;
6499
+ }
6500
+ if (isValue(lastTarget)) {
6501
+ const tableValue$1 = {};
6502
+ target[lastKey] = array ? [tableValue$1] : tableValue$1;
6503
+ return tableValue$1;
6504
+ }
6505
+ if (!array) {
6506
+ if (Array.isArray(lastTarget)) {
6507
+ const tableValue$1 = {};
6508
+ target[lastKey] = tableValue$1;
6509
+ return tableValue$1;
6510
+ }
6511
+ return lastTarget;
6512
+ }
6513
+ if (Array.isArray(lastTarget)) {
6514
+ const tableValue$1 = {};
6515
+ lastTarget.push(tableValue$1);
6516
+ return tableValue$1;
6517
+ }
6518
+ const tableValue = {};
6519
+ target[lastKey] = [tableValue];
6520
+ return tableValue;
6521
+ function getNextTargetFromKey(currTarget, key) {
6522
+ const nextTarget = currTarget[key];
6523
+ if (nextTarget == null) {
6524
+ const val = {};
6525
+ currTarget[key] = val;
6526
+ return val;
6527
+ }
6528
+ if (isValue(nextTarget)) {
6529
+ const val = {};
6530
+ currTarget[key] = val;
6531
+ return val;
6532
+ }
6533
+ let resultTarget = nextTarget;
6534
+ while (Array.isArray(resultTarget)) {
6535
+ const lastIndex = resultTarget.length - 1;
6536
+ const nextElement = resultTarget[lastIndex];
6537
+ if (isValue(nextElement)) {
6538
+ const val = {};
6539
+ resultTarget[lastIndex] = val;
6540
+ return val;
6541
+ }
6542
+ resultTarget = nextElement;
6543
+ }
6544
+ return resultTarget;
6545
+ }
6546
+ }
6547
+ function set(baseTable, keys, value) {
6548
+ let target = baseTable;
6549
+ for (let index = 0; index < keys.length - 1; index++) {
6550
+ const key = keys[index];
6551
+ const nextTarget = target[key];
6552
+ if (nextTarget == null) {
6553
+ const val = {};
6554
+ target[key] = val;
6555
+ target = val;
6556
+ } else if (isValue(nextTarget) || Array.isArray(nextTarget)) {
6557
+ const val = {};
6558
+ target[key] = val;
6559
+ target = val;
6560
+ } else target = nextTarget;
6561
+ }
6562
+ target[last(keys)] = value;
6563
+ }
6564
+ function isValue(value) {
6565
+ return typeof value !== "object" || value instanceof Date;
6566
+ }
6567
+ function parseTOML(code, options) {
6568
+ return parseForESLint(code, options).ast;
6569
+ }
6570
+
6571
+ // src/core/ops/atomic-file.ts
6572
+ import { mkdirSync as mkdirSync2, renameSync, unlinkSync, writeFileSync } from "node:fs";
6573
+ import path2 from "node:path";
6574
+ function sleepSync(ms) {
6575
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
6576
+ }
6577
+ function errCode(e) {
6578
+ return e.code;
6579
+ }
6580
+ function renameWithRetry(from, to, opts = {}) {
6581
+ const rename = opts.rename ?? renameSync;
6582
+ const sleep = opts.sleep ?? sleepSync;
6583
+ const win = (opts.platform ?? process.platform) === "win32";
6584
+ for (let attempt = 0; ; attempt += 1) {
6585
+ try {
6586
+ rename(from, to);
6587
+ return;
6588
+ } catch (e) {
6589
+ const busy = win && ATOMIC_RENAME_BUSY_CODES.includes(errCode(e) ?? "");
6590
+ if (!busy || attempt >= ATOMIC_RENAME_RETRIES) throw e;
6591
+ sleep(ATOMIC_RENAME_DELAY_MS);
6592
+ }
6593
+ }
6594
+ }
6595
+ function unlinkWithRetry(file, opts = {}) {
6596
+ const unlink = opts.unlink ?? unlinkSync;
6597
+ const sleep = opts.sleep ?? sleepSync;
6598
+ const win = (opts.platform ?? process.platform) === "win32";
6599
+ for (let attempt = 0; ; attempt += 1) {
6600
+ try {
6601
+ unlink(file);
6602
+ return;
6603
+ } catch (e) {
6604
+ if (errCode(e) === "ENOENT") return;
6605
+ const busy = win && ATOMIC_RENAME_BUSY_CODES.includes(errCode(e) ?? "");
6606
+ if (!busy || attempt >= ATOMIC_RENAME_RETRIES) throw replaceFailure(file, e);
6607
+ sleep(ATOMIC_RENAME_DELAY_MS);
6608
+ }
6609
+ }
6610
+ }
6611
+ function replaceFailure(file, e) {
6612
+ const busy = ATOMIC_RENAME_BUSY_CODES.includes(errCode(e) ?? "");
6613
+ const cause = e.message;
6614
+ return new Error(busy ? `Could not replace ${file}: ${cause}. Fix: close the program using ${file}, then re-run` : `Could not write ${file}: ${cause}. Fix: check the path and its permissions, then re-run`, { cause: e });
6615
+ }
6616
+ function removeTmpFile(tmp, opts = {}) {
6617
+ try {
6618
+ unlinkWithRetry(tmp, opts);
6619
+ } catch {
4645
6620
  }
4646
- scanAll(home, scope.tmp ?? tmpdir(), out2);
4647
- return out2;
6621
+ }
6622
+ function atomicWriteFile(file, text2, opts = {}) {
6623
+ mkdirSync2(path2.dirname(file), { recursive: true });
6624
+ const tmp = path2.join(path2.dirname(file), `${ATOMIC_TMP_PREFIX}${path2.basename(file)}${ATOMIC_TMP_MARK}${process.pid}`);
6625
+ try {
6626
+ writeFileSync(tmp, text2);
6627
+ renameWithRetry(tmp, file, opts);
6628
+ } catch (e) {
6629
+ removeTmpFile(tmp, opts);
6630
+ throw replaceFailure(file, e);
6631
+ }
6632
+ }
6633
+
6634
+ // src/core/ops/host-text.ts
6635
+ var BOM_CODE = 65279;
6636
+ var CR_CODE = 13;
6637
+ var CRLF = "\r\n";
6638
+ var LF = "\n";
6639
+ function hostLayout(raw) {
6640
+ let crlf = 0;
6641
+ let lf = 0;
6642
+ for (let i2 = raw.indexOf(LF); i2 >= 0; i2 = raw.indexOf(LF, i2 + 1)) {
6643
+ if (i2 > 0 && raw.charCodeAt(i2 - 1) === CR_CODE) crlf += 1;
6644
+ else lf += 1;
6645
+ }
6646
+ return { bom: raw.length > 0 && raw.charCodeAt(0) === BOM_CODE, crlf: crlf > 0 && crlf >= lf };
6647
+ }
6648
+ function hostText(raw) {
6649
+ const bare = raw.length > 0 && raw.charCodeAt(0) === BOM_CODE ? raw.slice(1) : raw;
6650
+ return bare.indexOf(CRLF) < 0 ? bare : bare.split(CRLF).join(LF);
6651
+ }
6652
+ function withLayout(text2, layout) {
6653
+ const eol = layout.crlf ? text2.split(LF).join(CRLF) : text2;
6654
+ return layout.bom ? String.fromCharCode(BOM_CODE) + eol : eol;
4648
6655
  }
4649
6656
 
4650
6657
  // src/core/ops/host-config.ts
4651
- import { existsSync as existsSync3, readFileSync as readFileSync2, renameSync, writeFileSync } from "node:fs";
4652
- import { dirname as dirname2, join as join4 } from "node:path";
4653
6658
  function stripJsonComments(text2) {
4654
6659
  let out2 = "";
4655
6660
  let i2 = 0;
@@ -4782,171 +6787,63 @@ function scanJson(text2, format) {
4782
6787
  if (sc.i !== clean.length) sc.fail();
4783
6788
  return { clean, root, value };
4784
6789
  }
4785
- function tomlKeyPath(s) {
4786
- const out2 = [];
4787
- let i2 = 0;
4788
- for (; ; ) {
4789
- while (s[i2] === " " || s[i2] === " ") i2 += 1;
4790
- let seg = "";
4791
- if (s[i2] === '"' || s[i2] === "'") {
4792
- const q = s[i2];
4793
- let j2 = i2 + 1;
4794
- while (j2 < s.length && s[j2] !== q) j2 += q === '"' && s[j2] === "\\" ? 2 : 1;
4795
- if (j2 >= s.length) throw new SyntaxError("key");
4796
- seg = q === '"' ? JSON.parse(s.slice(i2, j2 + 1)) : s.slice(i2 + 1, j2);
4797
- i2 = j2 + 1;
4798
- } else {
4799
- while (i2 < s.length && !" .".includes(s[i2])) {
4800
- seg += s[i2];
4801
- i2 += 1;
4802
- }
4803
- if (seg === "") throw new SyntaxError("key");
4804
- }
4805
- out2.push(seg);
4806
- while (s[i2] === " " || s[i2] === " ") i2 += 1;
4807
- if (i2 >= s.length) return out2;
4808
- if (s[i2] !== ".") throw new SyntaxError("key");
4809
- i2 += 1;
4810
- }
6790
+ function keyNames(key) {
6791
+ return key.keys.map((k) => k.type === "TOMLBare" ? k.name : k.value);
4811
6792
  }
4812
- var TomlValue = class {
4813
- i = 0;
4814
- s;
4815
- constructor(s) {
4816
- this.s = s;
4817
- }
4818
- ws() {
4819
- for (; ; ) {
4820
- while (this.i < this.s.length && " \r\n".includes(this.s[this.i])) this.i += 1;
4821
- if (this.s[this.i] !== "#") return;
4822
- while (this.i < this.s.length && this.s[this.i] !== "\n") this.i += 1;
4823
- }
4824
- }
4825
- read() {
4826
- this.ws();
4827
- const c3 = this.s[this.i];
4828
- if (c3 === '"' || c3 === "'") {
4829
- let j3 = this.i + 1;
4830
- while (j3 < this.s.length && this.s[j3] !== c3 && this.s[j3] !== "\n") j3 += c3 === '"' && this.s[j3] === "\\" ? 2 : 1;
4831
- if (this.s[j3] !== c3) throw new SyntaxError("string");
4832
- const raw = this.s.slice(this.i, j3 + 1);
4833
- this.i = j3 + 1;
4834
- return c3 === '"' ? JSON.parse(raw) : raw.slice(1, -1);
4835
- }
4836
- if (c3 === "[") {
4837
- this.i += 1;
4838
- const out2 = [];
4839
- for (; ; ) {
4840
- this.ws();
4841
- if (this.s[this.i] === "]") {
4842
- this.i += 1;
4843
- return out2;
4844
- }
4845
- out2.push(this.read());
4846
- this.ws();
4847
- if (this.s[this.i] === ",") {
4848
- this.i += 1;
4849
- continue;
4850
- }
4851
- if (this.s[this.i] !== "]") throw new SyntaxError("array");
4852
- }
4853
- }
4854
- if (c3 === "{") {
4855
- this.i += 1;
4856
- const out2 = {};
4857
- for (; ; ) {
4858
- this.ws();
4859
- if (this.s[this.i] === "}") {
4860
- this.i += 1;
4861
- return out2;
4862
- }
4863
- const eq = this.s.indexOf("=", this.i);
4864
- if (eq < 0) throw new SyntaxError("inline table");
4865
- const key = tomlKeyPath(this.s.slice(this.i, eq));
4866
- this.i = eq + 1;
4867
- setPath(out2, key, this.read());
4868
- this.ws();
4869
- if (this.s[this.i] === ",") {
4870
- this.i += 1;
4871
- continue;
4872
- }
4873
- if (this.s[this.i] !== "}") throw new SyntaxError("inline table");
4874
- }
4875
- }
4876
- let j2 = this.i;
4877
- while (j2 < this.s.length && !" \r\n,]}#".includes(this.s[j2])) j2 += 1;
4878
- const word = this.s.slice(this.i, j2);
4879
- this.i = j2;
4880
- if (word === "true") return true;
4881
- if (word === "false") return false;
4882
- const n3 = Number(word.split("_").join(""));
4883
- if (word === "" || Number.isNaN(n3)) throw new SyntaxError("value");
4884
- return n3;
4885
- }
4886
- };
4887
- function setPath(target, path8, value) {
4888
- let cur = target;
4889
- for (let k = 0; k < path8.length - 1; k += 1) {
4890
- const next = cur[path8[k]];
4891
- if (next === void 0) cur[path8[k]] = {};
4892
- else if (!isPlainObject(next)) throw new SyntaxError("key conflict");
4893
- cur = cur[path8[k]];
4894
- }
4895
- if (cur[path8[path8.length - 1]] !== void 0) throw new SyntaxError("duplicate key");
4896
- cur[path8[path8.length - 1]] = value;
6793
+ function lineStartOf(text2, at) {
6794
+ return at === 0 ? 0 : text2.lastIndexOf("\n", at - 1) + 1;
6795
+ }
6796
+ function lineEndOf(text2, at) {
6797
+ const nl = text2.indexOf("\n", at);
6798
+ return nl < 0 ? text2.length : nl + 1;
6799
+ }
6800
+ function tomlValue(text2) {
6801
+ return getStaticTOMLValue(parseTOML(text2));
4897
6802
  }
4898
6803
  function scanToml(text2) {
4899
- const value = {};
6804
+ const program = parseTOML(text2);
4900
6805
  const tables = [];
4901
- let table2 = value;
4902
- let i2 = 0;
4903
- while (i2 < text2.length) {
4904
- const lineEnd = text2.indexOf("\n", i2) < 0 ? text2.length : text2.indexOf("\n", i2) + 1;
4905
- const line = text2.slice(i2, lineEnd).trim();
4906
- if (line === "" || line.startsWith("#")) {
4907
- i2 = lineEnd;
4908
- continue;
4909
- }
4910
- if (line.startsWith("[")) {
4911
- if (line.startsWith("[[")) throw new SyntaxError("array of tables");
4912
- const close = line.indexOf("]");
4913
- if (close < 0) throw new SyntaxError("header");
4914
- const path8 = tomlKeyPath(line.slice(1, close));
4915
- if (tables.length > 0) tables[tables.length - 1].end = i2;
4916
- tables.push({ path: path8, start: i2, end: text2.length });
4917
- let cur = value;
4918
- for (const seg of path8) {
4919
- if (cur[seg] === void 0) cur[seg] = {};
4920
- if (!isPlainObject(cur[seg])) throw new SyntaxError("table conflict");
4921
- cur = cur[seg];
4922
- }
4923
- table2 = cur;
4924
- i2 = lineEnd;
6806
+ const keys = [];
6807
+ const addKey = (base, kv) => {
6808
+ keys.push({ base, full: [...base, ...keyNames(kv.key)], start: kv.range[0], end: kv.range[1], inline: kv.value.type === "TOMLInlineTable" });
6809
+ };
6810
+ for (const node of program.body[0].body) {
6811
+ if (node.type === "TOMLKeyValue") {
6812
+ addKey([], node);
4925
6813
  continue;
4926
6814
  }
4927
- const eq = text2.indexOf("=", i2);
4928
- if (eq < 0 || eq >= lineEnd) throw new SyntaxError("key/value");
4929
- const key = tomlKeyPath(text2.slice(i2, eq));
4930
- const reader = new TomlValue(text2);
4931
- reader.i = eq + 1;
4932
- setPath(table2, key, reader.read());
4933
- while (reader.i < text2.length && (text2[reader.i] === " " || text2[reader.i] === " ")) reader.i += 1;
4934
- if (text2[reader.i] === "#") while (reader.i < text2.length && text2[reader.i] !== "\n") reader.i += 1;
4935
- if (reader.i < text2.length && text2[reader.i] !== "\n" && text2[reader.i] !== "\r") throw new SyntaxError("trailing text");
4936
- i2 = text2.indexOf("\n", reader.i) < 0 ? text2.length : text2.indexOf("\n", reader.i) + 1;
6815
+ if (!node.resolvedKey.every((seg) => typeof seg === "string")) continue;
6816
+ const path9 = node.resolvedKey;
6817
+ for (const kv of node.body) addKey(path9, kv);
6818
+ if (node.kind !== "standard") continue;
6819
+ const start = lineStartOf(text2, node.range[0]);
6820
+ const headEnd = lineEndOf(text2, node.key.range[1]);
6821
+ const last2 = node.body[node.body.length - 1];
6822
+ tables.push({
6823
+ path: path9,
6824
+ header: text2.slice(start, text2[headEnd - 1] === "\n" ? headEnd - 1 : headEnd),
6825
+ start,
6826
+ end: last2 === void 0 ? headEnd : lineEndOf(text2, last2.range[1])
6827
+ });
4937
6828
  }
4938
- return { value, tables };
6829
+ return { value: getStaticTOMLValue(program), tables, keys };
6830
+ }
6831
+ function tomlTableSpans(text2) {
6832
+ return scanToml(text2).tables;
6833
+ }
6834
+ function tomlHeaderText(path9) {
6835
+ return "[" + path9.map(tomlHeaderKey).join(".") + "]";
4939
6836
  }
4940
- function parseHostConfig(agent, path8, text2, format) {
6837
+ function parseHostConfig(agent, path9, text2, format) {
4941
6838
  try {
4942
6839
  return format === "toml" ? scanToml(text2).value : scanJson(text2, format).value;
4943
6840
  } catch {
4944
- throw new CtxError("CONFIG_PARSE_FAILED", { agent, path: path8, format });
6841
+ throw new CtxError("CONFIG_PARSE_FAILED", { agent, path: path9, format });
4945
6842
  }
4946
6843
  }
4947
- function hostConfigValueAt(value, path8) {
6844
+ function hostConfigValueAt(value, path9) {
4948
6845
  let cur = value;
4949
- for (const seg of path8) {
6846
+ for (const seg of path9) {
4950
6847
  if (!isPlainObject(cur)) return void 0;
4951
6848
  cur = cur[seg];
4952
6849
  }
@@ -4979,103 +6876,431 @@ function indentUnit(root, clean) {
4979
6876
  function render(value, unit, base) {
4980
6877
  return JSON.stringify(value, null, unit).split("\n").join("\n" + base);
4981
6878
  }
4982
- function nest(path8, value) {
4983
- let out2 = value;
4984
- for (let k = path8.length - 1; k >= 0; k -= 1) out2 = { [path8[k]]: out2 };
4985
- return out2;
6879
+ function nest(path9, value) {
6880
+ let out2 = value;
6881
+ for (let k = path9.length - 1; k >= 0; k -= 1) out2 = { [path9[k]]: out2 };
6882
+ return out2;
6883
+ }
6884
+ function setJsonText(text2, format, path9, value) {
6885
+ const doc = scanJson(text2, format);
6886
+ const unit = indentUnit(doc.root, doc.clean);
6887
+ if (doc.root === null) return render(nest(path9, value), unit, "") + "\n";
6888
+ let node = doc.root;
6889
+ let depth = 0;
6890
+ while (depth < path9.length && node.kind === "object") {
6891
+ const hit = node.members.find((m3) => m3.key === path9[depth]);
6892
+ if (hit === void 0) break;
6893
+ node = hit.node;
6894
+ depth += 1;
6895
+ }
6896
+ if (depth === path9.length) {
6897
+ return text2.slice(0, node.start) + render(value, unit, lineIndent(doc.clean, node.start)) + text2.slice(node.end);
6898
+ }
6899
+ if (node.kind !== "object") throw new SyntaxError("not an object at " + path9.slice(0, depth).join("."));
6900
+ const rest = nest(path9.slice(depth + 1), value);
6901
+ const last2 = node.members[node.members.length - 1];
6902
+ if (last2 === void 0) {
6903
+ const base2 = lineIndent(doc.clean, node.start);
6904
+ const member2 = "\n" + base2 + unit + JSON.stringify(path9[depth]) + ": " + render(rest, unit, base2 + unit) + "\n" + base2;
6905
+ return text2.slice(0, node.start + 1) + member2 + text2.slice(node.end - 1);
6906
+ }
6907
+ const base = lineIndent(doc.clean, last2.keyStart);
6908
+ let at = last2.node.end;
6909
+ while (" \r\n".includes(doc.clean[at])) at += 1;
6910
+ const trailing = doc.clean[at] === ",";
6911
+ const insertAt = trailing ? at + 1 : last2.node.end;
6912
+ const member = (trailing ? "" : ",") + "\n" + base + JSON.stringify(path9[depth]) + ": " + render(rest, unit, base);
6913
+ return text2.slice(0, insertAt) + member + text2.slice(insertAt);
6914
+ }
6915
+ function tomlScalar(v) {
6916
+ if (Array.isArray(v)) return "[" + v.map(tomlScalar).join(", ") + "]";
6917
+ if (isPlainObject(v)) return "{ " + Object.entries(v).map(([k, x2]) => tomlHeaderKey(k) + " = " + tomlScalar(x2)).join(", ") + " }";
6918
+ if (typeof v === "string") return JSON.stringify(v);
6919
+ if (typeof v === "number" || typeof v === "boolean") return String(v);
6920
+ throw new SyntaxError("unsupported TOML value");
6921
+ }
6922
+ function tomlHeaderKey(seg) {
6923
+ if (seg === "") return '""';
6924
+ for (const ch of seg) {
6925
+ const bare = ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch >= "0" && ch <= "9" || ch === "_" || ch === "-";
6926
+ if (!bare) return JSON.stringify(seg);
6927
+ }
6928
+ return seg;
6929
+ }
6930
+ function tomlBlock(path9, value) {
6931
+ let out2 = "[" + path9.map(tomlHeaderKey).join(".") + "]\n";
6932
+ const subs = [];
6933
+ for (const [k, v] of Object.entries(value)) {
6934
+ if (isPlainObject(v)) subs.push(tomlBlock([...path9, k], v));
6935
+ else out2 += tomlHeaderKey(k) + " = " + tomlScalar(v) + "\n";
6936
+ }
6937
+ return [out2, ...subs].join("\n");
6938
+ }
6939
+ function under(path9, prefix) {
6940
+ return path9.length >= prefix.length && prefix.every((seg, k) => path9[k] === seg);
6941
+ }
6942
+ function keyLineRange(text2, k) {
6943
+ const ls = lineStartOf(text2, k.start);
6944
+ const le = lineEndOf(text2, k.end);
6945
+ const rest = text2.slice(k.end, le).trim();
6946
+ const alone = text2.slice(ls, k.start).trim() === "" && (rest === "" || rest.startsWith("#"));
6947
+ return alone ? [ls, le] : [k.start, k.end];
6948
+ }
6949
+ function withValueAt(root, rel, value) {
6950
+ if (rel.length === 0) return value;
6951
+ const base = isPlainObject(root) ? { ...root } : {};
6952
+ const next = withValueAt(base[rel[0]], rel.slice(1), value);
6953
+ if (next === void 0) delete base[rel[0]];
6954
+ else base[rel[0]] = next;
6955
+ return base;
6956
+ }
6957
+ function replaceToml(text2, doc, path9, value) {
6958
+ const block2 = value === void 0 ? "" : tomlBlock(path9, value);
6959
+ const owned = doc.tables.filter((t2) => under(t2.path, path9));
6960
+ const cuts = doc.keys.filter((k) => under(k.full, path9) && !under(k.base, path9)).map((k) => [...keyLineRange(text2, k), ""]);
6961
+ owned.forEach((t2, n3) => cuts.push([t2.start, t2.end, n3 === 0 ? block2 : ""]));
6962
+ cuts.sort((a2, b3) => b3[0] - a2[0]);
6963
+ let out2 = text2;
6964
+ for (const [s, e, put] of cuts) out2 = out2.slice(0, s) + put + out2.slice(e);
6965
+ if (owned.length > 0 || block2 === "") return out2;
6966
+ const sep = out2 === "" ? "" : out2.endsWith("\n\n") ? "" : out2.endsWith("\n") ? "\n" : "\n\n";
6967
+ return out2 + sep + block2;
6968
+ }
6969
+ var tableLike = (v) => v === void 0 || isPlainObject(v);
6970
+ function setTomlText(text2, path9, value) {
6971
+ if (value !== void 0 && !isPlainObject(value)) throw new SyntaxError("TOML edits replace a whole table");
6972
+ const doc = scanToml(text2);
6973
+ const cur = hostConfigValueAt(doc.value, path9);
6974
+ if (sameValue(cur, value)) return text2;
6975
+ const inline = doc.keys.find((k) => k.inline && k.full.length < path9.length && under(path9, k.full));
6976
+ if (inline !== void 0) {
6977
+ const whole = withValueAt(hostConfigValueAt(doc.value, inline.full), path9.slice(inline.full.length), value);
6978
+ return replaceToml(text2, doc, inline.full, whole);
6979
+ }
6980
+ if (isPlainObject(cur) && isPlainObject(value)) {
6981
+ const names = [.../* @__PURE__ */ new Set([...Object.keys(cur), ...Object.keys(value)])].filter((k) => !sameValue(cur[k], value[k]));
6982
+ if (names.every((k) => tableLike(cur[k]) && tableLike(value[k]))) {
6983
+ let out2 = text2;
6984
+ for (const k of names) out2 = setTomlText(out2, [...path9, k], value[k]);
6985
+ return out2;
6986
+ }
6987
+ }
6988
+ return replaceToml(text2, doc, path9, value);
6989
+ }
6990
+ function setText(agent, path9, text2, format, key, value) {
6991
+ try {
6992
+ if (format !== "toml") return setJsonText(text2, format, key, value);
6993
+ const out2 = setTomlText(text2, key, value);
6994
+ const landed = hostConfigValueAt(tomlValue(out2), key);
6995
+ const emptyTable = isPlainObject(value) && Object.keys(value).length === 0;
6996
+ if (!sameValue(landed, value) && !(emptyTable && landed === void 0)) throw new SyntaxError("edit did not land");
6997
+ return out2;
6998
+ } catch {
6999
+ throw new CtxError("CONFIG_PARSE_FAILED", { agent, path: path9, format });
7000
+ }
7001
+ }
7002
+ function applyEdits(agent, path9, text2, format, wanted) {
7003
+ const parsed = parseHostConfig(agent, path9, text2, format);
7004
+ let out2 = text2;
7005
+ const edits = [];
7006
+ for (const [key, after] of wanted) {
7007
+ const before = hostConfigValueAt(parsed, key);
7008
+ if (sameValue(before, after)) continue;
7009
+ out2 = setText(agent, path9, out2, format, key, after);
7010
+ edits.push({ path: key.join("."), before, after });
7011
+ }
7012
+ return { text: out2, format, edits };
7013
+ }
7014
+ function editHostConfigText(agent, path9, text2, format, wanted) {
7015
+ return applyEdits(agent, path9, text2, format, wanted);
7016
+ }
7017
+
7018
+ // src/core/ops/detect-v1.ts
7019
+ var isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
7020
+ var keyPath = (...parts) => parts.join(".");
7021
+ var finding = (file, path9, reason) => ({ file, path: path9, reason });
7022
+ function stripJsonc(text2) {
7023
+ let out2 = "";
7024
+ let inStr = false;
7025
+ let esc = false;
7026
+ for (let i2 = 0; i2 < text2.length; i2++) {
7027
+ const c3 = text2[i2];
7028
+ if (inStr) {
7029
+ out2 += c3;
7030
+ if (esc) esc = false;
7031
+ else if (c3 === "\\") esc = true;
7032
+ else if (c3 === '"') inStr = false;
7033
+ continue;
7034
+ }
7035
+ if (c3 === '"') {
7036
+ inStr = true;
7037
+ out2 += c3;
7038
+ continue;
7039
+ }
7040
+ if (c3 === "/" && text2[i2 + 1] === "/") {
7041
+ while (i2 < text2.length && text2[i2] !== "\n") i2++;
7042
+ out2 += "\n";
7043
+ continue;
7044
+ }
7045
+ if (c3 === "/" && text2[i2 + 1] === "*") {
7046
+ const end = text2.indexOf("*/", i2 + 2);
7047
+ i2 = end === -1 ? text2.length : end + 1;
7048
+ continue;
7049
+ }
7050
+ if (c3 === ",") {
7051
+ let j2 = i2 + 1;
7052
+ while (j2 < text2.length && " \r\n".includes(text2[j2])) j2++;
7053
+ if (text2[j2] === "}" || text2[j2] === "]") continue;
7054
+ }
7055
+ out2 += c3;
7056
+ }
7057
+ return out2;
7058
+ }
7059
+ function readJson(file) {
7060
+ try {
7061
+ return JSON.parse(stripJsonc(hostText(readFileSync2(file, "utf8"))));
7062
+ } catch {
7063
+ return void 0;
7064
+ }
7065
+ }
7066
+ function readText(file) {
7067
+ try {
7068
+ return hostText(readFileSync2(file, "utf8"));
7069
+ } catch {
7070
+ return "";
7071
+ }
7072
+ }
7073
+ function readTomlTables(file) {
7074
+ try {
7075
+ return tomlTableSpans(readText(file));
7076
+ } catch {
7077
+ return [];
7078
+ }
7079
+ }
7080
+ var listOf = (v) => Array.isArray(v) ? v : [];
7081
+ var commandOf = (v) => isObj(v) && typeof v.command === "string" ? v.command : null;
7082
+ function nestedCommands(doc) {
7083
+ const out2 = [];
7084
+ if (!isObj(doc) || !isObj(doc[HOOKS_KEY])) return out2;
7085
+ for (const [event, groups] of Object.entries(doc[HOOKS_KEY])) {
7086
+ listOf(groups).forEach((group2, i2) => {
7087
+ if (!isObj(group2)) return;
7088
+ listOf(group2[HOOKS_KEY]).forEach((inner, j2) => {
7089
+ const command = commandOf(inner);
7090
+ if (command !== null) out2.push({ path: keyPath(HOOKS_KEY, event, i2, HOOKS_KEY, j2), command });
7091
+ });
7092
+ });
7093
+ }
7094
+ return out2;
7095
+ }
7096
+ function flatCommands(events2, prefix) {
7097
+ const out2 = [];
7098
+ if (!isObj(events2)) return out2;
7099
+ for (const [event, entries] of Object.entries(events2)) {
7100
+ listOf(entries).forEach((entry2, i2) => {
7101
+ const command = commandOf(entry2);
7102
+ if (command !== null) out2.push({ path: keyPath(...prefix, event, i2), command });
7103
+ });
7104
+ }
7105
+ return out2;
7106
+ }
7107
+ var isV1Hook = (cmd) => cmd.includes(SERVER_KEY) && (V1_SCRIPT_NAMES.some((name) => cmd.includes(name)) || cmd.includes(V1_HOOK_COMMAND));
7108
+ var isCodexScript = (cmd) => cmd.includes(V1_SCRIPT_EXT) && V1_PATH_SEPS.some((sep) => cmd.includes(V1_CODEX_HOOKS_DIR.join(sep) + sep));
7109
+ function dataDir(dir, reason, out2) {
7110
+ if (existsSync3(dir)) out2.push(finding(dir, "", reason));
7111
+ }
7112
+ function mcpEntry(file, doc, out2) {
7113
+ if (isObj(doc) && isObj(doc[MCP_SERVERS_KEY]) && Object.hasOwn(doc[MCP_SERVERS_KEY], SERVER_KEY)) {
7114
+ out2.push(finding(file, keyPath(MCP_SERVERS_KEY, SERVER_KEY), V1_REASON.mcpEntry));
7115
+ }
7116
+ }
7117
+ function claudeShapeSettings(agentHome, out2) {
7118
+ const file = join4(agentHome, SETTINGS_FILE);
7119
+ const doc = readJson(file);
7120
+ for (const c3 of nestedCommands(doc)) {
7121
+ if (c3.command.includes(V1_CACHE_HEAL_NAME)) out2.push(finding(file, c3.path, V1_REASON.cacheHealHook));
7122
+ else if (isV1Hook(c3.command)) out2.push(finding(file, c3.path, V1_REASON.hook));
7123
+ }
7124
+ const status = isObj(doc) ? commandOf(doc[STATUS_LINE_KEY]) : null;
7125
+ if (status !== null && status.includes(V1_STATUSLINE_COMMAND)) {
7126
+ out2.push(finding(file, STATUS_LINE_KEY, V1_REASON.statusLine));
7127
+ }
7128
+ mcpEntry(file, doc, out2);
7129
+ }
7130
+ function v1HookFile(file, out2) {
7131
+ const doc = readJson(file);
7132
+ const cmds = isObj(doc) ? flatCommands(doc[HOOKS_KEY], [HOOKS_KEY]) : [];
7133
+ if (cmds.some((c3) => c3.command.includes(V1_HOOK_COMMAND))) out2.push(finding(file, "", V1_REASON.hookFile));
7134
+ }
7135
+ function scanClaudeCode(home, agentHome, out2) {
7136
+ claudeShapeSettings(agentHome, out2);
7137
+ for (const ext of V1_CACHE_HEAL_EXTS) {
7138
+ const file = join4(agentHome, V1_HOOKS_DIR_NAME, V1_CACHE_HEAL_NAME + ext);
7139
+ if (existsSync3(file)) out2.push(finding(file, "", V1_REASON.cacheHealFile));
7140
+ }
7141
+ const userFile = join4(home, CLAUDE_USER_CONFIG_FILE);
7142
+ mcpEntry(userFile, readJson(userFile), out2);
7143
+ dataDir(join4(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
7144
+ }
7145
+ function scanCodex(agentHome, out2) {
7146
+ const hooksFile = join4(agentHome, HOOKS_JSON_FILE);
7147
+ for (const c3 of nestedCommands(readJson(hooksFile))) {
7148
+ if (c3.command.includes(V1_CODEX_HOOK_COMMAND) || isCodexScript(c3.command)) {
7149
+ out2.push(finding(hooksFile, c3.path, V1_REASON.codexHook));
7150
+ }
7151
+ }
7152
+ const tomlFile = join4(agentHome, CONFIG_TOML_FILE);
7153
+ for (const span of readTomlTables(tomlFile)) {
7154
+ if (tomlHeaderText(span.path).startsWith(V1_TOML_SECTION_PREFIX)) out2.push(finding(tomlFile, span.header.trim(), V1_REASON.codexToml));
7155
+ }
7156
+ dataDir(join4(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
7157
+ }
7158
+ function scanGemini(agentHome, out2) {
7159
+ const file = join4(agentHome, SETTINGS_FILE);
7160
+ for (const c3 of nestedCommands(readJson(file))) {
7161
+ if (c3.command.includes(SERVER_KEY)) out2.push(finding(file, c3.path, V1_REASON.hook));
7162
+ }
7163
+ dataDir(join4(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDirShared, out2);
4986
7164
  }
4987
- function setJsonText(text2, format, path8, value) {
4988
- const doc = scanJson(text2, format);
4989
- const unit = indentUnit(doc.root, doc.clean);
4990
- if (doc.root === null) return render(nest(path8, value), unit, "") + "\n";
4991
- let node = doc.root;
4992
- let depth = 0;
4993
- while (depth < path8.length && node.kind === "object") {
4994
- const hit = node.members.find((m3) => m3.key === path8[depth]);
4995
- if (hit === void 0) break;
4996
- node = hit.node;
4997
- depth += 1;
7165
+ function scanVscode(agentHome, project, out2) {
7166
+ if (project !== void 0) {
7167
+ v1HookFile(join4(project, GITHUB_DIR_NAME, V1_HOOKS_DIR_NAME, OWN_HOOK_FILE), out2);
7168
+ const mcpFile = join4(project, VSCODE_DIR_NAME, VSCODE_MCP_FILE);
7169
+ const doc = readJson(mcpFile);
7170
+ const servers = isObj(doc) && isObj(doc[VSCODE_MCP_SERVERS_KEY]) ? doc[VSCODE_MCP_SERVERS_KEY] : {};
7171
+ const entry2 = Object.hasOwn(servers, SERVER_KEY) ? servers[SERVER_KEY] : void 0;
7172
+ if (isObj(entry2) && (entry2.command === V1_BIN_COMMAND || listOf(entry2.args).some((a2) => a2 === V1_BIN_COMMAND))) {
7173
+ out2.push(finding(mcpFile, keyPath(VSCODE_MCP_SERVERS_KEY, SERVER_KEY), V1_REASON.vscodeMcp));
7174
+ }
7175
+ dataDir(join4(project, GITHUB_DIR_NAME, V1_DATA_DIR_NAME, V1_SESSIONS_DIR_NAME), V1_REASON.dataDir, out2);
4998
7176
  }
4999
- if (depth === path8.length) {
5000
- return text2.slice(0, node.start) + render(value, unit, lineIndent(doc.clean, node.start)) + text2.slice(node.end);
7177
+ dataDir(join4(agentHome, V1_DATA_DIR_NAME, V1_SESSIONS_DIR_NAME), V1_REASON.dataDir, out2);
7178
+ }
7179
+ function jsonFiles(dir) {
7180
+ try {
7181
+ return readdirSync2(dir).filter((name) => name.endsWith(KIRO_AGENT_FILE_EXT)).sort();
7182
+ } catch {
7183
+ return [];
5001
7184
  }
5002
- if (node.kind !== "object") throw new SyntaxError("not an object at " + path8.slice(0, depth).join("."));
5003
- const rest = nest(path8.slice(depth + 1), value);
5004
- const last = node.members[node.members.length - 1];
5005
- if (last === void 0) {
5006
- const base2 = lineIndent(doc.clean, node.start);
5007
- const member2 = "\n" + base2 + unit + JSON.stringify(path8[depth]) + ": " + render(rest, unit, base2 + unit) + "\n" + base2;
5008
- return text2.slice(0, node.start + 1) + member2 + text2.slice(node.end - 1);
7185
+ }
7186
+ function scanKiro(agentHome, project, out2) {
7187
+ const agentsDir = join4(agentHome, KIRO_AGENTS_DIR);
7188
+ const defaultFile = join4(agentHome, ...KIRO_AGENT_FILE);
7189
+ for (const name of jsonFiles(agentsDir)) {
7190
+ const file = join4(agentsDir, name);
7191
+ const doc = readJson(file);
7192
+ if (isObj(doc) && doc[KIRO_AGENT_NAME_KEY] === SERVER_KEY) {
7193
+ out2.push(finding(file, "", V1_REASON.kiroAgentFile));
7194
+ continue;
7195
+ }
7196
+ if (file !== defaultFile) continue;
7197
+ for (const c3 of isObj(doc) ? flatCommands(doc[HOOKS_KEY], [HOOKS_KEY]) : []) {
7198
+ if (isV1Hook(c3.command)) out2.push(finding(file, c3.path, V1_REASON.kiroHook));
7199
+ }
5009
7200
  }
5010
- const base = lineIndent(doc.clean, last.keyStart);
5011
- let at = last.node.end;
5012
- while (" \r\n".includes(doc.clean[at])) at += 1;
5013
- const trailing = doc.clean[at] === ",";
5014
- const insertAt = trailing ? at + 1 : last.node.end;
5015
- const member = (trailing ? "" : ",") + "\n" + base + JSON.stringify(path8[depth]) + ": " + render(rest, unit, base);
5016
- return text2.slice(0, insertAt) + member + text2.slice(insertAt);
7201
+ const steeringDocs = [join4(agentHome, ...KIRO_STEERING_FILE)];
7202
+ if (project !== void 0) steeringDocs.push(join4(project, ...AGENT_HOME_DIR.kiro, ...KIRO_STEERING_FILE));
7203
+ for (const file of steeringDocs) {
7204
+ if (existsSync3(file)) out2.push(finding(file, "", V1_REASON.kiroSteering));
7205
+ }
7206
+ dataDir(join4(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
5017
7207
  }
5018
- function tomlScalar(v) {
5019
- if (Array.isArray(v)) return "[" + v.map(tomlScalar).join(", ") + "]";
5020
- if (typeof v === "string") return JSON.stringify(v);
5021
- if (typeof v === "number" || typeof v === "boolean") return String(v);
5022
- throw new SyntaxError("unsupported TOML value");
7208
+ function scanPi(piAgentDir, agentHome, out2) {
7209
+ const file = join4(piAgentDir, SETTINGS_FILE);
7210
+ const doc = readJson(file);
7211
+ listOf(isObj(doc) ? doc[PI_PACKAGES_KEY] : void 0).forEach((pkg, i2) => {
7212
+ const spec = isObj(pkg) ? pkg[PI_PACKAGE_SOURCE_KEY] : pkg;
7213
+ if (spec === V1_PI_PACKAGE) out2.push(finding(file, keyPath(PI_PACKAGES_KEY, i2), V1_REASON.piNpm));
7214
+ });
7215
+ dataDir(join4(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
5023
7216
  }
5024
- function tomlHeaderKey(seg) {
5025
- for (const ch of seg) {
5026
- const bare = ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch >= "0" && ch <= "9" || ch === "_" || ch === "-";
5027
- if (!bare) return JSON.stringify(seg);
7217
+ function scanOpencode(agentHome, out2) {
7218
+ for (const name of OPENCODE_CONFIG_FILES) {
7219
+ const file = join4(agentHome, name);
7220
+ const doc = readJson(file);
7221
+ if (!isObj(doc) || !Array.isArray(doc[OPENCODE_PLUGIN_KEY])) continue;
7222
+ doc[OPENCODE_PLUGIN_KEY].forEach((spec, i2) => {
7223
+ if (spec === V1_OPENCODE_PLUGIN_SPEC) out2.push(finding(file, keyPath(OPENCODE_PLUGIN_KEY, i2), V1_REASON.opencodePlugin));
7224
+ });
7225
+ return;
5028
7226
  }
5029
- return seg;
5030
7227
  }
5031
- function tomlBlock(path8, value) {
5032
- let out2 = "[" + path8.map(tomlHeaderKey).join(".") + "]\n";
5033
- const subs = [];
5034
- for (const [k, v] of Object.entries(value)) {
5035
- if (isPlainObject(v)) subs.push(tomlBlock([...path8, k], v));
5036
- else out2 += tomlHeaderKey(k) + " = " + tomlScalar(v) + "\n";
7228
+ function scanZcode(agentHome, out2) {
7229
+ const configFile = join4(agentHome, ZCODE_CLI_DIR, CONFIG_JSON_FILE);
7230
+ const config = readJson(configFile);
7231
+ const events2 = isObj(config) && isObj(config[HOOKS_KEY]) ? config[HOOKS_KEY][ZCODE_EVENTS_KEY] : void 0;
7232
+ for (const c3 of flatCommands(events2, [HOOKS_KEY, ZCODE_EVENTS_KEY])) {
7233
+ if (c3.command.includes(V1_HOOK_COMMAND)) out2.push(finding(configFile, c3.path, V1_REASON.zcodeHook));
7234
+ }
7235
+ const hooksFile = join4(agentHome, ZCODE_CLI_DIR, HOOKS_JSON_FILE);
7236
+ for (const c3 of nestedCommands(readJson(hooksFile))) {
7237
+ if (c3.command.includes(V1_HOOK_COMMAND)) out2.push(finding(hooksFile, c3.path, V1_REASON.zcodeHook));
5037
7238
  }
5038
- return [out2, ...subs].join("\n");
5039
7239
  }
5040
- function setTomlText(text2, path8, value) {
5041
- if (!isPlainObject(value)) throw new SyntaxError("TOML edits replace a whole table");
5042
- const doc = scanToml(text2);
5043
- const owned = doc.tables.filter((t2) => t2.path.length >= path8.length && path8.every((seg, k) => t2.path[k] === seg));
5044
- const block2 = tomlBlock(path8, value);
5045
- if (owned.length === 0) {
5046
- const sep = text2 === "" ? "" : text2.endsWith("\n\n") ? "" : text2.endsWith("\n") ? "\n" : "\n\n";
5047
- return text2 + sep + block2;
5048
- }
5049
- let out2 = text2.slice(0, owned[0].start) + block2;
5050
- let cursor3 = owned[0].end;
5051
- for (const t2 of owned.slice(1)) {
5052
- out2 += text2.slice(cursor3, t2.start).trim() === "" ? "" : text2.slice(cursor3, t2.start);
5053
- cursor3 = t2.end;
5054
- }
5055
- const tail = text2.slice(cursor3);
5056
- return out2 + (tail === "" || block2.endsWith("\n\n") ? "" : "\n") + tail;
5057
- }
5058
- function setText(agent, path8, text2, format, key, value) {
7240
+ function firstTmpMatch(dir) {
7241
+ let handle;
5059
7242
  try {
5060
- return format === "toml" ? setTomlText(text2, key, value) : setJsonText(text2, format, key, value);
7243
+ handle = opendirSync(dir);
5061
7244
  } catch {
5062
- throw new CtxError("CONFIG_PARSE_FAILED", { agent, path: path8, format });
7245
+ return null;
5063
7246
  }
5064
- }
5065
- function applyEdits(agent, path8, text2, format, wanted) {
5066
- const parsed = parseHostConfig(agent, path8, text2, format);
5067
- let out2 = text2;
5068
- const edits = [];
5069
- for (const [key, after] of wanted) {
5070
- const before = hostConfigValueAt(parsed, key);
5071
- if (sameValue(before, after)) continue;
5072
- out2 = setText(agent, path8, out2, format, key, after);
5073
- edits.push({ path: key.join("."), before, after });
7247
+ try {
7248
+ for (let e = handle.readSync(); e !== null; e = handle.readSync()) {
7249
+ if (e.name.startsWith(V1_TMP_PREFIX)) return e.name;
7250
+ }
7251
+ return null;
7252
+ } catch {
7253
+ return null;
7254
+ } finally {
7255
+ handle.closeSync();
5074
7256
  }
5075
- return { text: out2, format, edits };
5076
7257
  }
5077
- function editHostConfigText(agent, path8, text2, format, wanted) {
5078
- return applyEdits(agent, path8, text2, format, wanted);
7258
+ function scanAll(home, tmp, out2) {
7259
+ const root = join4(home, DATA_ROOT.slice(1));
7260
+ for (const name of V1_DATA_ROOT_ENTRIES) dataDir(join4(root, name), V1_REASON.dataRoot, out2);
7261
+ if (firstTmpMatch(tmp) !== null) out2.push(finding(tmp, V1_TMP_PREFIX + "*", V1_REASON.tmpFile));
7262
+ }
7263
+ function detectV1(agent, home, scope = {}) {
7264
+ const out2 = [];
7265
+ const project = scope.project;
7266
+ const agentHome = agent === "claude-code" && scope.claudeDir !== void 0 ? scope.claudeDir : agent === "copilot-cli" && scope.copilotDir !== void 0 ? scope.copilotDir : agent === "kiro" && scope.kiroDir !== void 0 ? scope.kiroDir : agent === "opencode" && scope.opencodeDir !== void 0 ? scope.opencodeDir : join4(home, ...AGENT_HOME_DIR[agent]);
7267
+ switch (agent) {
7268
+ case "claude-code":
7269
+ scanClaudeCode(home, agentHome, out2);
7270
+ break;
7271
+ case "codex":
7272
+ scanCodex(agentHome, out2);
7273
+ break;
7274
+ case "gemini":
7275
+ scanGemini(agentHome, out2);
7276
+ break;
7277
+ case "qwen":
7278
+ claudeShapeSettings(agentHome, out2);
7279
+ dataDir(join4(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
7280
+ break;
7281
+ case "copilot-cli":
7282
+ v1HookFile(join4(agentHome, V1_HOOKS_DIR_NAME, OWN_HOOK_FILE), out2);
7283
+ dataDir(join4(agentHome, V1_DATA_DIR_NAME), V1_REASON.dataDir, out2);
7284
+ break;
7285
+ case "vscode":
7286
+ scanVscode(agentHome, project, out2);
7287
+ break;
7288
+ case "kiro":
7289
+ scanKiro(agentHome, project, out2);
7290
+ break;
7291
+ case "pi":
7292
+ scanPi(scope.piAgentDir !== void 0 && scope.piAgentDir !== "" ? scope.piAgentDir : join4(agentHome, PI_AGENT_DIR), agentHome, out2);
7293
+ break;
7294
+ // D-WIN-PIDIR-1: empty is unset
7295
+ case "opencode":
7296
+ scanOpencode(agentHome, out2);
7297
+ break;
7298
+ case "zcode":
7299
+ scanZcode(agentHome, out2);
7300
+ break;
7301
+ }
7302
+ scanAll(home, scope.tmp ?? tmpdir(), out2);
7303
+ return out2;
5079
7304
  }
5080
7305
 
5081
7306
  // src/core/ops/plugin-root.ts
@@ -5110,9 +7335,10 @@ function nestedShape(row, cmd, timeout, withMatcher) {
5110
7335
  }
5111
7336
  return { hooks };
5112
7337
  }
7338
+ var POWERSHELL_CALL = "& ";
5113
7339
  function flatShape(row, cmd, timeoutKey) {
5114
7340
  const hooks = {};
5115
- for (const [, native] of events(row)) hooks[native] = [{ ...entry(cmd), [timeoutKey]: seconds(row) }];
7341
+ for (const [, native] of events(row)) hooks[native] = [{ ...entry(cmd), powershell: POWERSHELL_CALL + cmd, [timeoutKey]: seconds(row) }];
5116
7342
  return { version: 1, hooks };
5117
7343
  }
5118
7344
  function kiroShape(row, cmd) {
@@ -5172,11 +7398,17 @@ var OPENCODE_PLUGIN = ["opencode", "plugin.js"];
5172
7398
  var CODEX_CONFIG_FILE = "config.toml";
5173
7399
  var CODEX_HOME_ENV2 = "CODEX_HOME";
5174
7400
  var CODEX_DIR = ".codex";
7401
+ var COPILOT_DIR = ".copilot";
7402
+ var KIRO_DIR = AGENT_HOME_DIR.kiro[0];
7403
+ var OPENCODE_HOME_SEGS = AGENT_HOME_DIR.opencode;
5175
7404
  function agentPath(ctx, id, rel) {
5176
7405
  const segs = typeof rel === "string" ? rel.split("/") : [...rel];
5177
7406
  const codexHome = ctx.env[CODEX_HOME_ENV2];
5178
- if (id === "codex" && segs[0] === CODEX_DIR && codexHome !== void 0 && codexHome !== "") return path2.join(codexHome, ...segs.slice(1));
5179
- return path2.join(ctx.home, ...segs);
7407
+ if (id === "codex" && segs[0] === CODEX_DIR && codexHome !== void 0 && codexHome !== "") return path3.join(codexHome, ...segs.slice(1));
7408
+ if (id === "copilot-cli" && segs[0] === COPILOT_DIR) return path3.join(copilotDirOf(ctx.env, ctx.home), ...segs.slice(1));
7409
+ if (id === "kiro" && segs[0] === KIRO_DIR) return path3.join(kiroDirOf(ctx.env, ctx.home), ...segs.slice(1));
7410
+ if (id === "opencode" && segs[0] === OPENCODE_HOME_SEGS[0] && segs[1] === OPENCODE_HOME_SEGS[1]) return path3.join(opencodeDirOf(ctx.env, ctx.home), ...segs.slice(2));
7411
+ return path3.join(ctx.home, ...segs);
5180
7412
  }
5181
7413
  function renderSkill(text2, prefix) {
5182
7414
  const prefixes = typeof prefix === "string" ? [prefix] : prefix;
@@ -5206,12 +7438,12 @@ function extensionPlugin(bin, id) {
5206
7438
  };
5207
7439
  }
5208
7440
  var NATIVE_PLUGIN = {
5209
- codex: { bin: "codex", args: ["plugin", "list"], plugin: PLUGIN_ID, hooksVia: ".codex-plugin", skillsVia: path2.join("codex", SKILLS_DIR_NAME), format: "table" },
7441
+ codex: { bin: "codex", args: ["plugin", "list"], plugin: PLUGIN_ID, hooksVia: ".codex-plugin", skillsVia: path3.join("codex", SKILLS_DIR_NAME), format: "table" },
5210
7442
  qwen: extensionPlugin("qwen", "qwen"),
5211
7443
  gemini: extensionPlugin("gemini", "gemini")
5212
7444
  };
5213
7445
  function serverCmd(ctx, id) {
5214
- return [process.execPath, path2.join(ctx.pkgDir, SERVER_BUNDLE), AGENT_FLAG, id];
7446
+ return [process.execPath, path3.join(ctx.pkgDir, SERVER_BUNDLE), AGENT_FLAG, id];
5215
7447
  }
5216
7448
  function hookCommandString(row) {
5217
7449
  const [node, file, flag, id] = row.hookCommand ?? [];
@@ -5232,7 +7464,7 @@ function configFor(ctx, id) {
5232
7464
  const [node, server, flag, agent] = serverCmd(ctx, id);
5233
7465
  const own2 = OWN_MCP_ENTRY[id];
5234
7466
  if (own2) {
5235
- const file = agentPath(ctx, id, own2.file);
7467
+ const file = id === "vscode" ? ownMcpFileOf(id, own2.file, ctx.env, ctx.home) : agentPath(ctx, id, own2.file);
5236
7468
  const format = file.endsWith(".toml") ? "toml" : id === "vscode" ? "jsonc" : "json";
5237
7469
  const args = id === "vscode" ? [server, flag, agent, WORKSPACE_FOLDER_FLAG, VSCODE_WORKSPACE_VAR] : [server, flag, agent];
5238
7470
  const also = own2.also?.map(([k, v]) => [k, v]);
@@ -5240,8 +7472,8 @@ function configFor(ctx, id) {
5240
7472
  }
5241
7473
  if (id === "opencode") {
5242
7474
  return {
5243
- file: path2.join(ctx.home, ".config", "opencode", "opencode.json"),
5244
- format: "json",
7475
+ file: path3.join(opencodeDirOf(ctx.env, ctx.home), OPENCODE_BASE_CONFIG_FILE),
7476
+ format: "jsonc",
5245
7477
  key: ["mcp", SERVER_KEY],
5246
7478
  value: { type: "local", command: [node, server, flag, agent], enabled: true }
5247
7479
  };
@@ -5269,7 +7501,7 @@ function cliFor(ctx, id) {
5269
7501
  }
5270
7502
  function copyFor(ctx, id) {
5271
7503
  if (id !== "claude-code") return void 0;
5272
- const file = path2.join(ctx.home, HOST_CONFIG_DIR_NAME, HOST_PLUGINS_DIR_NAME, INSTALLED_PLUGINS_FILE);
7504
+ const file = path3.join(claudeDirOf(ctx.env, ctx.home), HOST_PLUGINS_DIR_NAME, INSTALLED_PLUGINS_FILE);
5273
7505
  return { host: "Claude Code", bin: "claude", plugin: PLUGIN_ID, file, refresh: ["plugin", "update", PLUGIN_ID] };
5274
7506
  }
5275
7507
  var LIST = {
@@ -5288,13 +7520,13 @@ function hookFilesFor(ctx, id) {
5288
7520
  case "codex":
5289
7521
  return [{ file: agentPath(ctx, id, [CODEX_DIR, "hooks.json"]), mode: "rewrite" }];
5290
7522
  case "copilot-cli":
5291
- return [{ file: path2.join(home, ".copilot", "hooks", "context-mode.json"), mode: "rewrite" }];
7523
+ return [{ file: agentPath(ctx, id, [COPILOT_DIR, "hooks", "context-mode.json"]), mode: "rewrite" }];
5292
7524
  case "claude-code":
5293
- return [{ file: path2.join(home, ".claude", "settings.json"), mode: "drop" }];
7525
+ return [{ file: path3.join(claudeDirOf(ctx.env, home), "settings.json"), mode: "drop" }];
5294
7526
  case "gemini":
5295
- return [{ file: path2.join(home, ".gemini", "settings.json"), mode: "drop" }];
7527
+ return [{ file: path3.join(home, ".gemini", "settings.json"), mode: "drop" }];
5296
7528
  case "qwen":
5297
- return [{ file: path2.join(home, ".qwen", "settings.json"), mode: "drop" }];
7529
+ return [{ file: path3.join(home, ".qwen", "settings.json"), mode: "drop" }];
5298
7530
  default:
5299
7531
  return [];
5300
7532
  }
@@ -5305,15 +7537,15 @@ function hookInstallFor(ctx, row, command) {
5305
7537
  const shape = HOOK_SHAPES[row.id];
5306
7538
  if (!shape) throw new Error(`setup: ${row.id} has a home-file hook channel and no hook shape`);
5307
7539
  const file = agentPath(ctx, row.id, ch.path);
5308
- if (row.id === "codex") return { kind: "file", file, shape: shape(row, command), command, trust: path2.join(path2.dirname(file), CODEX_CONFIG_FILE) };
7540
+ if (row.id === "codex") return { kind: "file", file, shape: shape(row, command), command, trust: path3.join(path3.dirname(file), CODEX_CONFIG_FILE) };
5309
7541
  return { kind: "file", file, shape: shape(row, command), command };
5310
7542
  }
5311
7543
  if (row.id === "opencode") {
5312
7544
  return {
5313
7545
  kind: "plugin-list",
5314
- file: path2.join(ctx.home, ".config", "opencode", "opencode.json"),
7546
+ file: path3.join(opencodeDirOf(ctx.env, ctx.home), OPENCODE_BASE_CONFIG_FILE),
5315
7547
  key: ["plugin"],
5316
- entry: path2.join(ctx.pkgDir, ...OPENCODE_PLUGIN)
7548
+ entry: path3.join(ctx.pkgDir, ...OPENCODE_PLUGIN)
5317
7549
  };
5318
7550
  }
5319
7551
  return { kind: "package", via: ch.path };
@@ -5327,11 +7559,11 @@ function skillInstallFor(ctx, row) {
5327
7559
  const ch = row.skillChannel;
5328
7560
  if (ch.kind === "package") return { kind: "package", via: ch.path };
5329
7561
  const dir = agentPath(ctx, row.id, ch.path);
5330
- const src = path2.join(ctx.pkgDir, bareSkillDir());
7562
+ const src = path3.join(ctx.pkgDir, bareSkillDir());
5331
7563
  return { kind: "dir", dir, prefixes: skillDirPrefixes(ch.path), files: COMMAND_SKILLS.map((name) => ({
5332
7564
  name,
5333
- src: path2.join(src, name, SKILL_FILE),
5334
- file: path2.join(dir, name, SKILL_FILE)
7565
+ src: path3.join(src, name, SKILL_FILE),
7566
+ file: path3.join(dir, name, SKILL_FILE)
5335
7567
  })) };
5336
7568
  }
5337
7569
  function buildRegistry(ctx) {
@@ -5339,7 +7571,7 @@ function buildRegistry(ctx) {
5339
7571
  const id = row.id;
5340
7572
  const config = configFor(ctx, id);
5341
7573
  const hookFiles = hookFilesFor(ctx, id);
5342
- const hookCommand = [process.execPath, path2.join(ctx.pkgDir, HOOK_BUNDLE), AGENT_FLAG, id];
7574
+ const hookCommand = [process.execPath, path3.join(ctx.pkgDir, HOOK_BUNDLE), AGENT_FLAG, id];
5343
7575
  const command = `"${hookCommand[0]}" "${hookCommand[1]}" ${AGENT_FLAG} ${id}`;
5344
7576
  const hookInstall = hookInstallFor(ctx, getAdapter(id), command);
5345
7577
  const skillInstall = skillInstallFor(ctx, row);
@@ -5361,7 +7593,7 @@ function buildRegistry(ctx) {
5361
7593
  hookInstall,
5362
7594
  skillInstall,
5363
7595
  hookRunCommand: hookCommand,
5364
- allowedWrites: [...new Set(writes.map((f2) => path2.resolve(f2)))],
7596
+ allowedWrites: [...new Set(writes.map((f2) => path3.resolve(f2)))],
5365
7597
  goldenPayload: golden(row, ctx.home)
5366
7598
  };
5367
7599
  if (row.installMode !== "in-process") out2.hookCommand = hookCommand;
@@ -5373,8 +7605,8 @@ function buildRegistry(ctx) {
5373
7605
  });
5374
7606
  }
5375
7607
  function assertWritable(row, file) {
5376
- const abs = path2.resolve(file);
5377
- if (INSTRUCTION_FILES.includes(path2.basename(abs)) || !row.allowedWrites.includes(abs)) {
7608
+ const abs = path3.resolve(file);
7609
+ if (INSTRUCTION_FILES.includes(path3.basename(abs)) || !row.allowedWrites.includes(abs)) {
5378
7610
  throw new Error(`setup: write to ${abs} is not allowed for ${row.id}`);
5379
7611
  }
5380
7612
  }
@@ -5382,7 +7614,91 @@ function assertWritable(row, file) {
5382
7614
  // src/setup/codex-trust.ts
5383
7615
  import { createHash } from "node:crypto";
5384
7616
  import { existsSync as existsSync5, realpathSync as realpathSync3 } from "node:fs";
5385
- import path3 from "node:path";
7617
+ import path5 from "node:path";
7618
+
7619
+ // src/setup/spawn-bin.ts
7620
+ import { spawnSync } from "node:child_process";
7621
+ import { accessSync, constants as fsc, statSync } from "node:fs";
7622
+ import path4 from "node:path";
7623
+
7624
+ // src/core/sandbox/path-entries.ts
7625
+ function pathEntries(value, platform = process.platform, delimiter = platform === "win32" ? ";" : ":") {
7626
+ const win = platform === "win32";
7627
+ return value.split(delimiter).map((e) => win && e.length >= 2 && e.startsWith('"') && e.endsWith('"') ? e.slice(1, -1) : e).filter(Boolean);
7628
+ }
7629
+
7630
+ // src/setup/spawn-bin.ts
7631
+ var WIN_EXT = ".COM;.EXE;.BAT;.CMD";
7632
+ var WIN_SHIM_EXTS = Object.freeze([".cmd", ".bat"]);
7633
+ var DEFAULT_COMSPEC = "cmd.exe";
7634
+ function envGet(env, k) {
7635
+ return env[Object.keys(env).find((x2) => x2.toUpperCase() === k) ?? k];
7636
+ }
7637
+ function whichBin(bin, env, platform = process.platform) {
7638
+ const get = (k) => envGet(env, k);
7639
+ const win = platform === "win32";
7640
+ const exts = win ? (get("PATHEXT") || WIN_EXT).split(";").filter(Boolean) : [""];
7641
+ const names = win && path4.extname(bin) ? [bin] : exts.map((e) => bin + e.toLowerCase());
7642
+ for (const dir of pathEntries(get("PATH") ?? "", platform)) {
7643
+ for (const n3 of names) {
7644
+ const f2 = path4.join(dir, n3);
7645
+ try {
7646
+ accessSync(f2, fsc.X_OK);
7647
+ if (statSync(f2).isFile()) return f2;
7648
+ } catch {
7649
+ }
7650
+ }
7651
+ }
7652
+ return void 0;
7653
+ }
7654
+ var CMD_QUOTE_CHARS = '"&|<>^()!';
7655
+ var CMD_PERCENT = "%";
7656
+ var CMD_SUBSTRING_MARK = ":";
7657
+ var CMD_DYNAMIC_VARS = Object.freeze(["CD", "DATE", "TIME", "RANDOM", "ERRORLEVEL", "CMDEXTVERSION", "CMDCMDLINE", "HIGHESTNUMANODENUMBER"]);
7658
+ function needsCmdQuotes(a2) {
7659
+ if (a2 === "") return true;
7660
+ for (const c3 of a2) if (c3.trim() === "" || CMD_QUOTE_CHARS.includes(c3)) return true;
7661
+ return false;
7662
+ }
7663
+ function expandablePercent(text2, env) {
7664
+ const names = new Set(CMD_DYNAMIC_VARS);
7665
+ for (const k of Object.keys(env)) names.add(k.toUpperCase());
7666
+ for (let i2 = text2.indexOf(CMD_PERCENT); i2 >= 0; i2 = text2.indexOf(CMD_PERCENT, i2 + 1)) {
7667
+ for (let j2 = text2.indexOf(CMD_PERCENT, i2 + 1); j2 >= 0; j2 = text2.indexOf(CMD_PERCENT, j2 + 1)) {
7668
+ const inner = text2.slice(i2 + 1, j2);
7669
+ const cut = inner.indexOf(CMD_SUBSTRING_MARK);
7670
+ const name = cut < 0 ? inner : inner.slice(0, cut);
7671
+ if (name !== "" && names.has(name.toUpperCase())) return `${CMD_PERCENT}${inner}${CMD_PERCENT}`;
7672
+ }
7673
+ }
7674
+ return void 0;
7675
+ }
7676
+ function winCmdLine(file, args, env = {}) {
7677
+ for (const a2 of [file, ...args]) {
7678
+ const hit = expandablePercent(a2, env);
7679
+ if (hit !== void 0) throw new Error(`cannot run ${file} through cmd.exe: cmd.exe expands ${hit} inside quotes, so the value ${JSON.stringify(a2)} would change. Use a path and arguments without it`);
7680
+ }
7681
+ const q = (a2) => needsCmdQuotes(a2) ? `"${a2.split('"').join('""')}"` : a2;
7682
+ return `"${[file, ...args].map(q).join(" ")}"`;
7683
+ }
7684
+ function spawnForm(file, args, env, platform = process.platform) {
7685
+ if (platform === "win32" && WIN_SHIM_EXTS.includes(path4.extname(file).toLowerCase())) {
7686
+ return { command: envGet(env, "COMSPEC") || DEFAULT_COMSPEC, args: ["/d", "/v:off", "/s", "/c", winCmdLine(file, args, env)], windowsVerbatimArguments: true };
7687
+ }
7688
+ return { command: file, args, windowsVerbatimArguments: false };
7689
+ }
7690
+ function spawnShim(file, args, env, opts, platform = process.platform) {
7691
+ let f2;
7692
+ try {
7693
+ f2 = spawnForm(file, args, env, platform);
7694
+ } catch (e) {
7695
+ const error = e instanceof Error ? e : new Error(String(e));
7696
+ return { pid: 0, output: [null, "", error.message], stdout: "", stderr: error.message, status: null, signal: null, error };
7697
+ }
7698
+ return spawnSync(f2.command, f2.args, { ...opts, env, windowsVerbatimArguments: f2.windowsVerbatimArguments, windowsHide: true });
7699
+ }
7700
+
7701
+ // src/setup/codex-trust.ts
5386
7702
  var isObj2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
5387
7703
  var TRUST_KEY = ["hooks", "state"];
5388
7704
  var CODEX_TRUST_PATH = TRUST_KEY.join(".") + ".";
@@ -5402,18 +7718,58 @@ function snake(name) {
5402
7718
  return out2;
5403
7719
  }
5404
7720
  function realFile(file) {
5405
- let dir = path3.resolve(file);
7721
+ let dir = path5.resolve(file);
5406
7722
  const rest = [];
5407
- while (!existsSync5(dir) && path3.dirname(dir) !== dir) {
5408
- rest.unshift(path3.basename(dir));
5409
- dir = path3.dirname(dir);
7723
+ while (!existsSync5(dir) && path5.dirname(dir) !== dir) {
7724
+ rest.unshift(path5.basename(dir));
7725
+ dir = path5.dirname(dir);
7726
+ }
7727
+ return path5.join(realpathSync3(dir), ...rest);
7728
+ }
7729
+ var ASK_TIMEOUT_MS = 1e4;
7730
+ var ASK_TRIES = 3;
7731
+ var WIN_VERBATIM_PREFIX = "\\\\?\\";
7732
+ function codexHomeFromReply(out2) {
7733
+ for (const line of out2.split("\n")) {
7734
+ let m3;
7735
+ try {
7736
+ m3 = JSON.parse(line);
7737
+ } catch {
7738
+ continue;
7739
+ }
7740
+ if (isObj2(m3) && isObj2(m3.result) && typeof m3.result.codexHome === "string" && m3.result.codexHome !== "") return m3.result.codexHome;
7741
+ }
7742
+ return void 0;
7743
+ }
7744
+ function askCodexHome(env) {
7745
+ const bin = whichBin("codex", env);
7746
+ if (!bin) return void 0;
7747
+ const input = JSON.stringify({ id: 1, method: "initialize", params: { clientInfo: { name: "context-mode-setup", version: "2.0.0" } } }) + "\n";
7748
+ for (let i2 = 0; i2 < ASK_TRIES; i2++) {
7749
+ const r2 = spawnShim(bin, ["app-server"], env, { input, encoding: "utf8", timeout: ASK_TIMEOUT_MS });
7750
+ const home = typeof r2.stdout === "string" ? codexHomeFromReply(r2.stdout) : void 0;
7751
+ if (home !== void 0) return home;
5410
7752
  }
5411
- return path3.join(realpathSync3(dir), ...rest);
7753
+ return void 0;
7754
+ }
7755
+ function sameDir(a2, b3, platform) {
7756
+ if (platform !== "win32") return path5.posix.normalize(a2) === path5.posix.normalize(b3);
7757
+ const norm = (p3) => {
7758
+ const bare = p3.startsWith(WIN_VERBATIM_PREFIX) ? p3.slice(WIN_VERBATIM_PREFIX.length) : p3;
7759
+ const n3 = path5.win32.normalize(bare).toLowerCase();
7760
+ return n3.length > 3 && n3.endsWith("\\") ? n3.slice(0, -1) : n3;
7761
+ };
7762
+ return norm(a2) === norm(b3);
7763
+ }
7764
+ function codexKeyDir(o2, platform = process.platform) {
7765
+ return o2.asked !== void 0 && sameDir(o2.dir, o2.asked, platform) ? o2.asked : o2.real(o2.dir);
5412
7766
  }
5413
- function codexTrustEntries(hooksFile, doc, command) {
7767
+ function codexTrustEntries(hooksFile, doc, command, env) {
5414
7768
  const out2 = [];
5415
7769
  if (!isObj2(doc) || !isObj2(doc.hooks)) return out2;
5416
- const real = realFile(hooksFile);
7770
+ const abs = path5.resolve(hooksFile);
7771
+ const dir = codexKeyDir({ dir: path5.dirname(abs), asked: env ? askCodexHome(env) : void 0, real: env && !env.CODEX_HOME ? (p3) => path5.resolve(p3) : realFile });
7772
+ const real = (dir.startsWith(WIN_VERBATIM_PREFIX) ? path5.win32 : path5).join(dir, path5.basename(abs));
5417
7773
  for (const [event, groups] of Object.entries(doc.hooks)) {
5418
7774
  if (!Array.isArray(groups)) continue;
5419
7775
  groups.forEach((g2, gi) => {
@@ -5431,47 +7787,10 @@ function codexTrustEntries(hooksFile, doc, command) {
5431
7787
  }
5432
7788
 
5433
7789
  // src/setup/engine.ts
5434
- import { spawn, spawnSync } from "node:child_process";
5435
- import { closeSync, existsSync as existsSync6, mkdirSync as mkdirSync2, mkdtempSync, openSync, readFileSync as readFileSync3, readSync, readdirSync as readdirSync4, realpathSync as realpathSync4, renameSync as renameSync2, rmSync, statSync as statSync2, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
7790
+ import { spawn, spawnSync as spawnSync2 } from "node:child_process";
7791
+ import { closeSync, existsSync as existsSync6, mkdirSync as mkdirSync3, mkdtempSync, openSync, readFileSync as readFileSync3, readSync, readdirSync as readdirSync4, realpathSync as realpathSync4, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
5436
7792
  import { tmpdir as tmpdir2 } from "node:os";
5437
- import path5 from "node:path";
5438
-
5439
- // src/setup/spawn-bin.ts
5440
- import { accessSync, constants as fsc, statSync } from "node:fs";
5441
- import path4 from "node:path";
5442
- var WIN_EXT = ".COM;.EXE;.BAT;.CMD";
5443
- var WIN_SHIM_EXTS = Object.freeze([".cmd", ".bat"]);
5444
- var DEFAULT_COMSPEC = "cmd.exe";
5445
- function envGet(env, k) {
5446
- return env[Object.keys(env).find((x2) => x2.toUpperCase() === k) ?? k];
5447
- }
5448
- function whichBin(bin, env, platform = process.platform) {
5449
- const get = (k) => envGet(env, k);
5450
- const win = platform === "win32";
5451
- const exts = win ? (get("PATHEXT") || WIN_EXT).split(";").filter(Boolean) : [""];
5452
- const names = win && path4.extname(bin) ? [bin] : exts.map((e) => bin + e.toLowerCase());
5453
- for (const dir of (get("PATH") ?? "").split(win ? ";" : ":").filter(Boolean)) {
5454
- for (const n3 of names) {
5455
- const f2 = path4.join(dir, n3);
5456
- try {
5457
- accessSync(f2, fsc.X_OK);
5458
- if (statSync(f2).isFile()) return f2;
5459
- } catch {
5460
- }
5461
- }
5462
- }
5463
- return void 0;
5464
- }
5465
- function winCmdLine(file, args) {
5466
- const q = (a2) => a2 === "" || /[\s"&|<>^()%!]/.test(a2) ? `"${a2.replace(/"/g, '""')}"` : a2;
5467
- return `"${[file, ...args].map(q).join(" ")}"`;
5468
- }
5469
- function spawnForm(file, args, env, platform = process.platform) {
5470
- if (platform === "win32" && WIN_SHIM_EXTS.includes(path4.extname(file).toLowerCase())) {
5471
- return { command: envGet(env, "COMSPEC") || DEFAULT_COMSPEC, args: ["/d", "/s", "/c", winCmdLine(file, args)], windowsVerbatimArguments: true };
5472
- }
5473
- return { command: file, args, windowsVerbatimArguments: false };
5474
- }
7793
+ import path6 from "node:path";
5475
7794
 
5476
7795
  // src/setup/hook-sample.ts
5477
7796
  var SAMPLE_FILE = "big.log";
@@ -5564,16 +7883,16 @@ function isNativeBinary(file) {
5564
7883
  return BINARY_MAGICS.some((m3) => hex.startsWith(m3));
5565
7884
  }
5566
7885
  function owningPackage(dir) {
5567
- for (let d = dir; ; d = path5.dirname(d)) {
5568
- const f2 = path5.join(d, "package.json");
7886
+ for (let d = dir; ; d = path6.dirname(d)) {
7887
+ const f2 = path6.join(d, "package.json");
5569
7888
  if (existsSync6(f2)) {
5570
7889
  try {
5571
- return String(JSON.parse(readFileSync3(f2, "utf8")).name);
7890
+ return String(JSON.parse(hostText(readFileSync3(f2, "utf8"))).name);
5572
7891
  } catch {
5573
7892
  return void 0;
5574
7893
  }
5575
7894
  }
5576
- if (path5.dirname(d) === d) return void 0;
7895
+ if (path6.dirname(d) === d) return void 0;
5577
7896
  }
5578
7897
  }
5579
7898
  function hostBin(bin, env, platform = process.platform) {
@@ -5581,30 +7900,32 @@ function hostBin(bin, env, platform = process.platform) {
5581
7900
  if (!real) return { file: which(bin, env, platform), shims: [] };
5582
7901
  const get = (k) => env[Object.keys(env).find((x2) => x2.toUpperCase() === k) ?? k];
5583
7902
  const shims = [];
5584
- for (const dir of (get("PATH") ?? "").split(platform === "win32" ? ";" : ":").filter(Boolean)) {
7903
+ for (const dir of pathEntries(get("PATH") ?? "", platform)) {
5585
7904
  const own2 = which(bin, { PATH: dir, ...get("PATHEXT") ? { PATHEXT: get("PATHEXT") } : {} }, platform);
5586
- for (const f2 of [own2, ...real.extra.map((p3) => path5.join(dir, ...p3))]) {
7905
+ for (const f2 of [own2, ...real.extra.map((p3) => path6.join(dir, ...p3))]) {
5587
7906
  if (!f2 || !existsSync6(f2) || !statSync2(f2).isFile()) continue;
5588
7907
  const file = realpathSync4(f2);
5589
- if (isNativeBinary(file) || owningPackage(path5.dirname(file)) === real.pkg) return { file, shims };
7908
+ if (isNativeBinary(file) || owningPackage(path6.dirname(file)) === real.pkg) return { file, shims };
5590
7909
  shims.push(f2);
5591
7910
  }
5592
7911
  }
5593
7912
  return { file: void 0, shims };
5594
7913
  }
7914
+ var WIN_EXIT_CRASH = 3221226505;
7915
+ function installExitOk(status, listed, platform = process.platform) {
7916
+ if (status === 0) return true;
7917
+ return platform === "win32" && status === WIN_EXIT_CRASH && listed;
7918
+ }
5595
7919
  function runBin(bin, args, env, input) {
5596
- const f2 = spawnForm(hostBin(bin, env).file ?? bin, args, env);
5597
- return spawnSync(f2.command, f2.args, { env, encoding: "utf8", input, timeout: VERIFY_TIMEOUT_MS, windowsVerbatimArguments: f2.windowsVerbatimArguments, windowsHide: true });
7920
+ return spawnShim(hostBin(bin, env).file ?? bin, args, env, { encoding: "utf8", input, timeout: VERIFY_TIMEOUT_MS });
5598
7921
  }
5599
7922
  function readOr(file) {
5600
- return existsSync6(file) ? readFileSync3(file, "utf8") : void 0;
7923
+ return existsSync6(file) ? hostText(readFileSync3(file, "utf8")) : void 0;
5601
7924
  }
5602
- function atomicWrite(file, text2) {
5603
- mkdirSync2(path5.dirname(file), { recursive: true });
5604
- const tmp = path5.join(path5.dirname(file), `.${path5.basename(file)}.cm-tmp-${process.pid}`);
5605
- writeFileSync2(tmp, text2);
5606
- renameSync2(tmp, file);
7925
+ function readRaw(file) {
7926
+ return existsSync6(file) ? readFileSync3(file, "utf8") : void 0;
5607
7927
  }
7928
+ var atomicWrite = atomicWriteFile;
5608
7929
  function pidAlive(pid) {
5609
7930
  try {
5610
7931
  process.kill(pid, 0);
@@ -5636,7 +7957,20 @@ function planHookFile(row, hf) {
5636
7957
  for (const [event, groups] of Object.entries(doc.hooks)) {
5637
7958
  if (!Array.isArray(groups)) continue;
5638
7959
  for (let g2 = groups.length - 1; g2 >= 0; g2--) {
5639
- const list2 = isObj3(groups[g2]) ? groups[g2].hooks : void 0;
7960
+ const group2 = groups[g2];
7961
+ if (isObj3(group2) && typeof group2.command === "string" && !Array.isArray(group2.hooks)) {
7962
+ if (!group2.command.includes(V1_HOOK_MARK)) continue;
7963
+ const at = `hooks.${event}[${g2}].command`;
7964
+ if (hf.mode === "rewrite") {
7965
+ changes.push({ file: hf.file, path: at, before: group2.command, after: want });
7966
+ group2.command = want;
7967
+ } else {
7968
+ changes.push({ file: hf.file, path: at, before: group2.command, after: null });
7969
+ groups.splice(g2, 1);
7970
+ }
7971
+ continue;
7972
+ }
7973
+ const list2 = isObj3(group2) ? group2.hooks : void 0;
5640
7974
  if (!Array.isArray(list2)) continue;
5641
7975
  for (let h2 = list2.length - 1; h2 >= 0; h2--) {
5642
7976
  const cmd = isObj3(list2[h2]) ? list2[h2].command : void 0;
@@ -5655,28 +7989,38 @@ function planHookFile(row, hf) {
5655
7989
  }
5656
7990
  return changes.length ? { file: hf.file, before, after: JSON.stringify(doc, null, 2) + "\n", changes } : void 0;
5657
7991
  }
5658
- var holds = (v, mark) => JSON.stringify(v).includes(JSON.stringify(mark).slice(1, -1));
7992
+ var MARK_LEFT = ["/", "\\", '"'];
7993
+ function isOwnHookCommand(cmd, agent) {
7994
+ if (typeof cmd !== "string") return false;
7995
+ const at = cmd.lastIndexOf(HOOK_BUNDLE);
7996
+ if (at <= 0 || !MARK_LEFT.includes(cmd[at - 1])) return false;
7997
+ let tail = cmd.slice(at + HOOK_BUNDLE.length);
7998
+ if (tail.startsWith('"')) tail = tail.slice(1);
7999
+ return tail.trim() === `${AGENT_FLAG} ${agent}`;
8000
+ }
8001
+ var holdsOwn = (v, agent) => typeof v === "string" ? isOwnHookCommand(v, agent) : Array.isArray(v) ? v.some((x2) => holdsOwn(x2, agent)) : isObj3(v) ? Object.values(v).some((x2) => holdsOwn(x2, agent)) : false;
5659
8002
  var same = (a2, b3) => JSON.stringify(a2) === JSON.stringify(b3);
5660
- function mergeOwn(cur, want, mark) {
8003
+ function mergeOwn(cur, want, agent) {
5661
8004
  if (isObj3(want)) {
5662
8005
  const base = isObj3(cur) ? { ...cur } : {};
5663
- for (const [k, v] of Object.entries(want)) base[k] = mergeOwn(base[k], v, mark);
8006
+ for (const [k, v] of Object.entries(want)) base[k] = mergeOwn(base[k], v, agent);
5664
8007
  return base;
5665
8008
  }
5666
8009
  if (Array.isArray(want)) {
5667
- const base = Array.isArray(cur) ? cur.filter((x2) => !holds(x2, mark) || want.some((w) => same(w, x2))) : [];
8010
+ const base = Array.isArray(cur) ? cur.filter((x2) => !holdsOwn(x2, agent) || want.some((w) => same(w, x2))) : [];
5668
8011
  for (const w of want) if (!base.some((x2) => same(x2, w))) base.push(w);
5669
8012
  return base;
5670
8013
  }
5671
8014
  return want;
5672
8015
  }
5673
- function planJsonKeys(row, edits, file, want) {
8016
+ var fileFormat = (row, file) => row.config?.file === file ? row.config.format : "json";
8017
+ function planJsonKeys(row, edits, file, format, want) {
5674
8018
  const prior = edits.find((e) => e.file === file);
5675
8019
  const text2 = prior ? prior.after : readOr(file);
5676
8020
  let doc = {};
5677
8021
  if (text2 !== void 0 && text2.trim() !== "") {
5678
8022
  try {
5679
- doc = JSON.parse(text2);
8023
+ doc = parseHostConfig(row.id, file, text2, format);
5680
8024
  } catch {
5681
8025
  throw new Error(parseFail(row, file));
5682
8026
  }
@@ -5684,7 +8028,7 @@ function planJsonKeys(row, edits, file, want) {
5684
8028
  if (!isObj3(doc)) throw new Error(parseFail(row, file));
5685
8029
  let res;
5686
8030
  try {
5687
- res = editHostConfigText(row.id, file, text2 ?? "", "json", want(doc));
8031
+ res = editHostConfigText(row.id, file, text2 ?? "", format, want(doc));
5688
8032
  } catch (e) {
5689
8033
  if (e instanceof CtxError) throw new Error(parseFail(row, file));
5690
8034
  throw e;
@@ -5696,10 +8040,10 @@ function planJsonKeys(row, edits, file, want) {
5696
8040
  prior.changes.push(...changes);
5697
8041
  } else edits.push({ file, before: text2, after: res.text, changes });
5698
8042
  }
5699
- function planCodexTrust(row, edits, hooksFile, file, command) {
8043
+ function planCodexTrust(row, edits, hooksFile, file, command, env) {
5700
8044
  const hooksText = edits.find((e) => e.file === hooksFile)?.after ?? readOr(hooksFile);
5701
8045
  if (hooksText === void 0) return;
5702
- const want = codexTrustEntries(hooksFile, JSON.parse(hooksText), command);
8046
+ const want = codexTrustEntries(hooksFile, JSON.parse(hooksText), command, env);
5703
8047
  if (!want.length) return;
5704
8048
  const prior = edits.find((e) => e.file === file);
5705
8049
  const text2 = prior ? prior.after : readOr(file);
@@ -5717,13 +8061,13 @@ function planCodexTrust(row, edits, hooksFile, file, command) {
5717
8061
  prior.changes.push(...changes);
5718
8062
  } else edits.push({ file, before: text2, after: res.text, changes });
5719
8063
  }
5720
- function planHookInstall(row, edits) {
8064
+ function planHookInstall(row, edits, env) {
5721
8065
  const h2 = row.hookInstall;
5722
8066
  if (h2.kind === "file") {
5723
- planJsonKeys(row, edits, h2.file, (doc) => Object.keys(h2.shape).map((k) => [[k], mergeOwn(doc[k], h2.shape[k], h2.command)]));
5724
- if (h2.trust) planCodexTrust(row, edits, h2.file, h2.trust, h2.command);
8067
+ planJsonKeys(row, edits, h2.file, fileFormat(row, h2.file), (doc) => Object.keys(h2.shape).map((k) => [[k], mergeOwn(doc[k], h2.shape[k], row.id)]));
8068
+ if (h2.trust) planCodexTrust(row, edits, h2.file, h2.trust, h2.command, env);
5725
8069
  } else if (h2.kind === "plugin-list") {
5726
- planJsonKeys(row, edits, h2.file, (doc) => {
8070
+ planJsonKeys(row, edits, h2.file, fileFormat(row, h2.file), (doc) => {
5727
8071
  const cur = doc[h2.key[0]];
5728
8072
  const list2 = Array.isArray(cur) ? cur : [];
5729
8073
  return [[h2.key, list2.includes(h2.entry) ? list2 : [...list2, h2.entry]]];
@@ -5736,11 +8080,11 @@ function planSkills(row, edits) {
5736
8080
  for (const f2 of s.files) {
5737
8081
  if (!existsSync6(f2.src)) throw new Error(`preflight: ${f2.src} is missing`);
5738
8082
  const after = renderSkill(readFileSync3(f2.src, "utf8"), s.prefixes);
5739
- const before = readOr(f2.file);
5740
- if (before !== after) edits.push({ file: f2.file, before, after, changes: [{ file: f2.file, path: f2.name, before: before === void 0 ? null : "old", after: "SKILL.md" }] });
8083
+ const before = readRaw(f2.file);
8084
+ if (before !== after) edits.push({ plain: true, file: f2.file, before, after, changes: [{ file: f2.file, path: f2.name, before: before === void 0 ? null : "old", after: "SKILL.md" }] });
5741
8085
  }
5742
8086
  }
5743
- function planRow(row, listed, stale) {
8087
+ function planRow(row, listed, stale, env) {
5744
8088
  const edits = [];
5745
8089
  if (row.config) {
5746
8090
  const c3 = row.config;
@@ -5758,7 +8102,7 @@ function planRow(row, listed, stale) {
5758
8102
  const e = planHookFile(row, hf);
5759
8103
  if (e) edits.push(e);
5760
8104
  }
5761
- planHookInstall(row, edits);
8105
+ planHookInstall(row, edits, env);
5762
8106
  planSkills(row, edits);
5763
8107
  const cli = row.config || !row.cli || listed ? [] : row.cli.install;
5764
8108
  const refresh = listed && stale && row.copy ? [row.copy.refresh] : [];
@@ -5773,7 +8117,7 @@ function listCheck(row, env) {
5773
8117
  }
5774
8118
  function packageVersion(pkgDir) {
5775
8119
  try {
5776
- const v = JSON.parse(readFileSync3(path5.join(pkgDir, "package.json"), "utf8")).version;
8120
+ const v = JSON.parse(hostText(readFileSync3(path6.join(pkgDir, "package.json"), "utf8"))).version;
5777
8121
  return typeof v === "string" ? v : void 0;
5778
8122
  } catch {
5779
8123
  return void 0;
@@ -5800,7 +8144,7 @@ function copyCheck(row, pkgDir) {
5800
8144
  }
5801
8145
  function mcpCheck(cmd, env) {
5802
8146
  return new Promise((resolve) => {
5803
- const child = spawn(cmd[0], cmd.slice(1), { env, stdio: ["pipe", "pipe", "ignore"], detached: process.platform !== "win32" });
8147
+ const child = spawn(cmd[0], cmd.slice(1), { env, stdio: ["pipe", "pipe", "ignore"], detached: process.platform !== "win32", windowsHide: true });
5804
8148
  const reap = () => {
5805
8149
  child.kill();
5806
8150
  };
@@ -5855,7 +8199,7 @@ function hookRound(row, env) {
5855
8199
  const bare = [];
5856
8200
  for (let i2 = 0; i2 < HOOK_SAMPLES; i2++) {
5857
8201
  let t2 = performance.now();
5858
- const r2 = spawnSync(cmd[0], cmd.slice(1), { env, input, encoding: "utf8", timeout: VERIFY_TIMEOUT_MS });
8202
+ const r2 = spawnSync2(cmd[0], cmd.slice(1), { env, input, encoding: "utf8", timeout: VERIFY_TIMEOUT_MS, windowsHide: true });
5859
8203
  wall.push(performance.now() - t2);
5860
8204
  if (r2.status !== 0) return { name: "hook", ok: false, detail: `hook exited ${r2.status}: ${`${r2.stderr}`.trim()}` };
5861
8205
  const out2 = `${r2.stdout}`.trim();
@@ -5868,7 +8212,7 @@ function hookRound(row, env) {
5868
8212
  if (!isObj3(j2)) return { name: "hook", ok: false, detail: `hook answer is not a JSON object: ${out2.slice(0, 200)}` };
5869
8213
  }
5870
8214
  t2 = performance.now();
5871
- spawnSync(cmd[0], ["-e", ""], { env, timeout: VERIFY_TIMEOUT_MS });
8215
+ spawnSync2(cmd[0], ["-e", ""], { env, timeout: VERIFY_TIMEOUT_MS, windowsHide: true });
5872
8216
  bare.push(performance.now() - t2);
5873
8217
  }
5874
8218
  const wallP95Ms = Math.round(p95(wall));
@@ -5892,7 +8236,7 @@ function parseCheck(row) {
5892
8236
  const c3 = row.config;
5893
8237
  if (!c3) return { name: "parse", ok: true };
5894
8238
  try {
5895
- const r2 = editHostConfigText(row.id, c3.file, readFileSync3(c3.file, "utf8"), c3.format, configEdits(c3));
8239
+ const r2 = editHostConfigText(row.id, c3.file, readOr(c3.file) ?? "", c3.format, configEdits(c3));
5896
8240
  return { name: "parse", ok: r2.edits.length === 0, detail: r2.edits.length ? "entry differs after write" : void 0 };
5897
8241
  } catch (e) {
5898
8242
  return { name: "parse", ok: false, detail: e.message };
@@ -5908,7 +8252,7 @@ function hookRegisteredCheck(row, env, list2) {
5908
8252
  }
5909
8253
  const edits = [];
5910
8254
  try {
5911
- planHookInstall(row, edits);
8255
+ planHookInstall(row, edits, env);
5912
8256
  } catch (e) {
5913
8257
  return { name: "hook-registered", ok: false, detail: e.message };
5914
8258
  }
@@ -5918,19 +8262,19 @@ function hookRegisteredCheck(row, env, list2) {
5918
8262
  return { name: "hook-registered", ok: false, detail: `${h2.file} lacks the context-mode hook entry` };
5919
8263
  }
5920
8264
  function hookRunsCheck(row, env) {
5921
- const root = mkdtempSync(path5.join(tmpdir2(), "cm-doctor-runs-"));
8265
+ const root = mkdtempSync(path6.join(tmpdir2(), "cm-doctor-runs-"));
5922
8266
  try {
5923
- const home = path5.join(root, "home");
5924
- const proj = path5.join(root, "proj");
5925
- mkdirSync2(home);
5926
- mkdirSync2(proj);
8267
+ const home = path6.join(root, "home");
8268
+ const proj = path6.join(root, "proj");
8269
+ mkdirSync3(home);
8270
+ mkdirSync3(proj);
5927
8271
  const text2 = sampleText();
5928
- writeFileSync2(path5.join(proj, SAMPLE_FILE), text2);
8272
+ writeFileSync2(path6.join(proj, SAMPLE_FILE), text2);
5929
8273
  const { effect, payload } = hookSample(row.id, proj, text2);
5930
8274
  const sampleEnv = { ...env, HOME: home, USERPROFILE: home };
5931
8275
  delete sampleEnv.CLAUDE_PROJECT_DIR;
5932
8276
  const cmd = row.hookRunCommand;
5933
- const r2 = spawnSync(cmd[0], cmd.slice(1), { env: sampleEnv, cwd: proj, input: JSON.stringify(payload), encoding: "utf8", timeout: VERIFY_TIMEOUT_MS });
8277
+ const r2 = spawnSync2(cmd[0], cmd.slice(1), { env: sampleEnv, cwd: proj, input: JSON.stringify(payload), encoding: "utf8", timeout: VERIFY_TIMEOUT_MS, windowsHide: true });
5934
8278
  const bad = sampleVerdict(row.id, effect, text2, { status: r2.status, stdout: `${r2.stdout ?? ""}`, stderr: `${r2.stderr ?? ""}` });
5935
8279
  return bad === null ? { name: "hook-runs", ok: true } : { name: "hook-runs", ok: false, detail: bad };
5936
8280
  } finally {
@@ -5940,7 +8284,7 @@ function hookRunsCheck(row, env) {
5940
8284
  var SEEN_SQL = "SELECT 1 FROM events WHERE agent = ? LIMIT 1";
5941
8285
  var NOT_SEEN_LINE = "not seen yet, run one tool call";
5942
8286
  function hookSeenCheck(row, home) {
5943
- const base = path5.join(home, STATE_DIR, PROJECTS_DIR_NAME);
8287
+ const base = path6.join(home, STATE_DIR, PROJECTS_DIR_NAME);
5944
8288
  const dirs = existsSync6(base) ? readdirSync4(base) : [];
5945
8289
  let sqlite;
5946
8290
  try {
@@ -5949,7 +8293,7 @@ function hookSeenCheck(row, home) {
5949
8293
  sqlite = void 0;
5950
8294
  }
5951
8295
  for (const d of dirs) {
5952
- const file = path5.join(base, d, DB_FILE_NAME);
8296
+ const file = path6.join(base, d, DB_FILE_NAME);
5953
8297
  if (!sqlite || !existsSync6(file)) continue;
5954
8298
  let db;
5955
8299
  try {
@@ -5965,10 +8309,10 @@ function hookSeenCheck(row, home) {
5965
8309
  function skillsCheck(row, pkgDir) {
5966
8310
  const s = row.skillInstall;
5967
8311
  if (s.kind === "package") {
5968
- const miss = COMMAND_SKILLS.map((n3) => path5.join(pkgDir, s.via, n3, SKILL_FILE)).filter((f2) => !existsSync6(f2));
8312
+ const miss = COMMAND_SKILLS.map((n3) => path6.join(pkgDir, s.via, n3, SKILL_FILE)).filter((f2) => !existsSync6(f2));
5969
8313
  return { name: "skills", ok: miss.length === 0, detail: miss.length ? `missing ${miss.join(", ")}` : void 0 };
5970
8314
  }
5971
- const bad = s.files.filter((f2) => readOr(f2.file) !== (existsSync6(f2.src) ? renderSkill(readFileSync3(f2.src, "utf8"), s.prefixes) : void 0));
8315
+ const bad = s.files.filter((f2) => readRaw(f2.file) !== (existsSync6(f2.src) ? renderSkill(readFileSync3(f2.src, "utf8"), s.prefixes) : void 0));
5972
8316
  return { name: "skills", ok: bad.length === 0, detail: bad.length ? `${bad.map((f2) => f2.file).join(", ")} missing or without the ${s.prefixes.join(" / ") || "plain"} tool prefix` : void 0 };
5973
8317
  }
5974
8318
  var PLUGIN_ENABLED = "enabled";
@@ -6065,16 +8409,16 @@ var Run = class {
6065
8409
  this.runId = runId;
6066
8410
  }
6067
8411
  get dir() {
6068
- return path5.join(this.root, BACKUP_DIR, this.runId);
8412
+ return path6.join(this.root, BACKUP_DIR, this.runId);
6069
8413
  }
6070
8414
  save() {
6071
- if (this.manifest) atomicWrite(path5.join(this.dir, MANIFEST), JSON.stringify(this.manifest, null, 2));
8415
+ if (this.manifest) atomicWrite(path6.join(this.dir, MANIFEST), JSON.stringify(this.manifest, null, 2));
6072
8416
  }
6073
8417
  record(e, bytes) {
6074
8418
  if (!this.manifest) this.manifest = { runId: this.runId, path: this.dir, entries: [] };
6075
8419
  if (bytes !== void 0) {
6076
- const rel = path5.join(FILES, String(this.manifest.entries.length));
6077
- atomicWrite(path5.join(this.dir, rel), bytes);
8420
+ const rel = path6.join(FILES, String(this.manifest.entries.length));
8421
+ atomicWrite(path6.join(this.dir, rel), bytes);
6078
8422
  e.backup = rel;
6079
8423
  }
6080
8424
  this.manifest.entries.push(e);
@@ -6094,13 +8438,13 @@ function undo(dir, entries, env) {
6094
8438
  continue;
6095
8439
  }
6096
8440
  if (!e.file) continue;
6097
- if (e.existed && e.backup) atomicWrite(e.file, readFileSync3(path5.join(dir, e.backup), "utf8"));
6098
- else if (existsSync6(e.file)) unlinkSync(e.file);
8441
+ if (e.existed && e.backup) atomicWrite(e.file, readFileSync3(path6.join(dir, e.backup), "utf8"));
8442
+ else unlinkWithRetry(e.file);
6099
8443
  }
6100
8444
  }
6101
8445
  function takeLock(root, runId) {
6102
- const file = path5.join(root, LOCK_FILE);
6103
- mkdirSync2(root, { recursive: true });
8446
+ const file = path6.join(root, LOCK_FILE);
8447
+ mkdirSync3(root, { recursive: true });
6104
8448
  for (let attempt = 0; attempt < 2; attempt++) {
6105
8449
  try {
6106
8450
  writeFileSync2(file, JSON.stringify({ pid: process.pid, runId }), { flag: "wx" });
@@ -6118,18 +8462,25 @@ function takeLock(root, runId) {
6118
8462
  }
6119
8463
  return `setup lock ${file} could not be taken`;
6120
8464
  }
8465
+ function agentHomeDir(id, ctx) {
8466
+ if (id === "claude-code") return claudeDirOf(ctx.env, ctx.home);
8467
+ if (id === "copilot-cli") return copilotDirOf(ctx.env, ctx.home);
8468
+ if (id === "kiro") return kiroDirOf(ctx.env, ctx.home);
8469
+ if (id === "opencode") return opencodeDirOf(ctx.env, ctx.home);
8470
+ return path6.join(ctx.home, ...AGENT_HOME_DIR[id]);
8471
+ }
6121
8472
  function detectAgents(reg, ctx) {
6122
- return reg.filter((r2) => existsSync6(path5.join(ctx.home, ...AGENT_HOME_DIR[r2.id])) || r2.listCommand && which(r2.listCommand.bin, ctx.env)).map((r2) => r2.id);
8473
+ return reg.filter((r2) => existsSync6(agentHomeDir(r2.id, ctx)) || r2.listCommand && which(r2.listCommand.bin, ctx.env)).map((r2) => r2.id);
6123
8474
  }
6124
8475
  async function runSetup(opts) {
6125
8476
  const ctx = { home: opts.home, pkgDir: opts.pkgDir, env: opts.env };
6126
- const runId = opts.runId ?? (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8477
+ const runId = opts.runId ?? (/* @__PURE__ */ new Date()).toISOString().split(":").join("-").split(".").join("-");
6127
8478
  const reg = buildRegistry(ctx);
6128
8479
  for (const f2 of ["server.mjs", "hook.mjs"]) {
6129
- if (!existsSync6(path5.join(ctx.pkgDir, f2))) return { exitCode: 1, agents: [], error: `preflight: ${path5.join(ctx.pkgDir, f2)} is missing` };
8480
+ if (!existsSync6(path6.join(ctx.pkgDir, f2))) return { exitCode: 1, agents: [], error: `preflight: ${path6.join(ctx.pkgDir, f2)} is missing` };
6130
8481
  }
6131
8482
  const ids = opts.agents ?? detectAgents(reg, ctx);
6132
- const root = path5.join(ctx.home, STATE_DIR);
8483
+ const root = path6.join(ctx.home, STATE_DIR);
6133
8484
  if (!opts.dryRun) {
6134
8485
  const held = takeLock(root, runId);
6135
8486
  if (held) return { exitCode: 1, agents: [], error: held };
@@ -6139,7 +8490,7 @@ async function runSetup(opts) {
6139
8490
  let current;
6140
8491
  const onAbort = () => {
6141
8492
  if (current !== void 0 && !opts.dryRun) run.rollback(current, ctx.env);
6142
- if (!opts.dryRun) rmSync(path5.join(root, LOCK_FILE), { force: true });
8493
+ if (!opts.dryRun) rmSync(path6.join(root, LOCK_FILE), { force: true });
6143
8494
  };
6144
8495
  opts.signal?.addEventListener("abort", onAbort, { once: true });
6145
8496
  try {
@@ -6158,7 +8509,7 @@ async function runSetup(opts) {
6158
8509
  }
6159
8510
  } finally {
6160
8511
  opts.signal?.removeEventListener("abort", onAbort);
6161
- if (!opts.dryRun) rmSync(path5.join(root, LOCK_FILE), { force: true });
8512
+ if (!opts.dryRun) rmSync(path6.join(root, LOCK_FILE), { force: true });
6162
8513
  }
6163
8514
  return { exitCode: agents.some((a2) => a2.status === "FAIL") ? 1 : 0, agents, backupDir: run.manifest ? run.dir : void 0 };
6164
8515
  }
@@ -6175,23 +8526,24 @@ async function setupRow(row, ctx, run, dryRun) {
6175
8526
  let plan;
6176
8527
  try {
6177
8528
  const listed = needsBin ? listCheck(row, ctx.env)?.ok === true : false;
6178
- plan = planRow(row, listed, copyCheck(row, ctx.pkgDir)?.ok === false);
8529
+ plan = planRow(row, listed, copyCheck(row, ctx.pkgDir)?.ok === false, ctx.env);
6179
8530
  } catch (e) {
6180
8531
  return { ...res, status: "FAIL", reason: e.message };
6181
8532
  }
6182
8533
  const configEdited = (file) => plan.edits.some((e) => e.file === file && e.changes.some((c3) => !isTrust(row, c3)));
6183
- res.v1 = detectV1(row.id, ctx.home).filter((f2) => !(row.config && f2.file === row.config.file && !configEdited(f2.file)));
8534
+ res.v1 = detectV1(row.id, ctx.home, { claudeDir: claudeDirOf(ctx.env, ctx.home), copilotDir: copilotDirOf(ctx.env, ctx.home), kiroDir: kiroDirOf(ctx.env, ctx.home), opencodeDir: opencodeDirOf(ctx.env, ctx.home) }).filter((f2) => !(row.config && f2.file === row.config.file && !configEdited(f2.file)));
6184
8535
  res.changes = [...plan.edits.flatMap((e) => e.changes), ...[...plan.cli, ...plan.refresh].map((args) => ({ command: [row.cli.bin, ...args] }))];
6185
8536
  if (dryRun) return res;
6186
8537
  try {
6187
8538
  for (const e of plan.edits) {
6188
8539
  assertWritable(row, e.file);
6189
- run.record({ agent: row.id, file: e.file, existed: e.before !== void 0 }, e.before);
6190
- atomicWrite(e.file, e.after);
8540
+ const raw = readRaw(e.file);
8541
+ run.record({ agent: row.id, file: e.file, existed: raw !== void 0 }, raw);
8542
+ atomicWrite(e.file, e.plain || raw === void 0 ? e.after : withLayout(e.after, hostLayout(raw)));
6191
8543
  }
6192
8544
  for (const args of plan.cli) {
6193
8545
  const r2 = runBin(row.cli.bin, args, ctx.env, row.cli.input ?? "");
6194
- if (r2.status !== 0) throw new Error(`${row.cli.bin} ${args.join(" ")} exited ${r2.status}: ${`${r2.stderr}`.trim()}`);
8546
+ if (!installExitOk(r2.status, r2.status === WIN_EXIT_CRASH && listCheck(row, ctx.env)?.ok === true)) throw new Error(`${row.cli.bin} ${args.join(" ")} exited ${r2.status}: ${`${r2.stderr}`.trim()}`);
6195
8547
  }
6196
8548
  if (plan.cli.length) for (const args of row.cli.remove) run.record({ agent: row.id, undo: { bin: row.cli.bin, args } });
6197
8549
  for (const args of plan.refresh) {
@@ -6214,10 +8566,10 @@ async function runDoctor(opts) {
6214
8566
  const ctx = { home: opts.home, pkgDir: opts.pkgDir, env: opts.env };
6215
8567
  const reg = buildRegistry(ctx);
6216
8568
  for (const f2 of ["server.mjs", "hook.mjs"]) {
6217
- if (!existsSync6(path5.join(ctx.pkgDir, f2))) return { exitCode: 1, agents: [], error: `preflight: ${path5.join(ctx.pkgDir, f2)} is missing` };
8569
+ if (!existsSync6(path6.join(ctx.pkgDir, f2))) return { exitCode: 1, agents: [], error: `preflight: ${path6.join(ctx.pkgDir, f2)} is missing` };
6218
8570
  }
6219
8571
  const ids = opts.agents ?? detectAgents(reg, ctx);
6220
- const run = new Run(path5.join(ctx.home, STATE_DIR), "doctor");
8572
+ const run = new Run(path6.join(ctx.home, STATE_DIR), "doctor");
6221
8573
  const agents = [];
6222
8574
  for (const id of ids) {
6223
8575
  const row = reg.find((r2) => r2.id === id);
@@ -6267,37 +8619,46 @@ function isTrust(row, c3) {
6267
8619
  }
6268
8620
  function runRemove(opts) {
6269
8621
  const env = opts.env ?? process.env;
6270
- const root = path5.join(opts.home, STATE_DIR);
6271
- const base = path5.join(root, BACKUP_DIR);
8622
+ const root = path6.join(opts.home, STATE_DIR);
8623
+ const base = path6.join(root, BACKUP_DIR);
6272
8624
  if (!existsSync6(base)) return { exitCode: 0, restored: 0 };
6273
8625
  const held = takeLock(root, "remove");
6274
8626
  if (held) return { exitCode: 1, restored: 0, error: held };
6275
8627
  let restored = 0;
6276
8628
  try {
6277
- const runs = readdirSync4(base).map((r2) => path5.join(base, r2)).filter((d) => existsSync6(path5.join(d, MANIFEST))).sort().reverse();
8629
+ const runs = readdirSync4(base).map((r2) => path6.join(base, r2)).filter((d) => existsSync6(path6.join(d, MANIFEST))).sort().reverse();
6278
8630
  for (const dir of runs) {
6279
- const m3 = JSON.parse(readFileSync3(path5.join(dir, MANIFEST), "utf8"));
8631
+ const m3 = JSON.parse(readFileSync3(path6.join(dir, MANIFEST), "utf8"));
6280
8632
  undo(dir, m3.entries, env);
6281
8633
  restored += m3.entries.length;
6282
- renameSync2(path5.join(dir, MANIFEST), path5.join(dir, MANIFEST_DONE));
8634
+ renameWithRetry(path6.join(dir, MANIFEST), path6.join(dir, MANIFEST_DONE));
6283
8635
  }
6284
8636
  } finally {
6285
- rmSync(path5.join(root, LOCK_FILE), { force: true });
8637
+ rmSync(path6.join(root, LOCK_FILE), { force: true });
6286
8638
  }
6287
8639
  return { exitCode: 0, restored };
6288
8640
  }
6289
8641
 
6290
8642
  // src/setup/print.ts
6291
8643
  import { readFileSync as readFileSync4 } from "node:fs";
8644
+ var SHELL_SAFE_PUNCT = "@%+=:,./-_";
8645
+ function isShellSafe(s) {
8646
+ if (s === "") return false;
8647
+ for (const c3 of s) {
8648
+ const alnum = c3 >= "a" && c3 <= "z" || c3 >= "A" && c3 <= "Z" || c3 >= "0" && c3 <= "9";
8649
+ if (!alnum && !SHELL_SAFE_PUNCT.includes(c3)) return false;
8650
+ }
8651
+ return true;
8652
+ }
6292
8653
  function shellWord(s) {
6293
- return /^[\w@%+=:,./-]+$/.test(s) ? s : `'${s.replaceAll("'", `'"'"'`)}'`;
8654
+ return isShellSafe(s) ? s : `'${s.replaceAll("'", `'"'"'`)}'`;
6294
8655
  }
6295
- function printPlan(row) {
8656
+ function printPlan(row, env) {
6296
8657
  const steps = [];
6297
8658
  const h2 = row.hookInstall;
6298
8659
  if (row.config) {
6299
8660
  const c3 = row.config;
6300
- const trust = h2.kind === "file" && h2.trust === c3.file ? codexTrustEntries(h2.file, h2.shape, h2.command) : [];
8661
+ const trust = h2.kind === "file" && h2.trust === c3.file ? codexTrustEntries(h2.file, h2.shape, h2.command, env) : [];
6301
8662
  const block2 = editHostConfigText(row.id, c3.file, "", c3.format, [...configEdits(c3), ...trust]).text;
6302
8663
  steps.push({ kind: "config", file: c3.file, format: c3.format, key: c3.key, block: block2 });
6303
8664
  } else if (row.cli) {
@@ -6468,7 +8829,7 @@ function buildIssueReport(command, res, ui) {
6468
8829
  return { text: redact(lines.join("\n"), ui.ctx), title };
6469
8830
  }
6470
8831
  function ghReady(env) {
6471
- const r2 = spawnSync2("gh", ["auth", "status"], { env, stdio: "ignore", timeout: 1e4 });
8832
+ const r2 = spawnSync3("gh", ["auth", "status"], { env, stdio: "ignore", timeout: 1e4, windowsHide: true });
6472
8833
  return r2.status === 0;
6473
8834
  }
6474
8835
  function issueUrl(title, body) {
@@ -6479,9 +8840,9 @@ async function report(ui, command, res, write) {
6479
8840
  const { text: text2, title } = buildIssueReport(command, res, ui);
6480
8841
  let file = "";
6481
8842
  if (write) {
6482
- const dir = path6.join(ui.ctx.home, STATE_DIR, REPORT_DIR);
6483
- mkdirSync3(dir, { recursive: true });
6484
- file = path6.join(dir, `${command}-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.md`);
8843
+ const dir = path7.join(ui.ctx.home, STATE_DIR, REPORT_DIR);
8844
+ mkdirSync4(dir, { recursive: true });
8845
+ file = path7.join(dir, `${command}-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.md`);
6485
8846
  writeFileSync3(file, text2);
6486
8847
  }
6487
8848
  const gh = `gh issue create --repo ${ISSUE_REPO} --title ${JSON.stringify(title)} --body-file ${JSON.stringify(file || "<report>")}`;
@@ -6499,7 +8860,7 @@ async function report(ui, command, res, write) {
6499
8860
  return;
6500
8861
  }
6501
8862
  if (file && ghReady(ui.ctx.env)) {
6502
- const r2 = spawnSync2("gh", ["issue", "create", "--repo", ISSUE_REPO, "--title", title, "--body-file", file], { env: ui.ctx.env, encoding: "utf8", timeout: 6e4 });
8863
+ const r2 = spawnSync3("gh", ["issue", "create", "--repo", ISSUE_REPO, "--title", title, "--body-file", file], { env: ui.ctx.env, encoding: "utf8", timeout: 6e4, windowsHide: true });
6503
8864
  if (r2.status === 0) {
6504
8865
  p3.log.success(`Issue opened: ${`${r2.stdout}`.trim()}`);
6505
8866
  return;
@@ -6589,7 +8950,7 @@ async function remove(ui) {
6589
8950
  }
6590
8951
  }
6591
8952
  if (ui.f.dryRun) {
6592
- out(`Would restore every file recorded under ${path6.join(ui.ctx.home, STATE_DIR, "backups")}`);
8953
+ out(`Would restore every file recorded under ${path7.join(ui.ctx.home, STATE_DIR, "backups")}`);
6593
8954
  return EXIT_OK;
6594
8955
  }
6595
8956
  const r2 = runRemove({ home: ui.ctx.home, env: ui.ctx.env });
@@ -6600,7 +8961,7 @@ async function remove(ui) {
6600
8961
  }
6601
8962
  function printManual(ui, id) {
6602
8963
  const row = buildRegistry(ui.ctx).find((r2) => r2.id === id);
6603
- const p3 = printPlan(row);
8964
+ const p3 = printPlan(row, ui.ctx.env);
6604
8965
  if (ui.f.json) out(JSON.stringify({ command: "setup", print: p3 }));
6605
8966
  else out(printText(p3));
6606
8967
  return EXIT_OK;
@@ -6721,20 +9082,20 @@ async function upgrade(ui) {
6721
9082
  }
6722
9083
  const shell = process.platform === "win32";
6723
9084
  progress2(ui, `running ${install}`);
6724
- const r2 = spawnSync2(npm, ["i", "-g", spec], { env: ui.ctx.env, encoding: "utf8", shell });
9085
+ const r2 = spawnSync3(npm, ["i", "-g", spec], { env: ui.ctx.env, encoding: "utf8", shell, windowsHide: true });
6725
9086
  if (r2.status !== 0) {
6726
9087
  const why = (`${r2.stderr ?? ""}`.trim().split("\n").pop() ?? "") || (r2.error?.message ?? "");
6727
9088
  err(`FAIL upgrade: ${install} exited ${r2.status ?? "?"}${why ? `: ${why}` : ""}. Fix: ${install}`);
6728
9089
  return EXIT_FAIL;
6729
9090
  }
6730
- const root = `${spawnSync2(npm, ["root", "-g"], { env: ui.ctx.env, encoding: "utf8", shell }).stdout ?? ""}`.trim();
6731
- const cli = path6.join(root, "context-mode", "cli.mjs");
9091
+ const root = `${spawnSync3(npm, ["root", "-g"], { env: ui.ctx.env, encoding: "utf8", shell, windowsHide: true }).stdout ?? ""}`.trim();
9092
+ const cli = path7.join(root, "context-mode", "cli.mjs");
6732
9093
  if (!root || !existsSync7(cli)) {
6733
9094
  err(`FAIL upgrade: ${cli} not found after ${install}. Fix: ${install}`);
6734
9095
  return EXIT_FAIL;
6735
9096
  }
6736
9097
  progress2(ui, `running context-mode ${repairArgs.join(" ")}`);
6737
- const c3 = spawnSync2(process.execPath, [cli, ...repairArgs], { env: ui.ctx.env, stdio: "inherit" });
9098
+ const c3 = spawnSync3(process.execPath, [cli, ...repairArgs], { env: ui.ctx.env, stdio: "inherit", windowsHide: true });
6738
9099
  return c3.status ?? (c3.signal === "SIGINT" ? EXIT_SIGINT : EXIT_FAIL);
6739
9100
  }
6740
9101
  async function runCommand(cmd, args, env) {
@@ -6751,7 +9112,7 @@ Run context-mode ${cmd} --help.`);
6751
9112
  out(HELP[cmd].trimEnd());
6752
9113
  return EXIT_OK;
6753
9114
  }
6754
- const ctx = { home: process.env.HOME || os.homedir(), pkgDir: env.pkgDir, env: process.env };
9115
+ const ctx = { home: homeDirOf(process.env) ?? os.homedir(), pkgDir: env.pkgDir, env: process.env };
6755
9116
  const tty = !!process.stdin.isTTY && !!process.stdout.isTTY;
6756
9117
  const interactive = tty && !f2.yes && !f2.noInput && !f2.json && !f2.list && !f2.print;
6757
9118
  if (interactive && !process.stdout.columns) Object.defineProperty(process.stdout, "columns", { value: 80, configurable: true });
@@ -6812,10 +9173,10 @@ function route(argv, version) {
6812
9173
  ` };
6813
9174
  }
6814
9175
  function main() {
6815
- const dir = path7.dirname(realpathSync5(fileURLToPath2(import.meta.url)));
9176
+ const dir = path8.dirname(realpathSync5(fileURLToPath2(import.meta.url)));
6816
9177
  let version = "";
6817
9178
  try {
6818
- version = String(JSON.parse(readFileSync5(path7.join(dir, PACKAGE_FILE), "utf8")).version);
9179
+ version = String(JSON.parse(readFileSync5(path8.join(dir, PACKAGE_FILE), "utf8")).version);
6819
9180
  } catch (err2) {
6820
9181
  process.stderr.write(`${SERVER_KEY}: cannot read ${PACKAGE_FILE}: ${err2.message}
6821
9182
  `);
@@ -6839,7 +9200,7 @@ function main() {
6839
9200
  process.exitCode = r2.code;
6840
9201
  return;
6841
9202
  }
6842
- const child = spawn2(process.execPath, [path7.join(dir, r2.file), ...r2.args], { stdio: "inherit" });
9203
+ const child = spawn2(process.execPath, [path8.join(dir, r2.file), ...r2.args], { stdio: "inherit", windowsHide: true });
6843
9204
  process.on("SIGINT", () => {
6844
9205
  });
6845
9206
  child.on("error", (err2) => {