@hachej/boring-agent 0.1.63 → 0.1.64
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/{chunk-G6YPXDHR.js → chunk-UPRDF2PB.js} +2 -1
- package/dist/front/index.d.ts +8 -3
- package/dist/front/index.js +14 -9
- package/dist/{piChatEvent-B6GDifo2.d.ts → piChatEvent-JbwYVBZj.d.ts} +1 -0
- package/dist/server/index.d.ts +31 -1
- package/dist/server/index.js +141 -30
- package/dist/shared/index.d.ts +2 -2
- package/dist/shared/index.js +1 -1
- package/package.json +2 -2
|
@@ -171,7 +171,8 @@ var BoringChatPartSchema = z2.discriminatedUnion("type", [
|
|
|
171
171
|
filename: z2.string().optional(),
|
|
172
172
|
mediaType: z2.string().optional(),
|
|
173
173
|
url: z2.string().optional(),
|
|
174
|
-
path: z2.string().optional()
|
|
174
|
+
path: z2.string().optional(),
|
|
175
|
+
filesystem: z2.string().optional()
|
|
175
176
|
}),
|
|
176
177
|
z2.object({
|
|
177
178
|
type: z2.literal("notice"),
|
package/dist/front/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ComponentProps, HTMLAttributes, FormEvent, ReactNode, ComponentType } from 'react';
|
|
4
4
|
import { FileUIPart, ChatStatus, UIMessage } from 'ai';
|
|
5
|
-
import { T as ToolUiMetadata, B as BoringChatPart, d as BoringChatMessage, m as PiChatStatus, r as QueuedUserMessage, C as ChatError, P as PiChatEvent, o as PromptPayload, p as PromptReceipt, F as FollowUpPayload, i as FollowUpReceipt, Q as QueueClearPayload, q as QueueClearReceipt, I as InterruptPayload, e as CommandReceipt, S as StopPayload, s as StopReceipt } from '../piChatEvent-
|
|
5
|
+
import { T as ToolUiMetadata, B as BoringChatPart, d as BoringChatMessage, m as PiChatStatus, r as QueuedUserMessage, C as ChatError, P as PiChatEvent, o as PromptPayload, p as PromptReceipt, F as FollowUpPayload, i as FollowUpReceipt, Q as QueueClearPayload, q as QueueClearReceipt, I as InterruptPayload, e as CommandReceipt, S as StopPayload, s as StopReceipt } from '../piChatEvent-JbwYVBZj.js';
|
|
6
6
|
import { e as SessionSummary } from '../chatSubmitPayload-DHqQL2wD.js';
|
|
7
7
|
import { InputGroupAddon, InputGroupButton, InputGroupTextarea, Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from '@hachej/boring-ui-kit';
|
|
8
8
|
import { Streamdown } from 'streamdown';
|
|
@@ -650,7 +650,9 @@ interface PiChatPanelProps<TComposerBlocker extends ComposerBlocker = ComposerBl
|
|
|
650
650
|
clientNonce: string;
|
|
651
651
|
}) => void;
|
|
652
652
|
onData?: (part: unknown) => void;
|
|
653
|
-
onOpenArtifact?: (path: string
|
|
653
|
+
onOpenArtifact?: (path: string, options?: {
|
|
654
|
+
filesystem?: string;
|
|
655
|
+
}) => void;
|
|
654
656
|
composerBlockers?: TComposerBlocker[];
|
|
655
657
|
onComposerStop?: () => void;
|
|
656
658
|
onComposerBlockerAction?: (blocker: TComposerBlocker, action: string) => void;
|
|
@@ -677,7 +679,10 @@ interface DebugDrawerProps {
|
|
|
677
679
|
}
|
|
678
680
|
declare function DebugDrawer({ apiBaseUrl, fetch, sessionId, messages, requestHeaders, storageScope, width, onWidthChange }: DebugDrawerProps): react_jsx_runtime.JSX.Element;
|
|
679
681
|
|
|
680
|
-
|
|
682
|
+
interface OpenArtifactOptions {
|
|
683
|
+
filesystem?: string;
|
|
684
|
+
}
|
|
685
|
+
type OpenArtifactHandler = (path: string, options?: OpenArtifactOptions) => void;
|
|
681
686
|
interface ArtifactOpenProviderProps {
|
|
682
687
|
onOpenArtifact?: OpenArtifactHandler;
|
|
683
688
|
children: ReactNode;
|
package/dist/front/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
StopReceiptSchema,
|
|
14
14
|
extractToolUiMetadata,
|
|
15
15
|
sanitizeToolUiMetadata
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-UPRDF2PB.js";
|
|
17
17
|
import {
|
|
18
18
|
DebugDrawer,
|
|
19
19
|
cn,
|
|
@@ -1534,7 +1534,7 @@ function toHeaderProps(part) {
|
|
|
1534
1534
|
toolName: part.toolName
|
|
1535
1535
|
};
|
|
1536
1536
|
}
|
|
1537
|
-
function PathLabel({ path }) {
|
|
1537
|
+
function PathLabel({ path, filesystem }) {
|
|
1538
1538
|
const onOpen = useOpenArtifact();
|
|
1539
1539
|
if (!onOpen) {
|
|
1540
1540
|
return /* @__PURE__ */ jsx11("span", { className: "font-mono text-[12.5px] text-foreground/85", children: path });
|
|
@@ -1542,7 +1542,8 @@ function PathLabel({ path }) {
|
|
|
1542
1542
|
const open = (e) => {
|
|
1543
1543
|
e.preventDefault();
|
|
1544
1544
|
e.stopPropagation();
|
|
1545
|
-
onOpen(path);
|
|
1545
|
+
if (filesystem) onOpen(path, { filesystem });
|
|
1546
|
+
else onOpen(path);
|
|
1546
1547
|
};
|
|
1547
1548
|
const handleKeyDown = (e) => {
|
|
1548
1549
|
if (e.key === "Enter" || e.key === " ") open(e);
|
|
@@ -1603,11 +1604,11 @@ function renderRuntimeNotReady(part) {
|
|
|
1603
1604
|
function renderReadinessBlock(part) {
|
|
1604
1605
|
return renderWorkspaceNotReady(part) ?? renderRuntimeNotReady(part);
|
|
1605
1606
|
}
|
|
1606
|
-
function pathTitle(prefix, path) {
|
|
1607
|
+
function pathTitle(prefix, path, filesystem) {
|
|
1607
1608
|
return /* @__PURE__ */ jsxs10("span", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
1608
1609
|
/* @__PURE__ */ jsx11("span", { className: "text-muted-foreground", children: prefix }),
|
|
1609
1610
|
/* @__PURE__ */ jsx11("span", { className: "text-muted-foreground/40", "aria-hidden": "true", children: "\xB7" }),
|
|
1610
|
-
/* @__PURE__ */ jsx11(PathLabel, { path })
|
|
1611
|
+
/* @__PURE__ */ jsx11(PathLabel, { path, filesystem })
|
|
1611
1612
|
] });
|
|
1612
1613
|
}
|
|
1613
1614
|
function renderBash2(part) {
|
|
@@ -1649,10 +1650,11 @@ function renderRead2(part) {
|
|
|
1649
1650
|
const input = asRecord2(part.input);
|
|
1650
1651
|
const output = asRecord2(part.output);
|
|
1651
1652
|
const path = typeof input.path === "string" ? input.path : "";
|
|
1653
|
+
const filesystem = typeof input.filesystem === "string" ? input.filesystem : void 0;
|
|
1652
1654
|
const content = extractTextContent(output);
|
|
1653
1655
|
const lang = langFromPath(path);
|
|
1654
1656
|
return /* @__PURE__ */ jsxs10(Tool2, { children: [
|
|
1655
|
-
/* @__PURE__ */ jsx11(ToolHeader, { icon: /* @__PURE__ */ jsx11(FileTextIcon, { className: "size-4 text-muted-foreground" }), title: pathTitle("read", path), ...toHeaderProps(part) }),
|
|
1657
|
+
/* @__PURE__ */ jsx11(ToolHeader, { icon: /* @__PURE__ */ jsx11(FileTextIcon, { className: "size-4 text-muted-foreground" }), title: pathTitle("read", path, filesystem), ...toHeaderProps(part) }),
|
|
1656
1658
|
/* @__PURE__ */ jsxs10(ToolContent, { children: [
|
|
1657
1659
|
/* @__PURE__ */ jsx11(ToolInput, { input }),
|
|
1658
1660
|
content && /* @__PURE__ */ jsxs10("section", { className: "space-y-2", children: [
|
|
@@ -1667,11 +1669,12 @@ function renderWrite2(part) {
|
|
|
1667
1669
|
if (readiness) return readiness;
|
|
1668
1670
|
const input = asRecord2(part.input);
|
|
1669
1671
|
const path = typeof input.path === "string" ? input.path : "";
|
|
1672
|
+
const filesystem = typeof input.filesystem === "string" ? input.filesystem : void 0;
|
|
1670
1673
|
const content = typeof input.content === "string" ? input.content : "";
|
|
1671
1674
|
const bytes = content.length;
|
|
1672
1675
|
const lang = langFromPath(path);
|
|
1673
1676
|
return /* @__PURE__ */ jsxs10(Tool2, { children: [
|
|
1674
|
-
/* @__PURE__ */ jsx11(ToolHeader, { icon: /* @__PURE__ */ jsx11(FilePlus2Icon, { className: "size-4 text-muted-foreground" }), title: pathTitle("write", path), ...toHeaderProps(part) }),
|
|
1677
|
+
/* @__PURE__ */ jsx11(ToolHeader, { icon: /* @__PURE__ */ jsx11(FilePlus2Icon, { className: "size-4 text-muted-foreground" }), title: pathTitle("write", path, filesystem), ...toHeaderProps(part) }),
|
|
1675
1678
|
/* @__PURE__ */ jsx11(ToolContent, { children: /* @__PURE__ */ jsxs10(Artifact, { className: "rounded-none border-0 bg-transparent shadow-none", children: [
|
|
1676
1679
|
/* @__PURE__ */ jsxs10(ArtifactHeader, { className: "border-0 px-0 pt-0 pb-2", children: [
|
|
1677
1680
|
/* @__PURE__ */ jsxs10("div", { children: [
|
|
@@ -1728,10 +1731,11 @@ function renderEdit2(part) {
|
|
|
1728
1731
|
if (readiness) return readiness;
|
|
1729
1732
|
const input = asRecord2(part.input);
|
|
1730
1733
|
const path = typeof input.path === "string" ? input.path : "";
|
|
1734
|
+
const filesystem = typeof input.filesystem === "string" ? input.filesystem : void 0;
|
|
1731
1735
|
const oldString = typeof input.oldString === "string" ? input.oldString : "";
|
|
1732
1736
|
const newString = typeof input.newString === "string" ? input.newString : "";
|
|
1733
1737
|
return /* @__PURE__ */ jsxs10(Tool2, { children: [
|
|
1734
|
-
/* @__PURE__ */ jsx11(ToolHeader, { icon: /* @__PURE__ */ jsx11(FileDiffIcon, { className: "size-4 text-muted-foreground" }), title: pathTitle("edit", path), ...toHeaderProps(part) }),
|
|
1738
|
+
/* @__PURE__ */ jsx11(ToolHeader, { icon: /* @__PURE__ */ jsx11(FileDiffIcon, { className: "size-4 text-muted-foreground" }), title: pathTitle("edit", path, filesystem), ...toHeaderProps(part) }),
|
|
1735
1739
|
/* @__PURE__ */ jsxs10(ToolContent, { children: [
|
|
1736
1740
|
/* @__PURE__ */ jsxs10("section", { className: "space-y-2", children: [
|
|
1737
1741
|
/* @__PURE__ */ jsx11("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Diff" }),
|
|
@@ -7046,7 +7050,8 @@ function PiTimelineMessage({ message, isLast, isStreaming, showThoughts, toolRen
|
|
|
7046
7050
|
const canOpen = Boolean(openArtifact && openPath);
|
|
7047
7051
|
const openAttachment = () => {
|
|
7048
7052
|
if (!openPath) return;
|
|
7049
|
-
openArtifact?.(openPath);
|
|
7053
|
+
if (file.filesystem) openArtifact?.(openPath, { filesystem: file.filesystem });
|
|
7054
|
+
else openArtifact?.(openPath);
|
|
7050
7055
|
};
|
|
7051
7056
|
const openAttachmentFromKeyboard = (event) => {
|
|
7052
7057
|
if (event.key !== "Enter" && event.key !== " ") return;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -490,6 +490,35 @@ interface RuntimeFilesystemBindingOperations {
|
|
|
490
490
|
isDirectory: boolean;
|
|
491
491
|
metadata?: unknown;
|
|
492
492
|
}>;
|
|
493
|
+
write?(descriptor: {
|
|
494
|
+
filesystem: string;
|
|
495
|
+
path: string;
|
|
496
|
+
content: string;
|
|
497
|
+
expectedMtimeMs?: number;
|
|
498
|
+
}): Promise<{
|
|
499
|
+
mtimeMs?: number;
|
|
500
|
+
metadata?: unknown;
|
|
501
|
+
}>;
|
|
502
|
+
delete?(descriptor: {
|
|
503
|
+
filesystem: string;
|
|
504
|
+
path: string;
|
|
505
|
+
}): Promise<{
|
|
506
|
+
metadata?: unknown;
|
|
507
|
+
}>;
|
|
508
|
+
move?(descriptor: {
|
|
509
|
+
filesystem: string;
|
|
510
|
+
from: string;
|
|
511
|
+
to: string;
|
|
512
|
+
}): Promise<{
|
|
513
|
+
metadata?: unknown;
|
|
514
|
+
}>;
|
|
515
|
+
mkdir?(descriptor: {
|
|
516
|
+
filesystem: string;
|
|
517
|
+
path: string;
|
|
518
|
+
recursive?: boolean;
|
|
519
|
+
}): Promise<{
|
|
520
|
+
metadata?: unknown;
|
|
521
|
+
}>;
|
|
493
522
|
rejectMutation(operation: string, descriptor: {
|
|
494
523
|
filesystem: string;
|
|
495
524
|
path: string;
|
|
@@ -497,7 +526,7 @@ interface RuntimeFilesystemBindingOperations {
|
|
|
497
526
|
}
|
|
498
527
|
interface RuntimeFilesystemBinding {
|
|
499
528
|
readonly filesystem: string;
|
|
500
|
-
readonly access: 'readonly';
|
|
529
|
+
readonly access: 'readonly' | 'readwrite';
|
|
501
530
|
readonly operations: RuntimeFilesystemBindingOperations;
|
|
502
531
|
}
|
|
503
532
|
interface RuntimeBundle {
|
|
@@ -1024,6 +1053,7 @@ interface RegisterAgentRoutesOptions {
|
|
|
1024
1053
|
workspaceRoot: string;
|
|
1025
1054
|
runtimeMode: RuntimeModeId;
|
|
1026
1055
|
workspaceFsCapability?: Workspace['fsCapability'];
|
|
1056
|
+
authSubject?: string;
|
|
1027
1057
|
}) => AgentTool[] | Promise<AgentTool[]>;
|
|
1028
1058
|
systemPromptAppend?: string;
|
|
1029
1059
|
/** Optional dynamic system-prompt source forwarded to the harness. */
|
package/dist/server/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
StopPayloadSchema,
|
|
14
14
|
extractToolUiMetadata,
|
|
15
15
|
sanitizeToolUiMetadata2 as sanitizeToolUiMetadata
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-UPRDF2PB.js";
|
|
17
17
|
|
|
18
18
|
// src/server/sandbox/direct/createDirectSandbox.ts
|
|
19
19
|
import { spawn } from "child_process";
|
|
@@ -2872,14 +2872,6 @@ function fileRoutes(app, opts, done) {
|
|
|
2872
2872
|
async function resolveFilesystemBinding(request, filesystem) {
|
|
2873
2873
|
return (await resolveFilesystemBindings(request)).find((binding) => binding.filesystem === filesystem);
|
|
2874
2874
|
}
|
|
2875
|
-
async function rejectUnsupportedFilesystemMutation(request, reply, filesystem) {
|
|
2876
|
-
const binding = await resolveFilesystemBinding(request, filesystem);
|
|
2877
|
-
if (!binding) return sendNotFoundOrDenied(reply);
|
|
2878
|
-
if (binding.access === "readonly") return sendFilesystemBindingMutationDenied(reply, filesystem, binding.access);
|
|
2879
|
-
return reply.code(501).send({
|
|
2880
|
-
error: { code: ERROR_CODE_INTERNAL, message: `${filesystem} binding access is not supported by this route` }
|
|
2881
|
-
});
|
|
2882
|
-
}
|
|
2883
2875
|
app.get("/api/v1/files/raw", async (request, reply) => {
|
|
2884
2876
|
const query = request.query;
|
|
2885
2877
|
const path4 = requireStringParam(query.path, "path", reply);
|
|
@@ -2888,7 +2880,7 @@ function fileRoutes(app, opts, done) {
|
|
|
2888
2880
|
if (filesystem !== USER_FILESYSTEM_ID) {
|
|
2889
2881
|
try {
|
|
2890
2882
|
const binding = await resolveFilesystemBinding(request, filesystem);
|
|
2891
|
-
if (!binding
|
|
2883
|
+
if (!binding) return sendNotFoundOrDenied(reply);
|
|
2892
2884
|
const result = await binding.operations.read({ filesystem, path: path4 });
|
|
2893
2885
|
const bytes = Buffer.from(result.content, "utf8");
|
|
2894
2886
|
return reply.header("content-type", contentTypeForPath(path4)).header("content-length", String(bytes.byteLength)).header("cache-control", "no-store").header("x-content-type-options", "nosniff").send(bytes);
|
|
@@ -2953,9 +2945,9 @@ function fileRoutes(app, opts, done) {
|
|
|
2953
2945
|
if (filesystem !== USER_FILESYSTEM_ID) {
|
|
2954
2946
|
try {
|
|
2955
2947
|
const binding = await resolveFilesystemBinding(request, filesystem);
|
|
2956
|
-
if (!binding
|
|
2948
|
+
if (!binding) return sendNotFoundOrDenied(reply);
|
|
2957
2949
|
const result = await binding.operations.read({ filesystem, path: path4 });
|
|
2958
|
-
return { content: result.content };
|
|
2950
|
+
return { content: result.content, access: binding.access };
|
|
2959
2951
|
} catch {
|
|
2960
2952
|
return sendNotFoundOrDenied(reply);
|
|
2961
2953
|
}
|
|
@@ -2973,11 +2965,11 @@ function fileRoutes(app, opts, done) {
|
|
|
2973
2965
|
const workspace = await resolveWorkspace(request);
|
|
2974
2966
|
if (workspace.readFileWithStat) {
|
|
2975
2967
|
const { content: content2, stat: stat13 } = await workspace.readFileWithStat(path4);
|
|
2976
|
-
return { content: content2, mtimeMs: stat13.kind === "file" ? stat13.mtimeMs : void 0 };
|
|
2968
|
+
return { content: content2, mtimeMs: stat13.kind === "file" ? stat13.mtimeMs : void 0, access: "readwrite" };
|
|
2977
2969
|
}
|
|
2978
2970
|
const content = await workspace.readFile(path4);
|
|
2979
2971
|
const stat12 = await workspace.stat(path4);
|
|
2980
|
-
return { content, mtimeMs: stat12.kind === "file" ? stat12.mtimeMs : void 0 };
|
|
2972
|
+
return { content, mtimeMs: stat12.kind === "file" ? stat12.mtimeMs : void 0, access: "readwrite" };
|
|
2981
2973
|
} catch (err) {
|
|
2982
2974
|
return classifyError(err, reply, "file");
|
|
2983
2975
|
}
|
|
@@ -2992,9 +2984,27 @@ function fileRoutes(app, opts, done) {
|
|
|
2992
2984
|
});
|
|
2993
2985
|
}
|
|
2994
2986
|
const filesystem = requestedFilesystem(body.filesystem);
|
|
2995
|
-
if (filesystem !== USER_FILESYSTEM_ID) return await rejectUnsupportedFilesystemMutation(request, reply, filesystem);
|
|
2996
2987
|
const expectedMtimeMs = typeof body.expectedMtimeMs === "number" ? body.expectedMtimeMs : null;
|
|
2997
2988
|
const shouldReturnMtimeMs = body.returnMtimeMs !== false || expectedMtimeMs !== null;
|
|
2989
|
+
if (filesystem !== USER_FILESYSTEM_ID) {
|
|
2990
|
+
try {
|
|
2991
|
+
const binding = await resolveFilesystemBinding(request, filesystem);
|
|
2992
|
+
if (!binding) return sendNotFoundOrDenied(reply);
|
|
2993
|
+
if (binding.access !== "readwrite") return sendFilesystemBindingMutationDenied(reply, filesystem, binding.access);
|
|
2994
|
+
if (!binding.operations.write) {
|
|
2995
|
+
return reply.code(501).send({ error: { code: ERROR_CODE_INTERNAL, message: `${filesystem} write operation is unavailable` } });
|
|
2996
|
+
}
|
|
2997
|
+
const result = await binding.operations.write({
|
|
2998
|
+
filesystem,
|
|
2999
|
+
path: path4,
|
|
3000
|
+
content: body.content,
|
|
3001
|
+
...expectedMtimeMs !== null ? { expectedMtimeMs } : {}
|
|
3002
|
+
});
|
|
3003
|
+
return shouldReturnMtimeMs ? { ok: true, mtimeMs: result.mtimeMs } : { ok: true };
|
|
3004
|
+
} catch (err) {
|
|
3005
|
+
return classifyError(err, reply, "file");
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
2998
3008
|
try {
|
|
2999
3009
|
const workspace = await resolveWorkspace(request);
|
|
3000
3010
|
if (expectedMtimeMs !== null) {
|
|
@@ -3127,7 +3137,20 @@ function fileRoutes(app, opts, done) {
|
|
|
3127
3137
|
const path4 = requireStringParam(query.path, "path", reply);
|
|
3128
3138
|
if (path4 === null) return;
|
|
3129
3139
|
const filesystem = requestedFilesystem(query.filesystem);
|
|
3130
|
-
if (filesystem !== USER_FILESYSTEM_ID)
|
|
3140
|
+
if (filesystem !== USER_FILESYSTEM_ID) {
|
|
3141
|
+
try {
|
|
3142
|
+
const binding = await resolveFilesystemBinding(request, filesystem);
|
|
3143
|
+
if (!binding) return sendNotFoundOrDenied(reply);
|
|
3144
|
+
if (binding.access !== "readwrite") return sendFilesystemBindingMutationDenied(reply, filesystem, binding.access);
|
|
3145
|
+
if (!binding.operations.delete) {
|
|
3146
|
+
return reply.code(501).send({ error: { code: ERROR_CODE_INTERNAL, message: `${filesystem} delete operation is unavailable` } });
|
|
3147
|
+
}
|
|
3148
|
+
await binding.operations.delete({ filesystem, path: path4 });
|
|
3149
|
+
return { ok: true };
|
|
3150
|
+
} catch (err) {
|
|
3151
|
+
return classifyError(err, reply, "file");
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3131
3154
|
try {
|
|
3132
3155
|
const workspace = await resolveWorkspace(request);
|
|
3133
3156
|
await workspace.unlink(path4);
|
|
@@ -3143,7 +3166,20 @@ function fileRoutes(app, opts, done) {
|
|
|
3143
3166
|
const to = requireStringParam(body?.to, "to", reply);
|
|
3144
3167
|
if (to === null) return;
|
|
3145
3168
|
const filesystem = requestedFilesystem(body.filesystem);
|
|
3146
|
-
if (filesystem !== USER_FILESYSTEM_ID)
|
|
3169
|
+
if (filesystem !== USER_FILESYSTEM_ID) {
|
|
3170
|
+
try {
|
|
3171
|
+
const binding = await resolveFilesystemBinding(request, filesystem);
|
|
3172
|
+
if (!binding) return sendNotFoundOrDenied(reply);
|
|
3173
|
+
if (binding.access !== "readwrite") return sendFilesystemBindingMutationDenied(reply, filesystem, binding.access);
|
|
3174
|
+
if (!binding.operations.move) {
|
|
3175
|
+
return reply.code(501).send({ error: { code: ERROR_CODE_INTERNAL, message: `${filesystem} move operation is unavailable` } });
|
|
3176
|
+
}
|
|
3177
|
+
await binding.operations.move({ filesystem, from, to });
|
|
3178
|
+
return { ok: true };
|
|
3179
|
+
} catch (err) {
|
|
3180
|
+
return classifyError(err, reply, "file");
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3147
3183
|
try {
|
|
3148
3184
|
const workspace = await resolveWorkspace(request);
|
|
3149
3185
|
await workspace.rename(from, to);
|
|
@@ -3158,7 +3194,20 @@ function fileRoutes(app, opts, done) {
|
|
|
3158
3194
|
if (path4 === null) return;
|
|
3159
3195
|
const recursive = body.recursive === true;
|
|
3160
3196
|
const filesystem = requestedFilesystem(body.filesystem);
|
|
3161
|
-
if (filesystem !== USER_FILESYSTEM_ID)
|
|
3197
|
+
if (filesystem !== USER_FILESYSTEM_ID) {
|
|
3198
|
+
try {
|
|
3199
|
+
const binding = await resolveFilesystemBinding(request, filesystem);
|
|
3200
|
+
if (!binding) return sendNotFoundOrDenied(reply);
|
|
3201
|
+
if (binding.access !== "readwrite") return sendFilesystemBindingMutationDenied(reply, filesystem, binding.access);
|
|
3202
|
+
if (!binding.operations.mkdir) {
|
|
3203
|
+
return reply.code(501).send({ error: { code: ERROR_CODE_INTERNAL, message: `${filesystem} mkdir operation is unavailable` } });
|
|
3204
|
+
}
|
|
3205
|
+
await binding.operations.mkdir({ filesystem, path: path4, recursive });
|
|
3206
|
+
return { ok: true };
|
|
3207
|
+
} catch (err) {
|
|
3208
|
+
return classifyError(err, reply, "directory");
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3162
3211
|
try {
|
|
3163
3212
|
const workspace = await resolveWorkspace(request);
|
|
3164
3213
|
await workspace.mkdir(path4, { recursive });
|
|
@@ -3175,7 +3224,7 @@ function fileRoutes(app, opts, done) {
|
|
|
3175
3224
|
if (filesystem !== USER_FILESYSTEM_ID) {
|
|
3176
3225
|
try {
|
|
3177
3226
|
const binding = await resolveFilesystemBinding(request, filesystem);
|
|
3178
|
-
if (!binding
|
|
3227
|
+
if (!binding) return sendNotFoundOrDenied(reply);
|
|
3179
3228
|
const result = await binding.operations.stat({ filesystem, path: path4 });
|
|
3180
3229
|
return result.isDirectory ? { kind: "dir" } : { kind: "file", size: 0 };
|
|
3181
3230
|
} catch {
|
|
@@ -9201,6 +9250,14 @@ function joinPath2(base, name) {
|
|
|
9201
9250
|
if (base === ".") return name;
|
|
9202
9251
|
return `${base}/${name}`;
|
|
9203
9252
|
}
|
|
9253
|
+
function requestedFilesystem3(value) {
|
|
9254
|
+
return typeof value === "string" && value.length > 0 ? value : "user";
|
|
9255
|
+
}
|
|
9256
|
+
function sendNotFoundOrDenied2(reply) {
|
|
9257
|
+
return reply.code(404).send({
|
|
9258
|
+
error: { code: ERROR_CODE_NOT_FOUND_OR_DENIED, message: "not found or denied" }
|
|
9259
|
+
});
|
|
9260
|
+
}
|
|
9204
9261
|
async function listTree(workspace, dir, recursive) {
|
|
9205
9262
|
const entries = [];
|
|
9206
9263
|
const initialEntries = await workspace.readdir(dir);
|
|
@@ -9225,12 +9282,44 @@ async function listTree(workspace, dir, recursive) {
|
|
|
9225
9282
|
}
|
|
9226
9283
|
return entries;
|
|
9227
9284
|
}
|
|
9285
|
+
async function listBoundTree(binding, dir, recursive) {
|
|
9286
|
+
const root = dir === "." ? "/" : dir;
|
|
9287
|
+
const displayParentDir = dir === "." || dir === "/" ? "." : dir.replace(/\/+$/, "");
|
|
9288
|
+
const entries = [];
|
|
9289
|
+
const rootEntries = await binding.operations.list({ filesystem: binding.filesystem, path: root });
|
|
9290
|
+
const queue = [
|
|
9291
|
+
{ parentDir: displayParentDir || ".", items: rootEntries.entries, depth: 0 }
|
|
9292
|
+
];
|
|
9293
|
+
while (queue.length > 0) {
|
|
9294
|
+
if (entries.length >= MAX_ENTRIES) break;
|
|
9295
|
+
const batch = queue.shift();
|
|
9296
|
+
for (const name of batch.items) {
|
|
9297
|
+
if (entries.length >= MAX_ENTRIES) break;
|
|
9298
|
+
const entryPath = joinPath2(batch.parentDir, name);
|
|
9299
|
+
const stat12 = await binding.operations.stat({ filesystem: binding.filesystem, path: entryPath });
|
|
9300
|
+
const kind = stat12.isDirectory ? "dir" : "file";
|
|
9301
|
+
entries.push({ name, kind, path: entryPath });
|
|
9302
|
+
if (recursive && kind === "dir" && batch.depth < MAX_DEPTH && !isIgnoredDirName(name)) {
|
|
9303
|
+
try {
|
|
9304
|
+
const childEntries = await binding.operations.list({ filesystem: binding.filesystem, path: entryPath });
|
|
9305
|
+
queue.push({ parentDir: entryPath, items: childEntries.entries, depth: batch.depth + 1 });
|
|
9306
|
+
} catch {
|
|
9307
|
+
}
|
|
9308
|
+
}
|
|
9309
|
+
}
|
|
9310
|
+
}
|
|
9311
|
+
return entries;
|
|
9312
|
+
}
|
|
9228
9313
|
function treeRoutes(app, opts, done) {
|
|
9229
9314
|
async function resolveWorkspace(request) {
|
|
9230
9315
|
if (opts.getWorkspace) return await opts.getWorkspace(request);
|
|
9231
9316
|
if (opts.workspace) return opts.workspace;
|
|
9232
9317
|
throw new Error("workspace route requires workspace or getWorkspace");
|
|
9233
9318
|
}
|
|
9319
|
+
async function resolveFilesystemBinding(request, filesystem) {
|
|
9320
|
+
const bindings = opts.getFilesystemBindings ? await opts.getFilesystemBindings(request) ?? [] : opts.filesystemBindings ?? [];
|
|
9321
|
+
return bindings.find((binding) => binding.filesystem === filesystem);
|
|
9322
|
+
}
|
|
9234
9323
|
app.get(
|
|
9235
9324
|
"/api/v1/tree",
|
|
9236
9325
|
async (request, reply) => {
|
|
@@ -9246,6 +9335,16 @@ function treeRoutes(app, opts, done) {
|
|
|
9246
9335
|
throw err;
|
|
9247
9336
|
}
|
|
9248
9337
|
const recursive = request.query.recursive === "true";
|
|
9338
|
+
const filesystem = requestedFilesystem3(request.query.filesystem);
|
|
9339
|
+
if (filesystem !== "user") {
|
|
9340
|
+
try {
|
|
9341
|
+
const binding = await resolveFilesystemBinding(request, filesystem);
|
|
9342
|
+
if (!binding) return sendNotFoundOrDenied2(reply);
|
|
9343
|
+
return { entries: await listBoundTree(binding, dir, recursive) };
|
|
9344
|
+
} catch {
|
|
9345
|
+
return sendNotFoundOrDenied2(reply);
|
|
9346
|
+
}
|
|
9347
|
+
}
|
|
9249
9348
|
try {
|
|
9250
9349
|
const workspace = await resolveWorkspace(request);
|
|
9251
9350
|
const entries = await listTree(workspace, dir, recursive);
|
|
@@ -12513,7 +12612,7 @@ async function createAgentApp(opts = {}) {
|
|
|
12513
12612
|
});
|
|
12514
12613
|
await app.register(fileRoutes, { workspace: runtimeBundle.workspace });
|
|
12515
12614
|
await app.register(fsEventsRoutes, { workspace: runtimeBundle.workspace });
|
|
12516
|
-
await app.register(treeRoutes, { workspace: runtimeBundle.workspace });
|
|
12615
|
+
await app.register(treeRoutes, { workspace: runtimeBundle.workspace, filesystemBindings: runtimeBundle.filesystemBindings });
|
|
12517
12616
|
await app.register(searchRoutes, { fileSearch: runtimeBundle.fileSearch });
|
|
12518
12617
|
await app.register(gitRoutes, {
|
|
12519
12618
|
getWorkspaceRoot: () => getOptionalRuntimeBundleStorageRoot(runtimeBundle)
|
|
@@ -12771,6 +12870,12 @@ function normalizeSessionNamespace(value) {
|
|
|
12771
12870
|
const trimmed = value.trim();
|
|
12772
12871
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
12773
12872
|
}
|
|
12873
|
+
function getRequestAuthSubject(request) {
|
|
12874
|
+
const userId = request?.user?.id;
|
|
12875
|
+
if (typeof userId === "string" && userId.trim()) return userId.trim();
|
|
12876
|
+
const authSubject = request?.workspaceContext?.authSubject;
|
|
12877
|
+
return typeof authSubject === "string" && authSubject.trim() ? authSubject.trim() : void 0;
|
|
12878
|
+
}
|
|
12774
12879
|
function createHttpError(code, message, details = {}) {
|
|
12775
12880
|
const error = new Error(message);
|
|
12776
12881
|
error.code = code;
|
|
@@ -12829,7 +12934,7 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
12829
12934
|
app.addHook("onClose", async () => {
|
|
12830
12935
|
await modeAdapter.dispose?.();
|
|
12831
12936
|
});
|
|
12832
|
-
const requestScopedRuntime = typeof opts.getWorkspaceId === "function" || typeof opts.getWorkspaceRoot === "function" || typeof opts.getTemplatePath === "function" || typeof opts.getPi === "function" || typeof opts.getSessionNamespace === "function" || typeof opts.getSystemPromptDynamic === "function";
|
|
12937
|
+
const requestScopedRuntime = typeof opts.getWorkspaceId === "function" || typeof opts.getWorkspaceRoot === "function" || typeof opts.getTemplatePath === "function" || typeof opts.getPi === "function" || typeof opts.getExtraTools === "function" || typeof opts.getSessionNamespace === "function" || typeof opts.getSystemPromptDynamic === "function";
|
|
12833
12938
|
const sessionChangesTracker = new InMemorySessionChangesTracker();
|
|
12834
12939
|
const externalPluginsEnabled = opts.externalPlugins !== false;
|
|
12835
12940
|
const runtimeBindings = /* @__PURE__ */ new Map();
|
|
@@ -12849,6 +12954,7 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
12849
12954
|
const scopedTemplatePath = opts.getTemplatePath ? await opts.getTemplatePath({ workspaceId, workspaceRoot: root, request }) : templatePath;
|
|
12850
12955
|
const pi = await resolveScopePi(workspaceId, root, request);
|
|
12851
12956
|
const sessionNamespace = normalizeSessionNamespace(opts.getSessionNamespace ? await opts.getSessionNamespace({ workspaceId, workspaceRoot: root, request }) : opts.sessionNamespace);
|
|
12957
|
+
const extraToolsAuthSubject = opts.getExtraTools ? getRequestAuthSubject(request) : void 0;
|
|
12852
12958
|
return {
|
|
12853
12959
|
root,
|
|
12854
12960
|
templatePath: scopedTemplatePath,
|
|
@@ -12860,7 +12966,8 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
12860
12966
|
root,
|
|
12861
12967
|
scopedTemplatePath ?? null,
|
|
12862
12968
|
pi,
|
|
12863
|
-
sessionNamespace ?? null
|
|
12969
|
+
sessionNamespace ?? null,
|
|
12970
|
+
extraToolsAuthSubject ?? null
|
|
12864
12971
|
])
|
|
12865
12972
|
};
|
|
12866
12973
|
}
|
|
@@ -13044,7 +13151,8 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13044
13151
|
workspaceId,
|
|
13045
13152
|
workspaceRoot: root,
|
|
13046
13153
|
runtimeMode: resolvedMode,
|
|
13047
|
-
workspaceFsCapability: runtimeBundle.workspace.fsCapability
|
|
13154
|
+
workspaceFsCapability: runtimeBundle.workspace.fsCapability,
|
|
13155
|
+
authSubject: getRequestAuthSubject(request)
|
|
13048
13156
|
}) : [];
|
|
13049
13157
|
const tools = mergeTools({
|
|
13050
13158
|
standardTools,
|
|
@@ -13136,7 +13244,8 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13136
13244
|
return await ensureRuntimeBindingReady(
|
|
13137
13245
|
workspaceId,
|
|
13138
13246
|
scope,
|
|
13139
|
-
await existing.promise
|
|
13247
|
+
await existing.promise,
|
|
13248
|
+
request
|
|
13140
13249
|
);
|
|
13141
13250
|
}
|
|
13142
13251
|
}
|
|
@@ -13150,17 +13259,18 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13150
13259
|
return await ensureRuntimeBindingReady(
|
|
13151
13260
|
workspaceId,
|
|
13152
13261
|
scope,
|
|
13153
|
-
await created.promise
|
|
13262
|
+
await created.promise,
|
|
13263
|
+
request
|
|
13154
13264
|
);
|
|
13155
13265
|
} catch (error) {
|
|
13156
13266
|
if (runtimeBindings.get(scope.key) === created) runtimeBindings.delete(scope.key);
|
|
13157
13267
|
throw error;
|
|
13158
13268
|
}
|
|
13159
13269
|
}
|
|
13160
|
-
async function recreateRuntimeBinding(workspaceId, scope) {
|
|
13270
|
+
async function recreateRuntimeBinding(workspaceId, scope, request) {
|
|
13161
13271
|
runtimeBindings.delete(scope.key);
|
|
13162
13272
|
modeAdapter.evictCachedRuntime?.({ workspaceId });
|
|
13163
|
-
const created = createRuntimeBindingEntry(workspaceId, scope);
|
|
13273
|
+
const created = createRuntimeBindingEntry(workspaceId, scope, request);
|
|
13164
13274
|
runtimeBindings.set(scope.key, created);
|
|
13165
13275
|
evictRuntimeBindings();
|
|
13166
13276
|
try {
|
|
@@ -13172,7 +13282,7 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13172
13282
|
throw error;
|
|
13173
13283
|
}
|
|
13174
13284
|
}
|
|
13175
|
-
async function ensureRuntimeBindingReady(workspaceId, scope, binding) {
|
|
13285
|
+
async function ensureRuntimeBindingReady(workspaceId, scope, binding, request) {
|
|
13176
13286
|
const healthCheck = modeAdapter.cachedBindingHealthCheck;
|
|
13177
13287
|
if (!healthCheck) return binding;
|
|
13178
13288
|
const now = Date.now();
|
|
@@ -13189,7 +13299,7 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13189
13299
|
err: result.error,
|
|
13190
13300
|
workspaceId
|
|
13191
13301
|
}, result.message ?? "[runtime] cached runtime invalid; recreating");
|
|
13192
|
-
return await recreateRuntimeBinding(workspaceId, scope);
|
|
13302
|
+
return await recreateRuntimeBinding(workspaceId, scope, request);
|
|
13193
13303
|
}
|
|
13194
13304
|
const hasRuntimeProvisioningInput = opts.provisionWorkspace !== false && Boolean(opts.provisionRuntime);
|
|
13195
13305
|
const staticBinding = requestScopedRuntime ? null : await getOrCreateRuntimeBinding(sessionId);
|
|
@@ -13282,7 +13392,8 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13282
13392
|
getWorkspace: async (request) => (await getBindingForRequest(request)).runtimeBundle.workspace
|
|
13283
13393
|
});
|
|
13284
13394
|
await app.register(treeRoutes, {
|
|
13285
|
-
getWorkspace: async (request) => (await getBindingForRequest(request)).runtimeBundle.workspace
|
|
13395
|
+
getWorkspace: async (request) => (await getBindingForRequest(request)).runtimeBundle.workspace,
|
|
13396
|
+
getFilesystemBindings: async (request) => (await getBindingForRequest(request)).runtimeBundle.filesystemBindings
|
|
13286
13397
|
});
|
|
13287
13398
|
await app.register(searchRoutes, {
|
|
13288
13399
|
getFileSearch: async (request) => (await getBindingForRequest(request)).runtimeBundle.fileSearch
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { W as Workspace, S as Sandbox, F as FileSearch, A as AgentTool } from '../agentPluginEvents-Ddn5DQ5E.js';
|
|
2
2
|
export { a as AgentHarness, C as CommandNotifyPayload, E as Entry, b as ExecOptions, c as ExecResult, I as IsolatedCodeInput, d as IsolatedCodeOutput, J as JSONSchema, R as RunContext, e as SandboxCapability, f as SandboxHandleRecord, g as SandboxHandleStore, h as SendMessageInput, i as Stat, T as TelemetryEvent, j as TelemetrySink, k as ToolExecContext, l as ToolResult, m as WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT, n as WORKSPACE_COMMAND_NOTIFY_EVENT, o as WorkspaceRuntimeContext, p as noopTelemetry, s as safeCapture } from '../agentPluginEvents-Ddn5DQ5E.js';
|
|
3
|
-
import { B as BoringChatPart, T as ToolUiMetadata } from '../piChatEvent-
|
|
4
|
-
export { A as ApiErrorPayload, a as ApiErrorPayloadSchema, b as ApiErrorResponse, c as ApiErrorResponseSchema, d as BoringChatMessage, C as ChatError, e as CommandReceipt, E as ERROR_CODES, f as ErrorCode, g as ErrorLogFields, h as ErrorLogFieldsSchema, F as FollowUpPayload, i as FollowUpReceipt, I as InterruptPayload, j as InterruptReceipt, P as PiChatEvent, k as PiChatHeartbeatFrame, l as PiChatSnapshot, m as PiChatStatus, n as PiChatStreamFrame, o as PromptPayload, p as PromptReceipt, Q as QueueClearPayload, q as QueueClearReceipt, r as QueuedUserMessage, S as StopPayload, s as StopReceipt, t as extractToolUiMetadata, u as isToolUiMetadata } from '../piChatEvent-
|
|
3
|
+
import { B as BoringChatPart, T as ToolUiMetadata } from '../piChatEvent-JbwYVBZj.js';
|
|
4
|
+
export { A as ApiErrorPayload, a as ApiErrorPayloadSchema, b as ApiErrorResponse, c as ApiErrorResponseSchema, d as BoringChatMessage, C as ChatError, e as CommandReceipt, E as ERROR_CODES, f as ErrorCode, g as ErrorLogFields, h as ErrorLogFieldsSchema, F as FollowUpPayload, i as FollowUpReceipt, I as InterruptPayload, j as InterruptReceipt, P as PiChatEvent, k as PiChatHeartbeatFrame, l as PiChatSnapshot, m as PiChatStatus, n as PiChatStreamFrame, o as PromptPayload, p as PromptReceipt, Q as QueueClearPayload, q as QueueClearReceipt, r as QueuedUserMessage, S as StopPayload, s as StopReceipt, t as extractToolUiMetadata, u as isToolUiMetadata } from '../piChatEvent-JbwYVBZj.js';
|
|
5
5
|
export { C as ChatAttachmentPayload, a as ChatModelSelection, b as ChatSubmitPayload, S as SessionCtx, c as SessionDetail, d as SessionStore, e as SessionSummary, T as ThinkingLevel } from '../chatSubmitPayload-DHqQL2wD.js';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
|
package/dist/shared/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hachej/boring-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.64",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Pane-embeddable coding agent. Ships direct/local/vercel-sandbox execution modes behind one interface.",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"use-stick-to-bottom": "^1.1.3",
|
|
75
75
|
"yaml": "^2.8.3",
|
|
76
76
|
"zod": "^3.25.76",
|
|
77
|
-
"@hachej/boring-ui-kit": "0.1.
|
|
77
|
+
"@hachej/boring-ui-kit": "0.1.64"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@antithesishq/bombadil": "0.5.0",
|