@hasna/assistants 1.1.4 → 1.1.6
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/dist/cli.js +5360 -2077
- package/dist/lib.d.ts +4 -2
- package/dist/lib.js +2415 -417
- package/package.json +1 -2
package/dist/lib.js
CHANGED
|
@@ -240,7 +240,21 @@ var init_runtime = __esm(async () => {
|
|
|
240
240
|
// ../shared/src/utils.ts
|
|
241
241
|
import { randomUUID } from "crypto";
|
|
242
242
|
function generateId() {
|
|
243
|
-
|
|
243
|
+
const base = randomUUID();
|
|
244
|
+
if (base !== lastUuidBase) {
|
|
245
|
+
lastUuidBase = base;
|
|
246
|
+
uuidCounter = 0;
|
|
247
|
+
return base;
|
|
248
|
+
}
|
|
249
|
+
uuidCounter = uuidCounter + 1 & 281474976710655;
|
|
250
|
+
const parts = base.split("-");
|
|
251
|
+
if (parts.length !== 5) {
|
|
252
|
+
return base;
|
|
253
|
+
}
|
|
254
|
+
const baseValue = BigInt(`0x${parts[4]}`);
|
|
255
|
+
const nextValue = baseValue + BigInt(uuidCounter) & 0xffffffffffffn;
|
|
256
|
+
const nextLast = nextValue.toString(16).padStart(12, "0");
|
|
257
|
+
return `${parts[0]}-${parts[1]}-${parts[2]}-${parts[3]}-${nextLast}`;
|
|
244
258
|
}
|
|
245
259
|
function now() {
|
|
246
260
|
return Date.now();
|
|
@@ -302,6 +316,7 @@ function substituteVariables(template, args, env = {}) {
|
|
|
302
316
|
});
|
|
303
317
|
return result;
|
|
304
318
|
}
|
|
319
|
+
var lastUuidBase = "", uuidCounter = 0;
|
|
305
320
|
var init_utils = () => {};
|
|
306
321
|
|
|
307
322
|
// ../shared/src/models.ts
|
|
@@ -6887,6 +6902,22 @@ function mergeConfig(base, override) {
|
|
|
6887
6902
|
...override.messages?.storage || {}
|
|
6888
6903
|
}
|
|
6889
6904
|
},
|
|
6905
|
+
webhooks: {
|
|
6906
|
+
...base.webhooks || {},
|
|
6907
|
+
...override.webhooks || {},
|
|
6908
|
+
injection: {
|
|
6909
|
+
...base.webhooks?.injection || {},
|
|
6910
|
+
...override.webhooks?.injection || {}
|
|
6911
|
+
},
|
|
6912
|
+
storage: {
|
|
6913
|
+
...base.webhooks?.storage || {},
|
|
6914
|
+
...override.webhooks?.storage || {}
|
|
6915
|
+
},
|
|
6916
|
+
security: {
|
|
6917
|
+
...base.webhooks?.security || {},
|
|
6918
|
+
...override.webhooks?.security || {}
|
|
6919
|
+
}
|
|
6920
|
+
},
|
|
6890
6921
|
memory: {
|
|
6891
6922
|
...base.memory || {},
|
|
6892
6923
|
...override.memory || {},
|
|
@@ -7027,7 +7058,8 @@ async function ensureConfigDir(sessionId) {
|
|
|
7027
7058
|
mkdir2(join(configDir, "state"), { recursive: true }),
|
|
7028
7059
|
mkdir2(join(configDir, "energy"), { recursive: true }),
|
|
7029
7060
|
mkdir2(join(configDir, "jobs"), { recursive: true }),
|
|
7030
|
-
mkdir2(join(configDir, "inbox"), { recursive: true })
|
|
7061
|
+
mkdir2(join(configDir, "inbox"), { recursive: true }),
|
|
7062
|
+
mkdir2(join(configDir, "webhooks"), { recursive: true })
|
|
7031
7063
|
];
|
|
7032
7064
|
if (sessionId) {
|
|
7033
7065
|
dirs.push(mkdir2(join(configDir, "temp", sessionId), { recursive: true }));
|
|
@@ -7227,6 +7259,21 @@ var init_config = __esm(async () => {
|
|
|
7227
7259
|
maxAgeDays: 90
|
|
7228
7260
|
}
|
|
7229
7261
|
},
|
|
7262
|
+
webhooks: {
|
|
7263
|
+
enabled: false,
|
|
7264
|
+
injection: {
|
|
7265
|
+
enabled: true,
|
|
7266
|
+
maxPerTurn: 5
|
|
7267
|
+
},
|
|
7268
|
+
storage: {
|
|
7269
|
+
maxEvents: 1000,
|
|
7270
|
+
maxAgeDays: 30
|
|
7271
|
+
},
|
|
7272
|
+
security: {
|
|
7273
|
+
maxTimestampAgeMs: 300000,
|
|
7274
|
+
rateLimitPerMinute: 60
|
|
7275
|
+
}
|
|
7276
|
+
},
|
|
7230
7277
|
memory: {
|
|
7231
7278
|
enabled: true,
|
|
7232
7279
|
injection: {
|
|
@@ -13120,8 +13167,8 @@ var init_evaluator = __esm(() => {
|
|
|
13120
13167
|
});
|
|
13121
13168
|
|
|
13122
13169
|
// ../core/src/guardrails/store.ts
|
|
13123
|
-
import { readFileSync as readFileSync7, writeFileSync as writeFileSync8, existsSync as
|
|
13124
|
-
import { join as
|
|
13170
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync8, existsSync as existsSync14, mkdirSync as mkdirSync8 } from "fs";
|
|
13171
|
+
import { join as join22, dirname as dirname10 } from "path";
|
|
13125
13172
|
import { createHash as createHash3 } from "crypto";
|
|
13126
13173
|
function generatePolicyId(name, scope) {
|
|
13127
13174
|
const hash = createHash3("sha256").update(`${name}-${scope}-${Date.now()}`).digest("hex").slice(0, 8);
|
|
@@ -13143,16 +13190,16 @@ class GuardrailsStore {
|
|
|
13143
13190
|
getFilePath(location) {
|
|
13144
13191
|
switch (location) {
|
|
13145
13192
|
case "user":
|
|
13146
|
-
return
|
|
13193
|
+
return join22(getConfigDir(), "guardrails.json");
|
|
13147
13194
|
case "project":
|
|
13148
|
-
return
|
|
13195
|
+
return join22(this.cwd, ".assistants", "guardrails.json");
|
|
13149
13196
|
case "local":
|
|
13150
|
-
return
|
|
13197
|
+
return join22(this.cwd, ".assistants", "guardrails.local.json");
|
|
13151
13198
|
}
|
|
13152
13199
|
}
|
|
13153
13200
|
loadFrom(location) {
|
|
13154
13201
|
const filePath = this.getFilePath(location);
|
|
13155
|
-
if (!
|
|
13202
|
+
if (!existsSync14(filePath)) {
|
|
13156
13203
|
return null;
|
|
13157
13204
|
}
|
|
13158
13205
|
try {
|
|
@@ -13167,9 +13214,9 @@ class GuardrailsStore {
|
|
|
13167
13214
|
}
|
|
13168
13215
|
save(location, config) {
|
|
13169
13216
|
const filePath = this.getFilePath(location);
|
|
13170
|
-
const dir =
|
|
13171
|
-
if (!
|
|
13172
|
-
|
|
13217
|
+
const dir = dirname10(filePath);
|
|
13218
|
+
if (!existsSync14(dir)) {
|
|
13219
|
+
mkdirSync8(dir, { recursive: true });
|
|
13173
13220
|
}
|
|
13174
13221
|
ensurePolicyIds(config);
|
|
13175
13222
|
writeFileSync8(filePath, JSON.stringify({ guardrails: config }, null, 2), "utf-8");
|
|
@@ -42572,8 +42619,8 @@ var require_core3 = __commonJS((exports) => {
|
|
|
42572
42619
|
function many1(p) {
|
|
42573
42620
|
return ab(p, many(p), (head, tail) => [head, ...tail]);
|
|
42574
42621
|
}
|
|
42575
|
-
function ab(pa, pb,
|
|
42576
|
-
return (data, i) => mapOuter(pa(data, i), (ma) => mapInner(pb(data, ma.position), (vb, j) =>
|
|
42622
|
+
function ab(pa, pb, join23) {
|
|
42623
|
+
return (data, i) => mapOuter(pa(data, i), (ma) => mapInner(pb(data, ma.position), (vb, j) => join23(ma.value, vb, data, i, j)));
|
|
42577
42624
|
}
|
|
42578
42625
|
function left(pa, pb) {
|
|
42579
42626
|
return ab(pa, pb, (va) => va);
|
|
@@ -42581,8 +42628,8 @@ var require_core3 = __commonJS((exports) => {
|
|
|
42581
42628
|
function right(pa, pb) {
|
|
42582
42629
|
return ab(pa, pb, (va, vb) => vb);
|
|
42583
42630
|
}
|
|
42584
|
-
function abc(pa, pb, pc,
|
|
42585
|
-
return (data, i) => mapOuter(pa(data, i), (ma) => mapOuter(pb(data, ma.position), (mb) => mapInner(pc(data, mb.position), (vc, j) =>
|
|
42631
|
+
function abc(pa, pb, pc, join23) {
|
|
42632
|
+
return (data, i) => mapOuter(pa(data, i), (ma) => mapOuter(pb(data, ma.position), (mb) => mapInner(pc(data, mb.position), (vc, j) => join23(ma.value, mb.value, vc, data, i, j))));
|
|
42586
42633
|
}
|
|
42587
42634
|
function middle(pa, pb, pc) {
|
|
42588
42635
|
return abc(pa, pb, pc, (ra, rb) => rb);
|
|
@@ -51296,14 +51343,14 @@ var init_email_parser = __esm(() => {
|
|
|
51296
51343
|
});
|
|
51297
51344
|
|
|
51298
51345
|
// ../core/src/workspace/shared.ts
|
|
51299
|
-
import { join as
|
|
51346
|
+
import { join as join23 } from "path";
|
|
51300
51347
|
import { homedir as homedir11 } from "os";
|
|
51301
51348
|
import {
|
|
51302
|
-
existsSync as
|
|
51303
|
-
mkdirSync as
|
|
51349
|
+
existsSync as existsSync15,
|
|
51350
|
+
mkdirSync as mkdirSync9,
|
|
51304
51351
|
writeFileSync as writeFileSync9,
|
|
51305
51352
|
readFileSync as readFileSync8,
|
|
51306
|
-
readdirSync as
|
|
51353
|
+
readdirSync as readdirSync6,
|
|
51307
51354
|
rmSync,
|
|
51308
51355
|
renameSync
|
|
51309
51356
|
} from "fs";
|
|
@@ -51312,33 +51359,33 @@ class SharedWorkspaceManager {
|
|
|
51312
51359
|
basePath;
|
|
51313
51360
|
constructor(basePath) {
|
|
51314
51361
|
const envHome = process.env.HOME || process.env.USERPROFILE || homedir11();
|
|
51315
|
-
this.basePath = basePath ||
|
|
51362
|
+
this.basePath = basePath || join23(envHome, ".assistants", "workspaces");
|
|
51316
51363
|
this.ensureDir();
|
|
51317
51364
|
this.migrateAgentsToAssistants();
|
|
51318
51365
|
}
|
|
51319
51366
|
ensureDir() {
|
|
51320
|
-
if (!
|
|
51321
|
-
|
|
51367
|
+
if (!existsSync15(this.basePath)) {
|
|
51368
|
+
mkdirSync9(this.basePath, { recursive: true });
|
|
51322
51369
|
}
|
|
51323
51370
|
}
|
|
51324
51371
|
migrateAgentsToAssistants() {
|
|
51325
51372
|
try {
|
|
51326
|
-
const dirs =
|
|
51373
|
+
const dirs = readdirSync6(this.basePath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
51327
51374
|
for (const dir of dirs) {
|
|
51328
|
-
const wsPath =
|
|
51329
|
-
const oldAgentsDir =
|
|
51330
|
-
const newAssistantsDir =
|
|
51331
|
-
if (
|
|
51375
|
+
const wsPath = join23(this.basePath, dir);
|
|
51376
|
+
const oldAgentsDir = join23(wsPath, "agents");
|
|
51377
|
+
const newAssistantsDir = join23(wsPath, "assistants");
|
|
51378
|
+
if (existsSync15(oldAgentsDir) && !existsSync15(newAssistantsDir)) {
|
|
51332
51379
|
renameSync(oldAgentsDir, newAssistantsDir);
|
|
51333
51380
|
}
|
|
51334
51381
|
}
|
|
51335
51382
|
} catch {}
|
|
51336
51383
|
}
|
|
51337
51384
|
getWorkspacePath(id) {
|
|
51338
|
-
return
|
|
51385
|
+
return join23(this.basePath, id);
|
|
51339
51386
|
}
|
|
51340
51387
|
getMetadataPath(id) {
|
|
51341
|
-
return
|
|
51388
|
+
return join23(this.getWorkspacePath(id), "workspace.json");
|
|
51342
51389
|
}
|
|
51343
51390
|
create(name, createdBy, participants, description) {
|
|
51344
51391
|
const id = `ws_${generateId().slice(0, 8)}`;
|
|
@@ -51353,9 +51400,9 @@ class SharedWorkspaceManager {
|
|
|
51353
51400
|
status: "active"
|
|
51354
51401
|
};
|
|
51355
51402
|
const wsPath = this.getWorkspacePath(id);
|
|
51356
|
-
|
|
51403
|
+
mkdirSync9(join23(wsPath, "shared"), { recursive: true });
|
|
51357
51404
|
for (const assistantId of workspace.participants) {
|
|
51358
|
-
|
|
51405
|
+
mkdirSync9(join23(wsPath, "assistants", assistantId), { recursive: true });
|
|
51359
51406
|
}
|
|
51360
51407
|
writeFileSync9(this.getMetadataPath(id), JSON.stringify(workspace, null, 2));
|
|
51361
51408
|
return workspace;
|
|
@@ -51370,15 +51417,15 @@ class SharedWorkspaceManager {
|
|
|
51370
51417
|
workspace.updatedAt = Date.now();
|
|
51371
51418
|
writeFileSync9(this.getMetadataPath(workspaceId), JSON.stringify(workspace, null, 2));
|
|
51372
51419
|
}
|
|
51373
|
-
const assistantDir =
|
|
51374
|
-
if (!
|
|
51375
|
-
|
|
51420
|
+
const assistantDir = join23(this.getWorkspacePath(workspaceId), "assistants", assistantId);
|
|
51421
|
+
if (!existsSync15(assistantDir)) {
|
|
51422
|
+
mkdirSync9(assistantDir, { recursive: true });
|
|
51376
51423
|
}
|
|
51377
51424
|
}
|
|
51378
51425
|
get(workspaceId) {
|
|
51379
51426
|
try {
|
|
51380
51427
|
const metadataPath = this.getMetadataPath(workspaceId);
|
|
51381
|
-
if (!
|
|
51428
|
+
if (!existsSync15(metadataPath))
|
|
51382
51429
|
return null;
|
|
51383
51430
|
return JSON.parse(readFileSync8(metadataPath, "utf-8"));
|
|
51384
51431
|
} catch {
|
|
@@ -51389,15 +51436,15 @@ class SharedWorkspaceManager {
|
|
|
51389
51436
|
return this.getWorkspacePath(workspaceId);
|
|
51390
51437
|
}
|
|
51391
51438
|
getSharedPath(workspaceId) {
|
|
51392
|
-
return
|
|
51439
|
+
return join23(this.getWorkspacePath(workspaceId), "shared");
|
|
51393
51440
|
}
|
|
51394
51441
|
getAssistantPath(workspaceId, assistantId) {
|
|
51395
|
-
return
|
|
51442
|
+
return join23(this.getWorkspacePath(workspaceId), "assistants", assistantId);
|
|
51396
51443
|
}
|
|
51397
51444
|
list(includeArchived = false) {
|
|
51398
51445
|
try {
|
|
51399
51446
|
this.ensureDir();
|
|
51400
|
-
const dirs =
|
|
51447
|
+
const dirs = readdirSync6(this.basePath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
51401
51448
|
const workspaces = [];
|
|
51402
51449
|
for (const dir of dirs) {
|
|
51403
51450
|
const workspace = this.get(dir);
|
|
@@ -51425,7 +51472,7 @@ class SharedWorkspaceManager {
|
|
|
51425
51472
|
}
|
|
51426
51473
|
delete(workspaceId) {
|
|
51427
51474
|
const wsPath = this.getWorkspacePath(workspaceId);
|
|
51428
|
-
if (
|
|
51475
|
+
if (existsSync15(wsPath)) {
|
|
51429
51476
|
rmSync(wsPath, { recursive: true, force: true });
|
|
51430
51477
|
}
|
|
51431
51478
|
}
|
|
@@ -51485,9 +51532,9 @@ var init_defaults2 = __esm(() => {
|
|
|
51485
51532
|
});
|
|
51486
51533
|
|
|
51487
51534
|
// ../core/src/budget/tracker.ts
|
|
51488
|
-
import { join as
|
|
51535
|
+
import { join as join24, dirname as dirname11 } from "path";
|
|
51489
51536
|
import { homedir as homedir12 } from "os";
|
|
51490
|
-
import { existsSync as
|
|
51537
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10, readFileSync as readFileSync9 } from "fs";
|
|
51491
51538
|
function createEmptyUsage() {
|
|
51492
51539
|
const now2 = new Date().toISOString();
|
|
51493
51540
|
return {
|
|
@@ -51521,16 +51568,16 @@ class BudgetTracker {
|
|
|
51521
51568
|
}
|
|
51522
51569
|
getStatePath() {
|
|
51523
51570
|
const envHome = process.env.HOME || process.env.USERPROFILE || homedir12();
|
|
51524
|
-
return
|
|
51571
|
+
return join24(envHome, ".assistants", "budget", `${this.sessionId}.json`);
|
|
51525
51572
|
}
|
|
51526
51573
|
getProjectStatePath(projectId) {
|
|
51527
51574
|
const envHome = process.env.HOME || process.env.USERPROFILE || homedir12();
|
|
51528
|
-
return
|
|
51575
|
+
return join24(envHome, ".assistants", "budget", `project-${projectId}.json`);
|
|
51529
51576
|
}
|
|
51530
51577
|
loadState() {
|
|
51531
51578
|
try {
|
|
51532
51579
|
const statePath = this.getStatePath();
|
|
51533
|
-
if (!
|
|
51580
|
+
if (!existsSync16(statePath))
|
|
51534
51581
|
return;
|
|
51535
51582
|
const data = JSON.parse(readFileSync9(statePath, "utf-8"));
|
|
51536
51583
|
if (data.version !== PERSISTENCE_VERSION && data.version !== 1)
|
|
@@ -51551,7 +51598,7 @@ class BudgetTracker {
|
|
|
51551
51598
|
loadProjectState(projectId) {
|
|
51552
51599
|
try {
|
|
51553
51600
|
const statePath = this.getProjectStatePath(projectId);
|
|
51554
|
-
if (!
|
|
51601
|
+
if (!existsSync16(statePath))
|
|
51555
51602
|
return createEmptyUsage();
|
|
51556
51603
|
const data = JSON.parse(readFileSync9(statePath, "utf-8"));
|
|
51557
51604
|
return data;
|
|
@@ -51564,9 +51611,9 @@ class BudgetTracker {
|
|
|
51564
51611
|
return;
|
|
51565
51612
|
try {
|
|
51566
51613
|
const statePath = this.getProjectStatePath(projectId);
|
|
51567
|
-
const stateDir =
|
|
51568
|
-
if (!
|
|
51569
|
-
|
|
51614
|
+
const stateDir = dirname11(statePath);
|
|
51615
|
+
if (!existsSync16(stateDir)) {
|
|
51616
|
+
mkdirSync10(stateDir, { recursive: true });
|
|
51570
51617
|
}
|
|
51571
51618
|
writeFileSync10(statePath, JSON.stringify(usage, null, 2));
|
|
51572
51619
|
} catch {}
|
|
@@ -51576,9 +51623,9 @@ class BudgetTracker {
|
|
|
51576
51623
|
return;
|
|
51577
51624
|
try {
|
|
51578
51625
|
const statePath = this.getStatePath();
|
|
51579
|
-
const stateDir =
|
|
51580
|
-
if (!
|
|
51581
|
-
|
|
51626
|
+
const stateDir = dirname11(statePath);
|
|
51627
|
+
if (!existsSync16(stateDir)) {
|
|
51628
|
+
mkdirSync10(stateDir, { recursive: true });
|
|
51582
51629
|
}
|
|
51583
51630
|
const state = {
|
|
51584
51631
|
version: PERSISTENCE_VERSION,
|
|
@@ -52151,8 +52198,8 @@ var init_types2 = __esm(() => {
|
|
|
52151
52198
|
});
|
|
52152
52199
|
|
|
52153
52200
|
// ../core/src/registry/store.ts
|
|
52154
|
-
import { existsSync as
|
|
52155
|
-
import { join as
|
|
52201
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync11 } from "fs";
|
|
52202
|
+
import { join as join25, dirname as dirname12 } from "path";
|
|
52156
52203
|
import { homedir as homedir13 } from "os";
|
|
52157
52204
|
function generateAssistantId() {
|
|
52158
52205
|
return `assistant_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
@@ -52290,12 +52337,12 @@ class RegistryStore {
|
|
|
52290
52337
|
return this.config.storagePath;
|
|
52291
52338
|
}
|
|
52292
52339
|
const home = process.env.HOME || process.env.USERPROFILE || homedir13();
|
|
52293
|
-
return
|
|
52340
|
+
return join25(home, ".assistants", "registry", "assistants.json");
|
|
52294
52341
|
}
|
|
52295
52342
|
loadFromFile() {
|
|
52296
52343
|
try {
|
|
52297
52344
|
const path = this.getStoragePath();
|
|
52298
|
-
if (!
|
|
52345
|
+
if (!existsSync17(path))
|
|
52299
52346
|
return;
|
|
52300
52347
|
const data = JSON.parse(readFileSync10(path, "utf-8"));
|
|
52301
52348
|
if (Array.isArray(data.assistants)) {
|
|
@@ -52310,9 +52357,9 @@ class RegistryStore {
|
|
|
52310
52357
|
return;
|
|
52311
52358
|
try {
|
|
52312
52359
|
const path = this.getStoragePath();
|
|
52313
|
-
const dir =
|
|
52314
|
-
if (!
|
|
52315
|
-
|
|
52360
|
+
const dir = dirname12(path);
|
|
52361
|
+
if (!existsSync17(dir)) {
|
|
52362
|
+
mkdirSync11(dir, { recursive: true });
|
|
52316
52363
|
}
|
|
52317
52364
|
const data = {
|
|
52318
52365
|
version: 1,
|
|
@@ -61274,14 +61321,14 @@ var exports_anthropic = {};
|
|
|
61274
61321
|
__export(exports_anthropic, {
|
|
61275
61322
|
AnthropicClient: () => AnthropicClient
|
|
61276
61323
|
});
|
|
61277
|
-
import { readFileSync as readFileSync11, existsSync as
|
|
61324
|
+
import { readFileSync as readFileSync11, existsSync as existsSync19 } from "fs";
|
|
61278
61325
|
import { homedir as homedir15 } from "os";
|
|
61279
|
-
import { join as
|
|
61326
|
+
import { join as join27 } from "path";
|
|
61280
61327
|
function loadApiKeyFromSecrets() {
|
|
61281
61328
|
const envHome = process.env.HOME || process.env.USERPROFILE;
|
|
61282
61329
|
const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir15();
|
|
61283
|
-
const secretsPath =
|
|
61284
|
-
if (
|
|
61330
|
+
const secretsPath = join27(homeDir, ".secrets");
|
|
61331
|
+
if (existsSync19(secretsPath)) {
|
|
61285
61332
|
try {
|
|
61286
61333
|
const content = readFileSync11(secretsPath, "utf-8");
|
|
61287
61334
|
const match = content.match(/export\s+ANTHROPIC_API_KEY\s*=\s*["']?([^"'\n]+)["']?/);
|
|
@@ -67297,14 +67344,14 @@ var exports_openai = {};
|
|
|
67297
67344
|
__export(exports_openai, {
|
|
67298
67345
|
OpenAIClient: () => OpenAIClient
|
|
67299
67346
|
});
|
|
67300
|
-
import { readFileSync as readFileSync12, existsSync as
|
|
67347
|
+
import { readFileSync as readFileSync12, existsSync as existsSync20 } from "fs";
|
|
67301
67348
|
import { homedir as homedir16 } from "os";
|
|
67302
|
-
import { join as
|
|
67349
|
+
import { join as join28 } from "path";
|
|
67303
67350
|
function loadApiKeyFromSecrets2() {
|
|
67304
67351
|
const envHome = process.env.HOME || process.env.USERPROFILE;
|
|
67305
67352
|
const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir16();
|
|
67306
|
-
const secretsPath =
|
|
67307
|
-
if (
|
|
67353
|
+
const secretsPath = join28(homeDir, ".secrets");
|
|
67354
|
+
if (existsSync20(secretsPath)) {
|
|
67308
67355
|
try {
|
|
67309
67356
|
const content = readFileSync12(secretsPath, "utf-8");
|
|
67310
67357
|
const match = content.match(/export\s+OPENAI_API_KEY\s*=\s*["']?([^"'\n]+)["']?/);
|
|
@@ -80501,7 +80548,7 @@ var require_readFile = __commonJS((exports) => {
|
|
|
80501
80548
|
var promises_1 = __require("fs/promises");
|
|
80502
80549
|
exports.filePromises = {};
|
|
80503
80550
|
exports.fileIntercept = {};
|
|
80504
|
-
var
|
|
80551
|
+
var readFile14 = (path2, options) => {
|
|
80505
80552
|
if (exports.fileIntercept[path2] !== undefined) {
|
|
80506
80553
|
return exports.fileIntercept[path2];
|
|
80507
80554
|
}
|
|
@@ -80510,7 +80557,7 @@ var require_readFile = __commonJS((exports) => {
|
|
|
80510
80557
|
}
|
|
80511
80558
|
return exports.filePromises[path2];
|
|
80512
80559
|
};
|
|
80513
|
-
exports.readFile =
|
|
80560
|
+
exports.readFile = readFile14;
|
|
80514
80561
|
});
|
|
80515
80562
|
|
|
80516
80563
|
// ../../node_modules/.bun/@smithy+shared-ini-file-loader@4.4.3/node_modules/@smithy/shared-ini-file-loader/dist-cjs/index.js
|
|
@@ -80520,7 +80567,7 @@ var require_dist_cjs35 = __commonJS((exports) => {
|
|
|
80520
80567
|
var getSSOTokenFromFile = require_getSSOTokenFromFile();
|
|
80521
80568
|
var path2 = __require("path");
|
|
80522
80569
|
var types11 = require_dist_cjs();
|
|
80523
|
-
var
|
|
80570
|
+
var readFile14 = require_readFile();
|
|
80524
80571
|
var ENV_PROFILE = "AWS_PROFILE";
|
|
80525
80572
|
var DEFAULT_PROFILE2 = "default";
|
|
80526
80573
|
var getProfileName = (init2) => init2.profile || process.env[ENV_PROFILE] || DEFAULT_PROFILE2;
|
|
@@ -80604,10 +80651,10 @@ var require_dist_cjs35 = __commonJS((exports) => {
|
|
|
80604
80651
|
resolvedConfigFilepath = path2.join(homeDir, configFilepath.slice(2));
|
|
80605
80652
|
}
|
|
80606
80653
|
const parsedFiles = await Promise.all([
|
|
80607
|
-
|
|
80654
|
+
readFile14.readFile(resolvedConfigFilepath, {
|
|
80608
80655
|
ignoreCache: init2.ignoreCache
|
|
80609
80656
|
}).then(parseIni).then(getConfigData).catch(swallowError$1),
|
|
80610
|
-
|
|
80657
|
+
readFile14.readFile(resolvedFilepath, {
|
|
80611
80658
|
ignoreCache: init2.ignoreCache
|
|
80612
80659
|
}).then(parseIni).catch(swallowError$1)
|
|
80613
80660
|
]);
|
|
@@ -80618,7 +80665,7 @@ var require_dist_cjs35 = __commonJS((exports) => {
|
|
|
80618
80665
|
};
|
|
80619
80666
|
var getSsoSessionData = (data) => Object.entries(data).filter(([key]) => key.startsWith(types11.IniSectionType.SSO_SESSION + CONFIG_PREFIX_SEPARATOR)).reduce((acc, [key, value]) => ({ ...acc, [key.substring(key.indexOf(CONFIG_PREFIX_SEPARATOR) + 1)]: value }), {});
|
|
80620
80667
|
var swallowError = () => ({});
|
|
80621
|
-
var loadSsoSessionData = async (init2 = {}) =>
|
|
80668
|
+
var loadSsoSessionData = async (init2 = {}) => readFile14.readFile(init2.configFilepath ?? getConfigFilepath()).then(parseIni).then(getSsoSessionData).catch(swallowError);
|
|
80622
80669
|
var mergeConfigFiles = (...files) => {
|
|
80623
80670
|
const merged = {};
|
|
80624
80671
|
for (const file of files) {
|
|
@@ -80638,10 +80685,10 @@ var require_dist_cjs35 = __commonJS((exports) => {
|
|
|
80638
80685
|
};
|
|
80639
80686
|
var externalDataInterceptor = {
|
|
80640
80687
|
getFileRecord() {
|
|
80641
|
-
return
|
|
80688
|
+
return readFile14.fileIntercept;
|
|
80642
80689
|
},
|
|
80643
80690
|
interceptFile(path3, contents) {
|
|
80644
|
-
|
|
80691
|
+
readFile14.fileIntercept[path3] = Promise.resolve(contents);
|
|
80645
80692
|
},
|
|
80646
80693
|
getTokenRecord() {
|
|
80647
80694
|
return getSSOTokenFromFile.tokenIntercept;
|
|
@@ -80659,7 +80706,7 @@ var require_dist_cjs35 = __commonJS((exports) => {
|
|
|
80659
80706
|
Object.defineProperty(exports, "readFile", {
|
|
80660
80707
|
enumerable: true,
|
|
80661
80708
|
get: function() {
|
|
80662
|
-
return
|
|
80709
|
+
return readFile14.readFile;
|
|
80663
80710
|
}
|
|
80664
80711
|
});
|
|
80665
80712
|
exports.CONFIG_PREFIX_SEPARATOR = CONFIG_PREFIX_SEPARATOR;
|
|
@@ -87996,7 +88043,7 @@ var require_signin = __commonJS((exports) => {
|
|
|
87996
88043
|
import { createHash as createHash4, createPrivateKey, createPublicKey, sign } from "crypto";
|
|
87997
88044
|
import { promises as fs2 } from "fs";
|
|
87998
88045
|
import { homedir as homedir18 } from "os";
|
|
87999
|
-
import { dirname as
|
|
88046
|
+
import { dirname as dirname16, join as join36 } from "path";
|
|
88000
88047
|
var import_property_provider18, import_protocol_http10, import_shared_ini_file_loader6, LoginCredentialsFetcher;
|
|
88001
88048
|
var init_LoginCredentialsFetcher = __esm(() => {
|
|
88002
88049
|
import_property_provider18 = __toESM(require_dist_cjs17(), 1);
|
|
@@ -88149,17 +88196,17 @@ var init_LoginCredentialsFetcher = __esm(() => {
|
|
|
88149
88196
|
}
|
|
88150
88197
|
async saveToken(token) {
|
|
88151
88198
|
const tokenFilePath = this.getTokenFilePath();
|
|
88152
|
-
const directory =
|
|
88199
|
+
const directory = dirname16(tokenFilePath);
|
|
88153
88200
|
try {
|
|
88154
88201
|
await fs2.mkdir(directory, { recursive: true });
|
|
88155
88202
|
} catch (error2) {}
|
|
88156
88203
|
await fs2.writeFile(tokenFilePath, JSON.stringify(token, null, 2), "utf8");
|
|
88157
88204
|
}
|
|
88158
88205
|
getTokenFilePath() {
|
|
88159
|
-
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ??
|
|
88206
|
+
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join36(homedir18(), ".aws", "login", "cache");
|
|
88160
88207
|
const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
|
|
88161
88208
|
const loginSessionSha256 = createHash4("sha256").update(loginSessionBytes).digest("hex");
|
|
88162
|
-
return
|
|
88209
|
+
return join36(directory, `${loginSessionSha256}.json`);
|
|
88163
88210
|
}
|
|
88164
88211
|
derToRawSignature(derSignature) {
|
|
88165
88212
|
let offset = 2;
|
|
@@ -89198,8 +89245,8 @@ function many(p4) {
|
|
|
89198
89245
|
function many1(p4) {
|
|
89199
89246
|
return ab2(p4, many(p4), (head, tail) => [head, ...tail]);
|
|
89200
89247
|
}
|
|
89201
|
-
function ab2(pa, pb,
|
|
89202
|
-
return (data, i4) => mapOuter(pa(data, i4), (ma) => mapInner(pb(data, ma.position), (vb, j4) =>
|
|
89248
|
+
function ab2(pa, pb, join38) {
|
|
89249
|
+
return (data, i4) => mapOuter(pa(data, i4), (ma) => mapInner(pb(data, ma.position), (vb, j4) => join38(ma.value, vb, data, i4, j4)));
|
|
89203
89250
|
}
|
|
89204
89251
|
function left(pa, pb) {
|
|
89205
89252
|
return ab2(pa, pb, (va) => va);
|
|
@@ -89207,8 +89254,8 @@ function left(pa, pb) {
|
|
|
89207
89254
|
function right(pa, pb) {
|
|
89208
89255
|
return ab2(pa, pb, (va, vb) => vb);
|
|
89209
89256
|
}
|
|
89210
|
-
function abc(pa, pb, pc,
|
|
89211
|
-
return (data, i4) => mapOuter(pa(data, i4), (ma) => mapOuter(pb(data, ma.position), (mb) => mapInner(pc(data, mb.position), (vc, j4) =>
|
|
89257
|
+
function abc(pa, pb, pc, join38) {
|
|
89258
|
+
return (data, i4) => mapOuter(pa(data, i4), (ma) => mapOuter(pb(data, ma.position), (mb) => mapInner(pc(data, mb.position), (vc, j4) => join38(ma.value, mb.value, vc, data, i4, j4))));
|
|
89212
89259
|
}
|
|
89213
89260
|
function middle(pa, pb, pc) {
|
|
89214
89261
|
return abc(pa, pb, pc, (ra, rb) => rb);
|
|
@@ -110706,12 +110753,70 @@ var init_node2 = __esm(() => {
|
|
|
110706
110753
|
decoder = new TextDecoder("utf-8");
|
|
110707
110754
|
});
|
|
110708
110755
|
|
|
110756
|
+
// ../core/src/webhooks/crypto.ts
|
|
110757
|
+
var exports_crypto = {};
|
|
110758
|
+
__export(exports_crypto, {
|
|
110759
|
+
verifySignature: () => verifySignature,
|
|
110760
|
+
signPayload: () => signPayload,
|
|
110761
|
+
isTimestampValid: () => isTimestampValid,
|
|
110762
|
+
generateWebhookSecret: () => generateWebhookSecret,
|
|
110763
|
+
generateWebhookId: () => generateWebhookId,
|
|
110764
|
+
generateEventId: () => generateEventId,
|
|
110765
|
+
generateDeliveryId: () => generateDeliveryId
|
|
110766
|
+
});
|
|
110767
|
+
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
110768
|
+
function generateWebhookSecret() {
|
|
110769
|
+
const bytes = randomBytes(32);
|
|
110770
|
+
return `whsec_${bytes.toString("hex")}`;
|
|
110771
|
+
}
|
|
110772
|
+
function signPayload(payload, secret) {
|
|
110773
|
+
const key = secret.startsWith("whsec_") ? secret.slice(6) : secret;
|
|
110774
|
+
return createHmac("sha256", key).update(payload).digest("hex");
|
|
110775
|
+
}
|
|
110776
|
+
function verifySignature(payload, signature, secret) {
|
|
110777
|
+
try {
|
|
110778
|
+
const expected = signPayload(payload, secret);
|
|
110779
|
+
const sigBuffer = Buffer.from(signature, "hex");
|
|
110780
|
+
const expectedBuffer = Buffer.from(expected, "hex");
|
|
110781
|
+
if (sigBuffer.length !== expectedBuffer.length) {
|
|
110782
|
+
return false;
|
|
110783
|
+
}
|
|
110784
|
+
return timingSafeEqual(sigBuffer, expectedBuffer);
|
|
110785
|
+
} catch {
|
|
110786
|
+
return false;
|
|
110787
|
+
}
|
|
110788
|
+
}
|
|
110789
|
+
function isTimestampValid(timestamp, maxAgeMs = 300000) {
|
|
110790
|
+
try {
|
|
110791
|
+
const eventTime = new Date(timestamp).getTime();
|
|
110792
|
+
if (isNaN(eventTime))
|
|
110793
|
+
return false;
|
|
110794
|
+
const now2 = Date.now();
|
|
110795
|
+
const age = Math.abs(now2 - eventTime);
|
|
110796
|
+
return age <= maxAgeMs;
|
|
110797
|
+
} catch {
|
|
110798
|
+
return false;
|
|
110799
|
+
}
|
|
110800
|
+
}
|
|
110801
|
+
function generateWebhookId() {
|
|
110802
|
+
return `whk_${generateId().slice(0, 12)}`;
|
|
110803
|
+
}
|
|
110804
|
+
function generateEventId() {
|
|
110805
|
+
return `evt_${generateId().slice(0, 12)}`;
|
|
110806
|
+
}
|
|
110807
|
+
function generateDeliveryId() {
|
|
110808
|
+
return `dlv_${generateId().slice(0, 12)}`;
|
|
110809
|
+
}
|
|
110810
|
+
var init_crypto = __esm(() => {
|
|
110811
|
+
init_src2();
|
|
110812
|
+
});
|
|
110813
|
+
|
|
110709
110814
|
// ../core/src/index.ts
|
|
110710
110815
|
await init_runtime();
|
|
110711
110816
|
|
|
110712
110817
|
// ../core/src/agent/loop.ts
|
|
110713
110818
|
init_src2();
|
|
110714
|
-
import { join as
|
|
110819
|
+
import { join as join46 } from "path";
|
|
110715
110820
|
|
|
110716
110821
|
// ../core/src/agent/context.ts
|
|
110717
110822
|
init_src2();
|
|
@@ -115766,16 +115871,191 @@ function registerEnergyTools(registry, context) {
|
|
|
115766
115871
|
}
|
|
115767
115872
|
}
|
|
115768
115873
|
|
|
115874
|
+
// ../core/src/heartbeat/history.ts
|
|
115875
|
+
await init_config();
|
|
115876
|
+
import { dirname as dirname4, join as join6 } from "path";
|
|
115877
|
+
import { mkdirSync as mkdirSync2, existsSync as existsSync4, readdirSync as readdirSync2 } from "fs";
|
|
115878
|
+
import { appendFile as appendFile2, readFile as readFile2 } from "fs/promises";
|
|
115879
|
+
function applySessionPlaceholder(path, sessionId) {
|
|
115880
|
+
if (path.includes("{sessionId}")) {
|
|
115881
|
+
return path.replace("{sessionId}", sessionId);
|
|
115882
|
+
}
|
|
115883
|
+
return path;
|
|
115884
|
+
}
|
|
115885
|
+
function resolveHeartbeatPersistPath(sessionId, persistPath) {
|
|
115886
|
+
if (persistPath) {
|
|
115887
|
+
return applySessionPlaceholder(persistPath, sessionId);
|
|
115888
|
+
}
|
|
115889
|
+
return join6(getConfigDir(), "heartbeats", `${sessionId}.json`);
|
|
115890
|
+
}
|
|
115891
|
+
function resolveHeartbeatHistoryPath(sessionId, historyPath) {
|
|
115892
|
+
if (historyPath) {
|
|
115893
|
+
return applySessionPlaceholder(historyPath, sessionId);
|
|
115894
|
+
}
|
|
115895
|
+
return join6(getConfigDir(), "heartbeats", "runs", `${sessionId}.jsonl`);
|
|
115896
|
+
}
|
|
115897
|
+
function listHeartbeatHistorySessions(baseDir) {
|
|
115898
|
+
const dir = baseDir ?? join6(getConfigDir(), "heartbeats", "runs");
|
|
115899
|
+
if (!existsSync4(dir))
|
|
115900
|
+
return [];
|
|
115901
|
+
return readdirSync2(dir).filter((file) => file.endsWith(".jsonl")).map((file) => file.replace(/\.jsonl$/, ""));
|
|
115902
|
+
}
|
|
115903
|
+
async function appendHeartbeatHistory(historyPath, heartbeat) {
|
|
115904
|
+
try {
|
|
115905
|
+
mkdirSync2(dirname4(historyPath), { recursive: true });
|
|
115906
|
+
await appendFile2(historyPath, `${JSON.stringify(heartbeat)}
|
|
115907
|
+
`, "utf-8");
|
|
115908
|
+
} catch {}
|
|
115909
|
+
}
|
|
115910
|
+
async function readHeartbeatHistory(historyPath, options = {}) {
|
|
115911
|
+
try {
|
|
115912
|
+
const content = await readFile2(historyPath, "utf-8");
|
|
115913
|
+
const lines = content.split(`
|
|
115914
|
+
`).filter(Boolean);
|
|
115915
|
+
const parsed = [];
|
|
115916
|
+
for (const line of lines) {
|
|
115917
|
+
try {
|
|
115918
|
+
parsed.push(JSON.parse(line));
|
|
115919
|
+
} catch {}
|
|
115920
|
+
}
|
|
115921
|
+
const order = options.order ?? "desc";
|
|
115922
|
+
const ordered = order === "desc" ? parsed.reverse() : parsed;
|
|
115923
|
+
if (options.limit && options.limit > 0) {
|
|
115924
|
+
return ordered.slice(0, options.limit);
|
|
115925
|
+
}
|
|
115926
|
+
return ordered;
|
|
115927
|
+
} catch {
|
|
115928
|
+
return [];
|
|
115929
|
+
}
|
|
115930
|
+
}
|
|
115931
|
+
async function readLatestHeartbeat(persistPath, historyPath) {
|
|
115932
|
+
if (historyPath) {
|
|
115933
|
+
const history = await readHeartbeatHistory(historyPath, { limit: 1, order: "desc" });
|
|
115934
|
+
if (history.length > 0)
|
|
115935
|
+
return history[0];
|
|
115936
|
+
}
|
|
115937
|
+
try {
|
|
115938
|
+
const content = await readFile2(persistPath, "utf-8");
|
|
115939
|
+
return JSON.parse(content);
|
|
115940
|
+
} catch {
|
|
115941
|
+
return null;
|
|
115942
|
+
}
|
|
115943
|
+
}
|
|
115944
|
+
|
|
115945
|
+
// ../core/src/tools/heartbeat.ts
|
|
115946
|
+
var heartbeatStatusTool = {
|
|
115947
|
+
name: "heartbeat_status",
|
|
115948
|
+
description: "Get heartbeat status, last heartbeat record, and optional recent runs for a session.",
|
|
115949
|
+
parameters: {
|
|
115950
|
+
type: "object",
|
|
115951
|
+
properties: {
|
|
115952
|
+
sessionId: {
|
|
115953
|
+
type: "string",
|
|
115954
|
+
description: "Optional session id (defaults to current session)"
|
|
115955
|
+
},
|
|
115956
|
+
includeRuns: {
|
|
115957
|
+
type: "boolean",
|
|
115958
|
+
description: "Include recent heartbeat runs in the response"
|
|
115959
|
+
},
|
|
115960
|
+
limit: {
|
|
115961
|
+
type: "number",
|
|
115962
|
+
description: "Max number of runs to include (default: 20)"
|
|
115963
|
+
}
|
|
115964
|
+
},
|
|
115965
|
+
required: []
|
|
115966
|
+
}
|
|
115967
|
+
};
|
|
115968
|
+
var heartbeatRunsTool = {
|
|
115969
|
+
name: "heartbeat_runs",
|
|
115970
|
+
description: "List heartbeat runs for a session with optional limits and ordering.",
|
|
115971
|
+
parameters: {
|
|
115972
|
+
type: "object",
|
|
115973
|
+
properties: {
|
|
115974
|
+
sessionId: {
|
|
115975
|
+
type: "string",
|
|
115976
|
+
description: "Optional session id (defaults to current session)"
|
|
115977
|
+
},
|
|
115978
|
+
limit: {
|
|
115979
|
+
type: "number",
|
|
115980
|
+
description: "Max number of runs to return (default: 50)"
|
|
115981
|
+
},
|
|
115982
|
+
order: {
|
|
115983
|
+
type: "string",
|
|
115984
|
+
description: 'Sort order: "asc" or "desc" (default: desc)',
|
|
115985
|
+
enum: ["asc", "desc"]
|
|
115986
|
+
}
|
|
115987
|
+
},
|
|
115988
|
+
required: []
|
|
115989
|
+
}
|
|
115990
|
+
};
|
|
115991
|
+
var heartbeatTools = [heartbeatStatusTool, heartbeatRunsTool];
|
|
115992
|
+
function parseLimit(value, fallback) {
|
|
115993
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
115994
|
+
return Math.floor(value);
|
|
115995
|
+
}
|
|
115996
|
+
return fallback;
|
|
115997
|
+
}
|
|
115998
|
+
function createHeartbeatToolExecutors(context) {
|
|
115999
|
+
return {
|
|
116000
|
+
heartbeat_status: async (input) => {
|
|
116001
|
+
const sessionId = typeof input.sessionId === "string" && input.sessionId.trim().length > 0 ? input.sessionId.trim() : context.sessionId;
|
|
116002
|
+
const config = context.getHeartbeatConfig?.() ?? null;
|
|
116003
|
+
const persistPath = resolveHeartbeatPersistPath(sessionId, config?.persistPath);
|
|
116004
|
+
const historyPath = resolveHeartbeatHistoryPath(sessionId, config?.historyPath);
|
|
116005
|
+
const lastHeartbeat = await readLatestHeartbeat(persistPath, historyPath);
|
|
116006
|
+
const state = context.getHeartbeatState?.() ?? null;
|
|
116007
|
+
const staleThreshold = config?.staleThresholdMs ?? 120000;
|
|
116008
|
+
const lastTimestamp = lastHeartbeat ? new Date(lastHeartbeat.timestamp).getTime() : null;
|
|
116009
|
+
const computedStale = lastTimestamp ? Date.now() - lastTimestamp > staleThreshold : true;
|
|
116010
|
+
const includeRuns = Boolean(input.includeRuns);
|
|
116011
|
+
const limit = parseLimit(input.limit, 20);
|
|
116012
|
+
const runs = includeRuns ? await readHeartbeatHistory(historyPath, { limit, order: "desc" }) : undefined;
|
|
116013
|
+
const enabled = state?.enabled ?? (config ? true : false);
|
|
116014
|
+
return JSON.stringify({
|
|
116015
|
+
success: true,
|
|
116016
|
+
sessionId,
|
|
116017
|
+
enabled,
|
|
116018
|
+
state: state?.state ?? lastHeartbeat?.state ?? null,
|
|
116019
|
+
isStale: state?.isStale ?? computedStale,
|
|
116020
|
+
lastActivity: state?.lastActivity ?? lastHeartbeat?.lastActivity ?? null,
|
|
116021
|
+
uptimeSeconds: state?.uptimeSeconds ?? lastHeartbeat?.stats?.uptimeSeconds ?? null,
|
|
116022
|
+
lastHeartbeat,
|
|
116023
|
+
runs
|
|
116024
|
+
});
|
|
116025
|
+
},
|
|
116026
|
+
heartbeat_runs: async (input) => {
|
|
116027
|
+
const sessionId = typeof input.sessionId === "string" && input.sessionId.trim().length > 0 ? input.sessionId.trim() : context.sessionId;
|
|
116028
|
+
const config = context.getHeartbeatConfig?.() ?? null;
|
|
116029
|
+
const historyPath = resolveHeartbeatHistoryPath(sessionId, config?.historyPath);
|
|
116030
|
+
const order = input.order === "asc" ? "asc" : "desc";
|
|
116031
|
+
const limit = parseLimit(input.limit, 50);
|
|
116032
|
+
const runs = await readHeartbeatHistory(historyPath, { limit, order });
|
|
116033
|
+
return JSON.stringify({
|
|
116034
|
+
success: true,
|
|
116035
|
+
sessionId,
|
|
116036
|
+
count: runs.length,
|
|
116037
|
+
runs
|
|
116038
|
+
});
|
|
116039
|
+
}
|
|
116040
|
+
};
|
|
116041
|
+
}
|
|
116042
|
+
function registerHeartbeatTools(registry, context) {
|
|
116043
|
+
const executors = createHeartbeatToolExecutors(context);
|
|
116044
|
+
for (const tool of heartbeatTools) {
|
|
116045
|
+
registry.register(tool, executors[tool.name]);
|
|
116046
|
+
}
|
|
116047
|
+
}
|
|
116048
|
+
|
|
115769
116049
|
// ../core/src/tools/context-entries.ts
|
|
115770
116050
|
init_src2();
|
|
115771
116051
|
|
|
115772
116052
|
// ../core/src/projects/store.ts
|
|
115773
116053
|
init_src2();
|
|
115774
|
-
import { join as
|
|
115775
|
-
import { mkdir as mkdir4, readdir, readFile as
|
|
116054
|
+
import { join as join7 } from "path";
|
|
116055
|
+
import { mkdir as mkdir4, readdir, readFile as readFile3, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
|
|
115776
116056
|
var SAFE_ID_PATTERN2 = /^[a-zA-Z0-9_-]+$/;
|
|
115777
116057
|
function projectsDir(cwd) {
|
|
115778
|
-
return
|
|
116058
|
+
return join7(cwd, ".assistants", "projects");
|
|
115779
116059
|
}
|
|
115780
116060
|
function isSafeId2(id) {
|
|
115781
116061
|
return SAFE_ID_PATTERN2.test(id);
|
|
@@ -115783,7 +116063,7 @@ function isSafeId2(id) {
|
|
|
115783
116063
|
function projectPath(cwd, id) {
|
|
115784
116064
|
if (!isSafeId2(id))
|
|
115785
116065
|
return null;
|
|
115786
|
-
return
|
|
116066
|
+
return join7(projectsDir(cwd), `${id}.json`);
|
|
115787
116067
|
}
|
|
115788
116068
|
async function ensureProjectsDir(cwd) {
|
|
115789
116069
|
await mkdir4(projectsDir(cwd), { recursive: true });
|
|
@@ -115800,7 +116080,7 @@ async function listProjects(cwd) {
|
|
|
115800
116080
|
if (!file.endsWith(".json"))
|
|
115801
116081
|
continue;
|
|
115802
116082
|
try {
|
|
115803
|
-
const raw = await
|
|
116083
|
+
const raw = await readFile3(join7(dir, file), "utf-8");
|
|
115804
116084
|
const parsed = JSON.parse(raw);
|
|
115805
116085
|
if (parsed?.id && parsed?.name) {
|
|
115806
116086
|
projects.push(parsed);
|
|
@@ -115817,7 +116097,7 @@ async function readProject(cwd, id) {
|
|
|
115817
116097
|
const path = projectPath(cwd, id);
|
|
115818
116098
|
if (!path)
|
|
115819
116099
|
return null;
|
|
115820
|
-
const raw = await
|
|
116100
|
+
const raw = await readFile3(path, "utf-8");
|
|
115821
116101
|
const project = JSON.parse(raw);
|
|
115822
116102
|
if (!project?.id || !project?.name)
|
|
115823
116103
|
return null;
|
|
@@ -115884,9 +116164,9 @@ function hasProjectNameConflict(projects, name) {
|
|
|
115884
116164
|
}
|
|
115885
116165
|
|
|
115886
116166
|
// ../core/src/projects/context.ts
|
|
115887
|
-
import { readFile as
|
|
116167
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
115888
116168
|
import { homedir as homedir5 } from "os";
|
|
115889
|
-
import { resolve as resolve2, join as
|
|
116169
|
+
import { resolve as resolve2, join as join8 } from "path";
|
|
115890
116170
|
|
|
115891
116171
|
// ../core/src/validation/paths.ts
|
|
115892
116172
|
import { resolve, normalize, relative, isAbsolute } from "path";
|
|
@@ -115967,7 +116247,7 @@ function normalizeEntryLabel(entry) {
|
|
|
115967
116247
|
}
|
|
115968
116248
|
async function renderFileEntry(entry, options) {
|
|
115969
116249
|
const rawPath = entry.value.trim();
|
|
115970
|
-
const expandedPath = rawPath === "~" ? homedir5() : rawPath.startsWith("~/") ?
|
|
116250
|
+
const expandedPath = rawPath === "~" ? homedir5() : rawPath.startsWith("~/") ? join8(homedir5(), rawPath.slice(2)) : rawPath;
|
|
115971
116251
|
const resolved = resolve2(options.cwd, expandedPath);
|
|
115972
116252
|
const validation = await validatePath(resolved, { allowedPaths: [options.cwd] });
|
|
115973
116253
|
if (!validation.valid) {
|
|
@@ -115975,7 +116255,7 @@ async function renderFileEntry(entry, options) {
|
|
|
115975
116255
|
}
|
|
115976
116256
|
let content = "";
|
|
115977
116257
|
try {
|
|
115978
|
-
const data = await
|
|
116258
|
+
const data = await readFile4(validation.resolved, "utf-8");
|
|
115979
116259
|
const limit = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
115980
116260
|
if (data.length > limit) {
|
|
115981
116261
|
content = `${data.slice(0, limit)}
|
|
@@ -116480,8 +116760,8 @@ function registerSecurityTools(registry, context) {
|
|
|
116480
116760
|
|
|
116481
116761
|
// ../core/src/logger.ts
|
|
116482
116762
|
await init_config();
|
|
116483
|
-
import { existsSync as
|
|
116484
|
-
import { join as
|
|
116763
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, appendFileSync, readdirSync as readdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
116764
|
+
import { join as join9 } from "path";
|
|
116485
116765
|
var SAFE_ID_PATTERN3 = /^[a-zA-Z0-9_-]+$/;
|
|
116486
116766
|
function isValidId(id) {
|
|
116487
116767
|
return typeof id === "string" && id.length > 0 && SAFE_ID_PATTERN3.test(id);
|
|
@@ -116493,14 +116773,14 @@ class Logger {
|
|
|
116493
116773
|
sessionId;
|
|
116494
116774
|
constructor(sessionId, basePath) {
|
|
116495
116775
|
this.sessionId = sessionId;
|
|
116496
|
-
this.logDir =
|
|
116776
|
+
this.logDir = join9(basePath || getConfigDir(), "logs");
|
|
116497
116777
|
this.ensureDir(this.logDir);
|
|
116498
116778
|
const date = new Date().toISOString().split("T")[0];
|
|
116499
|
-
this.logFile =
|
|
116779
|
+
this.logFile = join9(this.logDir, `${date}.log`);
|
|
116500
116780
|
}
|
|
116501
116781
|
ensureDir(dir) {
|
|
116502
|
-
if (!
|
|
116503
|
-
|
|
116782
|
+
if (!existsSync5(dir)) {
|
|
116783
|
+
mkdirSync3(dir, { recursive: true });
|
|
116504
116784
|
}
|
|
116505
116785
|
}
|
|
116506
116786
|
write(level, message, data) {
|
|
@@ -116532,12 +116812,12 @@ class Logger {
|
|
|
116532
116812
|
this.write("error", message, data);
|
|
116533
116813
|
}
|
|
116534
116814
|
static readEntries(options) {
|
|
116535
|
-
const logDir =
|
|
116536
|
-
if (!
|
|
116815
|
+
const logDir = join9(options?.basePath || getConfigDir(), "logs");
|
|
116816
|
+
if (!existsSync5(logDir))
|
|
116537
116817
|
return [];
|
|
116538
116818
|
const levelOrder = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
116539
116819
|
const minLevel = options?.level ? levelOrder[options.level] : 0;
|
|
116540
|
-
const files =
|
|
116820
|
+
const files = readdirSync3(logDir).filter((f) => /^\d{4}-\d{2}-\d{2}\.log$/.test(f)).sort((a, b) => b.localeCompare(a));
|
|
116541
116821
|
const entries = [];
|
|
116542
116822
|
for (const file of files) {
|
|
116543
116823
|
if (options?.since) {
|
|
@@ -116547,7 +116827,7 @@ class Logger {
|
|
|
116547
116827
|
break;
|
|
116548
116828
|
}
|
|
116549
116829
|
try {
|
|
116550
|
-
const content = readFileSync3(
|
|
116830
|
+
const content = readFileSync3(join9(logDir, file), "utf-8");
|
|
116551
116831
|
const lines = content.trim().split(`
|
|
116552
116832
|
`).filter(Boolean);
|
|
116553
116833
|
for (const line of lines) {
|
|
@@ -116570,10 +116850,10 @@ class Logger {
|
|
|
116570
116850
|
return entries.slice(offset, offset + limit);
|
|
116571
116851
|
}
|
|
116572
116852
|
static listLogDates(basePath) {
|
|
116573
|
-
const logDir =
|
|
116574
|
-
if (!
|
|
116853
|
+
const logDir = join9(basePath || getConfigDir(), "logs");
|
|
116854
|
+
if (!existsSync5(logDir))
|
|
116575
116855
|
return [];
|
|
116576
|
-
return
|
|
116856
|
+
return readdirSync3(logDir).filter((f) => /^\d{4}-\d{2}-\d{2}\.log$/.test(f)).map((f) => f.replace(".log", "")).sort((a, b) => b.localeCompare(a));
|
|
116577
116857
|
}
|
|
116578
116858
|
}
|
|
116579
116859
|
|
|
@@ -116588,13 +116868,13 @@ class SessionStorage {
|
|
|
116588
116868
|
this.sessionId = sessionId;
|
|
116589
116869
|
const root = basePath || getConfigDir();
|
|
116590
116870
|
const safeAssistantId = isValidId(assistantId) ? assistantId : null;
|
|
116591
|
-
this.sessionsDir = safeAssistantId ?
|
|
116871
|
+
this.sessionsDir = safeAssistantId ? join9(root, "assistants", safeAssistantId, "sessions") : join9(root, "sessions");
|
|
116592
116872
|
this.ensureDir(this.sessionsDir);
|
|
116593
|
-
this.sessionFile =
|
|
116873
|
+
this.sessionFile = join9(this.sessionsDir, `${sessionId}.json`);
|
|
116594
116874
|
}
|
|
116595
116875
|
ensureDir(dir) {
|
|
116596
|
-
if (!
|
|
116597
|
-
|
|
116876
|
+
if (!existsSync5(dir)) {
|
|
116877
|
+
mkdirSync3(dir, { recursive: true });
|
|
116598
116878
|
}
|
|
116599
116879
|
}
|
|
116600
116880
|
save(data) {
|
|
@@ -116607,7 +116887,7 @@ class SessionStorage {
|
|
|
116607
116887
|
}
|
|
116608
116888
|
load() {
|
|
116609
116889
|
try {
|
|
116610
|
-
if (!
|
|
116890
|
+
if (!existsSync5(this.sessionFile))
|
|
116611
116891
|
return null;
|
|
116612
116892
|
return JSON.parse(readFileSync3(this.sessionFile, "utf-8"));
|
|
116613
116893
|
} catch {
|
|
@@ -116616,8 +116896,8 @@ class SessionStorage {
|
|
|
116616
116896
|
}
|
|
116617
116897
|
static getActiveAssistantId() {
|
|
116618
116898
|
try {
|
|
116619
|
-
const activePath =
|
|
116620
|
-
if (!
|
|
116899
|
+
const activePath = join9(getConfigDir(), "active.json");
|
|
116900
|
+
if (!existsSync5(activePath))
|
|
116621
116901
|
return null;
|
|
116622
116902
|
const raw = readFileSync3(activePath, "utf-8");
|
|
116623
116903
|
const data = JSON.parse(raw);
|
|
@@ -116631,38 +116911,65 @@ class SessionStorage {
|
|
|
116631
116911
|
}
|
|
116632
116912
|
}
|
|
116633
116913
|
static resolveSessionsDir(assistantId) {
|
|
116914
|
+
return SessionStorage.resolveSessionsDirWithAssistant(assistantId).dir;
|
|
116915
|
+
}
|
|
116916
|
+
static resolveSessionsDirWithAssistant(assistantId) {
|
|
116634
116917
|
const root = getConfigDir();
|
|
116635
116918
|
const safeAssistantId = isValidId(assistantId) ? assistantId : null;
|
|
116636
116919
|
const resolvedId = safeAssistantId ?? SessionStorage.getActiveAssistantId();
|
|
116637
116920
|
if (resolvedId && isValidId(resolvedId)) {
|
|
116638
|
-
const assistantDir =
|
|
116639
|
-
if (
|
|
116640
|
-
return assistantDir;
|
|
116921
|
+
const assistantDir = join9(root, "assistants", resolvedId, "sessions");
|
|
116922
|
+
if (existsSync5(assistantDir)) {
|
|
116923
|
+
return { dir: assistantDir, assistantId: resolvedId };
|
|
116641
116924
|
}
|
|
116642
116925
|
}
|
|
116643
|
-
return
|
|
116926
|
+
return { dir: join9(root, "sessions"), assistantId: null };
|
|
116644
116927
|
}
|
|
116645
|
-
static
|
|
116646
|
-
|
|
116647
|
-
if (!existsSync4(sessionsDir))
|
|
116928
|
+
static readSessionsFromDir(sessionsDir, assistantId) {
|
|
116929
|
+
if (!existsSync5(sessionsDir))
|
|
116648
116930
|
return [];
|
|
116649
116931
|
const sessions = [];
|
|
116650
|
-
const files =
|
|
116932
|
+
const files = readdirSync3(sessionsDir);
|
|
116651
116933
|
for (const file of files) {
|
|
116652
116934
|
if (!file.endsWith(".json"))
|
|
116653
116935
|
continue;
|
|
116654
116936
|
try {
|
|
116655
|
-
const filePath =
|
|
116937
|
+
const filePath = join9(sessionsDir, file);
|
|
116656
116938
|
const content = JSON.parse(readFileSync3(filePath, "utf-8"));
|
|
116657
116939
|
sessions.push({
|
|
116658
116940
|
id: file.replace(".json", ""),
|
|
116659
116941
|
cwd: content.cwd,
|
|
116660
116942
|
startedAt: content.startedAt,
|
|
116661
116943
|
updatedAt: content.updatedAt,
|
|
116662
|
-
messageCount: content.messages?.length || 0
|
|
116944
|
+
messageCount: content.messages?.length || 0,
|
|
116945
|
+
assistantId
|
|
116663
116946
|
});
|
|
116664
116947
|
} catch {}
|
|
116665
116948
|
}
|
|
116949
|
+
return sessions;
|
|
116950
|
+
}
|
|
116951
|
+
static listSessions(assistantId) {
|
|
116952
|
+
const { dir, assistantId: resolvedAssistantId } = SessionStorage.resolveSessionsDirWithAssistant(assistantId);
|
|
116953
|
+
const sessions = SessionStorage.readSessionsFromDir(dir, resolvedAssistantId);
|
|
116954
|
+
return sessions.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
116955
|
+
}
|
|
116956
|
+
static listAllSessions() {
|
|
116957
|
+
const root = getConfigDir();
|
|
116958
|
+
const sessions = [];
|
|
116959
|
+
const rootSessionsDir = join9(root, "sessions");
|
|
116960
|
+
sessions.push(...SessionStorage.readSessionsFromDir(rootSessionsDir, null));
|
|
116961
|
+
const assistantsDir = join9(root, "assistants");
|
|
116962
|
+
if (existsSync5(assistantsDir)) {
|
|
116963
|
+
const entries = readdirSync3(assistantsDir, { withFileTypes: true });
|
|
116964
|
+
for (const entry of entries) {
|
|
116965
|
+
if (!entry.isDirectory())
|
|
116966
|
+
continue;
|
|
116967
|
+
if (!isValidId(entry.name))
|
|
116968
|
+
continue;
|
|
116969
|
+
const assistantSessionsDir = join9(assistantsDir, entry.name, "sessions");
|
|
116970
|
+
sessions.push(...SessionStorage.readSessionsFromDir(assistantSessionsDir, entry.name));
|
|
116971
|
+
}
|
|
116972
|
+
}
|
|
116666
116973
|
return sessions.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
116667
116974
|
}
|
|
116668
116975
|
static getLatestSession(assistantId) {
|
|
@@ -116674,9 +116981,9 @@ class SessionStorage {
|
|
|
116674
116981
|
return null;
|
|
116675
116982
|
}
|
|
116676
116983
|
const sessionsDir = SessionStorage.resolveSessionsDir(assistantId);
|
|
116677
|
-
const sessionFile =
|
|
116984
|
+
const sessionFile = join9(sessionsDir, `${sessionId}.json`);
|
|
116678
116985
|
try {
|
|
116679
|
-
if (!
|
|
116986
|
+
if (!existsSync5(sessionFile))
|
|
116680
116987
|
return null;
|
|
116681
116988
|
return JSON.parse(readFileSync3(sessionFile, "utf-8"));
|
|
116682
116989
|
} catch {
|
|
@@ -116688,40 +116995,40 @@ function initAssistantsDir() {
|
|
|
116688
116995
|
const baseDir = getConfigDir();
|
|
116689
116996
|
const dirs = [
|
|
116690
116997
|
baseDir,
|
|
116691
|
-
|
|
116692
|
-
|
|
116693
|
-
|
|
116694
|
-
|
|
116695
|
-
|
|
116696
|
-
|
|
116697
|
-
|
|
116698
|
-
|
|
116699
|
-
|
|
116998
|
+
join9(baseDir, "logs"),
|
|
116999
|
+
join9(baseDir, "assistants"),
|
|
117000
|
+
join9(baseDir, "shared", "skills"),
|
|
117001
|
+
join9(baseDir, "commands"),
|
|
117002
|
+
join9(baseDir, "temp"),
|
|
117003
|
+
join9(baseDir, "heartbeats"),
|
|
117004
|
+
join9(baseDir, "state"),
|
|
117005
|
+
join9(baseDir, "energy"),
|
|
117006
|
+
join9(baseDir, "migration")
|
|
116700
117007
|
];
|
|
116701
117008
|
for (const dir of dirs) {
|
|
116702
|
-
if (!
|
|
116703
|
-
|
|
117009
|
+
if (!existsSync5(dir)) {
|
|
117010
|
+
mkdirSync3(dir, { recursive: true });
|
|
116704
117011
|
}
|
|
116705
117012
|
}
|
|
116706
117013
|
}
|
|
116707
117014
|
|
|
116708
117015
|
// ../core/src/hooks/logger.ts
|
|
116709
117016
|
await init_config();
|
|
116710
|
-
import { join as
|
|
116711
|
-
import { existsSync as
|
|
117017
|
+
import { join as join10 } from "path";
|
|
117018
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, appendFileSync as appendFileSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
116712
117019
|
var MAX_ENTRIES = 1000;
|
|
116713
117020
|
function getLogPath() {
|
|
116714
|
-
return
|
|
117021
|
+
return join10(getConfigDir(), "logs", "hooks.jsonl");
|
|
116715
117022
|
}
|
|
116716
117023
|
function ensureLogsDir() {
|
|
116717
|
-
const logsDir =
|
|
116718
|
-
if (!
|
|
116719
|
-
|
|
117024
|
+
const logsDir = join10(getConfigDir(), "logs");
|
|
117025
|
+
if (!existsSync6(logsDir)) {
|
|
117026
|
+
mkdirSync4(logsDir, { recursive: true });
|
|
116720
117027
|
}
|
|
116721
117028
|
}
|
|
116722
117029
|
function rotateIfNeeded() {
|
|
116723
117030
|
const logPath = getLogPath();
|
|
116724
|
-
if (!
|
|
117031
|
+
if (!existsSync6(logPath))
|
|
116725
117032
|
return;
|
|
116726
117033
|
try {
|
|
116727
117034
|
const content = readFileSync4(logPath, "utf-8");
|
|
@@ -116779,7 +117086,7 @@ class HookLogger {
|
|
|
116779
117086
|
}
|
|
116780
117087
|
static getHistory(limit = 50, hookId) {
|
|
116781
117088
|
const logPath = getLogPath();
|
|
116782
|
-
if (!
|
|
117089
|
+
if (!existsSync6(logPath))
|
|
116783
117090
|
return [];
|
|
116784
117091
|
try {
|
|
116785
117092
|
const content = readFileSync4(logPath, "utf-8");
|
|
@@ -116801,7 +117108,7 @@ class HookLogger {
|
|
|
116801
117108
|
}
|
|
116802
117109
|
static clearHistory() {
|
|
116803
117110
|
const logPath = getLogPath();
|
|
116804
|
-
if (
|
|
117111
|
+
if (existsSync6(logPath)) {
|
|
116805
117112
|
writeFileSync3(logPath, "", "utf-8");
|
|
116806
117113
|
}
|
|
116807
117114
|
}
|
|
@@ -117172,22 +117479,22 @@ function registerLogsTools(registry, context) {
|
|
|
117172
117479
|
|
|
117173
117480
|
// ../core/src/sessions/verification.ts
|
|
117174
117481
|
init_src2();
|
|
117175
|
-
import { join as
|
|
117176
|
-
import { existsSync as
|
|
117482
|
+
import { join as join11 } from "path";
|
|
117483
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4, readdirSync as readdirSync4, unlinkSync } from "fs";
|
|
117177
117484
|
|
|
117178
117485
|
class VerificationSessionStore {
|
|
117179
117486
|
basePath;
|
|
117180
117487
|
maxSessions;
|
|
117181
117488
|
lastTimestamp;
|
|
117182
117489
|
constructor(basePath, maxSessions = 100) {
|
|
117183
|
-
this.basePath =
|
|
117490
|
+
this.basePath = join11(basePath, "verifications");
|
|
117184
117491
|
this.maxSessions = maxSessions;
|
|
117185
117492
|
this.lastTimestamp = 0;
|
|
117186
117493
|
this.ensureDirectory();
|
|
117187
117494
|
}
|
|
117188
117495
|
ensureDirectory() {
|
|
117189
|
-
if (!
|
|
117190
|
-
|
|
117496
|
+
if (!existsSync7(this.basePath)) {
|
|
117497
|
+
mkdirSync5(this.basePath, { recursive: true });
|
|
117191
117498
|
}
|
|
117192
117499
|
}
|
|
117193
117500
|
create(parentSessionId, goals, verificationResult) {
|
|
@@ -117212,12 +117519,12 @@ class VerificationSessionStore {
|
|
|
117212
117519
|
return session;
|
|
117213
117520
|
}
|
|
117214
117521
|
save(session) {
|
|
117215
|
-
const filePath =
|
|
117522
|
+
const filePath = join11(this.basePath, `${session.id}.json`);
|
|
117216
117523
|
writeFileSync4(filePath, JSON.stringify(session, null, 2));
|
|
117217
117524
|
}
|
|
117218
117525
|
get(id) {
|
|
117219
|
-
const filePath =
|
|
117220
|
-
if (!
|
|
117526
|
+
const filePath = join11(this.basePath, `${id}.json`);
|
|
117527
|
+
if (!existsSync7(filePath)) {
|
|
117221
117528
|
return null;
|
|
117222
117529
|
}
|
|
117223
117530
|
try {
|
|
@@ -117232,7 +117539,7 @@ class VerificationSessionStore {
|
|
|
117232
117539
|
const files = this.listFiles();
|
|
117233
117540
|
for (const file of files) {
|
|
117234
117541
|
try {
|
|
117235
|
-
const content = readFileSync5(
|
|
117542
|
+
const content = readFileSync5(join11(this.basePath, file), "utf-8");
|
|
117236
117543
|
const session = JSON.parse(content);
|
|
117237
117544
|
if (session.parentSessionId === parentSessionId) {
|
|
117238
117545
|
sessions.push(session);
|
|
@@ -117248,7 +117555,7 @@ class VerificationSessionStore {
|
|
|
117248
117555
|
const files = this.listFiles();
|
|
117249
117556
|
for (const file of files) {
|
|
117250
117557
|
try {
|
|
117251
|
-
const content = readFileSync5(
|
|
117558
|
+
const content = readFileSync5(join11(this.basePath, file), "utf-8");
|
|
117252
117559
|
const session = JSON.parse(content);
|
|
117253
117560
|
sessions.push(session);
|
|
117254
117561
|
} catch {
|
|
@@ -117265,10 +117572,10 @@ class VerificationSessionStore {
|
|
|
117265
117572
|
this.save(session);
|
|
117266
117573
|
}
|
|
117267
117574
|
listFiles() {
|
|
117268
|
-
if (!
|
|
117575
|
+
if (!existsSync7(this.basePath)) {
|
|
117269
117576
|
return [];
|
|
117270
117577
|
}
|
|
117271
|
-
return
|
|
117578
|
+
return readdirSync4(this.basePath).filter((f) => f.endsWith(".json"));
|
|
117272
117579
|
}
|
|
117273
117580
|
pruneOldSessions() {
|
|
117274
117581
|
const files = this.listFiles();
|
|
@@ -117278,7 +117585,7 @@ class VerificationSessionStore {
|
|
|
117278
117585
|
const sessions = [];
|
|
117279
117586
|
for (const file of files) {
|
|
117280
117587
|
try {
|
|
117281
|
-
const content = readFileSync5(
|
|
117588
|
+
const content = readFileSync5(join11(this.basePath, file), "utf-8");
|
|
117282
117589
|
const session = JSON.parse(content);
|
|
117283
117590
|
sessions.push({
|
|
117284
117591
|
file,
|
|
@@ -117292,7 +117599,7 @@ class VerificationSessionStore {
|
|
|
117292
117599
|
const toRemove = sessions.slice(0, sessions.length - this.maxSessions);
|
|
117293
117600
|
for (const item of toRemove) {
|
|
117294
117601
|
try {
|
|
117295
|
-
unlinkSync(
|
|
117602
|
+
unlinkSync(join11(this.basePath, item.file));
|
|
117296
117603
|
} catch {
|
|
117297
117604
|
continue;
|
|
117298
117605
|
}
|
|
@@ -117302,7 +117609,7 @@ class VerificationSessionStore {
|
|
|
117302
117609
|
const files = this.listFiles();
|
|
117303
117610
|
for (const file of files) {
|
|
117304
117611
|
try {
|
|
117305
|
-
unlinkSync(
|
|
117612
|
+
unlinkSync(join11(this.basePath, file));
|
|
117306
117613
|
} catch {
|
|
117307
117614
|
continue;
|
|
117308
117615
|
}
|
|
@@ -117364,7 +117671,7 @@ class HookLoader {
|
|
|
117364
117671
|
// ../core/src/hooks/executor.ts
|
|
117365
117672
|
init_src2();
|
|
117366
117673
|
await init_runtime();
|
|
117367
|
-
import { existsSync as
|
|
117674
|
+
import { existsSync as existsSync8 } from "fs";
|
|
117368
117675
|
|
|
117369
117676
|
// ../core/src/hooks/background.ts
|
|
117370
117677
|
class BackgroundProcessManager {
|
|
@@ -117578,7 +117885,7 @@ class HookExecutor {
|
|
|
117578
117885
|
}
|
|
117579
117886
|
try {
|
|
117580
117887
|
const runtime = getRuntime();
|
|
117581
|
-
const cwd = input.cwd &&
|
|
117888
|
+
const cwd = input.cwd && existsSync8(input.cwd) ? input.cwd : process.cwd();
|
|
117582
117889
|
const isWindows = process.platform === "win32";
|
|
117583
117890
|
const shellBinary = isWindows ? "cmd" : runtime.which("bash") || "sh";
|
|
117584
117891
|
const shellArgs = isWindows ? ["/c", hook.command] : ["-lc", hook.command];
|
|
@@ -117631,7 +117938,7 @@ class HookExecutor {
|
|
|
117631
117938
|
return null;
|
|
117632
117939
|
try {
|
|
117633
117940
|
const runtime = getRuntime();
|
|
117634
|
-
const cwd = input.cwd &&
|
|
117941
|
+
const cwd = input.cwd && existsSync8(input.cwd) ? input.cwd : process.cwd();
|
|
117635
117942
|
const isWindows = process.platform === "win32";
|
|
117636
117943
|
const shellBinary = isWindows ? "cmd" : runtime.which("bash") || "sh";
|
|
117637
117944
|
const shellArgs = isWindows ? ["/c", hook.command] : ["-lc", hook.command];
|
|
@@ -118200,8 +118507,8 @@ function createScopeVerificationHook() {
|
|
|
118200
118507
|
}
|
|
118201
118508
|
// ../core/src/hooks/store.ts
|
|
118202
118509
|
await init_config();
|
|
118203
|
-
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as
|
|
118204
|
-
import { join as
|
|
118510
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
|
|
118511
|
+
import { join as join12, dirname as dirname5 } from "path";
|
|
118205
118512
|
import { createHash as createHash2 } from "crypto";
|
|
118206
118513
|
function generateHookId2(event, hook) {
|
|
118207
118514
|
const content = hook.command || hook.prompt || "";
|
|
@@ -118228,16 +118535,16 @@ class HookStore {
|
|
|
118228
118535
|
getFilePath(location) {
|
|
118229
118536
|
switch (location) {
|
|
118230
118537
|
case "user":
|
|
118231
|
-
return
|
|
118538
|
+
return join12(getConfigDir(), "hooks.json");
|
|
118232
118539
|
case "project":
|
|
118233
|
-
return
|
|
118540
|
+
return join12(this.cwd, ".assistants", "hooks.json");
|
|
118234
118541
|
case "local":
|
|
118235
|
-
return
|
|
118542
|
+
return join12(this.cwd, ".assistants", "hooks.local.json");
|
|
118236
118543
|
}
|
|
118237
118544
|
}
|
|
118238
118545
|
loadFrom(location) {
|
|
118239
118546
|
const filePath = this.getFilePath(location);
|
|
118240
|
-
if (!
|
|
118547
|
+
if (!existsSync9(filePath)) {
|
|
118241
118548
|
return {};
|
|
118242
118549
|
}
|
|
118243
118550
|
try {
|
|
@@ -118252,9 +118559,9 @@ class HookStore {
|
|
|
118252
118559
|
}
|
|
118253
118560
|
save(location, config) {
|
|
118254
118561
|
const filePath = this.getFilePath(location);
|
|
118255
|
-
const dir =
|
|
118256
|
-
if (!
|
|
118257
|
-
|
|
118562
|
+
const dir = dirname5(filePath);
|
|
118563
|
+
if (!existsSync9(dir)) {
|
|
118564
|
+
mkdirSync6(dir, { recursive: true });
|
|
118258
118565
|
}
|
|
118259
118566
|
ensureHookIds(config);
|
|
118260
118567
|
writeFileSync5(filePath, JSON.stringify({ hooks: config }, null, 2), "utf-8");
|
|
@@ -118394,7 +118701,7 @@ class HookStore {
|
|
|
118394
118701
|
// ../core/src/hooks/tester.ts
|
|
118395
118702
|
init_src2();
|
|
118396
118703
|
await init_runtime();
|
|
118397
|
-
import { existsSync as
|
|
118704
|
+
import { existsSync as existsSync10 } from "fs";
|
|
118398
118705
|
var sampleInputs = {
|
|
118399
118706
|
SessionStart: {
|
|
118400
118707
|
source: "test"
|
|
@@ -118518,7 +118825,7 @@ class HookTester {
|
|
|
118518
118825
|
}
|
|
118519
118826
|
async executeCommand(command, input, timeout) {
|
|
118520
118827
|
const runtime = getRuntime();
|
|
118521
|
-
const cwd = input.cwd &&
|
|
118828
|
+
const cwd = input.cwd && existsSync10(input.cwd) ? input.cwd : process.cwd();
|
|
118522
118829
|
const isWindows = process.platform === "win32";
|
|
118523
118830
|
const shellBinary = isWindows ? "cmd" : runtime.which("bash") || "sh";
|
|
118524
118831
|
const shellArgs = isWindows ? ["/c", command] : ["-lc", command];
|
|
@@ -119625,7 +119932,7 @@ await __promiseAll([
|
|
|
119625
119932
|
init_config(),
|
|
119626
119933
|
init_runtime()
|
|
119627
119934
|
]);
|
|
119628
|
-
import { join as
|
|
119935
|
+
import { join as join13, resolve as resolve4, dirname as dirname6, sep } from "path";
|
|
119629
119936
|
import { homedir as homedir7 } from "os";
|
|
119630
119937
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
119631
119938
|
|
|
@@ -119791,7 +120098,7 @@ function isWithinPath2(target, base) {
|
|
|
119791
120098
|
var currentSessionId = "default";
|
|
119792
120099
|
function getScriptsFolder(cwd, sessionId) {
|
|
119793
120100
|
const resolvedSessionId = sessionId || currentSessionId;
|
|
119794
|
-
return
|
|
120101
|
+
return join13(getProjectConfigDir(cwd), "scripts", resolvedSessionId);
|
|
119795
120102
|
}
|
|
119796
120103
|
function isInScriptsFolder(path, cwd, sessionId) {
|
|
119797
120104
|
const scriptsFolder = resolve4(getScriptsFolder(cwd, sessionId));
|
|
@@ -120000,7 +120307,7 @@ class FilesystemTools {
|
|
|
120000
120307
|
});
|
|
120001
120308
|
}
|
|
120002
120309
|
const sanitizedFilename = filename.replace(/\.\.[/\\]/g, "").replace(/\.\./g, "").replace(/^[/\\]+/, "");
|
|
120003
|
-
const path =
|
|
120310
|
+
const path = join13(scriptsFolder, sanitizedFilename);
|
|
120004
120311
|
if (!isInScriptsFolder(path, baseCwd, input.sessionId)) {
|
|
120005
120312
|
throw new ToolExecutionError(`Cannot write outside scripts folder. Files are saved to ${scriptsFolder}`, {
|
|
120006
120313
|
toolName: "write",
|
|
@@ -120043,7 +120350,7 @@ class FilesystemTools {
|
|
|
120043
120350
|
retryable: false
|
|
120044
120351
|
});
|
|
120045
120352
|
}
|
|
120046
|
-
const dir =
|
|
120353
|
+
const dir = dirname6(validated.resolved);
|
|
120047
120354
|
await mkdir5(dir, { recursive: true });
|
|
120048
120355
|
const runtime = getRuntime();
|
|
120049
120356
|
await runtime.write(validated.resolved, content);
|
|
@@ -120251,7 +120558,7 @@ class FilesystemTools {
|
|
|
120251
120558
|
if (file.includes(".Trash") || file.includes(".Spotlight-V100") || file.includes(".fseventsd")) {
|
|
120252
120559
|
continue;
|
|
120253
120560
|
}
|
|
120254
|
-
const filePath =
|
|
120561
|
+
const filePath = join13(validated.resolved, file);
|
|
120255
120562
|
try {
|
|
120256
120563
|
const content = await runtime.file(filePath).text();
|
|
120257
120564
|
const lines = content.split(`
|
|
@@ -121094,8 +121401,8 @@ function isPrivateIPv42(octets) {
|
|
|
121094
121401
|
// ../core/src/tools/feedback.ts
|
|
121095
121402
|
init_src2();
|
|
121096
121403
|
await init_config();
|
|
121097
|
-
import { join as
|
|
121098
|
-
import { existsSync as
|
|
121404
|
+
import { join as join14 } from "path";
|
|
121405
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
121099
121406
|
function normalizeTags(value) {
|
|
121100
121407
|
if (Array.isArray(value)) {
|
|
121101
121408
|
const tags = value.map((t) => String(t).trim()).filter(Boolean);
|
|
@@ -121109,16 +121416,16 @@ function normalizeTags(value) {
|
|
|
121109
121416
|
}
|
|
121110
121417
|
function resolveFeedbackDir(cwd) {
|
|
121111
121418
|
const baseCwd = cwd && cwd.trim().length > 0 ? cwd : process.cwd();
|
|
121112
|
-
const projectConfigDir =
|
|
121113
|
-
if (
|
|
121114
|
-
return
|
|
121419
|
+
const projectConfigDir = join14(baseCwd, ".assistants");
|
|
121420
|
+
if (existsSync11(projectConfigDir)) {
|
|
121421
|
+
return join14(projectConfigDir, "feedback");
|
|
121115
121422
|
}
|
|
121116
|
-
return
|
|
121423
|
+
return join14(getConfigDir(), "feedback");
|
|
121117
121424
|
}
|
|
121118
121425
|
function saveFeedbackEntry(entry, cwd) {
|
|
121119
121426
|
const feedbackDir = resolveFeedbackDir(cwd);
|
|
121120
|
-
|
|
121121
|
-
const path =
|
|
121427
|
+
mkdirSync7(feedbackDir, { recursive: true });
|
|
121428
|
+
const path = join14(feedbackDir, `${entry.id}.json`);
|
|
121122
121429
|
writeFileSync6(path, JSON.stringify(entry, null, 2));
|
|
121123
121430
|
return { path };
|
|
121124
121431
|
}
|
|
@@ -121218,15 +121525,15 @@ init_src2();
|
|
|
121218
121525
|
|
|
121219
121526
|
// ../core/src/scheduler/store.ts
|
|
121220
121527
|
await init_config();
|
|
121221
|
-
import { join as
|
|
121222
|
-
import { mkdir as mkdir6, readdir as readdir2, readFile as
|
|
121528
|
+
import { join as join15 } from "path";
|
|
121529
|
+
import { mkdir as mkdir6, readdir as readdir2, readFile as readFile5, unlink as unlink3, writeFile as writeFile3, open as open2 } from "fs/promises";
|
|
121223
121530
|
var DEFAULT_LOCK_TTL_MS = 10 * 60 * 1000;
|
|
121224
121531
|
var SAFE_ID_PATTERN4 = /^[a-zA-Z0-9_-]+$/;
|
|
121225
121532
|
function schedulesDir(cwd) {
|
|
121226
|
-
return
|
|
121533
|
+
return join15(getProjectConfigDir(cwd), "schedules");
|
|
121227
121534
|
}
|
|
121228
121535
|
function locksDir(cwd) {
|
|
121229
|
-
return
|
|
121536
|
+
return join15(schedulesDir(cwd), "locks");
|
|
121230
121537
|
}
|
|
121231
121538
|
function isSafeId3(id) {
|
|
121232
121539
|
return SAFE_ID_PATTERN4.test(id);
|
|
@@ -121234,10 +121541,10 @@ function isSafeId3(id) {
|
|
|
121234
121541
|
function schedulePath(cwd, id) {
|
|
121235
121542
|
if (!isSafeId3(id))
|
|
121236
121543
|
return null;
|
|
121237
|
-
return
|
|
121544
|
+
return join15(schedulesDir(cwd), `${id}.json`);
|
|
121238
121545
|
}
|
|
121239
121546
|
function lockPath(cwd, id) {
|
|
121240
|
-
return
|
|
121547
|
+
return join15(locksDir(cwd), `${id}.lock.json`);
|
|
121241
121548
|
}
|
|
121242
121549
|
async function ensureDirs(cwd) {
|
|
121243
121550
|
await mkdir6(schedulesDir(cwd), { recursive: true });
|
|
@@ -121252,7 +121559,7 @@ async function listSchedules(cwd, options) {
|
|
|
121252
121559
|
if (!file.endsWith(".json"))
|
|
121253
121560
|
continue;
|
|
121254
121561
|
try {
|
|
121255
|
-
const raw = await
|
|
121562
|
+
const raw = await readFile5(join15(dir, file), "utf-8");
|
|
121256
121563
|
const parsed = JSON.parse(raw);
|
|
121257
121564
|
if (parsed?.id)
|
|
121258
121565
|
schedules.push(parsed);
|
|
@@ -121279,7 +121586,7 @@ async function getSchedule(cwd, id) {
|
|
|
121279
121586
|
const path = schedulePath(cwd, id);
|
|
121280
121587
|
if (!path)
|
|
121281
121588
|
return null;
|
|
121282
|
-
const raw = await
|
|
121589
|
+
const raw = await readFile5(path, "utf-8");
|
|
121283
121590
|
return JSON.parse(raw);
|
|
121284
121591
|
} catch {
|
|
121285
121592
|
return null;
|
|
@@ -121360,7 +121667,7 @@ async function updateSchedule(cwd, id, updater) {
|
|
|
121360
121667
|
const path = schedulePath(cwd, id);
|
|
121361
121668
|
if (!path)
|
|
121362
121669
|
return null;
|
|
121363
|
-
const raw = await
|
|
121670
|
+
const raw = await readFile5(path, "utf-8");
|
|
121364
121671
|
const schedule = JSON.parse(raw);
|
|
121365
121672
|
const updated = updater(schedule);
|
|
121366
121673
|
await saveSchedule(cwd, updated);
|
|
@@ -121382,7 +121689,7 @@ async function acquireScheduleLock(cwd, id, ownerId, ttlMs = DEFAULT_LOCK_TTL_MS
|
|
|
121382
121689
|
return true;
|
|
121383
121690
|
} catch {
|
|
121384
121691
|
try {
|
|
121385
|
-
const raw = await
|
|
121692
|
+
const raw = await readFile5(path, "utf-8");
|
|
121386
121693
|
const lock = JSON.parse(raw);
|
|
121387
121694
|
const updatedAt = lock?.updatedAt || lock?.createdAt || 0;
|
|
121388
121695
|
const ttl = lock?.ttlMs ?? ttlMs;
|
|
@@ -121408,7 +121715,7 @@ async function releaseScheduleLock(cwd, id, ownerId) {
|
|
|
121408
121715
|
return;
|
|
121409
121716
|
const path = lockPath(cwd, id);
|
|
121410
121717
|
try {
|
|
121411
|
-
const raw = await
|
|
121718
|
+
const raw = await readFile5(path, "utf-8");
|
|
121412
121719
|
const lock = JSON.parse(raw);
|
|
121413
121720
|
if (lock?.ownerId === ownerId) {
|
|
121414
121721
|
await unlink3(path);
|
|
@@ -121420,7 +121727,7 @@ async function refreshScheduleLock(cwd, id, ownerId) {
|
|
|
121420
121727
|
return;
|
|
121421
121728
|
const path = lockPath(cwd, id);
|
|
121422
121729
|
try {
|
|
121423
|
-
const raw = await
|
|
121730
|
+
const raw = await readFile5(path, "utf-8");
|
|
121424
121731
|
const lock = JSON.parse(raw);
|
|
121425
121732
|
if (lock?.ownerId === ownerId) {
|
|
121426
121733
|
const updated = { ...lock, updatedAt: Date.now() };
|
|
@@ -121433,7 +121740,7 @@ async function readSchedule(cwd, id) {
|
|
|
121433
121740
|
const path = schedulePath(cwd, id);
|
|
121434
121741
|
if (!path)
|
|
121435
121742
|
return null;
|
|
121436
|
-
const raw = await
|
|
121743
|
+
const raw = await readFile5(path, "utf-8");
|
|
121437
121744
|
const schedule = JSON.parse(raw);
|
|
121438
121745
|
if (!schedule?.id)
|
|
121439
121746
|
return null;
|
|
@@ -121772,9 +122079,9 @@ class SchedulerTool {
|
|
|
121772
122079
|
// ../core/src/tools/image.ts
|
|
121773
122080
|
init_src2();
|
|
121774
122081
|
await init_runtime();
|
|
121775
|
-
import { existsSync as
|
|
122082
|
+
import { existsSync as existsSync12, writeFileSync as writeFileSync7, unlinkSync as unlinkSync2 } from "fs";
|
|
121776
122083
|
import { tmpdir } from "os";
|
|
121777
|
-
import { join as
|
|
122084
|
+
import { join as join16 } from "path";
|
|
121778
122085
|
import { homedir as homedir8 } from "os";
|
|
121779
122086
|
var FETCH_TIMEOUT_MS = 30000;
|
|
121780
122087
|
var MAX_IMAGE_SIZE_BYTES = 10 * 1024 * 1024;
|
|
@@ -121793,7 +122100,7 @@ async function getViuPath() {
|
|
|
121793
122100
|
const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir8();
|
|
121794
122101
|
const locations = [
|
|
121795
122102
|
"viu",
|
|
121796
|
-
|
|
122103
|
+
join16(homeDir, ".cargo", "bin", "viu"),
|
|
121797
122104
|
"/usr/local/bin/viu",
|
|
121798
122105
|
"/opt/homebrew/bin/viu"
|
|
121799
122106
|
];
|
|
@@ -121898,7 +122205,7 @@ class ImageDisplayTool {
|
|
|
121898
122205
|
offset += chunk.length;
|
|
121899
122206
|
}
|
|
121900
122207
|
const ext = contentType.split("/")[1]?.split(";")[0] || "png";
|
|
121901
|
-
tempFile =
|
|
122208
|
+
tempFile = join16(tmpdir(), `assistants-image-${generateId()}.${ext}`);
|
|
121902
122209
|
writeFileSync7(tempFile, buffer);
|
|
121903
122210
|
localPath = tempFile;
|
|
121904
122211
|
} catch (error) {
|
|
@@ -121908,7 +122215,7 @@ class ImageDisplayTool {
|
|
|
121908
122215
|
return `Error: Failed to fetch image: ${error instanceof Error ? error.message : String(error)}`;
|
|
121909
122216
|
}
|
|
121910
122217
|
}
|
|
121911
|
-
if (!
|
|
122218
|
+
if (!existsSync12(localPath)) {
|
|
121912
122219
|
return `Error: Image file not found: ${localPath}`;
|
|
121913
122220
|
}
|
|
121914
122221
|
try {
|
|
@@ -121936,7 +122243,7 @@ class ImageDisplayTool {
|
|
|
121936
122243
|
} catch (error) {
|
|
121937
122244
|
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
121938
122245
|
} finally {
|
|
121939
|
-
if (tempFile &&
|
|
122246
|
+
if (tempFile && existsSync12(tempFile)) {
|
|
121940
122247
|
try {
|
|
121941
122248
|
unlinkSync2(tempFile);
|
|
121942
122249
|
} catch {}
|
|
@@ -121956,7 +122263,7 @@ init_errors();
|
|
|
121956
122263
|
|
|
121957
122264
|
// ../core/src/skills/create.ts
|
|
121958
122265
|
await init_config();
|
|
121959
|
-
import { join as
|
|
122266
|
+
import { join as join17, dirname as dirname7 } from "path";
|
|
121960
122267
|
import { mkdir as mkdir7, stat, writeFile as writeFile4, rm } from "fs/promises";
|
|
121961
122268
|
function slugify(input) {
|
|
121962
122269
|
return input.trim().toLowerCase().replace(/[^a-z0-9\s_-]/g, "").replace(/[\s_]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -122013,9 +122320,9 @@ function buildDefaultContent() {
|
|
|
122013
122320
|
}
|
|
122014
122321
|
function resolveSkillRoot(scope, cwd) {
|
|
122015
122322
|
if (scope === "global") {
|
|
122016
|
-
return
|
|
122323
|
+
return join17(getConfigDir(), "shared", "skills");
|
|
122017
122324
|
}
|
|
122018
|
-
return
|
|
122325
|
+
return join17(cwd, ".assistants", "skills");
|
|
122019
122326
|
}
|
|
122020
122327
|
async function pathExists(path) {
|
|
122021
122328
|
try {
|
|
@@ -122029,8 +122336,8 @@ async function createSkill(options) {
|
|
|
122029
122336
|
const scope = options.scope ?? "project";
|
|
122030
122337
|
const { skillName, dirName } = normalizeName2(options.name);
|
|
122031
122338
|
const root = resolveSkillRoot(scope, options.cwd);
|
|
122032
|
-
const directory =
|
|
122033
|
-
const filePath =
|
|
122339
|
+
const directory = join17(root, dirName);
|
|
122340
|
+
const filePath = join17(directory, "SKILL.md");
|
|
122034
122341
|
if (!options.overwrite && await pathExists(filePath)) {
|
|
122035
122342
|
throw new Error(`Skill already exists at ${filePath}`);
|
|
122036
122343
|
}
|
|
@@ -122053,7 +122360,7 @@ ${content}
|
|
|
122053
122360
|
// ../core/src/skills/executor.ts
|
|
122054
122361
|
init_src2();
|
|
122055
122362
|
await init_runtime();
|
|
122056
|
-
import { dirname as
|
|
122363
|
+
import { dirname as dirname8 } from "path";
|
|
122057
122364
|
|
|
122058
122365
|
class SkillExecutor {
|
|
122059
122366
|
constructor() {}
|
|
@@ -122074,7 +122381,7 @@ ARGUMENTS: ${args.join(" ")}`;
|
|
|
122074
122381
|
if (matches.length === 0) {
|
|
122075
122382
|
return content;
|
|
122076
122383
|
}
|
|
122077
|
-
const skillDir =
|
|
122384
|
+
const skillDir = dirname8(skillFilePath);
|
|
122078
122385
|
let result = content;
|
|
122079
122386
|
const runtime = getRuntime();
|
|
122080
122387
|
for (const match of matches) {
|
|
@@ -122697,9 +123004,9 @@ Respond with ALLOW or DENY on the first line, followed by a short reason.`,
|
|
|
122697
123004
|
// ../core/src/skills/loader.ts
|
|
122698
123005
|
init_src2();
|
|
122699
123006
|
var import_fast_glob = __toESM(require_out4(), 1);
|
|
122700
|
-
import { join as
|
|
123007
|
+
import { join as join18, basename as basename3, dirname as dirname9 } from "path";
|
|
122701
123008
|
import { homedir as homedir9 } from "os";
|
|
122702
|
-
import { readFile as
|
|
123009
|
+
import { readFile as readFile6, stat as stat2 } from "fs/promises";
|
|
122703
123010
|
|
|
122704
123011
|
class SkillLoader {
|
|
122705
123012
|
skills = new Map;
|
|
@@ -122707,9 +123014,9 @@ class SkillLoader {
|
|
|
122707
123014
|
const includeContent = options.includeContent ?? true;
|
|
122708
123015
|
const envHome = process.env.HOME || process.env.USERPROFILE;
|
|
122709
123016
|
const userHome = envHome && envHome.trim().length > 0 ? envHome : homedir9();
|
|
122710
|
-
const userSkillsDir =
|
|
123017
|
+
const userSkillsDir = join18(userHome, ".assistants", "shared", "skills");
|
|
122711
123018
|
await this.loadFromDirectory(userSkillsDir, { includeContent });
|
|
122712
|
-
const projectSkillsDir =
|
|
123019
|
+
const projectSkillsDir = join18(projectDir, ".assistants", "skills");
|
|
122713
123020
|
await this.loadFromDirectory(projectSkillsDir, { includeContent });
|
|
122714
123021
|
const nestedFiles = await import_fast_glob.default("**/.assistants/skills/*/SKILL.md", {
|
|
122715
123022
|
cwd: projectDir,
|
|
@@ -122717,7 +123024,7 @@ class SkillLoader {
|
|
|
122717
123024
|
ignore: ["**/node_modules/**"]
|
|
122718
123025
|
});
|
|
122719
123026
|
for (const file of nestedFiles) {
|
|
122720
|
-
await this.loadSkillFile(
|
|
123027
|
+
await this.loadSkillFile(join18(projectDir, file), { includeContent });
|
|
122721
123028
|
}
|
|
122722
123029
|
}
|
|
122723
123030
|
async loadFromDirectory(dir, options = {}) {
|
|
@@ -122733,13 +123040,13 @@ class SkillLoader {
|
|
|
122733
123040
|
const filesToLoad = [];
|
|
122734
123041
|
const skillPrefixFiles = await import_fast_glob.default("skill-*/SKILL.md", { cwd: dir });
|
|
122735
123042
|
for (const file of skillPrefixFiles) {
|
|
122736
|
-
filesToLoad.push(
|
|
123043
|
+
filesToLoad.push(join18(dir, file));
|
|
122737
123044
|
}
|
|
122738
123045
|
const regularFiles = await import_fast_glob.default("*/SKILL.md", { cwd: dir });
|
|
122739
123046
|
for (const file of regularFiles) {
|
|
122740
123047
|
const dirName = file.split(/[\\/]/)[0];
|
|
122741
123048
|
if (!dirName.startsWith("skill-")) {
|
|
122742
|
-
filesToLoad.push(
|
|
123049
|
+
filesToLoad.push(join18(dir, file));
|
|
122743
123050
|
}
|
|
122744
123051
|
}
|
|
122745
123052
|
const loadTasks = [];
|
|
@@ -122751,10 +123058,10 @@ class SkillLoader {
|
|
|
122751
123058
|
}
|
|
122752
123059
|
async loadSkillFile(filePath, options = {}) {
|
|
122753
123060
|
try {
|
|
122754
|
-
const content = await
|
|
123061
|
+
const content = await readFile6(filePath, "utf-8");
|
|
122755
123062
|
const { frontmatter, content: markdownContent } = parseFrontmatter(content);
|
|
122756
123063
|
const includeContent = options.includeContent ?? true;
|
|
122757
|
-
const dirName = basename3(
|
|
123064
|
+
const dirName = basename3(dirname9(filePath));
|
|
122758
123065
|
const name = frontmatter.name || dirName;
|
|
122759
123066
|
let description = frontmatter.description || "";
|
|
122760
123067
|
if (!description && markdownContent) {
|
|
@@ -122852,8 +123159,8 @@ class SkillLoader {
|
|
|
122852
123159
|
}
|
|
122853
123160
|
// ../core/src/commands/loader.ts
|
|
122854
123161
|
await init_runtime();
|
|
122855
|
-
import { existsSync as
|
|
122856
|
-
import { join as
|
|
123162
|
+
import { existsSync as existsSync13, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
123163
|
+
import { join as join19, basename as basename4, extname as extname2 } from "path";
|
|
122857
123164
|
import { homedir as homedir10 } from "os";
|
|
122858
123165
|
|
|
122859
123166
|
class CommandLoader {
|
|
@@ -122866,17 +123173,17 @@ class CommandLoader {
|
|
|
122866
123173
|
this.commands.clear();
|
|
122867
123174
|
const envHome = process.env.HOME || process.env.USERPROFILE;
|
|
122868
123175
|
const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir10();
|
|
122869
|
-
const globalDir =
|
|
123176
|
+
const globalDir = join19(homeDir, ".assistants", "commands");
|
|
122870
123177
|
await this.loadFromDirectory(globalDir, "global");
|
|
122871
|
-
const projectDir =
|
|
123178
|
+
const projectDir = join19(this.cwd, ".assistants", "commands");
|
|
122872
123179
|
await this.loadFromDirectory(projectDir, "project");
|
|
122873
123180
|
}
|
|
122874
123181
|
async loadFromDirectory(dir, source, prefix = "") {
|
|
122875
|
-
if (!
|
|
123182
|
+
if (!existsSync13(dir))
|
|
122876
123183
|
return;
|
|
122877
|
-
const entries =
|
|
123184
|
+
const entries = readdirSync5(dir);
|
|
122878
123185
|
for (const entry of entries) {
|
|
122879
|
-
const fullPath =
|
|
123186
|
+
const fullPath = join19(dir, entry);
|
|
122880
123187
|
const stat3 = statSync2(fullPath);
|
|
122881
123188
|
if (stat3.isDirectory()) {
|
|
122882
123189
|
const newPrefix = prefix ? `${prefix}:${entry}` : entry;
|
|
@@ -123150,11 +123457,11 @@ ${truncatedStderr}`;
|
|
|
123150
123457
|
}
|
|
123151
123458
|
// ../core/src/commands/builtin.ts
|
|
123152
123459
|
await init_runtime();
|
|
123153
|
-
import { join as
|
|
123460
|
+
import { join as join26 } from "path";
|
|
123154
123461
|
import { homedir as homedir14, platform as platform2, release, arch as arch2 } from "os";
|
|
123155
|
-
init_src2();
|
|
123156
123462
|
await init_config();
|
|
123157
|
-
import { existsSync as
|
|
123463
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
123464
|
+
init_src2();
|
|
123158
123465
|
|
|
123159
123466
|
// ../core/src/scheduler/format.ts
|
|
123160
123467
|
function formatRelativeTime(timestamp, now2 = Date.now()) {
|
|
@@ -123184,11 +123491,11 @@ init_src2();
|
|
|
123184
123491
|
|
|
123185
123492
|
// ../core/src/jobs/job-store.ts
|
|
123186
123493
|
await init_config();
|
|
123187
|
-
import { join as
|
|
123188
|
-
import { mkdir as mkdir8, readdir as readdir3, readFile as
|
|
123494
|
+
import { join as join20 } from "path";
|
|
123495
|
+
import { mkdir as mkdir8, readdir as readdir3, readFile as readFile7, unlink as unlink4, writeFile as writeFile5 } from "fs/promises";
|
|
123189
123496
|
var SAFE_ID_PATTERN5 = /^[a-zA-Z0-9_-]+$/;
|
|
123190
123497
|
function jobsDir() {
|
|
123191
|
-
return
|
|
123498
|
+
return join20(getConfigDir(), "jobs");
|
|
123192
123499
|
}
|
|
123193
123500
|
function isSafeId4(id) {
|
|
123194
123501
|
return SAFE_ID_PATTERN5.test(id);
|
|
@@ -123196,7 +123503,7 @@ function isSafeId4(id) {
|
|
|
123196
123503
|
function jobPath(id) {
|
|
123197
123504
|
if (!isSafeId4(id))
|
|
123198
123505
|
return null;
|
|
123199
|
-
return
|
|
123506
|
+
return join20(jobsDir(), `${id}.json`);
|
|
123200
123507
|
}
|
|
123201
123508
|
async function ensureDir() {
|
|
123202
123509
|
await mkdir8(jobsDir(), { recursive: true });
|
|
@@ -123214,7 +123521,7 @@ async function readJob(id) {
|
|
|
123214
123521
|
const path = jobPath(id);
|
|
123215
123522
|
if (!path)
|
|
123216
123523
|
return null;
|
|
123217
|
-
const raw = await
|
|
123524
|
+
const raw = await readFile7(path, "utf-8");
|
|
123218
123525
|
const job = JSON.parse(raw);
|
|
123219
123526
|
if (!job?.id)
|
|
123220
123527
|
return null;
|
|
@@ -123243,7 +123550,7 @@ async function listJobs() {
|
|
|
123243
123550
|
if (!file.endsWith(".json"))
|
|
123244
123551
|
continue;
|
|
123245
123552
|
try {
|
|
123246
|
-
const raw = await
|
|
123553
|
+
const raw = await readFile7(join20(dir, file), "utf-8");
|
|
123247
123554
|
const job = JSON.parse(raw);
|
|
123248
123555
|
if (job?.id)
|
|
123249
123556
|
jobs.push(job);
|
|
@@ -123830,15 +124137,15 @@ var PRIORITY_ORDER = {
|
|
|
123830
124137
|
};
|
|
123831
124138
|
// ../core/src/tasks/store.ts
|
|
123832
124139
|
init_src2();
|
|
123833
|
-
import { join as
|
|
123834
|
-
import { mkdir as mkdir9, readFile as
|
|
124140
|
+
import { join as join21 } from "path";
|
|
124141
|
+
import { mkdir as mkdir9, readFile as readFile8, writeFile as writeFile6 } from "fs/promises";
|
|
123835
124142
|
var TASKS_DIR = ".assistants/tasks";
|
|
123836
124143
|
var TASKS_FILE = "tasks.json";
|
|
123837
124144
|
function tasksDir(cwd) {
|
|
123838
|
-
return
|
|
124145
|
+
return join21(cwd, TASKS_DIR);
|
|
123839
124146
|
}
|
|
123840
124147
|
function tasksPath(cwd) {
|
|
123841
|
-
return
|
|
124148
|
+
return join21(tasksDir(cwd), TASKS_FILE);
|
|
123842
124149
|
}
|
|
123843
124150
|
async function ensureTasksDir(cwd) {
|
|
123844
124151
|
await mkdir9(tasksDir(cwd), { recursive: true });
|
|
@@ -123852,7 +124159,7 @@ function defaultStoreData() {
|
|
|
123852
124159
|
}
|
|
123853
124160
|
async function loadTaskStore(cwd) {
|
|
123854
124161
|
try {
|
|
123855
|
-
const raw = await
|
|
124162
|
+
const raw = await readFile8(tasksPath(cwd), "utf-8");
|
|
123856
124163
|
const data = JSON.parse(raw);
|
|
123857
124164
|
if (!Array.isArray(data.tasks)) {
|
|
123858
124165
|
return defaultStoreData();
|
|
@@ -124139,6 +124446,7 @@ class BuiltinCommands {
|
|
|
124139
124446
|
loader.register(this.clearCommand());
|
|
124140
124447
|
loader.register(this.newCommand());
|
|
124141
124448
|
loader.register(this.sessionCommand());
|
|
124449
|
+
loader.register(this.resumeCommand());
|
|
124142
124450
|
loader.register(this.statusCommand());
|
|
124143
124451
|
loader.register(this.tokensCommand());
|
|
124144
124452
|
loader.register(this.contextCommand());
|
|
@@ -124166,6 +124474,7 @@ class BuiltinCommands {
|
|
|
124166
124474
|
loader.register(this.hooksCommand());
|
|
124167
124475
|
loader.register(this.feedbackCommand());
|
|
124168
124476
|
loader.register(this.schedulesCommand());
|
|
124477
|
+
loader.register(this.heartbeatCommand());
|
|
124169
124478
|
loader.register(this.connectorsCommand());
|
|
124170
124479
|
loader.register(this.securityLogCommand());
|
|
124171
124480
|
loader.register(this.guardrailsCommand());
|
|
@@ -124174,6 +124483,7 @@ class BuiltinCommands {
|
|
|
124174
124483
|
loader.register(this.secretsCommand());
|
|
124175
124484
|
loader.register(this.jobsCommand());
|
|
124176
124485
|
loader.register(this.messagesCommand());
|
|
124486
|
+
loader.register(this.webhooksCommand());
|
|
124177
124487
|
loader.register(this.tasksCommand());
|
|
124178
124488
|
loader.register(this.exitCommand());
|
|
124179
124489
|
}
|
|
@@ -124908,6 +125218,10 @@ Usage: /identity create --template <name>
|
|
|
124908
125218
|
context.emit("done");
|
|
124909
125219
|
return { handled: true };
|
|
124910
125220
|
}
|
|
125221
|
+
if (action === "edit") {
|
|
125222
|
+
context.emit("done");
|
|
125223
|
+
return { handled: true, showPanel: "identity", panelInitialValue: `edit:${match.id}` };
|
|
125224
|
+
}
|
|
124911
125225
|
context.emit("text", `
|
|
124912
125226
|
## Identity Details
|
|
124913
125227
|
|
|
@@ -124987,6 +125301,8 @@ To update fields, use the web UI or edit the identity file directly.
|
|
|
124987
125301
|
context.emit("text", `/identity switch <name|id> Switch to identity
|
|
124988
125302
|
`);
|
|
124989
125303
|
context.emit("text", `/identity show <name|id> Show identity details
|
|
125304
|
+
`);
|
|
125305
|
+
context.emit("text", `/identity edit <name|id> Edit identity in panel
|
|
124990
125306
|
`);
|
|
124991
125307
|
context.emit("text", `/identity set-default <name|id> Set as default
|
|
124992
125308
|
`);
|
|
@@ -126978,6 +127294,197 @@ To enable:
|
|
|
126978
127294
|
context.emit("text", `Unknown messages command: ${subcommand}
|
|
126979
127295
|
`);
|
|
126980
127296
|
context.emit("text", `Use /messages help for available commands.
|
|
127297
|
+
`);
|
|
127298
|
+
context.emit("done");
|
|
127299
|
+
return { handled: true };
|
|
127300
|
+
}
|
|
127301
|
+
};
|
|
127302
|
+
}
|
|
127303
|
+
webhooksCommand() {
|
|
127304
|
+
return {
|
|
127305
|
+
name: "webhooks",
|
|
127306
|
+
description: "Manage webhooks for receiving push events from external sources",
|
|
127307
|
+
builtin: true,
|
|
127308
|
+
selfHandled: true,
|
|
127309
|
+
content: "",
|
|
127310
|
+
handler: async (args, context) => {
|
|
127311
|
+
const trimmed = args.trim();
|
|
127312
|
+
const [subcommand, ...rest] = trimmed.split(/\s+/);
|
|
127313
|
+
const subArgs = rest.join(" ");
|
|
127314
|
+
if (!subcommand || subcommand === "ui") {
|
|
127315
|
+
context.emit("done");
|
|
127316
|
+
return { handled: true, showPanel: "webhooks" };
|
|
127317
|
+
}
|
|
127318
|
+
const manager = context.getWebhooksManager?.();
|
|
127319
|
+
if (!manager) {
|
|
127320
|
+
context.emit("text", `Webhooks are not enabled. Set webhooks.enabled: true in config.
|
|
127321
|
+
`);
|
|
127322
|
+
context.emit("done");
|
|
127323
|
+
return { handled: true };
|
|
127324
|
+
}
|
|
127325
|
+
if (subcommand === "list") {
|
|
127326
|
+
try {
|
|
127327
|
+
const webhooks = await manager.list();
|
|
127328
|
+
if (webhooks.length === 0) {
|
|
127329
|
+
context.emit("text", `No webhooks registered. Use /webhooks create <name> <source> to create one.
|
|
127330
|
+
`);
|
|
127331
|
+
} else {
|
|
127332
|
+
context.emit("text", `Webhooks (${webhooks.length}):
|
|
127333
|
+
|
|
127334
|
+
`);
|
|
127335
|
+
for (const wh of webhooks) {
|
|
127336
|
+
const statusIcon = wh.status === "active" ? "\u25CF" : wh.status === "paused" ? "\u25D0" : "\u2717";
|
|
127337
|
+
const lastDelivery = wh.lastDeliveryAt ? new Date(wh.lastDeliveryAt).toLocaleDateString() : "never";
|
|
127338
|
+
context.emit("text", ` ${statusIcon} ${wh.name} (${wh.id})
|
|
127339
|
+
`);
|
|
127340
|
+
context.emit("text", ` Source: ${wh.source} | Events: ${wh.deliveryCount} | Last: ${lastDelivery}
|
|
127341
|
+
`);
|
|
127342
|
+
}
|
|
127343
|
+
}
|
|
127344
|
+
} catch (error) {
|
|
127345
|
+
context.emit("text", `Error: ${error instanceof Error ? error.message : String(error)}
|
|
127346
|
+
`);
|
|
127347
|
+
}
|
|
127348
|
+
context.emit("done");
|
|
127349
|
+
return { handled: true };
|
|
127350
|
+
}
|
|
127351
|
+
if (subcommand === "create") {
|
|
127352
|
+
const parts = subArgs.split(/\s+/);
|
|
127353
|
+
const name = parts[0];
|
|
127354
|
+
const source = parts[1] || "custom";
|
|
127355
|
+
if (!name) {
|
|
127356
|
+
context.emit("text", `Usage: /webhooks create <name> [source]
|
|
127357
|
+
`);
|
|
127358
|
+
context.emit("text", `Example: /webhooks create gmail-hook gmail
|
|
127359
|
+
`);
|
|
127360
|
+
context.emit("done");
|
|
127361
|
+
return { handled: true };
|
|
127362
|
+
}
|
|
127363
|
+
try {
|
|
127364
|
+
const result = await manager.create({ name, source });
|
|
127365
|
+
if (result.success) {
|
|
127366
|
+
context.emit("text", `Webhook created!
|
|
127367
|
+
|
|
127368
|
+
`);
|
|
127369
|
+
context.emit("text", ` ID: ${result.webhookId}
|
|
127370
|
+
`);
|
|
127371
|
+
context.emit("text", ` URL: ${result.url}
|
|
127372
|
+
`);
|
|
127373
|
+
context.emit("text", ` Secret: ${result.secret}
|
|
127374
|
+
`);
|
|
127375
|
+
context.emit("text", `
|
|
127376
|
+
Configure the external source with the URL and secret above.
|
|
127377
|
+
`);
|
|
127378
|
+
} else {
|
|
127379
|
+
context.emit("text", `Error: ${result.message}
|
|
127380
|
+
`);
|
|
127381
|
+
}
|
|
127382
|
+
} catch (error) {
|
|
127383
|
+
context.emit("text", `Error: ${error instanceof Error ? error.message : String(error)}
|
|
127384
|
+
`);
|
|
127385
|
+
}
|
|
127386
|
+
context.emit("done");
|
|
127387
|
+
return { handled: true };
|
|
127388
|
+
}
|
|
127389
|
+
if (subcommand === "delete") {
|
|
127390
|
+
const id = subArgs.trim();
|
|
127391
|
+
if (!id) {
|
|
127392
|
+
context.emit("text", `Usage: /webhooks delete <webhook-id>
|
|
127393
|
+
`);
|
|
127394
|
+
context.emit("done");
|
|
127395
|
+
return { handled: true };
|
|
127396
|
+
}
|
|
127397
|
+
try {
|
|
127398
|
+
const result = await manager.delete(id);
|
|
127399
|
+
context.emit("text", `${result.message}
|
|
127400
|
+
`);
|
|
127401
|
+
} catch (error) {
|
|
127402
|
+
context.emit("text", `Error: ${error instanceof Error ? error.message : String(error)}
|
|
127403
|
+
`);
|
|
127404
|
+
}
|
|
127405
|
+
context.emit("done");
|
|
127406
|
+
return { handled: true };
|
|
127407
|
+
}
|
|
127408
|
+
if (subcommand === "events") {
|
|
127409
|
+
const webhookId = subArgs.trim();
|
|
127410
|
+
if (!webhookId) {
|
|
127411
|
+
context.emit("text", `Usage: /webhooks events <webhook-id>
|
|
127412
|
+
`);
|
|
127413
|
+
context.emit("done");
|
|
127414
|
+
return { handled: true };
|
|
127415
|
+
}
|
|
127416
|
+
try {
|
|
127417
|
+
const events = await manager.listEvents(webhookId, { limit: 20 });
|
|
127418
|
+
if (events.length === 0) {
|
|
127419
|
+
context.emit("text", `No events received for this webhook.
|
|
127420
|
+
`);
|
|
127421
|
+
} else {
|
|
127422
|
+
context.emit("text", `Recent events (${events.length}):
|
|
127423
|
+
|
|
127424
|
+
`);
|
|
127425
|
+
for (const evt of events) {
|
|
127426
|
+
const statusIcon = evt.status === "pending" ? "\u23F3" : evt.status === "injected" ? "\uD83D\uDCE8" : "\u2713";
|
|
127427
|
+
context.emit("text", ` ${statusIcon} ${evt.eventType} (${evt.id})
|
|
127428
|
+
`);
|
|
127429
|
+
context.emit("text", ` ${new Date(evt.timestamp).toLocaleString()} | ${evt.preview}
|
|
127430
|
+
`);
|
|
127431
|
+
}
|
|
127432
|
+
}
|
|
127433
|
+
} catch (error) {
|
|
127434
|
+
context.emit("text", `Error: ${error instanceof Error ? error.message : String(error)}
|
|
127435
|
+
`);
|
|
127436
|
+
}
|
|
127437
|
+
context.emit("done");
|
|
127438
|
+
return { handled: true };
|
|
127439
|
+
}
|
|
127440
|
+
if (subcommand === "test") {
|
|
127441
|
+
const id = subArgs.trim();
|
|
127442
|
+
if (!id) {
|
|
127443
|
+
context.emit("text", `Usage: /webhooks test <webhook-id>
|
|
127444
|
+
`);
|
|
127445
|
+
context.emit("done");
|
|
127446
|
+
return { handled: true };
|
|
127447
|
+
}
|
|
127448
|
+
try {
|
|
127449
|
+
const result = await manager.sendTestEvent(id);
|
|
127450
|
+
if (result.success) {
|
|
127451
|
+
context.emit("text", `Test event sent! Event ID: ${result.eventId}
|
|
127452
|
+
`);
|
|
127453
|
+
} else {
|
|
127454
|
+
context.emit("text", `Error: ${result.message}
|
|
127455
|
+
`);
|
|
127456
|
+
}
|
|
127457
|
+
} catch (error) {
|
|
127458
|
+
context.emit("text", `Error: ${error instanceof Error ? error.message : String(error)}
|
|
127459
|
+
`);
|
|
127460
|
+
}
|
|
127461
|
+
context.emit("done");
|
|
127462
|
+
return { handled: true };
|
|
127463
|
+
}
|
|
127464
|
+
if (subcommand === "help") {
|
|
127465
|
+
context.emit("text", `Webhook Commands:
|
|
127466
|
+
|
|
127467
|
+
`);
|
|
127468
|
+
context.emit("text", `/webhooks Open webhooks panel
|
|
127469
|
+
`);
|
|
127470
|
+
context.emit("text", `/webhooks list List all webhooks
|
|
127471
|
+
`);
|
|
127472
|
+
context.emit("text", `/webhooks create <name> <source> Create a webhook
|
|
127473
|
+
`);
|
|
127474
|
+
context.emit("text", `/webhooks delete <id> Delete a webhook
|
|
127475
|
+
`);
|
|
127476
|
+
context.emit("text", `/webhooks events <id> List events for a webhook
|
|
127477
|
+
`);
|
|
127478
|
+
context.emit("text", `/webhooks test <id> Send a test event
|
|
127479
|
+
`);
|
|
127480
|
+
context.emit("text", `/webhooks help Show this help
|
|
127481
|
+
`);
|
|
127482
|
+
context.emit("done");
|
|
127483
|
+
return { handled: true };
|
|
127484
|
+
}
|
|
127485
|
+
context.emit("text", `Unknown command: ${subcommand}
|
|
127486
|
+
`);
|
|
127487
|
+
context.emit("text", `Use /webhooks help for available commands.
|
|
126981
127488
|
`);
|
|
126982
127489
|
context.emit("done");
|
|
126983
127490
|
return { handled: true };
|
|
@@ -127576,6 +128083,91 @@ Usage: /session assign <agent-name>
|
|
|
127576
128083
|
}
|
|
127577
128084
|
};
|
|
127578
128085
|
}
|
|
128086
|
+
resumeCommand() {
|
|
128087
|
+
return {
|
|
128088
|
+
name: "resume",
|
|
128089
|
+
description: "Resume saved sessions from disk",
|
|
128090
|
+
builtin: true,
|
|
128091
|
+
selfHandled: true,
|
|
128092
|
+
content: "",
|
|
128093
|
+
handler: async (args, context) => {
|
|
128094
|
+
const trimmed = args.trim().toLowerCase();
|
|
128095
|
+
const showAll = trimmed.includes("--all");
|
|
128096
|
+
const cleanedArgs = trimmed.replace("--all", "").trim();
|
|
128097
|
+
if (!cleanedArgs || cleanedArgs === "ui") {
|
|
128098
|
+
context.emit("done");
|
|
128099
|
+
return {
|
|
128100
|
+
handled: true,
|
|
128101
|
+
showPanel: "resume",
|
|
128102
|
+
panelInitialValue: showAll ? "all" : "cwd"
|
|
128103
|
+
};
|
|
128104
|
+
}
|
|
128105
|
+
if (cleanedArgs === "list" || cleanedArgs === "--list") {
|
|
128106
|
+
const allSessions = SessionStorage.listAllSessions();
|
|
128107
|
+
const normalizeCwd = (value) => value.replace(/\/+$/, "");
|
|
128108
|
+
const targetCwd = normalizeCwd(context.cwd);
|
|
128109
|
+
const sessions = showAll ? allSessions : allSessions.filter((session) => normalizeCwd(session.cwd) === targetCwd);
|
|
128110
|
+
if (sessions.length === 0) {
|
|
128111
|
+
context.emit("text", showAll ? `No saved sessions found.
|
|
128112
|
+
` : `No saved sessions found for this directory.
|
|
128113
|
+
`);
|
|
128114
|
+
context.emit("done");
|
|
128115
|
+
return { handled: true };
|
|
128116
|
+
}
|
|
128117
|
+
const assistantManager = context.getAssistantManager?.();
|
|
128118
|
+
const assistantNames = assistantManager ? new Map(assistantManager.listAssistants().map((a) => [a.id, a.name])) : null;
|
|
128119
|
+
const truncate = (value, maxLen) => value.length > maxLen ? `${value.slice(0, maxLen - 3)}...` : value;
|
|
128120
|
+
const escapeCell = (value) => value.replace(/\|/g, "\\|").replace(/\s+/g, " ").trim();
|
|
128121
|
+
let output = `
|
|
128122
|
+
`;
|
|
128123
|
+
if (showAll) {
|
|
128124
|
+
output += `| ID | Assistant | Updated | Messages | CWD |
|
|
128125
|
+
`;
|
|
128126
|
+
output += `|----|-----------|---------|----------|-----|
|
|
128127
|
+
`;
|
|
128128
|
+
} else {
|
|
128129
|
+
output += `| ID | Updated | Messages | CWD |
|
|
128130
|
+
`;
|
|
128131
|
+
output += `|----|---------|----------|-----|
|
|
128132
|
+
`;
|
|
128133
|
+
}
|
|
128134
|
+
for (const session of sessions) {
|
|
128135
|
+
const updated = formatRelativeTime(new Date(session.updatedAt).getTime());
|
|
128136
|
+
const messageCount = session.messageCount ?? 0;
|
|
128137
|
+
const cwd = escapeCell(truncate(singleLine2(session.cwd || ""), 48));
|
|
128138
|
+
const id = escapeCell(session.id.slice(0, 8));
|
|
128139
|
+
if (showAll) {
|
|
128140
|
+
const assistantLabel = session.assistantId ? assistantNames?.get(session.assistantId) || session.assistantId : "default";
|
|
128141
|
+
output += `| ${id} | ${escapeCell(truncate(assistantLabel, 16))} | ${updated} | ${messageCount} | ${cwd} |
|
|
128142
|
+
`;
|
|
128143
|
+
} else {
|
|
128144
|
+
output += `| ${id} | ${updated} | ${messageCount} | ${cwd} |
|
|
128145
|
+
`;
|
|
128146
|
+
}
|
|
128147
|
+
}
|
|
128148
|
+
context.emit("text", output);
|
|
128149
|
+
context.emit("done");
|
|
128150
|
+
return { handled: true };
|
|
128151
|
+
}
|
|
128152
|
+
context.emit("text", `
|
|
128153
|
+
**Resume** - Load saved sessions from disk
|
|
128154
|
+
|
|
128155
|
+
`);
|
|
128156
|
+
context.emit("text", `Usage:
|
|
128157
|
+
`);
|
|
128158
|
+
context.emit("text", ` /resume Open interactive panel (current folder)
|
|
128159
|
+
`);
|
|
128160
|
+
context.emit("text", ` /resume --all Open interactive panel (all sessions)
|
|
128161
|
+
`);
|
|
128162
|
+
context.emit("text", ` /resume list Show text table (current folder)
|
|
128163
|
+
`);
|
|
128164
|
+
context.emit("text", ` /resume list --all Show text table (all sessions)
|
|
128165
|
+
`);
|
|
128166
|
+
context.emit("done");
|
|
128167
|
+
return { handled: true };
|
|
128168
|
+
}
|
|
128169
|
+
};
|
|
128170
|
+
}
|
|
127579
128171
|
tokensCommand() {
|
|
127580
128172
|
return {
|
|
127581
128173
|
name: "tokens",
|
|
@@ -128869,9 +129461,9 @@ Format the summary as a brief bullet-point list. This summary will replace the c
|
|
|
128869
129461
|
}
|
|
128870
129462
|
if (action === "show" || action === "paths") {
|
|
128871
129463
|
const configPaths = [
|
|
128872
|
-
|
|
128873
|
-
|
|
128874
|
-
|
|
129464
|
+
join26(context.cwd, ".assistants", "config.json"),
|
|
129465
|
+
join26(context.cwd, ".assistants", "config.local.json"),
|
|
129466
|
+
join26(getConfigDir(), "config.json")
|
|
128875
129467
|
];
|
|
128876
129468
|
let message = `
|
|
128877
129469
|
**Configuration**
|
|
@@ -128880,7 +129472,7 @@ Format the summary as a brief bullet-point list. This summary will replace the c
|
|
|
128880
129472
|
message += `**Config File Locations:**
|
|
128881
129473
|
`;
|
|
128882
129474
|
for (const path of configPaths) {
|
|
128883
|
-
const exists =
|
|
129475
|
+
const exists = existsSync18(path);
|
|
128884
129476
|
message += ` ${exists ? "\u2713" : "\u25CB"} ${path}
|
|
128885
129477
|
`;
|
|
128886
129478
|
}
|
|
@@ -128889,9 +129481,9 @@ Format the summary as a brief bullet-point list. This summary will replace the c
|
|
|
128889
129481
|
message += `
|
|
128890
129482
|
**Commands Directories:**
|
|
128891
129483
|
`;
|
|
128892
|
-
message += ` - Project: ${
|
|
129484
|
+
message += ` - Project: ${join26(context.cwd, ".assistants", "commands")}
|
|
128893
129485
|
`;
|
|
128894
|
-
message += ` - Global: ${
|
|
129486
|
+
message += ` - Global: ${join26(homeDir, ".assistants", "commands")}
|
|
128895
129487
|
`;
|
|
128896
129488
|
context.emit("text", message);
|
|
128897
129489
|
context.emit("done");
|
|
@@ -129724,8 +130316,8 @@ ${error instanceof Error ? error.message : String(error)}
|
|
|
129724
130316
|
selfHandled: true,
|
|
129725
130317
|
content: "",
|
|
129726
130318
|
handler: async (args, context) => {
|
|
129727
|
-
const commandsDir =
|
|
129728
|
-
|
|
130319
|
+
const commandsDir = join26(context.cwd, ".assistants", "commands");
|
|
130320
|
+
mkdirSync12(commandsDir, { recursive: true });
|
|
129729
130321
|
const exampleCommand = `---
|
|
129730
130322
|
name: reflect
|
|
129731
130323
|
description: Reflect on the conversation and suggest next steps
|
|
@@ -129740,8 +130332,8 @@ Please summarize the last interaction and suggest 2-3 next steps.
|
|
|
129740
130332
|
- Focus on clarity
|
|
129741
130333
|
- Ask a follow-up question if needed
|
|
129742
130334
|
`;
|
|
129743
|
-
const examplePath =
|
|
129744
|
-
if (!
|
|
130335
|
+
const examplePath = join26(commandsDir, "reflect.md");
|
|
130336
|
+
if (!existsSync18(examplePath)) {
|
|
129745
130337
|
writeFileSync12(examplePath, exampleCommand);
|
|
129746
130338
|
}
|
|
129747
130339
|
let message = `
|
|
@@ -130412,7 +131004,7 @@ Memory Statistics
|
|
|
130412
131004
|
return { handled: true };
|
|
130413
131005
|
}
|
|
130414
131006
|
if (action === "export") {
|
|
130415
|
-
const filePath = rest[0] ||
|
|
131007
|
+
const filePath = rest[0] || join26(getConfigDir(), "memories-export.json");
|
|
130416
131008
|
const memories = await manager.export();
|
|
130417
131009
|
try {
|
|
130418
131010
|
const content = JSON.stringify(memories, null, 2);
|
|
@@ -130609,6 +131201,136 @@ Importing ${validMemories.length} valid entries (skipping ${errors.length} inval
|
|
|
130609
131201
|
context.emit("text", ` /schedules list Show text table (this session)
|
|
130610
131202
|
`);
|
|
130611
131203
|
context.emit("text", ` /schedules list --all Show all schedules
|
|
131204
|
+
`);
|
|
131205
|
+
context.emit("done");
|
|
131206
|
+
return { handled: true };
|
|
131207
|
+
}
|
|
131208
|
+
};
|
|
131209
|
+
}
|
|
131210
|
+
heartbeatCommand() {
|
|
131211
|
+
return {
|
|
131212
|
+
name: "heartbeat",
|
|
131213
|
+
description: "View heartbeat status and recent heartbeat runs",
|
|
131214
|
+
builtin: true,
|
|
131215
|
+
selfHandled: true,
|
|
131216
|
+
content: "",
|
|
131217
|
+
handler: async (args, context) => {
|
|
131218
|
+
const trimmed = args.trim().toLowerCase();
|
|
131219
|
+
const showAll = trimmed.includes("--all");
|
|
131220
|
+
const cleanedArgs = trimmed.replace("--all", "").trim();
|
|
131221
|
+
const heartbeatState = context.getHeartbeatState?.() ?? null;
|
|
131222
|
+
const heartbeatConfig = context.getHeartbeatConfig?.() ?? null;
|
|
131223
|
+
const historyPathTemplate = heartbeatConfig?.historyPath;
|
|
131224
|
+
if (!cleanedArgs || cleanedArgs === "ui") {
|
|
131225
|
+
context.emit("done");
|
|
131226
|
+
return { handled: true, showPanel: "heartbeat" };
|
|
131227
|
+
}
|
|
131228
|
+
if (cleanedArgs === "list" || cleanedArgs === "--list") {
|
|
131229
|
+
const canEnumerate = !historyPathTemplate || historyPathTemplate.includes("{sessionId}");
|
|
131230
|
+
const sessionIds = showAll && canEnumerate ? listHeartbeatHistorySessions() : [context.sessionId];
|
|
131231
|
+
const rows = [];
|
|
131232
|
+
for (const sessionId of sessionIds) {
|
|
131233
|
+
const historyPath = resolveHeartbeatHistoryPath(sessionId, historyPathTemplate);
|
|
131234
|
+
const runs = await readHeartbeatHistory(historyPath, { order: "desc" });
|
|
131235
|
+
for (const run of runs) {
|
|
131236
|
+
rows.push({ sessionId, run });
|
|
131237
|
+
}
|
|
131238
|
+
}
|
|
131239
|
+
if (rows.length === 0) {
|
|
131240
|
+
context.emit("text", showAll ? `No heartbeat runs found.
|
|
131241
|
+
` : `No heartbeat runs found for this session.
|
|
131242
|
+
`);
|
|
131243
|
+
context.emit("done");
|
|
131244
|
+
return { handled: true };
|
|
131245
|
+
}
|
|
131246
|
+
rows.sort((a, b) => {
|
|
131247
|
+
const aTime = new Date(a.run.timestamp).getTime();
|
|
131248
|
+
const bTime = new Date(b.run.timestamp).getTime();
|
|
131249
|
+
return bTime - aTime;
|
|
131250
|
+
});
|
|
131251
|
+
const rel = (iso) => formatRelativeTime(iso ? new Date(iso).getTime() : undefined);
|
|
131252
|
+
if (heartbeatState) {
|
|
131253
|
+
const stateLine = `State: ${heartbeatState.state} | Stale: ${heartbeatState.isStale ? "yes" : "no"} | Last Activity: ${rel(heartbeatState.lastActivity)}`;
|
|
131254
|
+
context.emit("text", `
|
|
131255
|
+
**Heartbeat Status**
|
|
131256
|
+
${stateLine}
|
|
131257
|
+
|
|
131258
|
+
`);
|
|
131259
|
+
}
|
|
131260
|
+
const escapeCell = (value) => value.replace(/\|/g, "\\|").replace(/\s+/g, " ").trim();
|
|
131261
|
+
let output = `
|
|
131262
|
+
`;
|
|
131263
|
+
if (showAll) {
|
|
131264
|
+
output += `| Session | Time | State | Last Activity | Msgs | Tools | Errors |
|
|
131265
|
+
`;
|
|
131266
|
+
output += `|--------|------|-------|---------------|------|-------|--------|
|
|
131267
|
+
`;
|
|
131268
|
+
} else {
|
|
131269
|
+
output += `| Time | State | Last Activity | Msgs | Tools | Errors |
|
|
131270
|
+
`;
|
|
131271
|
+
output += `|------|-------|---------------|------|-------|--------|
|
|
131272
|
+
`;
|
|
131273
|
+
}
|
|
131274
|
+
for (const { sessionId, run } of rows) {
|
|
131275
|
+
const time = rel(run.timestamp);
|
|
131276
|
+
const activity = rel(run.lastActivity);
|
|
131277
|
+
const stats = run.stats || { messagesProcessed: 0, toolCallsExecuted: 0, errorsEncountered: 0 };
|
|
131278
|
+
if (showAll) {
|
|
131279
|
+
output += `| ${escapeCell(sessionId.slice(0, 8))} | ${time} | ${run.state} | ${activity} | ${stats.messagesProcessed} | ${stats.toolCallsExecuted} | ${stats.errorsEncountered} |
|
|
131280
|
+
`;
|
|
131281
|
+
} else {
|
|
131282
|
+
output += `| ${time} | ${run.state} | ${activity} | ${stats.messagesProcessed} | ${stats.toolCallsExecuted} | ${stats.errorsEncountered} |
|
|
131283
|
+
`;
|
|
131284
|
+
}
|
|
131285
|
+
}
|
|
131286
|
+
context.emit("text", output);
|
|
131287
|
+
if (showAll && historyPathTemplate && !historyPathTemplate.includes("{sessionId}")) {
|
|
131288
|
+
context.emit("text", `
|
|
131289
|
+
Note: custom heartbeat historyPath does not include {sessionId}; showing current session only.
|
|
131290
|
+
`);
|
|
131291
|
+
}
|
|
131292
|
+
context.emit("done");
|
|
131293
|
+
return { handled: true };
|
|
131294
|
+
}
|
|
131295
|
+
if (cleanedArgs === "status") {
|
|
131296
|
+
if (!heartbeatState) {
|
|
131297
|
+
context.emit("text", `Heartbeat status unavailable.
|
|
131298
|
+
`);
|
|
131299
|
+
context.emit("done");
|
|
131300
|
+
return { handled: true };
|
|
131301
|
+
}
|
|
131302
|
+
const rel = (iso) => formatRelativeTime(iso ? new Date(iso).getTime() : undefined);
|
|
131303
|
+
context.emit("text", `
|
|
131304
|
+
**Heartbeat Status**
|
|
131305
|
+
`);
|
|
131306
|
+
context.emit("text", `State: ${heartbeatState.state}
|
|
131307
|
+
`);
|
|
131308
|
+
context.emit("text", `Enabled: ${heartbeatState.enabled ? "yes" : "no"}
|
|
131309
|
+
`);
|
|
131310
|
+
context.emit("text", `Stale: ${heartbeatState.isStale ? "yes" : "no"}
|
|
131311
|
+
`);
|
|
131312
|
+
context.emit("text", `Last Activity: ${rel(heartbeatState.lastActivity)}
|
|
131313
|
+
`);
|
|
131314
|
+
context.emit("text", `Uptime: ${heartbeatState.uptimeSeconds}s
|
|
131315
|
+
`);
|
|
131316
|
+
context.emit("done");
|
|
131317
|
+
return { handled: true };
|
|
131318
|
+
}
|
|
131319
|
+
context.emit("text", `
|
|
131320
|
+
**Heartbeat** - View heartbeat status and run history
|
|
131321
|
+
|
|
131322
|
+
`);
|
|
131323
|
+
context.emit("text", `Usage:
|
|
131324
|
+
`);
|
|
131325
|
+
context.emit("text", ` /heartbeat Open interactive panel
|
|
131326
|
+
`);
|
|
131327
|
+
context.emit("text", ` /heartbeat ui Open interactive panel
|
|
131328
|
+
`);
|
|
131329
|
+
context.emit("text", ` /heartbeat list Show text table (this session)
|
|
131330
|
+
`);
|
|
131331
|
+
context.emit("text", ` /heartbeat list --all Show text table for all sessions
|
|
131332
|
+
`);
|
|
131333
|
+
context.emit("text", ` /heartbeat status Show current heartbeat status
|
|
130612
131334
|
`);
|
|
130613
131335
|
context.emit("done");
|
|
130614
131336
|
return { handled: true };
|
|
@@ -131094,10 +131816,9 @@ async function createLLMClient(config) {
|
|
|
131094
131816
|
await init_config();
|
|
131095
131817
|
|
|
131096
131818
|
// ../core/src/heartbeat/manager.ts
|
|
131097
|
-
import { dirname as
|
|
131098
|
-
import { mkdirSync as
|
|
131099
|
-
import { readFile as
|
|
131100
|
-
|
|
131819
|
+
import { dirname as dirname13 } from "path";
|
|
131820
|
+
import { mkdirSync as mkdirSync13 } from "fs";
|
|
131821
|
+
import { readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
|
|
131101
131822
|
class HeartbeatManager {
|
|
131102
131823
|
config;
|
|
131103
131824
|
state = "idle";
|
|
@@ -131106,6 +131827,7 @@ class HeartbeatManager {
|
|
|
131106
131827
|
stats;
|
|
131107
131828
|
intervalId;
|
|
131108
131829
|
listeners = new Set;
|
|
131830
|
+
lastHeartbeatAt = null;
|
|
131109
131831
|
constructor(config) {
|
|
131110
131832
|
this.config = config;
|
|
131111
131833
|
this.startTime = Date.now();
|
|
@@ -131116,8 +131838,8 @@ class HeartbeatManager {
|
|
|
131116
131838
|
errorsEncountered: 0,
|
|
131117
131839
|
uptimeSeconds: 0
|
|
131118
131840
|
};
|
|
131119
|
-
const dir =
|
|
131120
|
-
|
|
131841
|
+
const dir = dirname13(config.persistPath);
|
|
131842
|
+
mkdirSync13(dir, { recursive: true });
|
|
131121
131843
|
}
|
|
131122
131844
|
start(sessionId) {
|
|
131123
131845
|
if (this.intervalId)
|
|
@@ -131159,6 +131881,10 @@ class HeartbeatManager {
|
|
|
131159
131881
|
getStartTime() {
|
|
131160
131882
|
return this.startTime;
|
|
131161
131883
|
}
|
|
131884
|
+
getNextHeartbeatAt() {
|
|
131885
|
+
const base = this.lastHeartbeatAt ?? Date.now();
|
|
131886
|
+
return base + this.config.intervalMs;
|
|
131887
|
+
}
|
|
131162
131888
|
getStats() {
|
|
131163
131889
|
return {
|
|
131164
131890
|
...this.stats,
|
|
@@ -131173,14 +131899,17 @@ class HeartbeatManager {
|
|
|
131173
131899
|
this.lastActivity = Date.now();
|
|
131174
131900
|
}
|
|
131175
131901
|
async emit(sessionId) {
|
|
131902
|
+
const now2 = Date.now();
|
|
131903
|
+
this.lastHeartbeatAt = now2;
|
|
131904
|
+
const uptimeSeconds = Math.floor((now2 - this.startTime) / 1000);
|
|
131176
131905
|
const heartbeat = {
|
|
131177
131906
|
sessionId,
|
|
131178
|
-
timestamp: new Date().toISOString(),
|
|
131907
|
+
timestamp: new Date(now2).toISOString(),
|
|
131179
131908
|
state: this.state,
|
|
131180
131909
|
lastActivity: new Date(this.lastActivity).toISOString(),
|
|
131181
131910
|
stats: {
|
|
131182
131911
|
...this.stats,
|
|
131183
|
-
uptimeSeconds
|
|
131912
|
+
uptimeSeconds
|
|
131184
131913
|
}
|
|
131185
131914
|
};
|
|
131186
131915
|
for (const listener of this.listeners) {
|
|
@@ -131191,11 +131920,14 @@ class HeartbeatManager {
|
|
|
131191
131920
|
async persist(heartbeat) {
|
|
131192
131921
|
try {
|
|
131193
131922
|
await writeFile7(this.config.persistPath, JSON.stringify(heartbeat, null, 2));
|
|
131923
|
+
if (this.config.historyPath) {
|
|
131924
|
+
await appendHeartbeatHistory(this.config.historyPath, heartbeat);
|
|
131925
|
+
}
|
|
131194
131926
|
} catch {}
|
|
131195
131927
|
}
|
|
131196
131928
|
static async checkStale(path2, thresholdMs) {
|
|
131197
131929
|
try {
|
|
131198
|
-
const content = await
|
|
131930
|
+
const content = await readFile9(path2, "utf-8");
|
|
131199
131931
|
const heartbeat = JSON.parse(content);
|
|
131200
131932
|
const age = Date.now() - new Date(heartbeat.timestamp).getTime();
|
|
131201
131933
|
return { isStale: age > thresholdMs, lastHeartbeat: heartbeat };
|
|
@@ -131205,15 +131937,15 @@ class HeartbeatManager {
|
|
|
131205
131937
|
}
|
|
131206
131938
|
}
|
|
131207
131939
|
// ../core/src/heartbeat/persistence.ts
|
|
131208
|
-
import { dirname as
|
|
131209
|
-
import { mkdirSync as
|
|
131210
|
-
import { readFile as
|
|
131940
|
+
import { dirname as dirname14 } from "path";
|
|
131941
|
+
import { mkdirSync as mkdirSync14 } from "fs";
|
|
131942
|
+
import { readFile as readFile10, writeFile as writeFile8, unlink as unlink5 } from "fs/promises";
|
|
131211
131943
|
|
|
131212
131944
|
class StatePersistence {
|
|
131213
131945
|
path;
|
|
131214
131946
|
constructor(path2) {
|
|
131215
131947
|
this.path = path2;
|
|
131216
|
-
|
|
131948
|
+
mkdirSync14(dirname14(path2), { recursive: true });
|
|
131217
131949
|
}
|
|
131218
131950
|
async save(state) {
|
|
131219
131951
|
try {
|
|
@@ -131222,7 +131954,7 @@ class StatePersistence {
|
|
|
131222
131954
|
}
|
|
131223
131955
|
async load() {
|
|
131224
131956
|
try {
|
|
131225
|
-
const content = await
|
|
131957
|
+
const content = await readFile10(this.path, "utf-8");
|
|
131226
131958
|
return JSON.parse(content);
|
|
131227
131959
|
} catch {
|
|
131228
131960
|
return null;
|
|
@@ -131354,7 +132086,7 @@ async function ensureWatchdogSchedule(cwd, sessionId, intervalMs = DEFAULT_WATCH
|
|
|
131354
132086
|
}
|
|
131355
132087
|
// ../core/src/heartbeat/install-skills.ts
|
|
131356
132088
|
await init_config();
|
|
131357
|
-
import { join as
|
|
132089
|
+
import { join as join29 } from "path";
|
|
131358
132090
|
var MAIN_LOOP_SKILL = `---
|
|
131359
132091
|
name: main-loop
|
|
131360
132092
|
description: Autonomous heartbeat \u2014 review goals, check async results, act on pending items, and schedule next wakeup.
|
|
@@ -131418,8 +132150,8 @@ You are the watchdog. Your only job is to verify the heartbeat is running and fo
|
|
|
131418
132150
|
`;
|
|
131419
132151
|
async function writeSkillIfMissing(dir, skillName, content) {
|
|
131420
132152
|
const { mkdir: mkdir10, writeFile: writeFile9, access } = await import("fs/promises");
|
|
131421
|
-
const skillDir =
|
|
131422
|
-
const skillFile =
|
|
132153
|
+
const skillDir = join29(dir, `skill-${skillName}`);
|
|
132154
|
+
const skillFile = join29(skillDir, "SKILL.md");
|
|
131423
132155
|
try {
|
|
131424
132156
|
await access(skillFile);
|
|
131425
132157
|
return false;
|
|
@@ -131429,7 +132161,7 @@ async function writeSkillIfMissing(dir, skillName, content) {
|
|
|
131429
132161
|
return true;
|
|
131430
132162
|
}
|
|
131431
132163
|
async function installHeartbeatSkills() {
|
|
131432
|
-
const sharedSkillsDir =
|
|
132164
|
+
const sharedSkillsDir = join29(getConfigDir(), "shared", "skills");
|
|
131433
132165
|
const installed = [];
|
|
131434
132166
|
const results = await Promise.all([
|
|
131435
132167
|
writeSkillIfMissing(sharedSkillsDir, "main-loop", MAIN_LOOP_SKILL),
|
|
@@ -131603,15 +132335,15 @@ class EnergyManager {
|
|
|
131603
132335
|
}
|
|
131604
132336
|
}
|
|
131605
132337
|
// ../core/src/energy/storage.ts
|
|
131606
|
-
import { dirname as
|
|
131607
|
-
import { mkdirSync as
|
|
131608
|
-
import { readFile as
|
|
132338
|
+
import { dirname as dirname15 } from "path";
|
|
132339
|
+
import { mkdirSync as mkdirSync15 } from "fs";
|
|
132340
|
+
import { readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
|
|
131609
132341
|
|
|
131610
132342
|
class EnergyStorage {
|
|
131611
132343
|
path;
|
|
131612
132344
|
constructor(path2) {
|
|
131613
132345
|
this.path = path2;
|
|
131614
|
-
|
|
132346
|
+
mkdirSync15(dirname15(path2), { recursive: true });
|
|
131615
132347
|
}
|
|
131616
132348
|
async save(state) {
|
|
131617
132349
|
try {
|
|
@@ -131620,7 +132352,7 @@ class EnergyStorage {
|
|
|
131620
132352
|
}
|
|
131621
132353
|
async load() {
|
|
131622
132354
|
try {
|
|
131623
|
-
const content = await
|
|
132355
|
+
const content = await readFile11(this.path, "utf-8");
|
|
131624
132356
|
return JSON.parse(content);
|
|
131625
132357
|
} catch {
|
|
131626
132358
|
return null;
|
|
@@ -131678,15 +132410,15 @@ function validateToolCalls(toolCalls, tools) {
|
|
|
131678
132410
|
}
|
|
131679
132411
|
|
|
131680
132412
|
// ../core/src/voice/utils.ts
|
|
131681
|
-
import { existsSync as
|
|
132413
|
+
import { existsSync as existsSync21, readFileSync as readFileSync13 } from "fs";
|
|
131682
132414
|
import { homedir as homedir17 } from "os";
|
|
131683
|
-
import { join as
|
|
132415
|
+
import { join as join30 } from "path";
|
|
131684
132416
|
import { spawnSync } from "child_process";
|
|
131685
132417
|
function loadApiKeyFromSecrets3(key) {
|
|
131686
132418
|
const envHome = process.env.HOME || process.env.USERPROFILE;
|
|
131687
132419
|
const homeDir = envHome && envHome.trim().length > 0 ? envHome : homedir17();
|
|
131688
|
-
const secretsPath =
|
|
131689
|
-
if (!
|
|
132420
|
+
const secretsPath = join30(homeDir, ".secrets");
|
|
132421
|
+
if (!existsSync21(secretsPath))
|
|
131690
132422
|
return;
|
|
131691
132423
|
try {
|
|
131692
132424
|
const content = readFileSync13(secretsPath, "utf-8");
|
|
@@ -131798,7 +132530,7 @@ class SystemSTT {
|
|
|
131798
132530
|
// ../core/src/voice/tts.ts
|
|
131799
132531
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
131800
132532
|
import { tmpdir as tmpdir2 } from "os";
|
|
131801
|
-
import { join as
|
|
132533
|
+
import { join as join31 } from "path";
|
|
131802
132534
|
import { readFileSync as readFileSync14, unlinkSync as unlinkSync4 } from "fs";
|
|
131803
132535
|
class ElevenLabsTTS {
|
|
131804
132536
|
apiKey;
|
|
@@ -131902,7 +132634,7 @@ class SystemTTS {
|
|
|
131902
132634
|
if (!say) {
|
|
131903
132635
|
throw new Error('System TTS not available: missing "say" command.');
|
|
131904
132636
|
}
|
|
131905
|
-
const output =
|
|
132637
|
+
const output = join31(tmpdir2(), `assistants-tts-${Date.now()}.aiff`);
|
|
131906
132638
|
const args = [];
|
|
131907
132639
|
if (this.voiceId) {
|
|
131908
132640
|
args.push("-v", this.voiceId);
|
|
@@ -131924,7 +132656,7 @@ class SystemTTS {
|
|
|
131924
132656
|
}
|
|
131925
132657
|
const espeak = findExecutable("espeak") || findExecutable("espeak-ng");
|
|
131926
132658
|
if (espeak) {
|
|
131927
|
-
const output =
|
|
132659
|
+
const output = join31(tmpdir2(), `assistants-tts-${Date.now()}.wav`);
|
|
131928
132660
|
const args = ["-w", output];
|
|
131929
132661
|
if (this.voiceId) {
|
|
131930
132662
|
args.push("-v", this.voiceId);
|
|
@@ -131951,14 +132683,14 @@ class SystemTTS {
|
|
|
131951
132683
|
// ../core/src/voice/player.ts
|
|
131952
132684
|
import { spawn } from "child_process";
|
|
131953
132685
|
import { tmpdir as tmpdir3 } from "os";
|
|
131954
|
-
import { join as
|
|
132686
|
+
import { join as join32 } from "path";
|
|
131955
132687
|
import { unlink as unlink6, writeFileSync as writeFileSync13 } from "fs";
|
|
131956
132688
|
class AudioPlayer {
|
|
131957
132689
|
currentProcess = null;
|
|
131958
132690
|
playing = false;
|
|
131959
132691
|
async play(audio, options = {}) {
|
|
131960
132692
|
const format = options.format ?? "mp3";
|
|
131961
|
-
const tempFile =
|
|
132693
|
+
const tempFile = join32(tmpdir3(), `assistants-audio-${Date.now()}.${format}`);
|
|
131962
132694
|
writeFileSync13(tempFile, Buffer.from(audio));
|
|
131963
132695
|
const player = this.resolvePlayer(format);
|
|
131964
132696
|
if (!player) {
|
|
@@ -132026,7 +132758,7 @@ class AudioPlayer {
|
|
|
132026
132758
|
// ../core/src/voice/recorder.ts
|
|
132027
132759
|
import { spawn as spawn2 } from "child_process";
|
|
132028
132760
|
import { tmpdir as tmpdir4 } from "os";
|
|
132029
|
-
import { join as
|
|
132761
|
+
import { join as join33 } from "path";
|
|
132030
132762
|
import { readFileSync as readFileSync15, unlink as unlink7 } from "fs";
|
|
132031
132763
|
class AudioRecorder {
|
|
132032
132764
|
currentProcess = null;
|
|
@@ -132039,7 +132771,7 @@ class AudioRecorder {
|
|
|
132039
132771
|
const duration = options.durationSeconds ?? 5;
|
|
132040
132772
|
const sampleRate = options.sampleRate ?? 16000;
|
|
132041
132773
|
const channels = options.channels ?? 1;
|
|
132042
|
-
const output =
|
|
132774
|
+
const output = join33(tmpdir4(), `assistants-record-${Date.now()}.wav`);
|
|
132043
132775
|
this.currentOutputPath = output;
|
|
132044
132776
|
this.stoppedIntentionally = false;
|
|
132045
132777
|
const recorder = this.resolveRecorder(sampleRate, channels, duration, output);
|
|
@@ -132240,15 +132972,15 @@ class VoiceManager {
|
|
|
132240
132972
|
}
|
|
132241
132973
|
// ../core/src/identity/assistant-manager.ts
|
|
132242
132974
|
init_src2();
|
|
132243
|
-
import { existsSync as
|
|
132244
|
-
import { mkdir as mkdir11, readFile as
|
|
132245
|
-
import { join as
|
|
132975
|
+
import { existsSync as existsSync23 } from "fs";
|
|
132976
|
+
import { mkdir as mkdir11, readFile as readFile13, writeFile as writeFile11, rm as rm3 } from "fs/promises";
|
|
132977
|
+
import { join as join35 } from "path";
|
|
132246
132978
|
|
|
132247
132979
|
// ../core/src/identity/identity-manager.ts
|
|
132248
132980
|
init_src2();
|
|
132249
|
-
import { existsSync as
|
|
132250
|
-
import { mkdir as mkdir10, readFile as
|
|
132251
|
-
import { join as
|
|
132981
|
+
import { existsSync as existsSync22 } from "fs";
|
|
132982
|
+
import { mkdir as mkdir10, readFile as readFile12, writeFile as writeFile10, rm as rm2 } from "fs/promises";
|
|
132983
|
+
import { join as join34 } from "path";
|
|
132252
132984
|
var SAFE_ID_PATTERN6 = /^[a-zA-Z0-9_-]+$/;
|
|
132253
132985
|
function isValidId2(id) {
|
|
132254
132986
|
return typeof id === "string" && id.length > 0 && SAFE_ID_PATTERN6.test(id);
|
|
@@ -132289,20 +133021,20 @@ class IdentityManager {
|
|
|
132289
133021
|
this.basePath = basePath;
|
|
132290
133022
|
}
|
|
132291
133023
|
get identitiesRoot() {
|
|
132292
|
-
return
|
|
133024
|
+
return join34(this.basePath, "assistants", this.assistantId, "identities");
|
|
132293
133025
|
}
|
|
132294
133026
|
get indexPath() {
|
|
132295
|
-
return
|
|
133027
|
+
return join34(this.identitiesRoot, "index.json");
|
|
132296
133028
|
}
|
|
132297
133029
|
get activePath() {
|
|
132298
|
-
return
|
|
133030
|
+
return join34(this.identitiesRoot, "active.json");
|
|
132299
133031
|
}
|
|
132300
133032
|
identityPath(id) {
|
|
132301
133033
|
validateId(id, "identityId");
|
|
132302
|
-
return
|
|
133034
|
+
return join34(this.identitiesRoot, `${id}.json`);
|
|
132303
133035
|
}
|
|
132304
133036
|
assistantConfigPath() {
|
|
132305
|
-
return
|
|
133037
|
+
return join34(this.basePath, "assistants", this.assistantId, "config.json");
|
|
132306
133038
|
}
|
|
132307
133039
|
async initialize() {
|
|
132308
133040
|
await mkdir10(this.identitiesRoot, { recursive: true });
|
|
@@ -132428,11 +133160,11 @@ class IdentityManager {
|
|
|
132428
133160
|
`);
|
|
132429
133161
|
}
|
|
132430
133162
|
async readIndex() {
|
|
132431
|
-
if (!
|
|
133163
|
+
if (!existsSync22(this.indexPath)) {
|
|
132432
133164
|
return { identities: [] };
|
|
132433
133165
|
}
|
|
132434
133166
|
try {
|
|
132435
|
-
const raw = await
|
|
133167
|
+
const raw = await readFile12(this.indexPath, "utf-8");
|
|
132436
133168
|
const data = JSON.parse(raw);
|
|
132437
133169
|
const identities = Array.isArray(data.identities) ? data.identities : [];
|
|
132438
133170
|
return { identities: identities.filter(isValidId2) };
|
|
@@ -132454,10 +133186,10 @@ class IdentityManager {
|
|
|
132454
133186
|
}
|
|
132455
133187
|
async readIdentity(id) {
|
|
132456
133188
|
const path2 = this.identityPath(id);
|
|
132457
|
-
if (!
|
|
133189
|
+
if (!existsSync22(path2))
|
|
132458
133190
|
return null;
|
|
132459
133191
|
try {
|
|
132460
|
-
const raw = await
|
|
133192
|
+
const raw = await readFile12(path2, "utf-8");
|
|
132461
133193
|
return JSON.parse(raw);
|
|
132462
133194
|
} catch {
|
|
132463
133195
|
return null;
|
|
@@ -132468,10 +133200,10 @@ class IdentityManager {
|
|
|
132468
133200
|
await writeFile10(this.identityPath(identity.id), JSON.stringify(identity, null, 2));
|
|
132469
133201
|
}
|
|
132470
133202
|
async readActive() {
|
|
132471
|
-
if (!
|
|
133203
|
+
if (!existsSync22(this.activePath))
|
|
132472
133204
|
return null;
|
|
132473
133205
|
try {
|
|
132474
|
-
const raw = await
|
|
133206
|
+
const raw = await readFile12(this.activePath, "utf-8");
|
|
132475
133207
|
const data = JSON.parse(raw);
|
|
132476
133208
|
const id = data.id || null;
|
|
132477
133209
|
if (id && !isValidId2(id)) {
|
|
@@ -132487,10 +133219,10 @@ class IdentityManager {
|
|
|
132487
133219
|
await writeFile10(this.activePath, JSON.stringify({ id }, null, 2));
|
|
132488
133220
|
}
|
|
132489
133221
|
async loadAssistant() {
|
|
132490
|
-
if (!
|
|
133222
|
+
if (!existsSync22(this.assistantConfigPath()))
|
|
132491
133223
|
return null;
|
|
132492
133224
|
try {
|
|
132493
|
-
const raw = await
|
|
133225
|
+
const raw = await readFile12(this.assistantConfigPath(), "utf-8");
|
|
132494
133226
|
return JSON.parse(raw);
|
|
132495
133227
|
} catch {
|
|
132496
133228
|
return null;
|
|
@@ -132520,17 +133252,17 @@ class AssistantManager {
|
|
|
132520
133252
|
this.basePath = basePath;
|
|
132521
133253
|
}
|
|
132522
133254
|
get assistantsRoot() {
|
|
132523
|
-
return
|
|
133255
|
+
return join35(this.basePath, "assistants");
|
|
132524
133256
|
}
|
|
132525
133257
|
get indexPath() {
|
|
132526
|
-
return
|
|
133258
|
+
return join35(this.assistantsRoot, "index.json");
|
|
132527
133259
|
}
|
|
132528
133260
|
get activePath() {
|
|
132529
|
-
return
|
|
133261
|
+
return join35(this.basePath, "active.json");
|
|
132530
133262
|
}
|
|
132531
133263
|
assistantConfigPath(id) {
|
|
132532
133264
|
validateId2(id, "assistantId");
|
|
132533
|
-
return
|
|
133265
|
+
return join35(this.assistantsRoot, id, "config.json");
|
|
132534
133266
|
}
|
|
132535
133267
|
async initialize() {
|
|
132536
133268
|
await mkdir11(this.assistantsRoot, { recursive: true });
|
|
@@ -132585,7 +133317,7 @@ class AssistantManager {
|
|
|
132585
133317
|
if (!this.assistants.has(id)) {
|
|
132586
133318
|
throw new Error(`Assistant ${id} not found`);
|
|
132587
133319
|
}
|
|
132588
|
-
await rm3(
|
|
133320
|
+
await rm3(join35(this.assistantsRoot, id), { recursive: true, force: true });
|
|
132589
133321
|
this.assistants.delete(id);
|
|
132590
133322
|
await this.removeFromIndex(id);
|
|
132591
133323
|
if (this.activeId === id) {
|
|
@@ -132616,11 +133348,11 @@ class AssistantManager {
|
|
|
132616
133348
|
return new IdentityManager(assistantId, this.basePath);
|
|
132617
133349
|
}
|
|
132618
133350
|
async readIndex() {
|
|
132619
|
-
if (!
|
|
133351
|
+
if (!existsSync23(this.indexPath)) {
|
|
132620
133352
|
return { assistants: [] };
|
|
132621
133353
|
}
|
|
132622
133354
|
try {
|
|
132623
|
-
const raw = await
|
|
133355
|
+
const raw = await readFile13(this.indexPath, "utf-8");
|
|
132624
133356
|
const data = JSON.parse(raw);
|
|
132625
133357
|
const assistants = Array.isArray(data.assistants) ? data.assistants : [];
|
|
132626
133358
|
return { assistants: assistants.filter(isValidId3) };
|
|
@@ -132642,10 +133374,10 @@ class AssistantManager {
|
|
|
132642
133374
|
}
|
|
132643
133375
|
async readAssistant(id) {
|
|
132644
133376
|
const configPath = this.assistantConfigPath(id);
|
|
132645
|
-
if (!
|
|
133377
|
+
if (!existsSync23(configPath))
|
|
132646
133378
|
return null;
|
|
132647
133379
|
try {
|
|
132648
|
-
const raw = await
|
|
133380
|
+
const raw = await readFile13(configPath, "utf-8");
|
|
132649
133381
|
return JSON.parse(raw);
|
|
132650
133382
|
} catch {
|
|
132651
133383
|
return null;
|
|
@@ -132653,15 +133385,15 @@ class AssistantManager {
|
|
|
132653
133385
|
}
|
|
132654
133386
|
async persistAssistant(assistant) {
|
|
132655
133387
|
validateId2(assistant.id, "assistantId");
|
|
132656
|
-
const dir =
|
|
133388
|
+
const dir = join35(this.assistantsRoot, assistant.id);
|
|
132657
133389
|
await mkdir11(dir, { recursive: true });
|
|
132658
133390
|
await writeFile11(this.assistantConfigPath(assistant.id), JSON.stringify(assistant, null, 2));
|
|
132659
133391
|
}
|
|
132660
133392
|
async readActive() {
|
|
132661
|
-
if (!
|
|
133393
|
+
if (!existsSync23(this.activePath))
|
|
132662
133394
|
return null;
|
|
132663
133395
|
try {
|
|
132664
|
-
const raw = await
|
|
133396
|
+
const raw = await readFile13(this.activePath, "utf-8");
|
|
132665
133397
|
const data = JSON.parse(raw);
|
|
132666
133398
|
const id = data.id || null;
|
|
132667
133399
|
if (id && !isValidId3(id)) {
|
|
@@ -132678,7 +133410,7 @@ class AssistantManager {
|
|
|
132678
133410
|
}
|
|
132679
133411
|
}
|
|
132680
133412
|
// ../core/src/inbox/inbox-manager.ts
|
|
132681
|
-
import { join as
|
|
133413
|
+
import { join as join38 } from "path";
|
|
132682
133414
|
|
|
132683
133415
|
// ../../node_modules/.bun/@aws-sdk+middleware-expect-continue@3.972.3/node_modules/@aws-sdk/middleware-expect-continue/dist-es/index.js
|
|
132684
133416
|
var import_protocol_http = __toESM(require_dist_cjs2(), 1);
|
|
@@ -141536,8 +142268,8 @@ class S3InboxClient {
|
|
|
141536
142268
|
}
|
|
141537
142269
|
|
|
141538
142270
|
// ../core/src/inbox/storage/local-cache.ts
|
|
141539
|
-
import { join as
|
|
141540
|
-
import { mkdir as mkdir12, readFile as
|
|
142271
|
+
import { join as join37, basename as basename5 } from "path";
|
|
142272
|
+
import { mkdir as mkdir12, readFile as readFile15, writeFile as writeFile13, rm as rm4, readdir as readdir4, stat as stat3 } from "fs/promises";
|
|
141541
142273
|
import { createHash as createHash5 } from "crypto";
|
|
141542
142274
|
var STRICT_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
141543
142275
|
var SAFE_FILENAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
@@ -141574,18 +142306,18 @@ class LocalInboxCache {
|
|
|
141574
142306
|
validateAssistantId(options.assistantId);
|
|
141575
142307
|
this.assistantId = options.assistantId;
|
|
141576
142308
|
this.basePath = options.basePath;
|
|
141577
|
-
this.cacheDir =
|
|
142309
|
+
this.cacheDir = join37(this.basePath, this.assistantId);
|
|
141578
142310
|
}
|
|
141579
142311
|
async ensureDirectories() {
|
|
141580
|
-
await mkdir12(
|
|
141581
|
-
await mkdir12(
|
|
142312
|
+
await mkdir12(join37(this.cacheDir, "emails"), { recursive: true });
|
|
142313
|
+
await mkdir12(join37(this.cacheDir, "attachments"), { recursive: true });
|
|
141582
142314
|
}
|
|
141583
142315
|
async loadIndex() {
|
|
141584
142316
|
if (this.index)
|
|
141585
142317
|
return this.index;
|
|
141586
142318
|
try {
|
|
141587
|
-
const indexPath =
|
|
141588
|
-
const content = await
|
|
142319
|
+
const indexPath = join37(this.cacheDir, "index.json");
|
|
142320
|
+
const content = await readFile15(indexPath, "utf-8");
|
|
141589
142321
|
this.index = JSON.parse(content);
|
|
141590
142322
|
return this.index;
|
|
141591
142323
|
} catch {
|
|
@@ -141597,7 +142329,7 @@ class LocalInboxCache {
|
|
|
141597
142329
|
if (!this.index)
|
|
141598
142330
|
return;
|
|
141599
142331
|
await this.ensureDirectories();
|
|
141600
|
-
const indexPath =
|
|
142332
|
+
const indexPath = join37(this.cacheDir, "index.json");
|
|
141601
142333
|
await writeFile13(indexPath, JSON.stringify(this.index, null, 2));
|
|
141602
142334
|
}
|
|
141603
142335
|
async saveEmail(email) {
|
|
@@ -141606,7 +142338,7 @@ class LocalInboxCache {
|
|
|
141606
142338
|
throw new Error(`Failed to create safe filename for email ID: "${email.id}"`);
|
|
141607
142339
|
}
|
|
141608
142340
|
await this.ensureDirectories();
|
|
141609
|
-
const emailPath =
|
|
142341
|
+
const emailPath = join37(this.cacheDir, "emails", `${filename}.json`);
|
|
141610
142342
|
await writeFile13(emailPath, JSON.stringify(email, null, 2));
|
|
141611
142343
|
const index = await this.loadIndex();
|
|
141612
142344
|
const existingIdx = index.emails.findIndex((e3) => e3.id === email.id);
|
|
@@ -141641,8 +142373,8 @@ class LocalInboxCache {
|
|
|
141641
142373
|
return null;
|
|
141642
142374
|
}
|
|
141643
142375
|
try {
|
|
141644
|
-
const emailPath =
|
|
141645
|
-
const content = await
|
|
142376
|
+
const emailPath = join37(this.cacheDir, "emails", `${filename}.json`);
|
|
142377
|
+
const content = await readFile15(emailPath, "utf-8");
|
|
141646
142378
|
return JSON.parse(content);
|
|
141647
142379
|
} catch {
|
|
141648
142380
|
return null;
|
|
@@ -141701,9 +142433,9 @@ class LocalInboxCache {
|
|
|
141701
142433
|
if (!safeFilename) {
|
|
141702
142434
|
throw new Error("Invalid attachment filename");
|
|
141703
142435
|
}
|
|
141704
|
-
const attachmentDir =
|
|
142436
|
+
const attachmentDir = join37(this.cacheDir, "attachments", emailFilename);
|
|
141705
142437
|
await mkdir12(attachmentDir, { recursive: true });
|
|
141706
|
-
const attachmentPath =
|
|
142438
|
+
const attachmentPath = join37(attachmentDir, safeFilename);
|
|
141707
142439
|
await writeFile13(attachmentPath, content);
|
|
141708
142440
|
return attachmentPath;
|
|
141709
142441
|
}
|
|
@@ -141717,7 +142449,7 @@ class LocalInboxCache {
|
|
|
141717
142449
|
return null;
|
|
141718
142450
|
}
|
|
141719
142451
|
try {
|
|
141720
|
-
const attachmentPath =
|
|
142452
|
+
const attachmentPath = join37(this.cacheDir, "attachments", emailFilename, safeFilename);
|
|
141721
142453
|
await stat3(attachmentPath);
|
|
141722
142454
|
return attachmentPath;
|
|
141723
142455
|
} catch {
|
|
@@ -141749,10 +142481,10 @@ class LocalInboxCache {
|
|
|
141749
142481
|
for (const { id, filename } of toRemove) {
|
|
141750
142482
|
index.emails = index.emails.filter((e3) => e3.id !== id);
|
|
141751
142483
|
try {
|
|
141752
|
-
await rm4(
|
|
142484
|
+
await rm4(join37(this.cacheDir, "emails", `${filename}.json`));
|
|
141753
142485
|
} catch {}
|
|
141754
142486
|
try {
|
|
141755
|
-
await rm4(
|
|
142487
|
+
await rm4(join37(this.cacheDir, "attachments", filename), { recursive: true });
|
|
141756
142488
|
} catch {}
|
|
141757
142489
|
}
|
|
141758
142490
|
if (toRemove.length > 0) {
|
|
@@ -141763,20 +142495,20 @@ class LocalInboxCache {
|
|
|
141763
142495
|
async getCacheSize() {
|
|
141764
142496
|
let totalSize = 0;
|
|
141765
142497
|
try {
|
|
141766
|
-
const emailsDir =
|
|
142498
|
+
const emailsDir = join37(this.cacheDir, "emails");
|
|
141767
142499
|
const files = await readdir4(emailsDir);
|
|
141768
142500
|
for (const file of files) {
|
|
141769
|
-
const fileStat = await stat3(
|
|
142501
|
+
const fileStat = await stat3(join37(emailsDir, file));
|
|
141770
142502
|
totalSize += fileStat.size;
|
|
141771
142503
|
}
|
|
141772
142504
|
} catch {}
|
|
141773
142505
|
try {
|
|
141774
|
-
const attachmentsDir =
|
|
142506
|
+
const attachmentsDir = join37(this.cacheDir, "attachments");
|
|
141775
142507
|
const dirs = await readdir4(attachmentsDir);
|
|
141776
142508
|
for (const dir of dirs) {
|
|
141777
|
-
const files = await readdir4(
|
|
142509
|
+
const files = await readdir4(join37(attachmentsDir, dir));
|
|
141778
142510
|
for (const file of files) {
|
|
141779
|
-
const fileStat = await stat3(
|
|
142511
|
+
const fileStat = await stat3(join37(attachmentsDir, dir, file));
|
|
141780
142512
|
totalSize += fileStat.size;
|
|
141781
142513
|
}
|
|
141782
142514
|
}
|
|
@@ -144364,7 +145096,7 @@ class InboxManager {
|
|
|
144364
145096
|
}
|
|
144365
145097
|
}
|
|
144366
145098
|
function createInboxManager(assistantId, assistantName, config, configDir) {
|
|
144367
|
-
const basePath =
|
|
145099
|
+
const basePath = join38(configDir, "inbox");
|
|
144368
145100
|
return new InboxManager({
|
|
144369
145101
|
assistantId,
|
|
144370
145102
|
assistantName,
|
|
@@ -147125,13 +147857,13 @@ init_src2();
|
|
|
147125
147857
|
|
|
147126
147858
|
// ../core/src/messages/storage/local-storage.ts
|
|
147127
147859
|
await init_runtime();
|
|
147128
|
-
import { join as
|
|
147860
|
+
import { join as join39 } from "path";
|
|
147129
147861
|
import { homedir as homedir19 } from "os";
|
|
147130
147862
|
import { mkdir as mkdir13, readdir as readdir5, rm as rm5 } from "fs/promises";
|
|
147131
147863
|
function getMessagesBasePath() {
|
|
147132
147864
|
const envOverride = process.env.ASSISTANTS_DIR;
|
|
147133
147865
|
const home = envOverride && envOverride.trim() ? envOverride : homedir19();
|
|
147134
|
-
return
|
|
147866
|
+
return join39(home, ".assistants", "messages");
|
|
147135
147867
|
}
|
|
147136
147868
|
var SAFE_ID_PATTERN8 = /^[a-zA-Z0-9_-]+$/;
|
|
147137
147869
|
|
|
@@ -147152,27 +147884,27 @@ class LocalMessagesStorage {
|
|
|
147152
147884
|
const assistantPath = this.getAssistantPath(assistantId);
|
|
147153
147885
|
await Promise.all([
|
|
147154
147886
|
mkdir13(this.basePath, { recursive: true }),
|
|
147155
|
-
mkdir13(
|
|
147156
|
-
mkdir13(
|
|
147887
|
+
mkdir13(join39(assistantPath, "messages"), { recursive: true }),
|
|
147888
|
+
mkdir13(join39(assistantPath, "threads"), { recursive: true })
|
|
147157
147889
|
]);
|
|
147158
147890
|
}
|
|
147159
147891
|
getAssistantPath(assistantId) {
|
|
147160
147892
|
this.validateSafeId(assistantId, "assistantId");
|
|
147161
|
-
return
|
|
147893
|
+
return join39(this.basePath, assistantId);
|
|
147162
147894
|
}
|
|
147163
147895
|
getIndexPath(assistantId) {
|
|
147164
|
-
return
|
|
147896
|
+
return join39(this.getAssistantPath(assistantId), "index.json");
|
|
147165
147897
|
}
|
|
147166
147898
|
getMessagePath(assistantId, messageId) {
|
|
147167
147899
|
this.validateSafeId(messageId, "messageId");
|
|
147168
|
-
return
|
|
147900
|
+
return join39(this.getAssistantPath(assistantId), "messages", `${messageId}.json`);
|
|
147169
147901
|
}
|
|
147170
147902
|
getThreadPath(assistantId, threadId) {
|
|
147171
147903
|
this.validateSafeId(threadId, "threadId");
|
|
147172
|
-
return
|
|
147904
|
+
return join39(this.getAssistantPath(assistantId), "threads", `${threadId}.json`);
|
|
147173
147905
|
}
|
|
147174
147906
|
getRegistryPath() {
|
|
147175
|
-
return
|
|
147907
|
+
return join39(this.basePath, "registry.json");
|
|
147176
147908
|
}
|
|
147177
147909
|
async loadRegistry() {
|
|
147178
147910
|
try {
|
|
@@ -147456,7 +148188,7 @@ class LocalMessagesStorage {
|
|
|
147456
148188
|
async listThreads(assistantId) {
|
|
147457
148189
|
const runtime = getRuntime();
|
|
147458
148190
|
const assistantPath = this.getAssistantPath(assistantId);
|
|
147459
|
-
const threadsDir =
|
|
148191
|
+
const threadsDir = join39(assistantPath, "threads");
|
|
147460
148192
|
try {
|
|
147461
148193
|
const files = await readdir5(threadsDir);
|
|
147462
148194
|
const threads = [];
|
|
@@ -147464,7 +148196,7 @@ class LocalMessagesStorage {
|
|
|
147464
148196
|
if (!file.endsWith(".json"))
|
|
147465
148197
|
continue;
|
|
147466
148198
|
try {
|
|
147467
|
-
const threadFile = runtime.file(
|
|
148199
|
+
const threadFile = runtime.file(join39(threadsDir, file));
|
|
147468
148200
|
const thread = await threadFile.json();
|
|
147469
148201
|
threads.push(thread);
|
|
147470
148202
|
} catch {}
|
|
@@ -147520,8 +148252,8 @@ class LocalMessagesStorage {
|
|
|
147520
148252
|
}
|
|
147521
148253
|
|
|
147522
148254
|
// ../core/src/messages/watcher.ts
|
|
147523
|
-
import { watch, existsSync as
|
|
147524
|
-
import { join as
|
|
148255
|
+
import { watch, existsSync as existsSync24, readdirSync as readdirSync7 } from "fs";
|
|
148256
|
+
import { join as join40 } from "path";
|
|
147525
148257
|
class InboxWatcher {
|
|
147526
148258
|
assistantId;
|
|
147527
148259
|
inboxPath;
|
|
@@ -147532,14 +148264,14 @@ class InboxWatcher {
|
|
|
147532
148264
|
constructor(assistantId, basePath) {
|
|
147533
148265
|
this.assistantId = assistantId;
|
|
147534
148266
|
const base = basePath || getMessagesBasePath();
|
|
147535
|
-
this.inboxPath =
|
|
148267
|
+
this.inboxPath = join40(base, assistantId, "messages");
|
|
147536
148268
|
}
|
|
147537
148269
|
start() {
|
|
147538
148270
|
if (this.running)
|
|
147539
148271
|
return;
|
|
147540
148272
|
this.running = true;
|
|
147541
148273
|
this.snapshotExisting();
|
|
147542
|
-
if (!
|
|
148274
|
+
if (!existsSync24(this.inboxPath)) {
|
|
147543
148275
|
this.pollForDirectory();
|
|
147544
148276
|
return;
|
|
147545
148277
|
}
|
|
@@ -147564,8 +148296,8 @@ class InboxWatcher {
|
|
|
147564
148296
|
}
|
|
147565
148297
|
snapshotExisting() {
|
|
147566
148298
|
try {
|
|
147567
|
-
if (
|
|
147568
|
-
const files =
|
|
148299
|
+
if (existsSync24(this.inboxPath)) {
|
|
148300
|
+
const files = readdirSync7(this.inboxPath);
|
|
147569
148301
|
for (const file of files) {
|
|
147570
148302
|
if (file.endsWith(".json")) {
|
|
147571
148303
|
this.knownFiles.add(file);
|
|
@@ -147607,7 +148339,7 @@ class InboxWatcher {
|
|
|
147607
148339
|
clearInterval(interval);
|
|
147608
148340
|
return;
|
|
147609
148341
|
}
|
|
147610
|
-
if (
|
|
148342
|
+
if (existsSync24(this.inboxPath)) {
|
|
147611
148343
|
clearInterval(interval);
|
|
147612
148344
|
this.snapshotExisting();
|
|
147613
148345
|
this.startWatching();
|
|
@@ -148284,25 +149016,1096 @@ function registerMessagesTools(registry2, getMessagesManager) {
|
|
|
148284
149016
|
registry2.register(tool, executors[tool.name]);
|
|
148285
149017
|
}
|
|
148286
149018
|
}
|
|
148287
|
-
// ../core/src/
|
|
148288
|
-
|
|
149019
|
+
// ../core/src/webhooks/storage/local-storage.ts
|
|
149020
|
+
await init_runtime();
|
|
149021
|
+
import { join as join41 } from "path";
|
|
148289
149022
|
import { homedir as homedir20 } from "os";
|
|
148290
|
-
import {
|
|
149023
|
+
import { mkdir as mkdir14, readdir as readdir6, rm as rm6 } from "fs/promises";
|
|
149024
|
+
function getWebhooksBasePath() {
|
|
149025
|
+
const envOverride = process.env.ASSISTANTS_DIR;
|
|
149026
|
+
const home = envOverride && envOverride.trim() ? envOverride : homedir20();
|
|
149027
|
+
return join41(home, ".assistants", "webhooks");
|
|
149028
|
+
}
|
|
149029
|
+
var SAFE_ID_PATTERN9 = /^[a-zA-Z0-9_-]+$/;
|
|
149030
|
+
|
|
149031
|
+
class LocalWebhookStorage {
|
|
149032
|
+
basePath;
|
|
149033
|
+
constructor(options = {}) {
|
|
149034
|
+
this.basePath = options.basePath || getWebhooksBasePath();
|
|
149035
|
+
}
|
|
149036
|
+
validateSafeId(id, idType) {
|
|
149037
|
+
if (!id || typeof id !== "string") {
|
|
149038
|
+
throw new Error(`Invalid ${idType}: must be a non-empty string`);
|
|
149039
|
+
}
|
|
149040
|
+
if (!SAFE_ID_PATTERN9.test(id)) {
|
|
149041
|
+
throw new Error(`Invalid ${idType}: "${id}" contains invalid characters. Only alphanumeric characters, hyphens, and underscores are allowed.`);
|
|
149042
|
+
}
|
|
149043
|
+
}
|
|
149044
|
+
async ensureDirectories(webhookId) {
|
|
149045
|
+
const dirs = [
|
|
149046
|
+
mkdir14(this.basePath, { recursive: true }),
|
|
149047
|
+
mkdir14(join41(this.basePath, "registrations"), { recursive: true }),
|
|
149048
|
+
mkdir14(join41(this.basePath, "events"), { recursive: true }),
|
|
149049
|
+
mkdir14(join41(this.basePath, "deliveries"), { recursive: true })
|
|
149050
|
+
];
|
|
149051
|
+
if (webhookId) {
|
|
149052
|
+
this.validateSafeId(webhookId, "webhookId");
|
|
149053
|
+
dirs.push(mkdir14(join41(this.basePath, "events", webhookId), { recursive: true }));
|
|
149054
|
+
dirs.push(mkdir14(join41(this.basePath, "deliveries", webhookId), { recursive: true }));
|
|
149055
|
+
}
|
|
149056
|
+
await Promise.all(dirs);
|
|
149057
|
+
}
|
|
149058
|
+
getIndexPath() {
|
|
149059
|
+
return join41(this.basePath, "index.json");
|
|
149060
|
+
}
|
|
149061
|
+
getRegistrationPath(webhookId) {
|
|
149062
|
+
this.validateSafeId(webhookId, "webhookId");
|
|
149063
|
+
return join41(this.basePath, "registrations", `${webhookId}.json`);
|
|
149064
|
+
}
|
|
149065
|
+
getEventIndexPath(webhookId) {
|
|
149066
|
+
this.validateSafeId(webhookId, "webhookId");
|
|
149067
|
+
return join41(this.basePath, "events", webhookId, "index.json");
|
|
149068
|
+
}
|
|
149069
|
+
getEventPath(webhookId, eventId) {
|
|
149070
|
+
this.validateSafeId(webhookId, "webhookId");
|
|
149071
|
+
this.validateSafeId(eventId, "eventId");
|
|
149072
|
+
return join41(this.basePath, "events", webhookId, `${eventId}.json`);
|
|
149073
|
+
}
|
|
149074
|
+
getDeliveryPath(webhookId, deliveryId) {
|
|
149075
|
+
this.validateSafeId(webhookId, "webhookId");
|
|
149076
|
+
this.validateSafeId(deliveryId, "deliveryId");
|
|
149077
|
+
return join41(this.basePath, "deliveries", webhookId, `${deliveryId}.json`);
|
|
149078
|
+
}
|
|
149079
|
+
async loadIndex() {
|
|
149080
|
+
try {
|
|
149081
|
+
const runtime = getRuntime();
|
|
149082
|
+
const file = runtime.file(this.getIndexPath());
|
|
149083
|
+
if (!await file.exists()) {
|
|
149084
|
+
return { webhooks: [], lastUpdated: new Date().toISOString() };
|
|
149085
|
+
}
|
|
149086
|
+
return await file.json();
|
|
149087
|
+
} catch {
|
|
149088
|
+
return { webhooks: [], lastUpdated: new Date().toISOString() };
|
|
149089
|
+
}
|
|
149090
|
+
}
|
|
149091
|
+
async saveIndex(index) {
|
|
149092
|
+
const runtime = getRuntime();
|
|
149093
|
+
await mkdir14(this.basePath, { recursive: true });
|
|
149094
|
+
index.lastUpdated = new Date().toISOString();
|
|
149095
|
+
await runtime.write(this.getIndexPath(), JSON.stringify(index, null, 2));
|
|
149096
|
+
}
|
|
149097
|
+
async saveRegistration(registration) {
|
|
149098
|
+
const runtime = getRuntime();
|
|
149099
|
+
await this.ensureDirectories(registration.id);
|
|
149100
|
+
await runtime.write(this.getRegistrationPath(registration.id), JSON.stringify(registration, null, 2));
|
|
149101
|
+
const index = await this.loadIndex();
|
|
149102
|
+
const existing = index.webhooks.findIndex((w6) => w6.id === registration.id);
|
|
149103
|
+
const listItem = {
|
|
149104
|
+
id: registration.id,
|
|
149105
|
+
name: registration.name,
|
|
149106
|
+
source: registration.source,
|
|
149107
|
+
status: registration.status,
|
|
149108
|
+
deliveryCount: registration.deliveryCount,
|
|
149109
|
+
createdAt: registration.createdAt,
|
|
149110
|
+
lastDeliveryAt: registration.lastDeliveryAt
|
|
149111
|
+
};
|
|
149112
|
+
if (existing >= 0) {
|
|
149113
|
+
index.webhooks[existing] = listItem;
|
|
149114
|
+
} else {
|
|
149115
|
+
index.webhooks.unshift(listItem);
|
|
149116
|
+
}
|
|
149117
|
+
await this.saveIndex(index);
|
|
149118
|
+
}
|
|
149119
|
+
async loadRegistration(webhookId) {
|
|
149120
|
+
try {
|
|
149121
|
+
const runtime = getRuntime();
|
|
149122
|
+
const file = runtime.file(this.getRegistrationPath(webhookId));
|
|
149123
|
+
if (!await file.exists()) {
|
|
149124
|
+
return null;
|
|
149125
|
+
}
|
|
149126
|
+
return await file.json();
|
|
149127
|
+
} catch {
|
|
149128
|
+
return null;
|
|
149129
|
+
}
|
|
149130
|
+
}
|
|
149131
|
+
async deleteRegistration(webhookId) {
|
|
149132
|
+
try {
|
|
149133
|
+
const regPath = this.getRegistrationPath(webhookId);
|
|
149134
|
+
const runtime = getRuntime();
|
|
149135
|
+
const file = runtime.file(regPath);
|
|
149136
|
+
if (!await file.exists()) {
|
|
149137
|
+
return false;
|
|
149138
|
+
}
|
|
149139
|
+
await rm6(regPath);
|
|
149140
|
+
const index = await this.loadIndex();
|
|
149141
|
+
const idx = index.webhooks.findIndex((w6) => w6.id === webhookId);
|
|
149142
|
+
if (idx >= 0) {
|
|
149143
|
+
index.webhooks.splice(idx, 1);
|
|
149144
|
+
await this.saveIndex(index);
|
|
149145
|
+
}
|
|
149146
|
+
try {
|
|
149147
|
+
await rm6(join41(this.basePath, "events", webhookId), { recursive: true, force: true });
|
|
149148
|
+
await rm6(join41(this.basePath, "deliveries", webhookId), { recursive: true, force: true });
|
|
149149
|
+
} catch {}
|
|
149150
|
+
return true;
|
|
149151
|
+
} catch {
|
|
149152
|
+
return false;
|
|
149153
|
+
}
|
|
149154
|
+
}
|
|
149155
|
+
async listRegistrations() {
|
|
149156
|
+
const index = await this.loadIndex();
|
|
149157
|
+
return index.webhooks;
|
|
149158
|
+
}
|
|
149159
|
+
async loadEventIndex(webhookId) {
|
|
149160
|
+
try {
|
|
149161
|
+
const runtime = getRuntime();
|
|
149162
|
+
const file = runtime.file(this.getEventIndexPath(webhookId));
|
|
149163
|
+
if (!await file.exists()) {
|
|
149164
|
+
return {
|
|
149165
|
+
events: [],
|
|
149166
|
+
lastUpdated: new Date().toISOString(),
|
|
149167
|
+
totalEvents: 0,
|
|
149168
|
+
pendingCount: 0
|
|
149169
|
+
};
|
|
149170
|
+
}
|
|
149171
|
+
return await file.json();
|
|
149172
|
+
} catch {
|
|
149173
|
+
return {
|
|
149174
|
+
events: [],
|
|
149175
|
+
lastUpdated: new Date().toISOString(),
|
|
149176
|
+
totalEvents: 0,
|
|
149177
|
+
pendingCount: 0
|
|
149178
|
+
};
|
|
149179
|
+
}
|
|
149180
|
+
}
|
|
149181
|
+
async saveEventIndex(webhookId, index) {
|
|
149182
|
+
const runtime = getRuntime();
|
|
149183
|
+
this.validateSafeId(webhookId, "webhookId");
|
|
149184
|
+
await mkdir14(join41(this.basePath, "events", webhookId), { recursive: true });
|
|
149185
|
+
index.lastUpdated = new Date().toISOString();
|
|
149186
|
+
await runtime.write(this.getEventIndexPath(webhookId), JSON.stringify(index, null, 2));
|
|
149187
|
+
}
|
|
149188
|
+
async saveEvent(event) {
|
|
149189
|
+
const runtime = getRuntime();
|
|
149190
|
+
await this.ensureDirectories(event.webhookId);
|
|
149191
|
+
await runtime.write(this.getEventPath(event.webhookId, event.id), JSON.stringify(event, null, 2));
|
|
149192
|
+
const eventIndex = await this.loadEventIndex(event.webhookId);
|
|
149193
|
+
const payloadStr = JSON.stringify(event.payload);
|
|
149194
|
+
const listItem = {
|
|
149195
|
+
id: event.id,
|
|
149196
|
+
source: event.source,
|
|
149197
|
+
eventType: event.eventType,
|
|
149198
|
+
preview: payloadStr.slice(0, 100) + (payloadStr.length > 100 ? "..." : ""),
|
|
149199
|
+
timestamp: event.timestamp,
|
|
149200
|
+
status: event.status
|
|
149201
|
+
};
|
|
149202
|
+
eventIndex.events.unshift(listItem);
|
|
149203
|
+
eventIndex.totalEvents++;
|
|
149204
|
+
if (event.status === "pending") {
|
|
149205
|
+
eventIndex.pendingCount++;
|
|
149206
|
+
}
|
|
149207
|
+
await this.saveEventIndex(event.webhookId, eventIndex);
|
|
149208
|
+
}
|
|
149209
|
+
async loadEvent(webhookId, eventId) {
|
|
149210
|
+
try {
|
|
149211
|
+
const runtime = getRuntime();
|
|
149212
|
+
const file = runtime.file(this.getEventPath(webhookId, eventId));
|
|
149213
|
+
if (!await file.exists()) {
|
|
149214
|
+
return null;
|
|
149215
|
+
}
|
|
149216
|
+
return await file.json();
|
|
149217
|
+
} catch {
|
|
149218
|
+
return null;
|
|
149219
|
+
}
|
|
149220
|
+
}
|
|
149221
|
+
async updateEventStatus(webhookId, eventId, status, timestamp) {
|
|
149222
|
+
const runtime = getRuntime();
|
|
149223
|
+
const event = await this.loadEvent(webhookId, eventId);
|
|
149224
|
+
if (!event)
|
|
149225
|
+
return;
|
|
149226
|
+
const oldStatus = event.status;
|
|
149227
|
+
event.status = status;
|
|
149228
|
+
if (status === "injected" && timestamp) {
|
|
149229
|
+
event.injectedAt = timestamp;
|
|
149230
|
+
}
|
|
149231
|
+
await runtime.write(this.getEventPath(webhookId, eventId), JSON.stringify(event, null, 2));
|
|
149232
|
+
const eventIndex = await this.loadEventIndex(webhookId);
|
|
149233
|
+
const indexItem = eventIndex.events.find((e6) => e6.id === eventId);
|
|
149234
|
+
if (indexItem) {
|
|
149235
|
+
indexItem.status = status;
|
|
149236
|
+
}
|
|
149237
|
+
if (oldStatus === "pending" && status !== "pending") {
|
|
149238
|
+
eventIndex.pendingCount = Math.max(0, eventIndex.pendingCount - 1);
|
|
149239
|
+
}
|
|
149240
|
+
await this.saveEventIndex(webhookId, eventIndex);
|
|
149241
|
+
}
|
|
149242
|
+
async listEvents(webhookId, options) {
|
|
149243
|
+
const eventIndex = await this.loadEventIndex(webhookId);
|
|
149244
|
+
let events = [...eventIndex.events];
|
|
149245
|
+
if (options?.pendingOnly) {
|
|
149246
|
+
events = events.filter((e6) => e6.status === "pending");
|
|
149247
|
+
}
|
|
149248
|
+
if (options?.limit && options.limit > 0) {
|
|
149249
|
+
events = events.slice(0, options.limit);
|
|
149250
|
+
}
|
|
149251
|
+
return events;
|
|
149252
|
+
}
|
|
149253
|
+
async saveDelivery(delivery) {
|
|
149254
|
+
const runtime = getRuntime();
|
|
149255
|
+
this.validateSafeId(delivery.webhookId, "webhookId");
|
|
149256
|
+
await mkdir14(join41(this.basePath, "deliveries", delivery.webhookId), { recursive: true });
|
|
149257
|
+
await runtime.write(this.getDeliveryPath(delivery.webhookId, delivery.id), JSON.stringify(delivery, null, 2));
|
|
149258
|
+
}
|
|
149259
|
+
async listDeliveries(webhookId, options) {
|
|
149260
|
+
this.validateSafeId(webhookId, "webhookId");
|
|
149261
|
+
const deliveriesDir = join41(this.basePath, "deliveries", webhookId);
|
|
149262
|
+
try {
|
|
149263
|
+
const files = await readdir6(deliveriesDir);
|
|
149264
|
+
const runtime = getRuntime();
|
|
149265
|
+
const deliveries = [];
|
|
149266
|
+
for (const file of files) {
|
|
149267
|
+
if (!file.endsWith(".json"))
|
|
149268
|
+
continue;
|
|
149269
|
+
try {
|
|
149270
|
+
const deliveryFile = runtime.file(join41(deliveriesDir, file));
|
|
149271
|
+
const delivery = await deliveryFile.json();
|
|
149272
|
+
deliveries.push(delivery);
|
|
149273
|
+
} catch {}
|
|
149274
|
+
}
|
|
149275
|
+
deliveries.sort((a5, b8) => new Date(b8.receivedAt).getTime() - new Date(a5.receivedAt).getTime());
|
|
149276
|
+
if (options?.limit && options.limit > 0) {
|
|
149277
|
+
return deliveries.slice(0, options.limit);
|
|
149278
|
+
}
|
|
149279
|
+
return deliveries;
|
|
149280
|
+
} catch {
|
|
149281
|
+
return [];
|
|
149282
|
+
}
|
|
149283
|
+
}
|
|
149284
|
+
async cleanupEvents(webhookId, maxAgeDays) {
|
|
149285
|
+
const cutoffDate = new Date;
|
|
149286
|
+
cutoffDate.setDate(cutoffDate.getDate() - maxAgeDays);
|
|
149287
|
+
const cutoffTime = cutoffDate.getTime();
|
|
149288
|
+
const eventIndex = await this.loadEventIndex(webhookId);
|
|
149289
|
+
const toDelete = [];
|
|
149290
|
+
for (const evt of eventIndex.events) {
|
|
149291
|
+
const evtTime = new Date(evt.timestamp).getTime();
|
|
149292
|
+
if (evtTime < cutoffTime) {
|
|
149293
|
+
toDelete.push(evt.id);
|
|
149294
|
+
}
|
|
149295
|
+
}
|
|
149296
|
+
for (const id of toDelete) {
|
|
149297
|
+
try {
|
|
149298
|
+
await rm6(this.getEventPath(webhookId, id));
|
|
149299
|
+
} catch {}
|
|
149300
|
+
}
|
|
149301
|
+
eventIndex.events = eventIndex.events.filter((e6) => !toDelete.includes(e6.id));
|
|
149302
|
+
eventIndex.pendingCount = eventIndex.events.filter((e6) => e6.status === "pending").length;
|
|
149303
|
+
await this.saveEventIndex(webhookId, eventIndex);
|
|
149304
|
+
return toDelete.length;
|
|
149305
|
+
}
|
|
149306
|
+
async enforceMaxEvents(webhookId, maxEvents) {
|
|
149307
|
+
const eventIndex = await this.loadEventIndex(webhookId);
|
|
149308
|
+
if (eventIndex.events.length <= maxEvents) {
|
|
149309
|
+
return 0;
|
|
149310
|
+
}
|
|
149311
|
+
const sorted = [...eventIndex.events].sort((a5, b8) => new Date(a5.timestamp).getTime() - new Date(b8.timestamp).getTime());
|
|
149312
|
+
const toDelete = sorted.slice(0, eventIndex.events.length - maxEvents);
|
|
149313
|
+
for (const evt of toDelete) {
|
|
149314
|
+
try {
|
|
149315
|
+
await rm6(this.getEventPath(webhookId, evt.id));
|
|
149316
|
+
} catch {}
|
|
149317
|
+
}
|
|
149318
|
+
const deleteIds = new Set(toDelete.map((e6) => e6.id));
|
|
149319
|
+
eventIndex.events = eventIndex.events.filter((e6) => !deleteIds.has(e6.id));
|
|
149320
|
+
eventIndex.pendingCount = eventIndex.events.filter((e6) => e6.status === "pending").length;
|
|
149321
|
+
await this.saveEventIndex(webhookId, eventIndex);
|
|
149322
|
+
return toDelete.length;
|
|
149323
|
+
}
|
|
149324
|
+
}
|
|
149325
|
+
|
|
149326
|
+
// ../core/src/webhooks/watcher.ts
|
|
149327
|
+
import { watch as watch2, existsSync as existsSync25, readdirSync as readdirSync8 } from "fs";
|
|
149328
|
+
import { join as join42 } from "path";
|
|
149329
|
+
class WebhookEventWatcher {
|
|
149330
|
+
basePath;
|
|
149331
|
+
eventsPath;
|
|
149332
|
+
watchers = new Map;
|
|
149333
|
+
callbacks = new Set;
|
|
149334
|
+
knownFiles = new Map;
|
|
149335
|
+
running = false;
|
|
149336
|
+
directoryWatcher = null;
|
|
149337
|
+
constructor(basePath) {
|
|
149338
|
+
this.basePath = basePath || getWebhooksBasePath();
|
|
149339
|
+
this.eventsPath = join42(this.basePath, "events");
|
|
149340
|
+
}
|
|
149341
|
+
start() {
|
|
149342
|
+
if (this.running)
|
|
149343
|
+
return;
|
|
149344
|
+
this.running = true;
|
|
149345
|
+
if (!existsSync25(this.eventsPath)) {
|
|
149346
|
+
this.pollForDirectory();
|
|
149347
|
+
return;
|
|
149348
|
+
}
|
|
149349
|
+
this.startWatchingAll();
|
|
149350
|
+
}
|
|
149351
|
+
stop() {
|
|
149352
|
+
this.running = false;
|
|
149353
|
+
for (const [, watcher] of this.watchers) {
|
|
149354
|
+
watcher.close();
|
|
149355
|
+
}
|
|
149356
|
+
this.watchers.clear();
|
|
149357
|
+
if (this.directoryWatcher) {
|
|
149358
|
+
this.directoryWatcher.close();
|
|
149359
|
+
this.directoryWatcher = null;
|
|
149360
|
+
}
|
|
149361
|
+
this.callbacks.clear();
|
|
149362
|
+
this.knownFiles.clear();
|
|
149363
|
+
}
|
|
149364
|
+
onNewEvent(cb2) {
|
|
149365
|
+
this.callbacks.add(cb2);
|
|
149366
|
+
return () => {
|
|
149367
|
+
this.callbacks.delete(cb2);
|
|
149368
|
+
};
|
|
149369
|
+
}
|
|
149370
|
+
isRunning() {
|
|
149371
|
+
return this.running;
|
|
149372
|
+
}
|
|
149373
|
+
startWatchingAll() {
|
|
149374
|
+
try {
|
|
149375
|
+
this.directoryWatcher = watch2(this.eventsPath, (eventType, filename) => {
|
|
149376
|
+
if (!filename || eventType !== "rename")
|
|
149377
|
+
return;
|
|
149378
|
+
const dirPath = join42(this.eventsPath, filename);
|
|
149379
|
+
if (existsSync25(dirPath) && !this.watchers.has(filename)) {
|
|
149380
|
+
this.watchWebhookDir(filename);
|
|
149381
|
+
}
|
|
149382
|
+
});
|
|
149383
|
+
this.directoryWatcher.on("error", () => {
|
|
149384
|
+
if (this.running) {
|
|
149385
|
+
this.directoryWatcher?.close();
|
|
149386
|
+
this.directoryWatcher = null;
|
|
149387
|
+
setTimeout(() => {
|
|
149388
|
+
if (this.running)
|
|
149389
|
+
this.startWatchingAll();
|
|
149390
|
+
}, 5000);
|
|
149391
|
+
}
|
|
149392
|
+
});
|
|
149393
|
+
} catch {}
|
|
149394
|
+
try {
|
|
149395
|
+
const dirs = readdirSync8(this.eventsPath);
|
|
149396
|
+
for (const dir of dirs) {
|
|
149397
|
+
this.watchWebhookDir(dir);
|
|
149398
|
+
}
|
|
149399
|
+
} catch {}
|
|
149400
|
+
}
|
|
149401
|
+
watchWebhookDir(webhookId) {
|
|
149402
|
+
if (this.watchers.has(webhookId))
|
|
149403
|
+
return;
|
|
149404
|
+
const dirPath = join42(this.eventsPath, webhookId);
|
|
149405
|
+
if (!existsSync25(dirPath))
|
|
149406
|
+
return;
|
|
149407
|
+
const known = new Set;
|
|
149408
|
+
try {
|
|
149409
|
+
const files = readdirSync8(dirPath);
|
|
149410
|
+
for (const file of files) {
|
|
149411
|
+
if (file.endsWith(".json") && file !== "index.json") {
|
|
149412
|
+
known.add(file);
|
|
149413
|
+
}
|
|
149414
|
+
}
|
|
149415
|
+
} catch {}
|
|
149416
|
+
this.knownFiles.set(webhookId, known);
|
|
149417
|
+
try {
|
|
149418
|
+
const watcher = watch2(dirPath, (eventType, filename) => {
|
|
149419
|
+
if (!filename || !filename.endsWith(".json") || filename === "index.json")
|
|
149420
|
+
return;
|
|
149421
|
+
const knownSet = this.knownFiles.get(webhookId);
|
|
149422
|
+
if (eventType === "rename" && knownSet && !knownSet.has(filename)) {
|
|
149423
|
+
knownSet.add(filename);
|
|
149424
|
+
const eventId = filename.replace(".json", "");
|
|
149425
|
+
this.notifyCallbacks(webhookId, eventId);
|
|
149426
|
+
}
|
|
149427
|
+
});
|
|
149428
|
+
watcher.on("error", () => {
|
|
149429
|
+
if (this.running) {
|
|
149430
|
+
watcher.close();
|
|
149431
|
+
this.watchers.delete(webhookId);
|
|
149432
|
+
setTimeout(() => {
|
|
149433
|
+
if (this.running)
|
|
149434
|
+
this.watchWebhookDir(webhookId);
|
|
149435
|
+
}, 5000);
|
|
149436
|
+
}
|
|
149437
|
+
});
|
|
149438
|
+
this.watchers.set(webhookId, watcher);
|
|
149439
|
+
} catch {}
|
|
149440
|
+
}
|
|
149441
|
+
pollForDirectory() {
|
|
149442
|
+
if (!this.running)
|
|
149443
|
+
return;
|
|
149444
|
+
const interval = setInterval(() => {
|
|
149445
|
+
if (!this.running) {
|
|
149446
|
+
clearInterval(interval);
|
|
149447
|
+
return;
|
|
149448
|
+
}
|
|
149449
|
+
if (existsSync25(this.eventsPath)) {
|
|
149450
|
+
clearInterval(interval);
|
|
149451
|
+
this.startWatchingAll();
|
|
149452
|
+
}
|
|
149453
|
+
}, 5000);
|
|
149454
|
+
}
|
|
149455
|
+
notifyCallbacks(webhookId, eventId) {
|
|
149456
|
+
for (const cb2 of this.callbacks) {
|
|
149457
|
+
try {
|
|
149458
|
+
cb2(webhookId, eventId);
|
|
149459
|
+
} catch {}
|
|
149460
|
+
}
|
|
149461
|
+
}
|
|
149462
|
+
}
|
|
149463
|
+
|
|
149464
|
+
// ../core/src/webhooks/manager.ts
|
|
149465
|
+
init_crypto();
|
|
149466
|
+
|
|
149467
|
+
class WebhooksManager {
|
|
149468
|
+
assistantId;
|
|
149469
|
+
config;
|
|
149470
|
+
storage;
|
|
149471
|
+
watcher = null;
|
|
149472
|
+
eventCallbacks = new Set;
|
|
149473
|
+
rateLimits = new Map;
|
|
149474
|
+
constructor(options) {
|
|
149475
|
+
this.assistantId = options.assistantId;
|
|
149476
|
+
this.config = options.config;
|
|
149477
|
+
this.storage = new LocalWebhookStorage({
|
|
149478
|
+
basePath: options.config.storage?.basePath || getWebhooksBasePath()
|
|
149479
|
+
});
|
|
149480
|
+
}
|
|
149481
|
+
async initialize() {
|
|
149482
|
+
await this.storage.ensureDirectories();
|
|
149483
|
+
}
|
|
149484
|
+
async create(input) {
|
|
149485
|
+
try {
|
|
149486
|
+
const webhookId = generateWebhookId();
|
|
149487
|
+
const secret = generateWebhookSecret();
|
|
149488
|
+
const now2 = new Date().toISOString();
|
|
149489
|
+
const registration = {
|
|
149490
|
+
id: webhookId,
|
|
149491
|
+
name: input.name,
|
|
149492
|
+
source: input.source,
|
|
149493
|
+
description: input.description,
|
|
149494
|
+
secret,
|
|
149495
|
+
eventsFilter: input.eventsFilter || [],
|
|
149496
|
+
status: "active",
|
|
149497
|
+
deliveryCount: 0,
|
|
149498
|
+
createdAt: now2,
|
|
149499
|
+
updatedAt: now2
|
|
149500
|
+
};
|
|
149501
|
+
await this.storage.saveRegistration(registration);
|
|
149502
|
+
const url = `/api/v1/webhooks/receive/${webhookId}`;
|
|
149503
|
+
return {
|
|
149504
|
+
success: true,
|
|
149505
|
+
message: `Webhook "${input.name}" created for source "${input.source}"`,
|
|
149506
|
+
webhookId,
|
|
149507
|
+
secret,
|
|
149508
|
+
url
|
|
149509
|
+
};
|
|
149510
|
+
} catch (error2) {
|
|
149511
|
+
return {
|
|
149512
|
+
success: false,
|
|
149513
|
+
message: `Failed to create webhook: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
149514
|
+
};
|
|
149515
|
+
}
|
|
149516
|
+
}
|
|
149517
|
+
async list() {
|
|
149518
|
+
return this.storage.listRegistrations();
|
|
149519
|
+
}
|
|
149520
|
+
async get(webhookId) {
|
|
149521
|
+
return this.storage.loadRegistration(webhookId);
|
|
149522
|
+
}
|
|
149523
|
+
async update(input) {
|
|
149524
|
+
try {
|
|
149525
|
+
const registration = await this.storage.loadRegistration(input.id);
|
|
149526
|
+
if (!registration) {
|
|
149527
|
+
return { success: false, message: `Webhook "${input.id}" not found.` };
|
|
149528
|
+
}
|
|
149529
|
+
if (input.name !== undefined)
|
|
149530
|
+
registration.name = input.name;
|
|
149531
|
+
if (input.description !== undefined)
|
|
149532
|
+
registration.description = input.description;
|
|
149533
|
+
if (input.eventsFilter !== undefined)
|
|
149534
|
+
registration.eventsFilter = input.eventsFilter;
|
|
149535
|
+
if (input.status !== undefined)
|
|
149536
|
+
registration.status = input.status;
|
|
149537
|
+
registration.updatedAt = new Date().toISOString();
|
|
149538
|
+
await this.storage.saveRegistration(registration);
|
|
149539
|
+
return {
|
|
149540
|
+
success: true,
|
|
149541
|
+
message: `Webhook "${registration.name}" updated.`,
|
|
149542
|
+
webhookId: registration.id
|
|
149543
|
+
};
|
|
149544
|
+
} catch (error2) {
|
|
149545
|
+
return {
|
|
149546
|
+
success: false,
|
|
149547
|
+
message: `Failed to update webhook: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
149548
|
+
};
|
|
149549
|
+
}
|
|
149550
|
+
}
|
|
149551
|
+
async delete(webhookId) {
|
|
149552
|
+
const deleted = await this.storage.deleteRegistration(webhookId);
|
|
149553
|
+
if (deleted) {
|
|
149554
|
+
return { success: true, message: `Webhook ${webhookId} deleted.` };
|
|
149555
|
+
}
|
|
149556
|
+
return { success: false, message: `Webhook ${webhookId} not found.` };
|
|
149557
|
+
}
|
|
149558
|
+
async receiveEvent(input) {
|
|
149559
|
+
try {
|
|
149560
|
+
const registration = await this.storage.loadRegistration(input.webhookId);
|
|
149561
|
+
if (!registration) {
|
|
149562
|
+
return { success: false, message: "Webhook not found." };
|
|
149563
|
+
}
|
|
149564
|
+
if (registration.status !== "active") {
|
|
149565
|
+
return { success: false, message: "Webhook is not active." };
|
|
149566
|
+
}
|
|
149567
|
+
if (!this.checkRateLimit(input.webhookId)) {
|
|
149568
|
+
return { success: false, message: "Rate limit exceeded." };
|
|
149569
|
+
}
|
|
149570
|
+
const maxTimestampAge = this.config.security?.maxTimestampAgeMs || 300000;
|
|
149571
|
+
if (!isTimestampValid(input.timestamp, maxTimestampAge)) {
|
|
149572
|
+
return { success: false, message: "Timestamp too old or invalid." };
|
|
149573
|
+
}
|
|
149574
|
+
const payloadStr = JSON.stringify(input.payload);
|
|
149575
|
+
if (!verifySignature(payloadStr, input.signature, registration.secret)) {
|
|
149576
|
+
return { success: false, message: "Invalid signature." };
|
|
149577
|
+
}
|
|
149578
|
+
if (registration.eventsFilter.length > 0 && !registration.eventsFilter.includes(input.eventType)) {
|
|
149579
|
+
return { success: false, message: `Event type "${input.eventType}" not accepted by this webhook.` };
|
|
149580
|
+
}
|
|
149581
|
+
const eventId = generateEventId();
|
|
149582
|
+
const deliveryId = generateDeliveryId();
|
|
149583
|
+
const now2 = new Date().toISOString();
|
|
149584
|
+
const event = {
|
|
149585
|
+
id: eventId,
|
|
149586
|
+
webhookId: input.webhookId,
|
|
149587
|
+
source: registration.source,
|
|
149588
|
+
eventType: input.eventType,
|
|
149589
|
+
payload: input.payload,
|
|
149590
|
+
timestamp: input.timestamp,
|
|
149591
|
+
signature: input.signature,
|
|
149592
|
+
status: "pending"
|
|
149593
|
+
};
|
|
149594
|
+
await this.storage.saveEvent(event);
|
|
149595
|
+
const delivery = {
|
|
149596
|
+
id: deliveryId,
|
|
149597
|
+
webhookId: input.webhookId,
|
|
149598
|
+
eventId,
|
|
149599
|
+
receivedAt: now2,
|
|
149600
|
+
status: "accepted",
|
|
149601
|
+
httpStatus: 200,
|
|
149602
|
+
remoteIp: input.remoteIp
|
|
149603
|
+
};
|
|
149604
|
+
await this.storage.saveDelivery(delivery);
|
|
149605
|
+
registration.deliveryCount++;
|
|
149606
|
+
registration.lastDeliveryAt = now2;
|
|
149607
|
+
registration.updatedAt = now2;
|
|
149608
|
+
await this.storage.saveRegistration(registration);
|
|
149609
|
+
return {
|
|
149610
|
+
success: true,
|
|
149611
|
+
message: "Event received.",
|
|
149612
|
+
deliveryId,
|
|
149613
|
+
eventId
|
|
149614
|
+
};
|
|
149615
|
+
} catch (error2) {
|
|
149616
|
+
return {
|
|
149617
|
+
success: false,
|
|
149618
|
+
message: `Failed to process event: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
149619
|
+
};
|
|
149620
|
+
}
|
|
149621
|
+
}
|
|
149622
|
+
async sendTestEvent(webhookId) {
|
|
149623
|
+
const registration = await this.storage.loadRegistration(webhookId);
|
|
149624
|
+
if (!registration) {
|
|
149625
|
+
return { success: false, message: `Webhook "${webhookId}" not found.` };
|
|
149626
|
+
}
|
|
149627
|
+
const { signPayload: signPayload2 } = await Promise.resolve().then(() => (init_crypto(), exports_crypto));
|
|
149628
|
+
const payload = { test: true, message: "Test event from assistant", timestamp: new Date().toISOString() };
|
|
149629
|
+
const payloadStr = JSON.stringify(payload);
|
|
149630
|
+
const signature = signPayload2(payloadStr, registration.secret);
|
|
149631
|
+
return this.receiveEvent({
|
|
149632
|
+
webhookId,
|
|
149633
|
+
payload,
|
|
149634
|
+
signature,
|
|
149635
|
+
timestamp: new Date().toISOString(),
|
|
149636
|
+
eventType: "test"
|
|
149637
|
+
});
|
|
149638
|
+
}
|
|
149639
|
+
async listEvents(webhookId, options) {
|
|
149640
|
+
return this.storage.listEvents(webhookId, options);
|
|
149641
|
+
}
|
|
149642
|
+
async listDeliveries(webhookId, options) {
|
|
149643
|
+
return this.storage.listDeliveries(webhookId, options);
|
|
149644
|
+
}
|
|
149645
|
+
async getPendingForInjection() {
|
|
149646
|
+
const injectionConfig = this.config.injection || {};
|
|
149647
|
+
if (injectionConfig.enabled === false) {
|
|
149648
|
+
return [];
|
|
149649
|
+
}
|
|
149650
|
+
const maxPerTurn = injectionConfig.maxPerTurn || 5;
|
|
149651
|
+
const webhooks = await this.storage.listRegistrations();
|
|
149652
|
+
const allPending = [];
|
|
149653
|
+
for (const webhook of webhooks) {
|
|
149654
|
+
if (webhook.status !== "active")
|
|
149655
|
+
continue;
|
|
149656
|
+
const pendingItems = await this.storage.listEvents(webhook.id, { pendingOnly: true });
|
|
149657
|
+
for (const item of pendingItems) {
|
|
149658
|
+
const event = await this.storage.loadEvent(webhook.id, item.id);
|
|
149659
|
+
if (event && event.status === "pending") {
|
|
149660
|
+
allPending.push(event);
|
|
149661
|
+
}
|
|
149662
|
+
}
|
|
149663
|
+
}
|
|
149664
|
+
allPending.sort((a5, b8) => new Date(a5.timestamp).getTime() - new Date(b8.timestamp).getTime());
|
|
149665
|
+
return allPending.slice(0, maxPerTurn);
|
|
149666
|
+
}
|
|
149667
|
+
async markInjected(events) {
|
|
149668
|
+
const now2 = new Date().toISOString();
|
|
149669
|
+
for (const { webhookId, eventId } of events) {
|
|
149670
|
+
await this.storage.updateEventStatus(webhookId, eventId, "injected", now2);
|
|
149671
|
+
}
|
|
149672
|
+
}
|
|
149673
|
+
buildInjectionContext(events) {
|
|
149674
|
+
if (events.length === 0) {
|
|
149675
|
+
return "";
|
|
149676
|
+
}
|
|
149677
|
+
const lines = [];
|
|
149678
|
+
lines.push("## Pending Webhook Events");
|
|
149679
|
+
lines.push("");
|
|
149680
|
+
lines.push(`You have ${events.length} pending webhook event(s):`);
|
|
149681
|
+
for (const evt of events) {
|
|
149682
|
+
lines.push("");
|
|
149683
|
+
lines.push(`### ${evt.source}: ${evt.eventType}`);
|
|
149684
|
+
lines.push(`**Webhook:** ${evt.webhookId} | **Received:** ${formatDate2(evt.timestamp)}`);
|
|
149685
|
+
lines.push("");
|
|
149686
|
+
lines.push("```json");
|
|
149687
|
+
lines.push(JSON.stringify(evt.payload, null, 2));
|
|
149688
|
+
lines.push("```");
|
|
149689
|
+
lines.push(`*Event ID: ${evt.id}*`);
|
|
149690
|
+
lines.push("---");
|
|
149691
|
+
}
|
|
149692
|
+
lines.push("");
|
|
149693
|
+
lines.push("Process these events as appropriate. Use webhook tools to manage webhooks.");
|
|
149694
|
+
return lines.join(`
|
|
149695
|
+
`);
|
|
149696
|
+
}
|
|
149697
|
+
startWatching() {
|
|
149698
|
+
if (this.watcher)
|
|
149699
|
+
return;
|
|
149700
|
+
this.watcher = new WebhookEventWatcher(this.config.storage?.basePath);
|
|
149701
|
+
this.watcher.onNewEvent(async (webhookId, eventId) => {
|
|
149702
|
+
try {
|
|
149703
|
+
const event = await this.storage.loadEvent(webhookId, eventId);
|
|
149704
|
+
if (event) {
|
|
149705
|
+
for (const cb2 of this.eventCallbacks) {
|
|
149706
|
+
try {
|
|
149707
|
+
cb2(event);
|
|
149708
|
+
} catch {}
|
|
149709
|
+
}
|
|
149710
|
+
}
|
|
149711
|
+
} catch {}
|
|
149712
|
+
});
|
|
149713
|
+
this.watcher.start();
|
|
149714
|
+
}
|
|
149715
|
+
stopWatching() {
|
|
149716
|
+
if (this.watcher) {
|
|
149717
|
+
this.watcher.stop();
|
|
149718
|
+
this.watcher = null;
|
|
149719
|
+
}
|
|
149720
|
+
this.eventCallbacks.clear();
|
|
149721
|
+
}
|
|
149722
|
+
onEvent(callback) {
|
|
149723
|
+
this.eventCallbacks.add(callback);
|
|
149724
|
+
return () => {
|
|
149725
|
+
this.eventCallbacks.delete(callback);
|
|
149726
|
+
};
|
|
149727
|
+
}
|
|
149728
|
+
isWatching() {
|
|
149729
|
+
return this.watcher?.isRunning() ?? false;
|
|
149730
|
+
}
|
|
149731
|
+
checkRateLimit(webhookId) {
|
|
149732
|
+
const maxPerMinute = this.config.security?.rateLimitPerMinute || 60;
|
|
149733
|
+
const now2 = Date.now();
|
|
149734
|
+
const windowMs = 60000;
|
|
149735
|
+
let entry = this.rateLimits.get(webhookId);
|
|
149736
|
+
if (!entry || now2 - entry.windowStart >= windowMs) {
|
|
149737
|
+
entry = { count: 0, windowStart: now2 };
|
|
149738
|
+
this.rateLimits.set(webhookId, entry);
|
|
149739
|
+
}
|
|
149740
|
+
entry.count++;
|
|
149741
|
+
return entry.count <= maxPerMinute;
|
|
149742
|
+
}
|
|
149743
|
+
async cleanup() {
|
|
149744
|
+
const maxAgeDays = this.config.storage?.maxAgeDays || 30;
|
|
149745
|
+
const maxEvents = this.config.storage?.maxEvents || 1000;
|
|
149746
|
+
const webhooks = await this.storage.listRegistrations();
|
|
149747
|
+
let totalDeleted = 0;
|
|
149748
|
+
for (const webhook of webhooks) {
|
|
149749
|
+
totalDeleted += await this.storage.cleanupEvents(webhook.id, maxAgeDays);
|
|
149750
|
+
totalDeleted += await this.storage.enforceMaxEvents(webhook.id, maxEvents);
|
|
149751
|
+
}
|
|
149752
|
+
return totalDeleted;
|
|
149753
|
+
}
|
|
149754
|
+
}
|
|
149755
|
+
function formatDate2(isoDate) {
|
|
149756
|
+
const date = new Date(isoDate);
|
|
149757
|
+
return date.toLocaleString();
|
|
149758
|
+
}
|
|
149759
|
+
function createWebhooksManager(assistantId, config) {
|
|
149760
|
+
return new WebhooksManager({
|
|
149761
|
+
assistantId,
|
|
149762
|
+
config
|
|
149763
|
+
});
|
|
149764
|
+
}
|
|
149765
|
+
|
|
149766
|
+
// ../core/src/webhooks/index.ts
|
|
149767
|
+
init_crypto();
|
|
149768
|
+
|
|
149769
|
+
// ../core/src/webhooks/tools.ts
|
|
149770
|
+
var webhookCreateTool = {
|
|
149771
|
+
name: "webhook_create",
|
|
149772
|
+
description: "Create a new webhook endpoint. Returns the URL and secret needed for the external source to send events. The secret is used for HMAC-SHA256 signature verification.",
|
|
149773
|
+
parameters: {
|
|
149774
|
+
type: "object",
|
|
149775
|
+
properties: {
|
|
149776
|
+
name: {
|
|
149777
|
+
type: "string",
|
|
149778
|
+
description: 'Human-readable name for the webhook (e.g., "Gmail notifications")'
|
|
149779
|
+
},
|
|
149780
|
+
source: {
|
|
149781
|
+
type: "string",
|
|
149782
|
+
description: 'Source identifier (e.g., "gmail", "notion", "github", "custom")'
|
|
149783
|
+
},
|
|
149784
|
+
description: {
|
|
149785
|
+
type: "string",
|
|
149786
|
+
description: "Description of what this webhook handles (optional)"
|
|
149787
|
+
},
|
|
149788
|
+
eventsFilter: {
|
|
149789
|
+
type: "array",
|
|
149790
|
+
description: 'Event types to accept (optional, empty = accept all). Example: ["message.received", "issue.opened"]',
|
|
149791
|
+
items: { type: "string", description: "Event type name" }
|
|
149792
|
+
}
|
|
149793
|
+
},
|
|
149794
|
+
required: ["name", "source"]
|
|
149795
|
+
}
|
|
149796
|
+
};
|
|
149797
|
+
var webhookListTool = {
|
|
149798
|
+
name: "webhook_list",
|
|
149799
|
+
description: "List all registered webhooks with their status, source, and delivery counts.",
|
|
149800
|
+
parameters: {
|
|
149801
|
+
type: "object",
|
|
149802
|
+
properties: {},
|
|
149803
|
+
required: []
|
|
149804
|
+
}
|
|
149805
|
+
};
|
|
149806
|
+
var webhookGetTool = {
|
|
149807
|
+
name: "webhook_get",
|
|
149808
|
+
description: "Get full details of a webhook including its secret, URL, events filter, and delivery count.",
|
|
149809
|
+
parameters: {
|
|
149810
|
+
type: "object",
|
|
149811
|
+
properties: {
|
|
149812
|
+
id: {
|
|
149813
|
+
type: "string",
|
|
149814
|
+
description: "The webhook ID (e.g., whk_abc123)"
|
|
149815
|
+
}
|
|
149816
|
+
},
|
|
149817
|
+
required: ["id"]
|
|
149818
|
+
}
|
|
149819
|
+
};
|
|
149820
|
+
var webhookUpdateTool = {
|
|
149821
|
+
name: "webhook_update",
|
|
149822
|
+
description: "Update a webhook registration. Can change name, description, events filter, or status (active/paused).",
|
|
149823
|
+
parameters: {
|
|
149824
|
+
type: "object",
|
|
149825
|
+
properties: {
|
|
149826
|
+
id: {
|
|
149827
|
+
type: "string",
|
|
149828
|
+
description: "The webhook ID to update"
|
|
149829
|
+
},
|
|
149830
|
+
name: {
|
|
149831
|
+
type: "string",
|
|
149832
|
+
description: "New name (optional)"
|
|
149833
|
+
},
|
|
149834
|
+
description: {
|
|
149835
|
+
type: "string",
|
|
149836
|
+
description: "New description (optional)"
|
|
149837
|
+
},
|
|
149838
|
+
eventsFilter: {
|
|
149839
|
+
type: "array",
|
|
149840
|
+
description: "New events filter (optional)",
|
|
149841
|
+
items: { type: "string", description: "Event type name" }
|
|
149842
|
+
},
|
|
149843
|
+
status: {
|
|
149844
|
+
type: "string",
|
|
149845
|
+
description: "New status: active or paused (optional)",
|
|
149846
|
+
enum: ["active", "paused"]
|
|
149847
|
+
}
|
|
149848
|
+
},
|
|
149849
|
+
required: ["id"]
|
|
149850
|
+
}
|
|
149851
|
+
};
|
|
149852
|
+
var webhookDeleteTool = {
|
|
149853
|
+
name: "webhook_delete",
|
|
149854
|
+
description: "Delete a webhook registration and all its event history.",
|
|
149855
|
+
parameters: {
|
|
149856
|
+
type: "object",
|
|
149857
|
+
properties: {
|
|
149858
|
+
id: {
|
|
149859
|
+
type: "string",
|
|
149860
|
+
description: "The webhook ID to delete"
|
|
149861
|
+
}
|
|
149862
|
+
},
|
|
149863
|
+
required: ["id"]
|
|
149864
|
+
}
|
|
149865
|
+
};
|
|
149866
|
+
var webhookEventsTool = {
|
|
149867
|
+
name: "webhook_events",
|
|
149868
|
+
description: "List recent events received by a webhook. Shows event type, payload preview, and status.",
|
|
149869
|
+
parameters: {
|
|
149870
|
+
type: "object",
|
|
149871
|
+
properties: {
|
|
149872
|
+
webhookId: {
|
|
149873
|
+
type: "string",
|
|
149874
|
+
description: "The webhook ID to list events for"
|
|
149875
|
+
},
|
|
149876
|
+
limit: {
|
|
149877
|
+
type: "number",
|
|
149878
|
+
description: "Maximum number of events to return (default: 20)"
|
|
149879
|
+
},
|
|
149880
|
+
pendingOnly: {
|
|
149881
|
+
type: "boolean",
|
|
149882
|
+
description: "Only show pending (unprocessed) events (default: false)"
|
|
149883
|
+
}
|
|
149884
|
+
},
|
|
149885
|
+
required: ["webhookId"]
|
|
149886
|
+
}
|
|
149887
|
+
};
|
|
149888
|
+
var webhookTestTool = {
|
|
149889
|
+
name: "webhook_test",
|
|
149890
|
+
description: "Send a test event to a webhook to verify it is working correctly.",
|
|
149891
|
+
parameters: {
|
|
149892
|
+
type: "object",
|
|
149893
|
+
properties: {
|
|
149894
|
+
id: {
|
|
149895
|
+
type: "string",
|
|
149896
|
+
description: "The webhook ID to send a test event to"
|
|
149897
|
+
}
|
|
149898
|
+
},
|
|
149899
|
+
required: ["id"]
|
|
149900
|
+
}
|
|
149901
|
+
};
|
|
149902
|
+
function createWebhookToolExecutors(getWebhooksManager) {
|
|
149903
|
+
return {
|
|
149904
|
+
webhook_create: async (input) => {
|
|
149905
|
+
const manager = getWebhooksManager();
|
|
149906
|
+
if (!manager) {
|
|
149907
|
+
return "Error: Webhooks are not enabled or configured. Set webhooks.enabled: true in config.";
|
|
149908
|
+
}
|
|
149909
|
+
const name2 = String(input.name || "").trim();
|
|
149910
|
+
const source = String(input.source || "").trim();
|
|
149911
|
+
const description = input.description ? String(input.description).trim() : undefined;
|
|
149912
|
+
const eventsFilter = Array.isArray(input.eventsFilter) ? input.eventsFilter.map(String) : undefined;
|
|
149913
|
+
if (!name2)
|
|
149914
|
+
return "Error: Webhook name is required.";
|
|
149915
|
+
if (!source)
|
|
149916
|
+
return "Error: Source identifier is required.";
|
|
149917
|
+
const result = await manager.create({ name: name2, source, description, eventsFilter });
|
|
149918
|
+
if (result.success) {
|
|
149919
|
+
const lines = [];
|
|
149920
|
+
lines.push(`Webhook created successfully!`);
|
|
149921
|
+
lines.push("");
|
|
149922
|
+
lines.push(`**ID:** ${result.webhookId}`);
|
|
149923
|
+
lines.push(`**URL:** ${result.url}`);
|
|
149924
|
+
lines.push(`**Secret:** ${result.secret}`);
|
|
149925
|
+
lines.push("");
|
|
149926
|
+
lines.push("**Setup instructions for the external source:**");
|
|
149927
|
+
lines.push(`1. Set webhook URL to: \`<your-base-url>${result.url}\``);
|
|
149928
|
+
lines.push(`2. Set signing secret to: \`${result.secret}\``);
|
|
149929
|
+
lines.push("3. Include these headers with each POST:");
|
|
149930
|
+
lines.push(" - `X-Webhook-Signature`: HMAC-SHA256 hex digest of the JSON body");
|
|
149931
|
+
lines.push(" - `X-Webhook-Timestamp`: ISO 8601 timestamp");
|
|
149932
|
+
lines.push(" - `X-Webhook-Event`: Event type name");
|
|
149933
|
+
return lines.join(`
|
|
149934
|
+
`);
|
|
149935
|
+
}
|
|
149936
|
+
return `Error: ${result.message}`;
|
|
149937
|
+
},
|
|
149938
|
+
webhook_list: async () => {
|
|
149939
|
+
const manager = getWebhooksManager();
|
|
149940
|
+
if (!manager) {
|
|
149941
|
+
return "Error: Webhooks are not enabled or configured.";
|
|
149942
|
+
}
|
|
149943
|
+
try {
|
|
149944
|
+
const webhooks = await manager.list();
|
|
149945
|
+
if (webhooks.length === 0) {
|
|
149946
|
+
return "No webhooks registered. Use webhook_create to create one.";
|
|
149947
|
+
}
|
|
149948
|
+
const lines = [];
|
|
149949
|
+
lines.push(`## Webhooks (${webhooks.length})`);
|
|
149950
|
+
lines.push("");
|
|
149951
|
+
for (const wh of webhooks) {
|
|
149952
|
+
const statusIcon = wh.status === "active" ? "\u25CF" : wh.status === "paused" ? "\u25D0" : "\u2717";
|
|
149953
|
+
const statusColor = wh.status === "active" ? "" : ` [${wh.status}]`;
|
|
149954
|
+
const lastDelivery = wh.lastDeliveryAt ? new Date(wh.lastDeliveryAt).toLocaleDateString() : "never";
|
|
149955
|
+
lines.push(`${statusIcon} **${wh.name}** (${wh.id})${statusColor}`);
|
|
149956
|
+
lines.push(` Source: ${wh.source} | Events: ${wh.deliveryCount} | Last: ${lastDelivery}`);
|
|
149957
|
+
lines.push("");
|
|
149958
|
+
}
|
|
149959
|
+
return lines.join(`
|
|
149960
|
+
`);
|
|
149961
|
+
} catch (error2) {
|
|
149962
|
+
return `Error listing webhooks: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
149963
|
+
}
|
|
149964
|
+
},
|
|
149965
|
+
webhook_get: async (input) => {
|
|
149966
|
+
const manager = getWebhooksManager();
|
|
149967
|
+
if (!manager) {
|
|
149968
|
+
return "Error: Webhooks are not enabled or configured.";
|
|
149969
|
+
}
|
|
149970
|
+
const id = String(input.id || "").trim();
|
|
149971
|
+
if (!id)
|
|
149972
|
+
return "Error: Webhook ID is required.";
|
|
149973
|
+
try {
|
|
149974
|
+
const webhook = await manager.get(id);
|
|
149975
|
+
if (!webhook) {
|
|
149976
|
+
return `Webhook ${id} not found.`;
|
|
149977
|
+
}
|
|
149978
|
+
const lines = [];
|
|
149979
|
+
lines.push(`## Webhook: ${webhook.name}`);
|
|
149980
|
+
lines.push("");
|
|
149981
|
+
lines.push(`**ID:** ${webhook.id}`);
|
|
149982
|
+
lines.push(`**Source:** ${webhook.source}`);
|
|
149983
|
+
lines.push(`**Status:** ${webhook.status}`);
|
|
149984
|
+
if (webhook.description) {
|
|
149985
|
+
lines.push(`**Description:** ${webhook.description}`);
|
|
149986
|
+
}
|
|
149987
|
+
lines.push(`**Secret:** ${webhook.secret}`);
|
|
149988
|
+
lines.push(`**URL:** /api/v1/webhooks/receive/${webhook.id}`);
|
|
149989
|
+
lines.push(`**Events Filter:** ${webhook.eventsFilter.length > 0 ? webhook.eventsFilter.join(", ") : "all"}`);
|
|
149990
|
+
lines.push(`**Deliveries:** ${webhook.deliveryCount}`);
|
|
149991
|
+
lines.push(`**Created:** ${new Date(webhook.createdAt).toLocaleString()}`);
|
|
149992
|
+
if (webhook.lastDeliveryAt) {
|
|
149993
|
+
lines.push(`**Last Delivery:** ${new Date(webhook.lastDeliveryAt).toLocaleString()}`);
|
|
149994
|
+
}
|
|
149995
|
+
return lines.join(`
|
|
149996
|
+
`);
|
|
149997
|
+
} catch (error2) {
|
|
149998
|
+
return `Error getting webhook: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
149999
|
+
}
|
|
150000
|
+
},
|
|
150001
|
+
webhook_update: async (input) => {
|
|
150002
|
+
const manager = getWebhooksManager();
|
|
150003
|
+
if (!manager) {
|
|
150004
|
+
return "Error: Webhooks are not enabled or configured.";
|
|
150005
|
+
}
|
|
150006
|
+
const id = String(input.id || "").trim();
|
|
150007
|
+
if (!id)
|
|
150008
|
+
return "Error: Webhook ID is required.";
|
|
150009
|
+
const name2 = input.name ? String(input.name).trim() : undefined;
|
|
150010
|
+
const description = input.description ? String(input.description).trim() : undefined;
|
|
150011
|
+
const eventsFilter = Array.isArray(input.eventsFilter) ? input.eventsFilter.map(String) : undefined;
|
|
150012
|
+
const status = input.status;
|
|
150013
|
+
const result = await manager.update({ id, name: name2, description, eventsFilter, status });
|
|
150014
|
+
return result.message;
|
|
150015
|
+
},
|
|
150016
|
+
webhook_delete: async (input) => {
|
|
150017
|
+
const manager = getWebhooksManager();
|
|
150018
|
+
if (!manager) {
|
|
150019
|
+
return "Error: Webhooks are not enabled or configured.";
|
|
150020
|
+
}
|
|
150021
|
+
const id = String(input.id || "").trim();
|
|
150022
|
+
if (!id)
|
|
150023
|
+
return "Error: Webhook ID is required.";
|
|
150024
|
+
const result = await manager.delete(id);
|
|
150025
|
+
return result.message;
|
|
150026
|
+
},
|
|
150027
|
+
webhook_events: async (input) => {
|
|
150028
|
+
const manager = getWebhooksManager();
|
|
150029
|
+
if (!manager) {
|
|
150030
|
+
return "Error: Webhooks are not enabled or configured.";
|
|
150031
|
+
}
|
|
150032
|
+
const webhookId = String(input.webhookId || "").trim();
|
|
150033
|
+
if (!webhookId)
|
|
150034
|
+
return "Error: Webhook ID is required.";
|
|
150035
|
+
const limit2 = typeof input.limit === "number" ? input.limit : 20;
|
|
150036
|
+
const pendingOnly = input.pendingOnly === true;
|
|
150037
|
+
try {
|
|
150038
|
+
const events = await manager.listEvents(webhookId, { limit: limit2, pendingOnly });
|
|
150039
|
+
if (events.length === 0) {
|
|
150040
|
+
return pendingOnly ? "No pending events for this webhook." : "No events received for this webhook.";
|
|
150041
|
+
}
|
|
150042
|
+
const lines = [];
|
|
150043
|
+
lines.push(`## Events for ${webhookId} (${events.length})`);
|
|
150044
|
+
lines.push("");
|
|
150045
|
+
for (const evt of events) {
|
|
150046
|
+
const statusIcon = evt.status === "pending" ? "\u23F3" : evt.status === "injected" ? "\uD83D\uDCE8" : evt.status === "processed" ? "\u2713" : "\u2717";
|
|
150047
|
+
const date = new Date(evt.timestamp).toLocaleString();
|
|
150048
|
+
lines.push(`${statusIcon} **${evt.eventType}** (${evt.id})`);
|
|
150049
|
+
lines.push(` Source: ${evt.source} | Status: ${evt.status} | ${date}`);
|
|
150050
|
+
lines.push(` Preview: ${evt.preview}`);
|
|
150051
|
+
lines.push("");
|
|
150052
|
+
}
|
|
150053
|
+
return lines.join(`
|
|
150054
|
+
`);
|
|
150055
|
+
} catch (error2) {
|
|
150056
|
+
return `Error listing events: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
150057
|
+
}
|
|
150058
|
+
},
|
|
150059
|
+
webhook_test: async (input) => {
|
|
150060
|
+
const manager = getWebhooksManager();
|
|
150061
|
+
if (!manager) {
|
|
150062
|
+
return "Error: Webhooks are not enabled or configured.";
|
|
150063
|
+
}
|
|
150064
|
+
const id = String(input.id || "").trim();
|
|
150065
|
+
if (!id)
|
|
150066
|
+
return "Error: Webhook ID is required.";
|
|
150067
|
+
const result = await manager.sendTestEvent(id);
|
|
150068
|
+
if (result.success) {
|
|
150069
|
+
return `Test event sent successfully! Event ID: ${result.eventId}, Delivery ID: ${result.deliveryId}`;
|
|
150070
|
+
}
|
|
150071
|
+
return `Error: ${result.message}`;
|
|
150072
|
+
}
|
|
150073
|
+
};
|
|
150074
|
+
}
|
|
150075
|
+
var webhookTools = [
|
|
150076
|
+
webhookCreateTool,
|
|
150077
|
+
webhookListTool,
|
|
150078
|
+
webhookGetTool,
|
|
150079
|
+
webhookUpdateTool,
|
|
150080
|
+
webhookDeleteTool,
|
|
150081
|
+
webhookEventsTool,
|
|
150082
|
+
webhookTestTool
|
|
150083
|
+
];
|
|
150084
|
+
function registerWebhookTools(registry2, getWebhooksManager) {
|
|
150085
|
+
const executors = createWebhookToolExecutors(getWebhooksManager);
|
|
150086
|
+
for (const tool of webhookTools) {
|
|
150087
|
+
registry2.register(tool, executors[tool.name]);
|
|
150088
|
+
}
|
|
150089
|
+
}
|
|
150090
|
+
// ../core/src/sessions/store.ts
|
|
150091
|
+
import { join as join43 } from "path";
|
|
150092
|
+
import { homedir as homedir21 } from "os";
|
|
150093
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync16, writeFileSync as writeFileSync14, readFileSync as readFileSync17, readdirSync as readdirSync9, unlinkSync as unlinkSync5 } from "fs";
|
|
148291
150094
|
|
|
148292
150095
|
class SessionStore {
|
|
148293
150096
|
basePath;
|
|
148294
150097
|
constructor(basePath) {
|
|
148295
|
-
const envHome = process.env.HOME || process.env.USERPROFILE ||
|
|
148296
|
-
this.basePath = basePath ||
|
|
150098
|
+
const envHome = process.env.HOME || process.env.USERPROFILE || homedir21();
|
|
150099
|
+
this.basePath = basePath || join43(envHome, ".assistants", "sessions");
|
|
148297
150100
|
this.ensureDir();
|
|
148298
150101
|
}
|
|
148299
150102
|
ensureDir() {
|
|
148300
|
-
if (!
|
|
148301
|
-
|
|
150103
|
+
if (!existsSync26(this.basePath)) {
|
|
150104
|
+
mkdirSync16(this.basePath, { recursive: true });
|
|
148302
150105
|
}
|
|
148303
150106
|
}
|
|
148304
150107
|
getSessionPath(id) {
|
|
148305
|
-
return
|
|
150108
|
+
return join43(this.basePath, `${id}.json`);
|
|
148306
150109
|
}
|
|
148307
150110
|
save(data) {
|
|
148308
150111
|
try {
|
|
@@ -148313,7 +150116,7 @@ class SessionStore {
|
|
|
148313
150116
|
load(id) {
|
|
148314
150117
|
try {
|
|
148315
150118
|
const filePath = this.getSessionPath(id);
|
|
148316
|
-
if (!
|
|
150119
|
+
if (!existsSync26(filePath))
|
|
148317
150120
|
return null;
|
|
148318
150121
|
return JSON.parse(readFileSync17(filePath, "utf-8"));
|
|
148319
150122
|
} catch {
|
|
@@ -148323,11 +150126,11 @@ class SessionStore {
|
|
|
148323
150126
|
list() {
|
|
148324
150127
|
try {
|
|
148325
150128
|
this.ensureDir();
|
|
148326
|
-
const files =
|
|
150129
|
+
const files = readdirSync9(this.basePath).filter((f6) => f6.endsWith(".json"));
|
|
148327
150130
|
const sessions = [];
|
|
148328
150131
|
for (const file of files) {
|
|
148329
150132
|
try {
|
|
148330
|
-
const data = JSON.parse(readFileSync17(
|
|
150133
|
+
const data = JSON.parse(readFileSync17(join43(this.basePath, file), "utf-8"));
|
|
148331
150134
|
sessions.push(data);
|
|
148332
150135
|
} catch {}
|
|
148333
150136
|
}
|
|
@@ -148339,7 +150142,7 @@ class SessionStore {
|
|
|
148339
150142
|
delete(id) {
|
|
148340
150143
|
try {
|
|
148341
150144
|
const filePath = this.getSessionPath(id);
|
|
148342
|
-
if (
|
|
150145
|
+
if (existsSync26(filePath)) {
|
|
148343
150146
|
unlinkSync5(filePath);
|
|
148344
150147
|
}
|
|
148345
150148
|
} catch {}
|
|
@@ -148387,6 +150190,7 @@ class EmbeddedClient {
|
|
|
148387
150190
|
this.assistantLoop = createAssistant({
|
|
148388
150191
|
cwd: this.cwd,
|
|
148389
150192
|
sessionId,
|
|
150193
|
+
assistantId: options?.assistantId,
|
|
148390
150194
|
allowedTools: options?.allowedTools,
|
|
148391
150195
|
extraSystemPrompt: options?.systemPrompt,
|
|
148392
150196
|
model: options?.model,
|
|
@@ -148637,6 +150441,12 @@ class EmbeddedClient {
|
|
|
148637
150441
|
}
|
|
148638
150442
|
return null;
|
|
148639
150443
|
}
|
|
150444
|
+
getWebhooksManager() {
|
|
150445
|
+
if (typeof this.assistantLoop.getWebhooksManager === "function") {
|
|
150446
|
+
return this.assistantLoop.getWebhooksManager();
|
|
150447
|
+
}
|
|
150448
|
+
return null;
|
|
150449
|
+
}
|
|
148640
150450
|
getWalletManager() {
|
|
148641
150451
|
if (typeof this.assistantLoop.getWalletManager === "function") {
|
|
148642
150452
|
return this.assistantLoop.getWalletManager();
|
|
@@ -148748,17 +150558,25 @@ class SessionRegistry {
|
|
|
148748
150558
|
maxBufferedChunks = 2000;
|
|
148749
150559
|
store;
|
|
148750
150560
|
constructor(clientFactory) {
|
|
148751
|
-
this.clientFactory = clientFactory ?? ((cwd) => new EmbeddedClient(cwd));
|
|
150561
|
+
this.clientFactory = clientFactory ?? ((cwd, options) => new EmbeddedClient(cwd, options));
|
|
148752
150562
|
this.store = new SessionStore;
|
|
148753
150563
|
}
|
|
148754
150564
|
async createSession(cwdOrOptions) {
|
|
148755
150565
|
const options = typeof cwdOrOptions === "string" ? { cwd: cwdOrOptions } : cwdOrOptions;
|
|
148756
|
-
const
|
|
150566
|
+
const clientOptions = {
|
|
150567
|
+
sessionId: options.sessionId,
|
|
150568
|
+
initialMessages: options.initialMessages,
|
|
150569
|
+
startedAt: options.startedAt,
|
|
150570
|
+
assistantId: options.assistantId
|
|
150571
|
+
};
|
|
150572
|
+
const client = this.clientFactory(options.cwd, clientOptions);
|
|
148757
150573
|
await client.initialize();
|
|
150574
|
+
const parsedStartedAt = options.startedAt ? new Date(options.startedAt).getTime() : Date.now();
|
|
150575
|
+
const startedAt = Number.isNaN(parsedStartedAt) ? Date.now() : parsedStartedAt;
|
|
148758
150576
|
const sessionInfo = {
|
|
148759
150577
|
id: client.getSessionId(),
|
|
148760
150578
|
cwd: options.cwd,
|
|
148761
|
-
startedAt
|
|
150579
|
+
startedAt,
|
|
148762
150580
|
updatedAt: Date.now(),
|
|
148763
150581
|
isProcessing: false,
|
|
148764
150582
|
client,
|
|
@@ -150497,9 +152315,9 @@ function createSelfAwarenessToolExecutors(context) {
|
|
|
150497
152315
|
return JSON.stringify(response, null, 2);
|
|
150498
152316
|
},
|
|
150499
152317
|
workspace_map: async (input) => {
|
|
150500
|
-
const { readdir:
|
|
152318
|
+
const { readdir: readdir7, stat: stat5, access } = await import("fs/promises");
|
|
150501
152319
|
const { execSync } = await import("child_process");
|
|
150502
|
-
const { join:
|
|
152320
|
+
const { join: join44, basename: basename6 } = await import("path");
|
|
150503
152321
|
const depth = input.depth ?? 3;
|
|
150504
152322
|
const includeGitStatus = input.include_git_status !== false;
|
|
150505
152323
|
const includeRecentFiles = input.include_recent_files !== false;
|
|
@@ -150534,7 +152352,7 @@ function createSelfAwarenessToolExecutors(context) {
|
|
|
150534
152352
|
if (currentDepth > depth)
|
|
150535
152353
|
return [];
|
|
150536
152354
|
try {
|
|
150537
|
-
const entries = await
|
|
152355
|
+
const entries = await readdir7(dir, { withFileTypes: true });
|
|
150538
152356
|
const nodes = [];
|
|
150539
152357
|
let fileCount = 0;
|
|
150540
152358
|
for (const entry of entries) {
|
|
@@ -150545,7 +152363,7 @@ function createSelfAwarenessToolExecutors(context) {
|
|
|
150545
152363
|
break;
|
|
150546
152364
|
}
|
|
150547
152365
|
if (entry.isDirectory()) {
|
|
150548
|
-
const children = await buildTree(
|
|
152366
|
+
const children = await buildTree(join44(dir, entry.name), currentDepth + 1);
|
|
150549
152367
|
nodes.push({
|
|
150550
152368
|
name: entry.name,
|
|
150551
152369
|
type: "directory",
|
|
@@ -150571,7 +152389,7 @@ function createSelfAwarenessToolExecutors(context) {
|
|
|
150571
152389
|
};
|
|
150572
152390
|
if (includeGitStatus) {
|
|
150573
152391
|
try {
|
|
150574
|
-
await access(
|
|
152392
|
+
await access(join44(cwd, ".git"));
|
|
150575
152393
|
gitStatus.isRepo = true;
|
|
150576
152394
|
try {
|
|
150577
152395
|
const branch = execSync("git branch --show-current", { cwd, encoding: "utf-8" }).trim();
|
|
@@ -150598,11 +152416,11 @@ function createSelfAwarenessToolExecutors(context) {
|
|
|
150598
152416
|
if (recentFiles.length >= 10)
|
|
150599
152417
|
return;
|
|
150600
152418
|
try {
|
|
150601
|
-
const entries = await
|
|
152419
|
+
const entries = await readdir7(dir, { withFileTypes: true });
|
|
150602
152420
|
for (const entry of entries) {
|
|
150603
152421
|
if (shouldIgnore(entry.name))
|
|
150604
152422
|
continue;
|
|
150605
|
-
const fullPath =
|
|
152423
|
+
const fullPath = join44(dir, entry.name);
|
|
150606
152424
|
const relPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
150607
152425
|
if (entry.isFile()) {
|
|
150608
152426
|
try {
|
|
@@ -150636,12 +152454,12 @@ function createSelfAwarenessToolExecutors(context) {
|
|
|
150636
152454
|
let projectName = basename6(cwd);
|
|
150637
152455
|
for (const indicator of projectIndicators) {
|
|
150638
152456
|
try {
|
|
150639
|
-
await access(
|
|
152457
|
+
await access(join44(cwd, indicator.file));
|
|
150640
152458
|
projectType = indicator.type;
|
|
150641
152459
|
if (indicator.file === "package.json") {
|
|
150642
152460
|
try {
|
|
150643
|
-
const { readFile:
|
|
150644
|
-
const pkg = JSON.parse(await
|
|
152461
|
+
const { readFile: readFile16 } = await import("fs/promises");
|
|
152462
|
+
const pkg = JSON.parse(await readFile16(join44(cwd, indicator.file), "utf-8"));
|
|
150645
152463
|
projectName = pkg.name || projectName;
|
|
150646
152464
|
} catch {}
|
|
150647
152465
|
}
|
|
@@ -153203,8 +155021,8 @@ await __promiseAll([
|
|
|
153203
155021
|
init_config(),
|
|
153204
155022
|
init_runtime()
|
|
153205
155023
|
]);
|
|
153206
|
-
import { join as
|
|
153207
|
-
import { existsSync as
|
|
155024
|
+
import { join as join44, dirname as dirname18 } from "path";
|
|
155025
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync17 } from "fs";
|
|
153208
155026
|
var MAX_KEY_LENGTH2 = 256;
|
|
153209
155027
|
var MAX_VALUE_SIZE = 65536;
|
|
153210
155028
|
var MAX_SUMMARY_LENGTH2 = 500;
|
|
@@ -153217,10 +155035,10 @@ class GlobalMemoryManager {
|
|
|
153217
155035
|
config;
|
|
153218
155036
|
constructor(options = {}) {
|
|
153219
155037
|
const baseDir = getConfigDir();
|
|
153220
|
-
const path2 = options.dbPath ||
|
|
153221
|
-
const dir =
|
|
153222
|
-
if (!
|
|
153223
|
-
|
|
155038
|
+
const path2 = options.dbPath || join44(baseDir, "memory.db");
|
|
155039
|
+
const dir = dirname18(path2);
|
|
155040
|
+
if (!existsSync27(dir)) {
|
|
155041
|
+
mkdirSync17(dir, { recursive: true });
|
|
153224
155042
|
}
|
|
153225
155043
|
const runtime = getRuntime();
|
|
153226
155044
|
this.db = runtime.openDatabase(path2);
|
|
@@ -154623,9 +156441,9 @@ function createCapabilityChain(scope, capabilities) {
|
|
|
154623
156441
|
};
|
|
154624
156442
|
}
|
|
154625
156443
|
// ../core/src/capabilities/storage.ts
|
|
154626
|
-
import { existsSync as
|
|
154627
|
-
import { join as
|
|
154628
|
-
import { homedir as
|
|
156444
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync18, readFileSync as readFileSync18, writeFileSync as writeFileSync15 } from "fs";
|
|
156445
|
+
import { join as join45, dirname as dirname19 } from "path";
|
|
156446
|
+
import { homedir as homedir22 } from "os";
|
|
154629
156447
|
var DEFAULT_STORAGE_CONFIG = {
|
|
154630
156448
|
enabled: true,
|
|
154631
156449
|
autoSave: true
|
|
@@ -154644,15 +156462,15 @@ class CapabilityStorage {
|
|
|
154644
156462
|
if (this.config.storagePath) {
|
|
154645
156463
|
return this.config.storagePath;
|
|
154646
156464
|
}
|
|
154647
|
-
const home = process.env.HOME || process.env.USERPROFILE ||
|
|
154648
|
-
return
|
|
156465
|
+
const home = process.env.HOME || process.env.USERPROFILE || homedir22();
|
|
156466
|
+
return join45(home, ".assistants", "capabilities", "store.json");
|
|
154649
156467
|
}
|
|
154650
156468
|
load() {
|
|
154651
156469
|
if (!this.config.enabled)
|
|
154652
156470
|
return;
|
|
154653
156471
|
try {
|
|
154654
156472
|
const path2 = this.getStoragePath();
|
|
154655
|
-
if (!
|
|
156473
|
+
if (!existsSync28(path2))
|
|
154656
156474
|
return;
|
|
154657
156475
|
const data = JSON.parse(readFileSync18(path2, "utf-8"));
|
|
154658
156476
|
if (data.chains) {
|
|
@@ -154672,9 +156490,9 @@ class CapabilityStorage {
|
|
|
154672
156490
|
return;
|
|
154673
156491
|
try {
|
|
154674
156492
|
const path2 = this.getStoragePath();
|
|
154675
|
-
const dir =
|
|
154676
|
-
if (!
|
|
154677
|
-
|
|
156493
|
+
const dir = dirname19(path2);
|
|
156494
|
+
if (!existsSync28(dir)) {
|
|
156495
|
+
mkdirSync18(dir, { recursive: true });
|
|
154678
156496
|
}
|
|
154679
156497
|
const data = {
|
|
154680
156498
|
version: 1,
|
|
@@ -155016,6 +156834,7 @@ class AssistantLoop {
|
|
|
155016
156834
|
heartbeatManager = null;
|
|
155017
156835
|
heartbeatPersistence = null;
|
|
155018
156836
|
heartbeatRecovery = null;
|
|
156837
|
+
heartbeatRuntimeConfig = null;
|
|
155019
156838
|
lastUserMessage = null;
|
|
155020
156839
|
lastToolName = null;
|
|
155021
156840
|
pendingToolCalls = new Map;
|
|
@@ -155057,6 +156876,7 @@ class AssistantLoop {
|
|
|
155057
156876
|
secretsManager = null;
|
|
155058
156877
|
jobManager = null;
|
|
155059
156878
|
messagesManager = null;
|
|
156879
|
+
webhooksManager = null;
|
|
155060
156880
|
memoryManager = null;
|
|
155061
156881
|
memoryInjector = null;
|
|
155062
156882
|
contextInjector = null;
|
|
@@ -155064,6 +156884,7 @@ class AssistantLoop {
|
|
|
155064
156884
|
subassistantManager = null;
|
|
155065
156885
|
depth = 0;
|
|
155066
156886
|
pendingMessagesContext = null;
|
|
156887
|
+
pendingWebhooksContext = null;
|
|
155067
156888
|
pendingMemoryContext = null;
|
|
155068
156889
|
identityContext = null;
|
|
155069
156890
|
projectContext = null;
|
|
@@ -155272,6 +157093,20 @@ class AssistantLoop {
|
|
|
155272
157093
|
}
|
|
155273
157094
|
});
|
|
155274
157095
|
}
|
|
157096
|
+
if (this.config?.webhooks?.enabled) {
|
|
157097
|
+
const assistant = this.assistantManager?.getActive();
|
|
157098
|
+
const assistantId = assistant?.id || this.sessionId;
|
|
157099
|
+
this.webhooksManager = createWebhooksManager(assistantId, this.config.webhooks);
|
|
157100
|
+
await this.webhooksManager.initialize();
|
|
157101
|
+
registerWebhookTools(this.toolRegistry, () => this.webhooksManager);
|
|
157102
|
+
this.webhooksManager.startWatching();
|
|
157103
|
+
this.webhooksManager.onEvent((event) => {
|
|
157104
|
+
const context = this.webhooksManager.buildInjectionContext([event]);
|
|
157105
|
+
if (context) {
|
|
157106
|
+
this.pendingWebhooksContext = context;
|
|
157107
|
+
}
|
|
157108
|
+
});
|
|
157109
|
+
}
|
|
155275
157110
|
const memoryConfig = this.config?.memory;
|
|
155276
157111
|
if (memoryConfig?.enabled !== false) {
|
|
155277
157112
|
const assistant = this.assistantManager?.getActive();
|
|
@@ -155374,6 +157209,11 @@ class AssistantLoop {
|
|
|
155374
157209
|
}
|
|
155375
157210
|
}
|
|
155376
157211
|
});
|
|
157212
|
+
registerHeartbeatTools(this.toolRegistry, {
|
|
157213
|
+
sessionId: this.sessionId,
|
|
157214
|
+
getHeartbeatState: () => this.getHeartbeatState(),
|
|
157215
|
+
getHeartbeatConfig: () => this.heartbeatRuntimeConfig
|
|
157216
|
+
});
|
|
155377
157217
|
registerContextEntryTools(this.toolRegistry, {
|
|
155378
157218
|
cwd: this.cwd,
|
|
155379
157219
|
getActiveProjectId: () => this.activeProjectId,
|
|
@@ -155483,6 +157323,102 @@ class AssistantLoop {
|
|
|
155483
157323
|
if (this.extraSystemPrompt) {
|
|
155484
157324
|
this.context.addSystemMessage(this.extraSystemPrompt);
|
|
155485
157325
|
}
|
|
157326
|
+
if (this.config?.heartbeat?.enabled !== false) {
|
|
157327
|
+
this.context.addSystemMessage(`## Heartbeat Basics
|
|
157328
|
+
- The system can trigger scheduled runs via \`/main-loop\` or \`/watchdog\`.
|
|
157329
|
+
- If invoked with those commands, follow the heartbeat skill instructions.
|
|
157330
|
+
- Heartbeat schedules use the id \`heartbeat-${this.sessionId}\`.`);
|
|
157331
|
+
}
|
|
157332
|
+
if (this.config?.heartbeat?.autonomous) {
|
|
157333
|
+
const maxSleepMin = Math.round((this.config.heartbeat.maxSleepMs ?? 1800000) / 60000);
|
|
157334
|
+
this.context.addSystemMessage(`## Autonomous Heartbeat System
|
|
157335
|
+
|
|
157336
|
+
You are running in **autonomous mode**. You manage your own wakeup schedule.
|
|
157337
|
+
|
|
157338
|
+
### How it works
|
|
157339
|
+
- After every turn, a safety-net hook ensures a heartbeat schedule exists
|
|
157340
|
+
- The heartbeat fires \`/main-loop\` which runs your autonomous check-in skill
|
|
157341
|
+
- A watchdog monitors your health and forces a wakeup if you're overdue
|
|
157342
|
+
|
|
157343
|
+
### Your responsibilities at the END of every turn
|
|
157344
|
+
1. **Save state** to memory before the turn ends:
|
|
157345
|
+
- \`memory_save agent.heartbeat.intention "what you plan to do next"\`
|
|
157346
|
+
- \`memory_save agent.state.pending "items waiting for follow-up"\`
|
|
157347
|
+
- \`memory_save agent.state.lastActions "what you just did"\`
|
|
157348
|
+
2. **Schedule your next heartbeat**:
|
|
157349
|
+
- Delete old: \`schedule_delete heartbeat-${this.sessionId}\`
|
|
157350
|
+
- Create new: \`schedule_create\` with \`kind: "once"\`, \`actionType: "message"\`, \`message: "/main-loop"\`, and \`at\` set to your chosen time
|
|
157351
|
+
3. **Save goals** when they change: \`memory_save agent.goals "..."\`
|
|
157352
|
+
|
|
157353
|
+
### Timing guidelines
|
|
157354
|
+
| Situation | Wake up in |
|
|
157355
|
+
|-----------|-----------|
|
|
157356
|
+
| Active jobs running or tasks pending | 1\u20133 minutes |
|
|
157357
|
+
| Goals exist but nothing urgent | 5\u201315 minutes |
|
|
157358
|
+
| Nothing pending, user idle | 15\u2013${maxSleepMin} minutes (max) |
|
|
157359
|
+
|
|
157360
|
+
### Key memory keys
|
|
157361
|
+
- \`agent.heartbeat.last\` \u2014 when you last ran (save ISO timestamp)
|
|
157362
|
+
- \`agent.heartbeat.next\` \u2014 when you plan to run next
|
|
157363
|
+
- \`agent.heartbeat.intention\` \u2014 why you're waking up
|
|
157364
|
+
- \`agent.goals\` \u2014 your active goals
|
|
157365
|
+
- \`agent.state.pending\` \u2014 items waiting
|
|
157366
|
+
- \`agent.state.lastActions\` \u2014 what you did recently
|
|
157367
|
+
|
|
157368
|
+
### Rules
|
|
157369
|
+
- **Stay fast** \u2014 if work takes >30s, delegate to a subassistant
|
|
157370
|
+
- **Never sleep longer than ${maxSleepMin} minutes** \u2014 the system enforces this cap
|
|
157371
|
+
- **Always schedule your next heartbeat** \u2014 if you forget, the safety net creates a default one
|
|
157372
|
+
`);
|
|
157373
|
+
}
|
|
157374
|
+
if (this.config.heartbeat?.enabled !== false) {
|
|
157375
|
+
this.context.addSystemMessage(`## Heartbeat Basics
|
|
157376
|
+
- The system can trigger scheduled runs via \`/main-loop\` or \`/watchdog\`.
|
|
157377
|
+
- If invoked with those commands, follow the heartbeat skill instructions.
|
|
157378
|
+
- Heartbeat schedules use the id \`heartbeat-${this.sessionId}\`.`);
|
|
157379
|
+
}
|
|
157380
|
+
if (this.config.heartbeat?.autonomous) {
|
|
157381
|
+
const maxSleepMin = Math.round((this.config.heartbeat.maxSleepMs ?? 1800000) / 60000);
|
|
157382
|
+
this.context.addSystemMessage(`## Autonomous Heartbeat System
|
|
157383
|
+
|
|
157384
|
+
You are running in **autonomous mode**. You manage your own wakeup schedule.
|
|
157385
|
+
|
|
157386
|
+
### How it works
|
|
157387
|
+
- After every turn, a safety-net hook ensures a heartbeat schedule exists
|
|
157388
|
+
- The heartbeat fires \`/main-loop\` which runs your autonomous check-in skill
|
|
157389
|
+
- A watchdog monitors your health and forces a wakeup if you're overdue
|
|
157390
|
+
|
|
157391
|
+
### Your responsibilities at the END of every turn
|
|
157392
|
+
1. **Save state** to memory before the turn ends:
|
|
157393
|
+
- \`memory_save agent.heartbeat.intention "what you plan to do next"\`
|
|
157394
|
+
- \`memory_save agent.state.pending "items waiting for follow-up"\`
|
|
157395
|
+
- \`memory_save agent.state.lastActions "what you just did"\`
|
|
157396
|
+
2. **Schedule your next heartbeat**:
|
|
157397
|
+
- Delete old: \`schedule_delete heartbeat-${this.sessionId}\`
|
|
157398
|
+
- Create new: \`schedule_create\` with \`kind: "once"\`, \`actionType: "message"\`, \`message: "/main-loop"\`, and \`at\` set to your chosen time
|
|
157399
|
+
3. **Save goals** when they change: \`memory_save agent.goals "..."\`
|
|
157400
|
+
|
|
157401
|
+
### Timing guidelines
|
|
157402
|
+
| Situation | Wake up in |
|
|
157403
|
+
|-----------|-----------|
|
|
157404
|
+
| Active jobs running or tasks pending | 1\u20133 minutes |
|
|
157405
|
+
| Goals exist but nothing urgent | 5\u201315 minutes |
|
|
157406
|
+
| Nothing pending, user idle | 15\u2013${maxSleepMin} minutes (max) |
|
|
157407
|
+
|
|
157408
|
+
### Key memory keys
|
|
157409
|
+
- \`agent.heartbeat.last\` \u2014 when you last ran (save ISO timestamp)
|
|
157410
|
+
- \`agent.heartbeat.next\` \u2014 when you plan to run next
|
|
157411
|
+
- \`agent.heartbeat.intention\` \u2014 why you're waking up
|
|
157412
|
+
- \`agent.goals\` \u2014 your active goals
|
|
157413
|
+
- \`agent.state.pending\` \u2014 items waiting
|
|
157414
|
+
- \`agent.state.lastActions\` \u2014 what you did recently
|
|
157415
|
+
|
|
157416
|
+
### Rules
|
|
157417
|
+
- **Stay fast** \u2014 if work takes >30s, delegate to a subassistant
|
|
157418
|
+
- **Never sleep longer than ${maxSleepMin} minutes** \u2014 the system enforces this cap
|
|
157419
|
+
- **Always schedule your next heartbeat** \u2014 if you forget, the safety net creates a default one
|
|
157420
|
+
`);
|
|
157421
|
+
}
|
|
155486
157422
|
this.contextManager?.refreshState(this.context.getMessages());
|
|
155487
157423
|
await this.hookExecutor.execute(this.hookLoader.getHooks("SessionStart"), {
|
|
155488
157424
|
session_id: this.sessionId,
|
|
@@ -155500,6 +157436,7 @@ class AssistantLoop {
|
|
|
155500
157436
|
this.isRunning = true;
|
|
155501
157437
|
try {
|
|
155502
157438
|
await this.injectPendingMessages();
|
|
157439
|
+
await this.injectPendingWebhookEvents();
|
|
155503
157440
|
await this.injectMemoryContext(userMessage);
|
|
155504
157441
|
await this.injectContextInfo();
|
|
155505
157442
|
} catch (error2) {
|
|
@@ -156216,6 +158153,7 @@ class AssistantLoop {
|
|
|
156216
158153
|
getWalletManager: () => this.walletManager,
|
|
156217
158154
|
getSecretsManager: () => this.secretsManager,
|
|
156218
158155
|
getMessagesManager: () => this.messagesManager,
|
|
158156
|
+
getWebhooksManager: () => this.webhooksManager,
|
|
156219
158157
|
getMemoryManager: () => this.memoryManager,
|
|
156220
158158
|
refreshIdentityContext: async () => {
|
|
156221
158159
|
if (this.identityManager) {
|
|
@@ -156242,6 +158180,8 @@ class AssistantLoop {
|
|
|
156242
158180
|
this.setProjectContext(content);
|
|
156243
158181
|
},
|
|
156244
158182
|
getVoiceState: () => this.getVoiceState(),
|
|
158183
|
+
getHeartbeatState: () => this.getHeartbeatState(),
|
|
158184
|
+
getHeartbeatConfig: () => this.heartbeatRuntimeConfig,
|
|
156245
158185
|
enableVoice: () => {
|
|
156246
158186
|
if (!this.voiceManager) {
|
|
156247
158187
|
throw new Error("Voice support is not available.");
|
|
@@ -156452,6 +158392,7 @@ class AssistantLoop {
|
|
|
156452
158392
|
this.voiceManager?.stopSpeaking();
|
|
156453
158393
|
this.voiceManager?.stopListening();
|
|
156454
158394
|
this.messagesManager?.stopWatching();
|
|
158395
|
+
this.webhooksManager?.stopWatching();
|
|
156455
158396
|
this.memoryManager?.close();
|
|
156456
158397
|
this.memoryManager = null;
|
|
156457
158398
|
this.memoryInjector = null;
|
|
@@ -156499,12 +158440,16 @@ class AssistantLoop {
|
|
|
156499
158440
|
const lastActivity = this.heartbeatManager.getLastActivity();
|
|
156500
158441
|
const age = Date.now() - lastActivity;
|
|
156501
158442
|
const stats = this.heartbeatManager.getStats();
|
|
158443
|
+
const intervalMs = this.heartbeatRuntimeConfig?.intervalMs ?? this.config?.heartbeat?.intervalMs ?? 15000;
|
|
158444
|
+
const nextHeartbeatAt = this.heartbeatManager.getNextHeartbeatAt();
|
|
156502
158445
|
return {
|
|
156503
158446
|
enabled: true,
|
|
156504
158447
|
state: this.heartbeatManager.getState(),
|
|
156505
158448
|
lastActivity: new Date(lastActivity).toISOString(),
|
|
156506
158449
|
uptimeSeconds: stats.uptimeSeconds,
|
|
156507
|
-
isStale: age > staleThresholdMs
|
|
158450
|
+
isStale: age > staleThresholdMs,
|
|
158451
|
+
intervalMs,
|
|
158452
|
+
nextHeartbeatAt: new Date(nextHeartbeatAt).toISOString()
|
|
156508
158453
|
};
|
|
156509
158454
|
}
|
|
156510
158455
|
getAssistantManager() {
|
|
@@ -156516,6 +158461,9 @@ class AssistantLoop {
|
|
|
156516
158461
|
getMessagesManager() {
|
|
156517
158462
|
return this.messagesManager;
|
|
156518
158463
|
}
|
|
158464
|
+
getWebhooksManager() {
|
|
158465
|
+
return this.webhooksManager;
|
|
158466
|
+
}
|
|
156519
158467
|
getWalletManager() {
|
|
156520
158468
|
return this.walletManager;
|
|
156521
158469
|
}
|
|
@@ -156747,7 +158695,8 @@ ${content.trim()}`);
|
|
|
156747
158695
|
const heartbeatConfig = this.buildHeartbeatConfig(this.config);
|
|
156748
158696
|
if (!heartbeatConfig)
|
|
156749
158697
|
return;
|
|
156750
|
-
|
|
158698
|
+
this.heartbeatRuntimeConfig = heartbeatConfig;
|
|
158699
|
+
const statePath = join46(getConfigDir(), "state", `${this.sessionId}.json`);
|
|
156751
158700
|
this.heartbeatManager = new HeartbeatManager(heartbeatConfig);
|
|
156752
158701
|
this.heartbeatPersistence = new StatePersistence(statePath);
|
|
156753
158702
|
this.heartbeatRecovery = new RecoveryManager(this.heartbeatPersistence, heartbeatConfig.persistPath, heartbeatConfig.staleThresholdMs, {
|
|
@@ -156868,7 +158817,7 @@ ${content.trim()}`);
|
|
|
156868
158817
|
async startEnergySystem() {
|
|
156869
158818
|
if (!this.config || this.config.energy?.enabled === false)
|
|
156870
158819
|
return;
|
|
156871
|
-
const statePath =
|
|
158820
|
+
const statePath = join46(getConfigDir(), "energy", "state.json");
|
|
156872
158821
|
this.energyManager = new EnergyManager(this.config.energy, new EnergyStorage(statePath));
|
|
156873
158822
|
await this.energyManager.initialize();
|
|
156874
158823
|
this.refreshEnergyEffects();
|
|
@@ -156929,6 +158878,29 @@ ${effects.message}
|
|
|
156929
158878
|
this.pendingMessagesContext = null;
|
|
156930
158879
|
}
|
|
156931
158880
|
}
|
|
158881
|
+
async injectPendingWebhookEvents() {
|
|
158882
|
+
if (!this.webhooksManager)
|
|
158883
|
+
return;
|
|
158884
|
+
try {
|
|
158885
|
+
if (this.pendingWebhooksContext) {
|
|
158886
|
+
const previous = this.pendingWebhooksContext.trim();
|
|
158887
|
+
this.context.removeSystemMessages((content) => content.trim() === previous);
|
|
158888
|
+
this.pendingWebhooksContext = null;
|
|
158889
|
+
}
|
|
158890
|
+
const pending = await this.webhooksManager.getPendingForInjection();
|
|
158891
|
+
if (pending.length === 0) {
|
|
158892
|
+
return;
|
|
158893
|
+
}
|
|
158894
|
+
this.pendingWebhooksContext = this.webhooksManager.buildInjectionContext(pending);
|
|
158895
|
+
if (this.pendingWebhooksContext) {
|
|
158896
|
+
this.context.addSystemMessage(this.pendingWebhooksContext);
|
|
158897
|
+
}
|
|
158898
|
+
await this.webhooksManager.markInjected(pending.map((e6) => ({ webhookId: e6.webhookId, eventId: e6.id })));
|
|
158899
|
+
} catch (error2) {
|
|
158900
|
+
console.error("Failed to inject pending webhook events:", error2);
|
|
158901
|
+
this.pendingWebhooksContext = null;
|
|
158902
|
+
}
|
|
158903
|
+
}
|
|
156932
158904
|
async injectMemoryContext(userMessage) {
|
|
156933
158905
|
if (!this.memoryInjector || !this.memoryInjector.isEnabled())
|
|
156934
158906
|
return;
|
|
@@ -157198,11 +159170,13 @@ ${this.identityContext}`);
|
|
|
157198
159170
|
return null;
|
|
157199
159171
|
const intervalMs = Math.max(1000, config.heartbeat?.intervalMs ?? 15000);
|
|
157200
159172
|
const staleThresholdMs = Math.max(intervalMs * 2, config.heartbeat?.staleThresholdMs ?? 120000);
|
|
157201
|
-
const persistPath = config.heartbeat?.persistPath ??
|
|
159173
|
+
const persistPath = config.heartbeat?.persistPath ?? join46(getConfigDir(), "heartbeats", `${this.sessionId}.json`);
|
|
159174
|
+
const historyPath = config.heartbeat?.historyPath ?? join46(getConfigDir(), "heartbeats", "runs", `${this.sessionId}.jsonl`);
|
|
157202
159175
|
return {
|
|
157203
159176
|
intervalMs,
|
|
157204
159177
|
staleThresholdMs,
|
|
157205
|
-
persistPath
|
|
159178
|
+
persistPath,
|
|
159179
|
+
historyPath
|
|
157206
159180
|
};
|
|
157207
159181
|
}
|
|
157208
159182
|
async buildSummaryClient(contextConfig) {
|
|
@@ -157586,9 +159560,9 @@ class StatsTracker {
|
|
|
157586
159560
|
}
|
|
157587
159561
|
}
|
|
157588
159562
|
// ../core/src/tools/connector-index.ts
|
|
157589
|
-
import { join as
|
|
157590
|
-
import { homedir as
|
|
157591
|
-
import { existsSync as
|
|
159563
|
+
import { join as join47, dirname as dirname20 } from "path";
|
|
159564
|
+
import { homedir as homedir23 } from "os";
|
|
159565
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync19, writeFileSync as writeFileSync16, readFileSync as readFileSync19 } from "fs";
|
|
157592
159566
|
var TAG_KEYWORDS = {
|
|
157593
159567
|
email: ["email", "mail", "inbox", "send", "receive", "message", "compose"],
|
|
157594
159568
|
calendar: ["calendar", "event", "meeting", "schedule", "appointment"],
|
|
@@ -157622,16 +159596,16 @@ class ConnectorIndex {
|
|
|
157622
159596
|
}
|
|
157623
159597
|
getHomeDir() {
|
|
157624
159598
|
const envHome = process.env.HOME || process.env.USERPROFILE;
|
|
157625
|
-
return envHome && envHome.trim().length > 0 ? envHome :
|
|
159599
|
+
return envHome && envHome.trim().length > 0 ? envHome : homedir23();
|
|
157626
159600
|
}
|
|
157627
159601
|
getCachePath() {
|
|
157628
|
-
return
|
|
159602
|
+
return join47(this.getHomeDir(), ".assistants", "cache", "connector-index.json");
|
|
157629
159603
|
}
|
|
157630
159604
|
loadDiskCache() {
|
|
157631
159605
|
ConnectorIndex.indexLoaded = true;
|
|
157632
159606
|
try {
|
|
157633
159607
|
const cachePath = this.getCachePath();
|
|
157634
|
-
if (!
|
|
159608
|
+
if (!existsSync29(cachePath))
|
|
157635
159609
|
return;
|
|
157636
159610
|
const data = JSON.parse(readFileSync19(cachePath, "utf-8"));
|
|
157637
159611
|
if (data.version !== INDEX_VERSION)
|
|
@@ -157647,9 +159621,9 @@ class ConnectorIndex {
|
|
|
157647
159621
|
saveDiskCache() {
|
|
157648
159622
|
try {
|
|
157649
159623
|
const cachePath = this.getCachePath();
|
|
157650
|
-
const cacheDir =
|
|
157651
|
-
if (!
|
|
157652
|
-
|
|
159624
|
+
const cacheDir = dirname20(cachePath);
|
|
159625
|
+
if (!existsSync29(cacheDir)) {
|
|
159626
|
+
mkdirSync19(cacheDir, { recursive: true });
|
|
157653
159627
|
}
|
|
157654
159628
|
const data = {
|
|
157655
159629
|
version: INDEX_VERSION,
|
|
@@ -158140,7 +160114,8 @@ async function runHeadless(options) {
|
|
|
158140
160114
|
jsonSchema,
|
|
158141
160115
|
continue: shouldContinue,
|
|
158142
160116
|
resume,
|
|
158143
|
-
cwdProvided
|
|
160117
|
+
cwdProvided,
|
|
160118
|
+
timeoutMs
|
|
158144
160119
|
} = options;
|
|
158145
160120
|
let sessionData = null;
|
|
158146
160121
|
if (resume) {
|
|
@@ -158221,7 +160196,14 @@ IMPORTANT: Your response MUST be valid JSON conforming to this schema:
|
|
|
158221
160196
|
${jsonSchema}`;
|
|
158222
160197
|
}
|
|
158223
160198
|
try {
|
|
158224
|
-
|
|
160199
|
+
if (timeoutMs && timeoutMs > 0) {
|
|
160200
|
+
await Promise.race([
|
|
160201
|
+
client.send(message),
|
|
160202
|
+
new Promise((_3, reject) => setTimeout(() => reject(new Error(`Headless run timed out after ${timeoutMs}ms`)), timeoutMs))
|
|
160203
|
+
]);
|
|
160204
|
+
} else {
|
|
160205
|
+
await client.send(message);
|
|
160206
|
+
}
|
|
158225
160207
|
} catch (error2) {
|
|
158226
160208
|
hadError = true;
|
|
158227
160209
|
errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -158331,6 +160313,7 @@ function parseArgs(argv) {
|
|
|
158331
160313
|
version: false,
|
|
158332
160314
|
help: false,
|
|
158333
160315
|
print: null,
|
|
160316
|
+
headlessTimeoutMs: null,
|
|
158334
160317
|
outputFormat: "text",
|
|
158335
160318
|
allowedTools: [],
|
|
158336
160319
|
systemPrompt: null,
|
|
@@ -158419,6 +160402,21 @@ function parseArgs(argv) {
|
|
|
158419
160402
|
}
|
|
158420
160403
|
continue;
|
|
158421
160404
|
}
|
|
160405
|
+
if (arg === "--headless-timeout" || arg === "--headless-timeout-ms") {
|
|
160406
|
+
const nextArg = args[i5 + 1];
|
|
160407
|
+
if (nextArg === undefined || isFlag(nextArg)) {
|
|
160408
|
+
options.errors.push(`${arg} requires a millisecond value`);
|
|
160409
|
+
} else {
|
|
160410
|
+
const parsed = Number(nextArg);
|
|
160411
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
160412
|
+
options.errors.push(`${arg} must be a positive number of milliseconds`);
|
|
160413
|
+
} else {
|
|
160414
|
+
options.headlessTimeoutMs = Math.floor(parsed);
|
|
160415
|
+
}
|
|
160416
|
+
i5++;
|
|
160417
|
+
}
|
|
160418
|
+
continue;
|
|
160419
|
+
}
|
|
158422
160420
|
if (arg === "--continue" || arg === "-c") {
|
|
158423
160421
|
options.continue = true;
|
|
158424
160422
|
continue;
|