@runcore-sh/runcore 0.1.8 → 0.1.10
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/access/manifest.d.ts +59 -0
- package/dist/access/manifest.d.ts.map +1 -0
- package/dist/access/manifest.js +251 -0
- package/dist/access/manifest.js.map +1 -0
- package/dist/activity/log.d.ts +1 -1
- package/dist/activity/log.d.ts.map +1 -1
- package/dist/agents/autonomous.d.ts.map +1 -1
- package/dist/agents/autonomous.js +38 -0
- package/dist/agents/autonomous.js.map +1 -1
- package/dist/agents/governance.d.ts +70 -0
- package/dist/agents/governance.d.ts.map +1 -0
- package/dist/agents/governance.js +220 -0
- package/dist/agents/governance.js.map +1 -0
- package/dist/agents/governed-spawn.d.ts +83 -0
- package/dist/agents/governed-spawn.d.ts.map +1 -0
- package/dist/agents/governed-spawn.js +186 -0
- package/dist/agents/governed-spawn.js.map +1 -0
- package/dist/agents/heartbeat.d.ts +91 -0
- package/dist/agents/heartbeat.d.ts.map +1 -0
- package/dist/agents/heartbeat.js +323 -0
- package/dist/agents/heartbeat.js.map +1 -0
- package/dist/agents/index.d.ts +4 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +6 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/spawn-policy.d.ts +45 -0
- package/dist/agents/spawn-policy.d.ts.map +1 -0
- package/dist/agents/spawn-policy.js +202 -0
- package/dist/agents/spawn-policy.js.map +1 -0
- package/dist/alert.d.ts +16 -0
- package/dist/alert.d.ts.map +1 -0
- package/dist/alert.js +70 -0
- package/dist/alert.js.map +1 -0
- package/dist/cli.js +261 -32
- package/dist/cli.js.map +1 -1
- package/dist/credentials/store.d.ts +1 -1
- package/dist/credentials/store.d.ts.map +1 -1
- package/dist/credentials/store.js +14 -3
- package/dist/credentials/store.js.map +1 -1
- package/dist/crystallizer.d.ts +56 -0
- package/dist/crystallizer.d.ts.map +1 -0
- package/dist/crystallizer.js +159 -0
- package/dist/crystallizer.js.map +1 -0
- package/dist/distiller.d.ts +48 -0
- package/dist/distiller.d.ts.map +1 -0
- package/dist/distiller.js +140 -0
- package/dist/distiller.js.map +1 -0
- package/dist/files/deep-index.d.ts +59 -0
- package/dist/files/deep-index.d.ts.map +1 -0
- package/dist/files/deep-index.js +337 -0
- package/dist/files/deep-index.js.map +1 -0
- package/dist/files/import.d.ts +44 -0
- package/dist/files/import.d.ts.map +1 -0
- package/dist/files/import.js +213 -0
- package/dist/files/import.js.map +1 -0
- package/dist/files/index-local.d.ts +37 -0
- package/dist/files/index-local.d.ts.map +1 -0
- package/dist/files/index-local.js +198 -0
- package/dist/files/index-local.js.map +1 -0
- package/dist/google/auth.d.ts +2 -0
- package/dist/google/auth.d.ts.map +1 -1
- package/dist/google/auth.js +2 -0
- package/dist/google/auth.js.map +1 -1
- package/dist/integrations/gate.d.ts +40 -0
- package/dist/integrations/gate.d.ts.map +1 -0
- package/dist/integrations/gate.js +100 -0
- package/dist/integrations/gate.js.map +1 -0
- package/dist/lib/audit.d.ts +43 -0
- package/dist/lib/audit.d.ts.map +1 -0
- package/dist/lib/audit.js +120 -0
- package/dist/lib/audit.js.map +1 -0
- package/dist/lib/brain-io.d.ts.map +1 -1
- package/dist/lib/brain-io.js +52 -0
- package/dist/lib/brain-io.js.map +1 -1
- package/dist/lib/dpapi.d.ts +14 -0
- package/dist/lib/dpapi.d.ts.map +1 -0
- package/dist/lib/dpapi.js +104 -0
- package/dist/lib/dpapi.js.map +1 -0
- package/dist/lib/glob-match.d.ts +22 -0
- package/dist/lib/glob-match.d.ts.map +1 -0
- package/dist/lib/glob-match.js +64 -0
- package/dist/lib/glob-match.js.map +1 -0
- package/dist/lib/locked.d.ts +40 -0
- package/dist/lib/locked.d.ts.map +1 -0
- package/dist/lib/locked.js +130 -0
- package/dist/lib/locked.js.map +1 -0
- package/dist/llm/complete.d.ts.map +1 -1
- package/dist/llm/complete.js +5 -2
- package/dist/llm/complete.js.map +1 -1
- package/dist/llm/fetch-guard.d.ts +16 -0
- package/dist/llm/fetch-guard.d.ts.map +1 -0
- package/dist/llm/fetch-guard.js +61 -0
- package/dist/llm/fetch-guard.js.map +1 -0
- package/dist/llm/guard.d.ts +40 -0
- package/dist/llm/guard.d.ts.map +1 -0
- package/dist/llm/guard.js +88 -0
- package/dist/llm/guard.js.map +1 -0
- package/dist/llm/membrane.d.ts +46 -0
- package/dist/llm/membrane.d.ts.map +1 -0
- package/dist/llm/membrane.js +123 -0
- package/dist/llm/membrane.js.map +1 -0
- package/dist/llm/providers/index.d.ts +5 -1
- package/dist/llm/providers/index.d.ts.map +1 -1
- package/dist/llm/providers/index.js +8 -1
- package/dist/llm/providers/index.js.map +1 -1
- package/dist/llm/redact.d.ts +39 -0
- package/dist/llm/redact.d.ts.map +1 -0
- package/dist/llm/redact.js +155 -0
- package/dist/llm/redact.js.map +1 -0
- package/dist/llm/sensitive-registry.d.ts +33 -0
- package/dist/llm/sensitive-registry.d.ts.map +1 -0
- package/dist/llm/sensitive-registry.js +106 -0
- package/dist/llm/sensitive-registry.js.map +1 -0
- package/dist/mcp-server.d.ts +11 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +520 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mdns.d.ts +17 -0
- package/dist/mdns.d.ts.map +1 -0
- package/dist/mdns.js +110 -0
- package/dist/mdns.js.map +1 -0
- package/dist/nerve/push.d.ts +26 -0
- package/dist/nerve/push.d.ts.map +1 -0
- package/dist/nerve/push.js +170 -0
- package/dist/nerve/push.js.map +1 -0
- package/dist/nerve/state.d.ts +35 -0
- package/dist/nerve/state.d.ts.map +1 -0
- package/dist/nerve/state.js +257 -0
- package/dist/nerve/state.js.map +1 -0
- package/dist/posture/engine.d.ts +41 -0
- package/dist/posture/engine.d.ts.map +1 -0
- package/dist/posture/engine.js +217 -0
- package/dist/posture/engine.js.map +1 -0
- package/dist/posture/index.d.ts +11 -0
- package/dist/posture/index.d.ts.map +1 -0
- package/dist/posture/index.js +10 -0
- package/dist/posture/index.js.map +1 -0
- package/dist/posture/middleware.d.ts +30 -0
- package/dist/posture/middleware.d.ts.map +1 -0
- package/dist/posture/middleware.js +92 -0
- package/dist/posture/middleware.js.map +1 -0
- package/dist/posture/types.d.ts +61 -0
- package/dist/posture/types.d.ts.map +1 -0
- package/dist/posture/types.js +48 -0
- package/dist/posture/types.js.map +1 -0
- package/dist/resend/inbox.d.ts +23 -0
- package/dist/resend/inbox.d.ts.map +1 -0
- package/dist/resend/inbox.js +198 -0
- package/dist/resend/inbox.js.map +1 -0
- package/dist/resend/webhooks.d.ts +30 -0
- package/dist/resend/webhooks.d.ts.map +1 -0
- package/dist/resend/webhooks.js +244 -0
- package/dist/resend/webhooks.js.map +1 -0
- package/dist/server.d.ts +5 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +773 -58
- package/dist/server.js.map +1 -1
- package/dist/settings.d.ts +14 -1
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +32 -1
- package/dist/settings.js.map +1 -1
- package/dist/tier/bond.d.ts +51 -0
- package/dist/tier/bond.d.ts.map +1 -0
- package/dist/tier/bond.js +154 -0
- package/dist/tier/bond.js.map +1 -0
- package/dist/tier/freeze.d.ts +21 -0
- package/dist/tier/freeze.d.ts.map +1 -0
- package/dist/tier/freeze.js +73 -0
- package/dist/tier/freeze.js.map +1 -0
- package/dist/tier/gate.d.ts +11 -0
- package/dist/tier/gate.d.ts.map +1 -0
- package/dist/tier/gate.js +25 -0
- package/dist/tier/gate.js.map +1 -0
- package/dist/tier/heartbeat.d.ts +22 -0
- package/dist/tier/heartbeat.d.ts.map +1 -0
- package/dist/tier/heartbeat.js +128 -0
- package/dist/tier/heartbeat.js.map +1 -0
- package/dist/tier/token.d.ts +22 -0
- package/dist/tier/token.d.ts.map +1 -0
- package/dist/tier/token.js +100 -0
- package/dist/tier/token.js.map +1 -0
- package/dist/tier/types.d.ts +44 -0
- package/dist/tier/types.d.ts.map +1 -0
- package/dist/tier/types.js +61 -0
- package/dist/tier/types.js.map +1 -0
- package/dist/updater.d.ts +32 -0
- package/dist/updater.d.ts.map +1 -0
- package/dist/updater.js +145 -0
- package/dist/updater.js.map +1 -0
- package/dist/vault/policy.d.ts +42 -0
- package/dist/vault/policy.d.ts.map +1 -0
- package/dist/vault/policy.js +159 -0
- package/dist/vault/policy.js.map +1 -0
- package/dist/vault/store.d.ts +6 -0
- package/dist/vault/store.d.ts.map +1 -1
- package/dist/vault/store.js +15 -5
- package/dist/vault/store.js.map +1 -1
- package/dist/vault/transfer.d.ts +33 -0
- package/dist/vault/transfer.d.ts.map +1 -0
- package/dist/vault/transfer.js +187 -0
- package/dist/vault/transfer.js.map +1 -0
- package/dist/voucher.d.ts +39 -0
- package/dist/voucher.d.ts.map +1 -0
- package/dist/voucher.js +105 -0
- package/dist/voucher.js.map +1 -0
- package/dist/webhooks/handlers.d.ts +10 -0
- package/dist/webhooks/handlers.d.ts.map +1 -1
- package/dist/webhooks/handlers.js +53 -0
- package/dist/webhooks/handlers.js.map +1 -1
- package/dist/webhooks/index.d.ts +2 -2
- package/dist/webhooks/index.d.ts.map +1 -1
- package/dist/webhooks/index.js +2 -2
- package/dist/webhooks/index.js.map +1 -1
- package/dist/webhooks/verify.d.ts +8 -0
- package/dist/webhooks/verify.d.ts.map +1 -1
- package/dist/webhooks/verify.js +56 -0
- package/dist/webhooks/verify.js.map +1 -1
- package/package.json +8 -2
- package/public/board.html +8 -3
- package/public/browser.html +8 -3
- package/public/library.html +8 -3
- package/public/observatory.html +8 -3
- package/public/ops.html +8 -3
- package/public/registry.html +627 -0
- package/public/roadmap.html +975 -0
package/dist/mdns.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mDNS service announcement for Core board discovery.
|
|
3
|
+
* Announces the HTTP server as `_core-board._tcp.local` so that
|
|
4
|
+
* Dash and other instances can find it on the LAN automatically.
|
|
5
|
+
*
|
|
6
|
+
* Gated behind `settings.mesh.lanAnnounce` — disabled by default.
|
|
7
|
+
*/
|
|
8
|
+
import mdns from "multicast-dns";
|
|
9
|
+
import { hostname } from "node:os";
|
|
10
|
+
import { createLogger } from "./utils/logger.js";
|
|
11
|
+
import { getInstanceName } from "./instance.js";
|
|
12
|
+
const log = createLogger("mdns");
|
|
13
|
+
const SERVICE_TYPE = "_core-board._tcp.local";
|
|
14
|
+
let responder = null;
|
|
15
|
+
let announcedPort = 0;
|
|
16
|
+
/**
|
|
17
|
+
* Start announcing the Core board service on the local network.
|
|
18
|
+
* Call after the HTTP server is listening and the actual port is known.
|
|
19
|
+
*/
|
|
20
|
+
export function startMdns(port) {
|
|
21
|
+
if (responder)
|
|
22
|
+
return; // already running
|
|
23
|
+
announcedPort = port;
|
|
24
|
+
const instance = getInstanceName();
|
|
25
|
+
const host = hostname();
|
|
26
|
+
const serviceName = `${instance}._core-board._tcp.local`;
|
|
27
|
+
responder = mdns();
|
|
28
|
+
// Respond to queries for our service type
|
|
29
|
+
responder.on("query", (query) => {
|
|
30
|
+
const dominated = query.questions.some((q) => q.name === SERVICE_TYPE ||
|
|
31
|
+
q.name === serviceName);
|
|
32
|
+
if (!dominated)
|
|
33
|
+
return;
|
|
34
|
+
responder.respond({
|
|
35
|
+
answers: [
|
|
36
|
+
{
|
|
37
|
+
name: serviceName,
|
|
38
|
+
type: "SRV",
|
|
39
|
+
data: { port: announcedPort, target: host, priority: 0, weight: 0 },
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: serviceName,
|
|
43
|
+
type: "TXT",
|
|
44
|
+
data: [`instance=${instance}`, `port=${announcedPort}`],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: SERVICE_TYPE,
|
|
48
|
+
type: "PTR",
|
|
49
|
+
data: serviceName,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
// Proactive announcement (GBYE → announce pattern)
|
|
55
|
+
responder.respond({
|
|
56
|
+
answers: [
|
|
57
|
+
{
|
|
58
|
+
name: SERVICE_TYPE,
|
|
59
|
+
type: "PTR",
|
|
60
|
+
data: serviceName,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: serviceName,
|
|
64
|
+
type: "SRV",
|
|
65
|
+
data: { port: announcedPort, target: host, priority: 0, weight: 0 },
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: serviceName,
|
|
69
|
+
type: "TXT",
|
|
70
|
+
data: [`instance=${instance}`, `port=${announcedPort}`],
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
log.info(`mDNS announcing ${serviceName} on port ${announcedPort}`);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Stop the mDNS responder and send a goodbye packet.
|
|
78
|
+
*/
|
|
79
|
+
export function stopMdns() {
|
|
80
|
+
if (!responder)
|
|
81
|
+
return;
|
|
82
|
+
const instance = getInstanceName();
|
|
83
|
+
const serviceName = `${instance}._core-board._tcp.local`;
|
|
84
|
+
// Send goodbye (TTL=0) so peers flush the record immediately
|
|
85
|
+
try {
|
|
86
|
+
responder.respond({
|
|
87
|
+
answers: [
|
|
88
|
+
{
|
|
89
|
+
name: SERVICE_TYPE,
|
|
90
|
+
type: "PTR",
|
|
91
|
+
data: serviceName,
|
|
92
|
+
ttl: 0,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: serviceName,
|
|
96
|
+
type: "SRV",
|
|
97
|
+
data: { port: announcedPort, target: hostname(), priority: 0, weight: 0 },
|
|
98
|
+
ttl: 0,
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// best-effort goodbye
|
|
105
|
+
}
|
|
106
|
+
responder.destroy();
|
|
107
|
+
responder = null;
|
|
108
|
+
log.info("mDNS responder stopped");
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=mdns.js.map
|
package/dist/mdns.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mdns.js","sourceRoot":"","sources":["../src/mdns.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,IAAI,MAAM,eAAe,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;AAEjC,MAAM,YAAY,GAAG,wBAAwB,CAAC;AAE9C,IAAI,SAAS,GAAmC,IAAI,CAAC;AACrD,IAAI,aAAa,GAAG,CAAC,CAAC;AAEtB;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,SAAS;QAAE,OAAO,CAAC,kBAAkB;IAEzC,aAAa,GAAG,IAAI,CAAC;IACrB,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IACxB,MAAM,WAAW,GAAG,GAAG,QAAQ,yBAAyB,CAAC;IAEzD,SAAS,GAAG,IAAI,EAAE,CAAC;IAEnB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;QAC9B,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CACpC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,KAAK,YAAY;YACvB,CAAC,CAAC,IAAI,KAAK,WAAW,CACzB,CAAC;QACF,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,SAAU,CAAC,OAAO,CAAC;YACjB,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,KAAK;oBACX,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;iBACpE;gBACD;oBACE,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,KAAK;oBACX,IAAI,EAAE,CAAC,YAAY,QAAQ,EAAE,EAAE,QAAQ,aAAa,EAAE,CAAC;iBACxD;gBACD;oBACE,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,KAAK;oBACX,IAAI,EAAE,WAAW;iBAClB;aACF;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,mDAAmD;IACnD,SAAS,CAAC,OAAO,CAAC;QAChB,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,WAAW;aAClB;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;aACpE;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,CAAC,YAAY,QAAQ,EAAE,EAAE,QAAQ,aAAa,EAAE,CAAC;aACxD;SACF;KACF,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,mBAAmB,WAAW,YAAY,aAAa,EAAE,CAAC,CAAC;AACtE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC,SAAS;QAAE,OAAO;IAEvB,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,WAAW,GAAG,GAAG,QAAQ,yBAAyB,CAAC;IAEzD,6DAA6D;IAC7D,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC;YAChB,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,KAAK;oBACX,IAAI,EAAE,WAAW;oBACjB,GAAG,EAAE,CAAC;iBACP;gBACD;oBACE,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,KAAK;oBACX,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;oBACzE,GAAG,EAAE,CAAC;iBACP;aACF;SACF,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;IAED,SAAS,CAAC,OAAO,EAAE,CAAC;IACpB,SAAS,GAAG,IAAI,CAAC;IACjB,GAAG,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Push — sends notifications to nerve endings (phone, browser, etc.)
|
|
3
|
+
*
|
|
4
|
+
* VAPID keys generated on first run and stored in brain/identity/.
|
|
5
|
+
* Subscriptions stored in brain/memory/push-subscriptions.jsonl.
|
|
6
|
+
* Stateless: any instance can send to any subscribed nerve.
|
|
7
|
+
*/
|
|
8
|
+
import type { NerveState } from "./state.js";
|
|
9
|
+
/** Initialize VAPID keys — generate on first run, load on subsequent. */
|
|
10
|
+
export declare function initPush(): Promise<string>;
|
|
11
|
+
/** Get the VAPID public key (needed by clients to subscribe). */
|
|
12
|
+
export declare function getVapidPublicKey(): string;
|
|
13
|
+
/** Store a push subscription from a nerve endpoint. */
|
|
14
|
+
export declare function addSubscription(subscription: {
|
|
15
|
+
endpoint: string;
|
|
16
|
+
keys: {
|
|
17
|
+
p256dh: string;
|
|
18
|
+
auth: string;
|
|
19
|
+
};
|
|
20
|
+
}, label?: string): Promise<string>;
|
|
21
|
+
/** Send a push notification to all subscribed nerve endings. */
|
|
22
|
+
export declare function pushToAll(title: string, body: string, data?: Record<string, unknown>): Promise<number>;
|
|
23
|
+
export declare function checkAndNotify(state: NerveState): Promise<void>;
|
|
24
|
+
export declare function startPushMonitor(getState: () => Promise<NerveState>, intervalMs?: number): void;
|
|
25
|
+
export declare function stopPushMonitor(): void;
|
|
26
|
+
//# sourceMappingURL=push.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/nerve/push.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAsBvD,yEAAyE;AACzE,wBAAsB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAqBhD;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,IAAI,MAAM,CAG1C;AAED,uDAAuD;AACvD,wBAAsB,eAAe,CACnC,YAAY,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAC1E,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAYjB;AAyBD,gEAAgE;AAChE,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA6B5G;AAKD,wBAAsB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BrE;AAQD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,EACnC,UAAU,SAAS,GAClB,IAAI,CAeN;AAED,wBAAgB,eAAe,IAAI,IAAI,CAMtC"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Push — sends notifications to nerve endings (phone, browser, etc.)
|
|
3
|
+
*
|
|
4
|
+
* VAPID keys generated on first run and stored in brain/identity/.
|
|
5
|
+
* Subscriptions stored in brain/memory/push-subscriptions.jsonl.
|
|
6
|
+
* Stateless: any instance can send to any subscribed nerve.
|
|
7
|
+
*/
|
|
8
|
+
import webPush from "web-push";
|
|
9
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
10
|
+
import { existsSync } from "node:fs";
|
|
11
|
+
import { join, resolve } from "node:path";
|
|
12
|
+
import { readBrainLines, appendBrainLine, ensureBrainJsonl } from "../lib/brain-io.js";
|
|
13
|
+
import { createLogger } from "../utils/logger.js";
|
|
14
|
+
const log = createLogger("nerve-push");
|
|
15
|
+
const BRAIN_DIR = resolve(process.cwd(), "brain");
|
|
16
|
+
const KEYS_PATH = join(BRAIN_DIR, "identity", ".vapid-keys.json");
|
|
17
|
+
const SUBS_PATH = join(BRAIN_DIR, "memory", "push-subscriptions.jsonl");
|
|
18
|
+
let vapidKeys = null;
|
|
19
|
+
/** Initialize VAPID keys — generate on first run, load on subsequent. */
|
|
20
|
+
export async function initPush() {
|
|
21
|
+
if (existsSync(KEYS_PATH)) {
|
|
22
|
+
const raw = await readFile(KEYS_PATH, "utf-8");
|
|
23
|
+
vapidKeys = JSON.parse(raw);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
const keys = webPush.generateVAPIDKeys();
|
|
27
|
+
vapidKeys = { publicKey: keys.publicKey, privateKey: keys.privateKey };
|
|
28
|
+
await mkdir(join(BRAIN_DIR, "identity"), { recursive: true });
|
|
29
|
+
await writeFile(KEYS_PATH, JSON.stringify(vapidKeys, null, 2), "utf-8");
|
|
30
|
+
log.info("Generated new VAPID keys");
|
|
31
|
+
}
|
|
32
|
+
webPush.setVapidDetails("mailto:hello@herrmangroup.com", vapidKeys.publicKey, vapidKeys.privateKey);
|
|
33
|
+
await ensureBrainJsonl(SUBS_PATH, JSON.stringify({ _schema: "push-subscriptions", _version: "1.0" }));
|
|
34
|
+
log.info("Push notifications initialized");
|
|
35
|
+
return vapidKeys.publicKey;
|
|
36
|
+
}
|
|
37
|
+
/** Get the VAPID public key (needed by clients to subscribe). */
|
|
38
|
+
export function getVapidPublicKey() {
|
|
39
|
+
if (!vapidKeys)
|
|
40
|
+
throw new Error("Push not initialized");
|
|
41
|
+
return vapidKeys.publicKey;
|
|
42
|
+
}
|
|
43
|
+
/** Store a push subscription from a nerve endpoint. */
|
|
44
|
+
export async function addSubscription(subscription, label) {
|
|
45
|
+
const id = `push_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
|
|
46
|
+
const record = {
|
|
47
|
+
id,
|
|
48
|
+
endpoint: subscription.endpoint,
|
|
49
|
+
keys: subscription.keys,
|
|
50
|
+
createdAt: new Date().toISOString(),
|
|
51
|
+
label,
|
|
52
|
+
};
|
|
53
|
+
await appendBrainLine(SUBS_PATH, JSON.stringify(record));
|
|
54
|
+
log.info(`Push subscription added: ${id}${label ? ` (${label})` : ""}`);
|
|
55
|
+
return id;
|
|
56
|
+
}
|
|
57
|
+
/** Load all active subscriptions. */
|
|
58
|
+
async function loadSubscriptions() {
|
|
59
|
+
const lines = await readBrainLines(SUBS_PATH);
|
|
60
|
+
const subs = [];
|
|
61
|
+
const removed = new Set();
|
|
62
|
+
for (const line of lines) {
|
|
63
|
+
try {
|
|
64
|
+
const obj = JSON.parse(line);
|
|
65
|
+
if (obj._schema)
|
|
66
|
+
continue;
|
|
67
|
+
if (obj.status === "removed" && obj.id) {
|
|
68
|
+
removed.add(obj.id);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (obj.id && obj.endpoint)
|
|
72
|
+
subs.push(obj);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return subs.filter(s => !removed.has(s.id));
|
|
79
|
+
}
|
|
80
|
+
/** Remove a dead subscription (append-only). */
|
|
81
|
+
async function removeSubscription(id) {
|
|
82
|
+
await appendBrainLine(SUBS_PATH, JSON.stringify({ id, status: "removed", removedAt: new Date().toISOString() }));
|
|
83
|
+
}
|
|
84
|
+
/** Send a push notification to all subscribed nerve endings. */
|
|
85
|
+
export async function pushToAll(title, body, data) {
|
|
86
|
+
const subs = await loadSubscriptions();
|
|
87
|
+
let sent = 0;
|
|
88
|
+
for (const sub of subs) {
|
|
89
|
+
const pushSub = {
|
|
90
|
+
endpoint: sub.endpoint,
|
|
91
|
+
keys: sub.keys,
|
|
92
|
+
};
|
|
93
|
+
try {
|
|
94
|
+
await webPush.sendNotification(pushSub, JSON.stringify({
|
|
95
|
+
title,
|
|
96
|
+
body,
|
|
97
|
+
data: { ...data, timestamp: new Date().toISOString() },
|
|
98
|
+
}));
|
|
99
|
+
sent++;
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (err.statusCode === 410 || err.statusCode === 404) {
|
|
103
|
+
// Subscription expired or invalid — remove it
|
|
104
|
+
await removeSubscription(sub.id);
|
|
105
|
+
log.info(`Removed expired subscription: ${sub.id}`);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
log.warn(`Push failed for ${sub.id}: ${err.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return sent;
|
|
113
|
+
}
|
|
114
|
+
/** Map nerve state to push notification when dots change. */
|
|
115
|
+
let lastState = null;
|
|
116
|
+
export async function checkAndNotify(state) {
|
|
117
|
+
const current = {
|
|
118
|
+
sense: state.sense.color,
|
|
119
|
+
work: state.work.color,
|
|
120
|
+
joy: state.joy.color,
|
|
121
|
+
};
|
|
122
|
+
if (!lastState) {
|
|
123
|
+
lastState = current;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// Only notify on transitions TO amber
|
|
127
|
+
const transitions = [];
|
|
128
|
+
if (current.sense === "amber" && lastState.sense !== "amber") {
|
|
129
|
+
transitions.push(`Sense: ${state.sense.label} — ${state.sense.detail}`);
|
|
130
|
+
}
|
|
131
|
+
if (current.work === "amber" && lastState.work !== "amber") {
|
|
132
|
+
transitions.push(`Work: ${state.work.label} — ${state.work.detail}`);
|
|
133
|
+
}
|
|
134
|
+
if (current.joy === "amber" && lastState.joy !== "amber") {
|
|
135
|
+
transitions.push(`Joy: ${state.joy.label} — ${state.joy.detail}`);
|
|
136
|
+
}
|
|
137
|
+
lastState = current;
|
|
138
|
+
if (transitions.length > 0) {
|
|
139
|
+
const body = transitions.join("\n");
|
|
140
|
+
await pushToAll("Attention", body, { state: current });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// ── Background push monitor ─────────────────────────────────────────────────
|
|
144
|
+
// Runs server-side on a timer, independent of any client connection.
|
|
145
|
+
// This is what makes push work when the phone is in your pocket.
|
|
146
|
+
let monitorInterval = null;
|
|
147
|
+
export function startPushMonitor(getState, intervalMs = 30_000) {
|
|
148
|
+
if (monitorInterval)
|
|
149
|
+
return;
|
|
150
|
+
monitorInterval = setInterval(async () => {
|
|
151
|
+
try {
|
|
152
|
+
const state = await getState();
|
|
153
|
+
await checkAndNotify(state);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
log.warn("Push monitor tick failed", {
|
|
157
|
+
error: err instanceof Error ? err.message : String(err),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}, intervalMs);
|
|
161
|
+
log.info(`Push monitor started: checking every ${intervalMs / 1000}s`);
|
|
162
|
+
}
|
|
163
|
+
export function stopPushMonitor() {
|
|
164
|
+
if (monitorInterval) {
|
|
165
|
+
clearInterval(monitorInterval);
|
|
166
|
+
monitorInterval = null;
|
|
167
|
+
log.info("Push monitor stopped");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=push.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/nerve/push.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nerve State — translates raw system internals into three-dot field.
|
|
3
|
+
*
|
|
4
|
+
* Three dots: Sense, Work, Joy.
|
|
5
|
+
* Three colors: blue (calm), green (moving), amber (attention).
|
|
6
|
+
* No identities. No agent names. Just aggregate state.
|
|
7
|
+
*
|
|
8
|
+
* The public API is a feeling.
|
|
9
|
+
*/
|
|
10
|
+
export declare function setPendingUpdate(info: {
|
|
11
|
+
current: string;
|
|
12
|
+
latest: string;
|
|
13
|
+
}): void;
|
|
14
|
+
export declare function clearPendingUpdate(): void;
|
|
15
|
+
export type DotColor = "blue" | "green" | "amber";
|
|
16
|
+
export interface DotState {
|
|
17
|
+
color: DotColor;
|
|
18
|
+
label: string;
|
|
19
|
+
detail: string;
|
|
20
|
+
items: DrilldownItem[];
|
|
21
|
+
}
|
|
22
|
+
export interface DrilldownItem {
|
|
23
|
+
text: string;
|
|
24
|
+
age?: string;
|
|
25
|
+
type: "info" | "active" | "attention";
|
|
26
|
+
}
|
|
27
|
+
export interface NerveState {
|
|
28
|
+
sense: DotState;
|
|
29
|
+
work: DotState;
|
|
30
|
+
joy: DotState;
|
|
31
|
+
timestamp: string;
|
|
32
|
+
}
|
|
33
|
+
/** Get the full nerve state — three dots of field. */
|
|
34
|
+
export declare function getNerveState(): Promise<NerveState>;
|
|
35
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/nerve/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAaH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAEhF;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAElD,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC;CACvC;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,QAAQ,CAAC;IAChB,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,QAAQ,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AA8ND,sDAAsD;AACtD,wBAAsB,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAazD"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nerve State — translates raw system internals into three-dot field.
|
|
3
|
+
*
|
|
4
|
+
* Three dots: Sense, Work, Joy.
|
|
5
|
+
* Three colors: blue (calm), green (moving), amber (attention).
|
|
6
|
+
* No identities. No agent names. Just aggregate state.
|
|
7
|
+
*
|
|
8
|
+
* The public API is a feeling.
|
|
9
|
+
*/
|
|
10
|
+
import { getPressureIntegrator } from "../pulse/pressure.js";
|
|
11
|
+
import { getBoardProvider } from "../board/provider.js";
|
|
12
|
+
import { listTasks as listAgentTasks } from "../agents/index.js";
|
|
13
|
+
import { readBrainLines } from "../lib/brain-io.js";
|
|
14
|
+
import { join, resolve } from "node:path";
|
|
15
|
+
const BRAIN_DIR = resolve(process.cwd(), "brain");
|
|
16
|
+
// Pending major update — set by auto-updater, read by Sense dot
|
|
17
|
+
let pendingUpdate = null;
|
|
18
|
+
export function setPendingUpdate(info) {
|
|
19
|
+
pendingUpdate = info;
|
|
20
|
+
}
|
|
21
|
+
export function clearPendingUpdate() {
|
|
22
|
+
pendingUpdate = null;
|
|
23
|
+
}
|
|
24
|
+
function ago(ms) {
|
|
25
|
+
if (ms < 60_000)
|
|
26
|
+
return "just now";
|
|
27
|
+
if (ms < 3_600_000)
|
|
28
|
+
return `${Math.floor(ms / 60_000)}m ago`;
|
|
29
|
+
if (ms < 86_400_000)
|
|
30
|
+
return `${Math.floor(ms / 3_600_000)}h ago`;
|
|
31
|
+
return `${Math.floor(ms / 86_400_000)}d ago`;
|
|
32
|
+
}
|
|
33
|
+
/** Read open loops from crystallizer JSONL. */
|
|
34
|
+
async function getOpenLoops() {
|
|
35
|
+
try {
|
|
36
|
+
const lines = await readBrainLines(join(BRAIN_DIR, "memory", "open-loops.jsonl"));
|
|
37
|
+
const loopMap = new Map();
|
|
38
|
+
for (const line of lines) {
|
|
39
|
+
try {
|
|
40
|
+
const obj = JSON.parse(line);
|
|
41
|
+
if (obj._schema)
|
|
42
|
+
continue;
|
|
43
|
+
if (obj.id)
|
|
44
|
+
loopMap.set(obj.id, obj);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const loops = Array.from(loopMap.values());
|
|
51
|
+
return {
|
|
52
|
+
open: loops.filter((l) => l.status === "open").length,
|
|
53
|
+
precipitated: loops.filter((l) => l.status === "precipitated").length,
|
|
54
|
+
items: loops.filter((l) => l.status === "open" || l.status === "precipitated"),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return { open: 0, precipitated: 0, items: [] };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Read recent notifications. */
|
|
62
|
+
async function getRecentNotifications() {
|
|
63
|
+
try {
|
|
64
|
+
const lines = await readBrainLines(join(BRAIN_DIR, "operations", "notifications.jsonl"));
|
|
65
|
+
const cutoff = Date.now() - 24 * 60 * 60 * 1000; // last 24h
|
|
66
|
+
const recent = [];
|
|
67
|
+
for (const line of lines) {
|
|
68
|
+
try {
|
|
69
|
+
const obj = JSON.parse(line);
|
|
70
|
+
if (obj._schema)
|
|
71
|
+
continue;
|
|
72
|
+
if (obj.timestamp && new Date(obj.timestamp).getTime() > cutoff) {
|
|
73
|
+
recent.push(obj);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { count: recent.length, items: recent.slice(-10).reverse() };
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return { count: 0, items: [] };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Compute Sense dot — what the system is perceiving. */
|
|
87
|
+
async function computeSense() {
|
|
88
|
+
const integrator = getPressureIntegrator();
|
|
89
|
+
const loops = await getOpenLoops();
|
|
90
|
+
const notifs = await getRecentNotifications();
|
|
91
|
+
const items = [];
|
|
92
|
+
// Voltage state
|
|
93
|
+
let voltageColor = "blue";
|
|
94
|
+
let voltageLabel = "Quiet";
|
|
95
|
+
if (integrator) {
|
|
96
|
+
const status = integrator.getStatus();
|
|
97
|
+
if (status.voltage > status.threshold * 0.7) {
|
|
98
|
+
voltageColor = "amber";
|
|
99
|
+
voltageLabel = "Pressure building";
|
|
100
|
+
items.push({ text: `Voltage: ${Math.round(status.voltage)}/${status.threshold}mV`, type: "attention" });
|
|
101
|
+
}
|
|
102
|
+
else if (status.voltage > status.threshold * 0.3) {
|
|
103
|
+
voltageColor = "green";
|
|
104
|
+
voltageLabel = "Active";
|
|
105
|
+
items.push({ text: `Voltage: ${Math.round(status.voltage)}/${status.threshold}mV`, type: "active" });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Precipitated loops = amber
|
|
109
|
+
if (loops.precipitated > 0) {
|
|
110
|
+
voltageColor = "amber";
|
|
111
|
+
voltageLabel = "Something crystallized";
|
|
112
|
+
for (const l of loops.items.filter((l) => l.status === "precipitated")) {
|
|
113
|
+
items.push({ text: `Precipitated: "${l.query}"`, type: "attention" });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Open loops
|
|
117
|
+
if (loops.open > 0) {
|
|
118
|
+
items.push({ text: `${loops.open} open loop${loops.open !== 1 ? "s" : ""} filtering`, type: "info" });
|
|
119
|
+
for (const l of loops.items.filter((l) => l.status === "open").slice(0, 3)) {
|
|
120
|
+
const evidence = l.evidence?.length ?? 0;
|
|
121
|
+
items.push({ text: `"${l.query}" — ${evidence}/${l.threshold} evidence`, type: "active" });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Pending major update
|
|
125
|
+
if (pendingUpdate) {
|
|
126
|
+
voltageColor = "amber";
|
|
127
|
+
voltageLabel = "Update available";
|
|
128
|
+
items.push({ text: `Core ${pendingUpdate.latest} available (UI changes)`, type: "attention" });
|
|
129
|
+
}
|
|
130
|
+
// Recent notifications
|
|
131
|
+
if (notifs.count > 0) {
|
|
132
|
+
items.push({ text: `${notifs.count} notification${notifs.count !== 1 ? "s" : ""} in last 24h`, type: "info" });
|
|
133
|
+
}
|
|
134
|
+
const detail = items.length === 0
|
|
135
|
+
? "Nothing to report"
|
|
136
|
+
: items.filter(i => i.type !== "info").map(i => i.text).join(". ") || `${loops.open} loops, ${notifs.count} notifications`;
|
|
137
|
+
return {
|
|
138
|
+
color: voltageColor,
|
|
139
|
+
label: voltageLabel,
|
|
140
|
+
detail,
|
|
141
|
+
items,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/** Compute Work dot — what's in motion. */
|
|
145
|
+
async function computeWork() {
|
|
146
|
+
const items = [];
|
|
147
|
+
let color = "blue";
|
|
148
|
+
let label = "Idle";
|
|
149
|
+
// Agent tasks
|
|
150
|
+
try {
|
|
151
|
+
const tasks = await listAgentTasks();
|
|
152
|
+
const running = tasks.filter((t) => t.status === "running");
|
|
153
|
+
const queued = tasks.filter((t) => t.status === "queued");
|
|
154
|
+
const failed = tasks.filter((t) => t.status === "failed");
|
|
155
|
+
const completed = tasks.filter((t) => t.status === "completed");
|
|
156
|
+
if (running.length > 0) {
|
|
157
|
+
color = "green";
|
|
158
|
+
label = "Working";
|
|
159
|
+
items.push({ text: `${running.length} agent${running.length !== 1 ? "s" : ""} running`, type: "active" });
|
|
160
|
+
}
|
|
161
|
+
if (queued.length > 0) {
|
|
162
|
+
items.push({ text: `${queued.length} queued`, type: "info" });
|
|
163
|
+
}
|
|
164
|
+
if (failed.length > 0) {
|
|
165
|
+
color = "amber";
|
|
166
|
+
label = "Needs attention";
|
|
167
|
+
items.push({ text: `${failed.length} failed`, type: "attention" });
|
|
168
|
+
}
|
|
169
|
+
if (completed.length > 0) {
|
|
170
|
+
items.push({ text: `${completed.length} completed`, type: "info" });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch { /* agents not initialized */ }
|
|
174
|
+
// Board items
|
|
175
|
+
try {
|
|
176
|
+
const board = getBoardProvider();
|
|
177
|
+
if (board) {
|
|
178
|
+
const issues = await board.listIssues() ?? [];
|
|
179
|
+
const todo = issues.filter((i) => i.state === "todo" || i.state === "open");
|
|
180
|
+
const inProgress = issues.filter((i) => i.state === "in_progress" || i.state === "doing");
|
|
181
|
+
if (inProgress.length > 0) {
|
|
182
|
+
if (color === "blue") {
|
|
183
|
+
color = "green";
|
|
184
|
+
label = "In progress";
|
|
185
|
+
}
|
|
186
|
+
items.push({ text: `${inProgress.length} board item${inProgress.length !== 1 ? "s" : ""} in progress`, type: "active" });
|
|
187
|
+
}
|
|
188
|
+
if (todo.length > 0) {
|
|
189
|
+
items.push({ text: `${todo.length} in backlog`, type: "info" });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch { /* board not available */ }
|
|
194
|
+
const detail = items.length === 0
|
|
195
|
+
? "Nothing in motion"
|
|
196
|
+
: items.filter(i => i.type !== "info").map(i => i.text).join(". ") || "Quiet";
|
|
197
|
+
return { color, label, detail, items };
|
|
198
|
+
}
|
|
199
|
+
/** Compute Joy dot — how outcomes feel. */
|
|
200
|
+
async function computeJoy() {
|
|
201
|
+
const items = [];
|
|
202
|
+
let color = "blue";
|
|
203
|
+
let label = "Steady";
|
|
204
|
+
// Check for precipitated loops (crystallized answers = joy)
|
|
205
|
+
const loops = await getOpenLoops();
|
|
206
|
+
if (loops.precipitated > 0) {
|
|
207
|
+
color = "green";
|
|
208
|
+
label = "Discovery";
|
|
209
|
+
items.push({ text: `${loops.precipitated} question${loops.precipitated !== 1 ? "s" : ""} answered themselves`, type: "active" });
|
|
210
|
+
}
|
|
211
|
+
// Recent completions
|
|
212
|
+
try {
|
|
213
|
+
const tasks = await listAgentTasks();
|
|
214
|
+
const now = Date.now();
|
|
215
|
+
const recentCompleted = tasks.filter((t) => {
|
|
216
|
+
if (t.status !== "completed")
|
|
217
|
+
return false;
|
|
218
|
+
const completedAt = t.completedAt ? new Date(t.completedAt).getTime() : 0;
|
|
219
|
+
return now - completedAt < 3_600_000; // last hour
|
|
220
|
+
});
|
|
221
|
+
if (recentCompleted.length > 0) {
|
|
222
|
+
if (color === "blue") {
|
|
223
|
+
color = "green";
|
|
224
|
+
label = "Productive";
|
|
225
|
+
}
|
|
226
|
+
items.push({ text: `${recentCompleted.length} task${recentCompleted.length !== 1 ? "s" : ""} completed this hour`, type: "active" });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch { /* agents not initialized */ }
|
|
230
|
+
// Check for notifications needing human input
|
|
231
|
+
const notifs = await getRecentNotifications();
|
|
232
|
+
const needsHuman = notifs.items.filter((n) => n.message?.includes("NEEDS_HUMAN") || n.message?.includes("needs your input"));
|
|
233
|
+
if (needsHuman.length > 0) {
|
|
234
|
+
color = "amber";
|
|
235
|
+
label = "Waiting on you";
|
|
236
|
+
items.push({ text: `${needsHuman.length} item${needsHuman.length !== 1 ? "s" : ""} waiting for your input`, type: "attention" });
|
|
237
|
+
}
|
|
238
|
+
const detail = items.length === 0
|
|
239
|
+
? "All good"
|
|
240
|
+
: items.map(i => i.text).join(". ");
|
|
241
|
+
return { color, label, detail, items };
|
|
242
|
+
}
|
|
243
|
+
/** Get the full nerve state — three dots of field. */
|
|
244
|
+
export async function getNerveState() {
|
|
245
|
+
const [sense, work, joy] = await Promise.all([
|
|
246
|
+
computeSense(),
|
|
247
|
+
computeWork(),
|
|
248
|
+
computeJoy(),
|
|
249
|
+
]);
|
|
250
|
+
return {
|
|
251
|
+
sense,
|
|
252
|
+
work,
|
|
253
|
+
joy,
|
|
254
|
+
timestamp: new Date().toISOString(),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/nerve/state.ts"],"names":[],"mappings":"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"}
|