@psnext/slingcli 2.5.20260623-1 → 2.5.20260629-1
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/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +5 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +2 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.js +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +51 -47
- package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js +9 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +9 -6
- package/node_modules/@earendil-works/pi-ai/dist/api/cloudflare.js +0 -18
- package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js +6 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js +6 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +15 -25
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +30 -26
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +189 -204
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +24 -21
- package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js +2 -5
- package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.js +11 -2
- package/node_modules/@earendil-works/pi-ai/dist/auth/helpers.js +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +19 -4
- package/node_modules/@earendil-works/pi-ai/dist/compat.js +81 -7
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +45 -0
- package/node_modules/@earendil-works/pi-ai/dist/images-models.js +7 -3
- package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/legacy-api-aliases.js +49 -0
- package/node_modules/@earendil-works/pi-ai/dist/models.js +7 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js +25 -8
- package/node_modules/@earendil-works/pi-ai/dist/providers/ant-ling.models.js +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.js +0 -34
- package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.js +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.js +21 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-auth.js +85 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.js +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.models.js +13 -13
- package/node_modules/@earendil-works/pi-ai/dist/providers/deepseek.models.js +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js +1 -20
- package/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.models.js +19 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/huggingface.models.js +72 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/minimax-cn.models.js +4 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/minimax.models.js +4 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.models.js +19 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js +11 -11
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.js +15 -15
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +310 -39
- package/node_modules/@earendil-works/pi-ai/dist/providers/together.models.js +37 -18
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +349 -77
- package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js +7 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/zai-coding-cn.models.js +6 -6
- package/node_modules/@earendil-works/pi-ai/dist/providers/zai.models.js +6 -6
- package/node_modules/@earendil-works/pi-ai/dist/utils/estimate.js +95 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/headers.js +10 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +86 -0
- package/node_modules/@earendil-works/pi-ai/package.json +1 -33
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/file-processor.js +13 -25
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +15 -30
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +6 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +5 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +2 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +9 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +11 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/timings.js +24 -14
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +12 -25
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +20 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +9 -9
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/extension-editor.js +12 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/session-selector.js +14 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +37 -25
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.js +14 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +16 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/rpc-entry.js +10 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-convert.js +21 -15
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-process.js +83 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/mime.js +41 -0
- package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +12 -12
- package/node_modules/@earendil-works/pi-coding-agent/package.json +8 -5
- package/node_modules/@earendil-works/pi-orchestrator/dist/cli.js +136 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/config.js +55 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/handler.js +105 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/index.js +11 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/ipc/client.js +56 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/ipc/protocol.js +12 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/ipc/server.js +145 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/radius.js +365 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/rpc-process.js +168 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/serve.js +70 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/storage.js +58 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/supervisor.js +290 -0
- package/node_modules/@earendil-works/pi-orchestrator/dist/types.js +2 -0
- package/node_modules/@earendil-works/pi-orchestrator/package.json +45 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +3 -0
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/diagnostics_channel.d.ts +17 -20
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/brace-expansion/dist/commonjs/index.js +24 -14
- package/node_modules/brace-expansion/dist/commonjs/index.js.map +1 -1
- package/node_modules/brace-expansion/dist/esm/index.js +24 -14
- package/node_modules/brace-expansion/dist/esm/index.js.map +1 -1
- package/node_modules/brace-expansion/package.json +2 -2
- package/node_modules/google-auth-library/build/src/auth/googleauth.js +1 -1
- package/node_modules/google-auth-library/package.json +4 -4
- package/package.json +7 -6
- package/slingshot/index.js +302 -304
- package/node_modules/@earendil-works/pi-ai/dist/api-registry.js +0 -44
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { APP_NAME } from "./config.js";
|
|
3
|
+
import { configureHttpDispatcher } from "./core/http-dispatcher.js";
|
|
4
|
+
import { main } from "./main.js";
|
|
5
|
+
process.title = `${APP_NAME}-rpc`;
|
|
6
|
+
process.env.PI_CODING_AGENT = "true";
|
|
7
|
+
process.emitWarning = (() => { });
|
|
8
|
+
configureHttpDispatcher();
|
|
9
|
+
main(["--mode", "rpc", ...process.argv.slice(2)]);
|
|
10
|
+
//# sourceMappingURL=rpc-entry.js.map
|
|
@@ -1,31 +1,18 @@
|
|
|
1
1
|
import { applyExifOrientation } from "./exif-orientation.js";
|
|
2
2
|
import { loadPhoton } from "./photon.js";
|
|
3
|
-
|
|
4
|
-
* Convert image to PNG format for terminal display.
|
|
5
|
-
* Kitty graphics protocol requires PNG format (f=100).
|
|
6
|
-
*/
|
|
7
|
-
export async function convertToPng(base64Data, mimeType) {
|
|
8
|
-
// Already PNG, no conversion needed
|
|
9
|
-
if (mimeType === "image/png") {
|
|
10
|
-
return { data: base64Data, mimeType };
|
|
11
|
-
}
|
|
3
|
+
export async function convertImageBytesToPng(bytes) {
|
|
12
4
|
const photon = await loadPhoton();
|
|
13
5
|
if (!photon) {
|
|
14
6
|
// Photon not available, can't convert
|
|
15
7
|
return null;
|
|
16
8
|
}
|
|
17
9
|
try {
|
|
18
|
-
const bytes = new Uint8Array(Buffer.from(base64Data, "base64"));
|
|
19
10
|
const rawImage = photon.PhotonImage.new_from_byteslice(bytes);
|
|
20
11
|
const image = applyExifOrientation(photon, rawImage, bytes);
|
|
21
12
|
if (image !== rawImage)
|
|
22
13
|
rawImage.free();
|
|
23
14
|
try {
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
data: Buffer.from(pngBuffer).toString("base64"),
|
|
27
|
-
mimeType: "image/png",
|
|
28
|
-
};
|
|
15
|
+
return new Uint8Array(image.get_bytes());
|
|
29
16
|
}
|
|
30
17
|
finally {
|
|
31
18
|
image.free();
|
|
@@ -36,4 +23,23 @@ export async function convertToPng(base64Data, mimeType) {
|
|
|
36
23
|
return null;
|
|
37
24
|
}
|
|
38
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Convert image to PNG format for terminal display.
|
|
28
|
+
* Kitty graphics protocol requires PNG format (f=100).
|
|
29
|
+
*/
|
|
30
|
+
export async function convertToPng(base64Data, mimeType) {
|
|
31
|
+
// Already PNG, no conversion needed
|
|
32
|
+
if (mimeType === "image/png") {
|
|
33
|
+
return { data: base64Data, mimeType };
|
|
34
|
+
}
|
|
35
|
+
const bytes = new Uint8Array(Buffer.from(base64Data, "base64"));
|
|
36
|
+
const pngBytes = await convertImageBytesToPng(bytes);
|
|
37
|
+
if (!pngBytes) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
data: Buffer.from(pngBytes).toString("base64"),
|
|
42
|
+
mimeType: "image/png",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
39
45
|
//# sourceMappingURL=image-convert.js.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { convertImageBytesToPng } from "./image-convert.js";
|
|
2
|
+
import { formatDimensionNote, resizeImage } from "./image-resize.js";
|
|
3
|
+
function baseMimeType(mimeType) {
|
|
4
|
+
return mimeType.split(";")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();
|
|
5
|
+
}
|
|
6
|
+
function normalizeSupportedImageMimeType(mimeType) {
|
|
7
|
+
switch (baseMimeType(mimeType)) {
|
|
8
|
+
case "image/png":
|
|
9
|
+
return "image/png";
|
|
10
|
+
case "image/jpeg":
|
|
11
|
+
case "image/jpg":
|
|
12
|
+
return "image/jpeg";
|
|
13
|
+
case "image/gif":
|
|
14
|
+
return "image/gif";
|
|
15
|
+
case "image/webp":
|
|
16
|
+
return "image/webp";
|
|
17
|
+
default:
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function normalizeImage(bytes, mimeType) {
|
|
22
|
+
const normalizedMimeType = normalizeSupportedImageMimeType(mimeType);
|
|
23
|
+
if (normalizedMimeType) {
|
|
24
|
+
return { bytes, mimeType: normalizedMimeType };
|
|
25
|
+
}
|
|
26
|
+
const pngBytes = await convertImageBytesToPng(bytes);
|
|
27
|
+
if (!pngBytes) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
bytes: pngBytes,
|
|
32
|
+
mimeType: "image/png",
|
|
33
|
+
convertedFrom: baseMimeType(mimeType),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function conversionHint(from, to) {
|
|
37
|
+
if (!from || from === to)
|
|
38
|
+
return undefined;
|
|
39
|
+
return `[Image converted from ${from} to ${to}.]`;
|
|
40
|
+
}
|
|
41
|
+
export async function processImage(bytes, mimeType, options) {
|
|
42
|
+
const autoResizeImages = options?.autoResizeImages ?? true;
|
|
43
|
+
const normalized = await normalizeImage(bytes, mimeType);
|
|
44
|
+
if (!normalized) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
message: "[Image omitted: could not be converted to a supported inline image format.]",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (autoResizeImages) {
|
|
51
|
+
const resized = await resizeImage(normalized.bytes, normalized.mimeType, options?.resizeOptions);
|
|
52
|
+
if (!resized) {
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
message: "[Image omitted: could not be resized below the inline image size limit.]",
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const hints = [];
|
|
59
|
+
const convertedHint = conversionHint(normalized.convertedFrom, resized.mimeType);
|
|
60
|
+
if (convertedHint)
|
|
61
|
+
hints.push(convertedHint);
|
|
62
|
+
const dimensionNote = formatDimensionNote(resized);
|
|
63
|
+
if (dimensionNote)
|
|
64
|
+
hints.push(dimensionNote);
|
|
65
|
+
return {
|
|
66
|
+
ok: true,
|
|
67
|
+
data: resized.data,
|
|
68
|
+
mimeType: resized.mimeType,
|
|
69
|
+
hints,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const hints = [];
|
|
73
|
+
const convertedHint = conversionHint(normalized.convertedFrom, normalized.mimeType);
|
|
74
|
+
if (convertedHint)
|
|
75
|
+
hints.push(convertedHint);
|
|
76
|
+
return {
|
|
77
|
+
ok: true,
|
|
78
|
+
data: Buffer.from(normalized.bytes).toString("base64"),
|
|
79
|
+
mimeType: normalized.mimeType,
|
|
80
|
+
hints,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=image-process.js.map
|
|
@@ -14,6 +14,9 @@ export function detectSupportedImageMimeType(buffer) {
|
|
|
14
14
|
if (startsWithAscii(buffer, 0, "RIFF") && startsWithAscii(buffer, 8, "WEBP")) {
|
|
15
15
|
return "image/webp";
|
|
16
16
|
}
|
|
17
|
+
if (startsWithAscii(buffer, 0, "BM") && isBmp(buffer)) {
|
|
18
|
+
return "image/bmp";
|
|
19
|
+
}
|
|
17
20
|
return null;
|
|
18
21
|
}
|
|
19
22
|
export async function detectSupportedImageMimeTypeFromFile(filePath) {
|
|
@@ -46,12 +49,50 @@ function isAnimatedPng(buffer) {
|
|
|
46
49
|
}
|
|
47
50
|
return false;
|
|
48
51
|
}
|
|
52
|
+
function isBmp(buffer) {
|
|
53
|
+
if (buffer.length < 26)
|
|
54
|
+
return false;
|
|
55
|
+
const declaredFileSize = readUint32LE(buffer, 2);
|
|
56
|
+
const pixelDataOffset = readUint32LE(buffer, 10);
|
|
57
|
+
const dibHeaderSize = readUint32LE(buffer, 14);
|
|
58
|
+
if (declaredFileSize !== 0 && declaredFileSize < 26)
|
|
59
|
+
return false;
|
|
60
|
+
if (pixelDataOffset < 14 + dibHeaderSize)
|
|
61
|
+
return false;
|
|
62
|
+
if (declaredFileSize !== 0 && pixelDataOffset >= declaredFileSize)
|
|
63
|
+
return false;
|
|
64
|
+
let colorPlanes;
|
|
65
|
+
let bitsPerPixel;
|
|
66
|
+
if (dibHeaderSize === 12) {
|
|
67
|
+
colorPlanes = readUint16LE(buffer, 22);
|
|
68
|
+
bitsPerPixel = readUint16LE(buffer, 24);
|
|
69
|
+
}
|
|
70
|
+
else if (dibHeaderSize >= 40 && dibHeaderSize <= 124) {
|
|
71
|
+
if (buffer.length < 30)
|
|
72
|
+
return false;
|
|
73
|
+
colorPlanes = readUint16LE(buffer, 26);
|
|
74
|
+
bitsPerPixel = readUint16LE(buffer, 28);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return colorPlanes === 1 && [1, 4, 8, 16, 24, 32].includes(bitsPerPixel);
|
|
80
|
+
}
|
|
81
|
+
function readUint16LE(buffer, offset) {
|
|
82
|
+
return (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8);
|
|
83
|
+
}
|
|
49
84
|
function readUint32BE(buffer, offset) {
|
|
50
85
|
return ((buffer[offset] ?? 0) * 0x1000000 +
|
|
51
86
|
((buffer[offset + 1] ?? 0) << 16) +
|
|
52
87
|
((buffer[offset + 2] ?? 0) << 8) +
|
|
53
88
|
(buffer[offset + 3] ?? 0));
|
|
54
89
|
}
|
|
90
|
+
function readUint32LE(buffer, offset) {
|
|
91
|
+
return ((buffer[offset] ?? 0) +
|
|
92
|
+
((buffer[offset + 1] ?? 0) << 8) +
|
|
93
|
+
((buffer[offset + 2] ?? 0) << 16) +
|
|
94
|
+
(buffer[offset + 3] ?? 0) * 0x1000000);
|
|
95
|
+
}
|
|
55
96
|
function startsWith(buffer, bytes) {
|
|
56
97
|
if (buffer.length < bytes.length)
|
|
57
98
|
return false;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-coding-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.80.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@earendil-works/pi-coding-agent",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.80.2",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
13
|
-
"@earendil-works/pi-ai": "^0.
|
|
14
|
-
"@earendil-works/pi-tui": "^0.
|
|
12
|
+
"@earendil-works/pi-agent-core": "^0.80.2",
|
|
13
|
+
"@earendil-works/pi-ai": "^0.80.2",
|
|
14
|
+
"@earendil-works/pi-tui": "^0.80.2",
|
|
15
15
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
16
16
|
"chalk": "5.6.2",
|
|
17
17
|
"cross-spawn": "7.0.6",
|
|
@@ -474,11 +474,11 @@
|
|
|
474
474
|
}
|
|
475
475
|
},
|
|
476
476
|
"node_modules/@earendil-works/pi-agent-core": {
|
|
477
|
-
"version": "0.
|
|
478
|
-
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.
|
|
477
|
+
"version": "0.80.2",
|
|
478
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.80.2.tgz",
|
|
479
479
|
"license": "MIT",
|
|
480
480
|
"dependencies": {
|
|
481
|
-
"@earendil-works/pi-ai": "^0.
|
|
481
|
+
"@earendil-works/pi-ai": "^0.80.2",
|
|
482
482
|
"ignore": "7.0.5",
|
|
483
483
|
"typebox": "1.1.38",
|
|
484
484
|
"yaml": "2.9.0"
|
|
@@ -488,8 +488,8 @@
|
|
|
488
488
|
}
|
|
489
489
|
},
|
|
490
490
|
"node_modules/@earendil-works/pi-ai": {
|
|
491
|
-
"version": "0.
|
|
492
|
-
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.
|
|
491
|
+
"version": "0.80.2",
|
|
492
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.80.2.tgz",
|
|
493
493
|
"license": "MIT",
|
|
494
494
|
"dependencies": {
|
|
495
495
|
"@anthropic-ai/sdk": "0.91.1",
|
|
@@ -512,8 +512,8 @@
|
|
|
512
512
|
}
|
|
513
513
|
},
|
|
514
514
|
"node_modules/@earendil-works/pi-tui": {
|
|
515
|
-
"version": "0.
|
|
516
|
-
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.
|
|
515
|
+
"version": "0.80.2",
|
|
516
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.80.2.tgz",
|
|
517
517
|
"license": "MIT",
|
|
518
518
|
"dependencies": {
|
|
519
519
|
"get-east-asian-width": "1.6.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-coding-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.80.2",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"piConfig": {
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
".": {
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
18
18
|
"import": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./rpc-entry": {
|
|
21
|
+
"import": "./dist/rpc-entry.js"
|
|
19
22
|
}
|
|
20
23
|
},
|
|
21
24
|
"files": [
|
|
@@ -28,7 +31,7 @@
|
|
|
28
31
|
],
|
|
29
32
|
"scripts": {
|
|
30
33
|
"clean": "shx rm -rf dist",
|
|
31
|
-
"build": "tsgo -p tsconfig.build.json && shx chmod +x dist/cli.js && npm run copy-assets",
|
|
34
|
+
"build": "tsgo -p tsconfig.build.json && shx chmod +x dist/cli.js dist/rpc-entry.js && npm run copy-assets",
|
|
32
35
|
"build:binary": "npm --prefix ../tui run build && npm --prefix ../ai run build && npm --prefix ../agent run build && npm run build && bun build --compile ./dist/bun/cli.js ./src/utils/image-resize-worker.ts --outfile dist/pi && npm run copy-binary-assets",
|
|
33
36
|
"copy-assets": "shx mkdir -p dist/modes/interactive/theme && shx cp src/modes/interactive/theme/*.json dist/modes/interactive/theme/ && shx mkdir -p dist/modes/interactive/assets && shx cp src/modes/interactive/assets/*.png dist/modes/interactive/assets/ && shx mkdir -p dist/core/export-html/vendor && shx cp src/core/export-html/template.html src/core/export-html/template.css src/core/export-html/template.js dist/core/export-html/ && shx cp src/core/export-html/vendor/*.js dist/core/export-html/vendor/",
|
|
34
37
|
"copy-binary-assets": "shx cp package.json dist/ && shx cp README.md dist/ && shx cp CHANGELOG.md dist/ && shx mkdir -p dist/theme && shx cp src/modes/interactive/theme/*.json dist/theme/ && shx mkdir -p dist/assets && shx cp src/modes/interactive/assets/*.png dist/assets/ && shx mkdir -p dist/export-html/vendor && shx cp src/core/export-html/template.html dist/export-html/ && shx cp src/core/export-html/vendor/*.js dist/export-html/vendor/ && shx cp -r docs dist/ && shx cp -r examples dist/ && shx cp ../../node_modules/@silvia-odwyer/photon-node/photon_rs_bg.wasm dist/",
|
|
@@ -37,9 +40,9 @@
|
|
|
37
40
|
"prepublishOnly": "npm run clean && npm run build && npm run shrinkwrap"
|
|
38
41
|
},
|
|
39
42
|
"dependencies": {
|
|
40
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
41
|
-
"@earendil-works/pi-ai": "^0.
|
|
42
|
-
"@earendil-works/pi-tui": "^0.
|
|
43
|
+
"@earendil-works/pi-agent-core": "^0.80.2",
|
|
44
|
+
"@earendil-works/pi-ai": "^0.80.2",
|
|
45
|
+
"@earendil-works/pi-tui": "^0.80.2",
|
|
43
46
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
44
47
|
"chalk": "5.6.2",
|
|
45
48
|
"cross-spawn": "7.0.6",
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { createConnection } from "node:net";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { cwd } from "node:process";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { getSocketPath } from "./config.js";
|
|
8
|
+
import { sendIpcRequest } from "./ipc/client.js";
|
|
9
|
+
import { encodeMessage } from "./ipc/protocol.js";
|
|
10
|
+
import { serve } from "./serve.js";
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
|
|
14
|
+
function printHelp() {
|
|
15
|
+
console.log(`orchestrator v${packageJson.version}\n\nUsage:\n orchestrator serve\n orchestrator list\n orchestrator spawn [--cwd <path>] [--label <label>]\n orchestrator status <instance-id>\n orchestrator stop <instance-id>\n orchestrator rpc <instance-id> <json-command>\n orchestrator rpc-stream <instance-id>\n orchestrator --help\n orchestrator --version\n\nRPC stream stdin expects JSONL RpcCommand or extension_ui_response messages.`);
|
|
16
|
+
}
|
|
17
|
+
function printResponse(response) {
|
|
18
|
+
console.log(JSON.stringify(response, null, 2));
|
|
19
|
+
}
|
|
20
|
+
function getFlagValue(args, flag) {
|
|
21
|
+
const index = args.indexOf(flag);
|
|
22
|
+
if (index === -1 || index + 1 >= args.length) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return args[index + 1];
|
|
26
|
+
}
|
|
27
|
+
async function rpcStream(instanceId) {
|
|
28
|
+
const socket = createConnection(getSocketPath());
|
|
29
|
+
let stdinBuffer = "";
|
|
30
|
+
process.stdin.setEncoding("utf8");
|
|
31
|
+
await new Promise((resolve, reject) => {
|
|
32
|
+
socket.once("connect", () => {
|
|
33
|
+
socket.write(encodeMessage({ type: "rpc_stream", instanceId }));
|
|
34
|
+
resolve();
|
|
35
|
+
});
|
|
36
|
+
socket.once("error", reject);
|
|
37
|
+
});
|
|
38
|
+
socket.on("data", (chunk) => {
|
|
39
|
+
process.stdout.write(chunk.toString());
|
|
40
|
+
});
|
|
41
|
+
console.error(`connected to rpc stream ${instanceId}; send JSONL RpcCommand or extension_ui_response on stdin`);
|
|
42
|
+
socket.on("error", (error) => {
|
|
43
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
44
|
+
process.exit(1);
|
|
45
|
+
});
|
|
46
|
+
socket.on("end", () => {
|
|
47
|
+
process.exit(0);
|
|
48
|
+
});
|
|
49
|
+
process.stdin.on("data", (chunk) => {
|
|
50
|
+
stdinBuffer += chunk;
|
|
51
|
+
while (true) {
|
|
52
|
+
const newlineIndex = stdinBuffer.indexOf("\n");
|
|
53
|
+
if (newlineIndex === -1) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const line = stdinBuffer.slice(0, newlineIndex).trim();
|
|
57
|
+
stdinBuffer = stdinBuffer.slice(newlineIndex + 1);
|
|
58
|
+
if (!line) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const parsed = JSON.parse(line);
|
|
62
|
+
socket.write(encodeMessage(parsed));
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async function main() {
|
|
67
|
+
const args = process.argv.slice(2);
|
|
68
|
+
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
69
|
+
printHelp();
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
if (args[0] === "--version" || args[0] === "-v") {
|
|
73
|
+
console.log(packageJson.version);
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
if (args[0] === "serve") {
|
|
77
|
+
await serve();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (args[0] === "list") {
|
|
81
|
+
printResponse(await sendIpcRequest({ type: "list" }));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (args[0] === "spawn") {
|
|
85
|
+
const spawnCwd = getFlagValue(args, "--cwd") ?? cwd();
|
|
86
|
+
const label = getFlagValue(args, "--label");
|
|
87
|
+
printResponse(await sendIpcRequest({ type: "spawn", cwd: spawnCwd, label }));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (args[0] === "status") {
|
|
91
|
+
const instanceId = args[1];
|
|
92
|
+
if (!instanceId) {
|
|
93
|
+
console.error("Usage: orchestrator status <instance-id>");
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
printResponse(await sendIpcRequest({ type: "status", instanceId }));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (args[0] === "stop") {
|
|
100
|
+
const instanceId = args[1];
|
|
101
|
+
if (!instanceId) {
|
|
102
|
+
console.error("Usage: orchestrator stop <instance-id>");
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
printResponse(await sendIpcRequest({ type: "stop", instanceId }));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (args[0] === "rpc") {
|
|
109
|
+
const instanceId = args[1];
|
|
110
|
+
const commandJson = args[2];
|
|
111
|
+
if (!instanceId || !commandJson) {
|
|
112
|
+
console.error("Usage: orchestrator rpc <instance-id> <json-command>");
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
printResponse(await sendIpcRequest({
|
|
116
|
+
type: "rpc",
|
|
117
|
+
instanceId,
|
|
118
|
+
command: JSON.parse(commandJson),
|
|
119
|
+
}));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (args[0] === "rpc-stream") {
|
|
123
|
+
const instanceId = args[1];
|
|
124
|
+
if (!instanceId) {
|
|
125
|
+
console.error("Usage: orchestrator rpc-stream <instance-id>");
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
await rpcStream(instanceId);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
console.error(`Unknown command: ${args[0]}`);
|
|
132
|
+
printHelp();
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
await main();
|
|
136
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const CONFIG_DIR_NAME = ".pi";
|
|
6
|
+
const ENV_ORCHESTRATOR_DIR = "PI_ORCHESTRATOR_DIR";
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
/**
|
|
10
|
+
* Detect if we're running as a Bun compiled binary.
|
|
11
|
+
* Bun binaries have import.meta.url containing "$bunfs", "~BUN", or "%7EBUN" (Bun's virtual filesystem path)
|
|
12
|
+
*/
|
|
13
|
+
export const isBunBinary = import.meta.url.includes("$bunfs") || import.meta.url.includes("~BUN") || import.meta.url.includes("%7EBUN");
|
|
14
|
+
function getPackageJsonPath() {
|
|
15
|
+
let dir = __dirname;
|
|
16
|
+
while (dir !== dirname(dir)) {
|
|
17
|
+
const packageJsonPath = join(dir, "package.json");
|
|
18
|
+
if (existsSync(packageJsonPath)) {
|
|
19
|
+
return packageJsonPath;
|
|
20
|
+
}
|
|
21
|
+
dir = dirname(dir);
|
|
22
|
+
}
|
|
23
|
+
return join(__dirname, "package.json");
|
|
24
|
+
}
|
|
25
|
+
let pkg = {};
|
|
26
|
+
try {
|
|
27
|
+
pkg = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8"));
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
const err = e;
|
|
31
|
+
if (err.code !== "ENOENT")
|
|
32
|
+
throw e;
|
|
33
|
+
}
|
|
34
|
+
export const VERSION = pkg.version || "0.0.0";
|
|
35
|
+
export function getOrchestratorDir() {
|
|
36
|
+
const envDir = process.env[ENV_ORCHESTRATOR_DIR];
|
|
37
|
+
if (envDir) {
|
|
38
|
+
return envDir;
|
|
39
|
+
}
|
|
40
|
+
const piDir = process.env.PI_CONFIG_DIR || join(homedir(), CONFIG_DIR_NAME);
|
|
41
|
+
return join(piDir, "orchestrator");
|
|
42
|
+
}
|
|
43
|
+
export function getAuthPath() {
|
|
44
|
+
return join(getOrchestratorDir(), "auth.json");
|
|
45
|
+
}
|
|
46
|
+
export function getMachinePath() {
|
|
47
|
+
return join(getOrchestratorDir(), "machine.json");
|
|
48
|
+
}
|
|
49
|
+
export function getInstancesPath() {
|
|
50
|
+
return join(getOrchestratorDir(), "instances.json");
|
|
51
|
+
}
|
|
52
|
+
export function getSocketPath() {
|
|
53
|
+
return join(getOrchestratorDir(), "orchestrator.sock");
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { supervisor } from "./supervisor.js";
|
|
2
|
+
function toInstanceSummary(instance) {
|
|
3
|
+
return {
|
|
4
|
+
id: instance.id,
|
|
5
|
+
status: instance.status,
|
|
6
|
+
cwd: instance.cwd,
|
|
7
|
+
label: instance.label,
|
|
8
|
+
sessionId: instance.sessionId,
|
|
9
|
+
sessionFile: instance.sessionFile,
|
|
10
|
+
radiusPiId: instance.radiusPiId,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function unknownInstanceError(instanceId) {
|
|
14
|
+
return {
|
|
15
|
+
type: "error",
|
|
16
|
+
ok: false,
|
|
17
|
+
error: `Unknown instance: ${instanceId}`,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export async function handleIpcRequest(request) {
|
|
21
|
+
switch (request.type) {
|
|
22
|
+
case "spawn": {
|
|
23
|
+
const instance = await supervisor.spawnInstance({
|
|
24
|
+
cwd: request.cwd,
|
|
25
|
+
label: request.label,
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
type: "spawn_result",
|
|
29
|
+
ok: true,
|
|
30
|
+
instance: toInstanceSummary(instance),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
case "list": {
|
|
34
|
+
return {
|
|
35
|
+
type: "list_result",
|
|
36
|
+
ok: true,
|
|
37
|
+
instances: supervisor.listInstances().map(toInstanceSummary),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
case "status": {
|
|
41
|
+
const instance = supervisor.getInstance(request.instanceId);
|
|
42
|
+
if (!instance) {
|
|
43
|
+
return unknownInstanceError(request.instanceId);
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
type: "status_result",
|
|
47
|
+
ok: true,
|
|
48
|
+
instance: toInstanceSummary(instance),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
case "stop": {
|
|
52
|
+
const instance = await supervisor.stopInstance(request.instanceId);
|
|
53
|
+
if (!instance) {
|
|
54
|
+
return unknownInstanceError(request.instanceId);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
type: "stop_result",
|
|
58
|
+
ok: true,
|
|
59
|
+
instanceId: request.instanceId,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
case "rpc": {
|
|
63
|
+
const response = await supervisor.handleRpc(request.instanceId, request.command);
|
|
64
|
+
if (!response) {
|
|
65
|
+
return unknownInstanceError(request.instanceId);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
type: "rpc_result",
|
|
69
|
+
ok: true,
|
|
70
|
+
response,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
case "rpc_stream": {
|
|
74
|
+
const instance = supervisor.getInstance(request.instanceId);
|
|
75
|
+
if (!instance) {
|
|
76
|
+
return unknownInstanceError(request.instanceId);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
type: "rpc_ready",
|
|
80
|
+
ok: true,
|
|
81
|
+
instance: toInstanceSummary(instance),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function openRpcStream(instanceId, onResponse, onSessionEvent, onUiRequest) {
|
|
87
|
+
const handle = supervisor.openRpcStream(instanceId, onSessionEvent, onUiRequest);
|
|
88
|
+
if (!handle) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
async handleRequest(request) {
|
|
93
|
+
if (request.type === "extension_ui_response") {
|
|
94
|
+
handle.handleUiResponse(request);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const response = await handle.handleRpc(request);
|
|
98
|
+
onResponse(response);
|
|
99
|
+
},
|
|
100
|
+
close() {
|
|
101
|
+
handle.close();
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from "./config.js";
|
|
2
|
+
export * from "./handler.js";
|
|
3
|
+
export * from "./ipc/client.js";
|
|
4
|
+
export * from "./ipc/protocol.js";
|
|
5
|
+
export * from "./ipc/server.js";
|
|
6
|
+
export * from "./rpc-process.js";
|
|
7
|
+
export * from "./serve.js";
|
|
8
|
+
export * from "./storage.js";
|
|
9
|
+
export * from "./supervisor.js";
|
|
10
|
+
export * from "./types.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { createConnection } from "node:net";
|
|
2
|
+
import { getSocketPath } from "../config.js";
|
|
3
|
+
import { encodeMessage, parseResponseLine } from "./protocol.js";
|
|
4
|
+
export async function sendIpcRequest(request) {
|
|
5
|
+
const socketPath = getSocketPath();
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const socket = createConnection(socketPath);
|
|
8
|
+
let buffer = "";
|
|
9
|
+
let settled = false;
|
|
10
|
+
const cleanup = () => {
|
|
11
|
+
socket.removeAllListeners();
|
|
12
|
+
socket.end();
|
|
13
|
+
};
|
|
14
|
+
socket.on("connect", () => {
|
|
15
|
+
socket.write(encodeMessage(request));
|
|
16
|
+
});
|
|
17
|
+
socket.on("data", (chunk) => {
|
|
18
|
+
buffer += chunk.toString();
|
|
19
|
+
const newlineIndex = buffer.indexOf("\n");
|
|
20
|
+
if (newlineIndex === -1) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const line = buffer.slice(0, newlineIndex).trim();
|
|
24
|
+
if (!line) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
settled = true;
|
|
29
|
+
resolve(parseResponseLine(line));
|
|
30
|
+
cleanup();
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
settled = true;
|
|
34
|
+
reject(error);
|
|
35
|
+
cleanup();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
socket.on("error", (error) => {
|
|
39
|
+
if (settled) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
settled = true;
|
|
43
|
+
reject(error);
|
|
44
|
+
cleanup();
|
|
45
|
+
});
|
|
46
|
+
socket.on("end", () => {
|
|
47
|
+
if (settled) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
settled = true;
|
|
51
|
+
reject(new Error(`Orchestrator socket closed before a response was received: ${socketPath}`));
|
|
52
|
+
cleanup();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=client.js.map
|