@hasna/recordings 0.1.35 → 0.1.37
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 +60 -0
- package/dist/cli/index.js +34 -13
- package/dist/db/storage-config.d.ts +2 -1
- package/dist/db/storage-config.d.ts.map +1 -1
- package/dist/db/storage-sync.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +152 -7
- package/dist/mcp/index.js +34 -13
- package/dist/sdk/index.d.ts +16 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +171 -0
- package/dist/sdk/v1.generated.d.ts +150 -0
- package/dist/sdk/v1.generated.d.ts.map +1 -0
- package/dist/server/cloud.d.ts +49 -0
- package/dist/server/cloud.d.ts.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +6812 -0
- package/dist/server/openapi.d.ts +614 -0
- package/dist/server/openapi.d.ts.map +1 -0
- package/dist/server/repo.d.ts +34 -0
- package/dist/server/repo.d.ts.map +1 -0
- package/dist/server/serve.d.ts +11 -0
- package/dist/server/serve.d.ts.map +1 -0
- package/dist/server/v1.d.ts +6 -0
- package/dist/server/v1.d.ts.map +1 -0
- package/dist/storage.js +17 -7
- package/dist/version.d.ts +1 -1
- package/package.json +16 -5
- package/scripts/generate-sdk.ts +31 -0
- package/scripts/install_macos_app.sh +2 -2
- package/scripts/migrate.ts +37 -0
- package/scripts/release-guard.ts +129 -0
- package/src/native/Recordings/RecordingsTests/CLIRunnerTests.swift +1 -1
package/README.md
CHANGED
|
@@ -42,6 +42,49 @@ MCP_HTTP=1 MCP_HTTP_PORT=8829 recordings-mcp
|
|
|
42
42
|
|
|
43
43
|
Endpoints: `GET /health` → `{"status":"ok","name":"recordings"}`, MCP at `/mcp`.
|
|
44
44
|
|
|
45
|
+
## HTTP API (`recordings-serve`)
|
|
46
|
+
|
|
47
|
+
`recordings-serve` is the self-hosted HTTP API. In cloud mode it is PURE REMOTE
|
|
48
|
+
(Amendment A1): the process reads/writes the shared cloud Postgres directly with
|
|
49
|
+
API-key auth via [`@hasna/contracts`](https://www.npmjs.com/package/@hasna/contracts).
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
recordings-serve --port 8874 # start the API
|
|
53
|
+
recordings-serve migrate # apply the cloud schema, then exit
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Service surface (unauthenticated): `GET /health`, `GET /ready`, `GET /version`
|
|
57
|
+
(each returns `{status, version, mode}`), and `GET /openapi.json` (the OpenAPI
|
|
58
|
+
3.1 document the SDK is generated from).
|
|
59
|
+
|
|
60
|
+
Versioned API (`/v1/*`, API-key auth via `x-api-key` or `Authorization: Bearer`):
|
|
61
|
+
|
|
62
|
+
| Method | Path | Scope |
|
|
63
|
+
| ------ | ---- | ----- |
|
|
64
|
+
| GET/POST | `/v1/recordings` | `recordings:read` / `recordings:write` |
|
|
65
|
+
| GET/DELETE | `/v1/recordings/:id` | `recordings:read` / `recordings:write` |
|
|
66
|
+
| GET | `/v1/stats` | `recordings:read` |
|
|
67
|
+
| GET/POST | `/v1/agents` · GET `/v1/agents/:id` | `recordings:read` / `recordings:write` |
|
|
68
|
+
| GET/POST | `/v1/projects` · GET `/v1/projects/:id` | `recordings:read` / `recordings:write` |
|
|
69
|
+
|
|
70
|
+
Env: `HASNA_RECORDINGS_DATABASE_URL` (remote Postgres DSN — enables cloud `/v1`)
|
|
71
|
+
and `HASNA_RECORDINGS_API_SIGNING_KEY` (HMAC signing secret for API-key auth).
|
|
72
|
+
|
|
73
|
+
## SDK
|
|
74
|
+
|
|
75
|
+
The typed `/v1` client is generated from the serve OpenAPI document
|
|
76
|
+
(`bun run generate:sdk`):
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { RecordingsV1Client } from "@hasna/recordings/sdk";
|
|
80
|
+
|
|
81
|
+
const client = new RecordingsV1Client({
|
|
82
|
+
baseUrl: process.env.RECORDINGS_API_URL!,
|
|
83
|
+
apiKey: process.env.RECORDINGS_API_KEY!,
|
|
84
|
+
});
|
|
85
|
+
const { recordings } = await client.listRecordings({ limit: 20 });
|
|
86
|
+
```
|
|
87
|
+
|
|
45
88
|
## Storage Sync
|
|
46
89
|
|
|
47
90
|
This package has native local/remote sync. Local data stays in SQLite under
|
|
@@ -49,6 +92,21 @@ This package has native local/remote sync. Local data stays in SQLite under
|
|
|
49
92
|
`HASNA_RECORDINGS_DATABASE_URL` is set or `~/.hasna/recordings/storage/config.json` is
|
|
50
93
|
configured.
|
|
51
94
|
|
|
95
|
+
The optional config file uses a `postgres` object:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"mode": "remote",
|
|
100
|
+
"postgres": {
|
|
101
|
+
"host": "db.example",
|
|
102
|
+
"port": 5432,
|
|
103
|
+
"username": "recordings",
|
|
104
|
+
"password_env": "RECORDINGS_DATABASE_PASSWORD",
|
|
105
|
+
"ssl": true
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
52
110
|
```bash
|
|
53
111
|
recordings storage status
|
|
54
112
|
recordings storage migrate
|
|
@@ -57,6 +115,8 @@ recordings storage pull
|
|
|
57
115
|
```
|
|
58
116
|
|
|
59
117
|
`RECORDINGS_DATABASE_URL` is accepted as the non-Hasna fallback database URL.
|
|
118
|
+
`HASNA_RECORDINGS_STORAGE_CONFIG` can point automation at a non-default storage
|
|
119
|
+
config file.
|
|
60
120
|
|
|
61
121
|
## Data Directory
|
|
62
122
|
|
package/dist/cli/index.js
CHANGED
|
@@ -5098,7 +5098,7 @@ var init_pg_migrate = __esm(() => {
|
|
|
5098
5098
|
var require_package = __commonJS((exports, module) => {
|
|
5099
5099
|
module.exports = {
|
|
5100
5100
|
name: "@hasna/recordings",
|
|
5101
|
-
version: "0.1.
|
|
5101
|
+
version: "0.1.37",
|
|
5102
5102
|
type: "module",
|
|
5103
5103
|
description: "Speech-to-text recording tool with MCP and CLI \u2014 records, transcribes, and optionally enhances text using AI",
|
|
5104
5104
|
repository: {
|
|
@@ -5109,7 +5109,8 @@ var require_package = __commonJS((exports, module) => {
|
|
|
5109
5109
|
types: "dist/index.d.ts",
|
|
5110
5110
|
bin: {
|
|
5111
5111
|
recordings: "dist/cli/index.js",
|
|
5112
|
-
"recordings-mcp": "dist/mcp/index.js"
|
|
5112
|
+
"recordings-mcp": "dist/mcp/index.js",
|
|
5113
|
+
"recordings-serve": "dist/server/index.js"
|
|
5113
5114
|
},
|
|
5114
5115
|
exports: {
|
|
5115
5116
|
".": {
|
|
@@ -5119,20 +5120,29 @@ var require_package = __commonJS((exports, module) => {
|
|
|
5119
5120
|
"./storage": {
|
|
5120
5121
|
import: "./dist/storage.js",
|
|
5121
5122
|
types: "./dist/storage.d.ts"
|
|
5123
|
+
},
|
|
5124
|
+
"./sdk": {
|
|
5125
|
+
import: "./dist/sdk/index.js",
|
|
5126
|
+
types: "./dist/sdk/index.d.ts"
|
|
5122
5127
|
}
|
|
5123
5128
|
},
|
|
5124
5129
|
scripts: {
|
|
5125
5130
|
clean: "rm -rf dist",
|
|
5126
|
-
build: "bun run clean && bun run build:cli && bun run build:mcp && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
|
|
5131
|
+
build: "bun run clean && bun run build:cli && bun run build:mcp && bun run build:serve && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
|
|
5127
5132
|
"build:cli": "bun build src/cli/index.ts --target=bun --outfile=dist/cli/index.js --external=commander --external=chalk --external=openai",
|
|
5128
5133
|
"build:mcp": "bun build src/mcp/index.ts --target=bun --outfile=dist/mcp/index.js --external=@modelcontextprotocol/sdk --external=openai",
|
|
5129
|
-
"build:
|
|
5134
|
+
"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",
|
|
5135
|
+
"build:lib": "bun build src/index.ts src/storage.ts src/sdk/index.ts --target=bun --outdir=dist --external=openai",
|
|
5136
|
+
"generate:sdk": "bun run scripts/generate-sdk.ts",
|
|
5137
|
+
migrate: "bun run scripts/migrate.ts",
|
|
5130
5138
|
typecheck: "tsc --noEmit",
|
|
5131
5139
|
test: "bun test",
|
|
5132
5140
|
"test:coverage": "bun test --coverage",
|
|
5133
5141
|
"dev:cli": "bun run src/cli/index.ts",
|
|
5134
5142
|
"dev:mcp": "bun run src/mcp/index.ts",
|
|
5135
|
-
|
|
5143
|
+
"verify:release": "bun run scripts/release-guard.ts",
|
|
5144
|
+
prepack: "bun run build && bun run verify:release",
|
|
5145
|
+
prepublishOnly: "bun run typecheck && bun run test",
|
|
5136
5146
|
postinstall: "bash scripts/install_macos_app.sh --postinstall"
|
|
5137
5147
|
},
|
|
5138
5148
|
files: [
|
|
@@ -5148,6 +5158,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
5148
5158
|
"LICENSE"
|
|
5149
5159
|
],
|
|
5150
5160
|
dependencies: {
|
|
5161
|
+
"@hasna/contracts": "0.4.1",
|
|
5151
5162
|
"@hasna/events": "^0.1.11",
|
|
5152
5163
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
5153
5164
|
chalk: "^5.4.1",
|
|
@@ -6989,7 +7000,7 @@ async function processText(rawText, config, systemPrompt) {
|
|
|
6989
7000
|
}
|
|
6990
7001
|
|
|
6991
7002
|
// src/version.ts
|
|
6992
|
-
var VERSION = "0.1.
|
|
7003
|
+
var VERSION = "0.1.37";
|
|
6993
7004
|
|
|
6994
7005
|
// src/cli/storage.ts
|
|
6995
7006
|
import chalk from "chalk";
|
|
@@ -6998,11 +7009,12 @@ import chalk from "chalk";
|
|
|
6998
7009
|
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
|
|
6999
7010
|
import { homedir as homedir3 } from "os";
|
|
7000
7011
|
import { join as join4 } from "path";
|
|
7001
|
-
var
|
|
7012
|
+
var LEGACY_DATABASE_CONFIG_KEY = ["r", "d", "s"].join("");
|
|
7002
7013
|
var RECORDINGS_STORAGE_ENV = "HASNA_RECORDINGS_DATABASE_URL";
|
|
7003
7014
|
var RECORDINGS_STORAGE_FALLBACK_ENV = "RECORDINGS_DATABASE_URL";
|
|
7004
7015
|
var RECORDINGS_STORAGE_MODE_ENV = "HASNA_RECORDINGS_STORAGE_MODE";
|
|
7005
7016
|
var RECORDINGS_STORAGE_MODE_FALLBACK_ENV = "RECORDINGS_STORAGE_MODE";
|
|
7017
|
+
var RECORDINGS_STORAGE_CONFIG_ENV = "HASNA_RECORDINGS_STORAGE_CONFIG";
|
|
7006
7018
|
var STORAGE_DATABASE_ENV = [RECORDINGS_STORAGE_ENV, RECORDINGS_STORAGE_FALLBACK_ENV];
|
|
7007
7019
|
function readEnv(name) {
|
|
7008
7020
|
const value = process.env[name]?.trim();
|
|
@@ -7029,10 +7041,16 @@ function getStorageDatabaseUrl() {
|
|
|
7029
7041
|
const env = getStorageDatabaseEnv();
|
|
7030
7042
|
return env ? readEnv(env.name) : undefined;
|
|
7031
7043
|
}
|
|
7044
|
+
function getStorageConfigPath() {
|
|
7045
|
+
const override = readEnv(RECORDINGS_STORAGE_CONFIG_ENV);
|
|
7046
|
+
if (override)
|
|
7047
|
+
return override;
|
|
7048
|
+
return join4(homedir3(), ".hasna", "recordings", "storage", "config.json");
|
|
7049
|
+
}
|
|
7032
7050
|
function getStorageConfig() {
|
|
7033
7051
|
const config = {
|
|
7034
7052
|
mode: "local",
|
|
7035
|
-
|
|
7053
|
+
postgres: {
|
|
7036
7054
|
host: "",
|
|
7037
7055
|
port: 5432,
|
|
7038
7056
|
username: "",
|
|
@@ -7040,11 +7058,13 @@ function getStorageConfig() {
|
|
|
7040
7058
|
ssl: true
|
|
7041
7059
|
}
|
|
7042
7060
|
};
|
|
7043
|
-
|
|
7061
|
+
const storageConfigPath = getStorageConfigPath();
|
|
7062
|
+
if (existsSync4(storageConfigPath)) {
|
|
7044
7063
|
try {
|
|
7045
|
-
const raw = JSON.parse(readFileSync2(
|
|
7064
|
+
const raw = JSON.parse(readFileSync2(storageConfigPath, "utf-8"));
|
|
7065
|
+
const legacyDatabaseConfig = typeof raw[LEGACY_DATABASE_CONFIG_KEY] === "object" && raw[LEGACY_DATABASE_CONFIG_KEY] !== null ? raw[LEGACY_DATABASE_CONFIG_KEY] : {};
|
|
7046
7066
|
config.mode = normalizeMode(raw.mode) ?? config.mode;
|
|
7047
|
-
config.
|
|
7067
|
+
config.postgres = { ...config.postgres, ...legacyDatabaseConfig, ...raw.postgres ?? {} };
|
|
7048
7068
|
} catch {}
|
|
7049
7069
|
}
|
|
7050
7070
|
const modeOverride = readEnv(RECORDINGS_STORAGE_MODE_ENV) ?? readEnv(RECORDINGS_STORAGE_MODE_FALLBACK_ENV);
|
|
@@ -7061,7 +7081,7 @@ function getStorageConnectionString(dbName = "recordings") {
|
|
|
7061
7081
|
if (direct)
|
|
7062
7082
|
return direct;
|
|
7063
7083
|
const config = getStorageConfig();
|
|
7064
|
-
const { host, port, username, password_env, ssl } = config.
|
|
7084
|
+
const { host, port, username, password_env, ssl } = config.postgres;
|
|
7065
7085
|
if (!host || !username) {
|
|
7066
7086
|
throw new Error("Storage database is not configured. Set HASNA_RECORDINGS_DATABASE_URL or configure ~/.hasna/recordings/storage/config.json.");
|
|
7067
7087
|
}
|
|
@@ -7146,8 +7166,9 @@ async function runStorageMigrations(remote) {
|
|
|
7146
7166
|
function getStorageStatus(db = getDatabase()) {
|
|
7147
7167
|
const config = getStorageConfig();
|
|
7148
7168
|
const activeEnv = getStorageDatabaseEnv();
|
|
7169
|
+
const hasConfiguredPostgres = Boolean(config.postgres.host && config.postgres.username);
|
|
7149
7170
|
return {
|
|
7150
|
-
configured: Boolean(activeEnv),
|
|
7171
|
+
configured: Boolean(activeEnv) || hasConfiguredPostgres,
|
|
7151
7172
|
mode: config.mode,
|
|
7152
7173
|
enabled: config.mode === "hybrid" || config.mode === "remote",
|
|
7153
7174
|
env: STORAGE_DATABASE_ENV,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type StorageMode = "local" | "hybrid" | "remote";
|
|
2
2
|
export interface StorageConfig {
|
|
3
3
|
mode: StorageMode;
|
|
4
|
-
|
|
4
|
+
postgres: {
|
|
5
5
|
host: string;
|
|
6
6
|
port: number;
|
|
7
7
|
username: string;
|
|
@@ -16,6 +16,7 @@ export declare const RECORDINGS_STORAGE_ENV = "HASNA_RECORDINGS_DATABASE_URL";
|
|
|
16
16
|
export declare const RECORDINGS_STORAGE_FALLBACK_ENV = "RECORDINGS_DATABASE_URL";
|
|
17
17
|
export declare const RECORDINGS_STORAGE_MODE_ENV = "HASNA_RECORDINGS_STORAGE_MODE";
|
|
18
18
|
export declare const RECORDINGS_STORAGE_MODE_FALLBACK_ENV = "RECORDINGS_STORAGE_MODE";
|
|
19
|
+
export declare const RECORDINGS_STORAGE_CONFIG_ENV = "HASNA_RECORDINGS_STORAGE_CONFIG";
|
|
19
20
|
export declare const STORAGE_DATABASE_ENV: readonly ["HASNA_RECORDINGS_DATABASE_URL", "RECORDINGS_DATABASE_URL"];
|
|
20
21
|
export declare const STORAGE_MODE_ENV: readonly ["HASNA_RECORDINGS_STORAGE_MODE", "RECORDINGS_STORAGE_MODE"];
|
|
21
22
|
export declare function getStorageDatabaseEnvName(): (typeof STORAGE_DATABASE_ENV)[number] | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-config.d.ts","sourceRoot":"","sources":["../../src/db/storage-config.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,
|
|
1
|
+
{"version":3,"file":"storage-config.d.ts","sourceRoot":"","sources":["../../src/db/storage-config.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,GAAG,EAAE,OAAO,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,eAAO,MAAM,sBAAsB,kCAAkC,CAAC;AACtE,eAAO,MAAM,+BAA+B,4BAA4B,CAAC;AACzE,eAAO,MAAM,2BAA2B,kCAAkC,CAAC;AAC3E,eAAO,MAAM,oCAAoC,4BAA4B,CAAC;AAC9E,eAAO,MAAM,6BAA6B,oCAAoC,CAAC;AAC/E,eAAO,MAAM,oBAAoB,uEAAqE,CAAC;AACvG,eAAO,MAAM,gBAAgB,uEAA+E,CAAC;AAa7G,wBAAgB,yBAAyB,IAAI,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAKxF;AAED,wBAAgB,qBAAqB,IAAI,UAAU,GAAG,IAAI,CAGzD;AAED,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,SAAS,CAG1D;AAQD,wBAAgB,gBAAgB,IAAI,aAAa,CAoChD;AAED,wBAAgB,0BAA0B,CAAC,MAAM,SAAe,GAAG,MAAM,CAiBxE;AAED,eAAO,MAAM,mBAAmB,mCAA6B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-sync.d.ts","sourceRoot":"","sources":["../../src/db/storage-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EACL,oBAAoB,EAIpB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,oBAAoB,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,eAAO,MAAM,cAAc,6EAMjB,CAAC;AAEX,eAAO,MAAM,yBAAyB,6EAAiB,CAAC;AA6ExD,wBAAsB,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,CAE5D;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhF;AAED,wBAAgB,gBAAgB,CAAC,EAAE,GAAE,QAAwB,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"storage-sync.d.ts","sourceRoot":"","sources":["../../src/db/storage-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EACL,oBAAoB,EAIpB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,oBAAoB,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,eAAO,MAAM,cAAc,6EAMjB,CAAC;AAEX,eAAO,MAAM,yBAAyB,6EAAiB,CAAC;AA6ExD,wBAAsB,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,CAE5D;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhF;AAED,wBAAgB,gBAAgB,CAAC,EAAE,GAAE,QAAwB,GAAG,aAAa,CAqB5E;AAED,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,MAAM,EAAwB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAuBtG;AAED,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,MAAM,EAAwB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAuBtG;AAED,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,MAAM,EAAwB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAAC,IAAI,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC,CAKpI;AAED,wBAAgB,kBAAkB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAQzD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,4 +12,6 @@ export { loadConfig, getDataDir, ensureDataDir, DEFAULT_CONFIG, } from "./lib/co
|
|
|
12
12
|
export { transcribeAudio, transcribeBuffer, resetClient, } from "./lib/transcriber.js";
|
|
13
13
|
export { needsEnhancement, enhanceText, processText, resetEnhancementClient, } from "./lib/enhancer.js";
|
|
14
14
|
export { startRecording, stopRecording, isRecording, getCurrentFile, checkRecordingDeps, recordDuration, } from "./lib/recorder.js";
|
|
15
|
+
export { RecordingsV1Client, RecordingsV1ApiError, } from "./sdk/index.js";
|
|
16
|
+
export type { RecordingsV1ClientOptions, RecordingsV1Recording, RecordingsV1Agent, RecordingsV1Project, RecordingsV1CreateRecordingInput, RecordingsV1RegisterAgentInput, RecordingsV1RegisterProjectInput, } from "./sdk/index.js";
|
|
15
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,SAAS,EACT,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,KAAK,EACL,OAAO,EACP,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,SAAS,EACT,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAC/B,2BAA2B,EAC3B,oCAAoC,EACpC,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG/E,OAAO,EACL,eAAe,EACf,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGrE,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,cAAc,GACf,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,cAAc,EACd,aAAa,EACb,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,cAAc,GACf,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,SAAS,EACT,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,KAAK,EACL,OAAO,EACP,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,SAAS,EACT,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAC/B,2BAA2B,EAC3B,oCAAoC,EACpC,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG/E,OAAO,EACL,eAAe,EACf,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGrE,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,cAAc,GACf,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,cAAc,EACd,aAAa,EACb,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,cAAc,GACf,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,gCAAgC,EAChC,8BAA8B,EAC9B,gCAAgC,GACjC,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4902,6 +4902,139 @@ var require_lib2 = __commonJS((exports, module) => {
|
|
|
4902
4902
|
});
|
|
4903
4903
|
});
|
|
4904
4904
|
|
|
4905
|
+
// src/sdk/v1.generated.ts
|
|
4906
|
+
class ApiError extends Error {
|
|
4907
|
+
status;
|
|
4908
|
+
body;
|
|
4909
|
+
constructor(status, message, body) {
|
|
4910
|
+
super(message);
|
|
4911
|
+
this.status = status;
|
|
4912
|
+
this.body = body;
|
|
4913
|
+
this.name = "ApiError";
|
|
4914
|
+
}
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4917
|
+
class RecordingsV1Client {
|
|
4918
|
+
baseUrl;
|
|
4919
|
+
apiKey;
|
|
4920
|
+
fetchImpl;
|
|
4921
|
+
baseHeaders;
|
|
4922
|
+
constructor(options) {
|
|
4923
|
+
if (!options.baseUrl)
|
|
4924
|
+
throw new Error("RecordingsV1Client requires a baseUrl.");
|
|
4925
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
4926
|
+
this.apiKey = options.apiKey;
|
|
4927
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
4928
|
+
this.baseHeaders = options.headers ?? {};
|
|
4929
|
+
}
|
|
4930
|
+
async request(method, path, opts) {
|
|
4931
|
+
const url = new URL(this.baseUrl + path);
|
|
4932
|
+
if (opts.query) {
|
|
4933
|
+
for (const [key, value] of Object.entries(opts.query)) {
|
|
4934
|
+
if (value !== undefined && value !== null)
|
|
4935
|
+
url.searchParams.set(key, String(value));
|
|
4936
|
+
}
|
|
4937
|
+
}
|
|
4938
|
+
const headers = { Accept: "application/json", ...this.baseHeaders, ...opts.init?.headers };
|
|
4939
|
+
if (this.apiKey)
|
|
4940
|
+
headers["x-api-key"] = this.apiKey;
|
|
4941
|
+
let payload;
|
|
4942
|
+
if (opts.body !== undefined) {
|
|
4943
|
+
headers["Content-Type"] = "application/json";
|
|
4944
|
+
payload = JSON.stringify(opts.body);
|
|
4945
|
+
}
|
|
4946
|
+
const response = await this.fetchImpl(url.toString(), { ...opts.init, method, headers, body: payload });
|
|
4947
|
+
const text = await response.text();
|
|
4948
|
+
const data = text ? (() => {
|
|
4949
|
+
try {
|
|
4950
|
+
return JSON.parse(text);
|
|
4951
|
+
} catch {
|
|
4952
|
+
return text;
|
|
4953
|
+
}
|
|
4954
|
+
})() : undefined;
|
|
4955
|
+
if (!response.ok) {
|
|
4956
|
+
throw new ApiError(response.status, `${method} ${path} failed: ${response.status}`, data);
|
|
4957
|
+
}
|
|
4958
|
+
return data;
|
|
4959
|
+
}
|
|
4960
|
+
async listAgents(init) {
|
|
4961
|
+
return this.request("GET", `/v1/agents`, {
|
|
4962
|
+
body: undefined,
|
|
4963
|
+
query: undefined,
|
|
4964
|
+
init
|
|
4965
|
+
});
|
|
4966
|
+
}
|
|
4967
|
+
async registerAgent(body, init) {
|
|
4968
|
+
return this.request("POST", `/v1/agents`, {
|
|
4969
|
+
body,
|
|
4970
|
+
query: undefined,
|
|
4971
|
+
init
|
|
4972
|
+
});
|
|
4973
|
+
}
|
|
4974
|
+
async getAgent(id, init) {
|
|
4975
|
+
return this.request("GET", `/v1/agents/${encodeURIComponent(String(id))}`, {
|
|
4976
|
+
body: undefined,
|
|
4977
|
+
query: undefined,
|
|
4978
|
+
init
|
|
4979
|
+
});
|
|
4980
|
+
}
|
|
4981
|
+
async listProjects(init) {
|
|
4982
|
+
return this.request("GET", `/v1/projects`, {
|
|
4983
|
+
body: undefined,
|
|
4984
|
+
query: undefined,
|
|
4985
|
+
init
|
|
4986
|
+
});
|
|
4987
|
+
}
|
|
4988
|
+
async registerProject(body, init) {
|
|
4989
|
+
return this.request("POST", `/v1/projects`, {
|
|
4990
|
+
body,
|
|
4991
|
+
query: undefined,
|
|
4992
|
+
init
|
|
4993
|
+
});
|
|
4994
|
+
}
|
|
4995
|
+
async getProject(id, init) {
|
|
4996
|
+
return this.request("GET", `/v1/projects/${encodeURIComponent(String(id))}`, {
|
|
4997
|
+
body: undefined,
|
|
4998
|
+
query: undefined,
|
|
4999
|
+
init
|
|
5000
|
+
});
|
|
5001
|
+
}
|
|
5002
|
+
async listRecordings(query, init) {
|
|
5003
|
+
return this.request("GET", `/v1/recordings`, {
|
|
5004
|
+
body: undefined,
|
|
5005
|
+
query,
|
|
5006
|
+
init
|
|
5007
|
+
});
|
|
5008
|
+
}
|
|
5009
|
+
async createRecording(body, init) {
|
|
5010
|
+
return this.request("POST", `/v1/recordings`, {
|
|
5011
|
+
body,
|
|
5012
|
+
query: undefined,
|
|
5013
|
+
init
|
|
5014
|
+
});
|
|
5015
|
+
}
|
|
5016
|
+
async getRecording(id, init) {
|
|
5017
|
+
return this.request("GET", `/v1/recordings/${encodeURIComponent(String(id))}`, {
|
|
5018
|
+
body: undefined,
|
|
5019
|
+
query: undefined,
|
|
5020
|
+
init
|
|
5021
|
+
});
|
|
5022
|
+
}
|
|
5023
|
+
async deleteRecording(id, init) {
|
|
5024
|
+
return this.request("DELETE", `/v1/recordings/${encodeURIComponent(String(id))}`, {
|
|
5025
|
+
body: undefined,
|
|
5026
|
+
query: undefined,
|
|
5027
|
+
init
|
|
5028
|
+
});
|
|
5029
|
+
}
|
|
5030
|
+
async getRecordingStats(init) {
|
|
5031
|
+
return this.request("GET", `/v1/stats`, {
|
|
5032
|
+
body: undefined,
|
|
5033
|
+
query: undefined,
|
|
5034
|
+
init
|
|
5035
|
+
});
|
|
5036
|
+
}
|
|
5037
|
+
}
|
|
4905
5038
|
// src/types/index.ts
|
|
4906
5039
|
class RecordingNotFoundError extends Error {
|
|
4907
5040
|
constructor(id) {
|
|
@@ -5371,11 +5504,12 @@ class PgAdapterAsync {
|
|
|
5371
5504
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
5372
5505
|
import { homedir as homedir2 } from "os";
|
|
5373
5506
|
import { join as join2 } from "path";
|
|
5374
|
-
var
|
|
5507
|
+
var LEGACY_DATABASE_CONFIG_KEY = ["r", "d", "s"].join("");
|
|
5375
5508
|
var RECORDINGS_STORAGE_ENV = "HASNA_RECORDINGS_DATABASE_URL";
|
|
5376
5509
|
var RECORDINGS_STORAGE_FALLBACK_ENV = "RECORDINGS_DATABASE_URL";
|
|
5377
5510
|
var RECORDINGS_STORAGE_MODE_ENV = "HASNA_RECORDINGS_STORAGE_MODE";
|
|
5378
5511
|
var RECORDINGS_STORAGE_MODE_FALLBACK_ENV = "RECORDINGS_STORAGE_MODE";
|
|
5512
|
+
var RECORDINGS_STORAGE_CONFIG_ENV = "HASNA_RECORDINGS_STORAGE_CONFIG";
|
|
5379
5513
|
var STORAGE_DATABASE_ENV = [RECORDINGS_STORAGE_ENV, RECORDINGS_STORAGE_FALLBACK_ENV];
|
|
5380
5514
|
var STORAGE_MODE_ENV = [RECORDINGS_STORAGE_MODE_ENV, RECORDINGS_STORAGE_MODE_FALLBACK_ENV];
|
|
5381
5515
|
function readEnv(name) {
|
|
@@ -5403,10 +5537,16 @@ function getStorageDatabaseUrl() {
|
|
|
5403
5537
|
const env = getStorageDatabaseEnv();
|
|
5404
5538
|
return env ? readEnv(env.name) : undefined;
|
|
5405
5539
|
}
|
|
5540
|
+
function getStorageConfigPath() {
|
|
5541
|
+
const override = readEnv(RECORDINGS_STORAGE_CONFIG_ENV);
|
|
5542
|
+
if (override)
|
|
5543
|
+
return override;
|
|
5544
|
+
return join2(homedir2(), ".hasna", "recordings", "storage", "config.json");
|
|
5545
|
+
}
|
|
5406
5546
|
function getStorageConfig() {
|
|
5407
5547
|
const config = {
|
|
5408
5548
|
mode: "local",
|
|
5409
|
-
|
|
5549
|
+
postgres: {
|
|
5410
5550
|
host: "",
|
|
5411
5551
|
port: 5432,
|
|
5412
5552
|
username: "",
|
|
@@ -5414,11 +5554,13 @@ function getStorageConfig() {
|
|
|
5414
5554
|
ssl: true
|
|
5415
5555
|
}
|
|
5416
5556
|
};
|
|
5417
|
-
|
|
5557
|
+
const storageConfigPath = getStorageConfigPath();
|
|
5558
|
+
if (existsSync2(storageConfigPath)) {
|
|
5418
5559
|
try {
|
|
5419
|
-
const raw = JSON.parse(readFileSync2(
|
|
5560
|
+
const raw = JSON.parse(readFileSync2(storageConfigPath, "utf-8"));
|
|
5561
|
+
const legacyDatabaseConfig = typeof raw[LEGACY_DATABASE_CONFIG_KEY] === "object" && raw[LEGACY_DATABASE_CONFIG_KEY] !== null ? raw[LEGACY_DATABASE_CONFIG_KEY] : {};
|
|
5420
5562
|
config.mode = normalizeMode(raw.mode) ?? config.mode;
|
|
5421
|
-
config.
|
|
5563
|
+
config.postgres = { ...config.postgres, ...legacyDatabaseConfig, ...raw.postgres ?? {} };
|
|
5422
5564
|
} catch {}
|
|
5423
5565
|
}
|
|
5424
5566
|
const modeOverride = readEnv(RECORDINGS_STORAGE_MODE_ENV) ?? readEnv(RECORDINGS_STORAGE_MODE_FALLBACK_ENV);
|
|
@@ -5435,7 +5577,7 @@ function getStorageConnectionString(dbName = "recordings") {
|
|
|
5435
5577
|
if (direct)
|
|
5436
5578
|
return direct;
|
|
5437
5579
|
const config = getStorageConfig();
|
|
5438
|
-
const { host, port, username, password_env, ssl } = config.
|
|
5580
|
+
const { host, port, username, password_env, ssl } = config.postgres;
|
|
5439
5581
|
if (!host || !username) {
|
|
5440
5582
|
throw new Error("Storage database is not configured. Set HASNA_RECORDINGS_DATABASE_URL or configure ~/.hasna/recordings/storage/config.json.");
|
|
5441
5583
|
}
|
|
@@ -5587,8 +5729,9 @@ async function runStorageMigrations(remote) {
|
|
|
5587
5729
|
function getStorageStatus(db = getDatabase()) {
|
|
5588
5730
|
const config = getStorageConfig();
|
|
5589
5731
|
const activeEnv = getStorageDatabaseEnv();
|
|
5732
|
+
const hasConfiguredPostgres = Boolean(config.postgres.host && config.postgres.username);
|
|
5590
5733
|
return {
|
|
5591
|
-
configured: Boolean(activeEnv),
|
|
5734
|
+
configured: Boolean(activeEnv) || hasConfiguredPostgres,
|
|
5592
5735
|
mode: config.mode,
|
|
5593
5736
|
enabled: config.mode === "hybrid" || config.mode === "remote",
|
|
5594
5737
|
env: STORAGE_DATABASE_ENV,
|
|
@@ -6324,6 +6467,8 @@ export {
|
|
|
6324
6467
|
STORAGE_TABLES,
|
|
6325
6468
|
STORAGE_MODE_ENV,
|
|
6326
6469
|
STORAGE_DATABASE_ENV,
|
|
6470
|
+
RecordingsV1Client,
|
|
6471
|
+
ApiError as RecordingsV1ApiError,
|
|
6327
6472
|
RecordingNotFoundError,
|
|
6328
6473
|
RecordingError,
|
|
6329
6474
|
RECORDINGS_STORAGE_TABLES,
|
package/dist/mcp/index.js
CHANGED
|
@@ -4920,7 +4920,7 @@ var require_lib2 = __commonJS((exports, module) => {
|
|
|
4920
4920
|
var require_package = __commonJS((exports, module) => {
|
|
4921
4921
|
module.exports = {
|
|
4922
4922
|
name: "@hasna/recordings",
|
|
4923
|
-
version: "0.1.
|
|
4923
|
+
version: "0.1.37",
|
|
4924
4924
|
type: "module",
|
|
4925
4925
|
description: "Speech-to-text recording tool with MCP and CLI \u2014 records, transcribes, and optionally enhances text using AI",
|
|
4926
4926
|
repository: {
|
|
@@ -4931,7 +4931,8 @@ var require_package = __commonJS((exports, module) => {
|
|
|
4931
4931
|
types: "dist/index.d.ts",
|
|
4932
4932
|
bin: {
|
|
4933
4933
|
recordings: "dist/cli/index.js",
|
|
4934
|
-
"recordings-mcp": "dist/mcp/index.js"
|
|
4934
|
+
"recordings-mcp": "dist/mcp/index.js",
|
|
4935
|
+
"recordings-serve": "dist/server/index.js"
|
|
4935
4936
|
},
|
|
4936
4937
|
exports: {
|
|
4937
4938
|
".": {
|
|
@@ -4941,20 +4942,29 @@ var require_package = __commonJS((exports, module) => {
|
|
|
4941
4942
|
"./storage": {
|
|
4942
4943
|
import: "./dist/storage.js",
|
|
4943
4944
|
types: "./dist/storage.d.ts"
|
|
4945
|
+
},
|
|
4946
|
+
"./sdk": {
|
|
4947
|
+
import: "./dist/sdk/index.js",
|
|
4948
|
+
types: "./dist/sdk/index.d.ts"
|
|
4944
4949
|
}
|
|
4945
4950
|
},
|
|
4946
4951
|
scripts: {
|
|
4947
4952
|
clean: "rm -rf dist",
|
|
4948
|
-
build: "bun run clean && bun run build:cli && bun run build:mcp && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
|
|
4953
|
+
build: "bun run clean && bun run build:cli && bun run build:mcp && bun run build:serve && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
|
|
4949
4954
|
"build:cli": "bun build src/cli/index.ts --target=bun --outfile=dist/cli/index.js --external=commander --external=chalk --external=openai",
|
|
4950
4955
|
"build:mcp": "bun build src/mcp/index.ts --target=bun --outfile=dist/mcp/index.js --external=@modelcontextprotocol/sdk --external=openai",
|
|
4951
|
-
"build:
|
|
4956
|
+
"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",
|
|
4957
|
+
"build:lib": "bun build src/index.ts src/storage.ts src/sdk/index.ts --target=bun --outdir=dist --external=openai",
|
|
4958
|
+
"generate:sdk": "bun run scripts/generate-sdk.ts",
|
|
4959
|
+
migrate: "bun run scripts/migrate.ts",
|
|
4952
4960
|
typecheck: "tsc --noEmit",
|
|
4953
4961
|
test: "bun test",
|
|
4954
4962
|
"test:coverage": "bun test --coverage",
|
|
4955
4963
|
"dev:cli": "bun run src/cli/index.ts",
|
|
4956
4964
|
"dev:mcp": "bun run src/mcp/index.ts",
|
|
4957
|
-
|
|
4965
|
+
"verify:release": "bun run scripts/release-guard.ts",
|
|
4966
|
+
prepack: "bun run build && bun run verify:release",
|
|
4967
|
+
prepublishOnly: "bun run typecheck && bun run test",
|
|
4958
4968
|
postinstall: "bash scripts/install_macos_app.sh --postinstall"
|
|
4959
4969
|
},
|
|
4960
4970
|
files: [
|
|
@@ -4970,6 +4980,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
4970
4980
|
"LICENSE"
|
|
4971
4981
|
],
|
|
4972
4982
|
dependencies: {
|
|
4983
|
+
"@hasna/contracts": "0.4.1",
|
|
4973
4984
|
"@hasna/events": "^0.1.11",
|
|
4974
4985
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
4975
4986
|
chalk: "^5.4.1",
|
|
@@ -9810,17 +9821,18 @@ async function processText(rawText, config, systemPrompt) {
|
|
|
9810
9821
|
}
|
|
9811
9822
|
|
|
9812
9823
|
// src/version.ts
|
|
9813
|
-
var VERSION = "0.1.
|
|
9824
|
+
var VERSION = "0.1.37";
|
|
9814
9825
|
|
|
9815
9826
|
// src/db/storage-config.ts
|
|
9816
9827
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
9817
9828
|
import { homedir as homedir2 } from "os";
|
|
9818
9829
|
import { join as join2 } from "path";
|
|
9819
|
-
var
|
|
9830
|
+
var LEGACY_DATABASE_CONFIG_KEY = ["r", "d", "s"].join("");
|
|
9820
9831
|
var RECORDINGS_STORAGE_ENV = "HASNA_RECORDINGS_DATABASE_URL";
|
|
9821
9832
|
var RECORDINGS_STORAGE_FALLBACK_ENV = "RECORDINGS_DATABASE_URL";
|
|
9822
9833
|
var RECORDINGS_STORAGE_MODE_ENV = "HASNA_RECORDINGS_STORAGE_MODE";
|
|
9823
9834
|
var RECORDINGS_STORAGE_MODE_FALLBACK_ENV = "RECORDINGS_STORAGE_MODE";
|
|
9835
|
+
var RECORDINGS_STORAGE_CONFIG_ENV = "HASNA_RECORDINGS_STORAGE_CONFIG";
|
|
9824
9836
|
var STORAGE_DATABASE_ENV = [RECORDINGS_STORAGE_ENV, RECORDINGS_STORAGE_FALLBACK_ENV];
|
|
9825
9837
|
function readEnv(name) {
|
|
9826
9838
|
const value = process.env[name]?.trim();
|
|
@@ -9847,10 +9859,16 @@ function getStorageDatabaseUrl() {
|
|
|
9847
9859
|
const env = getStorageDatabaseEnv();
|
|
9848
9860
|
return env ? readEnv(env.name) : undefined;
|
|
9849
9861
|
}
|
|
9862
|
+
function getStorageConfigPath() {
|
|
9863
|
+
const override = readEnv(RECORDINGS_STORAGE_CONFIG_ENV);
|
|
9864
|
+
if (override)
|
|
9865
|
+
return override;
|
|
9866
|
+
return join2(homedir2(), ".hasna", "recordings", "storage", "config.json");
|
|
9867
|
+
}
|
|
9850
9868
|
function getStorageConfig() {
|
|
9851
9869
|
const config = {
|
|
9852
9870
|
mode: "local",
|
|
9853
|
-
|
|
9871
|
+
postgres: {
|
|
9854
9872
|
host: "",
|
|
9855
9873
|
port: 5432,
|
|
9856
9874
|
username: "",
|
|
@@ -9858,11 +9876,13 @@ function getStorageConfig() {
|
|
|
9858
9876
|
ssl: true
|
|
9859
9877
|
}
|
|
9860
9878
|
};
|
|
9861
|
-
|
|
9879
|
+
const storageConfigPath = getStorageConfigPath();
|
|
9880
|
+
if (existsSync2(storageConfigPath)) {
|
|
9862
9881
|
try {
|
|
9863
|
-
const raw = JSON.parse(readFileSync2(
|
|
9882
|
+
const raw = JSON.parse(readFileSync2(storageConfigPath, "utf-8"));
|
|
9883
|
+
const legacyDatabaseConfig = typeof raw[LEGACY_DATABASE_CONFIG_KEY] === "object" && raw[LEGACY_DATABASE_CONFIG_KEY] !== null ? raw[LEGACY_DATABASE_CONFIG_KEY] : {};
|
|
9864
9884
|
config.mode = normalizeMode(raw.mode) ?? config.mode;
|
|
9865
|
-
config.
|
|
9885
|
+
config.postgres = { ...config.postgres, ...legacyDatabaseConfig, ...raw.postgres ?? {} };
|
|
9866
9886
|
} catch {}
|
|
9867
9887
|
}
|
|
9868
9888
|
const modeOverride = readEnv(RECORDINGS_STORAGE_MODE_ENV) ?? readEnv(RECORDINGS_STORAGE_MODE_FALLBACK_ENV);
|
|
@@ -9879,7 +9899,7 @@ function getStorageConnectionString(dbName = "recordings") {
|
|
|
9879
9899
|
if (direct)
|
|
9880
9900
|
return direct;
|
|
9881
9901
|
const config = getStorageConfig();
|
|
9882
|
-
const { host, port, username, password_env, ssl } = config.
|
|
9902
|
+
const { host, port, username, password_env, ssl } = config.postgres;
|
|
9883
9903
|
if (!host || !username) {
|
|
9884
9904
|
throw new Error("Storage database is not configured. Set HASNA_RECORDINGS_DATABASE_URL or configure ~/.hasna/recordings/storage/config.json.");
|
|
9885
9905
|
}
|
|
@@ -10083,8 +10103,9 @@ async function runStorageMigrations(remote) {
|
|
|
10083
10103
|
function getStorageStatus(db = getDatabase()) {
|
|
10084
10104
|
const config = getStorageConfig();
|
|
10085
10105
|
const activeEnv = getStorageDatabaseEnv();
|
|
10106
|
+
const hasConfiguredPostgres = Boolean(config.postgres.host && config.postgres.username);
|
|
10086
10107
|
return {
|
|
10087
|
-
configured: Boolean(activeEnv),
|
|
10108
|
+
configured: Boolean(activeEnv) || hasConfiguredPostgres,
|
|
10088
10109
|
mode: config.mode,
|
|
10089
10110
|
enabled: config.mode === "hybrid" || config.mode === "remote",
|
|
10090
10111
|
env: STORAGE_DATABASE_ENV,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hasna/recordings SDK — typed `/v1` cloud client.
|
|
3
|
+
*
|
|
4
|
+
* Generated from the serve OpenAPI document (src/server/openapi.ts). Regenerate
|
|
5
|
+
* with `bun run generate:sdk`.
|
|
6
|
+
*
|
|
7
|
+
* import { RecordingsV1Client } from "@hasna/recordings/sdk";
|
|
8
|
+
* const client = new RecordingsV1Client({
|
|
9
|
+
* baseUrl: process.env.RECORDINGS_API_URL!,
|
|
10
|
+
* apiKey: process.env.RECORDINGS_API_KEY!,
|
|
11
|
+
* });
|
|
12
|
+
* const { recordings } = await client.listRecordings({ limit: 20 });
|
|
13
|
+
*/
|
|
14
|
+
export { RecordingsV1Client, ApiError as RecordingsV1ApiError, } from "./v1.generated.js";
|
|
15
|
+
export type { RecordingsV1ClientOptions, Recording as RecordingsV1Recording, Agent as RecordingsV1Agent, Project as RecordingsV1Project, CreateRecordingInput as RecordingsV1CreateRecordingInput, RegisterAgentInput as RecordingsV1RegisterAgentInput, RegisterProjectInput as RecordingsV1RegisterProjectInput, } from "./v1.generated.js";
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sdk/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,kBAAkB,EAClB,QAAQ,IAAI,oBAAoB,GACjC,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,yBAAyB,EACzB,SAAS,IAAI,qBAAqB,EAClC,KAAK,IAAI,iBAAiB,EAC1B,OAAO,IAAI,mBAAmB,EAC9B,oBAAoB,IAAI,gCAAgC,EACxD,kBAAkB,IAAI,8BAA8B,EACpD,oBAAoB,IAAI,gCAAgC,GACzD,MAAM,mBAAmB,CAAC"}
|