@hasna/instructions 0.6.1 → 0.7.1

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 (85) hide show
  1. package/README.md +141 -10
  2. package/dist/chunks/{apply-ynfn1av7.js → apply-c3sd4agz.js} +5 -3
  3. package/dist/chunks/{apply-sfzja1f3.js → apply-pnn7a3y7.js} +6 -3
  4. package/dist/chunks/database-wstmr56z.js +23 -0
  5. package/dist/chunks/{index-pkscjnj5.js → index-3djthcm6.js} +0 -1
  6. package/dist/chunks/index-5d7zdftc.js +186 -0
  7. package/dist/chunks/{index-1hpwskwd.js → index-6jncnnw7.js} +318 -329
  8. package/dist/chunks/index-8rb7ng2y.js +148 -0
  9. package/dist/chunks/{index-v7dkb384.js → index-aj66f6xr.js} +243 -100
  10. package/dist/chunks/index-fpeyzn3n.js +186 -0
  11. package/dist/chunks/{index-9p9gn7gh.js → index-jg8ptcwh.js} +5 -7
  12. package/dist/chunks/index-mvckkf15.js +363 -0
  13. package/dist/chunks/index-n3fjspr0.js +119 -0
  14. package/dist/chunks/{index-85n5wnd8.js → index-pdpg8a44.js} +5 -7
  15. package/dist/chunks/{index-e9epbsvs.js → index-r7nfef2g.js} +15 -4
  16. package/dist/chunks/{index-axhwg61p.js → index-ypcef3a2.js} +15 -4
  17. package/dist/chunks/legacy-store-migration-z2m5yzyk.js +322 -0
  18. package/dist/chunks/{local-a9nen65z.js → local-0a9gja58.js} +142 -2
  19. package/dist/chunks/{local-0d8qrc92.js → local-969ye538.js} +153 -188
  20. package/dist/chunks/s3-backup-hxe3zpfz.js +240 -0
  21. package/dist/chunks/s3-config-hhght91k.js +14 -0
  22. package/dist/chunks/s3-object-store-n0s82swt.js +14 -0
  23. package/dist/chunks/{sync-vy1yjvs6.js → sync-q5hvwq6e.js} +4 -4
  24. package/dist/chunks/{sync-m46fc257.js → sync-xtkbm5br.js} +5 -4
  25. package/dist/chunks/{template-02wjvv05.js → template-fsfxpe4p.js} +1 -1
  26. package/dist/chunks/{template-ke972qqe.js → template-wgnzdn7h.js} +1 -1
  27. package/dist/cli/index.js +1236 -256
  28. package/dist/data/config-store.d.ts +10 -1
  29. package/dist/data/config-store.d.ts.map +1 -1
  30. package/dist/db/configs.d.ts +4 -1
  31. package/dist/db/configs.d.ts.map +1 -1
  32. package/dist/db/local.d.ts +1 -1
  33. package/dist/db/local.d.ts.map +1 -1
  34. package/dist/index.js +1086 -215
  35. package/dist/lib/apply.d.ts +7 -0
  36. package/dist/lib/apply.d.ts.map +1 -1
  37. package/dist/lib/compact-output.d.ts +3 -18
  38. package/dist/lib/compact-output.d.ts.map +1 -1
  39. package/dist/lib/export.d.ts +22 -3
  40. package/dist/lib/export.d.ts.map +1 -1
  41. package/dist/lib/import.d.ts +18 -0
  42. package/dist/lib/import.d.ts.map +1 -1
  43. package/dist/lib/legacy-store-migration.d.ts +39 -0
  44. package/dist/lib/legacy-store-migration.d.ts.map +1 -0
  45. package/dist/lib/managed-skill-runtimes.d.ts +1 -0
  46. package/dist/lib/managed-skill-runtimes.d.ts.map +1 -1
  47. package/dist/lib/sync-dir.d.ts.map +1 -1
  48. package/dist/mcp/index.js +41 -30
  49. package/dist/mcp/server.d.ts.map +1 -1
  50. package/dist/sdk/index.d.ts +2 -0
  51. package/dist/sdk/index.d.ts.map +1 -1
  52. package/dist/sdk/index.js +229 -10
  53. package/dist/sdk/resolve.d.ts +1 -1
  54. package/dist/sdk/resolve.d.ts.map +1 -1
  55. package/dist/sdk/v1-client.d.ts +58 -0
  56. package/dist/sdk/v1-client.d.ts.map +1 -0
  57. package/dist/sdk/v1.generated.d.ts +242 -21
  58. package/dist/sdk/v1.generated.d.ts.map +1 -1
  59. package/dist/server/cloud.d.ts.map +1 -1
  60. package/dist/server/index.d.ts +13 -5
  61. package/dist/server/index.d.ts.map +1 -1
  62. package/dist/server/index.js +1261 -427
  63. package/dist/server/openapi.d.ts +1379 -93
  64. package/dist/server/openapi.d.ts.map +1 -1
  65. package/dist/server/v1.d.ts +25 -1
  66. package/dist/server/v1.d.ts.map +1 -1
  67. package/dist/storage/cloud-store.d.ts +45 -2
  68. package/dist/storage/cloud-store.d.ts.map +1 -1
  69. package/dist/storage/index.d.ts +7 -0
  70. package/dist/storage/index.d.ts.map +1 -0
  71. package/dist/storage/index.js +744 -0
  72. package/dist/storage/s3-backup.d.ts +76 -0
  73. package/dist/storage/s3-backup.d.ts.map +1 -0
  74. package/dist/storage/s3-config.d.ts +46 -0
  75. package/dist/storage/s3-config.d.ts.map +1 -0
  76. package/dist/storage/s3-object-store.d.ts +70 -0
  77. package/dist/storage/s3-object-store.d.ts.map +1 -0
  78. package/dist/types/index.d.ts +98 -3
  79. package/dist/types/index.d.ts.map +1 -1
  80. package/hasna.contract.json +110 -0
  81. package/migrations/0001_instructions.sql +63 -0
  82. package/migrations/0002_api_keys.sql +20 -0
  83. package/migrations/0003_idempotency_receipts.sql +24 -0
  84. package/package.json +24 -13
  85. package/assets/skills/inbox/SKILL.md +0 -86
@@ -15,7 +15,14 @@ import {
15
15
  isTemplate,
16
16
  renderTemplate,
17
17
  renderTemplatePreview
18
- } from "./index-pkscjnj5.js";
18
+ } from "./index-n3fjspr0.js";
19
+ import {
20
+ INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS,
21
+ clientTransportEnvKeys,
22
+ instructionsLocalModeNotice,
23
+ instructionsResolverInputs,
24
+ selectsInstructionsLocalStore
25
+ } from "./index-fpeyzn3n.js";
19
26
  import {
20
27
  __export,
21
28
  __require
@@ -24,6 +31,7 @@ import {
24
31
  // src/lib/compact-output.ts
25
32
  var DEFAULT_LIST_LIMIT = 20;
26
33
  var MAX_LIST_LIMIT = 100;
34
+ var MAX_LIST_CURSOR = 1e5;
27
35
  function parseLimit(value, fallback = DEFAULT_LIST_LIMIT, max = MAX_LIST_LIMIT) {
28
36
  const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
29
37
  if (!Number.isFinite(parsed) || parsed <= 0)
@@ -34,7 +42,7 @@ function parseCursor(value) {
34
42
  const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
35
43
  if (!Number.isFinite(parsed) || parsed < 0)
36
44
  return 0;
37
- return Math.floor(parsed);
45
+ return Math.min(Math.floor(parsed), MAX_LIST_CURSOR);
38
46
  }
39
47
  function paginate(items, opts = {}) {
40
48
  const limit = parseLimit(opts.limit, opts.defaultLimit ?? DEFAULT_LIST_LIMIT, opts.maxLimit ?? MAX_LIST_LIMIT);
@@ -110,9 +118,9 @@ import { createHash as createHash6 } from "crypto";
110
118
 
111
119
  // src/lib/session-render.ts
112
120
  import { createHash as createHash5 } from "crypto";
113
- import { existsSync as existsSync5, readFileSync as readFileSync4, realpathSync as realpathSync2, statSync as statSync3 } from "fs";
114
- import { homedir as homedir5 } from "os";
115
- import { basename as basename4, dirname as dirname4, extname as extname2, isAbsolute as isAbsolute3, join as join6, parse as parse2, posix as posix2, relative as relative2, resolve as resolve8 } from "path";
121
+ import { existsSync as existsSync4, readFileSync as readFileSync4, realpathSync as realpathSync2, statSync as statSync3 } from "fs";
122
+ import { homedir as homedir4 } from "os";
123
+ import { basename as basename4, dirname as dirname4, extname as extname2, isAbsolute as isAbsolute3, join as join5, parse as parse2, posix as posix2, relative as relative2, resolve as resolve6 } from "path";
116
124
 
117
125
  // src/lib/codewith-shared-todos-storage-standard.ts
118
126
  var CODEWITH_SHARED_TODOS_STORAGE_STANDARD_SLUG = "codewith-shared-todos-storage-standard";
@@ -8161,105 +8169,6 @@ function detectClaudeAuthorityConflicts(targetHome, ownedAuthorities = []) {
8161
8169
  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."
8162
8170
  }];
8163
8171
  }
8164
- // src/lib/raw-store-root.ts
8165
- import { resolve as resolve7 } from "path";
8166
-
8167
- // src/lib/app-home.ts
8168
- import { existsSync as existsSync4 } from "fs";
8169
- import { homedir as homedir4 } from "os";
8170
- import { join as join5, resolve as resolve6 } from "path";
8171
- import { homedir as pathsResolverHomedir2 } from "os";
8172
- import { join as pathsResolverJoin2 } from "path";
8173
- var PATHS_RESOLVER_KIND_ENV2 = {
8174
- config: "HASNA_CONFIG_HOME",
8175
- data: "HASNA_DATA_HOME",
8176
- state: "HASNA_STATE_HOME",
8177
- cache: "HASNA_CACHE_HOME"
8178
- };
8179
- var PATHS_RESOLVER_APP_SLUG_RE2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
8180
- function pathsResolverAssertApp2(app) {
8181
- if (typeof app !== "string" || app.length === 0) {
8182
- throw new TypeError("paths: app must be a non-empty string");
8183
- }
8184
- if (!PATHS_RESOLVER_APP_SLUG_RE2.test(app)) {
8185
- throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
8186
- }
8187
- }
8188
- function pathsResolverAssertKind2(kind) {
8189
- if (!Object.keys(PATHS_RESOLVER_KIND_ENV2).includes(kind)) {
8190
- throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV2).join(", ")}`);
8191
- }
8192
- }
8193
- function pathsResolverBaseDir2(kind, options) {
8194
- pathsResolverAssertKind2(kind);
8195
- const env = options.env ?? process.env;
8196
- const override = env[PATHS_RESOLVER_KIND_ENV2[kind]];
8197
- if (typeof override === "string" && override.length > 0)
8198
- return override;
8199
- const home = options.home ?? pathsResolverHomedir2();
8200
- const platform = options.platform ?? process.platform;
8201
- if (platform === "darwin") {
8202
- switch (kind) {
8203
- case "config":
8204
- case "data":
8205
- return pathsResolverJoin2(home, "Library", "Application Support", "Hasna");
8206
- case "cache":
8207
- return pathsResolverJoin2(home, "Library", "Caches", "Hasna");
8208
- case "state":
8209
- return pathsResolverJoin2(home, "Library", "Logs", "Hasna");
8210
- }
8211
- }
8212
- switch (kind) {
8213
- case "config":
8214
- return pathsResolverJoin2(home, ".config", "hasna");
8215
- case "data":
8216
- return pathsResolverJoin2(home, ".local", "share", "hasna");
8217
- case "state":
8218
- return pathsResolverJoin2(home, ".local", "state", "hasna");
8219
- case "cache":
8220
- return pathsResolverJoin2(home, ".cache", "hasna");
8221
- }
8222
- }
8223
- function pathsResolverResolve2(kind, options) {
8224
- pathsResolverAssertApp2(options.app);
8225
- const appSegment = options.internal === true ? pathsResolverJoin2("internal", options.app) : options.app;
8226
- return pathsResolverJoin2(pathsResolverBaseDir2(kind, options), appSegment);
8227
- }
8228
- function configDir(options) {
8229
- return pathsResolverResolve2("config", options);
8230
- }
8231
- var HASNA_CONFIGS_HOME_ENV = "HASNA_CONFIGS_HOME";
8232
- function homeDir3(env = process.env) {
8233
- return env["HOME"] || env["USERPROFILE"] || homedir4();
8234
- }
8235
- function legacyStoreHome(env = process.env) {
8236
- return resolve6(join5(homeDir3(env), ".hasna", "instructions"));
8237
- }
8238
- function resolverStoreHome(env = process.env) {
8239
- return configDir({ app: "configs", env, home: env.HOME || env.USERPROFILE || homedir4() });
8240
- }
8241
- function adoptResolverStoreHome(resolved, env = process.env) {
8242
- const override = env.HASNA_CONFIG_HOME;
8243
- if (typeof override === "string" && override.trim().length > 0)
8244
- return true;
8245
- return existsSync4(join5(resolved, "instructions.db"));
8246
- }
8247
- function exactStoreHome(env = process.env) {
8248
- const v = env[HASNA_CONFIGS_HOME_ENV];
8249
- return v && v.trim() ? v.trim() : undefined;
8250
- }
8251
- function getConfigsStoreHome(env = process.env) {
8252
- const exact = exactStoreHome(env);
8253
- if (exact)
8254
- return resolve6(exact);
8255
- const resolved = resolverStoreHome(env);
8256
- return adoptResolverStoreHome(resolved, env) ? resolve6(resolved) : legacyStoreHome(env);
8257
- }
8258
-
8259
- // src/lib/raw-store-root.ts
8260
- function getRawStoreRoot(env = process.env) {
8261
- return resolve7(getConfigsStoreHome(env));
8262
- }
8263
8172
 
8264
8173
  // src/lib/session-render.ts
8265
8174
  var ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000;
@@ -8542,13 +8451,13 @@ function yamlQuote2(value) {
8542
8451
  return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
8543
8452
  }
8544
8453
  function defaultTargetHome(tool, profile, sessionId) {
8545
- const home = process.env["HOME"] || homedir5();
8546
- return join6(home, ".hasna", "accounts", "profiles", tool, slug(profile));
8454
+ const home = process.env["HOME"] || homedir4();
8455
+ return join5(home, ".hasna", "accounts", "profiles", tool, slug(profile));
8547
8456
  }
8548
8457
  function joinTarget(targetHome, relativePath) {
8549
8458
  const safeTargetHome = assertSafeTargetRoot(targetHome);
8550
8459
  const safeRelativePath2 = assertSafeRelativePath(relativePath);
8551
- return join6(safeTargetHome, ...safeRelativePath2.split("/"));
8460
+ return join5(safeTargetHome, ...safeRelativePath2.split("/"));
8552
8461
  }
8553
8462
  function makeFile(targetHome, relativePath, role, content, sourceIds) {
8554
8463
  const safeTargetHome = assertSafeTargetRoot(targetHome);
@@ -9118,7 +9027,7 @@ function buildOpenCodeFiles(targetHome, adapter, profile, sources, providerConfi
9118
9027
  ...sources.flatMap((source) => source.resolvedRules.map((rule) => rule.id))
9119
9028
  ]);
9120
9029
  const existingConfigPath = joinTarget(targetHome, adapter.configFile);
9121
- const selectedConfig = existsSync5(existingConfigPath) ? readOpenCodeConfig(readFileSync4(existingConfigPath, "utf8"), existingConfigPath) : providerConfig ? readOpenCodeConfig(providerConfig.content, providerConfig.sourceId) : {};
9030
+ const selectedConfig = existsSync4(existingConfigPath) ? readOpenCodeConfig(readFileSync4(existingConfigPath, "utf8"), existingConfigPath) : providerConfig ? readOpenCodeConfig(providerConfig.content, providerConfig.sourceId) : {};
9122
9031
  const preservedInstructions = normalizeOpenCodeInstructions(selectedConfig["instructions"]).filter((path) => !pathIsManagedOpenCodeInstruction(path, adapter.managedDir));
9123
9032
  const config = {
9124
9033
  ...selectedConfig,
@@ -9321,7 +9230,7 @@ function adapterFor(input) {
9321
9230
  return gatedNativeImports ? CODEWITH_NATIVE_ADAPTER : CODEWITH_FLATTENED_ADAPTER;
9322
9231
  }
9323
9232
  function getHomeDir() {
9324
- return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir5();
9233
+ return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir4();
9325
9234
  }
9326
9235
  function cleanSessionPathInput(path) {
9327
9236
  const trimmed = path.trim();
@@ -9336,16 +9245,16 @@ function resolveSessionPath(path) {
9336
9245
  throw new Error("Session render path cannot be empty.");
9337
9246
  const home = getHomeDir();
9338
9247
  if (cleaned === "~")
9339
- return resolve8(home);
9248
+ return resolve6(home);
9340
9249
  if (cleaned.startsWith("~/"))
9341
- return resolve8(home, cleaned.slice(2));
9250
+ return resolve6(home, cleaned.slice(2));
9342
9251
  if (cleaned === "{{HOME}}" || cleaned === "${HOME}")
9343
- return resolve8(home);
9252
+ return resolve6(home);
9344
9253
  if (cleaned.startsWith("{{HOME}}/"))
9345
- return resolve8(home, cleaned.slice("{{HOME}}/".length));
9254
+ return resolve6(home, cleaned.slice("{{HOME}}/".length));
9346
9255
  if (cleaned.startsWith("${HOME}/"))
9347
- return resolve8(home, cleaned.slice("${HOME}/".length));
9348
- return resolve8(cleaned);
9256
+ return resolve6(home, cleaned.slice("${HOME}/".length));
9257
+ return resolve6(cleaned);
9349
9258
  }
9350
9259
  function assertSafeRelativePath(relativePath) {
9351
9260
  if (!relativePath.trim())
@@ -9361,7 +9270,7 @@ function assertSafeRelativePath(relativePath) {
9361
9270
  function assertSafeTargetRoot(targetHome) {
9362
9271
  if (!isAbsolute3(targetHome))
9363
9272
  throw new Error(`Session render target must be an absolute path: ${targetHome}`);
9364
- const normalized = resolve8(targetHome);
9273
+ const normalized = resolve6(targetHome);
9365
9274
  if (normalized === parse2(normalized).root) {
9366
9275
  throw new Error(`Session render target cannot be the filesystem root: ${targetHome}`);
9367
9276
  }
@@ -9596,7 +9505,7 @@ function planSessionRender(input) {
9596
9505
  sourceId: input.providerConfig.sourceId,
9597
9506
  selectedPayloadSha256: sha2565(input.providerConfig.content),
9598
9507
  renderedPayloadSha256: files.find((file) => file.relativePath === adapter.configFile)?.sha256 ?? sha2565(input.providerConfig.content),
9599
- selected: !existsSync5(joinTarget(targetHome, adapter.configFile))
9508
+ selected: !existsSync4(joinTarget(targetHome, adapter.configFile))
9600
9509
  }
9601
9510
  } : {},
9602
9511
  ...projectContext ? {
@@ -9879,7 +9788,7 @@ ${item.content.trimEnd()}`).join(`
9879
9788
  }
9880
9789
  function readIdentitySourcePath(sourcePath, baseDir, sourceId) {
9881
9790
  const resolvedPath = resolveIdentitySourcePath(sourcePath.path, baseDir, sourceId);
9882
- if (!existsSync5(resolvedPath)) {
9791
+ if (!existsSync4(resolvedPath)) {
9883
9792
  if (sourcePath.required) {
9884
9793
  throw new Error(`Required identity instruction source path not found for ${sourceId}: ${sourcePath.path}`);
9885
9794
  }
@@ -9902,8 +9811,8 @@ function resolveIdentitySourcePath(path, baseDir, sourceId) {
9902
9811
  throw new Error(`Identity instruction source path cannot be empty for ${sourceId}.`);
9903
9812
  if (cleaned.includes("\\"))
9904
9813
  throw new Error(`Identity instruction source path must use POSIX separators for ${sourceId}: ${path}`);
9905
- const resolvedPath = isAbsolute3(cleaned) ? resolve8(cleaned) : resolve8(baseDir, cleaned);
9906
- if (!pathIsInside(resolvedPath, resolve8(baseDir))) {
9814
+ const resolvedPath = isAbsolute3(cleaned) ? resolve6(cleaned) : resolve6(baseDir, cleaned);
9815
+ if (!pathIsInside(resolvedPath, resolve6(baseDir))) {
9907
9816
  throw new Error(`Identity instruction source path escapes export directory for ${sourceId}: ${path}`);
9908
9817
  }
9909
9818
  return resolvedPath;
@@ -10559,12 +10468,18 @@ function deepFreeze2(value) {
10559
10468
  return Object.freeze(value);
10560
10469
  }
10561
10470
 
10562
- // ../contracts/dist/client/transport.js
10471
+ // ../../node_modules/.bun/@hasna+contracts@1.0.2+e8014c875821e0be/node_modules/@hasna/contracts/dist/client/storage.js
10472
+ import { isIP } from "net";
10473
+ import { spawnSync } from "child_process";
10474
+ import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readFileSync as readFileSync5 } from "fs";
10475
+ import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
10563
10476
  import { createRequire } from "module";
10477
+ import { hostname as osHostname } from "os";
10478
+ import { isAbsolute as isAbsolute4, join as join6 } from "path";
10564
10479
  function envToken(name) {
10565
10480
  return name.toUpperCase().replace(/-/g, "_");
10566
10481
  }
10567
- function clientTransportEnvKeys(name) {
10482
+ function clientTransportEnvKeys2(name) {
10568
10483
  const envSegment = envToken(name);
10569
10484
  return {
10570
10485
  apiUrlKeys: [`HASNA_${envSegment}_API_URL`, `${envSegment}_API_URL`],
@@ -10578,46 +10493,6 @@ var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE";
10578
10493
  function credentialPointerEnvKey(name) {
10579
10494
  return `HASNA_${envToken(name)}_API_KEY_REF`;
10580
10495
  }
10581
- var MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
10582
- var INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
10583
- var CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
10584
- var AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
10585
- var SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
10586
- var requireSecretsSdk = createRequire(import.meta.url);
10587
- var IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
10588
- var AUTHORITY_OVERRIDE_HEADERS = new Set([
10589
- "host",
10590
- ":authority",
10591
- "forwarded",
10592
- "x-forwarded-host",
10593
- "x-original-host"
10594
- ]);
10595
-
10596
- // ../contracts/dist/client/storage.js
10597
- import { isIP } from "net";
10598
- import { spawnSync } from "child_process";
10599
- import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readFileSync as readFileSync5 } from "fs";
10600
- import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
10601
- import { createRequire as createRequire2 } from "module";
10602
- import { hostname as osHostname } from "os";
10603
- import { isAbsolute as isAbsolute4, join as join7 } from "path";
10604
- function envToken2(name) {
10605
- return name.toUpperCase().replace(/-/g, "_");
10606
- }
10607
- function clientTransportEnvKeys2(name) {
10608
- const envSegment = envToken2(name);
10609
- return {
10610
- apiUrlKeys: [`HASNA_${envSegment}_API_URL`, `${envSegment}_API_URL`],
10611
- apiKeyKeys: [`HASNA_${envSegment}_API_KEY`, `${envSegment}_API_KEY`]
10612
- };
10613
- }
10614
- function credentialOverrideEnvKey2(name) {
10615
- return `HASNA_${envToken2(name)}_API_KEY_OVERRIDE`;
10616
- }
10617
- var CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE";
10618
- function credentialPointerEnvKey2(name) {
10619
- return `HASNA_${envToken2(name)}_API_KEY_REF`;
10620
- }
10621
10496
 
10622
10497
  class CredentialResolutionError extends Error {
10623
10498
  appName;
@@ -10648,12 +10523,12 @@ var KEYCHAIN_SECURITY_BIN = "/usr/bin/security";
10648
10523
  var KEYCHAIN_SERVICE_PREFIX = "hasna.credentials";
10649
10524
  var KEYCHAIN_ITEM_NOT_FOUND_STATUS = 44;
10650
10525
  var KEYCHAIN_SPAWN_TIMEOUT_MS = 1e4;
10651
- var MAX_CREDENTIAL_FILE_BYTES2 = 64 * 1024;
10526
+ var MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
10652
10527
  var SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
10653
10528
  var SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
10654
10529
  var ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
10655
10530
  var VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
10656
- function homeDir4(env) {
10531
+ function homeDir3(env) {
10657
10532
  const home = env.HOME?.trim();
10658
10533
  return home ? home : null;
10659
10534
  }
@@ -10665,15 +10540,15 @@ function hasnaHomeDir(env) {
10665
10540
  const override = absoluteOverride(env, HASNA_HOME_ENV_KEY);
10666
10541
  if (override)
10667
10542
  return override;
10668
- const home = homeDir4(env);
10669
- return home ? join7(home, HASNA_HOME_DIR) : null;
10543
+ const home = homeDir3(env);
10544
+ return home ? join6(home, HASNA_HOME_DIR) : null;
10670
10545
  }
10671
10546
  function appConfigDir(name, env) {
10672
10547
  const configRoot = absoluteOverride(env, HASNA_CONFIG_HOME_ENV_KEY);
10673
10548
  if (configRoot)
10674
- return join7(configRoot, name);
10549
+ return join6(configRoot, name);
10675
10550
  const root = hasnaHomeDir(env);
10676
- return root ? join7(root, name, CONFIG_SUBDIR) : null;
10551
+ return root ? join6(root, name, CONFIG_SUBDIR) : null;
10677
10552
  }
10678
10553
  function credentialDiskSourceList(name, env, profile = null) {
10679
10554
  if (!SAFE_APP_SLUG.test(name))
@@ -10682,7 +10557,7 @@ function credentialDiskSourceList(name, env, profile = null) {
10682
10557
  if (!directory)
10683
10558
  return [];
10684
10559
  const file = profile ? `${CREDENTIALS_FILE}-${profile}` : CREDENTIALS_FILE;
10685
- return [{ path: join7(directory, file), tier: "disk" }];
10560
+ return [{ path: join6(directory, file), tier: "disk" }];
10686
10561
  }
10687
10562
  function credentialDiskSources(name, env) {
10688
10563
  return credentialDiskSourceList(name, env, null).map((s) => s.path);
@@ -10755,7 +10630,7 @@ function readAppConfigFile(path) {
10755
10630
  const uid = process.getuid?.() ?? process.geteuid?.();
10756
10631
  if (uid !== undefined && before.uid !== uid)
10757
10632
  unsafe("the file is not owned by the current user");
10758
- if (before.size > MAX_CREDENTIAL_FILE_BYTES2)
10633
+ if (before.size > MAX_CREDENTIAL_FILE_BYTES)
10759
10634
  unsafe("the file exceeds the size limit");
10760
10635
  const bytes = readFileSync5(fd);
10761
10636
  const after = fstatSync2(fd);
@@ -10810,14 +10685,14 @@ function appConfigDiskValue(name, env, keys) {
10810
10685
  }
10811
10686
  function assertUsableCredential(appName, source, value) {
10812
10687
  if (VAULT_POINTER_SHAPE.test(value)) {
10813
- throw new CredentialResolutionError(appName, `The credential from ${source} looks like a secrets-vault pointer (a path-shaped reference like ` + `'namespace/app/live/api_key'). A vault path is NEVER accepted as a literal API key. ` + `Use ${credentialPointerEnvKey2(appName)} to resolve the key through the vault, or provide the actual key value.`, [source]);
10688
+ throw new CredentialResolutionError(appName, `The credential from ${source} looks like a secrets-vault pointer (a path-shaped reference like ` + `'namespace/app/live/api_key'). A vault path is NEVER accepted as a literal API key. ` + `Use ${credentialPointerEnvKey(appName)} to resolve the key through the vault, or provide the actual key value.`, [source]);
10814
10689
  }
10815
10690
  if (!ILLEGAL_IN_HEADER_VALUE.test(value))
10816
10691
  return;
10817
10692
  throw new CredentialResolutionError(appName, `The credential from ${source} contains characters that cannot be sent in an HTTP header ` + `(a control character or non-ASCII byte). A file written with CR-only line endings is the usual ` + `cause. Rewrite that credential file with one LF-terminated KEY=value line. ` + `The value is not shown here, and is deliberately never logged.`, [source]);
10818
10693
  }
10819
- var INSPECT_CUSTOM2 = Symbol.for("nodejs.util.inspect.custom");
10820
- var CREDENTIAL_SEAL2 = Symbol.for("hasna:contracts:sealedCredential");
10694
+ var INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
10695
+ var CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
10821
10696
  var CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider";
10822
10697
  function sealCredential(fields) {
10823
10698
  const { apiKey } = fields;
@@ -10843,13 +10718,13 @@ function sealCredential(fields) {
10843
10718
  configurable: false
10844
10719
  });
10845
10720
  }
10846
- Object.defineProperty(sealed, INSPECT_CUSTOM2, {
10721
+ Object.defineProperty(sealed, INSPECT_CUSTOM, {
10847
10722
  value: () => ({ ...visible, apiKey: "[redacted]" }),
10848
10723
  enumerable: false,
10849
10724
  writable: false,
10850
10725
  configurable: false
10851
10726
  });
10852
- Object.defineProperty(sealed, CREDENTIAL_SEAL2, {
10727
+ Object.defineProperty(sealed, CREDENTIAL_SEAL, {
10853
10728
  value: true,
10854
10729
  enumerable: false,
10855
10730
  writable: false,
@@ -10858,7 +10733,7 @@ function sealCredential(fields) {
10858
10733
  return Object.freeze(sealed);
10859
10734
  }
10860
10735
  function isSealedCredential(credential) {
10861
- return credential[CREDENTIAL_SEAL2] === true;
10736
+ return credential[CREDENTIAL_SEAL] === true;
10862
10737
  }
10863
10738
  function explicitCredential(appName, apiKey) {
10864
10739
  const source = "explicit apiKey option";
@@ -10905,9 +10780,9 @@ function firstEnvValue(env, keys) {
10905
10780
  }
10906
10781
  return null;
10907
10782
  }
10908
- var AMBIENT_ENVIRONMENT2 = Symbol.for("hasna:contracts:ambientClientEnvironment");
10783
+ var AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
10909
10784
  function isAmbientEnvironment(env) {
10910
- return env === process.env || env[AMBIENT_ENVIRONMENT2] === true;
10785
+ return env === process.env || env[AMBIENT_ENVIRONMENT] === true;
10911
10786
  }
10912
10787
  function defaultKeychainRunner(argv) {
10913
10788
  const result = spawnSync(KEYCHAIN_SECURITY_BIN, [...argv], {
@@ -10980,9 +10855,9 @@ function snapshotClientEnvironment(name, env) {
10980
10855
  for (const key of [
10981
10856
  ...keys.apiUrlKeys,
10982
10857
  ...keys.apiKeyKeys,
10983
- credentialOverrideEnvKey2(name),
10984
- credentialPointerEnvKey2(name),
10985
- CREDENTIAL_PROFILE_ENV_KEY2,
10858
+ credentialOverrideEnvKey(name),
10859
+ credentialPointerEnvKey(name),
10860
+ CREDENTIAL_PROFILE_ENV_KEY,
10986
10861
  "HOME",
10987
10862
  HASNA_HOME_ENV_KEY,
10988
10863
  HASNA_CONFIG_HOME_ENV_KEY,
@@ -11001,7 +10876,7 @@ function snapshotClientEnvironment(name, env) {
11001
10876
  snapshot[key] = descriptor.value;
11002
10877
  }
11003
10878
  if (ambient) {
11004
- Object.defineProperty(snapshot, AMBIENT_ENVIRONMENT2, {
10879
+ Object.defineProperty(snapshot, AMBIENT_ENVIRONMENT, {
11005
10880
  value: true,
11006
10881
  enumerable: false,
11007
10882
  writable: false,
@@ -11029,7 +10904,7 @@ function resolveCredential(name, env, options = {}) {
11029
10904
  warning: null
11030
10905
  });
11031
10906
  }
11032
- const overrideKeyName = credentialOverrideEnvKey2(name);
10907
+ const overrideKeyName = credentialOverrideEnvKey(name);
11033
10908
  const overrideRaw = Object.prototype.hasOwnProperty.call(env, overrideKeyName) ? env[overrideKeyName] : undefined;
11034
10909
  if (overrideRaw !== undefined) {
11035
10910
  const override = overrideRaw.trim();
@@ -11046,7 +10921,7 @@ function resolveCredential(name, env, options = {}) {
11046
10921
  warning: null
11047
10922
  });
11048
10923
  }
11049
- const pointerKeyName = credentialPointerEnvKey2(name);
10924
+ const pointerKeyName = credentialPointerEnvKey(name);
11050
10925
  const pointerRaw = Object.prototype.hasOwnProperty.call(env, pointerKeyName) ? env[pointerKeyName] : undefined;
11051
10926
  if (pointerRaw !== undefined) {
11052
10927
  const pointer = pointerRaw.trim();
@@ -11069,13 +10944,13 @@ function resolveCredential(name, env, options = {}) {
11069
10944
  if (options.profile !== undefined && !options.profile.trim()) {
11070
10945
  throw new CredentialResolutionError(name, "The explicit profile argument is blank; an explicit identity selection never falls through.", ["explicit profile argument"]);
11071
10946
  }
11072
- const profileRaw = Object.prototype.hasOwnProperty.call(env, CREDENTIAL_PROFILE_ENV_KEY2) ? env[CREDENTIAL_PROFILE_ENV_KEY2] : undefined;
10947
+ const profileRaw = Object.prototype.hasOwnProperty.call(env, CREDENTIAL_PROFILE_ENV_KEY) ? env[CREDENTIAL_PROFILE_ENV_KEY] : undefined;
11073
10948
  if (profileRaw !== undefined && !profileRaw.trim()) {
11074
- throw new CredentialResolutionError(name, `${CREDENTIAL_PROFILE_ENV_KEY2} is set but blank.`, [CREDENTIAL_PROFILE_ENV_KEY2]);
10949
+ throw new CredentialResolutionError(name, `${CREDENTIAL_PROFILE_ENV_KEY} is set but blank.`, [CREDENTIAL_PROFILE_ENV_KEY]);
11075
10950
  }
11076
10951
  const profile = options.profile?.trim() || profileRaw?.trim();
11077
10952
  if (profile) {
11078
- const profileSource = options.profile?.trim() ? "explicit profile argument" : CREDENTIAL_PROFILE_ENV_KEY2;
10953
+ const profileSource = options.profile?.trim() ? "explicit profile argument" : CREDENTIAL_PROFILE_ENV_KEY;
11079
10954
  if (!SAFE_PROFILE.test(profile)) {
11080
10955
  throw new CredentialResolutionError(name, `Profile name from ${profileSource} is not usable in a path. ` + `Use letters, digits, dot, dash, or underscore.`, [profileSource]);
11081
10956
  }
@@ -11094,7 +10969,7 @@ function resolveCredential(name, env, options = {}) {
11094
10969
  });
11095
10970
  }
11096
10971
  }
11097
- throw new CredentialResolutionError(name, `Profile '${profile}' (from ${profileSource}) has no ${apiKeyKeys[0]} for '${name}'. ` + `Looked in: ${paths.join(", ") || "<no HOME in this environment>"}. ` + `A profile names WHICH identity to use, so it is never resolved around \u2014 ` + `create the profile's credential file or unset ${CREDENTIAL_PROFILE_ENV_KEY2}.`, paths);
10972
+ throw new CredentialResolutionError(name, `Profile '${profile}' (from ${profileSource}) has no ${apiKeyKeys[0]} for '${name}'. ` + `Looked in: ${paths.join(", ") || "<no HOME in this environment>"}. ` + `A profile names WHICH identity to use, so it is never resolved around \u2014 ` + `create the profile's credential file or unset ${CREDENTIAL_PROFILE_ENV_KEY}.`, paths);
11098
10973
  }
11099
10974
  const definedEnvEntries = apiKeyKeys.filter((key) => Object.prototype.hasOwnProperty.call(env, key) && env[key] !== undefined).map((key) => ({ key, value: String(env[key]).trim() }));
11100
10975
  const blankEnv = definedEnvEntries.find((entry) => entry.value.length === 0);
@@ -11150,8 +11025,8 @@ function resolveCredential(name, env, options = {}) {
11150
11025
  }
11151
11026
  return null;
11152
11027
  }
11153
- var SECRETS_PACKAGE_SPECIFIER2 = "@hasna/" + "secrets";
11154
- var requireSecretsSdk2 = createRequire2(import.meta.url);
11028
+ var SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
11029
+ var requireSecretsSdk = createRequire(import.meta.url);
11155
11030
  async function completePointerCredential(name, pointerResolution, env = process.env) {
11156
11031
  const vaultKey = pointerResolution.pointerVaultKey;
11157
11032
  const pointerEnvKey = pointerResolution.source;
@@ -11160,7 +11035,7 @@ async function completePointerCredential(name, pointerResolution, env = process.
11160
11035
  }
11161
11036
  let secretsSdk;
11162
11037
  try {
11163
- secretsSdk = requireSecretsSdk2(SECRETS_PACKAGE_SPECIFIER2);
11038
+ secretsSdk = requireSecretsSdk(SECRETS_PACKAGE_SPECIFIER);
11164
11039
  } catch {
11165
11040
  throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets SDK (@hasna/secrets) is not installed ` + `in this process. A vault pointer is TERMINAL: install @hasna/secrets to resolve it, or unset ${pointerEnvKey}.`, [pointerEnvKey]);
11166
11041
  }
@@ -11457,8 +11332,8 @@ function authFailureGuidance(credential) {
11457
11332
  return `${origin}, which was re-read from disk on this very call \u2014 so a stale shell is NOT the cause here. ` + `The stored credential is genuinely being rejected: rotate it, or re-run the fleet key distribution ` + `so this machine gets the current key.`;
11458
11333
  }
11459
11334
  var DEFAULT_RETRY_STATUSES = [408, 425, 429, 500, 502, 503, 504];
11460
- var IDEMPOTENT_METHODS2 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
11461
- var AUTHORITY_OVERRIDE_HEADERS2 = new Set([
11335
+ var IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
11336
+ var AUTHORITY_OVERRIDE_HEADERS = new Set([
11462
11337
  "host",
11463
11338
  ":authority",
11464
11339
  "forwarded",
@@ -11468,7 +11343,7 @@ var AUTHORITY_OVERRIDE_HEADERS2 = new Set([
11468
11343
  function assertNoAuthorityOverrideHeaders(headers, source) {
11469
11344
  if (!headers)
11470
11345
  return;
11471
- const forbidden = Object.keys(headers).find((name) => AUTHORITY_OVERRIDE_HEADERS2.has(name.trim().toLowerCase()));
11346
+ const forbidden = Object.keys(headers).find((name) => AUTHORITY_OVERRIDE_HEADERS.has(name.trim().toLowerCase()));
11472
11347
  if (forbidden) {
11473
11348
  throw new Error(`Authenticated ${source} headers must not set authority header '${forbidden}'.`);
11474
11349
  }
@@ -11494,7 +11369,7 @@ function appendQuery(path, query) {
11494
11369
  return path;
11495
11370
  return `${path}${path.includes("?") ? "&" : "?"}${qs}`;
11496
11371
  }
11497
- var defaultSleep = (ms) => new Promise((resolve9) => setTimeout(resolve9, ms));
11372
+ var defaultSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
11498
11373
  function createHasnaHttpTransportInternal(options, requestBindingProvider) {
11499
11374
  const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
11500
11375
  const base = toV1BaseUrl(options.baseUrl);
@@ -11602,7 +11477,7 @@ function createHasnaHttpTransportInternal(options, requestBindingProvider) {
11602
11477
  const upper = method.toUpperCase();
11603
11478
  const rel = appendQuery(path.startsWith("/") ? path : `/${path}`, opts.query);
11604
11479
  const retry = resolveRetry(opts.retry);
11605
- const methodRetryable = IDEMPOTENT_METHODS2.has(upper) || Boolean(opts.idempotencyKey);
11480
+ const methodRetryable = IDEMPOTENT_METHODS.has(upper) || Boolean(opts.idempotencyKey);
11606
11481
  const maxAttempts = retry && methodRetryable ? retry.retries + 1 : 1;
11607
11482
  const binding = requestBindingProvider ? await requestBindingProvider() : {
11608
11483
  baseUrl: base,
@@ -11779,56 +11654,6 @@ function resolveStorageClient(name, env = process.env, overrides) {
11779
11654
  return { transport: "http", client: createHasnaStorageClient(name, wired.client) };
11780
11655
  }
11781
11656
 
11782
- // src/lib/local-opt-in.ts
11783
- var INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS = ["HASNA_INSTRUCTIONS_LOCAL"];
11784
- function instructionsLocalModeNotice() {
11785
- return `instructions: local mode \u2014 ${INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS[0]}=1 selects the on-box SQLite store, ` + `and no hosted authority was configured. Set HASNA_INSTRUCTIONS_API_KEY (or add the Keychain item ` + `hasna.credentials.instructions.api-key, or write ~/.hasna/instructions/config/credentials) to go hosted.`;
11786
- }
11787
- function isInstructionsLocalOptIn(env = process.env) {
11788
- return INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS.some((key) => (env[key] ?? "").trim() === "1");
11789
- }
11790
- function instructionsAuthorityEnvKeys() {
11791
- const keys = clientTransportEnvKeys("instructions");
11792
- return [
11793
- ...keys.apiUrlKeys,
11794
- ...keys.apiKeyKeys,
11795
- credentialOverrideEnvKey("instructions"),
11796
- credentialPointerEnvKey("instructions"),
11797
- CREDENTIAL_PROFILE_ENV_KEY
11798
- ];
11799
- }
11800
- function hasInstructionsEnvAuthorityIntent(env = process.env) {
11801
- return instructionsAuthorityEnvKeys().some((key) => (env[key] ?? "").trim() !== "");
11802
- }
11803
- function selectsInstructionsLocalStore(env = process.env) {
11804
- return !hasInstructionsEnvAuthorityIntent(env) && isInstructionsLocalOptIn(env);
11805
- }
11806
- function instructionsResolverEnv(env) {
11807
- const blanks = instructionsAuthorityEnvKeys().filter((key) => (key in env) && (env[key] ?? "").trim() === "");
11808
- if (blanks.length === 0)
11809
- return env;
11810
- const next = { ...env };
11811
- for (const key of blanks)
11812
- delete next[key];
11813
- return next;
11814
- }
11815
- var CONTRACTS_AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
11816
- function isAmbientInstructionsEnv(env) {
11817
- if (typeof process !== "undefined" && env === process.env)
11818
- return true;
11819
- return env[CONTRACTS_AMBIENT_ENVIRONMENT] === true;
11820
- }
11821
- function instructionsResolverInputs(env, credentials = {}) {
11822
- const normalised = instructionsResolverEnv(env);
11823
- if (normalised === env)
11824
- return { env: normalised, credentials };
11825
- const keychain = { ...credentials.keychain };
11826
- if (keychain.enabled === undefined && keychain.run === undefined) {
11827
- keychain.enabled = isAmbientInstructionsEnv(env);
11828
- }
11829
- return { env: normalised, credentials: { ...credentials, keychain } };
11830
- }
11831
-
11832
11657
  // src/lib/transport-resolver.ts
11833
11658
  var INSTRUCTIONS_APP = "instructions";
11834
11659
  var INSTRUCTIONS_LOCAL_OPT_IN_ENV = INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS[0];
@@ -11871,11 +11696,11 @@ function announceLocalInstructionsMode(write = (line) => process.stderr.write(`$
11871
11696
  }
11872
11697
 
11873
11698
  // src/data/config-store.ts
11874
- function parseBoundedPagePayload(value, label) {
11699
+ function parseBoundedPagePayload(value, label, expected) {
11875
11700
  const page = value;
11876
11701
  const consumed = Number(page?.cursor) + (page?.items?.length ?? 0);
11877
11702
  const complete = Boolean(page && Number.isSafeInteger(page.total) && consumed >= Number(page.total));
11878
- if (!page || !Array.isArray(page.items) || !Number.isSafeInteger(page.total) || Number(page.total) < 0 || !Number.isSafeInteger(page.limit) || Number(page.limit) < 1 || !Number.isSafeInteger(page.cursor) || Number(page.cursor) < 0 || page.items.length > Number(page.limit) || typeof page.has_more !== "boolean" || typeof page.complete !== "boolean" || page.truncated !== false || page.next_cursor !== null && !Number.isSafeInteger(page.next_cursor) || page.complete !== complete || page.has_more !== !complete || page.next_cursor !== (complete ? null : consumed)) {
11703
+ if (!page || !Array.isArray(page.items) || !Number.isSafeInteger(page.total) || Number(page.total) < 0 || !Number.isSafeInteger(page.limit) || Number(page.limit) < 1 || !Number.isSafeInteger(page.cursor) || Number(page.cursor) < 0 || page.items.length > Number(page.limit) || typeof page.has_more !== "boolean" || typeof page.complete !== "boolean" || page.truncated !== false || page.next_cursor !== null && !Number.isSafeInteger(page.next_cursor) || page.complete !== complete || page.has_more !== !complete || page.next_cursor !== (complete ? null : consumed) || expected !== undefined && Number(page.cursor) !== expected.cursor) {
11879
11704
  throw new Error(`${label} returned an invalid or truncated bounded-read envelope`);
11880
11705
  }
11881
11706
  return {
@@ -11887,7 +11712,7 @@ function parseBoundedOrLegacyPage(value, legacyItems, options, label) {
11887
11712
  if (value && typeof value === "object") {
11888
11713
  const candidate = value;
11889
11714
  if ("items" in candidate || "total" in candidate || "complete" in candidate || "truncated" in candidate || "next_cursor" in candidate) {
11890
- return parseBoundedPagePayload(value, label);
11715
+ return parseBoundedPagePayload(value, label, normalizeBoundedReadOptions(options));
11891
11716
  }
11892
11717
  }
11893
11718
  if (!Array.isArray(legacyItems)) {
@@ -11897,6 +11722,78 @@ function parseBoundedOrLegacyPage(value, legacyItems, options, label) {
11897
11722
  const page = boundedReadPage(legacyItems.slice(normalized.cursor, normalized.cursor + normalized.limit), legacyItems.length, normalized);
11898
11723
  return { ...page, source_bounded: false };
11899
11724
  }
11725
+ function projectBoundedPage(page, project) {
11726
+ return {
11727
+ items: page.items.map(project),
11728
+ total: page.total,
11729
+ limit: page.limit,
11730
+ cursor: page.cursor,
11731
+ next_cursor: page.next_cursor,
11732
+ has_more: page.has_more,
11733
+ complete: page.complete,
11734
+ truncated: page.truncated,
11735
+ source_bounded: page.source_bounded
11736
+ };
11737
+ }
11738
+
11739
+ class CollectionChangedWhilePagingError extends Error {
11740
+ constructor(label, detail) {
11741
+ super(`${label} changed while paging: ${detail}`);
11742
+ this.name = "CollectionChangedWhilePagingError";
11743
+ }
11744
+ }
11745
+ var COLLECTION_READ_ATTEMPTS = 2;
11746
+ async function aggregateBoundedCollection(label, readPage, identity, options = {}) {
11747
+ let lastError = null;
11748
+ for (let attempt = 0;attempt < COLLECTION_READ_ATTEMPTS; attempt += 1) {
11749
+ try {
11750
+ const items = [];
11751
+ const seen = new Set;
11752
+ let expectedTotal = null;
11753
+ let cursor = 0;
11754
+ let previousIdentity = null;
11755
+ while (true) {
11756
+ const page = await readPage(cursor);
11757
+ if (page.cursor !== cursor) {
11758
+ throw new CollectionChangedWhilePagingError(label, `server returned cursor ${page.cursor} for requested cursor ${cursor}`);
11759
+ }
11760
+ if (expectedTotal === null)
11761
+ expectedTotal = page.total;
11762
+ else if (page.total !== expectedTotal) {
11763
+ throw new CollectionChangedWhilePagingError(label, `total changed from ${expectedTotal} to ${page.total}`);
11764
+ }
11765
+ for (const item of page.items) {
11766
+ const key = identity(item);
11767
+ if (!key)
11768
+ throw new CollectionChangedWhilePagingError(label, "an item had no stable identity");
11769
+ if (seen.has(key))
11770
+ throw new CollectionChangedWhilePagingError(label, `duplicate identity ${key}`);
11771
+ if (options.requireAscendingIdentity && page.source_bounded && previousIdentity !== null && key <= previousIdentity) {
11772
+ throw new CollectionChangedWhilePagingError(label, `identity order was not strictly increasing at ${key}`);
11773
+ }
11774
+ seen.add(key);
11775
+ previousIdentity = key;
11776
+ items.push(item);
11777
+ }
11778
+ if (page.complete) {
11779
+ if (items.length !== expectedTotal) {
11780
+ throw new CollectionChangedWhilePagingError(label, `received ${items.length} unique rows for total ${expectedTotal}`);
11781
+ }
11782
+ return items;
11783
+ }
11784
+ if (page.next_cursor === null || page.next_cursor <= cursor) {
11785
+ throw new CollectionChangedWhilePagingError(label, `cursor did not advance from ${cursor}`);
11786
+ }
11787
+ cursor = page.next_cursor;
11788
+ }
11789
+ } catch (error) {
11790
+ if (!(error instanceof CollectionChangedWhilePagingError))
11791
+ throw error;
11792
+ lastError = error;
11793
+ }
11794
+ }
11795
+ throw lastError ?? new CollectionChangedWhilePagingError(label, "read did not stabilize");
11796
+ }
11900
11797
  var LOCAL_OPT_IN_ENV = INSTRUCTIONS_LOCAL_OPT_IN_ENV;
11901
11798
  function isCloudAuthError(err) {
11902
11799
  return typeof err === "object" && err !== null && err.name === "HasnaHttpError" && (err.status === 401 || err.status === 403);
@@ -11922,7 +11819,7 @@ function formatCliError(err, env = process.env) {
11922
11819
  var localStoreModulePromise = null;
11923
11820
  function localStoreModule() {
11924
11821
  if (!localStoreModulePromise)
11925
- localStoreModulePromise = import("./local-0d8qrc92.js");
11822
+ localStoreModulePromise = import("./local-969ye538.js");
11926
11823
  return localStoreModulePromise;
11927
11824
  }
11928
11825
 
@@ -11936,6 +11833,15 @@ class LocalConfigStore {
11936
11833
  async listConfigs(filter) {
11937
11834
  return (await localStoreModule()).listConfigs(filter, this.db);
11938
11835
  }
11836
+ async listConfigsPage(filter = {}, options = {}) {
11837
+ return (await localStoreModule()).listConfigsPage(filter, options, this.db);
11838
+ }
11839
+ async listConfigIdentitiesPage(filter = {}, options = {}) {
11840
+ return (await localStoreModule()).listConfigIdentitiesPage(filter, options, this.db);
11841
+ }
11842
+ async listConfigSummariesPage(filter = {}, options = {}) {
11843
+ return (await localStoreModule()).listConfigSummariesPage(filter, options, this.db);
11844
+ }
11939
11845
  async getConfig(idOrSlug) {
11940
11846
  return (await localStoreModule()).getConfig(idOrSlug, this.db);
11941
11847
  }
@@ -11970,15 +11876,7 @@ class LocalConfigStore {
11970
11876
  return (await localStoreModule()).pruneSnapshots(configId, keep, this.db);
11971
11877
  }
11972
11878
  async listProfiles() {
11973
- const profiles = [];
11974
- let cursor = 0;
11975
- while (true) {
11976
- const page = await this.listProfilesPage({ limit: 100, cursor });
11977
- profiles.push(...page.items);
11978
- if (page.complete)
11979
- return profiles;
11980
- cursor = page.next_cursor;
11981
- }
11879
+ return aggregateBoundedCollection("profile list", (cursor) => this.listProfilesPage({ limit: 100, cursor }), (profile) => profile.id);
11982
11880
  }
11983
11881
  async listProfilesPage(options = {}) {
11984
11882
  return (await localStoreModule()).listProfilesPage(options, this.db);
@@ -11987,15 +11885,7 @@ class LocalConfigStore {
11987
11885
  return (await localStoreModule()).getProfile(idOrSlug, this.db);
11988
11886
  }
11989
11887
  async getProfileConfigs(idOrSlug) {
11990
- const configs = [];
11991
- let cursor = 0;
11992
- while (true) {
11993
- const page = await this.getProfileConfigsPage(idOrSlug, { limit: 100, cursor });
11994
- configs.push(...page.items);
11995
- if (page.complete)
11996
- return configs;
11997
- cursor = page.next_cursor;
11998
- }
11888
+ return aggregateBoundedCollection("profile membership", (cursor) => this.getProfileConfigsPage(idOrSlug, { limit: 100, cursor }), (config) => config.id);
11999
11889
  }
12000
11890
  async getProfileConfigsPage(idOrSlug, options = {}) {
12001
11891
  return (await localStoreModule()).getProfileConfigsPage(idOrSlug, options, this.db);
@@ -12055,6 +11945,43 @@ class LocalConfigStore {
12055
11945
  (await localStoreModule()).resetLocalDatabase();
12056
11946
  }
12057
11947
  }
11948
+ function toConfigIdentity(value) {
11949
+ const record = value && typeof value === "object" ? value : {};
11950
+ return {
11951
+ id: String(record.id ?? ""),
11952
+ name: String(record.name ?? ""),
11953
+ slug: String(record.slug ?? ""),
11954
+ kind: String(record.kind ?? ""),
11955
+ category: String(record.category ?? ""),
11956
+ agent: String(record.agent ?? ""),
11957
+ format: String(record.format ?? ""),
11958
+ is_template: Boolean(record.is_template),
11959
+ version: Number(record.version ?? 0),
11960
+ created_at: String(record.created_at ?? ""),
11961
+ updated_at: String(record.updated_at ?? ""),
11962
+ synced_at: record.synced_at == null ? null : String(record.synced_at)
11963
+ };
11964
+ }
11965
+ function toConfigSummary(value) {
11966
+ const record = value && typeof value === "object" ? value : {};
11967
+ const outputs = Array.isArray(record.outputs) ? record.outputs : [];
11968
+ return {
11969
+ id: String(record.id ?? ""),
11970
+ slug: String(record.slug ?? ""),
11971
+ name: String(record.name ?? ""),
11972
+ category: String(record.category ?? ""),
11973
+ agent: String(record.agent ?? ""),
11974
+ kind: String(record.kind ?? ""),
11975
+ format: String(record.format ?? ""),
11976
+ target_path: record.target_path == null ? null : String(record.target_path),
11977
+ output_count: Number(record.output_count ?? outputs.length),
11978
+ version: Number(record.version ?? 0),
11979
+ is_template: Boolean(record.is_template),
11980
+ ...record.updated_at !== undefined ? { updated_at: String(record.updated_at) } : {},
11981
+ ...record.description !== undefined ? { description: record.description == null ? null : String(record.description) } : {},
11982
+ ...Array.isArray(record.tags) ? { tags: record.tags.map(String) } : {}
11983
+ };
11984
+ }
12058
11985
 
12059
11986
  class CloudConfigStore {
12060
11987
  mode = "api";
@@ -12076,7 +12003,8 @@ class CloudConfigStore {
12076
12003
  throw err;
12077
12004
  }
12078
12005
  }
12079
- async listConfigs(filter = {}) {
12006
+ async listConfigsPage(filter = {}, options = {}) {
12007
+ const normalized = normalizeBoundedReadOptions(options);
12080
12008
  const params = new URLSearchParams;
12081
12009
  if (filter.category)
12082
12010
  params.set("category", filter.category);
@@ -12086,16 +12014,75 @@ class CloudConfigStore {
12086
12014
  params.set("kind", filter.kind);
12087
12015
  if (filter.search)
12088
12016
  params.set("search", filter.search);
12089
- const qs = params.toString();
12090
- const { data } = await this.request("GET", `/configs${qs ? `?${qs}` : ""}`);
12091
- let configs = data?.configs ?? [];
12017
+ for (const tag of filter.tags ?? [])
12018
+ params.append("tag", tag);
12019
+ params.set("limit", String(normalized.limit));
12020
+ params.set("cursor", String(normalized.cursor));
12021
+ const { data } = await this.request("GET", `/configs?${params.toString()}`);
12022
+ return parseBoundedOrLegacyPage(data, data?.configs, normalized, "config list");
12023
+ }
12024
+ async listConfigIdentitiesPage(filter = {}, options = {}) {
12025
+ const normalized = normalizeBoundedReadOptions(options);
12026
+ const params = new URLSearchParams;
12027
+ if (filter.category)
12028
+ params.set("category", filter.category);
12029
+ if (filter.agent)
12030
+ params.set("agent", filter.agent);
12031
+ if (filter.kind)
12032
+ params.set("kind", filter.kind);
12033
+ if (filter.search)
12034
+ params.set("search", filter.search);
12035
+ for (const tag of filter.tags ?? [])
12036
+ params.append("tag", tag);
12037
+ params.set("view", "identity");
12038
+ params.set("limit", String(normalized.limit));
12039
+ params.set("cursor", String(normalized.cursor));
12040
+ const { data } = await this.request("GET", `/configs?${params.toString()}`);
12041
+ const page = parseBoundedOrLegacyPage(data, data?.configs, normalized, "config identity list");
12042
+ if (page.items.some((item) => {
12043
+ const record = item && typeof item === "object" ? item : {};
12044
+ return ["content", "target_path", "outputs", "description", "tags"].some((field) => Object.prototype.hasOwnProperty.call(record, field));
12045
+ })) {
12046
+ throw new Error("Instructions /v1 config identity projection is unavailable; deploy the identity endpoint before using compact lists");
12047
+ }
12048
+ return projectBoundedPage(page, toConfigIdentity);
12049
+ }
12050
+ async listConfigSummariesPage(filter = {}, options = {}) {
12051
+ const normalized = normalizeBoundedReadOptions(options);
12052
+ const params = new URLSearchParams;
12053
+ if (filter.category)
12054
+ params.set("category", filter.category);
12055
+ if (filter.agent)
12056
+ params.set("agent", filter.agent);
12057
+ if (filter.kind)
12058
+ params.set("kind", filter.kind);
12059
+ if (filter.search)
12060
+ params.set("search", filter.search);
12061
+ for (const tag of filter.tags ?? [])
12062
+ params.append("tag", tag);
12063
+ params.set("view", "summary");
12064
+ params.set("limit", String(normalized.limit));
12065
+ params.set("cursor", String(normalized.cursor));
12066
+ const { data } = await this.request("GET", `/configs?${params.toString()}`);
12067
+ const page = parseBoundedOrLegacyPage(data, data?.configs, normalized, "config summary list");
12068
+ if (page.items.some((item) => {
12069
+ const record = item && typeof item === "object" ? item : {};
12070
+ return Object.prototype.hasOwnProperty.call(record, "content") || Object.prototype.hasOwnProperty.call(record, "outputs");
12071
+ })) {
12072
+ throw new Error("Instructions /v1 config summary projection is unavailable; deploy the summary endpoint before using summary lists");
12073
+ }
12074
+ return projectBoundedPage(page, toConfigSummary);
12075
+ }
12076
+ async listConfigs(filter = {}) {
12077
+ const configs = await aggregateBoundedCollection("config list", (cursor) => this.listConfigsPage(filter, { limit: 100, cursor }), (config) => config.id, { requireAscendingIdentity: true });
12078
+ let filtered = configs;
12092
12079
  if (filter.tags && filter.tags.length > 0) {
12093
- configs = configs.filter((c) => filter.tags.every((t) => c.tags.includes(t)));
12080
+ filtered = filtered.filter((config) => filter.tags.every((tag) => config.tags.includes(tag)));
12094
12081
  }
12095
12082
  if (filter.is_template !== undefined) {
12096
- configs = configs.filter((c) => c.is_template === filter.is_template);
12083
+ filtered = filtered.filter((config) => config.is_template === filter.is_template);
12097
12084
  }
12098
- return configs;
12085
+ return filtered;
12099
12086
  }
12100
12087
  async getConfig(idOrSlug) {
12101
12088
  const { status, data } = await this.request("GET", `/configs/${encodeURIComponent(idOrSlug)}`, undefined, { allow404: true });
@@ -12126,8 +12113,11 @@ class CloudConfigStore {
12126
12113
  return data ?? { total: 0 };
12127
12114
  }
12128
12115
  async listSnapshots(configId) {
12129
- const { data } = await this.request("GET", `/configs/${encodeURIComponent(configId)}/snapshots`);
12130
- return data?.snapshots ?? [];
12116
+ return aggregateBoundedCollection("snapshot list", async (cursor) => {
12117
+ const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
12118
+ const { data } = await this.request("GET", `/configs/${encodeURIComponent(configId)}/snapshots?limit=${normalized.limit}&cursor=${normalized.cursor}`);
12119
+ return parseBoundedOrLegacyPage(data, data?.snapshots, normalized, "snapshot list");
12120
+ }, (snapshot) => snapshot.id);
12131
12121
  }
12132
12122
  async getSnapshot(id) {
12133
12123
  const { status, data } = await this.request("GET", `/snapshots/${encodeURIComponent(id)}`, undefined, { allow404: true });
@@ -12150,15 +12140,7 @@ class CloudConfigStore {
12150
12140
  return data?.pruned ?? 0;
12151
12141
  }
12152
12142
  async listProfiles() {
12153
- const profiles = [];
12154
- let cursor = 0;
12155
- while (true) {
12156
- const page = await this.listProfilesPage({ limit: 100, cursor });
12157
- profiles.push(...page.items);
12158
- if (page.complete)
12159
- return profiles;
12160
- cursor = page.next_cursor;
12161
- }
12143
+ return aggregateBoundedCollection("profile list", (cursor) => this.listProfilesPage({ limit: 100, cursor }), (profile) => profile.id);
12162
12144
  }
12163
12145
  async listProfilesPage(options = {}) {
12164
12146
  const normalized = normalizeBoundedReadOptions(options);
@@ -12182,15 +12164,7 @@ class CloudConfigStore {
12182
12164
  return profile;
12183
12165
  }
12184
12166
  async getProfileConfigs(idOrSlug) {
12185
- const configs = [];
12186
- let cursor = 0;
12187
- while (true) {
12188
- const page = await this.getProfileConfigsPage(idOrSlug, { limit: 100, cursor });
12189
- configs.push(...page.items);
12190
- if (page.complete)
12191
- return configs;
12192
- cursor = page.next_cursor;
12193
- }
12167
+ return aggregateBoundedCollection("profile membership", (cursor) => this.getProfileConfigsPage(idOrSlug, { limit: 100, cursor }), (config) => config.id);
12194
12168
  }
12195
12169
  async getProfileConfigsPage(idOrSlug, options = {}) {
12196
12170
  const normalized = normalizeBoundedReadOptions(options);
@@ -12204,20 +12178,26 @@ class CloudConfigStore {
12204
12178
  return parseBoundedOrLegacyPage(data.configs, data.profile.configs, normalized, "profile membership");
12205
12179
  }
12206
12180
  async getProfileConfigBindings(idOrSlug) {
12207
- const { status, data } = await this.requestProfileRoute(idOrSlug, (profileId) => `/profiles/${encodeURIComponent(profileId)}/bindings`, (value) => Array.isArray(value?.bindings));
12208
- if (status === 404) {
12209
- const profile = await this.getProfile(idOrSlug);
12210
- const configs = await this.getProfileConfigs(idOrSlug);
12211
- return configs.map((config, sort_order) => ({
12212
- profile_id: profile.id,
12213
- config_id: config.id,
12214
- sort_order,
12215
- binding: legacyProfileConfigBinding()
12216
- }));
12217
- }
12218
- if (!data || !Array.isArray(data.bindings))
12219
- throw new ProfileNotFoundError(idOrSlug);
12220
- return data.bindings;
12181
+ let routeMissing = false;
12182
+ const bindings = await aggregateBoundedCollection("profile config bindings", async (cursor) => {
12183
+ const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
12184
+ const { status, data } = await this.requestProfileRoute(idOrSlug, (profileId) => `/profiles/${encodeURIComponent(profileId)}/bindings?limit=${normalized.limit}&cursor=${normalized.cursor}`, (value) => Boolean(value && (Array.isArray(value.bindings) || Array.isArray(value.items))));
12185
+ if (status === 404) {
12186
+ routeMissing = true;
12187
+ return { ...boundedReadPage([], 0, normalized), source_bounded: false };
12188
+ }
12189
+ return parseBoundedOrLegacyPage(data, data?.bindings, normalized, "profile config bindings");
12190
+ }, (binding) => `${binding.profile_id}\x00${binding.config_id}`);
12191
+ if (!routeMissing)
12192
+ return bindings;
12193
+ const profile = await this.getProfile(idOrSlug);
12194
+ const configs = await this.getProfileConfigs(idOrSlug);
12195
+ return configs.map((config, sort_order) => ({
12196
+ profile_id: profile.id,
12197
+ config_id: config.id,
12198
+ sort_order,
12199
+ binding: legacyProfileConfigBinding()
12200
+ }));
12221
12201
  }
12222
12202
  async requestProfileRoute(idOrSlug, pathForId, isUsable) {
12223
12203
  const attempted = new Set;
@@ -12275,14 +12255,20 @@ class CloudConfigStore {
12275
12255
  await this.request("DELETE", `/profiles/${encodeURIComponent(profileIdOrSlug)}/configs/${encodeURIComponent(configId)}`, undefined, { allow404: true });
12276
12256
  }
12277
12257
  async getProfileAssetBindings(profileIdOrSlug) {
12278
- const { status, data } = await this.requestProfileRoute(profileIdOrSlug, (profileId) => `/profiles/${encodeURIComponent(profileId)}/assets`, (value) => Array.isArray(value?.assets));
12279
- if (status === 404) {
12280
- await this.getProfile(profileIdOrSlug);
12281
- return [];
12282
- }
12283
- if (!data || !Array.isArray(data.assets))
12284
- throw new ProfileNotFoundError(profileIdOrSlug);
12285
- return data.assets;
12258
+ let routeMissing = false;
12259
+ const assets = await aggregateBoundedCollection("profile asset bindings", async (cursor) => {
12260
+ const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
12261
+ const { status, data } = await this.requestProfileRoute(profileIdOrSlug, (profileId) => `/profiles/${encodeURIComponent(profileId)}/assets?limit=${normalized.limit}&cursor=${normalized.cursor}`, (value) => Boolean(value && (Array.isArray(value.assets) || Array.isArray(value.items))));
12262
+ if (status === 404) {
12263
+ routeMissing = true;
12264
+ return { ...boundedReadPage([], 0, normalized), source_bounded: false };
12265
+ }
12266
+ return parseBoundedOrLegacyPage(data, data?.assets, normalized, "profile asset bindings");
12267
+ }, (asset) => `${asset.profile_id}\x00${asset.binding.assetKey}`);
12268
+ if (!routeMissing)
12269
+ return assets;
12270
+ await this.getProfile(profileIdOrSlug);
12271
+ return [];
12286
12272
  }
12287
12273
  async addAssetToProfile(profileIdOrSlug, sourceConfigId, binding) {
12288
12274
  const { data } = await this.request("POST", `/profiles/${encodeURIComponent(profileIdOrSlug)}/assets`, { source_config_id: sourceConfigId, binding }, { idempotent: true });
@@ -12352,8 +12338,11 @@ class CloudConfigStore {
12352
12338
  await this.request("POST", "/machines/applied", { hostname });
12353
12339
  }
12354
12340
  async listMachines() {
12355
- const { data } = await this.request("GET", "/machines");
12356
- return data?.machines ?? [];
12341
+ return aggregateBoundedCollection("machine list", async (cursor) => {
12342
+ const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
12343
+ const { data } = await this.request("GET", `/machines?limit=${normalized.limit}&cursor=${normalized.cursor}`);
12344
+ return parseBoundedOrLegacyPage(data, data?.machines, normalized, "machine list");
12345
+ }, (machine) => machine.id, { requireAscendingIdentity: true });
12357
12346
  }
12358
12347
  async sendFeedback(input) {
12359
12348
  await this.request("POST", "/feedback", {
@@ -12603,9 +12592,9 @@ async function ensureGlobalAgentRulesStandardConfig(store = resolveConfigStore()
12603
12592
  }
12604
12593
 
12605
12594
  // src/lib/machine.ts
12606
- import { arch as currentArch, homedir as homedir6, hostname as currentHostname, type as currentOsType } from "os";
12607
- import { existsSync as existsSync6 } from "fs";
12608
- import { join as join8 } from "path";
12595
+ import { arch as currentArch, homedir as homedir5, hostname as currentHostname, type as currentOsType } from "os";
12596
+ import { existsSync as existsSync5 } from "fs";
12597
+ import { join as join7 } from "path";
12609
12598
  var BREW_BUN_PATH = "/opt/homebrew/bin/bun";
12610
12599
  function normalizeOsFamily(os) {
12611
12600
  const value = (os ?? "").trim().toLowerCase();
@@ -12618,11 +12607,11 @@ function normalizeOsFamily(os) {
12618
12607
  return value || "unknown";
12619
12608
  }
12620
12609
  function detectMachineContext(overrides = {}) {
12621
- const homeDir5 = overrides.home_dir ?? process.env["CONFIGS_HOME"] ?? process.env["HOME"] ?? homedir6();
12610
+ const homeDir4 = overrides.home_dir ?? process.env["CONFIGS_HOME"] ?? process.env["HOME"] ?? homedir5();
12622
12611
  const os = overrides.os ?? currentOsType();
12623
12612
  const osFamily = normalizeOsFamily(os);
12624
- const bunBinDir = overrides.bun_bin_dir ?? join8(homeDir5, ".bun", "bin");
12625
- const defaultBunPath = osFamily === "macos" && existsSync6(BREW_BUN_PATH) ? BREW_BUN_PATH : join8(bunBinDir, "bun");
12613
+ const bunBinDir = overrides.bun_bin_dir ?? join7(homeDir4, ".bun", "bin");
12614
+ const defaultBunPath = osFamily === "macos" && existsSync5(BREW_BUN_PATH) ? BREW_BUN_PATH : join7(bunBinDir, "bun");
12626
12615
  return {
12627
12616
  id: "current-machine",
12628
12617
  hostname: overrides.hostname ?? currentHostname(),
@@ -12631,11 +12620,11 @@ function detectMachineContext(overrides = {}) {
12631
12620
  last_applied_at: null,
12632
12621
  created_at: "",
12633
12622
  os_family: osFamily,
12634
- home_dir: homeDir5,
12635
- workspace_root: overrides.workspace_root ?? join8(homeDir5, osFamily === "macos" ? "Workspace" : "workspace"),
12623
+ home_dir: homeDir4,
12624
+ workspace_root: overrides.workspace_root ?? join7(homeDir4, osFamily === "macos" ? "Workspace" : "workspace"),
12636
12625
  bun_bin_dir: bunBinDir,
12637
12626
  bun_path: overrides.bun_path ?? defaultBunPath,
12638
- path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${join8("/opt", "homebrew", "bin")}:${bunBinDir}` : bunBinDir)
12627
+ path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${join7("/opt", "homebrew", "bin")}:${bunBinDir}` : bunBinDir)
12639
12628
  };
12640
12629
  }
12641
12630
  function machineContextToVariables(machine) {
@@ -12699,4 +12688,4 @@ function renderMachineAwareContentPreview(content, variables) {
12699
12688
  return isTemplate(content) ? renderTemplatePreview(content, variables) : { content, unresolved: [] };
12700
12689
  }
12701
12690
 
12702
- export { DEFAULT_LIST_LIMIT, parseLimit, paginate, truncateText, truncateMiddle, normalizeBoundedReadOptions, boundedReadPage, ensureGlobalAgentRulesStandardConfig, ensureCodewithSharedTodosStorageStandardConfig, redactFormatForTarget, redactContent, scanSecrets, isSecretVarName, SESSION_RENDER_MANAGED_MARKER, SESSION_RENDER_SCHEMA, SESSION_RENDER_MANIFEST_RELATIVE_PATH, SESSION_INSTRUCTION_LAYERS, getSessionRenderSnapshotDir, sessionRenderSnapshotWorkspaceRoot, PROJECT_CONTEXT_MAX_INPUT_BYTES, SESSION_MANAGED_INPUT_MAX_BYTES, ProjectContextError, parseProjectContextBundle, planProjectContext, observeProjectContextSessionGuard, withProjectContextSessionGuard, applyProjectContext, writeProjectContextCoordinatedFile, removeProjectContextCoordinatedFile, isRetiredOrUnsupportedConfigAgent, retiredOrUnsupportedAgentReason, applyTransform, normalizeProfileAssetBinding, observeCursorGlobalAuthorityAtPath, isCursorGlobalAuthorityPath, stampCursorGlobalAuthorityMarker, detectCursorAuthorityConflicts, detectClaudeAuthorityConflicts, getRawStoreRoot, ANTIGRAVITY_RULE_FILE_CHAR_LIMIT, SESSION_RENDERER_OWNER_ID, SESSION_RENDER_TOOLS, SESSION_RENDER_OWNED_CONFIG_TARGETS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS, normalizeSessionInstructionSourceId, resolveSessionPath, planSessionRender, sourceFromFilePath, sourceFromConfig, sourcesFromIdentityExport, legacyProfileConfigBinding, normalizeProfileConfigBinding, planProfileSessionRender, hasInstructionsEnvAuthorityIntent, normalizeOsFamily, detectMachineContext, machineContextToVariables, resolveProfileVariables, templateizeMachineContent, renderMachineAwareContentPreview, formatCliError, CloudConfigStore, resolveConfigStore };
12691
+ export { DEFAULT_LIST_LIMIT, parseLimit, paginate, truncateText, truncateMiddle, normalizeBoundedReadOptions, boundedReadPage, ensureGlobalAgentRulesStandardConfig, ensureCodewithSharedTodosStorageStandardConfig, redactFormatForTarget, redactContent, scanSecrets, isSecretVarName, SESSION_RENDER_MANAGED_MARKER, SESSION_RENDER_SCHEMA, SESSION_RENDER_MANIFEST_RELATIVE_PATH, SESSION_INSTRUCTION_LAYERS, getSessionRenderSnapshotDir, sessionRenderSnapshotWorkspaceRoot, PROJECT_CONTEXT_MAX_INPUT_BYTES, SESSION_MANAGED_INPUT_MAX_BYTES, ProjectContextError, parseProjectContextBundle, planProjectContext, observeProjectContextSessionGuard, withProjectContextSessionGuard, applyProjectContext, writeProjectContextCoordinatedFile, removeProjectContextCoordinatedFile, isRetiredOrUnsupportedConfigAgent, retiredOrUnsupportedAgentReason, applyTransform, normalizeProfileAssetBinding, observeCursorGlobalAuthorityAtPath, isCursorGlobalAuthorityPath, stampCursorGlobalAuthorityMarker, detectCursorAuthorityConflicts, detectClaudeAuthorityConflicts, ANTIGRAVITY_RULE_FILE_CHAR_LIMIT, SESSION_RENDERER_OWNER_ID, SESSION_RENDER_TOOLS, SESSION_RENDER_OWNED_CONFIG_TARGETS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS, normalizeSessionInstructionSourceId, resolveSessionPath, planSessionRender, sourceFromFilePath, sourceFromConfig, sourcesFromIdentityExport, legacyProfileConfigBinding, normalizeProfileConfigBinding, planProfileSessionRender, normalizeOsFamily, detectMachineContext, machineContextToVariables, resolveProfileVariables, templateizeMachineContent, renderMachineAwareContentPreview, formatCliError, CloudConfigStore, resolveConfigStore };