nomoreide 0.1.99 → 0.1.101
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/README.md +26 -1
- package/dist/cli/git.js +5 -1
- package/dist/cli/git.js.map +1 -1
- package/dist/cli/profile.js +1 -1
- package/dist/cli/profile.js.map +1 -1
- package/dist/core/agent-profiles/index.d.ts +3 -2
- package/dist/core/agent-profiles/index.js +2 -1
- package/dist/core/agent-profiles/index.js.map +1 -1
- package/dist/core/agent-profiles/publication.d.ts +105 -0
- package/dist/core/agent-profiles/publication.js +126 -0
- package/dist/core/agent-profiles/publication.js.map +1 -0
- package/dist/core/agent-profiles/registry-client.d.ts +34 -1
- package/dist/core/agent-profiles/registry-client.js +12 -0
- package/dist/core/agent-profiles/registry-client.js.map +1 -1
- package/dist/core/agent-profiles/registry-config.d.ts +16 -2
- package/dist/core/agent-profiles/registry-config.js +76 -22
- package/dist/core/agent-profiles/registry-config.js.map +1 -1
- package/dist/core/agent-profiles/registry-transfer.js +28 -2
- package/dist/core/agent-profiles/registry-transfer.js.map +1 -1
- package/dist/core/agent-profiles/store.d.ts +25 -0
- package/dist/core/agent-profiles/store.js +186 -6
- package/dist/core/agent-profiles/store.js.map +1 -1
- package/dist/core/agent-profiles/transfer.js +64 -29
- package/dist/core/agent-profiles/transfer.js.map +1 -1
- package/dist/core/agent-profiles/types.d.ts +13 -6
- package/dist/core/agent-profiles/types.js.map +1 -1
- package/dist/core/agent-terminal.d.ts +3 -1
- package/dist/core/agent-terminal.js +24 -5
- package/dist/core/agent-terminal.js.map +1 -1
- package/dist/core/agent-transcripts.js +36 -3
- package/dist/core/agent-transcripts.js.map +1 -1
- package/dist/core/app-settings.d.ts +13 -0
- package/dist/core/app-settings.js +12 -0
- package/dist/core/app-settings.js.map +1 -1
- package/dist/core/config-store.d.ts +35 -1
- package/dist/core/config-store.js +173 -0
- package/dist/core/config-store.js.map +1 -1
- package/dist/core/context-library.d.ts +53 -0
- package/dist/core/context-library.js +510 -0
- package/dist/core/context-library.js.map +1 -0
- package/dist/core/context-types.d.ts +83 -0
- package/dist/core/context-types.js +9 -0
- package/dist/core/context-types.js.map +1 -0
- package/dist/core/daemon-client.d.ts +4 -0
- package/dist/core/daemon-client.js +18 -3
- package/dist/core/daemon-client.js.map +1 -1
- package/dist/core/db/data-masking.d.ts +3 -0
- package/dist/core/db/data-masking.js +14 -0
- package/dist/core/db/data-masking.js.map +1 -0
- package/dist/core/db/driver.d.ts +29 -1
- package/dist/core/db/driver.js +94 -0
- package/dist/core/db/driver.js.map +1 -1
- package/dist/core/db/export.d.ts +17 -0
- package/dist/core/db/export.js +67 -0
- package/dist/core/db/export.js.map +1 -0
- package/dist/core/db/mysql-driver.d.ts +3 -2
- package/dist/core/db/mysql-driver.js +53 -3
- package/dist/core/db/mysql-driver.js.map +1 -1
- package/dist/core/db/postgres-driver.d.ts +3 -2
- package/dist/core/db/postgres-driver.js +41 -3
- package/dist/core/db/postgres-driver.js.map +1 -1
- package/dist/core/db/sqlite-driver.d.ts +4 -2
- package/dist/core/db/sqlite-driver.js +68 -18
- package/dist/core/db/sqlite-driver.js.map +1 -1
- package/dist/core/db-peek.d.ts +9 -2
- package/dist/core/db-peek.js +20 -10
- package/dist/core/db-peek.js.map +1 -1
- package/dist/core/external-terminal.d.ts +60 -0
- package/dist/core/external-terminal.js +429 -0
- package/dist/core/external-terminal.js.map +1 -0
- package/dist/core/git-actions.d.ts +19 -0
- package/dist/core/git-actions.js +36 -4
- package/dist/core/git-actions.js.map +1 -1
- package/dist/core/git-identity.d.ts +78 -0
- package/dist/core/git-identity.js +178 -0
- package/dist/core/git-identity.js.map +1 -0
- package/dist/core/git-manager.d.ts +9 -1
- package/dist/core/git-manager.js +10 -3
- package/dist/core/git-manager.js.map +1 -1
- package/dist/core/github-context.js +1 -29
- package/dist/core/github-context.js.map +1 -1
- package/dist/core/github-manager.d.ts +6 -0
- package/dist/core/github-manager.js.map +1 -1
- package/dist/core/process-manager.js +10 -3
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/project-overview.d.ts +52 -0
- package/dist/core/project-overview.js +122 -0
- package/dist/core/project-overview.js.map +1 -0
- package/dist/core/repo-match.d.ts +12 -0
- package/dist/core/repo-match.js +40 -0
- package/dist/core/repo-match.js.map +1 -0
- package/dist/core/repo-onboard.d.ts +4 -4
- package/dist/core/ssh-servers.d.ts +52 -0
- package/dist/core/ssh-servers.js +194 -0
- package/dist/core/ssh-servers.js.map +1 -0
- package/dist/core/ssh-setup.d.ts +11 -0
- package/dist/core/ssh-setup.js +49 -0
- package/dist/core/ssh-setup.js.map +1 -0
- package/dist/core/terminal-manager.d.ts +40 -0
- package/dist/core/terminal-manager.js +320 -11
- package/dist/core/terminal-manager.js.map +1 -1
- package/dist/core/terminal-session.d.ts +12 -3
- package/dist/core/terminal-session.js +53 -4
- package/dist/core/terminal-session.js.map +1 -1
- package/dist/core/types.d.ts +62 -0
- package/dist/core/vercel-actions.d.ts +71 -0
- package/dist/core/vercel-actions.js +109 -0
- package/dist/core/vercel-actions.js.map +1 -0
- package/dist/core/vercel-auth.d.ts +58 -0
- package/dist/core/vercel-auth.js +130 -0
- package/dist/core/vercel-auth.js.map +1 -0
- package/dist/core/vercel-context.d.ts +25 -0
- package/dist/core/vercel-context.js +143 -0
- package/dist/core/vercel-context.js.map +1 -0
- package/dist/core/vercel-manager.d.ts +253 -0
- package/dist/core/vercel-manager.js +391 -0
- package/dist/core/vercel-manager.js.map +1 -0
- package/dist/core/vercel-oauth.d.ts +75 -0
- package/dist/core/vercel-oauth.js +223 -0
- package/dist/core/vercel-oauth.js.map +1 -0
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/tools/agent-registry.d.ts +2 -2
- package/dist/mcp/tools/agent-registry.js +3 -3
- package/dist/mcp/tools/agent-registry.js.map +1 -1
- package/dist/mcp/tools/docs.d.ts +1 -1
- package/dist/mcp/tools/docs.js +20 -8
- package/dist/mcp/tools/docs.js.map +1 -1
- package/dist/mcp/tools/git.js +20 -2
- package/dist/mcp/tools/git.js.map +1 -1
- package/dist/mcp/tools/index.d.ts +1 -1
- package/dist/mcp/tools/index.js +6 -0
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/terminal.d.ts +4 -0
- package/dist/mcp/tools/terminal.js +38 -0
- package/dist/mcp/tools/terminal.js.map +1 -0
- package/dist/mcp/tools/vercel.d.ts +12 -0
- package/dist/mcp/tools/vercel.js +103 -0
- package/dist/mcp/tools/vercel.js.map +1 -0
- package/dist/web/client/assets/code-editor-rHWIXkKg.js +30 -0
- package/dist/web/client/assets/context-graph-CcfJNAob.js +7 -0
- package/dist/web/client/assets/index-BhDAhmA1.js +1 -0
- package/dist/web/client/assets/index-BnFtcUqj.js +352 -0
- package/dist/web/client/assets/index-CqsghUD9.css +1 -0
- package/dist/web/client/assets/system-process-table-S4umMSEK.js +1 -0
- package/dist/web/client/index.html +2 -2
- package/dist/web/http-utils.d.ts +4 -1
- package/dist/web/http-utils.js +12 -2
- package/dist/web/http-utils.js.map +1 -1
- package/dist/web/routes/agent-chat-routes.js +29 -0
- package/dist/web/routes/agent-chat-routes.js.map +1 -1
- package/dist/web/routes/agent-profile-routes.js +32 -2
- package/dist/web/routes/agent-profile-routes.js.map +1 -1
- package/dist/web/routes/agent-registry-routes.js +68 -2
- package/dist/web/routes/agent-registry-routes.js.map +1 -1
- package/dist/web/routes/context-library-routes.d.ts +2 -0
- package/dist/web/routes/context-library-routes.js +139 -0
- package/dist/web/routes/context-library-routes.js.map +1 -0
- package/dist/web/routes/context.d.ts +2 -0
- package/dist/web/routes/context.js.map +1 -1
- package/dist/web/routes/database-routes.js +108 -1
- package/dist/web/routes/database-routes.js.map +1 -1
- package/dist/web/routes/git-routes.js +37 -7
- package/dist/web/routes/git-routes.js.map +1 -1
- package/dist/web/routes/index.js +8 -0
- package/dist/web/routes/index.js.map +1 -1
- package/dist/web/routes/overview-routes.d.ts +2 -0
- package/dist/web/routes/overview-routes.js +36 -0
- package/dist/web/routes/overview-routes.js.map +1 -0
- package/dist/web/routes/shell-routes.d.ts +8 -0
- package/dist/web/routes/shell-routes.js +11 -2
- package/dist/web/routes/shell-routes.js.map +1 -1
- package/dist/web/routes/ssh-server-routes.d.ts +3 -0
- package/dist/web/routes/ssh-server-routes.js +121 -0
- package/dist/web/routes/ssh-server-routes.js.map +1 -0
- package/dist/web/routes/terminal-routes.js +176 -7
- package/dist/web/routes/terminal-routes.js.map +1 -1
- package/dist/web/routes/vercel-routes.d.ts +2 -0
- package/dist/web/routes/vercel-routes.js +476 -0
- package/dist/web/routes/vercel-routes.js.map +1 -0
- package/dist/web/server.d.ts +9 -0
- package/dist/web/server.js +53 -13
- package/dist/web/server.js.map +1 -1
- package/package.json +5 -1
- package/dist/web/client/assets/code-editor-DUgkd8Vo.js +0 -28
- package/dist/web/client/assets/index-BTwlXmPn.css +0 -1
- package/dist/web/client/assets/index-CRM7WNxX.js +0 -308
- package/dist/web/client/assets/system-process-table-DbxLdSLC.js +0 -1
|
@@ -1,38 +1,90 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Profile registry configuration
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* Profile registry configuration. Credentials and target URLs live in
|
|
3
|
+
* `~/.nomoreide/config.json` and honor the `NOMOREIDE_*` environment variables.
|
|
4
|
+
*
|
|
5
|
+
* The registry began life as the brainctl platform, so every lookup falls back
|
|
6
|
+
* to the old `~/.brainctl/config.json` and `BRAINCTL_*` names: an existing
|
|
7
|
+
* brainctl sign-in keeps working, and the first write migrates it to the new
|
|
8
|
+
* path. The old names are the fallback, never the override — otherwise a stale
|
|
9
|
+
* `BRAINCTL_API_BASE_URL` left in a shell profile would silently win.
|
|
7
10
|
*/
|
|
8
11
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
9
12
|
import { homedir } from "node:os";
|
|
10
13
|
import path from "node:path";
|
|
11
|
-
export const DEFAULT_REGISTRY_API_BASE_URL = "https://api.
|
|
12
|
-
export const DEFAULT_REGISTRY_FRONTEND_URL = "https://
|
|
14
|
+
export const DEFAULT_REGISTRY_API_BASE_URL = "https://api.nomoreide.com";
|
|
15
|
+
export const DEFAULT_REGISTRY_FRONTEND_URL = "https://registry.nomoreide.com";
|
|
16
|
+
/**
|
|
17
|
+
* The pre-rename default. Still serving the same API — every CLI published
|
|
18
|
+
* before the rename has it compiled in — so it is a real production target, not
|
|
19
|
+
* a custom one.
|
|
20
|
+
*/
|
|
21
|
+
export const LEGACY_REGISTRY_API_BASE_URL = "https://api.brainctl.net";
|
|
22
|
+
export const LEGACY_REGISTRY_FRONTEND_URL = "https://www.brainctl.net";
|
|
23
|
+
/**
|
|
24
|
+
* API base → registry web UI, for the hosts we actually run. Without the legacy
|
|
25
|
+
* entry an `api.brainctl.net` left in a config would fall through to the
|
|
26
|
+
* `api.` → `app.` guess below and resolve to `app.brainctl.net`, which does not
|
|
27
|
+
* exist.
|
|
28
|
+
*/
|
|
29
|
+
const KNOWN_REGISTRY_FRONTENDS = new Map([
|
|
30
|
+
[DEFAULT_REGISTRY_API_BASE_URL, DEFAULT_REGISTRY_FRONTEND_URL],
|
|
31
|
+
[LEGACY_REGISTRY_API_BASE_URL, LEGACY_REGISTRY_FRONTEND_URL],
|
|
32
|
+
]);
|
|
33
|
+
/**
|
|
34
|
+
* Reads `NOMOREIDE_<suffix>`, falling back to the pre-rename `BRAINCTL_<suffix>`.
|
|
35
|
+
*/
|
|
36
|
+
function readBrandedEnv(env, suffix) {
|
|
37
|
+
return env[`NOMOREIDE_${suffix}`] ?? env[`BRAINCTL_${suffix}`];
|
|
38
|
+
}
|
|
39
|
+
/** Where config is written, and read from first. */
|
|
13
40
|
export function registryConfigPath(options = {}) {
|
|
14
41
|
const env = options.env ?? process.env;
|
|
15
42
|
return (options.configPath ??
|
|
16
|
-
env
|
|
17
|
-
path.join(env
|
|
43
|
+
readBrandedEnv(env, "CONFIG_PATH") ??
|
|
44
|
+
path.join(readBrandedEnv(env, "HOME") ?? homedir(), ".nomoreide", "config.json"));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Pre-rename location, read only when {@link registryConfigPath} has no file
|
|
48
|
+
* yet. Returns null when the caller pinned an explicit path or the resolved
|
|
49
|
+
* path is already the legacy one — there is nothing to fall back to.
|
|
50
|
+
*/
|
|
51
|
+
export function legacyRegistryConfigPath(options = {}) {
|
|
52
|
+
const env = options.env ?? process.env;
|
|
53
|
+
if (options.configPath ?? readBrandedEnv(env, "CONFIG_PATH"))
|
|
54
|
+
return null;
|
|
55
|
+
return path.join(readBrandedEnv(env, "HOME") ?? homedir(), ".brainctl", "config.json");
|
|
18
56
|
}
|
|
19
57
|
export function createRegistryConfigService(options = {}) {
|
|
20
58
|
const filePath = registryConfigPath(options);
|
|
21
|
-
|
|
59
|
+
const legacyPath = legacyRegistryConfigPath(options);
|
|
60
|
+
async function readFrom(candidate) {
|
|
22
61
|
let source;
|
|
23
62
|
try {
|
|
24
|
-
source = await readFile(
|
|
63
|
+
source = await readFile(candidate, "utf8");
|
|
25
64
|
}
|
|
26
65
|
catch {
|
|
27
|
-
return
|
|
66
|
+
return null;
|
|
28
67
|
}
|
|
29
68
|
try {
|
|
30
69
|
return normalizeConfig(JSON.parse(source));
|
|
31
70
|
}
|
|
32
71
|
catch (error) {
|
|
33
|
-
throw new Error(`Invalid registry config at ${
|
|
72
|
+
throw new Error(`Invalid registry config at ${candidate}: ${error.message}`);
|
|
34
73
|
}
|
|
35
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Falls back to the pre-rename file so an existing brainctl sign-in still
|
|
77
|
+
* resolves. Writes always land on {@link filePath}, so the next `set` migrates
|
|
78
|
+
* the config across without the user re-authenticating.
|
|
79
|
+
*/
|
|
80
|
+
async function read() {
|
|
81
|
+
const current = await readFrom(filePath);
|
|
82
|
+
if (current)
|
|
83
|
+
return current;
|
|
84
|
+
if (legacyPath)
|
|
85
|
+
return (await readFrom(legacyPath)) ?? {};
|
|
86
|
+
return {};
|
|
87
|
+
}
|
|
36
88
|
async function write(config) {
|
|
37
89
|
await mkdir(path.dirname(filePath), { recursive: true });
|
|
38
90
|
await writeFile(filePath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
@@ -55,7 +107,7 @@ export function createRegistryConfigService(options = {}) {
|
|
|
55
107
|
}
|
|
56
108
|
export async function resolveRegistryApiTarget(options = {}) {
|
|
57
109
|
const env = options.env ?? process.env;
|
|
58
|
-
const envValue = env
|
|
110
|
+
const envValue = readBrandedEnv(env, "API_BASE_URL") ?? readBrandedEnv(env, "API_URL");
|
|
59
111
|
if (envValue)
|
|
60
112
|
return toApiTarget(normalizeBaseUrl(envValue), "env");
|
|
61
113
|
const configService = options.configService ?? createRegistryConfigService(options);
|
|
@@ -71,8 +123,9 @@ export async function resolveRegistryApiBaseUrl(options = {}) {
|
|
|
71
123
|
}
|
|
72
124
|
export async function resolveRegistryApiToken(options = {}) {
|
|
73
125
|
const env = options.env ?? process.env;
|
|
74
|
-
|
|
75
|
-
|
|
126
|
+
const envToken = readBrandedEnv(env, "API_TOKEN");
|
|
127
|
+
if (envToken?.trim()) {
|
|
128
|
+
return { token: envToken.trim(), source: "env" };
|
|
76
129
|
}
|
|
77
130
|
const configService = options.configService ?? createRegistryConfigService(options);
|
|
78
131
|
const stored = await configService.get("apiToken");
|
|
@@ -83,8 +136,9 @@ export async function resolveRegistryApiToken(options = {}) {
|
|
|
83
136
|
/** Registry web UI base — where the browser sign-in flow lives. */
|
|
84
137
|
export async function resolveRegistryFrontendUrl(options = {}) {
|
|
85
138
|
const env = options.env ?? process.env;
|
|
86
|
-
|
|
87
|
-
|
|
139
|
+
const envFrontendUrl = readBrandedEnv(env, "FRONTEND_URL");
|
|
140
|
+
if (envFrontendUrl?.trim()) {
|
|
141
|
+
return normalizeBaseUrl(envFrontendUrl);
|
|
88
142
|
}
|
|
89
143
|
const configService = options.configService ?? createRegistryConfigService(options);
|
|
90
144
|
const stored = await configService.get("apiFrontendUrl");
|
|
@@ -92,9 +146,9 @@ export async function resolveRegistryFrontendUrl(options = {}) {
|
|
|
92
146
|
return normalizeBaseUrl(stored);
|
|
93
147
|
if (options.apiBaseUrl) {
|
|
94
148
|
try {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
149
|
+
const known = KNOWN_REGISTRY_FRONTENDS.get(normalizeBaseUrl(options.apiBaseUrl));
|
|
150
|
+
if (known)
|
|
151
|
+
return known;
|
|
98
152
|
const url = new URL(options.apiBaseUrl);
|
|
99
153
|
if (url.hostname === "localhost" || url.hostname === "127.0.0.1") {
|
|
100
154
|
return `${url.protocol}//${url.hostname}:5173`;
|
|
@@ -153,7 +207,7 @@ function normalizeBaseUrl(value) {
|
|
|
153
207
|
}
|
|
154
208
|
function toApiTarget(apiBaseUrl, source) {
|
|
155
209
|
let mode = "custom";
|
|
156
|
-
if (apiBaseUrl
|
|
210
|
+
if (KNOWN_REGISTRY_FRONTENDS.has(apiBaseUrl)) {
|
|
157
211
|
mode = "prod";
|
|
158
212
|
}
|
|
159
213
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-config.js","sourceRoot":"","sources":["../../../src/core/agent-profiles/registry-config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registry-config.js","sourceRoot":"","sources":["../../../src/core/agent-profiles/registry-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
|
9
9
|
import { tmpdir } from "node:os";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import { createRegistryClient } from "./registry-client.js";
|
|
12
|
-
import { getProfile } from "./store.js";
|
|
12
|
+
import { getProfile, writeProfileRegistryLink, } from "./store.js";
|
|
13
13
|
import { exportProfile, importProfile } from "./transfer.js";
|
|
14
14
|
export async function publishProfileToRegistry(input, options = {}) {
|
|
15
15
|
const version = input.version ?? "1.0.0";
|
|
@@ -60,6 +60,13 @@ export async function publishProfileToRegistry(input, options = {}) {
|
|
|
60
60
|
profileId: registryProfile.id,
|
|
61
61
|
versionId: registryVersion.id,
|
|
62
62
|
});
|
|
63
|
+
await writeProfileRegistryLink(input.name, {
|
|
64
|
+
origin: "published",
|
|
65
|
+
slug: input.slug,
|
|
66
|
+
version,
|
|
67
|
+
profileId: registryProfile.id,
|
|
68
|
+
versionId: registryVersion.id,
|
|
69
|
+
}, options);
|
|
63
70
|
return {
|
|
64
71
|
slug: input.slug,
|
|
65
72
|
profileId: registryProfile.id,
|
|
@@ -82,7 +89,7 @@ export async function installProfileFromRegistry(input, options = {}) {
|
|
|
82
89
|
if (!descriptor.download_url) {
|
|
83
90
|
throw new Error(`Registry profile "${slug}" has no downloadable package.`);
|
|
84
91
|
}
|
|
85
|
-
const response = await fetchImpl(descriptor.download_url);
|
|
92
|
+
const response = await fetchImpl(resolveDownloadUrl(descriptor.download_url, input.apiBaseUrl));
|
|
86
93
|
if (!response.ok) {
|
|
87
94
|
const text = await response.text().catch(() => "");
|
|
88
95
|
throw new Error(`Download failed: HTTP ${response.status}${text ? ` — ${text}` : ""}`);
|
|
@@ -98,10 +105,29 @@ export async function installProfileFromRegistry(input, options = {}) {
|
|
|
98
105
|
as: input.as,
|
|
99
106
|
credentials: input.credentials,
|
|
100
107
|
}, options);
|
|
108
|
+
await writeProfileRegistryLink(result.name, {
|
|
109
|
+
origin: "installed",
|
|
110
|
+
slug,
|
|
111
|
+
version: descriptor.version,
|
|
112
|
+
}, options);
|
|
101
113
|
return { ...result, version: descriptor.version, sourceKind: descriptor.source_kind };
|
|
102
114
|
}
|
|
103
115
|
finally {
|
|
104
116
|
await rm(dir, { recursive: true, force: true }).catch(() => { });
|
|
105
117
|
}
|
|
106
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Hosted profiles come back with a path relative to the API root
|
|
121
|
+
* (`/profiles/<slug>/download`) — correct REST, and what lets one API serve
|
|
122
|
+
* both api.brainctl.net and api.nomoreide.com. Node's fetch rejects a relative
|
|
123
|
+
* URL outright ("Failed to parse URL"), so join it onto the base we called.
|
|
124
|
+
*
|
|
125
|
+
* GitHub-sourced profiles return an absolute archive URL on another host
|
|
126
|
+
* entirely, which must pass through untouched.
|
|
127
|
+
*/
|
|
128
|
+
function resolveDownloadUrl(downloadUrl, apiBaseUrl) {
|
|
129
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(downloadUrl))
|
|
130
|
+
return downloadUrl;
|
|
131
|
+
return `${apiBaseUrl.replace(/\/$/, "")}/${downloadUrl.replace(/^\//, "")}`;
|
|
132
|
+
}
|
|
107
133
|
//# sourceMappingURL=registry-transfer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-transfer.js","sourceRoot":"","sources":["../../../src/core/agent-profiles/registry-transfer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAuB,MAAM,sBAAsB,CAAC;AACjF,OAAO,
|
|
1
|
+
{"version":3,"file":"registry-transfer.js","sourceRoot":"","sources":["../../../src/core/agent-profiles/registry-transfer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type AgentMcpEntry, type AgentName, type RemoteMcpEntry } from "../agent-env/index.js";
|
|
2
2
|
import { type Profile, type ProfileMcp, type ProfileSummary } from "./types.js";
|
|
3
|
+
import { type ProfileRegistryDiff, type ProfileRegistryLink } from "./publication.js";
|
|
3
4
|
export interface ProfileStoreOptions {
|
|
4
5
|
/** Injectable for tmpdir tests, like the agent-env readers. */
|
|
5
6
|
homeDir?: string;
|
|
@@ -18,6 +19,13 @@ export declare function createProfile(input: {
|
|
|
18
19
|
export declare function updateProfile(name: string, patch: Partial<Pick<Profile, "description" | "mcps" | "skills" | "plugins">>, options?: ProfileStoreOptions): Promise<Profile>;
|
|
19
20
|
export declare function deleteProfile(name: string, options?: ProfileStoreOptions): Promise<void>;
|
|
20
21
|
export declare function writeProfile(profile: Profile, options?: ProfileStoreOptions): Promise<void>;
|
|
22
|
+
export declare function readProfileRegistryLink(name: string, options?: ProfileStoreOptions): Promise<ProfileRegistryLink | null>;
|
|
23
|
+
export declare function writeProfileRegistryLink(name: string, input: Omit<ProfileRegistryLink, "schemaVersion" | "linkedAt" | "baseline">, options?: ProfileStoreOptions): Promise<ProfileRegistryLink>;
|
|
24
|
+
export declare function clearProfileRegistryLink(name: string, options?: ProfileStoreOptions): Promise<void>;
|
|
25
|
+
export declare function getProfileRegistryDiff(name: string, options?: ProfileStoreOptions): Promise<{
|
|
26
|
+
link: ProfileRegistryLink;
|
|
27
|
+
diff: ProfileRegistryDiff;
|
|
28
|
+
} | null>;
|
|
21
29
|
/**
|
|
22
30
|
* Capture an agent's live config (MCPs + local skills) into a new profile.
|
|
23
31
|
* Raw credential values are kept — the profile lives in the user's own config
|
|
@@ -29,6 +37,23 @@ export declare function snapshotProfileFromAgent(input: {
|
|
|
29
37
|
description?: string;
|
|
30
38
|
cwd: string;
|
|
31
39
|
}, options?: ProfileStoreOptions): Promise<Profile>;
|
|
40
|
+
/**
|
|
41
|
+
* Rebuild an existing profile from an agent's current environment. The new
|
|
42
|
+
* bundle is prepared in a sibling profile first, then swapped into place so a
|
|
43
|
+
* failed read/copy never destroys the last good profile.
|
|
44
|
+
*/
|
|
45
|
+
export declare function refreshProfileFromAgent(input: {
|
|
46
|
+
agent: AgentName;
|
|
47
|
+
name: string;
|
|
48
|
+
cwd: string;
|
|
49
|
+
}, options?: ProfileStoreOptions): Promise<Profile>;
|
|
50
|
+
/**
|
|
51
|
+
* Copy portable profile content as real files and directories. Agent skill
|
|
52
|
+
* directories are often links into a shared skill checkout; preserving those
|
|
53
|
+
* links would make the profile machine-specific and produce archives that the
|
|
54
|
+
* importer correctly refuses to extract.
|
|
55
|
+
*/
|
|
56
|
+
export declare function copyProfileAssetTree(source: string, target: string): Promise<void>;
|
|
32
57
|
export declare function toLocalProfileMcp(entry: AgentMcpEntry): ProfileMcp;
|
|
33
58
|
export declare function toRemoteProfileMcp(entry: RemoteMcpEntry): ProfileMcp;
|
|
34
59
|
/** Copy one bundled skill dir between profiles (no-op if the source has no files). */
|
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
* an agent goes through `apply.ts` (which uses the write-guarded
|
|
6
6
|
* agent-env-writers layer).
|
|
7
7
|
*/
|
|
8
|
-
import { cp, mkdir, readdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
9
|
-
import { createHash } from "node:crypto";
|
|
8
|
+
import { cp, lstat, mkdir, readdir, readFile, realpath, rename, rm, stat, writeFile, } from "node:fs/promises";
|
|
9
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
import { readAllAgentConfigs, } from "../agent-env/index.js";
|
|
13
13
|
import { PROFILE_NAME_PATTERN, profileSchema, } from "./types.js";
|
|
14
14
|
import { pluginBundleDigest } from "./plugin-bundle.js";
|
|
15
|
+
import { createProfileRegistrySnapshot, diffProfileRegistrySnapshots, profileRegistryLinkSchema, } from "./publication.js";
|
|
15
16
|
export function profilesRoot(options = {}) {
|
|
16
17
|
const home = options.homeDir ?? homedir();
|
|
17
18
|
return path.join(home, ".config", "nomoreide", "agent-profiles");
|
|
@@ -22,6 +23,9 @@ export function profileDir(name, options = {}) {
|
|
|
22
23
|
function profileFile(name, options = {}) {
|
|
23
24
|
return path.join(profileDir(name, options), "profile.json");
|
|
24
25
|
}
|
|
26
|
+
function profileRegistryFile(name, options = {}) {
|
|
27
|
+
return path.join(profileDir(name, options), "registry.json");
|
|
28
|
+
}
|
|
25
29
|
export function profileSkillsDir(name, options = {}) {
|
|
26
30
|
return path.join(profileDir(name, options), "skills");
|
|
27
31
|
}
|
|
@@ -52,6 +56,7 @@ export async function listProfiles(options = {}) {
|
|
|
52
56
|
const filePath = profileFile(entry.name, options);
|
|
53
57
|
const info = await stat(filePath);
|
|
54
58
|
const profile = await getProfile(entry.name, options);
|
|
59
|
+
const registry = await profileRegistrySummary(entry.name, profile, options);
|
|
55
60
|
summaries.push({
|
|
56
61
|
name: profile.name,
|
|
57
62
|
description: profile.description,
|
|
@@ -60,6 +65,7 @@ export async function listProfiles(options = {}) {
|
|
|
60
65
|
skillCount: profile.skills.length,
|
|
61
66
|
pluginCount: profile.plugins.length,
|
|
62
67
|
updatedAt: info.mtime.toISOString(),
|
|
68
|
+
...(registry ? { registry } : {}),
|
|
63
69
|
mtimeMs: info.mtimeMs,
|
|
64
70
|
});
|
|
65
71
|
}
|
|
@@ -144,6 +150,57 @@ export async function writeProfile(profile, options = {}) {
|
|
|
144
150
|
await writeFile(tmpPath, `${JSON.stringify(profile, null, 2)}\n`, "utf8");
|
|
145
151
|
await rename(tmpPath, filePath);
|
|
146
152
|
}
|
|
153
|
+
export async function readProfileRegistryLink(name, options = {}) {
|
|
154
|
+
try {
|
|
155
|
+
const parsed = profileRegistryLinkSchema.safeParse(JSON.parse(await readFile(profileRegistryFile(name, options), "utf8")));
|
|
156
|
+
return parsed.success ? parsed.data : null;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
export async function writeProfileRegistryLink(name, input, options = {}) {
|
|
163
|
+
const profile = await getProfile(name, options);
|
|
164
|
+
const link = {
|
|
165
|
+
schemaVersion: 1,
|
|
166
|
+
...input,
|
|
167
|
+
linkedAt: new Date().toISOString(),
|
|
168
|
+
baseline: await createProfileRegistrySnapshot(profile, profileDir(name, options)),
|
|
169
|
+
};
|
|
170
|
+
await writeProfileRegistryLinkData(name, link, options);
|
|
171
|
+
return link;
|
|
172
|
+
}
|
|
173
|
+
export async function clearProfileRegistryLink(name, options = {}) {
|
|
174
|
+
await rm(profileRegistryFile(name, options), { force: true });
|
|
175
|
+
}
|
|
176
|
+
export async function getProfileRegistryDiff(name, options = {}) {
|
|
177
|
+
const link = await readProfileRegistryLink(name, options);
|
|
178
|
+
if (!link)
|
|
179
|
+
return null;
|
|
180
|
+
const profile = await getProfile(name, options);
|
|
181
|
+
const current = await createProfileRegistrySnapshot(profile, profileDir(name, options));
|
|
182
|
+
return { link, diff: diffProfileRegistrySnapshots(link.baseline, current) };
|
|
183
|
+
}
|
|
184
|
+
async function profileRegistrySummary(name, profile, options) {
|
|
185
|
+
const link = await readProfileRegistryLink(name, options);
|
|
186
|
+
if (!link)
|
|
187
|
+
return undefined;
|
|
188
|
+
const current = await createProfileRegistrySnapshot(profile, profileDir(name, options));
|
|
189
|
+
return {
|
|
190
|
+
origin: link.origin,
|
|
191
|
+
slug: link.slug,
|
|
192
|
+
version: link.version,
|
|
193
|
+
linkedAt: link.linkedAt,
|
|
194
|
+
hasLocalChanges: current.contentDigest !== link.baseline.contentDigest,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async function writeProfileRegistryLinkData(name, link, options) {
|
|
198
|
+
const filePath = profileRegistryFile(name, options);
|
|
199
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
200
|
+
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
201
|
+
await writeFile(tmpPath, `${JSON.stringify(link, null, 2)}\n`, "utf8");
|
|
202
|
+
await rename(tmpPath, filePath);
|
|
203
|
+
}
|
|
147
204
|
/**
|
|
148
205
|
* Capture an agent's live config (MCPs + local skills) into a new profile.
|
|
149
206
|
* Raw credential values are kept — the profile lives in the user's own config
|
|
@@ -187,7 +244,7 @@ export async function snapshotProfileFromAgent(input, options = {}) {
|
|
|
187
244
|
try {
|
|
188
245
|
const target = path.join(profilePluginsDir(name, options), bundleKey);
|
|
189
246
|
await mkdir(path.dirname(target), { recursive: true });
|
|
190
|
-
await
|
|
247
|
+
await copyProfileAssetTree(plugin.installPath, target);
|
|
191
248
|
const digest = await pluginBundleDigest(target);
|
|
192
249
|
profile.plugins.push(toProfilePlugin(input.agent, plugin, bundleKey, digest));
|
|
193
250
|
for (const skill of [...(plugin.pluginSkills ?? []), ...(plugin.pluginCommands ?? [])]) {
|
|
@@ -212,7 +269,7 @@ export async function snapshotProfileFromAgent(input, options = {}) {
|
|
|
212
269
|
try {
|
|
213
270
|
const target = path.join(profileSkillsDir(name, options), path.basename(skill.name));
|
|
214
271
|
await mkdir(path.dirname(target), { recursive: true });
|
|
215
|
-
await
|
|
272
|
+
await copyProfileAssetTree(skill.installPath, target);
|
|
216
273
|
profile.skills.push({ name: skill.name });
|
|
217
274
|
}
|
|
218
275
|
catch {
|
|
@@ -222,6 +279,56 @@ export async function snapshotProfileFromAgent(input, options = {}) {
|
|
|
222
279
|
await writeProfile(profile, options);
|
|
223
280
|
return profile;
|
|
224
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Rebuild an existing profile from an agent's current environment. The new
|
|
284
|
+
* bundle is prepared in a sibling profile first, then swapped into place so a
|
|
285
|
+
* failed read/copy never destroys the last good profile.
|
|
286
|
+
*/
|
|
287
|
+
export async function refreshProfileFromAgent(input, options = {}) {
|
|
288
|
+
const name = assertValidProfileName(input.name);
|
|
289
|
+
const existing = await getProfile(name, options);
|
|
290
|
+
const registryLink = await readProfileRegistryLink(name, options);
|
|
291
|
+
const token = randomUUID();
|
|
292
|
+
const stagingName = `${name}.refresh-${token}`;
|
|
293
|
+
const currentDir = profileDir(name, options);
|
|
294
|
+
const stagingDir = profileDir(stagingName, options);
|
|
295
|
+
const backupDir = path.join(path.dirname(profilesRoot(options)), `.profile-backup-${token}`);
|
|
296
|
+
let staged = false;
|
|
297
|
+
let originalMoved = false;
|
|
298
|
+
try {
|
|
299
|
+
const captured = await snapshotProfileFromAgent({
|
|
300
|
+
agent: input.agent,
|
|
301
|
+
name: stagingName,
|
|
302
|
+
cwd: input.cwd,
|
|
303
|
+
description: existing.description,
|
|
304
|
+
}, options);
|
|
305
|
+
staged = true;
|
|
306
|
+
await writeFile(path.join(stagingDir, "profile.json"), `${JSON.stringify({ ...captured, name }, null, 2)}\n`, "utf8");
|
|
307
|
+
await rename(currentDir, backupDir);
|
|
308
|
+
originalMoved = true;
|
|
309
|
+
try {
|
|
310
|
+
await rename(stagingDir, currentDir);
|
|
311
|
+
staged = false;
|
|
312
|
+
if (registryLink) {
|
|
313
|
+
await writeProfileRegistryLinkData(name, registryLink, options);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
await rename(backupDir, currentDir);
|
|
318
|
+
originalMoved = false;
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
await rm(backupDir, { recursive: true, force: true });
|
|
322
|
+
originalMoved = false;
|
|
323
|
+
return getProfile(name, options);
|
|
324
|
+
}
|
|
325
|
+
finally {
|
|
326
|
+
if (staged)
|
|
327
|
+
await rm(stagingDir, { recursive: true, force: true });
|
|
328
|
+
if (originalMoved)
|
|
329
|
+
await rm(backupDir, { recursive: true, force: true });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
225
332
|
function pluginBundleKey(agent, name, source) {
|
|
226
333
|
const slug = name.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "plugin";
|
|
227
334
|
const digest = createHash("sha256")
|
|
@@ -250,6 +357,79 @@ function profileAssetFilter(source) {
|
|
|
250
357
|
const base = path.basename(source);
|
|
251
358
|
return base !== ".git" && base !== ".DS_Store";
|
|
252
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Copy portable profile content as real files and directories. Agent skill
|
|
362
|
+
* directories are often links into a shared skill checkout; preserving those
|
|
363
|
+
* links would make the profile machine-specific and produce archives that the
|
|
364
|
+
* importer correctly refuses to extract.
|
|
365
|
+
*/
|
|
366
|
+
export async function copyProfileAssetTree(source, target) {
|
|
367
|
+
try {
|
|
368
|
+
await validateProfileAssetTree(source);
|
|
369
|
+
await cp(source, target, {
|
|
370
|
+
recursive: true,
|
|
371
|
+
dereference: true,
|
|
372
|
+
filter: profileAssetFilter,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
await rm(target, { recursive: true, force: true });
|
|
377
|
+
throw error;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async function validateProfileAssetTree(source) {
|
|
381
|
+
const root = await realpath(source);
|
|
382
|
+
async function visit(directory, relativeDirectory, ancestors) {
|
|
383
|
+
const resolvedDirectory = await realpath(directory);
|
|
384
|
+
if (ancestors.has(resolvedDirectory)) {
|
|
385
|
+
throw new Error(`Profile asset contains a circular link: ${relativeDirectory || "."}`);
|
|
386
|
+
}
|
|
387
|
+
const nextAncestors = new Set(ancestors).add(resolvedDirectory);
|
|
388
|
+
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
389
|
+
if (!profileAssetFilter(entry.name))
|
|
390
|
+
continue;
|
|
391
|
+
const entryPath = path.join(directory, entry.name);
|
|
392
|
+
const relative = relativeDirectory
|
|
393
|
+
? path.join(relativeDirectory, entry.name)
|
|
394
|
+
: entry.name;
|
|
395
|
+
const info = await lstat(entryPath);
|
|
396
|
+
if (info.isSymbolicLink()) {
|
|
397
|
+
const resolved = await realpath(entryPath);
|
|
398
|
+
const targetInfo = await stat(resolved);
|
|
399
|
+
if (targetInfo.isDirectory()) {
|
|
400
|
+
if (!pathIsWithin(root, resolved)) {
|
|
401
|
+
throw new Error(`Profile asset link escapes its bundle: ${relative}`);
|
|
402
|
+
}
|
|
403
|
+
await visit(resolved, relative, nextAncestors);
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (!targetInfo.isFile()) {
|
|
407
|
+
throw new Error(`Profile asset contains an unsupported link: ${relative}`);
|
|
408
|
+
}
|
|
409
|
+
if (!pathIsWithin(root, resolved) && !isExternalSkillDocument(relative, resolved)) {
|
|
410
|
+
throw new Error(`Profile asset link escapes its bundle: ${relative}`);
|
|
411
|
+
}
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (info.isDirectory()) {
|
|
415
|
+
await visit(entryPath, relative, nextAncestors);
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (!info.isFile()) {
|
|
419
|
+
throw new Error(`Profile asset contains an unsupported file: ${relative}`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
await visit(root, "", new Set());
|
|
424
|
+
}
|
|
425
|
+
function pathIsWithin(root, candidate) {
|
|
426
|
+
const relative = path.relative(root, candidate);
|
|
427
|
+
return (relative === "" ||
|
|
428
|
+
(!path.isAbsolute(relative) && !relative.startsWith(`..${path.sep}`) && relative !== ".."));
|
|
429
|
+
}
|
|
430
|
+
function isExternalSkillDocument(relative, resolved) {
|
|
431
|
+
return relative === "SKILL.md" && path.basename(resolved) === "SKILL.md";
|
|
432
|
+
}
|
|
253
433
|
export function toLocalProfileMcp(entry) {
|
|
254
434
|
return {
|
|
255
435
|
kind: "local",
|
|
@@ -275,7 +455,7 @@ export async function copySkillBetweenProfiles(from, to, skillName, options = {}
|
|
|
275
455
|
const targetDir = path.join(profileSkillsDir(to, options), path.basename(skillName));
|
|
276
456
|
await mkdir(path.dirname(targetDir), { recursive: true });
|
|
277
457
|
await rm(targetDir, { recursive: true, force: true });
|
|
278
|
-
await
|
|
458
|
+
await copyProfileAssetTree(sourceDir, targetDir);
|
|
279
459
|
}
|
|
280
460
|
export async function copyPluginBetweenProfiles(from, to, bundleKey, options = {}) {
|
|
281
461
|
const safeKey = path.basename(bundleKey);
|
|
@@ -285,7 +465,7 @@ export async function copyPluginBetweenProfiles(from, to, bundleKey, options = {
|
|
|
285
465
|
const targetDir = path.join(profilePluginsDir(to, options), safeKey);
|
|
286
466
|
await mkdir(path.dirname(targetDir), { recursive: true });
|
|
287
467
|
await rm(targetDir, { recursive: true, force: true });
|
|
288
|
-
await
|
|
468
|
+
await copyProfileAssetTree(sourceDir, targetDir);
|
|
289
469
|
}
|
|
290
470
|
export async function pathExists(target) {
|
|
291
471
|
try {
|