@monster-orange/den 0.4.15 → 0.4.17
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/CHANGELOG.md +125 -0
- package/README.md +7 -7
- package/docs/distributions.md +137 -11
- package/package.json +1 -1
- package/src/shared/agents/conversations.ts +122 -4
- package/src/shared/agents/den-claude.ts +13 -1
- package/src/shared/agents/records.ts +19 -0
- package/src/shared/agents/runtime.ts +5 -0
- package/src/shared/github-app.ts +7 -0
- package/src/ui/cli/agent-ops.ts +304 -1
- package/src/ui/cli/agents-command.ts +71 -7
- package/src/ui/server/agent-routes.ts +92 -2
- package/src/ui/server/check-pool.ts +72 -0
- package/src/ui/server/github-routes.ts +1 -1
- package/src/ui/server/index.ts +127 -15
- package/src/ui/server/public/agents-page.js +358 -38
- package/src/ui/server/public/agents.html +10 -0
- package/src/ui/server/public/environments.html +223 -140
- package/src/ui/server/public/error-page.js +70 -15
- package/src/ui/server/public/error.html +18 -0
- package/src/ui/server/public/graph.css +18 -0
- package/src/ui/server/public/graph.js +23 -6
- package/src/ui/server/public/i18n/es.js +47 -5
- package/src/ui/server/public/i18n/ja.js +47 -5
- package/src/ui/server/public/index.html +6 -0
- package/src/ui/server/public/local-dev.html +188 -25
- package/src/ui/server/public/panel.js +1 -1
- package/src/ui/server/public/persona-ui.css +11 -0
- package/src/ui/server/public/release.html +19 -1
- package/src/ui/server/public/shell.js +187 -12
- package/src/ui/server/public/topbar.js +34 -1
- package/src/ui/server/public/view-scope.js +61 -0
- package/src/ui/server/public/workspace-picker.js +2 -0
- package/src/ui/server/route-classes.ts +8 -0
- package/src/ui/server/run-history.ts +181 -0
- package/src/ui/server/session-routes.ts +97 -17
- package/src/ui/server/ui-assets.ts +2 -0
|
@@ -174,6 +174,8 @@ export interface ListedSession {
|
|
|
174
174
|
/** The host has it (running, or ended with its scrollback): a pane can attach. */
|
|
175
175
|
attachable: boolean;
|
|
176
176
|
resumable?: boolean;
|
|
177
|
+
/** AG-18: Change persona… applies (its runtime can resume). */
|
|
178
|
+
personaChange?: boolean;
|
|
177
179
|
/** Why only Start fresh applies (AG-14.2): "<runtime> can't resume a conversation". */
|
|
178
180
|
noResume?: string;
|
|
179
181
|
/** When it was stopped, seen to end, or found interrupted (AG-14.1). */
|
|
@@ -243,6 +245,7 @@ export function listedSessions(
|
|
|
243
245
|
...(r.startedAt ? { startedAt: r.startedAt } : {}),
|
|
244
246
|
attachable: Boolean(s),
|
|
245
247
|
resumable: r.resumable,
|
|
248
|
+
...(r.personaChange ? { personaChange: true } : {}),
|
|
246
249
|
...(r.noResume ? { noResume: r.noResume } : {}),
|
|
247
250
|
...(r.stoppedAt ? { stoppedAt: r.stoppedAt } : {}),
|
|
248
251
|
...(r.endedAt ? { endedAt: r.endedAt } : {}),
|
|
@@ -359,18 +362,101 @@ const TEXT = (code: number) =>
|
|
|
359
362
|
: "Service Unavailable";
|
|
360
363
|
|
|
361
364
|
/**
|
|
362
|
-
*
|
|
363
|
-
*
|
|
365
|
+
* Whether a session is one the io route serves: this distribution's, in a
|
|
366
|
+
* workspace workspaces.yml names, active or not (0.4.17: an agent you can
|
|
367
|
+
* start and see, you can open). The person's and the agent's checks are
|
|
368
|
+
* the request guard's, before this.
|
|
364
369
|
*/
|
|
365
|
-
|
|
370
|
+
function servedSession(
|
|
371
|
+
s: SessionInfo,
|
|
372
|
+
target: string,
|
|
373
|
+
d: Resolved,
|
|
374
|
+
active: ReadonlySet<string>,
|
|
375
|
+
): boolean {
|
|
376
|
+
const p = parseSessionName(s.name, d.dist());
|
|
377
|
+
return (
|
|
378
|
+
p !== null &&
|
|
379
|
+
(active.has(p.workspace) || d.workspaceExists(p.workspace)) &&
|
|
380
|
+
(s.ref.id === target || s.name === target)
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Why the io route would refuse `target`, or null when it would open it:
|
|
386
|
+
* what a browser can't read from a refused upgrade (it sees only a close),
|
|
387
|
+
* so the page asks this with a plain GET (0.4.17).
|
|
388
|
+
*/
|
|
389
|
+
async function ioRefusal(
|
|
390
|
+
target: string,
|
|
391
|
+
d: Resolved,
|
|
392
|
+
): Promise<{ status: number; error: string; code: string } | null> {
|
|
393
|
+
let c: HostClient | null;
|
|
394
|
+
try {
|
|
395
|
+
c = await d.connectExisting();
|
|
396
|
+
} catch (e) {
|
|
397
|
+
return {
|
|
398
|
+
status: 503,
|
|
399
|
+
error: `the session host: ${(e as Error).message}`,
|
|
400
|
+
code: "session_host",
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
if (!c)
|
|
404
|
+
return {
|
|
405
|
+
status: 404,
|
|
406
|
+
error: `no session "${target}" (no session host is running)`,
|
|
407
|
+
code: "not_found",
|
|
408
|
+
};
|
|
409
|
+
try {
|
|
410
|
+
const active = new Set(d.activeWorkspaces());
|
|
411
|
+
const found = (await c.list()).some((s) =>
|
|
412
|
+
servedSession(s, target, d, active),
|
|
413
|
+
);
|
|
414
|
+
return found
|
|
415
|
+
? null
|
|
416
|
+
: {
|
|
417
|
+
status: 404,
|
|
418
|
+
error: `no session "${target}" here`,
|
|
419
|
+
code: "not_found",
|
|
420
|
+
};
|
|
421
|
+
} catch (e) {
|
|
422
|
+
return {
|
|
423
|
+
status: 503,
|
|
424
|
+
error: `the session host: ${(e as Error).message}`,
|
|
425
|
+
code: "session_host",
|
|
426
|
+
};
|
|
427
|
+
} finally {
|
|
428
|
+
c.close();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* A plain HTTP request to an io route: it is a WebSocket. For a GET, the
|
|
434
|
+
* refusal its upgrade would get (404, 503), else 426; 404 for anything
|
|
435
|
+
* else under /api/sessions/.
|
|
436
|
+
*/
|
|
437
|
+
export async function sendSessionHttp(
|
|
366
438
|
req: http.IncomingMessage,
|
|
367
439
|
res: http.ServerResponse,
|
|
368
440
|
pathname: string,
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
441
|
+
deps: SessionRouteDeps = {},
|
|
442
|
+
): Promise<void> {
|
|
443
|
+
const m = IO_PATH.exec(pathname);
|
|
444
|
+
if (m && (req.method === "GET" || req.method === "HEAD")) {
|
|
445
|
+
let target = m[1];
|
|
446
|
+
try {
|
|
447
|
+
target = decodeURIComponent(target);
|
|
448
|
+
} catch {
|
|
449
|
+
/* as given */
|
|
450
|
+
}
|
|
451
|
+
const why = await ioRefusal(target, resolve(deps));
|
|
452
|
+
if (why) {
|
|
453
|
+
sendJson(
|
|
454
|
+
res,
|
|
455
|
+
{ ok: false, error: why.error, code: why.code },
|
|
456
|
+
why.status,
|
|
457
|
+
);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
374
460
|
res.setHeader("Upgrade", "websocket");
|
|
375
461
|
res.setHeader("Connection", "Upgrade");
|
|
376
462
|
sendJson(
|
|
@@ -441,16 +527,10 @@ export async function handleSessionUpgrade(
|
|
|
441
527
|
const client = c;
|
|
442
528
|
let info: SessionInfo | undefined;
|
|
443
529
|
try {
|
|
444
|
-
const dist = d.dist();
|
|
445
530
|
const active = new Set(d.activeWorkspaces());
|
|
446
|
-
info = (await client.list()).find((s) =>
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
p !== null &&
|
|
450
|
-
active.has(p.workspace) &&
|
|
451
|
-
(s.ref.id === target || s.name === target)
|
|
452
|
-
);
|
|
453
|
-
});
|
|
531
|
+
info = (await client.list()).find((s) =>
|
|
532
|
+
servedSession(s, target, d, active),
|
|
533
|
+
);
|
|
454
534
|
} catch (e) {
|
|
455
535
|
client.close();
|
|
456
536
|
return refuse(
|
|
@@ -46,6 +46,8 @@ export const UI_MODULES: readonly string[] = [
|
|
|
46
46
|
// The UI's catalogs other than English (R19; en is in shell.js).
|
|
47
47
|
"/i18n/ja.js",
|
|
48
48
|
"/i18n/es.js",
|
|
49
|
+
// 0.4.17: one org and workspace rule for Environments and Releases.
|
|
50
|
+
"/view-scope.js",
|
|
49
51
|
];
|
|
50
52
|
|
|
51
53
|
/** URL path → file inside node_modules. */
|