@rynx-ai/daemon 0.1.10 → 0.1.11-beta.10
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/bundled-plugins/.rynx-plugin/marketplace.json +10 -0
- package/bundled-plugins/plugins/lark/.rynx-plugin/plugin.json +25 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.d.ts +48 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.js +56 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.d.ts +85 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.js +333 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.d.ts +109 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.js +347 -0
- package/bundled-plugins/plugins/lark/dist/host-adapters.d.ts +95 -0
- package/bundled-plugins/plugins/lark/dist/host-adapters.js +506 -0
- package/bundled-plugins/plugins/lark/dist/index.d.ts +7 -0
- package/bundled-plugins/plugins/lark/dist/index.js +7 -0
- package/bundled-plugins/plugins/lark/dist/lark-card-stream.d.ts +363 -0
- package/bundled-plugins/plugins/lark/dist/lark-card-stream.js +1335 -0
- package/bundled-plugins/plugins/lark/dist/lark-config-store.d.ts +30 -0
- package/bundled-plugins/plugins/lark/dist/lark-config-store.js +135 -0
- package/bundled-plugins/plugins/lark/dist/lark-content.d.ts +30 -0
- package/bundled-plugins/plugins/lark/dist/lark-content.js +138 -0
- package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.d.ts +65 -0
- package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.js +106 -0
- package/bundled-plugins/plugins/lark/dist/lark-diff-card.d.ts +25 -0
- package/bundled-plugins/plugins/lark/dist/lark-diff-card.js +58 -0
- package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.d.ts +16 -0
- package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.js +141 -0
- package/bundled-plugins/plugins/lark/dist/lark-resume-card.d.ts +31 -0
- package/bundled-plugins/plugins/lark/dist/lark-resume-card.js +105 -0
- package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.d.ts +18 -0
- package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.js +95 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/client.d.ts +8 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/client.js +32 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/index.d.ts +1 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/index.js +1 -0
- package/bundled-plugins/plugins/lark/dist/lark-sender.d.ts +114 -0
- package/bundled-plugins/plugins/lark/dist/lark-sender.js +323 -0
- package/bundled-plugins/plugins/lark/dist/lark-session-store.d.ts +13 -0
- package/bundled-plugins/plugins/lark/dist/lark-session-store.js +14 -0
- package/bundled-plugins/plugins/lark/dist/lark-settings-card.d.ts +55 -0
- package/bundled-plugins/plugins/lark/dist/lark-settings-card.js +158 -0
- package/bundled-plugins/plugins/lark/dist/lark-setup.d.ts +39 -0
- package/bundled-plugins/plugins/lark/dist/lark-setup.js +103 -0
- package/bundled-plugins/plugins/lark/dist/lark.d.ts +507 -0
- package/bundled-plugins/plugins/lark/dist/lark.js +1975 -0
- package/bundled-plugins/plugins/lark/dist/runtime.d.ts +13 -0
- package/bundled-plugins/plugins/lark/dist/runtime.js +131328 -0
- package/bundled-plugins/plugins/lark/dist/settings.d.ts +7 -0
- package/bundled-plugins/plugins/lark/dist/settings.js +126971 -0
- package/bundled-plugins/plugins/lark/package.json +57 -0
- package/bundled-plugins/plugins/lark/ui/assets/index-CGUVAMsv.css +1 -0
- package/bundled-plugins/plugins/lark/ui/assets/index-D8Amoe6a.js +201 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/index.html +13 -0
- package/dist/agent-file.js +0 -1
- package/dist/browser-artifact-management.d.ts +4 -1
- package/dist/browser-artifact-management.js +18 -10
- package/dist/browser-artifacts.d.ts +1 -0
- package/dist/browser-artifacts.js +1 -0
- package/dist/bundled-plugins.d.ts +15 -0
- package/dist/bundled-plugins.js +134 -0
- package/dist/chrome-for-testing-runtime.d.ts +27 -0
- package/dist/chrome-for-testing-runtime.js +193 -0
- package/dist/chrome-for-testing-store.d.ts +2 -0
- package/dist/chrome-for-testing-store.js +9 -0
- package/dist/control-deps.d.ts +6 -2
- package/dist/control-deps.js +88 -82
- package/dist/daemon-server.d.ts +7 -1
- package/dist/daemon-server.js +310 -87
- package/dist/db.js +181 -124
- package/dist/entry-path.d.ts +3 -0
- package/dist/entry-path.js +12 -0
- package/dist/index-daemon.js +3 -66
- package/dist/lifecycle.d.ts +12 -0
- package/dist/lifecycle.js +16 -0
- package/dist/maintenance-lease.d.ts +39 -0
- package/dist/maintenance-lease.js +250 -0
- package/dist/migrations/cleanup-legacy-sessions.d.ts +1 -1
- package/dist/migrations/cleanup-legacy-sessions.js +33 -15
- package/dist/official-plugins.d.ts +2 -0
- package/dist/official-plugins.js +2 -0
- package/dist/plugin-cli.d.ts +1 -3
- package/dist/plugin-cli.js +56 -45
- package/dist/plugin-host-leases.d.ts +4 -0
- package/dist/plugin-host-leases.js +7 -0
- package/dist/plugin-host-rpc.d.ts +73 -6
- package/dist/plugin-host-rpc.js +354 -81
- package/dist/plugin-installer.d.ts +24 -55
- package/dist/plugin-installer.js +258 -412
- package/dist/plugin-management-service.d.ts +30 -23
- package/dist/plugin-management-service.js +288 -105
- package/dist/plugin-marketplace.d.ts +35 -0
- package/dist/plugin-marketplace.js +299 -0
- package/dist/plugin-package.d.ts +22 -24
- package/dist/plugin-package.js +520 -571
- package/dist/plugin-skill-context.d.ts +4 -0
- package/dist/plugin-skill-context.js +35 -0
- package/dist/plugin-store.d.ts +36 -37
- package/dist/plugin-store.js +138 -92
- package/dist/plugin-supervisor.d.ts +50 -125
- package/dist/plugin-supervisor.js +678 -1030
- package/dist/pm2.d.ts +11 -2
- package/dist/pm2.js +130 -28
- package/dist/process.d.ts +12 -0
- package/dist/process.js +91 -0
- package/dist/runtime-project-store.d.ts +9 -0
- package/dist/runtime-project-store.js +83 -0
- package/dist/session-fallback-workspace.d.ts +22 -0
- package/dist/session-fallback-workspace.js +120 -0
- package/dist/session-fork-store.d.ts +41 -0
- package/dist/session-fork-store.js +288 -0
- package/dist/session-launch-operations.d.ts +23 -2
- package/dist/session-launch-operations.js +48 -7
- package/dist/session-meta-store.d.ts +12 -9
- package/dist/session-meta-store.js +50 -49
- package/dist/session-portal-grant-store.d.ts +29 -0
- package/dist/session-portal-grant-store.js +84 -0
- package/dist/setup-service.d.ts +21 -0
- package/dist/setup-service.js +39 -0
- package/dist/skills-catalog.d.ts +11 -2
- package/dist/skills-catalog.js +307 -7
- package/dist/system-dependencies.d.ts +26 -0
- package/dist/system-dependencies.js +149 -0
- package/package.json +36 -20
- package/dist/browser-cli-args.d.ts +0 -20
- package/dist/browser-cli-args.js +0 -100
- package/dist/channel-store.d.ts +0 -22
- package/dist/channel-store.js +0 -65
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -732
- package/dist/control-client.d.ts +0 -122
- package/dist/control-client.js +0 -855
- package/dist/control-endpoint.d.ts +0 -14
- package/dist/control-endpoint.js +0 -124
- package/dist/desktop-browser-host-client.d.ts +0 -35
- package/dist/desktop-browser-host-client.js +0 -415
- package/dist/instance-store.d.ts +0 -38
- package/dist/instance-store.js +0 -85
- package/dist/plugin-install-restart.d.ts +0 -13
- package/dist/plugin-install-restart.js +0 -24
- package/dist/plugin-runtime-control.d.ts +0 -2
- package/dist/plugin-runtime-control.js +0 -37
- package/dist/registry.d.ts +0 -10
- package/dist/registry.js +0 -52
- package/dist/setup.d.ts +0 -20
- package/dist/setup.js +0 -374
- package/dist/update.d.ts +0 -25
- package/dist/update.js +0 -133
package/dist/pm2.d.ts
CHANGED
|
@@ -8,12 +8,21 @@ export declare function formatControlUrl(host: string, port: number): string;
|
|
|
8
8
|
* entry from scratch (delete + start) so config flags are always fresh; the
|
|
9
9
|
* `force === false` path short-circuits when it's already online.
|
|
10
10
|
*/
|
|
11
|
-
export declare function startDaemon({ force, quiet }: {
|
|
11
|
+
export declare function startDaemon({ force, quiet, launchEnvironment, }: {
|
|
12
12
|
force: boolean;
|
|
13
13
|
quiet?: boolean;
|
|
14
|
+
launchEnvironment?: NodeJS.ProcessEnv;
|
|
14
15
|
}): number;
|
|
15
16
|
export declare function isPm2DaemonOnline(): boolean;
|
|
16
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Stop the daemon and terminate its dedicated pm2 supervisor.
|
|
19
|
+
*
|
|
20
|
+
* PM2_HOME lives below RYNX_HOME, so this supervisor cannot own unrelated
|
|
21
|
+
* applications. Leaving it alive across an npm replacement is unsafe: the
|
|
22
|
+
* daemon process container path is resolved inside the old pm2 package. Once
|
|
23
|
+
* npm swaps @rynx-ai/daemon, that cached path may no longer exist and every
|
|
24
|
+
* subsequent `rynx start` enters a restart loop before our code can run.
|
|
25
|
+
*/
|
|
17
26
|
export declare function stopDaemon(): number;
|
|
18
27
|
/** Print a one-line status; exit 0 only when online. */
|
|
19
28
|
export declare function statusDaemon(): number;
|
package/dist/pm2.js
CHANGED
|
@@ -10,15 +10,18 @@
|
|
|
10
10
|
import { spawn, spawnSync } from "node:child_process";
|
|
11
11
|
import { mkdirSync, realpathSync } from "node:fs";
|
|
12
12
|
import { createRequire } from "node:module";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { loadConfig } from "@rynx-ai/core";
|
|
13
|
+
import { userInfo } from "node:os";
|
|
14
|
+
import { delimiter, isAbsolute, join, resolve } from "node:path";
|
|
15
|
+
import { loadConfig, rynxHome } from "@rynx-ai/core";
|
|
17
16
|
import { daemonEntryRestartRequired } from "./daemon-build-status.js";
|
|
17
|
+
import { resolveDaemonEntry } from "./entry-path.js";
|
|
18
18
|
const require = createRequire(import.meta.url);
|
|
19
19
|
/** pm2 app name — single resident daemon per machine. */
|
|
20
20
|
const APP_NAME = "rynx";
|
|
21
21
|
const PM2_COMMAND_TIMEOUT_MS = 5_000;
|
|
22
|
+
const LOGIN_SHELL_PATH_TIMEOUT_MS = 5_000;
|
|
23
|
+
const LOGIN_SHELL_PATH_MAX_BYTES = 256 * 1024;
|
|
24
|
+
const REFRESH_LOGIN_SHELL_PATH_ENV = "RYNX_REFRESH_LOGIN_SHELL_PATH";
|
|
22
25
|
const DAEMON_PACKAGE_VERSION = require("../package.json").version;
|
|
23
26
|
/**
|
|
24
27
|
* Build a dialable control-console URL from the daemon's bind host/port. Bind-all
|
|
@@ -50,27 +53,76 @@ function pm2Bin() {
|
|
|
50
53
|
// pm2 ships its CLI at bin/pm2; run it with our own node.
|
|
51
54
|
return require.resolve("pm2/bin/pm2");
|
|
52
55
|
}
|
|
53
|
-
/** `index-daemon.js` sits next to this file in `dist/`. */
|
|
54
|
-
function daemonEntryPath() {
|
|
55
|
-
return join(dirname(fileURLToPath(import.meta.url)), "index-daemon.js");
|
|
56
|
-
}
|
|
57
56
|
function logsDir() {
|
|
58
|
-
const
|
|
59
|
-
const dir = join(home, "logs");
|
|
57
|
+
const dir = join(rynxHome(), "logs");
|
|
60
58
|
mkdirSync(dir, { recursive: true });
|
|
61
59
|
return dir;
|
|
62
60
|
}
|
|
63
61
|
function nodeRuntimeEnv() {
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
const home = rynxHome();
|
|
63
|
+
const pm2Home = join(home, "pm2");
|
|
64
|
+
mkdirSync(pm2Home, { recursive: true, mode: 0o700 });
|
|
65
|
+
return {
|
|
66
|
+
...process.env,
|
|
67
|
+
RYNX_HOME: home,
|
|
68
|
+
PM2_HOME: pm2Home,
|
|
69
|
+
...(process.versions.electron
|
|
70
|
+
? { ELECTRON_RUN_AS_NODE: "1" }
|
|
71
|
+
: {}),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A detached plugin updater intentionally receives a reduced environment and
|
|
76
|
+
* therefore has no SHELL. Starting the replacement daemon with that reduced
|
|
77
|
+
* PATH would make user-installed runtimes (for example an fnm-managed Codex)
|
|
78
|
+
* disappear after every upgrade. Recover the user's login-shell PATH only at
|
|
79
|
+
* this boundary; normal interactive starts keep their exact caller environment.
|
|
80
|
+
*/
|
|
81
|
+
function daemonStartEnv() {
|
|
82
|
+
const env = nodeRuntimeEnv();
|
|
83
|
+
const refreshLoginPath = env[REFRESH_LOGIN_SHELL_PATH_ENV] === "1";
|
|
84
|
+
delete env[REFRESH_LOGIN_SHELL_PATH_ENV];
|
|
85
|
+
if (!refreshLoginPath)
|
|
86
|
+
return env;
|
|
87
|
+
const shell = userInfo().shell?.trim();
|
|
88
|
+
if (!shell) {
|
|
89
|
+
throw new Error("cannot refresh daemon PATH: the user login shell is unavailable");
|
|
90
|
+
}
|
|
91
|
+
const result = spawnSync(shell, ["-lic", `printf '\\036%s\\037' "$PATH"`], {
|
|
92
|
+
encoding: "utf8",
|
|
93
|
+
// Do not feed an fnm/nvm "multishell" directory inherited from the old
|
|
94
|
+
// daemon back into the next login shell. Version managers prepend a new
|
|
95
|
+
// directory on every shell startup, so reusing the old PATH would grow
|
|
96
|
+
// it indefinitely across upgrades.
|
|
97
|
+
env: { ...env, SHELL: shell, PATH: loginShellBaselinePath() },
|
|
98
|
+
timeout: LOGIN_SHELL_PATH_TIMEOUT_MS,
|
|
99
|
+
killSignal: "SIGTERM",
|
|
100
|
+
maxBuffer: LOGIN_SHELL_PATH_MAX_BYTES,
|
|
101
|
+
});
|
|
102
|
+
if (result.error) {
|
|
103
|
+
throw new Error(`cannot refresh daemon PATH: ${result.error.message}`);
|
|
104
|
+
}
|
|
105
|
+
if (result.status !== 0) {
|
|
106
|
+
throw new Error(`cannot refresh daemon PATH: login shell exited ${result.status ?? "without status"}`);
|
|
66
107
|
}
|
|
67
|
-
|
|
108
|
+
const path = extractFramedPath(result.stdout);
|
|
109
|
+
if (!path) {
|
|
110
|
+
throw new Error("cannot refresh daemon PATH: login shell returned no framed PATH");
|
|
111
|
+
}
|
|
112
|
+
const npmPrefix = env.NPM_CONFIG_PREFIX?.trim();
|
|
113
|
+
const npmBin = npmPrefix && isAbsolute(npmPrefix)
|
|
114
|
+
? join(npmPrefix, "bin")
|
|
115
|
+
: "";
|
|
116
|
+
const refreshedPath = npmBin === ""
|
|
117
|
+
? path
|
|
118
|
+
: [npmBin, ...path.split(delimiter).filter((entry) => entry !== npmBin)].join(delimiter);
|
|
119
|
+
return { ...env, PATH: refreshedPath, SHELL: shell };
|
|
68
120
|
}
|
|
69
121
|
/** Run a pm2 command inheriting stdio; returns its exit code. */
|
|
70
|
-
function runPm2(args, quiet = false) {
|
|
122
|
+
function runPm2(args, quiet = false, env = nodeRuntimeEnv()) {
|
|
71
123
|
const res = spawnSync(process.execPath, [pm2Bin(), ...args], {
|
|
72
124
|
stdio: quiet ? "ignore" : "inherit",
|
|
73
|
-
env
|
|
125
|
+
env,
|
|
74
126
|
timeout: PM2_COMMAND_TIMEOUT_MS,
|
|
75
127
|
killSignal: "SIGTERM",
|
|
76
128
|
});
|
|
@@ -112,7 +164,7 @@ function pm2ErrorMessage(error) {
|
|
|
112
164
|
* entry from scratch (delete + start) so config flags are always fresh; the
|
|
113
165
|
* `force === false` path short-circuits when it's already online.
|
|
114
166
|
*/
|
|
115
|
-
export function startDaemon({ force, quiet = false }) {
|
|
167
|
+
export function startDaemon({ force, quiet = false, launchEnvironment, }) {
|
|
116
168
|
let existing;
|
|
117
169
|
try {
|
|
118
170
|
existing = describe();
|
|
@@ -134,6 +186,20 @@ export function startDaemon({ force, quiet = false }) {
|
|
|
134
186
|
if (staleBuild && !quiet) {
|
|
135
187
|
console.log("A newer daemon build is present on disk; restarting Rynx.");
|
|
136
188
|
}
|
|
189
|
+
let startEnv;
|
|
190
|
+
try {
|
|
191
|
+
// Resolve the replacement environment before deleting an existing app.
|
|
192
|
+
// A broken/hung login shell must leave the known-good daemon untouched.
|
|
193
|
+
startEnv = {
|
|
194
|
+
...daemonStartEnv(),
|
|
195
|
+
...launchEnvironment,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
if (!quiet)
|
|
200
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
201
|
+
return 1;
|
|
202
|
+
}
|
|
137
203
|
const dir = logsDir();
|
|
138
204
|
if (existing) {
|
|
139
205
|
const removed = runPm2(["delete", APP_NAME], quiet);
|
|
@@ -142,12 +208,12 @@ export function startDaemon({ force, quiet = false }) {
|
|
|
142
208
|
}
|
|
143
209
|
const status = runPm2([
|
|
144
210
|
"start",
|
|
145
|
-
|
|
211
|
+
resolveDaemonEntry(),
|
|
146
212
|
"--name",
|
|
147
213
|
APP_NAME,
|
|
148
|
-
//
|
|
214
|
+
// App and CLI share one daemon-owned state/workspace root.
|
|
149
215
|
"--cwd",
|
|
150
|
-
|
|
216
|
+
rynxHome(),
|
|
151
217
|
"--max-restarts",
|
|
152
218
|
"10",
|
|
153
219
|
"--restart-delay",
|
|
@@ -158,7 +224,7 @@ export function startDaemon({ force, quiet = false }) {
|
|
|
158
224
|
join(dir, "err.log"),
|
|
159
225
|
"--merge-logs",
|
|
160
226
|
"--time",
|
|
161
|
-
], quiet);
|
|
227
|
+
], quiet, startEnv);
|
|
162
228
|
if (status === 0 && !quiet) {
|
|
163
229
|
console.log(`rynx ${force ? "restarted" : "started"} (pm2 app "${APP_NAME}", logs: ${dir}).`);
|
|
164
230
|
console.log(`Control console: ${styleUrl(controlConsoleUrl())}`);
|
|
@@ -168,16 +234,35 @@ export function startDaemon({ force, quiet = false }) {
|
|
|
168
234
|
export function isPm2DaemonOnline() {
|
|
169
235
|
return describe()?.pm2_env?.status === "online";
|
|
170
236
|
}
|
|
171
|
-
/**
|
|
237
|
+
/**
|
|
238
|
+
* Stop the daemon and terminate its dedicated pm2 supervisor.
|
|
239
|
+
*
|
|
240
|
+
* PM2_HOME lives below RYNX_HOME, so this supervisor cannot own unrelated
|
|
241
|
+
* applications. Leaving it alive across an npm replacement is unsafe: the
|
|
242
|
+
* daemon process container path is resolved inside the old pm2 package. Once
|
|
243
|
+
* npm swaps @rynx-ai/daemon, that cached path may no longer exist and every
|
|
244
|
+
* subsequent `rynx start` enters a restart loop before our code can run.
|
|
245
|
+
*/
|
|
172
246
|
export function stopDaemon() {
|
|
173
|
-
|
|
247
|
+
const existing = describe();
|
|
248
|
+
if (!existing) {
|
|
249
|
+
// Even an empty process list can belong to a resident PM2 daemon whose
|
|
250
|
+
// module path is about to be replaced. `pm2 kill` is idempotent and is
|
|
251
|
+
// the only reliable package-upgrade boundary.
|
|
252
|
+
const killed = runPm2(["kill"], true);
|
|
253
|
+
if (killed !== 0)
|
|
254
|
+
return killed;
|
|
174
255
|
console.log("rynx is not running.");
|
|
175
256
|
return 0;
|
|
176
257
|
}
|
|
177
|
-
const
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
|
|
258
|
+
const removed = runPm2(["delete", APP_NAME]);
|
|
259
|
+
if (removed !== 0)
|
|
260
|
+
return removed;
|
|
261
|
+
const killed = runPm2(["kill"]);
|
|
262
|
+
if (killed !== 0)
|
|
263
|
+
return killed;
|
|
264
|
+
console.log("rynx stopped.");
|
|
265
|
+
return 0;
|
|
181
266
|
}
|
|
182
267
|
/** Print a one-line status; exit 0 only when online. */
|
|
183
268
|
export function statusDaemon() {
|
|
@@ -204,7 +289,7 @@ export function streamLogs() {
|
|
|
204
289
|
}
|
|
205
290
|
function residentBuildRestartRequired(app) {
|
|
206
291
|
const runningEntry = app.pm2_env?.pm_exec_path;
|
|
207
|
-
if (runningEntry && !sameEntryPath(runningEntry,
|
|
292
|
+
if (runningEntry && !sameEntryPath(runningEntry, resolveDaemonEntry()))
|
|
208
293
|
return true;
|
|
209
294
|
const runningVersion = app.pm2_env?.version;
|
|
210
295
|
if (runningVersion &&
|
|
@@ -215,7 +300,7 @@ function residentBuildRestartRequired(app) {
|
|
|
215
300
|
const startedAt = app.pm2_env?.pm_uptime;
|
|
216
301
|
return typeof startedAt === "number" &&
|
|
217
302
|
Number.isFinite(startedAt) &&
|
|
218
|
-
daemonEntryRestartRequired(
|
|
303
|
+
daemonEntryRestartRequired(resolveDaemonEntry(), startedAt);
|
|
219
304
|
}
|
|
220
305
|
function sameEntryPath(left, right) {
|
|
221
306
|
try {
|
|
@@ -225,3 +310,20 @@ function sameEntryPath(left, right) {
|
|
|
225
310
|
return resolve(left) === resolve(right);
|
|
226
311
|
}
|
|
227
312
|
}
|
|
313
|
+
function extractFramedPath(stdout) {
|
|
314
|
+
if (!stdout)
|
|
315
|
+
return undefined;
|
|
316
|
+
const start = stdout.lastIndexOf("\x1e");
|
|
317
|
+
if (start < 0)
|
|
318
|
+
return undefined;
|
|
319
|
+
const end = stdout.indexOf("\x1f", start + 1);
|
|
320
|
+
if (end < 0)
|
|
321
|
+
return undefined;
|
|
322
|
+
const value = stdout.slice(start + 1, end);
|
|
323
|
+
return value.trim() ? value : undefined;
|
|
324
|
+
}
|
|
325
|
+
function loginShellBaselinePath() {
|
|
326
|
+
return process.platform === "darwin"
|
|
327
|
+
? "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
|
328
|
+
: "/usr/local/bin:/usr/bin:/bin";
|
|
329
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface SupervisorProcess {
|
|
2
|
+
connected?: boolean;
|
|
3
|
+
disconnect?: () => void;
|
|
4
|
+
}
|
|
5
|
+
/** Release a parent/supervisor IPC handle after graceful daemon shutdown. */
|
|
6
|
+
export declare function disconnectSupervisorIpc(target?: SupervisorProcess): void;
|
|
7
|
+
/**
|
|
8
|
+
* Run the daemon in the current process. Process ownership and executable
|
|
9
|
+
* selection belong to the caller (CLI standalone lifecycle or App lifecycle).
|
|
10
|
+
*/
|
|
11
|
+
export declare function runDaemonProcess(): Promise<void>;
|
|
12
|
+
export {};
|
package/dist/process.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { startRynxDaemonServer } from "./daemon-server.js";
|
|
2
|
+
import { ensureBundledOfficialPlugins } from "./bundled-plugins.js";
|
|
3
|
+
import { installStdioEpipeGuard } from "./stdio-epipe-guard.js";
|
|
4
|
+
/** Release a parent/supervisor IPC handle after graceful daemon shutdown. */
|
|
5
|
+
export function disconnectSupervisorIpc(target = process) {
|
|
6
|
+
if (target.connected && typeof target.disconnect === "function") {
|
|
7
|
+
target.disconnect();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Run the daemon in the current process. Process ownership and executable
|
|
12
|
+
* selection belong to the caller (CLI standalone lifecycle or App lifecycle).
|
|
13
|
+
*/
|
|
14
|
+
export async function runDaemonProcess() {
|
|
15
|
+
installStdioEpipeGuard();
|
|
16
|
+
const followsApp = process.env.RYNX_DAEMON_LIFECYCLE === "follow-app";
|
|
17
|
+
let parentDisconnected = followsApp && !process.connected;
|
|
18
|
+
const recordParentDisconnect = () => {
|
|
19
|
+
parentDisconnected = true;
|
|
20
|
+
};
|
|
21
|
+
if (followsApp)
|
|
22
|
+
process.once("disconnect", recordParentDisconnect);
|
|
23
|
+
const preparePlugins = async () => {
|
|
24
|
+
try {
|
|
25
|
+
const bundled = await ensureBundledOfficialPlugins({ reclaimHostLeases: true });
|
|
26
|
+
if (bundled.status === "ready") {
|
|
27
|
+
console.log(JSON.stringify({
|
|
28
|
+
level: "info",
|
|
29
|
+
type: "bundled_plugins_ready",
|
|
30
|
+
installed: bundled.installed,
|
|
31
|
+
updated: bundled.updated,
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.error(JSON.stringify({
|
|
37
|
+
level: "error",
|
|
38
|
+
type: "bundled_plugins_failed",
|
|
39
|
+
error: error instanceof Error ? error.message : String(error),
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
let server;
|
|
44
|
+
try {
|
|
45
|
+
server = await startRynxDaemonServer({
|
|
46
|
+
preparePlugins,
|
|
47
|
+
onShutdownComplete: () => disconnectSupervisorIpc(),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
process.off("disconnect", recordParentDisconnect);
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
let shutdownPromise;
|
|
55
|
+
const shutdown = (signal) => {
|
|
56
|
+
if (shutdownPromise)
|
|
57
|
+
return shutdownPromise;
|
|
58
|
+
process.off("SIGINT", onSigint);
|
|
59
|
+
process.off("SIGTERM", onSigterm);
|
|
60
|
+
process.off("disconnect", onDisconnect);
|
|
61
|
+
shutdownPromise = (async () => {
|
|
62
|
+
console.log(JSON.stringify({ level: "info", type: "shutdown", signal }));
|
|
63
|
+
await server.shutdown();
|
|
64
|
+
})();
|
|
65
|
+
shutdownPromise.catch((error) => {
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
console.error(`Shutdown failed: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
|
|
68
|
+
});
|
|
69
|
+
return shutdownPromise;
|
|
70
|
+
};
|
|
71
|
+
const onSigint = () => {
|
|
72
|
+
void shutdown("SIGINT");
|
|
73
|
+
};
|
|
74
|
+
const onSigterm = () => {
|
|
75
|
+
void shutdown("SIGTERM");
|
|
76
|
+
};
|
|
77
|
+
const onDisconnect = () => {
|
|
78
|
+
if (process.env.RYNX_DAEMON_LIFECYCLE === "follow-app") {
|
|
79
|
+
void shutdown("APP_DISCONNECT");
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
process.once("SIGINT", onSigint);
|
|
83
|
+
process.once("SIGTERM", onSigterm);
|
|
84
|
+
if (followsApp) {
|
|
85
|
+
process.once("disconnect", onDisconnect);
|
|
86
|
+
process.off("disconnect", recordParentDisconnect);
|
|
87
|
+
if (parentDisconnected || !process.connected) {
|
|
88
|
+
void shutdown("APP_DISCONNECT");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type RuntimeProject, type RuntimeProjectInput, type RuntimeProjectStore } from "@rynx-ai/core";
|
|
2
|
+
/** SQLite-backed Project catalog owned by the current target Runtime. */
|
|
3
|
+
export declare class SqliteRuntimeProjectStore implements RuntimeProjectStore {
|
|
4
|
+
list(): Promise<RuntimeProject[]>;
|
|
5
|
+
get(id: string): Promise<RuntimeProject | undefined>;
|
|
6
|
+
create(input: RuntimeProjectInput): Promise<RuntimeProject>;
|
|
7
|
+
update(id: string, input: RuntimeProjectInput): Promise<RuntimeProject | undefined>;
|
|
8
|
+
remove(id: string): Promise<boolean>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { canonicalizeRuntimeProjectInput, runtimeProjectSchema, } from "@rynx-ai/core";
|
|
3
|
+
import { db } from "./db.js";
|
|
4
|
+
const COLUMNS = "id, name, directories_json, primary_dir, created_at, updated_at";
|
|
5
|
+
/** SQLite-backed Project catalog owned by the current target Runtime. */
|
|
6
|
+
export class SqliteRuntimeProjectStore {
|
|
7
|
+
async list() {
|
|
8
|
+
return db()
|
|
9
|
+
.prepare(`SELECT ${COLUMNS} FROM runtime_projects ORDER BY updated_at DESC, id`)
|
|
10
|
+
.all()
|
|
11
|
+
.map((row) => rowToProject(row));
|
|
12
|
+
}
|
|
13
|
+
async get(id) {
|
|
14
|
+
const row = db()
|
|
15
|
+
.prepare(`SELECT ${COLUMNS} FROM runtime_projects WHERE id = ?`)
|
|
16
|
+
.get(id);
|
|
17
|
+
return row ? rowToProject(row) : undefined;
|
|
18
|
+
}
|
|
19
|
+
async create(input) {
|
|
20
|
+
const resolved = await canonicalizeRuntimeProjectInput(input);
|
|
21
|
+
const timestamp = new Date().toISOString();
|
|
22
|
+
const project = {
|
|
23
|
+
id: randomUUID(),
|
|
24
|
+
...resolved,
|
|
25
|
+
createdAt: timestamp,
|
|
26
|
+
updatedAt: timestamp,
|
|
27
|
+
};
|
|
28
|
+
const parsed = runtimeProjectSchema.parse(project);
|
|
29
|
+
db()
|
|
30
|
+
.prepare(`INSERT INTO runtime_projects
|
|
31
|
+
(id, name, directories_json, primary_dir, created_at, updated_at)
|
|
32
|
+
VALUES (@id, @name, @directories, @primary, @createdAt, @updatedAt)`)
|
|
33
|
+
.run({
|
|
34
|
+
id: parsed.id,
|
|
35
|
+
name: parsed.name,
|
|
36
|
+
directories: JSON.stringify(parsed.directories),
|
|
37
|
+
primary: parsed.primary,
|
|
38
|
+
createdAt: parsed.createdAt,
|
|
39
|
+
updatedAt: parsed.updatedAt,
|
|
40
|
+
});
|
|
41
|
+
return parsed;
|
|
42
|
+
}
|
|
43
|
+
async update(id, input) {
|
|
44
|
+
const current = await this.get(id);
|
|
45
|
+
if (!current)
|
|
46
|
+
return undefined;
|
|
47
|
+
const resolved = await canonicalizeRuntimeProjectInput(input);
|
|
48
|
+
const project = runtimeProjectSchema.parse({
|
|
49
|
+
id: current.id,
|
|
50
|
+
...resolved,
|
|
51
|
+
createdAt: current.createdAt,
|
|
52
|
+
updatedAt: new Date().toISOString(),
|
|
53
|
+
});
|
|
54
|
+
db()
|
|
55
|
+
.prepare(`UPDATE runtime_projects
|
|
56
|
+
SET name = @name,
|
|
57
|
+
directories_json = @directories,
|
|
58
|
+
primary_dir = @primary,
|
|
59
|
+
updated_at = @updatedAt
|
|
60
|
+
WHERE id = @id`)
|
|
61
|
+
.run({
|
|
62
|
+
id: project.id,
|
|
63
|
+
name: project.name,
|
|
64
|
+
directories: JSON.stringify(project.directories),
|
|
65
|
+
primary: project.primary,
|
|
66
|
+
updatedAt: project.updatedAt,
|
|
67
|
+
});
|
|
68
|
+
return project;
|
|
69
|
+
}
|
|
70
|
+
async remove(id) {
|
|
71
|
+
return db().prepare("DELETE FROM runtime_projects WHERE id = ?").run(id).changes > 0;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function rowToProject(row) {
|
|
75
|
+
return runtimeProjectSchema.parse({
|
|
76
|
+
id: row.id,
|
|
77
|
+
name: row.name,
|
|
78
|
+
directories: JSON.parse(row.directories_json),
|
|
79
|
+
primary: row.primary_dir,
|
|
80
|
+
createdAt: row.created_at,
|
|
81
|
+
updatedAt: row.updated_at,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type SessionWorkspaceSnapshot } from "@rynx-ai/core";
|
|
2
|
+
export interface SessionFallbackRootOptions {
|
|
3
|
+
platform?: NodeJS.Platform;
|
|
4
|
+
home?: string;
|
|
5
|
+
env?: NodeJS.ProcessEnv;
|
|
6
|
+
readTextFile?: (path: string) => Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
export interface SessionFallbackWorkspaceOptions extends SessionFallbackRootOptions {
|
|
9
|
+
now?: () => Date;
|
|
10
|
+
randomId?: () => string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the user-visible root for Sessions created without a Project.
|
|
14
|
+
*
|
|
15
|
+
* Linux desktop environments can localize or relocate Documents through the
|
|
16
|
+
* XDG user-dirs file. Headless installations commonly omit that file, so they
|
|
17
|
+
* fall back to a visible `$HOME/Rynx` instead of creating an arbitrary
|
|
18
|
+
* `$HOME/Documents` tree. Other platforms retain the existing Documents root.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveSessionFallbackRoot(options?: SessionFallbackRootOptions): Promise<string>;
|
|
21
|
+
export declare function createSessionFallbackWorkspace(options?: SessionFallbackWorkspaceOptions): Promise<SessionWorkspaceSnapshot>;
|
|
22
|
+
export declare function discardSessionFallbackWorkspace(workspace: SessionWorkspaceSnapshot, options?: SessionFallbackRootOptions): Promise<void>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, realpath, rm } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { isAbsolute, join, normalize, relative } from "node:path";
|
|
5
|
+
import { sessionWorkspaceSnapshotSchema, } from "@rynx-ai/core";
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the user-visible root for Sessions created without a Project.
|
|
8
|
+
*
|
|
9
|
+
* Linux desktop environments can localize or relocate Documents through the
|
|
10
|
+
* XDG user-dirs file. Headless installations commonly omit that file, so they
|
|
11
|
+
* fall back to a visible `$HOME/Rynx` instead of creating an arbitrary
|
|
12
|
+
* `$HOME/Documents` tree. Other platforms retain the existing Documents root.
|
|
13
|
+
*/
|
|
14
|
+
export async function resolveSessionFallbackRoot(options = {}) {
|
|
15
|
+
const platform = options.platform ?? process.platform;
|
|
16
|
+
const home = normalize(options.home ?? homedir());
|
|
17
|
+
if (!isAbsolute(home))
|
|
18
|
+
throw new Error("Session fallback home must be absolute");
|
|
19
|
+
if (platform !== "linux")
|
|
20
|
+
return join(home, "Documents", "Rynx");
|
|
21
|
+
const env = options.env ?? process.env;
|
|
22
|
+
const configHome = env.XDG_CONFIG_HOME && isAbsolute(env.XDG_CONFIG_HOME)
|
|
23
|
+
? normalize(env.XDG_CONFIG_HOME)
|
|
24
|
+
: join(home, ".config");
|
|
25
|
+
const readTextFile = options.readTextFile ?? ((path) => readFile(path, "utf8"));
|
|
26
|
+
try {
|
|
27
|
+
const contents = await readTextFile(join(configHome, "user-dirs.dirs"));
|
|
28
|
+
const documents = parseXdgDocumentsDirectory(contents, home);
|
|
29
|
+
if (documents)
|
|
30
|
+
return join(documents, "Rynx");
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Missing or unreadable XDG configuration is normal on headless Linux.
|
|
34
|
+
}
|
|
35
|
+
return join(home, "Rynx");
|
|
36
|
+
}
|
|
37
|
+
export async function createSessionFallbackWorkspace(options = {}) {
|
|
38
|
+
const now = (options.now ?? (() => new Date()))();
|
|
39
|
+
const date = [
|
|
40
|
+
now.getFullYear(),
|
|
41
|
+
String(now.getMonth() + 1).padStart(2, "0"),
|
|
42
|
+
String(now.getDate()).padStart(2, "0"),
|
|
43
|
+
].join("-");
|
|
44
|
+
const fallbackRoot = await resolveSessionFallbackRoot(options);
|
|
45
|
+
await mkdir(fallbackRoot, { recursive: true });
|
|
46
|
+
const canonicalFallbackRoot = await realpath(fallbackRoot);
|
|
47
|
+
const dateDirectory = join(canonicalFallbackRoot, date);
|
|
48
|
+
await mkdir(dateDirectory, { recursive: true });
|
|
49
|
+
const canonicalDateDirectory = await realpath(dateDirectory);
|
|
50
|
+
if (relative(canonicalFallbackRoot, canonicalDateDirectory) !== date) {
|
|
51
|
+
throw new Error("Session fallback date directory resolves outside the managed root");
|
|
52
|
+
}
|
|
53
|
+
const randomId = options.randomId ?? randomUUID;
|
|
54
|
+
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
55
|
+
const directory = join(canonicalDateDirectory, randomId().slice(0, 8));
|
|
56
|
+
try {
|
|
57
|
+
await mkdir(directory);
|
|
58
|
+
const canonical = await realpath(directory);
|
|
59
|
+
return sessionWorkspaceSnapshotSchema.parse({
|
|
60
|
+
cwd: canonical,
|
|
61
|
+
allowedDirs: [canonical],
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error.code !== "EEXIST")
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
throw new Error("could not allocate a unique Session workspace directory");
|
|
70
|
+
}
|
|
71
|
+
export async function discardSessionFallbackWorkspace(workspace, options = {}) {
|
|
72
|
+
if (workspace.allowedDirs.length !== 1
|
|
73
|
+
|| workspace.allowedDirs[0] !== workspace.cwd) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
let canonicalRoot;
|
|
77
|
+
try {
|
|
78
|
+
canonicalRoot = await realpath(await resolveSessionFallbackRoot(options));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const relativePath = relative(canonicalRoot, workspace.cwd);
|
|
84
|
+
const segments = relativePath.split(/[\\/]/);
|
|
85
|
+
if (isAbsolute(relativePath)
|
|
86
|
+
|| relativePath.startsWith("..")
|
|
87
|
+
|| segments.length !== 2
|
|
88
|
+
|| !/^\d{4}-\d{2}-\d{2}$/.test(segments[0] ?? "")
|
|
89
|
+
|| !/^[0-9a-f]{8}$/.test(segments[1] ?? "")) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
await rm(workspace.cwd, { recursive: true, force: true });
|
|
93
|
+
}
|
|
94
|
+
function parseXdgDocumentsDirectory(contents, home) {
|
|
95
|
+
for (const line of contents.split(/\r?\n/)) {
|
|
96
|
+
const match = line.match(/^\s*XDG_DOCUMENTS_DIR\s*=\s*"((?:\\.|[^"])*)"\s*(?:#.*)?$/);
|
|
97
|
+
if (!match)
|
|
98
|
+
continue;
|
|
99
|
+
const raw = match[1];
|
|
100
|
+
let expanded;
|
|
101
|
+
if (raw === "$HOME" || raw === "${HOME}") {
|
|
102
|
+
expanded = home;
|
|
103
|
+
}
|
|
104
|
+
else if (raw.startsWith("$HOME/")) {
|
|
105
|
+
expanded = join(home, decodeXdgPath(raw.slice("$HOME/".length)));
|
|
106
|
+
}
|
|
107
|
+
else if (raw.startsWith("${HOME}/")) {
|
|
108
|
+
expanded = join(home, decodeXdgPath(raw.slice("${HOME}/".length)));
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
expanded = decodeXdgPath(raw);
|
|
112
|
+
}
|
|
113
|
+
if (!expanded.includes("\0") && isAbsolute(expanded))
|
|
114
|
+
return normalize(expanded);
|
|
115
|
+
}
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
function decodeXdgPath(value) {
|
|
119
|
+
return value.replace(/\\(.)/g, "$1");
|
|
120
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type MachineSessionRecord } from "@rynx-ai/core";
|
|
2
|
+
import type { SessionItem } from "@rynx-ai/protocol";
|
|
3
|
+
import { type MachineSessionForkOperationRecord, type MachineSessionForkStorePort } from "@rynx-ai/server";
|
|
4
|
+
/**
|
|
5
|
+
* SQLite/resource-file implementation of the fork publication boundary.
|
|
6
|
+
*
|
|
7
|
+
* Provider context is prepared before {@link commit}; this store then publishes
|
|
8
|
+
* Session metadata, an independent canonical transcript, referenced committed
|
|
9
|
+
* resources, and the completed operation in one SQLite transaction. Resource
|
|
10
|
+
* files use deterministic target ids, so a crash before the transaction can be
|
|
11
|
+
* retried safely.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SqliteSessionForkStore implements MachineSessionForkStorePort {
|
|
14
|
+
private readonly resourceRoot;
|
|
15
|
+
constructor(resourceRoot?: string);
|
|
16
|
+
claim(input: {
|
|
17
|
+
operationId: string;
|
|
18
|
+
requestHash: string;
|
|
19
|
+
sourceSessionId: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
}): MachineSessionForkOperationRecord;
|
|
22
|
+
commit(input: {
|
|
23
|
+
operationId: string;
|
|
24
|
+
target: MachineSessionRecord;
|
|
25
|
+
items: SessionItem[];
|
|
26
|
+
}): void;
|
|
27
|
+
publishNativeFork(input: {
|
|
28
|
+
sourceSessionId: string;
|
|
29
|
+
target: MachineSessionRecord;
|
|
30
|
+
items: SessionItem[];
|
|
31
|
+
}): void;
|
|
32
|
+
private publishTarget;
|
|
33
|
+
markError(operationId: string, error: string): void;
|
|
34
|
+
listReserved(): MachineSessionForkOperationRecord[];
|
|
35
|
+
hasReservedSource(sessionId: string): boolean;
|
|
36
|
+
markTargetDeleted(sessionId: string): void;
|
|
37
|
+
private read;
|
|
38
|
+
private copyResourceFile;
|
|
39
|
+
private sessionDirectory;
|
|
40
|
+
private resourcePath;
|
|
41
|
+
}
|