@kelloggt/dsh-program-agents 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +113 -2
  3. package/cordis.patch.yml +5 -0
  4. package/dist/app/agents.d.ts +50 -0
  5. package/dist/app/agents.js +70 -0
  6. package/dist/app/agents.js.map +1 -0
  7. package/dist/app/conversations.d.ts +8 -0
  8. package/dist/app/conversations.js +26 -0
  9. package/dist/app/conversations.js.map +1 -0
  10. package/dist/app/endpoints.d.ts +36 -0
  11. package/dist/app/endpoints.js +162 -0
  12. package/dist/app/endpoints.js.map +1 -0
  13. package/dist/app/inbox.d.ts +61 -0
  14. package/dist/app/inbox.js +253 -0
  15. package/dist/app/inbox.js.map +1 -0
  16. package/dist/app/index.d.ts +70 -0
  17. package/dist/app/index.js +147 -0
  18. package/dist/app/index.js.map +1 -0
  19. package/dist/app/mailbox.d.ts +63 -0
  20. package/dist/app/mailbox.js +173 -0
  21. package/dist/app/mailbox.js.map +1 -0
  22. package/dist/app/models.d.ts +32 -0
  23. package/dist/app/models.js +13 -0
  24. package/dist/app/models.js.map +1 -0
  25. package/dist/app/server.d.ts +36 -0
  26. package/dist/app/server.js +233 -0
  27. package/dist/app/server.js.map +1 -0
  28. package/dist/app/stream-server.d.ts +9 -0
  29. package/dist/app/stream-server.js +77 -0
  30. package/dist/app/stream-server.js.map +1 -0
  31. package/dist/app/stream.d.ts +4 -0
  32. package/dist/app/stream.js +93 -0
  33. package/dist/app/stream.js.map +1 -0
  34. package/dist/app/tools.d.ts +16 -0
  35. package/dist/app/tools.js +24 -0
  36. package/dist/app/tools.js.map +1 -0
  37. package/dist/client/controller.d.ts +21 -0
  38. package/dist/client/controller.js +140 -0
  39. package/dist/client/controller.js.map +1 -0
  40. package/dist/client/index.d.ts +22 -0
  41. package/dist/client/index.js +14 -0
  42. package/dist/client/index.js.map +1 -0
  43. package/dist/client/model.d.ts +66 -0
  44. package/dist/client/model.js +147 -0
  45. package/dist/client/model.js.map +1 -0
  46. package/dist/client/models.d.ts +11 -0
  47. package/dist/client/models.js +27 -0
  48. package/dist/client/models.js.map +1 -0
  49. package/dist/client/transport.d.ts +64 -0
  50. package/dist/client/transport.js +141 -0
  51. package/dist/client/transport.js.map +1 -0
  52. package/dist/client/view.d.ts +19 -0
  53. package/dist/client/view.js +69 -0
  54. package/dist/client/view.js.map +1 -0
  55. package/dist/client.js +673 -0
  56. package/dist/conversations.d.ts +92 -0
  57. package/dist/conversations.js +6 -0
  58. package/dist/conversations.js.map +1 -0
  59. package/dist/endpoints.d.ts +48 -0
  60. package/dist/endpoints.js +43 -0
  61. package/dist/endpoints.js.map +1 -0
  62. package/dist/examples/dashboard.js +42 -0
  63. package/dist/examples/dynamic-server.js +27 -0
  64. package/dist/examples/inbox-worker.js +22 -0
  65. package/dist/examples/model-slots.js +19 -0
  66. package/dist/examples/standalone-supervisor.js +20 -0
  67. package/dist/host/adapter.d.ts +195 -0
  68. package/dist/host/adapter.js +630 -0
  69. package/dist/host/adapter.js.map +1 -0
  70. package/dist/host/agents.d.ts +35 -0
  71. package/dist/host/agents.js +222 -0
  72. package/dist/host/agents.js.map +1 -0
  73. package/dist/host/audit.d.ts +14 -0
  74. package/dist/host/audit.js +39 -0
  75. package/dist/host/audit.js.map +1 -0
  76. package/dist/host/catalog.d.ts +53 -0
  77. package/dist/host/catalog.js +116 -0
  78. package/dist/host/catalog.js.map +1 -0
  79. package/dist/host/contracts.d.ts +38 -0
  80. package/dist/host/contracts.js +2 -0
  81. package/dist/host/contracts.js.map +1 -0
  82. package/dist/host/conversations.d.ts +41 -0
  83. package/dist/host/conversations.js +324 -0
  84. package/dist/host/conversations.js.map +1 -0
  85. package/dist/host/events.d.ts +12 -0
  86. package/dist/host/events.js +106 -0
  87. package/dist/host/events.js.map +1 -0
  88. package/dist/host/http.d.ts +14 -0
  89. package/dist/host/http.js +30 -0
  90. package/dist/host/http.js.map +1 -0
  91. package/dist/host/index.d.ts +23 -0
  92. package/dist/host/index.js +84 -0
  93. package/dist/host/index.js.map +1 -0
  94. package/dist/host/installed-v10.js +19797 -0
  95. package/dist/host/installed-v11.js +19797 -0
  96. package/dist/host/installed-v12.js +19797 -0
  97. package/dist/host/installed-v13.js +19797 -0
  98. package/dist/host/installed-v2.js +19797 -0
  99. package/dist/host/installed-v3.js +19797 -0
  100. package/dist/host/installed-v4.js +19797 -0
  101. package/dist/host/installed-v5.js +19797 -0
  102. package/dist/host/installed-v6.js +19797 -0
  103. package/dist/host/installed-v7.js +19797 -0
  104. package/dist/host/installed-v8.js +19797 -0
  105. package/dist/host/installed-v9.js +19797 -0
  106. package/dist/host/mcp.d.ts +11 -0
  107. package/dist/host/mcp.js +42 -0
  108. package/dist/host/mcp.js.map +1 -0
  109. package/dist/host/models.d.ts +37 -0
  110. package/dist/host/models.js +141 -0
  111. package/dist/host/models.js.map +1 -0
  112. package/dist/host/operations.d.ts +22 -0
  113. package/dist/host/operations.js +72 -0
  114. package/dist/host/operations.js.map +1 -0
  115. package/dist/host/plugin.js +19797 -0
  116. package/dist/host/policies.d.ts +36 -0
  117. package/dist/host/policies.js +73 -0
  118. package/dist/host/policies.js.map +1 -0
  119. package/dist/host/requests.d.ts +57 -0
  120. package/dist/host/requests.js +353 -0
  121. package/dist/host/requests.js.map +1 -0
  122. package/dist/host/tool-client.d.ts +19 -0
  123. package/dist/host/tool-client.js +62 -0
  124. package/dist/host/tool-client.js.map +1 -0
  125. package/dist/host/validation.d.ts +5 -0
  126. package/dist/host/validation.js +42 -0
  127. package/dist/host/validation.js.map +1 -0
  128. package/dist/mcp.d.ts +7 -0
  129. package/dist/mcp.js +2 -0
  130. package/dist/mcp.js.map +1 -0
  131. package/dist/models.d.ts +34 -0
  132. package/dist/models.js +53 -0
  133. package/dist/models.js.map +1 -0
  134. package/dist/monitoring/error-buffer.d.ts +89 -0
  135. package/dist/monitoring/error-buffer.js +355 -0
  136. package/dist/monitoring/error-buffer.js.map +1 -0
  137. package/dist/monitoring/fatal.d.ts +6 -0
  138. package/dist/monitoring/fatal.js +32 -0
  139. package/dist/monitoring/fatal.js.map +1 -0
  140. package/dist/monitoring/index.d.ts +7 -0
  141. package/dist/monitoring/index.js +8 -0
  142. package/dist/monitoring/index.js.map +1 -0
  143. package/dist/monitoring/logger.d.ts +45 -0
  144. package/dist/monitoring/logger.js +174 -0
  145. package/dist/monitoring/logger.js.map +1 -0
  146. package/dist/monitoring/schemas.d.ts +34 -0
  147. package/dist/monitoring/schemas.js +132 -0
  148. package/dist/monitoring/schemas.js.map +1 -0
  149. package/dist/monitoring/standard.d.ts +51 -0
  150. package/dist/monitoring/standard.js +140 -0
  151. package/dist/monitoring/standard.js.map +1 -0
  152. package/dist/monitoring/tailer.d.ts +41 -0
  153. package/dist/monitoring/tailer.js +210 -0
  154. package/dist/monitoring/tailer.js.map +1 -0
  155. package/dist/requests.d.ts +92 -0
  156. package/dist/requests.js +120 -0
  157. package/dist/requests.js.map +1 -0
  158. package/dist/runtime/bootstrap.d.ts +1 -0
  159. package/dist/runtime/bootstrap.js +25 -0
  160. package/dist/runtime/bootstrap.js.map +1 -0
  161. package/dist/runtime/definitions.d.ts +7 -0
  162. package/dist/runtime/definitions.js +138 -0
  163. package/dist/runtime/definitions.js.map +1 -0
  164. package/dist/runtime/index.d.ts +4 -0
  165. package/dist/runtime/index.js +4 -0
  166. package/dist/runtime/index.js.map +1 -0
  167. package/dist/runtime/log-file.d.ts +24 -0
  168. package/dist/runtime/log-file.js +124 -0
  169. package/dist/runtime/log-file.js.map +1 -0
  170. package/dist/runtime/protocol.d.ts +60 -0
  171. package/dist/runtime/protocol.js +155 -0
  172. package/dist/runtime/protocol.js.map +1 -0
  173. package/dist/runtime/registry.d.ts +8 -0
  174. package/dist/runtime/registry.js +38 -0
  175. package/dist/runtime/registry.js.map +1 -0
  176. package/dist/runtime/supervisor.d.ts +74 -0
  177. package/dist/runtime/supervisor.js +881 -0
  178. package/dist/runtime/supervisor.js.map +1 -0
  179. package/dist/sdk/connection.d.ts +33 -0
  180. package/dist/sdk/connection.js +265 -0
  181. package/dist/sdk/connection.js.map +1 -0
  182. package/dist/sdk/index.d.ts +8 -0
  183. package/dist/sdk/index.js +2 -0
  184. package/dist/sdk/index.js.map +1 -0
  185. package/dist/supervision.d.ts +22 -0
  186. package/dist/supervision.js +32 -0
  187. package/dist/supervision.js.map +1 -0
  188. package/dist/types.d.ts +170 -0
  189. package/dist/types.js +2 -0
  190. package/dist/types.js.map +1 -0
  191. package/docs/installation.md +35 -0
  192. package/docs/log-format.md +102 -0
  193. package/docs/publishing.md +45 -0
  194. package/docs/supervision.md +73 -0
  195. package/examples/dashboard.ts +31 -0
  196. package/examples/dsh-web-local.patch.yml +15 -0
  197. package/examples/dynamic-server.ts +13 -0
  198. package/examples/inbox-worker.ts +17 -0
  199. package/examples/model-slots.ts +12 -0
  200. package/examples/standalone-supervisor.ts +14 -0
  201. package/examples/watch-server.ts +12 -0
  202. package/package.json +131 -3
  203. package/schemas/dsh.http.request.v1.schema.json +14 -0
  204. package/schemas/dsh.program.error-batch.v1.schema.json +24 -0
  205. package/schemas/dsh.program.error.v1.schema.json +8 -0
  206. package/schemas/standard-log-record.v1.schema.json +26 -0
  207. package/skills/program-agents/SKILL.md +124 -0
  208. package/skills/program-agents/chat-sidebar.md +23 -0
  209. package/skills/program-agents/endpoints.md +92 -0
  210. package/skills/program-agents/inboxes.md +120 -0
  211. package/skills/program-agents/log-format.md +102 -0
  212. package/skills/program-agents/models.md +59 -0
  213. package/skills/program-agents/references/chat-sidebar/AgentSidebar.tsx +181 -0
  214. package/skills/program-agents/references/chat-sidebar/README.md +181 -0
  215. package/skills/program-agents/references/chat-sidebar/agent-sidebar.css +37 -0
  216. package/skills/program-agents/references/chat-sidebar/backend.ts +184 -0
  217. package/skills/program-agents/references/chat-sidebar/protocol.ts +214 -0
  218. package/skills/program-agents/schemas/dsh.http.request.v1.schema.json +14 -0
  219. package/skills/program-agents/schemas/dsh.program.error-batch.v1.schema.json +24 -0
  220. package/skills/program-agents/schemas/dsh.program.error.v1.schema.json +8 -0
  221. package/skills/program-agents/schemas/standard-log-record.v1.schema.json +26 -0
  222. package/skills/program-agents/ui-patterns.md +39 -0
@@ -0,0 +1,210 @@
1
+ import { open, stat, mkdir, rename } from 'node:fs/promises';
2
+ import { resolve, dirname } from 'node:path';
3
+ import { JsonlDecoder, MAX_LOG_LINE_BYTES } from './standard.js';
4
+ /** Bounded file reads, inode-aware rotation, truncation and partial-line handling. */
5
+ export class LogTailer {
6
+ options;
7
+ ready;
8
+ path;
9
+ handle;
10
+ identity;
11
+ offset = 0;
12
+ committed = 0;
13
+ cursor;
14
+ first = true;
15
+ closed = false;
16
+ timer;
17
+ work = Promise.resolve();
18
+ decoder;
19
+ records = [];
20
+ constructor(options) {
21
+ this.options = options;
22
+ if (options.pollMs !== undefined && (!Number.isSafeInteger(options.pollMs) || options.pollMs < 1))
23
+ throw new Error('Invalid polling interval');
24
+ this.path = resolve(options.logsPath);
25
+ this.decoder = new JsonlDecoder((record, offset) => this.records.push({ record, offset }));
26
+ this.ready = this.start();
27
+ }
28
+ report(error) { try {
29
+ this.options.onError?.(error);
30
+ }
31
+ catch { } }
32
+ async start() {
33
+ try {
34
+ if ((await stat(this.path)).isDirectory())
35
+ this.path = resolve(this.path, 'app-log.jsonl');
36
+ }
37
+ catch (error) {
38
+ if (error.code !== 'ENOENT')
39
+ throw error;
40
+ if (!/\.jsonl$/i.test(this.path))
41
+ this.path = resolve(this.path, 'app-log.jsonl');
42
+ }
43
+ if (this.options.cursorPath) {
44
+ try {
45
+ const handle = await open(resolve(this.options.cursorPath), 'r');
46
+ try {
47
+ if ((await handle.stat()).size > 8192)
48
+ throw new Error('Oversize log cursor');
49
+ const cursor = JSON.parse(await handle.readFile('utf8'));
50
+ if (cursor.version === 1 && cursor.path === this.path && Number.isSafeInteger(cursor.dev) && Number.isSafeInteger(cursor.ino) && Number.isSafeInteger(cursor.offset) && cursor.offset >= 0)
51
+ this.cursor = cursor;
52
+ }
53
+ finally {
54
+ await handle.close();
55
+ }
56
+ }
57
+ catch (error) {
58
+ if (error.code !== 'ENOENT')
59
+ throw error;
60
+ }
61
+ }
62
+ await this.poll();
63
+ if (!this.closed) {
64
+ this.timer = setInterval(() => { void this.poll().catch(error => this.report(error)); }, this.options.pollMs ?? 250);
65
+ this.timer.unref();
66
+ }
67
+ }
68
+ /** Exposed for deterministic shutdown/tests; overlapping polls serialize. */
69
+ poll() {
70
+ this.work = this.work.then(() => this.closed ? undefined : this.tick());
71
+ this.work = this.work.catch(error => { this.report(error); throw error; });
72
+ // Preserve a recoverable queue after transient filesystem/callback failures.
73
+ const result = this.work;
74
+ this.work = result.catch(() => { });
75
+ return result;
76
+ }
77
+ async attach() {
78
+ let handle;
79
+ try {
80
+ handle = await open(this.path, 'r');
81
+ }
82
+ catch (error) {
83
+ if (error.code === 'ENOENT') {
84
+ this.first = false;
85
+ return false;
86
+ }
87
+ throw error;
88
+ }
89
+ const info = await handle.stat();
90
+ if (!info.isFile()) {
91
+ await handle.close();
92
+ return false;
93
+ }
94
+ this.handle = handle;
95
+ this.identity = { dev: info.dev, ino: info.ino };
96
+ const cursorMatches = this.cursor && this.cursor.dev === info.dev && this.cursor.ino === info.ino && this.cursor.offset <= info.size;
97
+ this.offset = cursorMatches ? this.cursor.offset : this.first && !this.options.readExisting ? info.size : 0;
98
+ this.committed = this.offset;
99
+ this.first = false;
100
+ this.decoder.reset();
101
+ if (this.offset > 0 && !cursorMatches) {
102
+ const last = Buffer.alloc(1);
103
+ await handle.read(last, 0, 1, this.offset - 1);
104
+ if (last[0] !== 10)
105
+ this.decoder.discardPartialLine();
106
+ }
107
+ return true;
108
+ }
109
+ async readAvailable() {
110
+ const handle = this.handle;
111
+ const info = await handle.stat();
112
+ if (info.size < this.offset) {
113
+ this.offset = 0;
114
+ this.committed = 0;
115
+ this.decoder.reset();
116
+ }
117
+ const chunk = Buffer.alloc(MAX_LOG_LINE_BYTES);
118
+ // Maximum 512 KiB per poll, regardless of file size.
119
+ for (let i = 0; i < 8; i++) {
120
+ const { bytesRead } = await handle.read(chunk, 0, chunk.length, this.offset);
121
+ if (!bytesRead)
122
+ return true;
123
+ const start = this.offset;
124
+ this.decoder.push(chunk.subarray(0, bytesRead), start);
125
+ this.offset += bytesRead;
126
+ const records = this.records;
127
+ this.records = [];
128
+ try {
129
+ for (const { record, offset } of records)
130
+ await this.options.onRecord(record, { path: this.path, offset, ...(this.options.run ? { run: this.options.run } : {}) });
131
+ }
132
+ catch (error) {
133
+ // Replay this bounded chunk on callback failure; event_id consumers dedup.
134
+ this.offset = this.committed;
135
+ this.decoder.reset();
136
+ throw error;
137
+ }
138
+ // Commit through the last newline, including malformed/oversize lines.
139
+ const newline = chunk.subarray(0, bytesRead).lastIndexOf(10);
140
+ if (newline >= 0)
141
+ this.committed = start + newline + 1;
142
+ await this.persistCursor();
143
+ if (bytesRead < chunk.length)
144
+ return true;
145
+ }
146
+ return false;
147
+ }
148
+ async persistCursor() {
149
+ if (!this.options.cursorPath || !this.identity)
150
+ return;
151
+ const target = resolve(this.options.cursorPath);
152
+ await mkdir(dirname(target), { recursive: true, mode: 0o700 });
153
+ const temp = `${target}.tmp-${process.pid}`;
154
+ const handle = await open(temp, 'w', 0o600);
155
+ try {
156
+ await handle.writeFile(JSON.stringify({ version: 1, path: this.path, ...this.identity, offset: this.committed }));
157
+ await handle.sync();
158
+ }
159
+ finally {
160
+ await handle.close();
161
+ }
162
+ // Target is the resolved configured cursor path.
163
+ await rename(temp, target);
164
+ }
165
+ async tick() {
166
+ if (!this.handle && !await this.attach())
167
+ return;
168
+ const eof = await this.readAvailable();
169
+ let current;
170
+ try {
171
+ current = await stat(this.path);
172
+ }
173
+ catch (error) {
174
+ if (error.code !== 'ENOENT')
175
+ throw error;
176
+ return;
177
+ }
178
+ if (this.identity?.dev === current.dev && this.identity.ino === current.ino || !eof)
179
+ return;
180
+ await this.handle.close();
181
+ this.handle = undefined;
182
+ this.decoder.reset();
183
+ if (await this.attach())
184
+ await this.readAvailable();
185
+ }
186
+ async close() {
187
+ if (this.timer) {
188
+ clearInterval(this.timer);
189
+ this.timer = undefined;
190
+ }
191
+ try {
192
+ await this.ready;
193
+ await this.poll();
194
+ }
195
+ finally {
196
+ this.closed = true;
197
+ if (this.timer) {
198
+ clearInterval(this.timer);
199
+ this.timer = undefined;
200
+ }
201
+ await this.work;
202
+ if (this.handle) {
203
+ await this.handle.close();
204
+ this.handle = undefined;
205
+ }
206
+ }
207
+ }
208
+ }
209
+ export { LogTailer as JsonlMonitor };
210
+ //# sourceMappingURL=tailer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tailer.js","sourceRoot":"","sources":["../../src/monitoring/tailer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ import type { JsonValue } from './types.js';
2
+ /** Selection/creation is performed by the parent router, never by the durable store. */
3
+ export type AgentTarget = string | {
4
+ id: string;
5
+ } | {
6
+ name: string;
7
+ instructions?: string;
8
+ } | {
9
+ create: {
10
+ name: string;
11
+ instructions?: string;
12
+ };
13
+ };
14
+ /** JSON Schema Draft 2020-12, not the intentionally limited logging schema language. */
15
+ export type JSONSchema = Record<string, JsonValue> | boolean;
16
+ export type ResponseSchema = JSONSchema;
17
+ export type RequestStatus = 'pending' | 'answered' | 'cancelled' | 'expired' | 'failed' | 'dispatch-unknown';
18
+ export interface RequestScope {
19
+ ownerId: string;
20
+ program: string;
21
+ }
22
+ export interface ResponseReceipt {
23
+ id: string;
24
+ requestId: string;
25
+ status: 'answered';
26
+ agentId: string;
27
+ answeredAt: string;
28
+ }
29
+ export interface RequestRecord {
30
+ /** Server-generated opaque UUID. The id alias is provided for receipt-style callers. */
31
+ id: string;
32
+ requestId: string;
33
+ ownerId: string;
34
+ program: string;
35
+ /** Optional caller-provided idempotency key; this is not the server request identity. */
36
+ requestKey?: string;
37
+ target: JsonValue;
38
+ body: JsonValue;
39
+ responseSchema: ResponseSchema;
40
+ prompt?: string;
41
+ status: RequestStatus;
42
+ agentId?: string;
43
+ createdAt: string;
44
+ deadline: string;
45
+ dispatchAcceptedAt?: string;
46
+ answeredAt?: string;
47
+ closedAt?: string;
48
+ response?: JsonValue;
49
+ receipt?: ResponseReceipt;
50
+ error?: string;
51
+ }
52
+ export interface CreateRequestOptions {
53
+ /** Idempotency key scoped to ownerId + program; returned requestId is always a UUID. */
54
+ requestId?: string;
55
+ requestKey?: string;
56
+ target: JsonValue;
57
+ body: JsonValue;
58
+ responseSchema?: ResponseSchema;
59
+ prompt?: string;
60
+ timeoutMs?: number;
61
+ }
62
+ export interface RequestWaitOptions {
63
+ waitMs?: number;
64
+ }
65
+ export declare const REQUEST_LIMITS: Readonly<{
66
+ schemaBytes: number;
67
+ schemaDepth: 32;
68
+ /** Reserve four nesting levels for request/response and transport envelopes. */
69
+ payloadDepth: 28;
70
+ payloadNodes: 9900;
71
+ bodyBytes: number;
72
+ requestBytes: number;
73
+ promptBytes: number;
74
+ defaultTimeoutMs: 120000;
75
+ maxTimeoutMs: 3600000;
76
+ maxWaitMs: 30000;
77
+ pollMs: 50;
78
+ maxRequests: 10000;
79
+ maxPendingPerProgram: 128;
80
+ maxPending: 1024;
81
+ }>;
82
+ export declare const DEFAULT_RESPONSE_SCHEMA: ResponseSchema;
83
+ export type ResponseValidator = (body: unknown) => void;
84
+ /** Validate payloads before persistence, reserving depth and nodes for bridge framing. */
85
+ export declare function assertRequestPayload(value: unknown): asserts value is JsonValue;
86
+ /**
87
+ * Compile a real Draft 2020-12 schema. No coercion, default insertion, property
88
+ * removal, remote loading or format plugins. Unknown formats/keywords fail closed.
89
+ * Input/schema bounds constrain state, not CPU: trusted program regexes can still
90
+ * be expensive, and validation is not a sandbox or an execution time guarantee.
91
+ */
92
+ export declare function createResponseValidator(schema?: ResponseSchema): ResponseValidator;
@@ -0,0 +1,120 @@
1
+ import * as Ajv2020Module from 'ajv/dist/2020.js';
2
+ import { assertJson, ProgramError } from './runtime/protocol.js';
3
+ export const REQUEST_LIMITS = Object.freeze({
4
+ schemaBytes: 16 * 1024,
5
+ schemaDepth: 32,
6
+ /** Reserve four nesting levels for request/response and transport envelopes. */
7
+ payloadDepth: 28,
8
+ payloadNodes: 9900,
9
+ bodyBytes: 48 * 1024,
10
+ requestBytes: 56 * 1024,
11
+ promptBytes: 8 * 1024,
12
+ defaultTimeoutMs: 120_000,
13
+ maxTimeoutMs: 3_600_000,
14
+ maxWaitMs: 30_000,
15
+ pollMs: 50,
16
+ maxRequests: 10_000,
17
+ maxPendingPerProgram: 128,
18
+ maxPending: 1024,
19
+ });
20
+ export const DEFAULT_RESPONSE_SCHEMA = Object.freeze({ type: 'string' });
21
+ /** Validate payloads before persistence, reserving depth and nodes for bridge framing. */
22
+ export function assertRequestPayload(value) {
23
+ assertJson(value);
24
+ // assertJson has already excluded cycles, accessors, sparse arrays and non-JSON.
25
+ let nodes = 0;
26
+ const visit = (item, depth) => {
27
+ if (++nodes > REQUEST_LIMITS.payloadNodes || depth > REQUEST_LIMITS.payloadDepth)
28
+ throw new ProgramError('LIMIT', 'Request payload complexity exceeds framing-safe limits (depth 28, 9900 nodes)');
29
+ if (item && typeof item === 'object')
30
+ for (const child of Object.values(item))
31
+ visit(child, depth + 1);
32
+ };
33
+ visit(value, 0);
34
+ }
35
+ // Ajv is CommonJS in NodeNext. Both native ESM and TS runners expose one of these.
36
+ const Ajv2020 = (Ajv2020Module.default ?? Ajv2020Module.Ajv2020);
37
+ const schemaMaps = new Set(['$defs', 'definitions', 'properties', 'patternProperties', 'dependentSchemas']);
38
+ const schemaArrays = new Set(['allOf', 'anyOf', 'oneOf', 'prefixItems']);
39
+ const schemaChildren = new Set(['items', 'additionalProperties', 'contains', 'propertyNames', 'unevaluatedProperties', 'unevaluatedItems', 'not', 'if', 'then', 'else', 'contentSchema']);
40
+ function safeMessage(value) {
41
+ let message;
42
+ try {
43
+ message = value instanceof Error ? value.message : String(value);
44
+ }
45
+ catch {
46
+ message = 'Validation failed';
47
+ }
48
+ return message.slice(0, 512).replace(/[\u0000-\u001f\u007f]/g, ' ');
49
+ }
50
+ function checkReferences(schema) {
51
+ if (typeof schema === 'boolean')
52
+ return;
53
+ for (const keyword of ['$ref', '$dynamicRef', '$recursiveRef']) {
54
+ const ref = schema[keyword];
55
+ if (ref !== undefined && (typeof ref !== 'string' || !ref.startsWith('#')))
56
+ throw new ProgramError('INVALID_SCHEMA', 'Only local fragment schema references are supported; remote references are not fetched');
57
+ }
58
+ if (schema.$async !== undefined)
59
+ throw new ProgramError('INVALID_SCHEMA', 'Asynchronous response schemas are not supported');
60
+ for (const [key, value] of Object.entries(schema)) {
61
+ if (schemaMaps.has(key) && value && typeof value === 'object' && !Array.isArray(value)) {
62
+ for (const child of Object.values(value))
63
+ if (typeof child === 'boolean' || child && typeof child === 'object' && !Array.isArray(child))
64
+ checkReferences(child);
65
+ }
66
+ else if (schemaArrays.has(key) && Array.isArray(value)) {
67
+ for (const child of value)
68
+ if (typeof child === 'boolean' || child && typeof child === 'object' && !Array.isArray(child))
69
+ checkReferences(child);
70
+ }
71
+ else if (schemaChildren.has(key) && (typeof value === 'boolean' || value && typeof value === 'object' && !Array.isArray(value)))
72
+ checkReferences(value);
73
+ }
74
+ }
75
+ /**
76
+ * Compile a real Draft 2020-12 schema. No coercion, default insertion, property
77
+ * removal, remote loading or format plugins. Unknown formats/keywords fail closed.
78
+ * Input/schema bounds constrain state, not CPU: trusted program regexes can still
79
+ * be expensive, and validation is not a sandbox or an execution time guarantee.
80
+ */
81
+ export function createResponseValidator(schema = DEFAULT_RESPONSE_SCHEMA) {
82
+ let validate;
83
+ try {
84
+ assertJson(schema);
85
+ if (typeof schema !== 'boolean' && (!schema || typeof schema !== 'object' || Array.isArray(schema)))
86
+ throw new Error('Expected a JSON Schema object or boolean');
87
+ if (Buffer.byteLength(JSON.stringify(schema)) > REQUEST_LIMITS.schemaBytes)
88
+ throw new Error('Response schema exceeds 16 KiB');
89
+ // assertJson above enforces the shared depth-32 and finite JSON boundaries.
90
+ checkReferences(schema);
91
+ const ajv = new Ajv2020({ strict: true, allErrors: false, coerceTypes: false, removeAdditional: false, useDefaults: false, validateFormats: true, addUsedSchema: false });
92
+ validate = ajv.compile(JSON.parse(JSON.stringify(schema)));
93
+ }
94
+ catch (error) {
95
+ throw new ProgramError('INVALID_SCHEMA', `Invalid response schema: ${safeMessage(error)}`);
96
+ }
97
+ return (body) => {
98
+ try {
99
+ assertRequestPayload(body);
100
+ if (Buffer.byteLength(JSON.stringify(body)) > REQUEST_LIMITS.bodyBytes)
101
+ throw new Error('Response exceeds 48 KiB');
102
+ }
103
+ catch (error) {
104
+ throw new ProgramError('INVALID_RESPONSE', `Invalid response JSON: ${safeMessage(error)}`);
105
+ }
106
+ let valid;
107
+ try {
108
+ valid = validate(body);
109
+ }
110
+ catch (error) {
111
+ throw new ProgramError('INVALID_RESPONSE', `Response validation failed: ${safeMessage(error)}`);
112
+ }
113
+ if (!valid) {
114
+ const error = validate.errors?.[0];
115
+ const detail = error ? `${error.instancePath || '/'} ${error.message ?? 'does not match the response schema'}` : 'does not match the response schema';
116
+ throw new ProgramError('INVALID_RESPONSE', `Response ${safeMessage(detail)}`);
117
+ }
118
+ };
119
+ }
120
+ //# sourceMappingURL=requests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requests.js","sourceRoot":"","sources":["../src/requests.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import { pathToFileURL } from 'node:url';
2
+ import { beginRegistration, ChildConnection, endRegistration } from '../sdk/connection.js';
3
+ // This file is the fork target, not a general-purpose REPL. The supervisor alone
4
+ // chooses this already-configured entrypoint; no code or identity comes from tools.
5
+ const entry = process.argv[2];
6
+ const connection = new ChildConnection();
7
+ void connection.execute(async () => {
8
+ if (!entry)
9
+ throw new Error('Missing configured program entrypoint');
10
+ process.argv = [process.execPath, entry, ...process.argv.slice(3)];
11
+ const registration = beginRegistration();
12
+ try {
13
+ const module = await import(pathToFileURL(entry).href);
14
+ const main = module.default ?? registration.main;
15
+ if (module.default && registration.main)
16
+ throw new Error('Use either default main(ctx) or runProgram(main), not both');
17
+ if (typeof main !== 'function')
18
+ throw new Error('Program must export default main(ctx)');
19
+ return main;
20
+ }
21
+ finally {
22
+ endRegistration();
23
+ }
24
+ });
25
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/runtime/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG3F,iFAAiF;AACjF,oFAAoF;AACpF,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC9B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;AACzC,KAAK,UAAU,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;IACjC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACrE,OAAO,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,MAAM,YAAY,GAAG,iBAAiB,EAAE,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,MAAM,GAA8B,MAAM,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;QAClF,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC;QACjD,IAAI,MAAM,CAAC,OAAO,IAAI,YAAY,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QACvH,IAAI,OAAO,IAAI,KAAK,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACzF,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QAAC,eAAe,EAAE,CAAC;IAAC,CAAC;AAClC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ProgramDefinition, ProgramResource, ProgramUrlDefinition } from '../types.js';
2
+ export declare function normalizeResource(input: unknown, available?: boolean, requireType?: boolean): ProgramResource;
3
+ /** Configured recipes retain metadata without evaluating a listener or browser hostname. */
4
+ export declare function definitionResource(input: ProgramUrlDefinition): ProgramResource;
5
+ /** Definitions execute trusted code, but config/metadata still have bounded exact shapes. */
6
+ export declare function normalizeDefinition(program: string, input: ProgramDefinition): ProgramDefinition;
7
+ export declare function definitionCommand(definition: ProgramDefinition): string[];
@@ -0,0 +1,138 @@
1
+ import { isAbsolute, resolve } from 'node:path';
2
+ import { endpointName, normalizeEndpointPath } from '../endpoints.js';
3
+ import { normalizeSupervision } from '../supervision.js';
4
+ import { exactKeys, isRecord, ProgramError, RUNTIME_LIMITS, validName } from './protocol.js';
5
+ const controls = /[\u0000-\u001f\u007f]/;
6
+ /** Paths are informational descriptors; callers must never turn them into file:// links. */
7
+ function location(value, allowPath) {
8
+ if (typeof value !== 'string' || !value || value.length > 4096 || controls.test(value))
9
+ throw new ProgramError('INVALID_URL', 'Resource location must be a bounded HTTP(S) URL or documentation path');
10
+ if (allowPath && isAbsolute(value))
11
+ return value;
12
+ if (!/^https?:\/\//i.test(value) || /\s/.test(value))
13
+ throw new ProgramError('INVALID_URL', 'Resource URL must be explicit HTTP(S) without whitespace or controls');
14
+ let url;
15
+ try {
16
+ url = new URL(value);
17
+ }
18
+ catch {
19
+ throw new ProgramError('INVALID_URL', 'Resource URL must be absolute HTTP(S)');
20
+ }
21
+ if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password)
22
+ throw new ProgramError('INVALID_URL', 'Only HTTP(S) links without credentials may be published');
23
+ return url.href;
24
+ }
25
+ export function normalizeResource(input, available = false, requireType = false) {
26
+ if (!isRecord(input) || !exactKeys(input, ['id', 'title', 'url'], ['type', 'docs']) || !validName(input.id) || typeof input.title !== 'string' || input.title.length > 256 || (requireType && input.type === undefined) || (input.type !== undefined && !['ui', 'api', 'docs'].includes(input.type)))
27
+ throw new ProgramError('INVALID_INPUT', 'Invalid resource');
28
+ return {
29
+ id: input.id,
30
+ title: input.title,
31
+ url: location(input.url, input.type === 'docs'),
32
+ ...(input.type === undefined ? {} : { type: input.type }),
33
+ ...(input.docs === undefined ? {} : { docs: location(input.docs, true) }),
34
+ available,
35
+ };
36
+ }
37
+ /** Configured recipes retain metadata without evaluating a listener or browser hostname. */
38
+ export function definitionResource(input) {
39
+ if (input.endpoint === undefined)
40
+ return normalizeResource(input);
41
+ return {
42
+ id: input.id, title: input.title, type: input.type, url: '',
43
+ endpoint: input.endpoint, path: input.path ?? '/',
44
+ ...(input.docs === undefined ? {} : { docs: input.docs }), available: false,
45
+ };
46
+ }
47
+ function normalizeUrlDefinition(input, endpoints) {
48
+ if (!isRecord(input) || !exactKeys(input, ['id', 'title', 'type'], ['url', 'endpoint', 'path', 'docs']))
49
+ throw new ProgramError('INVALID_INPUT', 'Invalid configured resource');
50
+ if (input.url !== undefined) {
51
+ if (Object.hasOwn(input, 'endpoint') || Object.hasOwn(input, 'path'))
52
+ throw new ProgramError('INVALID_INPUT', 'Resource requires a literal URL or an endpoint recipe, not both');
53
+ const { available: _, ...resource } = normalizeResource(input, false, true);
54
+ return resource;
55
+ }
56
+ if (Object.hasOwn(input, 'url') || !validName(input.id) || typeof input.title !== 'string' || input.title.length > 256 || !['ui', 'api', 'docs'].includes(input.type) || !endpointName(input.endpoint) || !Object.hasOwn(endpoints, input.endpoint))
57
+ throw new ProgramError('INVALID_INPUT', 'Resource recipe must reference a configured endpoint');
58
+ return {
59
+ id: input.id, title: input.title, type: input.type,
60
+ endpoint: input.endpoint, path: normalizeEndpointPath(input.path),
61
+ ...(input.docs === undefined ? {} : { docs: location(input.docs, true) }),
62
+ };
63
+ }
64
+ /** Definitions execute trusted code, but config/metadata still have bounded exact shapes. */
65
+ export function normalizeDefinition(program, input) {
66
+ if (!validName(program) || !isRecord(input) || !exactKeys(input, [], ['entry', 'command', 'name', 'description', 'urls', 'endpoints', 'logsPath', 'cwd', 'args', 'env', 'allowedCapabilities', 'supervision']))
67
+ throw new ProgramError('INVALID_CONFIG', 'Invalid program definition');
68
+ const entry = input.entry;
69
+ const command = input.command;
70
+ if ((entry === undefined) === (command === undefined))
71
+ throw new ProgramError('INVALID_CONFIG', 'Program requires exactly one of entry or command');
72
+ const text = (value, max, empty = false) => typeof value === 'string' && (empty || value.length > 0) && value.length <= max && !value.includes('\0');
73
+ const argv = (value) => Array.isArray(value) && value.length <= 256 && Array.from(value).every((item) => text(item, 8192, true)) && Buffer.byteLength(JSON.stringify(value)) <= 64 * 1024;
74
+ if (entry !== undefined && !text(entry, 4096))
75
+ throw new ProgramError('INVALID_CONFIG', 'Invalid program entrypoint');
76
+ if (command !== undefined && (!argv(command) || !command.length || !command[0]))
77
+ throw new ProgramError('INVALID_CONFIG', 'Command must be a nonempty executable argv array');
78
+ if (input.args !== undefined && (!argv(input.args) || command !== undefined))
79
+ throw new ProgramError('INVALID_CONFIG', 'args is only supported with an SDK entrypoint; command already contains argv');
80
+ if (input.cwd !== undefined && !text(input.cwd, 4096))
81
+ throw new ProgramError('INVALID_CONFIG', 'Invalid program working directory');
82
+ if (input.name !== undefined && !text(input.name, 256))
83
+ throw new ProgramError('INVALID_CONFIG', 'Invalid program name');
84
+ if (input.description !== undefined && !text(input.description, 4096, true))
85
+ throw new ProgramError('INVALID_CONFIG', 'Invalid program description');
86
+ if (input.logsPath !== undefined && (!text(input.logsPath, 4096) || controls.test(input.logsPath)))
87
+ throw new ProgramError('INVALID_CONFIG', 'Invalid log path');
88
+ if (input.env !== undefined && (!isRecord(input.env) || Object.keys(input.env).length > 256 || Object.entries(input.env).some(([key, value]) => !key || key.includes('=') || key.includes('\0') || !text(value, 8192, true)) || Buffer.byteLength(JSON.stringify(input.env)) > 64 * 1024))
89
+ throw new ProgramError('INVALID_CONFIG', 'Invalid explicit program environment');
90
+ const reserved = new Set(['capabilities.list', 'parent.send', 'status.set', 'resources.publish', 'resources.unpublish']);
91
+ if (input.allowedCapabilities !== undefined && (!Array.isArray(input.allowedCapabilities) || input.allowedCapabilities.length > 256 || input.allowedCapabilities.some((capability) => !validName(capability) || reserved.has(capability))))
92
+ throw new ProgramError('INVALID_CONFIG', 'Invalid capability allowlist');
93
+ if (input.urls !== undefined && (!Array.isArray(input.urls) || input.urls.length > RUNTIME_LIMITS.resources))
94
+ throw new ProgramError('INVALID_CONFIG', 'Invalid static resource list');
95
+ if (input.endpoints !== undefined && (!isRecord(input.endpoints) || Object.keys(input.endpoints).length > 16))
96
+ throw new ProgramError('INVALID_CONFIG', 'At most 16 named endpoints may be configured');
97
+ const endpoints = {};
98
+ for (const [id, endpoint] of Object.entries(input.endpoints ?? {})) {
99
+ if (!endpointName(id) || !isRecord(endpoint) || !exactKeys(endpoint, ['port']) || (endpoint.port !== 'dynamic' && (!Number.isSafeInteger(endpoint.port) || endpoint.port < 1 || endpoint.port > 65535)))
100
+ throw new ProgramError('INVALID_CONFIG', 'Endpoint requires a bounded name and dynamic or fixed port (1–65535)');
101
+ endpoints[id] = { port: endpoint.port };
102
+ }
103
+ const urls = [];
104
+ try {
105
+ for (const item of input.urls ?? []) {
106
+ const resource = normalizeUrlDefinition(item, endpoints);
107
+ if (urls.some((other) => other.id === resource.id))
108
+ throw new ProgramError('INVALID_CONFIG', 'Duplicate static resource id');
109
+ urls.push(resource);
110
+ }
111
+ }
112
+ catch (error) {
113
+ throw new ProgramError('INVALID_CONFIG', error instanceof Error ? error.message : 'Invalid static resource');
114
+ }
115
+ const cwd = resolve(input.cwd ?? process.cwd());
116
+ let supervision;
117
+ try {
118
+ supervision = normalizeSupervision(input.supervision);
119
+ }
120
+ catch (error) {
121
+ throw new ProgramError('INVALID_CONFIG', error instanceof Error ? error.message : 'Invalid supervision settings');
122
+ }
123
+ return {
124
+ ...input,
125
+ cwd,
126
+ ...(entry === undefined ? { command: [...command] } : { entry: resolve(cwd, entry), args: [...(input.args ?? [])] }),
127
+ env: { ...input.env },
128
+ allowedCapabilities: [...new Set(input.allowedCapabilities ?? [])],
129
+ urls,
130
+ ...(input.endpoints === undefined ? {} : { endpoints }),
131
+ ...(supervision === undefined ? {} : { supervision }),
132
+ ...(input.logsPath === undefined ? {} : { logsPath: resolve(cwd, input.logsPath) }),
133
+ };
134
+ }
135
+ export function definitionCommand(definition) {
136
+ return definition.command ? [...definition.command] : [process.execPath, definition.entry, ...(definition.args ?? [])];
137
+ }
138
+ //# sourceMappingURL=definitions.js.map