@prismer/runtime 2.0.2 → 2.0.3
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/cli.cjs +73 -17
- package/dist/cli.js +73 -17
- package/dist/index.cjs +73 -17
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +73 -17
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -987,15 +987,30 @@ No @ needed; the human is the only other party.
|
|
|
987
987
|
);
|
|
988
988
|
}
|
|
989
989
|
await stopStaleHermesGateways(profileName, portOverride, config.startupTimeoutMs);
|
|
990
|
+
const hermesProfileDir = getHermesProfileDir(profileName);
|
|
991
|
+
try {
|
|
992
|
+
(0, import_node_fs2.mkdirSync)(hermesProfileDir, { recursive: true });
|
|
993
|
+
} catch (err) {
|
|
994
|
+
process.stderr.write(
|
|
995
|
+
`[hermes-adapter] failed to ensure hermes profile dir ${hermesProfileDir}: ${err.message}
|
|
996
|
+
`
|
|
997
|
+
);
|
|
998
|
+
}
|
|
990
999
|
(0, import_node_child_process3.spawn)("hermes", ["-p", profileName, "gateway", "run"], {
|
|
991
1000
|
detached: false,
|
|
992
1001
|
stdio: "ignore",
|
|
1002
|
+
cwd: hermesProfileDir,
|
|
993
1003
|
env: {
|
|
994
1004
|
...process.env,
|
|
995
1005
|
API_SERVER_ENABLED: "true",
|
|
996
1006
|
API_SERVER_KEY: config.apiKey,
|
|
997
1007
|
API_SERVER_PORT: String(portOverride),
|
|
998
1008
|
API_SERVER_HOST: "127.0.0.1",
|
|
1009
|
+
// TERMINAL_CWD is the env that hermes file_tools._resolve_path
|
|
1010
|
+
// honors over `os.getcwd()` for relative paths. Pin it to the
|
|
1011
|
+
// profile dir so even non-LLM-initiated writes (e.g. hermes
|
|
1012
|
+
// internal book-keeping) land in the sandbox.
|
|
1013
|
+
TERMINAL_CWD: hermesProfileDir,
|
|
999
1014
|
[config.prismerApiKeyEnv]: resolvePrismerApiKey(config)
|
|
1000
1015
|
}
|
|
1001
1016
|
});
|
|
@@ -1919,7 +1934,7 @@ var require_package = __commonJS({
|
|
|
1919
1934
|
"package.json"(exports2, module2) {
|
|
1920
1935
|
module2.exports = {
|
|
1921
1936
|
name: "@prismer/runtime",
|
|
1922
|
-
version: "2.0.
|
|
1937
|
+
version: "2.0.3",
|
|
1923
1938
|
description: "Prismer Cloud daemon runtime \u2014 TS-only adapter host for hosted IM agents",
|
|
1924
1939
|
type: "module",
|
|
1925
1940
|
main: "dist/index.js",
|
|
@@ -6566,12 +6581,23 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
6566
6581
|
let reply;
|
|
6567
6582
|
const outboxBase = deps.paths?.runsDir ? path2.join(deps.paths.runsDir, taskId) : null;
|
|
6568
6583
|
const outboxDir = outboxBase ? path2.join(outboxBase, "_outbox") : null;
|
|
6584
|
+
const workDir = outboxBase ? path2.join(outboxBase, "workdir") : null;
|
|
6569
6585
|
if (outboxDir) {
|
|
6570
6586
|
try {
|
|
6571
6587
|
await import_node_fs12.promises.mkdir(outboxDir, { recursive: true });
|
|
6572
6588
|
} catch (err) {
|
|
6573
6589
|
process.stderr.write(
|
|
6574
6590
|
`[daemon] outbox provision failed task=${taskId} dir=${outboxDir}: ${err.message}
|
|
6591
|
+
`
|
|
6592
|
+
);
|
|
6593
|
+
}
|
|
6594
|
+
}
|
|
6595
|
+
if (workDir) {
|
|
6596
|
+
try {
|
|
6597
|
+
await import_node_fs12.promises.mkdir(workDir, { recursive: true });
|
|
6598
|
+
} catch (err) {
|
|
6599
|
+
process.stderr.write(
|
|
6600
|
+
`[daemon] workdir provision failed task=${taskId} dir=${workDir}: ${err.message}
|
|
6575
6601
|
`
|
|
6576
6602
|
);
|
|
6577
6603
|
}
|
|
@@ -6654,7 +6680,8 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
6654
6680
|
profile
|
|
6655
6681
|
),
|
|
6656
6682
|
outboxDir,
|
|
6657
|
-
profile.config
|
|
6683
|
+
profile.config,
|
|
6684
|
+
workDir
|
|
6658
6685
|
);
|
|
6659
6686
|
const cfg = profile.config;
|
|
6660
6687
|
let profileSystemPrompt;
|
|
@@ -6676,12 +6703,16 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
6676
6703
|
conversationId: payload.conversationId,
|
|
6677
6704
|
prismerGoals: goalContext.map(toGoalMirrorPayload),
|
|
6678
6705
|
...composedSystemPrompt ? { systemPrompt: composedSystemPrompt } : {},
|
|
6679
|
-
// Wave-9: spawn-style adapters (claude-code, codex, openclaw)
|
|
6680
|
-
//
|
|
6681
|
-
// the LLM tool can resolve the
|
|
6682
|
-
// prompt instruction. Long-running adapters
|
|
6683
|
-
// and rely on the prompt-side instruction
|
|
6706
|
+
// Wave-9 / F18: spawn-style adapters (claude-code, codex, openclaw)
|
|
6707
|
+
// read these and inject `PRISMER_OUTBOX_DIR` / `PRISMER_WORKDIR`
|
|
6708
|
+
// into the child env so the LLM tool can resolve the paths even if
|
|
6709
|
+
// it doesn't read the prompt instruction. Long-running adapters
|
|
6710
|
+
// (Hermes) ignore these and rely on the prompt-side instruction
|
|
6711
|
+
// added above — but Hermes is now cwd-sandboxed to its profile
|
|
6712
|
+
// dir (~/.hermes/profiles/<name>/) so relative-path writes still
|
|
6713
|
+
// stay out of the user's source tree.
|
|
6684
6714
|
...outboxDir ? { prismerOutboxDir: outboxDir } : {},
|
|
6715
|
+
...workDir ? { prismerWorkDir: workDir } : {},
|
|
6685
6716
|
prismerObservability: {
|
|
6686
6717
|
identity: {
|
|
6687
6718
|
loaded: Boolean(profileSystemPrompt),
|
|
@@ -7085,18 +7116,43 @@ function stringifyPrinciples(value) {
|
|
|
7085
7116
|
}
|
|
7086
7117
|
return void 0;
|
|
7087
7118
|
}
|
|
7088
|
-
function appendOutboxInstruction(prompt, outboxDir, profileConfig) {
|
|
7119
|
+
function appendOutboxInstruction(prompt, outboxDir, profileConfig, workDir = null) {
|
|
7089
7120
|
if (!outboxDir) return prompt;
|
|
7090
7121
|
if (profileConfig?.disableOutboxHints === true) return prompt;
|
|
7091
|
-
const
|
|
7092
|
-
"[
|
|
7093
|
-
"
|
|
7094
|
-
|
|
7095
|
-
"
|
|
7096
|
-
"
|
|
7122
|
+
const lines = [
|
|
7123
|
+
"[File system rules \u2014 MANDATORY, server-enforced]",
|
|
7124
|
+
"",
|
|
7125
|
+
"You have TWO designated directories for this task. ALWAYS use absolute paths.",
|
|
7126
|
+
"NEVER write files with relative paths \u2014 they resolve against the agent process",
|
|
7127
|
+
"cwd which is sandboxed but unpredictable, and any path outside the two",
|
|
7128
|
+
"directories below is treated as malformed.",
|
|
7129
|
+
"",
|
|
7130
|
+
`1. **Outbox (auto-uploaded as chat attachments)** \u2014 write deliverables here:`,
|
|
7131
|
+
` ${outboxDir}`,
|
|
7132
|
+
" Any file you place here will be uploaded and shown to the user as an",
|
|
7133
|
+
" attachment in your reply. Use this for the final artifacts the user",
|
|
7134
|
+
" actually wants (PNG charts, DOCX reports, CSV exports, archives).",
|
|
7135
|
+
""
|
|
7136
|
+
];
|
|
7137
|
+
if (workDir) {
|
|
7138
|
+
lines.push(
|
|
7139
|
+
`2. **Workdir (scratch, NOT uploaded)** \u2014 write intermediate stuff here:`,
|
|
7140
|
+
` ${workDir}`,
|
|
7141
|
+
" Use for draft scripts, log files, intermediate CSVs, temp downloads \u2014",
|
|
7142
|
+
" anything the user doesn't need to see. These files are deleted later",
|
|
7143
|
+
" and never become chat attachments.",
|
|
7144
|
+
""
|
|
7145
|
+
);
|
|
7146
|
+
}
|
|
7147
|
+
lines.push(
|
|
7148
|
+
"If you produce a file but write it OUTSIDE both directories with a",
|
|
7149
|
+
"relative path, it will NOT become a chat attachment and may pollute the",
|
|
7150
|
+
"user's working directory. This is treated as a hard error.",
|
|
7151
|
+
"",
|
|
7152
|
+
"These paths are also exposed via env vars: PRISMER_OUTBOX_DIR" + (workDir ? " and PRISMER_WORKDIR" : "") + ".",
|
|
7097
7153
|
""
|
|
7098
|
-
|
|
7099
|
-
return `${
|
|
7154
|
+
);
|
|
7155
|
+
return `${lines.join("\n")}
|
|
7100
7156
|
${prompt}`;
|
|
7101
7157
|
}
|
|
7102
7158
|
function appendChannelContext(prompt, payload, profile) {
|
|
@@ -14937,7 +14993,7 @@ async function readResponseError(res) {
|
|
|
14937
14993
|
|
|
14938
14994
|
// src/cli/index.ts
|
|
14939
14995
|
init_ui();
|
|
14940
|
-
var VERSION = "2.0.
|
|
14996
|
+
var VERSION = "2.0.3";
|
|
14941
14997
|
function buildProgram() {
|
|
14942
14998
|
const program = new import_commander20.Command("prismer").description("Prismer Cloud daemon CLI (TS-only).").version(VERSION);
|
|
14943
14999
|
program.addCommand(buildBannerCommand());
|
package/dist/cli.js
CHANGED
|
@@ -965,15 +965,30 @@ No @ needed; the human is the only other party.
|
|
|
965
965
|
);
|
|
966
966
|
}
|
|
967
967
|
await stopStaleHermesGateways(profileName, portOverride, config.startupTimeoutMs);
|
|
968
|
+
const hermesProfileDir = getHermesProfileDir(profileName);
|
|
969
|
+
try {
|
|
970
|
+
mkdirSync(hermesProfileDir, { recursive: true });
|
|
971
|
+
} catch (err) {
|
|
972
|
+
process.stderr.write(
|
|
973
|
+
`[hermes-adapter] failed to ensure hermes profile dir ${hermesProfileDir}: ${err.message}
|
|
974
|
+
`
|
|
975
|
+
);
|
|
976
|
+
}
|
|
968
977
|
spawn3("hermes", ["-p", profileName, "gateway", "run"], {
|
|
969
978
|
detached: false,
|
|
970
979
|
stdio: "ignore",
|
|
980
|
+
cwd: hermesProfileDir,
|
|
971
981
|
env: {
|
|
972
982
|
...process.env,
|
|
973
983
|
API_SERVER_ENABLED: "true",
|
|
974
984
|
API_SERVER_KEY: config.apiKey,
|
|
975
985
|
API_SERVER_PORT: String(portOverride),
|
|
976
986
|
API_SERVER_HOST: "127.0.0.1",
|
|
987
|
+
// TERMINAL_CWD is the env that hermes file_tools._resolve_path
|
|
988
|
+
// honors over `os.getcwd()` for relative paths. Pin it to the
|
|
989
|
+
// profile dir so even non-LLM-initiated writes (e.g. hermes
|
|
990
|
+
// internal book-keeping) land in the sandbox.
|
|
991
|
+
TERMINAL_CWD: hermesProfileDir,
|
|
977
992
|
[config.prismerApiKeyEnv]: resolvePrismerApiKey(config)
|
|
978
993
|
}
|
|
979
994
|
});
|
|
@@ -1896,7 +1911,7 @@ var require_package = __commonJS({
|
|
|
1896
1911
|
"package.json"(exports, module) {
|
|
1897
1912
|
module.exports = {
|
|
1898
1913
|
name: "@prismer/runtime",
|
|
1899
|
-
version: "2.0.
|
|
1914
|
+
version: "2.0.3",
|
|
1900
1915
|
description: "Prismer Cloud daemon runtime \u2014 TS-only adapter host for hosted IM agents",
|
|
1901
1916
|
type: "module",
|
|
1902
1917
|
main: "dist/index.js",
|
|
@@ -6550,12 +6565,23 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
6550
6565
|
let reply;
|
|
6551
6566
|
const outboxBase = deps.paths?.runsDir ? path2.join(deps.paths.runsDir, taskId) : null;
|
|
6552
6567
|
const outboxDir = outboxBase ? path2.join(outboxBase, "_outbox") : null;
|
|
6568
|
+
const workDir = outboxBase ? path2.join(outboxBase, "workdir") : null;
|
|
6553
6569
|
if (outboxDir) {
|
|
6554
6570
|
try {
|
|
6555
6571
|
await fsp3.mkdir(outboxDir, { recursive: true });
|
|
6556
6572
|
} catch (err) {
|
|
6557
6573
|
process.stderr.write(
|
|
6558
6574
|
`[daemon] outbox provision failed task=${taskId} dir=${outboxDir}: ${err.message}
|
|
6575
|
+
`
|
|
6576
|
+
);
|
|
6577
|
+
}
|
|
6578
|
+
}
|
|
6579
|
+
if (workDir) {
|
|
6580
|
+
try {
|
|
6581
|
+
await fsp3.mkdir(workDir, { recursive: true });
|
|
6582
|
+
} catch (err) {
|
|
6583
|
+
process.stderr.write(
|
|
6584
|
+
`[daemon] workdir provision failed task=${taskId} dir=${workDir}: ${err.message}
|
|
6559
6585
|
`
|
|
6560
6586
|
);
|
|
6561
6587
|
}
|
|
@@ -6638,7 +6664,8 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
6638
6664
|
profile
|
|
6639
6665
|
),
|
|
6640
6666
|
outboxDir,
|
|
6641
|
-
profile.config
|
|
6667
|
+
profile.config,
|
|
6668
|
+
workDir
|
|
6642
6669
|
);
|
|
6643
6670
|
const cfg = profile.config;
|
|
6644
6671
|
let profileSystemPrompt;
|
|
@@ -6660,12 +6687,16 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
6660
6687
|
conversationId: payload.conversationId,
|
|
6661
6688
|
prismerGoals: goalContext.map(toGoalMirrorPayload),
|
|
6662
6689
|
...composedSystemPrompt ? { systemPrompt: composedSystemPrompt } : {},
|
|
6663
|
-
// Wave-9: spawn-style adapters (claude-code, codex, openclaw)
|
|
6664
|
-
//
|
|
6665
|
-
// the LLM tool can resolve the
|
|
6666
|
-
// prompt instruction. Long-running adapters
|
|
6667
|
-
// and rely on the prompt-side instruction
|
|
6690
|
+
// Wave-9 / F18: spawn-style adapters (claude-code, codex, openclaw)
|
|
6691
|
+
// read these and inject `PRISMER_OUTBOX_DIR` / `PRISMER_WORKDIR`
|
|
6692
|
+
// into the child env so the LLM tool can resolve the paths even if
|
|
6693
|
+
// it doesn't read the prompt instruction. Long-running adapters
|
|
6694
|
+
// (Hermes) ignore these and rely on the prompt-side instruction
|
|
6695
|
+
// added above — but Hermes is now cwd-sandboxed to its profile
|
|
6696
|
+
// dir (~/.hermes/profiles/<name>/) so relative-path writes still
|
|
6697
|
+
// stay out of the user's source tree.
|
|
6668
6698
|
...outboxDir ? { prismerOutboxDir: outboxDir } : {},
|
|
6699
|
+
...workDir ? { prismerWorkDir: workDir } : {},
|
|
6669
6700
|
prismerObservability: {
|
|
6670
6701
|
identity: {
|
|
6671
6702
|
loaded: Boolean(profileSystemPrompt),
|
|
@@ -7069,18 +7100,43 @@ function stringifyPrinciples(value) {
|
|
|
7069
7100
|
}
|
|
7070
7101
|
return void 0;
|
|
7071
7102
|
}
|
|
7072
|
-
function appendOutboxInstruction(prompt, outboxDir, profileConfig) {
|
|
7103
|
+
function appendOutboxInstruction(prompt, outboxDir, profileConfig, workDir = null) {
|
|
7073
7104
|
if (!outboxDir) return prompt;
|
|
7074
7105
|
if (profileConfig?.disableOutboxHints === true) return prompt;
|
|
7075
|
-
const
|
|
7076
|
-
"[
|
|
7077
|
-
"
|
|
7078
|
-
|
|
7079
|
-
"
|
|
7080
|
-
"
|
|
7106
|
+
const lines = [
|
|
7107
|
+
"[File system rules \u2014 MANDATORY, server-enforced]",
|
|
7108
|
+
"",
|
|
7109
|
+
"You have TWO designated directories for this task. ALWAYS use absolute paths.",
|
|
7110
|
+
"NEVER write files with relative paths \u2014 they resolve against the agent process",
|
|
7111
|
+
"cwd which is sandboxed but unpredictable, and any path outside the two",
|
|
7112
|
+
"directories below is treated as malformed.",
|
|
7113
|
+
"",
|
|
7114
|
+
`1. **Outbox (auto-uploaded as chat attachments)** \u2014 write deliverables here:`,
|
|
7115
|
+
` ${outboxDir}`,
|
|
7116
|
+
" Any file you place here will be uploaded and shown to the user as an",
|
|
7117
|
+
" attachment in your reply. Use this for the final artifacts the user",
|
|
7118
|
+
" actually wants (PNG charts, DOCX reports, CSV exports, archives).",
|
|
7119
|
+
""
|
|
7120
|
+
];
|
|
7121
|
+
if (workDir) {
|
|
7122
|
+
lines.push(
|
|
7123
|
+
`2. **Workdir (scratch, NOT uploaded)** \u2014 write intermediate stuff here:`,
|
|
7124
|
+
` ${workDir}`,
|
|
7125
|
+
" Use for draft scripts, log files, intermediate CSVs, temp downloads \u2014",
|
|
7126
|
+
" anything the user doesn't need to see. These files are deleted later",
|
|
7127
|
+
" and never become chat attachments.",
|
|
7128
|
+
""
|
|
7129
|
+
);
|
|
7130
|
+
}
|
|
7131
|
+
lines.push(
|
|
7132
|
+
"If you produce a file but write it OUTSIDE both directories with a",
|
|
7133
|
+
"relative path, it will NOT become a chat attachment and may pollute the",
|
|
7134
|
+
"user's working directory. This is treated as a hard error.",
|
|
7135
|
+
"",
|
|
7136
|
+
"These paths are also exposed via env vars: PRISMER_OUTBOX_DIR" + (workDir ? " and PRISMER_WORKDIR" : "") + ".",
|
|
7081
7137
|
""
|
|
7082
|
-
|
|
7083
|
-
return `${
|
|
7138
|
+
);
|
|
7139
|
+
return `${lines.join("\n")}
|
|
7084
7140
|
${prompt}`;
|
|
7085
7141
|
}
|
|
7086
7142
|
function appendChannelContext(prompt, payload, profile) {
|
|
@@ -14920,7 +14976,7 @@ async function readResponseError(res) {
|
|
|
14920
14976
|
|
|
14921
14977
|
// src/cli/index.ts
|
|
14922
14978
|
init_ui();
|
|
14923
|
-
var VERSION = "2.0.
|
|
14979
|
+
var VERSION = "2.0.3";
|
|
14924
14980
|
function buildProgram() {
|
|
14925
14981
|
const program = new Command20("prismer").description("Prismer Cloud daemon CLI (TS-only).").version(VERSION);
|
|
14926
14982
|
program.addCommand(buildBannerCommand());
|
package/dist/index.cjs
CHANGED
|
@@ -987,15 +987,30 @@ No @ needed; the human is the only other party.
|
|
|
987
987
|
);
|
|
988
988
|
}
|
|
989
989
|
await stopStaleHermesGateways(profileName, portOverride, config.startupTimeoutMs);
|
|
990
|
+
const hermesProfileDir = getHermesProfileDir(profileName);
|
|
991
|
+
try {
|
|
992
|
+
(0, import_node_fs2.mkdirSync)(hermesProfileDir, { recursive: true });
|
|
993
|
+
} catch (err) {
|
|
994
|
+
process.stderr.write(
|
|
995
|
+
`[hermes-adapter] failed to ensure hermes profile dir ${hermesProfileDir}: ${err.message}
|
|
996
|
+
`
|
|
997
|
+
);
|
|
998
|
+
}
|
|
990
999
|
(0, import_node_child_process.spawn)("hermes", ["-p", profileName, "gateway", "run"], {
|
|
991
1000
|
detached: false,
|
|
992
1001
|
stdio: "ignore",
|
|
1002
|
+
cwd: hermesProfileDir,
|
|
993
1003
|
env: {
|
|
994
1004
|
...process.env,
|
|
995
1005
|
API_SERVER_ENABLED: "true",
|
|
996
1006
|
API_SERVER_KEY: config.apiKey,
|
|
997
1007
|
API_SERVER_PORT: String(portOverride),
|
|
998
1008
|
API_SERVER_HOST: "127.0.0.1",
|
|
1009
|
+
// TERMINAL_CWD is the env that hermes file_tools._resolve_path
|
|
1010
|
+
// honors over `os.getcwd()` for relative paths. Pin it to the
|
|
1011
|
+
// profile dir so even non-LLM-initiated writes (e.g. hermes
|
|
1012
|
+
// internal book-keeping) land in the sandbox.
|
|
1013
|
+
TERMINAL_CWD: hermesProfileDir,
|
|
999
1014
|
[config.prismerApiKeyEnv]: resolvePrismerApiKey(config)
|
|
1000
1015
|
}
|
|
1001
1016
|
});
|
|
@@ -2280,7 +2295,7 @@ var require_package = __commonJS({
|
|
|
2280
2295
|
"package.json"(exports2, module2) {
|
|
2281
2296
|
module2.exports = {
|
|
2282
2297
|
name: "@prismer/runtime",
|
|
2283
|
-
version: "2.0.
|
|
2298
|
+
version: "2.0.3",
|
|
2284
2299
|
description: "Prismer Cloud daemon runtime \u2014 TS-only adapter host for hosted IM agents",
|
|
2285
2300
|
type: "module",
|
|
2286
2301
|
main: "dist/index.js",
|
|
@@ -4256,12 +4271,23 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
4256
4271
|
let reply;
|
|
4257
4272
|
const outboxBase = deps.paths?.runsDir ? path.join(deps.paths.runsDir, taskId) : null;
|
|
4258
4273
|
const outboxDir = outboxBase ? path.join(outboxBase, "_outbox") : null;
|
|
4274
|
+
const workDir = outboxBase ? path.join(outboxBase, "workdir") : null;
|
|
4259
4275
|
if (outboxDir) {
|
|
4260
4276
|
try {
|
|
4261
4277
|
await import_node_fs8.promises.mkdir(outboxDir, { recursive: true });
|
|
4262
4278
|
} catch (err) {
|
|
4263
4279
|
process.stderr.write(
|
|
4264
4280
|
`[daemon] outbox provision failed task=${taskId} dir=${outboxDir}: ${err.message}
|
|
4281
|
+
`
|
|
4282
|
+
);
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
if (workDir) {
|
|
4286
|
+
try {
|
|
4287
|
+
await import_node_fs8.promises.mkdir(workDir, { recursive: true });
|
|
4288
|
+
} catch (err) {
|
|
4289
|
+
process.stderr.write(
|
|
4290
|
+
`[daemon] workdir provision failed task=${taskId} dir=${workDir}: ${err.message}
|
|
4265
4291
|
`
|
|
4266
4292
|
);
|
|
4267
4293
|
}
|
|
@@ -4344,7 +4370,8 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
4344
4370
|
profile
|
|
4345
4371
|
),
|
|
4346
4372
|
outboxDir,
|
|
4347
|
-
profile.config
|
|
4373
|
+
profile.config,
|
|
4374
|
+
workDir
|
|
4348
4375
|
);
|
|
4349
4376
|
const cfg = profile.config;
|
|
4350
4377
|
let profileSystemPrompt;
|
|
@@ -4366,12 +4393,16 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
4366
4393
|
conversationId: payload.conversationId,
|
|
4367
4394
|
prismerGoals: goalContext.map(toGoalMirrorPayload),
|
|
4368
4395
|
...composedSystemPrompt ? { systemPrompt: composedSystemPrompt } : {},
|
|
4369
|
-
// Wave-9: spawn-style adapters (claude-code, codex, openclaw)
|
|
4370
|
-
//
|
|
4371
|
-
// the LLM tool can resolve the
|
|
4372
|
-
// prompt instruction. Long-running adapters
|
|
4373
|
-
// and rely on the prompt-side instruction
|
|
4396
|
+
// Wave-9 / F18: spawn-style adapters (claude-code, codex, openclaw)
|
|
4397
|
+
// read these and inject `PRISMER_OUTBOX_DIR` / `PRISMER_WORKDIR`
|
|
4398
|
+
// into the child env so the LLM tool can resolve the paths even if
|
|
4399
|
+
// it doesn't read the prompt instruction. Long-running adapters
|
|
4400
|
+
// (Hermes) ignore these and rely on the prompt-side instruction
|
|
4401
|
+
// added above — but Hermes is now cwd-sandboxed to its profile
|
|
4402
|
+
// dir (~/.hermes/profiles/<name>/) so relative-path writes still
|
|
4403
|
+
// stay out of the user's source tree.
|
|
4374
4404
|
...outboxDir ? { prismerOutboxDir: outboxDir } : {},
|
|
4405
|
+
...workDir ? { prismerWorkDir: workDir } : {},
|
|
4375
4406
|
prismerObservability: {
|
|
4376
4407
|
identity: {
|
|
4377
4408
|
loaded: Boolean(profileSystemPrompt),
|
|
@@ -4775,18 +4806,43 @@ function stringifyPrinciples(value) {
|
|
|
4775
4806
|
}
|
|
4776
4807
|
return void 0;
|
|
4777
4808
|
}
|
|
4778
|
-
function appendOutboxInstruction(prompt, outboxDir, profileConfig) {
|
|
4809
|
+
function appendOutboxInstruction(prompt, outboxDir, profileConfig, workDir = null) {
|
|
4779
4810
|
if (!outboxDir) return prompt;
|
|
4780
4811
|
if (profileConfig?.disableOutboxHints === true) return prompt;
|
|
4781
|
-
const
|
|
4782
|
-
"[
|
|
4783
|
-
"
|
|
4784
|
-
|
|
4785
|
-
"
|
|
4786
|
-
"
|
|
4812
|
+
const lines = [
|
|
4813
|
+
"[File system rules \u2014 MANDATORY, server-enforced]",
|
|
4814
|
+
"",
|
|
4815
|
+
"You have TWO designated directories for this task. ALWAYS use absolute paths.",
|
|
4816
|
+
"NEVER write files with relative paths \u2014 they resolve against the agent process",
|
|
4817
|
+
"cwd which is sandboxed but unpredictable, and any path outside the two",
|
|
4818
|
+
"directories below is treated as malformed.",
|
|
4819
|
+
"",
|
|
4820
|
+
`1. **Outbox (auto-uploaded as chat attachments)** \u2014 write deliverables here:`,
|
|
4821
|
+
` ${outboxDir}`,
|
|
4822
|
+
" Any file you place here will be uploaded and shown to the user as an",
|
|
4823
|
+
" attachment in your reply. Use this for the final artifacts the user",
|
|
4824
|
+
" actually wants (PNG charts, DOCX reports, CSV exports, archives).",
|
|
4825
|
+
""
|
|
4826
|
+
];
|
|
4827
|
+
if (workDir) {
|
|
4828
|
+
lines.push(
|
|
4829
|
+
`2. **Workdir (scratch, NOT uploaded)** \u2014 write intermediate stuff here:`,
|
|
4830
|
+
` ${workDir}`,
|
|
4831
|
+
" Use for draft scripts, log files, intermediate CSVs, temp downloads \u2014",
|
|
4832
|
+
" anything the user doesn't need to see. These files are deleted later",
|
|
4833
|
+
" and never become chat attachments.",
|
|
4834
|
+
""
|
|
4835
|
+
);
|
|
4836
|
+
}
|
|
4837
|
+
lines.push(
|
|
4838
|
+
"If you produce a file but write it OUTSIDE both directories with a",
|
|
4839
|
+
"relative path, it will NOT become a chat attachment and may pollute the",
|
|
4840
|
+
"user's working directory. This is treated as a hard error.",
|
|
4841
|
+
"",
|
|
4842
|
+
"These paths are also exposed via env vars: PRISMER_OUTBOX_DIR" + (workDir ? " and PRISMER_WORKDIR" : "") + ".",
|
|
4787
4843
|
""
|
|
4788
|
-
|
|
4789
|
-
return `${
|
|
4844
|
+
);
|
|
4845
|
+
return `${lines.join("\n")}
|
|
4790
4846
|
${prompt}`;
|
|
4791
4847
|
}
|
|
4792
4848
|
function appendChannelContext(prompt, payload, profile) {
|
|
@@ -15110,7 +15166,7 @@ async function readResponseError(res) {
|
|
|
15110
15166
|
|
|
15111
15167
|
// src/cli/index.ts
|
|
15112
15168
|
init_ui();
|
|
15113
|
-
var VERSION = "2.0.
|
|
15169
|
+
var VERSION = "2.0.3";
|
|
15114
15170
|
function buildProgram() {
|
|
15115
15171
|
const program = new import_commander20.Command("prismer").description("Prismer Cloud daemon CLI (TS-only).").version(VERSION);
|
|
15116
15172
|
program.addCommand(buildBannerCommand());
|
package/dist/index.d.cts
CHANGED
|
@@ -2269,8 +2269,8 @@ declare const CodexConfigSchema: z.ZodObject<{
|
|
|
2269
2269
|
apiKeyEnv: z.ZodDefault<z.ZodString>;
|
|
2270
2270
|
}, "strip", z.ZodTypeAny, {
|
|
2271
2271
|
model: string;
|
|
2272
|
-
sandbox: "read-only" | "workspace-write" | "danger-full-access";
|
|
2273
2272
|
cwd: string;
|
|
2273
|
+
sandbox: "read-only" | "workspace-write" | "danger-full-access";
|
|
2274
2274
|
apiKeyEnv: string;
|
|
2275
2275
|
systemPrompt?: string | undefined;
|
|
2276
2276
|
envVars?: Record<string, string> | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -2269,8 +2269,8 @@ declare const CodexConfigSchema: z.ZodObject<{
|
|
|
2269
2269
|
apiKeyEnv: z.ZodDefault<z.ZodString>;
|
|
2270
2270
|
}, "strip", z.ZodTypeAny, {
|
|
2271
2271
|
model: string;
|
|
2272
|
-
sandbox: "read-only" | "workspace-write" | "danger-full-access";
|
|
2273
2272
|
cwd: string;
|
|
2273
|
+
sandbox: "read-only" | "workspace-write" | "danger-full-access";
|
|
2274
2274
|
apiKeyEnv: string;
|
|
2275
2275
|
systemPrompt?: string | undefined;
|
|
2276
2276
|
envVars?: Record<string, string> | undefined;
|
package/dist/index.js
CHANGED
|
@@ -964,15 +964,30 @@ No @ needed; the human is the only other party.
|
|
|
964
964
|
);
|
|
965
965
|
}
|
|
966
966
|
await stopStaleHermesGateways(profileName, portOverride, config.startupTimeoutMs);
|
|
967
|
+
const hermesProfileDir = getHermesProfileDir(profileName);
|
|
968
|
+
try {
|
|
969
|
+
mkdirSync(hermesProfileDir, { recursive: true });
|
|
970
|
+
} catch (err) {
|
|
971
|
+
process.stderr.write(
|
|
972
|
+
`[hermes-adapter] failed to ensure hermes profile dir ${hermesProfileDir}: ${err.message}
|
|
973
|
+
`
|
|
974
|
+
);
|
|
975
|
+
}
|
|
967
976
|
spawn("hermes", ["-p", profileName, "gateway", "run"], {
|
|
968
977
|
detached: false,
|
|
969
978
|
stdio: "ignore",
|
|
979
|
+
cwd: hermesProfileDir,
|
|
970
980
|
env: {
|
|
971
981
|
...process.env,
|
|
972
982
|
API_SERVER_ENABLED: "true",
|
|
973
983
|
API_SERVER_KEY: config.apiKey,
|
|
974
984
|
API_SERVER_PORT: String(portOverride),
|
|
975
985
|
API_SERVER_HOST: "127.0.0.1",
|
|
986
|
+
// TERMINAL_CWD is the env that hermes file_tools._resolve_path
|
|
987
|
+
// honors over `os.getcwd()` for relative paths. Pin it to the
|
|
988
|
+
// profile dir so even non-LLM-initiated writes (e.g. hermes
|
|
989
|
+
// internal book-keeping) land in the sandbox.
|
|
990
|
+
TERMINAL_CWD: hermesProfileDir,
|
|
976
991
|
[config.prismerApiKeyEnv]: resolvePrismerApiKey(config)
|
|
977
992
|
}
|
|
978
993
|
});
|
|
@@ -2256,7 +2271,7 @@ var require_package = __commonJS({
|
|
|
2256
2271
|
"package.json"(exports, module) {
|
|
2257
2272
|
module.exports = {
|
|
2258
2273
|
name: "@prismer/runtime",
|
|
2259
|
-
version: "2.0.
|
|
2274
|
+
version: "2.0.3",
|
|
2260
2275
|
description: "Prismer Cloud daemon runtime \u2014 TS-only adapter host for hosted IM agents",
|
|
2261
2276
|
type: "module",
|
|
2262
2277
|
main: "dist/index.js",
|
|
@@ -4182,12 +4197,23 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
4182
4197
|
let reply;
|
|
4183
4198
|
const outboxBase = deps.paths?.runsDir ? path.join(deps.paths.runsDir, taskId) : null;
|
|
4184
4199
|
const outboxDir = outboxBase ? path.join(outboxBase, "_outbox") : null;
|
|
4200
|
+
const workDir = outboxBase ? path.join(outboxBase, "workdir") : null;
|
|
4185
4201
|
if (outboxDir) {
|
|
4186
4202
|
try {
|
|
4187
4203
|
await fsp3.mkdir(outboxDir, { recursive: true });
|
|
4188
4204
|
} catch (err) {
|
|
4189
4205
|
process.stderr.write(
|
|
4190
4206
|
`[daemon] outbox provision failed task=${taskId} dir=${outboxDir}: ${err.message}
|
|
4207
|
+
`
|
|
4208
|
+
);
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
if (workDir) {
|
|
4212
|
+
try {
|
|
4213
|
+
await fsp3.mkdir(workDir, { recursive: true });
|
|
4214
|
+
} catch (err) {
|
|
4215
|
+
process.stderr.write(
|
|
4216
|
+
`[daemon] workdir provision failed task=${taskId} dir=${workDir}: ${err.message}
|
|
4191
4217
|
`
|
|
4192
4218
|
);
|
|
4193
4219
|
}
|
|
@@ -4270,7 +4296,8 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
4270
4296
|
profile
|
|
4271
4297
|
),
|
|
4272
4298
|
outboxDir,
|
|
4273
|
-
profile.config
|
|
4299
|
+
profile.config,
|
|
4300
|
+
workDir
|
|
4274
4301
|
);
|
|
4275
4302
|
const cfg = profile.config;
|
|
4276
4303
|
let profileSystemPrompt;
|
|
@@ -4292,12 +4319,16 @@ async function handleDispatch(payload, requestId, deps) {
|
|
|
4292
4319
|
conversationId: payload.conversationId,
|
|
4293
4320
|
prismerGoals: goalContext.map(toGoalMirrorPayload),
|
|
4294
4321
|
...composedSystemPrompt ? { systemPrompt: composedSystemPrompt } : {},
|
|
4295
|
-
// Wave-9: spawn-style adapters (claude-code, codex, openclaw)
|
|
4296
|
-
//
|
|
4297
|
-
// the LLM tool can resolve the
|
|
4298
|
-
// prompt instruction. Long-running adapters
|
|
4299
|
-
// and rely on the prompt-side instruction
|
|
4322
|
+
// Wave-9 / F18: spawn-style adapters (claude-code, codex, openclaw)
|
|
4323
|
+
// read these and inject `PRISMER_OUTBOX_DIR` / `PRISMER_WORKDIR`
|
|
4324
|
+
// into the child env so the LLM tool can resolve the paths even if
|
|
4325
|
+
// it doesn't read the prompt instruction. Long-running adapters
|
|
4326
|
+
// (Hermes) ignore these and rely on the prompt-side instruction
|
|
4327
|
+
// added above — but Hermes is now cwd-sandboxed to its profile
|
|
4328
|
+
// dir (~/.hermes/profiles/<name>/) so relative-path writes still
|
|
4329
|
+
// stay out of the user's source tree.
|
|
4300
4330
|
...outboxDir ? { prismerOutboxDir: outboxDir } : {},
|
|
4331
|
+
...workDir ? { prismerWorkDir: workDir } : {},
|
|
4301
4332
|
prismerObservability: {
|
|
4302
4333
|
identity: {
|
|
4303
4334
|
loaded: Boolean(profileSystemPrompt),
|
|
@@ -4701,18 +4732,43 @@ function stringifyPrinciples(value) {
|
|
|
4701
4732
|
}
|
|
4702
4733
|
return void 0;
|
|
4703
4734
|
}
|
|
4704
|
-
function appendOutboxInstruction(prompt, outboxDir, profileConfig) {
|
|
4735
|
+
function appendOutboxInstruction(prompt, outboxDir, profileConfig, workDir = null) {
|
|
4705
4736
|
if (!outboxDir) return prompt;
|
|
4706
4737
|
if (profileConfig?.disableOutboxHints === true) return prompt;
|
|
4707
|
-
const
|
|
4708
|
-
"[
|
|
4709
|
-
"
|
|
4710
|
-
|
|
4711
|
-
"
|
|
4712
|
-
"
|
|
4738
|
+
const lines = [
|
|
4739
|
+
"[File system rules \u2014 MANDATORY, server-enforced]",
|
|
4740
|
+
"",
|
|
4741
|
+
"You have TWO designated directories for this task. ALWAYS use absolute paths.",
|
|
4742
|
+
"NEVER write files with relative paths \u2014 they resolve against the agent process",
|
|
4743
|
+
"cwd which is sandboxed but unpredictable, and any path outside the two",
|
|
4744
|
+
"directories below is treated as malformed.",
|
|
4745
|
+
"",
|
|
4746
|
+
`1. **Outbox (auto-uploaded as chat attachments)** \u2014 write deliverables here:`,
|
|
4747
|
+
` ${outboxDir}`,
|
|
4748
|
+
" Any file you place here will be uploaded and shown to the user as an",
|
|
4749
|
+
" attachment in your reply. Use this for the final artifacts the user",
|
|
4750
|
+
" actually wants (PNG charts, DOCX reports, CSV exports, archives).",
|
|
4751
|
+
""
|
|
4752
|
+
];
|
|
4753
|
+
if (workDir) {
|
|
4754
|
+
lines.push(
|
|
4755
|
+
`2. **Workdir (scratch, NOT uploaded)** \u2014 write intermediate stuff here:`,
|
|
4756
|
+
` ${workDir}`,
|
|
4757
|
+
" Use for draft scripts, log files, intermediate CSVs, temp downloads \u2014",
|
|
4758
|
+
" anything the user doesn't need to see. These files are deleted later",
|
|
4759
|
+
" and never become chat attachments.",
|
|
4760
|
+
""
|
|
4761
|
+
);
|
|
4762
|
+
}
|
|
4763
|
+
lines.push(
|
|
4764
|
+
"If you produce a file but write it OUTSIDE both directories with a",
|
|
4765
|
+
"relative path, it will NOT become a chat attachment and may pollute the",
|
|
4766
|
+
"user's working directory. This is treated as a hard error.",
|
|
4767
|
+
"",
|
|
4768
|
+
"These paths are also exposed via env vars: PRISMER_OUTBOX_DIR" + (workDir ? " and PRISMER_WORKDIR" : "") + ".",
|
|
4713
4769
|
""
|
|
4714
|
-
|
|
4715
|
-
return `${
|
|
4770
|
+
);
|
|
4771
|
+
return `${lines.join("\n")}
|
|
4716
4772
|
${prompt}`;
|
|
4717
4773
|
}
|
|
4718
4774
|
function appendChannelContext(prompt, payload, profile) {
|
|
@@ -15042,7 +15098,7 @@ async function readResponseError(res) {
|
|
|
15042
15098
|
|
|
15043
15099
|
// src/cli/index.ts
|
|
15044
15100
|
init_ui();
|
|
15045
|
-
var VERSION = "2.0.
|
|
15101
|
+
var VERSION = "2.0.3";
|
|
15046
15102
|
function buildProgram() {
|
|
15047
15103
|
const program = new Command20("prismer").description("Prismer Cloud daemon CLI (TS-only).").version(VERSION);
|
|
15048
15104
|
program.addCommand(buildBannerCommand());
|