@mrciphersmith/keryx 0.2.101 → 0.2.105

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.
Files changed (3) hide show
  1. package/dist/cli.js +89 -27
  2. package/dist/core.js +25 -1
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1089,6 +1089,8 @@ var init_providers = __esm(() => {
1089
1089
  label: "GitHub Copilot",
1090
1090
  baseUrl: "https://api.githubcopilot.com",
1091
1091
  envKey: "GITHUB_COPILOT_TOKEN",
1092
+ chatPath: "/chat/completions",
1093
+ modelsPath: "/models",
1092
1094
  models: ["gpt-4o", "gpt-4.1", "gpt-4o-mini"],
1093
1095
  note: "Copilot \xB7 device login"
1094
1096
  }
@@ -10264,6 +10266,28 @@ var init_templates3 = __esm(() => {
10264
10266
  init_default_tasks();
10265
10267
  });
10266
10268
 
10269
+ // src/lib/git-env.ts
10270
+ function withoutGitDiscoveryOverrides(env) {
10271
+ const clean = {};
10272
+ for (const [key, value] of Object.entries(env)) {
10273
+ if (value !== undefined && !GIT_DISCOVERY_OVERRIDE_VARS.includes(key)) {
10274
+ clean[key] = value;
10275
+ }
10276
+ }
10277
+ return clean;
10278
+ }
10279
+ var GIT_DISCOVERY_OVERRIDE_VARS;
10280
+ var init_git_env = __esm(() => {
10281
+ GIT_DISCOVERY_OVERRIDE_VARS = [
10282
+ "GIT_DIR",
10283
+ "GIT_WORK_TREE",
10284
+ "GIT_INDEX_FILE",
10285
+ "GIT_OBJECT_DIRECTORY",
10286
+ "GIT_ALTERNATE_OBJECT_DIRECTORIES",
10287
+ "GIT_COMMON_DIR"
10288
+ ];
10289
+ });
10290
+
10267
10291
  // src/metrics/provenance.ts
10268
10292
  async function collectGitProvenance(cwd) {
10269
10293
  const [commit, branch, worktree] = await Promise.all([
@@ -11674,7 +11698,12 @@ function pathExistsSync(filePath) {
11674
11698
  return existsSync11(filePath);
11675
11699
  }
11676
11700
  async function runCommand(command, cwd) {
11677
- const proc = Bun.spawn(command, { cwd, stdout: "pipe", stderr: "pipe" });
11701
+ const proc = Bun.spawn(command, {
11702
+ cwd,
11703
+ env: withoutGitDiscoveryOverrides(process.env),
11704
+ stdout: "pipe",
11705
+ stderr: "pipe"
11706
+ });
11678
11707
  const [stdout, stderr, exitCode] = await Promise.all([
11679
11708
  new Response(proc.stdout).text(),
11680
11709
  new Response(proc.stderr).text(),
@@ -11837,6 +11866,7 @@ function normalizePath3(file) {
11837
11866
  var IGNORED_DIRS, TEST_FILE_RE2, SOURCE_FILE_RE, CONFIG_FILE_RE, CI_FILE_RE, INSTRUCTION_FILE_RE, IMPORT_RE, DEFAULT_TESTING_CONFIG, BASE_STRATEGIES, BUN_LOCKFILES;
11838
11867
  var init_service2 = __esm(() => {
11839
11868
  init_fs();
11869
+ init_git_env();
11840
11870
  init_lifecycle();
11841
11871
  init_guard2();
11842
11872
  init_capability();
@@ -27377,9 +27407,6 @@ var init_slate_terminal_state = __esm(() => {
27377
27407
  });
27378
27408
 
27379
27409
  // src/commands/agent.ts
27380
- function isDurableToolCall(name, risk) {
27381
- return risk !== "read" || DURABLE_READ_TOOL_NAMES.has(name);
27382
- }
27383
27410
  function resolveAgentMaxRounds(env = process.env) {
27384
27411
  const raw = env[ENV_AGENT_MAX_ROUNDS];
27385
27412
  if (raw === undefined || raw.trim().length === 0) {
@@ -27995,7 +28022,8 @@ async function runAgentTurnCore(io, deps, history, userLine, options = {}) {
27995
28022
  return {};
27996
28023
  }
27997
28024
  const risk = toolByName.get(call.name)?.definition.risk;
27998
- if (isDurableToolCall(call.name, risk) && (untrustedContentSeen || batchContainsUntrustedWeb)) {
28025
+ const isPureReadTool = risk === "read" && !DURABLE_READ_TOOL_NAMES.has(call.name);
28026
+ if (!isPureReadTool && (untrustedContentSeen || batchContainsUntrustedWeb)) {
27999
28027
  const result = {
28000
28028
  output: "tool blocked: external web content cannot authorize further tool calls in this turn",
28001
28029
  isError: true
@@ -41137,6 +41165,24 @@ var init_device_code = __esm(() => {
41137
41165
  });
41138
41166
 
41139
41167
  // src/lib/oauth/copilot.ts
41168
+ function copilotApiBaseFromExchange(raw) {
41169
+ if (typeof raw !== "string" || raw.length === 0) {
41170
+ return;
41171
+ }
41172
+ try {
41173
+ const url = new URL(raw);
41174
+ if (url.protocol !== "https:" || url.username.length > 0 || url.password.length > 0) {
41175
+ return;
41176
+ }
41177
+ const host = url.hostname;
41178
+ if (host !== "api.githubcopilot.com" && !host.endsWith(".githubcopilot.com")) {
41179
+ return;
41180
+ }
41181
+ return `https://${host}${url.port.length > 0 ? `:${url.port}` : ""}`;
41182
+ } catch {
41183
+ return;
41184
+ }
41185
+ }
41140
41186
  function expiresInSecondsFrom(rec, now) {
41141
41187
  if (typeof rec.expires_at === "string") {
41142
41188
  const expires = Date.parse(rec.expires_at);
@@ -41197,7 +41243,12 @@ async function exchangeGithubTokenForCopilot(githubToken, http) {
41197
41243
  throw new DeviceCodeError("failed", "GitHub Copilot token exchange returned no token");
41198
41244
  }
41199
41245
  const expiresInSeconds = expiresInSecondsFrom(rec, Date.now());
41200
- return { accessToken: rec.token, ...expiresInSeconds !== undefined ? { expiresInSeconds } : {} };
41246
+ const apiBaseUrl = copilotApiBaseFromExchange(rec.endpoints?.api);
41247
+ return {
41248
+ accessToken: rec.token,
41249
+ ...expiresInSeconds !== undefined ? { expiresInSeconds } : {},
41250
+ ...apiBaseUrl !== undefined ? { apiBaseUrl } : {}
41251
+ };
41201
41252
  }
41202
41253
  var COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
41203
41254
  var init_copilot = __esm(() => {
@@ -41321,6 +41372,9 @@ async function loginRfc8628(input) {
41321
41372
  }, http);
41322
41373
  if (endpoints.afterToken === "github-copilot") {
41323
41374
  const copilot = await exchangeGithubTokenForCopilot(tokens.accessToken, http);
41375
+ if (copilot.apiBaseUrl !== undefined) {
41376
+ saveProviderBaseUrl("github-copilot", copilot.apiBaseUrl, input.dir);
41377
+ }
41324
41378
  return {
41325
41379
  accessToken: copilot.accessToken,
41326
41380
  refreshToken: tokens.accessToken,
@@ -41370,6 +41424,9 @@ async function refreshProviderGrant(provider, http, dir) {
41370
41424
  const endpoints = provider === "github-copilot" ? GITHUB_COPILOT_DEVICE : XAI_GROK_DEVICE;
41371
41425
  if (provider === "github-copilot") {
41372
41426
  const copilot = await exchangeGithubTokenForCopilot(grant.refresh, http);
41427
+ if (copilot.apiBaseUrl !== undefined) {
41428
+ saveProviderBaseUrl("github-copilot", copilot.apiBaseUrl, dir);
41429
+ }
41373
41430
  const next = grantFromTokens("device-code", {
41374
41431
  accessToken: copilot.accessToken,
41375
41432
  refreshToken: grant.refresh,
@@ -41424,6 +41481,7 @@ function logoutProvider(provider, dir) {
41424
41481
  }
41425
41482
  var SESSION_REFRESHED_GRANTS;
41426
41483
  var init_login = __esm(() => {
41484
+ init_shell_config();
41427
41485
  init_catalog();
41428
41486
  init_copilot();
41429
41487
  init_device_code();
@@ -45289,6 +45347,7 @@ init_templates3();
45289
45347
  init_service2();
45290
45348
 
45291
45349
  // src/testing/templates.ts
45350
+ init_git_env();
45292
45351
  function renderTestingConfig(input) {
45293
45352
  return `${JSON.stringify({
45294
45353
  schemaVersion: 1,
@@ -45481,6 +45540,11 @@ function renderTestingPrePushHook() {
45481
45540
  return 0
45482
45541
  fi
45483
45542
 
45543
+ # Git exports GIT_DIR to hooks. Inherited by the suite, it redirects every
45544
+ # fixture repo a test creates onto this checkout, so a fixture's
45545
+ # 'git config user.name' rewrites the identity of the repo being pushed.
45546
+ unset ${GIT_DISCOVERY_OVERRIDE_VARS.join(" ")}
45547
+
45484
45548
  if command -v keryx >/dev/null 2>&1; then
45485
45549
  keryx test run --changed --strict
45486
45550
  return $?
@@ -48228,7 +48292,7 @@ import path47 from "path";
48228
48292
  // package.json
48229
48293
  var package_default = {
48230
48294
  name: "@mrciphersmith/keryx",
48231
- version: "0.2.101",
48295
+ version: "0.2.105",
48232
48296
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
48233
48297
  private: false,
48234
48298
  publishConfig: {
@@ -79525,23 +79589,10 @@ function builtinReadOnlyTools(root) {
79525
79589
 
79526
79590
  // src/harness/tool/builtin/apply-patch-tool.ts
79527
79591
  init_patch_risk();
79592
+ init_git_env();
79528
79593
  var MAX_OUTPUT_BYTES = 20000;
79529
- var GIT_DISCOVERY_OVERRIDE_VARS = [
79530
- "GIT_DIR",
79531
- "GIT_WORK_TREE",
79532
- "GIT_INDEX_FILE",
79533
- "GIT_OBJECT_DIRECTORY",
79534
- "GIT_ALTERNATE_OBJECT_DIRECTORIES",
79535
- "GIT_COMMON_DIR"
79536
- ];
79537
79594
  function gitDiscoveryCleanEnv() {
79538
- const env = {};
79539
- for (const [key, value] of Object.entries(process.env)) {
79540
- if (value !== undefined && !GIT_DISCOVERY_OVERRIDE_VARS.includes(key)) {
79541
- env[key] = value;
79542
- }
79543
- }
79544
- return env;
79595
+ return withoutGitDiscoveryOverrides(process.env);
79545
79596
  }
79546
79597
  async function spawnGitApply(args, patch, cwd) {
79547
79598
  try {
@@ -95021,7 +95072,7 @@ function pickAuthMethodStep(otui, r, providerLabel, methods) {
95021
95072
  });
95022
95073
  });
95023
95074
  }
95024
- function runDeviceLoginInTui(otui, r, provider) {
95075
+ function runDeviceLoginInTui(otui, r, provider, dir) {
95025
95076
  return new Promise((resolve) => {
95026
95077
  const box = overlayBox(otui, r, "device-login");
95027
95078
  r.root.add(box);
@@ -95049,6 +95100,7 @@ function runDeviceLoginInTui(otui, r, provider) {
95049
95100
  provider,
95050
95101
  fetch: (input, init) => globalThis.fetch(input, init),
95051
95102
  signal: controller.signal,
95103
+ ...dir !== undefined ? { dir } : {},
95052
95104
  onChallenge: (challenge) => {
95053
95105
  status.content = otui.t`${otui.bold(challenge.userCode)}\n${otui.dim(challenge.verificationUri)}\n${otui.dim("Open that URL on any device and enter the code. Waiting for authorization\u2026")}`;
95054
95106
  openVerificationUrl(challenge.verificationUriComplete ?? challenge.verificationUri);
@@ -95165,12 +95217,14 @@ function selectProviderModelInTui(otui, r, detected, options = {}) {
95165
95217
  }
95166
95218
  continue;
95167
95219
  }
95168
- let selectedBaseUrl = options.onlyConnected || prov.baseUrl === undefined ? prov.baseUrl : await promptBaseUrlStep(otui, r, prov.label ?? prov.name, prov.baseUrl);
95169
- if (!options.onlyConnected && prov.baseUrl !== undefined && selectedBaseUrl === undefined) {
95220
+ const lockDiscoveredHost = prov.name === "github-copilot";
95221
+ let selectedBaseUrl = options.onlyConnected || prov.baseUrl === undefined || lockDiscoveredHost ? prov.baseUrl : await promptBaseUrlStep(otui, r, prov.label ?? prov.name, prov.baseUrl);
95222
+ if (!options.onlyConnected && !lockDiscoveredHost && prov.baseUrl !== undefined && selectedBaseUrl === undefined) {
95170
95223
  continue;
95171
95224
  }
95172
- if (!options.onlyConnected && selectedBaseUrl !== undefined)
95225
+ if (!options.onlyConnected && !lockDiscoveredHost && selectedBaseUrl !== undefined) {
95173
95226
  saveProviderBaseUrl(prov.name, selectedBaseUrl, options.configDir);
95227
+ }
95174
95228
  let selectedProvider = selectedBaseUrl === undefined ? prov : { ...prov, baseUrl: selectedBaseUrl };
95175
95229
  const envKey = prov.envKey;
95176
95230
  const label = prov.label ?? prov.name;
@@ -95198,7 +95252,15 @@ function selectProviderModelInTui(otui, r, detected, options = {}) {
95198
95252
  }
95199
95253
  }
95200
95254
  if (method === "device-code") {
95201
- return await runDeviceLoginInTui(otui, r, prov.name) ? "ok" : "back";
95255
+ if (!await runDeviceLoginInTui(otui, r, prov.name, options.configDir)) {
95256
+ return "back";
95257
+ }
95258
+ const saved = loadShellConfig(options.configDir).baseUrls?.[prov.name];
95259
+ if (typeof saved === "string" && saved.length > 0) {
95260
+ selectedBaseUrl = saved;
95261
+ selectedProvider = { ...prov, baseUrl: saved };
95262
+ }
95263
+ return "ok";
95202
95264
  }
95203
95265
  const kr = await promptApiKeyStep(otui, r, {
95204
95266
  label,
package/dist/core.js CHANGED
@@ -16331,6 +16331,25 @@ import { existsSync as existsSync7 } from "fs";
16331
16331
  import { mkdir as mkdir21, readFile as readFile29, readdir as readdir10, writeFile as writeFile17 } from "fs/promises";
16332
16332
  import path58 from "path";
16333
16333
 
16334
+ // src/lib/git-env.ts
16335
+ var GIT_DISCOVERY_OVERRIDE_VARS = [
16336
+ "GIT_DIR",
16337
+ "GIT_WORK_TREE",
16338
+ "GIT_INDEX_FILE",
16339
+ "GIT_OBJECT_DIRECTORY",
16340
+ "GIT_ALTERNATE_OBJECT_DIRECTORIES",
16341
+ "GIT_COMMON_DIR"
16342
+ ];
16343
+ function withoutGitDiscoveryOverrides(env) {
16344
+ const clean = {};
16345
+ for (const [key, value] of Object.entries(env)) {
16346
+ if (value !== undefined && !GIT_DISCOVERY_OVERRIDE_VARS.includes(key)) {
16347
+ clean[key] = value;
16348
+ }
16349
+ }
16350
+ return clean;
16351
+ }
16352
+
16334
16353
  // src/metrics/lifecycle.ts
16335
16354
  init_fs();
16336
16355
  init_guard();
@@ -17244,7 +17263,12 @@ function pathExistsSync(filePath) {
17244
17263
  return existsSync7(filePath);
17245
17264
  }
17246
17265
  async function runCommand2(command, cwd) {
17247
- const proc = Bun.spawn(command, { cwd, stdout: "pipe", stderr: "pipe" });
17266
+ const proc = Bun.spawn(command, {
17267
+ cwd,
17268
+ env: withoutGitDiscoveryOverrides(process.env),
17269
+ stdout: "pipe",
17270
+ stderr: "pipe"
17271
+ });
17248
17272
  const [stdout, stderr, exitCode] = await Promise.all([
17249
17273
  new Response(proc.stdout).text(),
17250
17274
  new Response(proc.stderr).text(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.2.101",
3
+ "version": "0.2.105",
4
4
  "description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
5
5
  "private": false,
6
6
  "publishConfig": {