nomoreide 0.1.70 → 0.1.72

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 (53) hide show
  1. package/dist/core/agent-profiles/apply.d.ts +36 -0
  2. package/dist/core/agent-profiles/apply.js +160 -0
  3. package/dist/core/agent-profiles/apply.js.map +1 -0
  4. package/dist/core/agent-profiles/credentials.d.ts +26 -0
  5. package/dist/core/agent-profiles/credentials.js +151 -0
  6. package/dist/core/agent-profiles/credentials.js.map +1 -0
  7. package/dist/core/agent-profiles/index.d.ts +14 -0
  8. package/dist/core/agent-profiles/index.js +15 -0
  9. package/dist/core/agent-profiles/index.js.map +1 -0
  10. package/dist/core/agent-profiles/registry-auth.d.ts +25 -0
  11. package/dist/core/agent-profiles/registry-auth.js +78 -0
  12. package/dist/core/agent-profiles/registry-auth.js.map +1 -0
  13. package/dist/core/agent-profiles/registry-client.d.ts +65 -0
  14. package/dist/core/agent-profiles/registry-client.js +97 -0
  15. package/dist/core/agent-profiles/registry-client.js.map +1 -0
  16. package/dist/core/agent-profiles/registry-config.d.ts +48 -0
  17. package/dist/core/agent-profiles/registry-config.js +164 -0
  18. package/dist/core/agent-profiles/registry-config.js.map +1 -0
  19. package/dist/core/agent-profiles/registry-transfer.d.ts +42 -0
  20. package/dist/core/agent-profiles/registry-transfer.js +102 -0
  21. package/dist/core/agent-profiles/registry-transfer.js.map +1 -0
  22. package/dist/core/agent-profiles/store.d.ts +35 -0
  23. package/dist/core/agent-profiles/store.js +210 -0
  24. package/dist/core/agent-profiles/store.js.map +1 -0
  25. package/dist/core/agent-profiles/transfer.d.ts +26 -0
  26. package/dist/core/agent-profiles/transfer.js +141 -0
  27. package/dist/core/agent-profiles/transfer.js.map +1 -0
  28. package/dist/core/agent-profiles/types.d.ts +250 -0
  29. package/dist/core/agent-profiles/types.js +63 -0
  30. package/dist/core/agent-profiles/types.js.map +1 -0
  31. package/dist/mcp/tools/agent-profiles.d.ts +9 -0
  32. package/dist/mcp/tools/agent-profiles.js +165 -0
  33. package/dist/mcp/tools/agent-profiles.js.map +1 -0
  34. package/dist/mcp/tools/agent-registry.d.ts +9 -0
  35. package/dist/mcp/tools/agent-registry.js +81 -0
  36. package/dist/mcp/tools/agent-registry.js.map +1 -0
  37. package/dist/mcp/tools/index.d.ts +1 -1
  38. package/dist/mcp/tools/index.js +6 -0
  39. package/dist/mcp/tools/index.js.map +1 -1
  40. package/dist/web/client/assets/{code-editor-tF2NdMJV.js → code-editor-fZ2dpXfw.js} +1 -1
  41. package/dist/web/client/assets/{index-CQmdoyuK.js → index-CraqLFuO.js} +140 -140
  42. package/dist/web/client/assets/index-n7aEcfkd.css +1 -0
  43. package/dist/web/client/index.html +2 -2
  44. package/dist/web/routes/agent-profile-routes.d.ts +8 -0
  45. package/dist/web/routes/agent-profile-routes.js +180 -0
  46. package/dist/web/routes/agent-profile-routes.js.map +1 -0
  47. package/dist/web/routes/agent-registry-routes.d.ts +2 -0
  48. package/dist/web/routes/agent-registry-routes.js +295 -0
  49. package/dist/web/routes/agent-registry-routes.js.map +1 -0
  50. package/dist/web/routes/index.js +6 -0
  51. package/dist/web/routes/index.js.map +1 -1
  52. package/package.json +1 -1
  53. package/dist/web/client/assets/index-C7lI87cF.css +0 -1
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Profile storage: `<home>/.config/nomoreide/agent-profiles/<name>/` holding a
3
+ * Zod-validated `profile.json` plus bundled skill directories under `skills/`.
4
+ * Writes here only touch nomoreide's own config area — applying a profile to
5
+ * an agent goes through `apply.ts` (which uses the write-guarded
6
+ * agent-env-writers layer).
7
+ */
8
+ import { cp, mkdir, readdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
9
+ import { homedir } from "node:os";
10
+ import path from "node:path";
11
+ import { readAllAgentConfigs, } from "../agent-env/index.js";
12
+ import { PROFILE_NAME_PATTERN, profileSchema, } from "./types.js";
13
+ export function profilesRoot(options = {}) {
14
+ const home = options.homeDir ?? homedir();
15
+ return path.join(home, ".config", "nomoreide", "agent-profiles");
16
+ }
17
+ export function profileDir(name, options = {}) {
18
+ return path.join(profilesRoot(options), path.basename(name));
19
+ }
20
+ function profileFile(name, options = {}) {
21
+ return path.join(profileDir(name, options), "profile.json");
22
+ }
23
+ export function profileSkillsDir(name, options = {}) {
24
+ return path.join(profileDir(name, options), "skills");
25
+ }
26
+ export function assertValidProfileName(name) {
27
+ const trimmed = name.trim();
28
+ if (!PROFILE_NAME_PATTERN.test(trimmed)) {
29
+ throw new Error(`Invalid profile name "${trimmed}". Use letters, numbers, ".", "_", or "-".`);
30
+ }
31
+ return trimmed;
32
+ }
33
+ export async function listProfiles(options = {}) {
34
+ const root = profilesRoot(options);
35
+ const summaries = [];
36
+ let entries;
37
+ try {
38
+ entries = await readdir(root, { withFileTypes: true });
39
+ }
40
+ catch {
41
+ return []; // no profiles yet
42
+ }
43
+ for (const entry of entries) {
44
+ if (!entry.isDirectory())
45
+ continue;
46
+ try {
47
+ const filePath = profileFile(entry.name, options);
48
+ const info = await stat(filePath);
49
+ const profile = await getProfile(entry.name, options);
50
+ summaries.push({
51
+ name: profile.name,
52
+ description: profile.description,
53
+ mcpCount: Object.keys(profile.mcps).length,
54
+ skillCount: profile.skills.length,
55
+ updatedAt: info.mtime.toISOString(),
56
+ mtimeMs: info.mtimeMs,
57
+ });
58
+ }
59
+ catch {
60
+ // not a profile folder (or corrupt) — skip it
61
+ }
62
+ }
63
+ return summaries
64
+ .sort((left, right) => right.mtimeMs - left.mtimeMs || left.name.localeCompare(right.name))
65
+ .map(({ mtimeMs: _mtimeMs, ...summary }) => summary);
66
+ }
67
+ export async function getProfile(name, options = {}) {
68
+ const filePath = profileFile(name, options);
69
+ let source;
70
+ try {
71
+ source = await readFile(filePath, "utf8");
72
+ }
73
+ catch {
74
+ throw new Error(`Profile "${name}" not found.`);
75
+ }
76
+ const parsed = profileSchema.safeParse(JSON.parse(source));
77
+ if (!parsed.success) {
78
+ throw new Error(`Profile "${name}" has an invalid profile.json.`);
79
+ }
80
+ return parsed.data;
81
+ }
82
+ export async function createProfile(input, options = {}) {
83
+ const name = assertValidProfileName(input.name);
84
+ if (await pathExists(profileFile(name, options))) {
85
+ throw new Error(`Profile "${name}" already exists.`);
86
+ }
87
+ const profile = {
88
+ name,
89
+ ...(input.description ? { description: input.description } : {}),
90
+ mcps: {},
91
+ skills: [],
92
+ };
93
+ await writeProfile(profile, options);
94
+ return profile;
95
+ }
96
+ export async function updateProfile(name, patch, options = {}) {
97
+ const existing = await getProfile(name, options);
98
+ const next = profileSchema.parse({ ...existing, ...patch, name: existing.name });
99
+ // Drop bundled skill dirs that are no longer referenced.
100
+ if (patch.skills) {
101
+ const kept = new Set(next.skills.map((skill) => skill.name));
102
+ for (const skill of existing.skills) {
103
+ if (!kept.has(skill.name)) {
104
+ await rm(path.join(profileSkillsDir(name, options), path.basename(skill.name)), {
105
+ recursive: true,
106
+ force: true,
107
+ });
108
+ }
109
+ }
110
+ }
111
+ await writeProfile(next, options);
112
+ return next;
113
+ }
114
+ export async function deleteProfile(name, options = {}) {
115
+ if (!(await pathExists(profileFile(name, options)))) {
116
+ throw new Error(`Profile "${name}" not found.`);
117
+ }
118
+ await rm(profileDir(name, options), { recursive: true, force: true });
119
+ }
120
+ export async function writeProfile(profile, options = {}) {
121
+ const folder = profileDir(profile.name, options);
122
+ await mkdir(folder, { recursive: true });
123
+ const filePath = profileFile(profile.name, options);
124
+ const tmpPath = `${filePath}.tmp.${Date.now()}`;
125
+ await writeFile(tmpPath, JSON.stringify(profile, null, 2) + "\n", "utf8");
126
+ await rename(tmpPath, filePath);
127
+ }
128
+ /**
129
+ * Capture an agent's live config (MCPs + local skills) into a new profile.
130
+ * Raw credential values are kept — the profile lives in the user's own config
131
+ * dir; redaction happens at export time.
132
+ */
133
+ export async function snapshotProfileFromAgent(input, options = {}) {
134
+ const name = assertValidProfileName(input.name);
135
+ if (await pathExists(profileFile(name, options))) {
136
+ throw new Error(`Profile "${name}" already exists.`);
137
+ }
138
+ const configs = await readAllAgentConfigs({ cwd: input.cwd, homeDir: options.homeDir });
139
+ const config = configs.find((candidate) => candidate.agent === input.agent);
140
+ if (!config?.exists && (config?.skills.length ?? 0) === 0) {
141
+ throw new Error(`Agent "${input.agent}" has no live config to snapshot.`);
142
+ }
143
+ const mcps = {};
144
+ for (const [key, entry] of Object.entries(config.mcpServers)) {
145
+ mcps[key] = toLocalProfileMcp(entry);
146
+ }
147
+ for (const [key, entry] of Object.entries(config.remoteMcpServers)) {
148
+ mcps[key] = toRemoteProfileMcp(entry);
149
+ }
150
+ const profile = {
151
+ name,
152
+ ...(input.description ? { description: input.description } : {}),
153
+ mcps,
154
+ skills: [],
155
+ };
156
+ // Bundle plain user-scope skills. Plugins are managed installs (excluded,
157
+ // same rule as ROR-61 staged writes); project skills belong to their repo.
158
+ for (const skill of config.skills) {
159
+ if (skill.kind === "plugin" || skill.scope !== "user" || !skill.installPath)
160
+ continue;
161
+ try {
162
+ const target = path.join(profileSkillsDir(name, options), path.basename(skill.name));
163
+ await mkdir(path.dirname(target), { recursive: true });
164
+ await cp(skill.installPath, target, { recursive: true });
165
+ profile.skills.push({ name: skill.name });
166
+ }
167
+ catch {
168
+ // unreadable skill dir — skip it rather than failing the snapshot
169
+ }
170
+ }
171
+ await writeProfile(profile, options);
172
+ return profile;
173
+ }
174
+ export function toLocalProfileMcp(entry) {
175
+ return {
176
+ kind: "local",
177
+ command: entry.command,
178
+ ...(entry.args ? { args: entry.args } : {}),
179
+ ...(entry.env ? { env: entry.env } : {}),
180
+ };
181
+ }
182
+ export function toRemoteProfileMcp(entry) {
183
+ return {
184
+ kind: "remote",
185
+ transport: entry.transport,
186
+ url: entry.url,
187
+ ...(entry.headers ? { headers: entry.headers } : {}),
188
+ ...(entry.env ? { env: entry.env } : {}),
189
+ };
190
+ }
191
+ /** Copy one bundled skill dir between profiles (no-op if the source has no files). */
192
+ export async function copySkillBetweenProfiles(from, to, skillName, options = {}) {
193
+ const sourceDir = path.join(profileSkillsDir(from, options), path.basename(skillName));
194
+ if (!(await pathExists(sourceDir)))
195
+ return;
196
+ const targetDir = path.join(profileSkillsDir(to, options), path.basename(skillName));
197
+ await mkdir(path.dirname(targetDir), { recursive: true });
198
+ await rm(targetDir, { recursive: true, force: true });
199
+ await cp(sourceDir, targetDir, { recursive: true });
200
+ }
201
+ export async function pathExists(target) {
202
+ try {
203
+ await stat(target);
204
+ return true;
205
+ }
206
+ catch {
207
+ return false;
208
+ }
209
+ }
210
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/core/agent-profiles/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { type ProfileStoreOptions } from "./store.js";
2
+ import { type CredentialSpec } from "./types.js";
3
+ export interface ExportResult {
4
+ archivePath: string;
5
+ /** Credentials that were redacted; the importer must supply these. */
6
+ credentials: CredentialSpec[];
7
+ }
8
+ export declare function exportProfile(input: {
9
+ name: string;
10
+ outputPath?: string;
11
+ cwd: string;
12
+ }, options?: ProfileStoreOptions): Promise<ExportResult>;
13
+ export interface ImportResult {
14
+ name: string;
15
+ mcpCount: number;
16
+ skillCount: number;
17
+ /** Credential keys the caller still has to fill in (placeholders kept). */
18
+ missingCredentials: CredentialSpec[];
19
+ }
20
+ export declare function importProfile(input: {
21
+ archivePath: string;
22
+ force?: boolean;
23
+ credentials?: Record<string, string>;
24
+ /** Override the imported profile's name (e.g. on collision). */
25
+ as?: string;
26
+ }, options?: ProfileStoreOptions): Promise<ImportResult>;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Portable profile archives (`.tar.gz`). Export redacts secret-looking env
3
+ * and header values into `${credentials.<key>}` placeholders — raw secrets
4
+ * never enter an archive. Import resolves placeholders from supplied
5
+ * credentials / the process environment and reports what's still missing.
6
+ *
7
+ * Archive layout: `manifest.json` + `profile.json` + `skills/<name>/…`.
8
+ * Tarballs are produced with the system `tar` (present on macOS, Linux, and
9
+ * Windows 10+), matching what brainctl shipped.
10
+ */
11
+ import { execFile } from "node:child_process";
12
+ import { cp, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
13
+ import { tmpdir } from "node:os";
14
+ import path from "node:path";
15
+ import { promisify } from "node:util";
16
+ import { findUnresolvedCredentialKeys, redactMcpCredentials, resolveMcpCredentials, } from "./credentials.js";
17
+ import { getProfile, pathExists, profileDir, profileSkillsDir, writeProfile, } from "./store.js";
18
+ import { profileManifestSchema, profileSchema, } from "./types.js";
19
+ const execFileAsync = promisify(execFile);
20
+ export async function exportProfile(input, options = {}) {
21
+ const profile = await getProfile(input.name, options);
22
+ const stagingDir = await mkdtemp(path.join(tmpdir(), "nomoreide-profile-pack-"));
23
+ try {
24
+ const credentials = new Map();
25
+ const redactedMcps = Object.fromEntries(Object.entries(profile.mcps).map(([key, config]) => {
26
+ const result = redactMcpCredentials(config);
27
+ for (const spec of result.credentials)
28
+ credentials.set(spec.key, spec);
29
+ return [key, result.redacted];
30
+ }));
31
+ const manifest = {
32
+ schemaVersion: 1,
33
+ profileName: profile.name,
34
+ createdBy: { tool: "nomoreide", version: await packageVersion() },
35
+ ...(credentials.size > 0 ? { credentials: Array.from(credentials.values()) } : {}),
36
+ };
37
+ await writeFile(path.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n", "utf8");
38
+ await writeFile(path.join(stagingDir, "profile.json"), JSON.stringify({ ...profile, mcps: redactedMcps }, null, 2) + "\n", "utf8");
39
+ for (const skill of profile.skills) {
40
+ const sourceDir = path.join(profileSkillsDir(input.name, options), path.basename(skill.name));
41
+ if (!(await pathExists(sourceDir)))
42
+ continue;
43
+ const target = path.join(stagingDir, "skills", path.basename(skill.name));
44
+ await mkdir(path.dirname(target), { recursive: true });
45
+ await cp(sourceDir, target, {
46
+ recursive: true,
47
+ filter: (src) => {
48
+ const base = path.basename(src);
49
+ return base !== ".git" && base !== ".DS_Store";
50
+ },
51
+ });
52
+ }
53
+ const archivePath = input.outputPath ?? path.join(input.cwd, `${profile.name}.tar.gz`);
54
+ await mkdir(path.dirname(archivePath), { recursive: true });
55
+ await execFileAsync("tar", ["-czf", archivePath, "-C", stagingDir, "."]);
56
+ return { archivePath, credentials: Array.from(credentials.values()) };
57
+ }
58
+ finally {
59
+ await rm(stagingDir, { recursive: true, force: true });
60
+ }
61
+ }
62
+ export async function importProfile(input, options = {}) {
63
+ if (!(await pathExists(input.archivePath))) {
64
+ throw new Error(`Archive not found: ${input.archivePath}`);
65
+ }
66
+ const extractDir = await mkdtemp(path.join(tmpdir(), "nomoreide-profile-import-"));
67
+ try {
68
+ try {
69
+ await execFileAsync("tar", ["-xzf", input.archivePath, "-C", extractDir]);
70
+ }
71
+ catch {
72
+ throw new Error("Could not extract the archive — is it a .tar.gz profile export?");
73
+ }
74
+ const manifest = profileManifestSchema.safeParse(JSON.parse(await readFile(path.join(extractDir, "manifest.json"), "utf8")));
75
+ if (!manifest.success) {
76
+ throw new Error("Archive has a missing or invalid manifest.json — not a nomoreide profile archive.");
77
+ }
78
+ const parsedProfile = profileSchema.safeParse(JSON.parse(await readFile(path.join(extractDir, "profile.json"), "utf8")));
79
+ if (!parsedProfile.success) {
80
+ throw new Error("Archive has a missing or invalid profile.json.");
81
+ }
82
+ const name = input.as ?? parsedProfile.data.name;
83
+ const profile = { ...parsedProfile.data, name };
84
+ if (!input.force && (await pathExists(path.join(profileDir(name, options), "profile.json")))) {
85
+ throw new Error(`Profile "${name}" already exists. Re-import with force to overwrite.`);
86
+ }
87
+ const missing = new Map();
88
+ profile.mcps = Object.fromEntries(Object.entries(profile.mcps).map(([key, config]) => {
89
+ const result = resolveMcpCredentials(config, {
90
+ credentials: input.credentials,
91
+ credentialSpecs: manifest.data.credentials,
92
+ environment: process.env,
93
+ });
94
+ for (const spec of result.missing)
95
+ missing.set(spec.key, spec);
96
+ return [key, result.resolved];
97
+ }));
98
+ await writeProfile(profile, options);
99
+ let skillCount = 0;
100
+ for (const skill of profile.skills) {
101
+ const sourceDir = path.join(extractDir, "skills", path.basename(skill.name));
102
+ if (!(await pathExists(sourceDir)))
103
+ continue;
104
+ const target = path.join(profileSkillsDir(name, options), path.basename(skill.name));
105
+ await mkdir(path.dirname(target), { recursive: true });
106
+ await rm(target, { recursive: true, force: true });
107
+ await cp(sourceDir, target, { recursive: true });
108
+ skillCount += 1;
109
+ }
110
+ // Anything a spec listed but resolution didn't reach (or that remains as
111
+ // a placeholder in the stored profile) counts as missing.
112
+ for (const key of findUnresolvedCredentialKeys(profile.mcps)) {
113
+ if (!missing.has(key)) {
114
+ missing.set(key, { key, required: true, description: `Credential ${key} is required` });
115
+ }
116
+ }
117
+ return {
118
+ name,
119
+ mcpCount: Object.keys(profile.mcps).length,
120
+ skillCount,
121
+ missingCredentials: Array.from(missing.values()),
122
+ };
123
+ }
124
+ finally {
125
+ await rm(extractDir, { recursive: true, force: true });
126
+ }
127
+ }
128
+ let cachedVersion;
129
+ async function packageVersion() {
130
+ if (!cachedVersion) {
131
+ try {
132
+ const pkg = JSON.parse(await readFile(new URL("../../../package.json", import.meta.url), "utf8"));
133
+ cachedVersion = pkg.version ?? "0.0.0";
134
+ }
135
+ catch {
136
+ cachedVersion = "0.0.0";
137
+ }
138
+ }
139
+ return cachedVersion;
140
+ }
141
+ //# sourceMappingURL=transfer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transfer.js","sourceRoot":"","sources":["../../../src/core/agent-profiles/transfer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Agent Profiles (ROR-62) — named bundles of MCP servers + skills that can be
3
+ * saved, applied to agents, and shared as portable `.tar.gz` archives.
4
+ *
5
+ * Profiles use nomoreide's own vocabulary (the same local/remote MCP shapes
6
+ * the agent-env readers emit) and are stored as Zod-validated JSON under
7
+ * `~/.config/nomoreide/agent-profiles/<name>/`. This deliberately does NOT
8
+ * read brainctl's YAML profiles — brainctl users migrate by re-snapshotting
9
+ * their live agent configs (one call), which recreates the profile here.
10
+ */
11
+ import { z } from "zod";
12
+ export declare const profileLocalMcpSchema: z.ZodObject<{
13
+ kind: z.ZodLiteral<"local">;
14
+ command: z.ZodString;
15
+ args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
16
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
17
+ }, "strip", z.ZodTypeAny, {
18
+ command: string;
19
+ kind: "local";
20
+ env?: Record<string, string> | undefined;
21
+ args?: string[] | undefined;
22
+ }, {
23
+ command: string;
24
+ kind: "local";
25
+ env?: Record<string, string> | undefined;
26
+ args?: string[] | undefined;
27
+ }>;
28
+ export declare const profileRemoteMcpSchema: z.ZodObject<{
29
+ kind: z.ZodLiteral<"remote">;
30
+ transport: z.ZodEnum<["http", "sse"]>;
31
+ url: z.ZodString;
32
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
33
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
34
+ }, "strip", z.ZodTypeAny, {
35
+ kind: "remote";
36
+ url: string;
37
+ transport: "http" | "sse";
38
+ env?: Record<string, string> | undefined;
39
+ headers?: Record<string, string> | undefined;
40
+ }, {
41
+ kind: "remote";
42
+ url: string;
43
+ transport: "http" | "sse";
44
+ env?: Record<string, string> | undefined;
45
+ headers?: Record<string, string> | undefined;
46
+ }>;
47
+ export declare const profileMcpSchema: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
48
+ kind: z.ZodLiteral<"local">;
49
+ command: z.ZodString;
50
+ args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
51
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
52
+ }, "strip", z.ZodTypeAny, {
53
+ command: string;
54
+ kind: "local";
55
+ env?: Record<string, string> | undefined;
56
+ args?: string[] | undefined;
57
+ }, {
58
+ command: string;
59
+ kind: "local";
60
+ env?: Record<string, string> | undefined;
61
+ args?: string[] | undefined;
62
+ }>, z.ZodObject<{
63
+ kind: z.ZodLiteral<"remote">;
64
+ transport: z.ZodEnum<["http", "sse"]>;
65
+ url: z.ZodString;
66
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
67
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
68
+ }, "strip", z.ZodTypeAny, {
69
+ kind: "remote";
70
+ url: string;
71
+ transport: "http" | "sse";
72
+ env?: Record<string, string> | undefined;
73
+ headers?: Record<string, string> | undefined;
74
+ }, {
75
+ kind: "remote";
76
+ url: string;
77
+ transport: "http" | "sse";
78
+ env?: Record<string, string> | undefined;
79
+ headers?: Record<string, string> | undefined;
80
+ }>]>;
81
+ export type ProfileLocalMcp = z.infer<typeof profileLocalMcpSchema>;
82
+ export type ProfileRemoteMcp = z.infer<typeof profileRemoteMcpSchema>;
83
+ export type ProfileMcp = z.infer<typeof profileMcpSchema>;
84
+ /** A skill bundled with the profile; its files live at `<profile>/skills/<name>/`. */
85
+ export declare const profileSkillSchema: z.ZodObject<{
86
+ name: z.ZodString;
87
+ }, "strip", z.ZodTypeAny, {
88
+ name: string;
89
+ }, {
90
+ name: string;
91
+ }>;
92
+ export declare const PROFILE_NAME_PATTERN: RegExp;
93
+ export declare const profileSchema: z.ZodObject<{
94
+ name: z.ZodString;
95
+ description: z.ZodOptional<z.ZodString>;
96
+ mcps: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
97
+ kind: z.ZodLiteral<"local">;
98
+ command: z.ZodString;
99
+ args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
100
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
101
+ }, "strip", z.ZodTypeAny, {
102
+ command: string;
103
+ kind: "local";
104
+ env?: Record<string, string> | undefined;
105
+ args?: string[] | undefined;
106
+ }, {
107
+ command: string;
108
+ kind: "local";
109
+ env?: Record<string, string> | undefined;
110
+ args?: string[] | undefined;
111
+ }>, z.ZodObject<{
112
+ kind: z.ZodLiteral<"remote">;
113
+ transport: z.ZodEnum<["http", "sse"]>;
114
+ url: z.ZodString;
115
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
116
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
117
+ }, "strip", z.ZodTypeAny, {
118
+ kind: "remote";
119
+ url: string;
120
+ transport: "http" | "sse";
121
+ env?: Record<string, string> | undefined;
122
+ headers?: Record<string, string> | undefined;
123
+ }, {
124
+ kind: "remote";
125
+ url: string;
126
+ transport: "http" | "sse";
127
+ env?: Record<string, string> | undefined;
128
+ headers?: Record<string, string> | undefined;
129
+ }>]>>>;
130
+ skills: z.ZodDefault<z.ZodArray<z.ZodObject<{
131
+ name: z.ZodString;
132
+ }, "strip", z.ZodTypeAny, {
133
+ name: string;
134
+ }, {
135
+ name: string;
136
+ }>, "many">>;
137
+ }, "strip", z.ZodTypeAny, {
138
+ skills: {
139
+ name: string;
140
+ }[];
141
+ name: string;
142
+ mcps: Record<string, {
143
+ command: string;
144
+ kind: "local";
145
+ env?: Record<string, string> | undefined;
146
+ args?: string[] | undefined;
147
+ } | {
148
+ kind: "remote";
149
+ url: string;
150
+ transport: "http" | "sse";
151
+ env?: Record<string, string> | undefined;
152
+ headers?: Record<string, string> | undefined;
153
+ }>;
154
+ description?: string | undefined;
155
+ }, {
156
+ name: string;
157
+ skills?: {
158
+ name: string;
159
+ }[] | undefined;
160
+ description?: string | undefined;
161
+ mcps?: Record<string, {
162
+ command: string;
163
+ kind: "local";
164
+ env?: Record<string, string> | undefined;
165
+ args?: string[] | undefined;
166
+ } | {
167
+ kind: "remote";
168
+ url: string;
169
+ transport: "http" | "sse";
170
+ env?: Record<string, string> | undefined;
171
+ headers?: Record<string, string> | undefined;
172
+ }> | undefined;
173
+ }>;
174
+ export type Profile = z.infer<typeof profileSchema>;
175
+ /** Credential a portable archive needs filled in at import time. */
176
+ export declare const credentialSpecSchema: z.ZodObject<{
177
+ key: z.ZodString;
178
+ required: z.ZodDefault<z.ZodBoolean>;
179
+ description: z.ZodOptional<z.ZodString>;
180
+ }, "strip", z.ZodTypeAny, {
181
+ key: string;
182
+ required: boolean;
183
+ description?: string | undefined;
184
+ }, {
185
+ key: string;
186
+ description?: string | undefined;
187
+ required?: boolean | undefined;
188
+ }>;
189
+ export type CredentialSpec = z.infer<typeof credentialSpecSchema>;
190
+ /** `manifest.json` inside a portable archive. */
191
+ export declare const profileManifestSchema: z.ZodObject<{
192
+ schemaVersion: z.ZodLiteral<1>;
193
+ profileName: z.ZodString;
194
+ createdBy: z.ZodOptional<z.ZodObject<{
195
+ tool: z.ZodString;
196
+ version: z.ZodString;
197
+ }, "strip", z.ZodTypeAny, {
198
+ version: string;
199
+ tool: string;
200
+ }, {
201
+ version: string;
202
+ tool: string;
203
+ }>>;
204
+ credentials: z.ZodOptional<z.ZodArray<z.ZodObject<{
205
+ key: z.ZodString;
206
+ required: z.ZodDefault<z.ZodBoolean>;
207
+ description: z.ZodOptional<z.ZodString>;
208
+ }, "strip", z.ZodTypeAny, {
209
+ key: string;
210
+ required: boolean;
211
+ description?: string | undefined;
212
+ }, {
213
+ key: string;
214
+ description?: string | undefined;
215
+ required?: boolean | undefined;
216
+ }>, "many">>;
217
+ }, "strip", z.ZodTypeAny, {
218
+ schemaVersion: 1;
219
+ profileName: string;
220
+ createdBy?: {
221
+ version: string;
222
+ tool: string;
223
+ } | undefined;
224
+ credentials?: {
225
+ key: string;
226
+ required: boolean;
227
+ description?: string | undefined;
228
+ }[] | undefined;
229
+ }, {
230
+ schemaVersion: 1;
231
+ profileName: string;
232
+ createdBy?: {
233
+ version: string;
234
+ tool: string;
235
+ } | undefined;
236
+ credentials?: {
237
+ key: string;
238
+ description?: string | undefined;
239
+ required?: boolean | undefined;
240
+ }[] | undefined;
241
+ }>;
242
+ export type ProfileManifest = z.infer<typeof profileManifestSchema>;
243
+ export interface ProfileSummary {
244
+ name: string;
245
+ description?: string;
246
+ mcpCount: number;
247
+ skillCount: number;
248
+ updatedAt: string;
249
+ }
250
+ export declare function slugifyProfileName(input: string): string;