@hasna/instructions 0.4.36 → 0.4.42

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 (57) hide show
  1. package/README.md +9 -8
  2. package/assets/skills/inbox/SKILL.md +86 -0
  3. package/dashboard/README.md +34 -70
  4. package/dist/cli/index.js +1673 -516
  5. package/dist/cli/raw-store-root.test.d.ts +2 -0
  6. package/dist/cli/raw-store-root.test.d.ts.map +1 -0
  7. package/dist/data/config-store.d.ts +4 -4
  8. package/dist/data/config-store.d.ts.map +1 -1
  9. package/dist/db/configs.d.ts.map +1 -1
  10. package/dist/db/database.d.ts.map +1 -1
  11. package/dist/generated/storage-kit/backend.d.ts +20 -0
  12. package/dist/generated/storage-kit/backend.d.ts.map +1 -0
  13. package/dist/generated/storage-kit/index.d.ts +2 -2
  14. package/dist/generated/storage-kit/index.d.ts.map +1 -1
  15. package/dist/generated/storage-kit/migrations.d.ts.map +1 -1
  16. package/dist/generated/storage-kit/own.d.ts +11 -0
  17. package/dist/generated/storage-kit/own.d.ts.map +1 -0
  18. package/dist/generated/storage-kit/pool.d.ts +7 -6
  19. package/dist/generated/storage-kit/pool.d.ts.map +1 -1
  20. package/dist/generated/storage-kit/tls.d.ts +30 -3
  21. package/dist/generated/storage-kit/tls.d.ts.map +1 -1
  22. package/dist/index.d.ts +4 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +945 -372
  25. package/dist/lib/instruction-graph.d.ts.map +1 -1
  26. package/dist/lib/managed-skill-runtimes.d.ts +80 -0
  27. package/dist/lib/managed-skill-runtimes.d.ts.map +1 -0
  28. package/dist/lib/managed-skill-runtimes.test.d.ts +2 -0
  29. package/dist/lib/managed-skill-runtimes.test.d.ts.map +1 -0
  30. package/dist/lib/raw-store-root.d.ts +17 -0
  31. package/dist/lib/raw-store-root.d.ts.map +1 -0
  32. package/dist/lib/retired-storage-mode.d.ts +8 -0
  33. package/dist/lib/retired-storage-mode.d.ts.map +1 -0
  34. package/dist/lib/session-apply.d.ts.map +1 -1
  35. package/dist/lib/session-authority.d.ts +27 -0
  36. package/dist/lib/session-authority.d.ts.map +1 -0
  37. package/dist/lib/session-authority.test.d.ts +2 -0
  38. package/dist/lib/session-authority.test.d.ts.map +1 -0
  39. package/dist/lib/session-render.d.ts +7 -3
  40. package/dist/lib/session-render.d.ts.map +1 -1
  41. package/dist/mcp/index.js +177 -115
  42. package/dist/server/cloud-auth.test.d.ts +2 -0
  43. package/dist/server/cloud-auth.test.d.ts.map +1 -0
  44. package/dist/server/cloud.d.ts +7 -4
  45. package/dist/server/cloud.d.ts.map +1 -1
  46. package/dist/server/cloud.test.d.ts +2 -0
  47. package/dist/server/cloud.test.d.ts.map +1 -0
  48. package/dist/server/index.d.ts +1 -1
  49. package/dist/server/index.js +781 -325
  50. package/dist/status.d.ts +11 -1
  51. package/dist/status.d.ts.map +1 -1
  52. package/dist/storage/cloud-store.d.ts.map +1 -1
  53. package/dist/storage/cloud-store.test.d.ts +2 -0
  54. package/dist/storage/cloud-store.test.d.ts.map +1 -0
  55. package/package.json +10 -7
  56. package/dist/generated/storage-kit/mode.d.ts +0 -48
  57. package/dist/generated/storage-kit/mode.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -104,16 +104,46 @@ import { randomUUID as randomUUID3 } from "crypto";
104
104
  // src/db/database.ts
105
105
  import { Database } from "bun:sqlite";
106
106
  import { existsSync, mkdirSync, rmSync } from "fs";
107
- import { join } from "path";
107
+ import { join as join2 } from "path";
108
108
  import { randomUUID } from "crypto";
109
+
110
+ // src/lib/retired-storage-mode.ts
111
+ var LEGACY_STORAGE_MODE_KEYS = [
112
+ "HASNA_INSTRUCTIONS_STORAGE_MODE",
113
+ "HASNA_INSTRUCTIONS_MODE",
114
+ "INSTRUCTIONS_STORAGE_MODE",
115
+ "INSTRUCTIONS_MODE"
116
+ ];
117
+ function firstDefinedEnvKey(env, keys) {
118
+ for (const key of keys) {
119
+ if (Object.hasOwn(env, key) && env[key] !== undefined)
120
+ return key;
121
+ }
122
+ return null;
123
+ }
124
+ function assertNoLegacyStorageMode(env = process.env) {
125
+ const legacyKey = firstDefinedEnvKey(env, LEGACY_STORAGE_MODE_KEYS);
126
+ if (!legacyKey)
127
+ return;
128
+ throw new Error(`${legacyKey} was removed. Deployment modes no longer exist: delete the storage-mode variable. ` + `The client uses the local SQLite store, or the HTTP API selected by ` + `HASNA_INSTRUCTIONS_API_URL + HASNA_INSTRUCTIONS_API_KEY. ` + `On the server, set HASNA_INSTRUCTIONS_DATABASE_URL to select the postgresql backend, ` + `or leave it unset for sqlite.`);
129
+ }
130
+
131
+ // src/lib/raw-store-root.ts
132
+ import { homedir } from "os";
133
+ import { join, resolve } from "path";
134
+ var RAW_STORE_ROOT_ENV = "HASNA_CONFIGS_HOME";
135
+ function getRawStoreRoot() {
136
+ return resolve(process.env[RAW_STORE_ROOT_ENV] || join(process.env["HOME"] || homedir(), ".hasna", "instructions"));
137
+ }
138
+
139
+ // src/db/database.ts
109
140
  function getDbPath() {
110
141
  if (process.env["HASNA_INSTRUCTIONS_DB_PATH"]) {
111
142
  return process.env["HASNA_INSTRUCTIONS_DB_PATH"];
112
143
  }
113
- const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
114
- const dir = join(home, ".hasna", "instructions");
144
+ const dir = getRawStoreRoot();
115
145
  mkdirSync(dir, { recursive: true });
116
- return join(dir, "instructions.db");
146
+ return join2(dir, "instructions.db");
117
147
  }
118
148
  function uuid() {
119
149
  return randomUUID();
@@ -210,8 +240,9 @@ var _db = null;
210
240
  function getDatabase(path) {
211
241
  if (_db)
212
242
  return _db;
243
+ assertNoLegacyStorageMode();
213
244
  if (!path && process.env["HASNA_INSTRUCTIONS_API_URL"] && process.env["HASNA_INSTRUCTIONS_API_KEY"]) {
214
- throw new Error("instructions is in self_hosted (cloud) mode: this command is not wired to the cloud API yet. " + "Unset HASNA_INSTRUCTIONS_API_URL / HASNA_INSTRUCTIONS_API_KEY to use it against the local store.");
245
+ throw new Error("instructions is using the HTTP API transport (HASNA_INSTRUCTIONS_API_URL set): this command is not wired to the API yet. " + "Unset HASNA_INSTRUCTIONS_API_URL / HASNA_INSTRUCTIONS_API_KEY to use it against the local store.");
215
246
  }
216
247
  const dbPath = path || getDbPath();
217
248
  const db = new Database(dbPath);
@@ -291,6 +322,34 @@ function insertFeedback(input, db) {
291
322
  d.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [input.message, input.email ?? null, input.category ?? "general", input.version ?? null]);
292
323
  }
293
324
 
325
+ // src/db/snapshots.ts
326
+ function createSnapshot(configId, content, version, db) {
327
+ const d = db || getDatabase();
328
+ const id = uuid();
329
+ const ts = now();
330
+ d.run("INSERT INTO config_snapshots (id, config_id, content, version, created_at) VALUES (?, ?, ?, ?, ?)", [id, configId, content, version, ts]);
331
+ return { id, config_id: configId, content, version, created_at: ts };
332
+ }
333
+ function listSnapshots(configId, db) {
334
+ const d = db || getDatabase();
335
+ return d.query("SELECT * FROM config_snapshots WHERE config_id = ? ORDER BY version DESC").all(configId);
336
+ }
337
+ function getSnapshot(id, db) {
338
+ const d = db || getDatabase();
339
+ return d.query("SELECT * FROM config_snapshots WHERE id = ?").get(id);
340
+ }
341
+ function getSnapshotByVersion(configId, version, db) {
342
+ const d = db || getDatabase();
343
+ return d.query("SELECT * FROM config_snapshots WHERE config_id = ? AND version = ?").get(configId, version);
344
+ }
345
+ function pruneSnapshots(configId, keep = 10, db) {
346
+ const d = db || getDatabase();
347
+ const result = d.run(`DELETE FROM config_snapshots WHERE config_id = ? AND id NOT IN (
348
+ SELECT id FROM config_snapshots WHERE config_id = ? ORDER BY version DESC LIMIT ?
349
+ )`, [configId, configId, keep]);
350
+ return result.changes;
351
+ }
352
+
294
353
  // src/db/configs.ts
295
354
  function rowToConfig(row) {
296
355
  let outputs = [];
@@ -329,25 +388,28 @@ function createConfig(input, db) {
329
388
  const slug = uniqueSlug(input.name, d);
330
389
  const tags = JSON.stringify(input.tags || []);
331
390
  const outputs = JSON.stringify(input.outputs || []);
332
- d.run(`INSERT INTO configs (id, name, slug, kind, category, agent, target_path, outputs, format, content, description, tags, is_template, version, created_at, updated_at, synced_at)
333
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, NULL)`, [
334
- id,
335
- input.name,
336
- slug,
337
- input.kind ?? "file",
338
- input.category,
339
- input.agent ?? "global",
340
- input.target_path ?? null,
341
- outputs,
342
- input.format ?? "text",
343
- input.content,
344
- input.description ?? null,
345
- tags,
346
- input.is_template ? 1 : 0,
347
- ts,
348
- ts
349
- ]);
350
- return getConfig(id, d);
391
+ return d.transaction(() => {
392
+ d.run(`INSERT INTO configs (id, name, slug, kind, category, agent, target_path, outputs, format, content, description, tags, is_template, version, created_at, updated_at, synced_at)
393
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, NULL)`, [
394
+ id,
395
+ input.name,
396
+ slug,
397
+ input.kind ?? "file",
398
+ input.category,
399
+ input.agent ?? "global",
400
+ input.target_path ?? null,
401
+ outputs,
402
+ input.format ?? "text",
403
+ input.content,
404
+ input.description ?? null,
405
+ tags,
406
+ input.is_template ? 1 : 0,
407
+ ts,
408
+ ts
409
+ ]);
410
+ createSnapshot(id, input.content, 1, d);
411
+ return getConfig(id, d);
412
+ })();
351
413
  }
352
414
  function getConfig(idOrSlug, db) {
353
415
  const d = db || getDatabase();
@@ -452,9 +514,13 @@ function updateConfig(idOrSlug, input, db) {
452
514
  updates.push("synced_at = ?");
453
515
  params.push(input.synced_at);
454
516
  }
455
- params.push(existing.id);
456
- d.run(`UPDATE configs SET ${updates.join(", ")} WHERE id = ?`, params);
457
- return getConfigById(existing.id, d);
517
+ return d.transaction(() => {
518
+ params.push(existing.id);
519
+ d.run(`UPDATE configs SET ${updates.join(", ")} WHERE id = ?`, params);
520
+ const updated = getConfigById(existing.id, d);
521
+ createSnapshot(updated.id, updated.content, updated.version, d);
522
+ return updated;
523
+ })();
458
524
  }
459
525
  function deleteConfig(idOrSlug, db) {
460
526
  const d = db || getDatabase();
@@ -473,9 +539,9 @@ function getConfigStats(db) {
473
539
  }
474
540
 
475
541
  // src/lib/machine.ts
476
- import { arch as currentArch, homedir, hostname as currentHostname, type as currentOsType } from "os";
542
+ import { arch as currentArch, homedir as homedir2, hostname as currentHostname, type as currentOsType } from "os";
477
543
  import { existsSync as existsSync2 } from "fs";
478
- import { join as join2 } from "path";
544
+ import { join as join3 } from "path";
479
545
 
480
546
  // src/lib/template.ts
481
547
  var VAR_PATTERN = /\{\{([A-Z0-9_]+)(?::([^}]*))?\}\}/g;
@@ -548,11 +614,11 @@ function normalizeOsFamily(os) {
548
614
  return value || "unknown";
549
615
  }
550
616
  function detectMachineContext(overrides = {}) {
551
- const homeDir = overrides.home_dir ?? process.env["CONFIGS_HOME"] ?? process.env["HOME"] ?? homedir();
617
+ const homeDir = overrides.home_dir ?? process.env["CONFIGS_HOME"] ?? process.env["HOME"] ?? homedir2();
552
618
  const os = overrides.os ?? currentOsType();
553
619
  const osFamily = normalizeOsFamily(os);
554
- const bunBinDir = overrides.bun_bin_dir ?? join2(homeDir, ".bun", "bin");
555
- const defaultBunPath = osFamily === "macos" && existsSync2(BREW_BUN_PATH) ? BREW_BUN_PATH : join2(bunBinDir, "bun");
620
+ const bunBinDir = overrides.bun_bin_dir ?? join3(homeDir, ".bun", "bin");
621
+ const defaultBunPath = osFamily === "macos" && existsSync2(BREW_BUN_PATH) ? BREW_BUN_PATH : join3(bunBinDir, "bun");
556
622
  return {
557
623
  id: "current-machine",
558
624
  hostname: overrides.hostname ?? currentHostname(),
@@ -562,10 +628,10 @@ function detectMachineContext(overrides = {}) {
562
628
  created_at: "",
563
629
  os_family: osFamily,
564
630
  home_dir: homeDir,
565
- workspace_root: overrides.workspace_root ?? join2(homeDir, osFamily === "macos" ? "Workspace" : "workspace"),
631
+ workspace_root: overrides.workspace_root ?? join3(homeDir, osFamily === "macos" ? "Workspace" : "workspace"),
566
632
  bun_bin_dir: bunBinDir,
567
633
  bun_path: overrides.bun_path ?? defaultBunPath,
568
- path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${join2("/opt", "homebrew", "bin")}:${bunBinDir}` : bunBinDir)
634
+ path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${join3("/opt", "homebrew", "bin")}:${bunBinDir}` : bunBinDir)
569
635
  };
570
636
  }
571
637
  function machineContextToVariables(machine) {
@@ -679,13 +745,13 @@ function boundedReadPage(items, total, options = {}) {
679
745
  }
680
746
 
681
747
  // src/lib/instruction-graph.ts
682
- import { createHash as createHash6 } from "crypto";
748
+ import { createHash as createHash7 } from "crypto";
683
749
 
684
750
  // src/lib/session-render.ts
685
- import { createHash as createHash5 } from "crypto";
686
- import { existsSync as existsSync4, readFileSync as readFileSync3, realpathSync, statSync as statSync2 } from "fs";
687
- import { homedir as homedir3 } from "os";
688
- import { basename as basename3, dirname as dirname2, extname as extname2, isAbsolute as isAbsolute3, join as join5, parse as parse2, posix as posix2, relative as relative2, resolve as resolve4 } from "path";
751
+ import { createHash as createHash6 } from "crypto";
752
+ import { existsSync as existsSync4, readFileSync as readFileSync4, realpathSync, statSync as statSync3 } from "fs";
753
+ import { homedir as homedir4 } from "os";
754
+ import { basename as basename3, dirname as dirname2, extname as extname2, isAbsolute as isAbsolute3, join as join7, parse as parse2, posix as posix2, relative as relative2, resolve as resolve6 } from "path";
689
755
 
690
756
  // src/lib/global-agent-rules-standard.ts
691
757
  import { createHash } from "crypto";
@@ -989,9 +1055,9 @@ import {
989
1055
  statSync,
990
1056
  writeFileSync
991
1057
  } from "fs";
992
- import { basename, dirname, isAbsolute, join as join3, parse, relative, resolve } from "path";
1058
+ import { basename, dirname, isAbsolute, join as join4, parse, relative, resolve as resolve2 } from "path";
993
1059
 
994
- // node_modules/zod/v3/external.js
1060
+ // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
995
1061
  var exports_external = {};
996
1062
  __export(exports_external, {
997
1063
  void: () => voidType,
@@ -1103,7 +1169,7 @@ __export(exports_external, {
1103
1169
  BRAND: () => BRAND
1104
1170
  });
1105
1171
 
1106
- // node_modules/zod/v3/helpers/util.js
1172
+ // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
1107
1173
  var util;
1108
1174
  (function(util2) {
1109
1175
  util2.assertEqual = (_) => {};
@@ -1234,7 +1300,7 @@ var getParsedType = (data) => {
1234
1300
  }
1235
1301
  };
1236
1302
 
1237
- // node_modules/zod/v3/ZodError.js
1303
+ // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/ZodError.js
1238
1304
  var ZodIssueCode = util.arrayToEnum([
1239
1305
  "invalid_type",
1240
1306
  "invalid_literal",
@@ -1353,7 +1419,7 @@ ZodError.create = (issues) => {
1353
1419
  return error;
1354
1420
  };
1355
1421
 
1356
- // node_modules/zod/v3/locales/en.js
1422
+ // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/locales/en.js
1357
1423
  var errorMap = (issue, _ctx) => {
1358
1424
  let message;
1359
1425
  switch (issue.code) {
@@ -1456,7 +1522,7 @@ var errorMap = (issue, _ctx) => {
1456
1522
  };
1457
1523
  var en_default = errorMap;
1458
1524
 
1459
- // node_modules/zod/v3/errors.js
1525
+ // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/errors.js
1460
1526
  var overrideErrorMap = en_default;
1461
1527
  function setErrorMap(map) {
1462
1528
  overrideErrorMap = map;
@@ -1464,7 +1530,7 @@ function setErrorMap(map) {
1464
1530
  function getErrorMap() {
1465
1531
  return overrideErrorMap;
1466
1532
  }
1467
- // node_modules/zod/v3/helpers/parseUtil.js
1533
+ // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
1468
1534
  var makeIssue = (params) => {
1469
1535
  const { data, path, errorMaps, issueData } = params;
1470
1536
  const fullPath = [...path, ...issueData.path || []];
@@ -1570,14 +1636,14 @@ var isAborted = (x) => x.status === "aborted";
1570
1636
  var isDirty = (x) => x.status === "dirty";
1571
1637
  var isValid = (x) => x.status === "valid";
1572
1638
  var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
1573
- // node_modules/zod/v3/helpers/errorUtil.js
1639
+ // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
1574
1640
  var errorUtil;
1575
1641
  (function(errorUtil2) {
1576
1642
  errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
1577
1643
  errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
1578
1644
  })(errorUtil || (errorUtil = {}));
1579
1645
 
1580
- // node_modules/zod/v3/types.js
1646
+ // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/types.js
1581
1647
  class ParseInputLazyPath {
1582
1648
  constructor(parent, value, path, key) {
1583
1649
  this._cachedPath = [];
@@ -4969,7 +5035,7 @@ var SECRET_KEY_PATTERN = /^(.*_?API_?KEY|.*_?TOKEN|.*_?SECRET|.*_?PASSWORD|.*_?P
4969
5035
  var VALUE_PATTERNS = [
4970
5036
  { re: /npm_[A-Za-z0-9]{36,}/, reason: "npm token" },
4971
5037
  { re: /gh[pousr]_[A-Za-z0-9_]{36,}/, reason: "GitHub token" },
4972
- { re: /sk-ant-[A-Za-z0-9\-_]{40,}/, reason: "Anthropic API key" },
5038
+ { re: /sk[-]ant-[A-Za-z0-9\-_]{40,}/, reason: "Anthropic API key" },
4973
5039
  { re: /sk-[A-Za-z0-9]{48,}/, reason: "OpenAI API key" },
4974
5040
  { re: /xoxb-[0-9]+-[A-Za-z0-9\-]+/, reason: "Slack bot token" },
4975
5041
  { re: /AIza[0-9A-Za-z\-_]{35}/, reason: "Google API key" },
@@ -5576,7 +5642,7 @@ function composeProjectContextSessionRender(input) {
5576
5642
  if (currentMarkers.block.id !== cache.project_id || currentMarkers.block.revision !== cache.revision || currentMarkers.block.hash !== cache.hash) {
5577
5643
  throw new ProjectContextError("MANAGED_BLOCK_CONFLICT", "project-context provider markers differ from the durable cache");
5578
5644
  }
5579
- const plannedIndexes = input.files.filter((file) => file.role === "index" && resolve(file.path) === paths.target);
5645
+ const plannedIndexes = input.files.filter((file) => file.role === "index" && resolve2(file.path) === paths.target);
5580
5646
  if (plannedIndexes.length !== 1) {
5581
5647
  throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "session renderer does not own the selected project-context provider target");
5582
5648
  }
@@ -5634,7 +5700,7 @@ function withProjectContextSessionGuard(guard, action, options = {}) {
5634
5700
  verify();
5635
5701
  return action(null);
5636
5702
  }
5637
- const lockPath = resolve(validated.workspace_root, ...PROJECT_CONTEXT_LOCK_PATH.split("/"));
5703
+ const lockPath = resolve2(validated.workspace_root, ...PROJECT_CONTEXT_LOCK_PATH.split("/"));
5638
5704
  const lock = acquireWorkspaceLock(validated.workspace_root, lockPath);
5639
5705
  try {
5640
5706
  verify();
@@ -5660,7 +5726,7 @@ function validateProjectContextSessionGuard(guard) {
5660
5726
  if (!isRecord(observed) || typeof observed.path !== "string") {
5661
5727
  throw new ProjectContextError("PROJECT_CONTEXT_SESSION_STALE", "session project-context guard contains malformed hash metadata");
5662
5728
  }
5663
- const path = resolve(observed.path);
5729
+ const path = resolve2(observed.path);
5664
5730
  if (!allowedPaths.has(path) || observedPaths.has(path)) {
5665
5731
  throw new ProjectContextError("PROJECT_CONTEXT_SESSION_STALE", "session project-context guard contains an unexpected or duplicate path");
5666
5732
  }
@@ -5682,7 +5748,7 @@ function validateProjectContextSessionGuard(guard) {
5682
5748
  function applyProjectContext(options) {
5683
5749
  const workspaceRoot = assertSafeWorkspaceRoot(options.workspace_root);
5684
5750
  const now2 = options.now ?? new Date;
5685
- const lockPath = resolve(workspaceRoot, ...PROJECT_CONTEXT_LOCK_PATH.split("/"));
5751
+ const lockPath = resolve2(workspaceRoot, ...PROJECT_CONTEXT_LOCK_PATH.split("/"));
5686
5752
  const lock = options.dry_run ? null : acquireWorkspaceLock(workspaceRoot, lockPath, options.test_hooks?.after_lock_open, options.test_hooks?.before_stale_lock_remove, options.test_hooks?.process_start_identity);
5687
5753
  try {
5688
5754
  const resolved = resolveBundleForApply(options, workspaceRoot, now2);
@@ -5829,7 +5895,7 @@ function resolveBundleForApply(options, workspaceRoot, now2) {
5829
5895
  if (!options.expected_project_id) {
5830
5896
  throw new ProjectContextError("PROJECT_CONTEXT_CACHE_ID_REQUIRED", "expected_project_id is required for stale-cache fallback");
5831
5897
  }
5832
- const cachePath = resolve(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
5898
+ const cachePath = resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
5833
5899
  const cache = readProjectContextCache(cachePath, workspaceRoot);
5834
5900
  if (!cache)
5835
5901
  throw new ProjectContextError("PROJECT_CONTEXT_CACHE_MISSING", "no last-known-good project context cache exists");
@@ -6185,7 +6251,7 @@ function buildManifest(plan, now2) {
6185
6251
  function buildSessionCompatibilityManifest(plan, now2) {
6186
6252
  const paths = runtimePaths(plan.workspace_root, plan.runtime);
6187
6253
  const tool = manifestTool(plan.runtime);
6188
- const targetHome = plan.runtime === "codewith" ? resolve(plan.workspace_root, ".codewith") : plan.workspace_root;
6254
+ const targetHome = plan.runtime === "codewith" ? resolve2(plan.workspace_root, ".codewith") : plan.workspace_root;
6189
6255
  const targetRelativePath = sessionTargetRelativePath(plan.runtime);
6190
6256
  const existing = existsSync3(paths.sessionManifest) ? readSessionManifestRecord(paths.sessionManifest, plan.workspace_root) : {
6191
6257
  schema: SESSION_RENDER_SCHEMA,
@@ -6207,7 +6273,7 @@ function buildSessionCompatibilityManifest(plan, now2) {
6207
6273
  throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "provider session manifest is malformed or incompatible");
6208
6274
  }
6209
6275
  const existingTargetHome = safeLegacyMetadataString(existing["targetHome"], null);
6210
- if (existingTargetHome !== null && resolve(existingTargetHome) !== targetHome) {
6276
+ if (existingTargetHome !== null && resolve2(existingTargetHome) !== targetHome) {
6211
6277
  throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "provider session manifest targets a different workspace");
6212
6278
  }
6213
6279
  const sources = sanitizeLegacySources(existing["sources"]).filter((source) => source["id"] !== "project-context-bundle");
@@ -6493,9 +6559,9 @@ function writeMetadataSnapshot(plan, now2) {
6493
6559
  const previous = readProjectContextManifest(plan.manifest_path, plan.workspace_root);
6494
6560
  if (!previous || previous.projectContext.revision === plan.bundle.revision && previous.projectContext.hash === plan.bundle.hash)
6495
6561
  return null;
6496
- const snapshotDir = resolve(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
6562
+ const snapshotDir = resolve2(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
6497
6563
  ensureSafeDirectory(snapshotDir, plan.workspace_root, 448);
6498
- const snapshotPath = resolve(snapshotDir, `${safeFilename(previous.projectContext.revision)}-${previous.projectContext.hash.slice(-12)}.json`);
6564
+ const snapshotPath = resolve2(snapshotDir, `${safeFilename(previous.projectContext.revision)}-${previous.projectContext.hash.slice(-12)}.json`);
6499
6565
  const snapshot = {
6500
6566
  schema: "hasna.configs.session-render-snapshot/v1",
6501
6567
  kind: "project-context-metadata",
@@ -6511,8 +6577,8 @@ function writeMetadataSnapshot(plan, now2) {
6511
6577
  return snapshotPath;
6512
6578
  }
6513
6579
  function metadataSnapshotMatchesManifest(plan, manifest) {
6514
- const snapshotDir = resolve(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
6515
- const snapshotPath = resolve(snapshotDir, `${safeFilename(manifest.projectContext.revision)}-${manifest.projectContext.hash.slice(-12)}.json`);
6580
+ const snapshotDir = resolve2(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
6581
+ const snapshotPath = resolve2(snapshotDir, `${safeFilename(manifest.projectContext.revision)}-${manifest.projectContext.hash.slice(-12)}.json`);
6516
6582
  if (!existsSync3(snapshotPath))
6517
6583
  return false;
6518
6584
  const record = readJsonRecord(snapshotPath, plan.workspace_root);
@@ -6561,10 +6627,10 @@ function writeProjectContextRollbackSnapshot(plan, now2, outputs) {
6561
6627
  sha256: nextHash
6562
6628
  };
6563
6629
  });
6564
- const snapshotDir = resolve(plan.workspace_root, ...SESSION_RENDER_SNAPSHOT_RELATIVE_DIR.split("/"));
6630
+ const snapshotDir = resolve2(plan.workspace_root, ...SESSION_RENDER_SNAPSHOT_RELATIVE_DIR.split("/"));
6565
6631
  ensureSafeDirectory(snapshotDir, plan.workspace_root, 448);
6566
6632
  const timestamp = now2.toISOString().replace(/[:.]/g, "-");
6567
- const snapshotPath = resolve(snapshotDir, `${timestamp}-${randomUUID2()}.json`);
6633
+ const snapshotPath = resolve2(snapshotDir, `${timestamp}-${randomUUID2()}.json`);
6568
6634
  const snapshot = {
6569
6635
  schema: "hasna.configs.session-render-snapshot/v2",
6570
6636
  createdAt: now2.toISOString(),
@@ -6629,7 +6695,7 @@ function readSessionManifestRecord(path, workspaceRoot) {
6629
6695
  }
6630
6696
  }
6631
6697
  function atomicWriteFile(path, content, workspaceRoot, defaultMode, expectedHash, afterExchange, atomicExchangeUnavailable = false, beforeInstall, portableCreateOnly = false, maxObservedBytes, allowPortableReplacement = false) {
6632
- const dir = resolve(path, "..");
6698
+ const dir = resolve2(path, "..");
6633
6699
  ensureSafeDirectory(dir, workspaceRoot, 448);
6634
6700
  assertNoSymlinkSegments(workspaceRoot, path);
6635
6701
  const anchoredOps = portableCreateOnly ? null : resolveAnchoredFsOps();
@@ -6646,7 +6712,7 @@ function atomicWriteFile(path, content, workspaceRoot, defaultMode, expectedHash
6646
6712
  const previous = anchoredFileObservation(directory, targetName);
6647
6713
  const previousMode = previous?.mode ?? defaultMode;
6648
6714
  const tempName = `.project-context-${randomUUID2()}.tmp`;
6649
- const tempPath = join3(dir, tempName);
6715
+ const tempPath = join4(dir, tempName);
6650
6716
  let fd = null;
6651
6717
  let preserveTemp = false;
6652
6718
  let directoryChanged = false;
@@ -6777,7 +6843,7 @@ function atomicWritePortable(path, content, workspaceRoot, defaultMode, expected
6777
6843
  }
6778
6844
  const dir = dirname(path);
6779
6845
  const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
6780
- const tempPath = join3(dir, `.project-context-${randomUUID2()}.tmp`);
6846
+ const tempPath = join4(dir, `.project-context-${randomUUID2()}.tmp`);
6781
6847
  let fd = null;
6782
6848
  let tempIdentity = null;
6783
6849
  try {
@@ -6834,7 +6900,7 @@ function atomicWritePortableReplacement(path, content, workspaceRoot, expectedHa
6834
6900
  }
6835
6901
  const dir = dirname(path);
6836
6902
  const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
6837
- const tempPath = join3(dir, `.project-context-${randomUUID2()}.tmp`);
6903
+ const tempPath = join4(dir, `.project-context-${randomUUID2()}.tmp`);
6838
6904
  const desiredHash = sha2562(content);
6839
6905
  let fd = null;
6840
6906
  let tempIdentity = null;
@@ -6903,11 +6969,11 @@ function portableFileHash(path, workspaceRoot, maxObservedBytes) {
6903
6969
  return createHash2("sha256").update(readFileSync(path)).digest("hex");
6904
6970
  }
6905
6971
  function writeProjectContextCoordinatedFile(input) {
6906
- atomicWriteFile(resolve(input.path), input.content, assertSafeWorkspaceRoot(input.workspace_root), input.default_mode ?? 420, input.expected_hash, undefined, false, input.test_hooks?.before_install, input.force_portable_file_ops ?? false, input.max_observed_bytes, input.allow_portable_replacement ?? false);
6972
+ atomicWriteFile(resolve2(input.path), input.content, assertSafeWorkspaceRoot(input.workspace_root), input.default_mode ?? 420, input.expected_hash, undefined, false, input.test_hooks?.before_install, input.force_portable_file_ops ?? false, input.max_observed_bytes, input.allow_portable_replacement ?? false);
6907
6973
  }
6908
6974
  function removeProjectContextCoordinatedFile(input) {
6909
6975
  const workspaceRoot = assertSafeWorkspaceRoot(input.workspace_root);
6910
- const path = resolve(input.path);
6976
+ const path = resolve2(input.path);
6911
6977
  assertNoSymlinkSegments(workspaceRoot, path);
6912
6978
  const dir = dirname(path);
6913
6979
  const anchoredOps = input.force_portable_file_ops ? null : resolveAnchoredFsOps();
@@ -6933,7 +6999,7 @@ function removeProjectContextCoordinatedFile(input) {
6933
6999
  throw new ProjectContextHashRace(`managed path changed during deletion: ${relativePosix(workspaceRoot, path)}`);
6934
7000
  }
6935
7001
  displaced = true;
6936
- input.test_hooks?.after_displace?.(join3(dir, displacedName));
7002
+ input.test_hooks?.after_displace?.(join4(dir, displacedName));
6937
7003
  const moved = anchoredFileObservation(directory, displacedName);
6938
7004
  if (!moved || moved.dev !== observed.dev || moved.ino !== observed.ino || moved.hash !== input.expected_hash || anchoredFileObservation(directory, targetName) !== null) {
6939
7005
  throw new ProjectContextHashRace(`managed path changed during deletion validation: ${relativePosix(workspaceRoot, path)}`);
@@ -6979,7 +7045,7 @@ function removePortableCoordinatedFile(path, workspaceRoot, expectedHash, maxObs
6979
7045
  }
6980
7046
  const dir = dirname(path);
6981
7047
  const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
6982
- const displacedPath = join3(dir, `.project-context-delete-${randomUUID2()}.tmp`);
7048
+ const displacedPath = join4(dir, `.project-context-delete-${randomUUID2()}.tmp`);
6983
7049
  let displaced = false;
6984
7050
  try {
6985
7051
  assertManagedDirectoryStable(dir, workspaceRoot, directoryIdentity);
@@ -7051,7 +7117,7 @@ function anchoredOpenExclusive(directory, name, mode) {
7051
7117
  const requestedMode = mode & 4095;
7052
7118
  let fd;
7053
7119
  try {
7054
- fd = openSync(join3(directory.path, name), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, requestedMode);
7120
+ fd = openSync(join4(directory.path, name), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, requestedMode);
7055
7121
  } catch {
7056
7122
  throw new ProjectContextHashRace(`could not create prepared managed file in ${relativePosix(directory.workspaceRoot, directory.path)}`);
7057
7123
  }
@@ -7094,7 +7160,7 @@ function anchoredFileObservation(directory, name) {
7094
7160
  const stat = fstatSync(fd);
7095
7161
  if (!stat.isFile())
7096
7162
  throw new ProjectContextHashRace("managed output is not a regular file");
7097
- const relativePath = relativePosix(directory.workspaceRoot, join3(directory.path, name));
7163
+ const relativePath = relativePosix(directory.workspaceRoot, join4(directory.path, name));
7098
7164
  const maxBytes = directory.maxObservedBytes === undefined ? managedObservationMaxBytes(relativePath) : directory.maxObservedBytes;
7099
7165
  if (maxBytes !== null && stat.size > maxBytes) {
7100
7166
  throw new ProjectContextHashRace(`managed output exceeds the safe read limit: ${relativePath}`);
@@ -7120,7 +7186,7 @@ function anchoredPreparedObservation(directory, name, path, stage) {
7120
7186
  return observed;
7121
7187
  }
7122
7188
  function captureManagedDirectoryIdentity(path, workspaceRoot) {
7123
- assertNoSymlinkSegments(workspaceRoot, join3(path, ".project-context-directory-guard"));
7189
+ assertNoSymlinkSegments(workspaceRoot, join4(path, ".project-context-directory-guard"));
7124
7190
  let stat;
7125
7191
  try {
7126
7192
  stat = lstatSync(path);
@@ -7133,7 +7199,7 @@ function captureManagedDirectoryIdentity(path, workspaceRoot) {
7133
7199
  return { dev: stat.dev, ino: stat.ino };
7134
7200
  }
7135
7201
  function assertManagedDirectoryStable(path, workspaceRoot, expected) {
7136
- assertNoSymlinkSegments(workspaceRoot, join3(path, ".project-context-directory-guard"));
7202
+ assertNoSymlinkSegments(workspaceRoot, join4(path, ".project-context-directory-guard"));
7137
7203
  let current;
7138
7204
  try {
7139
7205
  current = lstatSync(path);
@@ -7268,10 +7334,10 @@ function resolveAnchoredFsOps() {
7268
7334
  return null;
7269
7335
  }
7270
7336
  function acquireWorkspaceLock(workspaceRoot, lockPath, afterOpen, beforeStaleRemove, processStartIdentityLookup = processStartIdentity) {
7271
- const lockDirectory = resolve(lockPath, "..");
7337
+ const lockDirectory = resolve2(lockPath, "..");
7272
7338
  ensureSafeDirectory(lockDirectory, workspaceRoot, 448);
7273
7339
  assertNoSymlinkSegments(workspaceRoot, lockPath);
7274
- const tempPath = join3(lockDirectory, `.project-context-lock-${randomUUID2()}.tmp`);
7340
+ const tempPath = join4(lockDirectory, `.project-context-lock-${randomUUID2()}.tmp`);
7275
7341
  let fd = null;
7276
7342
  let openedIdentity = null;
7277
7343
  let openedContentHash = null;
@@ -7343,7 +7409,7 @@ function removeOwnedLockByInode(lockPath, identity, expectedHash) {
7343
7409
  if (expectedHash !== undefined && sha2562(readFileSync(lockPath, "utf8")) !== expectedHash)
7344
7410
  return;
7345
7411
  rmSync2(lockPath);
7346
- fsyncDirectory(resolve(lockPath, ".."));
7412
+ fsyncDirectory(resolve2(lockPath, ".."));
7347
7413
  } catch {}
7348
7414
  }
7349
7415
  function observeStaleWorkspaceLock(lockPath, workspaceRoot, processStartIdentityLookup = processStartIdentity) {
@@ -7422,7 +7488,7 @@ function tryTakeoverStaleWorkspaceLock(candidatePath, lockPath, workspaceRoot, c
7422
7488
  throw new ProjectContextError("PROJECT_CONTEXT_LOCK_LOST", "workspace lock changed during stale-lock takeover and could not be restored safely");
7423
7489
  }
7424
7490
  rmSync2(candidatePath);
7425
- fsyncDirectory(resolve(lockPath, ".."));
7491
+ fsyncDirectory(resolve2(lockPath, ".."));
7426
7492
  exchanged = false;
7427
7493
  return true;
7428
7494
  } catch (error) {
@@ -7501,8 +7567,8 @@ function releaseWorkspaceLock(lockPath, lock, workspaceRoot) {
7501
7567
  }
7502
7568
  return;
7503
7569
  }
7504
- const lockDirectory = resolve(lockPath, "..");
7505
- const releasePath = join3(lockDirectory, `.project-context-release-${randomUUID2()}.tmp`);
7570
+ const lockDirectory = resolve2(lockPath, "..");
7571
+ const releasePath = join4(lockDirectory, `.project-context-release-${randomUUID2()}.tmp`);
7506
7572
  let releaseFd = null;
7507
7573
  let releaseIdentity = null;
7508
7574
  let releaseHash = null;
@@ -7582,7 +7648,7 @@ function ensureSafeDirectory(path, workspaceRoot, mode) {
7582
7648
  const segments = rel.split(/[\\/]+/).filter(Boolean);
7583
7649
  let current = workspaceRoot;
7584
7650
  for (const segment of segments) {
7585
- current = join3(current, segment);
7651
+ current = join4(current, segment);
7586
7652
  if (existsSync3(current)) {
7587
7653
  if (lstatSync(current).isSymbolicLink())
7588
7654
  throw new ProjectContextError("PROJECT_CONTEXT_SYMLINK_REJECTED", `managed path uses a symlink: ${current}`);
@@ -7590,7 +7656,7 @@ function ensureSafeDirectory(path, workspaceRoot, mode) {
7590
7656
  throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", `managed path is not a directory: ${current}`);
7591
7657
  } else {
7592
7658
  mkdirSync2(current, { mode });
7593
- fsyncDirectory(resolve(current, ".."));
7659
+ fsyncDirectory(resolve2(current, ".."));
7594
7660
  }
7595
7661
  }
7596
7662
  }
@@ -7646,11 +7712,11 @@ function scanGeneratedContent(content) {
7646
7712
  function runtimePaths(workspaceRoot, runtime) {
7647
7713
  const relativeTarget = runtime === "claude" ? "CLAUDE.md" : runtime === "codewith" ? ".codewith/CODEWITH.md" : "AGENTS.md";
7648
7714
  return {
7649
- target: resolve(workspaceRoot, ...relativeTarget.split("/")),
7650
- fragment: resolve(workspaceRoot, ...PROJECT_CONTEXT_FRAGMENT_PATH.split("/")),
7651
- manifest: resolve(workspaceRoot, ...PROJECT_CONTEXT_MANIFEST_PATH.split("/")),
7652
- cache: resolve(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/")),
7653
- sessionManifest: runtime === "codewith" ? resolve(workspaceRoot, ".codewith", ".hasna", "session-render-manifest.json") : resolve(workspaceRoot, ".hasna", "session-render-manifest.json")
7715
+ target: resolve2(workspaceRoot, ...relativeTarget.split("/")),
7716
+ fragment: resolve2(workspaceRoot, ...PROJECT_CONTEXT_FRAGMENT_PATH.split("/")),
7717
+ manifest: resolve2(workspaceRoot, ...PROJECT_CONTEXT_MANIFEST_PATH.split("/")),
7718
+ cache: resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/")),
7719
+ sessionManifest: runtime === "codewith" ? resolve2(workspaceRoot, ".codewith", ".hasna", "session-render-manifest.json") : resolve2(workspaceRoot, ".hasna", "session-render-manifest.json")
7654
7720
  };
7655
7721
  }
7656
7722
  function projectContextSessionGuardPaths(paths, runtime) {
@@ -7660,7 +7726,7 @@ function projectContextSessionGuardPaths(paths, runtime) {
7660
7726
  paths.fragment,
7661
7727
  paths.target,
7662
7728
  paths.sessionManifest,
7663
- ...runtime === "codewith" ? [resolve(paths.target, "..", "CODEWITH.override.md")] : []
7729
+ ...runtime === "codewith" ? [resolve2(paths.target, "..", "CODEWITH.override.md")] : []
7664
7730
  ];
7665
7731
  }
7666
7732
  function sessionTargetRelativePath(runtime) {
@@ -7680,12 +7746,12 @@ function projectContextRuntimeForSessionTool(tool) {
7680
7746
  return null;
7681
7747
  }
7682
7748
  function projectContextWorkspaceForSession(input, runtime) {
7683
- const targetHome = resolve(input.target_home);
7749
+ const targetHome = resolve2(input.target_home);
7684
7750
  if (runtime === "codewith") {
7685
7751
  const workspaceRoot = basename(targetHome) === ".codewith" ? dirname(targetHome) : null;
7686
7752
  if (!workspaceRoot)
7687
7753
  return null;
7688
- if (input.project_root && resolve(input.project_root) !== workspaceRoot) {
7754
+ if (input.project_root && resolve2(input.project_root) !== workspaceRoot) {
7689
7755
  throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "Codewith project_root must be the parent workspace of target_home");
7690
7756
  }
7691
7757
  if (!existsSync3(workspaceRoot) || !lstatSync(workspaceRoot).isDirectory())
@@ -7699,7 +7765,7 @@ function projectContextWorkspaceForSession(input, runtime) {
7699
7765
  function assertCodewithTargetIsConsumed(workspaceRoot, runtime) {
7700
7766
  if (runtime !== "codewith")
7701
7767
  return;
7702
- const override = resolve(workspaceRoot, ".codewith", "CODEWITH.override.md");
7768
+ const override = resolve2(workspaceRoot, ".codewith", "CODEWITH.override.md");
7703
7769
  if (!existsSync3(override))
7704
7770
  return;
7705
7771
  assertNoSymlinkSegments(workspaceRoot, override);
@@ -7710,7 +7776,7 @@ function assertCodewithTargetIsConsumed(workspaceRoot, runtime) {
7710
7776
  function assertSafeWorkspaceRoot(path) {
7711
7777
  if (!isAbsolute(path))
7712
7778
  throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "workspace root must be absolute");
7713
- const normalized = resolve(path);
7779
+ const normalized = resolve2(path);
7714
7780
  if (normalized === parse(normalized).root)
7715
7781
  throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "workspace root cannot be the filesystem root");
7716
7782
  if (!existsSync3(normalized) || !lstatSync(normalized).isDirectory())
@@ -7727,17 +7793,17 @@ function assertNoSymlinkSegments(root, target) {
7727
7793
  }
7728
7794
  let current = root;
7729
7795
  for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
7730
- current = join3(current, segment);
7796
+ current = join4(current, segment);
7731
7797
  if (existsSync3(current) && lstatSync(current).isSymbolicLink()) {
7732
7798
  throw new ProjectContextError("PROJECT_CONTEXT_SYMLINK_REJECTED", `managed path uses a symlink: ${current}`);
7733
7799
  }
7734
7800
  }
7735
7801
  }
7736
7802
  function assertNoSymlinkAncestors(path) {
7737
- const normalized = resolve(path);
7803
+ const normalized = resolve2(path);
7738
7804
  let current = parse(normalized).root;
7739
7805
  for (const segment of relative(current, normalized).split(/[\\/]+/).filter(Boolean)) {
7740
- current = join3(current, segment);
7806
+ current = join4(current, segment);
7741
7807
  if (!existsSync3(current))
7742
7808
  return;
7743
7809
  if (lstatSync(current).isSymbolicLink())
@@ -7773,10 +7839,10 @@ function fragmentMatchesBundle(path, bundle, workspaceRoot) {
7773
7839
  }
7774
7840
  function durableSourcePath(path, workspaceRoot) {
7775
7841
  if (!path || path.startsWith("/dev/fd/"))
7776
- return resolve(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
7777
- const normalized = isAbsolute(path) ? resolve(path) : resolve(workspaceRoot, path);
7842
+ return resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
7843
+ const normalized = isAbsolute(path) ? resolve2(path) : resolve2(workspaceRoot, path);
7778
7844
  if (normalized.startsWith("/dev/fd/"))
7779
- return resolve(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
7845
+ return resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
7780
7846
  return normalized;
7781
7847
  }
7782
7848
  function compareRevisions(incoming, previous) {
@@ -8072,10 +8138,6 @@ function applyTransform(source, output, context = {}) {
8072
8138
  }
8073
8139
  }
8074
8140
 
8075
- // src/lib/asset-plan.ts
8076
- import { createHash as createHash3 } from "crypto";
8077
- import { isAbsolute as isAbsolute2, posix, resolve as resolve2 } from "path";
8078
-
8079
8141
  // src/lib/provider-version.ts
8080
8142
  function providerVersionSatisfies(version, range) {
8081
8143
  const current = parseProviderVersion(version);
@@ -8120,6 +8182,8 @@ function compareProviderVersions(left, right) {
8120
8182
  }
8121
8183
 
8122
8184
  // src/lib/asset-plan.ts
8185
+ import { createHash as createHash3 } from "crypto";
8186
+ import { isAbsolute as isAbsolute2, posix, resolve as resolve3 } from "path";
8123
8187
  var ASSET_PLAN_SCHEMA = "hasna.instructions.asset-plan/v1";
8124
8188
  var ASSET_CAPABILITY_SCHEMA = "hasna.instructions.asset-capability/v1";
8125
8189
  var ASSET_BUNDLE_SCHEMA = "hasna.instructions.asset-bundle/v1";
@@ -8384,8 +8448,8 @@ function resolveAssetDestination(item, roots) {
8384
8448
  if (!isAbsolute2(root))
8385
8449
  throw new Error(`Asset ${item.assetKey} destination root must be absolute.`);
8386
8450
  const relativePath = safeRelativePath(item.destination.relativePath);
8387
- const target = resolve2(root, ...relativePath.split("/"));
8388
- const normalizedRoot = resolve2(root);
8451
+ const target = resolve3(root, ...relativePath.split("/"));
8452
+ const normalizedRoot = resolve3(root);
8389
8453
  if (target === normalizedRoot)
8390
8454
  throw new Error(`Asset ${item.assetKey} destination cannot replace its root.`);
8391
8455
  if (!target.startsWith(`${normalizedRoot}/`))
@@ -8507,8 +8571,8 @@ function deepFreeze(value) {
8507
8571
  // src/lib/cursor-authority.ts
8508
8572
  import { createHash as createHash4 } from "crypto";
8509
8573
  import { lstatSync as lstatSync2, readFileSync as readFileSync2 } from "fs";
8510
- import { homedir as homedir2 } from "os";
8511
- import { join as join4, resolve as resolve3 } from "path";
8574
+ import { homedir as homedir3 } from "os";
8575
+ import { join as join5, resolve as resolve4 } from "path";
8512
8576
  var CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH = ".cursor/rules/hasna-global.mdc";
8513
8577
  var CURSOR_GLOBAL_AUTHORITY_MAX_BYTES = 256 * 1024;
8514
8578
  var CURSOR_GLOBAL_AUTHORITY_MANAGED_MARKER = "Managed by @hasna/configs cursor global authority";
@@ -8518,7 +8582,7 @@ function sha2564(content) {
8518
8582
  return createHash4("sha256").update(content).digest("hex");
8519
8583
  }
8520
8584
  function homeDir() {
8521
- return process.env["HOME"] || homedir2();
8585
+ return process.env["HOME"] || homedir3();
8522
8586
  }
8523
8587
  function markerPayload(content, markerLine, markerIndex) {
8524
8588
  const index = markerIndex ?? content.indexOf(markerLine);
@@ -8534,12 +8598,12 @@ function baseObservation(path) {
8534
8598
  };
8535
8599
  }
8536
8600
  function observeCursorGlobalAuthority(options = {}) {
8537
- const authorityPath = resolve3(join4(options.home ?? homeDir(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
8601
+ const authorityPath = resolve4(join5(options.home ?? homeDir(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
8538
8602
  const readFile = options.readFile ?? ((path) => readFileSync2(path, "utf8"));
8539
8603
  return observeCursorGlobalAuthorityPath(authorityPath, readFile);
8540
8604
  }
8541
8605
  function observeCursorGlobalAuthorityAtPath(authorityPath) {
8542
- return observeCursorGlobalAuthorityPath(resolve3(authorityPath), (path) => readFileSync2(path, "utf8"));
8606
+ return observeCursorGlobalAuthorityPath(resolve4(authorityPath), (path) => readFileSync2(path, "utf8"));
8543
8607
  }
8544
8608
  function observeCursorGlobalAuthorityPath(authorityPath, readFile) {
8545
8609
  const base = baseObservation(authorityPath);
@@ -8684,7 +8748,7 @@ function observeCursorGlobalAuthorityPath(authorityPath, readFile) {
8684
8748
  };
8685
8749
  }
8686
8750
  function isCursorGlobalAuthorityPath(path) {
8687
- return resolve3(path) === resolve3(join4(homeDir(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
8751
+ return resolve4(path) === resolve4(join5(homeDir(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
8688
8752
  }
8689
8753
  function stampCursorGlobalAuthorityMarker(content) {
8690
8754
  if (CURSOR_GLOBAL_AUTHORITY_MARKER_PATTERN.test(content))
@@ -8721,8 +8785,82 @@ function detectCursorAuthorityConflicts(observation = observeCursorGlobalAuthori
8721
8785
  }];
8722
8786
  }
8723
8787
 
8788
+ // src/lib/session-authority.ts
8789
+ import { createHash as createHash5 } from "crypto";
8790
+ import { lstatSync as lstatSync3, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
8791
+ import { join as join6, resolve as resolve5 } from "path";
8792
+ var CLAUDE_LEGACY_AUTHORITY_RELATIVE_PATH = "AGENTS.md";
8793
+ var CLAUDE_LEGACY_AUTHORITY_MAX_BYTES = 256 * 1024;
8794
+ var CLAUDE_LEGACY_MARKERS = [
8795
+ { id: "claude-agent-rules-heading", pattern: /^# Agent Rules \(Claude\)/m },
8796
+ { id: "no-worktrees-heading", pattern: /^## No Worktrees/m },
8797
+ { id: "no-worktrees-directive", pattern: /\bNever use git worktrees\b/m }
8798
+ ];
8799
+ function sha2565(content) {
8800
+ return createHash5("sha256").update(content).digest("hex");
8801
+ }
8802
+ function detectClaudeAuthorityConflicts(targetHome) {
8803
+ const authorityPath = resolve5(join6(targetHome, CLAUDE_LEGACY_AUTHORITY_RELATIVE_PATH));
8804
+ let stat;
8805
+ try {
8806
+ stat = lstatSync3(authorityPath);
8807
+ } catch {
8808
+ return [];
8809
+ }
8810
+ const provenanceBase = {
8811
+ tool: "claude",
8812
+ relativePath: CLAUDE_LEGACY_AUTHORITY_RELATIVE_PATH,
8813
+ path: authorityPath
8814
+ };
8815
+ if (stat.isSymbolicLink() || !stat.isFile()) {
8816
+ return [{
8817
+ ...provenanceBase,
8818
+ kind: "invalid-unmanaged-authority",
8819
+ sha256: null,
8820
+ markers: [],
8821
+ provenance: {
8822
+ source: "filesystem",
8823
+ authority: "unmanaged",
8824
+ observedPath: authorityPath,
8825
+ detection: "non-regular-file"
8826
+ },
8827
+ reason: "Claude target contains unmanaged AGENTS.md that is not a regular file; authority cannot be verified safely."
8828
+ }];
8829
+ }
8830
+ if (statSync2(authorityPath).size > CLAUDE_LEGACY_AUTHORITY_MAX_BYTES) {
8831
+ return [{
8832
+ ...provenanceBase,
8833
+ kind: "invalid-unmanaged-authority",
8834
+ sha256: null,
8835
+ markers: [],
8836
+ provenance: {
8837
+ source: "filesystem",
8838
+ authority: "unmanaged",
8839
+ observedPath: authorityPath,
8840
+ detection: "oversized-file"
8841
+ },
8842
+ reason: `Claude target contains unmanaged AGENTS.md larger than ${CLAUDE_LEGACY_AUTHORITY_MAX_BYTES} bytes; authority cannot be classified safely.`
8843
+ }];
8844
+ }
8845
+ const content = readFileSync3(authorityPath, "utf8");
8846
+ const markers = CLAUDE_LEGACY_MARKERS.filter((marker) => marker.pattern.test(content)).map((marker) => marker.id);
8847
+ const knownLegacy = markers.includes("no-worktrees-heading") && markers.includes("no-worktrees-directive");
8848
+ return [{
8849
+ ...provenanceBase,
8850
+ kind: knownLegacy ? "known-legacy-no-worktree" : "unknown-unmanaged-authority",
8851
+ sha256: sha2565(content),
8852
+ markers,
8853
+ provenance: {
8854
+ source: "filesystem",
8855
+ authority: "unmanaged",
8856
+ observedPath: authorityPath,
8857
+ detection: knownLegacy ? "known-legacy-markers" : "unknown-content"
8858
+ },
8859
+ reason: knownLegacy ? "Claude target contains unmanaged legacy AGENTS.md with no-worktree directives; migrate or remove it through an owned authority path before applying." : "Claude target contains unmanaged AGENTS.md with unknown authority content; refusing to guess whether it conflicts with the managed Claude render."
8860
+ }];
8861
+ }
8862
+
8724
8863
  // src/lib/session-render.ts
8725
- var RAW_STORE_ROOT_ENV = "HASNA_CONFIGS_HOME";
8726
8864
  var ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000;
8727
8865
  var SESSION_RENDERER_OWNER_ID = "instructions-session-renderer";
8728
8866
  var SESSION_RENDER_TOOLS = [
@@ -8934,11 +9072,11 @@ function ensureTrailingNewline3(content) {
8934
9072
  `) ? content : `${content}
8935
9073
  `;
8936
9074
  }
8937
- function sha2565(content) {
8938
- return createHash5("sha256").update(content).digest("hex");
9075
+ function sha2566(content) {
9076
+ return createHash6("sha256").update(content).digest("hex");
8939
9077
  }
8940
9078
  function fingerprint(value) {
8941
- return sha2565(JSON.stringify(value));
9079
+ return sha2566(JSON.stringify(value));
8942
9080
  }
8943
9081
  function canonicalFingerprintValue(value) {
8944
9082
  if (Array.isArray(value))
@@ -8956,7 +9094,7 @@ function ruleAttestation(rule) {
8956
9094
  };
8957
9095
  const applied = metadata["payloadFloorApplied"];
8958
9096
  return {
8959
- contentSha256: sha2565(rule.content ?? ""),
9097
+ contentSha256: sha2566(rule.content ?? ""),
8960
9098
  payloadFloorApplied: typeof applied === "boolean" ? applied : null,
8961
9099
  flooredFromRulesVersion: read("flooredFromRulesVersion"),
8962
9100
  flooredFromPayloadSha256: read("flooredFromPayloadSha256"),
@@ -9002,16 +9140,14 @@ function slug(value) {
9002
9140
  function yamlQuote2(value) {
9003
9141
  return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
9004
9142
  }
9005
- function getRawStoreRoot() {
9006
- return resolve4(process.env[RAW_STORE_ROOT_ENV] || join5(process.env["HOME"] || homedir3(), ".hasna", "configs"));
9007
- }
9008
9143
  function defaultTargetHome(tool, profile, sessionId) {
9009
- return join5(getRawStoreRoot(), "sessions", tool, slug(profile), slug(sessionId || "latest"));
9144
+ const home = process.env["HOME"] || homedir4();
9145
+ return join7(home, ".hasna", "accounts", "profiles", tool, slug(profile));
9010
9146
  }
9011
9147
  function joinTarget(targetHome, relativePath) {
9012
9148
  const safeTargetHome = assertSafeTargetRoot(targetHome);
9013
9149
  const safeRelativePath2 = assertSafeRelativePath(relativePath);
9014
- return join5(safeTargetHome, ...safeRelativePath2.split("/"));
9150
+ return join7(safeTargetHome, ...safeRelativePath2.split("/"));
9015
9151
  }
9016
9152
  function makeFile(targetHome, relativePath, role, content, sourceIds) {
9017
9153
  const safeTargetHome = assertSafeTargetRoot(targetHome);
@@ -9022,7 +9158,7 @@ function makeFile(targetHome, relativePath, role, content, sourceIds) {
9022
9158
  relativePath: safeRelativePath2,
9023
9159
  role,
9024
9160
  content: normalizedContent,
9025
- sha256: sha2565(normalizedContent),
9161
+ sha256: sha2566(normalizedContent),
9026
9162
  sourceIds
9027
9163
  };
9028
9164
  }
@@ -9056,7 +9192,7 @@ function applyAgentOperatingRulesFloor(source, content) {
9056
9192
  const floored = {
9057
9193
  payloadFloorApplied: true,
9058
9194
  flooredFromRulesVersion: parseAgentOperatingRulesVersion(content),
9059
- flooredFromPayloadSha256: sha2565(content)
9195
+ flooredFromPayloadSha256: sha2566(content)
9060
9196
  };
9061
9197
  return {
9062
9198
  content: payload.content,
@@ -9078,7 +9214,7 @@ function applyAgentOperatingRulesFloorToRule(source, rule, content) {
9078
9214
  const floored = {
9079
9215
  payloadFloorApplied: true,
9080
9216
  flooredFromRulesVersion: parseAgentOperatingRulesVersion(content),
9081
- flooredFromPayloadSha256: sha2565(content)
9217
+ flooredFromPayloadSha256: sha2566(content)
9082
9218
  };
9083
9219
  return {
9084
9220
  content: payload.content,
@@ -9097,7 +9233,7 @@ function skippedSource(source, reason) {
9097
9233
  order: source.resolvedOrder,
9098
9234
  path: source.path ?? null,
9099
9235
  hash: source.hash ?? null,
9100
- renderedPayloadSha256: sha2565(source.content),
9236
+ renderedPayloadSha256: sha2566(source.content),
9101
9237
  nonOverridable: source.nonOverridable === true,
9102
9238
  provenance: source.provenance ?? null
9103
9239
  }
@@ -9139,7 +9275,7 @@ function compareSessionInstructionSources(a, b) {
9139
9275
  return SESSION_LAYER_RANK[a.resolvedLayer] - SESSION_LAYER_RANK[b.resolvedLayer] || a.resolvedOrder - b.resolvedOrder || a.id.localeCompare(b.id);
9140
9276
  }
9141
9277
  function semanticPolicyIntegrity(body) {
9142
- return sha2565(body) === AGENT_OPERATING_RULES_PAYLOAD_SHA256 ? "pinned-digest" : "unverified-self-declared";
9278
+ return sha2566(body) === AGENT_OPERATING_RULES_PAYLOAD_SHA256 ? "pinned-digest" : "unverified-self-declared";
9143
9279
  }
9144
9280
  function semanticPolicyDeclaration(source) {
9145
9281
  const normalize = (value) => value.replace(/\r\n/g, `
@@ -9364,7 +9500,7 @@ function composeSources(sources, tool) {
9364
9500
  targetSourceId: target.id,
9365
9501
  targetNormalizedSourceId: target.normalizedId,
9366
9502
  targetHash: target.hash ?? null,
9367
- targetRenderedPayloadSha256: sha2565(target.content),
9503
+ targetRenderedPayloadSha256: sha2566(target.content),
9368
9504
  targetNonOverridable: protectedReplacement,
9369
9505
  authority: protectedReplacement ? "canonical-identity-export/codewith-provider/v1" : "overridable-source/v1"
9370
9506
  }
@@ -9455,16 +9591,51 @@ function indexHeader(tool, profile) {
9455
9591
  ].join(`
9456
9592
  `);
9457
9593
  }
9458
- function buildNativeImportFiles(targetHome, adapter, profile, sources) {
9594
+ var CLAUDE_PATHS_RULES_VERSION_RANGE = ">=2.1.84";
9595
+ function isCompiledClaudeGlobSource(adapter, source, providerVersion) {
9596
+ if (adapter.tool !== "claude")
9597
+ return false;
9598
+ if (providerVersion && !providerVersionSatisfies(providerVersion, CLAUDE_PATHS_RULES_VERSION_RANGE))
9599
+ return false;
9600
+ const compiledBinding = source.provenance?.["profileBinding"];
9601
+ if (!compiledBinding || typeof compiledBinding !== "object")
9602
+ return false;
9603
+ const activation = source.metadata?.["activation"];
9604
+ return activation?.mode === "glob";
9605
+ }
9606
+ function claudeGlobRuleFile(targetHome, index, source) {
9607
+ const globs = source.globs ?? [];
9608
+ if (globs.length === 0)
9609
+ throw new Error(`Claude glob source ${source.id} has no paths.`);
9610
+ const n = String(index + 1).padStart(2, "0");
9611
+ const relativePath = posix2.join("rules", `${n}-${source.normalizedId}.md`);
9612
+ const content = [
9613
+ "---",
9614
+ "paths:",
9615
+ ...globs.map((glob) => ` - ${yamlQuote2(glob)}`),
9616
+ "---",
9617
+ "",
9618
+ sectionForSource(source),
9619
+ ...source.resolvedRules.flatMap((rule) => ["", sectionForRule(source, rule)])
9620
+ ].join(`
9621
+ `);
9622
+ return makeFile(targetHome, relativePath, "rule", content, [source.id, ...source.resolvedRules.map((rule) => rule.id)]);
9623
+ }
9624
+ function buildNativeImportFiles(targetHome, adapter, profile, sources, providerVersion) {
9459
9625
  const indexFile = adapter.indexFile;
9460
- const fragments = sources.flatMap((source, index2) => [
9461
- makeFile(targetHome, fragmentPath(adapter, index2, source), "fragment", sectionForSource(source), [source.id]),
9462
- ...source.resolvedRules.map((rule) => makeFile(targetHome, ruleFragmentPath(adapter, source, rule), "rule", sectionForRule(source, rule), [source.id, rule.id]))
9463
- ]);
9626
+ const fragments = sources.flatMap((source, index2) => {
9627
+ if (isCompiledClaudeGlobSource(adapter, source, providerVersion))
9628
+ return [];
9629
+ return [
9630
+ makeFile(targetHome, fragmentPath(adapter, index2, source), "fragment", sectionForSource(source), [source.id]),
9631
+ ...source.resolvedRules.map((rule) => makeFile(targetHome, ruleFragmentPath(adapter, source, rule), "rule", sectionForRule(source, rule), [source.id, rule.id]))
9632
+ ];
9633
+ });
9634
+ const conditionalRules = sources.flatMap((source, index2) => isCompiledClaudeGlobSource(adapter, source, providerVersion) ? [claudeGlobRuleFile(targetHome, index2, source)] : []);
9464
9635
  const imports = fragments.map((file) => `@${importPath(indexFile, file.relativePath)}`);
9465
9636
  const index = makeFile(targetHome, indexFile, "index", [indexHeader(adapter.tool, profile), ...imports].join(`
9466
9637
  `), sources.map((source) => source.id));
9467
- return [index, ...fragments];
9638
+ return [index, ...fragments, ...conditionalRules];
9468
9639
  }
9469
9640
  function buildFlattenedMarkdownFiles(targetHome, adapter, profile, sources) {
9470
9641
  const content = [
@@ -9546,7 +9717,7 @@ function buildOpenCodeFiles(targetHome, adapter, profile, sources, providerConfi
9546
9717
  ...sources.flatMap((source) => source.resolvedRules.map((rule) => rule.id))
9547
9718
  ]);
9548
9719
  const existingConfigPath = joinTarget(targetHome, adapter.configFile);
9549
- const selectedConfig = existsSync4(existingConfigPath) ? readOpenCodeConfig(readFileSync3(existingConfigPath, "utf8"), existingConfigPath) : providerConfig ? readOpenCodeConfig(providerConfig.content, providerConfig.sourceId) : {};
9720
+ const selectedConfig = existsSync4(existingConfigPath) ? readOpenCodeConfig(readFileSync4(existingConfigPath, "utf8"), existingConfigPath) : providerConfig ? readOpenCodeConfig(providerConfig.content, providerConfig.sourceId) : {};
9550
9721
  const preservedInstructions = normalizeOpenCodeInstructions(selectedConfig["instructions"]).filter((path) => !pathIsManagedOpenCodeInstruction(path, adapter.managedDir));
9551
9722
  const config = {
9552
9723
  ...selectedConfig,
@@ -9652,10 +9823,10 @@ function makeAntigravityRuleFile(targetHome, relativePath, content, sourceIds) {
9652
9823
  }
9653
9824
  return file;
9654
9825
  }
9655
- function buildFiles(targetHome, adapter, profile, sources, providerConfig) {
9826
+ function buildFiles(targetHome, adapter, profile, sources, providerConfig, providerVersion) {
9656
9827
  switch (adapter.mode) {
9657
9828
  case "native-imports":
9658
- return buildNativeImportFiles(targetHome, adapter, profile, sources);
9829
+ return buildNativeImportFiles(targetHome, adapter, profile, sources, providerVersion);
9659
9830
  case "flattened-markdown":
9660
9831
  return buildFlattenedMarkdownFiles(targetHome, adapter, profile, sources);
9661
9832
  case "cursor-mdc":
@@ -9695,7 +9866,7 @@ function buildAssetFiles(input, targetHome, blocked) {
9695
9866
  relativePath: assertSafeRelativePath(relativePath),
9696
9867
  role: "asset",
9697
9868
  content,
9698
- sha256: sha2565(content),
9869
+ sha256: sha2566(content),
9699
9870
  sourceIds: [item.sourceConfigId, item.assetId]
9700
9871
  };
9701
9872
  });
@@ -9735,7 +9906,7 @@ function adapterFor(input) {
9735
9906
  return gatedNativeImports ? CODEWITH_NATIVE_ADAPTER : CODEWITH_FLATTENED_ADAPTER;
9736
9907
  }
9737
9908
  function getHomeDir() {
9738
- return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir3();
9909
+ return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir4();
9739
9910
  }
9740
9911
  function cleanSessionPathInput(path) {
9741
9912
  const trimmed = path.trim();
@@ -9750,16 +9921,16 @@ function resolveSessionPath(path) {
9750
9921
  throw new Error("Session render path cannot be empty.");
9751
9922
  const home = getHomeDir();
9752
9923
  if (cleaned === "~")
9753
- return resolve4(home);
9924
+ return resolve6(home);
9754
9925
  if (cleaned.startsWith("~/"))
9755
- return resolve4(home, cleaned.slice(2));
9926
+ return resolve6(home, cleaned.slice(2));
9756
9927
  if (cleaned === "{{HOME}}" || cleaned === "${HOME}")
9757
- return resolve4(home);
9928
+ return resolve6(home);
9758
9929
  if (cleaned.startsWith("{{HOME}}/"))
9759
- return resolve4(home, cleaned.slice("{{HOME}}/".length));
9930
+ return resolve6(home, cleaned.slice("{{HOME}}/".length));
9760
9931
  if (cleaned.startsWith("${HOME}/"))
9761
- return resolve4(home, cleaned.slice("${HOME}/".length));
9762
- return resolve4(cleaned);
9932
+ return resolve6(home, cleaned.slice("${HOME}/".length));
9933
+ return resolve6(cleaned);
9763
9934
  }
9764
9935
  function assertSafeRelativePath(relativePath) {
9765
9936
  if (!relativePath.trim())
@@ -9775,7 +9946,7 @@ function assertSafeRelativePath(relativePath) {
9775
9946
  function assertSafeTargetRoot(targetHome) {
9776
9947
  if (!isAbsolute3(targetHome))
9777
9948
  throw new Error(`Session render target must be an absolute path: ${targetHome}`);
9778
- const normalized = resolve4(targetHome);
9949
+ const normalized = resolve6(targetHome);
9779
9950
  if (normalized === parse2(normalized).root) {
9780
9951
  throw new Error(`Session render target cannot be the filesystem root: ${targetHome}`);
9781
9952
  }
@@ -9873,7 +10044,7 @@ function planSessionRender(input) {
9873
10044
  blockers: targetBlockers
9874
10045
  } = resolveRenderTarget(input);
9875
10046
  const authorityObservations = input.tool === "cursor" && targetKind !== "blocked" ? [observeCursorGlobalAuthority({ home: input.cursorAuthorityHome })] : [];
9876
- const authorityConflicts = input.tool === "cursor" && targetKind !== "blocked" ? detectCursorAuthorityConflicts(authorityObservations[0]) : [];
10047
+ const authorityConflicts = input.tool === "cursor" && targetKind !== "blocked" ? detectCursorAuthorityConflicts(authorityObservations[0]) : input.tool === "claude" && targetKind !== "blocked" ? detectClaudeAuthorityConflicts(targetHome) : [];
9877
10048
  const blockers = [
9878
10049
  ...targetBlockers,
9879
10050
  ...authorityConflicts.map((conflict) => `${conflict.relativePath}: ${conflict.reason}`)
@@ -9902,7 +10073,7 @@ function planSessionRender(input) {
9902
10073
  if (input.providerConfig && input.tool !== "opencode") {
9903
10074
  throw new Error("Provider base config is supported only for OpenCode session renders.");
9904
10075
  }
9905
- const baseFiles = blocked ? [] : buildFiles(targetHome, adapter, input.profile, orderedSources, input.providerConfig);
10076
+ const baseFiles = blocked ? [] : buildFiles(targetHome, adapter, input.profile, orderedSources, input.providerConfig, input.provider_version);
9906
10077
  const projectContext = blocked ? null : composeProjectContextSessionRender({
9907
10078
  tool: input.tool,
9908
10079
  adapter_mode: adapter.mode,
@@ -9971,7 +10142,7 @@ function planSessionRender(input) {
9971
10142
  hash: rule.hash ?? null,
9972
10143
  ...ruleAttestation(rule)
9973
10144
  })),
9974
- renderedPayloadSha256: sha2565(source.content),
10145
+ renderedPayloadSha256: sha2566(source.content),
9975
10146
  provenance: source.provenance ?? null,
9976
10147
  metadata: source.metadata ?? null
9977
10148
  })),
@@ -10009,8 +10180,8 @@ function planSessionRender(input) {
10009
10180
  ...input.providerConfig ? {
10010
10181
  providerConfig: {
10011
10182
  sourceId: input.providerConfig.sourceId,
10012
- selectedPayloadSha256: sha2565(input.providerConfig.content),
10013
- renderedPayloadSha256: files.find((file) => file.relativePath === adapter.configFile)?.sha256 ?? sha2565(input.providerConfig.content),
10183
+ selectedPayloadSha256: sha2566(input.providerConfig.content),
10184
+ renderedPayloadSha256: files.find((file) => file.relativePath === adapter.configFile)?.sha256 ?? sha2566(input.providerConfig.content),
10014
10185
  selected: !existsSync4(joinTarget(targetHome, adapter.configFile))
10015
10186
  }
10016
10187
  } : {},
@@ -10118,7 +10289,7 @@ function selectProfileConfigsForSessionRender(configs, tool) {
10118
10289
  const selectedSources = [];
10119
10290
  const equivalentSources = new Map;
10120
10291
  for (const candidate of sources) {
10121
- const key = sha2565(candidate.source.content);
10292
+ const key = sha2566(candidate.source.content);
10122
10293
  const existing = equivalentSources.get(key);
10123
10294
  if (!existing) {
10124
10295
  equivalentSources.set(key, {
@@ -10397,7 +10568,7 @@ function readIdentitySourcePath(sourcePath, baseDir, sourceId) {
10397
10568
  }
10398
10569
  return;
10399
10570
  }
10400
- const stat = statSync2(resolvedPath);
10571
+ const stat = statSync3(resolvedPath);
10401
10572
  if (!stat.isFile()) {
10402
10573
  throw new Error(`Identity instruction source path is not a file for ${sourceId}: ${sourcePath.path}`);
10403
10574
  }
@@ -10406,7 +10577,7 @@ function readIdentitySourcePath(sourcePath, baseDir, sourceId) {
10406
10577
  if (!pathIsInside(realPath, realBase)) {
10407
10578
  throw new Error(`Identity instruction source path escapes export directory for ${sourceId}: ${sourcePath.path}`);
10408
10579
  }
10409
- return readFileSync3(realPath, "utf-8");
10580
+ return readFileSync4(realPath, "utf-8");
10410
10581
  }
10411
10582
  function resolveIdentitySourcePath(path, baseDir, sourceId) {
10412
10583
  const cleaned = cleanSessionPathInput(path);
@@ -10414,8 +10585,8 @@ function resolveIdentitySourcePath(path, baseDir, sourceId) {
10414
10585
  throw new Error(`Identity instruction source path cannot be empty for ${sourceId}.`);
10415
10586
  if (cleaned.includes("\\"))
10416
10587
  throw new Error(`Identity instruction source path must use POSIX separators for ${sourceId}: ${path}`);
10417
- const resolvedPath = isAbsolute3(cleaned) ? resolve4(cleaned) : resolve4(baseDir, cleaned);
10418
- if (!pathIsInside(resolvedPath, resolve4(baseDir))) {
10588
+ const resolvedPath = isAbsolute3(cleaned) ? resolve6(cleaned) : resolve6(baseDir, cleaned);
10589
+ if (!pathIsInside(resolvedPath, resolve6(baseDir))) {
10419
10590
  throw new Error(`Identity instruction source path escapes export directory for ${sourceId}: ${path}`);
10420
10591
  }
10421
10592
  return resolvedPath;
@@ -10527,7 +10698,12 @@ function capability(provider, providerVersionRange, selectedRepresentation, load
10527
10698
  });
10528
10699
  }
10529
10700
  var DEFAULT_PROVIDER_CAPABILITIES = Object.freeze({
10530
- claude: capability("claude", ">=1.0.0", "native-import", "CLAUDE.md @ imports", { native_imports: true, asset_surface: "code" }),
10701
+ claude: capability("claude", ">=1.0.0", "native-import", "CLAUDE.md @ imports plus path-gated rules", {
10702
+ activation_modes: ["always", "glob"],
10703
+ native_imports: true,
10704
+ conditional_artifacts: true,
10705
+ asset_surface: "code"
10706
+ }),
10531
10707
  codex: capability("codex", ">=0.1.0", "flattened", "AGENTS.md", { asset_surface: "cli" }),
10532
10708
  cursor: capability("cursor", ">=1.0.0", "cursor-rule", ".cursor/rules/*.mdc", { activation_modes: ["always", "glob"], conditional_artifacts: true, asset_surface: "ide" }),
10533
10709
  opencode: capability("opencode", ">=1.0.0", "managed-fragment", "opencode.json instructions", { provider_variant: "v1-instructions", session_surface: "opencode-config-instructions" }),
@@ -10811,7 +10987,7 @@ function compileInstructionGraph(input) {
10811
10987
  effective_activation: effective.get(configId),
10812
10988
  fallback: row.binding.fallback,
10813
10989
  required: row.binding.required,
10814
- content_sha256: sha2566(config.content),
10990
+ content_sha256: sha2567(config.content),
10815
10991
  dependencies: dependencies.get(configId) ?? []
10816
10992
  };
10817
10993
  });
@@ -10848,7 +11024,7 @@ function compileInstructionGraph(input) {
10848
11024
  diagnostics
10849
11025
  };
10850
11026
  return {
10851
- plan: deepFreeze2({ ...planWithoutHash, source_hash: sha2566(stableJson2(planWithoutHash)) }),
11027
+ plan: deepFreeze2({ ...planWithoutHash, source_hash: sha2567(stableJson2(planWithoutHash)) }),
10852
11028
  sources,
10853
11029
  capability: capability2
10854
11030
  };
@@ -10873,7 +11049,6 @@ function planProfileSessionRender(input) {
10873
11049
  });
10874
11050
  const {
10875
11051
  profile_id: _profileId,
10876
- provider_version: _providerVersion,
10877
11052
  configs: _configs,
10878
11053
  bindings: _bindings,
10879
11054
  asset_configs: _assetConfigs,
@@ -11031,8 +11206,8 @@ class InstructionGraphValidationError extends Error {
11031
11206
  this.name = "InstructionGraphValidationError";
11032
11207
  }
11033
11208
  }
11034
- function sha2566(value) {
11035
- return createHash6("sha256").update(value).digest("hex");
11209
+ function sha2567(value) {
11210
+ return createHash7("sha256").update(value).digest("hex");
11036
11211
  }
11037
11212
  function stableJson2(value) {
11038
11213
  const canonical = (entry) => Array.isArray(entry) ? entry.map(canonical) : entry && typeof entry === "object" ? Object.fromEntries(Object.entries(entry).sort(([a], [b]) => a.localeCompare(b)).map(([key, child]) => [key, canonical(child)])) : entry;
@@ -11251,34 +11426,6 @@ function resolveProfileForMachineRead(machine = detectMachineContext(), options
11251
11426
  };
11252
11427
  }
11253
11428
 
11254
- // src/db/snapshots.ts
11255
- function createSnapshot(configId, content, version, db) {
11256
- const d = db || getDatabase();
11257
- const id = uuid();
11258
- const ts = now();
11259
- d.run("INSERT INTO config_snapshots (id, config_id, content, version, created_at) VALUES (?, ?, ?, ?, ?)", [id, configId, content, version, ts]);
11260
- return { id, config_id: configId, content, version, created_at: ts };
11261
- }
11262
- function listSnapshots(configId, db) {
11263
- const d = db || getDatabase();
11264
- return d.query("SELECT * FROM config_snapshots WHERE config_id = ? ORDER BY version DESC").all(configId);
11265
- }
11266
- function getSnapshot(id, db) {
11267
- const d = db || getDatabase();
11268
- return d.query("SELECT * FROM config_snapshots WHERE id = ?").get(id);
11269
- }
11270
- function getSnapshotByVersion(configId, version, db) {
11271
- const d = db || getDatabase();
11272
- return d.query("SELECT * FROM config_snapshots WHERE config_id = ? AND version = ?").get(configId, version);
11273
- }
11274
- function pruneSnapshots(configId, keep = 10, db) {
11275
- const d = db || getDatabase();
11276
- const result = d.run(`DELETE FROM config_snapshots WHERE config_id = ? AND id NOT IN (
11277
- SELECT id FROM config_snapshots WHERE config_id = ? ORDER BY version DESC LIMIT ?
11278
- )`, [configId, configId, keep]);
11279
- return result.changes;
11280
- }
11281
-
11282
11429
  // src/db/machines.ts
11283
11430
  import { arch, hostname, type } from "os";
11284
11431
  function currentHostname2() {
@@ -11358,16 +11505,17 @@ function parseBoundedOrLegacyPage(value, legacyItems, options, label) {
11358
11505
  var API_URL_ENV = "HASNA_INSTRUCTIONS_API_URL";
11359
11506
  var API_KEY_ENV = "HASNA_INSTRUCTIONS_API_KEY";
11360
11507
  function resolveCloudConfig(env = process.env) {
11508
+ assertNoLegacyStorageMode(env);
11361
11509
  const apiUrl = env[API_URL_ENV]?.trim();
11362
11510
  const apiKey = env[API_KEY_ENV]?.trim();
11363
11511
  if (!apiUrl && !apiKey)
11364
11512
  return null;
11365
11513
  if (!apiUrl || !apiKey) {
11366
- throw new Error(`API mode requires BOTH ${API_URL_ENV} and ${API_KEY_ENV}; only ` + `${apiUrl ? API_URL_ENV : API_KEY_ENV} is set. Set both to use the cloud API, ` + `or unset both to use the local store.`);
11514
+ throw new Error(`API mode requires BOTH ${API_URL_ENV} and ${API_KEY_ENV}; only ` + `${apiUrl ? API_URL_ENV : API_KEY_ENV} is set. Set both to use the HTTP API, ` + `or unset both to use the local store.`);
11367
11515
  }
11368
11516
  return { apiUrl, apiKey };
11369
11517
  }
11370
- function isCloudMode(env = process.env) {
11518
+ function isApiTransport(env = process.env) {
11371
11519
  return resolveCloudConfig(env) !== null;
11372
11520
  }
11373
11521
 
@@ -11844,16 +11992,16 @@ function resolveConfigStore(env = process.env) {
11844
11992
  return cloud ? new CloudConfigStore(cloud) : new LocalConfigStore;
11845
11993
  }
11846
11994
  // src/status.ts
11847
- import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
11995
+ import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
11848
11996
 
11849
11997
  // src/lib/apply.ts
11850
- import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync5, realpathSync as realpathSync2, writeFileSync as writeFileSync2 } from "fs";
11851
- import { basename as basename4, dirname as dirname4, join as join7, resolve as resolve5 } from "path";
11852
- import { homedir as homedir4 } from "os";
11998
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6, realpathSync as realpathSync2, writeFileSync as writeFileSync2 } from "fs";
11999
+ import { basename as basename4, dirname as dirname4, join as join9, resolve as resolve7 } from "path";
12000
+ import { homedir as homedir5 } from "os";
11853
12001
 
11854
12002
  // src/lib/session-render-ownership.ts
11855
- import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync3 } from "fs";
11856
- import { dirname as dirname3, join as join6, parse as parse3, relative as relative3, sep } from "path";
12003
+ import { existsSync as existsSync5, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
12004
+ import { dirname as dirname3, join as join8, parse as parse3, relative as relative3, sep } from "path";
11857
12005
  var MANIFEST_ANCESTOR_LIMIT = 24;
11858
12006
  var MANAGED_PATH_SEGMENTS = SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS.map((managedPath) => managedPath.split("/").filter(Boolean));
11859
12007
  var manifestCache = new Map;
@@ -11877,7 +12025,7 @@ function readManifestRelativePaths(manifestPath) {
11877
12025
  try {
11878
12026
  if (!existsSync5(manifestPath))
11879
12027
  return null;
11880
- stats = statSync3(manifestPath);
12028
+ stats = statSync4(manifestPath);
11881
12029
  } catch {
11882
12030
  return null;
11883
12031
  }
@@ -11887,7 +12035,7 @@ function readManifestRelativePaths(manifestPath) {
11887
12035
  }
11888
12036
  let manifest;
11889
12037
  try {
11890
- manifest = JSON.parse(readFileSync4(manifestPath, "utf-8"));
12038
+ manifest = JSON.parse(readFileSync5(manifestPath, "utf-8"));
11891
12039
  } catch {
11892
12040
  return null;
11893
12041
  }
@@ -11904,7 +12052,7 @@ function sessionRenderManifestClaimsPath(absolutePath2) {
11904
12052
  const root = parse3(absolutePath2).root;
11905
12053
  let home = dirname3(absolutePath2);
11906
12054
  for (let depth = 0;depth < MANIFEST_ANCESTOR_LIMIT; depth += 1) {
11907
- const manifestPath = join6(home, ...SESSION_RENDER_MANIFEST_RELATIVE_PATH.split("/"));
12055
+ const manifestPath = join8(home, ...SESSION_RENDER_MANIFEST_RELATIVE_PATH.split("/"));
11908
12056
  const relativePaths = readManifestRelativePaths(manifestPath);
11909
12057
  if (relativePaths) {
11910
12058
  const claimed = relative3(home, absolutePath2).split(sep).join("/");
@@ -11924,13 +12072,13 @@ function sessionRenderOwnsPath(absolutePath2) {
11924
12072
 
11925
12073
  // src/lib/apply.ts
11926
12074
  function getConfigHome() {
11927
- return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir4();
12075
+ return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir5();
11928
12076
  }
11929
12077
  function expandPath(p) {
11930
12078
  if (p.startsWith("~/")) {
11931
- return resolve5(getConfigHome(), p.slice(2));
12079
+ return resolve7(getConfigHome(), p.slice(2));
11932
12080
  }
11933
- return resolve5(p);
12081
+ return resolve7(p);
11934
12082
  }
11935
12083
  function normalizeTargetPath(p) {
11936
12084
  const expanded = expandPath(p);
@@ -11942,7 +12090,7 @@ function normalizeTargetPath(p) {
11942
12090
  while (true) {
11943
12091
  if (existsSync6(current)) {
11944
12092
  try {
11945
- return resolve5(realpathSync2(current), ...missingSegments);
12093
+ return resolve7(realpathSync2(current), ...missingSegments);
11946
12094
  } catch {
11947
12095
  return expanded;
11948
12096
  }
@@ -11971,7 +12119,7 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
11971
12119
  }
11972
12120
  const path = expandPath(renderedTargetPath);
11973
12121
  const renderedForTarget = isCursorGlobalAuthorityPath(path) ? stampCursorGlobalAuthorityMarker(renderedContent) : renderedContent;
11974
- const previousContent = existsSync6(path) ? readFileSync5(path, "utf-8") : null;
12122
+ const previousContent = existsSync6(path) ? readFileSync6(path, "utf-8") : null;
11975
12123
  const changed = previousContent !== renderedForTarget;
11976
12124
  if (!opts.dryRun) {
11977
12125
  const dir = dirname4(path);
@@ -12011,7 +12159,7 @@ function wouldDestroyACredential(targetPath, renderedContent, format) {
12011
12159
  const path = expandPath(targetPath);
12012
12160
  if (!existsSync6(path))
12013
12161
  return [];
12014
- current = readFileSync5(path, "utf-8");
12162
+ current = readFileSync6(path, "utf-8");
12015
12163
  } catch {
12016
12164
  return secretTokens;
12017
12165
  }
@@ -12335,14 +12483,14 @@ function sessionRendererOwnsCanonicalTarget(normalized, opts) {
12335
12483
  getConfigHome(),
12336
12484
  opts.vars?.["HOME_DIR"]
12337
12485
  ].filter((home) => typeof home === "string" && home.length > 0));
12338
- if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(join7(home, ...relativePath.split("/"))))))
12486
+ if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(join9(home, ...relativePath.split("/"))))))
12339
12487
  return true;
12340
12488
  return sessionRenderOwnsPath(normalized);
12341
12489
  }
12342
12490
 
12343
12491
  // src/lib/package-version.ts
12344
- import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
12345
- import { dirname as dirname5, join as join8 } from "path";
12492
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
12493
+ import { dirname as dirname5, join as join10 } from "path";
12346
12494
  import { fileURLToPath } from "url";
12347
12495
  var cached = null;
12348
12496
  function getPackageVersion() {
@@ -12351,9 +12499,9 @@ function getPackageVersion() {
12351
12499
  try {
12352
12500
  let dir = dirname5(fileURLToPath(import.meta.url));
12353
12501
  for (let i = 0;i < 8; i++) {
12354
- const pkgPath = join8(dir, "package.json");
12502
+ const pkgPath = join10(dir, "package.json");
12355
12503
  if (existsSync7(pkgPath)) {
12356
- const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
12504
+ const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
12357
12505
  if (pkg.name === "@hasna/instructions" && pkg.version) {
12358
12506
  cached = pkg.version;
12359
12507
  return cached;
@@ -12369,6 +12517,403 @@ function getPackageVersion() {
12369
12517
  return cached;
12370
12518
  }
12371
12519
 
12520
+ // src/lib/managed-skill-runtimes.ts
12521
+ import { createHash as createHash8 } from "crypto";
12522
+ import { spawnSync } from "child_process";
12523
+ import {
12524
+ existsSync as existsSync8,
12525
+ lstatSync as lstatSync4,
12526
+ mkdirSync as mkdirSync4,
12527
+ readFileSync as readFileSync8,
12528
+ renameSync as renameSync2,
12529
+ rmSync as rmSync3,
12530
+ writeFileSync as writeFileSync3
12531
+ } from "fs";
12532
+ import { homedir as homedir6 } from "os";
12533
+ import { dirname as dirname6, join as join11, parse as parse4, relative as relative4, resolve as resolve8 } from "path";
12534
+ var INBOX_CONVERSATIONS_MINIMUM_VERSION = "0.5.28";
12535
+ var INBOX_SKILL_MARKERS = [
12536
+ [".claude", "skills", "inbox", "SKILL.md"],
12537
+ [".codex", "skills", "inbox", "SKILL.md"],
12538
+ [".codewith", "skills", "inbox", "SKILL.md"],
12539
+ [".config", "opencode", "skills", "inbox", "SKILL.md"],
12540
+ [".cursor", "skills", "inbox", "SKILL.md"]
12541
+ ];
12542
+ var REQUIRED_WATCH_FLAGS = ["--from <agent>", "--all", "--full-content"];
12543
+ function sha2568(content) {
12544
+ return createHash8("sha256").update(content).digest("hex");
12545
+ }
12546
+ function lstatOrNull(path) {
12547
+ try {
12548
+ return lstatSync4(path);
12549
+ } catch {
12550
+ return null;
12551
+ }
12552
+ }
12553
+ function findSymlinkedAncestor(path) {
12554
+ const normalized = resolve8(path);
12555
+ const parsed = parse4(normalized);
12556
+ let current = parsed.root;
12557
+ const rel = relative4(parsed.root, normalized);
12558
+ for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
12559
+ current = join11(current, segment);
12560
+ if (!existsSync8(current))
12561
+ return null;
12562
+ if (lstatSync4(current).isSymbolicLink())
12563
+ return current;
12564
+ }
12565
+ return null;
12566
+ }
12567
+ function assertNoSymlinkAncestors2(path) {
12568
+ const found = findSymlinkedAncestor(path);
12569
+ if (found !== null) {
12570
+ throw new Error(`managed skill path uses a symlink ancestor: ${found}`);
12571
+ }
12572
+ }
12573
+ function packagedInboxSkillPath(explicitPath) {
12574
+ if (explicitPath)
12575
+ return explicitPath;
12576
+ const candidates = [
12577
+ join11(import.meta.dir, "..", "..", "assets", "skills", "inbox", "SKILL.md"),
12578
+ join11(import.meta.dir, "..", "assets", "skills", "inbox", "SKILL.md"),
12579
+ join11(process.cwd(), "assets", "skills", "inbox", "SKILL.md")
12580
+ ];
12581
+ const found = candidates.find((candidate) => existsSync8(candidate));
12582
+ if (!found) {
12583
+ throw new Error(`packaged inbox skill contract is missing (checked ${candidates.length} package-relative locations)`);
12584
+ }
12585
+ return found;
12586
+ }
12587
+ function readCanonicalSkill(explicitPath) {
12588
+ const assetPath = packagedInboxSkillPath(explicitPath);
12589
+ const stat = lstatOrNull(assetPath);
12590
+ if (!stat?.isFile()) {
12591
+ throw new Error("packaged inbox skill contract is not a regular file");
12592
+ }
12593
+ const content = readFileSync8(assetPath, "utf8");
12594
+ if (!content.includes("conversations watch --from <agent> --all")) {
12595
+ throw new Error("packaged inbox skill contract does not declare the canonical conversations watcher");
12596
+ }
12597
+ if (!content.includes("There is no separate")) {
12598
+ throw new Error("packaged inbox skill contract does not retire the legacy executable");
12599
+ }
12600
+ return { content, sha256: sha2568(content) };
12601
+ }
12602
+ function runProbe(command, args) {
12603
+ const result = spawnSync(command, args, {
12604
+ encoding: "utf8",
12605
+ timeout: 5000,
12606
+ stdio: ["ignore", "pipe", "pipe"]
12607
+ });
12608
+ if (result.error || result.status !== 0) {
12609
+ return { ok: false, output: "" };
12610
+ }
12611
+ return {
12612
+ ok: true,
12613
+ output: `${result.stdout ?? ""}
12614
+ ${result.stderr ?? ""}`.trim()
12615
+ };
12616
+ }
12617
+ function parseVersion(output) {
12618
+ return output.match(/\b(\d+\.\d+\.\d+)\b/)?.[1] ?? null;
12619
+ }
12620
+ function compareVersions(left, right) {
12621
+ const a = left.split(".").map(Number);
12622
+ const b = right.split(".").map(Number);
12623
+ for (let i = 0;i < Math.max(a.length, b.length); i++) {
12624
+ const delta = (a[i] ?? 0) - (b[i] ?? 0);
12625
+ if (delta !== 0)
12626
+ return delta;
12627
+ }
12628
+ return 0;
12629
+ }
12630
+ function inspectSkillMarkers(homeDir2) {
12631
+ return INBOX_SKILL_MARKERS.map((parts) => join11(homeDir2, ...parts)).map((path) => {
12632
+ const stat = lstatOrNull(path);
12633
+ if (!stat)
12634
+ return null;
12635
+ if (!stat.isFile()) {
12636
+ return { path, content: null, mode: null, regular: false };
12637
+ }
12638
+ return {
12639
+ path,
12640
+ content: readFileSync8(path, "utf8"),
12641
+ mode: stat.mode & 511,
12642
+ regular: true
12643
+ };
12644
+ }).filter((snapshot) => snapshot !== null);
12645
+ }
12646
+ function inspectInbox(options) {
12647
+ const homeDir2 = options.homeDir ?? homedir6();
12648
+ const runtimeCommand = options.conversationsCommand ?? "conversations";
12649
+ const snapshots = inspectSkillMarkers(homeDir2);
12650
+ const skillPresent = snapshots.length > 0;
12651
+ let canonicalContent = null;
12652
+ let canonicalSha256 = null;
12653
+ let assetError = null;
12654
+ try {
12655
+ const canonical = readCanonicalSkill(options.assetPath);
12656
+ canonicalContent = canonical.content;
12657
+ canonicalSha256 = canonical.sha256;
12658
+ } catch (error) {
12659
+ assetError = error instanceof Error ? error.message : String(error);
12660
+ }
12661
+ const versionProbe = skillPresent ? runProbe(runtimeCommand, ["--version"]) : { ok: false, output: "" };
12662
+ const helpProbe = versionProbe.ok ? runProbe(runtimeCommand, ["watch", "--help"]) : { ok: false, output: "" };
12663
+ const runtimeVersion = versionProbe.ok ? parseVersion(versionProbe.output) : null;
12664
+ const supportsFrom = helpProbe.ok && helpProbe.output.includes(REQUIRED_WATCH_FLAGS[0]);
12665
+ const supportsAll = helpProbe.ok && helpProbe.output.includes(REQUIRED_WATCH_FLAGS[1]);
12666
+ const supportsFullContent = helpProbe.ok && helpProbe.output.includes(REQUIRED_WATCH_FLAGS[2]);
12667
+ const packageReady = versionProbe.ok && runtimeVersion !== null && compareVersions(runtimeVersion, INBOX_CONVERSATIONS_MINIMUM_VERSION) >= 0 && helpProbe.ok && supportsFrom && supportsAll && supportsFullContent;
12668
+ const heartbeatProbe = skillPresent && packageReady && options.agent ? runProbe(runtimeCommand, ["agents", "heartbeat", "--from", options.agent, "--json"]) : null;
12669
+ const hostedHeartbeat = heartbeatProbe === null ? "unverified" : heartbeatProbe.ok ? "passed" : "failed";
12670
+ const deliveryVerified = hostedHeartbeat === "passed" && options.deliveryVerified === true;
12671
+ const staleMarkers = canonicalContent === null ? snapshots.map((snapshot) => snapshot.path) : snapshots.filter((snapshot) => !snapshot.regular || snapshot.content !== canonicalContent).map((snapshot) => snapshot.path);
12672
+ let reason = "skill not installed";
12673
+ if (skillPresent) {
12674
+ const nonRegular = snapshots.some((snapshot) => !snapshot.regular);
12675
+ const symlinkAncestor = snapshots.map((snapshot) => snapshot.path).map((path) => findSymlinkedAncestor(dirname6(path))).find((found) => found !== null);
12676
+ if (nonRegular)
12677
+ reason = "managed skill target is not a regular file";
12678
+ else if (symlinkAncestor)
12679
+ reason = `managed skill path uses a symlink ancestor: ${symlinkAncestor}`;
12680
+ else if (assetError)
12681
+ reason = assetError;
12682
+ else if (!versionProbe.ok)
12683
+ reason = "conversations command unavailable";
12684
+ else if (!runtimeVersion)
12685
+ reason = "conversations version is unreadable";
12686
+ else if (compareVersions(runtimeVersion, INBOX_CONVERSATIONS_MINIMUM_VERSION) < 0) {
12687
+ reason = `conversations ${runtimeVersion} is older than ${INBOX_CONVERSATIONS_MINIMUM_VERSION}`;
12688
+ } else if (!helpProbe.ok)
12689
+ reason = "conversations watch help is unavailable";
12690
+ else if (!supportsFrom || !supportsAll || !supportsFullContent) {
12691
+ const missing = [
12692
+ !supportsFrom ? "--from" : null,
12693
+ !supportsAll ? "--all" : null,
12694
+ !supportsFullContent ? "--full-content" : null
12695
+ ].filter((flag) => flag !== null);
12696
+ reason = `conversations watch is missing required flags: ${missing.join(", ")}`;
12697
+ } else if (staleMarkers.length > 0)
12698
+ reason = "skill contract stale";
12699
+ else if (hostedHeartbeat === "failed")
12700
+ reason = "hosted heartbeat failed; manual fallback required";
12701
+ else if (hostedHeartbeat === "unverified")
12702
+ reason = "hosted heartbeat unverified; manual fallback required";
12703
+ else if (!deliveryVerified)
12704
+ reason = "hosted heartbeat passed; channel and DM delivery verification required";
12705
+ else
12706
+ reason = "ready";
12707
+ }
12708
+ return {
12709
+ status: {
12710
+ skill: "inbox",
12711
+ runtime: "conversations watch",
12712
+ minimum_version: INBOX_CONVERSATIONS_MINIMUM_VERSION,
12713
+ skill_present: skillPresent,
12714
+ skill_markers: snapshots.map((snapshot) => snapshot.path),
12715
+ skill_contracts_current: snapshots.length - staleMarkers.length,
12716
+ stale_skill_markers: staleMarkers,
12717
+ expected_skill_sha256: canonicalSha256,
12718
+ runtime_command: runtimeCommand,
12719
+ runtime_present: versionProbe.ok,
12720
+ runtime_version: runtimeVersion,
12721
+ watch_supports_from: supportsFrom,
12722
+ watch_supports_all: supportsAll,
12723
+ watch_supports_full_content: supportsFullContent,
12724
+ hosted_heartbeat: hostedHeartbeat,
12725
+ delivery_verified: deliveryVerified,
12726
+ manual_fallback_ready: skillPresent && staleMarkers.length === 0 && packageReady,
12727
+ healthy: !skillPresent || reason === "ready",
12728
+ reason
12729
+ },
12730
+ canonicalContent,
12731
+ snapshots
12732
+ };
12733
+ }
12734
+ function inspectManagedSkillRuntimes(options = {}) {
12735
+ const runtime = inspectInbox(options).status;
12736
+ const installed = runtime.skill_present ? [runtime] : [];
12737
+ return {
12738
+ runtimes: [runtime],
12739
+ skills_present: installed.length,
12740
+ healthy: installed.filter((item) => item.healthy).length,
12741
+ missing: installed.filter((item) => !item.healthy).length
12742
+ };
12743
+ }
12744
+ function runtimeReadyForWrite(status) {
12745
+ return status.runtime_present && status.runtime_version !== null && compareVersions(status.runtime_version, INBOX_CONVERSATIONS_MINIMUM_VERSION) >= 0 && status.watch_supports_from && status.watch_supports_all && status.watch_supports_full_content;
12746
+ }
12747
+ function projectUpdatedStatus(status, contractCount) {
12748
+ const healthy = status.hosted_heartbeat === "passed" && status.delivery_verified;
12749
+ return {
12750
+ ...status,
12751
+ skill_contracts_current: contractCount,
12752
+ stale_skill_markers: [],
12753
+ manual_fallback_ready: true,
12754
+ healthy,
12755
+ reason: healthy ? "ready" : status.hosted_heartbeat === "failed" ? "hosted heartbeat failed; manual fallback required" : status.hosted_heartbeat === "unverified" ? "hosted heartbeat unverified; manual fallback required" : "hosted heartbeat passed; channel and DM delivery verification required"
12756
+ };
12757
+ }
12758
+ function cleanup(path) {
12759
+ rmSync3(path, { force: true });
12760
+ }
12761
+ function writeAtomic(path, content, mode) {
12762
+ assertNoSymlinkAncestors2(dirname6(path));
12763
+ const tempPath = `${path}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
12764
+ try {
12765
+ mkdirSync4(dirname6(path), { recursive: true, mode: 493 });
12766
+ writeFileSync3(tempPath, content, { mode, flag: "wx" });
12767
+ renameSync2(tempPath, path);
12768
+ } finally {
12769
+ cleanup(tempPath);
12770
+ }
12771
+ }
12772
+ var DEFAULT_SKILL_WRITE_FILE_OPERATIONS = {
12773
+ lstat: lstatOrNull,
12774
+ read: (path) => readFileSync8(path, "utf8"),
12775
+ write: writeAtomic
12776
+ };
12777
+ function writeSkillContractsTransactional(snapshots, canonicalContent, fileOperations = DEFAULT_SKILL_WRITE_FILE_OPERATIONS) {
12778
+ const written = [];
12779
+ try {
12780
+ for (const snapshot of snapshots) {
12781
+ const currentStat = fileOperations.lstat(snapshot.path);
12782
+ if (!currentStat?.isFile() || fileOperations.read(snapshot.path) !== snapshot.content) {
12783
+ throw new Error("managed skill changed after inspection; refusing a stale write");
12784
+ }
12785
+ fileOperations.write(snapshot.path, canonicalContent, snapshot.mode);
12786
+ written.push(snapshot);
12787
+ }
12788
+ return { ok: true, error: null, rollback_conflicts: [] };
12789
+ } catch (error) {
12790
+ const rollbackConflicts = [];
12791
+ for (const snapshot of written.reverse()) {
12792
+ const currentStat = fileOperations.lstat(snapshot.path);
12793
+ if (!currentStat?.isFile()) {
12794
+ rollbackConflicts.push(`${snapshot.path}: no longer a regular file`);
12795
+ continue;
12796
+ }
12797
+ let currentContent;
12798
+ try {
12799
+ currentContent = fileOperations.read(snapshot.path);
12800
+ } catch {
12801
+ rollbackConflicts.push(`${snapshot.path}: could not read the current file`);
12802
+ continue;
12803
+ }
12804
+ if (currentContent !== canonicalContent) {
12805
+ rollbackConflicts.push(`${snapshot.path}: changed after this reconciliation wrote it`);
12806
+ continue;
12807
+ }
12808
+ try {
12809
+ fileOperations.write(snapshot.path, snapshot.content, snapshot.mode);
12810
+ } catch {
12811
+ rollbackConflicts.push(`${snapshot.path}: still owned but could not be restored`);
12812
+ }
12813
+ }
12814
+ return {
12815
+ ok: false,
12816
+ error: error instanceof Error ? error.message : String(error),
12817
+ rollback_conflicts: rollbackConflicts
12818
+ };
12819
+ }
12820
+ }
12821
+ async function reconcileManagedSkillRuntimes(options = {}) {
12822
+ const dryRun = options.dryRun ?? false;
12823
+ const before = inspectInbox(options);
12824
+ const status = before.status;
12825
+ if (!status.skill_present) {
12826
+ return {
12827
+ runtimes: [{ ...status, action: "skipped", dry_run: dryRun, skill_contracts_changed: 0 }],
12828
+ changed: 0,
12829
+ failed: 0,
12830
+ dry_run: dryRun
12831
+ };
12832
+ }
12833
+ if (before.snapshots.some((snapshot) => !snapshot.regular)) {
12834
+ return {
12835
+ runtimes: [{ ...status, action: "failed", dry_run: dryRun, skill_contracts_changed: 0 }],
12836
+ changed: 0,
12837
+ failed: 1,
12838
+ dry_run: dryRun
12839
+ };
12840
+ }
12841
+ const symlinkedAncestor = before.snapshots.map((snapshot) => snapshot.path).map((path) => findSymlinkedAncestor(dirname6(path))).find((found) => found !== null);
12842
+ if (symlinkedAncestor) {
12843
+ return {
12844
+ runtimes: [{ ...status, action: "failed", dry_run: dryRun, skill_contracts_changed: 0 }],
12845
+ changed: 0,
12846
+ failed: 1,
12847
+ dry_run: dryRun
12848
+ };
12849
+ }
12850
+ if (!before.canonicalContent || !runtimeReadyForWrite(status)) {
12851
+ return {
12852
+ runtimes: [{ ...status, action: "failed", dry_run: dryRun, skill_contracts_changed: 0 }],
12853
+ changed: 0,
12854
+ failed: 1,
12855
+ dry_run: dryRun
12856
+ };
12857
+ }
12858
+ const staleSnapshots = before.snapshots.filter((snapshot) => snapshot.content !== before.canonicalContent);
12859
+ if (staleSnapshots.length === 0) {
12860
+ return {
12861
+ runtimes: [{ ...status, action: "unchanged", dry_run: dryRun, skill_contracts_changed: 0 }],
12862
+ changed: 0,
12863
+ failed: 0,
12864
+ dry_run: dryRun
12865
+ };
12866
+ }
12867
+ if (dryRun) {
12868
+ const projected = projectUpdatedStatus(status, before.snapshots.length);
12869
+ return {
12870
+ runtimes: [{
12871
+ ...projected,
12872
+ action: "update",
12873
+ dry_run: true,
12874
+ skill_contracts_changed: staleSnapshots.length
12875
+ }],
12876
+ changed: 1,
12877
+ failed: 0,
12878
+ dry_run: true
12879
+ };
12880
+ }
12881
+ const transaction = writeSkillContractsTransactional(staleSnapshots.map((snapshot) => ({
12882
+ path: snapshot.path,
12883
+ content: snapshot.content,
12884
+ mode: snapshot.mode ?? 420
12885
+ })), before.canonicalContent);
12886
+ if (!transaction.ok) {
12887
+ const rollbackConflictReason = transaction.rollback_conflicts.length > 0 ? `; rollback conflicts: ${transaction.rollback_conflicts.join("; ")}` : "";
12888
+ const reason = `${transaction.error ?? "managed skill reconciliation failed"}${rollbackConflictReason}`;
12889
+ return {
12890
+ runtimes: [{
12891
+ ...status,
12892
+ action: "failed",
12893
+ dry_run: false,
12894
+ skill_contracts_changed: 0,
12895
+ reason
12896
+ }],
12897
+ changed: 0,
12898
+ failed: 1,
12899
+ dry_run: false
12900
+ };
12901
+ }
12902
+ const after = inspectInbox(options).status;
12903
+ const accepted = after.healthy || after.manual_fallback_ready;
12904
+ return {
12905
+ runtimes: [{
12906
+ ...after,
12907
+ action: accepted ? "update" : "failed",
12908
+ dry_run: false,
12909
+ skill_contracts_changed: accepted ? staleSnapshots.length : 0
12910
+ }],
12911
+ changed: accepted ? 1 : 0,
12912
+ failed: accepted ? 0 : 1,
12913
+ dry_run: false
12914
+ };
12915
+ }
12916
+
12372
12917
  // src/status.ts
12373
12918
  var PACKAGE_NAME = "@hasna/instructions";
12374
12919
  var PACKAGE_VERSION = getPackageVersion();
@@ -12391,7 +12936,7 @@ function countBy(items, getValue) {
12391
12936
  }
12392
12937
  return counts;
12393
12938
  }
12394
- async function getConfigsStatus(store = resolveConfigStore()) {
12939
+ async function getConfigsStatus(store = resolveConfigStore(), options = {}) {
12395
12940
  let databaseReachable = true;
12396
12941
  let configs = [];
12397
12942
  let categoryStats = { total: 0 };
@@ -12415,11 +12960,11 @@ async function getConfigsStatus(store = resolveConfigStore()) {
12415
12960
  continue;
12416
12961
  knownTargets += 1;
12417
12962
  const targetPath = expandPath(config.target_path);
12418
- if (!existsSync8(targetPath)) {
12963
+ if (!existsSync9(targetPath)) {
12419
12964
  missingTargets += 1;
12420
12965
  continue;
12421
12966
  }
12422
- const disk = readFileSync7(targetPath, "utf-8");
12967
+ const disk = readFileSync9(targetPath, "utf-8");
12423
12968
  const { content: redactedDisk } = redactContent(disk, config.format);
12424
12969
  if (redactedDisk !== config.content) {
12425
12970
  driftedTargets += 1;
@@ -12445,7 +12990,11 @@ async function getConfigsStatus(store = resolveConfigStore()) {
12445
12990
  }
12446
12991
  }
12447
12992
  const byCategory = Object.fromEntries(Object.entries(categoryStats).filter(([key]) => key !== "total"));
12448
- const status = databaseReachable && driftedTargets === 0 && missingTargets === 0 && unredactedSecretFindings === 0 && retiredAgentRows === 0 ? "ok" : "warn";
12993
+ const managedSkillRuntimes = inspectManagedSkillRuntimes({
12994
+ homeDir: options.homeDir,
12995
+ conversationsCommand: options.conversationsCommand
12996
+ });
12997
+ const status = databaseReachable && driftedTargets === 0 && missingTargets === 0 && unredactedSecretFindings === 0 && retiredAgentRows === 0 && managedSkillRuntimes.missing === 0 ? "ok" : "warn";
12449
12998
  return {
12450
12999
  service: "configs",
12451
13000
  schemaVersion: "1.0",
@@ -12475,7 +13024,12 @@ async function getConfigsStatus(store = resolveConfigStore()) {
12475
13024
  profileLinks,
12476
13025
  machines,
12477
13026
  snapshots,
12478
- knownTargets
13027
+ knownTargets,
13028
+ managedSkillRuntimes: {
13029
+ skillsPresent: managedSkillRuntimes.skills_present,
13030
+ healthy: managedSkillRuntimes.healthy,
13031
+ missing: managedSkillRuntimes.missing
13032
+ }
12479
13033
  },
12480
13034
  health: {
12481
13035
  status,
@@ -12484,10 +13038,12 @@ async function getConfigsStatus(store = resolveConfigStore()) {
12484
13038
  missingTargets,
12485
13039
  unredactedSecretFindings,
12486
13040
  retiredAgentRows,
13041
+ missingManagedSkillRuntimes: managedSkillRuntimes.missing,
12487
13042
  hasDrift: driftedTargets > 0,
12488
13043
  hasMissingTargets: missingTargets > 0,
12489
13044
  hasUnredactedSecrets: unredactedSecretFindings > 0,
12490
- hasRetiredAgentRows: retiredAgentRows > 0
13045
+ hasRetiredAgentRows: retiredAgentRows > 0,
13046
+ hasMissingManagedSkillRuntimes: managedSkillRuntimes.missing > 0
12491
13047
  },
12492
13048
  safety: {
12493
13049
  includesConfigValues: false,
@@ -12572,16 +13128,16 @@ var PG_MIGRATIONS = [
12572
13128
  `CREATE INDEX IF NOT EXISTS profile_assets_source_config_idx ON profile_assets (source_config_id)`
12573
13129
  ];
12574
13130
  // src/lib/session-apply.ts
12575
- import { createHash as createHash7, randomUUID as randomUUID4 } from "crypto";
13131
+ import { createHash as createHash9, randomUUID as randomUUID4 } from "crypto";
12576
13132
  import {
12577
- existsSync as existsSync9,
12578
- lstatSync as lstatSync3,
12579
- mkdirSync as mkdirSync4,
12580
- readFileSync as readFileSync8,
13133
+ existsSync as existsSync10,
13134
+ lstatSync as lstatSync5,
13135
+ mkdirSync as mkdirSync5,
13136
+ readFileSync as readFileSync10,
12581
13137
  readdirSync,
12582
- statSync as statSync4
13138
+ statSync as statSync5
12583
13139
  } from "fs";
12584
- import { dirname as dirname6, isAbsolute as isAbsolute4, join as join9, parse as parse4, relative as relative4, resolve as resolve6 } from "path";
13140
+ import { dirname as dirname7, isAbsolute as isAbsolute4, join as join12, parse as parse5, relative as relative5, resolve as resolve9 } from "path";
12585
13141
  class SessionApplyError extends Error {
12586
13142
  constructor(message) {
12587
13143
  super(message);
@@ -12601,6 +13157,7 @@ function applySessionRenderUnlocked(plan, options, coordination) {
12601
13157
  }
12602
13158
  assertCursorAuthorityUnchanged(plan);
12603
13159
  const targetHome = assertSafeTargetHome(plan.targetHome);
13160
+ assertClaudeAuthorityStillClear(plan, targetHome);
12604
13161
  const payloadFiles = [...plan.files, ...plan.assetFiles ?? []];
12605
13162
  const files = [...payloadFiles, plan.manifestFile];
12606
13163
  const manifestPath = resolvePlannedFilePath(plan, plan.manifestFile, targetHome);
@@ -12701,14 +13258,23 @@ function assertCursorAuthorityUnchanged(plan) {
12701
13258
  throw new SessionApplyError("Cursor fixed global authority changed after planning; refusing to apply a stale render plan.");
12702
13259
  }
12703
13260
  }
13261
+ function assertClaudeAuthorityStillClear(plan, targetHome) {
13262
+ if (plan.tool !== "claude" || plan.targetKind === "blocked")
13263
+ return;
13264
+ const conflicts = detectClaudeAuthorityConflicts(targetHome);
13265
+ if (conflicts.length === 0)
13266
+ return;
13267
+ const summary = conflicts.map((conflict) => `${conflict.relativePath}: ${conflict.reason}`).join("; ");
13268
+ throw new SessionApplyError(`Claude authority changed after planning; refusing to apply: ${summary}`);
13269
+ }
12704
13270
  function ensureSessionTargetHome(targetHome) {
12705
- if (!existsSync9(targetHome))
12706
- mkdirSync4(targetHome, { recursive: true, mode: 448 });
13271
+ if (!existsSync10(targetHome))
13272
+ mkdirSync5(targetHome, { recursive: true, mode: 448 });
12707
13273
  assertSafeTargetHome(targetHome);
12708
13274
  }
12709
13275
  function checkSessionRenderDrift(targetHome, manifestPath) {
12710
13276
  const safeTargetHome = assertSafeTargetHome(targetHome);
12711
- const resolvedManifestPath = manifestPath ? resolveManifestRelativePath(relative4(safeTargetHome, resolve6(manifestPath)), safeTargetHome) : resolve6(safeTargetHome, ".hasna", "session-render-manifest.json");
13277
+ const resolvedManifestPath = manifestPath ? resolveManifestRelativePath(relative5(safeTargetHome, resolve9(manifestPath)), safeTargetHome) : resolve9(safeTargetHome, ".hasna", "session-render-manifest.json");
12712
13278
  const checkedAt = new Date().toISOString();
12713
13279
  const previousManifest = readPreviousManifest(resolvedManifestPath);
12714
13280
  if (!previousManifest) {
@@ -12725,7 +13291,7 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
12725
13291
  const drifted = [];
12726
13292
  for (const file of previousManifest.files) {
12727
13293
  const target = resolveManifestRelativePath(file.relativePath, safeTargetHome);
12728
- if (!existsSync9(target)) {
13294
+ if (!existsSync10(target)) {
12729
13295
  missing.push({
12730
13296
  path: target,
12731
13297
  relativePath: file.relativePath,
@@ -12735,7 +13301,7 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
12735
13301
  });
12736
13302
  continue;
12737
13303
  }
12738
- const actualSha256 = sha2567(readFileSync8(target, "utf-8"));
13304
+ const actualSha256 = sha2569(readFileSync10(target, "utf-8"));
12739
13305
  if (actualSha256 !== file.sha256) {
12740
13306
  drifted.push({
12741
13307
  path: target,
@@ -12758,8 +13324,8 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
12758
13324
  function restoreSessionRenderSnapshot(snapshotPath, options = {}) {
12759
13325
  const snapshot = readSessionRenderSnapshot(snapshotPath);
12760
13326
  const targetHome = assertSafeTargetHome(snapshot.targetHome);
12761
- const resolvedSnapshotPath = resolve6(snapshotPath);
12762
- const snapshotRelativePath = relative4(targetHome, resolvedSnapshotPath);
13327
+ const resolvedSnapshotPath = resolve9(snapshotPath);
13328
+ const snapshotRelativePath = relative5(targetHome, resolvedSnapshotPath);
12763
13329
  if (snapshotRelativePath === "" || snapshotRelativePath === ".." || snapshotRelativePath.startsWith("../") || isAbsolute4(snapshotRelativePath)) {
12764
13330
  throw new SessionApplyError("Session snapshot must be stored inside its target home.");
12765
13331
  }
@@ -12876,19 +13442,19 @@ function requiredRestoreHash(file) {
12876
13442
  return file.previousSha256;
12877
13443
  }
12878
13444
  function readSessionRenderSnapshot(snapshotPath) {
12879
- const resolved = resolve6(snapshotPath);
12880
- if (!existsSync9(resolved))
13445
+ const resolved = resolve9(snapshotPath);
13446
+ if (!existsSync10(resolved))
12881
13447
  throw new SessionApplyError(`Session snapshot not found: ${snapshotPath}`);
12882
- const stat = lstatSync3(resolved);
13448
+ const stat = lstatSync5(resolved);
12883
13449
  if (stat.isSymbolicLink() || !stat.isFile()) {
12884
13450
  throw new SessionApplyError(`Session snapshot is not a regular file: ${snapshotPath}`);
12885
13451
  }
12886
- if (statSync4(resolved).size > 32 * 1024 * 1024) {
13452
+ if (statSync5(resolved).size > 32 * 1024 * 1024) {
12887
13453
  throw new SessionApplyError(`Session snapshot exceeds the 32 MiB restore limit: ${snapshotPath}`);
12888
13454
  }
12889
13455
  let parsed;
12890
13456
  try {
12891
- parsed = JSON.parse(readFileSync8(resolved, "utf8"));
13457
+ parsed = JSON.parse(readFileSync10(resolved, "utf8"));
12892
13458
  } catch {
12893
13459
  throw new SessionApplyError(`Session snapshot is not valid JSON: ${snapshotPath}`);
12894
13460
  }
@@ -12910,7 +13476,7 @@ function readSessionRenderSnapshot(snapshotPath) {
12910
13476
  const previousManifest = snapshot.previousManifest;
12911
13477
  const previousFiles = new Map;
12912
13478
  for (const file of snapshot.files) {
12913
- if (!file || typeof file.relativePath !== "string" || typeof file.path !== "string" || typeof file.sha256 !== "string" || typeof file.content !== "string" || sha2567(file.content) !== file.sha256) {
13479
+ if (!file || typeof file.relativePath !== "string" || typeof file.path !== "string" || typeof file.sha256 !== "string" || typeof file.content !== "string" || sha2569(file.content) !== file.sha256) {
12914
13480
  throw new SessionApplyError(`Session snapshot previous file metadata is invalid: ${snapshotPath}`);
12915
13481
  }
12916
13482
  resolveSnapshotFilePath(file.relativePath, file.path, targetHome);
@@ -12957,8 +13523,8 @@ function readSessionRenderSnapshot(snapshotPath) {
12957
13523
  }
12958
13524
  function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previousManifestFiles, targetHome, snapshotPath) {
12959
13525
  assertNoNewerSessionSnapshot(snapshotPath, snapshot.createdAt, targetHome);
12960
- const manifestPath = resolve6(snapshot.manifestPath);
12961
- const manifestRelativePath = relative4(targetHome, manifestPath).replaceAll("\\", "/");
13526
+ const manifestPath = resolve9(snapshot.manifestPath);
13527
+ const manifestRelativePath = relative5(targetHome, manifestPath).replaceAll("\\", "/");
12962
13528
  resolveSnapshotFilePath(manifestRelativePath, snapshot.manifestPath, targetHome);
12963
13529
  const manifestSha256 = currentSessionFileHash(manifestPath, targetHome);
12964
13530
  if (manifestSha256 === null) {
@@ -12966,7 +13532,7 @@ function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previou
12966
13532
  }
12967
13533
  let parsedManifest;
12968
13534
  try {
12969
- parsedManifest = JSON.parse(readFileSync8(manifestPath, "utf8"));
13535
+ parsedManifest = JSON.parse(readFileSync10(manifestPath, "utf8"));
12970
13536
  } catch {
12971
13537
  throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest is not valid JSON: ${snapshotPath}`);
12972
13538
  }
@@ -12974,7 +13540,7 @@ function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previou
12974
13540
  throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest is invalid: ${snapshotPath}`);
12975
13541
  }
12976
13542
  const appliedManifest = parsedManifest;
12977
- if (appliedManifest.schema !== SESSION_RENDER_SCHEMA || appliedManifest.tool !== snapshot.tool || appliedManifest.profile !== snapshot.profile || typeof appliedManifest.targetHome !== "string" || resolve6(appliedManifest.targetHome) !== targetHome || appliedManifest.targetKind !== "session-home" && appliedManifest.targetKind !== "project-root" || !Array.isArray(appliedManifest.files)) {
13543
+ if (appliedManifest.schema !== SESSION_RENDER_SCHEMA || appliedManifest.tool !== snapshot.tool || appliedManifest.profile !== snapshot.profile || typeof appliedManifest.targetHome !== "string" || resolve9(appliedManifest.targetHome) !== targetHome || appliedManifest.targetKind !== "session-home" && appliedManifest.targetKind !== "project-root" || !Array.isArray(appliedManifest.files)) {
12978
13544
  throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest does not match its snapshot: ${snapshotPath}`);
12979
13545
  }
12980
13546
  const afterFiles = [];
@@ -13058,17 +13624,17 @@ function assertNoNewerSessionSnapshot(snapshotPath, createdAt, targetHome) {
13058
13624
  if (!Number.isFinite(createdAtMs)) {
13059
13625
  throw new SessionApplyError(`Pre-rollback legacy v1 snapshot has an invalid creation time: ${snapshotPath}`);
13060
13626
  }
13061
- for (const entry of readdirSync(dirname6(snapshotPath))) {
13062
- const candidatePath = resolve6(dirname6(snapshotPath), entry);
13063
- if (candidatePath === resolve6(snapshotPath) || !entry.endsWith(".json"))
13627
+ for (const entry of readdirSync(dirname7(snapshotPath))) {
13628
+ const candidatePath = resolve9(dirname7(snapshotPath), entry);
13629
+ if (candidatePath === resolve9(snapshotPath) || !entry.endsWith(".json"))
13064
13630
  continue;
13065
- const candidateStat = lstatSync3(candidatePath);
13631
+ const candidateStat = lstatSync5(candidatePath);
13066
13632
  if (candidateStat.isSymbolicLink() || !candidateStat.isFile() || candidateStat.size > 32 * 1024 * 1024)
13067
13633
  continue;
13068
13634
  try {
13069
- const candidate = JSON.parse(readFileSync8(candidatePath, "utf8"));
13635
+ const candidate = JSON.parse(readFileSync10(candidatePath, "utf8"));
13070
13636
  const candidateCreatedAtMs = typeof candidate.createdAt === "string" ? Date.parse(candidate.createdAt) : Number.NaN;
13071
- if ((candidate.schema === "hasna.configs.session-render-snapshot/v1" || candidate.schema === "hasna.configs.session-render-snapshot/v2") && typeof candidate.targetHome === "string" && resolve6(candidate.targetHome) === targetHome && Number.isFinite(candidateCreatedAtMs) && candidateCreatedAtMs >= createdAtMs) {
13637
+ if ((candidate.schema === "hasna.configs.session-render-snapshot/v1" || candidate.schema === "hasna.configs.session-render-snapshot/v2") && typeof candidate.targetHome === "string" && resolve9(candidate.targetHome) === targetHome && Number.isFinite(candidateCreatedAtMs) && candidateCreatedAtMs >= createdAtMs) {
13072
13638
  throw new SessionApplyError(`Cannot restore pre-rollback legacy v1 snapshot after a newer session snapshot exists: ${candidatePath}`);
13073
13639
  }
13074
13640
  } catch (error) {
@@ -13126,7 +13692,7 @@ function inferLegacySnapshotAction(file, previousFiles, previousManifestFiles, p
13126
13692
  return "create";
13127
13693
  }
13128
13694
  if (file.role === "manifest" && previousManifest) {
13129
- const previousManifestSha256 = sha2567(`${JSON.stringify(previousManifest, null, 2)}
13695
+ const previousManifestSha256 = sha2569(`${JSON.stringify(previousManifest, null, 2)}
13130
13696
  `);
13131
13697
  if (previousManifestSha256 !== file.sha256) {
13132
13698
  throw new SessionApplyError(`Cannot infer legacy v1 manifest action without a before-image: ${file.relativePath}`);
@@ -13137,15 +13703,15 @@ function inferLegacySnapshotAction(file, previousFiles, previousManifestFiles, p
13137
13703
  }
13138
13704
  function resolveSnapshotFilePath(relativePath, recordedPath, targetHome) {
13139
13705
  const path = resolveManifestRelativePath(relativePath, targetHome);
13140
- if (resolve6(recordedPath) !== path) {
13706
+ if (resolve9(recordedPath) !== path) {
13141
13707
  throw new SessionApplyError(`Session snapshot file path mismatch for ${relativePath}`);
13142
13708
  }
13143
13709
  return path;
13144
13710
  }
13145
13711
  function planFileResult(plan, file, targetHome, previousHashes, previousManifest, options) {
13146
13712
  const target = resolvePlannedFilePath(plan, file, targetHome);
13147
- const previousContent = existsSync9(target) ? readFileSync8(target, "utf-8") : null;
13148
- const previousSha256 = previousContent === null ? null : sha2567(previousContent);
13713
+ const previousContent = existsSync10(target) ? readFileSync10(target, "utf-8") : null;
13714
+ const previousSha256 = previousContent === null ? null : sha2569(previousContent);
13149
13715
  const previouslyManaged = isPreviouslyManaged(file, previousSha256, previousHashes, previousManifest);
13150
13716
  const changed = previousContent !== file.content;
13151
13717
  if (previousContent !== null && !options.force && !previouslyManaged) {
@@ -13222,28 +13788,31 @@ function planFileResult(plan, file, targetHome, previousHashes, previousManifest
13222
13788
  function assertNotSilentManagedWipeout(plan, results) {
13223
13789
  if (plan.allowEmptySources)
13224
13790
  return;
13225
- const managedDir = plan.adapter.managedDir;
13226
- const underManagedDir = (relativePath) => relativePath === managedDir || relativePath.startsWith(`${managedDir}/`);
13227
- const staleDeletions = results.filter((result) => result.action === "delete" && underManagedDir(result.relativePath));
13791
+ const staleDeletions = results.filter((result) => result.action === "delete" && isPlanManagedFile(plan, result.relativePath, result.role));
13228
13792
  if (staleDeletions.length === 0)
13229
13793
  return;
13230
- const managedRetained = results.some((result) => result.action !== "delete" && underManagedDir(result.relativePath));
13794
+ const managedRetained = results.some((result) => result.action !== "delete" && isPlanManagedFile(plan, result.relativePath, result.role));
13231
13795
  if (managedRetained)
13232
13796
  return;
13233
- throw new SessionApplyError(`Session render plan for ${plan.tool} (${plan.adapter.mode}) would delete ${staleDeletions.length} ` + `previously managed file(s) under "${managedDir}" and create or update none there: ` + `${staleDeletions.map((result) => result.relativePath).join(", ")}. ` + "Pass --allow-empty-sources only for explicit empty renders.");
13797
+ throw new SessionApplyError(`Session render plan for ${plan.tool} (${plan.adapter.mode}) would delete ${staleDeletions.length} ` + "previously managed file(s) and create or update none: " + `${staleDeletions.map((result) => result.relativePath).join(", ")}. ` + "Pass --allow-empty-sources only for explicit empty renders.");
13798
+ }
13799
+ function isPlanManagedFile(plan, relativePath, role) {
13800
+ const managedDir = plan.adapter.managedDir;
13801
+ if (relativePath === managedDir || relativePath.startsWith(`${managedDir}/`))
13802
+ return true;
13803
+ return plan.tool === "claude" && role === "rule" && relativePath.startsWith("rules/");
13234
13804
  }
13235
13805
  function planStaleFileResults(plan, targetHome, previousManifest, currentRelativePaths, options) {
13236
13806
  if (!previousManifest)
13237
13807
  return [];
13238
- const managedPrefix = `${plan.adapter.managedDir}/`;
13239
- return previousManifest.files.filter((file) => !currentRelativePaths.has(file.relativePath)).filter((file) => file.relativePath === plan.adapter.managedDir || file.relativePath.startsWith(managedPrefix)).map((file) => planStaleFileResult(file, targetHome, options)).filter((result) => result !== null);
13808
+ return previousManifest.files.filter((file) => !currentRelativePaths.has(file.relativePath)).filter((file) => isPlanManagedFile(plan, file.relativePath, file.role)).map((file) => planStaleFileResult(file, targetHome, options)).filter((result) => result !== null);
13240
13809
  }
13241
13810
  function planStaleFileResult(file, targetHome, options) {
13242
13811
  const target = resolveManifestRelativePath(file.relativePath, targetHome);
13243
- if (!existsSync9(target))
13812
+ if (!existsSync10(target))
13244
13813
  return null;
13245
- const previousContent = readFileSync8(target, "utf-8");
13246
- const previousSha256 = sha2567(previousContent);
13814
+ const previousContent = readFileSync10(target, "utf-8");
13815
+ const previousSha256 = sha2569(previousContent);
13247
13816
  if (!options.force && previousSha256 !== file.sha256) {
13248
13817
  return {
13249
13818
  path: target,
@@ -13287,20 +13856,20 @@ function isPreviouslyManaged(file, previousSha256, previousHashes, previousManif
13287
13856
  return previousHashes.get(file.relativePath) === previousSha256;
13288
13857
  }
13289
13858
  function resolvePlannedFilePath(plan, file, targetHome) {
13290
- const target = resolve6(targetHome, ...file.relativePath.split("/"));
13291
- const rel = relative4(targetHome, target);
13859
+ const target = resolve9(targetHome, ...file.relativePath.split("/"));
13860
+ const rel = relative5(targetHome, target);
13292
13861
  if (rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute4(rel)) {
13293
13862
  throw new SessionApplyError(`Session file escapes target home: ${file.relativePath}`);
13294
13863
  }
13295
- if (resolve6(file.path) !== target) {
13864
+ if (resolve9(file.path) !== target) {
13296
13865
  throw new SessionApplyError(`Session file path mismatch for ${file.relativePath}: ${file.path}`);
13297
13866
  }
13298
13867
  assertNoSymlinkSegments2(targetHome, target);
13299
13868
  return target;
13300
13869
  }
13301
13870
  function resolveManifestRelativePath(relativePath, targetHome) {
13302
- const target = resolve6(targetHome, ...relativePath.split(/[\\/]+/));
13303
- const rel = relative4(targetHome, target);
13871
+ const target = resolve9(targetHome, ...relativePath.split(/[\\/]+/));
13872
+ const rel = relative5(targetHome, target);
13304
13873
  if (rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute4(rel)) {
13305
13874
  throw new SessionApplyError(`Session manifest file escapes target home: ${relativePath}`);
13306
13875
  }
@@ -13308,10 +13877,10 @@ function resolveManifestRelativePath(relativePath, targetHome) {
13308
13877
  return target;
13309
13878
  }
13310
13879
  function readPreviousManifest(path) {
13311
- if (!existsSync9(path))
13880
+ if (!existsSync10(path))
13312
13881
  return null;
13313
13882
  try {
13314
- const parsed = JSON.parse(readFileSync8(path, "utf-8"));
13883
+ const parsed = JSON.parse(readFileSync10(path, "utf-8"));
13315
13884
  if (parsed.schema !== SESSION_RENDER_SCHEMA)
13316
13885
  return null;
13317
13886
  if (!Array.isArray(parsed.files))
@@ -13345,18 +13914,18 @@ function applyPlannedFile(plan, file, targetHome, resultsByPath, coordination, a
13345
13914
  function assertExpectedSessionFileHash(path, targetHome, expectedHash) {
13346
13915
  const actualHash = currentSessionFileHash(path, targetHome);
13347
13916
  if (actualHash !== expectedHash) {
13348
- throw new SessionApplyError(`Session apply path changed after planning: ${relative4(targetHome, path)}`);
13917
+ throw new SessionApplyError(`Session apply path changed after planning: ${relative5(targetHome, path)}`);
13349
13918
  }
13350
13919
  }
13351
13920
  function currentSessionFileHash(path, targetHome) {
13352
13921
  assertNoSymlinkSegments2(targetHome, path);
13353
- if (!existsSync9(path))
13922
+ if (!existsSync10(path))
13354
13923
  return null;
13355
- const stat = lstatSync3(path);
13924
+ const stat = lstatSync5(path);
13356
13925
  if (stat.isSymbolicLink() || !stat.isFile()) {
13357
13926
  throw new SessionApplyError(`Session apply path is not a regular file: ${path}`);
13358
13927
  }
13359
- return sha2567(readFileSync8(path, "utf-8"));
13928
+ return sha2569(readFileSync10(path, "utf-8"));
13360
13929
  }
13361
13930
  function requiredPreviousHash(result) {
13362
13931
  if (result.previousSha256 === null) {
@@ -13365,13 +13934,13 @@ function requiredPreviousHash(result) {
13365
13934
  return result.previousSha256;
13366
13935
  }
13367
13936
  function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousManifest, coordination, allowPortableFallback, forcePortableFileOps) {
13368
- const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").filter((result) => existsSync9(result.path)).map((result) => {
13369
- const content = readFileSync8(result.path, "utf-8");
13937
+ const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").filter((result) => existsSync10(result.path)).map((result) => {
13938
+ const content = readFileSync10(result.path, "utf-8");
13370
13939
  return {
13371
13940
  path: result.path,
13372
13941
  relativePath: result.relativePath,
13373
13942
  role: result.role,
13374
- sha256: sha2567(content),
13943
+ sha256: sha2569(content),
13375
13944
  content
13376
13945
  };
13377
13946
  });
@@ -13384,7 +13953,7 @@ function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousM
13384
13953
  };
13385
13954
  }
13386
13955
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
13387
- const snapshotPath = resolve6(targetHome, ".hasna", "session-render-snapshots", `${timestamp}-${randomUUID4()}.json`);
13956
+ const snapshotPath = resolve9(targetHome, ".hasna", "session-render-snapshots", `${timestamp}-${randomUUID4()}.json`);
13388
13957
  const afterFiles = results.map((result) => {
13389
13958
  if (result.action === "conflict") {
13390
13959
  throw new SessionApplyError(`Cannot snapshot unresolved conflict: ${result.relativePath}`);
@@ -13432,43 +14001,43 @@ function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousM
13432
14001
  function assertSafeTargetHome(targetHome) {
13433
14002
  if (!isAbsolute4(targetHome))
13434
14003
  throw new SessionApplyError(`Session target home must be absolute: ${targetHome}`);
13435
- const normalized = resolve6(targetHome);
13436
- if (normalized === parse4(normalized).root) {
14004
+ const normalized = resolve9(targetHome);
14005
+ if (normalized === parse5(normalized).root) {
13437
14006
  throw new SessionApplyError(`Session target home cannot be the filesystem root: ${targetHome}`);
13438
14007
  }
13439
- assertNoSymlinkAncestors2(normalized);
13440
- if (existsSync9(normalized) && lstatSync3(normalized).isSymbolicLink()) {
14008
+ assertNoSymlinkAncestors3(normalized);
14009
+ if (existsSync10(normalized) && lstatSync5(normalized).isSymbolicLink()) {
13441
14010
  throw new SessionApplyError(`Session target home cannot be a symlink: ${normalized}`);
13442
14011
  }
13443
14012
  return normalized;
13444
14013
  }
13445
14014
  function assertNoSymlinkSegments2(root, target) {
13446
- assertNoSymlinkAncestors2(root);
13447
- const rel = relative4(root, target);
14015
+ assertNoSymlinkAncestors3(root);
14016
+ const rel = relative5(root, target);
13448
14017
  let current = root;
13449
14018
  for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
13450
- current = join9(current, segment);
13451
- if (existsSync9(current) && lstatSync3(current).isSymbolicLink()) {
14019
+ current = join12(current, segment);
14020
+ if (existsSync10(current) && lstatSync5(current).isSymbolicLink()) {
13452
14021
  throw new SessionApplyError(`Session apply path uses a symlink: ${current}`);
13453
14022
  }
13454
14023
  }
13455
14024
  }
13456
- function assertNoSymlinkAncestors2(path) {
13457
- const normalized = resolve6(path);
13458
- const parsed = parse4(normalized);
14025
+ function assertNoSymlinkAncestors3(path) {
14026
+ const normalized = resolve9(path);
14027
+ const parsed = parse5(normalized);
13459
14028
  let current = parsed.root;
13460
- const rel = relative4(parsed.root, normalized);
14029
+ const rel = relative5(parsed.root, normalized);
13461
14030
  for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
13462
- current = join9(current, segment);
13463
- if (!existsSync9(current))
14031
+ current = join12(current, segment);
14032
+ if (!existsSync10(current))
13464
14033
  return;
13465
- if (lstatSync3(current).isSymbolicLink()) {
14034
+ if (lstatSync5(current).isSymbolicLink()) {
13466
14035
  throw new SessionApplyError(`Session apply path uses a symlink ancestor: ${current}`);
13467
14036
  }
13468
14037
  }
13469
14038
  }
13470
- function sha2567(content) {
13471
- return createHash7("sha256").update(content).digest("hex");
14039
+ function sha2569(content) {
14040
+ return createHash9("sha256").update(content).digest("hex");
13472
14041
  }
13473
14042
  // src/lib/project-dashboard-standard.ts
13474
14043
  var PROJECT_DASHBOARD_STANDARD_SLUG = "agent-managed-project-dashboard-standard";
@@ -13771,13 +14340,13 @@ async function ensureDangerousOperationGuardStandardConfig(store = resolveConfig
13771
14340
  }
13772
14341
  }
13773
14342
  // src/lib/sync.ts
13774
- import { existsSync as existsSync11, readdirSync as readdirSync3, readFileSync as readFileSync10 } from "fs";
13775
- import { basename as basename5, extname as extname3, join as join11 } from "path";
14343
+ import { existsSync as existsSync12, readdirSync as readdirSync3, readFileSync as readFileSync12 } from "fs";
14344
+ import { basename as basename5, extname as extname3, join as join14 } from "path";
13776
14345
 
13777
14346
  // src/lib/sync-dir.ts
13778
- import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
13779
- import { join as join10, relative as relative5 } from "path";
13780
- import { homedir as homedir5 } from "os";
14347
+ import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync11, statSync as statSync6 } from "fs";
14348
+ import { join as join13, relative as relative6 } from "path";
14349
+ import { homedir as homedir7 } from "os";
13781
14350
  var SKIP = [".db", ".db-shm", ".db-wal", ".log", ".lock", ".DS_Store", "node_modules", ".git"];
13782
14351
  function shouldSkip(p) {
13783
14352
  return SKIP.some((s) => p.includes(s));
@@ -13785,11 +14354,11 @@ function shouldSkip(p) {
13785
14354
  async function syncFromDir(dir, opts = {}) {
13786
14355
  const store = opts.store ?? resolveConfigStore();
13787
14356
  const absDir = expandPath(dir);
13788
- if (!existsSync10(absDir))
14357
+ if (!existsSync11(absDir))
13789
14358
  return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
13790
- const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) => join10(absDir, f)).filter((f) => statSync5(f).isFile());
14359
+ const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) => join13(absDir, f)).filter((f) => statSync6(f).isFile());
13791
14360
  const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
13792
- const home = homedir5();
14361
+ const home = homedir7();
13793
14362
  const allConfigs = await store.listConfigs();
13794
14363
  for (const file of files) {
13795
14364
  if (shouldSkip(file)) {
@@ -13797,7 +14366,7 @@ async function syncFromDir(dir, opts = {}) {
13797
14366
  continue;
13798
14367
  }
13799
14368
  try {
13800
- const content = readFileSync9(file, "utf-8");
14369
+ const content = readFileSync11(file, "utf-8");
13801
14370
  if (content.length > 500000) {
13802
14371
  result.skipped.push(file + " (too large)");
13803
14372
  continue;
@@ -13806,7 +14375,7 @@ async function syncFromDir(dir, opts = {}) {
13806
14375
  const existing = allConfigs.find((c) => c.target_path === targetPath);
13807
14376
  if (!existing) {
13808
14377
  if (!opts.dryRun)
13809
- await store.createConfig({ name: relative5(absDir, file), category: detectCategory(file), agent: detectAgent(file), target_path: targetPath, format: detectFormat(file), content });
14378
+ await store.createConfig({ name: relative6(absDir, file), category: detectCategory(file), agent: detectAgent(file), target_path: targetPath, format: detectFormat(file), content });
13810
14379
  result.added++;
13811
14380
  } else if (existing.content !== content) {
13812
14381
  if (!opts.dryRun)
@@ -13823,7 +14392,7 @@ async function syncFromDir(dir, opts = {}) {
13823
14392
  }
13824
14393
  async function syncToDir(dir, opts = {}) {
13825
14394
  const store = opts.store ?? resolveConfigStore();
13826
- const home = homedir5();
14395
+ const home = homedir7();
13827
14396
  const absDir = expandPath(dir);
13828
14397
  const normalized = dir.startsWith("~/") ? dir : absDir.replace(home, "~");
13829
14398
  const configs = (await store.listConfigs()).filter((c) => c.target_path && (c.target_path.startsWith(normalized) || c.target_path.startsWith(absDir)));
@@ -13847,7 +14416,7 @@ async function syncToDir(dir, opts = {}) {
13847
14416
  }
13848
14417
  function walkDir(dir, files = []) {
13849
14418
  for (const entry of readdirSync2(dir, { withFileTypes: true })) {
13850
- const full = join10(dir, entry.name);
14419
+ const full = join13(dir, entry.name);
13851
14420
  if (shouldSkip(full))
13852
14421
  continue;
13853
14422
  if (entry.isDirectory())
@@ -13908,7 +14477,7 @@ function isGeneratedOutputTarget2(config, owners) {
13908
14477
  return !!ownerIds && !ownerIds.has(config.id);
13909
14478
  }
13910
14479
  function hasClaudePromptSource() {
13911
- return existsSync11(expandPath("~/.claude/CLAUDE.md"));
14480
+ return existsSync12(expandPath("~/.claude/CLAUDE.md"));
13912
14481
  }
13913
14482
  function hasClaudeRuleSourceForCursorTarget(targetPath) {
13914
14483
  const absoluteTargetPath = expandPath(targetPath);
@@ -13916,7 +14485,7 @@ function hasClaudeRuleSourceForCursorTarget(targetPath) {
13916
14485
  if (!absoluteTargetPath.startsWith(`${absolutePrefix}/`) || !absoluteTargetPath.endsWith(".mdc"))
13917
14486
  return false;
13918
14487
  const stem = basename5(absoluteTargetPath, ".mdc");
13919
- return existsSync11(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync11(expandPath(`~/.claude/rules/${stem}.mdc`));
14488
+ return existsSync12(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync12(expandPath(`~/.claude/rules/${stem}.mdc`));
13920
14489
  }
13921
14490
  function isKnownGeneratedTargetPath(targetPath) {
13922
14491
  const normalizedTargetPath = normalizeTargetPath(targetPath);
@@ -13981,11 +14550,11 @@ async function syncProject(opts) {
13981
14550
  const allConfigs = await store.listConfigs();
13982
14551
  const machine = detectMachineContext();
13983
14552
  for (const pf of PROJECT_CONFIG_FILES) {
13984
- const abs = join11(absDir, pf.file);
13985
- if (!existsSync11(abs))
14553
+ const abs = join14(absDir, pf.file);
14554
+ if (!existsSync12(abs))
13986
14555
  continue;
13987
14556
  try {
13988
- const rawContent = readFileSync10(abs, "utf-8");
14557
+ const rawContent = readFileSync12(abs, "utf-8");
13989
14558
  if (rawContent.length > 500000) {
13990
14559
  result.skipped.push(pf.file);
13991
14560
  continue;
@@ -14014,20 +14583,20 @@ async function syncProject(opts) {
14014
14583
  }
14015
14584
  }
14016
14585
  for (const ruleDir of [
14017
- { dir: join11(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
14018
- { dir: join11(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" },
14019
- { dir: join11(absDir, ".cursor", "rules"), agent: "cursor", namePrefix: "cursor-rules" },
14020
- { dir: join11(absDir, ".github", "instructions"), agent: "copilot", namePrefix: "copilot-instructions" },
14021
- { dir: join11(absDir, ".devin", "rules"), agent: "devin", namePrefix: "devin-rules" },
14022
- { dir: join11(absDir, ".windsurf", "rules"), agent: "windsurf-legacy", namePrefix: "windsurf-rules" },
14023
- { dir: join11(absDir, ".clinerules"), agent: "cline", namePrefix: "cline-rules" }
14586
+ { dir: join14(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
14587
+ { dir: join14(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" },
14588
+ { dir: join14(absDir, ".cursor", "rules"), agent: "cursor", namePrefix: "cursor-rules" },
14589
+ { dir: join14(absDir, ".github", "instructions"), agent: "copilot", namePrefix: "copilot-instructions" },
14590
+ { dir: join14(absDir, ".devin", "rules"), agent: "devin", namePrefix: "devin-rules" },
14591
+ { dir: join14(absDir, ".windsurf", "rules"), agent: "windsurf-legacy", namePrefix: "windsurf-rules" },
14592
+ { dir: join14(absDir, ".clinerules"), agent: "cline", namePrefix: "cline-rules" }
14024
14593
  ]) {
14025
- if (!existsSync11(ruleDir.dir))
14594
+ if (!existsSync12(ruleDir.dir))
14026
14595
  continue;
14027
14596
  const mdFiles = readdirSync3(ruleDir.dir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc"));
14028
14597
  for (const f of mdFiles) {
14029
- const abs = join11(ruleDir.dir, f);
14030
- const raw = readFileSync10(abs, "utf-8");
14598
+ const abs = join14(ruleDir.dir, f);
14599
+ const raw = readFileSync12(abs, "utf-8");
14031
14600
  const redacted = redactContent(raw, "markdown");
14032
14601
  const machineAware = templateizeMachineContent(redacted.content, machine);
14033
14602
  const content = machineAware.content;
@@ -14066,20 +14635,20 @@ async function syncKnown(opts = {}) {
14066
14635
  for (const known of targets) {
14067
14636
  if (known.rulesDir) {
14068
14637
  const absDir = expandPath(known.rulesDir);
14069
- if (!existsSync11(absDir)) {
14638
+ if (!existsSync12(absDir)) {
14070
14639
  result.skipped.push(known.rulesDir);
14071
14640
  continue;
14072
14641
  }
14073
14642
  const extensions = known.rulesExtensions ?? [".md", ".mdc"];
14074
14643
  const ruleFiles = readdirSync3(absDir).filter((f) => extensions.some((ext) => f.endsWith(ext)));
14075
14644
  for (const f of ruleFiles) {
14076
- const abs2 = join11(absDir, f);
14645
+ const abs2 = join14(absDir, f);
14077
14646
  const targetPath = abs2.replace(home, "~");
14078
14647
  if (existingOutputOwners.has(normalizeTargetPath(targetPath)) || isKnownGeneratedTargetPath(targetPath)) {
14079
14648
  result.skipped.push(`${targetPath} (generated output)`);
14080
14649
  continue;
14081
14650
  }
14082
- const raw = readFileSync10(abs2, "utf-8");
14651
+ const raw = readFileSync12(abs2, "utf-8");
14083
14652
  const redacted = redactContent(raw, "markdown");
14084
14653
  const machineAware = templateizeMachineContent(redacted.content, machine);
14085
14654
  const content = machineAware.content;
@@ -14107,12 +14676,12 @@ async function syncKnown(opts = {}) {
14107
14676
  continue;
14108
14677
  }
14109
14678
  const abs = expandPath(known.path);
14110
- if (!existsSync11(abs)) {
14679
+ if (!existsSync12(abs)) {
14111
14680
  result.skipped.push(known.path);
14112
14681
  continue;
14113
14682
  }
14114
14683
  try {
14115
- const rawContent = normalizeKnownConfigSource(known, readFileSync10(abs, "utf-8"));
14684
+ const rawContent = normalizeKnownConfigSource(known, readFileSync12(abs, "utf-8"));
14116
14685
  if (rawContent.length > 500000) {
14117
14686
  result.skipped.push(known.path + " (too large)");
14118
14687
  continue;
@@ -14215,9 +14784,9 @@ function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
14215
14784
  }
14216
14785
  function buildDiff(expectedContent, targetPath, storedFormat, showSecrets) {
14217
14786
  const path = expandPath(targetPath);
14218
- if (!existsSync11(path))
14787
+ if (!existsSync12(path))
14219
14788
  return `(file not found on disk: ${path})`;
14220
- const diskContent = readFileSync10(path, "utf-8");
14789
+ const diskContent = readFileSync12(path, "utf-8");
14221
14790
  if (diskContent === expectedContent)
14222
14791
  return "(no diff \u2014 identical)";
14223
14792
  const format = redactFormatForTarget(targetPath, storedFormat);
@@ -14375,26 +14944,26 @@ function detectFormat(filePath) {
14375
14944
  return "text";
14376
14945
  }
14377
14946
  // src/lib/export.ts
14378
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
14379
- import { join as join12, resolve as resolve7 } from "path";
14947
+ import { existsSync as existsSync13, mkdirSync as mkdirSync6, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
14948
+ import { join as join15, resolve as resolve10 } from "path";
14380
14949
  import { tmpdir } from "os";
14381
14950
  async function exportConfigs(outputPath, opts = {}) {
14382
14951
  const store = opts.store ?? resolveConfigStore();
14383
14952
  const configs = await store.listConfigs(opts.filter);
14384
- const absOutput = resolve7(outputPath);
14385
- const tmpDir = join12(tmpdir(), `configs-export-${Date.now()}`);
14386
- const contentsDir = join12(tmpDir, "contents");
14953
+ const absOutput = resolve10(outputPath);
14954
+ const tmpDir = join15(tmpdir(), `configs-export-${Date.now()}`);
14955
+ const contentsDir = join15(tmpDir, "contents");
14387
14956
  try {
14388
- mkdirSync5(contentsDir, { recursive: true });
14957
+ mkdirSync6(contentsDir, { recursive: true });
14389
14958
  const manifest = {
14390
14959
  version: "1.0.0",
14391
14960
  exported_at: new Date().toISOString(),
14392
14961
  configs: configs.map(({ content: _content, ...meta }) => meta)
14393
14962
  };
14394
- writeFileSync3(join12(tmpDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
14963
+ writeFileSync4(join15(tmpDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
14395
14964
  for (const config of configs) {
14396
14965
  const fileName = `${config.slug}.${config.format === "text" ? "txt" : config.format}`;
14397
- writeFileSync3(join12(contentsDir, fileName), config.content, "utf-8");
14966
+ writeFileSync4(join15(contentsDir, fileName), config.content, "utf-8");
14398
14967
  }
14399
14968
  const proc = Bun.spawn(["tar", "czf", absOutput, "-C", tmpDir, "."], {
14400
14969
  stdout: "pipe",
@@ -14407,23 +14976,23 @@ async function exportConfigs(outputPath, opts = {}) {
14407
14976
  }
14408
14977
  return { path: absOutput, count: configs.length };
14409
14978
  } finally {
14410
- if (existsSync12(tmpDir)) {
14411
- rmSync3(tmpDir, { recursive: true, force: true });
14979
+ if (existsSync13(tmpDir)) {
14980
+ rmSync4(tmpDir, { recursive: true, force: true });
14412
14981
  }
14413
14982
  }
14414
14983
  }
14415
14984
  // src/lib/import.ts
14416
- import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync11, rmSync as rmSync4 } from "fs";
14417
- import { join as join13, resolve as resolve8 } from "path";
14985
+ import { existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync13, rmSync as rmSync5 } from "fs";
14986
+ import { join as join16, resolve as resolve11 } from "path";
14418
14987
  import { tmpdir as tmpdir2 } from "os";
14419
14988
  async function importConfigs(bundlePath, opts = {}) {
14420
14989
  const store = opts.store ?? resolveConfigStore();
14421
14990
  const conflict = opts.conflict ?? "skip";
14422
- const absPath = resolve8(bundlePath);
14423
- const tmpDir = join13(tmpdir2(), `configs-import-${Date.now()}`);
14991
+ const absPath = resolve11(bundlePath);
14992
+ const tmpDir = join16(tmpdir2(), `configs-import-${Date.now()}`);
14424
14993
  const result = { created: 0, updated: 0, skipped: 0, errors: [] };
14425
14994
  try {
14426
- mkdirSync6(tmpDir, { recursive: true });
14995
+ mkdirSync7(tmpDir, { recursive: true });
14427
14996
  const proc = Bun.spawn(["tar", "xzf", absPath, "-C", tmpDir], {
14428
14997
  stdout: "pipe",
14429
14998
  stderr: "pipe"
@@ -14433,15 +15002,15 @@ async function importConfigs(bundlePath, opts = {}) {
14433
15002
  const stderr = await new Response(proc.stderr).text();
14434
15003
  throw new Error(`tar extraction failed: ${stderr}`);
14435
15004
  }
14436
- const manifestPath = join13(tmpDir, "manifest.json");
14437
- if (!existsSync13(manifestPath))
15005
+ const manifestPath = join16(tmpDir, "manifest.json");
15006
+ if (!existsSync14(manifestPath))
14438
15007
  throw new Error("Invalid bundle: missing manifest.json");
14439
- const manifest = JSON.parse(readFileSync11(manifestPath, "utf-8"));
15008
+ const manifest = JSON.parse(readFileSync13(manifestPath, "utf-8"));
14440
15009
  for (const meta of manifest.configs) {
14441
15010
  try {
14442
15011
  const ext = meta.format === "text" ? "txt" : meta.format;
14443
- const contentFile = join13(tmpDir, "contents", `${meta.slug}.${ext}`);
14444
- const content = existsSync13(contentFile) ? readFileSync11(contentFile, "utf-8") : "";
15012
+ const contentFile = join16(tmpDir, "contents", `${meta.slug}.${ext}`);
15013
+ const content = existsSync14(contentFile) ? readFileSync13(contentFile, "utf-8") : "";
14445
15014
  let existing = null;
14446
15015
  try {
14447
15016
  existing = await store.getConfig(meta.slug);
@@ -14475,16 +15044,16 @@ async function importConfigs(bundlePath, opts = {}) {
14475
15044
  }
14476
15045
  return result;
14477
15046
  } finally {
14478
- if (existsSync13(tmpDir)) {
14479
- rmSync4(tmpDir, { recursive: true, force: true });
15047
+ if (existsSync14(tmpDir)) {
15048
+ rmSync5(tmpDir, { recursive: true, force: true });
14480
15049
  }
14481
15050
  }
14482
15051
  }
14483
15052
  // src/lib/package-manager-guard.ts
14484
15053
  import { execFileSync as execFileSync2 } from "child_process";
14485
- import { existsSync as existsSync14, lstatSync as lstatSync4, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "fs";
14486
- import { homedir as homedir6 } from "os";
14487
- import { basename as basename6, dirname as dirname7, isAbsolute as isAbsolute5, join as join14, relative as relative6, resolve as resolve9 } from "path";
15054
+ import { existsSync as existsSync15, lstatSync as lstatSync6, readdirSync as readdirSync4, readFileSync as readFileSync14 } from "fs";
15055
+ import { homedir as homedir8 } from "os";
15056
+ import { basename as basename6, dirname as dirname8, isAbsolute as isAbsolute5, join as join17, relative as relative7, resolve as resolve12 } from "path";
14488
15057
  var SKIP_DIRS = new Set([
14489
15058
  ".git",
14490
15059
  "node_modules",
@@ -14515,20 +15084,20 @@ var HOME_FILES = [
14515
15084
  var TOKEN_VALUE_PATTERNS = [
14516
15085
  { re: /npm_[A-Za-z0-9]{36,}/, rule: "literal-npm-token", detail: "literal npm token-like value" },
14517
15086
  { re: /gh[pousr]_[A-Za-z0-9_]{36,}/, rule: "literal-github-token", detail: "literal GitHub token-like value" },
14518
- { re: /sk-ant-[A-Za-z0-9\-_]{40,}/, rule: "literal-anthropic-key", detail: "literal Anthropic key-like value" },
15087
+ { re: /sk[-]ant-[A-Za-z0-9\-_]{40,}/, rule: "literal-anthropic-key", detail: "literal Anthropic key-like value" },
14519
15088
  { re: /sk-[A-Za-z0-9]{48,}/, rule: "literal-openai-key", detail: "literal OpenAI key-like value" },
14520
15089
  { re: /AKIA[0-9A-Z]{16}/, rule: "literal-aws-access-key", detail: "literal AWS access-key-like value" },
14521
15090
  { re: /xoxb-[0-9]+-[A-Za-z0-9-]+/, rule: "literal-slack-token", detail: "literal Slack token-like value" }
14522
15091
  ];
14523
15092
  function scanPackageManagerSecrets(options = {}) {
14524
- const cwd = options.cwd ? resolve9(options.cwd) : process.cwd();
14525
- const roots = (options.roots && options.roots.length > 0 ? options.roots : [cwd]).map((root) => resolve9(cwd, root));
15093
+ const cwd = options.cwd ? resolve12(options.cwd) : process.cwd();
15094
+ const roots = (options.roots && options.roots.length > 0 ? options.roots : [cwd]).map((root) => resolve12(cwd, root));
14526
15095
  const findings = [];
14527
15096
  let scannedFiles = 0;
14528
15097
  for (const root of roots) {
14529
- if (!existsSync14(root))
15098
+ if (!existsSync15(root))
14530
15099
  continue;
14531
- const stat = lstatSync4(root);
15100
+ const stat = lstatSync6(root);
14532
15101
  if (stat.isFile()) {
14533
15102
  if (!shouldScanRepoFile(root))
14534
15103
  continue;
@@ -14536,14 +15105,14 @@ function scanPackageManagerSecrets(options = {}) {
14536
15105
  if (text === null)
14537
15106
  continue;
14538
15107
  scannedFiles++;
14539
- findings.push(...scanFile(root, text, classifyRepoFile(root), isTrackedFile(root), dirname7(root)));
15108
+ findings.push(...scanFile(root, text, classifyRepoFile(root), isTrackedFile(root), dirname8(root)));
14540
15109
  continue;
14541
15110
  }
14542
15111
  if (!stat.isDirectory())
14543
15112
  continue;
14544
15113
  const tracked = trackedFiles(root);
14545
15114
  for (const file of collectRepoFiles(root)) {
14546
- const rel = toPosix(relative6(root, file));
15115
+ const rel = toPosix(relative7(root, file));
14547
15116
  const isTracked = tracked.has(rel);
14548
15117
  const text = readTextFile(file);
14549
15118
  if (text === null)
@@ -14553,10 +15122,10 @@ function scanPackageManagerSecrets(options = {}) {
14553
15122
  }
14554
15123
  }
14555
15124
  if (options.includeHome) {
14556
- const home = homedir6();
15125
+ const home = homedir8();
14557
15126
  for (const name of HOME_FILES) {
14558
- const file = join14(home, name);
14559
- if (!existsSync14(file))
15127
+ const file = join17(home, name);
15128
+ if (!existsSync15(file))
14560
15129
  continue;
14561
15130
  const text = readTextFile(file);
14562
15131
  if (text === null)
@@ -14580,12 +15149,12 @@ function collectRepoFiles(root) {
14580
15149
  if (entry.isDirectory()) {
14581
15150
  if (SKIP_DIRS.has(entry.name))
14582
15151
  continue;
14583
- visit(join14(dir, entry.name));
15152
+ visit(join17(dir, entry.name));
14584
15153
  continue;
14585
15154
  }
14586
15155
  if (!entry.isFile())
14587
15156
  continue;
14588
- const file = join14(dir, entry.name);
15157
+ const file = join17(dir, entry.name);
14589
15158
  if (shouldScanRepoFile(file))
14590
15159
  out.push(file);
14591
15160
  }
@@ -14620,10 +15189,10 @@ function isNpmrcName(name) {
14620
15189
  }
14621
15190
  function readTextFile(file) {
14622
15191
  try {
14623
- const stat = lstatSync4(file);
15192
+ const stat = lstatSync6(file);
14624
15193
  if (!stat.isFile() || stat.size > 5000000)
14625
15194
  return null;
14626
- const buf = readFileSync12(file);
15195
+ const buf = readFileSync14(file);
14627
15196
  if (buf.includes(0))
14628
15197
  return null;
14629
15198
  return buf.toString("utf-8");
@@ -14823,11 +15392,11 @@ function trackedFiles(root) {
14823
15392
  }
14824
15393
  function isTrackedFile(file) {
14825
15394
  try {
14826
- const repoRoot = execFileSync2("git", ["-C", dirname7(file), "rev-parse", "--show-toplevel"], {
15395
+ const repoRoot = execFileSync2("git", ["-C", dirname8(file), "rev-parse", "--show-toplevel"], {
14827
15396
  encoding: "utf-8",
14828
15397
  stdio: ["ignore", "pipe", "ignore"]
14829
15398
  }).trim();
14830
- const rel = toPosix(relative6(repoRoot, file));
15399
+ const rel = toPosix(relative7(repoRoot, file));
14831
15400
  execFileSync2("git", ["-C", repoRoot, "ls-files", "--error-unmatch", "--", rel], {
14832
15401
  stdio: ["ignore", "ignore", "ignore"]
14833
15402
  });
@@ -14853,13 +15422,13 @@ function stripInlineComment(value) {
14853
15422
  return value.replace(/\s[#;].*$/, "").trim();
14854
15423
  }
14855
15424
  function displayPath(file, root) {
14856
- const home = homedir6();
15425
+ const home = homedir8();
14857
15426
  if (root === home && (file === home || file.startsWith(home + "/")))
14858
- return "~/" + toPosix(relative6(home, file));
15427
+ return "~/" + toPosix(relative7(home, file));
14859
15428
  if (isAbsolute5(root) && file.startsWith(root + "/"))
14860
- return toPosix(relative6(root, file));
15429
+ return toPosix(relative7(root, file));
14861
15430
  if (file === home || file.startsWith(home + "/"))
14862
- return "~/" + toPosix(relative6(home, file));
15431
+ return "~/" + toPosix(relative7(home, file));
14863
15432
  return file;
14864
15433
  }
14865
15434
  function toPosix(path) {
@@ -14897,6 +15466,7 @@ export {
14897
15466
  renderMachineAwareContentPreview,
14898
15467
  renderMachineAwareContent,
14899
15468
  redactContent,
15469
+ reconcileManagedSkillRuntimes,
14900
15470
  providerVersionSatisfies,
14901
15471
  previewConfigs,
14902
15472
  planSessionRender,
@@ -14913,9 +15483,11 @@ export {
14913
15483
  machineContextToVariables,
14914
15484
  legacyProfileConfigBinding,
14915
15485
  isTemplate,
14916
- isCloudMode,
15486
+ isApiTransport,
15487
+ inspectManagedSkillRuntimes,
14917
15488
  importConfigs,
14918
15489
  hasSecrets,
15490
+ getRawStoreRoot,
14919
15491
  getConfigsStatus,
14920
15492
  extractTemplateVars,
14921
15493
  exportConfigs,
@@ -14992,6 +15564,7 @@ export {
14992
15564
  INSTRUCTION_GRAPH_PLAN_SCHEMA,
14993
15565
  INSTRUCTION_FALLBACKS,
14994
15566
  INSTRUCTION_ACTIVATION_MODES,
15567
+ INBOX_CONVERSATIONS_MINIMUM_VERSION,
14995
15568
  GLOBAL_AGENT_RULES_STANDARD_SLUG,
14996
15569
  GLOBAL_AGENT_RULES_STANDARD_CONTENT,
14997
15570
  DANGEROUS_OPERATION_GUARD_STANDARD_SLUG,