@monster-orange/den 0.4.14 → 0.4.16

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 (57) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/README.md +7 -7
  3. package/docs/distributions.md +226 -19
  4. package/package.json +1 -1
  5. package/src/shared/actor-token.ts +12 -0
  6. package/src/shared/agents/conversations.ts +155 -8
  7. package/src/shared/agents/den-claude.ts +25 -3
  8. package/src/shared/agents/records.ts +37 -0
  9. package/src/shared/agents/runtime.ts +11 -1
  10. package/src/shared/claim-code.ts +163 -0
  11. package/src/shared/cli-command.ts +31 -0
  12. package/src/shared/den-config.ts +12 -0
  13. package/src/shared/environment-manager/workspaces.ts +20 -0
  14. package/src/shared/github-app.ts +7 -0
  15. package/src/shared/web-session.ts +64 -5
  16. package/src/ui/cli/agent-ops.ts +372 -23
  17. package/src/ui/cli/agents-command.ts +71 -4
  18. package/src/ui/cli/doctor-command.ts +29 -3
  19. package/src/ui/cli/doctor-onboard.ts +26 -0
  20. package/src/ui/cli/flag-parser.ts +9 -1
  21. package/src/ui/cli/index.ts +29 -3
  22. package/src/ui/cli/onboard-command.ts +180 -0
  23. package/src/ui/cli/onboard-reads.ts +613 -0
  24. package/src/ui/cli/repo-command.ts +156 -10
  25. package/src/ui/cli/web-command.ts +92 -1
  26. package/src/ui/mcp/api.ts +14 -2
  27. package/src/ui/mcp/server.ts +12 -2
  28. package/src/ui/mcp/tools.ts +368 -1
  29. package/src/ui/server/agent-routes.ts +91 -7
  30. package/src/ui/server/approval-routes.ts +390 -0
  31. package/src/ui/server/approvals.ts +416 -0
  32. package/src/ui/server/github-routes.ts +13 -5
  33. package/src/ui/server/held-actions.ts +203 -0
  34. package/src/ui/server/http-helpers.ts +35 -0
  35. package/src/ui/server/index.ts +308 -21
  36. package/src/ui/server/lifecycle-exec.ts +70 -0
  37. package/src/ui/server/onboard-routes.ts +132 -0
  38. package/src/ui/server/pair-routes.ts +7 -4
  39. package/src/ui/server/public/agents-page.js +378 -30
  40. package/src/ui/server/public/agents.html +1 -0
  41. package/src/ui/server/public/error-page.js +97 -18
  42. package/src/ui/server/public/error.html +18 -0
  43. package/src/ui/server/public/header.js +1 -1
  44. package/src/ui/server/public/i18n/es.js +65 -5
  45. package/src/ui/server/public/i18n/ja.js +67 -5
  46. package/src/ui/server/public/index.html +1 -1
  47. package/src/ui/server/public/local-dev.html +5 -4
  48. package/src/ui/server/public/persona-ui.css +32 -0
  49. package/src/ui/server/public/release.html +0 -1
  50. package/src/ui/server/public/settings-registry.js +3 -1
  51. package/src/ui/server/public/settings.html +9 -1
  52. package/src/ui/server/public/shell.js +348 -5
  53. package/src/ui/server/request-guard.ts +2 -0
  54. package/src/ui/server/route-classes.ts +34 -1
  55. package/src/ui/server/session-routes.ts +14 -3
  56. package/src/ui/server/workspace-routes.ts +21 -10
  57. package/themes/den/den-theme.json +6 -6
@@ -0,0 +1,132 @@
1
+ /**
2
+ * ON-3's read routes (GET only; reads in route-classes.ts):
3
+ *
4
+ * /api/onboard/status what's set up and the one next step
5
+ * (onboard-reads.ts onboardStatus)
6
+ * /api/onboard/repos ?path=<folder>[&max=<n>]: the git repos in a
7
+ * folder, how each runs, suggested workspaces
8
+ * /api/onboard/manifest ?path=<repo>[&name&run&down&health]: the side-car
9
+ * manifest `repo add` would write, validated, and
10
+ * nothing written
11
+ *
12
+ * The MCP tools onboard_status, repos_detect and manifest_draft read these,
13
+ * and a page can show them as they are. A path outside the person's home
14
+ * folder, or in Den's state folder, is a 400 with the reason.
15
+ */
16
+ import * as http from "http";
17
+ import { AUDIT_HEADERS } from "../../shared/agent-actor.js";
18
+ import { getStateDir } from "../../shared/paths.js";
19
+ import { readWebPort } from "../../shared/edge/config.js";
20
+ import { DEFAULT_PORT } from "../../shared/constants.js";
21
+ import { sendJson } from "./http-helpers.js";
22
+ import {
23
+ checkOnboardPath,
24
+ manifestDraft,
25
+ onboardStatus,
26
+ processPathRules,
27
+ reposDetect,
28
+ type OnboardStatus,
29
+ type PathRules,
30
+ type RegisteredRepo,
31
+ } from "../cli/onboard-reads.js";
32
+ import { defaultStatusDeps, registeredRepos } from "../cli/onboard-command.js";
33
+ import type { ManifestValidator } from "../cli/repo-command.js";
34
+ import { runnableCli } from "../cli/doctor-onboard.js";
35
+
36
+ export interface OnboardRouteDeps {
37
+ rules: () => PathRules;
38
+ validate: ManifestValidator;
39
+ registered: () => RegisteredRepo[];
40
+ bin: () => string;
41
+ status: (o: { viaMcp: boolean }) => Promise<OnboardStatus>;
42
+ }
43
+
44
+ /** The web server's own deps; `validate` comes from its entry (index.ts). */
45
+ export function defaultOnboardRouteDeps(
46
+ validate: ManifestValidator,
47
+ version: string,
48
+ ): OnboardRouteDeps {
49
+ return {
50
+ rules: () => processPathRules(getStateDir()),
51
+ validate,
52
+ registered: registeredRepos,
53
+ bin: runnableCli,
54
+ status: async ({ viaMcp }) => {
55
+ let port: number;
56
+ try {
57
+ port = readWebPort();
58
+ } catch {
59
+ port = DEFAULT_PORT;
60
+ }
61
+ // This server is the web server asked about: it is answering.
62
+ return onboardStatus(
63
+ await defaultStatusDeps({
64
+ webUrl: `http://localhost:${port}`,
65
+ probeWeb: async () => ({ kind: "up", version }),
66
+ viaMcp,
67
+ }),
68
+ );
69
+ },
70
+ };
71
+ }
72
+
73
+ const param = (url: URL, k: string): string | undefined =>
74
+ url.searchParams.get(k) ?? undefined;
75
+
76
+ /** Handles the routes above; false when `pathname` is not one of them. */
77
+ export async function handleOnboardRoutes(
78
+ req: http.IncomingMessage,
79
+ res: http.ServerResponse,
80
+ pathname: string,
81
+ url: URL,
82
+ deps: OnboardRouteDeps,
83
+ ): Promise<boolean> {
84
+ if (
85
+ pathname !== "/api/onboard/status" &&
86
+ pathname !== "/api/onboard/repos" &&
87
+ pathname !== "/api/onboard/manifest"
88
+ )
89
+ return false;
90
+ if (req.method !== "GET" && req.method !== "HEAD") {
91
+ res.writeHead(405, { Allow: "GET" });
92
+ res.end("read-only");
93
+ return true;
94
+ }
95
+ try {
96
+ if (pathname === "/api/onboard/status") {
97
+ const viaMcp = req.headers[AUDIT_HEADERS.actor] === "agent";
98
+ sendJson(res, await deps.status({ viaMcp }));
99
+ return true;
100
+ }
101
+ const rules = deps.rules();
102
+ const check = checkOnboardPath(param(url, "path"), rules);
103
+ if (!check.ok) {
104
+ sendJson(res, { ok: false, error: check.error }, 400);
105
+ return true;
106
+ }
107
+ if (pathname === "/api/onboard/repos") {
108
+ const max = Number(param(url, "max"));
109
+ sendJson(
110
+ res,
111
+ reposDetect(check.dir, rules, {
112
+ registered: deps.registered,
113
+ bin: deps.bin(),
114
+ ...(Number.isInteger(max) && max > 0 ? { maxRepos: max } : {}),
115
+ }),
116
+ );
117
+ return true;
118
+ }
119
+ sendJson(
120
+ res,
121
+ manifestDraft(check.dir, rules, deps.validate, {
122
+ name: param(url, "name"),
123
+ run: param(url, "run"),
124
+ down: param(url, "down"),
125
+ health: param(url, "health"),
126
+ }),
127
+ );
128
+ } catch (e) {
129
+ sendJson(res, { ok: false, error: (e as Error).message }, 500);
130
+ }
131
+ return true;
132
+ }
@@ -22,8 +22,8 @@ export interface PairRouteDeps {
22
22
  pairs: PairRequests;
23
23
  sendJson: (res: http.ServerResponse, body: unknown, status?: number) => void;
24
24
  readBody: (req: http.IncomingMessage) => Promise<string>;
25
- /** A new browser session for this request (via "code"); its Set-Cookie line. */
26
- signIn: (req: http.IncomingMessage) => string;
25
+ /** A new browser session for this request (via "code"): its Set-Cookie line and approval key. */
26
+ signIn: (req: http.IncomingMessage) => { cookie: string; approveKey: string };
27
27
  /** The client's address for a new request's record, when Den knows it. */
28
28
  client: (req: http.IncomingMessage) => string | undefined;
29
29
  /** The commands that approve `code`: on the server, and by ssh from the browser's machine. */
@@ -132,8 +132,11 @@ export async function handlePairRoutes(
132
132
  deps.sendJson(res, { ok: false, state: "gone" }, 404);
133
133
  return true;
134
134
  }
135
- res.setHeader("Set-Cookie", deps.signIn(req));
136
- deps.sendJson(res, { ok: true, state: "ok" });
135
+ const s = deps.signIn(req);
136
+ res.setHeader("Set-Cookie", s.cookie);
137
+ res.setHeader("Cache-Control", "no-store");
138
+ // The approval key goes to this answer only (web-session.ts).
139
+ deps.sendJson(res, { ok: true, state: "ok", approveKey: s.approveKey });
137
140
  return true;
138
141
  }
139
142
  deps.sendJson(res, {