switchroom 0.18.12 → 0.18.13
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/agent-scheduler/index.js +8 -0
- package/dist/auth-broker/index.js +63 -65
- package/dist/cli/ms-365-write-pretool.mjs +31 -8
- package/dist/cli/notion-write-pretool.mjs +9 -1
- package/dist/cli/skill-validate-pretool.mjs +144 -2847
- package/dist/cli/switchroom.js +952 -3126
- package/dist/host-control/main.js +216 -2862
- package/dist/vault/approvals/kernel-server.js +67 -0
- package/dist/vault/broker/server.js +98 -44
- package/package.json +1 -1
- package/telegram-plugin/dist/bridge/bridge.js +49 -3
- package/telegram-plugin/dist/gateway/gateway.js +656 -2326
- package/telegram-plugin/dist/server.js +65 -3
- package/telegram-plugin/format.ts +19 -0
- package/telegram-plugin/gateway/approval-hold.ts +21 -2
- package/telegram-plugin/gateway/callback-query-handlers.ts +12 -0
- package/telegram-plugin/gateway/gateway.ts +221 -73
- package/telegram-plugin/history.ts +51 -0
- package/telegram-plugin/inline-keyboard-callbacks.ts +94 -0
- package/telegram-plugin/model-unavailable.ts +41 -11
- package/telegram-plugin/outbound-field-redact.ts +69 -0
- package/telegram-plugin/render/render.ts +32 -14
- package/telegram-plugin/scoped-approval.ts +11 -2
- package/telegram-plugin/secret-detect/chunker.ts +18 -4
- package/telegram-plugin/secret-detect/index.ts +12 -56
- package/telegram-plugin/send-gate-degraded.test.ts +131 -0
- package/telegram-plugin/send-gate.test.ts +25 -6
- package/telegram-plugin/send-gate.ts +82 -8
- package/telegram-plugin/session-tail.ts +82 -7
- package/telegram-plugin/subagent-watcher.ts +71 -16
- package/telegram-plugin/tests/approval-hold-outcome.test.ts +36 -5
- package/telegram-plugin/tests/callback-query-handlers.test.ts +65 -0
- package/telegram-plugin/tests/gateway-outbound-redact.test.ts +57 -0
- package/telegram-plugin/tests/history.test.ts +115 -0
- package/telegram-plugin/tests/inbound-message-types.test.ts +5 -1
- package/telegram-plugin/tests/inline-keyboard-callbacks.test.ts +164 -0
- package/telegram-plugin/tests/operator-events-session-tail.test.ts +74 -0
- package/telegram-plugin/tests/outbound-field-redact.test.ts +107 -0
- package/telegram-plugin/tests/reaction-gate-routing.test.ts +173 -0
- package/telegram-plugin/tests/render/render.test.ts +88 -0
- package/telegram-plugin/tests/scoped-approval.test.ts +27 -0
- package/telegram-plugin/tests/secret-detect-chunk-overlap.test.ts +65 -0
- package/telegram-plugin/tests/secret-detect-oauth-code.test.ts +5 -4
- package/telegram-plugin/tests/session-tail-sidecar-reap.test.ts +268 -0
- package/telegram-plugin/tests/subagent-watcher-fd-leak.test.ts +275 -0
- package/telegram-plugin/tests/worktree-watch-cwds.test.ts +215 -1
- package/telegram-plugin/worktree-watch-cwds.ts +194 -5
- package/telegram-plugin/secret-detect/secretlint-source.ts +0 -95
- package/telegram-plugin/tests/secret-detect-secretlint.test.ts +0 -105
|
@@ -4778,6 +4778,13 @@ var init_schema = __esm(() => {
|
|
|
4778
4778
|
});
|
|
4779
4779
|
});
|
|
4780
4780
|
|
|
4781
|
+
// src/util/atomic.ts
|
|
4782
|
+
import { closeSync, constants, fsyncSync, openSync, renameSync, rmSync, writeSync } from "node:fs";
|
|
4783
|
+
var TMP_OPEN_FLAGS;
|
|
4784
|
+
var init_atomic = __esm(() => {
|
|
4785
|
+
TMP_OPEN_FLAGS = constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0);
|
|
4786
|
+
});
|
|
4787
|
+
|
|
4781
4788
|
// src/config/merge.ts
|
|
4782
4789
|
function dedupe(items) {
|
|
4783
4790
|
const seen = new Set;
|
|
@@ -18249,6 +18256,13 @@ var ApprovalLookupRequestSchema = exports_external.object({
|
|
|
18249
18256
|
action: exports_external.string().min(1),
|
|
18250
18257
|
current_approver_set: exports_external.array(exports_external.string())
|
|
18251
18258
|
});
|
|
18259
|
+
var ApprovalLookupByRequestRequestSchema = exports_external.object({
|
|
18260
|
+
v: exports_external.literal(1),
|
|
18261
|
+
op: exports_external.literal("approval_lookup_by_request"),
|
|
18262
|
+
agent_unit: exports_external.string().min(1),
|
|
18263
|
+
request_id: exports_external.string().regex(/^[0-9a-f]{32}$/),
|
|
18264
|
+
current_approver_set: exports_external.array(exports_external.string())
|
|
18265
|
+
});
|
|
18252
18266
|
var ApprovalConsumeRequestSchema = exports_external.object({
|
|
18253
18267
|
v: exports_external.literal(1),
|
|
18254
18268
|
op: exports_external.literal("approval_consume"),
|
|
@@ -18303,6 +18317,7 @@ var RequestSchema = exports_external.discriminatedUnion("op", [
|
|
|
18303
18317
|
RevokeGrantRequestSchema,
|
|
18304
18318
|
ApprovalRequestRequestSchema,
|
|
18305
18319
|
ApprovalLookupRequestSchema,
|
|
18320
|
+
ApprovalLookupByRequestRequestSchema,
|
|
18306
18321
|
ApprovalConsumeRequestSchema,
|
|
18307
18322
|
ApprovalRevokeRequestSchema,
|
|
18308
18323
|
ApprovalListRequestSchema,
|
|
@@ -18664,6 +18679,30 @@ function lookupDecision(db, query, opts = {}, now = Date.now()) {
|
|
|
18664
18679
|
ORDER BY granted_at DESC LIMIT 1`).get(query.agent_unit, query.scope, query.action);
|
|
18665
18680
|
if (!row)
|
|
18666
18681
|
return { state: "no_decision" };
|
|
18682
|
+
return evaluateDecisionRow(db, row, currentCanonical, opts, now);
|
|
18683
|
+
}
|
|
18684
|
+
function lookupDecisionByRequestId(db, query, opts = {}, now = Date.now()) {
|
|
18685
|
+
const currentCanonical = canonicalizeApproverSet(query.current_approver_set);
|
|
18686
|
+
const nonceRow = db.query(`SELECT * FROM approval_nonces WHERE request_id = ?`).get(query.request_id);
|
|
18687
|
+
if (!nonceRow)
|
|
18688
|
+
return { state: "no_decision" };
|
|
18689
|
+
const nonce = nonceFromRow(nonceRow);
|
|
18690
|
+
if (nonce.agent_unit !== query.agent_unit)
|
|
18691
|
+
return { state: "no_decision" };
|
|
18692
|
+
if (nonce.decision_id === null) {
|
|
18693
|
+
if (nonce.expires_at < now)
|
|
18694
|
+
return { state: "expired" };
|
|
18695
|
+
return { state: "pending", request_id: nonce.request_id };
|
|
18696
|
+
}
|
|
18697
|
+
const decRow = db.query(`SELECT * FROM approval_decisions WHERE id = ?`).get(nonce.decision_id);
|
|
18698
|
+
if (!decRow)
|
|
18699
|
+
return { state: "expired" };
|
|
18700
|
+
if (decRow.revoked_at != null) {
|
|
18701
|
+
return { state: "denied", decision: rowToDecision(decRow) };
|
|
18702
|
+
}
|
|
18703
|
+
return evaluateDecisionRow(db, decRow, currentCanonical, opts, now);
|
|
18704
|
+
}
|
|
18705
|
+
function evaluateDecisionRow(db, row, currentCanonical, opts, now) {
|
|
18667
18706
|
const decision = rowToDecision(row);
|
|
18668
18707
|
if (decision.decision === "deny_perm") {
|
|
18669
18708
|
return { state: "denied", decision };
|
|
@@ -18860,6 +18899,7 @@ init_schema();
|
|
|
18860
18899
|
|
|
18861
18900
|
// src/agents/scaffold.ts
|
|
18862
18901
|
import { join as join4, resolve as resolve5 } from "node:path";
|
|
18902
|
+
init_atomic();
|
|
18863
18903
|
init_schema();
|
|
18864
18904
|
|
|
18865
18905
|
// src/config/users.ts
|
|
@@ -19301,6 +19341,33 @@ function handleRequest(socket, req, agent, db, peerUid, isOperator = false) {
|
|
|
19301
19341
|
socket.write(encodeResponse({ ok: true, state: r.state, decision }));
|
|
19302
19342
|
return;
|
|
19303
19343
|
}
|
|
19344
|
+
if (req.op === "approval_lookup_by_request") {
|
|
19345
|
+
const acl = checkApprovalAclByAgent(agent, req.agent_unit);
|
|
19346
|
+
if (!acl.allow) {
|
|
19347
|
+
socket.write(encodeResponse(errorResponse("DENIED", acl.reason)));
|
|
19348
|
+
return;
|
|
19349
|
+
}
|
|
19350
|
+
const r = lookupDecisionByRequestId(db, {
|
|
19351
|
+
agent_unit: req.agent_unit,
|
|
19352
|
+
request_id: req.request_id,
|
|
19353
|
+
current_approver_set: req.current_approver_set
|
|
19354
|
+
});
|
|
19355
|
+
const decision = r.state === "granted" || r.state === "denied" ? {
|
|
19356
|
+
id: r.decision.id,
|
|
19357
|
+
agent_unit: r.decision.agent_unit,
|
|
19358
|
+
scope: r.decision.scope,
|
|
19359
|
+
action: r.decision.action,
|
|
19360
|
+
decision: r.decision.decision,
|
|
19361
|
+
granted_at: r.decision.granted_at,
|
|
19362
|
+
granted_by_user_id: r.decision.granted_by_user_id,
|
|
19363
|
+
ttl_expires_at: r.decision.ttl_expires_at,
|
|
19364
|
+
last_used_at: r.decision.last_used_at,
|
|
19365
|
+
revoked_at: r.decision.revoked_at,
|
|
19366
|
+
revoke_reason: r.decision.revoke_reason
|
|
19367
|
+
} : null;
|
|
19368
|
+
socket.write(encodeResponse({ ok: true, state: r.state, decision }));
|
|
19369
|
+
return;
|
|
19370
|
+
}
|
|
19304
19371
|
if (req.op === "approval_consume") {
|
|
19305
19372
|
const peek = getNonce(db, req.request_id);
|
|
19306
19373
|
if (peek !== null) {
|
|
@@ -4778,6 +4778,13 @@ var init_schema = __esm(() => {
|
|
|
4778
4778
|
});
|
|
4779
4779
|
});
|
|
4780
4780
|
|
|
4781
|
+
// src/util/atomic.ts
|
|
4782
|
+
import { closeSync, constants, fsyncSync, openSync, renameSync, rmSync, writeSync } from "node:fs";
|
|
4783
|
+
var TMP_OPEN_FLAGS;
|
|
4784
|
+
var init_atomic = __esm(() => {
|
|
4785
|
+
TMP_OPEN_FLAGS = constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0);
|
|
4786
|
+
});
|
|
4787
|
+
|
|
4781
4788
|
// src/config/merge.ts
|
|
4782
4789
|
function dedupe(items) {
|
|
4783
4790
|
const seen = new Set;
|
|
@@ -18087,7 +18094,7 @@ var require_lib = __commonJS((exports, module) => {
|
|
|
18087
18094
|
|
|
18088
18095
|
// src/vault/broker/server.ts
|
|
18089
18096
|
import * as net from "node:net";
|
|
18090
|
-
import { mkdirSync as mkdirSync6, chmodSync as chmodSync4, chownSync, existsSync as existsSync11, readFileSync as readFileSync10, readdirSync as readdirSync4, statSync as statSync6, unlinkSync as unlinkSync6, writeFileSync as writeFileSync3, renameSync as
|
|
18097
|
+
import { mkdirSync as mkdirSync6, chmodSync as chmodSync4, chownSync, existsSync as existsSync11, readFileSync as readFileSync10, readdirSync as readdirSync4, statSync as statSync6, unlinkSync as unlinkSync6, writeFileSync as writeFileSync3, renameSync as renameSync7 } from "node:fs";
|
|
18091
18098
|
|
|
18092
18099
|
// src/agents/compose.ts
|
|
18093
18100
|
import { createHash } from "node:crypto";
|
|
@@ -18095,6 +18102,7 @@ init_schema();
|
|
|
18095
18102
|
|
|
18096
18103
|
// src/agents/scaffold.ts
|
|
18097
18104
|
import { join as join4, resolve as resolve6 } from "node:path";
|
|
18105
|
+
init_atomic();
|
|
18098
18106
|
init_schema();
|
|
18099
18107
|
|
|
18100
18108
|
// src/config/users.ts
|
|
@@ -18424,14 +18432,14 @@ init_loader();
|
|
|
18424
18432
|
import { randomBytes, scryptSync, createCipheriv, createDecipheriv } from "node:crypto";
|
|
18425
18433
|
import {
|
|
18426
18434
|
readFileSync as readFileSync5,
|
|
18427
|
-
writeSync as
|
|
18435
|
+
writeSync as writeSync3,
|
|
18428
18436
|
existsSync as existsSync6,
|
|
18429
|
-
renameSync,
|
|
18437
|
+
renameSync as renameSync2,
|
|
18430
18438
|
mkdirSync as mkdirSync2,
|
|
18431
18439
|
unlinkSync as unlinkSync2,
|
|
18432
|
-
fsyncSync as
|
|
18433
|
-
openSync as
|
|
18434
|
-
closeSync as
|
|
18440
|
+
fsyncSync as fsyncSync3,
|
|
18441
|
+
openSync as openSync3,
|
|
18442
|
+
closeSync as closeSync3,
|
|
18435
18443
|
lstatSync,
|
|
18436
18444
|
realpathSync as realpathSync2
|
|
18437
18445
|
} from "node:fs";
|
|
@@ -18440,10 +18448,10 @@ import { dirname, basename as basename2, resolve as resolve5 } from "node:path";
|
|
|
18440
18448
|
// src/vault/flock.ts
|
|
18441
18449
|
import {
|
|
18442
18450
|
existsSync as existsSync5,
|
|
18443
|
-
openSync,
|
|
18444
|
-
closeSync,
|
|
18445
|
-
writeSync,
|
|
18446
|
-
fsyncSync,
|
|
18451
|
+
openSync as openSync2,
|
|
18452
|
+
closeSync as closeSync2,
|
|
18453
|
+
writeSync as writeSync2,
|
|
18454
|
+
fsyncSync as fsyncSync2,
|
|
18447
18455
|
unlinkSync,
|
|
18448
18456
|
readFileSync as readFileSync4,
|
|
18449
18457
|
readdirSync as readdirSync3,
|
|
@@ -18568,7 +18576,7 @@ function acquireLock(vaultPath, options = {}) {
|
|
|
18568
18576
|
while (true) {
|
|
18569
18577
|
let fd = null;
|
|
18570
18578
|
try {
|
|
18571
|
-
fd =
|
|
18579
|
+
fd = openSync2(lockPath, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, 384);
|
|
18572
18580
|
} catch (err) {
|
|
18573
18581
|
const code = err?.code ?? "";
|
|
18574
18582
|
if (code === "EEXIST") {
|
|
@@ -18604,11 +18612,11 @@ function acquireLock(vaultPath, options = {}) {
|
|
|
18604
18612
|
${Date.now()}
|
|
18605
18613
|
${process.argv[1] ?? ""}
|
|
18606
18614
|
`;
|
|
18607
|
-
|
|
18608
|
-
|
|
18615
|
+
writeSync2(fd, meta);
|
|
18616
|
+
fsyncSync2(fd);
|
|
18609
18617
|
} catch {
|
|
18610
18618
|
try {
|
|
18611
|
-
|
|
18619
|
+
closeSync2(fd);
|
|
18612
18620
|
} catch {}
|
|
18613
18621
|
try {
|
|
18614
18622
|
unlinkSync(lockPath);
|
|
@@ -18619,7 +18627,7 @@ ${process.argv[1] ?? ""}
|
|
|
18619
18627
|
return {
|
|
18620
18628
|
release: () => {
|
|
18621
18629
|
try {
|
|
18622
|
-
|
|
18630
|
+
closeSync2(ownedFd);
|
|
18623
18631
|
} catch {}
|
|
18624
18632
|
try {
|
|
18625
18633
|
unlinkSync(lockPath);
|
|
@@ -18675,20 +18683,20 @@ function atomicWriteFileSync(path, data, mode) {
|
|
|
18675
18683
|
const dir = dirname(resolve5(effectivePath));
|
|
18676
18684
|
const tmp = resolve5(dir, `.${basename2(effectivePath)}.${process.pid}.${Date.now()}.tmp`);
|
|
18677
18685
|
try {
|
|
18678
|
-
const fd =
|
|
18686
|
+
const fd = openSync3(tmp, "wx", mode);
|
|
18679
18687
|
try {
|
|
18680
|
-
|
|
18681
|
-
|
|
18688
|
+
writeSync3(fd, data);
|
|
18689
|
+
fsyncSync3(fd);
|
|
18682
18690
|
} finally {
|
|
18683
|
-
|
|
18691
|
+
closeSync3(fd);
|
|
18684
18692
|
}
|
|
18685
|
-
|
|
18693
|
+
renameSync2(tmp, effectivePath);
|
|
18686
18694
|
try {
|
|
18687
|
-
const dirFd =
|
|
18695
|
+
const dirFd = openSync3(dir, "r");
|
|
18688
18696
|
try {
|
|
18689
|
-
|
|
18697
|
+
fsyncSync3(dirFd);
|
|
18690
18698
|
} finally {
|
|
18691
|
-
|
|
18699
|
+
closeSync3(dirFd);
|
|
18692
18700
|
}
|
|
18693
18701
|
} catch {}
|
|
18694
18702
|
} catch (err) {
|
|
@@ -19264,6 +19272,13 @@ var ApprovalLookupRequestSchema = exports_external.object({
|
|
|
19264
19272
|
action: exports_external.string().min(1),
|
|
19265
19273
|
current_approver_set: exports_external.array(exports_external.string())
|
|
19266
19274
|
});
|
|
19275
|
+
var ApprovalLookupByRequestRequestSchema = exports_external.object({
|
|
19276
|
+
v: exports_external.literal(1),
|
|
19277
|
+
op: exports_external.literal("approval_lookup_by_request"),
|
|
19278
|
+
agent_unit: exports_external.string().min(1),
|
|
19279
|
+
request_id: exports_external.string().regex(/^[0-9a-f]{32}$/),
|
|
19280
|
+
current_approver_set: exports_external.array(exports_external.string())
|
|
19281
|
+
});
|
|
19267
19282
|
var ApprovalConsumeRequestSchema = exports_external.object({
|
|
19268
19283
|
v: exports_external.literal(1),
|
|
19269
19284
|
op: exports_external.literal("approval_consume"),
|
|
@@ -19318,6 +19333,7 @@ var RequestSchema = exports_external.discriminatedUnion("op", [
|
|
|
19318
19333
|
RevokeGrantRequestSchema,
|
|
19319
19334
|
ApprovalRequestRequestSchema,
|
|
19320
19335
|
ApprovalLookupRequestSchema,
|
|
19336
|
+
ApprovalLookupByRequestRequestSchema,
|
|
19321
19337
|
ApprovalConsumeRequestSchema,
|
|
19322
19338
|
ApprovalRevokeRequestSchema,
|
|
19323
19339
|
ApprovalListRequestSchema,
|
|
@@ -19570,13 +19586,13 @@ import {
|
|
|
19570
19586
|
copyFileSync as copyFileSync2,
|
|
19571
19587
|
chmodSync,
|
|
19572
19588
|
existsSync as existsSync7,
|
|
19573
|
-
fsyncSync as
|
|
19589
|
+
fsyncSync as fsyncSync4,
|
|
19574
19590
|
lstatSync as lstatSync2,
|
|
19575
19591
|
mkdirSync as mkdirSync3,
|
|
19576
|
-
openSync as
|
|
19577
|
-
closeSync as
|
|
19592
|
+
openSync as openSync4,
|
|
19593
|
+
closeSync as closeSync4,
|
|
19578
19594
|
readFileSync as readFileSync7,
|
|
19579
|
-
renameSync as
|
|
19595
|
+
renameSync as renameSync3,
|
|
19580
19596
|
statSync as statSync4,
|
|
19581
19597
|
symlinkSync,
|
|
19582
19598
|
unlinkSync as unlinkSync3
|
|
@@ -19642,7 +19658,7 @@ function runMigration(home2, opts) {
|
|
|
19642
19658
|
copyFileSync2(oldPath, tempNew);
|
|
19643
19659
|
chmodSync(tempNew, 384);
|
|
19644
19660
|
fsyncFile(tempNew);
|
|
19645
|
-
|
|
19661
|
+
renameSync3(tempNew, newPath);
|
|
19646
19662
|
fsyncDir(parent);
|
|
19647
19663
|
atomicReplaceWithSymlink(oldPath, "vault/vault.enc");
|
|
19648
19664
|
fsyncDir(switchroomRoot);
|
|
@@ -19676,22 +19692,22 @@ function atomicReplaceWithSymlink(target, linkTarget) {
|
|
|
19676
19692
|
} catch {}
|
|
19677
19693
|
}
|
|
19678
19694
|
symlinkSync(linkTarget, tmp);
|
|
19679
|
-
|
|
19695
|
+
renameSync3(tmp, target);
|
|
19680
19696
|
}
|
|
19681
19697
|
function fsyncFile(path) {
|
|
19682
|
-
const fd =
|
|
19698
|
+
const fd = openSync4(path, "r+");
|
|
19683
19699
|
try {
|
|
19684
|
-
|
|
19700
|
+
fsyncSync4(fd);
|
|
19685
19701
|
} finally {
|
|
19686
|
-
|
|
19702
|
+
closeSync4(fd);
|
|
19687
19703
|
}
|
|
19688
19704
|
}
|
|
19689
19705
|
function fsyncDir(path) {
|
|
19690
|
-
const fd =
|
|
19706
|
+
const fd = openSync4(path, "r");
|
|
19691
19707
|
try {
|
|
19692
|
-
|
|
19708
|
+
fsyncSync4(fd);
|
|
19693
19709
|
} finally {
|
|
19694
|
-
|
|
19710
|
+
closeSync4(fd);
|
|
19695
19711
|
}
|
|
19696
19712
|
}
|
|
19697
19713
|
|
|
@@ -19702,15 +19718,15 @@ init_loader();
|
|
|
19702
19718
|
import { createHmac, randomBytes as randomBytes2, createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2 } from "node:crypto";
|
|
19703
19719
|
import {
|
|
19704
19720
|
chmodSync as chmodSync2,
|
|
19705
|
-
closeSync as
|
|
19721
|
+
closeSync as closeSync5,
|
|
19706
19722
|
existsSync as existsSync8,
|
|
19707
|
-
fsyncSync as
|
|
19723
|
+
fsyncSync as fsyncSync5,
|
|
19708
19724
|
mkdirSync as mkdirSync4,
|
|
19709
|
-
openSync as
|
|
19725
|
+
openSync as openSync5,
|
|
19710
19726
|
readFileSync as readFileSync8,
|
|
19711
|
-
renameSync as
|
|
19727
|
+
renameSync as renameSync4,
|
|
19712
19728
|
unlinkSync as unlinkSync4,
|
|
19713
|
-
writeSync as
|
|
19729
|
+
writeSync as writeSync4
|
|
19714
19730
|
} from "node:fs";
|
|
19715
19731
|
var FORMAT_VERSION = 1;
|
|
19716
19732
|
var SALT_LEN = 16;
|
|
@@ -19803,7 +19819,7 @@ import * as path from "node:path";
|
|
|
19803
19819
|
|
|
19804
19820
|
// src/util/audit-hashchain.ts
|
|
19805
19821
|
import { createHash as createHash4 } from "node:crypto";
|
|
19806
|
-
import { openSync as
|
|
19822
|
+
import { openSync as openSync6, readSync, fstatSync as fstatSync2, closeSync as closeSync6 } from "node:fs";
|
|
19807
19823
|
var CHAIN_GENESIS = "GENESIS";
|
|
19808
19824
|
var SEP = "\x00";
|
|
19809
19825
|
function rowHash(prev, seq, rowJsonNoChain) {
|
|
@@ -19824,7 +19840,7 @@ function chainRow(state, entry) {
|
|
|
19824
19840
|
function readTail(path, tailBytes = 64 * 1024) {
|
|
19825
19841
|
let fd;
|
|
19826
19842
|
try {
|
|
19827
|
-
fd =
|
|
19843
|
+
fd = openSync6(path, "r");
|
|
19828
19844
|
} catch {
|
|
19829
19845
|
return null;
|
|
19830
19846
|
}
|
|
@@ -19840,7 +19856,7 @@ function readTail(path, tailBytes = 64 * 1024) {
|
|
|
19840
19856
|
return null;
|
|
19841
19857
|
} finally {
|
|
19842
19858
|
try {
|
|
19843
|
-
|
|
19859
|
+
closeSync6(fd);
|
|
19844
19860
|
} catch {}
|
|
19845
19861
|
}
|
|
19846
19862
|
}
|
|
@@ -22196,6 +22212,9 @@ function lookupDecision(db, query, opts = {}, now = Date.now()) {
|
|
|
22196
22212
|
ORDER BY granted_at DESC LIMIT 1`).get(query.agent_unit, query.scope, query.action);
|
|
22197
22213
|
if (!row)
|
|
22198
22214
|
return { state: "no_decision" };
|
|
22215
|
+
return evaluateDecisionRow(db, row, currentCanonical, opts, now);
|
|
22216
|
+
}
|
|
22217
|
+
function evaluateDecisionRow(db, row, currentCanonical, opts, now) {
|
|
22199
22218
|
const decision = rowToDecision(row);
|
|
22200
22219
|
if (decision.decision === "deny_perm") {
|
|
22201
22220
|
return { state: "denied", decision };
|
|
@@ -23203,6 +23222,41 @@ class VaultBroker {
|
|
|
23203
23222
|
if (req.token !== undefined && req.token !== "") {
|
|
23204
23223
|
const v = await validateGrantForWrite(this.grantsDb, req.token, req.key);
|
|
23205
23224
|
if (v.ok) {
|
|
23225
|
+
const writeGrantAgentSlug = v.grant.agent_slug;
|
|
23226
|
+
if (agentName !== null && writeGrantAgentSlug !== agentName) {
|
|
23227
|
+
this.auditLogger.write({
|
|
23228
|
+
ts: new Date().toISOString(),
|
|
23229
|
+
op: "put",
|
|
23230
|
+
key: req.key,
|
|
23231
|
+
caller: auditCaller,
|
|
23232
|
+
pid: auditPid,
|
|
23233
|
+
cgroup: auditCgroup,
|
|
23234
|
+
result: "denied:grant-identity-mismatch",
|
|
23235
|
+
method: "grant",
|
|
23236
|
+
grant_id: v.grant.id
|
|
23237
|
+
});
|
|
23238
|
+
socket.write(encodeResponse(errorResponse("DENIED", "grant-identity-mismatch")));
|
|
23239
|
+
return;
|
|
23240
|
+
}
|
|
23241
|
+
const existingForScope = this.secrets[req.key];
|
|
23242
|
+
if (existingForScope !== undefined) {
|
|
23243
|
+
const writeScope = checkEntryScope(existingForScope.scope, writeGrantAgentSlug);
|
|
23244
|
+
if (!writeScope.allow) {
|
|
23245
|
+
this.auditLogger.write({
|
|
23246
|
+
ts: new Date().toISOString(),
|
|
23247
|
+
op: "put",
|
|
23248
|
+
key: req.key,
|
|
23249
|
+
caller: auditCaller,
|
|
23250
|
+
pid: auditPid,
|
|
23251
|
+
cgroup: auditCgroup,
|
|
23252
|
+
result: `denied:${writeScope.reason}`,
|
|
23253
|
+
method: "grant",
|
|
23254
|
+
grant_id: v.grant.id
|
|
23255
|
+
});
|
|
23256
|
+
socket.write(encodeResponse(errorResponse("DENIED", writeScope.reason)));
|
|
23257
|
+
return;
|
|
23258
|
+
}
|
|
23259
|
+
}
|
|
23206
23260
|
writeGrantId = v.grant.id;
|
|
23207
23261
|
} else if (v.reason === "grant-expired" || v.reason === "grant-revoked") {
|
|
23208
23262
|
this.auditLogger.write({
|
|
@@ -23550,7 +23604,7 @@ class VaultBroker {
|
|
|
23550
23604
|
const tokenPath = path3.join(tokenDir, ".vault-token");
|
|
23551
23605
|
const tmpPath = `${tokenPath}.tmp.${process.pid}`;
|
|
23552
23606
|
writeFileSync3(tmpPath, mintResult.token, { mode: 384 });
|
|
23553
|
-
|
|
23607
|
+
renameSync7(tmpPath, tokenPath);
|
|
23554
23608
|
try {
|
|
23555
23609
|
const uid = allocateAgentUid(agent);
|
|
23556
23610
|
chownSync(tokenPath, uid, uid);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchroom",
|
|
3
3
|
"//version": "NOT the release version — source of truth is the git tag, resolved by scripts/build.mjs:resolveVersion() (see CLAUDE.md > Standard release process). This field is stale by design and only the Layer-4 dev/non-tag fallback for build.mjs + src/cli/resolve-version.ts; do NOT bump it expecting a release to pick it up. npm-pack tarball naming needs a real version — do that as an UNCOMMITTED pack-time bump (see release step 6), never a committed one.",
|
|
4
|
-
"version": "0.18.
|
|
4
|
+
"version": "0.18.13",
|
|
5
5
|
"description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -23035,6 +23035,33 @@ function getNestedObj(obj, key) {
|
|
|
23035
23035
|
var DEFAULT_OPERATOR_EVENT_COOLDOWN_MS = 5 * 60000;
|
|
23036
23036
|
var cooldownMap = new Map;
|
|
23037
23037
|
|
|
23038
|
+
// text-voice-scrub.ts
|
|
23039
|
+
var NULL = "\x00";
|
|
23040
|
+
var FENCE_PH = `${NULL}VS_FENCE`;
|
|
23041
|
+
var INLINE_PH = `${NULL}VS_INLINE`;
|
|
23042
|
+
var HTML_CODE_PH = `${NULL}VS_HTMLCODE`;
|
|
23043
|
+
var HTML_PRE_PH = `${NULL}VS_HTMLPRE`;
|
|
23044
|
+
var URL_PH = `${NULL}VS_URL`;
|
|
23045
|
+
|
|
23046
|
+
// model-unavailable.ts
|
|
23047
|
+
var transientUpstreamSignals = [
|
|
23048
|
+
"not your usage limit",
|
|
23049
|
+
"not your account",
|
|
23050
|
+
"not your account's",
|
|
23051
|
+
"temporarily limiting requests",
|
|
23052
|
+
"temporarily rate",
|
|
23053
|
+
"server is temporarily",
|
|
23054
|
+
"would exceed your account\u2019s rate limit",
|
|
23055
|
+
"would exceed your account's rate limit"
|
|
23056
|
+
];
|
|
23057
|
+
function isTransientUpstreamSignal(text) {
|
|
23058
|
+
if (typeof text !== "string" || text.length === 0)
|
|
23059
|
+
return false;
|
|
23060
|
+
const sample = text.length > 16384 ? text.slice(0, 16384) : text;
|
|
23061
|
+
const lower = sample.toLowerCase();
|
|
23062
|
+
return transientUpstreamSignals.some((s) => lower.includes(s));
|
|
23063
|
+
}
|
|
23064
|
+
|
|
23038
23065
|
// tool-label-sidecar.ts
|
|
23039
23066
|
import { existsSync as existsSync2, readFileSync, statSync as statSync2 } from "node:fs";
|
|
23040
23067
|
import { join as join2 } from "node:path";
|
|
@@ -23453,7 +23480,8 @@ function detectErrorInTranscriptLine(line) {
|
|
|
23453
23480
|
const status = typeof obj.apiErrorStatus === "number" ? obj.apiErrorStatus : null;
|
|
23454
23481
|
const errStr = typeof obj.error === "string" ? obj.error : "";
|
|
23455
23482
|
const text = extractAssistantText(obj);
|
|
23456
|
-
const kind2 = status === 429 ?
|
|
23483
|
+
const kind2 = status === 429 ? isTransientUpstreamSignal(`${text}
|
|
23484
|
+
${errStr}`) ? "rate-limited" : "quota-exhausted" : classifyClaudeError({ type: errStr, status, message: text });
|
|
23457
23485
|
return {
|
|
23458
23486
|
kind: kind2,
|
|
23459
23487
|
raw: obj,
|
|
@@ -23547,6 +23575,7 @@ function startSessionTail(config2) {
|
|
|
23547
23575
|
const onOperatorEvent = config2.onOperatorEvent;
|
|
23548
23576
|
log?.(`session-tail: projectsDir=${projectsDir}`);
|
|
23549
23577
|
const sidecars = new Map;
|
|
23578
|
+
const createSidecar = config2.createSidecar ?? createToolLabelSidecar;
|
|
23550
23579
|
const stateDirForSidecar = process.env.TELEGRAM_STATE_DIR ?? null;
|
|
23551
23580
|
function sessionIdForFile(file) {
|
|
23552
23581
|
if (!file)
|
|
@@ -23561,7 +23590,7 @@ function startSessionTail(config2) {
|
|
|
23561
23590
|
if (existing)
|
|
23562
23591
|
return existing;
|
|
23563
23592
|
try {
|
|
23564
|
-
const s =
|
|
23593
|
+
const s = createSidecar({ stateDir: stateDirForSidecar, sessionId });
|
|
23565
23594
|
sidecars.set(sessionId, s);
|
|
23566
23595
|
s.onLabel((toolUseId, label, toolName) => {
|
|
23567
23596
|
rawOnEvent({ kind: "tool_label", toolUseId, label, toolName });
|
|
@@ -23572,6 +23601,17 @@ function startSessionTail(config2) {
|
|
|
23572
23601
|
return null;
|
|
23573
23602
|
}
|
|
23574
23603
|
}
|
|
23604
|
+
function stopSidecar(sessionId) {
|
|
23605
|
+
if (!sessionId)
|
|
23606
|
+
return;
|
|
23607
|
+
const s = sidecars.get(sessionId);
|
|
23608
|
+
if (!s)
|
|
23609
|
+
return;
|
|
23610
|
+
try {
|
|
23611
|
+
s.stop();
|
|
23612
|
+
} catch {}
|
|
23613
|
+
sidecars.delete(sessionId);
|
|
23614
|
+
}
|
|
23575
23615
|
function decorate(ev, sessionId) {
|
|
23576
23616
|
if (!sessionId)
|
|
23577
23617
|
return ev;
|
|
@@ -23664,6 +23704,11 @@ function startSessionTail(config2) {
|
|
|
23664
23704
|
} catch {}
|
|
23665
23705
|
watcher = null;
|
|
23666
23706
|
}
|
|
23707
|
+
const rotatedAwaySid = sessionIdForFile(currentFile);
|
|
23708
|
+
const nextSid = sessionIdForFile(file);
|
|
23709
|
+
if (rotatedAwaySid != null && rotatedAwaySid !== nextSid) {
|
|
23710
|
+
stopSidecar(rotatedAwaySid);
|
|
23711
|
+
}
|
|
23667
23712
|
currentFile = file;
|
|
23668
23713
|
const prior = fileCursors.get(file);
|
|
23669
23714
|
if (prior != null) {
|
|
@@ -23696,7 +23741,7 @@ function startSessionTail(config2) {
|
|
|
23696
23741
|
const multiAgent = isMultiAgentEnabled();
|
|
23697
23742
|
const CAP_TOOL_USE_THRESHOLD = 30;
|
|
23698
23743
|
const subTails = new Map;
|
|
23699
|
-
const IDLE_FSWATCH_TTL_MS = 5 * 60 * 1000;
|
|
23744
|
+
const IDLE_FSWATCH_TTL_MS = Math.max(1000, config2.subTailIdleReapMs ?? 5 * 60 * 1000);
|
|
23700
23745
|
function readSub(t) {
|
|
23701
23746
|
if (stopped)
|
|
23702
23747
|
return;
|
|
@@ -23803,6 +23848,7 @@ function startSessionTail(config2) {
|
|
|
23803
23848
|
} catch {}
|
|
23804
23849
|
t.watcher = null;
|
|
23805
23850
|
}
|
|
23851
|
+
stopSidecar(sessionIdForFile(t.file));
|
|
23806
23852
|
subTails.delete(file);
|
|
23807
23853
|
log?.(`session-tail: reaped idle sub ${t.agentId} (${file})`);
|
|
23808
23854
|
}
|