mirror of
https://github.com/harivansh-afk/clanker-agent.git
synced 2026-04-17 13:05:06 +00:00
move pi-mono into companion-cloud as apps/companion-os
- Copy all pi-mono source into apps/companion-os/ - Update Dockerfile to COPY pre-built binary instead of downloading from GitHub Releases - Update deploy-staging.yml to build pi from source (bun compile) before Docker build - Add apps/companion-os/** to path triggers - No more cross-repo dispatch needed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
0250f72976
579 changed files with 206942 additions and 0 deletions
|
|
@ -0,0 +1,121 @@
|
|||
import type { SandboxRuntimeProvider } from "./SandboxRuntimeProvider.js";
|
||||
|
||||
export interface DownloadableFile {
|
||||
fileName: string;
|
||||
content: string | Uint8Array;
|
||||
mimeType: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* File Download Runtime Provider
|
||||
*
|
||||
* Provides returnDownloadableFile() for creating user downloads.
|
||||
* Files returned this way are NOT accessible to the LLM later (one-time download).
|
||||
* Works both online (sends to extension) and offline (triggers browser download directly).
|
||||
* Collects files for retrieval by caller.
|
||||
*/
|
||||
export class FileDownloadRuntimeProvider implements SandboxRuntimeProvider {
|
||||
private files: DownloadableFile[] = [];
|
||||
|
||||
getData(): Record<string, any> {
|
||||
// No data needed
|
||||
return {};
|
||||
}
|
||||
|
||||
getRuntime(): (sandboxId: string) => void {
|
||||
return (_sandboxId: string) => {
|
||||
(window as any).returnDownloadableFile = async (
|
||||
fileName: string,
|
||||
content: any,
|
||||
mimeType?: string,
|
||||
) => {
|
||||
let finalContent: any, finalMimeType: string;
|
||||
|
||||
if (content instanceof Blob) {
|
||||
const arrayBuffer = await content.arrayBuffer();
|
||||
finalContent = new Uint8Array(arrayBuffer);
|
||||
finalMimeType =
|
||||
mimeType || content.type || "application/octet-stream";
|
||||
if (!mimeType && !content.type) {
|
||||
throw new Error(
|
||||
"returnDownloadableFile: MIME type is required for Blob content. Please provide a mimeType parameter (e.g., 'image/png').",
|
||||
);
|
||||
}
|
||||
} else if (content instanceof Uint8Array) {
|
||||
finalContent = content;
|
||||
if (!mimeType) {
|
||||
throw new Error(
|
||||
"returnDownloadableFile: MIME type is required for Uint8Array content. Please provide a mimeType parameter (e.g., 'image/png').",
|
||||
);
|
||||
}
|
||||
finalMimeType = mimeType;
|
||||
} else if (typeof content === "string") {
|
||||
finalContent = content;
|
||||
finalMimeType = mimeType || "text/plain";
|
||||
} else {
|
||||
finalContent = JSON.stringify(content, null, 2);
|
||||
finalMimeType = mimeType || "application/json";
|
||||
}
|
||||
|
||||
// Send to extension if in extension context (online mode)
|
||||
if ((window as any).sendRuntimeMessage) {
|
||||
const response = await (window as any).sendRuntimeMessage({
|
||||
type: "file-returned",
|
||||
fileName,
|
||||
content: finalContent,
|
||||
mimeType: finalMimeType,
|
||||
});
|
||||
if (response.error) throw new Error(response.error);
|
||||
} else {
|
||||
// Offline mode: trigger browser download directly
|
||||
const blob = new Blob(
|
||||
[finalContent instanceof Uint8Array ? finalContent : finalContent],
|
||||
{
|
||||
type: finalMimeType,
|
||||
},
|
||||
);
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = fileName;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
async handleMessage(
|
||||
message: any,
|
||||
respond: (response: any) => void,
|
||||
): Promise<void> {
|
||||
if (message.type === "file-returned") {
|
||||
// Collect file for caller
|
||||
this.files.push({
|
||||
fileName: message.fileName,
|
||||
content: message.content,
|
||||
mimeType: message.mimeType,
|
||||
});
|
||||
|
||||
respond({ success: true });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get collected files
|
||||
*/
|
||||
getFiles(): DownloadableFile[] {
|
||||
return this.files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset state for reuse
|
||||
*/
|
||||
reset(): void {
|
||||
this.files = [];
|
||||
}
|
||||
|
||||
getDescription(): string {
|
||||
return "returnDownloadableFile(filename, content, mimeType?) - Create downloadable file for user (one-time download, not accessible later)";
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue