@stackbilt/aegis-core 0.6.4 → 0.7.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 (112) hide show
  1. package/cli/aegis.mjs +356 -0
  2. package/package.json +9 -1
  3. package/schema.sql +4 -0
  4. package/src/adapters/voice/cloudflare-agent.ts +0 -0
  5. package/src/auth.ts +19 -7
  6. package/src/bluesky.ts +0 -0
  7. package/src/claude-tools/content.ts +0 -0
  8. package/src/claude-tools/email.ts +0 -0
  9. package/src/claude.ts +133 -268
  10. package/src/codebeast.ts +0 -0
  11. package/src/composite.ts +49 -79
  12. package/src/content/column.ts +0 -0
  13. package/src/content/hero-image.ts +0 -0
  14. package/src/content/index.ts +0 -0
  15. package/src/content/journal.ts +0 -0
  16. package/src/content/roundtable.ts +0 -0
  17. package/src/contracts/agenda-item.contract.ts +0 -0
  18. package/src/contracts/cc-task.contract.ts +0 -0
  19. package/src/contracts/goal.contract.ts +0 -0
  20. package/src/contracts/memory-entry.contract.ts +0 -0
  21. package/src/core.ts +5 -0
  22. package/src/dashboard.ts +0 -0
  23. package/src/decision-docs.ts +0 -0
  24. package/src/dispatch.ts +0 -0
  25. package/src/durable-objects/chat-session-auth.ts +20 -0
  26. package/src/durable-objects/chat-session.ts +251 -0
  27. package/src/edge-env.ts +0 -0
  28. package/src/exports.ts +0 -0
  29. package/src/github-projects.ts +0 -0
  30. package/src/groq.ts +61 -113
  31. package/src/index.ts +4 -0
  32. package/src/kernel/argus-actions.ts +0 -0
  33. package/src/kernel/argus-correlation.ts +0 -0
  34. package/src/kernel/board.ts +0 -0
  35. package/src/kernel/classify-memory-topic.ts +0 -0
  36. package/src/kernel/disambiguation.ts +55 -0
  37. package/src/kernel/dispatch.ts +59 -44
  38. package/src/kernel/dynamic-tools.ts +30 -52
  39. package/src/kernel/executor-port.ts +0 -0
  40. package/src/kernel/executor-router.ts +0 -0
  41. package/src/kernel/executors/claude.ts +1 -0
  42. package/src/kernel/executors/direct.ts +14 -0
  43. package/src/kernel/executors/workers-ai.ts +5 -0
  44. package/src/kernel/grounding/fabrication-detector.ts +0 -0
  45. package/src/kernel/grounding/fanout.ts +0 -0
  46. package/src/kernel/grounding/semantic-sanhedrin.ts +0 -0
  47. package/src/kernel/grounding/verify.ts +0 -0
  48. package/src/kernel/grounding-layer.ts +0 -0
  49. package/src/kernel/insight-cache.ts +0 -0
  50. package/src/kernel/memory/episodic.ts +3 -1
  51. package/src/kernel/memory/insights.ts +0 -0
  52. package/src/kernel/memory-guardrails.ts +0 -0
  53. package/src/kernel/memory-service.ts +0 -0
  54. package/src/kernel/patterns.ts +0 -0
  55. package/src/kernel/port.ts +0 -0
  56. package/src/kernel/provider-factory.ts +0 -0
  57. package/src/kernel/resilience.ts +0 -0
  58. package/src/kernel/router.ts +33 -11
  59. package/src/kernel/scheduled/agent-dispatch.ts +0 -0
  60. package/src/kernel/scheduled/argus-analytics.ts +0 -0
  61. package/src/kernel/scheduled/argus-heartbeat.ts +0 -0
  62. package/src/kernel/scheduled/argus-notify.ts +0 -0
  63. package/src/kernel/scheduled/board-sync.ts +0 -0
  64. package/src/kernel/scheduled/ci-watcher.ts +0 -0
  65. package/src/kernel/scheduled/content-drip.ts +0 -0
  66. package/src/kernel/scheduled/content.ts +0 -0
  67. package/src/kernel/scheduled/conversation-facts.ts +9 -7
  68. package/src/kernel/scheduled/cost-report.ts +0 -0
  69. package/src/kernel/scheduled/dev-activity.ts +0 -0
  70. package/src/kernel/scheduled/digest.ts +30 -3
  71. package/src/kernel/scheduled/dreaming/agenda-triage.ts +0 -0
  72. package/src/kernel/scheduled/dreaming/facts.ts +0 -0
  73. package/src/kernel/scheduled/dreaming/index.ts +0 -0
  74. package/src/kernel/scheduled/dreaming/llm.ts +9 -5
  75. package/src/kernel/scheduled/dreaming/pattern-synthesis.ts +0 -0
  76. package/src/kernel/scheduled/dreaming/persona.ts +0 -0
  77. package/src/kernel/scheduled/dreaming/symbolic.ts +0 -0
  78. package/src/kernel/scheduled/dreaming/task-proposals.ts +0 -0
  79. package/src/kernel/scheduled/entropy.ts +0 -0
  80. package/src/kernel/scheduled/feed-watcher.ts +0 -0
  81. package/src/kernel/scheduled/inbox-processor.ts +0 -0
  82. package/src/kernel/scheduled/issue-proposer.ts +0 -0
  83. package/src/kernel/scheduled/issue-watcher.ts +0 -0
  84. package/src/kernel/scheduled/pr-automerge.ts +0 -0
  85. package/src/kernel/scheduled/product-health.ts +0 -0
  86. package/src/kernel/scheduled/self-improvement.ts +0 -0
  87. package/src/kernel/scheduled/social-engage.ts +12 -8
  88. package/src/kernel/scheduled/task-audit.ts +0 -0
  89. package/src/kernel/types.ts +6 -0
  90. package/src/landing.ts +0 -0
  91. package/src/lib/audit-chain/chain.ts +0 -0
  92. package/src/lib/audit-chain/types.ts +0 -0
  93. package/src/lib/observability/errors.ts +0 -0
  94. package/src/operator/config.ts +0 -0
  95. package/src/operator/persona.ts +0 -0
  96. package/src/operator/prompt-builder.ts +3 -0
  97. package/src/pulse.ts +0 -0
  98. package/src/routes/bluesky.ts +0 -0
  99. package/src/routes/chat-ws.ts +17 -0
  100. package/src/routes/codebeast.ts +0 -0
  101. package/src/routes/content.ts +0 -0
  102. package/src/routes/dynamic-tools.ts +0 -0
  103. package/src/routes/observability.ts +0 -0
  104. package/src/routes/operator-logs.ts +0 -0
  105. package/src/routes/pages.ts +5 -1
  106. package/src/schema-enums.ts +0 -0
  107. package/src/task-intelligence.ts +0 -0
  108. package/src/types.ts +6 -0
  109. package/src/ui.ts +594 -2
  110. package/src/version.ts +3 -3
  111. package/src/wiki/client.ts +0 -0
  112. package/src/wiki/types.ts +0 -0
package/cli/aegis.mjs ADDED
@@ -0,0 +1,356 @@
1
+ #!/usr/bin/env node
2
+ // AEGIS CLI: zero-dependency terminal chat over /chat/ws.
3
+ // Requires Node >= 21 for the built-in WebSocket client.
4
+
5
+ import { readFileSync } from 'node:fs';
6
+ import { dirname, join } from 'node:path';
7
+ import readline from 'node:readline';
8
+ import { stdin, stdout } from 'node:process';
9
+ import { fileURLToPath } from 'node:url';
10
+
11
+ const pkg = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf8'));
12
+ const args = process.argv.slice(2);
13
+ const has = (flag) => args.includes(flag);
14
+ const argVal = (flag) => {
15
+ const i = args.indexOf(flag);
16
+ return i >= 0 ? args[i + 1] : undefined;
17
+ };
18
+
19
+ const HELP = `AEGIS CLI
20
+
21
+ Usage:
22
+ aegis [--host <host>] [--token <token>] [--exec <executor>] [--conversation <uuid>] [--verbose] [--quick]
23
+
24
+ Options:
25
+ --host <host> AEGIS worker host or URL. Defaults to AEGIS_HOST or aegis.stackbilt.dev.
26
+ --token <token> Bearer token. Defaults to AEGIS_TOKEN.
27
+ --exec <executor> Force an executor for this session. Use auto to let the kernel route.
28
+ --conversation <uuid> Resume an existing conversation.
29
+ --verbose Show executor/classification/cost metadata after each response.
30
+ --quick Skip the startup executor picker.
31
+ --version Print version and exit.
32
+ --help Print this help and exit.
33
+
34
+ REPL commands:
35
+ /new /exec [name] /verbose /clear /help /quit
36
+ `;
37
+
38
+ if (has('--help') || has('-h')) {
39
+ console.log(HELP.trimEnd());
40
+ process.exit(0);
41
+ }
42
+ if (has('--version') || has('-v')) {
43
+ console.log(pkg.version);
44
+ process.exit(0);
45
+ }
46
+ if (typeof WebSocket === 'undefined') {
47
+ console.error('AEGIS CLI requires Node >= 21 for built-in WebSocket support.');
48
+ process.exit(1);
49
+ }
50
+
51
+ let conversationId = argVal('--conversation') || null;
52
+ let executor = normalizeExecutor(argVal('--exec'));
53
+ let verbose = has('--verbose');
54
+ const quick = has('--quick') || Boolean(argVal('--exec'));
55
+ const token = argVal('--token') || process.env.AEGIS_TOKEN;
56
+ const host = normalizeHost(argVal('--host') || process.env.AEGIS_HOST || 'aegis.stackbilt.dev');
57
+
58
+ if (!token) {
59
+ console.error('Missing AEGIS_TOKEN. Set AEGIS_TOKEN or pass --token <token>.');
60
+ process.exit(1);
61
+ }
62
+
63
+ const c = {
64
+ reset: '\x1b[0m',
65
+ dim: '\x1b[2m',
66
+ bold: '\x1b[1m',
67
+ cyan: '\x1b[36m',
68
+ green: '\x1b[32m',
69
+ yellow: '\x1b[33m',
70
+ red: '\x1b[31m',
71
+ };
72
+ const paint = (color, s) => `${color}${s}${c.reset}`;
73
+
74
+ const EXECUTORS = [
75
+ { value: null, label: 'auto', hint: 'kernel routes automatically' },
76
+ { value: 'workers_ai', label: 'workers_ai', hint: 'Cloudflare Workers AI' },
77
+ { value: 'gpt_oss', label: 'gpt_oss', hint: 'tool-capable standard path' },
78
+ { value: 'groq', label: 'groq', hint: 'fast simple responses' },
79
+ { value: 'claude', label: 'claude', hint: 'reliability-critical work' },
80
+ { value: 'claude_opus', label: 'claude_opus', hint: 'frontier tier' },
81
+ { value: 'composite', label: 'composite', hint: 'multi-model synthesis' },
82
+ ];
83
+
84
+ const EXECUTOR_VALUES = new Set(EXECUTORS.map((e) => e.value).filter(Boolean));
85
+
86
+ function normalizeExecutor(value) {
87
+ if (!value || value === 'auto') return null;
88
+ return value;
89
+ }
90
+
91
+ function normalizeHost(value) {
92
+ return value.replace(/^https?:\/\//, '').replace(/^wss?:\/\//, '').replace(/\/+$/, '');
93
+ }
94
+
95
+ function printBanner() {
96
+ console.log('');
97
+ console.log(paint(c.cyan, 'AEGIS'));
98
+ console.log(paint(c.dim, 'persistent agent terminal'));
99
+ console.log('');
100
+ }
101
+
102
+ function select(title, options, initial = 0) {
103
+ return new Promise((resolve) => {
104
+ let idx = initial;
105
+ readline.emitKeypressEvents(stdin);
106
+ const wasRaw = Boolean(stdin.isRaw);
107
+ if (stdin.isTTY) stdin.setRawMode(true);
108
+
109
+ const draw = (first = false) => {
110
+ if (!first) stdout.write(`\x1b[${options.length + 1}A`);
111
+ stdout.write(`${c.bold}?${c.reset} ${title}\x1b[K\n`);
112
+ options.forEach((o, i) => {
113
+ const on = i === idx;
114
+ const pointer = on ? paint(c.cyan, '>') : ' ';
115
+ const label = on ? paint(c.cyan, o.label) : o.label;
116
+ const hint = o.hint ? paint(c.dim, ` - ${o.hint}`) : '';
117
+ stdout.write(`${pointer} ${label}${hint}\x1b[K\n`);
118
+ });
119
+ };
120
+
121
+ const done = (value) => {
122
+ stdin.removeListener('keypress', onKey);
123
+ if (stdin.isTTY) stdin.setRawMode(wasRaw);
124
+ resolve(value);
125
+ };
126
+
127
+ const onKey = (_str, key) => {
128
+ if (!key) return;
129
+ if (key.name === 'up' || key.name === 'k') {
130
+ idx = (idx - 1 + options.length) % options.length;
131
+ draw();
132
+ } else if (key.name === 'down' || key.name === 'j') {
133
+ idx = (idx + 1) % options.length;
134
+ draw();
135
+ } else if (key.name === 'return') {
136
+ done(options[idx].value);
137
+ } else if (key.name === 'escape') {
138
+ done(options[initial].value);
139
+ } else if (key.ctrl && key.name === 'c') {
140
+ stdout.write('\n');
141
+ process.exit(0);
142
+ }
143
+ };
144
+
145
+ draw(true);
146
+ stdin.on('keypress', onKey);
147
+ });
148
+ }
149
+
150
+ function makeSpinner(label) {
151
+ const frames = ['-', '\\', '|', '/'];
152
+ let i = 0;
153
+ let timer = null;
154
+ return {
155
+ start() {
156
+ if (timer) return;
157
+ timer = setInterval(() => {
158
+ stdout.write(`\r${paint(c.cyan, frames[i = (i + 1) % frames.length])} ${paint(c.dim, label)}\x1b[K`);
159
+ }, 90);
160
+ },
161
+ stop() {
162
+ if (timer) clearInterval(timer);
163
+ timer = null;
164
+ stdout.write('\r\x1b[K');
165
+ },
166
+ };
167
+ }
168
+
169
+ const fmtCost = (n) => (typeof n === 'number' ? `$${n.toFixed(5)}` : `$${n ?? 0}`);
170
+ const think = makeSpinner('thinking');
171
+ let rl = null;
172
+ let conn = null;
173
+
174
+ function connect() {
175
+ const q = new URLSearchParams({ token });
176
+ if (conversationId) q.set('conversationId', conversationId);
177
+ const ws = new WebSocket(`wss://${host}/chat/ws?${q.toString()}`, 'aegis-chat');
178
+ let streaming = false;
179
+ let pending = false;
180
+ let firstDelta = false;
181
+
182
+ ws.addEventListener('open', () => {
183
+ think.stop();
184
+ console.log(`${paint(c.green, 'connected')} ${paint(c.dim, host)}`);
185
+ console.log(`${paint(c.dim, 'executor')} ${executor || 'auto'}`);
186
+ console.log(`${paint(c.dim, 'conversation')} ${conversationId ?? 'new on first message'}`);
187
+ console.log(paint(c.dim, '/new /exec [name] /verbose /clear /help /quit'));
188
+ startRepl();
189
+ });
190
+
191
+ ws.addEventListener('message', (ev) => {
192
+ let frame;
193
+ try {
194
+ frame = JSON.parse(typeof ev.data === 'string' ? ev.data : ev.data.toString());
195
+ } catch {
196
+ return;
197
+ }
198
+
199
+ switch (frame.type) {
200
+ case 'history':
201
+ if (Array.isArray(frame.messages) && frame.messages.length) {
202
+ console.log(paint(c.dim, `${frame.messages.length} prior messages loaded`));
203
+ }
204
+ break;
205
+ case 'start':
206
+ if (frame.conversationId) conversationId = frame.conversationId;
207
+ streaming = true;
208
+ firstDelta = false;
209
+ break;
210
+ case 'delta':
211
+ if (!frame.text) break;
212
+ if (!firstDelta) {
213
+ think.stop();
214
+ stdout.write(`${paint(c.cyan, 'aegis')} `);
215
+ firstDelta = true;
216
+ }
217
+ stdout.write(frame.text);
218
+ break;
219
+ case 'done':
220
+ if (!firstDelta) think.stop();
221
+ streaming = false;
222
+ pending = false;
223
+ stdout.write('\n');
224
+ if (verbose && frame.metadata) {
225
+ const md = frame.metadata;
226
+ console.log(paint(c.dim, `${md.executor} / ${md.classification} / ${fmtCost(md.cost)} / ${md.latencyMs ?? '?'}ms${md.grounded !== undefined ? ` / grounded=${md.grounded}` : ''}`));
227
+ if (md.unverifiedClaims?.length) console.log(paint(c.yellow, `${md.unverifiedClaims.length} unverified claim(s)`));
228
+ }
229
+ rl?.prompt();
230
+ break;
231
+ case 'error':
232
+ think.stop();
233
+ streaming = false;
234
+ pending = false;
235
+ console.log(`\n${paint(c.red, 'error:')} ${frame.error}`);
236
+ rl?.prompt();
237
+ break;
238
+ }
239
+ });
240
+
241
+ ws.addEventListener('error', () => {
242
+ think.stop();
243
+ console.log(paint(c.red, 'websocket error'));
244
+ });
245
+ ws.addEventListener('close', (ev) => {
246
+ think.stop();
247
+ console.log(paint(c.dim, `disconnected${ev.reason ? ` (${ev.reason})` : ''}`));
248
+ process.exit(ev.code === 1000 ? 0 : 1);
249
+ });
250
+
251
+ return {
252
+ send(text) {
253
+ if (pending || streaming) {
254
+ console.log(paint(c.dim, 'still responding'));
255
+ return;
256
+ }
257
+ pending = true;
258
+ think.start();
259
+ ws.send(JSON.stringify({
260
+ type: 'message',
261
+ text,
262
+ conversationId,
263
+ eventId: crypto.randomUUID(),
264
+ ...(executor ? { executor } : {}),
265
+ }));
266
+ },
267
+ close() {
268
+ ws.close(1000, 'bye');
269
+ },
270
+ };
271
+ }
272
+
273
+ function startRepl() {
274
+ rl = readline.createInterface({ input: stdin, output: stdout, prompt: `${paint(c.green, '>')} ` });
275
+ rl.prompt();
276
+
277
+ rl.on('line', async (line) => {
278
+ const text = line.trim();
279
+ if (!text) {
280
+ rl.prompt();
281
+ return;
282
+ }
283
+
284
+ if (text.startsWith('/')) {
285
+ const [cmd, arg] = text.slice(1).split(/\s+/);
286
+ switch (cmd) {
287
+ case 'new':
288
+ conversationId = null;
289
+ console.log(paint(c.dim, 'new conversation on next message'));
290
+ break;
291
+ case 'exec':
292
+ if (arg) {
293
+ const next = normalizeExecutor(arg);
294
+ if (next && !EXECUTOR_VALUES.has(next)) {
295
+ console.log(paint(c.dim, `unknown executor: ${arg}`));
296
+ } else {
297
+ executor = next;
298
+ console.log(paint(c.dim, `executor -> ${executor || 'auto'}`));
299
+ }
300
+ break;
301
+ }
302
+ if (!stdin.isTTY) {
303
+ console.log(paint(c.dim, `usage: /exec <${EXECUTORS.map((e) => e.label).join('|')}>`));
304
+ break;
305
+ }
306
+ rl.removeAllListeners('line');
307
+ rl.close();
308
+ executor = await select('executor', EXECUTORS, Math.max(0, EXECUTORS.findIndex((e) => e.value === executor)));
309
+ console.log(paint(c.dim, `executor -> ${executor || 'auto'}`));
310
+ startRepl();
311
+ return;
312
+ case 'verbose':
313
+ verbose = !verbose;
314
+ console.log(paint(c.dim, `verbose ${verbose ? 'on' : 'off'}`));
315
+ break;
316
+ case 'clear':
317
+ stdout.write('\x1b[2J\x1b[H');
318
+ break;
319
+ case 'help':
320
+ console.log(paint(c.dim, '/new /exec [name] /verbose /clear /help /quit'));
321
+ break;
322
+ case 'quit':
323
+ case 'q':
324
+ case 'exit':
325
+ conn.close();
326
+ return;
327
+ default:
328
+ console.log(paint(c.dim, `unknown command /${cmd}`));
329
+ }
330
+ rl.prompt();
331
+ return;
332
+ }
333
+
334
+ conn.send(text);
335
+ });
336
+
337
+ rl.on('SIGINT', () => conn.close());
338
+ }
339
+
340
+ async function main() {
341
+ if (executor && !EXECUTOR_VALUES.has(executor)) {
342
+ console.error(`Unknown executor: ${executor}`);
343
+ process.exit(1);
344
+ }
345
+ printBanner();
346
+ if (!executor && !quick && stdin.isTTY) {
347
+ executor = await select('Launch executor', EXECUTORS, 0);
348
+ }
349
+ think.start();
350
+ conn = connect();
351
+ }
352
+
353
+ main().catch((err) => {
354
+ console.error(`aegis: ${err.message}`);
355
+ process.exit(1);
356
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackbilt/aegis-core",
3
- "version": "0.6.4",
3
+ "version": "0.7.0",
4
4
  "description": "Persistent AI agent framework for Cloudflare Workers. Multi-tier memory, autonomous goals, dreaming cycles, MCP native.",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
@@ -14,6 +14,9 @@
14
14
  "type": "module",
15
15
  "main": "src/exports.ts",
16
16
  "types": "src/exports.ts",
17
+ "bin": {
18
+ "aegis": "./cli/aegis.mjs"
19
+ },
17
20
  "exports": {
18
21
  ".": "./src/exports.ts",
19
22
  "./core": "./src/core.ts",
@@ -24,6 +27,7 @@
24
27
  "./kernel/dispatch": "./src/kernel/dispatch.ts",
25
28
  "./kernel/router": "./src/kernel/router.ts",
26
29
  "./kernel/types": "./src/kernel/types.ts",
30
+ "./kernel/disambiguation": "./src/kernel/disambiguation.ts",
27
31
  "./kernel/memory": "./src/kernel/memory/index.ts",
28
32
  "./kernel/memory-adapter": "./src/kernel/memory-adapter.ts",
29
33
  "./kernel/resilience": "./src/kernel/resilience.ts",
@@ -50,6 +54,7 @@
50
54
  "./routes/health": "./src/routes/health.ts",
51
55
  "./routes/sessions": "./src/routes/sessions.ts",
52
56
  "./routes/messages": "./src/routes/messages.ts",
57
+ "./routes/chat-ws": "./src/routes/chat-ws.ts",
53
58
  "./routes/conversations": "./src/routes/conversations.ts",
54
59
  "./routes/feedback": "./src/routes/feedback.ts",
55
60
  "./routes/observability": "./src/routes/observability.ts",
@@ -57,6 +62,8 @@
57
62
  "./routes/pages": "./src/routes/pages.ts",
58
63
  "./routes/dynamic-tools": "./src/routes/dynamic-tools.ts",
59
64
  "./adapters/voice": "./src/adapters/voice/cloudflare-agent.ts",
65
+ "./durable-objects/chat-session": "./src/durable-objects/chat-session.ts",
66
+ "./durable-objects/chat-session-auth": "./src/durable-objects/chat-session-auth.ts",
60
67
  "./schema-enums": "./src/schema-enums.ts",
61
68
  "./contracts/goal": "./src/contracts/goal.contract.ts",
62
69
  "./contracts/agenda-item": "./src/contracts/agenda-item.contract.ts",
@@ -99,6 +106,7 @@
99
106
  "wrangler": "^4.76.0"
100
107
  },
101
108
  "files": [
109
+ "cli/**/*.mjs",
102
110
  "src/**/*.ts",
103
111
  "schema.sql"
104
112
  ],
package/schema.sql CHANGED
@@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS conversations (
7
7
  id TEXT PRIMARY KEY,
8
8
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
9
9
  updated_at TEXT NOT NULL DEFAULT (datetime('now')),
10
+ user_id TEXT NOT NULL DEFAULT 'operator',
10
11
  title TEXT
11
12
  );
12
13
 
@@ -67,6 +68,7 @@ CREATE TABLE IF NOT EXISTS episodic_memory (
67
68
  executor TEXT, -- which executor handled this
68
69
  complexity_tier TEXT, -- aegis#563: procedureKey complement (low|mid|high); NULL for non-dispatcher producers
69
70
  executor_config TEXT, -- aegis#563: config snapshot at emit time (evaluator-replay fidelity)
71
+ grounding_gap INTEGER NOT NULL DEFAULT 0, -- aegis#497/#34: unresolved grounding gap observed on this episode
70
72
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
71
73
  );
72
74
 
@@ -199,6 +201,7 @@ CREATE TABLE IF NOT EXISTS operator_log (
199
201
 
200
202
  CREATE INDEX IF NOT EXISTS idx_messages_conversation ON messages(conversation_id);
201
203
  CREATE INDEX IF NOT EXISTS idx_messages_created ON messages(created_at);
204
+ CREATE INDEX IF NOT EXISTS idx_conversations_user_updated ON conversations(user_id, updated_at);
202
205
  CREATE INDEX IF NOT EXISTS idx_memory_topic ON memory_entries(topic);
203
206
  CREATE INDEX IF NOT EXISTS idx_memory_dedup ON memory_entries(topic, fact_hash);
204
207
  CREATE INDEX IF NOT EXISTS idx_memory_expires ON memory_entries(expires_at);
@@ -208,6 +211,7 @@ CREATE INDEX IF NOT EXISTS idx_episodic_class ON episodic_memory(intent_class);
208
211
  CREATE INDEX IF NOT EXISTS idx_episodic_created ON episodic_memory(created_at);
209
212
  CREATE INDEX IF NOT EXISTS idx_episodic_thread ON episodic_memory(thread_id);
210
213
  CREATE INDEX IF NOT EXISTS idx_episodic_class_complexity ON episodic_memory(intent_class, complexity_tier);
214
+ CREATE INDEX IF NOT EXISTS idx_episodic_grounding_gap ON episodic_memory(grounding_gap, created_at);
211
215
  CREATE INDEX IF NOT EXISTS idx_procedural_pattern ON procedural_memory(task_pattern);
212
216
  CREATE INDEX IF NOT EXISTS idx_procedural_status ON procedural_memory(status);
213
217
  CREATE INDEX IF NOT EXISTS idx_heartbeat_created ON heartbeat_results(created_at);
File without changes
package/src/auth.ts CHANGED
@@ -1,11 +1,19 @@
1
1
  import type { Context, Next } from 'hono';
2
2
  import type { Env } from './types.js';
3
3
 
4
- export async function bearerAuth(c: Context<{ Bindings: Env }>, next: Next): Promise<Response | void> {
5
- // Public routes — no auth required
6
- if (c.req.path === '/health' || c.req.path === '/pulse' || (c.req.path === '/' && c.req.method === 'GET') || c.req.path.startsWith('/tech') || c.req.path === '/api/feedback' || c.req.path === '/observe' || c.req.path.startsWith('/api/overworld/public')) {
7
- return next();
8
- }
4
+ export async function bearerAuth(c: Context<{ Bindings: Env }>, next: Next): Promise<Response | void> {
5
+ // Public routes — no auth required
6
+ if (
7
+ c.req.path === '/health' ||
8
+ c.req.path === '/pulse' ||
9
+ ((c.req.path === '/' || c.req.path === '/chat' || c.req.path === '/manifest.json' || c.req.path === '/sw.js') && c.req.method === 'GET') ||
10
+ c.req.path.startsWith('/tech') ||
11
+ c.req.path === '/api/feedback' ||
12
+ c.req.path === '/observe' ||
13
+ c.req.path.startsWith('/api/overworld/public')
14
+ ) {
15
+ return next();
16
+ }
9
17
 
10
18
  // Webhook routes — auth handled by per-route HMAC verification
11
19
  if (c.req.path.startsWith('/webhooks/') || c.req.path === '/api/webhook') {
@@ -31,8 +39,12 @@ export async function bearerAuth(c: Context<{ Bindings: Env }>, next: Next): Pro
31
39
  const token = extractBearer(authHeader) ?? cookieToken ?? queryToken;
32
40
 
33
41
  if (!token || token !== c.env.AEGIS_TOKEN) {
34
- // UI pages — show login page
35
- if ((c.req.path === '/chat' || c.req.path === '/overworld' || c.req.path === '/console') && c.req.method === 'GET') {
42
+ // UI pages — show the login form for top-level HTML navigations (a GET
43
+ // whose Accept includes text/html) so the operator can enter a token.
44
+ // Path-agnostic on purpose: any page route — core or downstream-variant
45
+ // (e.g. the daemon's /lite) — gets the form without core enumerating it.
46
+ // API/fetch requests (Accept */* or application/json) get JSON 401.
47
+ if (c.req.method === 'GET' && (c.req.header('Accept') ?? '').includes('text/html')) {
36
48
  return c.html(loginPage(), 401);
37
49
  }
38
50
  return c.json({ error: 'Unauthorized' }, 401);
package/src/bluesky.ts CHANGED
File without changes
File without changes
File without changes