@skein-code/cli 0.3.20 → 0.3.21

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/README.md CHANGED
@@ -94,7 +94,7 @@ To build, verify, and install a local package artifact from this checkout:
94
94
 
95
95
  ```bash
96
96
  npm run verify:package -- --output-dir artifacts/package
97
- npm install -g ./artifacts/package/skein-code-cli-0.3.16.tgz
97
+ npm install -g ./artifacts/package/skein-code-cli-0.3.21.tgz
98
98
  ```
99
99
 
100
100
  To install the published package from npm:
@@ -449,14 +449,18 @@ command instead of allowing a retrieval change to lower the quality bar.
449
449
  The persisted local index now stores content-addressed TypeScript compiler AST
450
450
  facts for definitions, calls, and relative imports. Matching definitions can
451
451
  expand a query and import/call neighbors may receive a bounded graph score;
452
- Python and SQL continue to use explicit syntax-aware fallbacks. Git recency is
453
- collected through a bounded, isolated read-only history scan and contributes
454
- only a small tie-break score; missing Git, timeouts, output limits, and
455
- non-repository workspaces degrade to lexical/graph retrieval. Search and
456
- context JSON expose the index generation, file hash, matched/expanded terms,
457
- and bm25/path/symbol/phrase/graph/recency breakdown without persisting the
458
- query or an additional copy of source. Index schema v2 artifacts rebuild as v3
459
- rather than being trusted after the parser contract changes.
452
+ Python module imports and SQL definitions/references use explicit syntax-aware
453
+ offline fallbacks. Git recency is collected through a bounded, isolated
454
+ read-only history scan and contributes only a small tie-break score; missing
455
+ Git, timeouts, output limits, and non-repository workspaces degrade to
456
+ lexical/graph retrieval. A failed configured verification may add a bounded
457
+ diagnostic tie-break for paths parsed from non-truncated process output. Those
458
+ hints are current-run only, clear on success or the next run, and cannot create
459
+ a zero-relevance hit. Search and context JSON expose the index generation, file
460
+ hash, matched/expanded terms, and bm25/path/symbol/phrase/graph/recency/
461
+ diagnostic breakdown without persisting the query, diagnostic path, or another
462
+ copy of source. Index schema v2 artifacts rebuild as v3 rather than being
463
+ trusted after the parser contract changes.
460
464
 
461
465
  The included fixture is a deterministic regression gate, not evidence for
462
466
  performance on every production repository. `--fresh-index` deletes and
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { createInterface as createInterface2 } from "node:readline/promises";
5
5
  import { stdin as input, stdout as output } from "node:process";
6
6
  import { writeFile as writeFile3 } from "node:fs/promises";
7
- import { basename as basename13, resolve as resolve24 } from "node:path";
7
+ import { basename as basename13, resolve as resolve25 } from "node:path";
8
8
  import { Command, Option } from "commander";
9
9
  import chalk4 from "chalk";
10
10
 
@@ -220,7 +220,7 @@ function isSqliteBusy(error) {
220
220
  // package.json
221
221
  var package_default = {
222
222
  name: "@skein-code/cli",
223
- version: "0.3.20",
223
+ version: "0.3.21",
224
224
  description: "A context-first, model-agnostic coding agent with an auditable terminal workspace.",
225
225
  type: "module",
226
226
  license: "MIT",
@@ -236,6 +236,10 @@ var package_default = {
236
236
  },
237
237
  skein: {
238
238
  releaseNotes: [
239
+ "Failed configured verification output yields bounded current-run diagnostic ranking without persisting paths",
240
+ "Diagnostic hints cannot create zero-relevance hits and are cleared on success or the next agent run",
241
+ "Python absolute and relative module imports now contribute deterministic offline graph adjacency",
242
+ "Context provenance exposes the diagnostic score alongside graph and isolated Git recency signals",
239
243
  "Local index v3 records TypeScript AST definitions, calls, and relative import adjacency for graph-assisted retrieval",
240
244
  "Context hits expose generation, content hash, matched terms, and bm25/path/symbol/phrase/graph score provenance",
241
245
  "Context benchmark v2 locks multilingual recall, MRR, useful-token, stale-hit, incremental-index, and warm-latency gates",
@@ -3113,7 +3117,7 @@ function executableNames(command2) {
3113
3117
  return [command2, ...extensions.map((extension) => `${command2}${extension}`)];
3114
3118
  }
3115
3119
  function runProcess(command2, args, options) {
3116
- return new Promise((resolve25, reject) => {
3120
+ return new Promise((resolve26, reject) => {
3117
3121
  const started = Date.now();
3118
3122
  const environment = options.inheritEnv === false ? {} : { ...process.env };
3119
3123
  for (const name of options.unsetEnv ?? []) delete environment[name];
@@ -3205,7 +3209,7 @@ function runProcess(command2, args, options) {
3205
3209
  reject(callbackError);
3206
3210
  return;
3207
3211
  }
3208
- resolve25({
3212
+ resolve26({
3209
3213
  command: [command2, ...args].join(" "),
3210
3214
  exitCode: code ?? (timedOut ? 124 : 1),
3211
3215
  stdout,
@@ -3474,6 +3478,8 @@ var MAX_QUERY_CACHE_ENTRIES = 64;
3474
3478
  var CHUNK_LINES = 100;
3475
3479
  var CHUNK_OVERLAP = 15;
3476
3480
  var MIN_STRUCTURAL_CHUNK_LINES = 12;
3481
+ var MAX_DIAGNOSTIC_SCORE = 0.05;
3482
+ var MAX_DIAGNOSTIC_HINTS_PER_COMMAND = 16;
3477
3483
  var LocalContextIndex = class {
3478
3484
  constructor(roots) {
3479
3485
  this.roots = roots;
@@ -3487,6 +3493,8 @@ var LocalContextIndex = class {
3487
3493
  workspace;
3488
3494
  queryCache = /* @__PURE__ */ new Map();
3489
3495
  gitRecency;
3496
+ diagnosticsByCommand = /* @__PURE__ */ new Map();
3497
+ diagnosticScores = /* @__PURE__ */ new Map();
3490
3498
  queryCacheHits = 0;
3491
3499
  queryCacheMisses = 0;
3492
3500
  fingerprintCache;
@@ -3605,6 +3613,23 @@ var LocalContextIndex = class {
3605
3613
  if (paths.length) this.queryCache.clear();
3606
3614
  if (this.dirtyPaths.size) this.refreshState = "dirty";
3607
3615
  }
3616
+ recordDiagnostics(update) {
3617
+ const paths = /* @__PURE__ */ new Set();
3618
+ for (const candidate of update.paths.slice(0, MAX_DIAGNOSTIC_HINTS_PER_COMMAND)) {
3619
+ const path = this.resolveDiagnosticPath(candidate);
3620
+ if (path) paths.add(path);
3621
+ }
3622
+ if (paths.size) this.diagnosticsByCommand.set(update.commandKey, paths);
3623
+ else this.diagnosticsByCommand.delete(update.commandKey);
3624
+ this.refreshDiagnosticScores();
3625
+ this.queryCache.clear();
3626
+ }
3627
+ resetDiagnostics() {
3628
+ if (!this.diagnosticsByCommand.size) return;
3629
+ this.diagnosticsByCommand.clear();
3630
+ this.diagnosticScores.clear();
3631
+ this.queryCache.clear();
3632
+ }
3608
3633
  async flushDirty() {
3609
3634
  if (!this.dirtyPaths.size) {
3610
3635
  return {
@@ -3690,6 +3715,7 @@ var LocalContextIndex = class {
3690
3715
  queryCacheEntries: this.queryCache.size,
3691
3716
  queryCacheHits: this.queryCacheHits,
3692
3717
  queryCacheMisses: this.queryCacheMisses,
3718
+ diagnosticHints: this.diagnosticScores.size,
3693
3719
  refreshState: this.refreshState,
3694
3720
  dirtyPaths: this.dirtyPaths.size,
3695
3721
  ...this.refreshError ? { refreshError: this.refreshError } : {},
@@ -3939,11 +3965,12 @@ var LocalContextIndex = class {
3939
3965
  );
3940
3966
  const graph = graphBoosts.get(chunk.absolutePath)?.score ?? 0;
3941
3967
  const recency = recencyScores.get(chunk.absolutePath) ?? 0;
3942
- const score = lexical.bm25 + lexical.path + lexical.symbol + lexical.phrase + graph + recency;
3943
- return { chunk, lexical, graph, recency, score };
3968
+ const diagnostic = this.diagnosticScores.get(chunk.absolutePath) ?? 0;
3969
+ const score = lexical.bm25 + lexical.path + lexical.symbol + lexical.phrase + graph + recency + diagnostic;
3970
+ return { chunk, lexical, graph, recency, diagnostic, score };
3944
3971
  }).filter(({ lexical, graph }) => lexical.bm25 + lexical.path + lexical.symbol + lexical.phrase + graph > 0).sort((left, right) => right.score - left.score || left.chunk.absolutePath.localeCompare(right.chunk.absolutePath));
3945
3972
  const covered = scored.filter(({ lexical, graph }) => graph > 0 || hasSufficientQueryCoverage(lexical.matchedTerms, coverageTerms));
3946
- return (covered.length ? covered : scored).slice(0, topK).map(({ chunk, lexical, graph, recency, score }) => {
3973
+ return (covered.length ? covered : scored).slice(0, topK).map(({ chunk, lexical, graph, recency, diagnostic, score }) => {
3947
3974
  const file = filesByPath.get(chunk.absolutePath);
3948
3975
  const breakdown = {
3949
3976
  bm25: roundScore(lexical.bm25),
@@ -3952,6 +3979,7 @@ var LocalContextIndex = class {
3952
3979
  phrase: roundScore(lexical.phrase),
3953
3980
  graph: roundScore(graph),
3954
3981
  recency: roundScore(recency),
3982
+ diagnostic: roundScore(diagnostic),
3955
3983
  total: roundScore(score)
3956
3984
  };
3957
3985
  const provenance = {
@@ -3967,7 +3995,7 @@ var LocalContextIndex = class {
3967
3995
  endLine: chunk.endLine,
3968
3996
  content: chunk.content,
3969
3997
  score,
3970
- source: "local-bm25+path+symbol+graph+recency",
3998
+ source: "local-bm25+path+symbol+graph+recency+diagnostic",
3971
3999
  ...chunk.symbol ? { symbol: chunk.symbol } : {},
3972
4000
  provenance
3973
4001
  };
@@ -4023,6 +4051,22 @@ var LocalContextIndex = class {
4023
4051
  this.queryCache.delete(oldest);
4024
4052
  }
4025
4053
  }
4054
+ resolveDiagnosticPath(candidate) {
4055
+ if (!candidate || candidate.includes("\0")) return void 0;
4056
+ const absolute = isAbsolute4(candidate) ? resolve10(candidate) : void 0;
4057
+ if (absolute && this.roots.some((root) => isWithinRoot(root, absolute))) return absolute;
4058
+ for (const root of this.roots) {
4059
+ const path = resolve10(root, candidate);
4060
+ if (isWithinRoot(root, path)) return path;
4061
+ }
4062
+ return void 0;
4063
+ }
4064
+ refreshDiagnosticScores() {
4065
+ this.diagnosticScores.clear();
4066
+ for (const paths of this.diagnosticsByCommand.values()) {
4067
+ for (const path of paths) this.diagnosticScores.set(path, MAX_DIAGNOSTIC_SCORE);
4068
+ }
4069
+ }
4026
4070
  };
4027
4071
  function isWithinRoot(root, path) {
4028
4072
  const offset = relative5(root, path);
@@ -4158,7 +4202,7 @@ function packContextHits(hits, roots, maxTokens, engine) {
4158
4202
  const text = selected.map((hit) => {
4159
4203
  const shownPath = workspaceAliasPath(hit.path, roots);
4160
4204
  const symbol = hit.symbol ? ` symbol="${escapeAttribute(hit.symbol)}"` : "";
4161
- const provenance = hit.provenance ? ` source="${escapeAttribute(hit.source)}" hash="${hit.provenance.contentHash.slice(0, 12)}" graph-score="${hit.provenance.score.graph.toFixed(3)}" recency-score="${hit.provenance.score.recency.toFixed(6)}"` : "";
4205
+ const provenance = hit.provenance ? ` source="${escapeAttribute(hit.source)}" hash="${hit.provenance.contentHash.slice(0, 12)}" graph-score="${hit.provenance.score.graph.toFixed(3)}" recency-score="${hit.provenance.score.recency.toFixed(6)}" diagnostic-score="${hit.provenance.score.diagnostic.toFixed(3)}"` : "";
4162
4206
  return `<code path="${escapeAttribute(shownPath)}" lines="${hit.startLine}-${hit.endLine}" score="${hit.score.toFixed(3)}"${symbol}${provenance}>
4163
4207
  ${hit.content}
4164
4208
  </code>`;
@@ -4485,18 +4529,37 @@ function definitionMatchesQuery(definitionTerms, queryTerms) {
4485
4529
  return shared.length >= required;
4486
4530
  }
4487
4531
  function resolveImportTargets(importer, specifier, files) {
4488
- if (!specifier.startsWith(".")) return [];
4489
- const base = posix.normalize(posix.join(posix.dirname(importer.path), specifier));
4490
- const extensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
4491
- const importedExtension = posix.extname(base);
4492
- const extensionless = extensions.includes(importedExtension) ? base.slice(0, -importedExtension.length) : base;
4493
- const candidates = /* @__PURE__ */ new Set([
4494
- base,
4495
- ...extensions.map((extension) => `${extensionless}${extension}`),
4496
- ...extensions.map((extension) => posix.join(extensionless, `index${extension}`))
4497
- ]);
4532
+ const candidates = /* @__PURE__ */ new Set();
4533
+ const extension = extname2(importer.path).toLocaleLowerCase();
4534
+ if (specifier.startsWith(".")) {
4535
+ const base = posix.normalize(posix.join(posix.dirname(importer.path), specifier));
4536
+ const extensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
4537
+ const importedExtension = posix.extname(base);
4538
+ const extensionless = extensions.includes(importedExtension) ? base.slice(0, -importedExtension.length) : base;
4539
+ candidates.add(base);
4540
+ for (const candidateExtension of extensions) {
4541
+ candidates.add(`${extensionless}${candidateExtension}`);
4542
+ candidates.add(posix.join(extensionless, `index${candidateExtension}`));
4543
+ }
4544
+ }
4545
+ if (extension === ".py") {
4546
+ const modulePath = resolvePythonModulePath(importer.path, specifier);
4547
+ if (modulePath) {
4548
+ candidates.add(`${modulePath}.py`);
4549
+ candidates.add(posix.join(modulePath, "__init__.py"));
4550
+ }
4551
+ }
4498
4552
  return files.filter((file) => file.root === importer.root && candidates.has(file.path)).map((file) => file.absolutePath);
4499
4553
  }
4554
+ function resolvePythonModulePath(importerPath, specifier) {
4555
+ const match = specifier.match(/^(\.+)(.*)$/u);
4556
+ if (!match) return specifier.split(".").filter(Boolean).join("/");
4557
+ const [, dots, remainder] = match;
4558
+ if (!dots || !remainder) return void 0;
4559
+ let base = posix.dirname(importerPath);
4560
+ for (let level = 1; level < dots.length; level += 1) base = posix.dirname(base);
4561
+ return posix.normalize(posix.join(base, remainder.split(".").filter(Boolean).join("/")));
4562
+ }
4500
4563
  function scoreChunk(chunk, terms, rawQuery, documentFrequency, documentCount, averageLength) {
4501
4564
  const frequencies = /* @__PURE__ */ new Map();
4502
4565
  for (const token of chunk.tokens) frequencies.set(token, (frequencies.get(token) ?? 0) + 1);
@@ -4587,6 +4650,12 @@ var ContextEngine = class {
4587
4650
  invalidate(paths) {
4588
4651
  this.local.invalidate(paths);
4589
4652
  }
4653
+ recordDiagnostics(update) {
4654
+ this.local.recordDiagnostics(update);
4655
+ }
4656
+ resetDiagnostics() {
4657
+ this.local.resetDiagnostics();
4658
+ }
4590
4659
  async flushDirty() {
4591
4660
  try {
4592
4661
  const result = await this.local.flushDirty();
@@ -4633,7 +4702,7 @@ function formatContextHits(hits, roots) {
4633
4702
  const path = workspaceAliasPath(hit.path, roots);
4634
4703
  const symbol = hit.symbol ? ` ${hit.symbol}` : "";
4635
4704
  const score = hit.provenance?.score;
4636
- const breakdown = score ? ` bm25=${score.bm25.toFixed(2)} path=${score.path.toFixed(2)} symbol=${score.symbol.toFixed(2)} graph=${score.graph.toFixed(2)} recency=${score.recency.toFixed(6)}` : "";
4705
+ const breakdown = score ? ` bm25=${score.bm25.toFixed(2)} path=${score.path.toFixed(2)} symbol=${score.symbol.toFixed(2)} graph=${score.graph.toFixed(2)} recency=${score.recency.toFixed(6)} diagnostic=${score.diagnostic.toFixed(3)}` : "";
4637
4706
  const hash4 = hit.provenance?.contentHash.slice(0, 12);
4638
4707
  return `[${hit.source} ${hit.score.toFixed(3)}${breakdown}${hash4 ? ` hash=${hash4}` : ""}]${symbol} ${path}:${hit.startLine}-${hit.endLine}`;
4639
4708
  }).join("\n");
@@ -8585,6 +8654,7 @@ function compact(value, limit) {
8585
8654
 
8586
8655
  // src/agent/completion-gate.ts
8587
8656
  import { createHash as createHash12 } from "node:crypto";
8657
+ import { isAbsolute as isAbsolute6, resolve as resolve17 } from "node:path";
8588
8658
 
8589
8659
  // src/tools/permissions.ts
8590
8660
  import { createHash as createHash11, createHmac, randomBytes } from "node:crypto";
@@ -8788,6 +8858,37 @@ function captureVerification(call, result, changeSequence, configuredCommands) {
8788
8858
  commandKey: createHash12("sha256").update(normalized).digest("hex")
8789
8859
  };
8790
8860
  }
8861
+ function verificationDiagnosticPaths(result, workspaceRoots) {
8862
+ if (result.ok || result.metadata?.sourceTruncated === true || typeof result.metadata?.exitCode !== "number" || result.metadata.exitCode === 0) return [];
8863
+ const roots = workspaceRoots.map((root) => resolve17(root));
8864
+ const cwd = typeof result.metadata.cwd === "string" ? resolve17(result.metadata.cwd) : void 0;
8865
+ const bases = cwd ? [cwd, ...roots] : roots;
8866
+ const candidates = /* @__PURE__ */ new Set();
8867
+ const pathPattern = String.raw`((?:[./][^\s():]+|[^\s():]+)\.[A-Za-z0-9]{1,10})`;
8868
+ const patterns = [
8869
+ new RegExp(`${pathPattern}\\(\\d+,\\d+\\):\\s*(?:error|warning|fatal)\\b`, "gimu"),
8870
+ new RegExp(`${pathPattern}:\\d+:\\d+:\\s*(?:error|warning|fatal)\\b`, "gimu"),
8871
+ new RegExp(`^\\s*(?:FAIL|ERROR)\\s+${pathPattern}`, "gimu")
8872
+ ];
8873
+ const output2 = result.content.slice(0, 2e5).split(/\r?\n/u).filter((line) => !/^\s*Command:/u.test(line)).join("\n");
8874
+ for (const pattern of patterns) {
8875
+ for (const match of output2.matchAll(pattern)) {
8876
+ const candidate = match[1];
8877
+ if (!candidate) continue;
8878
+ const path = resolveDiagnosticPath(candidate, bases, roots);
8879
+ if (path) candidates.add(path);
8880
+ if (candidates.size >= 16) return [...candidates];
8881
+ }
8882
+ }
8883
+ return [...candidates];
8884
+ }
8885
+ function resolveDiagnosticPath(candidate, bases, roots) {
8886
+ for (const base of bases) {
8887
+ const path = isAbsolute6(candidate) ? resolve17(candidate) : resolve17(base, candidate);
8888
+ if (roots.some((root) => isInside(root, path))) return path;
8889
+ }
8890
+ return void 0;
8891
+ }
8791
8892
  function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutationTracking = "complete", taskContract, audit = [], duplication) {
8792
8893
  const files = [...new Set(changedFiles)];
8793
8894
  const acceptance = taskContract ? buildAcceptance(taskContract, audit, evidence, currentChangeSequence) : void 0;
@@ -10500,6 +10601,7 @@ var AgentRunner = class {
10500
10601
  throw new Error("User input is too large; pass a focused request or attach files with @path.");
10501
10602
  }
10502
10603
  this.running = true;
10604
+ this.contextEngine.resetDiagnostics?.();
10503
10605
  const emit = async (event) => {
10504
10606
  await options.onEvent?.(event);
10505
10607
  };
@@ -10526,7 +10628,13 @@ var AgentRunner = class {
10526
10628
  this.changeSequence,
10527
10629
  this.config.agent.verifyCommands
10528
10630
  );
10529
- if (evidence) verificationEvidence.push(evidence);
10631
+ if (evidence) {
10632
+ verificationEvidence.push(evidence);
10633
+ this.contextEngine.recordDiagnostics?.({
10634
+ commandKey: evidence.commandKey,
10635
+ paths: verificationDiagnosticPaths(result, this.workspace.roots)
10636
+ });
10637
+ }
10530
10638
  };
10531
10639
  const completionReport = () => {
10532
10640
  const completion = buildRunCompletion(
@@ -11843,7 +11951,7 @@ function numeric(...values) {
11843
11951
  // src/agent/team-store.ts
11844
11952
  import { createHash as createHash16, randomUUID as randomUUID13 } from "node:crypto";
11845
11953
  import { lstat as lstat18, readFile as readFile17, readdir as readdir7, rm as rm3 } from "node:fs/promises";
11846
- import { join as join16, resolve as resolve17 } from "node:path";
11954
+ import { join as join16, resolve as resolve18 } from "node:path";
11847
11955
  import { z as z18 } from "zod";
11848
11956
  var runIdSchema = z18.string().uuid();
11849
11957
  var hashSchema = z18.string().regex(/^[a-f0-9]{64}$/u);
@@ -11927,9 +12035,9 @@ var TeamRunStore = class {
11927
12035
  managedDirectory;
11928
12036
  writes = Promise.resolve();
11929
12037
  constructor(workspace, directory) {
11930
- this.workspace = resolve17(workspace);
12038
+ this.workspace = resolve18(workspace);
11931
12039
  this.managedDirectory = directory === void 0;
11932
- this.directory = directory ? resolve17(directory) : join16(resolveProjectNamespaceSync(this.workspace).active, "team-runs");
12040
+ this.directory = directory ? resolve18(directory) : join16(resolveProjectNamespaceSync(this.workspace).active, "team-runs");
11933
12041
  }
11934
12042
  async create(input2) {
11935
12043
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -12016,7 +12124,7 @@ var TeamRunStore = class {
12016
12124
  const path = join16(this.runDirectory(runId), "manifest.json");
12017
12125
  await this.assertRegularFile(path);
12018
12126
  const manifest = manifestSchema2.parse(JSON.parse(await readFile17(path, "utf8")));
12019
- if (manifest.id !== runId || resolve17(manifest.workspace) !== this.workspace) {
12127
+ if (manifest.id !== runId || resolve18(manifest.workspace) !== this.workspace) {
12020
12128
  throw new Error("Team run manifest identity does not match its location.");
12021
12129
  }
12022
12130
  if (verify) {
@@ -12147,7 +12255,7 @@ var TeamRunStore = class {
12147
12255
  if (!info.isDirectory() || info.isSymbolicLink()) throw new Error("Team run storage is not a regular directory.");
12148
12256
  }
12149
12257
  async assertRegularFile(path) {
12150
- await assertNoSymlinkPath(this.workspace, resolve17(path, ".."));
12258
+ await assertNoSymlinkPath(this.workspace, resolve18(path, ".."));
12151
12259
  const info = await lstat18(path);
12152
12260
  if (!info.isFile() || info.isSymbolicLink()) throw new Error(`Team run file is not a regular file: ${path}`);
12153
12261
  }
@@ -12195,7 +12303,7 @@ function resolveAgentModelRoute(team, parent, profile) {
12195
12303
  import { createHash as createHash17 } from "node:crypto";
12196
12304
  import { lstat as lstat19, mkdtemp, realpath as realpath7, rm as rm4 } from "node:fs/promises";
12197
12305
  import { tmpdir as tmpdir2 } from "node:os";
12198
- import { isAbsolute as isAbsolute6, join as join17, resolve as resolve18 } from "node:path";
12306
+ import { isAbsolute as isAbsolute7, join as join17, resolve as resolve19 } from "node:path";
12199
12307
  var WriterLaneApplyError = class extends Error {
12200
12308
  constructor(message2, attempted, cause) {
12201
12309
  super(message2, cause === void 0 ? void 0 : { cause });
@@ -12208,8 +12316,8 @@ var WriterLane = class {
12208
12316
  workspace;
12209
12317
  constructor(workspace, workspaceRoots) {
12210
12318
  this.workspace = new WorkspaceAccess([
12211
- resolve18(workspace),
12212
- ...workspaceRoots.map((root) => resolve18(root))
12319
+ resolve19(workspace),
12320
+ ...workspaceRoots.map((root) => resolve19(root))
12213
12321
  ]);
12214
12322
  }
12215
12323
  async createDraft(maxPatchBytes, operation, signal) {
@@ -12414,7 +12522,7 @@ var WriterLane = class {
12414
12522
  const files = unique2(parseNumstatPaths(numstat.stdout));
12415
12523
  if (!files.length) throw new Error("Writer patch contains no file changes.");
12416
12524
  for (const file of files) {
12417
- if (isAbsolute6(file) || file === ".git" || file.startsWith(".git/") || file.includes("\0")) {
12525
+ if (isAbsolute7(file) || file === ".git" || file.startsWith(".git/") || file.includes("\0")) {
12418
12526
  throw new Error(`Writer patch contains an unsafe path: ${file}`);
12419
12527
  }
12420
12528
  await this.workspace.resolvePath(join17(repository.root, file), { allowMissing: true });
@@ -12432,7 +12540,7 @@ var WriterLane = class {
12432
12540
  if (topLevel.exitCode !== 0 || !topLevel.stdout.trim()) {
12433
12541
  throw new Error("The primary workspace must be a Git repository root for writer lanes.");
12434
12542
  }
12435
- const discoveredRoot = resolve18(topLevel.stdout.trim());
12543
+ const discoveredRoot = resolve19(topLevel.stdout.trim());
12436
12544
  if (await realpath7(discoveredRoot) !== await realpath7(root)) {
12437
12545
  throw new Error("The primary workspace must be the Git repository root for writer lanes.");
12438
12546
  }
@@ -12441,7 +12549,7 @@ var WriterLane = class {
12441
12549
  if (common.exitCode !== 0 || !common.stdout.trim()) {
12442
12550
  throw new Error(`Unable to resolve the Git common directory: ${processDetail(common)}`);
12443
12551
  }
12444
- const commonDirectory = await realpath7(isAbsolute6(common.stdout.trim()) ? common.stdout.trim() : resolve18(repositoryRoot, common.stdout.trim()));
12552
+ const commonDirectory = await realpath7(isAbsolute7(common.stdout.trim()) ? common.stdout.trim() : resolve19(repositoryRoot, common.stdout.trim()));
12445
12553
  return { root: repositoryRoot, commonDirectory, runtime };
12446
12554
  }
12447
12555
  async head(repository) {
@@ -12453,7 +12561,7 @@ var WriterLane = class {
12453
12561
  return value;
12454
12562
  }
12455
12563
  async cleanupWorktree(repository, worktree, added) {
12456
- const physicalWorktree = await realpath7(worktree).catch(() => resolve18(worktree));
12564
+ const physicalWorktree = await realpath7(worktree).catch(() => resolve19(worktree));
12457
12565
  if (added) {
12458
12566
  await runIsolatedGit(repository.runtime, [
12459
12567
  "worktree",
@@ -14379,7 +14487,7 @@ function formatResultDetail(result, paint = chalk2, glyphs = resolveCliGlyphs())
14379
14487
  }
14380
14488
 
14381
14489
  // src/cli/namespace-leases.ts
14382
- import { resolve as resolve19 } from "node:path";
14490
+ import { resolve as resolve20 } from "node:path";
14383
14491
  function cliNamespaceLeaseScopes(actionCommand) {
14384
14492
  const names = commandNames(actionCommand);
14385
14493
  const topLevel = names[1];
@@ -14401,7 +14509,7 @@ async function acquireCliNamespaceLeases(actionCommand) {
14401
14509
  const scopes = cliNamespaceLeaseScopes(actionCommand);
14402
14510
  const localOptions = actionCommand.opts();
14403
14511
  const globalOptions = actionCommand.optsWithGlobals();
14404
- const workspace = resolve19(localOptions.workspace ?? globalOptions.workspace ?? process.cwd());
14512
+ const workspace = resolve20(localOptions.workspace ?? globalOptions.workspace ?? process.cwd());
14405
14513
  const targets = scopes.map((scope) => scope === "project" ? projectNamespacePaths(workspace).canonical : homeNamespacePaths().canonical);
14406
14514
  const leases = [];
14407
14515
  try {
@@ -14653,7 +14761,7 @@ function graphemes(value) {
14653
14761
 
14654
14762
  // src/ui/theme.ts
14655
14763
  import { lstat as lstat20, readdir as readdir8, readFile as readFile18 } from "node:fs/promises";
14656
- import { basename as basename10, join as join19, resolve as resolve20 } from "node:path";
14764
+ import { basename as basename10, join as join19, resolve as resolve21 } from "node:path";
14657
14765
  import React, { createContext, useContext } from "react";
14658
14766
  function defineTheme(seed) {
14659
14767
  return {
@@ -14775,7 +14883,7 @@ async function reloadUserThemes(directory = userThemeDirectory()) {
14775
14883
  userThemeNames.clear();
14776
14884
  const loaded = [];
14777
14885
  const errors = [];
14778
- const resolvedDirectory = resolve20(directory);
14886
+ const resolvedDirectory = resolve21(directory);
14779
14887
  let entries;
14780
14888
  try {
14781
14889
  entries = await readdir8(resolvedDirectory, { encoding: "utf8" });
@@ -17239,7 +17347,7 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
17239
17347
  return () => clearInterval(timer);
17240
17348
  }, [busy]);
17241
17349
  const requestPermission = useCallback((call, category) => {
17242
- return new Promise((resolve25) => setPermission({ call, category, resolve: resolve25 }));
17350
+ return new Promise((resolve26) => setPermission({ call, category, resolve: resolve26 }));
17243
17351
  }, []);
17244
17352
  const onEvent = useCallback((event) => {
17245
17353
  switch (event.type) {
@@ -18075,8 +18183,8 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
18075
18183
  }, [append]);
18076
18184
  function settlePermission(grant, stop = false) {
18077
18185
  if (!permission) return;
18078
- const { call, category, resolve: resolve25 } = permission;
18079
- resolve25(grant);
18186
+ const { call, category, resolve: resolve26 } = permission;
18187
+ resolve26(grant);
18080
18188
  setPermission(void 0);
18081
18189
  if (grant === "session") {
18082
18190
  append({
@@ -19411,7 +19519,7 @@ async function runFirstRunOnboarding(initialConfig, options = {}) {
19411
19519
  }
19412
19520
 
19413
19521
  // src/runtime/extensions.ts
19414
- import { resolve as resolve23 } from "node:path";
19522
+ import { resolve as resolve24 } from "node:path";
19415
19523
 
19416
19524
  // src/mcp/manager.ts
19417
19525
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
@@ -19624,7 +19732,7 @@ function isRecord2(value) {
19624
19732
 
19625
19733
  // src/mcp/validation.ts
19626
19734
  import { stat as stat11, realpath as realpath8 } from "node:fs/promises";
19627
- import { isAbsolute as isAbsolute7, resolve as resolve21 } from "node:path";
19735
+ import { isAbsolute as isAbsolute8, resolve as resolve22 } from "node:path";
19628
19736
  var SERVER_NAME = /^[a-z][a-z0-9_-]{0,63}$/;
19629
19737
  var ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
19630
19738
  var HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
@@ -19696,9 +19804,9 @@ async function validateCwd(configured, options) {
19696
19804
  if (configured !== void 0 && (configured.length > 4e3 || CONTROL_CHARACTERS.test(configured))) {
19697
19805
  throw new Error("MCP working directory is invalid or too long");
19698
19806
  }
19699
- const defaultCwd = resolve21(options.cwd ?? process.cwd());
19700
- const candidate = configured ? isAbsolute7(configured) ? resolve21(configured) : resolve21(defaultCwd, configured) : defaultCwd;
19701
- const roots = options.workspaceRoots?.length ? options.workspaceRoots.map((root) => resolve21(root)) : [defaultCwd];
19807
+ const defaultCwd = resolve22(options.cwd ?? process.cwd());
19808
+ const candidate = configured ? isAbsolute8(configured) ? resolve22(configured) : resolve22(defaultCwd, configured) : defaultCwd;
19809
+ const roots = options.workspaceRoots?.length ? options.workspaceRoots.map((root) => resolve22(root)) : [defaultCwd];
19702
19810
  const resolvedCandidate = await realpath8(candidate).catch(() => {
19703
19811
  throw new Error(`MCP working directory does not exist: ${candidate}`);
19704
19812
  });
@@ -20352,7 +20460,7 @@ function scopeKey(scope, context) {
20352
20460
  // src/skills/catalog.ts
20353
20461
  import { lstat as lstat21, readFile as readFile20, readdir as readdir9, realpath as realpath9 } from "node:fs/promises";
20354
20462
  import { homedir as homedir4 } from "node:os";
20355
- import { basename as basename12, join as join21, resolve as resolve22 } from "node:path";
20463
+ import { basename as basename12, join as join21, resolve as resolve23 } from "node:path";
20356
20464
  import { parse as parseYaml3 } from "yaml";
20357
20465
  var SkillCatalog = class {
20358
20466
  constructor(workspace, config) {
@@ -20421,14 +20529,14 @@ ${skill.content}
20421
20529
  }
20422
20530
  function discoveryLocations(workspace, configured) {
20423
20531
  const home = homedir4();
20424
- const workspaceRoot = resolve22(workspace);
20532
+ const workspaceRoot = resolve23(workspace);
20425
20533
  return [
20426
20534
  { path: join21(home, ".agents", "skills"), scope: "user", trusted: true },
20427
20535
  { path: join21(home, ".claude", "skills"), scope: "user", trusted: true },
20428
20536
  { path: join21(home, ".augment", "skills"), scope: "user", trusted: true },
20429
20537
  { path: join21(resolveHomeNamespace(), "skills"), scope: "user", trusted: true },
20430
20538
  ...configured.map((path) => {
20431
- const resolved = resolve22(workspaceRoot, path);
20539
+ const resolved = resolve23(workspaceRoot, path);
20432
20540
  return {
20433
20541
  path: resolved,
20434
20542
  scope: "configured",
@@ -20457,7 +20565,7 @@ async function readMetadata(path) {
20457
20565
  const { frontmatter } = splitFrontmatter(raw);
20458
20566
  if (!frontmatter) return void 0;
20459
20567
  const parsed = parseYaml3(frontmatter);
20460
- const name = typeof parsed?.name === "string" ? parsed.name.trim() : basename12(resolve22(path, ".."));
20568
+ const name = typeof parsed?.name === "string" ? parsed.name.trim() : basename12(resolve23(path, ".."));
20461
20569
  const description = typeof parsed?.description === "string" ? parsed.description.trim() : "";
20462
20570
  if (!/^[a-z][a-z0-9_-]{0,63}$/.test(name) || !description || description.length > 1e3) {
20463
20571
  return void 0;
@@ -20478,7 +20586,7 @@ async function safeRead(path, maxBytes) {
20478
20586
  try {
20479
20587
  const info = await lstat21(path);
20480
20588
  if (!info.isFile() || info.isSymbolicLink() || info.size > maxBytes) return void 0;
20481
- const parent = resolve22(path, "..");
20589
+ const parent = resolve23(path, "..");
20482
20590
  const resolvedParent = await realpath9(parent);
20483
20591
  const resolvedPath = await realpath9(path);
20484
20592
  if (!resolvedPath.startsWith(`${resolvedParent}/`)) return void 0;
@@ -20663,7 +20771,7 @@ var ExtensionRuntime = class _ExtensionRuntime {
20663
20771
  delegation;
20664
20772
  initialized = false;
20665
20773
  static async create(config, registry, options = {}) {
20666
- const runtime = new _ExtensionRuntime(config, resolve23(config.workspaceRoots[0] ?? process.cwd()), options);
20774
+ const runtime = new _ExtensionRuntime(config, resolve24(config.workspaceRoots[0] ?? process.cwd()), options);
20667
20775
  try {
20668
20776
  await runtime.initialize(registry, options.signal);
20669
20777
  return runtime;
@@ -20868,15 +20976,15 @@ function upgradeCommandOverride(env = process.env) {
20868
20976
  return trimmed ? trimmed : void 0;
20869
20977
  }
20870
20978
  function runUpgrade(plan) {
20871
- return new Promise((resolve25) => {
20979
+ return new Promise((resolve26) => {
20872
20980
  const child = spawn2(plan.command, plan.args, {
20873
20981
  stdio: "inherit",
20874
20982
  shell: plan.shell ?? false
20875
20983
  });
20876
- child.on("error", () => resolve25({ ok: false, exitCode: 127, display: plan.display }));
20984
+ child.on("error", () => resolve26({ ok: false, exitCode: 127, display: plan.display }));
20877
20985
  child.on("close", (code) => {
20878
20986
  const exitCode = code ?? 1;
20879
- resolve25({ ok: exitCode === 0, exitCode, display: plan.display });
20987
+ resolve26({ ok: exitCode === 0, exitCode, display: plan.display });
20880
20988
  });
20881
20989
  });
20882
20990
  }
@@ -21138,7 +21246,7 @@ sessionCommand.command("export <id>").description("Export a session as Markdown"
21138
21246
  const store = new SessionStore(workspaceOption(options.workspace));
21139
21247
  const session = await requireSessionSelector(store, id);
21140
21248
  const markdown = sessionMarkdown(session);
21141
- if (options.output) await writeFile3(resolve24(options.output), markdown, "utf8");
21249
+ if (options.output) await writeFile3(resolve25(options.output), markdown, "utf8");
21142
21250
  else process.stdout.write(markdown);
21143
21251
  });
21144
21252
  var checkpointCommand = program.command("checkpoint").description("Inspect and restore pre-mutation snapshots");
@@ -21515,7 +21623,7 @@ async function runChat(prompts, options) {
21515
21623
  const stdinPrompt = !process.stdin.isTTY ? await readStdin() : "";
21516
21624
  const firstPrompt = [...prompts, stdinPrompt].filter(Boolean).join("\n\n").trim();
21517
21625
  if (shouldPrint && !firstPrompt) throw new Error("Provide a prompt argument or pipe input on stdin.");
21518
- const workspace = resolve24(options.workspace);
21626
+ const workspace = resolve25(options.workspace);
21519
21627
  let config = await runtimeConfig(workspace, options);
21520
21628
  let completedOnboarding = false;
21521
21629
  if (!shouldPrint && needsFirstRunOnboarding(config)) {
@@ -21740,14 +21848,14 @@ async function runAgentSetup(options) {
21740
21848
  `);
21741
21849
  }
21742
21850
  async function runtimeConfig(workspaceInput, options) {
21743
- const workspace = resolve24(workspaceInput);
21851
+ const workspace = resolve25(workspaceInput);
21744
21852
  const loaded = await loadConfig(workspace, options.config, {
21745
21853
  trustProjectConfig: options.trustProjectConfig === true
21746
21854
  });
21747
21855
  const roots = [
21748
21856
  workspace,
21749
21857
  ...loaded.workspaceRoots,
21750
- ...(options.addWorkspace ?? []).map((root) => resolve24(workspace, root))
21858
+ ...(options.addWorkspace ?? []).map((root) => resolve25(workspace, root))
21751
21859
  ];
21752
21860
  const provider = options.provider ? validateProvider(options.provider) : loaded.model.provider;
21753
21861
  return {
@@ -21903,7 +22011,7 @@ function collect(value, previous) {
21903
22011
  }
21904
22012
  function workspaceOption(value) {
21905
22013
  const rootOptions = program.opts();
21906
- return resolve24(value ?? rootOptions.workspace ?? process.cwd());
22014
+ return resolve25(value ?? rootOptions.workspace ?? process.cwd());
21907
22015
  }
21908
22016
  function runtimeOptions(options) {
21909
22017
  const root = program.opts();