@hasna/recordings 0.2.13 → 0.3.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 (120) hide show
  1. package/Dockerfile.package +4 -5
  2. package/README.md +113 -8
  3. package/bun.lock +2 -2
  4. package/dist/__tests__/helpers/installer-guard-execution.d.ts +22 -0
  5. package/dist/__tests__/helpers/installer-guard-execution.d.ts.map +1 -0
  6. package/dist/__tests__/helpers/installer-preflight.d.ts +22 -0
  7. package/dist/__tests__/helpers/installer-preflight.d.ts.map +1 -0
  8. package/dist/__tests__/helpers/native-fs-guard.d.ts.map +1 -1
  9. package/dist/__tests__/helpers/source-assertions.d.ts +169 -0
  10. package/dist/__tests__/helpers/source-assertions.d.ts.map +1 -0
  11. package/dist/__tests__/preload.d.ts +1 -4
  12. package/dist/__tests__/preload.d.ts.map +1 -1
  13. package/dist/cli/desktop-snapshot.d.ts +20 -0
  14. package/dist/cli/desktop-snapshot.d.ts.map +1 -0
  15. package/dist/cli/index.js +2078 -277
  16. package/dist/cli/macos-permissions.d.ts +72 -0
  17. package/dist/cli/macos-permissions.d.ts.map +1 -1
  18. package/dist/cli/macos-shortcut.d.ts +139 -0
  19. package/dist/cli/macos-shortcut.d.ts.map +1 -0
  20. package/dist/cli/trigger-probe.d.ts +172 -0
  21. package/dist/cli/trigger-probe.d.ts.map +1 -0
  22. package/dist/db/database.d.ts +9 -0
  23. package/dist/db/database.d.ts.map +1 -1
  24. package/dist/http/client.d.ts +10 -7
  25. package/dist/http/client.d.ts.map +1 -1
  26. package/dist/index.d.ts +3 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +634 -49
  29. package/dist/lib/capture-probe.d.ts +216 -0
  30. package/dist/lib/capture-probe.d.ts.map +1 -0
  31. package/dist/lib/config.d.ts.map +1 -1
  32. package/dist/lib/macos-bundle.d.ts +50 -0
  33. package/dist/lib/macos-bundle.d.ts.map +1 -0
  34. package/dist/lib/persistence-probe.d.ts +208 -0
  35. package/dist/lib/persistence-probe.d.ts.map +1 -0
  36. package/dist/lib/recorder.d.ts.map +1 -1
  37. package/dist/lib/retired-deployment-modes.d.ts +24 -0
  38. package/dist/lib/retired-deployment-modes.d.ts.map +1 -0
  39. package/dist/lib/transcriber.d.ts +60 -0
  40. package/dist/lib/transcriber.d.ts.map +1 -1
  41. package/dist/mcp/index.js +140 -56
  42. package/dist/server/cloud-config.d.ts +25 -3
  43. package/dist/server/cloud-config.d.ts.map +1 -1
  44. package/dist/server/cloud-readiness.d.ts.map +1 -1
  45. package/dist/server/cloud.d.ts +8 -7
  46. package/dist/server/cloud.d.ts.map +1 -1
  47. package/dist/server/index.js +187 -79
  48. package/dist/server/migrate-command.d.ts.map +1 -1
  49. package/dist/server/serve.d.ts.map +1 -1
  50. package/dist/storage.d.ts +2 -2
  51. package/dist/storage.d.ts.map +1 -1
  52. package/dist/storage.js +108 -49
  53. package/dist/store.d.ts +1 -1
  54. package/dist/store.d.ts.map +1 -1
  55. package/dist/version.d.ts +1 -1
  56. package/dist/version.d.ts.map +1 -1
  57. package/package.json +25 -6
  58. package/scripts/build_native_fs_guard.sh +15 -2
  59. package/scripts/ci-linux-suite.ts +403 -0
  60. package/scripts/ci-native-build.ts +402 -0
  61. package/scripts/enforce_identity_migration.sh +110 -0
  62. package/scripts/generate-sdk.ts +1 -1
  63. package/scripts/install_macos_app.sh +138 -24
  64. package/scripts/macos_artifact.ts +205 -33
  65. package/scripts/native/realtime-settle-probe/README.md +39 -0
  66. package/scripts/native/realtime-settle-probe/main.swift +135 -0
  67. package/scripts/policy/local-only-approved-targets.txt +21 -0
  68. package/scripts/read_local_only_targets.sh +203 -0
  69. package/scripts/scan-artifact.ts +40 -0
  70. package/scripts/set-version.ts +145 -0
  71. package/scripts/vacuity-manifest-gen.ts +96 -0
  72. package/scripts/vacuity-manifests/enhancement-screen-mirror.tsv +44 -0
  73. package/scripts/vacuity-manifests/install-chain.tsv +13 -0
  74. package/scripts/vacuity-manifests/must-survive-controls.tsv +10 -0
  75. package/scripts/vacuity-manifests/reorder.tsv +4 -0
  76. package/scripts/vacuity-manifests/source-side.tsv +15 -0
  77. package/scripts/vacuity-manifests/variable-operands.tsv +16 -0
  78. package/scripts/vacuity-manifests/version-sites.tsv +61 -0
  79. package/scripts/vacuity-mutation-battery.ts +266 -0
  80. package/src/native/Recordings/App/MenuBarStatusView.swift +14 -7
  81. package/src/native/Recordings/App/RuntimeSmoke.swift +5 -1
  82. package/src/native/Recordings/App/SidebarView.swift +1 -1
  83. package/src/native/Recordings/Package.swift +24 -5
  84. package/src/native/Recordings/RecordingsLib/EnhancementScreen.swift +91 -0
  85. package/src/native/Recordings/RecordingsLib/FnKeyMonitor.swift +27 -4
  86. package/src/native/Recordings/RecordingsLib/Info.plist +2 -2
  87. package/src/native/Recordings/RecordingsLib/MenuBarPresentation.swift +56 -3
  88. package/src/native/Recordings/RecordingsLib/NativePCMRecorder.swift +13 -0
  89. package/src/native/Recordings/RecordingsLib/PasteDeliveryVerification.swift +460 -0
  90. package/src/native/Recordings/RecordingsLib/RealtimeTranscriptionClient.swift +41 -7
  91. package/src/native/Recordings/RecordingsLib/RecordingAttemptAlert.swift +36 -0
  92. package/src/native/Recordings/RecordingsLib/RecordingEngine.swift +1071 -75
  93. package/src/native/Recordings/RecordingsLib/SettingsView.swift +47 -3
  94. package/src/native/Recordings/RecordingsLib/VoiceShortcuts.swift +11 -6
  95. package/src/native/Recordings/RecordingsTests/CLIRunnerTests.swift +3 -3
  96. package/src/native/Recordings/RecordingsTests/EnhancementScreenTests.swift +191 -0
  97. package/src/native/Recordings/RecordingsTests/MenuBarPresentationTests.swift +144 -4
  98. package/src/native/Recordings/RecordingsTests/PasteDeliveryVerificationTests.swift +463 -0
  99. package/src/native/Recordings/RecordingsTests/PasteTargetTests.swift +33 -20
  100. package/src/native/Recordings/RecordingsTests/ProjectStoreTests.swift +1 -1
  101. package/src/native/Recordings/RecordingsTests/RealtimeSettleBenchmark.swift +200 -0
  102. package/src/native/Recordings/RecordingsTests/RealtimeSettleBudgetTests.swift +80 -0
  103. package/src/native/Recordings/RecordingsTests/RealtimeTranscriptionTests.swift +22 -4
  104. package/src/native/Recordings/RecordingsTests/RecordingEngineDeliveryTests.swift +12 -6
  105. package/src/native/Recordings/RecordingsTests/RecordingEngineHomeIsolationTests.swift +67 -0
  106. package/src/native/Recordings/RecordingsTests/RecordingStartGateTests.swift +12 -3
  107. package/src/native/Recordings/RecordingsTests/RecordingStartTimingTests.swift +207 -11
  108. package/src/native/Recordings/RecordingsTests/SpeechIntentTests.swift +17 -6
  109. package/src/native/Recordings/RecordingsTests/TestHomeDirectory.swift +23 -0
  110. package/src/native/Recordings/Updater/Broker/ApplicationProcessQuiescence.swift +7 -1
  111. package/src/native/Recordings/Updater/Broker/AtomicActivation.swift +10 -10
  112. package/src/native/Recordings/Updater/Broker/BrokerMain.swift +5 -1
  113. package/src/native/Recordings/Updater/Broker/HostOSProductVersion.swift +1 -0
  114. package/src/native/Recordings/Updater/Broker/PeerIdentity.swift +59 -3
  115. package/src/native/Recordings/Updater/Protocol/UpdateProtocol.swift +21 -2
  116. package/src/native/Recordings/Updater/ProtocolTests/ExpectationIntegrityTests.swift +60 -0
  117. package/src/native/Recordings/Updater/ProtocolTests/UpdateXPCInterfaceTests.swift +113 -0
  118. package/src/native/Recordings/Updater/VerifierLauncher/RecordingsVerifierLauncher.c +106 -5
  119. package/src/native/Recordings/build.sh +75 -9
  120. package/scripts/native/prebuilds/darwin-universal/recordings_fs_guard.node +0 -0
package/dist/storage.js CHANGED
@@ -462,7 +462,8 @@ function findProjectRecordingsPath(entry) {
462
462
  function findRepositoryRoot(start) {
463
463
  let dir = start;
464
464
  while (true) {
465
- if (existsSync(join2(dir, ".git")))
465
+ const gitPath = join2(dir, ".git");
466
+ if (isRepositoryMarker(gitPath))
466
467
  return dir;
467
468
  const parent = dirname2(dir);
468
469
  if (parent === dir)
@@ -470,6 +471,15 @@ function findRepositoryRoot(start) {
470
471
  dir = parent;
471
472
  }
472
473
  }
474
+ function isRepositoryMarker(gitPath) {
475
+ try {
476
+ if (statSync(gitPath).isFile())
477
+ return true;
478
+ return existsSync(join2(gitPath, "HEAD"));
479
+ } catch {
480
+ return false;
481
+ }
482
+ }
473
483
  function canonicalExistingPath(path) {
474
484
  try {
475
485
  return realpathSync2(path);
@@ -498,14 +508,17 @@ function loadSecretKey(keyName) {
498
508
  try {
499
509
  const content = readFileSync(candidate, "utf-8");
500
510
  const match = content.match(new RegExp(`export\\s+${keyName}\\s*=\\s*"([^"]+)"`));
501
- if (match)
502
- return match[1];
511
+ const doubleQuotedValue = match?.[1];
512
+ if (doubleQuotedValue !== undefined)
513
+ return doubleQuotedValue;
503
514
  const match2 = content.match(new RegExp(`export\\s+${keyName}\\s*=\\s*'([^']+)'`));
504
- if (match2)
505
- return match2[1];
515
+ const singleQuotedValue = match2?.[1];
516
+ if (singleQuotedValue !== undefined)
517
+ return singleQuotedValue;
506
518
  const match3 = content.match(new RegExp(`${keyName}\\s*=\\s*(.+)`));
507
- if (match3)
508
- return match3[1].trim().replace(/^["']|["']$/g, "");
519
+ const unquotedValue = match3?.[1];
520
+ if (unquotedValue !== undefined)
521
+ return unquotedValue.trim().replace(/^["']|["']$/g, "");
509
522
  } catch {}
510
523
  }
511
524
  return "";
@@ -630,6 +643,7 @@ var MIGRATIONS = [
630
643
  ALTER TABLE agents ADD COLUMN active_project_id TEXT REFERENCES projects(id) ON DELETE SET NULL;
631
644
  `
632
645
  ];
646
+ var CURRENT_MIGRATION_LEVEL = MIGRATIONS.length - 1;
633
647
  function getDatabase(dbPath) {
634
648
  if (_db)
635
649
  return _db;
@@ -653,7 +667,11 @@ function runMigrations(db) {
653
667
  const currentLevel = result?.max_id ?? -1;
654
668
  for (let i = currentLevel + 1;i < MIGRATIONS.length; i++) {
655
669
  try {
656
- db.run(MIGRATIONS[i]);
670
+ const migration = MIGRATIONS[i];
671
+ if (migration === undefined) {
672
+ throw new Error(`Missing SQLite migration at version ${i}`);
673
+ }
674
+ db.run(migration);
657
675
  db.query("INSERT INTO _migrations (id) VALUES (?)").run(i);
658
676
  } catch (e) {
659
677
  if (isBenignMigrationError(e)) {
@@ -1003,7 +1021,7 @@ function setAgentFocus(idOrName, projectId, db) {
1003
1021
  }
1004
1022
 
1005
1023
  // src/version.ts
1006
- var VERSION = "0.2.13";
1024
+ var VERSION = "0.3.1";
1007
1025
 
1008
1026
  // src/db/feedback.ts
1009
1027
  function saveFeedback(input) {
@@ -1011,29 +1029,54 @@ function saveFeedback(input) {
1011
1029
  db.query("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)").run(input.message, input.email ?? null, input.category ?? "general", input.version ?? VERSION);
1012
1030
  }
1013
1031
 
1032
+ // src/lib/retired-deployment-modes.ts
1033
+ var RETIRED_DEPLOYMENT_MODES = [
1034
+ "local",
1035
+ "self_hosted",
1036
+ "cloud",
1037
+ "remote",
1038
+ "hybrid"
1039
+ ];
1040
+ function normalizeModeToken(value) {
1041
+ return value.trim().toLowerCase().replace(/-/g, "_");
1042
+ }
1043
+ function asRetiredDeploymentMode(value) {
1044
+ const token = normalizeModeToken(value);
1045
+ return RETIRED_DEPLOYMENT_MODES.includes(token) ? token : null;
1046
+ }
1047
+ function retiredDeploymentModeError(rawValue, sourceEnvKey, replacement) {
1048
+ const mode = asRetiredDeploymentMode(rawValue);
1049
+ const value = mode === "local" ? replacement.onBox : replacement.offBox;
1050
+ return new Error(`${sourceEnvKey}=${rawValue} names a deployment mode, and deployment modes are removed: ` + `${RETIRED_DEPLOYMENT_MODES.join(" | ")} no longer select anything. ` + `Set ${replacement.envKey}=${value} instead ` + `(${replacement.envKey} takes ${replacement.onBox} or ${replacement.offBox}).`);
1051
+ }
1052
+
1014
1053
  // src/http/client.ts
1015
- var DEPRECATED_MODE_ALIASES = ["self_hosted", "remote", "hybrid"];
1054
+ var SERVER_BACKEND_VALUES = ["sqlite", "postgresql", "postgres"];
1016
1055
  function envToken(name) {
1017
1056
  return name.toUpperCase().replace(/-/g, "_");
1018
1057
  }
1019
- function normalizeMode(value) {
1020
- const normalized = value.trim().toLowerCase().replace(/-/g, "_");
1021
- if (normalized === "local")
1022
- return { mode: "local", deprecatedAlias: null };
1023
- if (normalized === "cloud")
1024
- return { mode: "cloud", deprecatedAlias: null };
1025
- if (DEPRECATED_MODE_ALIASES.includes(normalized)) {
1026
- return { mode: "cloud", deprecatedAlias: normalized };
1058
+ function clientStoreReplacement(envKey) {
1059
+ return { envKey, onBox: "sqlite", offBox: "http" };
1060
+ }
1061
+ function normalizeClientStore(value, sourceEnvKey, replacementEnvKey) {
1062
+ const normalized = normalizeModeToken(value);
1063
+ if (normalized === "sqlite")
1064
+ return "sqlite";
1065
+ if (normalized === "http" || normalized === "https")
1066
+ return "http";
1067
+ if (asRetiredDeploymentMode(value)) {
1068
+ throw retiredDeploymentModeError(value, sourceEnvKey, clientStoreReplacement(replacementEnvKey));
1027
1069
  }
1028
- throw new Error(`Unknown storage mode: ${value}. Use local or cloud.`);
1070
+ throw new Error(`Unknown client store: ${value}. Use sqlite or http.`);
1029
1071
  }
1030
- function defaultCloudBaseUrl(name) {
1072
+ function defaultApiBaseUrl(name) {
1031
1073
  return `https://${name}.hasna.xyz`;
1032
1074
  }
1033
1075
  function envKeys(name) {
1034
1076
  const token = envToken(name);
1035
1077
  return {
1036
- modeKeys: [`HASNA_${token}_STORAGE_MODE`, `HASNA_${token}_MODE`, `${token}_STORAGE_MODE`, `${token}_MODE`],
1078
+ storeKeys: [`HASNA_${token}_CLIENT_STORE`, `${token}_CLIENT_STORE`],
1079
+ retiredModeKeys: [`HASNA_${token}_STORAGE_MODE`, `HASNA_${token}_MODE`, `${token}_STORAGE_MODE`, `${token}_MODE`],
1037
1080
  apiUrlKeys: [`HASNA_${token}_API_URL`, `${token}_API_URL`],
1038
1081
  apiKeyKeys: [`HASNA_${token}_API_KEY`, `${token}_API_KEY`]
1039
1082
  };
@@ -1046,6 +1089,20 @@ function firstEnv(env, keys) {
1046
1089
  }
1047
1090
  return null;
1048
1091
  }
1092
+ function assertNoRetiredMode(env, keys) {
1093
+ for (const key of keys.retiredModeKeys) {
1094
+ const value = env[key]?.trim();
1095
+ if (!value)
1096
+ continue;
1097
+ const normalized = normalizeModeToken(value);
1098
+ if (SERVER_BACKEND_VALUES.includes(normalized))
1099
+ continue;
1100
+ if (asRetiredDeploymentMode(value)) {
1101
+ throw retiredDeploymentModeError(value, key, clientStoreReplacement(keys.storeKeys[0]));
1102
+ }
1103
+ throw new Error(`${key}=${value} is not a client store. ${key} no longer selects one; ` + `set ${keys.storeKeys[0]}=sqlite or ${keys.storeKeys[0]}=http instead.`);
1104
+ }
1105
+ }
1049
1106
  function toV1BaseUrl(apiUrl) {
1050
1107
  const url = new URL(apiUrl);
1051
1108
  if (url.protocol !== "http:" && url.protocol !== "https:") {
@@ -1061,45 +1118,42 @@ function toV1BaseUrl(apiUrl) {
1061
1118
  }
1062
1119
  function resolveTransport(name, env = process.env) {
1063
1120
  const keys = envKeys(name);
1064
- const modeHit = firstEnv(env, keys.modeKeys);
1121
+ assertNoRetiredMode(env, keys);
1122
+ const storeHit = firstEnv(env, keys.storeKeys);
1065
1123
  const urlHit = firstEnv(env, keys.apiUrlKeys);
1066
1124
  const keyHit = firstEnv(env, keys.apiKeyKeys);
1067
- let mode = "local";
1068
- let deprecatedAlias = null;
1125
+ let requested = "sqlite";
1069
1126
  let modeSource = "default";
1070
- if (modeHit) {
1071
- const normalized = normalizeMode(modeHit.value);
1072
- mode = normalized.mode;
1073
- deprecatedAlias = normalized.deprecatedAlias;
1074
- modeSource = modeHit.key;
1127
+ if (storeHit) {
1128
+ requested = normalizeClientStore(storeHit.value, storeHit.key, keys.storeKeys[0]);
1129
+ modeSource = storeHit.key;
1075
1130
  } else if (urlHit && keyHit) {
1076
- mode = "cloud";
1131
+ requested = "http";
1077
1132
  modeSource = "auto:api-url+api-key";
1078
1133
  }
1079
- if (mode === "local") {
1080
- return { transport: "local", mode, deprecatedAlias, modeSource, baseUrl: null, apiKeyPresent: Boolean(keyHit), misconfigured: false, warning: null };
1134
+ if (requested === "sqlite") {
1135
+ return { transport: "sqlite", requested, modeSource, baseUrl: null, apiKeyPresent: Boolean(keyHit), misconfigured: false, warning: null };
1081
1136
  }
1082
1137
  if (!keyHit) {
1083
1138
  return {
1084
- transport: "local",
1085
- mode,
1086
- deprecatedAlias,
1139
+ transport: "sqlite",
1140
+ requested,
1087
1141
  modeSource,
1088
1142
  baseUrl: null,
1089
1143
  apiKeyPresent: false,
1090
1144
  misconfigured: true,
1091
- warning: `${modeSource}=cloud but no API key is set (${keys.apiKeyKeys[0]}). Refusing to route to cloud.`
1145
+ warning: `${modeSource}=http but no API key is set (${keys.apiKeyKeys[0]}). Refusing to route to the API.`
1092
1146
  };
1093
1147
  }
1094
- const rawUrl = urlHit?.value ?? defaultCloudBaseUrl(name);
1148
+ const rawUrl = urlHit?.value ?? defaultApiBaseUrl(name);
1095
1149
  let baseUrl;
1096
1150
  try {
1097
1151
  baseUrl = toV1BaseUrl(rawUrl);
1098
1152
  } catch (error) {
1099
1153
  const message = error instanceof Error ? error.message : String(error);
1100
- return { transport: "local", mode, deprecatedAlias, modeSource, baseUrl: null, apiKeyPresent: true, misconfigured: true, warning: `Invalid API URL: ${message}.` };
1154
+ return { transport: "sqlite", requested, modeSource, baseUrl: null, apiKeyPresent: true, misconfigured: true, warning: `Invalid API URL: ${message}.` };
1101
1155
  }
1102
- return { transport: "cloud-http", mode, deprecatedAlias, modeSource, baseUrl, apiKeyPresent: true, misconfigured: false, warning: null };
1156
+ return { transport: "http", requested, modeSource, baseUrl, apiKeyPresent: true, misconfigured: false, warning: null };
1103
1157
  }
1104
1158
 
1105
1159
  class HasnaHttpError extends Error {
@@ -1211,6 +1265,8 @@ function createHttpTransport(options) {
1211
1265
  const jitter = Math.floor(Math.random() * (backoff / 2 + 1));
1212
1266
  await sleep(backoff + jitter);
1213
1267
  }
1268
+ if (last === null)
1269
+ throw new Error(`Request to ${rel} completed without a result`);
1214
1270
  throw last.error;
1215
1271
  }
1216
1272
  return {
@@ -1282,17 +1338,17 @@ function createStorageClient(name, transport) {
1282
1338
  function resolveStorageClient(name, env = process.env, fetchImpl) {
1283
1339
  const resolution = resolveTransport(name, env);
1284
1340
  if (resolution.misconfigured) {
1285
- throw new Error(resolution.warning ?? `Client for '${name}' is misconfigured for cloud mode.`);
1341
+ throw new Error(resolution.warning ?? `Client for '${name}' is misconfigured for the /v1 API.`);
1286
1342
  }
1287
- if (resolution.transport === "local" || !resolution.baseUrl) {
1288
- return { transport: "local", client: null, resolution };
1343
+ if (resolution.transport === "sqlite" || !resolution.baseUrl) {
1344
+ return { transport: "sqlite", client: null, resolution };
1289
1345
  }
1290
1346
  const keys = envKeys(name);
1291
1347
  const apiKey = firstEnv(env, keys.apiKeyKeys)?.value;
1292
1348
  if (!apiKey)
1293
- throw new Error(`Client for '${name}' resolved to cloud-http without an API key.`);
1349
+ throw new Error(`Client for '${name}' resolved to the /v1 API without an API key.`);
1294
1350
  const transport = createHttpTransport({ name, baseUrl: resolution.baseUrl, apiKey, ...fetchImpl ? { fetchImpl } : {} });
1295
- return { transport: "cloud-http", client: createStorageClient(name, transport), resolution };
1351
+ return { transport: "http", client: createStorageClient(name, transport), resolution };
1296
1352
  }
1297
1353
 
1298
1354
  // src/store.ts
@@ -1316,12 +1372,15 @@ function listQuery(filter) {
1316
1372
  }
1317
1373
  function unwrap(res, key) {
1318
1374
  if (res && typeof res === "object" && key in res) {
1319
- return res[key];
1375
+ const value = res[key];
1376
+ if (value === undefined)
1377
+ throw new Error(`Response field ${key} is undefined`);
1378
+ return value;
1320
1379
  }
1321
1380
  return res;
1322
1381
  }
1323
1382
  var localStore = {
1324
- mode: "local",
1383
+ mode: "sqlite",
1325
1384
  baseUrl: null,
1326
1385
  async createRecording(input, idempotencyKey) {
1327
1386
  return withLocalStoreReaderLease(() => createRecording(input, undefined, idempotencyKey));
@@ -1374,7 +1433,7 @@ var localStore = {
1374
1433
  };
1375
1434
  function apiStore(client) {
1376
1435
  return {
1377
- mode: "cloud-http",
1436
+ mode: "http",
1378
1437
  baseUrl: client.baseUrl,
1379
1438
  async createRecording(input, idempotencyKey) {
1380
1439
  const keyCandidate = idempotencyKey === undefined && (input.id === undefined || input.id === null) ? randomUUID2() : idempotencyKey;
@@ -1517,7 +1576,7 @@ function getStore(env = process.env) {
1517
1576
  if (env === process.env && cached)
1518
1577
  return cached;
1519
1578
  const resolved = resolveStorageClient(APP, env);
1520
- const store = resolved.transport === "cloud-http" ? apiStore(resolved.client) : localStore;
1579
+ const store = resolved.transport === "http" ? apiStore(resolved.client) : localStore;
1521
1580
  if (env === process.env)
1522
1581
  cached = store;
1523
1582
  return store;
@@ -1558,7 +1617,7 @@ export {
1558
1617
  resolveTransport,
1559
1618
  resolveStorageClient,
1560
1619
  getStore,
1561
- defaultCloudBaseUrl,
1620
+ defaultApiBaseUrl,
1562
1621
  createStorageClient,
1563
1622
  createHttpTransport,
1564
1623
  __resetStore,
package/dist/store.d.ts CHANGED
@@ -10,7 +10,7 @@ export interface RecordingStats {
10
10
  by_model: Record<string, number>;
11
11
  }
12
12
  export interface Store {
13
- readonly mode: "local" | "cloud-http";
13
+ readonly mode: "sqlite" | "http";
14
14
  readonly baseUrl: string | null;
15
15
  createRecording(input: CreateRecordingInput, idempotencyKey?: string): Promise<Recording>;
16
16
  getRecording(id: string): Promise<Recording | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,SAAS,EACT,oBAAoB,EACpB,eAAe,EACf,KAAK,EACL,OAAO,EACR,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAAqC,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMzF,eAAO,MAAM,GAAG,eAAe,CAAC;AAEhC,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,eAAe,CAAC,KAAK,EAAE,oBAAoB,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1F,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IACpD,cAAc,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAC/D,eAAe,CAAC,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5D,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAChF,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IAG7C,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAClD,UAAU,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/B,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACxD,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAGjF,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACtD,YAAY,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAGnC,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAsPD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,KAAK,EACZ,MAAM,CAAC,EAAE,eAAe,GACvB,OAAO,CAAC,MAAM,CAAC,CA0BjB;AAID;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,GAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,KAAK,CAMzG;AAED,2CAA2C;AAC3C,wBAAgB,YAAY,IAAI,IAAI,CAEnC"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,SAAS,EACT,oBAAoB,EACpB,eAAe,EACf,KAAK,EACL,OAAO,EACR,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAAqC,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMzF,eAAO,MAAM,GAAG,eAAe,CAAC;AAEhC,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,eAAe,CAAC,KAAK,EAAE,oBAAoB,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1F,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IACpD,cAAc,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAC/D,eAAe,CAAC,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5D,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAChF,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IAG7C,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAClD,UAAU,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/B,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACxD,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAGjF,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACtD,YAAY,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAGnC,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAwPD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,KAAK,EACZ,MAAM,CAAC,EAAE,eAAe,GACvB,OAAO,CAAC,MAAM,CAAC,CA0BjB;AAID;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,GAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,KAAK,CAMzG;AAED,2CAA2C;AAC3C,wBAAgB,YAAY,IAAI,IAAI,CAEnC"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.2.13";
1
+ export declare const VERSION = "0.3.1";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,WAAW,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,UAAU,CAAC"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@hasna/recordings",
3
- "version": "0.2.13",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "description": "Speech-to-text recording tool with MCP and CLI — records, transcribes, and optionally enhances text using AI",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git+https://github.com/hasna/recordings.git"
8
+ "url": "git+https://github.com/hasna/apps"
9
9
  },
10
10
  "main": "dist/index.js",
11
11
  "types": "dist/index.d.ts",
@@ -28,6 +28,9 @@
28
28
  "types": "./dist/sdk/index.d.ts"
29
29
  }
30
30
  },
31
+ "engines": {
32
+ "bun": ">=1.0.0"
33
+ },
31
34
  "scripts": {
32
35
  "clean": "rm -rf dist",
33
36
  "build": "bun run clean && bun run build:cli && bun run build:mcp && bun run build:serve && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
@@ -39,13 +42,29 @@
39
42
  "generate:sdk": "bun run scripts/generate-sdk.ts",
40
43
  "migrate": "bun run scripts/migrate.ts",
41
44
  "typecheck": "tsc --noEmit",
45
+ "typecheck:tcc-contract": "tsc --noEmit -p tsconfig.tcc-contract.json",
42
46
  "test": "bun test",
47
+ "verify:ci-suite": "bun scripts/ci-linux-suite.ts --check",
48
+ "verify:ci-suite:run": "bun scripts/ci-linux-suite.ts --verify-run",
49
+ "verify:ci-native": "bun scripts/ci-native-build.ts",
50
+ "test:gated": "bun scripts/ci-linux-suite.ts --check && RECORDINGS_TEST_TIMEOUT_MS=\"${RECORDINGS_TEST_TIMEOUT_MS:-120000}\" bun test --timeout \"$RECORDINGS_TEST_TIMEOUT_MS\" $(bun scripts/ci-linux-suite.ts --gated)",
51
+ "test:vacuity-battery": "bun scripts/vacuity-manifest-gen.ts > \"${TMPDIR:-/tmp}/vacuity-corrupt-sites.tsv\" && bun scripts/vacuity-mutation-battery.ts \"${TMPDIR:-/tmp}/vacuity-corrupt-sites.tsv\"",
52
+ "test:vacuity-battery:source": "bun scripts/vacuity-mutation-battery.ts scripts/vacuity-manifests/source-side.tsv",
53
+ "test:vacuity-battery:chain": "bun scripts/vacuity-mutation-battery.ts scripts/vacuity-manifests/install-chain.tsv",
54
+ "test:vacuity-battery:vars": "bun scripts/vacuity-mutation-battery.ts scripts/vacuity-manifests/variable-operands.tsv",
55
+ "test:vacuity-battery:reorder": "bun scripts/vacuity-mutation-battery.ts scripts/vacuity-manifests/reorder.tsv",
43
56
  "test:coverage": "bun test --coverage",
44
57
  "dev:cli": "bun run src/cli/index.ts",
58
+ "desktop:snapshot": "bun run src/cli/index.ts app snapshot",
45
59
  "dev:mcp": "bun run src/mcp/index.ts",
46
60
  "verify:release": "bun run scripts/release-guard.ts",
47
- "prepack": "bun run build:native-fs-guard && bun run build && bun run verify:release",
48
- "prepublishOnly": "bun run typecheck && bun run test"
61
+ "scan:artifact": "bun run scripts/scan-artifact.ts",
62
+ "version:set": "bun run scripts/set-version.ts",
63
+ "version:check": "bun run scripts/set-version.ts --check",
64
+ "prepack": "bun run prepack:platform-gate && bun run version:check && bun run build && bun run verify:release && bun run scan:artifact",
65
+ "prepack:platform-gate": "bash -c 'if [ \"$(uname -s)\" = Darwin ]; then bun run build:native-fs-guard; else echo \"WARN: native fs-guard build skipped on $(uname -s) — dry-run/CI pack; publish recordings from macOS\"; fi'",
66
+ "prepublishOnly": "bun run typecheck && bun run test",
67
+ "typecheck:shortcut-contract": "tsc --noEmit -p tsconfig.test.json"
49
68
  },
50
69
  "files": [
51
70
  "dist/",
@@ -64,8 +83,8 @@
64
83
  "LICENSE"
65
84
  ],
66
85
  "dependencies": {
67
- "@hasna/contracts": "^0.4.2",
68
- "@hasna/events": "^0.1.11",
86
+ "@hasna/contracts": "0.8.4",
87
+ "@hasna/events": "0.1.11",
69
88
  "@modelcontextprotocol/sdk": "^1.12.1",
70
89
  "chalk": "^5.4.1",
71
90
  "commander": "^13.1.0",
@@ -14,8 +14,20 @@ PACKAGE_ROOT="$(cd "$(/usr/bin/dirname "$0")/.." && /bin/pwd -P)"
14
14
  SOURCE="$PACKAGE_ROOT/scripts/native/recordings_fs_guard.c"
15
15
  OUTPUT="${1:-$PACKAGE_ROOT/scripts/native/prebuilds/darwin-universal/recordings_fs_guard.node}"
16
16
  HEADERS="${2:-$PACKAGE_ROOT/node_modules/node-api-headers/include}"
17
- CLANG="$(/usr/bin/xcrun --find clang)"
17
+ CLANG="$(/usr/bin/xcrun --sdk macosx --find clang)"
18
+ SDK_PATH="$(/usr/bin/xcrun --sdk macosx --show-sdk-path)"
18
19
 
20
+ [ -n "$SDK_PATH" ] && [ -d "$SDK_PATH" ] || {
21
+ echo "Could not resolve a usable macOS SDK with pinned /usr/bin/xcrun." >&2
22
+ exit 1
23
+ }
24
+ # The published SDK path is a symlink (MacOSX.sdk -> MacOSX<version>.sdk), so
25
+ # canonicalize it and require the resolved sysroot to expose libc headers.
26
+ SDK_PATH="$(cd "$SDK_PATH" && /bin/pwd -P)"
27
+ [ -f "$SDK_PATH/usr/include/dirent.h" ] || {
28
+ echo "Resolved macOS SDK at ${SDK_PATH} does not provide system headers." >&2
29
+ exit 1
30
+ }
19
31
  [ -f "$SOURCE" ] && [ ! -L "$SOURCE" ] || {
20
32
  echo "Native filesystem guard source is missing or unsafe." >&2
21
33
  exit 1
@@ -41,6 +53,7 @@ COMMON=(
41
53
  -DNAPI_VERSION=9
42
54
  -DNODE_GYP_MODULE_NAME=recordings_fs_guard
43
55
  -I "$HEADERS"
56
+ -isysroot "$SDK_PATH"
44
57
  -mmacosx-version-min=13.0
45
58
  )
46
59
 
@@ -50,7 +63,7 @@ COMMON=(
50
63
  -output "$WORK_DIR/recordings_fs_guard.node"
51
64
  /bin/chmod 0644 "$WORK_DIR/recordings_fs_guard.node"
52
65
  /bin/mv "$WORK_DIR/recordings_fs_guard.node" "$OUTPUT"
53
- /usr/bin/lipo -verify_arch arm64 x86_64 "$OUTPUT"
66
+ /usr/bin/lipo "$OUTPUT" -verify_arch arm64 x86_64
54
67
  [ ! -e "$OUTPUT_PARENT/.recordings-fs-guard-build" ] || {
55
68
  echo "Native filesystem guard build intermediates escaped the private build directory." >&2
56
69
  exit 1