@ouro.bot/cli 0.1.0-alpha.210 → 0.1.0-alpha.212
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/changelog.json +12 -0
- package/dist/arc/cares.js +7 -46
- package/dist/arc/intentions.js +7 -47
- package/dist/arc/json-store.js +120 -0
- package/dist/arc/obligations.js +23 -107
- package/dist/heart/daemon/daemon.js +1 -1
- package/dist/heart/daemon/sense-manager.js +1 -1
- package/dist/mind/associative-recall.js +4 -34
- package/dist/mind/diary.js +4 -40
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/nerves/coverage/file-completeness.js +5 -0
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/api-client.js +71 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +8 -8
- package/dist/senses/{bluebubbles-entry.js → bluebubbles/entry.js} +6 -6
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +3 -3
- package/dist/senses/{bluebubbles.js → bluebubbles/index.js} +40 -40
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +2 -2
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +1 -1
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +2 -2
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/package.json +2 -2
package/dist/mind/diary.js
CHANGED
|
@@ -43,44 +43,14 @@ exports.searchDiaryEntries = searchDiaryEntries;
|
|
|
43
43
|
const fs = __importStar(require("fs"));
|
|
44
44
|
const path = __importStar(require("path"));
|
|
45
45
|
const crypto_1 = require("crypto");
|
|
46
|
-
const config_1 = require("../heart/config");
|
|
47
46
|
const identity_1 = require("../heart/identity");
|
|
48
47
|
const runtime_1 = require("../nerves/runtime");
|
|
49
48
|
const sync_1 = require("../heart/sync");
|
|
50
49
|
const associative_recall_1 = require("./associative-recall");
|
|
50
|
+
const embedding_provider_1 = require("./embedding-provider");
|
|
51
51
|
const DEDUP_THRESHOLD = 0.6;
|
|
52
52
|
const SEMANTIC_DEDUP_THRESHOLD = 0.95;
|
|
53
53
|
const ENTITY_TOKEN = /[a-z0-9]+/g;
|
|
54
|
-
const DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small";
|
|
55
|
-
class OpenAIEmbeddingProvider {
|
|
56
|
-
apiKey;
|
|
57
|
-
model;
|
|
58
|
-
constructor(apiKey, model = DEFAULT_EMBEDDING_MODEL) {
|
|
59
|
-
this.apiKey = apiKey;
|
|
60
|
-
this.model = model;
|
|
61
|
-
}
|
|
62
|
-
async embed(texts) {
|
|
63
|
-
const response = await fetch("https://api.openai.com/v1/embeddings", {
|
|
64
|
-
method: "POST",
|
|
65
|
-
headers: {
|
|
66
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
67
|
-
"Content-Type": "application/json",
|
|
68
|
-
},
|
|
69
|
-
body: JSON.stringify({
|
|
70
|
-
model: this.model,
|
|
71
|
-
input: texts,
|
|
72
|
-
}),
|
|
73
|
-
});
|
|
74
|
-
if (!response.ok) {
|
|
75
|
-
throw new Error(`embedding request failed: ${response.status} ${response.statusText}`);
|
|
76
|
-
}
|
|
77
|
-
const payload = (await response.json());
|
|
78
|
-
if (!payload.data || payload.data.length !== texts.length) {
|
|
79
|
-
throw new Error("embedding response missing expected vectors");
|
|
80
|
-
}
|
|
81
|
-
return payload.data.map((entry) => entry.embedding);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
54
|
function ensureDiaryStorePaths(rootDir) {
|
|
85
55
|
const factsPath = path.join(rootDir, "facts.jsonl");
|
|
86
56
|
const entitiesPath = path.join(rootDir, "entities.json");
|
|
@@ -219,14 +189,8 @@ function appendEntriesWithDedup(stores, incoming, options) {
|
|
|
219
189
|
});
|
|
220
190
|
return { added, skipped };
|
|
221
191
|
}
|
|
222
|
-
function createDefaultEmbeddingProvider() {
|
|
223
|
-
const apiKey = (0, config_1.getOpenAIEmbeddingsApiKey)().trim();
|
|
224
|
-
if (!apiKey)
|
|
225
|
-
return null;
|
|
226
|
-
return new OpenAIEmbeddingProvider(apiKey);
|
|
227
|
-
}
|
|
228
192
|
async function buildEmbedding(text, embeddingProvider) {
|
|
229
|
-
const provider = embeddingProvider ?? createDefaultEmbeddingProvider();
|
|
193
|
+
const provider = embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
|
|
230
194
|
if (!provider) {
|
|
231
195
|
(0, runtime_1.emitNervesEvent)({
|
|
232
196
|
level: "warn",
|
|
@@ -287,7 +251,7 @@ async function backfillEmbeddings(options) {
|
|
|
287
251
|
const needsEmbedding = facts.filter((f) => !Array.isArray(f.embedding) || f.embedding.length === 0);
|
|
288
252
|
if (needsEmbedding.length === 0)
|
|
289
253
|
return { total: facts.length, backfilled: 0, failed: 0 };
|
|
290
|
-
const provider = options?.embeddingProvider ?? createDefaultEmbeddingProvider();
|
|
254
|
+
const provider = options?.embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
|
|
291
255
|
if (!provider) {
|
|
292
256
|
(0, runtime_1.emitNervesEvent)({
|
|
293
257
|
level: "warn",
|
|
@@ -364,7 +328,7 @@ async function searchDiaryEntries(query, facts, embeddingProvider) {
|
|
|
364
328
|
if (embeddedFacts.length === 0) {
|
|
365
329
|
return substringFallback();
|
|
366
330
|
}
|
|
367
|
-
const provider = embeddingProvider ?? createDefaultEmbeddingProvider();
|
|
331
|
+
const provider = embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
|
|
368
332
|
if (!provider) {
|
|
369
333
|
return substringFallback();
|
|
370
334
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared OpenAI embedding provider.
|
|
4
|
+
*
|
|
5
|
+
* Both diary.ts and associative-recall.ts need to call the OpenAI embeddings
|
|
6
|
+
* API. This module provides the shared implementation so neither duplicates
|
|
7
|
+
* the fetch logic.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.OpenAIEmbeddingProvider = void 0;
|
|
11
|
+
exports.createDefaultEmbeddingProvider = createDefaultEmbeddingProvider;
|
|
12
|
+
const config_1 = require("../heart/config");
|
|
13
|
+
const runtime_1 = require("../nerves/runtime");
|
|
14
|
+
const DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small";
|
|
15
|
+
class OpenAIEmbeddingProvider {
|
|
16
|
+
apiKey;
|
|
17
|
+
model;
|
|
18
|
+
constructor(apiKey, model = DEFAULT_EMBEDDING_MODEL) {
|
|
19
|
+
this.apiKey = apiKey;
|
|
20
|
+
this.model = model;
|
|
21
|
+
}
|
|
22
|
+
async embed(texts) {
|
|
23
|
+
const response = await fetch("https://api.openai.com/v1/embeddings", {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
model: this.model,
|
|
31
|
+
input: texts,
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`embedding request failed: ${response.status} ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
const payload = (await response.json());
|
|
38
|
+
if (!payload.data || payload.data.length !== texts.length) {
|
|
39
|
+
throw new Error("embedding response missing expected vectors");
|
|
40
|
+
}
|
|
41
|
+
return payload.data.map((entry) => entry.embedding);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.OpenAIEmbeddingProvider = OpenAIEmbeddingProvider;
|
|
45
|
+
/**
|
|
46
|
+
* Create a default embedding provider from the configured API key.
|
|
47
|
+
* Returns null if no key is configured.
|
|
48
|
+
*/
|
|
49
|
+
function createDefaultEmbeddingProvider() {
|
|
50
|
+
const apiKey = (0, config_1.getOpenAIEmbeddingsApiKey)().trim();
|
|
51
|
+
if (!apiKey)
|
|
52
|
+
return null;
|
|
53
|
+
(0, runtime_1.emitNervesEvent)({
|
|
54
|
+
component: "mind",
|
|
55
|
+
event: "mind.embedding_provider_created",
|
|
56
|
+
message: "default embedding provider created",
|
|
57
|
+
meta: { model: DEFAULT_EMBEDDING_MODEL },
|
|
58
|
+
});
|
|
59
|
+
return new OpenAIEmbeddingProvider(apiKey);
|
|
60
|
+
}
|
|
@@ -61,6 +61,11 @@ const DISPATCH_EXEMPT_PATTERNS = [
|
|
|
61
61
|
// cli-parse and cli-render are pure functions with no side effects.
|
|
62
62
|
"daemon/cli-parse",
|
|
63
63
|
"daemon/cli-render",
|
|
64
|
+
// Shared utility modules: pure helpers consumed by modules that own observability.
|
|
65
|
+
"arc/json-store",
|
|
66
|
+
"repertoire/api-client",
|
|
67
|
+
"repertoire/github-client",
|
|
68
|
+
"mind/embedding-provider",
|
|
64
69
|
];
|
|
65
70
|
function isDispatchExempt(filePath) {
|
|
66
71
|
return DISPATCH_EXEMPT_PATTERNS.some((pattern) => filePath.includes(pattern));
|
|
@@ -9,6 +9,7 @@ exports.discoverOrganizations = discoverOrganizations;
|
|
|
9
9
|
exports.discoverProjects = discoverProjects;
|
|
10
10
|
const api_error_1 = require("../heart/api-error");
|
|
11
11
|
const runtime_1 = require("../nerves/runtime");
|
|
12
|
+
const api_client_1 = require("./api-client");
|
|
12
13
|
const ADO_BASE = "https://dev.azure.com";
|
|
13
14
|
const VSSPS_BASE = "https://app.vssps.visualstudio.com";
|
|
14
15
|
const DEFAULT_API_VERSION = "api-version=7.1";
|
|
@@ -30,62 +31,20 @@ function resolveContentType(method, path) {
|
|
|
30
31
|
// Generic ADO API request. Returns response body as pretty-printed JSON string.
|
|
31
32
|
// `host` overrides the base URL for non-standard APIs (e.g. "vsapm.dev.azure.com", "vssps.dev.azure.com").
|
|
32
33
|
async function adoRequest(token, method, org, path, body, host) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
Authorization: `Bearer ${token}`,
|
|
48
|
-
"Content-Type": contentType,
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
if (body)
|
|
52
|
-
opts.body = body;
|
|
53
|
-
const res = await fetch(url, opts);
|
|
54
|
-
if (!res.ok) {
|
|
55
|
-
(0, runtime_1.emitNervesEvent)({
|
|
56
|
-
level: "error",
|
|
57
|
-
event: "client.error",
|
|
58
|
-
component: "clients",
|
|
59
|
-
message: "ADO request failed",
|
|
60
|
-
meta: { client: "ado", method, org, path, status: res.status },
|
|
61
|
-
});
|
|
62
|
-
return (0, api_error_1.handleApiError)(res, "ADO", "ado");
|
|
63
|
-
}
|
|
64
|
-
const data = await res.json();
|
|
65
|
-
(0, runtime_1.emitNervesEvent)({
|
|
66
|
-
event: "client.request_end",
|
|
67
|
-
component: "clients",
|
|
68
|
-
message: "ADO request completed",
|
|
69
|
-
meta: { client: "ado", method, org, path, success: true },
|
|
70
|
-
});
|
|
71
|
-
return JSON.stringify(data, null, 2);
|
|
72
|
-
}
|
|
73
|
-
catch (err) {
|
|
74
|
-
(0, runtime_1.emitNervesEvent)({
|
|
75
|
-
level: "error",
|
|
76
|
-
event: "client.error",
|
|
77
|
-
component: "clients",
|
|
78
|
-
message: "ADO request threw exception",
|
|
79
|
-
meta: {
|
|
80
|
-
client: "ado",
|
|
81
|
-
method,
|
|
82
|
-
org,
|
|
83
|
-
path,
|
|
84
|
-
reason: err instanceof Error ? err.message : String(err),
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
return (0, api_error_1.handleApiError)(err, "ADO", "ado");
|
|
88
|
-
}
|
|
34
|
+
const base = host ? `https://${host}/${org}` : `${ADO_BASE}/${org}`;
|
|
35
|
+
const fullPath = ensureApiVersion(path);
|
|
36
|
+
return (0, api_client_1.apiRequest)({
|
|
37
|
+
baseUrl: base,
|
|
38
|
+
method,
|
|
39
|
+
path: fullPath,
|
|
40
|
+
token,
|
|
41
|
+
clientName: "ado",
|
|
42
|
+
serviceLabel: "ADO",
|
|
43
|
+
connectionName: "ado",
|
|
44
|
+
body,
|
|
45
|
+
contentType: resolveContentType(method, path),
|
|
46
|
+
eventMeta: { org },
|
|
47
|
+
});
|
|
89
48
|
}
|
|
90
49
|
// Backward-compatible thin wrapper: runs WIQL query and returns formatted work items.
|
|
91
50
|
async function queryWorkItems(token, org, query) {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared HTTP API client for Graph, ADO, and GitHub clients.
|
|
4
|
+
*
|
|
5
|
+
* All three API clients follow the same pattern: emit request_start event,
|
|
6
|
+
* build request with auth header, fetch, handle errors, emit request_end,
|
|
7
|
+
* and return pretty-printed JSON. This module extracts that shared logic.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.apiRequest = apiRequest;
|
|
11
|
+
const api_error_1 = require("../heart/api-error");
|
|
12
|
+
const runtime_1 = require("../nerves/runtime");
|
|
13
|
+
/**
|
|
14
|
+
* Execute an authenticated API request with standard logging and error handling.
|
|
15
|
+
* Returns the response body as a pretty-printed JSON string.
|
|
16
|
+
*/
|
|
17
|
+
async function apiRequest(options) {
|
|
18
|
+
const { baseUrl, method, path, token, clientName, serviceLabel, connectionName, body, extraHeaders, contentType, eventMeta, } = options;
|
|
19
|
+
try {
|
|
20
|
+
(0, runtime_1.emitNervesEvent)({
|
|
21
|
+
event: "client.request_start",
|
|
22
|
+
component: "clients",
|
|
23
|
+
message: `starting ${serviceLabel} request`,
|
|
24
|
+
meta: { client: clientName, method, path, ...eventMeta },
|
|
25
|
+
});
|
|
26
|
+
const url = `${baseUrl}${path}`;
|
|
27
|
+
const headers = {
|
|
28
|
+
Authorization: `Bearer ${token}`,
|
|
29
|
+
"Content-Type": contentType ?? "application/json",
|
|
30
|
+
...extraHeaders,
|
|
31
|
+
};
|
|
32
|
+
const opts = { method, headers };
|
|
33
|
+
if (body)
|
|
34
|
+
opts.body = body;
|
|
35
|
+
const res = await fetch(url, opts);
|
|
36
|
+
if (!res.ok) {
|
|
37
|
+
(0, runtime_1.emitNervesEvent)({
|
|
38
|
+
level: "error",
|
|
39
|
+
event: "client.error",
|
|
40
|
+
component: "clients",
|
|
41
|
+
message: `${serviceLabel} request failed`,
|
|
42
|
+
meta: { client: clientName, method, path, status: res.status, ...eventMeta },
|
|
43
|
+
});
|
|
44
|
+
return (0, api_error_1.handleApiError)(res, serviceLabel, connectionName);
|
|
45
|
+
}
|
|
46
|
+
const data = await res.json();
|
|
47
|
+
(0, runtime_1.emitNervesEvent)({
|
|
48
|
+
event: "client.request_end",
|
|
49
|
+
component: "clients",
|
|
50
|
+
message: `${serviceLabel} request completed`,
|
|
51
|
+
meta: { client: clientName, method, path, success: true, ...eventMeta },
|
|
52
|
+
});
|
|
53
|
+
return JSON.stringify(data, null, 2);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
(0, runtime_1.emitNervesEvent)({
|
|
57
|
+
level: "error",
|
|
58
|
+
event: "client.error",
|
|
59
|
+
component: "clients",
|
|
60
|
+
message: `${serviceLabel} request threw exception`,
|
|
61
|
+
meta: {
|
|
62
|
+
client: clientName,
|
|
63
|
+
method,
|
|
64
|
+
path,
|
|
65
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
66
|
+
...eventMeta,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
return (0, api_error_1.handleApiError)(err, serviceLabel, connectionName);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -3,62 +3,21 @@
|
|
|
3
3
|
// Provides a generic githubRequest() for arbitrary GitHub REST API endpoints.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.githubRequest = githubRequest;
|
|
6
|
-
const
|
|
7
|
-
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
const api_client_1 = require("./api-client");
|
|
8
7
|
const GITHUB_BASE = "https://api.github.com";
|
|
9
8
|
// Generic GitHub API request. Returns response body as pretty-printed JSON string.
|
|
10
9
|
async function githubRequest(token, method, path, body) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"Content-Type": "application/json",
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
if (body)
|
|
28
|
-
opts.body = body;
|
|
29
|
-
const res = await fetch(url, opts);
|
|
30
|
-
if (!res.ok) {
|
|
31
|
-
(0, runtime_1.emitNervesEvent)({
|
|
32
|
-
level: "error",
|
|
33
|
-
event: "client.error",
|
|
34
|
-
component: "clients",
|
|
35
|
-
message: "GitHub request failed",
|
|
36
|
-
meta: { client: "github", method, path, status: res.status },
|
|
37
|
-
});
|
|
38
|
-
return (0, api_error_1.handleApiError)(res, "GitHub", "github");
|
|
39
|
-
}
|
|
40
|
-
const data = await res.json();
|
|
41
|
-
(0, runtime_1.emitNervesEvent)({
|
|
42
|
-
event: "client.request_end",
|
|
43
|
-
component: "clients",
|
|
44
|
-
message: "GitHub request completed",
|
|
45
|
-
meta: { client: "github", method, path, success: true },
|
|
46
|
-
});
|
|
47
|
-
return JSON.stringify(data, null, 2);
|
|
48
|
-
}
|
|
49
|
-
catch (err) {
|
|
50
|
-
(0, runtime_1.emitNervesEvent)({
|
|
51
|
-
level: "error",
|
|
52
|
-
event: "client.error",
|
|
53
|
-
component: "clients",
|
|
54
|
-
message: "GitHub request threw exception",
|
|
55
|
-
meta: {
|
|
56
|
-
client: "github",
|
|
57
|
-
method,
|
|
58
|
-
path,
|
|
59
|
-
reason: err instanceof Error ? err.message : String(err),
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
return (0, api_error_1.handleApiError)(err, "GitHub", "github");
|
|
63
|
-
}
|
|
10
|
+
return (0, api_client_1.apiRequest)({
|
|
11
|
+
baseUrl: GITHUB_BASE,
|
|
12
|
+
method,
|
|
13
|
+
path,
|
|
14
|
+
token,
|
|
15
|
+
clientName: "github",
|
|
16
|
+
serviceLabel: "GitHub",
|
|
17
|
+
connectionName: "github",
|
|
18
|
+
body,
|
|
19
|
+
extraHeaders: {
|
|
20
|
+
Accept: "application/vnd.github+json",
|
|
21
|
+
},
|
|
22
|
+
});
|
|
64
23
|
}
|
|
@@ -7,61 +7,20 @@ exports.graphRequest = graphRequest;
|
|
|
7
7
|
exports.getProfile = getProfile;
|
|
8
8
|
const api_error_1 = require("../heart/api-error");
|
|
9
9
|
const runtime_1 = require("../nerves/runtime");
|
|
10
|
+
const api_client_1 = require("./api-client");
|
|
10
11
|
const GRAPH_BASE = "https://graph.microsoft.com/v1.0";
|
|
11
12
|
// Generic Graph API request. Returns response body as pretty-printed JSON string.
|
|
12
13
|
async function graphRequest(token, method, path, body) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
headers: {
|
|
24
|
-
Authorization: `Bearer ${token}`,
|
|
25
|
-
"Content-Type": "application/json",
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
if (body)
|
|
29
|
-
opts.body = body;
|
|
30
|
-
const res = await fetch(url, opts);
|
|
31
|
-
if (!res.ok) {
|
|
32
|
-
(0, runtime_1.emitNervesEvent)({
|
|
33
|
-
level: "error",
|
|
34
|
-
event: "client.error",
|
|
35
|
-
component: "clients",
|
|
36
|
-
message: "Graph request failed",
|
|
37
|
-
meta: { client: "graph", method, path, status: res.status },
|
|
38
|
-
});
|
|
39
|
-
return (0, api_error_1.handleApiError)(res, "Graph", "graph");
|
|
40
|
-
}
|
|
41
|
-
const data = await res.json();
|
|
42
|
-
(0, runtime_1.emitNervesEvent)({
|
|
43
|
-
event: "client.request_end",
|
|
44
|
-
component: "clients",
|
|
45
|
-
message: "Graph request completed",
|
|
46
|
-
meta: { client: "graph", method, path, success: true },
|
|
47
|
-
});
|
|
48
|
-
return JSON.stringify(data, null, 2);
|
|
49
|
-
}
|
|
50
|
-
catch (err) {
|
|
51
|
-
(0, runtime_1.emitNervesEvent)({
|
|
52
|
-
level: "error",
|
|
53
|
-
event: "client.error",
|
|
54
|
-
component: "clients",
|
|
55
|
-
message: "Graph request threw exception",
|
|
56
|
-
meta: {
|
|
57
|
-
client: "graph",
|
|
58
|
-
method,
|
|
59
|
-
path,
|
|
60
|
-
reason: err instanceof Error ? err.message : String(err),
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
return (0, api_error_1.handleApiError)(err, "Graph", "graph");
|
|
64
|
-
}
|
|
14
|
+
return (0, api_client_1.apiRequest)({
|
|
15
|
+
baseUrl: GRAPH_BASE,
|
|
16
|
+
method,
|
|
17
|
+
path,
|
|
18
|
+
token,
|
|
19
|
+
clientName: "graph",
|
|
20
|
+
serviceLabel: "Graph",
|
|
21
|
+
connectionName: "graph",
|
|
22
|
+
body,
|
|
23
|
+
});
|
|
65
24
|
}
|
|
66
25
|
// Backward-compatible thin wrapper: fetches /me and formats as human-readable text.
|
|
67
26
|
async function getProfile(token) {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createBlueBubblesClient = createBlueBubblesClient;
|
|
4
4
|
const node_crypto_1 = require("node:crypto");
|
|
5
|
-
const config_1 = require("
|
|
6
|
-
const identity_1 = require("
|
|
7
|
-
const runtime_1 = require("
|
|
8
|
-
const
|
|
9
|
-
const
|
|
5
|
+
const config_1 = require("../../heart/config");
|
|
6
|
+
const identity_1 = require("../../heart/identity");
|
|
7
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
8
|
+
const model_1 = require("./model");
|
|
9
|
+
const media_1 = require("./media");
|
|
10
10
|
function buildBlueBubblesApiUrl(baseUrl, endpoint, password) {
|
|
11
11
|
const root = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
12
12
|
const url = new URL(endpoint.replace(/^\//, ""), root);
|
|
@@ -423,13 +423,13 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
|
|
|
423
423
|
});
|
|
424
424
|
return repaired;
|
|
425
425
|
}
|
|
426
|
-
const normalized = (0,
|
|
426
|
+
const normalized = (0, model_1.normalizeBlueBubblesEvent)({
|
|
427
427
|
type: event.eventType,
|
|
428
428
|
data,
|
|
429
429
|
});
|
|
430
430
|
const recoveredMessage = event.kind === "mutation"
|
|
431
431
|
&& !event.shouldNotifyAgent
|
|
432
|
-
? (0,
|
|
432
|
+
? (0, model_1.normalizeBlueBubblesEvent)({
|
|
433
433
|
type: "new-message",
|
|
434
434
|
data,
|
|
435
435
|
})
|
|
@@ -440,7 +440,7 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
|
|
|
440
440
|
if (hydrated.kind === "message" &&
|
|
441
441
|
hydrated.balloonBundleId !== "com.apple.messages.URLBalloonProvider" &&
|
|
442
442
|
hydrated.attachments.length > 0) {
|
|
443
|
-
const media = await (0,
|
|
443
|
+
const media = await (0, media_1.hydrateBlueBubblesAttachments)(hydrated.attachments, config, channelConfig, {
|
|
444
444
|
preferAudioInput: providerSupportsAudioInput((0, identity_1.loadAgentConfig)().humanFacing.provider),
|
|
445
445
|
});
|
|
446
446
|
const transcriptSuffix = media.transcriptAdditions.map((entry) => `[${entry}]`).join("\n");
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Thin entrypoint for `npm run bluebubbles` / `node dist/senses/bluebubbles
|
|
3
|
-
// Separated from
|
|
2
|
+
// Thin entrypoint for `npm run bluebubbles` / `node dist/senses/bluebubbles/entry.js --agent <name>`.
|
|
3
|
+
// Separated from index.ts so the BlueBubbles adapter stays testable.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
if (!process.argv.includes("--agent")) {
|
|
6
6
|
// eslint-disable-next-line no-console -- pre-boot guard: --agent check before imports
|
|
7
|
-
console.error("Missing required --agent <name> argument.\nUsage: node dist/senses/bluebubbles
|
|
7
|
+
console.error("Missing required --agent <name> argument.\nUsage: node dist/senses/bluebubbles/entry.js --agent ouroboros");
|
|
8
8
|
process.exit(1);
|
|
9
9
|
}
|
|
10
|
-
const
|
|
11
|
-
const runtime_logging_1 = require("
|
|
10
|
+
const index_1 = require("./index");
|
|
11
|
+
const runtime_logging_1 = require("../../heart/daemon/runtime-logging");
|
|
12
12
|
(0, runtime_logging_1.configureDaemonRuntimeLogger)("bluebubbles");
|
|
13
|
-
(0,
|
|
13
|
+
(0, index_1.startBlueBubblesApp)();
|
|
@@ -38,9 +38,9 @@ exports.hasRecordedBlueBubblesInbound = hasRecordedBlueBubblesInbound;
|
|
|
38
38
|
exports.recordBlueBubblesInbound = recordBlueBubblesInbound;
|
|
39
39
|
const fs = __importStar(require("node:fs"));
|
|
40
40
|
const path = __importStar(require("node:path"));
|
|
41
|
-
const config_1 = require("
|
|
42
|
-
const identity_1 = require("
|
|
43
|
-
const runtime_1 = require("
|
|
41
|
+
const config_1 = require("../../heart/config");
|
|
42
|
+
const identity_1 = require("../../heart/identity");
|
|
43
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
44
44
|
function getBlueBubblesInboundLogPath(agentName, sessionKey) {
|
|
45
45
|
return path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "inbound", `${(0, config_1.sanitizeKey)(sessionKey)}.ndjson`);
|
|
46
46
|
}
|