@agimon-ai/po-core 0.0.0-alpha.12 → 0.0.0-alpha.13
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/dist/machineApi.cjs +71 -71
- package/dist/machineApi.cjs.map +1 -1
- package/dist/machineApi.d.mts +4 -1
- package/dist/machineApi.d.mts.map +1 -1
- package/dist/machineApi.mjs +71 -71
- package/dist/machineApi.mjs.map +1 -1
- package/dist/sessionFilesApi.cjs +28 -28
- package/dist/sessionFilesApi.cjs.map +1 -1
- package/dist/sessionFilesApi.d.mts +5 -2
- package/dist/sessionFilesApi.d.mts.map +1 -1
- package/dist/sessionFilesApi.mjs +28 -28
- package/dist/sessionFilesApi.mjs.map +1 -1
- package/dist/src/pi/piSessionRuntime.cjs +6 -2
- package/dist/src/pi/piSessionRuntime.cjs.map +1 -1
- package/dist/src/pi/piSessionRuntime.d.mts.map +1 -1
- package/dist/src/pi/piSessionRuntime.mjs +6 -2
- package/dist/src/pi/piSessionRuntime.mjs.map +1 -1
- package/dist/src/server/directHarnessRuntime.cjs +2 -2
- package/dist/src/server/directHarnessRuntime.cjs.map +1 -1
- package/dist/src/server/directHarnessRuntime.mjs +2 -2
- package/dist/src/server/directHarnessRuntime.mjs.map +1 -1
- package/dist/src/services/piExtensionHost/index.cjs +0 -1
- package/dist/src/services/piExtensionHost/index.cjs.map +1 -1
- package/dist/src/services/piExtensionHost/index.mjs +0 -1
- package/dist/src/services/piExtensionHost/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/machineApi.cjs
CHANGED
|
@@ -7,7 +7,6 @@ const require_sync = require("./src/services/piSettings/sync.cjs");
|
|
|
7
7
|
require("./runtimePiSettings.cjs");
|
|
8
8
|
const require_index$2 = require("./src/services/chatgptLogin/index.cjs");
|
|
9
9
|
const require_index$3 = require("./src/services/piExtensionHost/index.cjs");
|
|
10
|
-
const require_nodePlatform = require("./nodePlatform.cjs");
|
|
11
10
|
const require_index$4 = require("./src/services/providerAuth/index.cjs");
|
|
12
11
|
let node_path = require("node:path");
|
|
13
12
|
node_path = require_runtime.__toESM(node_path, 1);
|
|
@@ -18,83 +17,84 @@ function record(value) {
|
|
|
18
17
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
19
18
|
}
|
|
20
19
|
/** Machine-owned provider credentials and model catalog, available without a session. */
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
cwd,
|
|
41
|
-
agentDir: directory,
|
|
42
|
-
models: runtime,
|
|
43
|
-
extensionPaths: [...await require_index$3.resolvePiSettingsPackageEntries({
|
|
20
|
+
function createMachineApi({ fs }) {
|
|
21
|
+
return {
|
|
22
|
+
basePath: "po",
|
|
23
|
+
start(context) {
|
|
24
|
+
if (context.scope !== "global") throw new Error("Provider authentication requires the global mount.");
|
|
25
|
+
const auth = require_index$4.createProviderAuth({
|
|
26
|
+
onNotice: (message) => context.onNotice(message),
|
|
27
|
+
runtime: async () => {
|
|
28
|
+
const directory = require_core.piAgentDirectory(context.environment, context.homeDirectory);
|
|
29
|
+
const modelDir = require_sync.modelConfigDirectory(directory, context.homeDirectory);
|
|
30
|
+
const runtime = await _earendil_works_pi_coding_agent.ModelRuntime.create({
|
|
31
|
+
authPath: node_path.default.join(modelDir, "auth.json"),
|
|
32
|
+
modelsPath: node_path.default.join(modelDir, "models.json")
|
|
33
|
+
});
|
|
34
|
+
require_index$2.registerChatgptAuthProvider(runtime);
|
|
35
|
+
const onNotice = (message) => context.onNotice(message);
|
|
36
|
+
const cwd = context.homeDirectory ?? require_index$1.nodeHost.homeDirectory();
|
|
37
|
+
const settings = _earendil_works_pi_coding_agent.SettingsManager.create(cwd, directory);
|
|
38
|
+
await require_index$3.preloadPiExtensions({
|
|
44
39
|
cwd,
|
|
45
40
|
agentDir: directory,
|
|
46
|
-
|
|
41
|
+
models: runtime,
|
|
42
|
+
extensionPaths: [...await require_index$3.resolvePiSettingsPackageEntries({
|
|
43
|
+
cwd,
|
|
44
|
+
agentDir: directory,
|
|
45
|
+
settings,
|
|
46
|
+
onNotice
|
|
47
|
+
}), ...modelDir !== directory && await require_index.pathExists(fs, node_path.default.join(modelDir, "extensions"), dist_interop_chordContext_mjs.BACKGROUND_CONTEXT).catch(() => false) ? [node_path.default.join(modelDir, "extensions")] : []],
|
|
47
48
|
onNotice
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
if (url.pathname === "/logins" && request.method === "POST") {
|
|
68
|
-
const body = await request.json();
|
|
69
|
-
if (!record(body) || typeof body.providerId !== "string" || body.type !== "oauth" && body.type !== "api_key") return Response.json({ error: "A provider and supported login method are required." }, { status: 400 });
|
|
70
|
-
const result = await auth.startLogin(body.providerId, body.type);
|
|
71
|
-
return result.ok ? Response.json({ flow: result.flow }, { status: 201 }) : Response.json({ error: result.error }, { status: result.code === "unknown_provider" ? 404 : result.code === "busy" ? 409 : 400 });
|
|
72
|
-
}
|
|
73
|
-
const flow = /^\/logins\/([^/]+)(\/answer)?$/u.exec(url.pathname);
|
|
74
|
-
if (flow) {
|
|
75
|
-
const id = decodeURIComponent(flow[1]);
|
|
76
|
-
if (!auth.getLogin(id)) return Response.json({ error: "Login flow not found." }, { status: 404 });
|
|
77
|
-
if (flow[2] && request.method === "POST") {
|
|
49
|
+
});
|
|
50
|
+
return runtime;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
let closed = false;
|
|
54
|
+
return {
|
|
55
|
+
async fetch(request) {
|
|
56
|
+
if (closed) return Response.json({ error: "Provider mount is closed." }, { status: 503 });
|
|
57
|
+
const url = new URL(request.url);
|
|
58
|
+
try {
|
|
59
|
+
if (url.pathname === "/providers" && request.method === "GET") return Response.json({ providers: await auth.listProviders() });
|
|
60
|
+
if (url.pathname === "/models" && request.method === "GET") return Response.json({ models: await auth.listModels() });
|
|
61
|
+
const provider = /^\/providers\/([^/]+)$/u.exec(url.pathname);
|
|
62
|
+
if (provider && request.method === "DELETE") {
|
|
63
|
+
const result = await auth.logout(decodeURIComponent(provider[1]));
|
|
64
|
+
return result.ok ? Response.json({ ok: true }) : Response.json({ error: result.error }, { status: result.code === "unknown_provider" ? 404 : 502 });
|
|
65
|
+
}
|
|
66
|
+
if (url.pathname === "/logins" && request.method === "POST") {
|
|
78
67
|
const body = await request.json();
|
|
79
|
-
if (!record(body) || typeof body.
|
|
80
|
-
|
|
68
|
+
if (!record(body) || typeof body.providerId !== "string" || body.type !== "oauth" && body.type !== "api_key") return Response.json({ error: "A provider and supported login method are required." }, { status: 400 });
|
|
69
|
+
const result = await auth.startLogin(body.providerId, body.type);
|
|
70
|
+
return result.ok ? Response.json({ flow: result.flow }, { status: 201 }) : Response.json({ error: result.error }, { status: result.code === "unknown_provider" ? 404 : result.code === "busy" ? 409 : 400 });
|
|
71
|
+
}
|
|
72
|
+
const flow = /^\/logins\/([^/]+)(\/answer)?$/u.exec(url.pathname);
|
|
73
|
+
if (flow) {
|
|
74
|
+
const id = decodeURIComponent(flow[1]);
|
|
75
|
+
if (!auth.getLogin(id)) return Response.json({ error: "Login flow not found." }, { status: 404 });
|
|
76
|
+
if (flow[2] && request.method === "POST") {
|
|
77
|
+
const body = await request.json();
|
|
78
|
+
if (!record(body) || typeof body.promptId !== "string" || typeof body.value !== "string") return Response.json({ error: "A prompt ID and answer are required." }, { status: 400 });
|
|
79
|
+
return auth.answerLogin(id, body.promptId, body.value) === "answered" ? Response.json({ flow: auth.getLogin(id) }) : Response.json({ error: "Login is no longer waiting for this answer." }, { status: 409 });
|
|
80
|
+
}
|
|
81
|
+
if (!flow[2] && request.method === "GET") return Response.json({ flow: auth.getLogin(id) });
|
|
82
|
+
if (!flow[2] && request.method === "DELETE") return Response.json({ flow: auth.cancelLogin(id) });
|
|
81
83
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
return Response.json({ error: "Provider route not found." }, { status: 404 });
|
|
85
|
+
} catch (error) {
|
|
86
|
+
return Response.json({ error: error instanceof Error ? error.message : String(error) }, { status: error instanceof SyntaxError ? 400 : 502 });
|
|
84
87
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
},
|
|
89
|
+
close() {
|
|
90
|
+
closed = true;
|
|
91
|
+
auth.close();
|
|
88
92
|
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
};
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
97
|
//#endregion
|
|
98
|
-
exports.
|
|
98
|
+
exports.createMachineApi = createMachineApi;
|
|
99
99
|
|
|
100
100
|
//# sourceMappingURL=machineApi.cjs.map
|
package/dist/machineApi.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machineApi.cjs","names":["createProviderAuth","piAgentDirectory","modelConfigDirectory","ModelRuntime","path","nodeHost","createNodePlatform","SettingsManager","preloadPiExtensions","resolvePiSettingsPackageEntries","pathExists","BACKGROUND_CONTEXT"],"sources":["../src/server/machineApi.ts"],"sourcesContent":["import path from 'node:path';\n\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport { ModelRuntime, SettingsManager } from '@earendil-works/pi-coding-agent';\n\nimport type { PoApi } from '../exports/packageApi';\nimport { registerChatgptAuthProvider } from '../services/chatgptLogin';\nimport { nodeHost } from '../services/nodeHost';\nimport { createNodePlatform } from '../services/nodePlatform';\nimport { preloadPiExtensions, resolvePiSettingsPackageEntries } from '../services/piExtensionHost';\nimport { modelConfigDirectory, piAgentDirectory } from '../services/piSettings';\nimport { pathExists } from '../services/platformFiles';\nimport { createProviderAuth } from '../services/providerAuth';\n\nfunction record(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n/** Machine-owned provider credentials and model catalog, available without a session. */\nexport const machineApi: PoApi = {\n basePath: 'po',\n start(context) {\n if (context.scope !== 'global') throw new Error('Provider authentication requires the global mount.');\n const auth = createProviderAuth({\n onNotice: (message) => context.onNotice(message),\n runtime: async () => {\n const directory = piAgentDirectory(context.environment, context.homeDirectory);\n // Resolved as sessions resolve it (headlessSessionHost): with no model config of its\n // own, Po falls back to plain Pi's ~/.pi/agent, so this catalog matches the session picker.\n const modelDir = modelConfigDirectory(directory, context.homeDirectory);\n const runtime = await ModelRuntime.create({\n authPath: path.join(modelDir, 'auth.json'),\n modelsPath: path.join(modelDir, 'models.json'),\n });\n registerChatgptAuthProvider(runtime);\n // Providers registered by Pi settings packages (a Claude Code bridge, say) are\n // listed and pickable here as they are in sessions, which load the same packages.\n const onNotice = (message: string): void => context.onNotice(message);\n // Machine scope has no project, so the home directory stands in for Pi's cwd.\n const cwd = context.homeDirectory ?? nodeHost.homeDirectory();\n const fs = createNodePlatform({ homeDirectory: cwd }).env(cwd);\n const settings = SettingsManager.create(cwd, directory);\n await preloadPiExtensions({\n cwd,\n agentDir: directory,\n models: runtime,\n extensionPaths: [\n ...(await resolvePiSettingsPackageEntries({\n cwd,\n agentDir: directory,\n settings,\n onNotice,\n })),\n // The fallback brings Pi's own extensions with it, as sessions load them: a custom\n // provider such as a local Vertex bridge lives there, not in auth.json.\n ...(modelDir !== directory &&\n (await pathExists(fs, path.join(modelDir, 'extensions'), BACKGROUND_CONTEXT).catch(() => false))\n ? [path.join(modelDir, 'extensions')]\n : []),\n ],\n onNotice,\n });\n return runtime;\n },\n });\n let closed = false;\n return {\n async fetch(request) {\n if (closed) return Response.json({ error: 'Provider mount is closed.' }, { status: 503 });\n const url = new URL(request.url);\n try {\n if (url.pathname === '/providers' && request.method === 'GET')\n return Response.json({ providers: await auth.listProviders() });\n if (url.pathname === '/models' && request.method === 'GET')\n return Response.json({ models: await auth.listModels() });\n const provider = /^\\/providers\\/([^/]+)$/u.exec(url.pathname);\n if (provider && request.method === 'DELETE') {\n const result = await auth.logout(decodeURIComponent(provider[1]));\n return result.ok\n ? Response.json({ ok: true })\n : Response.json({ error: result.error }, { status: result.code === 'unknown_provider' ? 404 : 502 });\n }\n if (url.pathname === '/logins' && request.method === 'POST') {\n const body: unknown = await request.json();\n if (\n !record(body) ||\n typeof body.providerId !== 'string' ||\n (body.type !== 'oauth' && body.type !== 'api_key')\n )\n return Response.json({ error: 'A provider and supported login method are required.' }, { status: 400 });\n const result = await auth.startLogin(body.providerId, body.type);\n return result.ok\n ? Response.json({ flow: result.flow }, { status: 201 })\n : Response.json(\n { error: result.error },\n { status: result.code === 'unknown_provider' ? 404 : result.code === 'busy' ? 409 : 400 },\n );\n }\n const flow = /^\\/logins\\/([^/]+)(\\/answer)?$/u.exec(url.pathname);\n if (flow) {\n const id = decodeURIComponent(flow[1]);\n if (!auth.getLogin(id)) return Response.json({ error: 'Login flow not found.' }, { status: 404 });\n if (flow[2] && request.method === 'POST') {\n const body: unknown = await request.json();\n if (!record(body) || typeof body.promptId !== 'string' || typeof body.value !== 'string')\n return Response.json({ error: 'A prompt ID and answer are required.' }, { status: 400 });\n const answer = auth.answerLogin(id, body.promptId, body.value);\n return answer === 'answered'\n ? Response.json({ flow: auth.getLogin(id) })\n : Response.json({ error: 'Login is no longer waiting for this answer.' }, { status: 409 });\n }\n if (!flow[2] && request.method === 'GET') return Response.json({ flow: auth.getLogin(id) });\n if (!flow[2] && request.method === 'DELETE') return Response.json({ flow: auth.cancelLogin(id) });\n }\n return Response.json({ error: 'Provider route not found.' }, { status: 404 });\n } catch (error) {\n return Response.json(\n { error: error instanceof Error ? error.message : String(error) },\n { status: error instanceof SyntaxError ? 400 : 502 },\n );\n }\n },\n close() {\n closed = true;\n auth.close();\n },\n };\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"machineApi.cjs","names":["createProviderAuth","piAgentDirectory","modelConfigDirectory","ModelRuntime","path","nodeHost","SettingsManager","preloadPiExtensions","resolvePiSettingsPackageEntries","pathExists","BACKGROUND_CONTEXT"],"sources":["../src/server/machineApi.ts"],"sourcesContent":["import path from 'node:path';\n\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport { ModelRuntime, SettingsManager } from '@earendil-works/pi-coding-agent';\nimport type { FileSystem } from '@earendil-works/pi-durable/env';\n\nimport type { PoApi } from '../exports/packageApi';\nimport { registerChatgptAuthProvider } from '../services/chatgptLogin';\nimport { nodeHost } from '../services/nodeHost';\nimport { preloadPiExtensions, resolvePiSettingsPackageEntries } from '../services/piExtensionHost';\nimport { modelConfigDirectory, piAgentDirectory } from '../services/piSettings';\nimport { pathExists } from '../services/platformFiles';\nimport { createProviderAuth } from '../services/providerAuth';\n\nfunction record(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n/** Machine-owned provider credentials and model catalog, available without a session. */\nexport function createMachineApi({ fs }: { fs: FileSystem }): PoApi {\n return {\n basePath: 'po',\n start(context) {\n if (context.scope !== 'global') throw new Error('Provider authentication requires the global mount.');\n const auth = createProviderAuth({\n onNotice: (message) => context.onNotice(message),\n runtime: async () => {\n const directory = piAgentDirectory(context.environment, context.homeDirectory);\n // Resolved as sessions resolve it (headlessSessionHost): with no model config of its\n // own, Po falls back to plain Pi's ~/.pi/agent, so this catalog matches the session picker.\n const modelDir = modelConfigDirectory(directory, context.homeDirectory);\n const runtime = await ModelRuntime.create({\n authPath: path.join(modelDir, 'auth.json'),\n modelsPath: path.join(modelDir, 'models.json'),\n });\n registerChatgptAuthProvider(runtime);\n // Providers registered by Pi settings packages (a Claude Code bridge, say) are\n // listed and pickable here as they are in sessions, which load the same packages.\n const onNotice = (message: string): void => context.onNotice(message);\n // Machine scope has no project, so the home directory stands in for Pi's cwd.\n const cwd = context.homeDirectory ?? nodeHost.homeDirectory();\n const settings = SettingsManager.create(cwd, directory);\n await preloadPiExtensions({\n cwd,\n agentDir: directory,\n models: runtime,\n extensionPaths: [\n ...(await resolvePiSettingsPackageEntries({\n cwd,\n agentDir: directory,\n settings,\n onNotice,\n })),\n // The fallback brings Pi's own extensions with it, as sessions load them: a custom\n // provider such as a local Vertex bridge lives there, not in auth.json.\n ...(modelDir !== directory &&\n (await pathExists(fs, path.join(modelDir, 'extensions'), BACKGROUND_CONTEXT).catch(() => false))\n ? [path.join(modelDir, 'extensions')]\n : []),\n ],\n onNotice,\n });\n return runtime;\n },\n });\n let closed = false;\n return {\n async fetch(request) {\n if (closed) return Response.json({ error: 'Provider mount is closed.' }, { status: 503 });\n const url = new URL(request.url);\n try {\n if (url.pathname === '/providers' && request.method === 'GET')\n return Response.json({ providers: await auth.listProviders() });\n if (url.pathname === '/models' && request.method === 'GET')\n return Response.json({ models: await auth.listModels() });\n const provider = /^\\/providers\\/([^/]+)$/u.exec(url.pathname);\n if (provider && request.method === 'DELETE') {\n const result = await auth.logout(decodeURIComponent(provider[1]));\n return result.ok\n ? Response.json({ ok: true })\n : Response.json({ error: result.error }, { status: result.code === 'unknown_provider' ? 404 : 502 });\n }\n if (url.pathname === '/logins' && request.method === 'POST') {\n const body: unknown = await request.json();\n if (\n !record(body) ||\n typeof body.providerId !== 'string' ||\n (body.type !== 'oauth' && body.type !== 'api_key')\n )\n return Response.json({ error: 'A provider and supported login method are required.' }, { status: 400 });\n const result = await auth.startLogin(body.providerId, body.type);\n return result.ok\n ? Response.json({ flow: result.flow }, { status: 201 })\n : Response.json(\n { error: result.error },\n { status: result.code === 'unknown_provider' ? 404 : result.code === 'busy' ? 409 : 400 },\n );\n }\n const flow = /^\\/logins\\/([^/]+)(\\/answer)?$/u.exec(url.pathname);\n if (flow) {\n const id = decodeURIComponent(flow[1]);\n if (!auth.getLogin(id)) return Response.json({ error: 'Login flow not found.' }, { status: 404 });\n if (flow[2] && request.method === 'POST') {\n const body: unknown = await request.json();\n if (!record(body) || typeof body.promptId !== 'string' || typeof body.value !== 'string')\n return Response.json({ error: 'A prompt ID and answer are required.' }, { status: 400 });\n const answer = auth.answerLogin(id, body.promptId, body.value);\n return answer === 'answered'\n ? Response.json({ flow: auth.getLogin(id) })\n : Response.json({ error: 'Login is no longer waiting for this answer.' }, { status: 409 });\n }\n if (!flow[2] && request.method === 'GET') return Response.json({ flow: auth.getLogin(id) });\n if (!flow[2] && request.method === 'DELETE') return Response.json({ flow: auth.cancelLogin(id) });\n }\n return Response.json({ error: 'Provider route not found.' }, { status: 404 });\n } catch (error) {\n return Response.json(\n { error: error instanceof Error ? error.message : String(error) },\n { status: error instanceof SyntaxError ? 400 : 502 },\n );\n }\n },\n close() {\n closed = true;\n auth.close();\n },\n };\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/machineApi.d.mts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { PoApi } from "./src/schemas/packageApi.mjs";
|
|
2
2
|
import "./packageApi.mjs";
|
|
3
|
+
import { FileSystem } from "@earendil-works/pi-durable/env";
|
|
3
4
|
//#region src/server/machineApi.d.ts
|
|
4
5
|
/** Machine-owned provider credentials and model catalog, available without a session. */
|
|
5
|
-
export declare
|
|
6
|
+
export declare function createMachineApi({ fs }: {
|
|
7
|
+
fs: FileSystem;
|
|
8
|
+
}): PoApi;
|
|
6
9
|
//#endregion
|
|
7
10
|
//# sourceMappingURL=machineApi.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machineApi.d.mts","names":[],"sources":["../src/server/machineApi.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"machineApi.d.mts","names":[],"sources":["../src/server/machineApi.ts"],"mappings":";;;;;wBAkBgB,mBAAmB;EAAQ,IAAI;IAAe"}
|
package/dist/machineApi.mjs
CHANGED
|
@@ -5,7 +5,6 @@ import { modelConfigDirectory } from "./src/services/piSettings/sync.mjs";
|
|
|
5
5
|
import "./runtimePiSettings.mjs";
|
|
6
6
|
import { registerChatgptAuthProvider } from "./src/services/chatgptLogin/index.mjs";
|
|
7
7
|
import { preloadPiExtensions, resolvePiSettingsPackageEntries } from "./src/services/piExtensionHost/index.mjs";
|
|
8
|
-
import { createNodePlatform } from "./nodePlatform.mjs";
|
|
9
8
|
import { createProviderAuth } from "./src/services/providerAuth/index.mjs";
|
|
10
9
|
import path from "node:path";
|
|
11
10
|
import { ModelRuntime, SettingsManager } from "@earendil-works/pi-coding-agent";
|
|
@@ -15,83 +14,84 @@ function record(value) {
|
|
|
15
14
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
16
15
|
}
|
|
17
16
|
/** Machine-owned provider credentials and model catalog, available without a session. */
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
cwd,
|
|
38
|
-
agentDir: directory,
|
|
39
|
-
models: runtime,
|
|
40
|
-
extensionPaths: [...await resolvePiSettingsPackageEntries({
|
|
17
|
+
function createMachineApi({ fs }) {
|
|
18
|
+
return {
|
|
19
|
+
basePath: "po",
|
|
20
|
+
start(context) {
|
|
21
|
+
if (context.scope !== "global") throw new Error("Provider authentication requires the global mount.");
|
|
22
|
+
const auth = createProviderAuth({
|
|
23
|
+
onNotice: (message) => context.onNotice(message),
|
|
24
|
+
runtime: async () => {
|
|
25
|
+
const directory = piAgentDirectory(context.environment, context.homeDirectory);
|
|
26
|
+
const modelDir = modelConfigDirectory(directory, context.homeDirectory);
|
|
27
|
+
const runtime = await ModelRuntime.create({
|
|
28
|
+
authPath: path.join(modelDir, "auth.json"),
|
|
29
|
+
modelsPath: path.join(modelDir, "models.json")
|
|
30
|
+
});
|
|
31
|
+
registerChatgptAuthProvider(runtime);
|
|
32
|
+
const onNotice = (message) => context.onNotice(message);
|
|
33
|
+
const cwd = context.homeDirectory ?? nodeHost.homeDirectory();
|
|
34
|
+
const settings = SettingsManager.create(cwd, directory);
|
|
35
|
+
await preloadPiExtensions({
|
|
41
36
|
cwd,
|
|
42
37
|
agentDir: directory,
|
|
43
|
-
|
|
38
|
+
models: runtime,
|
|
39
|
+
extensionPaths: [...await resolvePiSettingsPackageEntries({
|
|
40
|
+
cwd,
|
|
41
|
+
agentDir: directory,
|
|
42
|
+
settings,
|
|
43
|
+
onNotice
|
|
44
|
+
}), ...modelDir !== directory && await pathExists(fs, path.join(modelDir, "extensions"), BACKGROUND_CONTEXT).catch(() => false) ? [path.join(modelDir, "extensions")] : []],
|
|
44
45
|
onNotice
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
if (url.pathname === "/logins" && request.method === "POST") {
|
|
65
|
-
const body = await request.json();
|
|
66
|
-
if (!record(body) || typeof body.providerId !== "string" || body.type !== "oauth" && body.type !== "api_key") return Response.json({ error: "A provider and supported login method are required." }, { status: 400 });
|
|
67
|
-
const result = await auth.startLogin(body.providerId, body.type);
|
|
68
|
-
return result.ok ? Response.json({ flow: result.flow }, { status: 201 }) : Response.json({ error: result.error }, { status: result.code === "unknown_provider" ? 404 : result.code === "busy" ? 409 : 400 });
|
|
69
|
-
}
|
|
70
|
-
const flow = /^\/logins\/([^/]+)(\/answer)?$/u.exec(url.pathname);
|
|
71
|
-
if (flow) {
|
|
72
|
-
const id = decodeURIComponent(flow[1]);
|
|
73
|
-
if (!auth.getLogin(id)) return Response.json({ error: "Login flow not found." }, { status: 404 });
|
|
74
|
-
if (flow[2] && request.method === "POST") {
|
|
46
|
+
});
|
|
47
|
+
return runtime;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
let closed = false;
|
|
51
|
+
return {
|
|
52
|
+
async fetch(request) {
|
|
53
|
+
if (closed) return Response.json({ error: "Provider mount is closed." }, { status: 503 });
|
|
54
|
+
const url = new URL(request.url);
|
|
55
|
+
try {
|
|
56
|
+
if (url.pathname === "/providers" && request.method === "GET") return Response.json({ providers: await auth.listProviders() });
|
|
57
|
+
if (url.pathname === "/models" && request.method === "GET") return Response.json({ models: await auth.listModels() });
|
|
58
|
+
const provider = /^\/providers\/([^/]+)$/u.exec(url.pathname);
|
|
59
|
+
if (provider && request.method === "DELETE") {
|
|
60
|
+
const result = await auth.logout(decodeURIComponent(provider[1]));
|
|
61
|
+
return result.ok ? Response.json({ ok: true }) : Response.json({ error: result.error }, { status: result.code === "unknown_provider" ? 404 : 502 });
|
|
62
|
+
}
|
|
63
|
+
if (url.pathname === "/logins" && request.method === "POST") {
|
|
75
64
|
const body = await request.json();
|
|
76
|
-
if (!record(body) || typeof body.
|
|
77
|
-
|
|
65
|
+
if (!record(body) || typeof body.providerId !== "string" || body.type !== "oauth" && body.type !== "api_key") return Response.json({ error: "A provider and supported login method are required." }, { status: 400 });
|
|
66
|
+
const result = await auth.startLogin(body.providerId, body.type);
|
|
67
|
+
return result.ok ? Response.json({ flow: result.flow }, { status: 201 }) : Response.json({ error: result.error }, { status: result.code === "unknown_provider" ? 404 : result.code === "busy" ? 409 : 400 });
|
|
68
|
+
}
|
|
69
|
+
const flow = /^\/logins\/([^/]+)(\/answer)?$/u.exec(url.pathname);
|
|
70
|
+
if (flow) {
|
|
71
|
+
const id = decodeURIComponent(flow[1]);
|
|
72
|
+
if (!auth.getLogin(id)) return Response.json({ error: "Login flow not found." }, { status: 404 });
|
|
73
|
+
if (flow[2] && request.method === "POST") {
|
|
74
|
+
const body = await request.json();
|
|
75
|
+
if (!record(body) || typeof body.promptId !== "string" || typeof body.value !== "string") return Response.json({ error: "A prompt ID and answer are required." }, { status: 400 });
|
|
76
|
+
return auth.answerLogin(id, body.promptId, body.value) === "answered" ? Response.json({ flow: auth.getLogin(id) }) : Response.json({ error: "Login is no longer waiting for this answer." }, { status: 409 });
|
|
77
|
+
}
|
|
78
|
+
if (!flow[2] && request.method === "GET") return Response.json({ flow: auth.getLogin(id) });
|
|
79
|
+
if (!flow[2] && request.method === "DELETE") return Response.json({ flow: auth.cancelLogin(id) });
|
|
78
80
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
return Response.json({ error: "Provider route not found." }, { status: 404 });
|
|
82
|
+
} catch (error) {
|
|
83
|
+
return Response.json({ error: error instanceof Error ? error.message : String(error) }, { status: error instanceof SyntaxError ? 400 : 502 });
|
|
81
84
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
},
|
|
86
|
+
close() {
|
|
87
|
+
closed = true;
|
|
88
|
+
auth.close();
|
|
85
89
|
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
};
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
94
|
//#endregion
|
|
95
|
-
export {
|
|
95
|
+
export { createMachineApi };
|
|
96
96
|
|
|
97
97
|
//# sourceMappingURL=machineApi.mjs.map
|
package/dist/machineApi.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machineApi.mjs","names":[],"sources":["../src/server/machineApi.ts"],"sourcesContent":["import path from 'node:path';\n\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport { ModelRuntime, SettingsManager } from '@earendil-works/pi-coding-agent';\
|
|
1
|
+
{"version":3,"file":"machineApi.mjs","names":[],"sources":["../src/server/machineApi.ts"],"sourcesContent":["import path from 'node:path';\n\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport { ModelRuntime, SettingsManager } from '@earendil-works/pi-coding-agent';\nimport type { FileSystem } from '@earendil-works/pi-durable/env';\n\nimport type { PoApi } from '../exports/packageApi';\nimport { registerChatgptAuthProvider } from '../services/chatgptLogin';\nimport { nodeHost } from '../services/nodeHost';\nimport { preloadPiExtensions, resolvePiSettingsPackageEntries } from '../services/piExtensionHost';\nimport { modelConfigDirectory, piAgentDirectory } from '../services/piSettings';\nimport { pathExists } from '../services/platformFiles';\nimport { createProviderAuth } from '../services/providerAuth';\n\nfunction record(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n/** Machine-owned provider credentials and model catalog, available without a session. */\nexport function createMachineApi({ fs }: { fs: FileSystem }): PoApi {\n return {\n basePath: 'po',\n start(context) {\n if (context.scope !== 'global') throw new Error('Provider authentication requires the global mount.');\n const auth = createProviderAuth({\n onNotice: (message) => context.onNotice(message),\n runtime: async () => {\n const directory = piAgentDirectory(context.environment, context.homeDirectory);\n // Resolved as sessions resolve it (headlessSessionHost): with no model config of its\n // own, Po falls back to plain Pi's ~/.pi/agent, so this catalog matches the session picker.\n const modelDir = modelConfigDirectory(directory, context.homeDirectory);\n const runtime = await ModelRuntime.create({\n authPath: path.join(modelDir, 'auth.json'),\n modelsPath: path.join(modelDir, 'models.json'),\n });\n registerChatgptAuthProvider(runtime);\n // Providers registered by Pi settings packages (a Claude Code bridge, say) are\n // listed and pickable here as they are in sessions, which load the same packages.\n const onNotice = (message: string): void => context.onNotice(message);\n // Machine scope has no project, so the home directory stands in for Pi's cwd.\n const cwd = context.homeDirectory ?? nodeHost.homeDirectory();\n const settings = SettingsManager.create(cwd, directory);\n await preloadPiExtensions({\n cwd,\n agentDir: directory,\n models: runtime,\n extensionPaths: [\n ...(await resolvePiSettingsPackageEntries({\n cwd,\n agentDir: directory,\n settings,\n onNotice,\n })),\n // The fallback brings Pi's own extensions with it, as sessions load them: a custom\n // provider such as a local Vertex bridge lives there, not in auth.json.\n ...(modelDir !== directory &&\n (await pathExists(fs, path.join(modelDir, 'extensions'), BACKGROUND_CONTEXT).catch(() => false))\n ? [path.join(modelDir, 'extensions')]\n : []),\n ],\n onNotice,\n });\n return runtime;\n },\n });\n let closed = false;\n return {\n async fetch(request) {\n if (closed) return Response.json({ error: 'Provider mount is closed.' }, { status: 503 });\n const url = new URL(request.url);\n try {\n if (url.pathname === '/providers' && request.method === 'GET')\n return Response.json({ providers: await auth.listProviders() });\n if (url.pathname === '/models' && request.method === 'GET')\n return Response.json({ models: await auth.listModels() });\n const provider = /^\\/providers\\/([^/]+)$/u.exec(url.pathname);\n if (provider && request.method === 'DELETE') {\n const result = await auth.logout(decodeURIComponent(provider[1]));\n return result.ok\n ? Response.json({ ok: true })\n : Response.json({ error: result.error }, { status: result.code === 'unknown_provider' ? 404 : 502 });\n }\n if (url.pathname === '/logins' && request.method === 'POST') {\n const body: unknown = await request.json();\n if (\n !record(body) ||\n typeof body.providerId !== 'string' ||\n (body.type !== 'oauth' && body.type !== 'api_key')\n )\n return Response.json({ error: 'A provider and supported login method are required.' }, { status: 400 });\n const result = await auth.startLogin(body.providerId, body.type);\n return result.ok\n ? Response.json({ flow: result.flow }, { status: 201 })\n : Response.json(\n { error: result.error },\n { status: result.code === 'unknown_provider' ? 404 : result.code === 'busy' ? 409 : 400 },\n );\n }\n const flow = /^\\/logins\\/([^/]+)(\\/answer)?$/u.exec(url.pathname);\n if (flow) {\n const id = decodeURIComponent(flow[1]);\n if (!auth.getLogin(id)) return Response.json({ error: 'Login flow not found.' }, { status: 404 });\n if (flow[2] && request.method === 'POST') {\n const body: unknown = await request.json();\n if (!record(body) || typeof body.promptId !== 'string' || typeof body.value !== 'string')\n return Response.json({ error: 'A prompt ID and answer are required.' }, { status: 400 });\n const answer = auth.answerLogin(id, body.promptId, body.value);\n return answer === 'answered'\n ? Response.json({ flow: auth.getLogin(id) })\n : Response.json({ error: 'Login is no longer waiting for this answer.' }, { status: 409 });\n }\n if (!flow[2] && request.method === 'GET') return Response.json({ flow: auth.getLogin(id) });\n if (!flow[2] && request.method === 'DELETE') return Response.json({ flow: auth.cancelLogin(id) });\n }\n return Response.json({ error: 'Provider route not found.' }, { status: 404 });\n } catch (error) {\n return Response.json(\n { error: error instanceof Error ? error.message : String(error) },\n { status: error instanceof SyntaxError ? 400 : 502 },\n );\n }\n },\n close() {\n closed = true;\n auth.close();\n },\n };\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/sessionFilesApi.cjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
|
|
3
|
-
const require_nodePlatform = require("./nodePlatform.cjs");
|
|
4
3
|
let node_path = require("node:path");
|
|
5
4
|
node_path = require_runtime.__toESM(node_path, 1);
|
|
6
5
|
let _earendil_works_pi_durable_env = require("@earendil-works/pi-durable/env");
|
|
@@ -67,34 +66,35 @@ async function listSessionFiles(fs, cwd, query, signal) {
|
|
|
67
66
|
}
|
|
68
67
|
return matches.sort().slice(0, MAX_FILE_RESULTS);
|
|
69
68
|
}
|
|
70
|
-
/** Bounded, read-only file completion rooted in the owning session. */
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
69
|
+
/** Bounded, read-only file completion rooted in the owning session, read through the server's platform fs. */
|
|
70
|
+
function createSessionFilesApi({ fs }) {
|
|
71
|
+
return {
|
|
72
|
+
basePath: "files",
|
|
73
|
+
start(context) {
|
|
74
|
+
if (context.scope !== "session" || !context.cwd) throw new Error("File completion requires a session.");
|
|
75
|
+
const cwd = context.cwd;
|
|
76
|
+
let closed = false;
|
|
77
|
+
return {
|
|
78
|
+
async fetch(request) {
|
|
79
|
+
if (closed) return new Response(null, { status: 503 });
|
|
80
|
+
const url = new URL(request.url);
|
|
81
|
+
if (request.method !== "GET" || url.pathname !== "/") return new Response(null, { status: 404 });
|
|
82
|
+
const query = (url.searchParams.get("q") ?? "").toLowerCase();
|
|
83
|
+
if (query.length > 256) return Response.json({ error: "File query is too long." }, { status: 400 });
|
|
84
|
+
try {
|
|
85
|
+
return Response.json({ files: await listSessionFiles(fs, cwd, query, request.signal) });
|
|
86
|
+
} catch {
|
|
87
|
+
return Response.json({ error: "File completion could not be read." }, { status: 503 });
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
close() {
|
|
91
|
+
closed = true;
|
|
89
92
|
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
};
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
97
|
//#endregion
|
|
98
|
-
exports.
|
|
98
|
+
exports.createSessionFilesApi = createSessionFilesApi;
|
|
99
99
|
|
|
100
100
|
//# sourceMappingURL=sessionFilesApi.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionFilesApi.cjs","names":["path","withAbortSignal","BACKGROUND_CONTEXT","getOrThrow"
|
|
1
|
+
{"version":3,"file":"sessionFilesApi.cjs","names":["path","withAbortSignal","BACKGROUND_CONTEXT","getOrThrow"],"sources":["../src/server/sessionFilesApi.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT, withAbortSignal } from '@earendil-works/chord/context';\nimport { getOrThrow, type FileSystem } from '@earendil-works/pi-durable/env';\nimport ignore from 'ignore';\n\nimport type { PoApi } from '../exports/packageApi';\n\nconst EXCLUDED_DIRECTORIES = new Set(['.git', 'node_modules']);\nconst IGNORE_FILES = ['.gitignore', '.poignore'];\nconst FILE_QUERY_TIMEOUT_MS = 2000;\nconst MAX_FILE_RESULTS = 50;\n\n/**\n * The project's ignore test, or nothing when it declares no rules.\n *\n * Only the session root's files are read. A nested .gitignore would need one\n * matcher per directory, and the cost of skipping it is a suggestion that\n * should not have been offered rather than a file that cannot be opened. An\n * unreadable or malformed file leaves completion listing everything, because\n * hiding the tree is the worse failure.\n */\nasync function readIgnoreRules(\n fs: FileSystem,\n cwd: string,\n context: Context,\n): Promise<((relativePath: string) => boolean) | undefined> {\n const rules = (\n await Promise.all(\n IGNORE_FILES.map(async (name) => {\n try {\n const result = await fs.readTextFile(path.join(cwd, name), context);\n return result.ok ? result.value : '';\n } catch {\n return '';\n }\n }),\n )\n ).join('\\n');\n if (rules.trim().length === 0) return undefined;\n try {\n const matcher = ignore().add(rules);\n return (relativePath: string): boolean => matcher.ignores(relativePath);\n } catch {\n return undefined;\n }\n}\n\nasync function listSessionFiles(fs: FileSystem, cwd: string, query: string, signal: AbortSignal): Promise<string[]> {\n const context = withAbortSignal(signal, BACKGROUND_CONTEXT);\n const isIgnored = await readIgnoreRules(fs, cwd, context);\n const deadline = Date.now() + FILE_QUERY_TIMEOUT_MS;\n const pending = [''];\n let next = 0;\n const matches: string[] = [];\n\n while (next < pending.length && matches.length < MAX_FILE_RESULTS) {\n if (signal.aborted) {\n throw signal.reason instanceof Error ? signal.reason : new Error('File completion was aborted.');\n }\n // ponytail: Return matches found so far on huge trees; a search index is the upgrade path.\n if (Date.now() > deadline && next > 0) break;\n const relativeDirectory = pending[next++];\n if (relativeDirectory === undefined) break;\n if (relativeDirectory !== '' && `${relativeDirectory}/`.toLowerCase().includes(query)) {\n matches.push(`${relativeDirectory}/`);\n }\n if (matches.length === MAX_FILE_RESULTS) break;\n const entries = getOrThrow(await fs.listDir(path.join(cwd, relativeDirectory), context));\n const matchingDirectories: string[] = [];\n for (const entry of entries) {\n // Ignore rules are written in posix form, and so is every result.\n const file = relativeDirectory === '' ? entry.name : `${relativeDirectory}/${entry.name}`;\n if (entry.kind === 'directory') {\n // An ignored directory is pruned rather than filtered at its leaves:\n // walking a build cache is what exhausts the completion budget. The\n // trailing slash is what makes a directory-only rule such as\n // '.nx-cache/' match.\n if (EXCLUDED_DIRECTORIES.has(entry.name) || isIgnored?.(`${file}/`) === true) continue;\n // Explore a matching folder before its siblings so its files follow it.\n if (query && entry.name.toLowerCase().includes(query)) matchingDirectories.push(file);\n else pending.push(file);\n } else if (entry.kind === 'file' && isIgnored?.(file) !== true && file.toLowerCase().includes(query)) {\n matches.push(file);\n }\n if (matches.length === MAX_FILE_RESULTS) break;\n }\n pending.splice(next, 0, ...matchingDirectories);\n }\n\n return matches.sort().slice(0, MAX_FILE_RESULTS);\n}\n\n/** Bounded, read-only file completion rooted in the owning session, read through the server's platform fs. */\nexport function createSessionFilesApi({ fs }: { fs: FileSystem }): PoApi {\n return {\n basePath: 'files',\n start(context) {\n if (context.scope !== 'session' || !context.cwd) throw new Error('File completion requires a session.');\n const cwd = context.cwd;\n let closed = false;\n return {\n async fetch(request) {\n if (closed) return new Response(null, { status: 503 });\n const url = new URL(request.url);\n if (request.method !== 'GET' || url.pathname !== '/') return new Response(null, { status: 404 });\n const query = (url.searchParams.get('q') ?? '').toLowerCase();\n if (query.length > 256) return Response.json({ error: 'File query is too long.' }, { status: 400 });\n try {\n return Response.json({ files: await listSessionFiles(fs, cwd, query, request.signal) });\n } catch {\n return Response.json({ error: 'File completion could not be read.' }, { status: 503 });\n }\n },\n close() {\n closed = true;\n },\n };\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { PoApi } from "./src/schemas/packageApi.mjs";
|
|
2
2
|
import "./packageApi.mjs";
|
|
3
|
+
import { FileSystem } from "@earendil-works/pi-durable/env";
|
|
3
4
|
//#region src/server/sessionFilesApi.d.ts
|
|
4
|
-
/** Bounded, read-only file completion rooted in the owning session. */
|
|
5
|
-
export declare
|
|
5
|
+
/** Bounded, read-only file completion rooted in the owning session, read through the server's platform fs. */
|
|
6
|
+
export declare function createSessionFilesApi({ fs }: {
|
|
7
|
+
fs: FileSystem;
|
|
8
|
+
}): PoApi;
|
|
6
9
|
//#endregion
|
|
7
10
|
//# sourceMappingURL=sessionFilesApi.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionFilesApi.d.mts","names":[],"sources":["../src/server/sessionFilesApi.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"sessionFilesApi.d.mts","names":[],"sources":["../src/server/sessionFilesApi.ts"],"mappings":";;;;;wBA+FgB,wBAAwB;EAAQ,IAAI;IAAe"}
|