@av-pi-studio/server 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +411 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/agent/agent-manager.d.ts +107 -0
- package/dist/agent/agent-manager.d.ts.map +1 -0
- package/dist/agent/agent-manager.js +218 -0
- package/dist/agent/agent-manager.js.map +1 -0
- package/dist/agent/agent-service.d.ts +36 -0
- package/dist/agent/agent-service.d.ts.map +1 -0
- package/dist/agent/agent-service.js +195 -0
- package/dist/agent/agent-service.js.map +1 -0
- package/dist/agent/index.d.ts +17 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +18 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/manifest.d.ts +7 -0
- package/dist/agent/manifest.d.ts.map +1 -0
- package/dist/agent/manifest.js +27 -0
- package/dist/agent/manifest.js.map +1 -0
- package/dist/agent/mcp-server.d.ts +100 -0
- package/dist/agent/mcp-server.d.ts.map +1 -0
- package/dist/agent/mcp-server.js +163 -0
- package/dist/agent/mcp-server.js.map +1 -0
- package/dist/agent/permissions.d.ts +71 -0
- package/dist/agent/permissions.d.ts.map +1 -0
- package/dist/agent/permissions.js +132 -0
- package/dist/agent/permissions.js.map +1 -0
- package/dist/agent/provider-contract.d.ts +134 -0
- package/dist/agent/provider-contract.d.ts.map +1 -0
- package/dist/agent/provider-contract.js +2 -0
- package/dist/agent/provider-contract.js.map +1 -0
- package/dist/agent/provider-registry.d.ts +37 -0
- package/dist/agent/provider-registry.d.ts.map +1 -0
- package/dist/agent/provider-registry.js +92 -0
- package/dist/agent/provider-registry.js.map +1 -0
- package/dist/agent/provider-snapshot.d.ts +52 -0
- package/dist/agent/provider-snapshot.d.ts.map +1 -0
- package/dist/agent/provider-snapshot.js +73 -0
- package/dist/agent/provider-snapshot.js.map +1 -0
- package/dist/agent/providers/mock/mock-provider.d.ts +44 -0
- package/dist/agent/providers/mock/mock-provider.d.ts.map +1 -0
- package/dist/agent/providers/mock/mock-provider.js +162 -0
- package/dist/agent/providers/mock/mock-provider.js.map +1 -0
- package/dist/agent/providers/pi/agent.d.ts +80 -0
- package/dist/agent/providers/pi/agent.d.ts.map +1 -0
- package/dist/agent/providers/pi/agent.js +322 -0
- package/dist/agent/providers/pi/agent.js.map +1 -0
- package/dist/agent/providers/pi/event-mapper.d.ts +17 -0
- package/dist/agent/providers/pi/event-mapper.d.ts.map +1 -0
- package/dist/agent/providers/pi/event-mapper.js +150 -0
- package/dist/agent/providers/pi/event-mapper.js.map +1 -0
- package/dist/agent/providers/pi/rpc-transport.d.ts +53 -0
- package/dist/agent/providers/pi/rpc-transport.d.ts.map +1 -0
- package/dist/agent/providers/pi/rpc-transport.js +190 -0
- package/dist/agent/providers/pi/rpc-transport.js.map +1 -0
- package/dist/agent/providers/pi/session-hydration.d.ts +11 -0
- package/dist/agent/providers/pi/session-hydration.d.ts.map +1 -0
- package/dist/agent/providers/pi/session-hydration.js +167 -0
- package/dist/agent/providers/pi/session-hydration.js.map +1 -0
- package/dist/agent/rewind-rpc.d.ts +15 -0
- package/dist/agent/rewind-rpc.d.ts.map +1 -0
- package/dist/agent/rewind-rpc.js +30 -0
- package/dist/agent/rewind-rpc.js.map +1 -0
- package/dist/agent/session-operations.d.ts +32 -0
- package/dist/agent/session-operations.d.ts.map +1 -0
- package/dist/agent/session-operations.js +130 -0
- package/dist/agent/session-operations.js.map +1 -0
- package/dist/agent/structured-generation.d.ts +39 -0
- package/dist/agent/structured-generation.d.ts.map +1 -0
- package/dist/agent/structured-generation.js +78 -0
- package/dist/agent/structured-generation.js.map +1 -0
- package/dist/agent/timeline-rpc.d.ts +21 -0
- package/dist/agent/timeline-rpc.d.ts.map +1 -0
- package/dist/agent/timeline-rpc.js +59 -0
- package/dist/agent/timeline-rpc.js.map +1 -0
- package/dist/agent/timeline-store.d.ts +100 -0
- package/dist/agent/timeline-store.d.ts.map +1 -0
- package/dist/agent/timeline-store.js +255 -0
- package/dist/agent/timeline-store.js.map +1 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +3 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/password-auth.d.ts +44 -0
- package/dist/auth/password-auth.d.ts.map +1 -0
- package/dist/auth/password-auth.js +78 -0
- package/dist/auth/password-auth.js.map +1 -0
- package/dist/config/daemon-config.d.ts +634 -0
- package/dist/config/daemon-config.d.ts.map +1 -0
- package/dist/config/daemon-config.js +258 -0
- package/dist/config/daemon-config.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/project-config.d.ts +104 -0
- package/dist/config/project-config.d.ts.map +1 -0
- package/dist/config/project-config.js +106 -0
- package/dist/config/project-config.js.map +1 -0
- package/dist/daemon/bootstrap.d.ts +37 -0
- package/dist/daemon/bootstrap.d.ts.map +1 -0
- package/dist/daemon/bootstrap.js +448 -0
- package/dist/daemon/bootstrap.js.map +1 -0
- package/dist/daemon/dev-bootstrap.d.ts +14 -0
- package/dist/daemon/dev-bootstrap.d.ts.map +1 -0
- package/dist/daemon/dev-bootstrap.js +231 -0
- package/dist/daemon/dev-bootstrap.js.map +1 -0
- package/dist/daemon/dev-main.d.ts +3 -0
- package/dist/daemon/dev-main.d.ts.map +1 -0
- package/dist/daemon/dev-main.js +36 -0
- package/dist/daemon/dev-main.js.map +1 -0
- package/dist/daemon/index.d.ts +15 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +21 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/main.d.ts +3 -0
- package/dist/daemon/main.d.ts.map +1 -0
- package/dist/daemon/main.js +29 -0
- package/dist/daemon/main.js.map +1 -0
- package/dist/daemon/orchestration-rpc.d.ts +19 -0
- package/dist/daemon/orchestration-rpc.d.ts.map +1 -0
- package/dist/daemon/orchestration-rpc.js +136 -0
- package/dist/daemon/orchestration-rpc.js.map +1 -0
- package/dist/files/download-token-store.d.ts +14 -0
- package/dist/files/download-token-store.d.ts.map +1 -0
- package/dist/files/download-token-store.js +33 -0
- package/dist/files/download-token-store.js.map +1 -0
- package/dist/files/file-explorer.d.ts +54 -0
- package/dist/files/file-explorer.d.ts.map +1 -0
- package/dist/files/file-explorer.js +182 -0
- package/dist/files/file-explorer.js.map +1 -0
- package/dist/files/file-transfer.d.ts +30 -0
- package/dist/files/file-transfer.d.ts.map +1 -0
- package/dist/files/file-transfer.js +132 -0
- package/dist/files/file-transfer.js.map +1 -0
- package/dist/files/index.d.ts +4 -0
- package/dist/files/index.d.ts.map +1 -0
- package/dist/files/index.js +5 -0
- package/dist/files/index.js.map +1 -0
- package/dist/http/host-allowlist.d.ts +15 -0
- package/dist/http/host-allowlist.d.ts.map +1 -0
- package/dist/http/host-allowlist.js +52 -0
- package/dist/http/host-allowlist.js.map +1 -0
- package/dist/http/http-server.d.ts +27 -0
- package/dist/http/http-server.d.ts.map +1 -0
- package/dist/http/http-server.js +76 -0
- package/dist/http/http-server.js.map +1 -0
- package/dist/http/index.d.ts +3 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +4 -0
- package/dist/http/index.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/index.d.ts +2 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +2 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.d.ts +48 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +53 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/orchestration/chat-service.d.ts +61 -0
- package/dist/orchestration/chat-service.d.ts.map +1 -0
- package/dist/orchestration/chat-service.js +156 -0
- package/dist/orchestration/chat-service.js.map +1 -0
- package/dist/orchestration/cron.d.ts +30 -0
- package/dist/orchestration/cron.d.ts.map +1 -0
- package/dist/orchestration/cron.js +136 -0
- package/dist/orchestration/cron.js.map +1 -0
- package/dist/orchestration/index.d.ts +5 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +6 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/loop-service.d.ts +129 -0
- package/dist/orchestration/loop-service.d.ts.map +1 -0
- package/dist/orchestration/loop-service.js +234 -0
- package/dist/orchestration/loop-service.js.map +1 -0
- package/dist/orchestration/schedule-service.d.ts +65 -0
- package/dist/orchestration/schedule-service.d.ts.map +1 -0
- package/dist/orchestration/schedule-service.js +201 -0
- package/dist/orchestration/schedule-service.js.map +1 -0
- package/dist/persistence/atomic-store.d.ts +45 -0
- package/dist/persistence/atomic-store.d.ts.map +1 -0
- package/dist/persistence/atomic-store.js +92 -0
- package/dist/persistence/atomic-store.js.map +1 -0
- package/dist/persistence/entity-schemas.d.ts +1707 -0
- package/dist/persistence/entity-schemas.d.ts.map +1 -0
- package/dist/persistence/entity-schemas.js +250 -0
- package/dist/persistence/entity-schemas.js.map +1 -0
- package/dist/persistence/entity-stores.d.ts +46 -0
- package/dist/persistence/entity-stores.d.ts.map +1 -0
- package/dist/persistence/entity-stores.js +167 -0
- package/dist/persistence/entity-stores.js.map +1 -0
- package/dist/persistence/index.d.ts +4 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +5 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/projects/checkout-diff-manager.d.ts +44 -0
- package/dist/projects/checkout-diff-manager.d.ts.map +1 -0
- package/dist/projects/checkout-diff-manager.js +82 -0
- package/dist/projects/checkout-diff-manager.js.map +1 -0
- package/dist/projects/git-checkout-rpc.d.ts +18 -0
- package/dist/projects/git-checkout-rpc.d.ts.map +1 -0
- package/dist/projects/git-checkout-rpc.js +57 -0
- package/dist/projects/git-checkout-rpc.js.map +1 -0
- package/dist/projects/git-detect.d.ts +21 -0
- package/dist/projects/git-detect.d.ts.map +1 -0
- package/dist/projects/git-detect.js +34 -0
- package/dist/projects/git-detect.js.map +1 -0
- package/dist/projects/git-operations.d.ts +67 -0
- package/dist/projects/git-operations.d.ts.map +1 -0
- package/dist/projects/git-operations.js +200 -0
- package/dist/projects/git-operations.js.map +1 -0
- package/dist/projects/github-service.d.ts +80 -0
- package/dist/projects/github-service.d.ts.map +1 -0
- package/dist/projects/github-service.js +172 -0
- package/dist/projects/github-service.js.map +1 -0
- package/dist/projects/index.d.ts +13 -0
- package/dist/projects/index.d.ts.map +1 -0
- package/dist/projects/index.js +19 -0
- package/dist/projects/index.js.map +1 -0
- package/dist/projects/open-project.d.ts +35 -0
- package/dist/projects/open-project.d.ts.map +1 -0
- package/dist/projects/open-project.js +106 -0
- package/dist/projects/open-project.js.map +1 -0
- package/dist/projects/reconciliation.d.ts +15 -0
- package/dist/projects/reconciliation.d.ts.map +1 -0
- package/dist/projects/reconciliation.js +63 -0
- package/dist/projects/reconciliation.js.map +1 -0
- package/dist/projects/status-projection.d.ts +33 -0
- package/dist/projects/status-projection.d.ts.map +1 -0
- package/dist/projects/status-projection.js +98 -0
- package/dist/projects/status-projection.js.map +1 -0
- package/dist/projects/workspace-activity.d.ts +28 -0
- package/dist/projects/workspace-activity.d.ts.map +1 -0
- package/dist/projects/workspace-activity.js +74 -0
- package/dist/projects/workspace-activity.js.map +1 -0
- package/dist/projects/workspace-git-service.d.ts +27 -0
- package/dist/projects/workspace-git-service.d.ts.map +1 -0
- package/dist/projects/workspace-git-service.js +60 -0
- package/dist/projects/workspace-git-service.js.map +1 -0
- package/dist/projects/workspace-registry.d.ts +59 -0
- package/dist/projects/workspace-registry.d.ts.map +1 -0
- package/dist/projects/workspace-registry.js +149 -0
- package/dist/projects/workspace-registry.js.map +1 -0
- package/dist/projects/worktree-service.d.ts +100 -0
- package/dist/projects/worktree-service.d.ts.map +1 -0
- package/dist/projects/worktree-service.js +216 -0
- package/dist/projects/worktree-service.js.map +1 -0
- package/dist/proxy/index.d.ts +4 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +5 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/proxy/service-hostname.d.ts +21 -0
- package/dist/proxy/service-hostname.d.ts.map +1 -0
- package/dist/proxy/service-hostname.js +44 -0
- package/dist/proxy/service-hostname.js.map +1 -0
- package/dist/proxy/service-port-registry.d.ts +36 -0
- package/dist/proxy/service-port-registry.d.ts.map +1 -0
- package/dist/proxy/service-port-registry.js +55 -0
- package/dist/proxy/service-port-registry.js.map +1 -0
- package/dist/proxy/service-proxy.d.ts +34 -0
- package/dist/proxy/service-proxy.d.ts.map +1 -0
- package/dist/proxy/service-proxy.js +54 -0
- package/dist/proxy/service-proxy.js.map +1 -0
- package/dist/terminal/index.d.ts +4 -0
- package/dist/terminal/index.d.ts.map +1 -0
- package/dist/terminal/index.js +5 -0
- package/dist/terminal/index.js.map +1 -0
- package/dist/terminal/pty-backend.d.ts +44 -0
- package/dist/terminal/pty-backend.d.ts.map +1 -0
- package/dist/terminal/pty-backend.js +119 -0
- package/dist/terminal/pty-backend.js.map +1 -0
- package/dist/terminal/screen-buffer.d.ts +21 -0
- package/dist/terminal/screen-buffer.d.ts.map +1 -0
- package/dist/terminal/screen-buffer.js +55 -0
- package/dist/terminal/screen-buffer.js.map +1 -0
- package/dist/terminal/terminal-manager.d.ts +79 -0
- package/dist/terminal/terminal-manager.d.ts.map +1 -0
- package/dist/terminal/terminal-manager.js +174 -0
- package/dist/terminal/terminal-manager.js.map +1 -0
- package/dist/terminal/terminal-rpc.d.ts +20 -0
- package/dist/terminal/terminal-rpc.d.ts.map +1 -0
- package/dist/terminal/terminal-rpc.js +122 -0
- package/dist/terminal/terminal-rpc.js.map +1 -0
- package/dist/util/concurrency.d.ts +16 -0
- package/dist/util/concurrency.d.ts.map +1 -0
- package/dist/util/concurrency.js +23 -0
- package/dist/util/concurrency.js.map +1 -0
- package/dist/util/index.d.ts +2 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +2 -0
- package/dist/util/index.js.map +1 -0
- package/dist/ws/capability-store.d.ts +11 -0
- package/dist/ws/capability-store.d.ts.map +1 -0
- package/dist/ws/capability-store.js +10 -0
- package/dist/ws/capability-store.js.map +1 -0
- package/dist/ws/index.d.ts +5 -0
- package/dist/ws/index.d.ts.map +1 -0
- package/dist/ws/index.js +6 -0
- package/dist/ws/index.js.map +1 -0
- package/dist/ws/router.d.ts +34 -0
- package/dist/ws/router.d.ts.map +1 -0
- package/dist/ws/router.js +97 -0
- package/dist/ws/router.js.map +1 -0
- package/dist/ws/session.d.ts +28 -0
- package/dist/ws/session.d.ts.map +1 -0
- package/dist/ws/session.js +36 -0
- package/dist/ws/session.js.map +1 -0
- package/dist/ws/ws-server.d.ts +41 -0
- package/dist/ws/ws-server.d.ts.map +1 -0
- package/dist/ws/ws-server.js +104 -0
- package/dist/ws/ws-server.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AACA,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const SERVER_PACKAGE: "@av-pi-studio/server";
|
|
2
|
+
/** Proves the server consumes protocol + highlight emitted declarations. */
|
|
3
|
+
export declare const SERVER_DEPS: readonly ["@av-pi-studio/protocol", "@av-pi-studio/highlight"];
|
|
4
|
+
export * from "./persistence/index.js";
|
|
5
|
+
export * from "./config/index.js";
|
|
6
|
+
export * from "./daemon/index.js";
|
|
7
|
+
export * from "./http/index.js";
|
|
8
|
+
export * from "./auth/index.js";
|
|
9
|
+
export * from "./ws/index.js";
|
|
10
|
+
export * from "./agent/index.js";
|
|
11
|
+
export * from "./projects/index.js";
|
|
12
|
+
export * from "./terminal/index.js";
|
|
13
|
+
export * from "./proxy/index.js";
|
|
14
|
+
export * from "./files/index.js";
|
|
15
|
+
export * from "./orchestration/index.js";
|
|
16
|
+
export * from "./logging/index.js";
|
|
17
|
+
export * from "./util/index.js";
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,EAAG,sBAA+B,CAAC;AAE9D,4EAA4E;AAC5E,eAAO,MAAM,WAAW,gEAAiD,CAAC;AAG1E,cAAc,wBAAwB,CAAC;AAGvC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,eAAe,CAAC;AAG9B,cAAc,kBAAkB,CAAC;AAGjC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,0BAA0B,CAAC;AAGzC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// @av-pi-studio/server — the daemon: WS API, agent supervision, stores, relay.
|
|
2
|
+
import { HIGHLIGHT_PACKAGE } from "@av-pi-studio/highlight";
|
|
3
|
+
import { PROTOCOL_PACKAGE } from "@av-pi-studio/protocol";
|
|
4
|
+
export const SERVER_PACKAGE = "@av-pi-studio/server";
|
|
5
|
+
/** Proves the server consumes protocol + highlight emitted declarations. */
|
|
6
|
+
export const SERVER_DEPS = [PROTOCOL_PACKAGE, HIGHLIGHT_PACKAGE];
|
|
7
|
+
// File-based JSON persistence (atomic store primitive + entity stores).
|
|
8
|
+
export * from "./persistence/index.js";
|
|
9
|
+
// Configuration (daemon config.json + per-project pi-studio.json).
|
|
10
|
+
export * from "./config/index.js";
|
|
11
|
+
// Daemon identity + bootstrap.
|
|
12
|
+
export * from "./daemon/index.js";
|
|
13
|
+
// HTTP server (host allowlist, CORS, health, auth pipeline).
|
|
14
|
+
export * from "./http/index.js";
|
|
15
|
+
// Optional password auth (bcrypt + bearer / WS subprotocol).
|
|
16
|
+
export * from "./auth/index.js";
|
|
17
|
+
// WebSocket server (handshake, sessions, capability rehydrate, routing).
|
|
18
|
+
export * from "./ws/index.js";
|
|
19
|
+
// Agent providers, registry, snapshot, and lifecycle manager.
|
|
20
|
+
export * from "./agent/index.js";
|
|
21
|
+
// Project + workspace registries, key derivation, reconciliation.
|
|
22
|
+
export * from "./projects/index.js";
|
|
23
|
+
// PTY terminal manager + binary stream.
|
|
24
|
+
export * from "./terminal/index.js";
|
|
25
|
+
// HTTP service proxy (generated hostnames + routing).
|
|
26
|
+
export * from "./proxy/index.js";
|
|
27
|
+
// File explorer + binary file transfer.
|
|
28
|
+
export * from "./files/index.js";
|
|
29
|
+
// Orchestration: chat rooms, schedules/heartbeats, loops.
|
|
30
|
+
export * from "./orchestration/index.js";
|
|
31
|
+
// Operational logging (pino + rotating file).
|
|
32
|
+
export * from "./logging/index.js";
|
|
33
|
+
// Shared utilities (bounded-concurrency helpers).
|
|
34
|
+
export * from "./util/index.js";
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,MAAM,CAAC,MAAM,cAAc,GAAG,sBAA+B,CAAC;AAE9D,4EAA4E;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,gBAAgB,EAAE,iBAAiB,CAAU,CAAC;AAE1E,wEAAwE;AACxE,cAAc,wBAAwB,CAAC;AAEvC,mEAAmE;AACnE,cAAc,mBAAmB,CAAC;AAElC,+BAA+B;AAC/B,cAAc,mBAAmB,CAAC;AAElC,6DAA6D;AAC7D,cAAc,iBAAiB,CAAC;AAEhC,6DAA6D;AAC7D,cAAc,iBAAiB,CAAC;AAEhC,yEAAyE;AACzE,cAAc,eAAe,CAAC;AAE9B,8DAA8D;AAC9D,cAAc,kBAAkB,CAAC;AAEjC,kEAAkE;AAClE,cAAc,qBAAqB,CAAC;AAEpC,wCAAwC;AACxC,cAAc,qBAAqB,CAAC;AAEpC,sDAAsD;AACtD,cAAc,kBAAkB,CAAC;AAEjC,wCAAwC;AACxC,cAAc,kBAAkB,CAAC;AAEjC,0DAA0D;AAC1D,cAAc,0BAA0B,CAAC;AAEzC,8CAA8C;AAC9C,cAAc,oBAAoB,CAAC;AAEnC,kDAAkD;AAClD,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/logging/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,KAAK,mBAAmB,EACxB,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,YAAY,GACb,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/logging/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EAIZ,YAAY,GACb,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon logging (operational concern; adopted from the reference daemon's `pino` stack). The rest
|
|
3
|
+
* of the codebase injects a `Pick<Console, "info" | "warn" | "error">`-shaped logger; a pino logger
|
|
4
|
+
* satisfies that shape, so existing call sites keep working while gaining levels + structure.
|
|
5
|
+
*
|
|
6
|
+
* - Dev / TTY: pretty, colorized, human-readable (no worker thread).
|
|
7
|
+
* - Daemon with a home dir: structured NDJSON to a rotating file under `$PI_STUDIO_HOME/logs/`.
|
|
8
|
+
*/
|
|
9
|
+
export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal" | "silent";
|
|
10
|
+
/** The structural logger the daemon passes around. A pino `Logger` is assignable to this. */
|
|
11
|
+
export interface Logger {
|
|
12
|
+
trace(obj: unknown, msg?: string): void;
|
|
13
|
+
trace(msg: string): void;
|
|
14
|
+
debug(obj: unknown, msg?: string): void;
|
|
15
|
+
debug(msg: string): void;
|
|
16
|
+
info(obj: unknown, msg?: string): void;
|
|
17
|
+
info(msg: string): void;
|
|
18
|
+
warn(obj: unknown, msg?: string): void;
|
|
19
|
+
warn(msg: string): void;
|
|
20
|
+
error(obj: unknown, msg?: string): void;
|
|
21
|
+
error(msg: string): void;
|
|
22
|
+
fatal(obj: unknown, msg?: string): void;
|
|
23
|
+
fatal(msg: string): void;
|
|
24
|
+
child(bindings: Record<string, unknown>): Logger;
|
|
25
|
+
}
|
|
26
|
+
export interface CreateLoggerOptions {
|
|
27
|
+
level?: LogLevel;
|
|
28
|
+
/** Pretty, colorized output (default: true when stdout is a TTY). */
|
|
29
|
+
pretty?: boolean;
|
|
30
|
+
/** Write structured NDJSON to a rotating file in this directory instead of stdout. */
|
|
31
|
+
logDir?: string;
|
|
32
|
+
/** Rotating-file size threshold (default "10M"). */
|
|
33
|
+
rotateSize?: string;
|
|
34
|
+
/** Rotating-file retained count (default 5). */
|
|
35
|
+
rotateMaxFiles?: number;
|
|
36
|
+
/** Base bindings attached to every line (e.g. `{ name: "pi-studio" }`). */
|
|
37
|
+
bindings?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
/** Build a pino logger per the options. Pure/synchronous; safe to call in tests. */
|
|
40
|
+
export declare function createLogger(options?: CreateLoggerOptions): Logger;
|
|
41
|
+
/**
|
|
42
|
+
* Daemon logger: NDJSON to `<home>/logs/` when a home dir is given (the long-running daemon), else a
|
|
43
|
+
* pretty/stdout dev logger.
|
|
44
|
+
*/
|
|
45
|
+
export declare function createDaemonLogger(home: string | undefined, options?: CreateLoggerOptions): Logger;
|
|
46
|
+
/** A no-op logger for tests / opt-out paths. */
|
|
47
|
+
export declare function silentLogger(): Logger;
|
|
48
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logging/logger.ts"],"names":[],"mappings":"AASA;;;;;;;GAOG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE1F,6FAA6F;AAC7F,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC;CAClD;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,qEAAqE;IACrE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAQD,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CA2BtE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,GAAE,mBAAwB,GAChC,MAAM,CAGR;AAED,gDAAgD;AAChD,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { pino } from "pino";
|
|
4
|
+
// `pino-pretty` is usable directly as a sonic-boom-compatible stream, which avoids spawning a
|
|
5
|
+
// transport worker thread (worker threads are awkward under Vitest and add shutdown latency).
|
|
6
|
+
import pinoPretty from "pino-pretty";
|
|
7
|
+
import { createStream as createRotatingStream } from "rotating-file-stream";
|
|
8
|
+
function resolveLevel(level) {
|
|
9
|
+
if (level)
|
|
10
|
+
return level;
|
|
11
|
+
const fromEnv = process.env.PI_STUDIO_LOG_LEVEL;
|
|
12
|
+
return fromEnv ?? "info";
|
|
13
|
+
}
|
|
14
|
+
/** Build a pino logger per the options. Pure/synchronous; safe to call in tests. */
|
|
15
|
+
export function createLogger(options = {}) {
|
|
16
|
+
const level = resolveLevel(options.level);
|
|
17
|
+
const base = { level, base: options.bindings ?? undefined };
|
|
18
|
+
if (level === "silent")
|
|
19
|
+
return pino({ ...base, level: "silent" });
|
|
20
|
+
if (options.logDir) {
|
|
21
|
+
mkdirSync(options.logDir, { recursive: true });
|
|
22
|
+
const stream = createRotatingStream("pi-studio.log", {
|
|
23
|
+
size: options.rotateSize ?? "10M",
|
|
24
|
+
maxFiles: options.rotateMaxFiles ?? 5,
|
|
25
|
+
path: options.logDir,
|
|
26
|
+
});
|
|
27
|
+
return pino(base, stream);
|
|
28
|
+
}
|
|
29
|
+
const pretty = options.pretty ?? Boolean(process.stdout.isTTY);
|
|
30
|
+
if (pretty) {
|
|
31
|
+
const stream = pinoPretty({
|
|
32
|
+
colorize: true,
|
|
33
|
+
translateTime: "SYS:HH:MM:ss.l",
|
|
34
|
+
ignore: "pid,hostname",
|
|
35
|
+
});
|
|
36
|
+
return pino(base, stream);
|
|
37
|
+
}
|
|
38
|
+
return pino(base);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Daemon logger: NDJSON to `<home>/logs/` when a home dir is given (the long-running daemon), else a
|
|
42
|
+
* pretty/stdout dev logger.
|
|
43
|
+
*/
|
|
44
|
+
export function createDaemonLogger(home, options = {}) {
|
|
45
|
+
if (home)
|
|
46
|
+
return createLogger({ ...options, logDir: options.logDir ?? join(home, "logs") });
|
|
47
|
+
return createLogger(options);
|
|
48
|
+
}
|
|
49
|
+
/** A no-op logger for tests / opt-out paths. */
|
|
50
|
+
export function silentLogger() {
|
|
51
|
+
return createLogger({ level: "silent" });
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logging/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,8FAA8F;AAC9F,8FAA8F;AAC9F,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,YAAY,IAAI,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AA4C5E,SAAS,YAAY,CAAC,KAA2B;IAC/C,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,mBAA2C,CAAC;IACxE,OAAO,OAAO,IAAI,MAAM,CAAC;AAC3B,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,YAAY,CAAC,UAA+B,EAAE;IAC5D,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,IAAI,SAAS,EAAE,CAAC;IAE5D,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAsB,CAAC;IAEvF,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,oBAAoB,CAAC,eAAe,EAAE;YACnD,IAAI,EAAE,OAAO,CAAC,UAAU,IAAI,KAAK;YACjC,QAAQ,EAAE,OAAO,CAAC,cAAc,IAAI,CAAC;YACrC,IAAI,EAAE,OAAO,CAAC,MAAM;SACrB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,IAAI,EAAE,MAAM,CAAsB,CAAC;IACjD,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/D,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,UAAU,CAAC;YACxB,QAAQ,EAAE,IAAI;YACd,aAAa,EAAE,gBAAgB;YAC/B,MAAM,EAAE,cAAc;SACvB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,IAAI,EAAE,MAAM,CAAsB,CAAC;IACjD,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAsB,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAwB,EACxB,UAA+B,EAAE;IAEjC,IAAI,IAAI;QAAE,OAAO,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAC5F,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,YAAY;IAC1B,OAAO,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ChatMessage, ChatRoom } from "../persistence/entity-schemas.js";
|
|
2
|
+
/**
|
|
3
|
+
* Chat rooms for agent↔agent / human↔agent coordination (features/chat-rooms.md). Backed by the
|
|
4
|
+
* shared `chat/rooms.json` store = `{ rooms, messages }` (persistence/entity-stores). Room names are
|
|
5
|
+
* unique case-insensitively; `@mentions` in a posted body are parsed into `mentionAgentIds` (unknown
|
|
6
|
+
* mentions dropped); reads are cursor based; waits block until a new message or timeout.
|
|
7
|
+
*/
|
|
8
|
+
export type { ChatMessage, ChatRoom, ChatStore } from "../persistence/entity-schemas.js";
|
|
9
|
+
/** Parse `@mentions` from a body into raw mention tokens (without the leading `@`). */
|
|
10
|
+
export declare function parseMentions(body: string): string[];
|
|
11
|
+
export interface ChatServiceDeps {
|
|
12
|
+
home: string;
|
|
13
|
+
/** Resolve a mention token → agent id (null if unknown → dropped). Defaults to identity-if-exists. */
|
|
14
|
+
resolveMention?: (token: string) => string | null;
|
|
15
|
+
now?: () => string;
|
|
16
|
+
}
|
|
17
|
+
export declare class ChatService {
|
|
18
|
+
private readonly deps;
|
|
19
|
+
private readonly now;
|
|
20
|
+
private store;
|
|
21
|
+
private loaded;
|
|
22
|
+
private readonly waiters;
|
|
23
|
+
constructor(deps: ChatServiceDeps);
|
|
24
|
+
private ensureLoaded;
|
|
25
|
+
private persist;
|
|
26
|
+
/** Create a room. Rejects a duplicate name (case-insensitive). */
|
|
27
|
+
createRoom(input: {
|
|
28
|
+
name: string;
|
|
29
|
+
purpose?: string;
|
|
30
|
+
}): Promise<ChatRoom>;
|
|
31
|
+
listRooms(): Promise<ChatRoom[]>;
|
|
32
|
+
inspectRoom(roomId: string): Promise<{
|
|
33
|
+
room: ChatRoom;
|
|
34
|
+
messages: ChatMessage[];
|
|
35
|
+
} | null>;
|
|
36
|
+
/** Delete a room and all its messages. */
|
|
37
|
+
deleteRoom(roomId: string): Promise<boolean>;
|
|
38
|
+
/** Post a message; parses + resolves `@mentions`; bumps room.updatedAt; notifies waiters. */
|
|
39
|
+
postMessage(input: {
|
|
40
|
+
roomId: string;
|
|
41
|
+
authorAgentId: string;
|
|
42
|
+
body: string;
|
|
43
|
+
replyToMessageId?: string;
|
|
44
|
+
}): Promise<ChatMessage>;
|
|
45
|
+
/** Read messages after `cursor` (an index into the room's message list). */
|
|
46
|
+
readMessages(roomId: string, cursor?: number): Promise<{
|
|
47
|
+
messages: ChatMessage[];
|
|
48
|
+
cursor: number;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Return new messages after `sinceCursor` immediately if any exist; otherwise block until a new
|
|
52
|
+
* message arrives or `timeoutMs` elapses (then return whatever is available, possibly empty).
|
|
53
|
+
*/
|
|
54
|
+
waitForMessages(roomId: string, sinceCursor: number, timeoutMs?: number): Promise<{
|
|
55
|
+
messages: ChatMessage[];
|
|
56
|
+
cursor: number;
|
|
57
|
+
}>;
|
|
58
|
+
private messagesFor;
|
|
59
|
+
private notifyWaiters;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=chat-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-service.d.ts","sourceRoot":"","sources":["../../src/orchestration/chat-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAa,MAAM,kCAAkC,CAAC;AAGzF;;;;;GAKG;AAEH,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAIzF,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAMpD;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,sGAAsG;IACtG,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAClD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAQD,qBAAa,WAAW;IAMV,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,KAAK,CAA0C;IACvD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAEhB,IAAI,EAAE,eAAe;YAIpC,YAAY;YAMZ,OAAO;IAIrB,kEAAkE;IAC5D,UAAU,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;IAoBxE,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAKhC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,QAAQ,EAAE,WAAW,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAO9F,0CAA0C;IACpC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUlD,6FAA6F;IACvF,WAAW,CAAC,KAAK,EAAE;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC;QACb,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,GAAG,OAAO,CAAC,WAAW,CAAC;IA4BxB,4EAA4E;IACtE,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,MAAM,SAAI,GACT,OAAO,CAAC;QAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAQvD;;;OAGG;IACG,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,SAAS,SAAS,GACjB,OAAO,CAAC;QAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAyBvD,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,aAAa;CAWtB"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { loadChat, saveChat } from "../persistence/entity-stores.js";
|
|
3
|
+
const MENTION_RE = /@([A-Za-z0-9_.:-]+)/g;
|
|
4
|
+
/** Parse `@mentions` from a body into raw mention tokens (without the leading `@`). */
|
|
5
|
+
export function parseMentions(body) {
|
|
6
|
+
const out = new Set();
|
|
7
|
+
for (const match of body.matchAll(MENTION_RE)) {
|
|
8
|
+
if (match[1])
|
|
9
|
+
out.add(match[1]);
|
|
10
|
+
}
|
|
11
|
+
return [...out];
|
|
12
|
+
}
|
|
13
|
+
export class ChatService {
|
|
14
|
+
deps;
|
|
15
|
+
now;
|
|
16
|
+
store = { rooms: [], messages: [] };
|
|
17
|
+
loaded = false;
|
|
18
|
+
waiters = new Set();
|
|
19
|
+
constructor(deps) {
|
|
20
|
+
this.deps = deps;
|
|
21
|
+
this.now = deps.now ?? (() => new Date().toISOString());
|
|
22
|
+
}
|
|
23
|
+
async ensureLoaded() {
|
|
24
|
+
if (this.loaded)
|
|
25
|
+
return;
|
|
26
|
+
this.store = await loadChat(this.deps.home);
|
|
27
|
+
this.loaded = true;
|
|
28
|
+
}
|
|
29
|
+
async persist() {
|
|
30
|
+
await saveChat(this.deps.home, this.store);
|
|
31
|
+
}
|
|
32
|
+
/** Create a room. Rejects a duplicate name (case-insensitive). */
|
|
33
|
+
async createRoom(input) {
|
|
34
|
+
await this.ensureLoaded();
|
|
35
|
+
const name = input.name.trim();
|
|
36
|
+
if (!name)
|
|
37
|
+
throw new Error("room name required");
|
|
38
|
+
if (this.store.rooms.some((r) => r.name.toLowerCase() === name.toLowerCase())) {
|
|
39
|
+
throw new Error("duplicate_room_name");
|
|
40
|
+
}
|
|
41
|
+
const ts = this.now();
|
|
42
|
+
const room = {
|
|
43
|
+
id: randomUUID(),
|
|
44
|
+
name,
|
|
45
|
+
purpose: input.purpose,
|
|
46
|
+
createdAt: ts,
|
|
47
|
+
updatedAt: ts,
|
|
48
|
+
};
|
|
49
|
+
this.store.rooms.push(room);
|
|
50
|
+
await this.persist();
|
|
51
|
+
return room;
|
|
52
|
+
}
|
|
53
|
+
async listRooms() {
|
|
54
|
+
await this.ensureLoaded();
|
|
55
|
+
return [...this.store.rooms];
|
|
56
|
+
}
|
|
57
|
+
async inspectRoom(roomId) {
|
|
58
|
+
await this.ensureLoaded();
|
|
59
|
+
const room = this.store.rooms.find((r) => r.id === roomId);
|
|
60
|
+
if (!room)
|
|
61
|
+
return null;
|
|
62
|
+
return { room, messages: this.messagesFor(roomId) };
|
|
63
|
+
}
|
|
64
|
+
/** Delete a room and all its messages. */
|
|
65
|
+
async deleteRoom(roomId) {
|
|
66
|
+
await this.ensureLoaded();
|
|
67
|
+
const before = this.store.rooms.length;
|
|
68
|
+
this.store.rooms = this.store.rooms.filter((r) => r.id !== roomId);
|
|
69
|
+
if (this.store.rooms.length === before)
|
|
70
|
+
return false;
|
|
71
|
+
this.store.messages = this.store.messages.filter((m) => m.roomId !== roomId);
|
|
72
|
+
await this.persist();
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
/** Post a message; parses + resolves `@mentions`; bumps room.updatedAt; notifies waiters. */
|
|
76
|
+
async postMessage(input) {
|
|
77
|
+
await this.ensureLoaded();
|
|
78
|
+
const room = this.store.rooms.find((r) => r.id === input.roomId);
|
|
79
|
+
if (!room)
|
|
80
|
+
throw new Error("unknown_room");
|
|
81
|
+
const resolve = this.deps.resolveMention ?? ((t) => t);
|
|
82
|
+
const mentionAgentIds = [];
|
|
83
|
+
for (const token of parseMentions(input.body)) {
|
|
84
|
+
const resolved = resolve(token);
|
|
85
|
+
if (resolved)
|
|
86
|
+
mentionAgentIds.push(resolved);
|
|
87
|
+
}
|
|
88
|
+
const message = {
|
|
89
|
+
id: randomUUID(),
|
|
90
|
+
roomId: input.roomId,
|
|
91
|
+
authorAgentId: input.authorAgentId,
|
|
92
|
+
body: input.body,
|
|
93
|
+
replyToMessageId: input.replyToMessageId,
|
|
94
|
+
mentionAgentIds,
|
|
95
|
+
createdAt: this.now(),
|
|
96
|
+
};
|
|
97
|
+
this.store.messages.push(message);
|
|
98
|
+
room.updatedAt = message.createdAt;
|
|
99
|
+
await this.persist();
|
|
100
|
+
this.notifyWaiters(input.roomId);
|
|
101
|
+
return message;
|
|
102
|
+
}
|
|
103
|
+
/** Read messages after `cursor` (an index into the room's message list). */
|
|
104
|
+
async readMessages(roomId, cursor = 0) {
|
|
105
|
+
await this.ensureLoaded();
|
|
106
|
+
const all = this.messagesFor(roomId);
|
|
107
|
+
const start = Math.max(0, cursor);
|
|
108
|
+
const messages = all.slice(start);
|
|
109
|
+
return { messages, cursor: all.length };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Return new messages after `sinceCursor` immediately if any exist; otherwise block until a new
|
|
113
|
+
* message arrives or `timeoutMs` elapses (then return whatever is available, possibly empty).
|
|
114
|
+
*/
|
|
115
|
+
async waitForMessages(roomId, sinceCursor, timeoutMs = 30_000) {
|
|
116
|
+
await this.ensureLoaded();
|
|
117
|
+
const immediate = this.messagesFor(roomId).slice(Math.max(0, sinceCursor));
|
|
118
|
+
if (immediate.length > 0) {
|
|
119
|
+
return { messages: immediate, cursor: this.messagesFor(roomId).length };
|
|
120
|
+
}
|
|
121
|
+
return new Promise((resolve) => {
|
|
122
|
+
const waiter = {
|
|
123
|
+
roomId,
|
|
124
|
+
sinceCursor,
|
|
125
|
+
resolve: (messages) => {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
this.waiters.delete(waiter);
|
|
128
|
+
resolve({ messages, cursor: this.messagesFor(roomId).length });
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
const timer = setTimeout(() => {
|
|
132
|
+
this.waiters.delete(waiter);
|
|
133
|
+
resolve({ messages: [], cursor: this.messagesFor(roomId).length });
|
|
134
|
+
}, timeoutMs);
|
|
135
|
+
this.waiters.add(waiter);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
messagesFor(roomId) {
|
|
139
|
+
return this.store.messages.filter((m) => m.roomId === roomId);
|
|
140
|
+
}
|
|
141
|
+
notifyWaiters(roomId) {
|
|
142
|
+
const roomMessages = this.messagesFor(roomId);
|
|
143
|
+
// Collect ready waiters first; `resolve` mutates `this.waiters`, so don't resolve mid-iteration.
|
|
144
|
+
const ready = [];
|
|
145
|
+
for (const waiter of this.waiters) {
|
|
146
|
+
if (waiter.roomId !== roomId)
|
|
147
|
+
continue;
|
|
148
|
+
const fresh = roomMessages.slice(Math.max(0, waiter.sinceCursor));
|
|
149
|
+
if (fresh.length > 0)
|
|
150
|
+
ready.push({ waiter, fresh });
|
|
151
|
+
}
|
|
152
|
+
for (const { waiter, fresh } of ready)
|
|
153
|
+
waiter.resolve(fresh);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=chat-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-service.js","sourceRoot":"","sources":["../../src/orchestration/chat-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal cron + interval next-time computation (features/schedules-heartbeats.md § Behavior).
|
|
3
|
+
* Supports standard 5-field cron (`min hour dom month dow`) with `*`, lists (`a,b`), ranges (`a-b`),
|
|
4
|
+
* and steps (`*/n`, `a-b/n`). An IANA `timezone` makes recurrence follow local wall-clock (DST-aware
|
|
5
|
+
* via `Intl.DateTimeFormat`); absent timezone = UTC.
|
|
6
|
+
*/
|
|
7
|
+
export declare class CronParseError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
interface CronFields {
|
|
11
|
+
minute: Set<number>;
|
|
12
|
+
hour: Set<number>;
|
|
13
|
+
dom: Set<number>;
|
|
14
|
+
month: Set<number>;
|
|
15
|
+
dow: Set<number>;
|
|
16
|
+
domRestricted: boolean;
|
|
17
|
+
dowRestricted: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function parseCron(expression: string): CronFields;
|
|
20
|
+
/** Validate a cron expression (throws `CronParseError` if invalid). */
|
|
21
|
+
export declare function assertValidCron(expression: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Next cron fire strictly after `after`, in the given timezone (default UTC). Steps minute-by-minute
|
|
24
|
+
* up to ~366 days; returns null if no match within the window.
|
|
25
|
+
*/
|
|
26
|
+
export declare function nextCronTime(expression: string, after: Date, timezone?: string): Date | null;
|
|
27
|
+
/** Next interval fire after `from`. */
|
|
28
|
+
export declare function nextEveryTime(everyMs: number, from: Date): Date;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=cron.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.d.ts","sourceRoot":"","sources":["../../src/orchestration/cron.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED,UAAU,UAAU;IAClB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACpB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;CACxB;AAwCD,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAexD;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAExD;AAiDD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAW5F;AAED,uCAAuC;AACvC,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAE/D"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal cron + interval next-time computation (features/schedules-heartbeats.md § Behavior).
|
|
3
|
+
* Supports standard 5-field cron (`min hour dom month dow`) with `*`, lists (`a,b`), ranges (`a-b`),
|
|
4
|
+
* and steps (`*/n`, `a-b/n`). An IANA `timezone` makes recurrence follow local wall-clock (DST-aware
|
|
5
|
+
* via `Intl.DateTimeFormat`); absent timezone = UTC.
|
|
6
|
+
*/
|
|
7
|
+
export class CronParseError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "CronParseError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const RANGES = {
|
|
14
|
+
minute: [0, 59],
|
|
15
|
+
hour: [0, 23],
|
|
16
|
+
dom: [1, 31],
|
|
17
|
+
month: [1, 12],
|
|
18
|
+
dow: [0, 6],
|
|
19
|
+
};
|
|
20
|
+
function parseField(field, name) {
|
|
21
|
+
const [lo, hi] = RANGES[name];
|
|
22
|
+
const values = new Set();
|
|
23
|
+
for (const part of field.split(",")) {
|
|
24
|
+
const [rangePart, stepPart] = part.split("/");
|
|
25
|
+
const step = stepPart ? Number.parseInt(stepPart, 10) : 1;
|
|
26
|
+
if (!Number.isInteger(step) || step < 1)
|
|
27
|
+
throw new CronParseError(`bad step in "${field}"`);
|
|
28
|
+
let start = lo;
|
|
29
|
+
let end = hi;
|
|
30
|
+
if (rangePart && rangePart !== "*") {
|
|
31
|
+
const bounds = rangePart.split("-");
|
|
32
|
+
start = Number.parseInt(bounds[0], 10);
|
|
33
|
+
end = bounds[1] !== undefined ? Number.parseInt(bounds[1], 10) : start;
|
|
34
|
+
if (Number.isNaN(start) || Number.isNaN(end))
|
|
35
|
+
throw new CronParseError(`bad range "${part}"`);
|
|
36
|
+
}
|
|
37
|
+
// dow: normalize 7 → 0 (Sunday).
|
|
38
|
+
if (name === "dow") {
|
|
39
|
+
start = start === 7 ? 0 : start;
|
|
40
|
+
end = end === 7 ? 0 : end;
|
|
41
|
+
}
|
|
42
|
+
if (start > end)
|
|
43
|
+
throw new CronParseError(`inverted range "${part}"`);
|
|
44
|
+
for (let v = start; v <= end; v += step) {
|
|
45
|
+
if (v < lo || v > hi)
|
|
46
|
+
throw new CronParseError(`value ${v} out of range for ${name}`);
|
|
47
|
+
values.add(v);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return values;
|
|
51
|
+
}
|
|
52
|
+
export function parseCron(expression) {
|
|
53
|
+
const fields = expression.trim().split(/\s+/);
|
|
54
|
+
if (fields.length !== 5) {
|
|
55
|
+
throw new CronParseError(`expected 5 cron fields, got ${fields.length}: "${expression}"`);
|
|
56
|
+
}
|
|
57
|
+
const [min, hour, dom, month, dow] = fields;
|
|
58
|
+
return {
|
|
59
|
+
minute: parseField(min, "minute"),
|
|
60
|
+
hour: parseField(hour, "hour"),
|
|
61
|
+
dom: parseField(dom, "dom"),
|
|
62
|
+
month: parseField(month, "month"),
|
|
63
|
+
dow: parseField(dow, "dow"),
|
|
64
|
+
domRestricted: dom !== "*",
|
|
65
|
+
dowRestricted: dow !== "*",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** Validate a cron expression (throws `CronParseError` if invalid). */
|
|
69
|
+
export function assertValidCron(expression) {
|
|
70
|
+
parseCron(expression);
|
|
71
|
+
}
|
|
72
|
+
function zonedParts(date, timeZone) {
|
|
73
|
+
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
74
|
+
timeZone,
|
|
75
|
+
year: "numeric",
|
|
76
|
+
month: "2-digit",
|
|
77
|
+
day: "2-digit",
|
|
78
|
+
hour: "2-digit",
|
|
79
|
+
minute: "2-digit",
|
|
80
|
+
hour12: false,
|
|
81
|
+
});
|
|
82
|
+
const parts = {};
|
|
83
|
+
for (const p of fmt.formatToParts(date)) {
|
|
84
|
+
if (p.type !== "literal")
|
|
85
|
+
parts[p.type] = p.value;
|
|
86
|
+
}
|
|
87
|
+
const year = Number.parseInt(parts.year, 10);
|
|
88
|
+
const month = Number.parseInt(parts.month, 10);
|
|
89
|
+
const day = Number.parseInt(parts.day, 10);
|
|
90
|
+
let hour = Number.parseInt(parts.hour, 10);
|
|
91
|
+
if (hour === 24)
|
|
92
|
+
hour = 0; // some environments render midnight as 24
|
|
93
|
+
const minute = Number.parseInt(parts.minute, 10);
|
|
94
|
+
// Day-of-week from the wall-clock calendar date.
|
|
95
|
+
const weekday = new Date(Date.UTC(year, month - 1, day)).getUTCDay();
|
|
96
|
+
return { year, month, day, hour, minute, weekday };
|
|
97
|
+
}
|
|
98
|
+
function matches(fields, p) {
|
|
99
|
+
if (!fields.minute.has(p.minute))
|
|
100
|
+
return false;
|
|
101
|
+
if (!fields.hour.has(p.hour))
|
|
102
|
+
return false;
|
|
103
|
+
if (!fields.month.has(p.month))
|
|
104
|
+
return false;
|
|
105
|
+
// Classic crontab: when both dom and dow are restricted, match if EITHER matches.
|
|
106
|
+
if (fields.domRestricted && fields.dowRestricted) {
|
|
107
|
+
return fields.dom.has(p.day) || fields.dow.has(p.weekday);
|
|
108
|
+
}
|
|
109
|
+
if (!fields.dom.has(p.day))
|
|
110
|
+
return false;
|
|
111
|
+
if (!fields.dow.has(p.weekday))
|
|
112
|
+
return false;
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Next cron fire strictly after `after`, in the given timezone (default UTC). Steps minute-by-minute
|
|
117
|
+
* up to ~366 days; returns null if no match within the window.
|
|
118
|
+
*/
|
|
119
|
+
export function nextCronTime(expression, after, timezone) {
|
|
120
|
+
const fields = parseCron(expression);
|
|
121
|
+
const tz = timezone ?? "UTC";
|
|
122
|
+
// Start at the next whole minute after `after`.
|
|
123
|
+
const start = new Date(Math.floor(after.getTime() / 60_000) * 60_000 + 60_000);
|
|
124
|
+
const maxIterations = 366 * 24 * 60;
|
|
125
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
126
|
+
const candidate = new Date(start.getTime() + i * 60_000);
|
|
127
|
+
if (matches(fields, zonedParts(candidate, tz)))
|
|
128
|
+
return candidate;
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
/** Next interval fire after `from`. */
|
|
133
|
+
export function nextEveryTime(everyMs, from) {
|
|
134
|
+
return new Date(from.getTime() + everyMs);
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=cron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.js","sourceRoot":"","sources":["../../src/orchestration/cron.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/orchestration/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC"}
|