@openparachute/agent 0.2.2 → 0.2.3-rc.3

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 (58) hide show
  1. package/.parachute/module.json +3 -3
  2. package/package.json +4 -1
  3. package/src/transports/vault.ts +40 -22
  4. package/web/ui/dist/assets/index-5KEwEhfi.js +60 -0
  5. package/web/ui/dist/index.html +1 -1
  6. package/src/_parked/interactive-spawn.test.ts +0 -324
  7. package/src/_parked/interactive-spawn.ts +0 -701
  8. package/src/agent-defs.test.ts +0 -1504
  9. package/src/agent-mcp-config.test.ts +0 -115
  10. package/src/agents.test.ts +0 -360
  11. package/src/auth.test.ts +0 -46
  12. package/src/backends/attached-queue.test.ts +0 -376
  13. package/src/backends/programmatic.test.ts +0 -1715
  14. package/src/backends/registry.test.ts +0 -1494
  15. package/src/backends/stream-json.test.ts +0 -570
  16. package/src/channel-backend-wiring.test.ts +0 -237
  17. package/src/credentials.test.ts +0 -274
  18. package/src/cron.test.ts +0 -342
  19. package/src/daemon-agent-def-api.test.ts +0 -166
  20. package/src/daemon-agent-defs-api.test.ts +0 -953
  21. package/src/daemon-agent-env-api.test.ts +0 -338
  22. package/src/daemon-attached-queue-store.test.ts +0 -65
  23. package/src/daemon-config-api.test.ts +0 -962
  24. package/src/daemon-jobs-api.test.ts +0 -271
  25. package/src/daemon-vault-chat.test.ts +0 -250
  26. package/src/daemon.test.ts +0 -746
  27. package/src/def-vaults.test.ts +0 -136
  28. package/src/delivery-state.test.ts +0 -110
  29. package/src/effective-env.test.ts +0 -114
  30. package/src/grants.test.ts +0 -638
  31. package/src/hub-jwt.test.ts +0 -161
  32. package/src/jobs.test.ts +0 -245
  33. package/src/mcp-http.test.ts +0 -265
  34. package/src/mint-token.test.ts +0 -152
  35. package/src/module-manifest.test.ts +0 -158
  36. package/src/programmatic-wiring.test.ts +0 -838
  37. package/src/registry.test.ts +0 -227
  38. package/src/resolve-port.test.ts +0 -64
  39. package/src/routing.test.ts +0 -184
  40. package/src/runner.test.ts +0 -506
  41. package/src/sandbox/config.test.ts +0 -150
  42. package/src/sandbox/egress.test.ts +0 -113
  43. package/src/sandbox/live-seatbelt.test.ts +0 -277
  44. package/src/sandbox/mounts.test.ts +0 -154
  45. package/src/sandbox/sandbox.test.ts +0 -168
  46. package/src/services-manifest.test.ts +0 -106
  47. package/src/spa-serve.test.ts +0 -116
  48. package/src/spawn-agent-cli.test.ts +0 -172
  49. package/src/spawn-agent.test.ts +0 -1218
  50. package/src/spawn-deps.test.ts +0 -54
  51. package/src/terminal-assets.test.ts +0 -50
  52. package/src/terminal.test.ts +0 -530
  53. package/src/transports/http-ui.test.ts +0 -455
  54. package/src/transports/telegram.test.ts +0 -174
  55. package/src/transports/vault.test.ts +0 -2011
  56. package/src/ui-kit.test.ts +0 -178
  57. package/web/ui/dist/assets/index-VFETBk0a.js +0 -60
  58. package/web/ui/tsconfig.json +0 -21
@@ -1,178 +0,0 @@
1
- /**
2
- * Unit tests for the shared UI kit (src/ui-kit.ts) — the foundation every
3
- * channel page adopts. Guards the shell contract (active-tab marking, controls
4
- * slot, nav set) + the token/CSS invariants the pages depend on.
5
- */
6
- import { describe, test, expect } from "bun:test";
7
- import { THEME_CSS, SHELL_JS, appShell, NAV_VIEWS, BRAND } from "./ui-kit.ts";
8
-
9
- describe("appShell", () => {
10
- test("renders the brand + all nav tabs, marking only the active one", () => {
11
- const h = appShell({ active: "agents" });
12
- expect(h).toContain("app-header");
13
- expect(h).toContain('class="brand-mark"');
14
- for (const v of NAV_VIEWS) expect(h).toContain(`data-view="${v.view}"`);
15
- // active tab gets class="active"; others don't.
16
- expect(h).toContain('data-view="agents" href="#" class="active"');
17
- expect(h).toContain('data-view="chat" href="#"');
18
- expect(h).not.toContain('data-view="chat" href="#" class="active"');
19
- });
20
-
21
- test("marks Home active when it is the current view", () => {
22
- const h = appShell({ active: "home" });
23
- expect(h).toContain('data-view="home" href="#" class="active"');
24
- expect(h).toContain('data-view="chat" href="#"');
25
- expect(h).not.toContain('data-view="chat" href="#" class="active"');
26
- });
27
-
28
- test("status defaults, and a custom status + tag suffix render", () => {
29
- expect(appShell({ active: "chat" })).toContain('id="status"');
30
- const h = appShell({ active: "chat", status: "● ready", tag: "chat" });
31
- expect(h).toContain("● ready");
32
- expect(h).toContain("· chat");
33
- });
34
-
35
- test("controls slot is injected before the status when provided, omitted otherwise", () => {
36
- const withCtl = appShell({ active: "terminal", controls: "<button id='reconnect'>Reconnect</button>" });
37
- expect(withCtl).toContain("app-controls");
38
- expect(withCtl).toContain("id='reconnect'");
39
- expect(appShell({ active: "terminal" })).not.toContain("app-controls");
40
- });
41
-
42
- test("nav covers exactly home/chat/agents/schedules/terminal/config, Home first", () => {
43
- expect(NAV_VIEWS.map((v) => v.view)).toEqual([
44
- "home",
45
- "chat",
46
- "agents",
47
- "schedules",
48
- "terminal",
49
- "config",
50
- ]);
51
- });
52
- });
53
-
54
- describe("THEME_CSS", () => {
55
- test("declares the brand tokens incl. the warm-light bg, accent, warn, and dark term pane", () => {
56
- expect(THEME_CSS).toContain(":root");
57
- expect(THEME_CSS).toContain(`--bg: ${BRAND.bg}`); // #faf8f4, the warm light brand
58
- expect(THEME_CSS).toContain(`--accent: ${BRAND.accent}`);
59
- expect(THEME_CSS).toContain(`--warn: ${BRAND.warn}`);
60
- expect(THEME_CSS).toContain(`--term-bg: ${BRAND.termBg}`); // #000 — the only intended black
61
- });
62
- test("ships the shared component layer (shell + buttons + banners + pills)", () => {
63
- for (const sel of [".app-nav", ".app-nav a.active", ".btn-primary", ".banner-warn", ".pill.warn"]) {
64
- expect(THEME_CSS).toContain(sel);
65
- }
66
- });
67
- test("carries NO leftover dark-console tokens (the pages unified on the brand)", () => {
68
- expect(THEME_CSS).not.toContain("#0f1115");
69
- expect(THEME_CSS).not.toContain("--panel");
70
- });
71
- });
72
-
73
- describe("SHELL_JS", () => {
74
- test("provides MOUNT derivation, nav wiring, token fetch, and helpers", () => {
75
- for (const sym of ["var MOUNT", "function wireShell", "function escapeHtml", "function setStatus", "function fetchToken", "function authedFetch", "function setTerminalNavVisible"]) {
76
- expect(SHELL_JS).toContain(sym);
77
- }
78
- // It hits the hub agent-token endpoint with the operator cookie.
79
- expect(SHELL_JS).toContain("/admin/agent-token");
80
- expect(SHELL_JS).toContain('credentials: "include"');
81
- });
82
-
83
- // Terminal-nav cleanup (Parachute Agent Phase 1): wireShell hides the standalone
84
- // Terminal nav entry by default (programmatic backend has no terminal); pages
85
- // reveal it via setTerminalNavVisible when an interactive agent exists. The
86
- // Terminal page itself (active === "terminal") shows it.
87
- test("wireShell gates the Terminal nav link via setTerminalNavVisible", () => {
88
- expect(SHELL_JS).toContain('a[data-view="terminal"]');
89
- // wireShell defaults the terminal entry to its own-page-only visibility.
90
- expect(SHELL_JS).toContain('setTerminalNavVisible(active === "terminal")');
91
- });
92
- test("is safe to interpolate — no naked backtick that could break a host literal", () => {
93
- expect(SHELL_JS.includes("`")).toBe(false);
94
- });
95
- test("exports a renderMarkdown helper (reused by the chat transcript)", () => {
96
- expect(SHELL_JS).toContain("function renderMarkdown");
97
- });
98
- });
99
-
100
- // renderMarkdown lives inside SHELL_JS (vanilla JS, no DOM). Evaluate SHELL_JS in
101
- // a fresh function scope and hand back its renderMarkdown so we can exercise it
102
- // directly — the same code the chat page runs in the browser.
103
- function loadRenderMarkdown(): (text: string) => string {
104
- // SHELL_JS defines `var MOUNT = window.location...` at the top; stub a minimal
105
- // window so that line doesn't throw when evaluated outside a browser.
106
- const factory = new Function(
107
- "window",
108
- SHELL_JS + "\nreturn renderMarkdown;",
109
- ) as (w: unknown) => (text: string) => string;
110
- return factory({ location: { pathname: "/ui" } });
111
- }
112
-
113
- describe("renderMarkdown (SHELL_JS, XSS-safe Markdown subset)", () => {
114
- const renderMarkdown = loadRenderMarkdown();
115
-
116
- test("escapes raw HTML first — a <script> tag never survives as markup", () => {
117
- const out = renderMarkdown("<script>alert(1)</script>");
118
- expect(out).not.toContain("<script>");
119
- expect(out).toContain("&lt;script&gt;");
120
- });
121
-
122
- test("renders bold and italic", () => {
123
- expect(renderMarkdown("**bold**")).toContain("<strong>bold</strong>");
124
- expect(renderMarkdown("an *italic* word")).toContain("<em>italic</em>");
125
- });
126
-
127
- test("renders inline code and fenced code blocks", () => {
128
- const bt = String.fromCharCode(96);
129
- expect(renderMarkdown(bt + "inline" + bt)).toContain("<code>inline</code>");
130
- const fenced = renderMarkdown(bt + bt + bt + "\nconst x = 1;\n" + bt + bt + bt);
131
- expect(fenced).toContain("<pre><code>");
132
- expect(fenced).toContain("const x = 1;");
133
- });
134
-
135
- test("does not apply inline rules inside code spans", () => {
136
- const bt = String.fromCharCode(96);
137
- const out = renderMarkdown(bt + "**not bold**" + bt);
138
- expect(out).toContain("<code>**not bold**</code>");
139
- expect(out).not.toContain("<strong>");
140
- });
141
-
142
- test("renders http/https links as anchors with the url preserved", () => {
143
- const out = renderMarkdown("[site](https://example.com/x)");
144
- expect(out).toContain('href="https://example.com/x"');
145
- expect(out).toContain(">site</a>");
146
- expect(out).toContain('rel="noopener noreferrer"');
147
- });
148
-
149
- test("rejects javascript: URLs — renders inert escaped text, no anchor", () => {
150
- const out = renderMarkdown("[click](javascript:alert(1))");
151
- // No anchor and no href is produced — the would-be URL never reaches markup.
152
- expect(out).not.toContain("<a ");
153
- expect(out).not.toContain("href=");
154
- // The markdown is left as inert escaped text (safe — not an executable link).
155
- expect(out).toContain("[click]");
156
- });
157
-
158
- test("rejects data: URLs too — only http/https survive as anchors", () => {
159
- const out = renderMarkdown("[x](data:text/html,<script>alert(1)</script>)");
160
- expect(out).not.toContain("<a ");
161
- expect(out).not.toContain("href=");
162
- // any escaped markup inside is inert text, never executable.
163
- expect(out).not.toContain("<script>");
164
- });
165
-
166
- test("escapes other canonical XSS vectors (img onerror, svg onload)", () => {
167
- const out1 = renderMarkdown('<img src=x onerror=alert(1)>');
168
- expect(out1).not.toContain("<img");
169
- expect(out1).toContain("&lt;img");
170
- const out2 = renderMarkdown('<svg onload=alert(1)>');
171
- expect(out2).not.toContain("<svg");
172
- expect(out2).toContain("&lt;svg");
173
- });
174
-
175
- test("converts newlines to <br>", () => {
176
- expect(renderMarkdown("line1\nline2")).toContain("line1<br>line2");
177
- });
178
- });