@xfey/tutti 0.1.68 → 0.1.69
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/chat-assistant/index.d.ts +1 -1
- package/dist/chat-assistant/index.js +1 -1
- package/dist/collaboration-state/task-compile-context.js +22 -5
- package/dist/control-plane/index.d.ts +2 -2
- package/dist/control-plane/index.js +5 -1
- package/dist/providers/openai/app-server/json-rpc.js +13 -1
- package/dist/providers/openai/app-server/linux-sandbox-readiness.js +6 -3
- package/dist/providers/openai/app-server/read-only-procedure.js +2 -2
- package/dist/providers/openai/app-server/smoke.js +2 -2
- package/dist/providers/openai/app-server/workspace-write-run.js +2 -2
- package/dist/providers/openai/codex-app-server.d.ts +10 -0
- package/dist/providers/openai/codex-app-server.js +22 -5
- package/dist/server-shell/cli/host-server-runtime.js +1 -1
- package/dist/server-shell/http/routes/project-api/messages-routes.js +1 -1
- package/dist/server-shell/http/routes/project-api/reference-files-routes.js +1 -1
- package/dist/server-shell/local-console/invocation-context.d.ts +2 -0
- package/dist/server-shell/local-console/invocation-context.js +10 -1
- package/package.json +1 -1
|
@@ -43,7 +43,7 @@ export type ReadOnlyChatAssistantOptions = {
|
|
|
43
43
|
workspaceRoot: string;
|
|
44
44
|
model: ReadOnlyChatAssistantModel;
|
|
45
45
|
promptsRoot?: string;
|
|
46
|
-
onScratchpadSourceChanged?: () => void;
|
|
46
|
+
onScratchpadSourceChanged?: (message: MessageProjection) => void;
|
|
47
47
|
now?: () => Date;
|
|
48
48
|
};
|
|
49
49
|
export declare function isChatAssistantOutput(value: unknown): value is ChatAssistantOutput;
|
|
@@ -206,7 +206,7 @@ export class ReadOnlyChatAssistant {
|
|
|
206
206
|
invalidates: mainChatMessageInvalidates(),
|
|
207
207
|
});
|
|
208
208
|
if (refs?.scratchpad_source !== "exclude") {
|
|
209
|
-
this.options.onScratchpadSourceChanged?.();
|
|
209
|
+
this.options.onScratchpadSourceChanged?.(message);
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
appendClarificationRoundAssistantMessage(input) {
|
|
@@ -2,6 +2,16 @@ import { withHostStoreTransaction } from "../store/index.js";
|
|
|
2
2
|
import { readScratchpadProjection } from "./scratchpad.js";
|
|
3
3
|
import { readScratchpadSourceState } from "./scratchpad-source-state.js";
|
|
4
4
|
import { nowIso, stringifyJson } from "./serialization.js";
|
|
5
|
+
function cursorIsAfter(left, right) {
|
|
6
|
+
if (left === undefined) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
if (right === undefined) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
const timeOrder = left.created_at.localeCompare(right.created_at);
|
|
13
|
+
return timeOrder > 0 || (timeOrder === 0 && left.message_id > right.message_id);
|
|
14
|
+
}
|
|
5
15
|
function parseStringArray(value, field) {
|
|
6
16
|
let parsed;
|
|
7
17
|
try {
|
|
@@ -238,11 +248,18 @@ export function rollbackTaskCompileContext(db, input) {
|
|
|
238
248
|
}
|
|
239
249
|
const rolledBackAt = nowIso(input.now);
|
|
240
250
|
const sourceState = readScratchpadSourceState(tx);
|
|
241
|
-
const dirtySince = sourceState.in_flight !== undefined &&
|
|
242
|
-
new Date(rolledBackAt).getTime() <= new Date(sourceState.in_flight.started_at).getTime()
|
|
243
|
-
? new Date(new Date(sourceState.in_flight.started_at).getTime() + 1).toISOString()
|
|
244
|
-
: rolledBackAt;
|
|
245
251
|
const after = context.source_window.after;
|
|
252
|
+
const through = context.source_window.through;
|
|
253
|
+
const hasBoundaryAfterSourceChanges = sourceState.dirty_since !== undefined ||
|
|
254
|
+
sourceState.in_flight !== undefined ||
|
|
255
|
+
cursorIsAfter(sourceState.refreshed_through_cursor, through);
|
|
256
|
+
const dirtySince = hasBoundaryAfterSourceChanges
|
|
257
|
+
? sourceState.in_flight !== undefined &&
|
|
258
|
+
new Date(rolledBackAt).getTime() <= new Date(sourceState.in_flight.started_at).getTime()
|
|
259
|
+
? new Date(new Date(sourceState.in_flight.started_at).getTime() + 1).toISOString()
|
|
260
|
+
: rolledBackAt
|
|
261
|
+
: null;
|
|
262
|
+
const restoredThrough = hasBoundaryAfterSourceChanges ? after : through;
|
|
246
263
|
tx.prepare(`
|
|
247
264
|
INSERT INTO scratchpad_source_state (
|
|
248
265
|
id,
|
|
@@ -261,7 +278,7 @@ export function rollbackTaskCompileContext(db, input) {
|
|
|
261
278
|
refreshed_through_cursor_message_id = excluded.refreshed_through_cursor_message_id,
|
|
262
279
|
dirty_since = excluded.dirty_since,
|
|
263
280
|
updated_at = excluded.updated_at
|
|
264
|
-
`).run(after?.created_at ?? null, after?.message_id ?? null,
|
|
281
|
+
`).run(after?.created_at ?? null, after?.message_id ?? null, restoredThrough?.created_at ?? null, restoredThrough?.message_id ?? null, dirtySince, rolledBackAt);
|
|
265
282
|
tx.prepare("DELETE FROM active_task_compile_context WHERE workflow_ref = ?").run(input.workflow_ref);
|
|
266
283
|
return true;
|
|
267
284
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ActivityRef, type ClarificationRoundRef, type IdempotencyKey, type WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
2
|
-
import type { ExecutionStatusProjection, ContextSyncDisposition, ContextSyncResult, RefreshScratchpadDisposition, RefreshScratchpadResult, RunSchedulerNowDisposition, RunSchedulerNowPayload, RefreshReferenceSummariesDisposition, RefreshReferenceSummariesPayload, RefreshReferenceSummariesResult, SendClarificationRoundMessageDisposition, SendClarificationRoundMessagePayload, SendClarificationRoundMessageResult, SubmitClarificationRoundDisposition, SubmitClarificationRoundPayload, SubmitClarificationRoundResult, SubmitWorklistDisposition, SubmitWorklistPayload, SubmitWorklistResult, ProcedureLane } from "@tutti/shared/schemas/api";
|
|
2
|
+
import type { ExecutionStatusProjection, MessageProjection, ContextSyncDisposition, ContextSyncResult, RefreshScratchpadDisposition, RefreshScratchpadResult, RunSchedulerNowDisposition, RunSchedulerNowPayload, RefreshReferenceSummariesDisposition, RefreshReferenceSummariesPayload, RefreshReferenceSummariesResult, SendClarificationRoundMessageDisposition, SendClarificationRoundMessagePayload, SendClarificationRoundMessageResult, SubmitClarificationRoundDisposition, SubmitClarificationRoundPayload, SubmitClarificationRoundResult, SubmitWorklistDisposition, SubmitWorklistPayload, SubmitWorklistResult, ProcedureLane } from "@tutti/shared/schemas/api";
|
|
3
3
|
import type { ContextSyncWorkflowTrigger } from "./workflows/index.js";
|
|
4
4
|
import type { ControlPlaneCommandResult, Phase5ControlPlaneOptions, StartupRecoveryOptions, StartupRecoveryResult, TrustedHumanAuthor } from "./types.js";
|
|
5
5
|
import { type ProjectBriefRefreshReason, type RefreshProjectBriefProjectionResult } from "./project-brief-refresh.js";
|
|
@@ -30,7 +30,7 @@ export declare class Phase5ControlPlane {
|
|
|
30
30
|
startScratchpadRefresh(options?: {
|
|
31
31
|
lane?: ProcedureLane;
|
|
32
32
|
}): ControlPlaneCommandResult<RefreshScratchpadDisposition, RefreshScratchpadResult>;
|
|
33
|
-
notifyScratchpadSourceChanged(): void;
|
|
33
|
+
notifyScratchpadSourceChanged(message: MessageProjection): void;
|
|
34
34
|
refreshProjectBrief(options: {
|
|
35
35
|
reason: ProjectBriefRefreshReason;
|
|
36
36
|
workflowRef?: WorkflowInvocationRef;
|
|
@@ -9,6 +9,7 @@ import { runControlPlaneStartupRecovery } from "./startup-recovery.js";
|
|
|
9
9
|
import { readControlPlaneExecutionStatus } from "./execution-status.js";
|
|
10
10
|
import { ScratchpadAutoRefreshScheduler } from "./scratchpad-auto-refresh.js";
|
|
11
11
|
import { startControlPlaneScratchpadRefresh } from "./scratchpad-refresh-start.js";
|
|
12
|
+
import { shouldUseMessageAsScratchpadSource } from "./scratchpad-source-messages.js";
|
|
12
13
|
import { startControlPlaneTaskCompile } from "./task-compile-start.js";
|
|
13
14
|
import { startControlPlaneTaskCompileContinuation } from "./task-compile-continuation.js";
|
|
14
15
|
import { startControlPlaneTaskBoundFollowUpCheck } from "./follow-up-start.js";
|
|
@@ -106,7 +107,10 @@ export class Phase5ControlPlane {
|
|
|
106
107
|
publishProcedureTransition: (state) => this.publishProcedureTransition(state),
|
|
107
108
|
});
|
|
108
109
|
}
|
|
109
|
-
notifyScratchpadSourceChanged() {
|
|
110
|
+
notifyScratchpadSourceChanged(message) {
|
|
111
|
+
if (!shouldUseMessageAsScratchpadSource(message)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
110
114
|
this.scratchpadAutoRefreshScheduler.notifySourceChanged();
|
|
111
115
|
}
|
|
112
116
|
refreshProjectBrief(options) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { StringDecoder } from "node:string_decoder";
|
|
2
2
|
import { redactText } from "@tutti/shared/utils";
|
|
3
|
+
const PROCESS_EXIT_STDERR_EXCERPT_MAX_LENGTH = 500;
|
|
3
4
|
export class CodexAppServerProtocolError extends Error {
|
|
4
5
|
code;
|
|
5
6
|
constructor(message, code) {
|
|
@@ -21,6 +22,16 @@ function normalizeProtocolError(method, error) {
|
|
|
21
22
|
const message = typeof rawMessage === "string" ? redactText(rawMessage) : "protocol_error";
|
|
22
23
|
return new CodexAppServerProtocolError(`Codex app-server request failed: ${method}: ${code}: ${message}`, "request_failed");
|
|
23
24
|
}
|
|
25
|
+
function processExitStderrExcerpt(value) {
|
|
26
|
+
const normalized = redactText(value).replace(/\s+/gu, " ").trim();
|
|
27
|
+
if (normalized.length === 0) {
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
if (normalized.length <= PROCESS_EXIT_STDERR_EXCERPT_MAX_LENGTH) {
|
|
31
|
+
return normalized;
|
|
32
|
+
}
|
|
33
|
+
return `${normalized.slice(0, PROCESS_EXIT_STDERR_EXCERPT_MAX_LENGTH)}...`;
|
|
34
|
+
}
|
|
24
35
|
export class CodexAppServerJsonRpcClient {
|
|
25
36
|
child;
|
|
26
37
|
options;
|
|
@@ -47,7 +58,8 @@ export class CodexAppServerJsonRpcClient {
|
|
|
47
58
|
});
|
|
48
59
|
child.on("exit", (code, signal) => {
|
|
49
60
|
this.closed = true;
|
|
50
|
-
|
|
61
|
+
const stderrExcerpt = processExitStderrExcerpt(this.stderrText);
|
|
62
|
+
this.rejectAll(new CodexAppServerProtocolError(`Codex app-server exited before request completed: code=${code ?? "null"} signal=${signal ?? "null"}${stderrExcerpt === "" ? "" : ` stderr=${stderrExcerpt}`}`, "process_exited"));
|
|
51
63
|
});
|
|
52
64
|
child.on("error", (error) => {
|
|
53
65
|
this.closed = true;
|
|
@@ -2,7 +2,7 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { buildCodexCliProcessPlan } from "../codex-app-server.js";
|
|
6
6
|
import { createCodexSpawnEnv } from "./runtime-helpers.js";
|
|
7
7
|
const DEFAULT_PROBE_TIMEOUT_MS = 10_000;
|
|
8
8
|
export const CODEX_LINUX_SANDBOX_GUIDANCE = "Install bubblewrap. On Ubuntu 24.04, also install apparmor-profiles and apparmor-utils and load the distribution bwrap-userns-restrict profile. Then run `tutti doctor` again.";
|
|
@@ -74,9 +74,12 @@ export function inspectCodexLinuxSandboxReadiness(options = {}) {
|
|
|
74
74
|
const codexHome = join(tempRoot, "codex-home");
|
|
75
75
|
mkdirSync(codexHome, { recursive: true, mode: 0o700 });
|
|
76
76
|
const runProbe = options.runProbe ?? defaultProbeRunner;
|
|
77
|
-
|
|
78
|
-
command: options.codexCommand ?? CODEX_APP_SERVER_COMMAND,
|
|
77
|
+
const processPlan = buildCodexCliProcessPlan({
|
|
79
78
|
args: ["sandbox", "--", "/bin/true"],
|
|
79
|
+
...(options.codexCommand === undefined ? {} : { codexCommand: options.codexCommand }),
|
|
80
|
+
});
|
|
81
|
+
return classifyProbeResult(runProbe({
|
|
82
|
+
...processPlan,
|
|
80
83
|
cwd: tempRoot,
|
|
81
84
|
env: createCodexSpawnEnv(codexHome, options.baseEnv ?? process.env),
|
|
82
85
|
timeoutMs: options.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS,
|
|
@@ -120,9 +120,9 @@ export async function runCodexAppServerReadOnlyProcedure(options) {
|
|
|
120
120
|
const processPlan = buildCodexAppServerProcessPlan({
|
|
121
121
|
codexHome,
|
|
122
122
|
configOverrides: buildCodexAppServerProviderConfigOverrides(options),
|
|
123
|
+
...(options.codexCommand === undefined ? {} : { codexCommand: options.codexCommand }),
|
|
123
124
|
});
|
|
124
|
-
const
|
|
125
|
-
const child = spawn(command, processPlan.args, {
|
|
125
|
+
const child = spawn(processPlan.command, processPlan.args, {
|
|
126
126
|
cwd: process.cwd(),
|
|
127
127
|
env: createCodexSpawnEnv(codexHome, options.baseEnv ?? process.env),
|
|
128
128
|
stdio: "pipe",
|
|
@@ -25,9 +25,9 @@ export async function runCodexAppServerNoWriteSmoke(options) {
|
|
|
25
25
|
const processPlan = buildCodexAppServerProcessPlan({
|
|
26
26
|
codexHome,
|
|
27
27
|
configOverrides: buildCodexAppServerProviderConfigOverrides(options),
|
|
28
|
+
...(options.codexCommand === undefined ? {} : { codexCommand: options.codexCommand }),
|
|
28
29
|
});
|
|
29
|
-
const
|
|
30
|
-
const child = spawn(command, processPlan.args, {
|
|
30
|
+
const child = spawn(processPlan.command, processPlan.args, {
|
|
31
31
|
cwd: process.cwd(),
|
|
32
32
|
env: createCodexSpawnEnv(codexHome, options.baseEnv ?? process.env),
|
|
33
33
|
stdio: "pipe",
|
|
@@ -196,9 +196,9 @@ export async function runCodexAppServerWorkspaceWriteRun(options) {
|
|
|
196
196
|
const processPlan = buildCodexAppServerProcessPlan({
|
|
197
197
|
codexHome,
|
|
198
198
|
configOverrides: buildCodexAppServerProviderConfigOverrides(options),
|
|
199
|
+
...(options.codexCommand === undefined ? {} : { codexCommand: options.codexCommand }),
|
|
199
200
|
});
|
|
200
|
-
const
|
|
201
|
-
const child = spawn(command, processPlan.args, {
|
|
201
|
+
const child = spawn(processPlan.command, processPlan.args, {
|
|
202
202
|
cwd: process.cwd(),
|
|
203
203
|
env: createCodexSpawnEnv(codexHome, options.baseEnv ?? process.env),
|
|
204
204
|
stdio: "pipe",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare const CODEX_APP_SERVER_ENTRYPOINT: string;
|
|
1
2
|
export declare const CODEX_APP_SERVER_COMMAND: string;
|
|
2
3
|
export declare const CODEX_APP_SERVER_LISTEN_URL: "stdio://";
|
|
3
4
|
export declare const CODEX_APP_SERVER_CLIENT_NAME: "tutti_host";
|
|
@@ -73,8 +74,13 @@ export type CodexAppServerTurnStartTemplatePlan = {
|
|
|
73
74
|
};
|
|
74
75
|
export type BuildCodexAppServerProcessPlanOptions = {
|
|
75
76
|
codexHome: string;
|
|
77
|
+
codexCommand?: string;
|
|
76
78
|
configOverrides?: readonly CodexAppServerConfigOverride[];
|
|
77
79
|
};
|
|
80
|
+
export type CodexCliProcessPlan = {
|
|
81
|
+
command: string;
|
|
82
|
+
args: string[];
|
|
83
|
+
};
|
|
78
84
|
export type CodexAppServerNoWriteSmokePlan = {
|
|
79
85
|
process: CodexAppServerProcessPlan;
|
|
80
86
|
initialize: CodexAppServerRequestPlan<"initialize", CodexAppServerInitializeRequestParams>;
|
|
@@ -107,6 +113,10 @@ export declare const CODEX_NO_WRITE_SMOKE_OUTPUT_SCHEMA: {
|
|
|
107
113
|
export declare function createCodexAppServerProcessEnv(options: {
|
|
108
114
|
codexHome: string;
|
|
109
115
|
}): Record<string, string>;
|
|
116
|
+
export declare function buildCodexCliProcessPlan(options: {
|
|
117
|
+
args: readonly string[];
|
|
118
|
+
codexCommand?: string;
|
|
119
|
+
}): CodexCliProcessPlan;
|
|
110
120
|
export declare function buildCodexAppServerProcessPlan(options: BuildCodexAppServerProcessPlanOptions): CodexAppServerProcessPlan;
|
|
111
121
|
export declare function createCodexAppServerNoWriteSmokePlan(options: CodexNoWriteSmokePlanOptions): CodexAppServerNoWriteSmokePlan;
|
|
112
122
|
export declare class CodexAppServerJsonlParseError extends Error {
|
|
@@ -2,7 +2,8 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import { dirname, isAbsolute, join } from "node:path";
|
|
3
3
|
import { DEFAULT_OPENAI_MODEL } from "./model-config.js";
|
|
4
4
|
const require = createRequire(import.meta.url);
|
|
5
|
-
export const
|
|
5
|
+
export const CODEX_APP_SERVER_ENTRYPOINT = join(dirname(require.resolve("@openai/codex/package.json")), "bin", "codex.js");
|
|
6
|
+
export const CODEX_APP_SERVER_COMMAND = process.execPath;
|
|
6
7
|
export const CODEX_APP_SERVER_LISTEN_URL = "stdio://";
|
|
7
8
|
export const CODEX_APP_SERVER_CLIENT_NAME = "tutti_host";
|
|
8
9
|
export const CODEX_APP_SERVER_CLIENT_TITLE = "Tutti Host";
|
|
@@ -37,12 +38,28 @@ export function createCodexAppServerProcessEnv(options) {
|
|
|
37
38
|
CODEX_HOME: options.codexHome,
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
|
-
export function
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
export function buildCodexCliProcessPlan(options) {
|
|
42
|
+
if (options.codexCommand !== undefined) {
|
|
43
|
+
assertNonEmpty(options.codexCommand, "codexCommand");
|
|
44
|
+
return {
|
|
45
|
+
command: options.codexCommand,
|
|
46
|
+
args: [...options.args],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
43
49
|
return {
|
|
44
50
|
command: CODEX_APP_SERVER_COMMAND,
|
|
45
|
-
args,
|
|
51
|
+
args: [CODEX_APP_SERVER_ENTRYPOINT, ...options.args],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function buildCodexAppServerProcessPlan(options) {
|
|
55
|
+
const codexArgs = ["app-server", "--listen", CODEX_APP_SERVER_LISTEN_URL];
|
|
56
|
+
pushConfigOverrides(codexArgs, options.configOverrides ?? []);
|
|
57
|
+
const processPlan = buildCodexCliProcessPlan({
|
|
58
|
+
args: codexArgs,
|
|
59
|
+
...(options.codexCommand === undefined ? {} : { codexCommand: options.codexCommand }),
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
...processPlan,
|
|
46
63
|
env: createCodexAppServerProcessEnv({ codexHome: options.codexHome }),
|
|
47
64
|
transport: {
|
|
48
65
|
kind: "stdio",
|
|
@@ -283,7 +283,7 @@ export async function startForegroundHostServer(options) {
|
|
|
283
283
|
return await resolution.model.answer(input);
|
|
284
284
|
},
|
|
285
285
|
},
|
|
286
|
-
onScratchpadSourceChanged: () => controlPlane.notifyScratchpadSourceChanged(),
|
|
286
|
+
onScratchpadSourceChanged: (message) => controlPlane.notifyScratchpadSourceChanged(message),
|
|
287
287
|
now,
|
|
288
288
|
});
|
|
289
289
|
let close = async () => { };
|
|
@@ -71,7 +71,7 @@ export function registerMessagesRoutes(app, { options, workspaceEvents, }) {
|
|
|
71
71
|
},
|
|
72
72
|
invalidates: mainChatMessageInvalidates(),
|
|
73
73
|
});
|
|
74
|
-
options.controlPlane?.notifyScratchpadSourceChanged();
|
|
74
|
+
options.controlPlane?.notifyScratchpadSourceChanged(execution.result.message);
|
|
75
75
|
options.chatAssistant?.enqueue({ message: execution.result.message });
|
|
76
76
|
}
|
|
77
77
|
return response;
|
|
@@ -137,7 +137,7 @@ export function registerReferenceFilesRoutes(app, { options, workspaceEvents, })
|
|
|
137
137
|
},
|
|
138
138
|
invalidates,
|
|
139
139
|
});
|
|
140
|
-
options.controlPlane?.notifyScratchpadSourceChanged();
|
|
140
|
+
options.controlPlane?.notifyScratchpadSourceChanged(execution.result.message);
|
|
141
141
|
options.controlPlane?.startReferenceSummaryRefresh({
|
|
142
142
|
paths: [execution.result.file.path],
|
|
143
143
|
});
|
|
@@ -19,10 +19,12 @@ export declare function createDesktopLocalConsoleInvocationContext(options: {
|
|
|
19
19
|
export declare function createLocalConsoleServiceEnvironment(options: {
|
|
20
20
|
env: NodeJS.ProcessEnv;
|
|
21
21
|
tuttiHome: string;
|
|
22
|
+
runtimeExecutablePath?: string;
|
|
22
23
|
}): NodeJS.ProcessEnv;
|
|
23
24
|
export declare function createLocalConsoleOperationEnvironment(options: {
|
|
24
25
|
serviceEnvironment: NodeJS.ProcessEnv;
|
|
25
26
|
invocationEnvironment: LocalConsoleInvocationEnvironment;
|
|
26
27
|
tuttiHome: string;
|
|
28
|
+
runtimeExecutablePath?: string;
|
|
27
29
|
}): NodeJS.ProcessEnv;
|
|
28
30
|
//# sourceMappingURL=invocation-context.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
1
|
+
import { delimiter, dirname, resolve } from "node:path";
|
|
2
2
|
export const LOCAL_CONSOLE_INVOCATION_ENV_KEYS = [
|
|
3
3
|
"DBUS_SESSION_BUS_ADDRESS",
|
|
4
4
|
"DISPLAY",
|
|
@@ -12,6 +12,12 @@ export const LOCAL_CONSOLE_INVOCATION_ENV_KEYS = [
|
|
|
12
12
|
"WAYLAND_DISPLAY",
|
|
13
13
|
"XDG_CURRENT_DESKTOP",
|
|
14
14
|
];
|
|
15
|
+
function mergeExecutablePaths(values, runtimeExecutablePath) {
|
|
16
|
+
const entries = [dirname(runtimeExecutablePath), ...values.flatMap((value) => value?.split(delimiter) ?? [])]
|
|
17
|
+
.map((entry) => entry.trim())
|
|
18
|
+
.filter((entry) => entry !== "");
|
|
19
|
+
return [...new Set(entries)].join(delimiter);
|
|
20
|
+
}
|
|
15
21
|
export function collectLocalConsoleInvocationEnvironment(env) {
|
|
16
22
|
const environment = {};
|
|
17
23
|
for (const key of LOCAL_CONSOLE_INVOCATION_ENV_KEYS) {
|
|
@@ -52,12 +58,15 @@ export function createLocalConsoleServiceEnvironment(options) {
|
|
|
52
58
|
environment[key] = value;
|
|
53
59
|
}
|
|
54
60
|
}
|
|
61
|
+
environment.PATH = mergeExecutablePaths([environment.PATH], options.runtimeExecutablePath ?? process.execPath);
|
|
55
62
|
return environment;
|
|
56
63
|
}
|
|
57
64
|
export function createLocalConsoleOperationEnvironment(options) {
|
|
65
|
+
const executablePath = mergeExecutablePaths([options.invocationEnvironment.PATH, options.serviceEnvironment.PATH], options.runtimeExecutablePath ?? process.execPath);
|
|
58
66
|
return {
|
|
59
67
|
...options.serviceEnvironment,
|
|
60
68
|
...options.invocationEnvironment,
|
|
69
|
+
PATH: executablePath,
|
|
61
70
|
TUTTI_HOME: options.tuttiHome,
|
|
62
71
|
};
|
|
63
72
|
}
|