pi-feats 0.1.3 → 0.1.5
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 +65 -6
- package/THIRD_PARTY_NOTICES.md +12 -0
- package/extensions/api-server/application-log-store.ts +35 -2
- package/extensions/api-server/application-runtime.ts +95 -23
- package/extensions/api-server/application-store.ts +26 -9
- package/extensions/api-server/profile-store.ts +79 -29
- package/extensions/api-server/server.ts +225 -51
- package/extensions/browser-harness/cdp/commands.ts +260 -0
- package/extensions/browser-harness/cdp/console-buffer.ts +188 -0
- package/extensions/browser-harness/cdp/discovery.ts +198 -0
- package/extensions/browser-harness/cdp/errors.ts +23 -0
- package/extensions/browser-harness/cdp/events.ts +170 -0
- package/extensions/browser-harness/cdp/network-buffer.ts +146 -0
- package/extensions/browser-harness/cdp/ownership.ts +73 -0
- package/extensions/browser-harness/cdp/record-store.ts +61 -0
- package/extensions/browser-harness/cdp/session.ts +403 -0
- package/extensions/browser-harness/cdp/steel-transport.ts +151 -0
- package/extensions/browser-harness/cdp/target-factory.ts +153 -0
- package/extensions/browser-harness/cdp/types.ts +82 -0
- package/extensions/browser-harness/client.ts +366 -0
- package/extensions/browser-harness/daemon/bridge.ts +531 -0
- package/extensions/browser-harness/daemon/index.ts +86 -0
- package/extensions/browser-harness/daemon/protocol.ts +110 -0
- package/extensions/browser-harness/daemon/queue.ts +85 -0
- package/extensions/browser-harness/daemon/server.ts +170 -0
- package/extensions/browser-harness/daemon/spawn.ts +124 -0
- package/extensions/browser-harness/daemon/transport.ts +178 -0
- package/extensions/browser-harness/domains/ax-tree.ts +179 -0
- package/extensions/browser-harness/domains/box.ts +51 -0
- package/extensions/browser-harness/domains/cdp-call.ts +55 -0
- package/extensions/browser-harness/domains/click.ts +97 -0
- package/extensions/browser-harness/domains/console.ts +219 -0
- package/extensions/browser-harness/domains/dialog.ts +34 -0
- package/extensions/browser-harness/domains/drag.ts +67 -0
- package/extensions/browser-harness/domains/element-call.ts +117 -0
- package/extensions/browser-harness/domains/files.ts +219 -0
- package/extensions/browser-harness/domains/fill-engine.ts +80 -0
- package/extensions/browser-harness/domains/form-batch.ts +65 -0
- package/extensions/browser-harness/domains/form.ts +283 -0
- package/extensions/browser-harness/domains/headers.ts +89 -0
- package/extensions/browser-harness/domains/history.ts +80 -0
- package/extensions/browser-harness/domains/isolated-tab.ts +91 -0
- package/extensions/browser-harness/domains/js.ts +241 -0
- package/extensions/browser-harness/domains/keyboard.ts +197 -0
- package/extensions/browser-harness/domains/navigate.ts +161 -0
- package/extensions/browser-harness/domains/network.ts +301 -0
- package/extensions/browser-harness/domains/page.ts +154 -0
- package/extensions/browser-harness/domains/readpage/read-page.ts +174 -0
- package/extensions/browser-harness/domains/readpage/readability.ts +65 -0
- package/extensions/browser-harness/domains/ref-resolve.ts +118 -0
- package/extensions/browser-harness/domains/render.ts +43 -0
- package/extensions/browser-harness/domains/screenshot-capture.ts +80 -0
- package/extensions/browser-harness/domains/screenshot.ts +76 -0
- package/extensions/browser-harness/domains/scroll.ts +59 -0
- package/extensions/browser-harness/domains/search/google-serp.ts +85 -0
- package/extensions/browser-harness/domains/search/web-search.ts +144 -0
- package/extensions/browser-harness/domains/setup.ts +35 -0
- package/extensions/browser-harness/domains/snapshot.ts +256 -0
- package/extensions/browser-harness/domains/tabs.ts +202 -0
- package/extensions/browser-harness/domains/target.ts +35 -0
- package/extensions/browser-harness/domains/viewport.ts +42 -0
- package/extensions/browser-harness/index.ts +88 -0
- package/extensions/browser-harness/profile/bind.ts +90 -0
- package/extensions/browser-harness/profile/browser-process.ts +320 -0
- package/extensions/browser-harness/profile/command.ts +189 -0
- package/extensions/browser-harness/profile/launch.ts +80 -0
- package/extensions/browser-harness/profile/list.ts +131 -0
- package/extensions/browser-harness/profile/paths.ts +103 -0
- package/extensions/browser-harness/profile/store.ts +84 -0
- package/extensions/browser-harness/prompt.ts +16 -0
- package/extensions/browser-harness/registry.ts +80 -0
- package/extensions/browser-harness/schemas/common.ts +11 -0
- package/extensions/browser-harness/schemas/parse.ts +23 -0
- package/extensions/browser-harness/setup.ts +47 -0
- package/extensions/browser-harness/state.ts +51 -0
- package/extensions/browser-harness/steel.ts +215 -0
- package/extensions/browser-harness/util/debug.ts +8 -0
- package/extensions/browser-harness/util/guards.ts +30 -0
- package/extensions/browser-harness/util/js-template.ts +12 -0
- package/extensions/browser-harness/util/mutex.ts +20 -0
- package/extensions/browser-harness/util/paths.ts +31 -0
- package/extensions/browser-harness/util/result.ts +9 -0
- package/extensions/browser-harness/util/sharp-shim.ts +42 -0
- package/extensions/browser-harness/util/tool.ts +185 -0
- package/extensions/browser-harness/util/truncate.ts +41 -0
- package/extensions/cli-resources.ts +54 -35
- package/extensions/composio/index.ts +163 -0
- package/extensions/context-memory/index.ts +58 -0
- package/extensions/conversation-search/index.ts +42 -0
- package/extensions/lib/application-context.ts +22 -0
- package/extensions/lib/application-handler-templates.ts +17 -1
- package/extensions/lib/builtin-tools.ts +24 -0
- package/extensions/lib/context-memory.ts +165 -0
- package/extensions/lib/conversation-search.ts +33 -0
- package/extensions/lib/profile-sandbox.ts +6 -0
- package/extensions/lib/workflow-harness.ts +238 -0
- package/extensions/pi-console-webui/app/[section]/page.tsx +6 -1
- package/extensions/pi-console-webui/app/api/admin/models/route.ts +22 -0
- package/extensions/pi-console-webui/app/applications/[slug]/page.tsx +15 -0
- package/extensions/pi-console-webui/app/layout.tsx +6 -1
- package/extensions/pi-console-webui/app/login/page.tsx +5 -9
- package/extensions/pi-console-webui/app/not-found.tsx +5 -0
- package/extensions/pi-console-webui/app/page.tsx +6 -0
- package/extensions/pi-console-webui/app/terminal/page.tsx +3 -0
- package/extensions/pi-console-webui/components/application-handler-editor.tsx +4 -4
- package/extensions/pi-console-webui/components/application-logs.tsx +14 -10
- package/extensions/pi-console-webui/components/application-mappings.tsx +10 -12
- package/extensions/pi-console-webui/components/application-settings.tsx +5 -1
- package/extensions/pi-console-webui/components/chat-workspace.tsx +7 -4
- package/extensions/pi-console-webui/components/console-page.tsx +6 -1
- package/extensions/pi-console-webui/components/console.tsx +60 -10
- package/extensions/pi-console-webui/components/login-form.tsx +14 -0
- package/extensions/pi-console-webui/components/models-config-form.tsx +31 -0
- package/extensions/pi-console-webui/components/profile-model-form.tsx +54 -0
- package/extensions/pi-console-webui/components/pulse-resources.tsx +14 -10
- package/extensions/pi-console-webui/components/skill-resources.tsx +3 -3
- package/extensions/pi-console-webui/lib/admin-models.ts +36 -0
- package/extensions/pi-console-webui/lib/page-metadata.ts +35 -0
- package/extensions/pi-console-webui/next.config.js +1 -0
- package/extensions/profile-ssh.ts +274 -0
- package/extensions/profiles.ts +70 -23
- package/extensions/pulse/index.ts +128 -14
- package/extensions/pulse/store.ts +110 -15
- package/extensions/sequential-workflow.ts +340 -256
- package/extensions/skill-sources/store.ts +24 -3
- package/licenses/pi-browser-harness-MIT.txt +21 -0
- package/package.json +23 -3
- package/schemas/sequential-workflow-template.schema.json +62 -0
- package/skills/browser-harness/SKILL.md +33 -0
- package/skills/composio-connections/SKILL.md +75 -0
- package/skills/profile-ssh/SKILL.md +65 -0
- package/skills/sequential-workflow/SKILL.md +70 -0
- package/skills/sequential-workflow-template/SKILL.md +44 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { copyFile, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { copyFile, mkdir, readFile, readlink, readdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join, relative, resolve } from "node:path";
|
|
4
4
|
import { ensureProfileSandbox } from "../lib/profile-sandbox.ts";
|
|
5
|
+
import { BUILTIN_TOOLS, activeBuiltinTools, updatedBuiltinTools } from "../lib/builtin-tools.ts";
|
|
5
6
|
|
|
6
|
-
export
|
|
7
|
+
export { BUILTIN_TOOLS } from "../lib/builtin-tools.ts";
|
|
7
8
|
export const RESOURCE_KINDS = ["tools", "skills", "extensions"] as const;
|
|
8
9
|
export type ResourceKind = typeof RESOURCE_KINDS[number];
|
|
9
10
|
type PolicyKey = "enabledTools" | "enabledSkills" | "enabledProfileSkills" | "enabledExtensions";
|
|
10
11
|
type SkillSources = { shared?: boolean; profile?: boolean };
|
|
11
|
-
type
|
|
12
|
+
type SkillResourceSource = "shared" | "profile" | "package";
|
|
13
|
+
type ProfilePolicy = Partial<Record<PolicyKey, string[]>> & { skillSources?: SkillSources; contextMemory?: { mode: "file"; target: "profile" | "identity" } | { mode: "handler"; handler: string } };
|
|
12
14
|
export type ProfileSettings = Record<string, unknown> & { profile?: ProfilePolicy; sandbox?: boolean };
|
|
13
15
|
export type Resource = { name: string; kind: ResourceKind; path?: string; source: "builtin" | "shared" | "profile" | "extension" | "package"; package?: string; enabled: boolean; protected?: boolean };
|
|
14
16
|
export type Package = { name: string; version?: string; description?: string; enabled: boolean; installed: boolean };
|
|
@@ -22,12 +24,24 @@ const policyKey: Record<ResourceKind, PolicyKey> = {
|
|
|
22
24
|
const protectedExtensions = new Set(["profiles", "api-server"]);
|
|
23
25
|
|
|
24
26
|
export class ProfileStore {
|
|
25
|
-
private readonly extensionTools = new Set<string
|
|
27
|
+
private readonly extensionTools = new Map<string, Set<string>>();
|
|
28
|
+
readonly agentDir: string;
|
|
26
29
|
|
|
27
|
-
constructor(
|
|
30
|
+
constructor(agentDir: string) { this.agentDir = agentDir; }
|
|
28
31
|
|
|
29
|
-
registerExtensionTools(names: Iterable<string>): void {
|
|
30
|
-
|
|
32
|
+
registerExtensionTools(profile: string, names: Iterable<string>): void {
|
|
33
|
+
const tools = this.extensionTools.get(profile) ?? new Set<string>();
|
|
34
|
+
for (const name of names) if (name && !(BUILTIN_TOOLS as readonly string[]).includes(name)) tools.add(name);
|
|
35
|
+
this.extensionTools.set(profile, tools);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
extensionToolNames(profile: string): Iterable<string> {
|
|
39
|
+
return this.extensionTools.get(profile) ?? [];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
clearExtensionTools(profile?: string): void {
|
|
43
|
+
if (profile) this.extensionTools.delete(profile);
|
|
44
|
+
else this.extensionTools.clear();
|
|
31
45
|
}
|
|
32
46
|
|
|
33
47
|
private profilesDir(): string { return join(this.agentDir, "profiles"); }
|
|
@@ -37,6 +51,13 @@ export class ProfileStore {
|
|
|
37
51
|
return join(this.profilesDir(), name);
|
|
38
52
|
}
|
|
39
53
|
private settingsPath(name: string): string { return join(this.directory(name), "settings.json"); }
|
|
54
|
+
private async linkSharedModels(name: string): Promise<void> {
|
|
55
|
+
if (name === "default") return;
|
|
56
|
+
const source = join(this.agentDir, "models.json"), target = join(this.directory(name), "models.json");
|
|
57
|
+
try { if (resolve(this.directory(name), await readlink(target)) === source) return; } catch { /* Missing or non-symlink target must be replaced. */ }
|
|
58
|
+
await rm(target, { force: true });
|
|
59
|
+
if (existsSync(source)) await symlink(source, target);
|
|
60
|
+
}
|
|
40
61
|
private skillSources(name: string, settings: ProfileSettings): Required<SkillSources> {
|
|
41
62
|
if (name === "default") return { shared: true, profile: false };
|
|
42
63
|
return { shared: settings.profile?.skillSources?.shared !== false, profile: settings.profile?.skillSources?.profile === true };
|
|
@@ -50,6 +71,7 @@ export class ProfileStore {
|
|
|
50
71
|
try {
|
|
51
72
|
const value = JSON.parse(await readFile(path, "utf8")) as unknown;
|
|
52
73
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("settings.json must contain an object");
|
|
74
|
+
await this.linkSharedModels(name);
|
|
53
75
|
return value as ProfileSettings;
|
|
54
76
|
} catch (error) {
|
|
55
77
|
if ((error as NodeJS.ErrnoException).code === "ENOENT" && name === "default") return {};
|
|
@@ -94,19 +116,32 @@ export class ProfileStore {
|
|
|
94
116
|
private enabled(settings: ProfileSettings, kind: ResourceKind, name: string, path?: string): boolean {
|
|
95
117
|
const values = settings.profile?.[policyKey[kind]];
|
|
96
118
|
if (values) return values.includes("*") || values.includes(name);
|
|
119
|
+
if (kind === "tools" && (BUILTIN_TOOLS as readonly string[]).includes(name)) return activeBuiltinTools(settings).includes(name);
|
|
97
120
|
const configured = settings[kind];
|
|
98
121
|
const exclusions = Array.isArray(configured) ? configured.filter((value): value is string => typeof value === "string" && value.startsWith("!")) : [];
|
|
99
122
|
return !path || !exclusions.includes(`!${path}`);
|
|
100
123
|
}
|
|
101
124
|
|
|
102
|
-
private async
|
|
125
|
+
private async packageSkillResources(settings: ProfileSettings): Promise<Resource[]> {
|
|
126
|
+
const resources: Resource[] = [];
|
|
127
|
+
for (const pkg of await this.configuredPackages(settings)) {
|
|
128
|
+
for (const entry of Array.isArray(pkg.manifest?.pi?.skills) ? pkg.manifest.pi.skills : []) {
|
|
129
|
+
if (typeof entry !== "string") continue;
|
|
130
|
+
for (const skill of await this.skillNames(join(pkg.base, entry))) resources.push({ name: skill.name, kind: "skills", path: skill.path, source: "package", package: pkg.name, enabled: this.skillEnabled(settings, "package", skill.name) });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return resources;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private async skillResources(profile: string, settings: ProfileSettings, runtimeSettings: ProfileSettings = settings): Promise<Resource[]> {
|
|
103
137
|
const sources = this.skillSources(profile, settings);
|
|
104
138
|
const entries = await Promise.all((["profile", "shared"] as const).filter((source) => sources[source]).map(async (source) => ({ source, entries: await this.skillNames(this.skillBase(profile, source)) })));
|
|
105
|
-
|
|
139
|
+
const local = entries.flatMap(({ source, entries }) => entries.map(({ name, path }) => ({ name, kind: "skills" as const, path, source, enabled: this.skillEnabled(settings, source, name) })));
|
|
140
|
+
return [...local, ...(sources.shared ? await this.packageSkillResources(runtimeSettings) : [])];
|
|
106
141
|
}
|
|
107
142
|
|
|
108
|
-
private skillEnabled(settings: ProfileSettings, source:
|
|
109
|
-
const values = settings.profile?.[source === "
|
|
143
|
+
private skillEnabled(settings: ProfileSettings, source: SkillResourceSource, name: string): boolean {
|
|
144
|
+
const values = settings.profile?.[source === "profile" ? "enabledProfileSkills" : "enabledSkills"];
|
|
110
145
|
return !values || values.includes("*") || values.includes(name);
|
|
111
146
|
}
|
|
112
147
|
|
|
@@ -120,12 +155,12 @@ export class ProfileStore {
|
|
|
120
155
|
return join(this.agentDir, "git", remote);
|
|
121
156
|
}
|
|
122
157
|
|
|
123
|
-
private async configuredPackages(settings: ProfileSettings): Promise<Array<{ source: string; base: string; name: string; manifest?: { version?: string; description?: string; pi?: { extensions?: unknown } } }>> {
|
|
158
|
+
private async configuredPackages(settings: ProfileSettings): Promise<Array<{ source: string; base: string; name: string; manifest?: { version?: string; description?: string; pi?: { extensions?: unknown; skills?: unknown } } }>> {
|
|
124
159
|
const sources = Array.isArray(settings.packages) ? settings.packages.filter((value): value is string => typeof value === "string") : [];
|
|
125
|
-
const packages: Array<{ source: string; base: string; name: string; manifest?: { version?: string; description?: string; pi?: { extensions?: unknown } } }> = [];
|
|
160
|
+
const packages: Array<{ source: string; base: string; name: string; manifest?: { version?: string; description?: string; pi?: { extensions?: unknown; skills?: unknown } } }> = [];
|
|
126
161
|
for (const source of sources) {
|
|
127
162
|
const base = this.packageBase(source); if (!base) continue;
|
|
128
|
-
try { const manifest = JSON.parse(await readFile(join(base, "package.json"), "utf8")) as { name?: string; version?: string; description?: string; pi?: { extensions?: unknown } }; packages.push({ source, base, name: manifest.name ?? source, manifest }); }
|
|
163
|
+
try { const manifest = JSON.parse(await readFile(join(base, "package.json"), "utf8")) as { name?: string; version?: string; description?: string; pi?: { extensions?: unknown; skills?: unknown } }; packages.push({ source, base, name: manifest.name ?? source, manifest }); }
|
|
129
164
|
catch { packages.push({ source, base, name: source.replace(/^npm:/, "") }); }
|
|
130
165
|
}
|
|
131
166
|
return packages;
|
|
@@ -159,8 +194,8 @@ export class ProfileStore {
|
|
|
159
194
|
const sources = new Map<string, string>(), tools = [...names];
|
|
160
195
|
for (const extension of await this.packageExtensions(settings)) try {
|
|
161
196
|
const source = await readFile(extension.path, "utf8");
|
|
162
|
-
for (const tool of tools) if (source.includes(`"${tool}"`) || source.includes(`'${tool}'`) || source.includes(`\`${tool}\``)) sources.set(tool, extension.package);
|
|
163
|
-
for (const block of source.matchAll(/TOOL_NAMES[^=]*=\s*\{([\s\S]*?)\}/g)) for (const name of block[1].matchAll(/:\s*["']([A-Za-z][A-Za-z0-9_-]{0,63})["']/g)) sources.set(name[1], extension.package);
|
|
197
|
+
for (const tool of tools) if (!(BUILTIN_TOOLS as readonly string[]).includes(tool) && (source.includes(`"${tool}"`) || source.includes(`'${tool}'`) || source.includes(`\`${tool}\``))) sources.set(tool, extension.package);
|
|
198
|
+
for (const block of source.matchAll(/TOOL_NAMES[^=]*=\s*\{([\s\S]*?)\}/g)) for (const name of block[1].matchAll(/:\s*["']([A-Za-z][A-Za-z0-9_-]{0,63})["']/g)) if (!(BUILTIN_TOOLS as readonly string[]).includes(name[1])) sources.set(name[1], extension.package);
|
|
164
199
|
} catch {}
|
|
165
200
|
return sources;
|
|
166
201
|
}
|
|
@@ -168,23 +203,25 @@ export class ProfileStore {
|
|
|
168
203
|
async resources(profile: string, kind: ResourceKind): Promise<Resource[]> {
|
|
169
204
|
const settings = await this.readSettings(profile);
|
|
170
205
|
const runtimeSettings = profile === "default" ? settings : await this.readSettings("default");
|
|
171
|
-
if (kind === "skills") return this.skillResources(profile, settings);
|
|
206
|
+
if (kind === "skills") return this.skillResources(profile, settings, runtimeSettings);
|
|
172
207
|
if (kind === "tools") {
|
|
173
|
-
const
|
|
174
|
-
const
|
|
208
|
+
const extensionTools = this.extensionToolNames(profile);
|
|
209
|
+
const sources = await this.packageToolSources(runtimeSettings, extensionTools);
|
|
210
|
+
const names = new Set([...extensionTools, ...sources.keys()]);
|
|
175
211
|
return [...BUILTIN_TOOLS.map((name) => ({ name, kind, source: "builtin" as const, enabled: this.enabled(settings, kind, name) })), ...[...names].sort().map((name) => sources.has(name) ? ({ name, kind, source: "package" as const, package: sources.get(name), enabled: this.enabled(settings, kind, name) }) : ({ name, kind, source: "extension" as const, enabled: this.enabled(settings, kind, name) }))];
|
|
176
212
|
}
|
|
177
|
-
return [...(await this.names("extensions")).map(({ name, path }) => ({ name, kind, path, source: "shared" as const, enabled: protectedExtensions.has(name) ? true : this.enabled(runtimeSettings, kind, name, path), protected: protectedExtensions.has(name) || undefined })), ...(await this.packageExtensions(runtimeSettings)).map(({ name, path, package: packageName }) => ({ name, kind, path, source: "package" as const, package: packageName, enabled: true }))];
|
|
213
|
+
return [...(await this.names("extensions")).map(({ name, path }) => ({ name, kind, path, source: "shared" as const, enabled: protectedExtensions.has(name) ? true : this.enabled(runtimeSettings, kind, name, path), protected: protectedExtensions.has(name) || undefined })), ...(await this.packageExtensions(runtimeSettings)).map(({ name, path, package: packageName }) => ({ name, kind, path, source: "package" as const, package: packageName, enabled: protectedExtensions.has(name) ? true : this.enabled(runtimeSettings, kind, name, path), protected: protectedExtensions.has(name) || undefined }))];
|
|
178
214
|
}
|
|
179
215
|
|
|
180
|
-
async resource(profile: string, kind: ResourceKind, name: string, source?:
|
|
216
|
+
async resource(profile: string, kind: ResourceKind, name: string, source?: SkillResourceSource): Promise<Resource> {
|
|
181
217
|
const resource = (await this.resources(profile, kind)).find((item) => item.name === name && (!source || item.source === source));
|
|
182
218
|
if (!resource) throw Object.assign(new Error("Resource not found"), { status: 404 });
|
|
183
219
|
return resource;
|
|
184
220
|
}
|
|
185
221
|
|
|
186
222
|
private async skillPaths(name: string, settings: ProfileSettings): Promise<string[]> {
|
|
187
|
-
|
|
223
|
+
const runtimeSettings = name === "default" ? settings : await this.readSettings("default");
|
|
224
|
+
return (await this.skillResources(name, settings, runtimeSettings)).filter((skill) => skill.enabled).map((skill) => skill.path!).filter(Boolean);
|
|
188
225
|
}
|
|
189
226
|
|
|
190
227
|
private async materializeResources(name: string, settings: ProfileSettings): Promise<ProfileSettings> {
|
|
@@ -232,7 +269,7 @@ export class ProfileStore {
|
|
|
232
269
|
return this.skillSources(profile, settings);
|
|
233
270
|
}
|
|
234
271
|
|
|
235
|
-
async readSkillDocument(profile: string, name: string, source?:
|
|
272
|
+
async readSkillDocument(profile: string, name: string, source?: SkillResourceSource): Promise<{ name: string; frontmatter: Record<string, string>; content: string }> {
|
|
236
273
|
const skill = await this.resource(profile, "skills", name, source);
|
|
237
274
|
if (!skill.path) throw Object.assign(new Error("Skill document not found"), { status: 404 });
|
|
238
275
|
const document = await readFile(join(skill.path, "SKILL.md"), "utf8");
|
|
@@ -247,9 +284,22 @@ export class ProfileStore {
|
|
|
247
284
|
return { name, frontmatter, content: match ? document.slice(match[0].length) : document };
|
|
248
285
|
}
|
|
249
286
|
|
|
250
|
-
async setResource(profile: string, kind: ResourceKind, name: string, enabled: boolean, source?:
|
|
287
|
+
async setResource(profile: string, kind: ResourceKind, name: string, enabled: boolean, source?: SkillResourceSource): Promise<Resource> {
|
|
251
288
|
const current = await this.resource(profile, kind, name, source);
|
|
252
289
|
if (current.protected && !enabled) throw Object.assign(new Error("This extension is required and cannot be disabled."), { status: 422 });
|
|
290
|
+
// The default profile uses Pi's defaultTools setting for native tool state
|
|
291
|
+
// unless it already has a legacy explicit enabledTools policy. Named profiles
|
|
292
|
+
// retain their explicit enabledTools policy.
|
|
293
|
+
if (kind === "tools" && current.source === "builtin" && profile === "default") {
|
|
294
|
+
const settings = await this.readSettings(profile);
|
|
295
|
+
if (!settings.profile?.enabledTools) {
|
|
296
|
+
const tools = updatedBuiltinTools(settings, name, enabled);
|
|
297
|
+
if (tools) settings.defaultTools = tools;
|
|
298
|
+
else delete settings.defaultTools;
|
|
299
|
+
await this.writeSettings(profile, settings);
|
|
300
|
+
return this.resource(profile, kind, name, source);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
253
303
|
// Extensions are shared runtime resources, so toggling one always updates
|
|
254
304
|
// the default runtime rather than materializing it in a profile workspace.
|
|
255
305
|
const settingsProfile = kind === "extensions" ? "default" : profile;
|
|
@@ -264,8 +314,9 @@ export class ProfileStore {
|
|
|
264
314
|
return this.resource(profile, kind, name, source);
|
|
265
315
|
}
|
|
266
316
|
|
|
267
|
-
async deleteSkill(profile: string, name: string, source?:
|
|
317
|
+
async deleteSkill(profile: string, name: string, source?: SkillResourceSource): Promise<void> {
|
|
268
318
|
const current = await this.resource(profile, "skills", name, source);
|
|
319
|
+
if (current.source === "package") throw Object.assign(new Error("Package Skills cannot be deleted here."), { status: 403 });
|
|
269
320
|
if (current.source === "shared" && profile !== "default") { await this.setResource(profile, "skills", name, false, "shared"); return; }
|
|
270
321
|
if (!current.path) throw Object.assign(new Error("Skill path not found."), { status: 404 });
|
|
271
322
|
await rm(current.path, { recursive: true, force: false });
|
|
@@ -290,10 +341,9 @@ export class ProfileStore {
|
|
|
290
341
|
await ensureProfileSandbox(destination, resolve(process.argv[1]));
|
|
291
342
|
await writeFile(join(destination, "SOUL.md"), "", "utf8");
|
|
292
343
|
await writeFile(join(destination, "guardrails.json"), "{\n \"guardrails\": []\n}\n", "utf8");
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
344
|
+
const auth = join(this.agentDir, "auth.json");
|
|
345
|
+
if (existsSync(auth)) await copyFile(auth, join(destination, "auth.json"));
|
|
346
|
+
await this.linkSharedModels(name);
|
|
297
347
|
return { name, path: destination };
|
|
298
348
|
}
|
|
299
349
|
|