@agimon-ai/doompi-core 0.0.1-alpha.119 → 0.0.1-alpha.121
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/contextDetailStore.cjs +6 -1
- package/dist/contextDetailStore.cjs.map +1 -1
- package/dist/contextDetailStore.d.mts +6 -0
- package/dist/contextDetailStore.d.mts.map +1 -1
- package/dist/contextDetailStore.mjs +5 -2
- package/dist/contextDetailStore.mjs.map +1 -1
- package/dist/headlessServer.cjs +29 -26
- package/dist/headlessServer.cjs.map +1 -1
- package/dist/headlessServer.d.mts.map +1 -1
- package/dist/headlessServer.mjs +22 -19
- package/dist/headlessServer.mjs.map +1 -1
- package/dist/packageApi.cjs +1 -0
- package/dist/packageApi.d.mts +2 -2
- package/dist/packageApi.mjs +2 -2
- package/dist/packageApiServer.cjs +1 -0
- package/dist/packageApiServer.cjs.map +1 -1
- package/dist/packageApiServer.d.mts +2 -0
- package/dist/packageApiServer.d.mts.map +1 -1
- package/dist/packageApiServer.mjs +1 -0
- package/dist/packageApiServer.mjs.map +1 -1
- package/dist/remoteApi.cjs +2 -0
- package/dist/remoteApi.cjs.map +1 -1
- package/dist/remoteApi.mjs +2 -0
- package/dist/remoteApi.mjs.map +1 -1
- package/dist/remoteRuntime.cjs +36 -15
- package/dist/remoteRuntime.cjs.map +1 -1
- package/dist/remoteRuntime.d.mts +3 -0
- package/dist/remoteRuntime.d.mts.map +1 -1
- package/dist/remoteRuntime.mjs +21 -0
- package/dist/remoteRuntime.mjs.map +1 -1
- package/dist/src/constants/sessionFiles.cjs +27 -0
- package/dist/src/constants/sessionFiles.cjs.map +1 -0
- package/dist/src/constants/sessionFiles.mjs +25 -0
- package/dist/src/constants/sessionFiles.mjs.map +1 -0
- package/dist/src/schemas/packageApi.cjs +3 -0
- package/dist/src/schemas/packageApi.cjs.map +1 -1
- package/dist/src/schemas/packageApi.d.mts +21 -0
- package/dist/src/schemas/packageApi.d.mts.map +1 -1
- package/dist/src/schemas/packageApi.mjs +3 -1
- package/dist/src/schemas/packageApi.mjs.map +1 -1
- package/dist/src/server/directHarnessRuntime.cjs +7 -1
- package/dist/src/server/directHarnessRuntime.cjs.map +1 -1
- package/dist/src/server/directHarnessRuntime.mjs +7 -1
- package/dist/src/server/directHarnessRuntime.mjs.map +1 -1
- package/dist/src/services/publicFileShares/index.cjs +181 -0
- package/dist/src/services/publicFileShares/index.cjs.map +1 -0
- package/dist/src/services/publicFileShares/index.d.mts +16 -0
- package/dist/src/services/publicFileShares/index.d.mts.map +1 -0
- package/dist/src/services/publicFileShares/index.mjs +177 -0
- package/dist/src/services/publicFileShares/index.mjs.map +1 -0
- package/dist/src/services/sessionAttachments/index.cjs +110 -0
- package/dist/src/services/sessionAttachments/index.cjs.map +1 -0
- package/dist/src/services/sessionAttachments/index.mjs +106 -0
- package/dist/src/services/sessionAttachments/index.mjs.map +1 -0
- package/dist/src/systems/child/adapters/headlessChildSessionService.cjs +1 -1
- package/dist/src/systems/child/adapters/headlessChildSessionService.cjs.map +1 -1
- package/dist/src/systems/child/adapters/headlessChildSessionService.mjs +1 -1
- package/dist/src/systems/child/adapters/headlessChildSessionService.mjs.map +1 -1
- package/dist/src/systems/child/types/childSession.cjs.map +1 -1
- package/dist/src/systems/child/types/childSession.d.mts +5 -0
- package/dist/src/systems/child/types/childSession.d.mts.map +1 -1
- package/dist/src/systems/child/types/childSession.mjs.map +1 -1
- package/dist/terminalPiChildSessionService.cjs +1 -1
- package/dist/terminalPiChildSessionService.cjs.map +1 -1
- package/dist/terminalPiChildSessionService.mjs +1 -1
- package/dist/terminalPiChildSessionService.mjs.map +1 -1
- package/package.json +14 -14
|
@@ -29,7 +29,10 @@ const PRIVATE_FILE_MODE = 384;
|
|
|
29
29
|
function agentDirectory(environment) {
|
|
30
30
|
return environment[AGENT_DIR_ENV] || node_path.default.join(node_os.default.homedir(), ".pi", "agent");
|
|
31
31
|
}
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* A session id reaches this from a query string, so it never becomes a path.
|
|
34
|
+
* `.` and `..` pass through unchanged: a caller using the result as a directory must refuse them.
|
|
35
|
+
*/
|
|
33
36
|
function safeName(sessionId) {
|
|
34
37
|
return sessionId.replace(/[^a-zA-Z0-9._-]/gu, "_");
|
|
35
38
|
}
|
|
@@ -91,10 +94,12 @@ function findContextItem(file, itemKind, name) {
|
|
|
91
94
|
return file.items.find((item) => item.itemKind === itemKind && item.name === name);
|
|
92
95
|
}
|
|
93
96
|
//#endregion
|
|
97
|
+
exports.agentDirectory = agentDirectory;
|
|
94
98
|
exports.contextDetailPath = contextDetailPath;
|
|
95
99
|
exports.findContextItem = findContextItem;
|
|
96
100
|
exports.readContextDetail = readContextDetail;
|
|
97
101
|
exports.removeContextDetail = removeContextDetail;
|
|
102
|
+
exports.safeName = safeName;
|
|
98
103
|
exports.writeContextDetail = writeContextDetail;
|
|
99
104
|
|
|
100
105
|
//# sourceMappingURL=contextDetailStore.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contextDetailStore.cjs","names":["path","os","fs"],"sources":["../src/services/contextDetailStore/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { CONTEXT_DETAIL_VERSION } from '../../constants/contextApi';\nimport type { ContextDetailFile, ContextItemDetail, ContextItemKind } from '../../types/contextApi';\n\n/**\n * Where the agent leaves the composition's detail for the session API to find.\n *\n * The two are separate processes: the inventory only exists inside the agent,\n * and the API that answers the browser is served by the session's host. Every\n * other package-owned API in the repository bridges that gap through the\n * filesystem rather than through the frame protocol, and this one follows,\n * because a file is also what makes the answer survive the agent going quiet\n * between turns.\n *\n * One file per session, replaced whole. The detail is a projection of the\n * composition, not a log of it, so an older copy has no reader.\n */\n\nconst DIRECTORY_NAME = 'doom-context';\nconst AGENT_DIR_ENV = 'PI_CODING_AGENT_DIR';\n/** Owner-only: a tool schema is not secret, but it describes the machine. */\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst PRIVATE_FILE_MODE = 0o600;\n\
|
|
1
|
+
{"version":3,"file":"contextDetailStore.cjs","names":["path","os","fs"],"sources":["../src/services/contextDetailStore/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { CONTEXT_DETAIL_VERSION } from '../../constants/contextApi';\nimport type { ContextDetailFile, ContextItemDetail, ContextItemKind } from '../../types/contextApi';\n\n/**\n * Where the agent leaves the composition's detail for the session API to find.\n *\n * The two are separate processes: the inventory only exists inside the agent,\n * and the API that answers the browser is served by the session's host. Every\n * other package-owned API in the repository bridges that gap through the\n * filesystem rather than through the frame protocol, and this one follows,\n * because a file is also what makes the answer survive the agent going quiet\n * between turns.\n *\n * One file per session, replaced whole. The detail is a projection of the\n * composition, not a log of it, so an older copy has no reader.\n */\n\nconst DIRECTORY_NAME = 'doom-context';\nconst AGENT_DIR_ENV = 'PI_CODING_AGENT_DIR';\n/** Owner-only: a tool schema is not secret, but it describes the machine. */\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst PRIVATE_FILE_MODE = 0o600;\n\nexport function agentDirectory(environment: Readonly<Record<string, string | undefined>>): string {\n return environment[AGENT_DIR_ENV] || path.join(os.homedir(), '.pi', 'agent');\n}\n\n/**\n * A session id reaches this from a query string, so it never becomes a path.\n * `.` and `..` pass through unchanged: a caller using the result as a directory must refuse them.\n */\nexport function safeName(sessionId: string): string {\n return sessionId.replace(/[^a-zA-Z0-9._-]/gu, '_');\n}\n\nexport function contextDetailPath(\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): string {\n return path.join(agentDirectory(environment), DIRECTORY_NAME, `${safeName(sessionId)}.json`);\n}\n\n/**\n * Publishes the detail for one session.\n *\n * Written through a temporary file so a reader never sees half a document, and\n * failures are reported to the caller rather than thrown: the panel works\n * without this, and a session must not be lost to a full disk.\n */\nexport function writeContextDetail(\n sessionId: string,\n revision: number,\n items: readonly ContextItemDetail[],\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): boolean {\n const target = contextDetailPath(sessionId, environment);\n const payload: ContextDetailFile = { version: CONTEXT_DETAIL_VERSION, revision, items };\n const temporary = `${target}.${String(process.pid)}.tmp`;\n try {\n fs.mkdirSync(path.dirname(target), { recursive: true, mode: PRIVATE_DIRECTORY_MODE });\n fs.writeFileSync(temporary, JSON.stringify(payload), { mode: PRIVATE_FILE_MODE });\n fs.renameSync(temporary, target);\n return true;\n } catch {\n try {\n fs.rmSync(temporary, { force: true });\n } catch {\n // The temporary file is already unreachable; nothing further to do.\n }\n return false;\n }\n}\n\n/** Drops a session's file. Called when the session ends, so the directory does not grow forever. */\nexport function removeContextDetail(\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): void {\n try {\n fs.rmSync(contextDetailPath(sessionId, environment), { force: true });\n } catch {\n // A file that cannot be removed is stale, not fatal; the next session with\n // this id overwrites it.\n }\n}\n\nfunction isDetailFile(value: unknown): value is ContextDetailFile {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as Record<string, unknown>;\n return candidate.version === CONTEXT_DETAIL_VERSION && Array.isArray(candidate.items);\n}\n\n/** What the session wrote, or undefined when it has not written yet. */\nexport function readContextDetail(\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): ContextDetailFile | undefined {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(contextDetailPath(sessionId, environment), 'utf8'));\n return isDetailFile(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** One row's detail, matched the way the panel identifies it. */\nexport function findContextItem(\n file: ContextDetailFile,\n itemKind: ContextItemKind,\n name: string,\n): ContextItemDetail | undefined {\n return file.items.find((item) => item.itemKind === itemKind && item.name === name);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,iBAAiB;AACvB,MAAM,gBAAgB;;AAEtB,MAAM,yBAAyB;AAC/B,MAAM,oBAAoB;AAE1B,SAAgB,eAAe,aAAmE;CAChG,OAAO,YAAY,kBAAkBA,UAAAA,QAAK,KAAKC,QAAAA,QAAG,QAAQ,GAAG,OAAO,OAAO;AAC7E;;;;;AAMA,SAAgB,SAAS,WAA2B;CAClD,OAAO,UAAU,QAAQ,qBAAqB,GAAG;AACnD;AAEA,SAAgB,kBACd,WACA,cAA4D,QAAQ,KAC5D;CACR,OAAOD,UAAAA,QAAK,KAAK,eAAe,WAAW,GAAG,gBAAgB,GAAG,SAAS,SAAS,EAAE,MAAM;AAC7F;;;;;;;;AASA,SAAgB,mBACd,WACA,UACA,OACA,cAA4D,QAAQ,KAC3D;CACT,MAAM,SAAS,kBAAkB,WAAW,WAAW;CACvD,MAAM,UAA6B;EAAE,SAAA;EAAiC;EAAU;CAAM;CACtF,MAAM,YAAY,GAAG,OAAO,GAAG,OAAO,QAAQ,GAAG,EAAE;CACnD,IAAI;EACF,QAAA,QAAG,UAAUA,UAAAA,QAAK,QAAQ,MAAM,GAAG;GAAE,WAAW;GAAM,MAAM;EAAuB,CAAC;EACpF,QAAA,QAAG,cAAc,WAAW,KAAK,UAAU,OAAO,GAAG,EAAE,MAAM,kBAAkB,CAAC;EAChF,QAAA,QAAG,WAAW,WAAW,MAAM;EAC/B,OAAO;CACT,QAAQ;EACN,IAAI;GACF,QAAA,QAAG,OAAO,WAAW,EAAE,OAAO,KAAK,CAAC;EACtC,QAAQ,CAER;EACA,OAAO;CACT;AACF;;AAGA,SAAgB,oBACd,WACA,cAA4D,QAAQ,KAC9D;CACN,IAAI;EACF,QAAA,QAAG,OAAO,kBAAkB,WAAW,WAAW,GAAG,EAAE,OAAO,KAAK,CAAC;CACtE,QAAQ,CAGR;AACF;AAEA,SAAS,aAAa,OAA4C;CAChE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,YAAY;CAClB,OAAO,UAAU,YAAA,KAAsC,MAAM,QAAQ,UAAU,KAAK;AACtF;;AAGA,SAAgB,kBACd,WACA,cAA4D,QAAQ,KACrC;CAC/B,IAAI;EACF,MAAM,SAAkB,KAAK,MAAME,QAAAA,QAAG,aAAa,kBAAkB,WAAW,WAAW,GAAG,MAAM,CAAC;EACrG,OAAO,aAAa,MAAM,IAAI,SAAS,KAAA;CACzC,QAAQ;EACN;CACF;AACF;;AAGA,SAAgB,gBACd,MACA,UACA,MAC+B;CAC/B,OAAO,KAAK,MAAM,MAAM,SAAS,KAAK,aAAa,YAAY,KAAK,SAAS,IAAI;AACnF"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { ContextDetailFile, ContextItemDetail, ContextItemKind } from "./typesContextApi.mjs";
|
|
2
2
|
//#region src/services/contextDetailStore/index.d.ts
|
|
3
|
+
export declare function agentDirectory(environment: Readonly<Record<string, string | undefined>>): string;
|
|
4
|
+
/**
|
|
5
|
+
* A session id reaches this from a query string, so it never becomes a path.
|
|
6
|
+
* `.` and `..` pass through unchanged: a caller using the result as a directory must refuse them.
|
|
7
|
+
*/
|
|
8
|
+
export declare function safeName(sessionId: string): string;
|
|
3
9
|
export declare function contextDetailPath(sessionId: string, environment?: Readonly<Record<string, string | undefined>>): string;
|
|
4
10
|
/**
|
|
5
11
|
* Publishes the detail for one session.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contextDetailStore.d.mts","names":[],"sources":["../src/services/contextDetailStore/index.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"contextDetailStore.d.mts","names":[],"sources":["../src/services/contextDetailStore/index.ts"],"mappings":";;wBA2BgB,eAAe,aAAa,SAAS;;;;;wBAQrC,SAAS;wBAIT,kBACd,mBACA,cAAa,SAAS;;;;;;;;wBAYR,mBACd,mBACA,kBACA,gBAAgB,qBAChB,cAAa,SAAS;;wBAqBR,oBACd,mBACA,cAAa,SAAS;;wBAiBR,kBACd,mBACA,cAAa,SAAS,sCACrB;;wBAUa,gBACd,MAAM,mBACN,UAAU,iBACV,eACC"}
|
|
@@ -24,7 +24,10 @@ const PRIVATE_FILE_MODE = 384;
|
|
|
24
24
|
function agentDirectory(environment) {
|
|
25
25
|
return environment[AGENT_DIR_ENV] || path.join(os.homedir(), ".pi", "agent");
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* A session id reaches this from a query string, so it never becomes a path.
|
|
29
|
+
* `.` and `..` pass through unchanged: a caller using the result as a directory must refuse them.
|
|
30
|
+
*/
|
|
28
31
|
function safeName(sessionId) {
|
|
29
32
|
return sessionId.replace(/[^a-zA-Z0-9._-]/gu, "_");
|
|
30
33
|
}
|
|
@@ -86,6 +89,6 @@ function findContextItem(file, itemKind, name) {
|
|
|
86
89
|
return file.items.find((item) => item.itemKind === itemKind && item.name === name);
|
|
87
90
|
}
|
|
88
91
|
//#endregion
|
|
89
|
-
export { contextDetailPath, findContextItem, readContextDetail, removeContextDetail, writeContextDetail };
|
|
92
|
+
export { agentDirectory, contextDetailPath, findContextItem, readContextDetail, removeContextDetail, safeName, writeContextDetail };
|
|
90
93
|
|
|
91
94
|
//# sourceMappingURL=contextDetailStore.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contextDetailStore.mjs","names":[],"sources":["../src/services/contextDetailStore/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { CONTEXT_DETAIL_VERSION } from '../../constants/contextApi';\nimport type { ContextDetailFile, ContextItemDetail, ContextItemKind } from '../../types/contextApi';\n\n/**\n * Where the agent leaves the composition's detail for the session API to find.\n *\n * The two are separate processes: the inventory only exists inside the agent,\n * and the API that answers the browser is served by the session's host. Every\n * other package-owned API in the repository bridges that gap through the\n * filesystem rather than through the frame protocol, and this one follows,\n * because a file is also what makes the answer survive the agent going quiet\n * between turns.\n *\n * One file per session, replaced whole. The detail is a projection of the\n * composition, not a log of it, so an older copy has no reader.\n */\n\nconst DIRECTORY_NAME = 'doom-context';\nconst AGENT_DIR_ENV = 'PI_CODING_AGENT_DIR';\n/** Owner-only: a tool schema is not secret, but it describes the machine. */\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst PRIVATE_FILE_MODE = 0o600;\n\
|
|
1
|
+
{"version":3,"file":"contextDetailStore.mjs","names":[],"sources":["../src/services/contextDetailStore/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { CONTEXT_DETAIL_VERSION } from '../../constants/contextApi';\nimport type { ContextDetailFile, ContextItemDetail, ContextItemKind } from '../../types/contextApi';\n\n/**\n * Where the agent leaves the composition's detail for the session API to find.\n *\n * The two are separate processes: the inventory only exists inside the agent,\n * and the API that answers the browser is served by the session's host. Every\n * other package-owned API in the repository bridges that gap through the\n * filesystem rather than through the frame protocol, and this one follows,\n * because a file is also what makes the answer survive the agent going quiet\n * between turns.\n *\n * One file per session, replaced whole. The detail is a projection of the\n * composition, not a log of it, so an older copy has no reader.\n */\n\nconst DIRECTORY_NAME = 'doom-context';\nconst AGENT_DIR_ENV = 'PI_CODING_AGENT_DIR';\n/** Owner-only: a tool schema is not secret, but it describes the machine. */\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst PRIVATE_FILE_MODE = 0o600;\n\nexport function agentDirectory(environment: Readonly<Record<string, string | undefined>>): string {\n return environment[AGENT_DIR_ENV] || path.join(os.homedir(), '.pi', 'agent');\n}\n\n/**\n * A session id reaches this from a query string, so it never becomes a path.\n * `.` and `..` pass through unchanged: a caller using the result as a directory must refuse them.\n */\nexport function safeName(sessionId: string): string {\n return sessionId.replace(/[^a-zA-Z0-9._-]/gu, '_');\n}\n\nexport function contextDetailPath(\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): string {\n return path.join(agentDirectory(environment), DIRECTORY_NAME, `${safeName(sessionId)}.json`);\n}\n\n/**\n * Publishes the detail for one session.\n *\n * Written through a temporary file so a reader never sees half a document, and\n * failures are reported to the caller rather than thrown: the panel works\n * without this, and a session must not be lost to a full disk.\n */\nexport function writeContextDetail(\n sessionId: string,\n revision: number,\n items: readonly ContextItemDetail[],\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): boolean {\n const target = contextDetailPath(sessionId, environment);\n const payload: ContextDetailFile = { version: CONTEXT_DETAIL_VERSION, revision, items };\n const temporary = `${target}.${String(process.pid)}.tmp`;\n try {\n fs.mkdirSync(path.dirname(target), { recursive: true, mode: PRIVATE_DIRECTORY_MODE });\n fs.writeFileSync(temporary, JSON.stringify(payload), { mode: PRIVATE_FILE_MODE });\n fs.renameSync(temporary, target);\n return true;\n } catch {\n try {\n fs.rmSync(temporary, { force: true });\n } catch {\n // The temporary file is already unreachable; nothing further to do.\n }\n return false;\n }\n}\n\n/** Drops a session's file. Called when the session ends, so the directory does not grow forever. */\nexport function removeContextDetail(\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): void {\n try {\n fs.rmSync(contextDetailPath(sessionId, environment), { force: true });\n } catch {\n // A file that cannot be removed is stale, not fatal; the next session with\n // this id overwrites it.\n }\n}\n\nfunction isDetailFile(value: unknown): value is ContextDetailFile {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as Record<string, unknown>;\n return candidate.version === CONTEXT_DETAIL_VERSION && Array.isArray(candidate.items);\n}\n\n/** What the session wrote, or undefined when it has not written yet. */\nexport function readContextDetail(\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): ContextDetailFile | undefined {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(contextDetailPath(sessionId, environment), 'utf8'));\n return isDetailFile(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** One row's detail, matched the way the panel identifies it. */\nexport function findContextItem(\n file: ContextDetailFile,\n itemKind: ContextItemKind,\n name: string,\n): ContextItemDetail | undefined {\n return file.items.find((item) => item.itemKind === itemKind && item.name === name);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,MAAM,iBAAiB;AACvB,MAAM,gBAAgB;;AAEtB,MAAM,yBAAyB;AAC/B,MAAM,oBAAoB;AAE1B,SAAgB,eAAe,aAAmE;CAChG,OAAO,YAAY,kBAAkB,KAAK,KAAK,GAAG,QAAQ,GAAG,OAAO,OAAO;AAC7E;;;;;AAMA,SAAgB,SAAS,WAA2B;CAClD,OAAO,UAAU,QAAQ,qBAAqB,GAAG;AACnD;AAEA,SAAgB,kBACd,WACA,cAA4D,QAAQ,KAC5D;CACR,OAAO,KAAK,KAAK,eAAe,WAAW,GAAG,gBAAgB,GAAG,SAAS,SAAS,EAAE,MAAM;AAC7F;;;;;;;;AASA,SAAgB,mBACd,WACA,UACA,OACA,cAA4D,QAAQ,KAC3D;CACT,MAAM,SAAS,kBAAkB,WAAW,WAAW;CACvD,MAAM,UAA6B;EAAE,SAAA;EAAiC;EAAU;CAAM;CACtF,MAAM,YAAY,GAAG,OAAO,GAAG,OAAO,QAAQ,GAAG,EAAE;CACnD,IAAI;EACF,GAAG,UAAU,KAAK,QAAQ,MAAM,GAAG;GAAE,WAAW;GAAM,MAAM;EAAuB,CAAC;EACpF,GAAG,cAAc,WAAW,KAAK,UAAU,OAAO,GAAG,EAAE,MAAM,kBAAkB,CAAC;EAChF,GAAG,WAAW,WAAW,MAAM;EAC/B,OAAO;CACT,QAAQ;EACN,IAAI;GACF,GAAG,OAAO,WAAW,EAAE,OAAO,KAAK,CAAC;EACtC,QAAQ,CAER;EACA,OAAO;CACT;AACF;;AAGA,SAAgB,oBACd,WACA,cAA4D,QAAQ,KAC9D;CACN,IAAI;EACF,GAAG,OAAO,kBAAkB,WAAW,WAAW,GAAG,EAAE,OAAO,KAAK,CAAC;CACtE,QAAQ,CAGR;AACF;AAEA,SAAS,aAAa,OAA4C;CAChE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,YAAY;CAClB,OAAO,UAAU,YAAA,KAAsC,MAAM,QAAQ,UAAU,KAAK;AACtF;;AAGA,SAAgB,kBACd,WACA,cAA4D,QAAQ,KACrC;CAC/B,IAAI;EACF,MAAM,SAAkB,KAAK,MAAM,GAAG,aAAa,kBAAkB,WAAW,WAAW,GAAG,MAAM,CAAC;EACrG,OAAO,aAAa,MAAM,IAAI,SAAS,KAAA;CACzC,QAAQ;EACN;CACF;AACF;;AAGA,SAAgB,gBACd,MACA,UACA,MAC+B;CAC/B,OAAO,KAAK,MAAM,MAAM,SAAS,KAAK,aAAa,YAAY,KAAK,SAAS,IAAI;AACnF"}
|
package/dist/headlessServer.cjs
CHANGED
|
@@ -5,9 +5,11 @@ const require_harnessErrorMessage = require("./src/server/harnessErrorMessage.cj
|
|
|
5
5
|
const require_contextDetailStore = require("./contextDetailStore.cjs");
|
|
6
6
|
const require_serverTelemetry = require("./serverTelemetry.cjs");
|
|
7
7
|
const require_packageApi = require("./src/schemas/packageApi.cjs");
|
|
8
|
-
const
|
|
9
|
-
const require_index
|
|
10
|
-
const require_index$
|
|
8
|
+
const require_sessionFiles = require("./src/constants/sessionFiles.cjs");
|
|
9
|
+
const require_index = require("./src/services/sessionAttachments/index.cjs");
|
|
10
|
+
const require_index$1 = require("./src/services/sessionMcpActivity/index.cjs");
|
|
11
|
+
const require_index$2 = require("./src/services/sessionMcpConversations/index.cjs");
|
|
12
|
+
const require_index$3 = require("./src/services/sessionMcpRegistrationStore/index.cjs");
|
|
11
13
|
const require_runtimeContextApi = require("./runtimeContextApi.cjs");
|
|
12
14
|
const require_headlessProtocol = require("./src/server/headlessProtocol.cjs");
|
|
13
15
|
const require_sessionMcpRoutes = require("./src/server/sessionMcpRoutes.cjs");
|
|
@@ -40,27 +42,11 @@ const DOOM_PACKAGE_API_PATH_PATTERN = /^\/api(?:\/workspaces\/([^/]+)(?:\/sessio
|
|
|
40
42
|
const HEALTH_ROLE = "hub";
|
|
41
43
|
const PROTOCOL_VERSION = 1;
|
|
42
44
|
const MAX_BODY_BYTES = 8388608;
|
|
43
|
-
const MAX_SESSION_FILE_BYTES = 26214400;
|
|
44
45
|
const DIRECTORY_SUGGESTION_LIMIT = 12;
|
|
45
46
|
const DIRECTORY_CHILDREN_LIMIT = 500;
|
|
46
47
|
const HOME_PREFIX = "~";
|
|
47
48
|
const WORKSPACE_NAME_MAX_LENGTH = 80;
|
|
48
49
|
const WORKSPACE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9 ._-]*$/u;
|
|
49
|
-
const SESSION_FILE_CONTENT_TYPES = {
|
|
50
|
-
".avif": "image/avif",
|
|
51
|
-
".bmp": "image/bmp",
|
|
52
|
-
".gif": "image/gif",
|
|
53
|
-
".jpeg": "image/jpeg",
|
|
54
|
-
".jpg": "image/jpeg",
|
|
55
|
-
".png": "image/png",
|
|
56
|
-
".svg": "image/svg+xml",
|
|
57
|
-
".webp": "image/webp",
|
|
58
|
-
".m4v": "video/mp4",
|
|
59
|
-
".mov": "video/quicktime",
|
|
60
|
-
".mp4": "video/mp4",
|
|
61
|
-
".webm": "video/webm",
|
|
62
|
-
".pdf": "application/pdf"
|
|
63
|
-
};
|
|
64
50
|
function sessionView(session) {
|
|
65
51
|
return {
|
|
66
52
|
id: session.id,
|
|
@@ -167,11 +153,11 @@ async function sessionFile(session, requestedPath) {
|
|
|
167
153
|
try {
|
|
168
154
|
const stat = await handle.stat();
|
|
169
155
|
if (!stat.isFile()) return Response.json({ error: "Session file not found." }, { status: 404 });
|
|
170
|
-
if (stat.size >
|
|
156
|
+
if (stat.size > 26214400) return Response.json({ error: "Session file is too large." }, { status: 413 });
|
|
171
157
|
const bytes = await handle.readFile();
|
|
172
|
-
if (bytes.byteLength >
|
|
158
|
+
if (bytes.byteLength > 26214400) return Response.json({ error: "Session file is too large." }, { status: 413 });
|
|
173
159
|
return new Response(bytes, { headers: {
|
|
174
|
-
"content-type": SESSION_FILE_CONTENT_TYPES[node_path.default.extname(filePath).toLowerCase()] ?? "application/octet-stream",
|
|
160
|
+
"content-type": require_sessionFiles.SESSION_FILE_CONTENT_TYPES[node_path.default.extname(filePath).toLowerCase()] ?? "application/octet-stream",
|
|
175
161
|
"content-length": String(bytes.byteLength),
|
|
176
162
|
"cache-control": "no-store",
|
|
177
163
|
"x-content-type-options": "nosniff"
|
|
@@ -243,13 +229,18 @@ async function directoryChildren(requested) {
|
|
|
243
229
|
directories
|
|
244
230
|
};
|
|
245
231
|
}
|
|
232
|
+
var RequestBodyTooLargeError = class extends Error {
|
|
233
|
+
constructor() {
|
|
234
|
+
super("Request body is too large.");
|
|
235
|
+
}
|
|
236
|
+
};
|
|
246
237
|
async function readBody(request) {
|
|
247
238
|
const chunks = [];
|
|
248
239
|
let size = 0;
|
|
249
240
|
for await (const chunk of request) {
|
|
250
241
|
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
251
242
|
size += buffer.byteLength;
|
|
252
|
-
if (size > MAX_BODY_BYTES) throw new
|
|
243
|
+
if (size > MAX_BODY_BYTES) throw new RequestBodyTooLargeError();
|
|
253
244
|
chunks.push(buffer);
|
|
254
245
|
}
|
|
255
246
|
return Buffer.concat(chunks);
|
|
@@ -367,9 +358,9 @@ async function serveHeadlessServer(options) {
|
|
|
367
358
|
publicOriginRevision: options.sessionMcpPublicOriginRevision,
|
|
368
359
|
onNotice: options.onNotice,
|
|
369
360
|
isSessionPersisted: options.isSessionPersisted,
|
|
370
|
-
activityStore: require_index.createSessionMcpActivityStore(sessionMcpStateDir),
|
|
371
|
-
conversationStore: require_index$
|
|
372
|
-
registrationStore: require_index$
|
|
361
|
+
activityStore: require_index$1.createSessionMcpActivityStore(sessionMcpStateDir),
|
|
362
|
+
conversationStore: require_index$2.createSessionMcpConversationStore(sessionMcpStateDir),
|
|
363
|
+
registrationStore: require_index$3.createSessionMcpRegistrationStore({
|
|
373
364
|
stateDir: sessionMcpStateDir,
|
|
374
365
|
onNotice: options.onNotice
|
|
375
366
|
})
|
|
@@ -793,6 +784,18 @@ async function serveHeadlessServer(options) {
|
|
|
793
784
|
await writeResponse(response, await sessionFile(session, url.searchParams.get("path")));
|
|
794
785
|
return;
|
|
795
786
|
}
|
|
787
|
+
if (suffix === "/attachments" && request.method === "POST") {
|
|
788
|
+
let bytes;
|
|
789
|
+
try {
|
|
790
|
+
bytes = await readBody(request);
|
|
791
|
+
} catch (error) {
|
|
792
|
+
if (!(error instanceof RequestBodyTooLargeError)) throw error;
|
|
793
|
+
json(response, 413, { error: "The attachment exceeds the 8 MB upload limit." });
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
json(response, 201, await require_index.writeSessionAttachment(sessionId, url.searchParams.get("name") ?? "file", bytes));
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
796
799
|
if (suffix === "/restart" && request.method === "POST" && options.restartSession) {
|
|
797
800
|
const restart = options.restartSession(session);
|
|
798
801
|
const settled = restart.then(() => void 0, () => void 0);
|