overlane 0.1.141 → 0.1.143

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/dist/overlane.mjs CHANGED
@@ -21068,6 +21068,121 @@ var init_code_index = __esm({
21068
21068
  }
21069
21069
  });
21070
21070
 
21071
+ // ../contracts/src/code-nav.ts
21072
+ var CodeNavFreshness, CodeNavMeta, CodeNavSymbol, CodeNavTextHit, CodeFindAnswer, CodeOutlineAnswer, CodeRefsAnswer, CodeSpanAnswer;
21073
+ var init_code_nav = __esm({
21074
+ "../contracts/src/code-nav.ts"() {
21075
+ "use strict";
21076
+ init_zod();
21077
+ CodeNavFreshness = external_exports.enum(["fresh", "partial", "stale", "unavailable"]);
21078
+ CodeNavMeta = external_exports.object({
21079
+ /** The commit the index describes; null with no index. */
21080
+ indexedCommit: external_exports.string().nullable(),
21081
+ /** The commit the caller asked about (the checkout's HEAD for the local source); null when unknown. */
21082
+ requestedCommit: external_exports.string().nullable(),
21083
+ coverage: external_exports.object({
21084
+ /** Files the index parsed. */
21085
+ files: external_exports.number().int().nonnegative(),
21086
+ symbols: external_exports.number().int().nonnegative(),
21087
+ /** Files that could not be parsed (unsupported language, too large). */
21088
+ uncovered: external_exports.number().int().nonnegative(),
21089
+ /** Files that differ between the indexed and the requested commit; their answers come from a pattern scan or are missing. */
21090
+ changedSinceIndex: external_exports.number().int().nonnegative()
21091
+ }).strict(),
21092
+ freshness: CodeNavFreshness,
21093
+ /** True when an empty or short answer may be missing results (stale, partial or uncovered files), as opposed to a certain "no match". */
21094
+ incomplete: external_exports.boolean(),
21095
+ notice: external_exports.string().optional(),
21096
+ /** The cloud index only: saved, uncommitted work merged over the snapshot, as `overlay <session> <age>` (ADR 0062). Absent when nothing is merged. */
21097
+ overlay: external_exports.string().optional()
21098
+ }).strict();
21099
+ CodeNavSymbol = external_exports.object({ kind: external_exports.string(), qualified: external_exports.string(), path: external_exports.string(), line: external_exports.number().int().positive(), endLine: external_exports.number().int().positive().optional() }).strict();
21100
+ CodeNavTextHit = external_exports.object({ path: external_exports.string(), line: external_exports.number().int().positive(), text: external_exports.string() }).strict();
21101
+ CodeFindAnswer = CodeNavMeta.extend({
21102
+ source: external_exports.enum(["index", "search"]),
21103
+ matches: external_exports.array(CodeNavSymbol),
21104
+ more: external_exports.boolean(),
21105
+ /** Literal-search lines, when the index could not answer. */
21106
+ lines: external_exports.array(CodeNavTextHit).optional()
21107
+ }).strict();
21108
+ CodeOutlineAnswer = CodeNavMeta.extend({
21109
+ path: external_exports.string(),
21110
+ source: external_exports.enum(["index", "pattern"]),
21111
+ symbols: external_exports.array(external_exports.object({ line: external_exports.number().int().positive(), kind: external_exports.string(), name: external_exports.string() }).strict())
21112
+ }).strict();
21113
+ CodeRefsAnswer = CodeNavMeta.extend({
21114
+ name: external_exports.string(),
21115
+ source: external_exports.enum(["index", "search"]),
21116
+ callers: external_exports.array(CodeNavSymbol),
21117
+ matches: external_exports.array(CodeNavTextHit),
21118
+ skippedImports: external_exports.number().int().nonnegative(),
21119
+ more: external_exports.number().int().nonnegative()
21120
+ }).strict();
21121
+ CodeSpanAnswer = CodeNavMeta.extend({
21122
+ found: external_exports.boolean(),
21123
+ path: external_exports.string(),
21124
+ kind: external_exports.string(),
21125
+ qualified: external_exports.string(),
21126
+ start: external_exports.number().int().nonnegative(),
21127
+ end: external_exports.number().int().nonnegative(),
21128
+ /** Other definitions of the same name, best first. */
21129
+ also: external_exports.array(CodeNavSymbol)
21130
+ }).strict();
21131
+ }
21132
+ });
21133
+
21134
+ // ../contracts/src/code-overlay.ts
21135
+ var NAV_TOOLS, NavTool, CodeShowAnswer, OVERLAY_TTL_MS, OVERLAY_MAX_FILES, OVERLAY_MAX_SYMBOLS_PER_FILE, OVERLAY_MAX_BYTES, SessionName, OverlayFile, OverlayPut, OverlayAck, OverlaySummary;
21136
+ var init_code_overlay = __esm({
21137
+ "../contracts/src/code-overlay.ts"() {
21138
+ "use strict";
21139
+ init_zod();
21140
+ init_common();
21141
+ init_code_index();
21142
+ init_code_nav();
21143
+ NAV_TOOLS = ["find", "outline", "refs", "span"];
21144
+ NavTool = external_exports.enum(NAV_TOOLS);
21145
+ CodeShowAnswer = CodeNavMeta.extend({
21146
+ path: external_exports.string(),
21147
+ start: external_exports.number().int().positive(),
21148
+ end: external_exports.number().int().nonnegative(),
21149
+ text: external_exports.string(),
21150
+ truncated: external_exports.boolean().optional()
21151
+ }).strict();
21152
+ OVERLAY_TTL_MS = 24 * 60 * 60 * 1e3;
21153
+ OVERLAY_MAX_FILES = 500;
21154
+ OVERLAY_MAX_SYMBOLS_PER_FILE = 2e3;
21155
+ OVERLAY_MAX_BYTES = 1024 * 1024;
21156
+ SessionName = external_exports.string().regex(/^[A-Za-z0-9._-]{1,64}$/, "a session is 1 to 64 letters, digits, dots, dashes or underscores");
21157
+ OverlayFile = external_exports.object({
21158
+ path: external_exports.string().min(1).max(1024),
21159
+ language: external_exports.string().min(1).max(32),
21160
+ /** Hash of the dirty bytes; lets a client skip a repost of an unchanged file. */
21161
+ contentHash: Sha256Digest,
21162
+ symbols: external_exports.array(IndexedSymbol).max(OVERLAY_MAX_SYMBOLS_PER_FILE)
21163
+ }).strict();
21164
+ OverlayPut = external_exports.object({
21165
+ session: SessionName,
21166
+ branch: external_exports.string().min(1).max(255),
21167
+ baseCommit: CommitSha,
21168
+ files: external_exports.array(OverlayFile).max(OVERLAY_MAX_FILES).default([]),
21169
+ deleted: external_exports.array(external_exports.string().min(1).max(1024)).max(OVERLAY_MAX_FILES).default([]),
21170
+ clean: external_exports.array(external_exports.string().min(1).max(1024)).max(OVERLAY_MAX_FILES).default([]),
21171
+ replace: external_exports.boolean().default(false)
21172
+ }).strict();
21173
+ OverlayAck = external_exports.object({
21174
+ session: external_exports.string(),
21175
+ branch: external_exports.string(),
21176
+ baseCommit: CommitSha,
21177
+ files: external_exports.number().int().nonnegative(),
21178
+ tombstones: external_exports.number().int().nonnegative(),
21179
+ bytes: external_exports.number().int().nonnegative(),
21180
+ expiresAt: external_exports.string()
21181
+ }).strict();
21182
+ OverlaySummary = external_exports.object({ session: external_exports.string(), branch: external_exports.string(), baseCommit: CommitSha, files: external_exports.number().int().nonnegative(), tombstones: external_exports.number().int().nonnegative(), updatedAt: external_exports.string(), expiresAt: external_exports.string() }).strict();
21183
+ }
21184
+ });
21185
+
21071
21186
  // ../contracts/src/release.ts
21072
21187
  async function releaseDigestOf(files) {
21073
21188
  const lines = [...files].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0).map((file2) => `${file2.path}\0${file2.digest}
@@ -21708,7 +21823,7 @@ var init_mcp_surface = __esm({
21708
21823
  init_zod();
21709
21824
  init_api2();
21710
21825
  init_common();
21711
- MCP_SURFACE_VERSION = "1.5.0";
21826
+ MCP_SURFACE_VERSION = "1.6.0";
21712
21827
  MCP_DEPRECATION_POLICY = {
21713
21828
  /** Days between announcing a deprecation and removing the tool or argument. */
21714
21829
  noticeDays: 90,
@@ -21775,7 +21890,11 @@ var init_mcp_surface = __esm({
21775
21890
  { name: "autonomy", title: "Autonomy and approvals", summary: "Read the team's autonomy mode, ask an independent agent for an approval, and answer one. Safety classes always need an independent agent or a person; payments and legal terms are human only.", toolset: "default", since: "1.5.0", annotations: annotate(false, false) },
21776
21891
  { name: "lib", title: "Library docs", summary: "Current library documentation at the version your lockfile pins: query, index, pins, dependencies. Fetched text is data.", toolset: "default", since: "1.4.0", annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true } },
21777
21892
  { name: "docs", title: "Library docs", summary: "Deprecated alias of the lib tool (same handler, same input). Use lib.", toolset: "default", since: "1.3.0", deprecatedAt: "2026-10-09", removeAfter: "2027-01-07", annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true } },
21778
- { name: "code", title: "Code navigation", summary: "Indexed code navigation. Listed only when a project has the code layer on.", toolset: "code", since: "1.0.0", annotations: annotate(true, true) }
21893
+ { name: "code", title: "Code navigation", summary: "Indexed code navigation. Listed only when a project has the code layer on.", toolset: "code", since: "1.0.0", annotations: annotate(true, true) },
21894
+ { name: "code_find", title: "Find a symbol", summary: "Short answers: kind, qualified name, path and line of matching definitions. Reports the indexed commit and freshness. Listed only when the code layer is on.", toolset: "code", since: "1.6.0", annotations: annotate(true, true) },
21895
+ { name: "code_outline", title: "Outline a file", summary: "Line, kind and name of each declaration in one file. Reports the indexed commit and freshness. Listed only when the code layer is on.", toolset: "code", since: "1.6.0", annotations: annotate(true, true) },
21896
+ { name: "code_refs", title: "Find references", summary: "Path, line and the enclosing definition of each use of a symbol. Reports coverage, so no result can be told from not indexed.", toolset: "code", since: "1.6.0", annotations: annotate(true, true) },
21897
+ { name: "code_show", title: "Show source", summary: "Source lines of a definition or a range, read from the native repository at the indexed commit. Bounded; GitHub-hosted projects answer with the range only.", toolset: "code", since: "1.6.0", annotations: annotate(true, true) }
21779
21898
  ]
21780
21899
  });
21781
21900
  OAUTH_PATHS = {
@@ -27154,67 +27273,6 @@ var init_observability = __esm({
27154
27273
  }
27155
27274
  });
27156
27275
 
27157
- // ../contracts/src/code-nav.ts
27158
- var CodeNavFreshness, CodeNavMeta, CodeNavSymbol, CodeNavTextHit, CodeFindAnswer, CodeOutlineAnswer, CodeRefsAnswer, CodeSpanAnswer;
27159
- var init_code_nav = __esm({
27160
- "../contracts/src/code-nav.ts"() {
27161
- "use strict";
27162
- init_zod();
27163
- CodeNavFreshness = external_exports.enum(["fresh", "partial", "stale", "unavailable"]);
27164
- CodeNavMeta = external_exports.object({
27165
- /** The commit the index describes; null with no index. */
27166
- indexedCommit: external_exports.string().nullable(),
27167
- /** The commit the caller asked about (the checkout's HEAD for the local source); null when unknown. */
27168
- requestedCommit: external_exports.string().nullable(),
27169
- coverage: external_exports.object({
27170
- /** Files the index parsed. */
27171
- files: external_exports.number().int().nonnegative(),
27172
- symbols: external_exports.number().int().nonnegative(),
27173
- /** Files that could not be parsed (unsupported language, too large). */
27174
- uncovered: external_exports.number().int().nonnegative(),
27175
- /** Files that differ between the indexed and the requested commit; their answers come from a pattern scan or are missing. */
27176
- changedSinceIndex: external_exports.number().int().nonnegative()
27177
- }).strict(),
27178
- freshness: CodeNavFreshness,
27179
- /** True when an empty or short answer may be missing results (stale, partial or uncovered files), as opposed to a certain "no match". */
27180
- incomplete: external_exports.boolean(),
27181
- notice: external_exports.string().optional()
27182
- }).strict();
27183
- CodeNavSymbol = external_exports.object({ kind: external_exports.string(), qualified: external_exports.string(), path: external_exports.string(), line: external_exports.number().int().positive(), endLine: external_exports.number().int().positive().optional() }).strict();
27184
- CodeNavTextHit = external_exports.object({ path: external_exports.string(), line: external_exports.number().int().positive(), text: external_exports.string() }).strict();
27185
- CodeFindAnswer = CodeNavMeta.extend({
27186
- source: external_exports.enum(["index", "search"]),
27187
- matches: external_exports.array(CodeNavSymbol),
27188
- more: external_exports.boolean(),
27189
- /** Literal-search lines, when the index could not answer. */
27190
- lines: external_exports.array(CodeNavTextHit).optional()
27191
- }).strict();
27192
- CodeOutlineAnswer = CodeNavMeta.extend({
27193
- path: external_exports.string(),
27194
- source: external_exports.enum(["index", "pattern"]),
27195
- symbols: external_exports.array(external_exports.object({ line: external_exports.number().int().positive(), kind: external_exports.string(), name: external_exports.string() }).strict())
27196
- }).strict();
27197
- CodeRefsAnswer = CodeNavMeta.extend({
27198
- name: external_exports.string(),
27199
- source: external_exports.enum(["index", "search"]),
27200
- callers: external_exports.array(CodeNavSymbol),
27201
- matches: external_exports.array(CodeNavTextHit),
27202
- skippedImports: external_exports.number().int().nonnegative(),
27203
- more: external_exports.number().int().nonnegative()
27204
- }).strict();
27205
- CodeSpanAnswer = CodeNavMeta.extend({
27206
- found: external_exports.boolean(),
27207
- path: external_exports.string(),
27208
- kind: external_exports.string(),
27209
- qualified: external_exports.string(),
27210
- start: external_exports.number().int().nonnegative(),
27211
- end: external_exports.number().int().nonnegative(),
27212
- /** Other definitions of the same name, best first. */
27213
- also: external_exports.array(CodeNavSymbol)
27214
- }).strict();
27215
- }
27216
- });
27217
-
27218
27276
  // ../contracts/src/index.ts
27219
27277
  var init_src = __esm({
27220
27278
  "../contracts/src/index.ts"() {
@@ -27229,6 +27287,7 @@ var init_src = __esm({
27229
27287
  init_api2();
27230
27288
  init_task_api();
27231
27289
  init_code_index();
27290
+ init_code_overlay();
27232
27291
  init_release();
27233
27292
  init_kit();
27234
27293
  init_identity();
@@ -34619,7 +34678,7 @@ var VERSION;
34619
34678
  var init_assets = __esm({
34620
34679
  "src/assets.ts"() {
34621
34680
  "use strict";
34622
- VERSION = true ? "0.1.141" : "0.0.0-dev";
34681
+ VERSION = true ? "0.1.143" : "0.0.0-dev";
34623
34682
  }
34624
34683
  });
34625
34684
 
@@ -42292,33 +42351,7 @@ ${JSON.stringify(symbolNames, null, 2)}`);
42292
42351
  }
42293
42352
  });
42294
42353
 
42295
- // ../index-builder/src/treesitter.ts
42296
- import { createHash as createHash5 } from "node:crypto";
42297
- import { createRequire } from "node:module";
42298
- function ensureInit() {
42299
- initialised ??= Parser.init({ locateFile: (name2) => assetFile(name2) });
42300
- return initialised;
42301
- }
42302
- function parserFor(language) {
42303
- let cached2 = parsers.get(language);
42304
- if (!cached2) {
42305
- const grammar = GRAMMAR_FILES[language];
42306
- if (!grammar) throw new Error(`no grammar for ${language}`);
42307
- cached2 = (async () => {
42308
- await ensureInit();
42309
- const loaded2 = await Language2.load(assetFile(grammar));
42310
- const parser = new Parser();
42311
- parser.setLanguage(loaded2);
42312
- return parser;
42313
- })();
42314
- parsers.set(language, cached2);
42315
- cached2.catch(() => parsers.delete(language));
42316
- }
42317
- return cached2;
42318
- }
42319
- function sha256Of2(content) {
42320
- return `sha256:${createHash5("sha256").update(content, "utf8").digest("hex")}`;
42321
- }
42354
+ // ../index-builder/src/treesitter-core.ts
42322
42355
  function rangeOf(node2) {
42323
42356
  return [node2.startPosition.row, node2.startPosition.column, node2.endPosition.row, node2.endPosition.column];
42324
42357
  }
@@ -42352,12 +42385,9 @@ function collect(extract, nodes, scope, parentId, prefix, path, symbols2, occurr
42352
42385
  }
42353
42386
  }
42354
42387
  }
42355
- async function parseDeclarations(path, content) {
42356
- const language = languageForPath(path);
42357
- if (language === null) return null;
42388
+ function extractShard(path, language, content, contentHash, parser) {
42358
42389
  const extract = EXTRACTORS[language];
42359
42390
  if (!extract) return null;
42360
- const parser = await parserFor(language);
42361
42391
  const tree = parser.parse(content);
42362
42392
  if (!tree) throw new Error(`tree-sitter could not parse ${path}`);
42363
42393
  try {
@@ -42367,7 +42397,7 @@ async function parseDeclarations(path, content) {
42367
42397
  return {
42368
42398
  schemaVersion: "1",
42369
42399
  path,
42370
- contentHash: sha256Of2(content),
42400
+ contentHash,
42371
42401
  language,
42372
42402
  precision: "declaration",
42373
42403
  symbols: [...symbols2.values()].sort((a, b) => compareRanges(a.range, b.range)),
@@ -42377,23 +42407,14 @@ async function parseDeclarations(path, content) {
42377
42407
  tree.delete();
42378
42408
  }
42379
42409
  }
42380
- var GRAMMAR_FILES, require2, initialised, parsers, NAME_NODE_TYPES, TS_FUNCTIONS, TS_CLASSES, TS_METHODS, TS_PROPERTIES, FUNCTION_VALUES, typescriptDecls, pythonDecls, ZIG_STRUCTS, zigDecls, EXTRACTORS;
42381
- var init_treesitter = __esm({
42382
- "../index-builder/src/treesitter.ts"() {
42410
+ var MAX_PARSE_BYTES, TREE_SITTER_INDEXER, NAME_NODE_TYPES, TS_FUNCTIONS, TS_CLASSES, TS_METHODS, TS_PROPERTIES, FUNCTION_VALUES, typescriptDecls, pythonDecls, ZIG_STRUCTS, zigDecls, EXTRACTORS;
42411
+ var init_treesitter_core = __esm({
42412
+ "../index-builder/src/treesitter-core.ts"() {
42383
42413
  "use strict";
42384
- init_assets();
42385
- init_web_tree_sitter();
42386
42414
  init_languages();
42387
42415
  init_ranges();
42388
- GRAMMAR_FILES = {
42389
- typescript: "@vscode/tree-sitter-wasm/wasm/tree-sitter-typescript.wasm",
42390
- tsx: "@vscode/tree-sitter-wasm/wasm/tree-sitter-tsx.wasm",
42391
- javascript: "@vscode/tree-sitter-wasm/wasm/tree-sitter-javascript.wasm",
42392
- python: "@vscode/tree-sitter-wasm/wasm/tree-sitter-python.wasm",
42393
- zig: "@tree-sitter-grammars/tree-sitter-zig/tree-sitter-zig.wasm"
42394
- };
42395
- require2 = createRequire(import.meta.url);
42396
- parsers = /* @__PURE__ */ new Map();
42416
+ MAX_PARSE_BYTES = 2e6;
42417
+ TREE_SITTER_INDEXER = { name: "web-tree-sitter", version: "0.27.0" };
42397
42418
  NAME_NODE_TYPES = /* @__PURE__ */ new Set(["identifier", "type_identifier", "property_identifier", "private_property_identifier", "nested_identifier"]);
42398
42419
  TS_FUNCTIONS = /* @__PURE__ */ new Set(["function_declaration", "generator_function_declaration", "function_signature"]);
42399
42420
  TS_CLASSES = /* @__PURE__ */ new Set(["class_declaration", "abstract_class_declaration"]);
@@ -42544,6 +42565,59 @@ var init_treesitter = __esm({
42544
42565
  }
42545
42566
  });
42546
42567
 
42568
+ // ../index-builder/src/treesitter.ts
42569
+ import { createHash as createHash5 } from "node:crypto";
42570
+ import { createRequire } from "node:module";
42571
+ function ensureInit() {
42572
+ initialised ??= Parser.init({ locateFile: (name2) => assetFile(name2) });
42573
+ return initialised;
42574
+ }
42575
+ function parserFor(language) {
42576
+ let cached2 = parsers.get(language);
42577
+ if (!cached2) {
42578
+ const grammar = GRAMMAR_FILES[language];
42579
+ if (!grammar) throw new Error(`no grammar for ${language}`);
42580
+ cached2 = (async () => {
42581
+ await ensureInit();
42582
+ const loaded2 = await Language2.load(assetFile(grammar));
42583
+ const parser = new Parser();
42584
+ parser.setLanguage(loaded2);
42585
+ return parser;
42586
+ })();
42587
+ parsers.set(language, cached2);
42588
+ cached2.catch(() => parsers.delete(language));
42589
+ }
42590
+ return cached2;
42591
+ }
42592
+ function sha256Of2(content) {
42593
+ return `sha256:${createHash5("sha256").update(content, "utf8").digest("hex")}`;
42594
+ }
42595
+ async function parseDeclarations(path, content) {
42596
+ const language = languageForPath(path);
42597
+ if (language === null) return null;
42598
+ const parser = await parserFor(language);
42599
+ return extractShard(path, language, content, sha256Of2(content), parser);
42600
+ }
42601
+ var GRAMMAR_FILES, require2, initialised, parsers;
42602
+ var init_treesitter = __esm({
42603
+ "../index-builder/src/treesitter.ts"() {
42604
+ "use strict";
42605
+ init_assets();
42606
+ init_web_tree_sitter();
42607
+ init_languages();
42608
+ init_treesitter_core();
42609
+ GRAMMAR_FILES = {
42610
+ typescript: "@vscode/tree-sitter-wasm/wasm/tree-sitter-typescript.wasm",
42611
+ tsx: "@vscode/tree-sitter-wasm/wasm/tree-sitter-tsx.wasm",
42612
+ javascript: "@vscode/tree-sitter-wasm/wasm/tree-sitter-javascript.wasm",
42613
+ python: "@vscode/tree-sitter-wasm/wasm/tree-sitter-python.wasm",
42614
+ zig: "@tree-sitter-grammars/tree-sitter-zig/tree-sitter-zig.wasm"
42615
+ };
42616
+ require2 = createRequire(import.meta.url);
42617
+ parsers = /* @__PURE__ */ new Map();
42618
+ }
42619
+ });
42620
+
42547
42621
  // ../index-builder/src/snapshot.ts
42548
42622
  import { execFile as execFile2 } from "node:child_process";
42549
42623
  import { createHash as createHash6 } from "node:crypto";
@@ -42642,7 +42716,7 @@ async function buildSnapshot(options) {
42642
42716
  function compareStrings(a, b) {
42643
42717
  return a < b ? -1 : a > b ? 1 : 0;
42644
42718
  }
42645
- var execFileAsync, MAX_PARSE_BYTES, TREE_SITTER_INDEXER;
42719
+ var execFileAsync;
42646
42720
  var init_snapshot = __esm({
42647
42721
  "../index-builder/src/snapshot.ts"() {
42648
42722
  "use strict";
@@ -42650,13 +42724,27 @@ var init_snapshot = __esm({
42650
42724
  init_languages();
42651
42725
  init_scip();
42652
42726
  init_treesitter();
42727
+ init_treesitter_core();
42653
42728
  execFileAsync = promisify(execFile2);
42654
- MAX_PARSE_BYTES = 2e6;
42655
- TREE_SITTER_INDEXER = { name: "web-tree-sitter", version: "0.27.0" };
42656
42729
  }
42657
42730
  });
42658
42731
 
42659
42732
  // ../index-builder/src/upload.ts
42733
+ function refusalHint(status, body2) {
42734
+ let code2 = "";
42735
+ try {
42736
+ code2 = String(JSON.parse(body2).error?.code ?? "");
42737
+ } catch {
42738
+ }
42739
+ if (status === 401) return "the service did not accept the credential; an Actions token needs permissions: id-token: write and an audience equal to the service origin (scheme and host, no path)";
42740
+ if (status === 403 && code2 === "insufficient_scope") return "the token cannot write; mint one that includes harness:write";
42741
+ if (status === 403) return "the repository is not a connected project of this tenant, or the tenant is wrong; check HARNESS_TENANT (gh-<repository owner id>) and that the project has this repository";
42742
+ if (status === 404 && code2 === "code_layer_off") return "the project has the code layer off; turn it on for the project, then run the upload again";
42743
+ if (status === 404 && code2 === "not_found") return "no such project in this tenant";
42744
+ if (status === 409) return "shards are missing at publish; run the upload again";
42745
+ if (status === 413) return "the request was larger than the service accepts";
42746
+ return null;
42747
+ }
42660
42748
  async function uploadSnapshot(options) {
42661
42749
  const doFetch = options.fetch ?? fetch;
42662
42750
  const base5 = options.serviceUrl.replace(/\/+$/, "");
@@ -42673,7 +42761,10 @@ async function uploadSnapshot(options) {
42673
42761
  if (response.ok) return response;
42674
42762
  const retryable = response.status === 429 || response.status >= 500;
42675
42763
  if (!retryable || attempt2 >= ATTEMPTS) {
42676
- throw new HttpError(`POST ${path} failed with status ${response.status}: ${(await response.text()).slice(0, 300)}`);
42764
+ const text = await response.text();
42765
+ const hint = refusalHint(response.status, text);
42766
+ throw new HttpError(`POST ${path} failed with status ${response.status}: ${text.slice(0, 300)}${hint === null ? "" : `
42767
+ ${hint}`}`);
42677
42768
  }
42678
42769
  failure4 = `status ${response.status}`;
42679
42770
  } catch (error62) {
@@ -43220,6 +43311,13 @@ import { mkdir as mkdir4, readdir as readdir4, rm as rm2, writeFile as writeFile
43220
43311
  import { join as join34, resolve as resolve18 } from "node:path";
43221
43312
  import { parseArgs as parseArgs2 } from "node:util";
43222
43313
  import { promisify as promisify3 } from "node:util";
43314
+ function originOf(url2) {
43315
+ try {
43316
+ return new URL(url2).origin;
43317
+ } catch {
43318
+ throw new UsageError2(`--service must be a URL, got "${url2}"`);
43319
+ }
43320
+ }
43223
43321
  async function git6(root, args2) {
43224
43322
  const { stdout } = await execFileAsync3("git", args2, { cwd: root, encoding: "utf8" });
43225
43323
  return stdout.trim();
@@ -43244,7 +43342,7 @@ async function snapshotFromArgs(values, env) {
43244
43342
  const repoText = projectId !== void 0 ? typeof values["repo"] === "string" ? values["repo"] : void 0 : (typeof values["repo"] === "string" ? values["repo"] : void 0) ?? env["GITHUB_REPOSITORY"] ?? await repositoryFromRemote(root);
43245
43343
  if (!repoText && projectId === void 0) throw new UsageError2("cannot determine the repository; pass --project ID, or --repo owner/name");
43246
43344
  const commit = (typeof values["commit"] === "string" ? values["commit"] : void 0) ?? env["GITHUB_SHA"] ?? await git6(root, ["rev-parse", "HEAD"]);
43247
- const branch = typeof values["branch"] === "string" ? values["branch"] : void 0;
43345
+ const branch = (typeof values["branch"] === "string" ? values["branch"] : void 0) ?? (env["GITHUB_REF_TYPE"] === "branch" ? env["GITHUB_REF_NAME"] : void 0);
43248
43346
  const tenant = (typeof values["tenant"] === "string" ? values["tenant"] : void 0) ?? env["HARNESS_TENANT"];
43249
43347
  if (!tenant) throw new UsageError2("missing --tenant (or HARNESS_TENANT)");
43250
43348
  const scip = Array.isArray(values["scip"]) ? values["scip"] : [];
@@ -43283,7 +43381,7 @@ async function runCli2(argv, env, out2 = console.log, err2 = console.error) {
43283
43381
  if (!service) throw new UsageError2("upload needs --service URL");
43284
43382
  const built = await snapshotFromArgs(values, env);
43285
43383
  const byProject = values.project !== void 0;
43286
- const token = !byProject && env["ACTIONS_ID_TOKEN_REQUEST_URL"] ? await getOidcToken(values.audience ?? service, env) : env["HARNESS_TOKEN"];
43384
+ const token = !byProject && env["ACTIONS_ID_TOKEN_REQUEST_URL"] ? await getOidcToken(values.audience ?? originOf(service), env) : env["HARNESS_TOKEN"];
43287
43385
  if (!token) throw new UsageError2(byProject ? "no credentials: set HARNESS_TOKEN" : "no credentials: run in GitHub Actions with id-token: write, or set HARNESS_TOKEN");
43288
43386
  const result = await uploadSnapshot({ serviceUrl: service, token, manifest: built.manifest, shards: built.shards, ...byProject ? { byProject: true } : {} });
43289
43387
  out2(`published ${built.manifest.commitSha}: ${built.shards.length} shards, ${result.missing} new, ${result.batches} batches`);
@@ -72303,6 +72401,7 @@ function assertionLines(block2) {
72303
72401
  const more = changed.length > 0 ? changed : rest;
72304
72402
  return [message, ...more.slice(0, 2)].map((l) => clip(l, 200));
72305
72403
  }
72404
+ var STRAY_FAIL = /\bFAIL\s+(\S+\.(?:test|spec)\.[cm]?[jt]sx?\s+>.+)$/;
72306
72405
  function parseVitest(output2) {
72307
72406
  const lines = stripAnsi(output2).split("\n");
72308
72407
  const { groups, prefixed: prefixed2 } = groupByPackage(lines);
@@ -72313,7 +72412,8 @@ function parseVitest(output2) {
72313
72412
  const block2 = parseVitestBlock(list2, name2);
72314
72413
  if (block2 !== null) packages.push(block2);
72315
72414
  }
72316
- if (packages.length === 0) return null;
72415
+ const strayAll = [...new Set(lines.map((l) => l.match(STRAY_FAIL)?.[1]?.trim()).filter((n) => n !== void 0))];
72416
+ if (packages.length === 0 && strayAll.length === 0) return null;
72317
72417
  const out2 = [];
72318
72418
  let explains = false;
72319
72419
  let failedTests = 0;
@@ -72344,7 +72444,12 @@ function parseVitest(output2) {
72344
72444
  if (p2.failures.length > MAX_FAILURES) out2.push(`+${p2.failures.length - MAX_FAILURES} more failing tests in the log`);
72345
72445
  }
72346
72446
  if (packages.length > 1) out2.push(`total: tests ${tot.passed} passed${tot.failed > 0 ? ` ${tot.failed} FAILED` : ""}${tot.skipped > 0 ? ` ${tot.skipped} skipped` : ""} in ${packages.length} packages`);
72347
- return { kind: "vitest", lines: out2, explains, data: { packages, failedTests } };
72447
+ const known = new Set(packages.flatMap((p2) => p2.failures.map((f) => f.name)));
72448
+ const stray = strayAll.filter((n) => ![...known].some((k) => n.endsWith(k) || k.endsWith(n)));
72449
+ for (const name2 of stray.slice(0, MAX_FAILURES)) out2.push(`FAIL ${name2}`);
72450
+ if (stray.length > MAX_FAILURES) out2.push(`+${stray.length - MAX_FAILURES} more failing tests in the log`);
72451
+ if (stray.length > 0) explains = true;
72452
+ return { kind: "vitest", lines: out2, explains, data: { packages, failedTests: failedTests + stray.length } };
72348
72453
  }
72349
72454
  var TSC_PLAIN = /^(.+?)\((\d+),(\d+)\): error (TS\d+): (.*)$/;
72350
72455
  var TSC_PRETTY = /^(.+?):(\d+):(\d+) - error (TS\d+): (.*)$/;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlane",
3
- "version": "0.1.141",
3
+ "version": "0.1.143",
4
4
  "description": "Overlane: connect a GitHub project to your coding agents. One portable CLI with project memory, tasks, a code index, guardrails and the Claude Code and Codex plugin.",
5
5
  "keywords": [
6
6
  "overlane",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mvrx-harness",
3
- "version": "0.1.141",
3
+ "version": "0.1.143",
4
4
  "description": "Overlane context at session start and the shared Overlane skills.",
5
5
  "author": {
6
6
  "name": "owenob1"