@nyte-ai/host 0.0.24 → 0.0.25-nightly.20261025.2
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/THIRD-PARTY-NOTICES.md +13 -5
- package/dist/chunks/{canvas-preview-gh7c9831.js → canvas-preview-27v3zkz4.js} +6 -2
- package/dist/chunks/{canvas-preview-w0mr5bkn.js → canvas-preview-3kmevzjy.js} +11 -8
- package/dist/chunks/{canvas-preview-9e15hp6q.js → canvas-preview-4rstzyd7.js} +4 -3
- package/dist/chunks/{canvas-preview-d97wvref.js → canvas-preview-75bmwhsr.js} +1 -1
- package/dist/chunks/{canvas-preview-e3vnkkc5.js → canvas-preview-dr46h8mm.js} +2 -1
- package/dist/chunks/{canvas-preview-vaatfznm.js → canvas-preview-ez9zdfq4.js} +16 -7
- package/dist/chunks/{canvas-preview-whfdhma6.js → canvas-preview-sdvgxnpf.js} +1 -1
- package/dist/chunks/{canvas-preview-gm0frf4b.js → canvas-preview-tq7ny7fm.js} +15 -0
- package/dist/chunks/canvas-preview-z2xdr07w.js +256 -0
- package/dist/src/index.js +9 -9
- package/dist/src/listen-fetch.d.ts +1 -1
- package/dist/src/listen-fetch.js +3 -3
- package/dist/src/listen.js +4 -4
- package/dist/src/local/provider.d.ts +1 -1
- package/dist/src/local/provider.js +2 -2
- package/dist/src/local/worktrees.d.ts +7 -3
- package/dist/src/local/worktrees.js +1 -2
- package/dist/src/mcp/hub.js +2 -2
- package/dist/src/mcp/tools.d.ts +9 -2
- package/dist/src/mcp/tools.js +1 -1
- package/dist/src/open.js +9 -9
- package/dist/src/serve/binding.d.ts +0 -1
- package/dist/src/serve/binding.js +1 -1
- package/dist/src/serve/handler.js +2 -2
- package/package.json +7 -8
- package/src/listen-fetch.ts +6 -3
- package/src/local/provider.ts +3 -1
- package/src/local/worktrees.ts +210 -30
- package/src/mcp/hub.ts +5 -1
- package/src/mcp/tools.ts +24 -8
- package/src/open.ts +6 -2
- package/src/serve/binding.ts +19 -1
- package/dist/chunks/canvas-preview-2jwbe14k.js +0 -130
package/THIRD-PARTY-NOTICES.md
CHANGED
|
@@ -55,6 +55,11 @@ SOFTWARE.
|
|
|
55
55
|
`@earendil-works/pi-codemode` 1.0.0 supply the MCP client and QuickJS
|
|
56
56
|
executor. Tool discovery and code-mode integration are adapted from commit
|
|
57
57
|
`86dfceec402ad77e563bf4feab5f26c42d5f5db6`.
|
|
58
|
+
- BM25 tool search (`tool_search`, `searchTools()`), tool namespaces with
|
|
59
|
+
`describeNamespace()`, the budgeted codemode listing and the one-line MCP
|
|
60
|
+
server summary (`packages/plugin/src/tool-search.ts`,
|
|
61
|
+
`packages/plugin/src/codemode.ts`, `packages/core/src/builtins/mcp.ts`) are
|
|
62
|
+
ported from commit `d5b3de22d0e24a3e9c38a9410d3329b099717283`.
|
|
58
63
|
- Transcript reconciliation, checkpoint instruction snapshots, provider system
|
|
59
64
|
updates, and cache warming are ported from the 1.0.0 release commit
|
|
60
65
|
`a13d35a742c6ef8462812a28fbe1d8c8b7431c32`.
|
|
@@ -312,11 +317,14 @@ Copyright 2025 OpenAI
|
|
|
312
317
|
front of the queue (`packages/tui/src/model/interactions.ts`) is its
|
|
313
318
|
`onEmptySubmit`. The rename
|
|
314
319
|
plugin's context construction, prompt, model fallback, and output cleanup
|
|
315
|
-
(`packages/plugin/src/rename.ts`) port OpenCode v2. The web
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
+
(`packages/plugin/src/rename.ts`) port OpenCode v2. The web plugin
|
|
321
|
+
(`packages/plugin/src/web/`) ports OpenCode v2's web search and fetch tools:
|
|
322
|
+
the search provider registry any plugin can add to (`searchProviders` in
|
|
323
|
+
`packages/core/src/contract/plugin.ts`), its Exa, Firecrawl, Parallel, and
|
|
324
|
+
Tavily adapters, their stateless MCP `tools/call` transport and response
|
|
325
|
+
bounds, the result and error vocabulary, `web_fetch`'s Accept headers,
|
|
326
|
+
Cloudflare-challenge retry and size limits, and the streaming HTML-to-Markdown
|
|
327
|
+
and HTML-to-text converters (`packages/plugin/src/web/html-markdown.ts`).
|
|
320
328
|
- Core's ripgrep resolver and search adapter (`packages/core/src/ripgrep.ts`,
|
|
321
329
|
`packages/core/src/ripgrep/binary.ts`) and filename search
|
|
322
330
|
(`packages/core/src/file-search.ts`) adapt OpenCode v2's core implementation.
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
checkToolSchemas2,
|
|
22
22
|
TracingMcpClient2,
|
|
23
23
|
bridgeTools2
|
|
24
|
-
} from "./canvas-preview-
|
|
24
|
+
} from "./canvas-preview-ez9zdfq4.js";
|
|
25
25
|
|
|
26
26
|
// src/mcp/hub.ts
|
|
27
27
|
import { join } from "node:path";
|
|
@@ -206,7 +206,11 @@ function hub(input) {
|
|
|
206
206
|
state: () => state,
|
|
207
207
|
brief: () => ({
|
|
208
208
|
name: entry.name,
|
|
209
|
+
description: link.entry.description,
|
|
209
210
|
instructions: listed?.instructions ?? null,
|
|
211
|
+
exposures: [
|
|
212
|
+
...new Set([link.entry.exposure, ...link.entry.toolExposure.map((pair) => pair[1])])
|
|
213
|
+
],
|
|
210
214
|
unavailable: listed === null && (state.kind === "failed" || state.kind === "needs-sign-in") ? state.kind : null
|
|
211
215
|
}),
|
|
212
216
|
challenge: () => challenge,
|
|
@@ -217,7 +221,7 @@ function hub(input) {
|
|
|
217
221
|
bridged = {
|
|
218
222
|
entry: link.entry,
|
|
219
223
|
listed,
|
|
220
|
-
tools: bridgeTools2(link.entry, listed
|
|
224
|
+
tools: bridgeTools2(link.entry, listed, call)
|
|
221
225
|
};
|
|
222
226
|
return bridged.tools;
|
|
223
227
|
},
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./canvas-preview-8xc0vn7v.js";
|
|
13
13
|
import {
|
|
14
14
|
localProvider2
|
|
15
|
-
} from "./canvas-preview-
|
|
15
|
+
} from "./canvas-preview-dr46h8mm.js";
|
|
16
16
|
import {
|
|
17
17
|
importLegacyTrust2
|
|
18
18
|
} from "./canvas-preview-9aqczacs.js";
|
|
@@ -21,13 +21,13 @@ import {
|
|
|
21
21
|
} from "./canvas-preview-4e0pxa32.js";
|
|
22
22
|
import {
|
|
23
23
|
listen2
|
|
24
|
-
} from "./canvas-preview-
|
|
24
|
+
} from "./canvas-preview-sdvgxnpf.js";
|
|
25
25
|
import {
|
|
26
26
|
nodeImages2
|
|
27
27
|
} from "./canvas-preview-y5y6ghaw.js";
|
|
28
28
|
import {
|
|
29
29
|
createMcpHub2
|
|
30
|
-
} from "./canvas-preview-
|
|
30
|
+
} from "./canvas-preview-27v3zkz4.js";
|
|
31
31
|
import {
|
|
32
32
|
loadPluginDirectory2,
|
|
33
33
|
pluginLoader2
|
|
@@ -65,12 +65,14 @@ import openaiAstraContext from "@nyte-ai/plugin/core/openai-astra-context";
|
|
|
65
65
|
import { openaiCompaction } from "@nyte-ai/plugin/core/openai-compaction";
|
|
66
66
|
import question from "@nyte-ai/plugin/core/question";
|
|
67
67
|
import rename from "@nyte-ai/plugin/core/rename";
|
|
68
|
+
import subagents from "@nyte-ai/plugin/core/subagents";
|
|
68
69
|
import telemetry from "@nyte-ai/plugin/core/telemetry";
|
|
69
|
-
import
|
|
70
|
+
import toolSearch from "@nyte-ai/plugin/core/tool-search";
|
|
71
|
+
import web from "@nyte-ai/plugin/core/web";
|
|
70
72
|
// package.json
|
|
71
73
|
var package_default = {
|
|
72
74
|
name: "@nyte-ai/host",
|
|
73
|
-
version: "0.0.
|
|
75
|
+
version: "0.0.25-nightly.20261025.2",
|
|
74
76
|
private: false,
|
|
75
77
|
license: "MIT",
|
|
76
78
|
repository: {
|
|
@@ -175,7 +177,7 @@ var package_default = {
|
|
|
175
177
|
},
|
|
176
178
|
scripts: {
|
|
177
179
|
clean: "rm -rf node_modules .turbo",
|
|
178
|
-
typecheck: "
|
|
180
|
+
typecheck: "tsc --noEmit",
|
|
179
181
|
test: "vitest --run",
|
|
180
182
|
"check:store": "node scripts/check-store.ts",
|
|
181
183
|
"build:package": "bun ../../scripts/sdk-packages.mjs build host"
|
|
@@ -200,7 +202,6 @@ var package_default = {
|
|
|
200
202
|
"@types/node": "^26.6.5",
|
|
201
203
|
"@types/pg": "^8.23.1",
|
|
202
204
|
"fast-check": "^4.10.2",
|
|
203
|
-
typescript: "6.0.3",
|
|
204
205
|
vitest: "^5.0.5"
|
|
205
206
|
},
|
|
206
207
|
engines: {
|
|
@@ -252,9 +253,11 @@ async function composeOpen(options, input) {
|
|
|
252
253
|
approvals,
|
|
253
254
|
question,
|
|
254
255
|
rename,
|
|
256
|
+
subagents,
|
|
255
257
|
bashDescription,
|
|
256
|
-
|
|
258
|
+
web,
|
|
257
259
|
codemode,
|
|
260
|
+
toolSearch,
|
|
258
261
|
openaiCompaction(models),
|
|
259
262
|
openaiAstraContext,
|
|
260
263
|
telemetry,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createHandler2
|
|
3
|
-
} from "./canvas-preview-
|
|
3
|
+
} from "./canvas-preview-75bmwhsr.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,
|
|
133
|
-
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) {
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from "./canvas-preview-crmzxxt8.js";
|
|
22
22
|
import {
|
|
23
23
|
localWorktrees2
|
|
24
|
-
} from "./canvas-preview-
|
|
24
|
+
} from "./canvas-preview-z2xdr07w.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
|
}
|
|
@@ -59,13 +59,21 @@ class TracingMcpClient2 extends McpClient {
|
|
|
59
59
|
return super.request(method, traceparent === null || params?._meta !== undefined ? params : { ...params, _meta: { traceparent } }, options);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
function bridgeTools2(entry,
|
|
63
|
-
const names = tools.map((tool) => toolName(entry.name, tool.name));
|
|
62
|
+
function bridgeTools2(entry, listed, call) {
|
|
63
|
+
const names = listed.tools.map((tool) => toolName(entry.name, tool.name));
|
|
64
64
|
const counts = Map.groupBy(names, (name) => name);
|
|
65
|
-
|
|
65
|
+
const description = entry.description?.trim() ?? "";
|
|
66
|
+
const instructions = listed.instructions?.trim() ?? "";
|
|
67
|
+
const namespace = {
|
|
68
|
+
name: `mcp__${entry.name}`.replace(/[^A-Za-z0-9_]/g, "_"),
|
|
69
|
+
aliases: [entry.name],
|
|
70
|
+
...description === "" ? {} : { description },
|
|
71
|
+
...instructions === "" ? {} : { instructions }
|
|
72
|
+
};
|
|
73
|
+
return listed.tools.map((tool, index) => {
|
|
66
74
|
const name = names[index];
|
|
67
75
|
const unique = (counts.get(name)?.length ?? 0) > 1 ? hashed(name, tool.name) : name;
|
|
68
|
-
return bridge(entry, tool, call, unique);
|
|
76
|
+
return bridge(entry, tool, call, unique, namespace);
|
|
69
77
|
});
|
|
70
78
|
}
|
|
71
79
|
function toolName(server, tool) {
|
|
@@ -82,14 +90,15 @@ function globMatches(pattern, value) {
|
|
|
82
90
|
const source = pattern.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
83
91
|
return new RegExp(`^${source}$`).test(value);
|
|
84
92
|
}
|
|
85
|
-
function bridge(entry, tool, call, name) {
|
|
93
|
+
function bridge(entry, tool, call, name, namespace) {
|
|
86
94
|
const output = tool.outputSchema;
|
|
95
|
+
const exposure = toolExposure2(entry, tool.name);
|
|
87
96
|
const definition = {
|
|
88
97
|
name,
|
|
89
|
-
namespace
|
|
98
|
+
namespace,
|
|
90
99
|
description: tool.description ?? tool.title ?? tool.name,
|
|
91
100
|
parameters: passthrough(tool.inputSchema),
|
|
92
|
-
exposure:
|
|
101
|
+
exposure: exposure === "code" ? "deferred" : exposure,
|
|
93
102
|
class: () => ({ kind: "custom", label: `${entry.name}: ${tool.title ?? tool.name}` }),
|
|
94
103
|
effects: tool.annotations?.readOnlyHint === true ? "none" : "workspace",
|
|
95
104
|
replay: tool.annotations?.readOnlyHint === true || tool.annotations?.idempotentHint === true ? "safe" : "never",
|
|
@@ -116,6 +116,7 @@ function bindConnection2(connection, options) {
|
|
|
116
116
|
"workspaces.inspect": ({ target }) => connection.workspaces.inspect(target),
|
|
117
117
|
"workspaces.add": ({ target, options }) => connection.workspaces.add(target, options),
|
|
118
118
|
"workspaces.forget": ({ id }) => connection.workspaces.forget(id),
|
|
119
|
+
"workspaces.cleanWorktrees": () => connection.workspaces.cleanWorktrees(),
|
|
119
120
|
"sessions.watch": async (input) => sessionsFrames(connection.sessions.watch(input)),
|
|
120
121
|
"sessions.start": async (input) => {
|
|
121
122
|
const { session, receipt } = await connection.sessions.start(input);
|
|
@@ -138,12 +139,22 @@ function bindConnection2(connection, options) {
|
|
|
138
139
|
await session(id).info();
|
|
139
140
|
return viewFrames(session(id).head(head).watch(options));
|
|
140
141
|
},
|
|
142
|
+
"head.see": async ({ session: id, head, commit }) => {
|
|
143
|
+
await session(id).head(head).see(commit);
|
|
144
|
+
return null;
|
|
145
|
+
},
|
|
141
146
|
"head.history": ({ session: id, head, before, limit }) => session(id).head(head).history({ before, limit }),
|
|
142
147
|
"head.tree": ({ session: id, head }) => session(id).head(head).tree(),
|
|
143
148
|
"head.move": async ({ session: id, head, position, options, id: receipt }) => ({
|
|
144
149
|
receipt: (await wire.move(id, head, position, { ...options, id: receipt })).id
|
|
145
150
|
}),
|
|
146
151
|
"head.compact": ({ session: id, head, instructions }) => session(id).head(head).compact({ instructions }),
|
|
152
|
+
"head.revise": ({ session: id, head, message, content, options }) => session(id).head(head).revise(message, content, options),
|
|
153
|
+
"head.hold": ({ session: id, head, message }) => wire.hold(id, head, message),
|
|
154
|
+
"head.release": async ({ session: id, head, message }) => {
|
|
155
|
+
await wire.release(id, head, message);
|
|
156
|
+
return null;
|
|
157
|
+
},
|
|
147
158
|
"heads.create": ({ session: id, name, input }) => session(id).heads.create(name, input),
|
|
148
159
|
"heads.merge": ({ session: id, name, options }) => session(id).heads.merge(name, options),
|
|
149
160
|
"heads.remove": ({ session: id, name, options }) => session(id).heads.remove(name, options),
|
|
@@ -175,6 +186,10 @@ function bindConnection2(connection, options) {
|
|
|
175
186
|
const answer = await session(id).part(part).answer({ signal });
|
|
176
187
|
return answer === null ? null : { action: String(answer.action), input: toJson(answer.input) };
|
|
177
188
|
},
|
|
189
|
+
"part.watch": async ({ session: id, part }) => {
|
|
190
|
+
await session(id).info();
|
|
191
|
+
return session(id).part(part).watch();
|
|
192
|
+
},
|
|
178
193
|
"part.close": async ({ session: id, part }) => {
|
|
179
194
|
await session(id).part(part).close();
|
|
180
195
|
return null;
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import {
|
|
2
|
+
run2
|
|
3
|
+
} from "./canvas-preview-bxnqt8cd.js";
|
|
4
|
+
|
|
5
|
+
// src/local/worktrees.ts
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import { copyFile, mkdir, realpath, rm, stat } from "node:fs/promises";
|
|
8
|
+
import { homedir, tmpdir } from "node:os";
|
|
9
|
+
import { basename, join, resolve } from "node:path";
|
|
10
|
+
import { SdkError } from "@nyte-ai/schema";
|
|
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 REGENERABLE = new Set([
|
|
57
|
+
"node_modules",
|
|
58
|
+
".turbo",
|
|
59
|
+
".next",
|
|
60
|
+
".nuxt",
|
|
61
|
+
".svelte-kit",
|
|
62
|
+
".vite",
|
|
63
|
+
".parcel-cache",
|
|
64
|
+
"dist",
|
|
65
|
+
"build",
|
|
66
|
+
"coverage",
|
|
67
|
+
"target",
|
|
68
|
+
".venv",
|
|
69
|
+
"__pycache__"
|
|
70
|
+
]);
|
|
71
|
+
var MAX_ATTEMPTS = 100;
|
|
72
|
+
function gitCommand(binary = "git") {
|
|
73
|
+
return async (cwd, args, env) => {
|
|
74
|
+
const ran = await run2(binary, ["-c", "core.quotepath=off", ...args], {
|
|
75
|
+
cwd,
|
|
76
|
+
env: { ...ENV, ...env }
|
|
77
|
+
});
|
|
78
|
+
if (ran.code !== 0)
|
|
79
|
+
throw new SdkError("unavailable", ran.stderr.trim() || `git ${args[0] ?? ""} failed.`);
|
|
80
|
+
return ran.stdout.toString("utf8");
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
async function listWorktrees2(cwd, options) {
|
|
84
|
+
const out = await gitCommand(options?.git)(cwd, ["worktree", "list", "--porcelain", "-z"]);
|
|
85
|
+
return out.split("\x00\x00").flatMap((record) => {
|
|
86
|
+
const fields = record.split("\x00");
|
|
87
|
+
const path = fields.find((field) => field.startsWith("worktree "))?.slice(9);
|
|
88
|
+
const branch = fields.find((field) => field.startsWith("branch refs/heads/"))?.slice(18);
|
|
89
|
+
return path === undefined ? [] : [{ path: resolve(path), branch: branch ?? null }];
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async function addWorktree2(cwd, input, options) {
|
|
93
|
+
await gitCommand(options?.git)(cwd, input.from === undefined ? ["worktree", "add", input.path, input.branch] : ["worktree", "add", "-b", input.branch, input.path, input.from]);
|
|
94
|
+
}
|
|
95
|
+
async function hasBranch2(cwd, name, options) {
|
|
96
|
+
return gitCommand(options?.git)(cwd, ["show-ref", "--verify", "--quiet", `refs/heads/${name}`]).then(() => true).catch(() => false);
|
|
97
|
+
}
|
|
98
|
+
function localWorktrees2(options) {
|
|
99
|
+
const git = gitCommand(options?.git);
|
|
100
|
+
const folders = join(options?.home ?? homedir(), ".nyte", "worktrees");
|
|
101
|
+
const commitAt = (cwd, revision) => git(cwd, ["rev-parse", "--verify", "--quiet", `${revision}^{commit}`]).then((out) => out.trim(), () => null);
|
|
102
|
+
const workingTree = async (repo) => {
|
|
103
|
+
const index = join(tmpdir(), `nyte-worktree-index-${randomUUID()}`);
|
|
104
|
+
const indexEnv = { GIT_INDEX_FILE: index };
|
|
105
|
+
try {
|
|
106
|
+
await copyFile(join(repo.gitDir, "index"), index).catch(() => {
|
|
107
|
+
return;
|
|
108
|
+
});
|
|
109
|
+
await git(repo.root, ["add", "-A", "--", "."], indexEnv);
|
|
110
|
+
return (await git(repo.root, ["write-tree"], indexEnv)).trim();
|
|
111
|
+
} finally {
|
|
112
|
+
await rm(index, { force: true });
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const findClaimedBranch = async (root, name) => {
|
|
116
|
+
const out = await git(root, [
|
|
117
|
+
"config",
|
|
118
|
+
"-z",
|
|
119
|
+
"--get-regexp",
|
|
120
|
+
`^branch\\..*\\.${SESSION_KEY}$`
|
|
121
|
+
]).catch(() => "");
|
|
122
|
+
for (const entry of out.split("\x00")) {
|
|
123
|
+
const newline = entry.indexOf(`
|
|
124
|
+
`);
|
|
125
|
+
const branch = entry.slice("branch.".length, newline - SESSION_KEY.length - 1);
|
|
126
|
+
if (newline > 0 && entry.slice(newline + 1) === name && await hasBranch2(root, branch, options))
|
|
127
|
+
return branch;
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
};
|
|
131
|
+
const claimBranch = async (root, parent, listed, input, head) => {
|
|
132
|
+
for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
|
|
133
|
+
const branch = `${input.prefix ?? ""}${branchName(input.title, attempt)}`;
|
|
134
|
+
const folder = join(parent, branch.replaceAll("/", "-"));
|
|
135
|
+
if (listed.some((worktree) => worktree.path === folder) || await stat(folder).catch(() => null) !== null)
|
|
136
|
+
continue;
|
|
137
|
+
const [created] = await Promise.allSettled([
|
|
138
|
+
git(root, ["branch", "--no-track", branch, head])
|
|
139
|
+
]);
|
|
140
|
+
if (created.status === "rejected") {
|
|
141
|
+
if (await hasBranch2(root, branch, options))
|
|
142
|
+
continue;
|
|
143
|
+
throw created.reason;
|
|
144
|
+
}
|
|
145
|
+
await writeConfig(root, `branch.${branch}.${SESSION_KEY}`, input.name);
|
|
146
|
+
return branch;
|
|
147
|
+
}
|
|
148
|
+
throw new SdkError("unavailable", `Every worktree name for "${input.title ?? input.name}" is taken in ${root}.`);
|
|
149
|
+
};
|
|
150
|
+
const writeConfig = async (root, key, value) => {
|
|
151
|
+
for (let attempt = 1;; attempt++) {
|
|
152
|
+
const [written] = await Promise.allSettled([git(root, ["config", key, value])]);
|
|
153
|
+
if (written.status === "fulfilled")
|
|
154
|
+
return;
|
|
155
|
+
if (attempt >= 20)
|
|
156
|
+
throw written.reason;
|
|
157
|
+
await new Promise((settle) => setTimeout(settle, 10 * attempt));
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
async create(env, input) {
|
|
162
|
+
const repo = await readRepository(git, env.cwd);
|
|
163
|
+
if (repo === null)
|
|
164
|
+
throw new SdkError("unavailable", `${env.cwd} is not in a git repository, so it cannot have a worktree.`);
|
|
165
|
+
const head = await commitAt(repo.root, "HEAD");
|
|
166
|
+
if (head === null)
|
|
167
|
+
throw new SdkError("unavailable", `${repo.root} has no commits yet, so a worktree has nothing to branch from.`);
|
|
168
|
+
const below = (root) => ({
|
|
169
|
+
kind: "local",
|
|
170
|
+
path: resolve(root, repo.prefix)
|
|
171
|
+
});
|
|
172
|
+
const listed = await listWorktrees2(repo.root, options);
|
|
173
|
+
const claimed = await findClaimedBranch(repo.root, input.name);
|
|
174
|
+
const open = listed.find((worktree) => claimed !== null && worktree.branch === claimed);
|
|
175
|
+
if (claimed !== null && open !== undefined)
|
|
176
|
+
return {
|
|
177
|
+
target: below(open.path),
|
|
178
|
+
branch: claimed,
|
|
179
|
+
base: await commitAt(repo.root, `refs/heads/${claimed}`) ?? head
|
|
180
|
+
};
|
|
181
|
+
const parent = join(folders, basename(repo.root));
|
|
182
|
+
await mkdir(parent, { recursive: true });
|
|
183
|
+
const realParent = await realpath(parent);
|
|
184
|
+
const branch = claimed ?? await claimBranch(repo.root, realParent, listed, input, head);
|
|
185
|
+
const base = claimed === null ? head : await commitAt(repo.root, `refs/heads/${claimed}`) ?? head;
|
|
186
|
+
const folder = join(realParent, branch.replaceAll("/", "-"));
|
|
187
|
+
const tree = await workingTree(repo);
|
|
188
|
+
await addWorktree2(repo.root, { path: folder, branch }, options);
|
|
189
|
+
if (tree !== (await git(folder, ["rev-parse", "HEAD^{tree}"])).trim()) {
|
|
190
|
+
await git(folder, ["read-tree", "-m", "-u", "HEAD", tree]);
|
|
191
|
+
await git(folder, ["reset", "-q"]);
|
|
192
|
+
}
|
|
193
|
+
return { target: below(folder), branch, base };
|
|
194
|
+
},
|
|
195
|
+
async remove(worktree) {
|
|
196
|
+
const path = "path" in worktree.target ? worktree.target.path : null;
|
|
197
|
+
if (path === null || await stat(path).catch(() => null) === null)
|
|
198
|
+
return { folder: "removed", branch: "kept" };
|
|
199
|
+
const [root = path, common = ""] = (await git(path, [
|
|
200
|
+
"rev-parse",
|
|
201
|
+
"--show-toplevel",
|
|
202
|
+
"--path-format=absolute",
|
|
203
|
+
"--git-common-dir"
|
|
204
|
+
])).split(`
|
|
205
|
+
`);
|
|
206
|
+
const status = await git(root, ["status", "--porcelain", "--ignored", "-z"]);
|
|
207
|
+
if (status.split("\x00").some((entry) => entry !== "" && !(entry.startsWith("!! ") && entry.endsWith("/"))))
|
|
208
|
+
return { folder: "kept", branch: "kept" };
|
|
209
|
+
await git(common, ["worktree", "remove", root]);
|
|
210
|
+
if (await commitAt(common, `refs/heads/${worktree.branch}`) !== worktree.base)
|
|
211
|
+
return { folder: "removed", branch: "kept" };
|
|
212
|
+
await git(common, ["branch", "-D", worktree.branch]);
|
|
213
|
+
return { folder: "removed", branch: "deleted" };
|
|
214
|
+
},
|
|
215
|
+
async clean(target) {
|
|
216
|
+
const path = "path" in target ? target.path : null;
|
|
217
|
+
if (path === null || await stat(path).catch(() => null) === null)
|
|
218
|
+
return false;
|
|
219
|
+
const root = (await git(path, ["rev-parse", "--show-toplevel"])).trim();
|
|
220
|
+
const within = await realpath(folders).catch(() => null);
|
|
221
|
+
if (within === null || !root.startsWith(`${within}/`))
|
|
222
|
+
return false;
|
|
223
|
+
const status = await git(root, [
|
|
224
|
+
"status",
|
|
225
|
+
"--porcelain",
|
|
226
|
+
"--ignored=traditional",
|
|
227
|
+
"--untracked-files=normal",
|
|
228
|
+
"-z"
|
|
229
|
+
]);
|
|
230
|
+
const regenerable = status.split("\x00").filter((entry) => entry.startsWith("!! ") && entry.endsWith("/")).map((entry) => entry.slice(3, -1)).filter((folder) => REGENERABLE.has(basename(folder)));
|
|
231
|
+
await Promise.all(regenerable.map((folder) => rm(join(root, folder), { recursive: true, force: true })));
|
|
232
|
+
return regenerable.length > 0;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
async function readRepository(git, cwd) {
|
|
237
|
+
const out = await git(cwd, [
|
|
238
|
+
"rev-parse",
|
|
239
|
+
"--show-toplevel",
|
|
240
|
+
"--absolute-git-dir",
|
|
241
|
+
"--show-prefix"
|
|
242
|
+
]).catch(() => null);
|
|
243
|
+
const [root, gitDir, prefix = ""] = out?.split(`
|
|
244
|
+
`) ?? [];
|
|
245
|
+
return root === undefined || gitDir === undefined || root === "" ? null : { root: resolve(root), gitDir: resolve(gitDir), prefix };
|
|
246
|
+
}
|
|
247
|
+
function branchName(title, attempt) {
|
|
248
|
+
const words = (title ?? "").normalize("NFKD").toLowerCase().split(/[^a-z0-9]+/u).filter((word) => word !== "");
|
|
249
|
+
const kept = words.filter((word) => !STOPWORDS.has(word));
|
|
250
|
+
const content = kept.filter((word) => !TYPE_WORDS.has(word));
|
|
251
|
+
const chosen = content.length >= 2 ? content : kept.length > 0 ? kept : words;
|
|
252
|
+
const stem = chosen.length === 0 ? "worktree" : chosen.slice(0, attempt === 1 ? 3 : 2).join("-");
|
|
253
|
+
return attempt === 1 ? stem : `${stem}-${attempt}`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export { listWorktrees2, addWorktree2, hasBranch2, localWorktrees2 };
|
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-
|
|
14
|
+
import"../chunks/canvas-preview-tq7ny7fm.js";
|
|
15
15
|
import"../chunks/canvas-preview-rp4x6y1h.js";
|
|
16
|
-
import"../chunks/canvas-preview-
|
|
16
|
+
import"../chunks/canvas-preview-75bmwhsr.js";
|
|
17
17
|
import {
|
|
18
18
|
listenFetch2
|
|
19
|
-
} from "../chunks/canvas-preview-
|
|
19
|
+
} from "../chunks/canvas-preview-4rstzyd7.js";
|
|
20
20
|
import {
|
|
21
21
|
listen2
|
|
22
|
-
} from "../chunks/canvas-preview-
|
|
22
|
+
} from "../chunks/canvas-preview-sdvgxnpf.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,17 +51,17 @@ import {
|
|
|
51
51
|
addWorktree2,
|
|
52
52
|
hasBranch2,
|
|
53
53
|
localWorktrees2
|
|
54
|
-
} from "../chunks/canvas-preview-
|
|
54
|
+
} from "../chunks/canvas-preview-z2xdr07w.js";
|
|
55
55
|
import {
|
|
56
56
|
localProvider2
|
|
57
|
-
} from "../chunks/canvas-preview-
|
|
57
|
+
} from "../chunks/canvas-preview-dr46h8mm.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";
|
|
61
|
-
import"../chunks/canvas-preview-
|
|
61
|
+
import"../chunks/canvas-preview-ez9zdfq4.js";
|
|
62
62
|
import {
|
|
63
63
|
createMcpHub2
|
|
64
|
-
} from "../chunks/canvas-preview-
|
|
64
|
+
} from "../chunks/canvas-preview-27v3zkz4.js";
|
|
65
65
|
import"../chunks/canvas-preview-9aqczacs.js";
|
|
66
66
|
import"../chunks/canvas-preview-4e0pxa32.js";
|
|
67
67
|
import"../chunks/canvas-preview-befkjea2.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-
|
|
87
|
+
} from "../chunks/canvas-preview-3kmevzjy.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";
|
package/dist/src/listen-fetch.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
listenFetch2
|
|
3
|
-
} from "../chunks/canvas-preview-
|
|
4
|
-
import"../chunks/canvas-preview-
|
|
5
|
-
import"../chunks/canvas-preview-
|
|
3
|
+
} from "../chunks/canvas-preview-4rstzyd7.js";
|
|
4
|
+
import"../chunks/canvas-preview-75bmwhsr.js";
|
|
5
|
+
import"../chunks/canvas-preview-tq7ny7fm.js";
|
|
6
6
|
import"../chunks/canvas-preview-rp4x6y1h.js";
|
|
7
7
|
export {
|
|
8
8
|
listenFetch2 as listenFetch
|
package/dist/src/listen.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
listen2
|
|
3
|
-
} from "../chunks/canvas-preview-
|
|
4
|
-
import"../chunks/canvas-preview-
|
|
5
|
-
import"../chunks/canvas-preview-
|
|
6
|
-
import"../chunks/canvas-preview-
|
|
3
|
+
} from "../chunks/canvas-preview-sdvgxnpf.js";
|
|
4
|
+
import"../chunks/canvas-preview-4rstzyd7.js";
|
|
5
|
+
import"../chunks/canvas-preview-75bmwhsr.js";
|
|
6
|
+
import"../chunks/canvas-preview-tq7ny7fm.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;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
localProvider2
|
|
3
|
-
} from "../../chunks/canvas-preview-
|
|
4
|
-
import"../../chunks/canvas-preview-
|
|
3
|
+
} from "../../chunks/canvas-preview-dr46h8mm.js";
|
|
4
|
+
import"../../chunks/canvas-preview-z2xdr07w.js";
|
|
5
5
|
import"../../chunks/canvas-preview-5ekjx6sw.js";
|
|
6
6
|
import"../../chunks/canvas-preview-8xc0vn7v.js";
|
|
7
7
|
import"../../chunks/canvas-preview-1sq7z9jq.js";
|