@nyte-ai/host 0.0.23 → 0.0.25-beta.1

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 (61) hide show
  1. package/README.md +2 -2
  2. package/THIRD-PARTY-NOTICES.md +2 -38
  3. package/dist/chunks/{canvas-preview-d97wvref.js → canvas-preview-1r9sgbj3.js} +1 -1
  4. package/dist/chunks/{canvas-preview-gm0frf4b.js → canvas-preview-2yzyt077.js} +14 -0
  5. package/dist/chunks/{canvas-preview-whfdhma6.js → canvas-preview-8sv3j0vt.js} +1 -1
  6. package/dist/chunks/{canvas-preview-e3vnkkc5.js → canvas-preview-9bxhwjrh.js} +2 -1
  7. package/dist/chunks/{canvas-preview-2jwbe14k.js → canvas-preview-bg63k8n7.js} +113 -21
  8. package/dist/chunks/{canvas-preview-9e15hp6q.js → canvas-preview-da6dwy05.js} +4 -3
  9. package/dist/chunks/{canvas-preview-ayayyd43.js → canvas-preview-dt89p9pm.js} +148 -6
  10. package/dist/src/durable-object.d.ts +1 -1
  11. package/dist/src/index.js +7 -7
  12. package/dist/src/listen-fetch.d.ts +1 -1
  13. package/dist/src/listen-fetch.js +3 -3
  14. package/dist/src/listen.js +4 -4
  15. package/dist/src/local/provider.d.ts +1 -1
  16. package/dist/src/local/provider.js +2 -2
  17. package/dist/src/local/worktrees.d.ts +7 -3
  18. package/dist/src/local/worktrees.js +1 -2
  19. package/dist/src/open.js +7 -7
  20. package/dist/src/serve/binding.d.ts +0 -1
  21. package/dist/src/serve/binding.js +1 -1
  22. package/dist/src/serve/handler.js +2 -2
  23. package/package.json +8 -31
  24. package/src/durable-object.ts +1 -1
  25. package/src/listen-fetch.ts +6 -3
  26. package/src/local/provider.ts +3 -1
  27. package/src/local/worktrees.ts +165 -30
  28. package/src/open.ts +7 -1
  29. package/src/serve/binding.ts +18 -1
  30. package/src/usage-history.ts +0 -1
  31. package/dist/chunks/canvas-preview-1f8h0he1.js +0 -81
  32. package/dist/chunks/canvas-preview-2zdyh9ny.js +0 -26
  33. package/dist/chunks/canvas-preview-65xqjw7f.js +0 -20
  34. package/dist/chunks/canvas-preview-dsb5829c.js +0 -166
  35. package/dist/chunks/canvas-preview-kzmp015w.js +0 -36
  36. package/dist/src/deploy/cloudflare/worker.d.ts +0 -50
  37. package/dist/src/deploy/cloudflare/worker.js +0 -196
  38. package/dist/src/deploy/vercel/nitro.config.d.ts +0 -2
  39. package/dist/src/deploy/vercel/nitro.config.js +0 -30
  40. package/dist/src/deploy/vercel/server/routes/[...].d.ts +0 -2
  41. package/dist/src/deploy/vercel/server/routes/[...].js +0 -18
  42. package/dist/src/deploy/vercel/server/utils/host.d.ts +0 -13
  43. package/dist/src/deploy/vercel/server/utils/host.js +0 -7
  44. package/dist/src/deploy/vercel/server/utils/repair.d.ts +0 -1
  45. package/dist/src/deploy/vercel/server/utils/repair.js +0 -6
  46. package/dist/src/deploy/vercel/server/utils/step.d.ts +0 -10
  47. package/dist/src/deploy/vercel/server/utils/step.js +0 -6
  48. package/dist/src/deploy/vercel/server/workflows/drive.d.ts +0 -14
  49. package/dist/src/deploy/vercel/server/workflows/drive.js +0 -13
  50. package/src/deploy/cloudflare/README.md +0 -3
  51. package/src/deploy/cloudflare/worker.ts +0 -306
  52. package/src/deploy/cloudflare/wrangler.jsonc +0 -12
  53. package/src/deploy/vercel/README.md +0 -3
  54. package/src/deploy/vercel/nitro.config.ts +0 -29
  55. package/src/deploy/vercel/server/routes/[...].ts +0 -10
  56. package/src/deploy/vercel/server/utils/host.ts +0 -104
  57. package/src/deploy/vercel/server/utils/repair.ts +0 -35
  58. package/src/deploy/vercel/server/utils/step.ts +0 -25
  59. package/src/deploy/vercel/server/workflows/drive.ts +0 -46
  60. package/src/deploy/vercel/tsconfig.json +0 -9
  61. package/src/deploy/vercel/types/bun.d.ts +0 -2
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # @nyte-ai/host
2
2
 
3
- The Node and edge sides of a Nyte host, around the host `composeHost` builds in `@nyte-ai/core`: `listen` serves it over `node:http` or as a bare fetch handler, and `listenFetch` (`@nyte-ai/host/listen-fetch`, node-free) is that fetch handler for Workers, both through `src/serve`'s handler, which binds `@nyte-ai/protocol`'s table to the server port `composeHost` returns, with token, pairing and custom authentication, CORS, the `/.nyte/identity` and `/.nyte/describe` routes, and in-process driving when the kernel only admits; `sqliteStore` (`node:sqlite`), `postgresStore` (any `pg`-shaped pool) and `durableObjectStore` (`@nyte-ai/host/durable-object`, a Durable Object's SQLite) implement core's `Store`, each publish one transaction with its compare-and-set and log append; `localProvider` serves a folder on this machine, with files over `node:fs` versioned by content, `.gitignore`-aware scan, find, search (ripgrep, else a scan) and watch, processes over pipes or a pty (`@lydell/node-pty`, loaded on first use), git over its CLI, each file's patch sent as its unified diff text, and run snapshots kept as hidden git refs or a content-addressed tree walk; `chatOnlyProvider` and `sandboxProvider` (`@nyte-ai/host/providers`, node-free) serve a workspace with no files and one in a remote sandbox; `loadPluginFiles` and `pluginLoader` import the core plugins in `.nyte/plugins` directories; and `src/deploy` holds two deployments, a Cloudflare Worker whose Durable Object runs one host from its alarm (`@nyte-ai/host/deploy/cloudflare`) and a Nitro app for Vercel whose heads run as workflows (`@nyte-ai/host/deploy/vercel`).
3
+ The Node and edge sides of a Nyte host, around the host `composeHost` builds in `@nyte-ai/core`: `listen` serves it over `node:http` or as a bare fetch handler, and `listenFetch` (`@nyte-ai/host/listen-fetch`, node-free) is that fetch handler for Workers, both through `src/serve`'s handler, which binds `@nyte-ai/protocol`'s table to the server port `composeHost` returns, with token, pairing and custom authentication, CORS, the `/.nyte/identity` and `/.nyte/describe` routes, and in-process driving when the kernel only admits; `sqliteStore` (`node:sqlite`), `postgresStore` (any `pg`-shaped pool) and `durableObjectStore` (`@nyte-ai/host/durable-object`, a Durable Object's SQLite) implement core's `Store`, each publish one transaction with its compare-and-set and log append; `localProvider` serves a folder on this machine, with files over `node:fs` versioned by content, `.gitignore`-aware scan, find, search (ripgrep, else a scan) and watch, processes over pipes or a pty (`@lydell/node-pty`, loaded on first use), git over its CLI, each file's patch sent as its unified diff text, and run snapshots kept as hidden git refs or a content-addressed tree walk; `chatOnlyProvider` and `sandboxProvider` (`@nyte-ai/host/providers`, node-free) serve a workspace with no files and one in a remote sandbox; and `loadPluginFiles` and `pluginLoader` import the core plugins in `.nyte/plugins` directories. Deployments built on these live in `packages/examples`: a Cloudflare Worker whose Durable Object runs one host from its alarm, and a Nitro app for Vercel whose heads run as workflows.
4
4
 
5
5
  ## Tests
6
6
 
7
- `pnpm --dir packages/host test` runs every store against one conformance suite: sqlite, postgres over pglite, and the Durable Object store over a `node:sqlite` stand-in of its SQL storage (`test/do-sql-stub.ts`), the same stand-in the alarm `pass` and the `NyteHost` cold-start tests use. Deferred (Part 2 §43i): running the Worker and the Durable Object store inside workerd, and checking that the Worker's import graph reaches no `node:*` module, until a package that already depends on `wrangler` takes them; host itself carries neither `miniflare` nor `esbuild`.
7
+ `pnpm --dir packages/host test` runs every store against one conformance suite: sqlite, postgres over pglite, and the Durable Object store over a `node:sqlite` stand-in of its SQL storage (`test/do-sql-stub.ts`). The Worker's alarm `pass` and `NyteHost` cold-start tests live with the Worker in `packages/examples/cloudflare`. Deferred (Part 2 §43i): running the Worker and the Durable Object store inside workerd, and checking that the Worker's import graph reaches no `node:*` module, until a package that already depends on `wrangler` takes them; host itself carries neither `miniflare` nor `esbuild`.
@@ -45,39 +45,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
45
45
  SOFTWARE.
46
46
  ```
47
47
 
48
- ## pi-claude-code (`earendil-works/pi-claude-code`)
49
-
50
- - Repository: https://github.com/earendil-works/pi-claude-code
51
- - What: the Claude Code CLI provider, single-turn relay, transcript replay,
52
- process reuse, and billing guards in `packages/plugin/examples/claude-code`
53
- are adapted from commit `70abb65186592ca788b29b3db22c3160d629c41f`.
54
-
55
- License: MIT, with the following notice:
56
-
57
- ```text
58
- MIT License
59
-
60
- Copyright (c) 2026 Armin Ronacher
61
-
62
- Permission is hereby granted, free of charge, to any person obtaining a copy
63
- of this software and associated documentation files (the "Software"), to deal
64
- in the Software without restriction, including without limitation the rights
65
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
66
- copies of the Software, and to permit persons to whom the Software is
67
- furnished to do so, subject to the following conditions:
68
-
69
- The above copyright notice and this permission notice shall be included in all
70
- copies or substantial portions of the Software.
71
-
72
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
74
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
75
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
76
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
77
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
78
- SOFTWARE.
79
- ```
80
-
81
48
  ## pi (`earendil-works/pi`)
82
49
 
83
50
  - Repository: https://github.com/earendil-works/pi
@@ -345,8 +312,8 @@ Copyright 2025 OpenAI
345
312
  front of the queue (`packages/tui/src/model/interactions.ts`) is its
346
313
  `onEmptySubmit`. The rename
347
314
  plugin's context construction, prompt, model fallback, and output cleanup
348
- (`packages/plugin/examples/rename.ts`) port OpenCode v2. The web-search
349
- plugin set (`packages/plugin/examples/web-search/`) ports its Exa, Firecrawl,
315
+ (`packages/plugin/src/rename.ts`) port OpenCode v2. The web-search
316
+ plugin set (`packages/plugin/src/web-search.ts`) ports its Exa, Firecrawl,
350
317
  Parallel, and Tavily adapters, its stateless MCP `tools/call` transport and
351
318
  response bounds, its result and error vocabulary, and its arrangement of one
352
319
  plugin per provider from OpenCode v2.
@@ -429,9 +396,6 @@ SOFTWARE.
429
396
  bypass, and connection tuning in `packages/host/src/sqlite*.ts` are adapted
430
397
  from `bf8ffe81a63c82d3de5fbaa9991fd5f30034a452`.
431
398
  - Homepage: https://t3.codes
432
- - What: the demo desktop app (`packages/demo/desktop`) follows T3 Code's
433
- control-surface shape — agents in a sidebar, a conversation workspace, a
434
- shared composer, and settings behind a dialog.
435
399
 
436
400
  License: MIT, with the following notice:
437
401
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  bindConnection2
3
- } from "./canvas-preview-gm0frf4b.js";
3
+ } from "./canvas-preview-2yzyt077.js";
4
4
  import {
5
5
  createStreamChannels2
6
6
  } from "./canvas-preview-rp4x6y1h.js";
@@ -138,12 +138,22 @@ function bindConnection2(connection, options) {
138
138
  await session(id).info();
139
139
  return viewFrames(session(id).head(head).watch(options));
140
140
  },
141
+ "head.see": async ({ session: id, head, commit }) => {
142
+ await session(id).head(head).see(commit);
143
+ return null;
144
+ },
141
145
  "head.history": ({ session: id, head, before, limit }) => session(id).head(head).history({ before, limit }),
142
146
  "head.tree": ({ session: id, head }) => session(id).head(head).tree(),
143
147
  "head.move": async ({ session: id, head, position, options, id: receipt }) => ({
144
148
  receipt: (await wire.move(id, head, position, { ...options, id: receipt })).id
145
149
  }),
146
150
  "head.compact": ({ session: id, head, instructions }) => session(id).head(head).compact({ instructions }),
151
+ "head.revise": ({ session: id, head, message, content, options }) => session(id).head(head).revise(message, content, options),
152
+ "head.hold": ({ session: id, head, message }) => wire.hold(id, head, message),
153
+ "head.release": async ({ session: id, head, message }) => {
154
+ await wire.release(id, head, message);
155
+ return null;
156
+ },
147
157
  "heads.create": ({ session: id, name, input }) => session(id).heads.create(name, input),
148
158
  "heads.merge": ({ session: id, name, options }) => session(id).heads.merge(name, options),
149
159
  "heads.remove": ({ session: id, name, options }) => session(id).heads.remove(name, options),
@@ -175,6 +185,10 @@ function bindConnection2(connection, options) {
175
185
  const answer = await session(id).part(part).answer({ signal });
176
186
  return answer === null ? null : { action: String(answer.action), input: toJson(answer.input) };
177
187
  },
188
+ "part.watch": async ({ session: id, part }) => {
189
+ await session(id).info();
190
+ return session(id).part(part).watch();
191
+ },
178
192
  "part.close": async ({ session: id, part }) => {
179
193
  await session(id).part(part).close();
180
194
  return null;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listenFetch2
3
- } from "./canvas-preview-9e15hp6q.js";
3
+ } from "./canvas-preview-da6dwy05.js";
4
4
 
5
5
  // src/listen.ts
6
6
  import { createServer } from "node:http";
@@ -21,7 +21,7 @@ import {
21
21
  } from "./canvas-preview-crmzxxt8.js";
22
22
  import {
23
23
  localWorktrees2
24
- } from "./canvas-preview-2jwbe14k.js";
24
+ } from "./canvas-preview-bg63k8n7.js";
25
25
 
26
26
  // src/local/provider.ts
27
27
  import { constants, realpathSync } from "node:fs";
@@ -87,6 +87,7 @@ function localProvider2(options) {
87
87
  return nests(env.cwd, state) || nests(state, env.cwd) && !nests(join(state, "worktrees"), env.cwd) ? undefined : localSnapshots2(env, { store, git: options?.git });
88
88
  },
89
89
  worktrees: localWorktrees2({ home, git: options?.git }),
90
+ realpath: (env, path) => realpath(isAbsolute(path) ? path : join(env.cwd, path)).catch(() => null),
90
91
  async destroy() {
91
92
  throw new SdkError("unavailable", "A local folder is never torn down.");
92
93
  }
@@ -1,6 +1,3 @@
1
- import {
2
- sha2562
3
- } from "./canvas-preview-0nq75h9k.js";
4
1
  import {
5
2
  run2
6
3
  } from "./canvas-preview-bxnqt8cd.js";
@@ -9,9 +6,54 @@ import {
9
6
  import { randomUUID } from "node:crypto";
10
7
  import { copyFile, mkdir, realpath, rm, stat } from "node:fs/promises";
11
8
  import { homedir, tmpdir } from "node:os";
12
- import { basename, dirname, join, resolve } from "node:path";
9
+ import { basename, join, resolve } from "node:path";
13
10
  import { SdkError } from "@nyte-ai/schema";
14
11
  var ENV = { GIT_TERMINAL_PROMPT: "0", LC_ALL: "C" };
12
+ var SESSION_KEY = "nyte-session";
13
+ var STOPWORDS = new Set([
14
+ "a",
15
+ "an",
16
+ "the",
17
+ "and",
18
+ "or",
19
+ "of",
20
+ "to",
21
+ "in",
22
+ "on",
23
+ "for",
24
+ "with",
25
+ "from",
26
+ "by",
27
+ "at",
28
+ "into",
29
+ "as",
30
+ "is",
31
+ "are",
32
+ "be",
33
+ "it",
34
+ "its",
35
+ "this",
36
+ "that",
37
+ "my",
38
+ "our",
39
+ "your"
40
+ ]);
41
+ var TYPE_WORDS = new Set([
42
+ "feat",
43
+ "feature",
44
+ "fix",
45
+ "add",
46
+ "chore",
47
+ "refactor",
48
+ "docs",
49
+ "test",
50
+ "perf",
51
+ "build",
52
+ "ci",
53
+ "revert",
54
+ "update"
55
+ ]);
56
+ var MAX_ATTEMPTS = 100;
15
57
  function gitCommand(binary = "git") {
16
58
  return async (cwd, args, env) => {
17
59
  const ran = await run2(binary, ["-c", "core.quotepath=off", ...args], {
@@ -55,6 +97,51 @@ function localWorktrees2(options) {
55
97
  await rm(index, { force: true });
56
98
  }
57
99
  };
100
+ const findClaimedBranch = async (root, name) => {
101
+ const out = await git(root, [
102
+ "config",
103
+ "-z",
104
+ "--get-regexp",
105
+ `^branch\\..*\\.${SESSION_KEY}$`
106
+ ]).catch(() => "");
107
+ for (const entry of out.split("\x00")) {
108
+ const newline = entry.indexOf(`
109
+ `);
110
+ const branch = entry.slice("branch.".length, newline - SESSION_KEY.length - 1);
111
+ if (newline > 0 && entry.slice(newline + 1) === name && await hasBranch2(root, branch, options))
112
+ return branch;
113
+ }
114
+ return null;
115
+ };
116
+ const claimBranch = async (root, parent, listed, input, head) => {
117
+ for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
118
+ const branch = branchName(input.title, attempt);
119
+ const folder = join(parent, branch);
120
+ if (listed.some((worktree) => worktree.path === folder) || await stat(folder).catch(() => null) !== null)
121
+ continue;
122
+ const [created] = await Promise.allSettled([
123
+ git(root, ["branch", "--no-track", branch, head])
124
+ ]);
125
+ if (created.status === "rejected") {
126
+ if (await hasBranch2(root, branch, options))
127
+ continue;
128
+ throw created.reason;
129
+ }
130
+ await writeConfig(root, `branch.${branch}.${SESSION_KEY}`, input.name);
131
+ return branch;
132
+ }
133
+ throw new SdkError("unavailable", `Every worktree name for "${input.title ?? input.name}" is taken in ${root}.`);
134
+ };
135
+ const writeConfig = async (root, key, value) => {
136
+ for (let attempt = 1;; attempt++) {
137
+ const [written] = await Promise.allSettled([git(root, ["config", key, value])]);
138
+ if (written.status === "fulfilled")
139
+ return;
140
+ if (attempt >= 20)
141
+ throw written.reason;
142
+ await new Promise((settle) => setTimeout(settle, 10 * attempt));
143
+ }
144
+ };
58
145
  return {
59
146
  async create(env, input) {
60
147
  const repo = await readRepository(git, env.cwd);
@@ -63,30 +150,32 @@ function localWorktrees2(options) {
63
150
  const head = await commitAt(repo.root, "HEAD");
64
151
  if (head === null)
65
152
  throw new SdkError("unavailable", `${repo.root} has no commits yet, so a worktree has nothing to branch from.`);
66
- const slug = worktreeSlug(input.name, input.title);
67
- const branch = `nyte/${slug}`;
68
153
  const below = (root) => ({
69
154
  kind: "local",
70
155
  path: resolve(root, repo.prefix)
71
156
  });
72
- const listed = (await listWorktrees2(repo.root, options)).find((worktree) => worktree.branch === branch);
73
- if (listed !== undefined)
157
+ const listed = await listWorktrees2(repo.root, options);
158
+ const claimed = await findClaimedBranch(repo.root, input.name);
159
+ const open = listed.find((worktree) => claimed !== null && worktree.branch === claimed);
160
+ if (claimed !== null && open !== undefined)
74
161
  return {
75
- target: below(listed.path),
76
- branch,
77
- base: await commitAt(repo.root, `refs/heads/${branch}`) ?? head
162
+ target: below(open.path),
163
+ branch: claimed,
164
+ base: await commitAt(repo.root, `refs/heads/${claimed}`) ?? head
78
165
  };
79
- const folder = join(folders, basename(repo.root), slug);
80
- const branched = await hasBranch2(repo.root, branch, options);
81
- const base = branched ? await commitAt(repo.root, `refs/heads/${branch}`) ?? head : head;
166
+ const parent = join(folders, basename(repo.root));
167
+ await mkdir(parent, { recursive: true });
168
+ const realParent = await realpath(parent);
169
+ const branch = claimed ?? await claimBranch(repo.root, realParent, listed, input, head);
170
+ const base = claimed === null ? head : await commitAt(repo.root, `refs/heads/${claimed}`) ?? head;
171
+ const folder = join(realParent, branch);
82
172
  const tree = await workingTree(repo);
83
- await mkdir(dirname(folder), { recursive: true });
84
- await addWorktree2(repo.root, branched ? { path: folder, branch } : { path: folder, branch, from: head }, options);
173
+ await addWorktree2(repo.root, { path: folder, branch }, options);
85
174
  if (tree !== (await git(folder, ["rev-parse", "HEAD^{tree}"])).trim()) {
86
175
  await git(folder, ["read-tree", "-m", "-u", "HEAD", tree]);
87
176
  await git(folder, ["reset", "-q"]);
88
177
  }
89
- return { target: below(await realpath(folder)), branch, base };
178
+ return { target: below(folder), branch, base };
90
179
  },
91
180
  async remove(worktree) {
92
181
  const path = "path" in worktree.target ? worktree.target.path : null;
@@ -121,10 +210,13 @@ async function readRepository(git, cwd) {
121
210
  `) ?? [];
122
211
  return root === undefined || gitDir === undefined || root === "" ? null : { root: resolve(root), gitDir: resolve(gitDir), prefix };
123
212
  }
124
- function worktreeSlug(name, title) {
125
- const words = (title ?? "").toLowerCase().replace(/[^a-z0-9]+/gu, "-").slice(0, 40).replace(/^-+|-+$/gu, "");
126
- const key = sha2562(name).slice(0, 8);
127
- return words === "" ? key : `${words}-${key}`;
213
+ function branchName(title, attempt) {
214
+ const words = (title ?? "").normalize("NFKD").toLowerCase().split(/[^a-z0-9]+/u).filter((word) => word !== "");
215
+ const kept = words.filter((word) => !STOPWORDS.has(word));
216
+ const content = kept.filter((word) => !TYPE_WORDS.has(word));
217
+ const chosen = content.length >= 2 ? content : kept.length > 0 ? kept : words;
218
+ const stem = chosen.length === 0 ? "worktree" : chosen.slice(0, attempt === 1 ? 3 : 2).join("-");
219
+ return attempt === 1 ? stem : `${stem}-${attempt}`;
128
220
  }
129
221
 
130
222
  export { listWorktrees2, addWorktree2, hasBranch2, localWorktrees2 };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createHandler2
3
- } from "./canvas-preview-d97wvref.js";
3
+ } from "./canvas-preview-1r9sgbj3.js";
4
4
 
5
5
  // src/listen-fetch.ts
6
6
  import { SdkError } from "@nyte-ai/schema";
@@ -104,6 +104,7 @@ async function listenFetch2(host, options) {
104
104
  };
105
105
  const unwatchCommits = server.onExternalCommit(externalCommit);
106
106
  const isListenerToken = auth.kind === "token" ? (token) => sameSecret(token, auth.token) : async () => false;
107
+ const listenerAuthority = auth.kind === "token" ? auth.authority ?? TOKEN_AUTHORITY : TOKEN_AUTHORITY;
107
108
  const fallback = auth.kind === "custom" ? async (request) => {
108
109
  const verdict = await auth.authorize(request);
109
110
  if ("deny" in verdict)
@@ -129,8 +130,8 @@ async function listenFetch2(host, options) {
129
130
  if (token !== undefined) {
130
131
  if (await isListenerToken(token))
131
132
  return {
132
- connection: connectionFor(flight, TOKEN, TOKEN_AUTHORITY, token),
133
- authority: TOKEN_AUTHORITY
133
+ connection: connectionFor(flight, TOKEN, listenerAuthority, token),
134
+ authority: listenerAuthority
134
135
  };
135
136
  const remembered = await findDevice(token);
136
137
  if (remembered !== null) {
@@ -12,7 +12,7 @@ import {
12
12
  } from "./canvas-preview-8xc0vn7v.js";
13
13
  import {
14
14
  localProvider2
15
- } from "./canvas-preview-e3vnkkc5.js";
15
+ } from "./canvas-preview-9bxhwjrh.js";
16
16
  import {
17
17
  importLegacyTrust2
18
18
  } from "./canvas-preview-9aqczacs.js";
@@ -21,7 +21,7 @@ import {
21
21
  } from "./canvas-preview-4e0pxa32.js";
22
22
  import {
23
23
  listen2
24
- } from "./canvas-preview-whfdhma6.js";
24
+ } from "./canvas-preview-8sv3j0vt.js";
25
25
  import {
26
26
  nodeImages2
27
27
  } from "./canvas-preview-y5y6ghaw.js";
@@ -39,9 +39,6 @@ import {
39
39
  storePath2,
40
40
  sqliteStore2
41
41
  } from "./canvas-preview-mstbvwz3.js";
42
- import {
43
- package_default
44
- } from "./canvas-preview-dsb5829c.js";
45
42
 
46
43
  // src/open.ts
47
44
  import { watch } from "node:fs";
@@ -70,6 +67,147 @@ import question from "@nyte-ai/plugin/core/question";
70
67
  import rename from "@nyte-ai/plugin/core/rename";
71
68
  import telemetry from "@nyte-ai/plugin/core/telemetry";
72
69
  import webSearch from "@nyte-ai/plugin/core/web-search";
70
+ // package.json
71
+ var package_default = {
72
+ name: "@nyte-ai/host",
73
+ version: "0.0.25-beta.1",
74
+ private: false,
75
+ license: "MIT",
76
+ repository: {
77
+ type: "git",
78
+ url: "git+https://github.com/interfaces-lab/nyte.git",
79
+ directory: "packages/host"
80
+ },
81
+ files: [
82
+ "dist",
83
+ "src",
84
+ "LICENSE",
85
+ "THIRD-PARTY-NOTICES.md"
86
+ ],
87
+ type: "module",
88
+ exports: {
89
+ ".": "./src/index.ts",
90
+ "./canvas-preview": "./src/canvas-preview.ts",
91
+ "./credentials": "./src/credentials.ts",
92
+ "./durable-object": "./src/durable-object.ts",
93
+ "./identity": "./src/identity.ts",
94
+ "./images": "./src/images/node.ts",
95
+ "./image-worker": "./src/images/worker.ts",
96
+ "./listen-fetch": "./src/listen-fetch.ts",
97
+ "./providers": "./src/providers.ts",
98
+ "./secrets": "./src/secrets.ts",
99
+ "./shell-env": "./src/shell-env.ts",
100
+ "./usage": "./src/usage.ts",
101
+ "./store-usage": "./src/store-usage.ts",
102
+ "./usage-service": "./src/usage-service.ts",
103
+ "./usage-scan": "./src/usage-scan.ts",
104
+ "./usage-worker": "./src/usage-worker.ts"
105
+ },
106
+ publishConfig: {
107
+ exports: {
108
+ ".": {
109
+ types: "./dist/src/index.d.ts",
110
+ import: "./dist/src/index.js"
111
+ },
112
+ "./canvas-preview": {
113
+ types: "./dist/src/canvas-preview.d.ts",
114
+ import: "./dist/src/canvas-preview.js"
115
+ },
116
+ "./credentials": {
117
+ types: "./dist/src/credentials.d.ts",
118
+ import: "./dist/src/credentials.js"
119
+ },
120
+ "./durable-object": {
121
+ types: "./dist/src/durable-object.d.ts",
122
+ import: "./dist/src/durable-object.js"
123
+ },
124
+ "./identity": {
125
+ types: "./dist/src/identity.d.ts",
126
+ import: "./dist/src/identity.js"
127
+ },
128
+ "./images": {
129
+ types: "./dist/src/images/node.d.ts",
130
+ import: "./dist/src/images/node.js"
131
+ },
132
+ "./image-worker": {
133
+ types: "./dist/src/images/worker.d.ts",
134
+ import: "./dist/src/images/worker.js"
135
+ },
136
+ "./listen-fetch": {
137
+ types: "./dist/src/listen-fetch.d.ts",
138
+ import: "./dist/src/listen-fetch.js"
139
+ },
140
+ "./providers": {
141
+ types: "./dist/src/providers.d.ts",
142
+ import: "./dist/src/providers.js"
143
+ },
144
+ "./secrets": {
145
+ types: "./dist/src/secrets.d.ts",
146
+ import: "./dist/src/secrets.js"
147
+ },
148
+ "./shell-env": {
149
+ types: "./dist/src/shell-env.d.ts",
150
+ import: "./dist/src/shell-env.js"
151
+ },
152
+ "./usage": {
153
+ types: "./dist/src/usage.d.ts",
154
+ import: "./dist/src/usage.js"
155
+ },
156
+ "./store-usage": {
157
+ types: "./dist/src/store-usage.d.ts",
158
+ import: "./dist/src/store-usage.js"
159
+ },
160
+ "./usage-service": {
161
+ types: "./dist/src/usage-service.d.ts",
162
+ import: "./dist/src/usage-service.js"
163
+ },
164
+ "./usage-scan": {
165
+ types: "./dist/src/usage-scan.d.ts",
166
+ import: "./dist/src/usage-scan.js"
167
+ },
168
+ "./usage-worker": {
169
+ types: "./dist/src/usage-worker.d.ts",
170
+ import: "./dist/src/usage-worker.js"
171
+ }
172
+ },
173
+ access: "public",
174
+ provenance: true
175
+ },
176
+ scripts: {
177
+ clean: "rm -rf node_modules .turbo",
178
+ typecheck: "tsc --noEmit",
179
+ test: "vitest --run",
180
+ "check:store": "node scripts/check-store.ts",
181
+ "build:package": "bun ../../scripts/sdk-packages.mjs build host"
182
+ },
183
+ dependencies: {
184
+ "@earendil-works/pi-mcp": "^1.3.0",
185
+ "@lydell/node-pty": "^1.2.0-beta.15",
186
+ "@nyte-ai/ai": "workspace:*",
187
+ "@nyte-ai/core": "workspace:*",
188
+ "@nyte-ai/plugin": "workspace:*",
189
+ "@nyte-ai/protocol": "workspace:*",
190
+ "@nyte-ai/schema": "workspace:*",
191
+ "@silvia-odwyer/photon": "^0.3.3",
192
+ fflate: "^0.8.3",
193
+ ignore: "^7.0.13",
194
+ pg: "^8.23.1",
195
+ typebox: "^1.4.2"
196
+ },
197
+ devDependencies: {
198
+ "@electric-sql/pglite": "^0.5.11",
199
+ "@nyte-ai/canvas": "workspace:*",
200
+ "@types/node": "^26.6.5",
201
+ "@types/pg": "^8.23.1",
202
+ "fast-check": "^4.10.2",
203
+ vitest: "^5.0.5"
204
+ },
205
+ engines: {
206
+ node: ">=26.4.0"
207
+ }
208
+ };
209
+
210
+ // src/open.ts
73
211
  var RELOAD_DEBOUNCE_MS = 250;
74
212
  var STORE_POLL_MS = 500;
75
213
  async function openHost2(options) {
@@ -343,7 +481,11 @@ async function settingsSeed(home) {
343
481
  return { seed: { settings, path }, issue: null };
344
482
  }
345
483
  function hostDescription() {
346
- return { name: hostname(), platform: process.platform, version: package_default.version };
484
+ return {
485
+ name: hostname(),
486
+ platform: process.platform,
487
+ version: typeof NYTE_BUILT_VERSION === "string" ? NYTE_BUILT_VERSION : package_default.version
488
+ };
347
489
  }
348
490
  function settingsPath(home) {
349
491
  return join(home, ".nyte", "settings.json");
@@ -10,5 +10,5 @@ export type DurableObjectSql = {
10
10
  };
11
11
  transactionSync<T>(closure: () => T): T;
12
12
  };
13
- /** Returns a `Store` over a Durable Object's SQLite storage, node-free, with the sqlite store's tables, row helpers (`store-rows.ts`) and semantics (§41f): `objects(id TEXT PRIMARY KEY, body TEXT NULL, bytes BLOB NULL)`, `refs(name TEXT PRIMARY KEY, target TEXT NULL, revision TEXT NOT NULL)` and `log(session TEXT, seq INTEGER, at INTEGER, event TEXT, PRIMARY KEY (session, seq))`, brought to core's `STORE_VERSION` by `migrateStore` on first `open()`, each commit one `transactionSync` and no backup; the open rejects with `SdkError("unavailable")` for a store a newer Nyte migrated. `put` ids the value with core's `objectId` and stores its JSON once; `putBlob` buffers the stream, ids it with `blobId` and stores the bytes once as an `ArrayBuffer`; an object and a blob that share an id share the row, each column filled once; `blob` reads the bytes back with their size and a null mime; a body, blob or logged event past the Durable Object's 2 MB row limit throws `SdkError("invalid")` before anything is written (§42k). `refs.set` runs inside one `transactionSync` with no await between its reads and writes, first rejecting with `SdkError("unavailable")` when a newer Nyte has migrated the store, with `RefStore.set`'s semantics, each revision a random UUID, any throw inside rolling the whole batch back. `list(prefix)` reads the name range from `prefix` in name order; `log` returns the events after `after` in seq order up to `limit`, each validated as a `SessionEvent`; `tail` is the session's last seq, or 0. Every `open()` returns a connection over the one storage; `close()` releases nothing, the storage being the object's. In workerd, which allows code generation only while modules load, the Worker turns TypeBox acceleration off at startup (`Settings.Set({ useAcceleration: false })` from `typebox/system`, as `deploy/cloudflare/worker.ts` does), or `log`'s validation throws inside a request. */
13
+ /** Returns a `Store` over a Durable Object's SQLite storage, node-free, with the sqlite store's tables, row helpers (`store-rows.ts`) and semantics (§41f): `objects(id TEXT PRIMARY KEY, body TEXT NULL, bytes BLOB NULL)`, `refs(name TEXT PRIMARY KEY, target TEXT NULL, revision TEXT NOT NULL)` and `log(session TEXT, seq INTEGER, at INTEGER, event TEXT, PRIMARY KEY (session, seq))`, brought to core's `STORE_VERSION` by `migrateStore` on first `open()`, each commit one `transactionSync` and no backup; the open rejects with `SdkError("unavailable")` for a store a newer Nyte migrated. `put` ids the value with core's `objectId` and stores its JSON once; `putBlob` buffers the stream, ids it with `blobId` and stores the bytes once as an `ArrayBuffer`; an object and a blob that share an id share the row, each column filled once; `blob` reads the bytes back with their size and a null mime; a body, blob or logged event past the Durable Object's 2 MB row limit throws `SdkError("invalid")` before anything is written (§42k). `refs.set` runs inside one `transactionSync` with no await between its reads and writes, first rejecting with `SdkError("unavailable")` when a newer Nyte has migrated the store, with `RefStore.set`'s semantics, each revision a random UUID, any throw inside rolling the whole batch back. `list(prefix)` reads the name range from `prefix` in name order; `log` returns the events after `after` in seq order up to `limit`, each validated as a `SessionEvent`; `tail` is the session's last seq, or 0. Every `open()` returns a connection over the one storage; `close()` releases nothing, the storage being the object's. In workerd, which allows code generation only while modules load, the Worker turns TypeBox acceleration off at startup (`Settings.Set({ useAcceleration: false })` from `typebox/system`, as `packages/examples/cloudflare/worker.ts` does), or `log`'s validation throws inside a request. */
14
14
  export declare function durableObjectStore(storage: DurableObjectSql): Store;
package/dist/src/index.js CHANGED
@@ -11,15 +11,15 @@ import"../chunks/canvas-preview-wg80rbc2.js";
11
11
  import {
12
12
  identitySigner2
13
13
  } from "../chunks/canvas-preview-5mex725c.js";
14
- import"../chunks/canvas-preview-gm0frf4b.js";
14
+ import"../chunks/canvas-preview-2yzyt077.js";
15
15
  import"../chunks/canvas-preview-rp4x6y1h.js";
16
- import"../chunks/canvas-preview-d97wvref.js";
16
+ import"../chunks/canvas-preview-1r9sgbj3.js";
17
17
  import {
18
18
  listenFetch2
19
- } from "../chunks/canvas-preview-9e15hp6q.js";
19
+ } from "../chunks/canvas-preview-da6dwy05.js";
20
20
  import {
21
21
  listen2
22
- } from "../chunks/canvas-preview-whfdhma6.js";
22
+ } from "../chunks/canvas-preview-8sv3j0vt.js";
23
23
  import"../chunks/canvas-preview-0nq75h9k.js";
24
24
  import"../chunks/canvas-preview-bxnqt8cd.js";
25
25
  import"../chunks/canvas-preview-yjz0f7n4.js";
@@ -51,10 +51,10 @@ import {
51
51
  addWorktree2,
52
52
  hasBranch2,
53
53
  localWorktrees2
54
- } from "../chunks/canvas-preview-2jwbe14k.js";
54
+ } from "../chunks/canvas-preview-bg63k8n7.js";
55
55
  import {
56
56
  localProvider2
57
- } from "../chunks/canvas-preview-e3vnkkc5.js";
57
+ } from "../chunks/canvas-preview-9bxhwjrh.js";
58
58
  import"../chunks/canvas-preview-kdqgrstc.js";
59
59
  import"../chunks/canvas-preview-5z63am63.js";
60
60
  import"../chunks/canvas-preview-pkzqg96v.js";
@@ -84,7 +84,7 @@ import {
84
84
  } from "../chunks/canvas-preview-mstbvwz3.js";
85
85
  import {
86
86
  openHost2
87
- } from "../chunks/canvas-preview-ayayyd43.js";
87
+ } from "../chunks/canvas-preview-dt89p9pm.js";
88
88
  import {
89
89
  postgresStore2
90
90
  } from "../chunks/canvas-preview-4b6sayhg.js";
@@ -1,6 +1,6 @@
1
1
  import type { ListenOptions, Listener } from "@nyte-ai/core";
2
2
  import type { ServedHost } from "@nyte-ai/core/server";
3
- /** Serves a composed host as a bare fetch handler with no socket and no `node:*` import, so a Worker can serve it (§41j): `before`, the unauthenticated identity and describe routes, then `createHandler` over one cached connection per principal and authority, every response carrying `X-Nyte-Host` (§43a, §43j). A request authenticates by a pairing code, then the listener token (compared in constant time over SHA-256 digests) or a device token remembered until a commit from another process moves the host's principals, then `authorize` under `custom`; a revoke aborts that principal's open requests and streams. A `token` shorter than 16 characters throws `SdkError("invalid")`; `execution` (default: run covering all) drives covered sessions in process on an `admit-only` host, covers their leases otherwise and takes nothing on a `dispatch` host (§42v); `close()` disconnects the clients and releases the execution once, after which every request answers `unavailable`. */
3
+ /** Serves a composed host as a bare fetch handler with no socket and no `node:*` import, so a Worker can serve it (§41j): `before`, the unauthenticated identity and describe routes, then `createHandler` over one cached connection per principal and authority, every response carrying `X-Nyte-Host` (§43a, §43j). A request authenticates by a pairing code, then the listener token (compared in constant time over SHA-256 digests, granting `auth.authority`) or a device token remembered until a commit from another process moves the host's principals, then `authorize` under `custom`; a revoke aborts that principal's open requests and streams. A `token` shorter than 16 characters throws `SdkError("invalid")`; `execution` (default: run covering all) drives covered sessions in process on an `admit-only` host, covers their leases otherwise and takes nothing on a `dispatch` host (§42v); `close()` disconnects the clients and releases the execution once, after which every request answers `unavailable`. */
4
4
  export declare function listenFetch(host: ServedHost, options: ListenOptions & {
5
5
  readonly transport: {
6
6
  readonly kind: "fetch";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  listenFetch2
3
- } from "../chunks/canvas-preview-9e15hp6q.js";
4
- import"../chunks/canvas-preview-d97wvref.js";
5
- import"../chunks/canvas-preview-gm0frf4b.js";
3
+ } from "../chunks/canvas-preview-da6dwy05.js";
4
+ import"../chunks/canvas-preview-1r9sgbj3.js";
5
+ import"../chunks/canvas-preview-2yzyt077.js";
6
6
  import"../chunks/canvas-preview-rp4x6y1h.js";
7
7
  export {
8
8
  listenFetch2 as listenFetch
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  listen2
3
- } from "../chunks/canvas-preview-whfdhma6.js";
4
- import"../chunks/canvas-preview-9e15hp6q.js";
5
- import"../chunks/canvas-preview-d97wvref.js";
6
- import"../chunks/canvas-preview-gm0frf4b.js";
3
+ } from "../chunks/canvas-preview-8sv3j0vt.js";
4
+ import"../chunks/canvas-preview-da6dwy05.js";
5
+ import"../chunks/canvas-preview-1r9sgbj3.js";
6
+ import"../chunks/canvas-preview-2yzyt077.js";
7
7
  import"../chunks/canvas-preview-rp4x6y1h.js";
8
8
  export {
9
9
  listen2 as listen
@@ -1,5 +1,5 @@
1
1
  import type { EnvironmentProvider } from "@nyte-ai/core";
2
- /** Returns the local environment provider (`kind: "local"`): a folder on this machine. `inspect` answers a `{ kind: "local", path }` target's `folderIdentity` (§41d), `available` when the path is a readable directory (else `unavailable { unreachable }`; a target without a path `unavailable { unsupported }`, identified by the hash of its locator), and the project sources present under it, relative to it, in this order: the plugin files `.nyte/plugins/<name>.{ts,mts,js,mjs}` and `.nyte/plugins/<name>/index.<ext>`, the skills `.nyte/skills/<name>/SKILL.md` and `.agents/skills/<name>/SKILL.md`, the prompts `.nyte/prompts/<name>.md`, then `.nyte/SYSTEM.md`, `.nyte/APPEND_SYSTEM.md` and `.nyte/mcp.json`: the files project trust gates. Context files such as `AGENTS.md` load without trust and are not listed. `attach` resolves the real path (a target that is not a directory throws `SdkError("unavailable")`) and returns an `ExecutionEnv` with that identity, `cwd` the real path, `files` from `localFiles` (with `ripgrep` and `formatter`), `exec` from `localExec`, and a `close` that ends its file watches and the jobs' readers, leaving running jobs alone. `git` is `localGit` (with `git`), `github` is `localGitHub` (with `gh` and `git`; the login is the machine's, `localGitHubAccount`), `snapshots` is `localSnapshots` storing tree walks under `<home>/.nyte/snapshots` (`home` default `os.homedir()`), and absent for a folder that contains `<home>/.nyte` or lies inside it outside `<home>/.nyte/worktrees` (the home folder itself, its ancestors, Nyte's own state): there a snapshot would walk or stage everything under home, the store and secrets included, to report changes in the store it just wrote; `worktrees` is `localWorktrees` (with `home` and `git`); no `browser` (the desktop wraps one in); `destroy` rejects with `SdkError("unavailable")`: a local folder is never torn down. */
2
+ /** Returns the local environment provider (`kind: "local"`): a folder on this machine. `inspect` answers a `{ kind: "local", path }` target's `folderIdentity` (§41d), `available` when the path is a readable directory (else `unavailable { unreachable }`; a target without a path `unavailable { unsupported }`, identified by the hash of its locator), and the project sources present under it, relative to it, in this order: the plugin files `.nyte/plugins/<name>.{ts,mts,js,mjs}` and `.nyte/plugins/<name>/index.<ext>`, the skills `.nyte/skills/<name>/SKILL.md` and `.agents/skills/<name>/SKILL.md`, the prompts `.nyte/prompts/<name>.md`, then `.nyte/SYSTEM.md`, `.nyte/APPEND_SYSTEM.md` and `.nyte/mcp.json`: the files project trust gates. Context files such as `AGENTS.md` load without trust and are not listed. `attach` resolves the real path (a target that is not a directory throws `SdkError("unavailable")`) and returns an `ExecutionEnv` with that identity, `cwd` the real path, `files` from `localFiles` (with `ripgrep` and `formatter`), `exec` from `localExec`, and a `close` that ends its file watches and the jobs' readers, leaving running jobs alone. `git` is `localGit` (with `git`), `github` is `localGitHub` (with `gh` and `git`; the login is the machine's, `localGitHubAccount`), `snapshots` is `localSnapshots` storing tree walks under `<home>/.nyte/snapshots` (`home` default `os.homedir()`), and absent for a folder that contains `<home>/.nyte` or lies inside it outside `<home>/.nyte/worktrees` (the home folder itself, its ancestors, Nyte's own state): there a snapshot would walk or stage everything under home, the store and secrets included, to report changes in the store it just wrote; `worktrees` is `localWorktrees` (with `home` and `git`); `realpath` is `fs.promises.realpath` (the native one, which spells each name as the disk stores it), a relative path resolved against `env.cwd`, null where it fails; no `browser` (the desktop wraps one in); `destroy` rejects with `SdkError("unavailable")`: a local folder is never torn down. */
3
3
  export declare function localProvider(options?: {
4
4
  readonly home?: string;
5
5
  readonly git?: string;