@runweave/server-linux-x64 0.1.18 → 0.1.20
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/manifest.json +27 -27
- package/native.tar.gz +0 -0
- package/package.json +1 -1
- package/payload/app-server/build-info.json +4 -4
- package/payload/app-server/index.cjs +30 -8
- package/payload/app-server/index.cjs.map +1 -1
- package/payload/backend/activity-sqlite-worker.cjs +29 -7
- package/payload/backend/build-info.json +4 -4
- package/payload/backend/dev-resources/control.cjs +29 -7
- package/payload/backend/index.cjs +193 -48
- package/payload/frontend/dist/build-info.json +3 -3
- package/payload/frontend/dist/companion.html +1 -1
- package/payload/frontend/dist/index.html +1 -1
- package/payload/plugins/pi/dist/bridge/runweave-hook-claude.cjs +9 -1
- package/payload/plugins/toolkit/.codex-plugin/plugin.json +1 -1
- package/payload/plugins/toolkit/hooks/runweave-hook-claude.cjs +9 -1
- package/payload/plugins/toolkit-release.json +1 -1
- package/payload/pty-host/index.cjs +126 -17
- package/payload/server/index.cjs +29 -7
|
@@ -31,11 +31,19 @@ function readClaudeIdentity() {
|
|
|
31
31
|
}
|
|
32
32
|
let claudePid = null;
|
|
33
33
|
const visited = new Set();
|
|
34
|
+
let childStartedAt = observedAt;
|
|
34
35
|
for (let pid = process.ppid; pid > 1; ) {
|
|
35
36
|
if (visited.has(pid)) return null;
|
|
36
37
|
visited.add(pid);
|
|
37
38
|
const entry = processes.get(pid);
|
|
38
|
-
|
|
39
|
+
// Windows retains the original parent PID after its process exits. A missing
|
|
40
|
+
// or reused parent above a live Claude is a process-tree boundary, not proof
|
|
41
|
+
// that Claude itself is gone. Never cross a reused PID into another tree.
|
|
42
|
+
if (!entry || (process.platform === "win32" && entry.startedAt > childStartedAt)) {
|
|
43
|
+
if (process.platform === "win32" && claudePid) break;
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
if (process.platform === "win32") childStartedAt = entry.startedAt;
|
|
39
47
|
if (["claude", "codex", "trae", "traex", "traecli", "pi"].includes(entry.command)) {
|
|
40
48
|
if (claudePid || entry.command !== "claude") return null;
|
|
41
49
|
claudePid = pid;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.2.0+codex.
|
|
1
|
+
{"version":"0.2.0+codex.1f41dea1d1860e2c0375919eb2d9f67bb26d58c31ef3f505300b96f5d3011d1c","digest":"1f41dea1d1860e2c0375919eb2d9f67bb26d58c31ef3f505300b96f5d3011d1c"}
|
|
@@ -14611,27 +14611,49 @@ function assertWindowsPrivatePath(file) {
|
|
|
14611
14611
|
if (process.platform !== "win32") return;
|
|
14612
14612
|
const script = `
|
|
14613
14613
|
$ErrorActionPreference = 'Stop'
|
|
14614
|
+
try {
|
|
14614
14615
|
# Use .NET directly: a parent pwsh may export a PSModulePath incompatible with Windows PowerShell.
|
|
14615
14616
|
$acl = if ([IO.Directory]::Exists($env:RUNWEAVE_PRIVATE_PATH)) {
|
|
14616
14617
|
[IO.Directory]::GetAccessControl($env:RUNWEAVE_PRIVATE_PATH)
|
|
14617
14618
|
} else { [IO.File]::GetAccessControl($env:RUNWEAVE_PRIVATE_PATH) }
|
|
14618
14619
|
$sid = [Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
14619
14620
|
$allowed = @($sid.Value, 'S-1-5-18', 'S-1-5-32-544')
|
|
14620
|
-
if ($acl.GetOwner([Security.Principal.SecurityIdentifier]).Value -notin $allowed) {
|
|
14621
|
+
if ($acl.GetOwner([Security.Principal.SecurityIdentifier]).Value -notin $allowed) { [Console]::Write('owner'); exit 0 }
|
|
14621
14622
|
foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
|
|
14622
|
-
if ($rule.AccessControlType -eq 'Allow' -and $rule.IdentityReference.Value -notin $allowed) {
|
|
14623
|
+
if ($rule.AccessControlType -eq 'Allow' -and $rule.IdentityReference.Value -notin $allowed) { [Console]::Write('access'); exit 0 }
|
|
14624
|
+
}
|
|
14625
|
+
[Console]::Write('private')
|
|
14626
|
+
} catch {
|
|
14627
|
+
[Console]::Write('check-failed:' + $_.Exception.GetType().FullName + ':' + $_.Exception.HResult)
|
|
14623
14628
|
}
|
|
14624
14629
|
`;
|
|
14630
|
+
const startedAt = performance.now();
|
|
14631
|
+
let result;
|
|
14625
14632
|
try {
|
|
14626
|
-
(0, import_node_child_process.execFileSync)("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")], {
|
|
14633
|
+
result = (0, import_node_child_process.execFileSync)("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")], {
|
|
14627
14634
|
env: { ...process.env, RUNWEAVE_PRIVATE_PATH: file },
|
|
14628
|
-
stdio: "ignore",
|
|
14635
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
14636
|
+
encoding: "utf8",
|
|
14637
|
+
maxBuffer: 64 * 1024,
|
|
14629
14638
|
timeout: 1e4,
|
|
14630
14639
|
windowsHide: true
|
|
14631
|
-
});
|
|
14632
|
-
} catch {
|
|
14633
|
-
|
|
14640
|
+
}).trim();
|
|
14641
|
+
} catch (cause) {
|
|
14642
|
+
const error = cause;
|
|
14643
|
+
throw new ConfigurationError(
|
|
14644
|
+
error.code === "ETIMEDOUT" ? "CONFIG_WINDOWS_ACL_CHECK_TIMEOUT" : "CONFIG_WINDOWS_ACL_CHECK_FAILED",
|
|
14645
|
+
[
|
|
14646
|
+
file,
|
|
14647
|
+
`exit=${error.status ?? "none"}`,
|
|
14648
|
+
`signal=${error.signal ?? "none"}`,
|
|
14649
|
+
`code=${error.code ?? "none"}`,
|
|
14650
|
+
`elapsedMs=${Math.round(performance.now() - startedAt)}`
|
|
14651
|
+
]
|
|
14652
|
+
);
|
|
14634
14653
|
}
|
|
14654
|
+
if (result === "owner" || result === "access") throw new ConfigurationError("CONFIG_WINDOWS_ACL_NOT_PRIVATE", [file, result]);
|
|
14655
|
+
if (/^check-failed:[A-Za-z0-9_.]+:-?\d+$/.test(result)) throw new ConfigurationError("CONFIG_WINDOWS_ACL_CHECK_FAILED", [file, result]);
|
|
14656
|
+
if (result !== "private") throw new ConfigurationError("CONFIG_WINDOWS_ACL_CHECK_FAILED", [file, "invalid-result"]);
|
|
14635
14657
|
}
|
|
14636
14658
|
|
|
14637
14659
|
// packages/config-node/src/private-file.ts
|
|
@@ -19669,8 +19691,14 @@ var TerminalOutputScreen = class _TerminalOutputScreen {
|
|
|
19669
19691
|
if (this.disposed) return;
|
|
19670
19692
|
this.pendingBytes += frame.range.toOffset - frame.range.fromOffset;
|
|
19671
19693
|
if (this.pendingBytes > RESUME_MAX_BYTES || this.queue.length >= 8192) {
|
|
19694
|
+
const failure = {
|
|
19695
|
+
code: this.pendingBytes > RESUME_MAX_BYTES ? "HOST_MIRROR_PENDING_LIMIT" : "HOST_MIRROR_QUEUE_LIMIT",
|
|
19696
|
+
bufferedBytes: this.pendingBytes,
|
|
19697
|
+
limitBytes: RESUME_MAX_BYTES,
|
|
19698
|
+
queuedOperations: this.queue.length
|
|
19699
|
+
};
|
|
19672
19700
|
this.dispose();
|
|
19673
|
-
this.onFailure();
|
|
19701
|
+
this.onFailure(failure);
|
|
19674
19702
|
return;
|
|
19675
19703
|
}
|
|
19676
19704
|
this.queue.push({ frame });
|
|
@@ -19775,8 +19803,14 @@ var TerminalOutputScreen = class _TerminalOutputScreen {
|
|
|
19775
19803
|
this.writing = false;
|
|
19776
19804
|
this.partialControlBytes = screenParserIsIdle(this.terminal) ? 0 : this.partialControlBytes + frame.range.toOffset - frame.range.fromOffset;
|
|
19777
19805
|
if (this.partialControlBytes > RESUME_MAX_BYTES) {
|
|
19806
|
+
const failure = {
|
|
19807
|
+
code: "HOST_MIRROR_CONTROL_LIMIT",
|
|
19808
|
+
bufferedBytes: this.partialControlBytes,
|
|
19809
|
+
limitBytes: RESUME_MAX_BYTES,
|
|
19810
|
+
queuedOperations: this.queue.length
|
|
19811
|
+
};
|
|
19778
19812
|
this.dispose();
|
|
19779
|
-
this.onFailure();
|
|
19813
|
+
this.onFailure(failure);
|
|
19780
19814
|
return;
|
|
19781
19815
|
}
|
|
19782
19816
|
this.completeSnapshot?.();
|
|
@@ -19794,6 +19828,43 @@ var TERMINAL_LIVE_SCROLLBACK_BYTES = 512 * 1024;
|
|
|
19794
19828
|
var TERMINAL_COMPACTED_SCROLLBACK_BYTES = 8 * 1024 * 1024;
|
|
19795
19829
|
var TERMINAL_PERSISTED_SCROLLBACK_BYTES = 10 * 1024 * 1024;
|
|
19796
19830
|
|
|
19831
|
+
// packages/pty-host/src/diagnostics.ts
|
|
19832
|
+
function hostErrorCode(error) {
|
|
19833
|
+
if (!(error instanceof Error)) return "HOST_OPERATION_FAILED";
|
|
19834
|
+
const code = error.code;
|
|
19835
|
+
if (code && /^(?:E[A-Z0-9_]+|HOST_[A-Z0-9_]+)$/.test(code)) return code;
|
|
19836
|
+
return /^HOST_[A-Z0-9_]+$/.test(error.message) ? error.message : "HOST_OPERATION_FAILED";
|
|
19837
|
+
}
|
|
19838
|
+
var actions = /* @__PURE__ */ new Set([
|
|
19839
|
+
"hello",
|
|
19840
|
+
"claimWriter",
|
|
19841
|
+
"listSessions",
|
|
19842
|
+
"createSession",
|
|
19843
|
+
"setUpstreams",
|
|
19844
|
+
"freeze",
|
|
19845
|
+
"stop",
|
|
19846
|
+
"writeInput",
|
|
19847
|
+
"getInputOperation",
|
|
19848
|
+
"getSnapshot",
|
|
19849
|
+
"readOutput",
|
|
19850
|
+
"resize",
|
|
19851
|
+
"signal",
|
|
19852
|
+
"closeSession",
|
|
19853
|
+
"attachSession"
|
|
19854
|
+
]);
|
|
19855
|
+
function diagnosticAction(action) {
|
|
19856
|
+
return actions.has(action) ? action : "unknown";
|
|
19857
|
+
}
|
|
19858
|
+
function writeHostDiagnostic(diagnostic) {
|
|
19859
|
+
process.stderr.write(JSON.stringify({ timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...diagnostic }) + "\n");
|
|
19860
|
+
}
|
|
19861
|
+
function reportHostDiagnostic(sink, diagnostic) {
|
|
19862
|
+
try {
|
|
19863
|
+
sink(diagnostic);
|
|
19864
|
+
} catch {
|
|
19865
|
+
}
|
|
19866
|
+
}
|
|
19867
|
+
|
|
19797
19868
|
// packages/pty-host/src/sessions.ts
|
|
19798
19869
|
var requireNative = (0, import_node_module.createRequire)((0, import_node_url.fileURLToPath)(__IMPORT_META_URL__));
|
|
19799
19870
|
var HostSession = class {
|
|
@@ -19813,8 +19884,14 @@ var HostSession = class {
|
|
|
19813
19884
|
rows: options.rows,
|
|
19814
19885
|
nextSequence: 1
|
|
19815
19886
|
};
|
|
19816
|
-
this.screen = new TerminalOutputScreen(this.buffer.cursor, () => {
|
|
19887
|
+
this.screen = new TerminalOutputScreen(this.buffer.cursor, (failure) => {
|
|
19817
19888
|
this.degraded = true;
|
|
19889
|
+
reportHostDiagnostic(writeHostDiagnostic, {
|
|
19890
|
+
event: "pty-host.mirror.failed",
|
|
19891
|
+
hostInstanceId,
|
|
19892
|
+
terminalSessionId: options.terminalSessionId,
|
|
19893
|
+
...failure
|
|
19894
|
+
});
|
|
19818
19895
|
}, TERMINAL_CLIENT_SCROLLBACK_LINES);
|
|
19819
19896
|
this.screen.resize(options.cols, options.rows);
|
|
19820
19897
|
this.inputs = new InputOperations((data) => this.terminal.write(data), () => this.info.status === "running", () => this.processGeneration);
|
|
@@ -19943,12 +20020,20 @@ var HostSession = class {
|
|
|
19943
20020
|
};
|
|
19944
20021
|
|
|
19945
20022
|
// packages/pty-host/src/transport.ts
|
|
20023
|
+
var HostTransportError = class extends Error {
|
|
20024
|
+
constructor(code, bufferedBytes, limitBytes = 4 * 1024 * 1024) {
|
|
20025
|
+
super(code);
|
|
20026
|
+
this.code = code;
|
|
20027
|
+
this.bufferedBytes = bufferedBytes;
|
|
20028
|
+
this.limitBytes = limitBytes;
|
|
20029
|
+
}
|
|
20030
|
+
};
|
|
19946
20031
|
function receiveJsonLines(socket, onMessage) {
|
|
19947
20032
|
let source = "";
|
|
19948
20033
|
socket.setEncoding("utf8");
|
|
19949
20034
|
socket.on("data", (data) => {
|
|
19950
20035
|
source += data;
|
|
19951
|
-
if (Buffer.byteLength(source) > 4 * 1024 * 1024) return socket.destroy(new
|
|
20036
|
+
if (Buffer.byteLength(source) > 4 * 1024 * 1024) return socket.destroy(new HostTransportError("HOST_MESSAGE_TOO_LARGE", Buffer.byteLength(source)));
|
|
19952
20037
|
let end;
|
|
19953
20038
|
while ((end = source.indexOf("\n")) !== -1) {
|
|
19954
20039
|
const line = source.slice(0, end);
|
|
@@ -19965,7 +20050,7 @@ function receiveJsonLines(socket, onMessage) {
|
|
|
19965
20050
|
function sendJson(socket, message) {
|
|
19966
20051
|
if (socket.destroyed) return false;
|
|
19967
20052
|
if (socket.writableLength > 4 * 1024 * 1024) {
|
|
19968
|
-
socket.destroy(new
|
|
20053
|
+
socket.destroy(new HostTransportError("HOST_OUTPUT_GAP", socket.writableLength));
|
|
19969
20054
|
return false;
|
|
19970
20055
|
}
|
|
19971
20056
|
socket.write(JSON.stringify(message) + "\n");
|
|
@@ -20030,10 +20115,21 @@ async function startHost(scope, release) {
|
|
|
20030
20115
|
};
|
|
20031
20116
|
const server = (0, import_node_net.createServer)((socket) => {
|
|
20032
20117
|
sockets.add(socket);
|
|
20033
|
-
|
|
20118
|
+
const connectionId = (0, import_node_crypto7.randomUUID)();
|
|
20119
|
+
let socketError;
|
|
20120
|
+
socket.on("error", (error) => {
|
|
20121
|
+
socketError = error;
|
|
20034
20122
|
});
|
|
20035
20123
|
const subscriptions = /* @__PURE__ */ new Map();
|
|
20036
20124
|
socket.on("close", () => {
|
|
20125
|
+
reportHostDiagnostic(writeHostDiagnostic, {
|
|
20126
|
+
event: "pty-host.connection.closed",
|
|
20127
|
+
hostInstanceId,
|
|
20128
|
+
connectionId,
|
|
20129
|
+
code: socketError ? hostErrorCode(socketError) : "HOST_PEER_CLOSED",
|
|
20130
|
+
writableBytes: socket.writableLength,
|
|
20131
|
+
...socketError instanceof HostTransportError ? { bufferedBytes: socketError.bufferedBytes, limitBytes: socketError.limitBytes } : {}
|
|
20132
|
+
});
|
|
20037
20133
|
sockets.delete(socket);
|
|
20038
20134
|
for (const unsubscribe of subscriptions.values()) unsubscribe();
|
|
20039
20135
|
});
|
|
@@ -20044,11 +20140,24 @@ async function startHost(scope, release) {
|
|
|
20044
20140
|
return;
|
|
20045
20141
|
}
|
|
20046
20142
|
const request = parsed.data;
|
|
20143
|
+
const startedAt = performance.now();
|
|
20047
20144
|
const reply = (result) => sendJson(socket, { requestId: request.requestId, result });
|
|
20048
|
-
const fail = (error) =>
|
|
20049
|
-
|
|
20050
|
-
|
|
20051
|
-
|
|
20145
|
+
const fail = (error) => {
|
|
20146
|
+
reportHostDiagnostic(writeHostDiagnostic, {
|
|
20147
|
+
event: "pty-host.request.failed",
|
|
20148
|
+
hostInstanceId,
|
|
20149
|
+
connectionId,
|
|
20150
|
+
requestId: request.requestId,
|
|
20151
|
+
action: diagnosticAction(request.action),
|
|
20152
|
+
code: error instanceof external_exports.ZodError ? "HOST_MESSAGE_INVALID" : hostErrorCode(error),
|
|
20153
|
+
elapsedMs: Math.round(performance.now() - startedAt),
|
|
20154
|
+
writableBytes: socket.writableLength
|
|
20155
|
+
});
|
|
20156
|
+
return sendJson(socket, {
|
|
20157
|
+
requestId: request.requestId,
|
|
20158
|
+
error: error instanceof external_exports.ZodError ? "HOST_MESSAGE_INVALID" : error.message
|
|
20159
|
+
});
|
|
20160
|
+
};
|
|
20052
20161
|
if (!isGatewayCredential(request.token, token)) {
|
|
20053
20162
|
fail(new Error("HOST_AUTH_FAILED"));
|
|
20054
20163
|
socket.end();
|
package/payload/server/index.cjs
CHANGED
|
@@ -7354,27 +7354,49 @@ function assertWindowsPrivatePath(file) {
|
|
|
7354
7354
|
if (process.platform !== "win32") return;
|
|
7355
7355
|
const script = `
|
|
7356
7356
|
$ErrorActionPreference = 'Stop'
|
|
7357
|
+
try {
|
|
7357
7358
|
# Use .NET directly: a parent pwsh may export a PSModulePath incompatible with Windows PowerShell.
|
|
7358
7359
|
$acl = if ([IO.Directory]::Exists($env:RUNWEAVE_PRIVATE_PATH)) {
|
|
7359
7360
|
[IO.Directory]::GetAccessControl($env:RUNWEAVE_PRIVATE_PATH)
|
|
7360
7361
|
} else { [IO.File]::GetAccessControl($env:RUNWEAVE_PRIVATE_PATH) }
|
|
7361
7362
|
$sid = [Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
7362
7363
|
$allowed = @($sid.Value, 'S-1-5-18', 'S-1-5-32-544')
|
|
7363
|
-
if ($acl.GetOwner([Security.Principal.SecurityIdentifier]).Value -notin $allowed) {
|
|
7364
|
+
if ($acl.GetOwner([Security.Principal.SecurityIdentifier]).Value -notin $allowed) { [Console]::Write('owner'); exit 0 }
|
|
7364
7365
|
foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
|
|
7365
|
-
if ($rule.AccessControlType -eq 'Allow' -and $rule.IdentityReference.Value -notin $allowed) {
|
|
7366
|
+
if ($rule.AccessControlType -eq 'Allow' -and $rule.IdentityReference.Value -notin $allowed) { [Console]::Write('access'); exit 0 }
|
|
7367
|
+
}
|
|
7368
|
+
[Console]::Write('private')
|
|
7369
|
+
} catch {
|
|
7370
|
+
[Console]::Write('check-failed:' + $_.Exception.GetType().FullName + ':' + $_.Exception.HResult)
|
|
7366
7371
|
}
|
|
7367
7372
|
`;
|
|
7373
|
+
const startedAt = performance.now();
|
|
7374
|
+
let result;
|
|
7368
7375
|
try {
|
|
7369
|
-
(0, import_node_child_process.execFileSync)("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")], {
|
|
7376
|
+
result = (0, import_node_child_process.execFileSync)("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(script, "utf16le").toString("base64")], {
|
|
7370
7377
|
env: { ...process.env, RUNWEAVE_PRIVATE_PATH: file },
|
|
7371
|
-
stdio: "ignore",
|
|
7378
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
7379
|
+
encoding: "utf8",
|
|
7380
|
+
maxBuffer: 64 * 1024,
|
|
7372
7381
|
timeout: 1e4,
|
|
7373
7382
|
windowsHide: true
|
|
7374
|
-
});
|
|
7375
|
-
} catch {
|
|
7376
|
-
|
|
7383
|
+
}).trim();
|
|
7384
|
+
} catch (cause) {
|
|
7385
|
+
const error = cause;
|
|
7386
|
+
throw new ConfigurationError(
|
|
7387
|
+
error.code === "ETIMEDOUT" ? "CONFIG_WINDOWS_ACL_CHECK_TIMEOUT" : "CONFIG_WINDOWS_ACL_CHECK_FAILED",
|
|
7388
|
+
[
|
|
7389
|
+
file,
|
|
7390
|
+
`exit=${error.status ?? "none"}`,
|
|
7391
|
+
`signal=${error.signal ?? "none"}`,
|
|
7392
|
+
`code=${error.code ?? "none"}`,
|
|
7393
|
+
`elapsedMs=${Math.round(performance.now() - startedAt)}`
|
|
7394
|
+
]
|
|
7395
|
+
);
|
|
7377
7396
|
}
|
|
7397
|
+
if (result === "owner" || result === "access") throw new ConfigurationError("CONFIG_WINDOWS_ACL_NOT_PRIVATE", [file, result]);
|
|
7398
|
+
if (/^check-failed:[A-Za-z0-9_.]+:-?\d+$/.test(result)) throw new ConfigurationError("CONFIG_WINDOWS_ACL_CHECK_FAILED", [file, result]);
|
|
7399
|
+
if (result !== "private") throw new ConfigurationError("CONFIG_WINDOWS_ACL_CHECK_FAILED", [file, "invalid-result"]);
|
|
7378
7400
|
}
|
|
7379
7401
|
|
|
7380
7402
|
// packages/config-node/src/private-file.ts
|