@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,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only per-agent timeline store (features/timeline-streaming.md § Timeline model,
|
|
3
|
+
* § Behavior). Rows persist alongside the agent record in `agents/{cwd}/{id}.json`.
|
|
4
|
+
*
|
|
5
|
+
* Key concepts:
|
|
6
|
+
* - **Epoch** — each run (`startTurn`) increments the epoch; rows within one epoch are ordered by
|
|
7
|
+
* monotonically-increasing `seq`.
|
|
8
|
+
* - **Source row** — one `AgentStreamEvent` mapped to one raw storage row (epoch + seq + timestamp
|
|
9
|
+
* owned by the daemon, never the provider).
|
|
10
|
+
* - **Projected item** — what a client renders. Multi-source events collapse: a tool-call lifecycle
|
|
11
|
+
* (status updates, result) is ONE projected item regardless of how many source rows it spans;
|
|
12
|
+
* adjacent assistant/reasoning chunks merge into one per run before counting toward the page limit.
|
|
13
|
+
* - **Page** — bounded at `DEFAULT_PAGE_SIZE` projected items; supports `direction:"before"|"after"`
|
|
14
|
+
* from an opaque cursor (encoded as base-10 `seq` string), with all paging fields.
|
|
15
|
+
*/
|
|
16
|
+
export const DEFAULT_PAGE_SIZE = 200;
|
|
17
|
+
/** Kind used for projection collapsing. */
|
|
18
|
+
function rowKind(event) {
|
|
19
|
+
if (event.kind === "tool_call")
|
|
20
|
+
return "tool_call";
|
|
21
|
+
if (event.kind === "assistant_message" || event.kind === "reasoning")
|
|
22
|
+
return "assistant";
|
|
23
|
+
return "other";
|
|
24
|
+
}
|
|
25
|
+
/** Collapse a contiguous slice of rows into projected items. */
|
|
26
|
+
export function projectRows(rows) {
|
|
27
|
+
const items = [];
|
|
28
|
+
let i = 0;
|
|
29
|
+
while (i < rows.length) {
|
|
30
|
+
const row = rows[i];
|
|
31
|
+
const kind = rowKind(row.event);
|
|
32
|
+
if (kind === "tool_call") {
|
|
33
|
+
// Collect all rows sharing the same callId (or adjacent tool rows if no callId).
|
|
34
|
+
const callId = row.event.kind === "tool_call" ? row.event.callId : undefined;
|
|
35
|
+
const group = [row.event];
|
|
36
|
+
let j = i + 1;
|
|
37
|
+
while (j < rows.length) {
|
|
38
|
+
const next = rows[j];
|
|
39
|
+
if (rowKind(next.event) !== "tool_call")
|
|
40
|
+
break;
|
|
41
|
+
const nextCallId = next.event.kind === "tool_call" ? next.event.callId : undefined;
|
|
42
|
+
if (callId !== undefined && nextCallId !== undefined && nextCallId !== callId)
|
|
43
|
+
break;
|
|
44
|
+
group.push(next.event);
|
|
45
|
+
j++;
|
|
46
|
+
}
|
|
47
|
+
items.push({
|
|
48
|
+
kind: "tool_call",
|
|
49
|
+
callId,
|
|
50
|
+
sourceSeqStart: row.seq,
|
|
51
|
+
sourceSeqEnd: rows[j - 1].seq,
|
|
52
|
+
events: group,
|
|
53
|
+
});
|
|
54
|
+
i = j;
|
|
55
|
+
}
|
|
56
|
+
else if (kind === "assistant") {
|
|
57
|
+
// Merge adjacent assistant/reasoning chunks.
|
|
58
|
+
const group = [row.event];
|
|
59
|
+
let j = i + 1;
|
|
60
|
+
while (j < rows.length && rowKind(rows[j].event) === "assistant") {
|
|
61
|
+
group.push(rows[j].event);
|
|
62
|
+
j++;
|
|
63
|
+
}
|
|
64
|
+
items.push({
|
|
65
|
+
kind: "assistant",
|
|
66
|
+
sourceSeqStart: row.seq,
|
|
67
|
+
sourceSeqEnd: rows[j - 1].seq,
|
|
68
|
+
events: group,
|
|
69
|
+
});
|
|
70
|
+
i = j;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
items.push({ kind: "other", sourceSeq: row.seq, event: row.event });
|
|
74
|
+
i++;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return items;
|
|
78
|
+
}
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Cursor encoding
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
/** Encode a cursor from a sequence number (opaque string → base-10 decimal). */
|
|
83
|
+
export function encodeCursor(seq) {
|
|
84
|
+
return String(seq);
|
|
85
|
+
}
|
|
86
|
+
/** Decode a cursor; returns `undefined` for an invalid/absent cursor. */
|
|
87
|
+
export function decodeCursor(cursor) {
|
|
88
|
+
if (cursor === null || cursor === undefined || cursor === "")
|
|
89
|
+
return undefined;
|
|
90
|
+
const n = Number(cursor);
|
|
91
|
+
return Number.isFinite(n) && n >= 0 ? n : undefined;
|
|
92
|
+
}
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// AgentTimelineStore
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
export class AgentTimelineStore {
|
|
97
|
+
rows = [];
|
|
98
|
+
epoch = 0;
|
|
99
|
+
nextSeq = 0;
|
|
100
|
+
now;
|
|
101
|
+
constructor(opts = {}) {
|
|
102
|
+
this.now = opts.now ?? (() => new Date().toISOString());
|
|
103
|
+
if (opts.initialRows && opts.initialRows.length > 0) {
|
|
104
|
+
this.rows = [...opts.initialRows];
|
|
105
|
+
const last = this.rows[this.rows.length - 1];
|
|
106
|
+
this.epoch = last.epoch;
|
|
107
|
+
this.nextSeq = last.seq + 1;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** Start a new epoch (called when a new run begins). */
|
|
111
|
+
startEpoch() {
|
|
112
|
+
this.epoch++;
|
|
113
|
+
return this.epoch;
|
|
114
|
+
}
|
|
115
|
+
/** Append one event, assigning the daemon-owned timestamp + monotonic seq. */
|
|
116
|
+
append(event) {
|
|
117
|
+
const row = {
|
|
118
|
+
epoch: this.epoch,
|
|
119
|
+
seq: this.nextSeq++,
|
|
120
|
+
timestamp: this.now(),
|
|
121
|
+
event,
|
|
122
|
+
};
|
|
123
|
+
this.rows.push(row);
|
|
124
|
+
return row;
|
|
125
|
+
}
|
|
126
|
+
currentEpoch() {
|
|
127
|
+
return this.epoch;
|
|
128
|
+
}
|
|
129
|
+
allRows() {
|
|
130
|
+
return this.rows;
|
|
131
|
+
}
|
|
132
|
+
rowCount() {
|
|
133
|
+
return this.rows.length;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Truncate the timeline back to just before the user message identified by messageId.
|
|
137
|
+
* The messageId corresponds to the `messageId` field in user_message stream events.
|
|
138
|
+
* Returns the ISO timestamp of the last retained row, or undefined if nothing was retained.
|
|
139
|
+
* (features/rewind.md § Wire contract)
|
|
140
|
+
*/
|
|
141
|
+
truncateBeforeMessage(messageId) {
|
|
142
|
+
const idx = this.rows.findIndex((row) => {
|
|
143
|
+
const event = row.event;
|
|
144
|
+
return event.kind === "user_message" && event.messageId === messageId;
|
|
145
|
+
});
|
|
146
|
+
if (idx <= 0) {
|
|
147
|
+
// Nothing to truncate or messageId not found — truncate all rows as safe fallback
|
|
148
|
+
if (idx === 0)
|
|
149
|
+
this.rows = [];
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
this.rows = this.rows.slice(0, idx);
|
|
153
|
+
const last = this.rows[this.rows.length - 1];
|
|
154
|
+
return last?.timestamp;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Return a bounded page of projected items.
|
|
158
|
+
*
|
|
159
|
+
* `direction:"after"` from cursor returns rows AFTER that seq (newer); `"before"` returns rows
|
|
160
|
+
* BEFORE that seq (older). Without a cursor, `"after"` returns from the start; `"before"` from
|
|
161
|
+
* the tail.
|
|
162
|
+
*/
|
|
163
|
+
page(opts) {
|
|
164
|
+
const limit = opts.limit ?? DEFAULT_PAGE_SIZE;
|
|
165
|
+
const cursorSeq = decodeCursor(opts.cursor);
|
|
166
|
+
const { direction } = opts;
|
|
167
|
+
// Select the source-row window.
|
|
168
|
+
let window;
|
|
169
|
+
if (direction === "after") {
|
|
170
|
+
const start = cursorSeq !== undefined ? this.rows.findIndex((r) => r.seq > cursorSeq) : 0;
|
|
171
|
+
window = start === -1 ? [] : this.rows.slice(start);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// "before": rows strictly before cursorSeq, reversed then sliced by projected count.
|
|
175
|
+
const end = cursorSeq !== undefined ? this.rows.findIndex((r) => r.seq >= cursorSeq) : this.rows.length;
|
|
176
|
+
window = end === -1 ? [...this.rows] : this.rows.slice(0, end);
|
|
177
|
+
// For "before" we project from the tail end.
|
|
178
|
+
window = window.toReversed();
|
|
179
|
+
}
|
|
180
|
+
// Project and take at most `limit` items, tracking which source rows we consumed.
|
|
181
|
+
const projected = [];
|
|
182
|
+
const usedSeqs = [];
|
|
183
|
+
// For "before" we reversed, so project then re-reverse at the end.
|
|
184
|
+
const allProjected = projectRows(direction === "after" ? window : window.toReversed());
|
|
185
|
+
const pageSlice = direction === "after" ? allProjected.slice(0, limit) : allProjected.slice(-limit);
|
|
186
|
+
for (const item of pageSlice) {
|
|
187
|
+
projected.push(item);
|
|
188
|
+
if (item.kind === "tool_call") {
|
|
189
|
+
usedSeqs.push(item.sourceSeqStart, item.sourceSeqEnd);
|
|
190
|
+
}
|
|
191
|
+
else if (item.kind === "assistant") {
|
|
192
|
+
usedSeqs.push(item.sourceSeqStart, item.sourceSeqEnd);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
usedSeqs.push(item.sourceSeq);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (projected.length === 0) {
|
|
199
|
+
return {
|
|
200
|
+
items: [],
|
|
201
|
+
seqStart: 0,
|
|
202
|
+
seqEnd: 0,
|
|
203
|
+
sourceSeqRanges: [],
|
|
204
|
+
collapsed: false,
|
|
205
|
+
hasNewer: false,
|
|
206
|
+
startCursor: null,
|
|
207
|
+
endCursor: null,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const minSeq = Math.min(...usedSeqs);
|
|
211
|
+
const maxSeq = Math.max(...usedSeqs);
|
|
212
|
+
// hasNewer: true when there are rows in the store with seq > maxSeq.
|
|
213
|
+
const hasNewer = this.rows.some((r) => r.seq > maxSeq);
|
|
214
|
+
// sourceSeqRanges: contiguous runs of source seqs covered by this page.
|
|
215
|
+
const pageRows = this.rows.filter((r) => r.seq >= minSeq && r.seq <= maxSeq);
|
|
216
|
+
const sourceSeqRanges = buildSeqRanges(pageRows.map((r) => r.seq));
|
|
217
|
+
// collapsed: any projected item spans >1 source row.
|
|
218
|
+
const collapsed = projected.some((item) => item.kind === "tool_call"
|
|
219
|
+
? item.sourceSeqStart !== item.sourceSeqEnd
|
|
220
|
+
: item.kind === "assistant"
|
|
221
|
+
? item.sourceSeqStart !== item.sourceSeqEnd
|
|
222
|
+
: false);
|
|
223
|
+
return {
|
|
224
|
+
items: projected,
|
|
225
|
+
seqStart: minSeq,
|
|
226
|
+
seqEnd: maxSeq,
|
|
227
|
+
sourceSeqRanges,
|
|
228
|
+
collapsed,
|
|
229
|
+
hasNewer,
|
|
230
|
+
startCursor: encodeCursor(minSeq),
|
|
231
|
+
endCursor: encodeCursor(maxSeq),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function buildSeqRanges(sorted) {
|
|
236
|
+
if (sorted.length === 0)
|
|
237
|
+
return [];
|
|
238
|
+
const ranges = [];
|
|
239
|
+
let start = sorted[0];
|
|
240
|
+
let end = start;
|
|
241
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
242
|
+
const n = sorted[i];
|
|
243
|
+
if (n === end + 1) {
|
|
244
|
+
end = n;
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
ranges.push({ start, end });
|
|
248
|
+
start = n;
|
|
249
|
+
end = n;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
ranges.push({ start, end });
|
|
253
|
+
return ranges;
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=timeline-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline-store.js","sourceRoot":"","sources":["../../src/agent/timeline-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AACA,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { IncomingMessage } from "node:http";
|
|
2
|
+
/**
|
|
3
|
+
* Optional shared-secret password auth (architecture/auth-security.md § Password auth, § Behavior).
|
|
4
|
+
*
|
|
5
|
+
* The password is sourced from `daemon.auth.password` (config) or `PI_STUDIO_PASSWORD` (env) and is
|
|
6
|
+
* **stored bcrypt-hashed**. When configured, every HTTP request needs `Authorization: Bearer
|
|
7
|
+
* <password>` and every WS upgrade needs subprotocol `pi-studio.bearer.<password>` (browsers cannot
|
|
8
|
+
* set custom WS headers). `GET /api/health` and CORS preflight are exempt (handled by the HTTP
|
|
9
|
+
* pipeline before `authenticate` runs).
|
|
10
|
+
*
|
|
11
|
+
* The daemon never stores or transmits provider API keys — there is nothing here to persist beyond
|
|
12
|
+
* the password hash.
|
|
13
|
+
*/
|
|
14
|
+
export declare const WS_BEARER_SUBPROTOCOL_PREFIX = "pi-studio.bearer.";
|
|
15
|
+
/** True if `value` is already a bcrypt hash (`$2a$` / `$2b$` / `$2y$`). */
|
|
16
|
+
export declare function isBcryptHash(value: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the stored bcrypt hash from config/env (env wins). A plaintext secret is hashed; an
|
|
19
|
+
* already-hashed value is used as-is. Returns `undefined` when no password is configured.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolvePasswordHash(opts: {
|
|
22
|
+
configPassword?: string;
|
|
23
|
+
envPassword?: string;
|
|
24
|
+
}): string | undefined;
|
|
25
|
+
/** Extract a bearer token from an `Authorization: Bearer <token>` header. */
|
|
26
|
+
export declare function bearerFromAuthHeader(header: string | undefined): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Extract the password from a `Sec-WebSocket-Protocol` header carrying
|
|
29
|
+
* `pi-studio.bearer.<password>` (the header is a comma-separated list of offered subprotocols).
|
|
30
|
+
*/
|
|
31
|
+
export declare function bearerFromSubprotocol(header: string | undefined): string | undefined;
|
|
32
|
+
export interface PasswordAuth {
|
|
33
|
+
/** Whether a password is configured. When false, all requests are allowed. */
|
|
34
|
+
readonly enabled: boolean;
|
|
35
|
+
/** Verify a presented plaintext token against the stored hash. */
|
|
36
|
+
verify(token: string | undefined): boolean;
|
|
37
|
+
/** Authenticate an HTTP request via the Authorization bearer header. */
|
|
38
|
+
authenticateHttp(req: Pick<IncomingMessage, "headers">): boolean;
|
|
39
|
+
/** Authenticate a WS upgrade via the `pi-studio.bearer.<password>` subprotocol. */
|
|
40
|
+
authenticateUpgrade(req: Pick<IncomingMessage, "headers">): boolean;
|
|
41
|
+
}
|
|
42
|
+
/** Build a {@link PasswordAuth} from a (possibly undefined) stored bcrypt hash. */
|
|
43
|
+
export declare function createPasswordAuth(passwordHash: string | undefined): PasswordAuth;
|
|
44
|
+
//# sourceMappingURL=password-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-auth.d.ts","sourceRoot":"","sources":["../../src/auth/password-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAIjD;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,4BAA4B,sBAAsB,CAAC;AAEhE,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,MAAM,GAAG,SAAS,CAIrB;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAInF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CASpF;AAED,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,kEAAkE;IAClE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IAC3C,wEAAwE;IACxE,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC;IACjE,mFAAmF;IACnF,mBAAmB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC;CACrE;AAED,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAuBjF"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import bcrypt from "bcryptjs";
|
|
2
|
+
/**
|
|
3
|
+
* Optional shared-secret password auth (architecture/auth-security.md § Password auth, § Behavior).
|
|
4
|
+
*
|
|
5
|
+
* The password is sourced from `daemon.auth.password` (config) or `PI_STUDIO_PASSWORD` (env) and is
|
|
6
|
+
* **stored bcrypt-hashed**. When configured, every HTTP request needs `Authorization: Bearer
|
|
7
|
+
* <password>` and every WS upgrade needs subprotocol `pi-studio.bearer.<password>` (browsers cannot
|
|
8
|
+
* set custom WS headers). `GET /api/health` and CORS preflight are exempt (handled by the HTTP
|
|
9
|
+
* pipeline before `authenticate` runs).
|
|
10
|
+
*
|
|
11
|
+
* The daemon never stores or transmits provider API keys — there is nothing here to persist beyond
|
|
12
|
+
* the password hash.
|
|
13
|
+
*/
|
|
14
|
+
export const WS_BEARER_SUBPROTOCOL_PREFIX = "pi-studio.bearer.";
|
|
15
|
+
/** True if `value` is already a bcrypt hash (`$2a$` / `$2b$` / `$2y$`). */
|
|
16
|
+
export function isBcryptHash(value) {
|
|
17
|
+
return /^\$2[aby]\$\d{2}\$/.test(value);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the stored bcrypt hash from config/env (env wins). A plaintext secret is hashed; an
|
|
21
|
+
* already-hashed value is used as-is. Returns `undefined` when no password is configured.
|
|
22
|
+
*/
|
|
23
|
+
export function resolvePasswordHash(opts) {
|
|
24
|
+
const raw = opts.envPassword?.trim() || opts.configPassword?.trim();
|
|
25
|
+
if (!raw)
|
|
26
|
+
return undefined;
|
|
27
|
+
return isBcryptHash(raw) ? raw : bcrypt.hashSync(raw, 10);
|
|
28
|
+
}
|
|
29
|
+
/** Extract a bearer token from an `Authorization: Bearer <token>` header. */
|
|
30
|
+
export function bearerFromAuthHeader(header) {
|
|
31
|
+
if (!header)
|
|
32
|
+
return undefined;
|
|
33
|
+
const match = header.match(/^Bearer\s+(.+)$/i);
|
|
34
|
+
return match ? match[1].trim() : undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Extract the password from a `Sec-WebSocket-Protocol` header carrying
|
|
38
|
+
* `pi-studio.bearer.<password>` (the header is a comma-separated list of offered subprotocols).
|
|
39
|
+
*/
|
|
40
|
+
export function bearerFromSubprotocol(header) {
|
|
41
|
+
if (!header)
|
|
42
|
+
return undefined;
|
|
43
|
+
for (const entry of header.split(",")) {
|
|
44
|
+
const proto = entry.trim();
|
|
45
|
+
if (proto.startsWith(WS_BEARER_SUBPROTOCOL_PREFIX)) {
|
|
46
|
+
return proto.slice(WS_BEARER_SUBPROTOCOL_PREFIX.length);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
/** Build a {@link PasswordAuth} from a (possibly undefined) stored bcrypt hash. */
|
|
52
|
+
export function createPasswordAuth(passwordHash) {
|
|
53
|
+
const enabled = passwordHash !== undefined;
|
|
54
|
+
const verify = (token) => {
|
|
55
|
+
if (!enabled)
|
|
56
|
+
return true;
|
|
57
|
+
if (!token)
|
|
58
|
+
return false;
|
|
59
|
+
return bcrypt.compareSync(token, passwordHash);
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
enabled,
|
|
63
|
+
verify,
|
|
64
|
+
authenticateHttp(req) {
|
|
65
|
+
if (!enabled)
|
|
66
|
+
return true;
|
|
67
|
+
return verify(bearerFromAuthHeader(req.headers.authorization));
|
|
68
|
+
},
|
|
69
|
+
authenticateUpgrade(req) {
|
|
70
|
+
if (!enabled)
|
|
71
|
+
return true;
|
|
72
|
+
const header = req.headers["sec-websocket-protocol"];
|
|
73
|
+
const value = Array.isArray(header) ? header.join(",") : header;
|
|
74
|
+
return verify(bearerFromSubprotocol(value));
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=password-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-auth.js","sourceRoot":"","sources":["../../src/auth/password-auth.ts"],"names":[],"mappings":"AAEA,OAAO,MAAM,MAAM,UAAU,CAAC;AAE9B;;;;;;;;;;;GAWG;AAEH,MAAM,CAAC,MAAM,4BAA4B,GAAG,mBAAmB,CAAC;AAEhE,2EAA2E;AAC3E,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAGnC;IACC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC;IACpE,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,oBAAoB,CAAC,MAA0B;IAC7D,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,CAAC,CAAE,KAAK,CAAC,CAAC,CAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAA0B;IAC9D,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,UAAU,CAAC,4BAA4B,CAAC,EAAE,CAAC;YACnD,OAAO,KAAK,CAAC,KAAK,CAAC,4BAA4B,CAAC,MAAM,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAaD,mFAAmF;AACnF,MAAM,UAAU,kBAAkB,CAAC,YAAgC;IACjE,MAAM,OAAO,GAAG,YAAY,KAAK,SAAS,CAAC;IAE3C,MAAM,MAAM,GAAG,CAAC,KAAyB,EAAW,EAAE;QACpD,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QACzB,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,YAAsB,CAAC,CAAC;IAC3D,CAAC,CAAC;IAEF,OAAO;QACL,OAAO;QACP,MAAM;QACN,gBAAgB,CAAC,GAAG;YAClB,IAAI,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;YAC1B,OAAO,MAAM,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;QACjE,CAAC;QACD,mBAAmB,CAAC,GAAG;YACrB,IAAI,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;YAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;YACrD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAChE,OAAO,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,CAAC;KACF,CAAC;AACJ,CAAC"}
|