@hasna/recordings 0.3.13 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +279 -43
- package/bun.lock +37 -38
- package/contracts/v1/fixtures.json +1206 -0
- package/dist/cli/index.js +1909 -619
- package/dist/cli/macos-shortcut.d.ts +2 -2
- package/dist/contracts/hosted-v1.d.ts +105 -0
- package/dist/contracts/hosted-v1.d.ts.map +1 -0
- package/dist/contracts/hosted-v1.js +41 -0
- package/dist/contracts/stream-v1.d.ts +117 -0
- package/dist/contracts/stream-v1.d.ts.map +1 -0
- package/dist/contracts/stream-v1.js +35 -0
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/pg-migrations.d.ts.map +1 -1
- package/dist/db/recordings.d.ts +6 -0
- package/dist/db/recordings.d.ts.map +1 -1
- package/dist/hosted/index.d.ts +58 -0
- package/dist/hosted/index.d.ts.map +1 -0
- package/dist/hosted/index.js +266 -0
- package/dist/hosted/transport.d.ts +36 -0
- package/dist/hosted/transport.d.ts.map +1 -0
- package/dist/hosted-v1-aavn7ktb.js +4114 -0
- package/dist/hosted-v1-gdr9extc.js +84 -0
- package/dist/http/client.d.ts +183 -22
- package/dist/http/client.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2879 -2288
- package/dist/lib/audio-artifact-storage.d.ts +98 -0
- package/dist/lib/audio-artifact-storage.d.ts.map +1 -0
- package/dist/lib/capture-probe.d.ts +3 -3
- package/dist/lib/capture-probe.d.ts.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/local-opt-in.d.ts +132 -0
- package/dist/lib/local-opt-in.d.ts.map +1 -0
- package/dist/lib/macos-bundle.d.ts +1 -1
- package/dist/lib/persistence-probe.d.ts +56 -17
- package/dist/lib/persistence-probe.d.ts.map +1 -1
- package/dist/lib/transcriber.d.ts.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1713 -459
- package/dist/sdk/index.d.ts +13 -5
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +904 -1
- package/dist/sdk/resolve.d.ts +53 -0
- package/dist/sdk/resolve.d.ts.map +1 -0
- package/dist/sdk/v1.generated.d.ts +6 -0
- package/dist/sdk/v1.generated.d.ts.map +1 -1
- package/dist/server/client-ip.d.ts +39 -0
- package/dist/server/client-ip.d.ts.map +1 -0
- package/dist/server/cloud-config.d.ts +12 -0
- package/dist/server/cloud-config.d.ts.map +1 -1
- package/dist/server/cloud-readiness.d.ts.map +1 -1
- package/dist/server/cloud.d.ts +20 -2
- package/dist/server/cloud.d.ts.map +1 -1
- package/dist/server/index.js +590 -287
- package/dist/server/migrate-command.d.ts +1 -1
- package/dist/server/migrate-command.d.ts.map +1 -1
- package/dist/server/openapi.d.ts +21 -0
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/repo.d.ts.map +1 -1
- package/dist/server/serve.d.ts.map +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +1358 -874
- package/dist/store.d.ts +12 -3
- package/dist/store.d.ts.map +1 -1
- package/dist/types/index.d.ts +15 -0
- package/dist/types/index.d.ts.map +1 -1
- package/docs/hosted-sdk.md +71 -0
- package/docs/wire-contracts.md +24 -0
- package/package.json +33 -11
- package/packaging/macos/build_release_pkg.sh +3 -3
- package/packaging/macos/managed_bootstrap.sh +4 -4
- package/packaging/macos/scripts/postinstall +2 -2
- package/packaging/macos/scripts/preinstall +2 -2
- package/scripts/build_companion_cli.sh +7 -1
- package/scripts/ci-linux-suite.ts +23 -13
- package/scripts/install_macos_app.sh +27 -24
- package/scripts/macos_artifact.ts +60 -49
- package/scripts/migrate.ts +4 -20
- package/scripts/native/prebuilds/darwin-universal/recordings_fs_guard.node +0 -0
- package/scripts/native/recordings_fs_guard.c +36 -4
- package/scripts/native-core-receipt.py +171 -0
- package/scripts/native_fs_guard.ts +2 -0
- package/scripts/release-suite-gate.ts +227 -150
- package/scripts/resolve_tailscale_cli.sh +24 -3
- package/scripts/smoke_macos_app.sh +21 -21
- package/src/native/Recordings/App/ContentView.swift +53 -68
- package/src/native/Recordings/App/MenuBarStatusView.swift +171 -61
- package/src/native/Recordings/App/RecordWorkspaceView.swift +47 -449
- package/src/native/Recordings/App/RecorderSettingsView.swift +75 -0
- package/src/native/Recordings/App/RecordingDetailView.swift +3 -4
- package/src/native/Recordings/App/RecordingsApp.swift +185 -9
- package/src/native/Recordings/App/RecordingsListView.swift +60 -112
- package/src/native/Recordings/App/RecordingsStore.swift +124 -109
- package/src/native/Recordings/App/Theme.swift +73 -61
- package/src/native/Recordings/Package.swift +1 -0
- package/src/native/Recordings/RecordingsLib/BlockingOperation.swift +29 -0
- package/src/native/Recordings/RecordingsLib/CaptureMonitor.swift +65 -0
- package/src/native/Recordings/RecordingsLib/Info.plist +3 -3
- package/src/native/Recordings/RecordingsLib/OpenAIAPIKeyStore.swift +75 -21
- package/src/native/Recordings/RecordingsLib/ProjectStore.swift +4 -4
- package/src/native/Recordings/RecordingsLib/Recording.swift +14 -2
- package/src/native/Recordings/RecordingsLib/RecordingEngine.swift +539 -89
- package/src/native/Recordings/RecordingsLib/RecordingGlassBackground.swift +34 -0
- package/src/native/Recordings/RecordingsLib/RecordingPasteTarget.swift +114 -0
- package/src/native/Recordings/RecordingsLib/RecordingProvider.swift +112 -0
- package/src/native/Recordings/RecordingsLib/RecordingsCLI.swift +17 -10
- package/src/native/Recordings/RecordingsLib/ServiceAPIConfiguration.swift +107 -0
- package/src/native/Recordings/RecordingsLib/ServiceConnectionView.swift +76 -0
- package/src/native/Recordings/RecordingsLib/SettingsView.swift +45 -149
- package/src/native/Recordings/RecordingsLib/SettingsWindowController.swift +48 -0
- package/src/native/Recordings/RecordingsTests/BlockingOperationTests.swift +85 -0
- package/src/native/Recordings/RecordingsTests/CLIRunnerTests.swift +454 -76
- package/src/native/Recordings/RecordingsTests/OpenAIAPIKeyStoreTests.swift +43 -38
- package/src/native/Recordings/RecordingsTests/PipeClosureFixture.swift +215 -0
- package/src/native/Recordings/RecordingsTests/ProjectStoreTests.swift +10 -10
- package/src/native/Recordings/RecordingsTests/RecorderSurfaceTests.swift +60 -0
- package/src/native/Recordings/RecordingsTests/RecordingDateTests.swift +26 -0
- package/src/native/Recordings/RecordingsTests/RecordingEngineDeliveryTests.swift +1 -1
- package/src/native/Recordings/RecordingsTests/RecordingFrozenPasteTargetTests.swift +50 -0
- package/src/native/Recordings/RecordingsTests/RecordingPasteTargetTrackerTests.swift +48 -0
- package/src/native/Recordings/RecordingsTests/RecordingProviderTests.swift +308 -0
- package/src/native/Recordings/RecordingsTests/RecordingStartGateTests.swift +1 -1
- package/src/native/Recordings/RecordingsTests/RecordingStartTimingTests.swift +123 -21
- package/src/native/Recordings/RecordingsTests/ServiceAPIConfigurationTests.swift +75 -0
- package/src/native/Recordings/RecordingsTests/SettingsWindowControllerTests.swift +28 -0
- package/src/native/Recordings/RecordingsTests/TestHomeDirectory.swift +5 -1
- package/src/native/Recordings/Updater/BootstrapPreflight/BootstrapPreflightMain.swift +1 -1
- package/src/native/Recordings/Updater/Broker/ApplicationNamespace.swift +2 -2
- package/src/native/Recordings/Updater/Broker/BrokerMain.swift +1 -1
- package/src/native/Recordings/Updater/Broker/CanonicalTreeCopy.swift +1 -1
- package/src/native/Recordings/Updater/Broker/InstallJournal.swift +1 -1
- package/src/native/Recordings/Updater/BrokerTests/ActivationRecoveryPolicyTests.swift +2 -2
- package/src/native/Recordings/Updater/Protocol/UpdateProtocol.swift +1 -1
- package/src/native/Recordings/Updater/VerifierLauncher/RecordingsVerifierLauncher.c +2 -2
- package/src/native/Recordings/build.sh +8 -7
- package/dist/__tests__/helpers/installer-guard-execution.d.ts +0 -22
- package/dist/__tests__/helpers/installer-guard-execution.d.ts.map +0 -1
- package/dist/__tests__/helpers/installer-preflight.d.ts +0 -22
- package/dist/__tests__/helpers/installer-preflight.d.ts.map +0 -1
- package/dist/__tests__/helpers/native-fs-guard.d.ts +0 -2
- package/dist/__tests__/helpers/native-fs-guard.d.ts.map +0 -1
- package/dist/__tests__/helpers/source-assertions.d.ts +0 -171
- package/dist/__tests__/helpers/source-assertions.d.ts.map +0 -1
- package/dist/__tests__/preload.d.ts +0 -2
- package/dist/__tests__/preload.d.ts.map +0 -1
- package/src/native/Recordings/App/SidebarView.swift +0 -212
package/dist/store.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Recording, CreateRecordingInput, RecordingFilter, Agent, Project } from "./types/index.js";
|
|
2
2
|
import { type FeedbackInput } from "./db/feedback.js";
|
|
3
|
+
import { type RecordsClientResolveOptions } from "./http/client.js";
|
|
4
|
+
import { AudioArtifactStorage } from "./lib/audio-artifact-storage.js";
|
|
3
5
|
export declare const APP = "recordings";
|
|
4
6
|
export type { FeedbackInput } from "./db/feedback.js";
|
|
5
7
|
export interface RecordingStats {
|
|
@@ -30,13 +32,20 @@ export interface Store {
|
|
|
30
32
|
saveFeedback(input: FeedbackInput): Promise<void>;
|
|
31
33
|
}
|
|
32
34
|
export declare function countStoreRecordings(store: Store, filter?: RecordingFilter): Promise<number>;
|
|
35
|
+
/** Test helper: force the LocalStore's artifact kit (e.g. an in-memory bucket). */
|
|
36
|
+
export declare function __setLocalArtifactStorage(storage: AudioArtifactStorage | null): void;
|
|
37
|
+
/** Test helper: clear the artifact-storage override. */
|
|
38
|
+
export declare function __resetLocalArtifactStorage(): void;
|
|
33
39
|
/**
|
|
34
40
|
* Resolve the active Store from the environment. Cached per-process after first
|
|
35
41
|
* resolution against `process.env`; pass an explicit `env` (e.g. in tests) to
|
|
36
|
-
* bypass the cache.
|
|
37
|
-
*
|
|
42
|
+
* bypass the cache. The hosted client re-resolves its credential on every
|
|
43
|
+
* request through the @hasna/contracts chain, so the cache never freezes a
|
|
44
|
+
* key. Throws a `REMOTE_API_*` failure when no credential resolves — the
|
|
45
|
+
* on-box file is reachable only through the explicit
|
|
46
|
+
* `HASNA_RECORDINGS_LOCAL=1` opt-in, never as a fallback.
|
|
38
47
|
*/
|
|
39
|
-
export declare function getStore(env?: NodeJS.ProcessEnv | Record<string, string | undefined
|
|
48
|
+
export declare function getStore(env?: NodeJS.ProcessEnv | Record<string, string | undefined>, options?: RecordsClientResolveOptions): Store;
|
|
40
49
|
/** Test helper: clear the cached Store. */
|
|
41
50
|
export declare function __resetStore(): void;
|
|
42
51
|
//# sourceMappingURL=store.d.ts.map
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export interface Recording {
|
|
2
2
|
id: string;
|
|
3
3
|
audio_path: string | null;
|
|
4
|
+
/** Object key of the uploaded audio in the configured artifact bucket, when the upload happened. */
|
|
5
|
+
audio_object_key: string | null;
|
|
6
|
+
/** Lowercase hex sha-256 of the uploaded audio bytes; content-addressed storage identity. */
|
|
7
|
+
audio_sha256: string | null;
|
|
8
|
+
/** Byte size of the uploaded audio object. */
|
|
9
|
+
audio_bytes: number | null;
|
|
4
10
|
raw_text: string;
|
|
5
11
|
processed_text: string | null;
|
|
6
12
|
processing_mode: ProcessingMode;
|
|
@@ -24,6 +30,9 @@ export interface CreateRecordingInput {
|
|
|
24
30
|
/** Stable caller-owned identity for retrying one logical recording create. */
|
|
25
31
|
id?: string;
|
|
26
32
|
audio_path?: string;
|
|
33
|
+
audio_object_key?: string;
|
|
34
|
+
audio_sha256?: string;
|
|
35
|
+
audio_bytes?: number;
|
|
27
36
|
raw_text: string;
|
|
28
37
|
processed_text?: string;
|
|
29
38
|
processing_mode?: ProcessingMode;
|
|
@@ -93,6 +102,12 @@ export interface RecordingsConfig {
|
|
|
93
102
|
db_path: string;
|
|
94
103
|
audio_dir: string;
|
|
95
104
|
max_recording_seconds: number;
|
|
105
|
+
/** Artifact bucket for uploaded audio (HASNA_RECORDINGS_S3_BUCKET / RECORDINGS_S3_BUCKET). Empty = local-only. */
|
|
106
|
+
s3_bucket: string;
|
|
107
|
+
/** Object-key prefix inside the bucket; defaults to "recordings" when the bucket is set. */
|
|
108
|
+
s3_prefix: string;
|
|
109
|
+
/** AWS region for the S3 client; defaults to AWS_REGION, then us-east-1. */
|
|
110
|
+
s3_region: string;
|
|
96
111
|
config_warnings?: string[];
|
|
97
112
|
}
|
|
98
113
|
export interface TranscriptionResult {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,oGAAoG;IACpG,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,6FAA6F;IAC7F,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,8CAA8C;IAC9C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,cAAc,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,UAAU,CAAC;AAEhD,MAAM,WAAW,oBAAoB;IACnC,8EAA8E;IAC9E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,cAAc,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,cAAc,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAID,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE3D,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,4BAA4B,CAAC,EAAE,MAAM,CAAC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;IAC1C,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,kHAAkH;IAClH,SAAS,EAAE,MAAM,CAAC;IAClB,4FAA4F;IAC5F,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAID,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAID,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,EAAE,EAAE,MAAM;CAIvB;AAED,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Hosted SDK
|
|
2
|
+
|
|
3
|
+
`@hasna/recordings/hosted` provides `HostedRecordingsClient` for hosted recording
|
|
4
|
+
metadata, account and paste-history operations. The existing `./sdk` retains its
|
|
5
|
+
separate legacy API. This additive client neither translates legacy fields nor
|
|
6
|
+
records audio, opens a login browser, manages credentials or starts a speech
|
|
7
|
+
provider. Bun is the tested runtime; browser compatibility is not claimed.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { HostedRecordingsClient, recordingCursor } from "@hasna/recordings/hosted";
|
|
11
|
+
|
|
12
|
+
const client = new HostedRecordingsClient({
|
|
13
|
+
apiBase: configuration.completeV1Base,
|
|
14
|
+
credentialProvider: ({ apiBase, signal }) => session.accessTokenFor(apiBase, signal),
|
|
15
|
+
});
|
|
16
|
+
const { recordings } = await client.listRecordings({ limit: 25 });
|
|
17
|
+
if (recordings.length === 25) {
|
|
18
|
+
const next = await client.listRecordings({ limit: 25, ...recordingCursor(recordings.at(-1)!) });
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The caller supplies a complete API base ending in `/v1`, including any prefix.
|
|
23
|
+
Remote bases require HTTPS; HTTP requires an explicit exact loopback address.
|
|
24
|
+
The client has no default endpoint or ambient environment, disk or Keychain
|
|
25
|
+
credential lookup. Public `health()` and `version()` never request credentials;
|
|
26
|
+
all other methods request a fresh caller-supplied Bearer credential. Injected
|
|
27
|
+
`fetch` is trusted and must honor manual redirects and AbortSignal. No request
|
|
28
|
+
follows a redirect, sends cookies or retries automatically.
|
|
29
|
+
|
|
30
|
+
`bootstrap()` sends an empty object; the server derives account/profile authority
|
|
31
|
+
from the authenticated session. `account()` reads that account and `ready()`
|
|
32
|
+
checks authenticated readiness. The caller owns OAuth, refresh and credential
|
|
33
|
+
storage. `logout()` revokes the current server session family; the caller must
|
|
34
|
+
also clear its stored credentials.
|
|
35
|
+
|
|
36
|
+
`listRecordings`, `getRecording`, `saveRecording` and `renameRecording` use
|
|
37
|
+
camelCase values: `id`, optional `sessionId`, `title`, `transcript`, and
|
|
38
|
+
`durationMs`. Duration is milliseconds. `deleteRecording` returns
|
|
39
|
+
`{state:'pending'}` for accepted cleanup or `{state:'removed'}` for completed
|
|
40
|
+
deletion. Pending is not proof that audio has been purged. Repeat explicitly;
|
|
41
|
+
reads may return the `recording_deleted` error after a permanent tombstone.
|
|
42
|
+
|
|
43
|
+
`listPasteReceipts`, `savePasteReceipt`, `deletePasteReceipt` and
|
|
44
|
+
`clearPasteHistory` use the hosted paste contract. An input `occurredAt` must be
|
|
45
|
+
UTC ending in `Z`; omit it for server time. `client_reported` receipt evidence
|
|
46
|
+
does not mean the server observed the target. Empty text remains valid when
|
|
47
|
+
retention is disabled. Recordings and receipts can contain private text; callers
|
|
48
|
+
should avoid logging responses.
|
|
49
|
+
|
|
50
|
+
Both lists require `before` and `beforeId` together or neither. `recordingCursor`
|
|
51
|
+
selects the last row's `createdAt` and ID; `pasteCursor` selects its `occurredAt`
|
|
52
|
+
and ID. There is no inferred total or automatic pagination. A full page can be
|
|
53
|
+
the last page. Inputs are validated before credentials or fetch; future JSON
|
|
54
|
+
response fields are preserved. Advertised metadata must include a compatible
|
|
55
|
+
version and all required capabilities; entirely absent metadata remains legacy
|
|
56
|
+
compatible. This is stricter than an older hosted adapter that accepted empty
|
|
57
|
+
capability advertisements.
|
|
58
|
+
|
|
59
|
+
The default 20-second deadline includes credential acquisition and the entire
|
|
60
|
+
response body. Caller cancellation has the same scope. Encoded JSON requests
|
|
61
|
+
are limited to 1 MiB before credentials are requested. Responses are limited to
|
|
62
|
+
4 MiB of decoded bytes by default, configurable from 1 KiB to 32 MiB; compressed
|
|
63
|
+
wire Content-Length is not compared with decoded size. The transport bounds its
|
|
64
|
+
growing buffer, not total process memory. Error bodies are cancelled unread.
|
|
65
|
+
|
|
66
|
+
`RecordingsSDKError` contains a fixed code/message and optional HTTP status and
|
|
67
|
+
validated UUID request ID. It retains no body, endpoint, token, server message or
|
|
68
|
+
original cause. A timed-out mutation may already have committed: reconcile using
|
|
69
|
+
the known recording or receipt ID instead of blindly retrying. This JSON client
|
|
70
|
+
does not implement audio upload/download, WebSocket sessions, native app control,
|
|
71
|
+
tenant storage, usage admission or provider execution.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Hosted recording wire contracts
|
|
2
|
+
|
|
3
|
+
The additive `@hasna/recordings/contracts/hosted-v1` and `@hasna/recordings/contracts/stream-v1` exports describe hosted recording metadata and PCM streaming. They perform no I/O, choose no endpoint, read no credentials and implement no provider or storage backend. Existing `./sdk`, CLI, MCP, serve, projects and native provider interfaces keep their existing behavior. The hosted camelCase API is distinct from the legacy SDK's snake_case API. Qualified timestamps require seconds; numeric offsets require a colon and valid hour/minute ranges.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { recordingInputParser } from "@hasna/recordings/contracts/hosted-v1";
|
|
7
|
+
import { streamEventParser } from "@hasna/recordings/contracts/stream-v1";
|
|
8
|
+
|
|
9
|
+
const request = recordingInputParser.parse(input);
|
|
10
|
+
const event = streamEventParser.safeParse(decodedEvent);
|
|
11
|
+
if (!event.success) handleInvalidContract(event.error.code);
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Every parser exposes an explicit `ContractParser<T>` interface with plain DTOs. `parse` throws a fixed `ContractValidationError`; `safeParse` returns `{success: true, data}` or `{success: false, error: {code: "invalid_contract"}}`. Neither error retains rejected data, schema-library internals or a cause. Consumers using different validation libraries can use these interfaces without exchanging Zod types.
|
|
15
|
+
|
|
16
|
+
Inputs reject unknown fields. Recording input has a UUID, title, transcript and duration in milliseconds; caller input cannot supply trusted provenance. Titles are trimmed. Paste input uses UTC timestamps ending in `Z`; output timestamps may have offsets. A paste receipt's `client_reported` evidence does not mean the server observed the target. Pagination requires `before` and `beforeId` together, or neither; either cursor component alone is invalid. Responses preserve extra JSON fields, including nested fields, while still checking known fields.
|
|
17
|
+
|
|
18
|
+
Hosted wire version `1.0` is independent of package and local-control versions. Metadata may be entirely absent for legacy v1. Once advertised, version and capabilities must both be present: major `1`, bounded minor, unique valid capability names, and all four required capabilities. Future compatible minors and additional capabilities are accepted. No incompatible advertisement downgrades to legacy mode. Bootstrap and version response parsers enforce these rules too. This intentionally tightens the previous hosted SDK's permissive metadata parsing to match service/native negotiation; it does not modify the legacy public SDK.
|
|
19
|
+
|
|
20
|
+
Streaming controls are strict. `parseStreamControlJSON` also enforces the existing 20,000-byte UTF-8 control-message ceiling. `pcmFrameParser` accepts only nonempty even-length PCM16 frames, from 2 through 24,000 bytes, without copying or converting them. The format is 24 kHz mono signed little-endian PCM16. Stream event parsers validate known event types, bounds, final capture identity and complete advertised metadata. New fields are allowed; unknown event types are rejected. Legacy final events may omit segments/provenance/recordingId, and legacy ready events may omit metadata/window fields.
|
|
21
|
+
|
|
22
|
+
These are value contracts, not a session state machine. The consumer must bind events to its current capture, require ready before sending, enforce sequence ordering, cumulative/buffer/deadline limits, require input finish before final delivery, validate renewal expiry against its clock, and require ready metadata when bootstrap advertised it. `acceptsAudioAcknowledgement` is a pure check against the consumer's sent and acknowledged byte counts; it does not update those counts. The consumer owns consent, authorization, cancellation and error display. Error-event messages are untrusted data and must not be logged as validation diagnostics.
|
|
23
|
+
|
|
24
|
+
Fictional positive and negative interoperability vectors are exported as `@hasna/recordings/contracts/fixtures/v1`. They freeze current input/output differences explicitly. Contract additions do not repoint or replace any legacy API. A subsequent reviewed package release and consumer adoption are required; introducing these modules does not publish them or change a deployed service.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/recordings",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
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": {
|
|
@@ -26,6 +26,19 @@
|
|
|
26
26
|
"./sdk": {
|
|
27
27
|
"import": "./dist/sdk/index.js",
|
|
28
28
|
"types": "./dist/sdk/index.d.ts"
|
|
29
|
+
},
|
|
30
|
+
"./contracts/hosted-v1": {
|
|
31
|
+
"import": "./dist/contracts/hosted-v1.js",
|
|
32
|
+
"types": "./dist/contracts/hosted-v1.d.ts"
|
|
33
|
+
},
|
|
34
|
+
"./contracts/stream-v1": {
|
|
35
|
+
"import": "./dist/contracts/stream-v1.js",
|
|
36
|
+
"types": "./dist/contracts/stream-v1.d.ts"
|
|
37
|
+
},
|
|
38
|
+
"./contracts/fixtures/v1": "./contracts/v1/fixtures.json",
|
|
39
|
+
"./hosted": {
|
|
40
|
+
"import": "./dist/hosted/index.js",
|
|
41
|
+
"types": "./dist/hosted/index.d.ts"
|
|
29
42
|
}
|
|
30
43
|
},
|
|
31
44
|
"engines": {
|
|
@@ -34,20 +47,20 @@
|
|
|
34
47
|
"scripts": {
|
|
35
48
|
"clean": "rm -rf dist",
|
|
36
49
|
"build": "bun run clean && bun run build:cli && bun run build:mcp && bun run build:serve && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
|
|
37
|
-
"build:cli": "bun build src/cli/index.ts --target=bun --outfile=dist/cli/index.js --external=commander --external=chalk --external=openai",
|
|
38
|
-
"build:mcp": "bun build src/mcp/index.ts --target=bun --outfile=dist/mcp/index.js --external=@modelcontextprotocol/sdk --external=openai",
|
|
39
|
-
"build:serve": "bun build src/server/index.ts --target=bun --outfile=dist/server/index.js --external=@modelcontextprotocol/sdk --external=@hasna/contracts --external=openai --external=pg",
|
|
40
|
-
"build:lib": "bun build src/index.ts src/storage.ts src/sdk/index.ts --target=bun --outdir=dist --external=openai",
|
|
50
|
+
"build:cli": "bun build src/cli/index.ts --target=bun --outfile=dist/cli/index.js --external=commander --external=chalk --external=openai --external=@aws-sdk/client-s3",
|
|
51
|
+
"build:mcp": "bun build src/mcp/index.ts --target=bun --outfile=dist/mcp/index.js --external=@modelcontextprotocol/sdk --external=openai --external=@aws-sdk/client-s3",
|
|
52
|
+
"build:serve": "bun build src/server/index.ts --target=bun --outfile=dist/server/index.js --external=@modelcontextprotocol/sdk --external=@hasna/contracts --external=openai --external=pg --external=@aws-sdk/client-s3",
|
|
53
|
+
"build:lib": "bun build src/index.ts src/storage.ts src/sdk/index.ts --target=bun --outdir=dist --external=openai --external=@aws-sdk/client-s3 && bun run build:contracts",
|
|
41
54
|
"build:native-fs-guard": "/bin/bash scripts/build_native_fs_guard.sh",
|
|
42
55
|
"generate:sdk": "bun run scripts/generate-sdk.ts",
|
|
43
56
|
"migrate": "bun run scripts/migrate.ts",
|
|
44
57
|
"typecheck": "tsc --noEmit",
|
|
45
58
|
"typecheck:tcc-contract": "tsc --noEmit -p tsconfig.tcc-contract.json",
|
|
46
|
-
"test": "bun
|
|
59
|
+
"test": "bun scripts/release-suite-gate.ts --all",
|
|
47
60
|
"verify:ci-suite": "bun scripts/ci-linux-suite.ts --check",
|
|
48
61
|
"verify:ci-suite:run": "bun scripts/ci-linux-suite.ts --verify-run",
|
|
49
62
|
"verify:ci-native": "bun scripts/ci-native-build.ts",
|
|
50
|
-
"test:gated": "bun scripts/
|
|
63
|
+
"test:gated": "bun scripts/release-suite-gate.ts",
|
|
51
64
|
"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
65
|
"test:vacuity-battery:source": "bun scripts/vacuity-mutation-battery.ts scripts/vacuity-manifests/source-side.tsv",
|
|
53
66
|
"test:vacuity-battery:chain": "bun scripts/vacuity-mutation-battery.ts scripts/vacuity-manifests/install-chain.tsv",
|
|
@@ -65,11 +78,16 @@
|
|
|
65
78
|
"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
79
|
"prepublishOnly": "bun run typecheck && bun run release-suite-gate",
|
|
67
80
|
"release-suite-gate": "bun run scripts/release-suite-gate.ts",
|
|
68
|
-
"typecheck:shortcut-contract": "tsc --noEmit -p tsconfig.test.json"
|
|
81
|
+
"typecheck:shortcut-contract": "tsc --noEmit -p tsconfig.test.json",
|
|
82
|
+
"build:contracts": "bun build src/contracts/hosted-v1.ts src/contracts/stream-v1.ts src/hosted/index.ts --target=bun --root src --outdir=dist --splitting --external=@hasna/contracts"
|
|
69
83
|
},
|
|
70
84
|
"files": [
|
|
71
85
|
"dist/",
|
|
86
|
+
"!dist/__tests__/",
|
|
72
87
|
"scripts/",
|
|
88
|
+
"!scripts/test-recorder-fixtures.ts",
|
|
89
|
+
"!scripts/**/__pycache__/",
|
|
90
|
+
"!scripts/**/*.pyc",
|
|
73
91
|
"Dockerfile.package",
|
|
74
92
|
"bun.lock",
|
|
75
93
|
"src/native/Recordings/App/",
|
|
@@ -81,10 +99,14 @@
|
|
|
81
99
|
"src/native/Recordings/build.sh",
|
|
82
100
|
"packaging/macos/",
|
|
83
101
|
"README.md",
|
|
84
|
-
"LICENSE"
|
|
102
|
+
"LICENSE",
|
|
103
|
+
"contracts/v1/fixtures.json",
|
|
104
|
+
"docs/wire-contracts.md",
|
|
105
|
+
"docs/hosted-sdk.md"
|
|
85
106
|
],
|
|
86
107
|
"dependencies": {
|
|
87
|
-
"@
|
|
108
|
+
"@aws-sdk/client-s3": "^3.1007.0",
|
|
109
|
+
"@hasna/contracts": "1.0.2",
|
|
88
110
|
"@hasna/events": "0.1.11",
|
|
89
111
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
90
112
|
"chalk": "^5.4.1",
|
|
@@ -94,7 +116,7 @@
|
|
|
94
116
|
"zod": "^3.24.2"
|
|
95
117
|
},
|
|
96
118
|
"devDependencies": {
|
|
97
|
-
"@types/bun": "
|
|
119
|
+
"@types/bun": "1.3.14",
|
|
98
120
|
"@types/pg": "^8.11.11",
|
|
99
121
|
"node-api-headers": "1.9.0",
|
|
100
122
|
"typescript": "^5.8.2"
|
|
@@ -224,7 +224,7 @@ case "$VERSION" in
|
|
|
224
224
|
esac
|
|
225
225
|
# The artifact basename is derived from the canonical bundle identity, never hardcoded:
|
|
226
226
|
# build.sh emits ${APP_BASENAME}-${VERSION}-macos-${RELEASE_SUBTYPE} with APP_BASENAME
|
|
227
|
-
# taken from the bundle name (currently
|
|
227
|
+
# taken from the bundle name (currently Hasna Recordings.app). The legacy
|
|
228
228
|
# Recordings-* form was dropped with the bundle rename and must not be re-required.
|
|
229
229
|
[ -n "$APP" ] && [ -d "$APP" ] || { echo "Package app bundle path is missing or invalid." >&2; exit 2; }
|
|
230
230
|
expected_basename="$(/usr/bin/basename "$APP" .app)-${VERSION}-macos-initial-bootstrap"
|
|
@@ -533,7 +533,7 @@ PACKAGE_BOOTSTRAP_ID="$(/usr/bin/uuidgen | /usr/bin/tr '[:upper:]' '[:lower:]')"
|
|
|
533
533
|
"$SCRIPTS"
|
|
534
534
|
require_no_extended_acl "$PACKAGE_STAGE_DIR"
|
|
535
535
|
|
|
536
|
-
/usr/bin/ditto "$APP" "$ROOT/Applications/
|
|
536
|
+
/usr/bin/ditto "$APP" "$ROOT/Applications/Hasna Recordings.app"
|
|
537
537
|
/bin/cp "$BROKER" "$ROOT/Library/PrivilegedHelperTools/com.hasna.recordings.updater"
|
|
538
538
|
/bin/cp "$VERIFIER" "$ROOT/Library/PrivilegedHelperTools/com.hasna.recordings.artifact-verifier"
|
|
539
539
|
/bin/cp "$PUBLIC_KEY" "$ROOT/Library/Application Support/Hasna/Recordings/Trust/envelope-keys/${KEY_EPOCH}.raw"
|
|
@@ -582,7 +582,7 @@ require_tree_without_extended_acl "$SCRIPTS"
|
|
|
582
582
|
"$ROOT/Library/LaunchDaemons/com.hasna.recordings.updater.plist"
|
|
583
583
|
/usr/bin/plutil -lint "$ROOT/Library/LaunchDaemons/com.hasna.recordings.updater.plist" >/dev/null
|
|
584
584
|
|
|
585
|
-
STAGED_APP="$ROOT/Applications/
|
|
585
|
+
STAGED_APP="$ROOT/Applications/Hasna Recordings.app"
|
|
586
586
|
STAGED_BROKER="$ROOT/Library/PrivilegedHelperTools/com.hasna.recordings.updater"
|
|
587
587
|
STAGED_CLIENT="$STAGED_APP/Contents/Helpers/recordings-update-client"
|
|
588
588
|
STAGED_VERIFIER="$ROOT/Library/PrivilegedHelperTools/com.hasna.recordings.artifact-verifier"
|
|
@@ -173,7 +173,7 @@ validate_target_ancestry() {
|
|
|
173
173
|
|
|
174
174
|
validate_target_ancestry
|
|
175
175
|
|
|
176
|
-
CLIENT="/Applications/
|
|
176
|
+
CLIENT="/Applications/Hasna Recordings.app/Contents/Helpers/recordings-update-client"
|
|
177
177
|
STATE="/var/db/com.hasna.recordings.updater/release-state.json"
|
|
178
178
|
AUTHORIZATION_ROOT="/private/var/db/com.hasna.recordings.bootstrap-authorization"
|
|
179
179
|
AUTHORIZATION_JOURNAL="${AUTHORIZATION_ROOT}/journal"
|
|
@@ -182,7 +182,7 @@ COHORT_PATHS=(
|
|
|
182
182
|
"/Library/PrivilegedHelperTools/com.hasna.recordings.updater"
|
|
183
183
|
"/Library/PrivilegedHelperTools/com.hasna.recordings.artifact-verifier"
|
|
184
184
|
"/Library/LaunchDaemons/com.hasna.recordings.updater.plist"
|
|
185
|
-
"/Applications/
|
|
185
|
+
"/Applications/Hasna Recordings.app"
|
|
186
186
|
"$CLIENT"
|
|
187
187
|
"/Library/Application Support/Hasna/Recordings/Trust"
|
|
188
188
|
"/Library/Application Support/Hasna/Recordings/Bootstrap"
|
|
@@ -304,7 +304,7 @@ PAYLOAD="$EXPANDED/Payload"
|
|
|
304
304
|
PREFLIGHT="$EXPANDED/Scripts/recordings-bootstrap-preflight"
|
|
305
305
|
EXPANDED_PREINSTALL="$EXPANDED/Scripts/preinstall"
|
|
306
306
|
EXPANDED_POSTINSTALL="$EXPANDED/Scripts/postinstall"
|
|
307
|
-
PAYLOAD_CLIENT="$PAYLOAD/Applications/
|
|
307
|
+
PAYLOAD_CLIENT="$PAYLOAD/Applications/Hasna Recordings.app/Contents/Helpers/recordings-update-client"
|
|
308
308
|
[ -d "$PAYLOAD" ] && [ ! -L "$PAYLOAD" ] && \
|
|
309
309
|
[ -x "$PREFLIGHT" ] && [ ! -L "$PREFLIGHT" ] && \
|
|
310
310
|
[ -x "$EXPANDED_PREINSTALL" ] && [ ! -L "$EXPANDED_PREINSTALL" ] && \
|
|
@@ -512,7 +512,7 @@ cohort_expected_mode() {
|
|
|
512
512
|
"/Library/PrivilegedHelperTools/com.hasna.recordings.updater"|\
|
|
513
513
|
"/Library/PrivilegedHelperTools/com.hasna.recordings.artifact-verifier") printf '555\n' ;;
|
|
514
514
|
"/Library/LaunchDaemons/com.hasna.recordings.updater.plist") printf '444\n' ;;
|
|
515
|
-
"/Applications/
|
|
515
|
+
"/Applications/Hasna Recordings.app"|"$CLIENT") printf '755\n' ;;
|
|
516
516
|
"/Library/Application Support/Hasna/Recordings/Trust") printf '700-or-755\n' ;;
|
|
517
517
|
"/Library/Application Support/Hasna/Recordings/Bootstrap"|\
|
|
518
518
|
"/Library/Application Support/Hasna/Recordings/Updates"|\
|
|
@@ -11,9 +11,9 @@ PACKAGE_BOOTSTRAP_ID="__RECORDINGS_PACKAGE_BOOTSTRAP_ID__"
|
|
|
11
11
|
AUTHORIZATION_ROOT="/private/var/db/com.hasna.recordings.bootstrap-authorization"
|
|
12
12
|
AUTHORIZATION_JOURNAL="${AUTHORIZATION_ROOT}/journal"
|
|
13
13
|
BROKER="/Library/PrivilegedHelperTools/com.hasna.recordings.updater"
|
|
14
|
-
CLIENT="/Applications/
|
|
14
|
+
CLIENT="/Applications/Hasna Recordings.app/Contents/Helpers/recordings-update-client"
|
|
15
15
|
VERIFIER="/Library/PrivilegedHelperTools/com.hasna.recordings.artifact-verifier"
|
|
16
|
-
APP="/Applications/
|
|
16
|
+
APP="/Applications/Hasna Recordings.app"
|
|
17
17
|
STATE_ROOT="/Library/Application Support/Hasna/Recordings/Updates"
|
|
18
18
|
TRUST_ROOT="/Library/Application Support/Hasna/Recordings/Trust"
|
|
19
19
|
BOOTSTRAP_ROOT="/Library/Application Support/Hasna/Recordings/Bootstrap"
|
|
@@ -248,8 +248,8 @@ COHORT_PATHS=(
|
|
|
248
248
|
"/Library/PrivilegedHelperTools/com.hasna.recordings.updater:555"
|
|
249
249
|
"/Library/PrivilegedHelperTools/com.hasna.recordings.artifact-verifier:555"
|
|
250
250
|
"/Library/LaunchDaemons/com.hasna.recordings.updater.plist:444"
|
|
251
|
-
"/Applications/
|
|
252
|
-
"/Applications/
|
|
251
|
+
"/Applications/Hasna Recordings.app:755"
|
|
252
|
+
"/Applications/Hasna Recordings.app/Contents/Helpers/recordings-update-client:755"
|
|
253
253
|
"/Applications/Recordings.app:755"
|
|
254
254
|
"/Applications/Recordings.app/Contents/Helpers/recordings-update-client:755"
|
|
255
255
|
"/Library/Application Support/Hasna/Recordings/Trust:700-or-755"
|
|
@@ -151,7 +151,13 @@ COMPILED_ARM64="$COMPILE_DIR/recordings.arm64"
|
|
|
151
151
|
COMPILED_X86_64="$COMPILE_DIR/recordings.x86_64"
|
|
152
152
|
"$MKDIR_EXECUTABLE" -p "$BUILD_HOME" "$BUN_CACHE" "$STAGED_ROOT" "$COMPILE_DIR"
|
|
153
153
|
"$CP_EXECUTABLE" "$ROOT/package.json" "$ROOT/bun.lock" "$ROOT/bunfig.toml" "$ROOT/tsconfig.json" "$STAGED_ROOT/"
|
|
154
|
-
"$
|
|
154
|
+
"$MKDIR_EXECUTABLE" -p "$STAGED_ROOT/src"
|
|
155
|
+
# The CLI has no Swift inputs. Walking src/native also walks SwiftPM's live
|
|
156
|
+
# .build cache, whose temporary files can disappear during a native build.
|
|
157
|
+
for source_entry in "$ROOT/src/"*; do
|
|
158
|
+
[ "$source_entry" != "$ROOT/src/native" ] || continue
|
|
159
|
+
"$CP_EXECUTABLE" -R "$source_entry" "$STAGED_ROOT/src/"
|
|
160
|
+
done
|
|
155
161
|
if [ -d "$ROOT/migrations" ]; then
|
|
156
162
|
"$CP_EXECUTABLE" -R "$ROOT/migrations" "$STAGED_ROOT/migrations"
|
|
157
163
|
fi
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
*
|
|
30
30
|
* Usage:
|
|
31
31
|
* bun scripts/ci-linux-suite.ts --check validate the quarantine file, print counts
|
|
32
|
+
* bun scripts/ci-linux-suite.ts --all every discovered tracked test, including quarantine
|
|
32
33
|
* bun scripts/ci-linux-suite.ts --gated newline-separated gated files
|
|
33
34
|
* bun scripts/ci-linux-suite.ts --quarantined newline-separated quarantined files
|
|
34
35
|
* bun scripts/ci-linux-suite.ts --verify-run <log> assert a gated run honoured the partition
|
|
@@ -41,6 +42,13 @@ import { spawnSync } from "node:child_process";
|
|
|
41
42
|
export const QUARANTINE_FILE = ".github/linux-quarantine.txt";
|
|
42
43
|
|
|
43
44
|
const TEST_SUFFIX = ".test.ts";
|
|
45
|
+
const BUN_TEST_SUFFIX = /[._](?:test|spec)\.(?:[cm]?[jt]sx?)$/;
|
|
46
|
+
|
|
47
|
+
function supportedTestFiles(paths: string[]): string[] {
|
|
48
|
+
const unsupported = paths.filter(path => BUN_TEST_SUFFIX.test(path) && !path.endsWith(TEST_SUFFIX));
|
|
49
|
+
if (unsupported.length) throw new Error(`unsupported test suffix; extend discovery and JUnit contracts before adding:\n${unsupported.join("\n")}`);
|
|
50
|
+
return paths.filter(path => path.endsWith(TEST_SUFFIX));
|
|
51
|
+
}
|
|
44
52
|
|
|
45
53
|
/** Directories never worth walking. `.build` holds SwiftPM output, which can be enormous. */
|
|
46
54
|
const SKIPPED_DIRS = new Set([".git", "node_modules", ".build", "dist"]);
|
|
@@ -92,7 +100,7 @@ export function entriesMissingReason(text: string): string[] {
|
|
|
92
100
|
* in the working tree.
|
|
93
101
|
*/
|
|
94
102
|
export function testFilesFromGit(repoRoot: string): string[] {
|
|
95
|
-
const result = spawnSync("git", ["-C", repoRoot, "ls-files", "-z"
|
|
103
|
+
const result = spawnSync("git", ["-C", repoRoot, "ls-files", "-z"], {
|
|
96
104
|
encoding: "utf8",
|
|
97
105
|
});
|
|
98
106
|
if (result.status !== 0) {
|
|
@@ -100,7 +108,7 @@ export function testFilesFromGit(repoRoot: string): string[] {
|
|
|
100
108
|
}
|
|
101
109
|
// -z because a path may legally contain a newline, and a newline-split enumeration would report
|
|
102
110
|
// one such path as two missing files — a disagreement that reads as a broken walker.
|
|
103
|
-
return result.stdout.split("\0").filter((path) => path.length > 0).sort();
|
|
111
|
+
return supportedTestFiles(result.stdout.split("\0").filter((path) => path.length > 0)).sort();
|
|
104
112
|
}
|
|
105
113
|
|
|
106
114
|
/**
|
|
@@ -118,13 +126,13 @@ export function testFilesFromWalk(repoRoot: string): string[] {
|
|
|
118
126
|
if (entry.isDirectory()) {
|
|
119
127
|
if (SKIPPED_DIRS.has(entry.name)) continue;
|
|
120
128
|
walk(absolute);
|
|
121
|
-
} else if (entry.isFile()
|
|
129
|
+
} else if (entry.isFile()) {
|
|
122
130
|
found.push(relative(repoRoot, absolute).split(sep).join("/"));
|
|
123
131
|
}
|
|
124
132
|
}
|
|
125
133
|
};
|
|
126
134
|
walk(repoRoot);
|
|
127
|
-
return found.sort();
|
|
135
|
+
return supportedTestFiles(found).sort();
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
export type DiscoveryDisagreement = { trackedNotOnDisk: string[]; onDiskUntracked: string[] };
|
|
@@ -257,7 +265,7 @@ function fail(message: string): never {
|
|
|
257
265
|
process.exit(1);
|
|
258
266
|
}
|
|
259
267
|
|
|
260
|
-
function loadPartition(repoRoot: string): Partition & { discovered: string[] } {
|
|
268
|
+
function loadPartition(repoRoot: string, requireNonemptyGated = true): Partition & { discovered: string[] } {
|
|
261
269
|
const fromGit = testFilesFromGit(repoRoot);
|
|
262
270
|
const { trackedNotOnDisk, onDiskUntracked } = compareDiscovery(fromGit, testFilesFromWalk(repoRoot));
|
|
263
271
|
if (trackedNotOnDisk.length > 0) {
|
|
@@ -293,16 +301,14 @@ function loadPartition(repoRoot: string): Partition & { discovered: string[] } {
|
|
|
293
301
|
} catch (error) {
|
|
294
302
|
fail(error instanceof Error ? error.message : String(error));
|
|
295
303
|
}
|
|
296
|
-
if (split.gated.length === 0) {
|
|
304
|
+
if (requireNonemptyGated && split.gated.length === 0) {
|
|
297
305
|
fail(
|
|
298
306
|
`Every discovered test file is quarantined by ${QUARANTINE_FILE}. The gate would run nothing.`,
|
|
299
307
|
);
|
|
300
308
|
}
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
|
|
304
|
-
// silently stopped being gated.
|
|
305
|
-
const whitespace = split.gated.filter((path) => /\s/.test(path));
|
|
309
|
+
// Keep the established newline/shell-safe manifest contract in both selections.
|
|
310
|
+
// Quarantined paths are still executable inputs to the explicit all-tests mode.
|
|
311
|
+
const whitespace = fromGit.filter((path) => /\s/.test(path));
|
|
306
312
|
if (whitespace.length > 0) {
|
|
307
313
|
fail(
|
|
308
314
|
"Test paths containing whitespace cannot be passed through unquoted word splitting:\n" +
|
|
@@ -318,8 +324,12 @@ function main(argv: string[]): void {
|
|
|
318
324
|
fail(`Run this from the repository root; ${QUARANTINE_FILE} is not there.`);
|
|
319
325
|
}
|
|
320
326
|
const mode = argv[0];
|
|
321
|
-
const { gated, quarantined, discovered } = loadPartition(repoRoot);
|
|
327
|
+
const { gated, quarantined, discovered } = loadPartition(repoRoot, mode !== "--all");
|
|
322
328
|
|
|
329
|
+
if (mode === "--all") {
|
|
330
|
+
console.log(discovered.join("\n"));
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
323
333
|
if (mode === "--gated") {
|
|
324
334
|
console.log(gated.join("\n"));
|
|
325
335
|
return;
|
|
@@ -395,7 +405,7 @@ function main(argv: string[]): void {
|
|
|
395
405
|
}
|
|
396
406
|
return;
|
|
397
407
|
}
|
|
398
|
-
fail("usage: --check | --gated | --quarantined | --verify-run <junit.xml>");
|
|
408
|
+
fail("usage: --check | --all | --gated | --quarantined | --verify-run <junit.xml>");
|
|
399
409
|
}
|
|
400
410
|
|
|
401
411
|
if (import.meta.main) {
|