@wrongstack/core 0.291.2 → 0.292.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/coordination/director-tools.d.ts.map +1 -1
- package/dist/coordination/index.js +113 -113
- package/dist/coordination/index.js.map +3 -3
- package/dist/core/agent-loop.d.ts.map +1 -1
- package/dist/core/agent-response.d.ts.map +1 -1
- package/dist/core/context.d.ts +10 -0
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/system-prompt-builder.d.ts +20 -1
- package/dist/core/system-prompt-builder.d.ts.map +1 -1
- package/dist/defaults/index.d.ts +1 -0
- package/dist/defaults/index.d.ts.map +1 -1
- package/dist/defaults/index.js +3132 -2440
- package/dist/defaults/index.js.map +4 -4
- package/dist/execution/auto-compaction-middleware.d.ts +34 -2
- package/dist/execution/auto-compaction-middleware.d.ts.map +1 -1
- package/dist/execution/compaction-core.d.ts +59 -0
- package/dist/execution/compaction-core.d.ts.map +1 -1
- package/dist/execution/compactor.d.ts.map +1 -1
- package/dist/execution/error-handler.d.ts +7 -0
- package/dist/execution/error-handler.d.ts.map +1 -1
- package/dist/execution/index.d.ts +1 -0
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +4677 -3924
- package/dist/execution/index.js.map +4 -4
- package/dist/execution/intelligent-compactor.d.ts.map +1 -1
- package/dist/execution/model-runtime.d.ts.map +1 -1
- package/dist/execution/selective-compactor.d.ts +10 -0
- package/dist/execution/selective-compactor.d.ts.map +1 -1
- package/dist/execution/subagent-compaction.d.ts +24 -0
- package/dist/execution/subagent-compaction.d.ts.map +1 -0
- package/dist/hq/alerts.d.ts +5 -0
- package/dist/hq/alerts.d.ts.map +1 -1
- package/dist/hq/auth-audit.d.ts +115 -0
- package/dist/hq/auth-audit.d.ts.map +1 -0
- package/dist/hq/auth-store.d.ts +98 -2
- package/dist/hq/auth-store.d.ts.map +1 -1
- package/dist/hq/brain-bridge.d.ts +2 -8
- package/dist/hq/brain-bridge.d.ts.map +1 -1
- package/dist/hq/bridge-context.d.ts +74 -0
- package/dist/hq/bridge-context.d.ts.map +1 -0
- package/dist/hq/cost-bridge.d.ts +4 -10
- package/dist/hq/cost-bridge.d.ts.map +1 -1
- package/dist/hq/fleet-bridge.d.ts +2 -8
- package/dist/hq/fleet-bridge.d.ts.map +1 -1
- package/dist/hq/index.d.ts +2 -0
- package/dist/hq/index.d.ts.map +1 -1
- package/dist/hq/index.js +358 -222
- package/dist/hq/index.js.map +4 -4
- package/dist/hq/protocol/session.d.ts +13 -0
- package/dist/hq/protocol/session.d.ts.map +1 -1
- package/dist/hq/tool-bridge.d.ts +2 -8
- package/dist/hq/tool-bridge.d.ts.map +1 -1
- package/dist/hq/worktree-bridge.d.ts +2 -8
- package/dist/hq/worktree-bridge.d.ts.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6054 -4741
- package/dist/index.js.map +4 -4
- package/dist/infrastructure/index.js +32 -15
- package/dist/infrastructure/index.js.map +2 -2
- package/dist/infrastructure/provider-cache-ledger.d.ts +48 -0
- package/dist/infrastructure/provider-cache-ledger.d.ts.map +1 -0
- package/dist/infrastructure/token-counter.d.ts +4 -2
- package/dist/infrastructure/token-counter.d.ts.map +1 -1
- package/dist/kernel/events/brain-events.d.ts +2 -0
- package/dist/kernel/events/brain-events.d.ts.map +1 -1
- package/dist/kernel/events/memory-events.d.ts +102 -0
- package/dist/kernel/events/memory-events.d.ts.map +1 -1
- package/dist/kernel/events/session-events.d.ts +35 -0
- package/dist/kernel/events/session-events.d.ts.map +1 -1
- package/dist/models/index.js +161 -78
- package/dist/models/index.js.map +3 -3
- package/dist/models/llm-selector.d.ts.map +1 -1
- package/dist/notifications/index.d.ts +40 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/notifier-impl.d.ts +34 -0
- package/dist/notifications/notifier-impl.d.ts.map +1 -0
- package/dist/notifications/notifier.d.ts +95 -0
- package/dist/notifications/notifier.d.ts.map +1 -0
- package/dist/notifications/types.d.ts +111 -0
- package/dist/notifications/types.d.ts.map +1 -0
- package/dist/plugin/api.d.ts +10 -1
- package/dist/plugin/api.d.ts.map +1 -1
- package/dist/registry/provider-registry.d.ts +1 -1
- package/dist/registry/provider-registry.d.ts.map +1 -1
- package/dist/security/index.js +15 -15
- package/dist/security/index.js.map +3 -3
- package/dist/skills/index.js +80 -80
- package/dist/skills/index.js.map +3 -3
- package/dist/storage/config-loader.d.ts +3 -5
- package/dist/storage/config-loader.d.ts.map +1 -1
- package/dist/storage/index.js +325 -259
- package/dist/storage/index.js.map +4 -4
- package/dist/storage/memory-consolidator.d.ts +14 -2
- package/dist/storage/memory-consolidator.d.ts.map +1 -1
- package/dist/storage/queue-store.d.ts +2 -0
- package/dist/storage/queue-store.d.ts.map +1 -1
- package/dist/tools/index.js +6 -6
- package/dist/tools/index.js.map +3 -3
- package/dist/tools/mcp-control.d.ts +1 -1
- package/dist/types/config.d.ts +64 -20
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/index.js +60 -34
- package/dist/types/index.js.map +3 -3
- package/dist/types/plugin.d.ts +11 -0
- package/dist/types/plugin.d.ts.map +1 -1
- package/dist/types/provider.d.ts +31 -0
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/token-counter.d.ts +8 -1
- package/dist/types/token-counter.d.ts.map +1 -1
- package/dist/utils/cache-key.d.ts +19 -0
- package/dist/utils/cache-key.d.ts.map +1 -0
- package/dist/utils/compaction-preview.d.ts +8 -0
- package/dist/utils/compaction-preview.d.ts.map +1 -0
- package/dist/utils/context-breakdown.d.ts +59 -0
- package/dist/utils/context-breakdown.d.ts.map +1 -0
- package/dist/utils/context-evidence.d.ts +22 -0
- package/dist/utils/context-evidence.d.ts.map +1 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1730 -1543
- package/dist/utils/index.js.map +4 -4
- package/dist/utils/token-estimate.d.ts +27 -0
- package/dist/utils/token-estimate.d.ts.map +1 -1
- package/instructions/llm/memory-consolidator.md +19 -3
- package/instructions/system.md +10 -2
- package/package.json +2 -2
package/dist/hq/index.js
CHANGED
|
@@ -1,3 +1,57 @@
|
|
|
1
|
+
// src/hq/bridge-context.ts
|
|
2
|
+
function createBridgeContext(options) {
|
|
3
|
+
const publisher = options.publisher;
|
|
4
|
+
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
5
|
+
const bridgeSessionId = options.sessionId;
|
|
6
|
+
const offs = [];
|
|
7
|
+
function sessionIdTag(eventSessionId) {
|
|
8
|
+
const tag = eventSessionId ?? bridgeSessionId;
|
|
9
|
+
return tag !== void 0 && tag.length > 0 ? { sessionId: tag } : {};
|
|
10
|
+
}
|
|
11
|
+
function safePublish(publishOptions) {
|
|
12
|
+
try {
|
|
13
|
+
publisher.publishEvent(publishOptions);
|
|
14
|
+
} catch {
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function track(off) {
|
|
18
|
+
offs.push(off);
|
|
19
|
+
}
|
|
20
|
+
function dispose() {
|
|
21
|
+
for (const off of offs) {
|
|
22
|
+
try {
|
|
23
|
+
off();
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
offs.length = 0;
|
|
28
|
+
}
|
|
29
|
+
return { now, sessionIdTag, safePublish, track, dispose };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/hq/auth-audit.ts
|
|
33
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
34
|
+
import * as path from "node:path";
|
|
35
|
+
function hqAuthAuditPath(dataDir) {
|
|
36
|
+
return path.join(dataDir, "auth-audit.jsonl");
|
|
37
|
+
}
|
|
38
|
+
function appendHqAuthAudit(dataDir, entry, options) {
|
|
39
|
+
try {
|
|
40
|
+
mkdirSync(dataDir, { recursive: true });
|
|
41
|
+
const line = `${JSON.stringify(entry)}
|
|
42
|
+
`;
|
|
43
|
+
appendFileSync(hqAuthAuditPath(dataDir), line, { encoding: "utf8", flag: "a" });
|
|
44
|
+
} catch (err) {
|
|
45
|
+
options?.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function logHqAuthAudit(dataDir, partial, options) {
|
|
49
|
+
const at = partial.at ?? (options?.now?.() ?? Date.now());
|
|
50
|
+
const { at: _omit, ...rest } = partial;
|
|
51
|
+
void _omit;
|
|
52
|
+
appendHqAuthAudit(dataDir, { at, ...rest }, options);
|
|
53
|
+
}
|
|
54
|
+
|
|
1
55
|
// src/hq/protocol/tool.ts
|
|
2
56
|
var DEFAULT_HQ_REDACTION_POLICY = {
|
|
3
57
|
rawContent: true,
|
|
@@ -1424,7 +1478,7 @@ var HqPublisher = class {
|
|
|
1424
1478
|
};
|
|
1425
1479
|
|
|
1426
1480
|
// src/hq/factory.ts
|
|
1427
|
-
import { createHash as
|
|
1481
|
+
import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
|
|
1428
1482
|
import * as fs4 from "node:fs";
|
|
1429
1483
|
import { hostname } from "node:os";
|
|
1430
1484
|
import { basename as basename5 } from "node:path";
|
|
@@ -1432,23 +1486,23 @@ import { basename as basename5 } from "node:path";
|
|
|
1432
1486
|
// src/coordination/global-mailbox.ts
|
|
1433
1487
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1434
1488
|
import * as fsp from "node:fs/promises";
|
|
1435
|
-
import * as
|
|
1489
|
+
import * as path5 from "node:path";
|
|
1436
1490
|
|
|
1437
1491
|
// src/utils/atomic-write.ts
|
|
1438
1492
|
import { randomBytes } from "node:crypto";
|
|
1439
1493
|
import * as fs2 from "node:fs/promises";
|
|
1440
1494
|
import { watch as watchDir } from "node:fs";
|
|
1441
|
-
import * as
|
|
1495
|
+
import * as path4 from "node:path";
|
|
1442
1496
|
|
|
1443
1497
|
// src/utils/session-scoped-path.ts
|
|
1444
|
-
import * as
|
|
1498
|
+
import * as path2 from "node:path";
|
|
1445
1499
|
function sessionScopedPath(dir, sessionId, suffix) {
|
|
1446
1500
|
if (!sessionId || sessionId.includes("\\") || sessionId.includes("..")) {
|
|
1447
1501
|
throw invalid(sessionId);
|
|
1448
1502
|
}
|
|
1449
|
-
const resolved =
|
|
1450
|
-
const rel =
|
|
1451
|
-
if (rel.startsWith("..") ||
|
|
1503
|
+
const resolved = path2.resolve(dir, `${sessionId}${suffix}`);
|
|
1504
|
+
const rel = path2.relative(path2.resolve(dir), resolved);
|
|
1505
|
+
if (rel.startsWith("..") || path2.isAbsolute(rel)) {
|
|
1452
1506
|
throw invalid(sessionId);
|
|
1453
1507
|
}
|
|
1454
1508
|
return resolved;
|
|
@@ -1466,21 +1520,21 @@ function invalid(sessionId) {
|
|
|
1466
1520
|
import { createHash } from "node:crypto";
|
|
1467
1521
|
import * as fs from "node:fs";
|
|
1468
1522
|
import * as os from "node:os";
|
|
1469
|
-
import * as
|
|
1523
|
+
import * as path3 from "node:path";
|
|
1470
1524
|
function canonicalProjectRoot(absRoot) {
|
|
1471
|
-
const checkoutRoot =
|
|
1472
|
-
const dotGit =
|
|
1525
|
+
const checkoutRoot = path3.resolve(absRoot);
|
|
1526
|
+
const dotGit = path3.join(checkoutRoot, ".git");
|
|
1473
1527
|
try {
|
|
1474
1528
|
if (!fs.statSync(dotGit).isFile()) return checkoutRoot;
|
|
1475
1529
|
const gitDirLine = fs.readFileSync(dotGit, "utf8").trim();
|
|
1476
1530
|
const match = /^gitdir:\s*(.+)$/i.exec(gitDirLine);
|
|
1477
1531
|
if (!match?.[1]) return checkoutRoot;
|
|
1478
|
-
const gitDir =
|
|
1479
|
-
const commonDirFile =
|
|
1532
|
+
const gitDir = path3.resolve(checkoutRoot, match[1].trim());
|
|
1533
|
+
const commonDirFile = path3.join(gitDir, "commondir");
|
|
1480
1534
|
if (!fs.statSync(commonDirFile).isFile()) return checkoutRoot;
|
|
1481
|
-
const commonDir =
|
|
1482
|
-
if (
|
|
1483
|
-
return
|
|
1535
|
+
const commonDir = path3.resolve(gitDir, fs.readFileSync(commonDirFile, "utf8").trim());
|
|
1536
|
+
if (path3.basename(commonDir).toLowerCase() !== ".git") return checkoutRoot;
|
|
1537
|
+
return path3.dirname(commonDir);
|
|
1484
1538
|
} catch {
|
|
1485
1539
|
return checkoutRoot;
|
|
1486
1540
|
}
|
|
@@ -1490,7 +1544,7 @@ function projectHash(absRoot) {
|
|
|
1490
1544
|
}
|
|
1491
1545
|
function projectSlug(absRoot) {
|
|
1492
1546
|
const identityRoot = canonicalProjectRoot(absRoot);
|
|
1493
|
-
const base = slugify(
|
|
1547
|
+
const base = slugify(path3.basename(identityRoot));
|
|
1494
1548
|
const hash = createHash("sha256").update(identityRoot).digest("hex").slice(0, 6);
|
|
1495
1549
|
return `${base}-${hash}`;
|
|
1496
1550
|
}
|
|
@@ -1499,83 +1553,83 @@ function slugify(name) {
|
|
|
1499
1553
|
}
|
|
1500
1554
|
function wstackGlobalRoot() {
|
|
1501
1555
|
const fromEnv = process.env["WRONGSTACK_HOME"];
|
|
1502
|
-
if (fromEnv && fromEnv.trim().length > 0) return
|
|
1503
|
-
return
|
|
1556
|
+
if (fromEnv && fromEnv.trim().length > 0) return path3.resolve(fromEnv);
|
|
1557
|
+
return path3.join(os.homedir(), ".wrongstack");
|
|
1504
1558
|
}
|
|
1505
1559
|
function resolveWstackPaths(opts) {
|
|
1506
|
-
const globalRoot = opts.globalRoot ?? (opts.userHome ?
|
|
1560
|
+
const globalRoot = opts.globalRoot ?? (opts.userHome ? path3.join(opts.userHome, ".wrongstack") : wstackGlobalRoot());
|
|
1507
1561
|
const homeDir = opts.userHome ?? os.homedir();
|
|
1508
1562
|
const hash = projectHash(opts.projectRoot);
|
|
1509
1563
|
const slug = projectSlug(opts.projectRoot);
|
|
1510
|
-
const projectDir =
|
|
1564
|
+
const projectDir = path3.join(globalRoot, "projects", slug);
|
|
1511
1565
|
return {
|
|
1512
1566
|
globalRoot,
|
|
1513
1567
|
projectRoot: opts.projectRoot,
|
|
1514
1568
|
homeDir,
|
|
1515
1569
|
configDir: globalRoot,
|
|
1516
|
-
globalConfig:
|
|
1517
|
-
profilesDir:
|
|
1570
|
+
globalConfig: path3.join(globalRoot, "config.json"),
|
|
1571
|
+
profilesDir: path3.join(globalRoot, "profiles"),
|
|
1518
1572
|
profileConfig: (name) => {
|
|
1519
1573
|
const safe = name.replace(/[/\\:]/g, "_").replace(/\.\./g, "_");
|
|
1520
|
-
return
|
|
1574
|
+
return path3.join(globalRoot, "profiles", safe || "default", "config.json");
|
|
1521
1575
|
},
|
|
1522
1576
|
profileStatuslineConfig: (name) => {
|
|
1523
1577
|
const safe = name.replace(/[/\\:]/g, "_").replace(/\.\./g, "_");
|
|
1524
|
-
return
|
|
1578
|
+
return path3.join(globalRoot, "profiles", safe || "default", "statusline.json");
|
|
1525
1579
|
},
|
|
1526
1580
|
profileModeConfig: (name) => {
|
|
1527
1581
|
const safe = name.replace(/[/\\:]/g, "_").replace(/\.\./g, "_");
|
|
1528
|
-
return
|
|
1582
|
+
return path3.join(globalRoot, "profiles", safe || "default", "mode.json");
|
|
1529
1583
|
},
|
|
1530
1584
|
profileProviderStatus: (name) => {
|
|
1531
1585
|
const safe = name.replace(/[/\\:]/g, "_").replace(/\.\./g, "_");
|
|
1532
|
-
return
|
|
1586
|
+
return path3.join(globalRoot, "profiles", safe || "default", "provider-status.json");
|
|
1533
1587
|
},
|
|
1534
1588
|
profileUpdateCache: (name) => {
|
|
1535
1589
|
const safe = name.replace(/[/\\:]/g, "_").replace(/\.\./g, "_");
|
|
1536
|
-
return
|
|
1590
|
+
return path3.join(globalRoot, "profiles", safe || "default", "update-cache.json");
|
|
1537
1591
|
},
|
|
1538
|
-
secretsKey:
|
|
1539
|
-
globalMemory:
|
|
1540
|
-
globalSkills:
|
|
1541
|
-
globalClaudeSkills:
|
|
1542
|
-
globalDesignKits:
|
|
1543
|
-
globalPrompts:
|
|
1544
|
-
globalInstructions:
|
|
1545
|
-
promptUsage:
|
|
1546
|
-
cacheDir:
|
|
1547
|
-
modelsCache:
|
|
1548
|
-
modelsOverlayCache:
|
|
1549
|
-
historyFile:
|
|
1550
|
-
logFile:
|
|
1592
|
+
secretsKey: path3.join(globalRoot, ".key"),
|
|
1593
|
+
globalMemory: path3.join(globalRoot, "memory.md"),
|
|
1594
|
+
globalSkills: path3.join(globalRoot, "skills"),
|
|
1595
|
+
globalClaudeSkills: path3.join(homeDir, ".claude", "skills"),
|
|
1596
|
+
globalDesignKits: path3.join(globalRoot, "design-kits"),
|
|
1597
|
+
globalPrompts: path3.join(globalRoot, "prompts"),
|
|
1598
|
+
globalInstructions: path3.join(globalRoot, "instructions"),
|
|
1599
|
+
promptUsage: path3.join(globalRoot, "prompt-usage.json"),
|
|
1600
|
+
cacheDir: path3.join(globalRoot, "cache"),
|
|
1601
|
+
modelsCache: path3.join(globalRoot, "cache", "models.dev.json"),
|
|
1602
|
+
modelsOverlayCache: path3.join(globalRoot, "cache", "models-overlay.json"),
|
|
1603
|
+
historyFile: path3.join(globalRoot, "history"),
|
|
1604
|
+
logFile: path3.join(globalRoot, "logs", "wrongstack.log"),
|
|
1551
1605
|
projectDir,
|
|
1552
|
-
projectCodebaseIndex:
|
|
1553
|
-
projectMemory:
|
|
1554
|
-
projectSessions:
|
|
1555
|
-
projectTrust:
|
|
1556
|
-
projectMeta:
|
|
1557
|
-
projectLocalConfig:
|
|
1558
|
-
inProjectConfig:
|
|
1559
|
-
inProjectAgentsFile:
|
|
1560
|
-
inProjectSkills:
|
|
1561
|
-
inProjectClaudeSkills:
|
|
1562
|
-
inProjectPrompts:
|
|
1563
|
-
inProjectInstructions:
|
|
1564
|
-
inProjectDesignKits:
|
|
1565
|
-
inProjectWorktrees:
|
|
1606
|
+
projectCodebaseIndex: path3.join(projectDir, "codebase-index"),
|
|
1607
|
+
projectMemory: path3.join(projectDir, "memory.md"),
|
|
1608
|
+
projectSessions: path3.join(projectDir, "sessions"),
|
|
1609
|
+
projectTrust: path3.join(projectDir, "trust.json"),
|
|
1610
|
+
projectMeta: path3.join(projectDir, "meta.json"),
|
|
1611
|
+
projectLocalConfig: path3.join(projectDir, "config.local.json"),
|
|
1612
|
+
inProjectConfig: path3.join(opts.projectRoot, ".wrongstack", "config.json"),
|
|
1613
|
+
inProjectAgentsFile: path3.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
|
|
1614
|
+
inProjectSkills: path3.join(opts.projectRoot, ".wrongstack", "skills"),
|
|
1615
|
+
inProjectClaudeSkills: path3.join(opts.projectRoot, ".claude", "skills"),
|
|
1616
|
+
inProjectPrompts: path3.join(opts.projectRoot, ".wrongstack", "prompts"),
|
|
1617
|
+
inProjectInstructions: path3.join(opts.projectRoot, ".wrongstack", "instructions"),
|
|
1618
|
+
inProjectDesignKits: path3.join(opts.projectRoot, ".wrongstack", "design-kits"),
|
|
1619
|
+
inProjectWorktrees: path3.join(opts.projectRoot, ".wrongstack", "worktrees"),
|
|
1566
1620
|
projectHash: hash,
|
|
1567
1621
|
projectSlug: slug,
|
|
1568
|
-
projectGoal:
|
|
1569
|
-
projectInputHistory:
|
|
1570
|
-
projectSpecs:
|
|
1571
|
-
projectTaskGraphs:
|
|
1572
|
-
projectSddSession:
|
|
1573
|
-
projectPlan:
|
|
1574
|
-
projectAutophase:
|
|
1575
|
-
projectSddBoards:
|
|
1576
|
-
syncConfig:
|
|
1577
|
-
configHistoryDir:
|
|
1578
|
-
projectStatus: (projectHash2) =>
|
|
1622
|
+
projectGoal: path3.join(projectDir, "goal.json"),
|
|
1623
|
+
projectInputHistory: path3.join(projectDir, "input-history.json"),
|
|
1624
|
+
projectSpecs: path3.join(projectDir, "specs"),
|
|
1625
|
+
projectTaskGraphs: path3.join(projectDir, "task-graphs"),
|
|
1626
|
+
projectSddSession: path3.join(projectDir, "sdd-session.json"),
|
|
1627
|
+
projectPlan: path3.join(projectDir, "plan.json"),
|
|
1628
|
+
projectAutophase: path3.join(projectDir, "autophase"),
|
|
1629
|
+
projectSddBoards: path3.join(projectDir, "sdd-boards"),
|
|
1630
|
+
syncConfig: path3.join(globalRoot, "sync.json"),
|
|
1631
|
+
configHistoryDir: path3.join(globalRoot, "config-history"),
|
|
1632
|
+
projectStatus: (projectHash2) => path3.join(globalRoot, "projects", projectHash2, "status.json")
|
|
1579
1633
|
};
|
|
1580
1634
|
}
|
|
1581
1635
|
|
|
@@ -1683,9 +1737,9 @@ var FsError = class extends WrongStackError {
|
|
|
1683
1737
|
|
|
1684
1738
|
// src/utils/atomic-write.ts
|
|
1685
1739
|
async function atomicWrite(targetPath, content, opts = {}) {
|
|
1686
|
-
const dir =
|
|
1740
|
+
const dir = path4.dirname(targetPath);
|
|
1687
1741
|
await fs2.mkdir(dir, { recursive: true });
|
|
1688
|
-
const tmp =
|
|
1742
|
+
const tmp = path4.join(dir, `.${path4.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
1689
1743
|
try {
|
|
1690
1744
|
if (typeof content === "string") {
|
|
1691
1745
|
await fs2.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
@@ -1727,9 +1781,9 @@ async function atomicWrite(targetPath, content, opts = {}) {
|
|
|
1727
1781
|
}
|
|
1728
1782
|
}
|
|
1729
1783
|
async function withFileLock(targetPath, fn, opts = {}) {
|
|
1730
|
-
const dir =
|
|
1784
|
+
const dir = path4.dirname(targetPath);
|
|
1731
1785
|
await fs2.mkdir(dir, { recursive: true });
|
|
1732
|
-
const lockPath =
|
|
1786
|
+
const lockPath = path4.join(dir, `.${path4.basename(targetPath)}.lock`);
|
|
1733
1787
|
const timeoutMs = opts.timeoutMs ?? 15e3;
|
|
1734
1788
|
const staleMs = opts.staleMs ?? 3e4;
|
|
1735
1789
|
const started = Date.now();
|
|
@@ -1788,8 +1842,8 @@ async function withFileLock(targetPath, fn, opts = {}) {
|
|
|
1788
1842
|
}
|
|
1789
1843
|
}
|
|
1790
1844
|
async function waitForLockRelease(lockPath, remainingMs) {
|
|
1791
|
-
const parentDir =
|
|
1792
|
-
const lockName =
|
|
1845
|
+
const parentDir = path4.dirname(lockPath);
|
|
1846
|
+
const lockName = path4.basename(lockPath);
|
|
1793
1847
|
const intervalMs = Math.min(remainingMs, 100);
|
|
1794
1848
|
return new Promise((resolve4) => {
|
|
1795
1849
|
let settled = false;
|
|
@@ -2127,15 +2181,15 @@ var GlobalMailbox = class {
|
|
|
2127
2181
|
* @param eventEmitter — optional SSE event emitter for HTTP bridge push
|
|
2128
2182
|
*/
|
|
2129
2183
|
constructor(projectDir, events, hqPublisher, eventEmitter) {
|
|
2130
|
-
this.messagePath =
|
|
2131
|
-
this.registryPath =
|
|
2132
|
-
this.clientRegistryPath =
|
|
2184
|
+
this.messagePath = path5.join(projectDir, MAILBOX_FILE);
|
|
2185
|
+
this.registryPath = path5.join(projectDir, "_mailbox.registry.json");
|
|
2186
|
+
this.clientRegistryPath = path5.join(projectDir, CLIENT_REGISTRY_FILE);
|
|
2133
2187
|
this._events = events;
|
|
2134
2188
|
this._hqPublisher = hqPublisher;
|
|
2135
2189
|
this.eventEmitter = eventEmitter;
|
|
2136
2190
|
}
|
|
2137
2191
|
get hqMailboxId() {
|
|
2138
|
-
return `${
|
|
2192
|
+
return `${path5.basename(path5.dirname(this.messagePath))}:mailbox`;
|
|
2139
2193
|
}
|
|
2140
2194
|
get hqPublisher() {
|
|
2141
2195
|
return typeof this._hqPublisher === "function" ? this._hqPublisher() : this._hqPublisher;
|
|
@@ -2174,7 +2228,7 @@ var GlobalMailbox = class {
|
|
|
2174
2228
|
expiresAt: input.ttlMs !== void 0 ? new Date(Date.now() + input.ttlMs).toISOString() : void 0
|
|
2175
2229
|
};
|
|
2176
2230
|
const line = JSON.stringify(msg) + LINE_SEPARATOR;
|
|
2177
|
-
await fsp.mkdir(
|
|
2231
|
+
await fsp.mkdir(path5.dirname(this.messagePath), { recursive: true });
|
|
2178
2232
|
await withFileLock(this.messagePath, async () => {
|
|
2179
2233
|
await fsp.appendFile(this.messagePath, line, "utf8");
|
|
2180
2234
|
const { mtimeMs, size } = await this._statMessageFile();
|
|
@@ -3148,7 +3202,7 @@ var GlobalMailbox = class {
|
|
|
3148
3202
|
this._messageCacheSize = size;
|
|
3149
3203
|
}
|
|
3150
3204
|
async _ensureRegistry() {
|
|
3151
|
-
await fsp.mkdir(
|
|
3205
|
+
await fsp.mkdir(path5.dirname(this.registryPath), { recursive: true });
|
|
3152
3206
|
}
|
|
3153
3207
|
/** Minimal shape-check for a deserialized agent registry entry.
|
|
3154
3208
|
* Logs a warning and returns `false` for structurally invalid data
|
|
@@ -3241,7 +3295,7 @@ var GlobalMailbox = class {
|
|
|
3241
3295
|
}
|
|
3242
3296
|
// ── Client registry internals ───────────────────────────────────────────
|
|
3243
3297
|
async _ensureClientRegistry() {
|
|
3244
|
-
await fsp.mkdir(
|
|
3298
|
+
await fsp.mkdir(path5.dirname(this.clientRegistryPath), { recursive: true });
|
|
3245
3299
|
}
|
|
3246
3300
|
async _readClientRegistry(opts) {
|
|
3247
3301
|
if (!opts?.fresh && this._clientRegistryCache && Date.now() - this._clientRegistryCacheAt < REGISTRY_CACHE_TTL_MS) {
|
|
@@ -3293,21 +3347,30 @@ var GlobalMailbox = class {
|
|
|
3293
3347
|
};
|
|
3294
3348
|
|
|
3295
3349
|
// src/hq/auth-store.ts
|
|
3296
|
-
import { randomBytes as randomBytes2, randomUUID as randomUUID3, scrypt, timingSafeEqual } from "node:crypto";
|
|
3350
|
+
import { createHash as createHash2, randomBytes as randomBytes2, randomUUID as randomUUID3, scrypt, timingSafeEqual } from "node:crypto";
|
|
3297
3351
|
import * as fs3 from "node:fs/promises";
|
|
3298
3352
|
import * as syncFs from "node:fs";
|
|
3299
|
-
import * as
|
|
3353
|
+
import * as path6 from "node:path";
|
|
3300
3354
|
var HQ_AUTH_FILE_VERSION = 1;
|
|
3301
3355
|
function defaultHqDataDir() {
|
|
3302
|
-
return
|
|
3356
|
+
return path6.join(wstackGlobalRoot(), "hq");
|
|
3303
3357
|
}
|
|
3304
3358
|
function resolveHqDataDir(override, env = process.env) {
|
|
3305
3359
|
const raw = override ?? env["WRONGSTACK_HQ_DATA_DIR"]?.trim();
|
|
3306
3360
|
if (!raw) return defaultHqDataDir();
|
|
3307
|
-
return
|
|
3361
|
+
return path6.isAbsolute(raw) ? path6.resolve(raw) : path6.resolve(process.cwd(), raw);
|
|
3362
|
+
}
|
|
3363
|
+
function isTokenExpired(token, at = Date.now()) {
|
|
3364
|
+
if (token === void 0) return false;
|
|
3365
|
+
const expiresAt = token.expiresAt;
|
|
3366
|
+
if (expiresAt === void 0) return false;
|
|
3367
|
+
const parsed = Date.parse(expiresAt);
|
|
3368
|
+
if (!Number.isFinite(parsed)) return false;
|
|
3369
|
+
return at >= parsed;
|
|
3308
3370
|
}
|
|
3309
3371
|
function tokenHasCapability(token, capability) {
|
|
3310
3372
|
if (token === void 0) return false;
|
|
3373
|
+
if (isTokenExpired(token)) return false;
|
|
3311
3374
|
if (token.capabilities === void 0) return true;
|
|
3312
3375
|
return token.capabilities.includes(capability);
|
|
3313
3376
|
}
|
|
@@ -3317,11 +3380,32 @@ function emptyHqAuthFile() {
|
|
|
3317
3380
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3318
3381
|
};
|
|
3319
3382
|
}
|
|
3383
|
+
var HQ_AUTH_CONTENT_HASH_REDACTED = "<redacted>";
|
|
3384
|
+
function hqAuthContentHash(file) {
|
|
3385
|
+
const REDACTED = HQ_AUTH_CONTENT_HASH_REDACTED;
|
|
3386
|
+
const redactToken = (t) => ({ ...t, token: REDACTED });
|
|
3387
|
+
try {
|
|
3388
|
+
const projection = {
|
|
3389
|
+
version: file.version,
|
|
3390
|
+
updatedAt: file.updatedAt,
|
|
3391
|
+
...file.redactionPolicy !== void 0 ? { redactionPolicy: file.redactionPolicy } : {},
|
|
3392
|
+
...file.browserTokens !== void 0 ? { browserTokens: file.browserTokens.map(redactToken) } : {},
|
|
3393
|
+
...file.clientTokens !== void 0 ? { clientTokens: file.clientTokens.map(redactToken) } : {},
|
|
3394
|
+
...file.passwordHash !== void 0 ? { passwordHash: REDACTED } : {},
|
|
3395
|
+
...file.cookieSecret !== void 0 ? { cookieSecret: REDACTED } : {},
|
|
3396
|
+
...file.alertRules !== void 0 ? { alertRules: file.alertRules } : {}
|
|
3397
|
+
};
|
|
3398
|
+
const payload = JSON.stringify(projection);
|
|
3399
|
+
return createHash2("sha256").update(payload).digest("hex");
|
|
3400
|
+
} catch {
|
|
3401
|
+
return void 0;
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3320
3404
|
function hqAuthFilePath(dataDir) {
|
|
3321
|
-
return
|
|
3405
|
+
return path6.join(dataDir, "auth.json");
|
|
3322
3406
|
}
|
|
3323
3407
|
function hqRuntimeFilePath(dataDir) {
|
|
3324
|
-
return
|
|
3408
|
+
return path6.join(dataDir, "runtime.json");
|
|
3325
3409
|
}
|
|
3326
3410
|
async function writeHqRuntimeFile(dataDir, file) {
|
|
3327
3411
|
const payload = {
|
|
@@ -3407,7 +3491,23 @@ async function ensureHqFirstRunAuthFile(dataDir, opts = {}) {
|
|
|
3407
3491
|
cookieSecret: mintHqCookieSecret()
|
|
3408
3492
|
};
|
|
3409
3493
|
await writeHqAuthFile(dataDir, authFile2);
|
|
3410
|
-
|
|
3494
|
+
const persisted2 = await readHqAuthFile(dataDir, opts);
|
|
3495
|
+
const hash2 = hqAuthContentHash(persisted2);
|
|
3496
|
+
const actorField2 = opts.actor ? { actor: opts.actor } : {};
|
|
3497
|
+
logHqAuthAudit(
|
|
3498
|
+
dataDir,
|
|
3499
|
+
{
|
|
3500
|
+
kind: "password-rotate",
|
|
3501
|
+
scope: "browser",
|
|
3502
|
+
tokenId: "(password-rotation)",
|
|
3503
|
+
...hash2 !== void 0 ? { contentHash: hash2 } : {},
|
|
3504
|
+
...actorField2
|
|
3505
|
+
},
|
|
3506
|
+
{
|
|
3507
|
+
onError: (err) => opts.warn?.(`HQ password-rotate audit write failed: ${err.message}`)
|
|
3508
|
+
}
|
|
3509
|
+
);
|
|
3510
|
+
return { authFile: persisted2, created: false };
|
|
3411
3511
|
}
|
|
3412
3512
|
}
|
|
3413
3513
|
return { authFile: existing, created: false };
|
|
@@ -3417,8 +3517,14 @@ async function ensureHqFirstRunAuthFile(dataDir, opts = {}) {
|
|
|
3417
3517
|
return { authFile: await readHqAuthFile(dataDir, opts), created: false };
|
|
3418
3518
|
}
|
|
3419
3519
|
}
|
|
3420
|
-
const browserToken = {
|
|
3421
|
-
|
|
3520
|
+
const browserToken = {
|
|
3521
|
+
...mintHqToken({ label: "first-run browser", ttlMs: opts.tokenTtlMs }),
|
|
3522
|
+
capabilities: ["control.enqueue"]
|
|
3523
|
+
};
|
|
3524
|
+
const clientToken = {
|
|
3525
|
+
...mintHqToken({ label: "first-run client", ttlMs: opts.tokenTtlMs }),
|
|
3526
|
+
capabilities: ["telemetry.publish"]
|
|
3527
|
+
};
|
|
3422
3528
|
const authFile = {
|
|
3423
3529
|
version: HQ_AUTH_FILE_VERSION,
|
|
3424
3530
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -3430,7 +3536,32 @@ async function ensureHqFirstRunAuthFile(dataDir, opts = {}) {
|
|
|
3430
3536
|
authFile.cookieSecret = mintHqCookieSecret();
|
|
3431
3537
|
}
|
|
3432
3538
|
await writeHqAuthFile(dataDir, authFile);
|
|
3433
|
-
|
|
3539
|
+
const persisted = await readHqAuthFile(dataDir, opts);
|
|
3540
|
+
const hash = hqAuthContentHash(persisted);
|
|
3541
|
+
const hashField = hash !== void 0 ? { contentHash: hash } : {};
|
|
3542
|
+
const actorField = opts.actor ? { actor: opts.actor } : {};
|
|
3543
|
+
for (const [scope, token] of [
|
|
3544
|
+
["browser", browserToken],
|
|
3545
|
+
["client", clientToken]
|
|
3546
|
+
]) {
|
|
3547
|
+
logHqAuthAudit(
|
|
3548
|
+
dataDir,
|
|
3549
|
+
{
|
|
3550
|
+
kind: "first-run",
|
|
3551
|
+
scope,
|
|
3552
|
+
tokenId: token.id,
|
|
3553
|
+
...hashField,
|
|
3554
|
+
...token.label ? { label: token.label } : {},
|
|
3555
|
+
capabilities: token.capabilities,
|
|
3556
|
+
...token.expiresAt ? { expiresAt: token.expiresAt } : {},
|
|
3557
|
+
...actorField
|
|
3558
|
+
},
|
|
3559
|
+
{
|
|
3560
|
+
onError: (err) => opts.warn?.(`HQ first-run audit write failed: ${err.message}`)
|
|
3561
|
+
}
|
|
3562
|
+
);
|
|
3563
|
+
}
|
|
3564
|
+
return { authFile: persisted, created: true, browserToken, clientToken };
|
|
3434
3565
|
}
|
|
3435
3566
|
async function mutateHqAuthFile(dataDir, mutator, opts = {}) {
|
|
3436
3567
|
const current = await readHqAuthFile(dataDir, opts);
|
|
@@ -3474,13 +3605,16 @@ async function verifyHqPassword(password, hash) {
|
|
|
3474
3605
|
function mintHqCookieSecret() {
|
|
3475
3606
|
return randomBytes2(32).toString("base64url");
|
|
3476
3607
|
}
|
|
3477
|
-
function mintHqToken(
|
|
3478
|
-
const
|
|
3608
|
+
function mintHqToken(labelOrOptions) {
|
|
3609
|
+
const opts = typeof labelOrOptions === "string" ? { label: labelOrOptions } : labelOrOptions ?? {};
|
|
3610
|
+
const at = opts.now ?? Date.now();
|
|
3611
|
+
const createdAtIso = new Date(at).toISOString();
|
|
3479
3612
|
return {
|
|
3480
3613
|
id: randomUUID3(),
|
|
3481
3614
|
token: randomUUID3().replace(/-/g, "") + randomUUID3().replace(/-/g, ""),
|
|
3482
|
-
|
|
3483
|
-
|
|
3615
|
+
createdAt: createdAtIso,
|
|
3616
|
+
...opts.label ? { label: opts.label } : {},
|
|
3617
|
+
...opts.ttlMs !== void 0 && Number.isFinite(opts.ttlMs) && opts.ttlMs > 0 ? { expiresAt: new Date(at + opts.ttlMs).toISOString() } : {}
|
|
3484
3618
|
};
|
|
3485
3619
|
}
|
|
3486
3620
|
var mintHqBrowserToken = mintHqToken;
|
|
@@ -3491,7 +3625,7 @@ function watchHqAuthFile(dataDir, onChange, opts = {}) {
|
|
|
3491
3625
|
let closed = false;
|
|
3492
3626
|
let watcher;
|
|
3493
3627
|
try {
|
|
3494
|
-
watcher = syncFs.watch(
|
|
3628
|
+
watcher = syncFs.watch(path6.dirname(file), { recursive: false });
|
|
3495
3629
|
} catch (err) {
|
|
3496
3630
|
opts.warn?.(`HQ auth watcher could not start: ${err.message}`);
|
|
3497
3631
|
return { close: () => {
|
|
@@ -3515,7 +3649,7 @@ function watchHqAuthFile(dataDir, onChange, opts = {}) {
|
|
|
3515
3649
|
watcher.on("change", (eventType, filename) => {
|
|
3516
3650
|
const name = typeof filename === "string" ? filename : "";
|
|
3517
3651
|
if (eventType === "rename" || eventType === "change") {
|
|
3518
|
-
if (!name || name === "auth.json" || name ===
|
|
3652
|
+
if (!name || name === "auth.json" || name === path6.basename(file)) {
|
|
3519
3653
|
trigger();
|
|
3520
3654
|
}
|
|
3521
3655
|
}
|
|
@@ -3601,10 +3735,10 @@ function resolveHqConfig(options = {}) {
|
|
|
3601
3735
|
};
|
|
3602
3736
|
}
|
|
3603
3737
|
function stableMachineId() {
|
|
3604
|
-
return
|
|
3738
|
+
return createHash3("sha256").update(hostname()).digest("hex").slice(0, 12);
|
|
3605
3739
|
}
|
|
3606
3740
|
function deriveProjectId(projectRoot) {
|
|
3607
|
-
return
|
|
3741
|
+
return createHash3("sha256").update(projectRoot).digest("hex").slice(0, 12);
|
|
3608
3742
|
}
|
|
3609
3743
|
function createHqPublisherFromEnv(options) {
|
|
3610
3744
|
const config = options.config ?? resolveHqConfig({ config: options.appConfig?.hq });
|
|
@@ -4057,7 +4191,7 @@ function startSessionTelemetryBridge(opts) {
|
|
|
4057
4191
|
// src/hq/fleet-bridge.ts
|
|
4058
4192
|
function startFleetTelemetryBridge(opts) {
|
|
4059
4193
|
const { events, publisher, runId } = opts;
|
|
4060
|
-
const
|
|
4194
|
+
const ctx = createBridgeContext(opts);
|
|
4061
4195
|
let lastHash = "";
|
|
4062
4196
|
function buildPayload(stats) {
|
|
4063
4197
|
const subagents = stats.subagentStatuses.map((s) => ({
|
|
@@ -4080,21 +4214,20 @@ function startFleetTelemetryBridge(opts) {
|
|
|
4080
4214
|
};
|
|
4081
4215
|
}
|
|
4082
4216
|
const off = events.on("coordinator.stats", (stats) => {
|
|
4217
|
+
const payload = buildPayload(stats);
|
|
4218
|
+
const hash = JSON.stringify(payload);
|
|
4219
|
+
if (hash === lastHash) return;
|
|
4220
|
+
lastHash = hash;
|
|
4083
4221
|
try {
|
|
4084
|
-
const payload = buildPayload(stats);
|
|
4085
|
-
const hash = JSON.stringify(payload);
|
|
4086
|
-
if (hash === lastHash) return;
|
|
4087
|
-
lastHash = hash;
|
|
4088
4222
|
publisher.publishFleetSnapshot(payload, {
|
|
4089
|
-
...
|
|
4090
|
-
timestamp: now()
|
|
4223
|
+
...ctx.sessionIdTag(),
|
|
4224
|
+
timestamp: ctx.now()
|
|
4091
4225
|
});
|
|
4092
4226
|
} catch {
|
|
4093
4227
|
}
|
|
4094
4228
|
});
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
};
|
|
4229
|
+
ctx.track(off);
|
|
4230
|
+
return ctx.dispose;
|
|
4098
4231
|
}
|
|
4099
4232
|
var FLEET_STATUS_MAP = {
|
|
4100
4233
|
running: "running",
|
|
@@ -4134,27 +4267,22 @@ function extractDecisionFields(dec) {
|
|
|
4134
4267
|
return out;
|
|
4135
4268
|
}
|
|
4136
4269
|
function startBrainTelemetryBridge(opts) {
|
|
4137
|
-
const { events
|
|
4138
|
-
const
|
|
4270
|
+
const { events } = opts;
|
|
4271
|
+
const ctx = createBridgeContext(opts);
|
|
4139
4272
|
function publish(kind, payload, at) {
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
timestamp: now()
|
|
4147
|
-
});
|
|
4148
|
-
} catch {
|
|
4149
|
-
}
|
|
4273
|
+
ctx.safePublish({
|
|
4274
|
+
type: "brain.event",
|
|
4275
|
+
payload: { kind, at, ...payload },
|
|
4276
|
+
...ctx.sessionIdTag(),
|
|
4277
|
+
timestamp: ctx.now()
|
|
4278
|
+
});
|
|
4150
4279
|
}
|
|
4151
|
-
|
|
4152
|
-
offs.push(
|
|
4280
|
+
ctx.track(
|
|
4153
4281
|
events.on("brain.decision_requested", (p) => {
|
|
4154
4282
|
publish("decision_requested", extractRequestFields(p.request), p.at);
|
|
4155
4283
|
})
|
|
4156
4284
|
);
|
|
4157
|
-
|
|
4285
|
+
ctx.track(
|
|
4158
4286
|
events.on("brain.decision_answered", (p) => {
|
|
4159
4287
|
publish("decision_answered", {
|
|
4160
4288
|
...extractRequestFields(p.request),
|
|
@@ -4162,7 +4290,7 @@ function startBrainTelemetryBridge(opts) {
|
|
|
4162
4290
|
}, p.at);
|
|
4163
4291
|
})
|
|
4164
4292
|
);
|
|
4165
|
-
|
|
4293
|
+
ctx.track(
|
|
4166
4294
|
events.on("brain.decision_ask_human", (p) => {
|
|
4167
4295
|
publish("decision_ask_human", {
|
|
4168
4296
|
...extractRequestFields(p.request),
|
|
@@ -4170,7 +4298,7 @@ function startBrainTelemetryBridge(opts) {
|
|
|
4170
4298
|
}, p.at);
|
|
4171
4299
|
})
|
|
4172
4300
|
);
|
|
4173
|
-
|
|
4301
|
+
ctx.track(
|
|
4174
4302
|
events.on("brain.decision_denied", (p) => {
|
|
4175
4303
|
publish("decision_denied", {
|
|
4176
4304
|
...extractRequestFields(p.request),
|
|
@@ -4178,7 +4306,7 @@ function startBrainTelemetryBridge(opts) {
|
|
|
4178
4306
|
}, p.at);
|
|
4179
4307
|
})
|
|
4180
4308
|
);
|
|
4181
|
-
|
|
4309
|
+
ctx.track(
|
|
4182
4310
|
events.on("brain.human_answered", (p) => {
|
|
4183
4311
|
const detail = typeof p.text === "string" ? p.text : p.optionId;
|
|
4184
4312
|
publish("human_answered", {
|
|
@@ -4188,7 +4316,7 @@ function startBrainTelemetryBridge(opts) {
|
|
|
4188
4316
|
}, p.at);
|
|
4189
4317
|
})
|
|
4190
4318
|
);
|
|
4191
|
-
|
|
4319
|
+
ctx.track(
|
|
4192
4320
|
events.on("brain.intervention", (p) => {
|
|
4193
4321
|
publish("intervention", {
|
|
4194
4322
|
...extractRequestFields(p.request),
|
|
@@ -4198,29 +4326,22 @@ function startBrainTelemetryBridge(opts) {
|
|
|
4198
4326
|
}, p.at);
|
|
4199
4327
|
})
|
|
4200
4328
|
);
|
|
4201
|
-
return
|
|
4202
|
-
for (const off of offs) off();
|
|
4203
|
-
};
|
|
4329
|
+
return ctx.dispose;
|
|
4204
4330
|
}
|
|
4205
4331
|
|
|
4206
4332
|
// src/hq/worktree-bridge.ts
|
|
4207
4333
|
function startWorktreeTelemetryBridge(opts) {
|
|
4208
|
-
const { events
|
|
4209
|
-
const
|
|
4210
|
-
function publish(payload,
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
timestamp: now()
|
|
4218
|
-
});
|
|
4219
|
-
} catch {
|
|
4220
|
-
}
|
|
4334
|
+
const { events } = opts;
|
|
4335
|
+
const ctx = createBridgeContext(opts);
|
|
4336
|
+
function publish(payload, eventSessionId) {
|
|
4337
|
+
ctx.safePublish({
|
|
4338
|
+
type: "worktree.event",
|
|
4339
|
+
payload,
|
|
4340
|
+
...ctx.sessionIdTag(eventSessionId),
|
|
4341
|
+
timestamp: ctx.now()
|
|
4342
|
+
});
|
|
4221
4343
|
}
|
|
4222
|
-
|
|
4223
|
-
offs.push(
|
|
4344
|
+
ctx.track(
|
|
4224
4345
|
events.on("worktree.allocated", (p) => {
|
|
4225
4346
|
publish(
|
|
4226
4347
|
{
|
|
@@ -4236,7 +4357,7 @@ function startWorktreeTelemetryBridge(opts) {
|
|
|
4236
4357
|
);
|
|
4237
4358
|
})
|
|
4238
4359
|
);
|
|
4239
|
-
|
|
4360
|
+
ctx.track(
|
|
4240
4361
|
events.on("worktree.committed", (p) => {
|
|
4241
4362
|
publish(
|
|
4242
4363
|
{
|
|
@@ -4253,7 +4374,7 @@ function startWorktreeTelemetryBridge(opts) {
|
|
|
4253
4374
|
);
|
|
4254
4375
|
})
|
|
4255
4376
|
);
|
|
4256
|
-
|
|
4377
|
+
ctx.track(
|
|
4257
4378
|
events.on("worktree.merged", (p) => {
|
|
4258
4379
|
publish(
|
|
4259
4380
|
{
|
|
@@ -4268,7 +4389,7 @@ function startWorktreeTelemetryBridge(opts) {
|
|
|
4268
4389
|
);
|
|
4269
4390
|
})
|
|
4270
4391
|
);
|
|
4271
|
-
|
|
4392
|
+
ctx.track(
|
|
4272
4393
|
events.on("worktree.conflict", (p) => {
|
|
4273
4394
|
publish(
|
|
4274
4395
|
{
|
|
@@ -4282,7 +4403,7 @@ function startWorktreeTelemetryBridge(opts) {
|
|
|
4282
4403
|
);
|
|
4283
4404
|
})
|
|
4284
4405
|
);
|
|
4285
|
-
|
|
4406
|
+
ctx.track(
|
|
4286
4407
|
events.on("worktree.released", (p) => {
|
|
4287
4408
|
publish(
|
|
4288
4409
|
{
|
|
@@ -4296,7 +4417,7 @@ function startWorktreeTelemetryBridge(opts) {
|
|
|
4296
4417
|
);
|
|
4297
4418
|
})
|
|
4298
4419
|
);
|
|
4299
|
-
|
|
4420
|
+
ctx.track(
|
|
4300
4421
|
events.on("worktree.failed", (p) => {
|
|
4301
4422
|
publish(
|
|
4302
4423
|
{
|
|
@@ -4310,63 +4431,52 @@ function startWorktreeTelemetryBridge(opts) {
|
|
|
4310
4431
|
);
|
|
4311
4432
|
})
|
|
4312
4433
|
);
|
|
4313
|
-
return
|
|
4314
|
-
for (const off of offs) off();
|
|
4315
|
-
};
|
|
4434
|
+
return ctx.dispose;
|
|
4316
4435
|
}
|
|
4317
4436
|
|
|
4318
4437
|
// src/hq/tool-bridge.ts
|
|
4319
4438
|
function startToolTelemetryBridge(opts) {
|
|
4320
4439
|
const { events, publisher } = opts;
|
|
4321
|
-
const
|
|
4440
|
+
const ctx = createBridgeContext(opts);
|
|
4322
4441
|
const inFlight = /* @__PURE__ */ new Map();
|
|
4323
|
-
function sessionIdTag(sessionId) {
|
|
4324
|
-
const tag = sessionId ?? opts.sessionId;
|
|
4325
|
-
return tag !== void 0 ? { sessionId: tag } : {};
|
|
4326
|
-
}
|
|
4327
4442
|
const offStarted = events.on("tool.started", (p) => {
|
|
4328
4443
|
inFlight.set(p.id, { name: p.name, startedAt: Date.now() });
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
});
|
|
4345
|
-
} catch {
|
|
4346
|
-
}
|
|
4444
|
+
const payload = {
|
|
4445
|
+
toolName: p.name,
|
|
4446
|
+
...p.input !== void 0 ? {
|
|
4447
|
+
inputSummary: summarizeHqToolArgs(p.input, {
|
|
4448
|
+
policy: publisher.redactionPolicy,
|
|
4449
|
+
...opts.projectRoot !== void 0 ? { projectRoot: opts.projectRoot } : {}
|
|
4450
|
+
})
|
|
4451
|
+
} : {}
|
|
4452
|
+
};
|
|
4453
|
+
ctx.safePublish({
|
|
4454
|
+
type: "tool.started",
|
|
4455
|
+
payload,
|
|
4456
|
+
...ctx.sessionIdTag(p.sessionId),
|
|
4457
|
+
timestamp: ctx.now()
|
|
4458
|
+
});
|
|
4347
4459
|
});
|
|
4348
4460
|
const offExecuted = events.on("tool.executed", (p) => {
|
|
4349
4461
|
const id = p.id;
|
|
4350
4462
|
if (id !== void 0) inFlight.delete(id);
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
});
|
|
4364
|
-
} catch {
|
|
4365
|
-
}
|
|
4463
|
+
const payload = {
|
|
4464
|
+
toolName: p.name,
|
|
4465
|
+
status: p.ok ? "success" : "error",
|
|
4466
|
+
durationMs: p.durationMs,
|
|
4467
|
+
...p.output !== void 0 && p.output.length > 0 ? { outputSummary: truncateForSummary(p.output, publisher.redactionPolicy) } : {}
|
|
4468
|
+
};
|
|
4469
|
+
ctx.safePublish({
|
|
4470
|
+
type: "tool.completed",
|
|
4471
|
+
payload,
|
|
4472
|
+
...ctx.sessionIdTag(p.sessionId),
|
|
4473
|
+
timestamp: ctx.now()
|
|
4474
|
+
});
|
|
4366
4475
|
});
|
|
4476
|
+
ctx.track(offStarted);
|
|
4477
|
+
ctx.track(offExecuted);
|
|
4367
4478
|
return () => {
|
|
4368
|
-
|
|
4369
|
-
offExecuted();
|
|
4479
|
+
ctx.dispose();
|
|
4370
4480
|
inFlight.clear();
|
|
4371
4481
|
};
|
|
4372
4482
|
}
|
|
@@ -4381,38 +4491,35 @@ function truncateForSummary(output, policy, max = 280) {
|
|
|
4381
4491
|
|
|
4382
4492
|
// src/hq/cost-bridge.ts
|
|
4383
4493
|
function startCostTelemetryBridge(opts) {
|
|
4384
|
-
const { events
|
|
4385
|
-
const
|
|
4494
|
+
const { events } = opts;
|
|
4495
|
+
const ctx = createBridgeContext(opts);
|
|
4386
4496
|
const off = events.on("token.accounted", (p) => {
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
} catch {
|
|
4406
|
-
}
|
|
4497
|
+
const usage = p.deltaUsage ?? p.usage;
|
|
4498
|
+
const payload = {
|
|
4499
|
+
inputTokens: usage.input,
|
|
4500
|
+
outputTokens: usage.output,
|
|
4501
|
+
totalTokens: usage.input + usage.output,
|
|
4502
|
+
costUsd: p.cost.total
|
|
4503
|
+
};
|
|
4504
|
+
if (p.provider !== void 0) payload.provider = p.provider;
|
|
4505
|
+
if (p.model !== void 0) payload.model = p.model;
|
|
4506
|
+
if (usage.cacheRead !== void 0) payload.cacheRead = usage.cacheRead;
|
|
4507
|
+
if (usage.cacheWrite !== void 0) payload.cacheWrite = usage.cacheWrite;
|
|
4508
|
+
const sessionId = opts.sessionId ?? p.sessionId;
|
|
4509
|
+
ctx.safePublish({
|
|
4510
|
+
type: "session.usage",
|
|
4511
|
+
payload,
|
|
4512
|
+
...sessionId !== void 0 ? { sessionId } : {},
|
|
4513
|
+
timestamp: ctx.now()
|
|
4514
|
+
});
|
|
4407
4515
|
});
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
};
|
|
4516
|
+
ctx.track(off);
|
|
4517
|
+
return ctx.dispose;
|
|
4411
4518
|
}
|
|
4412
4519
|
|
|
4413
4520
|
// src/hq/persistence.ts
|
|
4414
4521
|
import * as fs6 from "node:fs/promises";
|
|
4415
|
-
import * as
|
|
4522
|
+
import * as path7 from "node:path";
|
|
4416
4523
|
var DEFAULT_EVENT_LOG_MAX_LINES = 5e4;
|
|
4417
4524
|
var DEFAULT_EVENT_LOG_ROTATE_KEEP = 2e4;
|
|
4418
4525
|
var HqEventLog = class {
|
|
@@ -4423,7 +4530,7 @@ var HqEventLog = class {
|
|
|
4423
4530
|
lineCount = 0;
|
|
4424
4531
|
counted = false;
|
|
4425
4532
|
constructor(opts) {
|
|
4426
|
-
this.filePath =
|
|
4533
|
+
this.filePath = path7.join(opts.dataDir, "events.jsonl");
|
|
4427
4534
|
this.maxLines = opts.maxLines ?? DEFAULT_EVENT_LOG_MAX_LINES;
|
|
4428
4535
|
this.rotateKeep = opts.rotateKeep ?? DEFAULT_EVENT_LOG_ROTATE_KEEP;
|
|
4429
4536
|
}
|
|
@@ -4507,7 +4614,7 @@ var HqSnapshotStore = class {
|
|
|
4507
4614
|
filePath;
|
|
4508
4615
|
writeChain = Promise.resolve();
|
|
4509
4616
|
constructor(opts) {
|
|
4510
|
-
this.filePath =
|
|
4617
|
+
this.filePath = path7.join(opts.dataDir, "snapshot.json");
|
|
4511
4618
|
}
|
|
4512
4619
|
/** Persist a snapshot. Best-effort, never rejects. */
|
|
4513
4620
|
save(snapshot) {
|
|
@@ -4536,7 +4643,7 @@ var HqTimeseriesStore = class {
|
|
|
4536
4643
|
buckets = /* @__PURE__ */ new Map();
|
|
4537
4644
|
flushChain = Promise.resolve();
|
|
4538
4645
|
constructor(opts) {
|
|
4539
|
-
this.filePath =
|
|
4646
|
+
this.filePath = path7.join(opts.dataDir, "timeseries.jsonl");
|
|
4540
4647
|
this.bucketMs = opts.bucketMs ?? 5 * 60 * 1e3;
|
|
4541
4648
|
this.maxBuckets = opts.maxBuckets ?? 2016;
|
|
4542
4649
|
}
|
|
@@ -4655,7 +4762,7 @@ var HqSimpleLog = class {
|
|
|
4655
4762
|
filePath;
|
|
4656
4763
|
writeChain = Promise.resolve();
|
|
4657
4764
|
constructor(dataDir, filename) {
|
|
4658
|
-
this.filePath =
|
|
4765
|
+
this.filePath = path7.join(dataDir, filename);
|
|
4659
4766
|
}
|
|
4660
4767
|
/** Append one record as a JSON line. Best-effort, never rejects. */
|
|
4661
4768
|
append(record) {
|
|
@@ -4825,7 +4932,8 @@ var HqCommandAuditLog = class {
|
|
|
4825
4932
|
var DEFAULT_CONFIG = {
|
|
4826
4933
|
costThresholdUsd: 50,
|
|
4827
4934
|
staleMachineSeconds: 120,
|
|
4828
|
-
maxAgents: 0
|
|
4935
|
+
maxAgents: 0,
|
|
4936
|
+
tokenExpiryWarningHours: 24
|
|
4829
4937
|
};
|
|
4830
4938
|
function resolveConfig(config) {
|
|
4831
4939
|
return { ...DEFAULT_CONFIG, ...config ?? {} };
|
|
@@ -4882,6 +4990,27 @@ var RULES = [
|
|
|
4882
4990
|
}
|
|
4883
4991
|
return null;
|
|
4884
4992
|
}
|
|
4993
|
+
},
|
|
4994
|
+
{
|
|
4995
|
+
id: "token-expired-present",
|
|
4996
|
+
severity: "error",
|
|
4997
|
+
evaluate: (snapshot) => {
|
|
4998
|
+
if (snapshot === null) return null;
|
|
4999
|
+
const stats = snapshot.totals.tokenStats;
|
|
5000
|
+
if (stats === void 0 || stats.expired <= 0) return null;
|
|
5001
|
+
return `${stats.expired} expired token(s) filtered from live auth \u2014 rotate or revoke them`;
|
|
5002
|
+
}
|
|
5003
|
+
},
|
|
5004
|
+
{
|
|
5005
|
+
id: "token-expiry-imminent",
|
|
5006
|
+
severity: "warn",
|
|
5007
|
+
evaluate: (snapshot, config) => {
|
|
5008
|
+
if (snapshot === null) return null;
|
|
5009
|
+
if (config.tokenExpiryWarningHours <= 0) return null;
|
|
5010
|
+
const stats = snapshot.totals.tokenStats;
|
|
5011
|
+
if (stats === void 0 || stats.expiringSoon <= 0) return null;
|
|
5012
|
+
return `${stats.expiringSoon} token(s) expire within ${config.tokenExpiryWarningHours}h \u2014 mint replacements before they lapse`;
|
|
5013
|
+
}
|
|
4885
5014
|
}
|
|
4886
5015
|
];
|
|
4887
5016
|
var HqAlertEngine = class {
|
|
@@ -4987,6 +5116,7 @@ function toAlertMessage(alert) {
|
|
|
4987
5116
|
}
|
|
4988
5117
|
export {
|
|
4989
5118
|
DEFAULT_HQ_REDACTION_POLICY,
|
|
5119
|
+
HQ_AUTH_CONTENT_HASH_REDACTED,
|
|
4990
5120
|
HQ_AUTH_FILE_VERSION,
|
|
4991
5121
|
HQ_CLI_DEFAULT_HOST,
|
|
4992
5122
|
HQ_COMMAND_TYPES,
|
|
@@ -5000,9 +5130,11 @@ export {
|
|
|
5000
5130
|
HqSimpleLog,
|
|
5001
5131
|
HqSnapshotStore,
|
|
5002
5132
|
HqTimeseriesStore,
|
|
5133
|
+
appendHqAuthAudit,
|
|
5003
5134
|
assessHqExposure,
|
|
5004
5135
|
buildTranscriptFromEvents,
|
|
5005
5136
|
classifyMailboxRecipient,
|
|
5137
|
+
createBridgeContext,
|
|
5006
5138
|
createGlobalMailbox,
|
|
5007
5139
|
createHqEventEnvelope,
|
|
5008
5140
|
createHqPersistence,
|
|
@@ -5015,10 +5147,14 @@ export {
|
|
|
5015
5147
|
emptyHqAuthFile,
|
|
5016
5148
|
ensureHqFirstRunAuthFile,
|
|
5017
5149
|
hashHqPassword,
|
|
5150
|
+
hqAuthAuditPath,
|
|
5151
|
+
hqAuthContentHash,
|
|
5018
5152
|
hqAuthFilePath,
|
|
5019
5153
|
hqRuntimeFilePath,
|
|
5020
5154
|
isLoopbackHost,
|
|
5021
5155
|
isOpenMode,
|
|
5156
|
+
isTokenExpired,
|
|
5157
|
+
logHqAuthAudit,
|
|
5022
5158
|
mapMailboxAgentToHqSummary,
|
|
5023
5159
|
mapMailboxMessageToHqSummary,
|
|
5024
5160
|
mapSessionEventToEntries,
|