overlane 0.1.153 → 0.1.155

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 (26) hide show
  1. package/dist/overlane-full.mjs +445 -406
  2. package/dist/overlane.mjs +25373 -361
  3. package/package.json +1 -1
  4. package/plugins/.claude-plugin/marketplace.json +2 -1
  5. package/plugins/claude/.claude-plugin/marketplace.json +2 -1
  6. package/plugins/claude/plugins/overlane/.claude-plugin/plugin.json +3 -2
  7. package/plugins/claude/plugins/overlane/scripts/harness-codemap.mjs +20 -18
  8. package/plugins/claude/plugins/overlane/scripts/harness-context.mjs +23 -21
  9. package/plugins/claude/plugins/overlane/scripts/harness-guard.mjs +14 -14
  10. package/plugins/claude/plugins/overlane/scripts/harness-intake.mjs +24 -22
  11. package/plugins/claude/plugins/overlane/scripts/harness-overlay.mjs +19 -17
  12. package/plugins/claude/plugins/overlane/scripts/harness-quota.mjs +17 -17
  13. package/plugins/claude/plugins/overlane/scripts/harness-statusline.mjs +11 -11
  14. package/plugins/claude/plugins/overlane/scripts/harness-stop.mjs +22 -20
  15. package/plugins/claude/plugins/overlane/skills/run-step/SKILL.md +4 -4
  16. package/plugins/codex/plugins/overlane/.codex-plugin/plugin.json +4 -3
  17. package/plugins/codex/plugins/overlane/scripts/harness-codemap.mjs +20 -18
  18. package/plugins/codex/plugins/overlane/scripts/harness-context.mjs +23 -21
  19. package/plugins/codex/plugins/overlane/scripts/harness-guard.mjs +14 -14
  20. package/plugins/codex/plugins/overlane/scripts/harness-intake.mjs +24 -22
  21. package/plugins/codex/plugins/overlane/scripts/harness-overlay.mjs +19 -17
  22. package/plugins/codex/plugins/overlane/scripts/harness-quota.mjs +17 -17
  23. package/plugins/codex/plugins/overlane/scripts/harness-statusline.mjs +11 -11
  24. package/plugins/codex/plugins/overlane/scripts/harness-stop.mjs +22 -20
  25. package/plugins/codex/plugins/overlane/skills/run-step/SKILL.md +4 -4
  26. package/plugins/release-manifest.json +35 -36
@@ -20650,11 +20650,11 @@ var init_clients = __esm({
20650
20650
  // ../contracts/src/code-map.ts
20651
20651
  function codeMapDefault(setting, results = GATE_07_LATEST) {
20652
20652
  const result = results[setting];
20653
- if (result.verdict === "failed") return { setting, on: false, basis: "gate-07-failed", reason: `off: ${result.summary} (${result.evidence})`, gate07: "failed" };
20654
- if (result.verdict === "passed") return { setting, on: true, basis: "gate-07-passed", reason: `on: ${result.summary} (${result.evidence})`, gate07: "passed" };
20653
+ if (result.verdict === "failed") return { setting, on: false, basis: "gate-07-failed", reason: `off: ${result.summary}`, gate07: "failed" };
20654
+ if (result.verdict === "passed") return { setting, on: true, basis: "gate-07-passed", reason: `on: ${result.summary}`, gate07: "passed" };
20655
20655
  const on = SPEC_DEFAULT[setting];
20656
20656
  if (result.verdict === "pending") {
20657
- return { setting, on, basis: "spec-default-provisional", reason: `${on ? "on" : "off"} by the spec default, provisional: ${result.summary} (${result.evidence})`, gate07: "pending" };
20657
+ return { setting, on, basis: "spec-default-provisional", reason: `${on ? "on" : "off"} by the spec default, provisional: ${result.summary}`, gate07: "pending" };
20658
20658
  }
20659
20659
  return { setting, on, basis: "spec-default", reason: `${on ? "on" : "off"} by the spec default: ${result.summary}`, gate07: "not-applicable" };
20660
20660
  }
@@ -20672,22 +20672,19 @@ var init_code_map = __esm({
20672
20672
  GATE_07_LATEST = {
20673
20673
  "local-agent-with-grep": {
20674
20674
  verdict: "failed",
20675
- summary: "GATE-07 failed with a local checkout and grep: cueline 115% and afltables 109% of the native-search token cost",
20676
- evidence: "ADR 0018, docs/findings/gate-07-preliminary.md, docs/findings/gate-07-realism-afltables.md"
20675
+ summary: "measured with a local checkout and grep, the code tools cost more tokens (109% to 115%) than the agent's own search"
20677
20676
  },
20678
20677
  "cloud-session": {
20679
20678
  verdict: "pending",
20680
- summary: "re-run for agents without a checkout: the mechanical leg is recorded, the agent leg waits on a model",
20681
- evidence: "docs/findings/MS-A5-results.md (MS-A5.6)"
20679
+ summary: "re-run for agents without a checkout: the mechanical leg is recorded, the agent leg waits on a model"
20682
20680
  },
20683
20681
  bot: {
20684
20682
  verdict: "pending",
20685
- summary: "re-run for agents without a checkout: the mechanical leg is recorded, the agent leg waits on a model",
20686
- evidence: "docs/findings/MS-A5-results.md (MS-A5.6)"
20683
+ summary: "re-run for agents without a checkout: the mechanical leg is recorded, the agent leg waits on a model"
20687
20684
  },
20688
- "review-service": { verdict: "not-applicable", summary: "the review service has no grep to compare with; it uses the map as context", evidence: "ADR 0032 decision 3" },
20689
- "cross-repo": { verdict: "not-applicable", summary: "cross-repository questions have no single checkout to search", evidence: "ADR 0032 decision 2" },
20690
- wiki: { verdict: "not-applicable", summary: "the generated wiki is built from the map", evidence: "ADR 0032 decision 3" }
20685
+ "review-service": { verdict: "not-applicable", summary: "the review service has no grep to compare with; it uses the map as context" },
20686
+ "cross-repo": { verdict: "not-applicable", summary: "cross-repository questions have no single checkout to search" },
20687
+ wiki: { verdict: "not-applicable", summary: "the generated wiki is built from the map" }
20691
20688
  };
20692
20689
  SPEC_DEFAULT = {
20693
20690
  "local-agent-with-grep": false,
@@ -23755,7 +23752,7 @@ var init_wording = __esm({
23755
23752
  });
23756
23753
 
23757
23754
  // ../contracts/src/code-map-context.ts
23758
- var CodeMapDigest, CODE_MAP_DIGEST_PATH, CODE_INDEX_PATH;
23755
+ var CodeMapDigest;
23759
23756
  var init_code_map_context = __esm({
23760
23757
  "../contracts/src/code-map-context.ts"() {
23761
23758
  "use strict";
@@ -23772,8 +23769,6 @@ var init_code_map_context = __esm({
23772
23769
  /** Qualified names of the symbols the ranking put first. */
23773
23770
  seeds: external_exports.array(external_exports.string())
23774
23771
  }).strict();
23775
- CODE_MAP_DIGEST_PATH = ".harness/code-map.json";
23776
- CODE_INDEX_PATH = ".harness/code-index.json";
23777
23772
  }
23778
23773
  });
23779
23774
 
@@ -27285,6 +27280,38 @@ var init_observability = __esm({
27285
27280
  }
27286
27281
  });
27287
27282
 
27283
+ // ../contracts/src/overlane-paths.ts
27284
+ function isStatePath(path) {
27285
+ const p2 = path.replace(/\\/g, "/");
27286
+ return p2 === STATE_DIR || p2.startsWith(`${STATE_DIR}/`);
27287
+ }
27288
+ var OVERLANE_DIR, STATE_DIR, PLAN_DIR, STATE_GITIGNORE, STATE_FILES;
27289
+ var init_overlane_paths = __esm({
27290
+ "../contracts/src/overlane-paths.ts"() {
27291
+ "use strict";
27292
+ OVERLANE_DIR = ".overlane";
27293
+ STATE_DIR = ".overlane/state";
27294
+ PLAN_DIR = ".overlane/plan";
27295
+ STATE_GITIGNORE = "# Written by overlane (ADR 0067): this folder is local state and is never committed.\n*\n";
27296
+ STATE_FILES = {
27297
+ binding: "project.json",
27298
+ owned: "owned.json",
27299
+ task: "task.json",
27300
+ taskPolicy: "task-policy.json",
27301
+ run: "run.json",
27302
+ release: "release.json",
27303
+ codeMap: "code-map.json",
27304
+ codeIndex: "code-index.json",
27305
+ codeMapSetting: "code-map-setting.json",
27306
+ codemapSessions: "codemap-sessions",
27307
+ overlay: "overlay",
27308
+ misses: "misses.log",
27309
+ ledger: "token-ledger.jsonl",
27310
+ logs: "logs"
27311
+ };
27312
+ }
27313
+ });
27314
+
27288
27315
  // ../contracts/src/index.ts
27289
27316
  var init_src = __esm({
27290
27317
  "../contracts/src/index.ts"() {
@@ -27338,6 +27365,36 @@ var init_src = __esm({
27338
27365
  init_enterprise();
27339
27366
  init_observability();
27340
27367
  init_code_nav();
27368
+ init_overlane_paths();
27369
+ }
27370
+ });
27371
+
27372
+ // ../contracts/src/overlane-paths-node.ts
27373
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
27374
+ import { join } from "node:path";
27375
+ function stateDir(root) {
27376
+ return join(root, STATE_DIR);
27377
+ }
27378
+ function statePath(root, file2, ...rest) {
27379
+ return join(root, STATE_DIR, STATE_FILES[file2], ...rest);
27380
+ }
27381
+ function ensureStateDir(root) {
27382
+ const dir = stateDir(root);
27383
+ mkdirSync2(dir, { recursive: true });
27384
+ const path = join(dir, ".gitignore");
27385
+ let current2;
27386
+ try {
27387
+ current2 = readFileSync2(path, "utf8");
27388
+ } catch {
27389
+ current2 = null;
27390
+ }
27391
+ if (current2 !== STATE_GITIGNORE) writeFileSync2(path, STATE_GITIGNORE);
27392
+ return dir;
27393
+ }
27394
+ var init_overlane_paths_node = __esm({
27395
+ "../contracts/src/overlane-paths-node.ts"() {
27396
+ "use strict";
27397
+ init_overlane_paths();
27341
27398
  }
27342
27399
  });
27343
27400
 
@@ -34672,7 +34729,7 @@ var require_dist = __commonJS({
34672
34729
  });
34673
34730
 
34674
34731
  // src/assets.ts
34675
- import { basename as basename5, join as join32, resolve as resolve17 } from "node:path";
34732
+ import { basename as basename5, join as join28, resolve as resolve17 } from "node:path";
34676
34733
  import { fileURLToPath } from "node:url";
34677
34734
  function packageRoot(env = process.env) {
34678
34735
  const override = env["OVERLANE_PACKAGE_ROOT"];
@@ -34681,16 +34738,16 @@ function packageRoot(env = process.env) {
34681
34738
  }
34682
34739
  function assetDir(env = process.env) {
34683
34740
  const override = env["OVERLANE_ASSET_DIR"];
34684
- return override !== void 0 && override !== "" ? override : join32(packageRoot(env), "assets");
34741
+ return override !== void 0 && override !== "" ? override : join28(packageRoot(env), "assets");
34685
34742
  }
34686
34743
  function assetFile(name2) {
34687
- return join32(assetDir(), basename5(name2));
34744
+ return join28(assetDir(), basename5(name2));
34688
34745
  }
34689
34746
  var VERSION;
34690
34747
  var init_assets = __esm({
34691
34748
  "src/assets.ts"() {
34692
34749
  "use strict";
34693
- VERSION = true ? "0.1.153" : "0.0.0-dev";
34750
+ VERSION = true ? "0.1.155" : "0.0.0-dev";
34694
34751
  }
34695
34752
  });
34696
34753
 
@@ -42634,7 +42691,7 @@ var init_treesitter = __esm({
42634
42691
  import { execFile as execFile2 } from "node:child_process";
42635
42692
  import { createHash as createHash6 } from "node:crypto";
42636
42693
  import { lstat, readFile as readFile4 } from "node:fs/promises";
42637
- import { join as join33 } from "node:path";
42694
+ import { join as join29 } from "node:path";
42638
42695
  import { promisify } from "node:util";
42639
42696
  function shardKeyOf(shard) {
42640
42697
  return `sha256:${sha256Hex2(Buffer.from(`${shard.path}\0${shard.contentHash}\0${shard.precision}`, "utf8"))}`;
@@ -42661,7 +42718,7 @@ async function mapLimit(items, limit, task) {
42661
42718
  return results;
42662
42719
  }
42663
42720
  async function hashRegularFile(repoRoot, path) {
42664
- const absolute = join33(repoRoot, path);
42721
+ const absolute = join29(repoRoot, path);
42665
42722
  try {
42666
42723
  const stats = await lstat(absolute);
42667
42724
  if (!stats.isFile()) return null;
@@ -42699,7 +42756,7 @@ async function buildSnapshot(options) {
42699
42756
  const needParse = [...hashes.keys()].filter((path) => !byPath.has(path));
42700
42757
  const parsed = await mapLimit(needParse, 8, async (path) => {
42701
42758
  if (languageForPath(path) === null) return { path, shard: null };
42702
- const bytes = await readFile4(join33(options.repoRoot, path));
42759
+ const bytes = await readFile4(join29(options.repoRoot, path));
42703
42760
  if (bytes.byteLength > MAX_PARSE_BYTES) return { path, shard: null };
42704
42761
  const hash2 = `sha256:${sha256Hex2(bytes)}`;
42705
42762
  if (hash2 !== hashes.get(path)) throw new Error(`${path} changed while the snapshot was being built`);
@@ -43255,7 +43312,7 @@ var init_context_map = __esm({
43255
43312
  // ../index-builder/src/context-map-build.ts
43256
43313
  import { execFile as execFile3 } from "node:child_process";
43257
43314
  import { mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
43258
- import { dirname as dirname11, join as join34 } from "node:path";
43315
+ import { dirname as dirname8, join as join30 } from "node:path";
43259
43316
  import { promisify as promisify2 } from "node:util";
43260
43317
  async function git5(root, args2) {
43261
43318
  const { stdout } = await execFileAsync2("git", args2, { cwd: root, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
@@ -43268,7 +43325,7 @@ async function buildArtifactsForCheckout(options) {
43268
43325
  for (const path of tracked) {
43269
43326
  if (languageForPath(path) === null) continue;
43270
43327
  try {
43271
- const bytes = await readFile5(join34(options.root, path));
43328
+ const bytes = await readFile5(join30(options.root, path));
43272
43329
  if (bytes.byteLength > MAX_PARSE_BYTES) {
43273
43330
  uncovered += 1;
43274
43331
  continue;
@@ -43292,15 +43349,16 @@ async function buildArtifactsForCheckout(options) {
43292
43349
  return { digest, indexFile };
43293
43350
  }
43294
43351
  async function writeIndexFile(root, indexFile) {
43295
- const path = join34(root, CODE_INDEX_PATH);
43296
- await mkdir3(dirname11(path), { recursive: true });
43352
+ ensureStateDir(root);
43353
+ const path = statePath(root, "codeIndex");
43297
43354
  await writeFile3(path, `${JSON.stringify(indexFile)}
43298
43355
  `);
43299
43356
  return path;
43300
43357
  }
43301
43358
  async function writeDigest(root, digest, out2) {
43302
- const path = out2 ?? join34(root, CODE_MAP_DIGEST_PATH);
43303
- await mkdir3(dirname11(path), { recursive: true });
43359
+ if (out2 === void 0) ensureStateDir(root);
43360
+ const path = out2 ?? statePath(root, "codeMap");
43361
+ await mkdir3(dirname8(path), { recursive: true });
43304
43362
  await writeFile3(path, `${JSON.stringify(digest)}
43305
43363
  `);
43306
43364
  return path;
@@ -43310,6 +43368,7 @@ var init_context_map_build = __esm({
43310
43368
  "../index-builder/src/context-map-build.ts"() {
43311
43369
  "use strict";
43312
43370
  init_src();
43371
+ init_overlane_paths_node();
43313
43372
  init_context_map();
43314
43373
  init_languages();
43315
43374
  init_snapshot();
@@ -43320,7 +43379,7 @@ var init_context_map_build = __esm({
43320
43379
  // ../index-builder/src/run.ts
43321
43380
  import { execFile as execFile4 } from "node:child_process";
43322
43381
  import { mkdir as mkdir4, readdir as readdir4, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
43323
- import { join as join35, resolve as resolve18 } from "node:path";
43382
+ import { join as join31, resolve as resolve18 } from "node:path";
43324
43383
  import { parseArgs as parseArgs2 } from "node:util";
43325
43384
  import { promisify as promisify3 } from "node:util";
43326
43385
  function originOf(url2) {
@@ -43411,13 +43470,13 @@ ${USAGE}`);
43411
43470
  }
43412
43471
  }
43413
43472
  async function writeSnapshot(dir, built) {
43414
- await mkdir4(join35(dir, "shards"), { recursive: true });
43415
- for (const name2 of await readdir4(join35(dir, "shards"))) await rm2(join35(dir, "shards", name2));
43416
- await writeFile4(join35(dir, "manifest.json"), JSON.stringify(built.manifest, null, 2));
43417
- await writeFile4(join35(dir, "uncovered.json"), JSON.stringify(built.uncovered, null, 2));
43473
+ await mkdir4(join31(dir, "shards"), { recursive: true });
43474
+ for (const name2 of await readdir4(join31(dir, "shards"))) await rm2(join31(dir, "shards", name2));
43475
+ await writeFile4(join31(dir, "manifest.json"), JSON.stringify(built.manifest, null, 2));
43476
+ await writeFile4(join31(dir, "uncovered.json"), JSON.stringify(built.uncovered, null, 2));
43418
43477
  for (const shard of built.shards) {
43419
43478
  const name2 = shardKeyOf(shard).slice("sha256:".length);
43420
- await writeFile4(join35(dir, "shards", `${name2}.json`), JSON.stringify(shard));
43479
+ await writeFile4(join31(dir, "shards", `${name2}.json`), JSON.stringify(shard));
43421
43480
  }
43422
43481
  }
43423
43482
  var execFileAsync3, USAGE, UsageError2, OPTIONS;
@@ -43435,7 +43494,7 @@ var init_run = __esm({
43435
43494
  overlane-index map [--root DIR] [--out FILE] [--task TEXT]
43436
43495
  overlane-index upload --service URL --tenant ID (--project ID | --repo owner/name) --commit SHA [--branch B] [--scip FILE ...] [--root DIR] [--audience URL]
43437
43496
 
43438
- map writes the ranked code map digest (default .harness/code-map.json in the root) that the session-start hook delivers as context (ADR 0055). No model; --task ranks by the words of a task.
43497
+ map writes the ranked code map digest (default .overlane/state/code-map.json in the root) that the session-start hook delivers as context (ADR 0055). No model; --task ranks by the words of a task.
43439
43498
  --project indexes an Overlane project (no GitHub repository needed) and uploads with OVERLANE_TOKEN.
43440
43499
  --repo names a GitHub repository; in GitHub Actions the OIDC token is used when ACTIONS_ID_TOKEN_REQUEST_URL is set.
43441
43500
  Authentication for upload: OVERLANE_TOKEN (always for --project), or the GitHub Actions OIDC token for --repo.
@@ -58263,8 +58322,8 @@ var init_cloud = __esm({
58263
58322
 
58264
58323
  // ../code-shim/src/git.ts
58265
58324
  import { execFileSync as execFileSync2 } from "node:child_process";
58266
- import { existsSync as existsSync14 } from "node:fs";
58267
- import { join as join39 } from "node:path";
58325
+ import { existsSync as existsSync15 } from "node:fs";
58326
+ import { join as join35 } from "node:path";
58268
58327
  function git7(root, args2) {
58269
58328
  try {
58270
58329
  return execFileSync2("git", args2, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], maxBuffer: 64 * 1024 * 1024, timeout: 1e4 });
@@ -58326,7 +58385,7 @@ function readWorkingCopyState(root) {
58326
58385
  const head = headCommit2(root);
58327
58386
  const raw = git7(root, ["status", "--porcelain=v2", "-z", "--untracked-files=all"]);
58328
58387
  if (raw === null) return { head, dirty: /* @__PURE__ */ new Set(), deleted: /* @__PURE__ */ new Set(), renamed: /* @__PURE__ */ new Map() };
58329
- return { head, ...parseStatus(raw, (path) => existsSync14(join39(root, path))) };
58388
+ return { head, ...parseStatus(raw, (path) => existsSync15(join35(root, path))) };
58330
58389
  }
58331
58390
  var init_git2 = __esm({
58332
58391
  "../code-shim/src/git.ts"() {
@@ -58335,18 +58394,18 @@ var init_git2 = __esm({
58335
58394
  });
58336
58395
 
58337
58396
  // ../code-shim/src/config.ts
58338
- import { readFileSync as readFileSync22 } from "node:fs";
58397
+ import { readFileSync as readFileSync23 } from "node:fs";
58339
58398
  import { homedir as homedir3 } from "node:os";
58340
- import { join as join40 } from "node:path";
58399
+ import { join as join36 } from "node:path";
58341
58400
  function configDir2(env) {
58342
- const base5 = env["XDG_CONFIG_HOME"] ?? (process.platform === "win32" ? env["APPDATA"] : void 0) ?? join40(homedir3(), ".config");
58343
- return join40(base5, "overlane");
58401
+ const base5 = env["XDG_CONFIG_HOME"] ?? (process.platform === "win32" ? env["APPDATA"] : void 0) ?? join36(homedir3(), ".config");
58402
+ return join36(base5, "overlane");
58344
58403
  }
58345
58404
  function findToken2(env, serviceUrl, now) {
58346
58405
  const fromEnv = env["OVERLANE_TOKEN"];
58347
58406
  if (fromEnv !== void 0 && fromEnv.length > 0) return fromEnv;
58348
58407
  try {
58349
- const file2 = JSON.parse(readFileSync22(join40(configDir2(env), "credentials.json"), "utf8"));
58408
+ const file2 = JSON.parse(readFileSync23(join36(configDir2(env), "credentials.json"), "utf8"));
58350
58409
  const stored = file2[serviceUrl];
58351
58410
  if (stored === void 0 || typeof stored.accessToken !== "string" || stored.accessToken.length === 0) return null;
58352
58411
  if (typeof stored.expiresAt === "number" && stored.expiresAt <= now) return null;
@@ -58358,7 +58417,7 @@ function findToken2(env, serviceUrl, now) {
58358
58417
  function resolveCloudConfig(root, env, now) {
58359
58418
  let binding;
58360
58419
  try {
58361
- const parsed = ProjectBinding.safeParse(JSON.parse(readFileSync22(join40(root, ".harness", "project.json"), "utf8")));
58420
+ const parsed = ProjectBinding.safeParse(JSON.parse(readFileSync23(statePath(root, "binding"), "utf8")));
58362
58421
  if (!parsed.success) return null;
58363
58422
  binding = parsed.data;
58364
58423
  } catch {
@@ -58376,11 +58435,12 @@ var init_config = __esm({
58376
58435
  "use strict";
58377
58436
  init_src();
58378
58437
  init_git2();
58438
+ init_overlane_paths_node();
58379
58439
  }
58380
58440
  });
58381
58441
 
58382
58442
  // ../code-shim/src/local.ts
58383
- import { readFileSync as readFileSync23, statSync as statSync4 } from "node:fs";
58443
+ import { readFileSync as readFileSync24, statSync as statSync4 } from "node:fs";
58384
58444
  import { isAbsolute as isAbsolute2, relative as relative5, resolve as resolve19, sep as sep2 } from "node:path";
58385
58445
  function resolveInside(root, path) {
58386
58446
  const absolute = resolve19(root, path);
@@ -58500,7 +58560,7 @@ var init_local = __esm({
58500
58560
  let shard;
58501
58561
  try {
58502
58562
  this.parses += 1;
58503
- shard = await this.parse(path, readFileSync23(absolute, "utf8"));
58563
+ shard = await this.parse(path, readFileSync24(absolute, "utf8"));
58504
58564
  } catch {
58505
58565
  shard = null;
58506
58566
  }
@@ -58512,7 +58572,7 @@ var init_local = __esm({
58512
58572
  const absolute = resolveInside(this.root, path);
58513
58573
  if (absolute === null) return null;
58514
58574
  try {
58515
- return readFileSync23(absolute, "utf8");
58575
+ return readFileSync24(absolute, "utf8");
58516
58576
  } catch {
58517
58577
  return null;
58518
58578
  }
@@ -58522,7 +58582,7 @@ var init_local = __esm({
58522
58582
  const absolute = resolveInside(this.root, path);
58523
58583
  if (absolute === null) return void 0;
58524
58584
  try {
58525
- const lines = readFileSync23(absolute, "utf8").split("\n");
58585
+ const lines = readFileSync24(absolute, "utf8").split("\n");
58526
58586
  const start2 = range[0];
58527
58587
  if (start2 >= lines.length) return void 0;
58528
58588
  const end = Math.min(Math.max(range[2], start2), start2 + maxLines - 1, lines.length - 1);
@@ -58749,7 +58809,7 @@ var init_nav = __esm({
58749
58809
 
58750
58810
  // ../code-shim/src/edit.ts
58751
58811
  import { createHash as createHash8 } from "node:crypto";
58752
- import { readFileSync as readFileSync24, writeFileSync as writeFileSync11 } from "node:fs";
58812
+ import { readFileSync as readFileSync25, writeFileSync as writeFileSync12 } from "node:fs";
58753
58813
  function lineStarts(text2) {
58754
58814
  const starts = [0];
58755
58815
  for (let i2 = 0; i2 < text2.length; i2 += 1) if (text2[i2] === "\n") starts.push(i2 + 1);
@@ -58790,7 +58850,7 @@ async function editSymbol(index, args2) {
58790
58850
  if (!found.ok) return found;
58791
58851
  const absolute = resolveInside(index.root, args2.path);
58792
58852
  if (absolute === null) return { ok: false, reason: `path ${args2.path} is outside the repository` };
58793
- const original = readFileSync24(absolute, "utf8");
58853
+ const original = readFileSync25(absolute, "utf8");
58794
58854
  const starts = lineStarts(original);
58795
58855
  const range = found.symbol.enclosingRange ?? found.symbol.range;
58796
58856
  const from = offsetOf(starts, original, range[0], range[1]);
@@ -58818,7 +58878,7 @@ ${args2.content.replace(/\n+$/, "")}`;
58818
58878
  const before = positionAt(next, changedStart);
58819
58879
  const after = positionAt(next, insertAt + inserted.length);
58820
58880
  const bytes = Buffer.from(next, "utf8");
58821
- writeFileSync11(absolute, bytes);
58881
+ writeFileSync12(absolute, bytes);
58822
58882
  return {
58823
58883
  ok: true,
58824
58884
  path: args2.path,
@@ -58857,7 +58917,7 @@ async function renameSymbol(deps, args2) {
58857
58917
  if (absolute === null) return { ok: false, reason: `reference path ${path} is outside the repository` };
58858
58918
  let text2;
58859
58919
  try {
58860
- text2 = readFileSync24(absolute, "utf8");
58920
+ text2 = readFileSync25(absolute, "utf8");
58861
58921
  } catch {
58862
58922
  return { ok: false, reason: `cannot read ${path}` };
58863
58923
  }
@@ -58879,7 +58939,7 @@ async function renameSymbol(deps, args2) {
58879
58939
  let next = item.text;
58880
58940
  for (const offset of offsets) next = next.slice(0, offset) + args2.new_name + next.slice(offset + oldName.length);
58881
58941
  const bytes = Buffer.from(next, "utf8");
58882
- writeFileSync11(item.absolute, bytes);
58942
+ writeFileSync12(item.absolute, bytes);
58883
58943
  filesChanged.push({ path: item.path, edits: offsets.length, sha256: sha2563(bytes) });
58884
58944
  edits += offsets.length;
58885
58945
  }
@@ -59165,7 +59225,6 @@ init_zod();
59165
59225
 
59166
59226
  // ../cli/src/binding.ts
59167
59227
  init_src();
59168
- import { join as join2 } from "node:path";
59169
59228
 
59170
59229
  // ../cli/src/files.ts
59171
59230
  import { chmodSync, mkdirSync, readFileSync, rmdirSync, rmSync, writeFileSync } from "node:fs";
@@ -59211,52 +59270,10 @@ function jsonText(value) {
59211
59270
  `;
59212
59271
  }
59213
59272
 
59214
- // ../cli/src/owned.ts
59215
- init_zod();
59216
- import { join } from "node:path";
59217
- var BINDING_FILE = join(".harness", "project.json");
59218
- var OWNED_FILE = join(".harness", "owned.json");
59219
- var CODEX_CONFIG_FILE = join(".codex", "config.toml");
59220
- var OwnedAgent = external_exports.object({ marketplace: external_exports.boolean(), plugin: external_exports.boolean() }).strict();
59221
- var OwnedConfigLines = external_exports.object({ text: external_exports.string().min(1), createdFile: external_exports.boolean() }).strict();
59222
- var Owned = external_exports.object({
59223
- version: external_exports.literal(1),
59224
- serviceUrl: external_exports.string().min(1),
59225
- marketplaceRoot: external_exports.string().min(1),
59226
- claude: OwnedAgent.optional(),
59227
- codex: OwnedAgent.extend({ configLines: OwnedConfigLines.optional() }).strict().optional(),
59228
- binding: external_exports.boolean(),
59229
- excludeLine: external_exports.boolean()
59230
- }).strict();
59231
- function readOwned(root) {
59232
- const parsed = Owned.safeParse(readJson(join(root, OWNED_FILE)));
59233
- return parsed.success ? parsed.data : null;
59234
- }
59235
- function writeOwned(root, owned) {
59236
- const ordered = {
59237
- version: owned.version,
59238
- serviceUrl: owned.serviceUrl,
59239
- marketplaceRoot: owned.marketplaceRoot,
59240
- ...owned.claude === void 0 ? {} : { claude: { marketplace: owned.claude.marketplace, plugin: owned.claude.plugin } },
59241
- ...owned.codex === void 0 ? {} : {
59242
- codex: {
59243
- marketplace: owned.codex.marketplace,
59244
- plugin: owned.codex.plugin,
59245
- ...owned.codex.configLines === void 0 ? {} : { configLines: owned.codex.configLines }
59246
- }
59247
- },
59248
- binding: owned.binding,
59249
- excludeLine: owned.excludeLine
59250
- };
59251
- return writeIfDifferent(join(root, OWNED_FILE), jsonText(ordered));
59252
- }
59253
- function removeOwned(root) {
59254
- removeFile(join(root, OWNED_FILE));
59255
- }
59256
-
59257
59273
  // ../cli/src/binding.ts
59274
+ init_overlane_paths_node();
59258
59275
  function readBindingFile(root) {
59259
- const text2 = readText(join2(root, BINDING_FILE));
59276
+ const text2 = readText(statePath(root, "binding"));
59260
59277
  if (text2 === null) return { kind: "missing" };
59261
59278
  let raw;
59262
59279
  try {
@@ -59276,6 +59293,8 @@ function bindingText(binding) {
59276
59293
 
59277
59294
  // ../cli/src/connect.ts
59278
59295
  init_src();
59296
+ init_src();
59297
+ init_overlane_paths_node();
59279
59298
  import { existsSync as existsSync2 } from "node:fs";
59280
59299
  import { join as join6, resolve } from "node:path";
59281
59300
 
@@ -59537,7 +59556,7 @@ async function detectAgents(deps, agents, cwd) {
59537
59556
 
59538
59557
  // ../cli/src/credentials.ts
59539
59558
  init_zod();
59540
- import { join as join3 } from "node:path";
59559
+ import { join as join2 } from "node:path";
59541
59560
  var KEYCHAIN_SERVICE = "overlane";
59542
59561
  var StoredTokens = external_exports.object({ accessToken: external_exports.string().min(1), refreshToken: external_exports.string().min(1).optional(), expiresAt: external_exports.number().optional() }).strict();
59543
59562
  var ClientCache = external_exports.object({ clientId: external_exports.string().min(1), port: external_exports.number().int().min(1).max(65535) }).strict();
@@ -59547,10 +59566,10 @@ var AuthState = external_exports.object({
59547
59566
  }).strict();
59548
59567
  var CredentialFile = external_exports.record(external_exports.string(), StoredTokens);
59549
59568
  function authStatePath(deps) {
59550
- return join3(deps.paths.configDir, "auth.json");
59569
+ return join2(deps.paths.configDir, "auth.json");
59551
59570
  }
59552
59571
  function credentialsPath(deps) {
59553
- return join3(deps.paths.configDir, "credentials.json");
59572
+ return join2(deps.paths.configDir, "credentials.json");
59554
59573
  }
59555
59574
  function readAuthState(deps) {
59556
59575
  const parsed = AuthState.safeParse(readJson(authStatePath(deps)));
@@ -59675,6 +59694,49 @@ init_zod();
59675
59694
  import { existsSync } from "node:fs";
59676
59695
  import { join as join4 } from "node:path";
59677
59696
 
59697
+ // ../cli/src/owned.ts
59698
+ init_zod();
59699
+ import { join as join3 } from "node:path";
59700
+ init_overlane_paths_node();
59701
+ var BINDING_FILE = ".overlane/state/project.json";
59702
+ var OWNED_FILE = ".overlane/state/owned.json";
59703
+ var CODEX_CONFIG_FILE = join3(".codex", "config.toml");
59704
+ var OwnedAgent = external_exports.object({ marketplace: external_exports.boolean(), plugin: external_exports.boolean() }).strict();
59705
+ var OwnedConfigLines = external_exports.object({ text: external_exports.string().min(1), createdFile: external_exports.boolean() }).strict();
59706
+ var Owned = external_exports.object({
59707
+ version: external_exports.literal(1),
59708
+ serviceUrl: external_exports.string().min(1),
59709
+ marketplaceRoot: external_exports.string().min(1),
59710
+ claude: OwnedAgent.optional(),
59711
+ codex: OwnedAgent.extend({ configLines: OwnedConfigLines.optional() }).strict().optional(),
59712
+ binding: external_exports.boolean()
59713
+ }).strict();
59714
+ function readOwned(root) {
59715
+ const parsed = Owned.safeParse(readJson(statePath(root, "owned")));
59716
+ return parsed.success ? parsed.data : null;
59717
+ }
59718
+ function writeOwned(root, owned) {
59719
+ const ordered = {
59720
+ version: owned.version,
59721
+ serviceUrl: owned.serviceUrl,
59722
+ marketplaceRoot: owned.marketplaceRoot,
59723
+ ...owned.claude === void 0 ? {} : { claude: { marketplace: owned.claude.marketplace, plugin: owned.claude.plugin } },
59724
+ ...owned.codex === void 0 ? {} : {
59725
+ codex: {
59726
+ marketplace: owned.codex.marketplace,
59727
+ plugin: owned.codex.plugin,
59728
+ ...owned.codex.configLines === void 0 ? {} : { configLines: owned.codex.configLines }
59729
+ }
59730
+ },
59731
+ binding: owned.binding
59732
+ };
59733
+ ensureStateDir(root);
59734
+ return writeIfDifferent(statePath(root, "owned"), jsonText(ordered));
59735
+ }
59736
+ function removeOwned(root) {
59737
+ removeFile(statePath(root, "owned"));
59738
+ }
59739
+
59678
59740
  // ../cli/src/toml.ts
59679
59741
  function parseKeyPath(source) {
59680
59742
  const parts2 = [];
@@ -60101,7 +60163,7 @@ async function requireToken(deps, serviceUrl) {
60101
60163
 
60102
60164
  // ../cli/src/project.ts
60103
60165
  init_src();
60104
- import { basename, join as join5 } from "node:path";
60166
+ import { basename } from "node:path";
60105
60167
  var REMOTE_PATTERNS = [
60106
60168
  /^(?:https?|git|ssh):\/\/(?:[^@/]+@)?github\.com(?::\d+)?\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i,
60107
60169
  /^(?:[^@/]+@)?github\.com:([^/]+)\/([^/]+?)(?:\.git)?\/?$/i
@@ -60165,37 +60227,6 @@ async function headCommit(deps, root) {
60165
60227
  const sha = head.stdout.trim();
60166
60228
  return head.code === 0 && sha.length > 0 ? sha : null;
60167
60229
  }
60168
- var EXCLUDE_LINE = ".harness/";
60169
- async function excludePath(deps, root) {
60170
- const result = await deps.exec("git", ["rev-parse", "--path-format=absolute", "--git-path", "info/exclude"], { cwd: root });
60171
- if (result.code !== 0 || result.stdout.trim().length === 0) {
60172
- return join5(root, ".git", "info", "exclude");
60173
- }
60174
- return result.stdout.trim();
60175
- }
60176
- async function isHarnessIgnored(deps, root) {
60177
- const result = await deps.exec("git", ["check-ignore", "-q", ".harness/project.json"], { cwd: root });
60178
- return result.code === 0;
60179
- }
60180
- async function addExclude(deps, root) {
60181
- const path = await excludePath(deps, root);
60182
- const text2 = readText(path) ?? "";
60183
- if (text2.split("\n").includes(EXCLUDE_LINE)) return false;
60184
- const prefix = text2.length === 0 || text2.endsWith("\n") ? "" : "\n";
60185
- writeIfDifferent(path, `${text2}${prefix}${EXCLUDE_LINE}
60186
- `);
60187
- return true;
60188
- }
60189
- async function removeExclude(deps, root) {
60190
- const path = await excludePath(deps, root);
60191
- const text2 = readText(path);
60192
- if (text2 === null) return;
60193
- const lines = text2.split("\n");
60194
- const index = lines.indexOf(EXCLUDE_LINE);
60195
- if (index === -1) return;
60196
- lines.splice(index, 1);
60197
- writeIfDifferent(path, lines.join("\n"));
60198
- }
60199
60230
 
60200
60231
  // ../cli/src/readiness.ts
60201
60232
  function report(agent, state, detail, action) {
@@ -60219,7 +60250,7 @@ async function assessAgent(deps, input2) {
60219
60250
  return report(agent, "incompatible", input2.info.detail, `install ${label2} (\`${agent}\`) and run \`overlane doctor\` again`);
60220
60251
  }
60221
60252
  if (input2.binding.kind !== "ok") {
60222
- const why = input2.binding.kind === "missing" ? "no .harness/project.json" : `invalid .harness/project.json (${input2.binding.detail})`;
60253
+ const why = input2.binding.kind === "missing" ? "no .overlane/state/project.json" : `invalid .overlane/state/project.json (${input2.binding.detail})`;
60223
60254
  return report(agent, "blocked", why, "run `overlane connect`");
60224
60255
  }
60225
60256
  if (!input2.hasToken) return report(agent, "blocked", "no stored token for the service", "run `overlane connect` to sign in");
@@ -60436,7 +60467,7 @@ function normaliseServiceUrl(value) {
60436
60467
  return url2.toString().replace(/\/+$/, "");
60437
60468
  }
60438
60469
  function emptyOwned(serviceUrl, marketplaceRoot2) {
60439
- return { version: 1, serviceUrl, marketplaceRoot: marketplaceRoot2, binding: false, excludeLine: false };
60470
+ return { version: 1, serviceUrl, marketplaceRoot: marketplaceRoot2, binding: false };
60440
60471
  }
60441
60472
  async function connect(deps, options) {
60442
60473
  const infos = await detectAgents(deps, options.agents, deps.paths.cwd);
@@ -60490,7 +60521,7 @@ async function connect(deps, options) {
60490
60521
  }
60491
60522
  }
60492
60523
  }
60493
- const excludeNeeded = !await isHarnessIgnored(deps, root);
60524
+ const gitignoreNeeded = !existsSync2(join6(root, STATE_DIR, ".gitignore"));
60494
60525
  const bindingMissing = existing.kind !== "ok";
60495
60526
  const existingToken = await findToken(deps, serviceUrl);
60496
60527
  say(deps);
@@ -60506,21 +60537,21 @@ async function connect(deps, options) {
60506
60537
  }
60507
60538
  for (const line3 of present) say(deps, ` skip: ${line3}`);
60508
60539
  say(deps, ` write ${BINDING_FILE}: project ID, tenant ID, service URL, release digest and the release-signing public key from the service`);
60509
- say(deps, " write .harness/owned.json: the entries overlane added, so `overlane disconnect` removes only those");
60510
- if (excludeNeeded) say(deps, ` append ${EXCLUDE_LINE} to ${await excludePath(deps, root)}`);
60540
+ say(deps, ` write ${OWNED_FILE}: the entries overlane added, so \`overlane disconnect\` removes only those`);
60541
+ if (gitignoreNeeded) say(deps, ` write ${STATE_DIR}/.gitignore (\`*\`): local state is never committed`);
60511
60542
  for (const info2 of active) {
60512
60543
  say(deps, ` hook (${info2.agent}, SessionStart): node ${hookScript(marketplaceRoot2, info2.agent)}`);
60513
60544
  }
60514
- say(deps, " It runs at session start and reads .harness/project.json and git. When a harness token is available (OVERLANE_TOKEN, the OS");
60545
+ say(deps, " It runs at session start and reads .overlane/state/project.json and git. When a harness token is available (OVERLANE_TOKEN, the OS");
60515
60546
  say(deps, ` keychain or the 0600 file) it calls ${serviceUrl}/v1/tenants/<tenant>/projects/<project>/context?commit=<sha>`);
60516
60547
  say(deps, " with the token as a Bearer header, sending only the tenant, project and commit SHA. It never sends source code.");
60517
60548
  say(deps);
60518
60549
  if (options.dryRun) {
60519
60550
  say(deps, "Dry run: no command was run and no file was written.");
60520
60551
  const writes = [{ path: BINDING_FILE, action: "write", description: "project ID, tenant ID, service URL, release digest and the release-signing public key" }];
60521
- writes.push({ path: ".harness/owned.json", action: "write", description: "the entries overlane added, so `overlane disconnect` removes only those" });
60552
+ writes.push({ path: OWNED_FILE, action: "write", description: "the entries overlane added, so `overlane disconnect` removes only those" });
60522
60553
  if (codexEdit !== null) writes.push({ path: CODEX_CONFIG_FILE, action: "append", description: `enable the plugin for this project (${codexEdit.block.trim().split("\n").join("; ")})` });
60523
- if (excludeNeeded) writes.push({ path: await excludePath(deps, root), action: "append", description: EXCLUDE_LINE });
60554
+ if (gitignoreNeeded) writes.push({ path: `${STATE_DIR}/.gitignore`, action: "write", description: "`*`: the state folder ignores itself (ADR 0067)" });
60524
60555
  const plan3 = dryRunPlan({
60525
60556
  service: serviceUrl,
60526
60557
  requests: [
@@ -60537,7 +60568,7 @@ async function connect(deps, options) {
60537
60568
  });
60538
60569
  return { data: plan3 };
60539
60570
  }
60540
- const pending = steps.length > 0 || codexEdit !== null || excludeNeeded || bindingMissing;
60571
+ const pending = steps.length > 0 || codexEdit !== null || gitignoreNeeded || bindingMissing;
60541
60572
  if (pending && !options.yes) {
60542
60573
  if (!deps.isTTY) {
60543
60574
  const hint = `overlane connect${options.service === void 0 ? "" : ` --service ${options.service}`}${options.agents.length === AGENT_NAMES.length ? "" : ` --agents ${options.agents.join(",")}`}${options.marketplaceRoot === void 0 ? "" : ` --marketplace-root ${options.marketplaceRoot}`} --yes`;
@@ -60564,6 +60595,7 @@ async function connect(deps, options) {
60564
60595
  releaseDigest: record3.releaseDigest,
60565
60596
  ...servicePublicKey === null ? {} : { servicePublicKey }
60566
60597
  });
60598
+ ensureStateDir(root);
60567
60599
  const previousOwned = readOwned(root);
60568
60600
  const owned = previousOwned === null ? emptyOwned(serviceUrl, marketplaceRoot2) : { ...previousOwned, serviceUrl, marketplaceRoot: marketplaceRoot2 };
60569
60601
  try {
@@ -60585,13 +60617,12 @@ async function connect(deps, options) {
60585
60617
  verify(deps, root, active);
60586
60618
  say(deps, `[agents] ${CONNECT_STEPS.agents}: done`);
60587
60619
  await reportStep(deps, serviceUrl, token.token, me.tenantId, "agents", { agents: active.map((info2) => info2.agent === "claude" ? "claude-code" : info2.agent) });
60588
- if (writeIfDifferent(join6(root, BINDING_FILE), bindingText(binding))) {
60620
+ if (writeIfDifferent(statePath(root, "binding"), bindingText(binding))) {
60589
60621
  say(deps, `Wrote ${BINDING_FILE}`);
60590
60622
  wrote.push(BINDING_FILE);
60591
60623
  }
60592
60624
  if (codexEdit !== null) wrote.push(CODEX_CONFIG_FILE);
60593
60625
  owned.binding = true;
60594
- if (excludeNeeded && await addExclude(deps, root)) owned.excludeLine = true;
60595
60626
  say(deps, `[repo] ${CONNECT_STEPS.repo}: done`);
60596
60627
  const next = await reportStep(deps, serviceUrl, token.token, me.tenantId, "repo", { repo: repoChoice(project) });
60597
60628
  if (next !== null) say(deps, `Next in onboarding: ${next === "repo" ? "first-task" : next} (${CONNECT_STEPS[next === "repo" ? "first-task" : next]})`);
@@ -60791,7 +60822,7 @@ var authStatusCommand = defineCommand({
60791
60822
  });
60792
60823
 
60793
60824
  // ../cli/src/commands/client.ts
60794
- import { readFileSync as readFileSync3 } from "node:fs";
60825
+ import { readFileSync as readFileSync4 } from "node:fs";
60795
60826
  import { join as join8, resolve as resolve3 } from "node:path";
60796
60827
 
60797
60828
  // ../plugin-builder/src/adapters/plan.ts
@@ -60808,7 +60839,7 @@ function contextInstructions(client) {
60808
60839
  return [
60809
60840
  "## Overlane",
60810
60841
  "",
60811
- `This project shares context between coding agents through Overlane (${CLIENT_LABELS[client]} is one of them). Project and team IDs are in \`.harness/project.json\`.`,
60842
+ `This project shares context between coding agents through Overlane (${CLIENT_LABELS[client]} is one of them). Project and team IDs are in \`.overlane/state/project.json\`.`,
60812
60843
  "",
60813
60844
  "- At the start of every task, call the `harness_context` tool of the `overlane` MCP server (or run `overlane context`).",
60814
60845
  "- Claim work with `harness_task` before you change files, checkpoint before you stop or hand over, and submit with evidence. A task is done only when `harness_task get` shows it `verified`; saying so in chat is not enough.",
@@ -60873,7 +60904,7 @@ function planAdapter(client, surface, options = {}) {
60873
60904
  }
60874
60905
 
60875
60906
  // ../plugin-builder/src/adapters/install.ts
60876
- import { chmodSync as chmodSync2, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
60907
+ import { chmodSync as chmodSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
60877
60908
  import { dirname as dirname2, isAbsolute, join as join7, relative, resolve as resolve2 } from "node:path";
60878
60909
  function safePath(root, path) {
60879
60910
  const full = resolve2(root, path);
@@ -60944,7 +60975,7 @@ function applyPlan(root, ops, options = {}) {
60944
60975
  const applied = [];
60945
60976
  for (const op of ops) {
60946
60977
  const full = safePath(root, op.path);
60947
- const existing = existsSync3(full) ? readFileSync2(full, "utf8") : null;
60978
+ const existing = existsSync3(full) ? readFileSync3(full, "utf8") : null;
60948
60979
  let next;
60949
60980
  try {
60950
60981
  next = render(op, existing);
@@ -60954,8 +60985,8 @@ function applyPlan(root, ops, options = {}) {
60954
60985
  }
60955
60986
  const action = existing === null ? "created" : existing === next ? "unchanged" : "updated";
60956
60987
  if (action !== "unchanged" && options.dryRun !== true) {
60957
- mkdirSync2(dirname2(full), { recursive: true });
60958
- writeFileSync2(full, next);
60988
+ mkdirSync3(dirname2(full), { recursive: true });
60989
+ writeFileSync3(full, next);
60959
60990
  if (op.kind === "write" && op.executable === true) chmodSync2(full, 493);
60960
60991
  }
60961
60992
  applied.push({ path: join7(op.path), action });
@@ -60964,7 +60995,7 @@ function applyPlan(root, ops, options = {}) {
60964
60995
  }
60965
60996
 
60966
60997
  // ../plugin-builder/src/adapters/cloud.ts
60967
- var FALLBACK_DIR = ".harness/hooks";
60998
+ var FALLBACK_DIR = ".overlane/hooks";
60968
60999
  var CLAUDE_PLUGIN_SCRIPTS = ["claude", "plugins", "overlane", "scripts"];
60969
61000
  var FALLBACK_SCRIPTS = ["harness-context.mjs", "harness-stop.mjs"];
60970
61001
  function claudeFallbackSettings() {
@@ -61000,7 +61031,7 @@ function planCloudRecipe(client, options = {}) {
61000
61031
  "3. `overlane task submit <id>` with evidence when done. The completion gate is advisory on this path: the server still refuses to mark an unverified task verified."
61001
61032
  ].join("\n")
61002
61033
  },
61003
- { kind: "write", path: ".harness/codex-cloud-setup.sh", content: CODEX_SETUP_SCRIPT, executable: true }
61034
+ { kind: "write", path: `${FALLBACK_DIR}/codex-cloud-setup.sh`, content: CODEX_SETUP_SCRIPT, executable: true }
61004
61035
  ];
61005
61036
  }
61006
61037
  const ops = [];
@@ -61039,8 +61070,8 @@ var NEXT = {
61039
61070
  grok: ["Start Grok Build in this project; run `grok inspect` to see the overlane MCP server, then approve its sign-in."],
61040
61071
  cursor: ["Open the project in Cursor, enable the overlane server under Settings > MCP, and sign in when asked."],
61041
61072
  gemini: ["Run `gemini` in this project; the workspace extension `overlane` loads on start. Sign in when the MCP server asks."],
61042
- claude: ["Commit .claude/settings.json, .harness/hooks and CLAUDE.md. In the Claude Code on the web environment, add the secret OVERLANE_TOKEN (an agent token from `overlane token create`)."],
61043
- codex: ["Commit AGENTS.md and .harness/codex-cloud-setup.sh. In the Codex cloud environment, run the setup script and add the secret OVERLANE_TOKEN (an agent token from `overlane token create`). Completion gating is advisory on Codex cloud."]
61073
+ claude: ["Commit .claude/settings.json, .overlane/hooks and CLAUDE.md. In the Claude Code on the web environment, add the secret OVERLANE_TOKEN (an agent token from `overlane token create`)."],
61074
+ codex: ["Commit AGENTS.md and .overlane/hooks/codex-cloud-setup.sh. In the Codex cloud environment, run the setup script and add the secret OVERLANE_TOKEN (an agent token from `overlane token create`). Completion gating is advisory on Codex cloud."]
61044
61075
  };
61045
61076
  var clientInstallCommand = defineCommand({
61046
61077
  path: ["client", "install"],
@@ -61074,7 +61105,7 @@ var clientInstallCommand = defineCommand({
61074
61105
  const scripts = {};
61075
61106
  for (const script of FALLBACK_SCRIPTS) {
61076
61107
  try {
61077
- scripts[script] = readFileSync3(join8(root, ...CLAUDE_PLUGIN_SCRIPTS, script), "utf8");
61108
+ scripts[script] = readFileSync4(join8(root, ...CLAUDE_PLUGIN_SCRIPTS, script), "utf8");
61078
61109
  } catch {
61079
61110
  throw new UsageError(`the built Claude plugin was not found under ${root}`, { hint: "build it with the plugin builder or pass --marketplace-root" });
61080
61111
  }
@@ -61102,8 +61133,8 @@ init_zod();
61102
61133
 
61103
61134
  // ../cli/src/release/installed.ts
61104
61135
  init_src();
61105
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
61106
- import { dirname as dirname3, join as join9 } from "node:path";
61136
+ import { readFileSync as readFileSync5, renameSync, writeFileSync as writeFileSync4 } from "node:fs";
61137
+ import { join as join9 } from "node:path";
61107
61138
 
61108
61139
  // ../cli/src/release/verify.ts
61109
61140
  init_src();
@@ -61160,21 +61191,22 @@ function diffDigestOf(diff) {
61160
61191
  }
61161
61192
 
61162
61193
  // ../cli/src/release/installed.ts
61163
- var RELEASE_FILE = join9(".harness", "release.json");
61194
+ init_overlane_paths_node();
61195
+ var RELEASE_FILE = ".overlane/state/release.json";
61164
61196
  function readInstalled(root) {
61165
- const parsed = ReleaseManifest.safeParse(readJson(join9(root, RELEASE_FILE)));
61197
+ const parsed = ReleaseManifest.safeParse(readJson(statePath(root, "release")));
61166
61198
  return parsed.success ? parsed.data : null;
61167
61199
  }
61168
61200
  function writeInstalled(root, manifest) {
61169
- const path = join9(root, RELEASE_FILE);
61170
- mkdirSync3(dirname3(path), { recursive: true });
61201
+ ensureStateDir(root);
61202
+ const path = statePath(root, "release");
61171
61203
  const temp = `${path}.${process.pid}.tmp`;
61172
- writeFileSync3(temp, jsonText(manifest));
61204
+ writeFileSync4(temp, jsonText(manifest));
61173
61205
  renameSync(temp, path);
61174
61206
  }
61175
61207
  function diskDigest(marketplaceRoot2, file2) {
61176
61208
  try {
61177
- return sha256Of(readFileSync4(join9(marketplaceRoot2, file2.path)));
61209
+ return sha256Of(readFileSync5(join9(marketplaceRoot2, file2.path)));
61178
61210
  } catch {
61179
61211
  return null;
61180
61212
  }
@@ -61199,14 +61231,13 @@ function mismatchedFiles(marketplaceRoot2, target2) {
61199
61231
 
61200
61232
  // ../cli/src/release/update.ts
61201
61233
  init_src();
61202
- import { join as join13, resolve as resolve4 } from "node:path";
61234
+ import { join as join12, resolve as resolve4 } from "node:path";
61203
61235
 
61204
61236
  // ../cli/src/task/state.ts
61205
61237
  init_src();
61238
+ import { renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
61206
61239
  init_zod();
61207
- import { mkdirSync as mkdirSync4, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
61208
- import { dirname as dirname4, join as join10 } from "node:path";
61209
- var TASK_STATE_PATH = join10(".harness", "task.json");
61240
+ init_overlane_paths_node();
61210
61241
  var LocalTaskState = external_exports.object({
61211
61242
  taskId: TaskId,
61212
61243
  fencingToken: external_exports.number().int().nonnegative(),
@@ -61218,7 +61249,7 @@ var LocalTaskState = external_exports.object({
61218
61249
  }).strict();
61219
61250
  function readTaskState(root) {
61220
61251
  try {
61221
- const text2 = readText(join10(root, TASK_STATE_PATH));
61252
+ const text2 = readText(statePath(root, "task"));
61222
61253
  if (text2 === null) return null;
61223
61254
  const parsed = LocalTaskState.safeParse(JSON.parse(text2));
61224
61255
  return parsed.success ? parsed.data : null;
@@ -61227,27 +61258,27 @@ function readTaskState(root) {
61227
61258
  }
61228
61259
  }
61229
61260
  function writeTaskState(root, state) {
61230
- const path = join10(root, TASK_STATE_PATH);
61231
- mkdirSync4(dirname4(path), { recursive: true });
61261
+ ensureStateDir(root);
61262
+ const path = statePath(root, "task");
61232
61263
  const temp = `${path}.${process.pid}.tmp`;
61233
- writeFileSync4(temp, `${JSON.stringify(state, null, 2)}
61264
+ writeFileSync5(temp, `${JSON.stringify(state, null, 2)}
61234
61265
  `);
61235
61266
  renameSync2(temp, path);
61236
61267
  }
61237
61268
  function removeTaskState(root) {
61238
- rmSync2(join10(root, TASK_STATE_PATH), { force: true });
61269
+ rmSync2(statePath(root, "task"), { force: true });
61239
61270
  }
61240
61271
 
61241
61272
  // ../cli/src/release/approvals.ts
61242
61273
  init_src();
61243
61274
  init_zod();
61244
- import { chmodSync as chmodSync3, mkdirSync as mkdirSync5, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "node:fs";
61275
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync6, renameSync as renameSync3, writeFileSync as writeFileSync6 } from "node:fs";
61245
61276
  import { hostname as hostname3 } from "node:os";
61246
- import { dirname as dirname5, join as join11 } from "node:path";
61277
+ import { dirname as dirname4, join as join10 } from "node:path";
61247
61278
  var APPROVALS_FILE = "approvals.json";
61248
61279
  var Approvals = external_exports.array(ReleaseApproval);
61249
61280
  function approvalsPath(deps) {
61250
- return join11(deps.paths.configDir, APPROVALS_FILE);
61281
+ return join10(deps.paths.configDir, APPROVALS_FILE);
61251
61282
  }
61252
61283
  function readApprovals(deps) {
61253
61284
  const parsed = Approvals.safeParse(readJson(approvalsPath(deps)));
@@ -61260,29 +61291,29 @@ function recordApproval(deps, approval) {
61260
61291
  const full = ReleaseApproval.parse({ ...approval, machine: hostname3() || "unknown", approvedAt: new Date(deps.now()).toISOString() });
61261
61292
  const path = approvalsPath(deps);
61262
61293
  const all = [...readApprovals(deps).filter((existing) => existing.digest !== full.digest), full];
61263
- mkdirSync5(dirname5(path), { recursive: true });
61294
+ mkdirSync6(dirname4(path), { recursive: true });
61264
61295
  const temp = `${path}.${process.pid}.tmp`;
61265
- writeFileSync5(temp, jsonText(all), { mode: 384 });
61296
+ writeFileSync6(temp, jsonText(all), { mode: 384 });
61266
61297
  chmodSync3(temp, 384);
61267
61298
  renameSync3(temp, path);
61268
61299
  return full;
61269
61300
  }
61270
61301
 
61271
61302
  // ../cli/src/release/source.ts
61272
- import { mkdirSync as mkdirSync6, readFileSync as readFileSync5 } from "node:fs";
61273
- import { join as join12 } from "node:path";
61303
+ import { mkdirSync as mkdirSync7, readFileSync as readFileSync6 } from "node:fs";
61304
+ import { join as join11 } from "node:path";
61274
61305
  var SIDECAR_DIR = ".release";
61275
61306
  function sourceUrl(deps, source) {
61276
61307
  const override = deps.env["OVERLANE_RELEASE_SOURCE_URL"];
61277
61308
  return override !== void 0 && override.length > 0 ? override : `https://github.com/${source.repository}.git`;
61278
61309
  }
61279
61310
  async function git(deps, root, args2, quiet = false) {
61280
- const result = await deps.exec("git", [`--git-dir=${join12(root, ".git")}`, `--work-tree=${root}`, "-c", "advice.detachedHead=false", ...args2], { cwd: root });
61311
+ const result = await deps.exec("git", [`--git-dir=${join11(root, ".git")}`, `--work-tree=${root}`, "-c", "advice.detachedHead=false", ...args2], { cwd: root });
61281
61312
  if (result.code !== 0 && !quiet) throw new CliError(`\`git ${args2.join(" ")}\` failed (exit ${result.code}): ${(result.stderr || result.stdout).trim().slice(0, 400)}`);
61282
61313
  return { code: result.code, text: result.stdout.trim() };
61283
61314
  }
61284
61315
  async function fetchReleaseSource(deps, marketplaceRoot2, source) {
61285
- mkdirSync6(marketplaceRoot2, { recursive: true });
61316
+ mkdirSync7(marketplaceRoot2, { recursive: true });
61286
61317
  const url2 = sourceUrl(deps, source);
61287
61318
  if ((await git(deps, marketplaceRoot2, ["rev-parse", "--git-dir"], true)).code !== 0) await git(deps, marketplaceRoot2, ["init", "-q"]);
61288
61319
  say(deps, `Fetching ${source.repository}@${source.commit.slice(0, 12)} (${source.ref})`);
@@ -61302,7 +61333,7 @@ async function verifySourceTree(deps, marketplaceRoot2, files, digest) {
61302
61333
  for (const file2 of files) {
61303
61334
  let actual = null;
61304
61335
  try {
61305
- actual = sha256Of(readFileSync5(join12(marketplaceRoot2, file2.path)));
61336
+ actual = sha256Of(readFileSync6(join11(marketplaceRoot2, file2.path)));
61306
61337
  } catch {
61307
61338
  }
61308
61339
  if (actual === null) problems.push(`${file2.path} is missing`);
@@ -61462,7 +61493,7 @@ async function installRelease(deps, ctx, targetDigest, options, isPin) {
61462
61493
  }
61463
61494
  function syncBinding(root, binding, digest) {
61464
61495
  if (binding.releaseDigest === digest) return;
61465
- writeIfDifferent(join13(root, BINDING_FILE), bindingText({ ...binding, releaseDigest: digest }));
61496
+ writeIfDifferent(join12(root, BINDING_FILE), bindingText({ ...binding, releaseDigest: digest }));
61466
61497
  }
61467
61498
 
61468
61499
  // ../cli/src/kit/api.ts
@@ -61556,10 +61587,9 @@ function kitClient(deps, serviceUrl, binding, token) {
61556
61587
 
61557
61588
  // ../cli/src/kit/run-state.ts
61558
61589
  init_src();
61590
+ import { renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "node:fs";
61559
61591
  init_zod();
61560
- import { mkdirSync as mkdirSync7, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
61561
- import { dirname as dirname6, join as join14 } from "node:path";
61562
- var RUN_STATE_PATH = join14(".harness", "run.json");
61592
+ init_overlane_paths_node();
61563
61593
  var LocalRunState = external_exports.object({
61564
61594
  runId: external_exports.string().min(1),
61565
61595
  executor: external_exports.enum(["claude-code", "codex"]),
@@ -61570,7 +61600,7 @@ var LocalRunState = external_exports.object({
61570
61600
  }).strict();
61571
61601
  function readRunState(root) {
61572
61602
  try {
61573
- const text2 = readText(join14(root, RUN_STATE_PATH));
61603
+ const text2 = readText(statePath(root, "run"));
61574
61604
  if (text2 === null) return null;
61575
61605
  const parsed = LocalRunState.safeParse(JSON.parse(text2));
61576
61606
  return parsed.success ? parsed.data : null;
@@ -61579,15 +61609,15 @@ function readRunState(root) {
61579
61609
  }
61580
61610
  }
61581
61611
  function writeRunState(root, state) {
61582
- const path = join14(root, RUN_STATE_PATH);
61583
- mkdirSync7(dirname6(path), { recursive: true });
61612
+ ensureStateDir(root);
61613
+ const path = statePath(root, "run");
61584
61614
  const temp = `${path}.${process.pid}.tmp`;
61585
- writeFileSync6(temp, `${JSON.stringify(state, null, 2)}
61615
+ writeFileSync7(temp, `${JSON.stringify(state, null, 2)}
61586
61616
  `);
61587
61617
  renameSync4(temp, path);
61588
61618
  }
61589
61619
  function removeRunState(root) {
61590
- rmSync3(join14(root, RUN_STATE_PATH), { force: true });
61620
+ rmSync3(statePath(root, "run"), { force: true });
61591
61621
  }
61592
61622
 
61593
61623
  // ../cli/src/kit/run.ts
@@ -61608,7 +61638,7 @@ ${issues.map((issue2) => ` - ${issue2}`).join("\n")}` : message);
61608
61638
  // ../kit/src/plan-files.ts
61609
61639
  init_src();
61610
61640
  import { mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
61611
- import { join as join15 } from "node:path";
61641
+ import { join as join13 } from "node:path";
61612
61642
 
61613
61643
  // ../kit/src/text.ts
61614
61644
  var import_yaml = __toESM(require_dist(), 1);
@@ -61687,10 +61717,10 @@ function slugify2(value) {
61687
61717
  }
61688
61718
 
61689
61719
  // ../kit/src/plan-files.ts
61690
- var PLAN_DIR = ".harness/plan";
61720
+ var PLAN_DIR2 = PLAN_DIR;
61691
61721
  var planPaths = (repoDir) => {
61692
- const root = join15(repoDir, PLAN_DIR);
61693
- return { root, project: join15(root, "project.md"), milestones: join15(root, "milestones.md"), tasks: join15(root, "tasks"), task: (id2) => join15(root, "tasks", `${id2}.md`) };
61722
+ const root = join13(repoDir, PLAN_DIR2);
61723
+ return { root, project: join13(root, "project.md"), milestones: join13(root, "milestones.md"), tasks: join13(root, "tasks"), task: (id2) => join13(root, "tasks", `${id2}.md`) };
61694
61724
  };
61695
61725
  function parsePlan(input2, where2) {
61696
61726
  const result = Plan.safeParse(input2);
@@ -61749,11 +61779,11 @@ async function writePlan(repoDir, plan3) {
61749
61779
  ]);
61750
61780
  await mkdir(paths.tasks, { recursive: true });
61751
61781
  const keep = new Set(canonical.tasks.map((task) => `${task.id}.md`));
61752
- for (const entry of await readdir(paths.tasks)) if (entry.endsWith(".md") && !keep.has(entry)) await rm(join15(paths.tasks, entry));
61782
+ for (const entry of await readdir(paths.tasks)) if (entry.endsWith(".md") && !keep.has(entry)) await rm(join13(paths.tasks, entry));
61753
61783
  for (const [file2, text2] of files) await writeFile(file2, text2, "utf8");
61754
61784
  return [...files.keys()].map((file2) => file2.slice(repoDir.length).replace(/^\/+/, ""));
61755
61785
  }
61756
- async function readText2(file2) {
61786
+ async function readText3(file2) {
61757
61787
  try {
61758
61788
  return await readFile(file2, "utf8");
61759
61789
  } catch (error62) {
@@ -61815,8 +61845,8 @@ function parseTask(text2, where2) {
61815
61845
  }
61816
61846
  async function readPlan(repoDir) {
61817
61847
  const paths = planPaths(repoDir);
61818
- const { schemaVersion, project } = parseProject(await readText2(paths.project), paths.project);
61819
- const milestones = parseMilestones(await readText2(paths.milestones), paths.milestones);
61848
+ const { schemaVersion, project } = parseProject(await readText3(paths.project), paths.project);
61849
+ const milestones = parseMilestones(await readText3(paths.milestones), paths.milestones);
61820
61850
  let entries;
61821
61851
  try {
61822
61852
  entries = (await readdir(paths.tasks)).filter((entry) => entry.endsWith(".md"));
@@ -61825,8 +61855,8 @@ async function readPlan(repoDir) {
61825
61855
  }
61826
61856
  const tasks = [];
61827
61857
  for (const entry of entries.sort(naturalCompare)) {
61828
- const file2 = join15(paths.tasks, entry);
61829
- const task = parseTask(await readText2(file2), file2);
61858
+ const file2 = join13(paths.tasks, entry);
61859
+ const task = parseTask(await readText3(file2), file2);
61830
61860
  if (`${task.id}.md` !== entry) throw new KitError(`${file2}: file name must be ${task.id}.md`);
61831
61861
  tasks.push(task);
61832
61862
  }
@@ -61837,13 +61867,13 @@ async function readPlan(repoDir) {
61837
61867
  init_src();
61838
61868
  init_zod();
61839
61869
  import { mkdir as mkdir2, readdir as readdir3, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
61840
- import { basename as basename3, dirname as dirname7, join as join17, resolve as resolve6 } from "node:path";
61870
+ import { basename as basename3, dirname as dirname5, join as join15, resolve as resolve6 } from "node:path";
61841
61871
 
61842
61872
  // ../kit/src/detect.ts
61843
61873
  var import_yaml2 = __toESM(require_dist(), 1);
61844
61874
  init_src();
61845
61875
  import { readdir as readdir2, readFile as readFile2 } from "node:fs/promises";
61846
- import { basename as basename2, join as join16, resolve as resolve5 } from "node:path";
61876
+ import { basename as basename2, join as join14, resolve as resolve5 } from "node:path";
61847
61877
  var KINDS = ["typecheck", "lint", "build", "test"];
61848
61878
  async function readOptional(file2) {
61849
61879
  try {
@@ -61888,7 +61918,7 @@ async function detectCommands(repoDir) {
61888
61918
  if (!sources.includes(source)) sources.push(source);
61889
61919
  };
61890
61920
  const scriptBodies = /* @__PURE__ */ new Map();
61891
- const packageText = await readOptional(join16(root, "package.json"));
61921
+ const packageText = await readOptional(join14(root, "package.json"));
61892
61922
  if (packageText !== void 0) {
61893
61923
  let pkg;
61894
61924
  try {
@@ -61910,13 +61940,13 @@ async function detectCommands(repoDir) {
61910
61940
  install = pm === "npm" ? lock ? "npm ci" : "npm install" : `${pm} install`;
61911
61941
  if (!sources.includes("package.json")) sources.push("package.json");
61912
61942
  }
61913
- const makefile = await readOptional(join16(root, "Makefile")) ?? await readOptional(join16(root, "makefile"));
61943
+ const makefile = await readOptional(join14(root, "Makefile")) ?? await readOptional(join14(root, "makefile"));
61914
61944
  if (makefile !== void 0) {
61915
61945
  const targets = new Set([...makefile.matchAll(/^([A-Za-z0-9_.-]+)\s*:(?!=)/gm)].map((m) => m[1] ?? ""));
61916
61946
  const names = { typecheck: ["typecheck"], lint: ["lint"], build: ["build"], test: ["test", "tests"] };
61917
61947
  for (const kind of KINDS) for (const name2 of names[kind]) if (targets.has(name2)) add(kind, `make ${name2}`, "Makefile");
61918
61948
  }
61919
- const pyproject = await readOptional(join16(root, "pyproject.toml"));
61949
+ const pyproject = await readOptional(join14(root, "pyproject.toml"));
61920
61950
  if (pyproject !== void 0) {
61921
61951
  const files = await readdir2(root).catch(() => []);
61922
61952
  const runner = files.includes("uv.lock") ? "uv run " : files.includes("poetry.lock") || /\[tool\.poetry\]/.test(pyproject) ? "poetry run " : "";
@@ -61928,13 +61958,13 @@ async function detectCommands(repoDir) {
61928
61958
  else if (/^\[project\]/m.test(pyproject)) install = "pip install -e .";
61929
61959
  }
61930
61960
  }
61931
- const workflowDir = join16(root, ".github", "workflows");
61961
+ const workflowDir = join14(root, ".github", "workflows");
61932
61962
  const workflows = (await readdir2(workflowDir).catch(() => [])).filter((f) => /\.ya?ml$/.test(f)).sort();
61933
61963
  for (const file2 of workflows) {
61934
61964
  const source = `.github/workflows/${file2}`;
61935
61965
  let doc;
61936
61966
  try {
61937
- doc = (0, import_yaml2.parse)(await readOptional(join16(workflowDir, file2)) ?? "");
61967
+ doc = (0, import_yaml2.parse)(await readOptional(join14(workflowDir, file2)) ?? "");
61938
61968
  } catch {
61939
61969
  continue;
61940
61970
  }
@@ -61979,7 +62009,7 @@ async function draftPlanForExisting(repoDir, opts = {}) {
61979
62009
  const detected = await detectCommands(root);
61980
62010
  let pkgName;
61981
62011
  let pkgDescription;
61982
- const packageText = await readOptional(join16(root, "package.json"));
62012
+ const packageText = await readOptional(join14(root, "package.json"));
61983
62013
  if (packageText !== void 0) {
61984
62014
  try {
61985
62015
  const pkg = JSON.parse(packageText);
@@ -62139,13 +62169,13 @@ function parseConstitution(text2) {
62139
62169
  }
62140
62170
  async function findConstitution(repoDir) {
62141
62171
  for (const rel of CONSTITUTION_PATHS) {
62142
- const text2 = await readOptional2(join17(repoDir, rel));
62172
+ const text2 = await readOptional2(join15(repoDir, rel));
62143
62173
  if (text2 !== void 0) return { file: rel, text: text2 };
62144
62174
  }
62145
62175
  return void 0;
62146
62176
  }
62147
62177
  async function discoverFeatures(repoDir) {
62148
- const specsDir = join17(repoDir, "specs");
62178
+ const specsDir = join15(repoDir, "specs");
62149
62179
  let dirs;
62150
62180
  try {
62151
62181
  dirs = (await readdir3(specsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
@@ -62154,10 +62184,10 @@ async function discoverFeatures(repoDir) {
62154
62184
  }
62155
62185
  const features = [];
62156
62186
  for (const dir of dirs.sort(naturalCompare)) {
62157
- const tasksText = await readOptional2(join17(specsDir, dir, "tasks.md"));
62187
+ const tasksText = await readOptional2(join15(specsDir, dir, "tasks.md"));
62158
62188
  if (tasksText === void 0) continue;
62159
- const { phases, block: block2 } = parseTasksFile(tasksText, join17("specs", dir, "tasks.md"));
62160
- const specText = await readOptional2(join17(specsDir, dir, "spec.md")) ?? "";
62189
+ const { phases, block: block2 } = parseTasksFile(tasksText, join15("specs", dir, "tasks.md"));
62190
+ const specText = await readOptional2(join15(specsDir, dir, "spec.md")) ?? "";
62161
62191
  const number4 = /^(\d+)(?:-|$)/.exec(dir)?.[1];
62162
62192
  features.push({ dir, key: number4 ?? slugify2(dir).replace(/-/g, ""), phases, block: block2, stories: parseStories(specText), specText });
62163
62193
  }
@@ -62267,7 +62297,7 @@ async function gitRoot(deps, label2) {
62267
62297
  function boundProject(deps, root) {
62268
62298
  const bound = readBindingFile(root);
62269
62299
  if (bound.kind !== "ok") {
62270
- throw new CliError(bound.kind === "missing" ? "this project is not connected; run `overlane connect` first" : `.harness/project.json is invalid (${bound.detail}); run \`overlane connect\``, {
62300
+ throw new CliError(bound.kind === "missing" ? "this project is not connected; run `overlane connect` first" : `.overlane/state/project.json is invalid (${bound.detail}); run \`overlane connect\``, {
62271
62301
  code: "not_connected",
62272
62302
  exit: EXIT.conflict,
62273
62303
  hint: "overlane connect"
@@ -62304,7 +62334,7 @@ function otherAgent(name2) {
62304
62334
  }
62305
62335
 
62306
62336
  // ../cli/src/task/usage.ts
62307
- import { join as join18 } from "node:path";
62337
+ import { join as join16 } from "node:path";
62308
62338
  var FIVE_HOUR_WARN_PERCENT = 85;
62309
62339
  var WEEKLY_WARN_PERCENT = 90;
62310
62340
  var UNDATED_MAX_AGE_MS = 60 * 60 * 1e3;
@@ -62316,7 +62346,7 @@ function window2(value) {
62316
62346
  }
62317
62347
  function readUsage(deps) {
62318
62348
  try {
62319
- const text2 = readText(join18(deps.paths.configDir, "usage.json"));
62349
+ const text2 = readText(join16(deps.paths.configDir, "usage.json"));
62320
62350
  if (text2 === null) return null;
62321
62351
  const raw = JSON.parse(text2);
62322
62352
  if (typeof raw.updatedAt !== "number") return null;
@@ -62412,17 +62442,18 @@ function summarizeTask(view) {
62412
62442
  }
62413
62443
 
62414
62444
  // ../cli/src/task/workcopy.ts
62445
+ init_src();
62415
62446
  import { createHash as createHash3 } from "node:crypto";
62416
- import { lstatSync, readFileSync as readFileSync6, readlinkSync } from "node:fs";
62417
- import { join as join19 } from "node:path";
62418
- var isHarnessPath = (path) => path === ".harness" || path.startsWith(".harness/");
62447
+ import { lstatSync, readFileSync as readFileSync7, readlinkSync } from "node:fs";
62448
+ import { join as join17 } from "node:path";
62449
+ var isHarnessPath = (path) => isStatePath(path);
62419
62450
  var CONTENT_LIMIT = 16 * 1024 * 1024;
62420
62451
  function untrackedLine(root, path) {
62421
62452
  try {
62422
- const info2 = lstatSync(join19(root, path));
62423
- if (info2.isSymbolicLink()) return `${path}\0l:${readlinkSync(join19(root, path))}`;
62453
+ const info2 = lstatSync(join17(root, path));
62454
+ if (info2.isSymbolicLink()) return `${path}\0l:${readlinkSync(join17(root, path))}`;
62424
62455
  if (info2.isFile()) {
62425
- return info2.size <= CONTENT_LIMIT ? `${path}\0f:${createHash3("sha256").update(readFileSync6(join19(root, path))).digest("hex")}` : `${path}\0s:${info2.size}`;
62456
+ return info2.size <= CONTENT_LIMIT ? `${path}\0f:${createHash3("sha256").update(readFileSync7(join17(root, path))).digest("hex")}` : `${path}\0s:${info2.size}`;
62426
62457
  }
62427
62458
  } catch {
62428
62459
  }
@@ -62521,7 +62552,7 @@ async function heldTask(ctx) {
62521
62552
  const lease = view.contract.lease;
62522
62553
  if (view.state === "paused" || lease === void 0 || lease.fencingToken !== state.fencingToken) {
62523
62554
  removeTaskState(ctx.root);
62524
- throw new CliError(`task ${state.taskId} is ${view.state} and this working copy no longer holds its lease; cleared .harness/task.json`, {
62555
+ throw new CliError(`task ${state.taskId} is ${view.state} and this working copy no longer holds its lease; cleared .overlane/state/task.json`, {
62525
62556
  code: "lease_lost",
62526
62557
  exit: EXIT.conflict,
62527
62558
  hint: `overlane task resume ${state.taskId}`
@@ -62617,7 +62648,7 @@ async function startTask(deps, input2) {
62617
62648
  body: { requestId: "cli-<uuid>", expectedVersion: "<version from the first response>", holder: holderFor(executorName), executor, ttlSeconds: LEASE_TTL_SECONDS }
62618
62649
  }
62619
62650
  ],
62620
- writes: [{ path: ".harness/task.json", action: "write", description: "the lease and fencing token of the claimed task (never committed)" }]
62651
+ writes: [{ path: ".overlane/state/task.json", action: "write", description: "the lease and fencing token of the claimed task (never committed)" }]
62621
62652
  })
62622
62653
  );
62623
62654
  }
@@ -62656,7 +62687,7 @@ async function taskStatus(deps) {
62656
62687
  const lease = view.contract.lease;
62657
62688
  const leaseHeld = lease !== void 0 && lease.fencingToken === state.fencingToken;
62658
62689
  if (!leaseHeld) {
62659
- say(deps, "This working copy no longer holds the lease; `.harness/task.json` is stale. Use `overlane task resume` to claim the task again.");
62690
+ say(deps, "This working copy no longer holds the lease; `.overlane/state/task.json` is stale. Use `overlane task resume` to claim the task again.");
62660
62691
  } else {
62661
62692
  writeTaskState(ctx.root, { ...state, expectedVersion: view.version });
62662
62693
  }
@@ -62699,7 +62730,7 @@ async function writeCheckpoint(deps, input2) {
62699
62730
  dryRunPlan({
62700
62731
  service: project.serviceUrl,
62701
62732
  requests: [{ method: "POST", path: taskPaths.operation(tenantId, projectId, state2.taskId, "checkpoint"), body: request2, note: "expectedVersion is read from the service when this runs for real" }],
62702
- writes: input2.pause === void 0 ? [] : [{ path: ".harness/task.json", action: "delete", description: "the lease ends when the task is paused" }]
62733
+ writes: input2.pause === void 0 ? [] : [{ path: ".overlane/state/task.json", action: "delete", description: "the lease ends when the task is paused" }]
62703
62734
  })
62704
62735
  );
62705
62736
  return { kind: "planned", outcome };
@@ -62763,7 +62794,7 @@ async function resumeTask(deps, input2) {
62763
62794
  note: "sent only if the working copy matches the latest checkpoint's recovery route"
62764
62795
  }
62765
62796
  ],
62766
- writes: [{ path: ".harness/task.json", action: "write", description: "the lease and fencing token of the claimed task (never committed)" }]
62797
+ writes: [{ path: ".overlane/state/task.json", action: "write", description: "the lease and fencing token of the claimed task (never committed)" }]
62767
62798
  })
62768
62799
  );
62769
62800
  }
@@ -62821,7 +62852,7 @@ async function submitTask(deps, input2) {
62821
62852
  dryRunPlan({
62822
62853
  service: project.serviceUrl,
62823
62854
  requests: [{ method: "POST", path: taskPaths.operation(tenantId, projectId, state2.taskId, "submit"), body: request2, note: "expectedVersion is read from the service when this runs for real" }],
62824
- writes: [{ path: ".harness/task.json", action: "write", description: "the new task version" }]
62855
+ writes: [{ path: ".overlane/state/task.json", action: "write", description: "the new task version" }]
62825
62856
  })
62826
62857
  );
62827
62858
  }
@@ -62892,7 +62923,7 @@ async function recordEvidence(deps, input2) {
62892
62923
  const checkId = checkIdFor(command);
62893
62924
  if (!view.contract.requiredChecks.some((check2) => check2.id === checkId)) {
62894
62925
  throw new CliError(
62895
- `no required check of task ${taskId} matches this command (check ${checkId}); pass the verification command exactly as written in .harness/plan/tasks/${taskId}.md. Required checks: ${view.contract.requiredChecks.map((check2) => check2.id).join(", ") || "none"}`,
62926
+ `no required check of task ${taskId} matches this command (check ${checkId}); pass the verification command exactly as written in .overlane/plan/tasks/${taskId}.md. Required checks: ${view.contract.requiredChecks.map((check2) => check2.id).join(", ") || "none"}`,
62896
62927
  { code: "no_matching_check", exit: EXIT.notFound, hint: `overlane task status` }
62897
62928
  );
62898
62929
  }
@@ -63075,7 +63106,7 @@ async function startRun(deps, input2) {
63075
63106
  { method: "GET", path: kitPaths.policy(tenantId, projectId), note: "a paused policy or an executor outside executorsAllowed stops here with exit 6" },
63076
63107
  { method: "POST", path: kitPaths.runs(tenantId, projectId), body: StartRunRequest.parse({ requestId: requestId2(), executor: executorFor(executor2 === "codex" ? "codex" : "claude-code"), trigger }) }
63077
63108
  ],
63078
- writes: [{ path: ".harness/run.json", action: "write", description: "the run id, start time and policy snapshot (never committed)" }]
63109
+ writes: [{ path: ".overlane/state/run.json", action: "write", description: "the run id, start time and policy snapshot (never committed)" }]
63079
63110
  })
63080
63111
  );
63081
63112
  }
@@ -63167,8 +63198,8 @@ async function claimTask(deps, input2) {
63167
63198
  }
63168
63199
  ],
63169
63200
  writes: [
63170
- { path: ".harness/task.json", action: "write", description: "the lease and fencing token of the claimed task" },
63171
- { path: ".harness/run.json", action: "write", description: "adds the task to the run's claimed list" }
63201
+ { path: ".overlane/state/task.json", action: "write", description: "the lease and fencing token of the claimed task" },
63202
+ { path: ".overlane/state/run.json", action: "write", description: "adds the task to the run's claimed list" }
63172
63203
  ]
63173
63204
  })
63174
63205
  );
@@ -63211,9 +63242,9 @@ async function claimTask(deps, input2) {
63211
63242
  for (const criterion of contract.acceptanceCriteria) say(deps, ` - ${criterion}`);
63212
63243
  const commands = await verificationCommands(ctx.root, taskId);
63213
63244
  if (commands === null) {
63214
- say(deps, `Verification commands: see .harness/plan/tasks/${taskId}.md`);
63245
+ say(deps, `Verification commands: see .overlane/plan/tasks/${taskId}.md`);
63215
63246
  } else {
63216
- say(deps, `Verification commands (from .harness/plan/tasks/${taskId}.md; pass each one exactly as written to \`overlane task evidence\`):`);
63247
+ say(deps, `Verification commands (from .overlane/plan/tasks/${taskId}.md; pass each one exactly as written to \`overlane task evidence\`):`);
63217
63248
  for (const command of commands) say(deps, ` $ ${command}`);
63218
63249
  }
63219
63250
  return {
@@ -63224,7 +63255,7 @@ async function claimTask(deps, input2) {
63224
63255
  allowedPaths: [...contract.scope.allowedPaths],
63225
63256
  acceptanceCriteria: [...contract.acceptanceCriteria],
63226
63257
  verificationCommands: commands === null ? null : [...commands],
63227
- planFile: `.harness/plan/tasks/${taskId}.md`
63258
+ planFile: `.overlane/plan/tasks/${taskId}.md`
63228
63259
  }
63229
63260
  };
63230
63261
  } catch (error62) {
@@ -63271,7 +63302,7 @@ async function endRun(deps, input2) {
63271
63302
  dryRunPlan({
63272
63303
  service: project.serviceUrl,
63273
63304
  requests: [{ method: "POST", path: kitPaths.endRun(project.binding.tenantId, project.binding.projectId, run4.runId), body: EndRunRequest.parse({ requestId: requestId2(), stopReason: reason }) }],
63274
- writes: [{ path: ".harness/run.json", action: "delete", description: "the run ends" }]
63305
+ writes: [{ path: ".overlane/state/run.json", action: "delete", description: "the run ends" }]
63275
63306
  })
63276
63307
  );
63277
63308
  }
@@ -63283,7 +63314,7 @@ async function endRun(deps, input2) {
63283
63314
  } catch (error62) {
63284
63315
  if (error62 instanceof ServiceError && error62.code === "run_not_found") {
63285
63316
  removeRunState(ctx.root);
63286
- throw new CliError(`${error62.message}; removed the stale .harness/run.json`, { code: "run_not_found", exit: EXIT.notFound, hint: "overlane run start" });
63317
+ throw new CliError(`${error62.message}; removed the stale .overlane/state/run.json`, { code: "run_not_found", exit: EXIT.notFound, hint: "overlane run start" });
63287
63318
  }
63288
63319
  throw error62;
63289
63320
  }
@@ -63566,7 +63597,7 @@ var contextCommand = defineCommand({
63566
63597
  // ../cli/src/commands/lib.ts
63567
63598
  init_src();
63568
63599
  init_zod();
63569
- import { existsSync as existsSync4, readFileSync as readFileSync7 } from "node:fs";
63600
+ import { existsSync as existsSync4, readFileSync as readFileSync8 } from "node:fs";
63570
63601
  import { basename as basename4, resolve as resolve7 } from "node:path";
63571
63602
  var SERVICE_FLAG = { name: "service", type: "string", value: "URL", description: "The service address (default: OVERLANE_SERVICE_URL, then the project's binding, then the hosted service)" };
63572
63603
  var TEAM_FLAG = { name: "team", type: "string", value: "TENANT_ID", description: "The team (tenant) to act on (default: the one your token belongs to)" };
@@ -63682,7 +63713,7 @@ function readLockfiles(paths) {
63682
63713
  const kind = LOCKFILES.find(([pattern]) => pattern.test(basename4(file2)))?.[1];
63683
63714
  if (kind === void 0) throw new UsageError(`${file2} is not a lockfile this command reads`, { hint: "supported: package-lock.json, pnpm-lock.yaml, yarn.lock, requirements.txt, uv.lock, Cargo.lock, go.sum" });
63684
63715
  try {
63685
- return { kind, content: readFileSync7(resolve7(file2), "utf8") };
63716
+ return { kind, content: readFileSync8(resolve7(file2), "utf8") };
63686
63717
  } catch {
63687
63718
  throw new UsageError(`cannot read ${file2}`);
63688
63719
  }
@@ -63775,7 +63806,7 @@ var libAddCommand = defineCommand({
63775
63806
  if (version2 === void 0 || files.length === 0) throw new UsageError("add needs --version and at least one --file", { hint: "overlane lib add <library> --version 1.0.0 --file README.md" });
63776
63807
  const pages = files.map((file2) => {
63777
63808
  try {
63778
- return { title: basename4(file2), text: readFileSync7(resolve7(file2), "utf8") };
63809
+ return { title: basename4(file2), text: readFileSync8(resolve7(file2), "utf8") };
63779
63810
  } catch {
63780
63811
  throw new UsageError(`cannot read ${file2}`);
63781
63812
  }
@@ -64478,7 +64509,7 @@ var billingCommands = [
64478
64509
  init_src();
64479
64510
  init_zod();
64480
64511
  import { randomUUID as randomUUID4 } from "node:crypto";
64481
- import { readFileSync as readFileSync8, statSync } from "node:fs";
64512
+ import { readFileSync as readFileSync9, statSync } from "node:fs";
64482
64513
  import { resolve as resolve8 } from "node:path";
64483
64514
  var common3 = { needsAuth: true, needsNetwork: true };
64484
64515
  var requestId4 = () => `cli-${randomUUID4()}`;
@@ -64691,7 +64722,7 @@ function readPushFiles(inv) {
64691
64722
  let content;
64692
64723
  try {
64693
64724
  if (statSync(absolute).size > 5e6) throw new UsageError(`${path} is larger than 5 MB; push it with git and a token instead`, { hint: `overlane repo token <repo> --scope write` });
64694
- content = readFileSync8(absolute, "utf8");
64725
+ content = readFileSync9(absolute, "utf8");
64695
64726
  } catch (error62) {
64696
64727
  if (error62 instanceof UsageError) throw error62;
64697
64728
  throw new UsageError(`could not read ${path}`);
@@ -65075,7 +65106,7 @@ var repoCommands = [
65075
65106
  // ../cli/src/commands/ci.ts
65076
65107
  init_src();
65077
65108
  init_zod();
65078
- import { readFileSync as readFileSync9 } from "node:fs";
65109
+ import { readFileSync as readFileSync10 } from "node:fs";
65079
65110
  import { resolve as resolve9 } from "node:path";
65080
65111
  var RUN_ARG = { name: "run", required: true, description: "The run ID" };
65081
65112
  function arg2(inv, index, what, hint) {
@@ -65104,7 +65135,7 @@ var ciValidateCommand = defineCommand({
65104
65135
  const file2 = textFlag(inv, "file") ?? PIPELINE_CONFIG_PATH;
65105
65136
  let text2;
65106
65137
  try {
65107
- text2 = readFileSync9(resolve9(inv.deps.paths.cwd, file2), "utf8");
65138
+ text2 = readFileSync10(resolve9(inv.deps.paths.cwd, file2), "utf8");
65108
65139
  } catch {
65109
65140
  throw new UsageError(`could not read ${file2}`, { hint: "overlane ci validate --file <path>" });
65110
65141
  }
@@ -65608,7 +65639,7 @@ var deployCommands = [deployTargetsCommand, deployTargetAddCommand, deployEnvCre
65608
65639
  init_src();
65609
65640
  init_zod();
65610
65641
  import { randomUUID as randomUUID5 } from "node:crypto";
65611
- import { readFileSync as readFileSync10 } from "node:fs";
65642
+ import { readFileSync as readFileSync11 } from "node:fs";
65612
65643
  import { resolve as resolve10 } from "node:path";
65613
65644
  var common4 = { needsAuth: true, needsNetwork: true };
65614
65645
  var requestId5 = () => `cli-${randomUUID5()}`;
@@ -65620,9 +65651,9 @@ async function planned3(inv, method, path, body2, note) {
65620
65651
  const project = await offlineProject(inv.deps, "guard");
65621
65652
  return planOutcome(inv.deps, dryRunPlan({ service: project.serviceUrl, requests: [{ method, path: path(project.binding.tenantId), ...body2 === void 0 ? {} : { body: body2 }, ...note === void 0 ? {} : { note } }] }));
65622
65653
  }
65623
- function readText3(inv, path) {
65654
+ function readText4(inv, path) {
65624
65655
  try {
65625
- return readFileSync10(resolve10(inv.deps.paths.cwd, path), "utf8");
65656
+ return readFileSync11(resolve10(inv.deps.paths.cwd, path), "utf8");
65626
65657
  } catch {
65627
65658
  throw new UsageError(`could not read ${path}`, { hint: "overlane guard rules test --file rules.json --tool git.push" });
65628
65659
  }
@@ -65697,7 +65728,7 @@ var guardRulesTestCommand = defineCommand({
65697
65728
  if (file2 === void 0) throw new UsageError("rules test needs --file", { hint: "overlane guard rules test --file rules.json --tool git.push" });
65698
65729
  let json2;
65699
65730
  try {
65700
- json2 = JSON.parse(readText3(inv, file2));
65731
+ json2 = JSON.parse(readText4(inv, file2));
65701
65732
  } catch (error62) {
65702
65733
  if (error62 instanceof UsageError) throw error62;
65703
65734
  throw new UsageError(`${file2} is not valid JSON`);
@@ -65753,7 +65784,7 @@ var guardRulesPutCommand = defineCommand({
65753
65784
  const offline = await offlineProject(inv.deps, "guard");
65754
65785
  return planOutcome(inv.deps, dryRunPlan({ service: offline.serviceUrl, requests: [{ method: "PUT", path: guardPaths.rules(offline.binding.tenantId), body: { requestId: "<generated>", layer, ...layer === "project" ? { projectId: offline.binding.projectId } : {}, content: `<contents of ${file2}>`, ...reason === void 0 ? {} : { reason } }, note: "the file is validated and scanned for credentials on the server" }] }));
65755
65786
  }
65756
- const content = readText3(inv, file2);
65787
+ const content = readText4(inv, file2);
65757
65788
  const { call: call2, tenantId, projectId } = await connected3(inv);
65758
65789
  return { data: await call2(GuardRuleFileRecord, "PUT", guardPaths.rules(tenantId), { requestId: requestId5(), layer, ...layer === "project" ? { projectId } : {}, content, ...reason === void 0 ? {} : { reason } }) };
65759
65790
  }
@@ -65765,7 +65796,7 @@ async function evaluate(inv, dryRun) {
65765
65796
  ...actionOf(inv),
65766
65797
  ...textFlag(inv, "task") === void 0 ? {} : { taskHeld: textFlag(inv, "task") === "held" },
65767
65798
  ...textFlag(inv, "summary") === void 0 ? {} : { summary: textFlag(inv, "summary") },
65768
- ...contentFile === void 0 ? {} : { content: readText3(inv, contentFile) },
65799
+ ...contentFile === void 0 ? {} : { content: readText4(inv, contentFile) },
65769
65800
  ...dryRun ? { dryRun: true } : {}
65770
65801
  };
65771
65802
  const approval = textFlag(inv, "approval");
@@ -65826,7 +65857,7 @@ var guardScanCommand = defineCommand({
65826
65857
  const path = textFlag(inv, "path");
65827
65858
  if (path === void 0) throw new UsageError("scan needs --path", { hint: "overlane guard scan --path src/config.ts" });
65828
65859
  const { call: call2, tenantId } = await connected3(inv);
65829
- const result = await call2(SecretScanResult, "POST", guardPaths.scan(tenantId), { source: textFlag(inv, "source") ?? "push", content: readText3(inv, path), path });
65860
+ const result = await call2(SecretScanResult, "POST", guardPaths.scan(tenantId), { source: textFlag(inv, "source") ?? "push", content: readText4(inv, path), path });
65830
65861
  return result.blocked ? { data: result, exit: EXIT.blocked, error: new CliError("a credential was found; nothing should be pushed until it is removed and rotated", { code: "secret_detected", exit: EXIT.blocked, hint: "overlane guard scan --path <file>" }) } : { data: result };
65831
65862
  }
65832
65863
  });
@@ -66147,7 +66178,7 @@ var memoryCommands = [memorySearchCommand, memoryAddCommand, memoryConfirmComman
66147
66178
  init_src();
66148
66179
  init_zod();
66149
66180
  import { randomUUID as randomUUID7 } from "node:crypto";
66150
- import { readFileSync as readFileSync11 } from "node:fs";
66181
+ import { readFileSync as readFileSync12 } from "node:fs";
66151
66182
  var common6 = { needsAuth: true, needsNetwork: true };
66152
66183
  var requestId7 = () => `cli-${randomUUID7()}`;
66153
66184
  var PRIORITIES = ["P0", "P1", "P2", "P3"];
@@ -66341,7 +66372,7 @@ var issueImportCommand = defineCommand({
66341
66372
  if (file2 === void 0) throw new UsageError("import needs the path of the export file");
66342
66373
  let data;
66343
66374
  try {
66344
- data = JSON.parse(readFileSync11(file2, "utf8"));
66375
+ data = JSON.parse(readFileSync12(file2, "utf8"));
66345
66376
  } catch {
66346
66377
  throw new UsageError(`${file2} is not a readable JSON file`);
66347
66378
  }
@@ -67220,8 +67251,11 @@ var ConnectKitResult = external_exports.union([
67220
67251
  var ConnectAny = external_exports.union([ConnectResult, DryRunResult]);
67221
67252
 
67222
67253
  // ../cli/src/disconnect.ts
67223
- import { join as join20 } from "node:path";
67254
+ import { join as join18 } from "node:path";
67224
67255
  init_zod();
67256
+ init_src();
67257
+ init_overlane_paths_node();
67258
+ import { existsSync as existsSync5, readdirSync } from "node:fs";
67225
67259
  var DisconnectResult = withDryRun(
67226
67260
  external_exports.object({
67227
67261
  /** False when the project had nothing overlane added. */
@@ -67240,14 +67274,14 @@ async function disconnect(deps, options) {
67240
67274
  const owned = readOwned(root);
67241
67275
  const binding = readBindingFile(root);
67242
67276
  if (owned === null) {
67243
- say(deps, "Nothing to disconnect: this project has no .harness/owned.json, so overlane added nothing here.");
67244
- return { data: { disconnected: false, commands: [], removed: [], tokenDeleted: false, note: "this project has no .harness/owned.json, so overlane added nothing here" } };
67277
+ say(deps, "Nothing to disconnect: this project has no .overlane/state/owned.json, so overlane added nothing here.");
67278
+ return { data: { disconnected: false, commands: [], removed: [], tokenDeleted: false, note: "this project has no .overlane/state/owned.json, so overlane added nothing here" } };
67245
67279
  }
67246
67280
  const steps = [];
67247
67281
  if (owned.claude !== void 0) steps.push(...claudeRemoveSteps(readClaudeState(root), owned.claude));
67248
67282
  const codexState = readCodexState(deps, root);
67249
67283
  if (owned.codex !== void 0) steps.push(...codexRemoveSteps(codexState, owned.codex));
67250
- const configPath = join20(root, CODEX_CONFIG_FILE);
67284
+ const configPath = join18(root, CODEX_CONFIG_FILE);
67251
67285
  const lines = owned.codex?.configLines;
67252
67286
  const configText = readText(configPath);
67253
67287
  const configRemovable = lines !== void 0 && configText !== null && configText.includes(lines.text);
@@ -67256,14 +67290,12 @@ async function disconnect(deps, options) {
67256
67290
  $ ${formatCommand(step2)}`);
67257
67291
  if (configRemovable) say(deps, ` remove the lines overlane added to ${CODEX_CONFIG_FILE}`);
67258
67292
  say(deps, ` delete ${BINDING_FILE} and ${OWNED_FILE}`);
67259
- if (owned.excludeLine) say(deps, ` remove ${EXCLUDE_LINE} from ${await excludePath(deps, root)}`);
67260
67293
  say(deps, ` delete the stored token for ${owned.serviceUrl}`);
67261
67294
  if (options.dryRun) {
67262
67295
  say(deps, "Dry run: no command was run and no file was changed.");
67263
67296
  const writes = [];
67264
67297
  if (configRemovable) writes.push({ path: CODEX_CONFIG_FILE, action: "write", description: "remove the lines overlane added" });
67265
67298
  writes.push({ path: BINDING_FILE, action: "delete", description: "the project binding" }, { path: OWNED_FILE, action: "delete", description: "the record of what connect added" });
67266
- if (owned.excludeLine) writes.push({ path: await excludePath(deps, root), action: "write", description: `remove ${EXCLUDE_LINE}` });
67267
67299
  return {
67268
67300
  data: dryRunPlan({
67269
67301
  commands: steps.map((step2) => formatCommand(step2)),
@@ -67292,7 +67324,7 @@ async function disconnect(deps, options) {
67292
67324
  const without = configText.replace(lines.text, "");
67293
67325
  if (without.length === 0 && lines.createdFile) {
67294
67326
  removeFile(configPath);
67295
- removeDirIfEmpty(join20(root, ".codex"));
67327
+ removeDirIfEmpty(join18(root, ".codex"));
67296
67328
  } else {
67297
67329
  writeIfDifferent(configPath, without);
67298
67330
  }
@@ -67302,17 +67334,21 @@ async function disconnect(deps, options) {
67302
67334
  if (failures.length > 0) {
67303
67335
  writeOwned(root, remaining);
67304
67336
  for (const failure4 of failures) warn(deps, failure4);
67305
- throw new CliError("some native commands failed; the connection is only partly removed, and .harness/owned.json keeps what is left. Fix the cause and run `overlane disconnect` again", {
67337
+ throw new CliError("some native commands failed; the connection is only partly removed, and owned.json in the state folder keeps what is left. Fix the cause and run `overlane disconnect` again", {
67306
67338
  code: "partial_disconnect",
67307
67339
  hint: "overlane disconnect --force"
67308
67340
  });
67309
67341
  }
67310
- if (owned.excludeLine) await removeExclude(deps, root);
67311
- removeFile(join20(root, BINDING_FILE));
67342
+ removeFile(statePath(root, "binding"));
67312
67343
  removed.push(BINDING_FILE, OWNED_FILE);
67313
67344
  removeOwned(root);
67314
- removeFile(join20(root, ".harness", "misses.log"));
67315
- removeDirIfEmpty(join20(root, ".harness"));
67345
+ removeFile(statePath(root, "misses"));
67346
+ const state = join18(root, STATE_DIR);
67347
+ if (existsSync5(state) && readdirSync(state).every((name2) => name2 === ".gitignore")) {
67348
+ removeFile(join18(state, ".gitignore"));
67349
+ removeDirIfEmpty(state);
67350
+ }
67351
+ removeDirIfEmpty(join18(root, OVERLANE_DIR));
67316
67352
  const serviceUrl = binding.kind === "ok" ? binding.binding.serviceUrl : owned.serviceUrl;
67317
67353
  await deleteTokens(deps, serviceUrl);
67318
67354
  if (await loadTokens(deps, serviceUrl) !== null) {
@@ -67331,17 +67367,17 @@ init_zod();
67331
67367
 
67332
67368
  // ../cli/src/rules.ts
67333
67369
  init_src();
67334
- import { existsSync as existsSync5, lstatSync as lstatSync2, mkdirSync as mkdirSync8, readFileSync as readFileSync12, renameSync as renameSync5, writeFileSync as writeFileSync7 } from "node:fs";
67335
- import { dirname as dirname8, join as join21 } from "node:path";
67370
+ import { existsSync as existsSync6, lstatSync as lstatSync2, mkdirSync as mkdirSync9, readFileSync as readFileSync13, renameSync as renameSync5, writeFileSync as writeFileSync8 } from "node:fs";
67371
+ import { dirname as dirname6, join as join19 } from "node:path";
67336
67372
  function readIfRegular(root, relative6, unsafe) {
67337
- const full = join21(root, relative6);
67338
- if (!existsSync5(full) && !isLink(full)) return null;
67373
+ const full = join19(root, relative6);
67374
+ if (!existsSync6(full) && !isLink(full)) return null;
67339
67375
  const stat = lstatSync2(full);
67340
67376
  if (stat.isSymbolicLink() || !stat.isFile()) {
67341
67377
  unsafe.push(relative6);
67342
67378
  return null;
67343
67379
  }
67344
- return readFileSync12(full, "utf8");
67380
+ return readFileSync13(full, "utf8");
67345
67381
  }
67346
67382
  function isLink(path) {
67347
67383
  try {
@@ -67380,10 +67416,10 @@ function applyPlan2(root, plan3) {
67380
67416
  const written = [];
67381
67417
  for (const step2 of plan3.steps) {
67382
67418
  if (step2.next === null) continue;
67383
- const full = join21(root, step2.path);
67384
- mkdirSync8(dirname8(full), { recursive: true });
67419
+ const full = join19(root, step2.path);
67420
+ mkdirSync9(dirname6(full), { recursive: true });
67385
67421
  const temp = `${full}.overlane-tmp`;
67386
- writeFileSync7(temp, step2.next, { encoding: "utf8", mode: 420 });
67422
+ writeFileSync8(temp, step2.next, { encoding: "utf8", mode: 420 });
67387
67423
  renameSync5(temp, full);
67388
67424
  written.push(step2.path);
67389
67425
  }
@@ -67482,22 +67518,22 @@ async function doctor(deps, options) {
67482
67518
  // ../cli/src/kit/setup.ts
67483
67519
  init_src();
67484
67520
  import { randomUUID as randomUUID9 } from "node:crypto";
67485
- import { existsSync as existsSync7, readdirSync as readdirSync2 } from "node:fs";
67486
- import { join as join23 } from "node:path";
67521
+ import { existsSync as existsSync8, readdirSync as readdirSync3 } from "node:fs";
67522
+ import { join as join21 } from "node:path";
67487
67523
 
67488
67524
  // ../cli/src/kit/ci.ts
67489
- import { existsSync as existsSync6, readdirSync } from "node:fs";
67490
- import { join as join22 } from "node:path";
67525
+ import { existsSync as existsSync7, readdirSync as readdirSync2 } from "node:fs";
67526
+ import { join as join20 } from "node:path";
67491
67527
  var ACTION_PINS = {
67492
67528
  checkout: "actions/checkout@v7.0.1",
67493
67529
  setupNode: "actions/setup-node@v7.0.0",
67494
67530
  pnpm: "pnpm/action-setup@v6.1.0",
67495
67531
  setupPython: "actions/setup-python@v7.0.0"
67496
67532
  };
67497
- var CI_FILE = join22(".github", "workflows", "ci.yml");
67533
+ var CI_FILE = join20(".github", "workflows", "ci.yml");
67498
67534
  function hasCi(root) {
67499
67535
  try {
67500
- return readdirSync(join22(root, ".github", "workflows")).some((name2) => /\.ya?ml$/.test(name2));
67536
+ return readdirSync2(join20(root, ".github", "workflows")).some((name2) => /\.ya?ml$/.test(name2));
67501
67537
  } catch {
67502
67538
  return false;
67503
67539
  }
@@ -67509,12 +67545,12 @@ function ciWorkflow(root, detected) {
67509
67545
  for (const run3 of detected.typecheck ?? []) commands.push({ name: "Typecheck", run: run3 });
67510
67546
  for (const run3 of detected.test) commands.push({ name: "Test", run: run3 });
67511
67547
  if (!commands.some((command) => command.name !== "Install")) return null;
67512
- const node2 = existsSync6(join22(root, "package.json"));
67513
- const python = existsSync6(join22(root, "pyproject.toml"));
67548
+ const node2 = existsSync7(join20(root, "package.json"));
67549
+ const python = existsSync7(join20(root, "pyproject.toml"));
67514
67550
  const steps = [` - uses: ${ACTION_PINS.checkout}`];
67515
67551
  if (node2) {
67516
67552
  if (detected.install?.startsWith("pnpm")) steps.push(` - uses: ${ACTION_PINS.pnpm}`);
67517
- const version2 = existsSync6(join22(root, ".nvmrc")) ? "node-version-file: .nvmrc" : "node-version: 22";
67553
+ const version2 = existsSync7(join20(root, ".nvmrc")) ? "node-version-file: .nvmrc" : "node-version: 22";
67518
67554
  steps.push(` - uses: ${ACTION_PINS.setupNode}`, " with:", ` ${version2}`);
67519
67555
  }
67520
67556
  if (python) {
@@ -67532,7 +67568,7 @@ var BLOCK_END = "<!-- overlane-kit:run-step:end -->";
67532
67568
  var BLOCK_BODY = [
67533
67569
  "## Autonomous runs",
67534
67570
  "",
67535
- "The plan is in `.harness/plan/`. To work on it, use the run-step skill: one bounded run, one task at a time, within the task's allowed paths.",
67571
+ "The plan is in `.overlane/plan/`. To work on it, use the run-step skill: one bounded run, one task at a time, within the task's allowed paths.",
67536
67572
  AGENTS_LINE,
67537
67573
  "Decide questions yourself and record the decision with `overlane run decide`; do not wait for an answer."
67538
67574
  ].join("\n");
@@ -67556,7 +67592,7 @@ var INSTRUCTION_FILES = ["CLAUDE.md", "AGENTS.md"];
67556
67592
  var runPrompt = (projectId) => `Run one bounded step with the run-step skill for project ${projectId}.`;
67557
67593
  function hasSpecKit(root) {
67558
67594
  try {
67559
- return readdirSync2(join23(root, "specs"), { withFileTypes: true }).some((entry) => entry.isDirectory() && existsSync7(join23(root, "specs", entry.name, "tasks.md")));
67595
+ return readdirSync3(join21(root, "specs"), { withFileTypes: true }).some((entry) => entry.isDirectory() && existsSync8(join21(root, "specs", entry.name, "tasks.md")));
67560
67596
  } catch {
67561
67597
  return false;
67562
67598
  }
@@ -67613,15 +67649,15 @@ async function connectKit(deps, options) {
67613
67649
  const project = await detectProject(deps, { name: options.name, provider: options.provider });
67614
67650
  const { root } = project;
67615
67651
  if (await headCommit(deps, root) === null) throw new CliError("the repository has no commit yet; make an initial commit first");
67616
- const planDir = join23(root, PLAN_DIR);
67617
- const planExists = existsSync7(join23(planDir, "project.md"));
67652
+ const planDir = join21(root, PLAN_DIR2);
67653
+ const planExists = existsSync8(join21(planDir, "project.md"));
67618
67654
  const ciExists = hasCi(root);
67619
67655
  let plan3;
67620
67656
  let planSource;
67621
67657
  try {
67622
67658
  if (planExists) {
67623
67659
  plan3 = await readPlan(root);
67624
- planSource = `${PLAN_DIR}/ already exists; kept as it is`;
67660
+ planSource = `${PLAN_DIR2}/ already exists; kept as it is`;
67625
67661
  } else if (options.mode === "new") {
67626
67662
  plan3 = newPlan(project.name, options.goal ?? "", !ciExists);
67627
67663
  planSource = "minimal plan from --goal";
@@ -67638,7 +67674,7 @@ async function connectKit(deps, options) {
67638
67674
  }
67639
67675
  const detected = await detectCommands(root);
67640
67676
  const workflow = ciExists ? null : ciWorkflow(root, detected);
67641
- const blocks = INSTRUCTION_FILES.map((file2) => ({ file: file2, before: readText(join23(root, file2)) })).map((entry) => ({ ...entry, after: withBlock2(entry.before) }));
67677
+ const blocks = INSTRUCTION_FILES.map((file2) => ({ file: file2, before: readText(join21(root, file2)) })).map((entry) => ({ ...entry, after: withBlock2(entry.before) }));
67642
67678
  const blockChanges = blocks.filter((entry) => entry.after !== entry.before);
67643
67679
  const firstMilestone = plan3.milestones[0]?.id ?? DEFAULT_RUN_POLICY.buildAheadLimit;
67644
67680
  const branchExists = (await gitOut(deps, root, "rev-parse", "--verify", "--quiet", `refs/heads/${KIT_BRANCH}`)).code === 0;
@@ -67648,10 +67684,10 @@ async function connectKit(deps, options) {
67648
67684
  if (unsaved.length > 0 && !options.dryRun) throw new CliError(`uncommitted changes in ${unsaved.join(", ")}; commit or stash them so the kit commit holds only its own lines`);
67649
67685
  say(deps, `Kit setup (${options.mode}) for ${projectLabel(project)}`);
67650
67686
  say(deps, ` branch: create ${KIT_BRANCH}`);
67651
- say(deps, ` plan: ${planSource} (${plan3.milestones.length} milestone(s), ${plan3.tasks.length} task(s))${planExists ? "" : `, written to ${PLAN_DIR}/`}`);
67687
+ say(deps, ` plan: ${planSource} (${plan3.milestones.length} milestone(s), ${plan3.tasks.length} task(s))${planExists ? "" : `, written to ${PLAN_DIR2}/`}`);
67652
67688
  say(deps, ciExists ? " ci: a workflow already exists; left alone" : workflow === null ? " ci: no install, typecheck or test command detected, so no workflow is written (the plan task adds it)" : ` ci: write ${CI_FILE} (pinned actions; runs ${[detected.install, ...detected.typecheck ?? [], ...detected.test].filter((c2) => c2 !== void 0).join("; ")})`);
67653
67689
  for (const entry of blocks) say(deps, ` ${entry.file}: ${entry.after === entry.before ? "block already present" : entry.before === null ? "create with the run-step block" : "append the run-step block (your text is untouched)"}`);
67654
- say(deps, " binding: the normal connect flow (plugins, .harness/project.json)");
67690
+ say(deps, " binding: the normal connect flow (plugins, .overlane/state/project.json)");
67655
67691
  say(deps, ` policy: default run policy, build-ahead limit ${firstMilestone}`);
67656
67692
  say(deps, " sync: send the plan to the service");
67657
67693
  say(deps, " review: commit on the branch and open one pull request (or print the exact commands)");
@@ -67664,7 +67700,7 @@ async function connectKit(deps, options) {
67664
67700
  say(deps, "Dry run: no file was written and no branch, commit or service change was made.");
67665
67701
  const base5 = inner.data !== void 0 && "dryRun" in inner.data ? inner.data : dryRunPlan({});
67666
67702
  const writes = [
67667
- ...planExists ? [] : [{ path: `${PLAN_DIR}/`, action: "write", description: planSource }],
67703
+ ...planExists ? [] : [{ path: `${PLAN_DIR2}/`, action: "write", description: planSource }],
67668
67704
  ...workflow === null ? [] : [{ path: CI_FILE, action: "write", description: "CI workflow with pinned actions" }],
67669
67705
  ...blockChanges.map((entry) => ({ path: entry.file, action: entry.before === null ? "write" : "append", description: "the run-step block" })),
67670
67706
  ...base5.writes
@@ -67693,22 +67729,22 @@ async function connectKit(deps, options) {
67693
67729
  await gitOk(deps, root, "switch", "-c", KIT_BRANCH);
67694
67730
  if (!planExists) await writePlan(root, plan3);
67695
67731
  const written = [];
67696
- if (workflow !== null && writeIfDifferent(join23(root, CI_FILE), workflow)) written.push(CI_FILE);
67697
- for (const entry of blockChanges) if (writeIfDifferent(join23(root, entry.file), entry.after)) written.push(entry.file);
67698
- const agentConfig = [join23(".claude", "settings.json"), join23(".codex", "config.toml")];
67732
+ if (workflow !== null && writeIfDifferent(join21(root, CI_FILE), workflow)) written.push(CI_FILE);
67733
+ for (const entry of blockChanges) if (writeIfDifferent(join21(root, entry.file), entry.after)) written.push(entry.file);
67734
+ const agentConfig = [join21(".claude", "settings.json"), join21(".codex", "config.toml")];
67699
67735
  const preDirty = new Set(await dirty(deps, root, agentConfig));
67700
- const preExisting = new Set(agentConfig.filter((file2) => existsSync7(join23(root, file2))));
67736
+ const preExisting = new Set(agentConfig.filter((file2) => existsSync8(join21(root, file2))));
67701
67737
  const connected11 = await connect(deps, { ...options, yes: true });
67702
67738
  if (connected11.error !== void 0 || readBindingFile(root).kind !== "ok") {
67703
67739
  throw new CliError(`connect did not finish; the kit files are on ${KIT_BRANCH}, uncommitted. Fix the cause and run \`overlane connect\`, then commit`, { code: "connect_incomplete", hint: "overlane connect --yes" });
67704
67740
  }
67705
67741
  const connectData = connected11.data !== void 0 && !("dryRun" in connected11.data) ? connected11.data : void 0;
67706
67742
  for (const file2 of agentConfig) {
67707
- if (!existsSync7(join23(root, file2)) || preDirty.has(file2) || preExisting.has(file2) && (await dirty(deps, root, [file2])).length === 0) continue;
67743
+ if (!existsSync8(join21(root, file2)) || preDirty.has(file2) || preExisting.has(file2) && (await dirty(deps, root, [file2])).length === 0) continue;
67708
67744
  if ((await gitOut(deps, root, "check-ignore", "-q", "--", file2)).code === 0) continue;
67709
67745
  written.push(file2);
67710
67746
  }
67711
- await gitOk(deps, root, "add", "-f", "--", PLAN_DIR);
67747
+ await gitOk(deps, root, "add", "-f", "--", PLAN_DIR2);
67712
67748
  if (written.length > 0) await gitOk(deps, root, "add", "--", ...written);
67713
67749
  await gitOk(deps, root, "commit", "-m", "Set up the project kit", "-m", `Plan files, ${workflow === null ? "no new CI" : "CI"} and the run-step block. Review, merge, then the scheduler runs bounded steps.`);
67714
67750
  const sha = (await gitOk(deps, root, "rev-parse", "HEAD")).trim();
@@ -67770,7 +67806,7 @@ var ROOT_FLAG = { name: "marketplace-root", type: "string", value: "DIR", descri
67770
67806
  var connectCommand = defineCommand({
67771
67807
  path: ["connect"],
67772
67808
  summary: "Connect this project (native Overlane, or your GitHub repository): sign in, bind it, register the plugin; --kit also sets up a plan",
67773
- description: "Works in any git project, with no GitHub account: without a GitHub origin the project is a native Overlane project named after the folder (--name renames it). With a github.com origin it binds that repository instead (--provider overlane keeps it native). Detects the installed agents, previews the plan, then (with --yes) signs in through the browser, creates or looks up the project on the service, runs the agents' native plugin commands, writes .harness/project.json and records what it added in .harness/owned.json so `overlane disconnect` removes only that. With --kit existing|new it also drafts the plan files, CI and a pull request. Without a terminal it never prompts: pass --yes, or --dry-run to preview.",
67809
+ description: "Works in any git project, with no GitHub account: without a GitHub origin the project is a native Overlane project named after the folder (--name renames it). With a github.com origin it binds that repository instead (--provider overlane keeps it native). Detects the installed agents, previews the plan, then (with --yes) signs in through the browser, creates or looks up the project on the service, runs the agents' native plugin commands, writes .overlane/state/project.json and records what it added in .overlane/state/owned.json so `overlane disconnect` removes only that. With --kit existing|new it also drafts the plan files, CI and a pull request. Without a terminal it never prompts: pass --yes, or --dry-run to preview.",
67774
67810
  flags: [
67775
67811
  { name: "service", type: "string", value: "URL", description: "Service address (https); default is the hosted service or OVERLANE_SERVICE_URL" },
67776
67812
  ROOT_FLAG,
@@ -67822,7 +67858,7 @@ var doctorCommand = defineCommand({
67822
67858
  var disconnectCommand = defineCommand({
67823
67859
  path: ["disconnect"],
67824
67860
  summary: "Remove what connect added to this project and delete the stored token",
67825
- description: "Removes only what .harness/owned.json records: the native plugin entries, the Codex config lines connect appended, the binding, and the stored token. Hosted history is untouched. Destructive: without a terminal it needs --force.",
67861
+ description: "Removes only what .overlane/state/owned.json records: the native plugin entries, the Codex config lines connect appended, the binding, and the stored token. Hosted history is untouched. Destructive: without a terminal it needs --force.",
67826
67862
  examples: ["overlane disconnect --dry-run", "overlane disconnect --force"],
67827
67863
  effect: "destructive",
67828
67864
  keywords: ["remove", "uninstall", "unlink", "detach", "undo connect", "leave", "delete binding", "forget", "sign out", "logout", "clean up"],
@@ -67925,7 +67961,7 @@ async function updateRelease(deps, input2) {
67925
67961
  { method: "GET", path: input2.to === void 0 ? releasePaths.one(tenantId, "<pinned digest>") : releasePaths.one(tenantId, input2.to) }
67926
67962
  ],
67927
67963
  commands: [...updateSteps("claude"), ...updateSteps("codex")].map((step2) => `${step2.command} ${step2.args.join(" ")}`),
67928
- writes: [{ path: ".harness/release.json", action: "write", description: "the installed release record, written only after the commands succeed" }],
67964
+ writes: [{ path: ".overlane/state/release.json", action: "write", description: "the installed release record, written only after the commands succeed" }],
67929
67965
  notes: ["No credentials were found, so the release was not read and no diff is shown."]
67930
67966
  })
67931
67967
  );
@@ -67945,7 +67981,7 @@ async function rollbackRelease(deps, input2) {
67945
67981
  service: project.serviceUrl,
67946
67982
  requests: [{ method: "POST", path: releasePaths.rollback(project.binding.tenantId, project.binding.projectId), body: {}, note: "moves the project's pin back to the previous release" }],
67947
67983
  commands: [...updateSteps("claude"), ...updateSteps("codex")].map((step2) => `${step2.command} ${step2.args.join(" ")}`),
67948
- writes: [{ path: ".harness/release.json", action: "write", description: "the installed release record, written only after the commands succeed" }],
67984
+ writes: [{ path: ".overlane/state/release.json", action: "write", description: "the installed release record, written only after the commands succeed" }],
67949
67985
  notes: ["After the pin moves, the previous release is installed the way `overlane release update` installs it."]
67950
67986
  })
67951
67987
  );
@@ -68025,7 +68061,7 @@ var releaseListCommand = defineCommand({
68025
68061
  var releaseStatusCommand = defineCommand({
68026
68062
  path: ["release", "status"],
68027
68063
  summary: "Show the installed release against the project's pin",
68028
- description: `Compares the installed release (.harness/release.json) with the project binding and the service's pin, and lists approvals recorded on this machine. Works when the service is down (the pin then reads "unreachable").`,
68064
+ description: `Compares the installed release (.overlane/state/release.json) with the project binding and the service's pin, and lists approvals recorded on this machine. Works when the service is down (the pin then reads "unreachable").`,
68029
68065
  examples: ["overlane release status"],
68030
68066
  effect: "read",
68031
68067
  ...common9,
@@ -68124,7 +68160,7 @@ var EXECUTOR = { name: "executor", type: "string", enum: ["claude-code", "codex"
68124
68160
  var STOP_NOTE = "A stop (policy paused, a budget spent, nothing runnable) exits 6 with the reason in the error code and the exact `overlane run end --reason ...` as the hint.";
68125
68161
  var runStartCommand = defineCommand({
68126
68162
  path: ["run", "start"],
68127
- summary: "Start a bounded run and record it in .harness/run.json",
68163
+ summary: "Start a bounded run and record it in .overlane/state/run.json",
68128
68164
  description: `Starts one bounded run for this working copy after checking the run policy. ${STOP_NOTE}`,
68129
68165
  flags: [{ name: "trigger", type: "string", enum: ["schedule", "interactive", "event"], default: "interactive", description: "What started the run" }, EXECUTOR],
68130
68166
  examples: ["overlane run start --trigger schedule", "overlane run start --dry-run"],
@@ -68178,7 +68214,7 @@ var runDecideCommand = defineCommand({
68178
68214
  var runEndCommand = defineCommand({
68179
68215
  path: ["run", "end"],
68180
68216
  summary: "End the active run and release its leases",
68181
- description: "Ends the run with a stop reason, removes .harness/run.json and reports how many tasks were claimed and verified. Run it even when stopping early. Exit 1 when the service reports leases that were not released.",
68217
+ description: "Ends the run with a stop reason, removes .overlane/state/run.json and reports how many tasks were claimed and verified. Run it even when stopping early. Exit 1 when the service reports leases that were not released.",
68182
68218
  flags: [{ name: "reason", type: "string", required: true, enum: RUN_STOP_REASONS, description: "Why the run ended" }],
68183
68219
  examples: ["overlane run end --reason nothing_runnable", "overlane run end --reason error"],
68184
68220
  effect: "write",
@@ -68224,17 +68260,17 @@ var runResumeCommand = defineCommand({
68224
68260
  var runCommands = [runStartCommand, runNextCommand, runClaimCommand, runDecideCommand, runEndCommand, runStatusCommand, runPauseCommand, runResumeCommand];
68225
68261
 
68226
68262
  // ../cli/src/task/queue.ts
68263
+ import { randomUUID as randomUUID10 } from "node:crypto";
68264
+ import { renameSync as renameSync6, writeFileSync as writeFileSync9 } from "node:fs";
68227
68265
  init_src();
68228
68266
  init_zod();
68229
- import { randomUUID as randomUUID10 } from "node:crypto";
68230
- import { mkdirSync as mkdirSync9, renameSync as renameSync6, writeFileSync as writeFileSync8 } from "node:fs";
68231
- import { dirname as dirname9, join as join24 } from "node:path";
68232
- var TASK_POLICY_PATH = join24(".harness", "task-policy.json");
68267
+ init_overlane_paths_node();
68268
+ var TASK_POLICY_PATH = ".overlane/state/task-policy.json";
68233
68269
  function writePolicyFile(root, policy, nowMs) {
68234
- const path = join24(root, TASK_POLICY_PATH);
68235
- mkdirSync9(dirname9(path), { recursive: true });
68270
+ ensureStateDir(root);
68271
+ const path = statePath(root, "taskPolicy");
68236
68272
  const temp = `${path}.${process.pid}.tmp`;
68237
- writeFileSync8(temp, `${JSON.stringify({ enforcement: policy.enforcement, ...policy.reason === void 0 ? {} : { reason: policy.reason }, checkedAt: new Date(nowMs).toISOString() }, null, 2)}
68273
+ writeFileSync9(temp, `${JSON.stringify({ enforcement: policy.enforcement, ...policy.reason === void 0 ? {} : { reason: policy.reason }, checkedAt: new Date(nowMs).toISOString() }, null, 2)}
68238
68274
  `);
68239
68275
  renameSync6(temp, path);
68240
68276
  }
@@ -68433,7 +68469,7 @@ var taskPrioritiseCommand = defineCommand({
68433
68469
  var taskPolicyCommand = defineCommand({
68434
68470
  path: ["task", "policy"],
68435
68471
  summary: "Show whether changes need an active task, and refresh this working copy's copy",
68436
- description: "Reads the project's task requirement (default `required`: edits and mutating shell commands are refused without an active task) and writes it to .harness/task-policy.json for the hooks.",
68472
+ description: "Reads the project's task requirement (default `required`: edits and mutating shell commands are refused without an active task) and writes it to .overlane/state/task-policy.json for the hooks.",
68437
68473
  examples: ["overlane task policy"],
68438
68474
  effect: "read",
68439
68475
  ...common11,
@@ -68823,7 +68859,7 @@ var TaskStartResult = withDryRun(
68823
68859
  external_exports.object({ taskId: external_exports.string(), version: external_exports.number(), state: external_exports.string(), holder: external_exports.string(), leaseExpiresAt: external_exports.string().optional(), next: external_exports.string() })
68824
68860
  );
68825
68861
  var TaskStatusResult = external_exports.object({
68826
- /** This working copy holds a task (`.harness/task.json`). */
68862
+ /** This working copy holds a task (`.overlane/state/task.json`). */
68827
68863
  held: external_exports.boolean(),
68828
68864
  /** The held task still has this working copy's lease. */
68829
68865
  leaseHeld: external_exports.boolean().optional(),
@@ -68869,7 +68905,7 @@ var taskListCommand = defineCommand({
68869
68905
  var taskStartCommand = defineCommand({
68870
68906
  path: ["task", "start"],
68871
68907
  summary: "Claim an existing task, or create one with a contract and claim it",
68872
- description: "With a TASK_ID, claims that ready or paused task for this working copy (same checks as `task resume`). Without one, creates a task (outcome, acceptance criteria, required checks, allowed paths) at the current commit and claims it, writing the lease to .harness/task.json. Fails with exit 5 if this working copy already holds a task.",
68908
+ description: "With a TASK_ID, claims that ready or paused task for this working copy (same checks as `task resume`). Without one, creates a task (outcome, acceptance criteria, required checks, allowed paths) at the current commit and claims it, writing the lease to .overlane/state/task.json. Fails with exit 5 if this working copy already holds a task.",
68873
68909
  args: [{ name: "task-id", required: false, description: "An existing task to claim; omit to create one from the flags" }],
68874
68910
  flags: [
68875
68911
  { name: "outcome", type: "string", value: "TEXT", description: "What the task must achieve (up to 500 characters)" },
@@ -69351,7 +69387,7 @@ var developerCommands = [
69351
69387
  // ../cli/src/commands/connector.ts
69352
69388
  init_src();
69353
69389
  init_zod();
69354
- import { readFileSync as readFileSync13 } from "node:fs";
69390
+ import { readFileSync as readFileSync14 } from "node:fs";
69355
69391
  var Summary = external_exports.object({ provider: external_exports.string(), name: external_exports.string(), domain: external_exports.string(), auth: external_exports.string(), actions: external_exports.number(), nativeAlternative: external_exports.string() });
69356
69392
  var summary = (c2) => ({ provider: c2.provider, name: c2.displayName, domain: c2.domain, auth: c2.auth.type === "oauth" ? `OAuth (${c2.auth.scopes.join(" ")})` : `key (${c2.auth.keyLabel})`, actions: c2.actions.length, nativeAlternative: c2.nativeAlternative });
69357
69393
  var Action2 = external_exports.object({ name: external_exports.string(), summary: external_exports.string(), kind: external_exports.enum(["read", "write", "destructive"]), gateClass: external_exports.string().nullable() });
@@ -69546,7 +69582,7 @@ function inputOf(inv) {
69546
69582
  const inline = textFlag(inv, "input");
69547
69583
  const file2 = textFlag(inv, "input-file");
69548
69584
  if (inline !== void 0 && file2 !== void 0) throw new UsageError("give --input or --input-file, not both", { hint: "overlane schema connector run" });
69549
- const text2 = inline ?? (file2 === void 0 ? "{}" : readFileSync13(file2, "utf8"));
69585
+ const text2 = inline ?? (file2 === void 0 ? "{}" : readFileSync14(file2, "utf8"));
69550
69586
  try {
69551
69587
  const parsed = JSON.parse(text2);
69552
69588
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("not an object");
@@ -70651,7 +70687,7 @@ var egressCommands = [egressPolicyShowCommand, egressPolicySetCommand, egressChe
70651
70687
  // ../cli/src/commands/enterprise.ts
70652
70688
  init_src();
70653
70689
  init_zod();
70654
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "node:fs";
70690
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync10 } from "node:fs";
70655
70691
  import { resolve as resolve13 } from "node:path";
70656
70692
  var common20 = { needsAuth: true, needsNetwork: true };
70657
70693
  async function connected9(inv) {
@@ -70742,8 +70778,8 @@ var enterpriseAuditExportCommand = defineCommand({
70742
70778
  const exported = await call2(AuditExport, "POST", enterprisePaths.auditExports(tenantId), {});
70743
70779
  const file2 = resolve13(inv.deps.paths.cwd, textFlag(inv, "out") ?? "audit.csv");
70744
70780
  const manifestFile = `${file2}.manifest.json`;
70745
- writeFileSync9(file2, exported.csv);
70746
- writeFileSync9(manifestFile, `${JSON.stringify(exported.manifest, null, 2)}
70781
+ writeFileSync10(file2, exported.csv);
70782
+ writeFileSync10(manifestFile, `${JSON.stringify(exported.manifest, null, 2)}
70747
70783
  `);
70748
70784
  return { data: { file: file2, manifestFile, manifest: exported.manifest } };
70749
70785
  }
@@ -70770,8 +70806,8 @@ var enterpriseAuditVerifyCommand = defineCommand({
70770
70806
  let manifest;
70771
70807
  let csv;
70772
70808
  try {
70773
- csv = readFileSync14(path, "utf8");
70774
- manifest = AuditExportManifest.parse(JSON.parse(readFileSync14(manifestPath, "utf8")));
70809
+ csv = readFileSync15(path, "utf8");
70810
+ manifest = AuditExportManifest.parse(JSON.parse(readFileSync15(manifestPath, "utf8")));
70775
70811
  } catch {
70776
70812
  throw new UsageError(`could not read ${file2} and its manifest`, { hint: "overlane enterprise audit export --out audit.csv" });
70777
70813
  }
@@ -71038,7 +71074,7 @@ var enterpriseDataExportCommand = defineCommand({
71038
71074
  const { call: call2, tenantId } = await connected9(inv);
71039
71075
  const report2 = await call2(DataExportReport, "POST", enterprisePaths.dataExport(tenantId), body2);
71040
71076
  const file2 = resolve13(inv.deps.paths.cwd, textFlag(inv, "out") ?? "export.ndjson");
71041
- writeFileSync9(file2, report2.ndjson);
71077
+ writeFileSync10(file2, report2.ndjson);
71042
71078
  return { data: { file: file2, totalRows: report2.totalRows, stores: report2.stores } };
71043
71079
  }
71044
71080
  });
@@ -71655,13 +71691,13 @@ init_src();
71655
71691
  init_zod();
71656
71692
 
71657
71693
  // ../cli/src/token/brief.ts
71658
- import { existsSync as existsSync9, readFileSync as readFileSync15 } from "node:fs";
71659
- import { join as join26 } from "node:path";
71694
+ import { existsSync as existsSync10, readFileSync as readFileSync16 } from "node:fs";
71695
+ import { join as join23 } from "node:path";
71660
71696
 
71661
71697
  // ../cli/src/token/ctx.ts
71662
71698
  import { execFile } from "node:child_process";
71663
- import { existsSync as existsSync8 } from "node:fs";
71664
- import { dirname as dirname10, join as join25, relative as relative2, resolve as resolve14 } from "node:path";
71699
+ import { existsSync as existsSync9 } from "node:fs";
71700
+ import { dirname as dirname7, join as join22, relative as relative2, resolve as resolve14 } from "node:path";
71665
71701
  var CoreError = class extends Error {
71666
71702
  exit;
71667
71703
  hint;
@@ -71689,8 +71725,8 @@ function nodeCtx(cwd, env = process.env, now = Date.now) {
71689
71725
  function findRoot(cwd) {
71690
71726
  let dir = resolve14(cwd);
71691
71727
  for (; ; ) {
71692
- if (existsSync8(join25(dir, ".git")) || existsSync8(join25(dir, ".harness"))) return dir;
71693
- const up = dirname10(dir);
71728
+ if (existsSync9(join22(dir, ".git")) || existsSync9(join22(dir, ".overlane"))) return dir;
71729
+ const up = dirname7(dir);
71694
71730
  if (up === dir) return resolve14(cwd);
71695
71731
  dir = up;
71696
71732
  }
@@ -71746,9 +71782,9 @@ async function brief(ctx, input2) {
71746
71782
  lines.push(parsed === null ? "not a git repository" : formatGitBrief(parsed));
71747
71783
  }
71748
71784
  if (mode === "tasks" || mode === "all") {
71749
- const file2 = join26(root, "TASKS.md");
71750
- if (existsSync9(file2)) {
71751
- const open2 = openP0Lines(readFileSync15(file2, "utf8"));
71785
+ const file2 = join23(root, "TASKS.md");
71786
+ if (existsSync10(file2)) {
71787
+ const open2 = openP0Lines(readFileSync16(file2, "utf8"));
71752
71788
  data.tasks = { source: "TASKS.md", open: open2.slice(0, MAX_TASKS), more: Math.max(0, open2.length - MAX_TASKS) };
71753
71789
  lines.push(...open2.length === 0 ? ["no open P0 lines in TASKS.md"] : [`${open2.length} open P0:`, ...data.tasks.open], ...data.tasks.more > 0 ? [`+${data.tasks.more} more in TASKS.md`] : []);
71754
71790
  } else {
@@ -71760,13 +71796,13 @@ async function brief(ctx, input2) {
71760
71796
  }
71761
71797
 
71762
71798
  // ../cli/src/token/code.ts
71763
- import { existsSync as existsSync11, readFileSync as readFileSync17, statSync as statSync2 } from "node:fs";
71764
- import { join as join28, relative as relative3, resolve as resolve15 } from "node:path";
71799
+ import { existsSync as existsSync12, readFileSync as readFileSync18, statSync as statSync2 } from "node:fs";
71800
+ import { join as join24, relative as relative3, resolve as resolve15 } from "node:path";
71765
71801
 
71766
71802
  // ../cli/src/token/index-file.ts
71767
- import { existsSync as existsSync10, readFileSync as readFileSync16 } from "node:fs";
71768
- import { join as join27 } from "node:path";
71769
- var INDEX_PATH = ".harness/code-index.json";
71803
+ import { existsSync as existsSync11, readFileSync as readFileSync17 } from "node:fs";
71804
+ init_overlane_paths_node();
71805
+ init_src();
71770
71806
  var BUILD_INDEX_COMMAND = "node packages/index-builder/dist/overlane-index.mjs map --root .";
71771
71807
  var LoadedIndex = class {
71772
71808
  constructor(sha, fileCount, uncovered, builtAt, rows, edges) {
@@ -71865,11 +71901,11 @@ function loadFreshIndex(ctx, root) {
71865
71901
  return pending;
71866
71902
  }
71867
71903
  async function loadFreshIndexUncached(ctx, root) {
71868
- const file2 = join27(root, INDEX_PATH);
71869
- if (!existsSync10(file2)) return { state: "missing" };
71904
+ const file2 = statePath(root, "codeIndex");
71905
+ if (!existsSync11(file2)) return { state: "missing" };
71870
71906
  let text2;
71871
71907
  try {
71872
- text2 = readFileSync16(file2, "utf8");
71908
+ text2 = readFileSync17(file2, "utf8");
71873
71909
  } catch {
71874
71910
  return { state: "missing" };
71875
71911
  }
@@ -71882,7 +71918,7 @@ async function loadFreshIndexUncached(ctx, root) {
71882
71918
  ctx.git(["rev-list", "--count", `${index.sha}..HEAD`], root)
71883
71919
  ]);
71884
71920
  if (diff.code !== 0) return { state: "unusable", reason: `the index was built at ${index.sha.slice(0, 7)}, which this checkout does not have` };
71885
- const changed = new Set([...diff.stdout.split("\n"), ...untracked.code === 0 ? untracked.stdout.split("\n") : []].filter((p2) => p2 !== "" && !p2.startsWith(".harness/")));
71921
+ const changed = new Set([...diff.stdout.split("\n"), ...untracked.code === 0 ? untracked.stdout.split("\n") : []].filter((p2) => p2 !== "" && !isStatePath(p2)));
71886
71922
  return { state: "ready", index, headSha: head.code === 0 ? head.stdout.trim() : "", behind: count.code === 0 ? Number.parseInt(count.stdout.trim(), 10) || 0 : 0, changed };
71887
71923
  }
71888
71924
 
@@ -71998,9 +72034,9 @@ var escapeRegex2 = (text2) => text2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
71998
72034
  var isTestPath = (path) => /(?:^|\/)(?:tests?|__tests__|fixtures)\/|\.(?:test|spec)\.[a-z]+$/.test(path);
71999
72035
  function readLines(root, path) {
72000
72036
  try {
72001
- const file2 = join28(root, path);
72037
+ const file2 = join24(root, path);
72002
72038
  if (statSync2(file2).size > 4 * 1024 * 1024) return null;
72003
- return readFileSync17(file2, "utf8").split("\n");
72039
+ return readFileSync18(file2, "utf8").split("\n");
72004
72040
  } catch {
72005
72041
  return null;
72006
72042
  }
@@ -72049,7 +72085,7 @@ function scanForDefinitions(root, files, name2) {
72049
72085
  return hits;
72050
72086
  }
72051
72087
  function indexProblem(fresh) {
72052
- if (fresh.state === "missing") return `no code index at .harness/code-index.json; build it with: ${BUILD_INDEX_COMMAND}`;
72088
+ if (fresh.state === "missing") return `no code index at .overlane/state/code-index.json; build it with: ${BUILD_INDEX_COMMAND}`;
72053
72089
  if (fresh.state === "unusable") return `code index unusable (${fresh.reason}); rebuild with: ${BUILD_INDEX_COMMAND}`;
72054
72090
  return "";
72055
72091
  }
@@ -72112,7 +72148,7 @@ function numbered(lines, from, to) {
72112
72148
  function resolveFile(ctx, root, path) {
72113
72149
  for (const base5 of [root, ctx.cwd]) {
72114
72150
  const full = resolve15(base5, path);
72115
- if (existsSync11(full) && statSync2(full).isFile()) return relative3(root, full);
72151
+ if (existsSync12(full) && statSync2(full).isFile()) return relative3(root, full);
72116
72152
  }
72117
72153
  return null;
72118
72154
  }
@@ -72306,19 +72342,19 @@ async function refsCore(ctx, input2) {
72306
72342
  }
72307
72343
 
72308
72344
  // ../cli/src/token/cloud.ts
72345
+ init_overlane_paths_node();
72309
72346
  import { execFileSync } from "node:child_process";
72310
- import { readFileSync as readFileSync18 } from "node:fs";
72347
+ import { readFileSync as readFileSync19 } from "node:fs";
72311
72348
  import { homedir } from "node:os";
72312
- import { join as join29 } from "node:path";
72349
+ import { join as join25 } from "node:path";
72313
72350
  var CLOUD_TIMEOUT_MS = 4e3;
72314
- var BINDING_FILE2 = join29(".harness", "project.json");
72315
72351
  var KEYCHAIN_SERVICE2 = "overlane";
72316
72352
  var CloudUnavailable = class extends Error {
72317
72353
  };
72318
72354
  var text = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
72319
72355
  function readCloudBinding(root) {
72320
72356
  try {
72321
- const raw = JSON.parse(readFileSync18(join29(root, BINDING_FILE2), "utf8"));
72357
+ const raw = JSON.parse(readFileSync19(statePath(root, "binding"), "utf8"));
72322
72358
  const serviceUrl = text(raw["serviceUrl"]);
72323
72359
  const tenantId = text(raw["tenantId"]);
72324
72360
  const projectId = text(raw["projectId"]);
@@ -72329,8 +72365,8 @@ function readCloudBinding(root) {
72329
72365
  }
72330
72366
  }
72331
72367
  function configDir(env) {
72332
- const base5 = env["XDG_CONFIG_HOME"] ?? (process.platform === "win32" ? env["APPDATA"] : void 0) ?? join29(homedir(), ".config");
72333
- return join29(base5, "overlane");
72368
+ const base5 = env["XDG_CONFIG_HOME"] ?? (process.platform === "win32" ? env["APPDATA"] : void 0) ?? join25(homedir(), ".config");
72369
+ return join25(base5, "overlane");
72334
72370
  }
72335
72371
  function readKeychain(serviceUrl) {
72336
72372
  const commands = {
@@ -72365,7 +72401,7 @@ function findCloudToken(ctx, serviceUrl) {
72365
72401
  }
72366
72402
  }
72367
72403
  try {
72368
- const file2 = JSON.parse(readFileSync18(join29(configDir(ctx.env), "credentials.json"), "utf8"));
72404
+ const file2 = JSON.parse(readFileSync19(join25(configDir(ctx.env), "credentials.json"), "utf8"));
72369
72405
  return usable(file2[serviceUrl], ctx.now());
72370
72406
  } catch {
72371
72407
  return null;
@@ -72373,7 +72409,7 @@ function findCloudToken(ctx, serviceUrl) {
72373
72409
  }
72374
72410
  function readOverlaySession(root) {
72375
72411
  try {
72376
- const id2 = readFileSync18(join29(root, ".harness", "overlay", "session"), "utf8").trim();
72412
+ const id2 = readFileSync19(statePath(root, "overlay", "session"), "utf8").trim();
72377
72413
  return /^[A-Za-z0-9._-]{1,64}$/.test(id2) ? id2 : void 0;
72378
72414
  } catch {
72379
72415
  return void 0;
@@ -72576,8 +72612,8 @@ var codeShow = (ctx, input2) => cloudFirst(
72576
72612
 
72577
72613
  // ../cli/src/token/exec.ts
72578
72614
  import { spawn } from "node:child_process";
72579
- import { createWriteStream, mkdirSync as mkdirSync10 } from "node:fs";
72580
- import { join as join30 } from "node:path";
72615
+ import { createWriteStream, mkdirSync as mkdirSync11 } from "node:fs";
72616
+ import { join as join26 } from "node:path";
72581
72617
 
72582
72618
  // ../cli/src/token/parsers.ts
72583
72619
  var ANSI = /\u001b\[[0-9;?]*[A-Za-z]/g;
@@ -72918,6 +72954,7 @@ function summarise(command, output2, exit) {
72918
72954
  }
72919
72955
 
72920
72956
  // ../cli/src/token/exec.ts
72957
+ init_overlane_paths_node();
72921
72958
  var MAX_CAPTURE = 64 * 1024 * 1024;
72922
72959
  var SAFE_TOKEN = /^[A-Za-z0-9_@%+=:,./~-]+$/;
72923
72960
  var quote2 = (token) => SAFE_TOKEN.test(token) ? token : `'${token.replaceAll("'", "'\\''")}'`;
@@ -72940,10 +72977,11 @@ async function execCommand(ctx, input2) {
72940
72977
  }
72941
72978
  const command = commandLine(input2.tokens);
72942
72979
  const root = findRoot(ctx.cwd);
72943
- const dir = join30(root, ".harness", "logs");
72944
- mkdirSync10(dir, { recursive: true });
72980
+ ensureStateDir(root);
72981
+ const dir = statePath(root, "logs");
72982
+ mkdirSync11(dir, { recursive: true });
72945
72983
  const started = ctx.now();
72946
- const logFile = join30(dir, `${utcStamp(started)}-${slugOf(input2.name, command)}.log`);
72984
+ const logFile = join26(dir, `${utcStamp(started)}-${slugOf(input2.name, command)}.log`);
72947
72985
  const stream = createWriteStream(logFile);
72948
72986
  const chunks = [];
72949
72987
  let captured = 0;
@@ -72982,9 +73020,10 @@ function signalNumber(signal) {
72982
73020
  }
72983
73021
 
72984
73022
  // ../cli/src/token/ledger.ts
72985
- import { existsSync as existsSync12, readFileSync as readFileSync19 } from "node:fs";
72986
- import { join as join31, resolve as resolve16 } from "node:path";
72987
- var LEDGER_PATH = ".harness/token-ledger.jsonl";
73023
+ import { existsSync as existsSync13, readFileSync as readFileSync20 } from "node:fs";
73024
+ import { resolve as resolve16 } from "node:path";
73025
+ init_overlane_paths_node();
73026
+ var LEDGER_PATH = ".overlane/state/token-ledger.jsonl";
72988
73027
  var CATEGORY_RULES = [
72989
73028
  ["wrangler", /\bwrangler\b/],
72990
73029
  ["typecheck", /\btsc\b|\btypecheck\b/],
@@ -73116,16 +73155,16 @@ async function tokensReport(ctx, input2) {
73116
73155
  let read;
73117
73156
  if (input2.transcript !== void 0) {
73118
73157
  const file2 = resolve16(ctx.cwd, input2.transcript);
73119
- if (!existsSync12(file2)) return { data: { source: input2.transcript, since: input2.since ?? null, calls: 0, tokens: 0, skipped: 0, rows: [] }, lines: [`none: no transcript at ${input2.transcript}`], exit: 4 };
73158
+ if (!existsSync13(file2)) return { data: { source: input2.transcript, since: input2.since ?? null, calls: 0, tokens: 0, skipped: 0, rows: [] }, lines: [`none: no transcript at ${input2.transcript}`], exit: 4 };
73120
73159
  source = input2.transcript;
73121
- read = readTranscript(readFileSync19(file2, "utf8"));
73160
+ read = readTranscript(readFileSync20(file2, "utf8"));
73122
73161
  } else {
73123
- const file2 = join31(root, LEDGER_PATH);
73124
- if (!existsSync12(file2)) {
73162
+ const file2 = statePath(root, "ledger");
73163
+ if (!existsSync13(file2)) {
73125
73164
  return { data: { source: LEDGER_PATH, since: input2.since ?? null, calls: 0, tokens: 0, skipped: 0, rows: [] }, lines: [`none: no ledger at ${LEDGER_PATH}; the tool-call hook writes it, or pass --transcript <path.jsonl>`], exit: 4 };
73126
73165
  }
73127
73166
  source = LEDGER_PATH;
73128
- read = readLedger(readFileSync19(file2, "utf8"));
73167
+ read = readLedger(readFileSync20(file2, "utf8"));
73129
73168
  }
73130
73169
  const calls = cutoff === null ? read.calls : read.calls.filter((c2) => c2.ts >= cutoff);
73131
73170
  const report2 = buildReport(calls, top, source, input2.since ?? null, read.skipped);
@@ -73147,7 +73186,7 @@ var TOKEN_COMMANDS = [
73147
73186
  {
73148
73187
  path: ["code", "find"],
73149
73188
  summary: "Find where a symbol is defined: one line each, kind, qualified name, path:line",
73150
- description: `Looks the name up in the local code index (.harness/code-index.json) and prints "kind qualified path:line", best match first, at most --limit lines (default 20). Entries in files that changed since the index was built are replaced by a pattern scan, and the output says so. With no index, or one this checkout does not have, it prints one line saying so and falls back to a bounded literal search (git grep -n -w, at most 20 lines). ${NOTE} Use this in place of grep for "where is X defined".`,
73189
+ description: `Looks the name up in the local code index (.overlane/state/code-index.json) and prints "kind qualified path:line", best match first, at most --limit lines (default 20). Entries in files that changed since the index was built are replaced by a pattern scan, and the output says so. With no index, or one this checkout does not have, it prints one line saying so and falls back to a bounded literal search (git grep -n -w, at most 20 lines). ${NOTE} Use this in place of grep for "where is X defined".`,
73151
73190
  args: [{ name: "name", required: true, description: "Symbol name, or a qualified name such as Class.method" }],
73152
73191
  flags: [
73153
73192
  { name: "kind", type: "string", value: "KIND", description: "Only this kind: function, class, interface, type, constant, method, variable, property, namespace" },
@@ -73195,7 +73234,7 @@ var TOKEN_COMMANDS = [
73195
73234
  {
73196
73235
  path: ["exec"],
73197
73236
  summary: "Run a command; keep the full output in a log and print a short status and parsed summary",
73198
- description: `Runs the command after -- through the shell, streams nothing, saves stdout and stderr to .harness/logs/TIMESTAMP-NAME.log, and prints one line "ok|FAIL exit=N 12.3s log=PATH" followed by a summary parsed from the output: vitest (files and tests per package, each failing test with the first lines of its assertion), tsc (error count and the first 10 errors), esbuild and astro build errors, wrangler deploy (version id, routes, errors), wrangler d1 (bookmark, applied migrations), git push (ref updates or the rejection). A command it does not know prints nothing more on success and its last 20 lines on failure. The exit code is the command's. A failure always shows its cause; the full text is in the log.`,
73237
+ description: `Runs the command after -- through the shell, streams nothing, saves stdout and stderr to .overlane/state/logs/TIMESTAMP-NAME.log, and prints one line "ok|FAIL exit=N 12.3s log=PATH" followed by a summary parsed from the output: vitest (files and tests per package, each failing test with the first lines of its assertion), tsc (error count and the first 10 errors), esbuild and astro build errors, wrangler deploy (version id, routes, errors), wrangler d1 (bookmark, applied migrations), git push (ref updates or the rejection). A command it does not know prints nothing more on success and its last 20 lines on failure. The exit code is the command's. A failure always shows its cause; the full text is in the log.`,
73199
73238
  args: [{ name: "command", required: true, variadic: true, description: "The command and its arguments, after --" }],
73200
73239
  flags: [{ name: "name", type: "string", value: "NAME", description: "Label used in the log file name" }],
73201
73240
  examples: ["overlane exec -- pnpm -r test", "overlane exec --name typecheck -- pnpm -r typecheck", "overlane exec -- 'git push -u origin wip/unit'"],
@@ -73219,7 +73258,7 @@ var TOKEN_COMMANDS = [
73219
73258
  {
73220
73259
  path: ["tokens", "report"],
73221
73260
  summary: "Where tool-call tokens went, by category, with the terse command that replaces each",
73222
- description: `Reads .harness/token-ledger.jsonl (one JSON object per tool call: ts, tool, category, inChars, outChars, command) or, with --transcript, a Claude Code transcript (tool_use and tool_result pairs, Bash calls categorised by command: test, typecheck, wrangler, build, git, grep/sed/cat, curl, other). Prints the top categories by estimated tokens (characters / 4) with calls, average and the suggested replacement: grep, cat and sed to overlane code find, show, outline and refs; test, typecheck, build and wrangler to overlane exec; git status and log to overlane brief git. ${NOTE}`,
73261
+ description: `Reads .overlane/state/token-ledger.jsonl (one JSON object per tool call: ts, tool, category, inChars, outChars, command) or, with --transcript, a Claude Code transcript (tool_use and tool_result pairs, Bash calls categorised by command: test, typecheck, wrangler, build, git, grep/sed/cat, curl, other). Prints the top categories by estimated tokens (characters / 4) with calls, average and the suggested replacement: grep, cat and sed to overlane code find, show, outline and refs; test, typecheck, build and wrangler to overlane exec; git status and log to overlane brief git. ${NOTE}`,
73223
73262
  args: [],
73224
73263
  flags: [
73225
73264
  { name: "since", type: "string", value: "WINDOW", description: "Only calls in this window: 7d, 12h, 30m, 2w or a date" },
@@ -73253,7 +73292,7 @@ function tokenCommand(path, result, effect = "read") {
73253
73292
  handler: async (inv) => {
73254
73293
  if (inv.dryRun) {
73255
73294
  const line3 = inv.positionals.join(" ");
73256
- return planOutcome(inv.deps, dryRunPlan({ commands: [line3], writes: [{ path: ".harness/logs", action: "write", description: "the full output of the command, in a new log file" }] }));
73295
+ return planOutcome(inv.deps, dryRunPlan({ commands: [line3], writes: [{ path: ".overlane/state/logs", action: "write", description: "the full output of the command, in a new log file" }] }));
73257
73296
  }
73258
73297
  const ctx = nodeCtx(inv.deps.paths.cwd, inv.deps.env, inv.deps.now);
73259
73298
  try {
@@ -73563,38 +73602,38 @@ init_src2();
73563
73602
 
73564
73603
  // src/data-dir.ts
73565
73604
  import { homedir as homedir2 } from "node:os";
73566
- import { join as join36 } from "node:path";
73605
+ import { join as join32 } from "node:path";
73567
73606
  function dataDir(env = process.env, home = homedir2()) {
73568
73607
  const override = env["OVERLANE_DATA_DIR"];
73569
73608
  if (override !== void 0 && override !== "") return override;
73570
- const base5 = env["XDG_DATA_HOME"] ?? (process.platform === "win32" ? env["LOCALAPPDATA"] : void 0) ?? (process.platform === "darwin" ? join36(home, "Library", "Application Support") : join36(home, ".local", "share"));
73571
- return join36(base5, "overlane");
73609
+ const base5 = env["XDG_DATA_HOME"] ?? (process.platform === "win32" ? env["LOCALAPPDATA"] : void 0) ?? (process.platform === "darwin" ? join32(home, "Library", "Application Support") : join32(home, ".local", "share"));
73610
+ return join32(base5, "overlane");
73572
73611
  }
73573
73612
  function marketplaceRoot(env = process.env, home = homedir2()) {
73574
- return join36(dataDir(env, home), "marketplace");
73613
+ return join32(dataDir(env, home), "marketplace");
73575
73614
  }
73576
73615
 
73577
73616
  // src/plugin.ts
73578
- import { readFileSync as readFileSync21 } from "node:fs";
73579
- import { join as join38 } from "node:path";
73617
+ import { readFileSync as readFileSync22 } from "node:fs";
73618
+ import { join as join34 } from "node:path";
73580
73619
  import { parseArgs as parseArgs3 } from "node:util";
73581
73620
 
73582
73621
  // src/marketplace.ts
73583
73622
  init_src();
73584
73623
  import { createHash as createHash7 } from "node:crypto";
73585
- import { cpSync, existsSync as existsSync13, mkdirSync as mkdirSync11, readdirSync as readdirSync3, readFileSync as readFileSync20, renameSync as renameSync7, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync10 } from "node:fs";
73586
- import { dirname as dirname12, join as join37, relative as relative4, sep } from "node:path";
73624
+ import { cpSync, existsSync as existsSync14, mkdirSync as mkdirSync12, readdirSync as readdirSync4, readFileSync as readFileSync21, renameSync as renameSync7, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync11 } from "node:fs";
73625
+ import { dirname as dirname9, join as join33, relative as relative4, sep } from "node:path";
73587
73626
  var CLIENT_DIRS = ["claude", "codex"];
73588
73627
  var TREE_DIRS = [...CLIENT_DIRS, ".claude-plugin", ".agents"];
73589
73628
  var EMBEDDED_MANIFEST = "release-manifest.json";
73590
- var INSTALLED_MANIFEST = join37(".release", "manifest.json");
73629
+ var INSTALLED_MANIFEST = join33(".release", "manifest.json");
73591
73630
  var MarketplaceError = class extends Error {
73592
73631
  };
73593
73632
  function loadEmbedded(packageRoot2) {
73594
- const dir = join37(packageRoot2, "plugins");
73595
- const path = join37(dir, EMBEDDED_MANIFEST);
73596
- if (!existsSync13(path)) throw new MarketplaceError(`this package has no embedded plugin release (${path} is missing)`);
73597
- const parsed = ReleaseManifest.safeParse(JSON.parse(readFileSync20(path, "utf8")));
73633
+ const dir = join33(packageRoot2, "plugins");
73634
+ const path = join33(dir, EMBEDDED_MANIFEST);
73635
+ if (!existsSync14(path)) throw new MarketplaceError(`this package has no embedded plugin release (${path} is missing)`);
73636
+ const parsed = ReleaseManifest.safeParse(JSON.parse(readFileSync21(path, "utf8")));
73598
73637
  if (!parsed.success) throw new MarketplaceError(`the embedded release manifest is invalid: ${parsed.error.message}`);
73599
73638
  return { dir, manifest: parsed.data };
73600
73639
  }
@@ -73602,10 +73641,10 @@ function sha2562(data) {
73602
73641
  return `sha256:${createHash7("sha256").update(data).digest("hex")}`;
73603
73642
  }
73604
73643
  function listFiles(root, dir = root) {
73605
- if (!existsSync13(dir)) return [];
73644
+ if (!existsSync14(dir)) return [];
73606
73645
  const out2 = [];
73607
- for (const entry of readdirSync3(dir, { withFileTypes: true })) {
73608
- const full = join37(dir, entry.name);
73646
+ for (const entry of readdirSync4(dir, { withFileTypes: true })) {
73647
+ const full = join33(dir, entry.name);
73609
73648
  if (entry.isDirectory()) out2.push(...listFiles(root, full));
73610
73649
  else out2.push(relative4(root, full).split(sep).join("/"));
73611
73650
  }
@@ -73617,15 +73656,15 @@ async function verifyTree(treeRoot, manifest) {
73617
73656
  if (recomputed !== manifest.digest) problems.push(`manifest digest ${manifest.digest} does not match its file list (${recomputed})`);
73618
73657
  const listed = new Set(manifest.files.map((file2) => file2.path));
73619
73658
  for (const file2 of manifest.files) {
73620
- const path = join37(treeRoot, file2.path);
73621
- if (!existsSync13(path)) {
73659
+ const path = join33(treeRoot, file2.path);
73660
+ if (!existsSync14(path)) {
73622
73661
  problems.push(`missing: ${file2.path}`);
73623
73662
  continue;
73624
73663
  }
73625
- if (sha2562(readFileSync20(path)) !== file2.digest) problems.push(`modified: ${file2.path}`);
73664
+ if (sha2562(readFileSync21(path)) !== file2.digest) problems.push(`modified: ${file2.path}`);
73626
73665
  }
73627
73666
  for (const client of TREE_DIRS) {
73628
- for (const found of listFiles(join37(treeRoot, client))) {
73667
+ for (const found of listFiles(join33(treeRoot, client))) {
73629
73668
  if (!listed.has(`${client}/${found}`)) problems.push(`unlisted: ${client}/${found}`);
73630
73669
  }
73631
73670
  }
@@ -73633,7 +73672,7 @@ async function verifyTree(treeRoot, manifest) {
73633
73672
  }
73634
73673
  function readInstalledManifest(target2) {
73635
73674
  try {
73636
- const parsed = ReleaseManifest.safeParse(JSON.parse(readFileSync20(join37(target2, INSTALLED_MANIFEST), "utf8")));
73675
+ const parsed = ReleaseManifest.safeParse(JSON.parse(readFileSync21(join33(target2, INSTALLED_MANIFEST), "utf8")));
73637
73676
  return parsed.success ? parsed.data : null;
73638
73677
  } catch {
73639
73678
  return null;
@@ -73658,23 +73697,23 @@ async function syncMarketplace(embedded, target2) {
73658
73697
  const staging = `${target2}.new-${process.pid}`;
73659
73698
  const previous = `${target2}.old-${process.pid}`;
73660
73699
  rmSync4(staging, { recursive: true, force: true });
73661
- mkdirSync11(staging, { recursive: true });
73700
+ mkdirSync12(staging, { recursive: true });
73662
73701
  try {
73663
73702
  for (const client of TREE_DIRS) {
73664
- if (existsSync13(join37(embedded.dir, client))) cpSync(join37(embedded.dir, client), join37(staging, client), { recursive: true });
73703
+ if (existsSync14(join33(embedded.dir, client))) cpSync(join33(embedded.dir, client), join33(staging, client), { recursive: true });
73665
73704
  }
73666
- mkdirSync11(join37(staging, ".release"), { recursive: true });
73667
- writeFileSync10(join37(staging, INSTALLED_MANIFEST), `${JSON.stringify(embedded.manifest, null, 2)}
73705
+ mkdirSync12(join33(staging, ".release"), { recursive: true });
73706
+ writeFileSync11(join33(staging, INSTALLED_MANIFEST), `${JSON.stringify(embedded.manifest, null, 2)}
73668
73707
  `);
73669
73708
  const after = await verifyTree(staging, embedded.manifest);
73670
73709
  if (after.length > 0) throw new MarketplaceError(`the copied plugin files do not match the release manifest:
73671
73710
  ${after.join("\n ")}`);
73672
- mkdirSync11(dirname12(target2), { recursive: true });
73673
- if (existsSync13(target2)) renameSync7(target2, previous);
73711
+ mkdirSync12(dirname9(target2), { recursive: true });
73712
+ if (existsSync14(target2)) renameSync7(target2, previous);
73674
73713
  try {
73675
73714
  renameSync7(staging, target2);
73676
73715
  } catch (error62) {
73677
- if (existsSync13(previous)) renameSync7(previous, target2);
73716
+ if (existsSync14(previous)) renameSync7(previous, target2);
73678
73717
  throw error62;
73679
73718
  }
73680
73719
  rmSync4(previous, { recursive: true, force: true });
@@ -73684,7 +73723,7 @@ async function syncMarketplace(embedded, target2) {
73684
73723
  }
73685
73724
  async function ensureMarketplace(embedded, target2) {
73686
73725
  const installed = readInstalledManifest(target2);
73687
- const present = existsSync13(target2) && statSync3(target2).isDirectory();
73726
+ const present = existsSync14(target2) && statSync3(target2).isDirectory();
73688
73727
  if (installed !== null && present && !isNewer(embedded.manifest.version, installed.version)) return false;
73689
73728
  await syncMarketplace(embedded, target2);
73690
73729
  return true;
@@ -73696,8 +73735,8 @@ var PLUGIN_USAGE = ` overlane plugin install [--scope project|user] [--client c
73696
73735
  var PluginUsageError = class extends Error {
73697
73736
  };
73698
73737
  function readNames(treeRoot, client) {
73699
- const file2 = client === "claude" ? join38(treeRoot, "claude", ".claude-plugin", "marketplace.json") : join38(treeRoot, "codex", ".agents", "plugins", "marketplace.json");
73700
- const parsed = JSON.parse(readFileSync21(file2, "utf8"));
73738
+ const file2 = client === "claude" ? join34(treeRoot, "claude", ".claude-plugin", "marketplace.json") : join34(treeRoot, "codex", ".agents", "plugins", "marketplace.json");
73739
+ const parsed = JSON.parse(readFileSync22(file2, "utf8"));
73701
73740
  const record3 = parsed;
73702
73741
  const plugin = record3.plugins?.[0]?.name;
73703
73742
  if (typeof record3.name !== "string" || typeof plugin !== "string") throw new MarketplaceError(`${file2} names no marketplace or plugin`);
@@ -73743,7 +73782,7 @@ ${PLUGIN_USAGE}`);
73743
73782
  const key = `${names.plugin}@${names.marketplace}`;
73744
73783
  if (!await available(deps, client)) {
73745
73784
  if (explicit !== void 0) {
73746
- deps.stderr(`overlane: \`${client}\` was not found on PATH; the marketplace is at ${join38(root, client)}
73785
+ deps.stderr(`overlane: \`${client}\` was not found on PATH; the marketplace is at ${join34(root, client)}
73747
73786
  `);
73748
73787
  failed = true;
73749
73788
  } else {
@@ -73755,7 +73794,7 @@ ${PLUGIN_USAGE}`);
73755
73794
  ranAny = true;
73756
73795
  deps.stdout(`${client}:
73757
73796
  `);
73758
- const dir = join38(root, client);
73797
+ const dir = join34(root, client);
73759
73798
  const steps = client === "claude" ? [
73760
73799
  ["claude", ["plugin", "marketplace", "add", dir, "--scope", scope]],
73761
73800
  ["claude", ["plugin", "marketplace", "update", names.marketplace]],
@@ -73923,7 +73962,7 @@ var packageCommands = [indexBuildCommand, indexUploadCommand, shimCommand, plugi
73923
73962
  // src/deps.ts
73924
73963
  import { execFile as execFile5, spawn as spawn2 } from "node:child_process";
73925
73964
  import { homedir as homedir4 } from "node:os";
73926
- import { join as join41 } from "node:path";
73965
+ import { join as join37 } from "node:path";
73927
73966
  import { createInterface } from "node:readline/promises";
73928
73967
  function exec(command, args2, options) {
73929
73968
  return new Promise((resolveResult) => {
@@ -73969,8 +74008,8 @@ async function confirm(question) {
73969
74008
  }
73970
74009
  }
73971
74010
  function configDir3(env) {
73972
- const base5 = env["XDG_CONFIG_HOME"] ?? (process.platform === "win32" ? env["APPDATA"] : void 0) ?? join41(homedir4(), ".config");
73973
- return join41(base5, "overlane");
74011
+ const base5 = env["XDG_CONFIG_HOME"] ?? (process.platform === "win32" ? env["APPDATA"] : void 0) ?? join37(homedir4(), ".config");
74012
+ return join37(base5, "overlane");
73974
74013
  }
73975
74014
  function createDeps2(env = process.env) {
73976
74015
  return {