@standardagents/code 0.13.6 → 0.13.8
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/README.md +21 -4
- package/dist/index.js +231 -101
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import readline3 from 'readline/promises';
|
|
|
5
5
|
import { stdout, stdin } from 'process';
|
|
6
6
|
import * as api_star from '@standardagents/code-network/api';
|
|
7
7
|
import * as stream_star from '@standardagents/code-network/stream';
|
|
8
|
+
import * as snapshot_epoch_star from '@standardagents/code-network/snapshot-epoch';
|
|
8
9
|
import * as hub_star from '@standardagents/code-network/hub';
|
|
9
10
|
import * as subagent_streams_star from '@standardagents/code-network/subagent-streams';
|
|
10
11
|
import * as session_state_star from '@standardagents/code-network/session-state';
|
|
@@ -12,7 +13,7 @@ import * as transcript_delivery_star from '@standardagents/code-network/transcri
|
|
|
12
13
|
import * as approvals_star from '@standardagents/code-network/approvals';
|
|
13
14
|
import net from 'net';
|
|
14
15
|
import { setImmediate } from 'timers';
|
|
15
|
-
import
|
|
16
|
+
import fs12 from 'fs';
|
|
16
17
|
import { permissionKey, Bridge as Bridge$1 } from '@standardagents/code-network/bridge';
|
|
17
18
|
import readline from 'readline';
|
|
18
19
|
import * as types_star from '@standardagents/code-network/types';
|
|
@@ -71,6 +72,10 @@ var themeGray = isLightTheme ? "\x1B[38;5;244m" : "\x1B[90m";
|
|
|
71
72
|
var stream_exports = {};
|
|
72
73
|
__reExport(stream_exports, stream_star);
|
|
73
74
|
|
|
75
|
+
// src/snapshot-epoch.ts
|
|
76
|
+
var snapshot_epoch_exports = {};
|
|
77
|
+
__reExport(snapshot_epoch_exports, snapshot_epoch_star);
|
|
78
|
+
|
|
74
79
|
// src/hub.ts
|
|
75
80
|
var hub_exports = {};
|
|
76
81
|
__reExport(hub_exports, hub_star);
|
|
@@ -98,10 +103,10 @@ var AccountUserStream = class {
|
|
|
98
103
|
options.uniqueConnectionId
|
|
99
104
|
);
|
|
100
105
|
}
|
|
101
|
-
start() {
|
|
106
|
+
async start() {
|
|
102
107
|
if (this.started) return;
|
|
103
108
|
this.started = true;
|
|
104
|
-
this.hub.start();
|
|
109
|
+
await this.hub.start();
|
|
105
110
|
}
|
|
106
111
|
onEvent(listener) {
|
|
107
112
|
this.eventListeners.add(listener);
|
|
@@ -114,7 +119,7 @@ var AccountUserStream = class {
|
|
|
114
119
|
/** Wait for a live socket. The timeout is local and performs no network work. */
|
|
115
120
|
waitUntilConnected(timeoutMs = 15e3) {
|
|
116
121
|
if (this.connected) return Promise.resolve();
|
|
117
|
-
this.start();
|
|
122
|
+
void this.start();
|
|
118
123
|
return new Promise((resolve, reject) => {
|
|
119
124
|
let timer;
|
|
120
125
|
const remove = this.onConnection((state) => {
|
|
@@ -212,6 +217,7 @@ function riskCeiling(state) {
|
|
|
212
217
|
function decide(state, tool, risk, hasPermissionRequest) {
|
|
213
218
|
const effectiveRisk = typeof risk === "number" ? Math.min(5, Math.max(1, risk)) : hasPermissionRequest ? 3 : 1;
|
|
214
219
|
if (state.alwaysAllow.has(tool)) return "allow";
|
|
220
|
+
if (hasPermissionRequest) return "ask";
|
|
215
221
|
return effectiveRisk <= riskCeiling(state) ? "allow" : "ask";
|
|
216
222
|
}
|
|
217
223
|
var CATASTROPHIC_PATTERNS = [
|
|
@@ -415,7 +421,7 @@ var ToolLedger = class {
|
|
|
415
421
|
if (this.loaded) return;
|
|
416
422
|
this.loaded = true;
|
|
417
423
|
try {
|
|
418
|
-
const raw =
|
|
424
|
+
const raw = fs12.readFileSync(this.file, "utf8");
|
|
419
425
|
const parsed = JSON.parse(raw);
|
|
420
426
|
for (const [id, entry] of Object.entries(parsed)) {
|
|
421
427
|
if (entry && typeof entry.ok === "boolean") this.entries.set(id, entry);
|
|
@@ -447,13 +453,13 @@ var ToolLedger = class {
|
|
|
447
453
|
}
|
|
448
454
|
persist() {
|
|
449
455
|
try {
|
|
450
|
-
|
|
456
|
+
fs12.mkdirSync(ledgerDir(), { recursive: true });
|
|
451
457
|
const out = {};
|
|
452
458
|
for (const [id, entry] of this.entries) {
|
|
453
459
|
const size = entry.result ? Buffer.byteLength(entry.result) : 0;
|
|
454
460
|
out[id] = size > MAX_RESULT_BYTES ? { ...entry, result: void 0 } : entry;
|
|
455
461
|
}
|
|
456
|
-
|
|
462
|
+
fs12.writeFileSync(this.file, JSON.stringify(out), { mode: 384 });
|
|
457
463
|
} catch {
|
|
458
464
|
}
|
|
459
465
|
}
|
|
@@ -1541,6 +1547,46 @@ var WordMill = class {
|
|
|
1541
1547
|
// src/types.ts
|
|
1542
1548
|
var types_exports = {};
|
|
1543
1549
|
__reExport(types_exports, types_star);
|
|
1550
|
+
|
|
1551
|
+
// src/subprocess-env.ts
|
|
1552
|
+
var INHERITED_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
1553
|
+
"APPDATA",
|
|
1554
|
+
"COMSPEC",
|
|
1555
|
+
"HOME",
|
|
1556
|
+
"LANG",
|
|
1557
|
+
"LC_ALL",
|
|
1558
|
+
"LC_CTYPE",
|
|
1559
|
+
"LOCALAPPDATA",
|
|
1560
|
+
"LOGNAME",
|
|
1561
|
+
"PATH",
|
|
1562
|
+
"PATHEXT",
|
|
1563
|
+
"PROGRAMDATA",
|
|
1564
|
+
"SHELL",
|
|
1565
|
+
"SYSTEMROOT",
|
|
1566
|
+
"TEMP",
|
|
1567
|
+
"TERM",
|
|
1568
|
+
"TMP",
|
|
1569
|
+
"TMPDIR",
|
|
1570
|
+
"USER",
|
|
1571
|
+
"USERPROFILE",
|
|
1572
|
+
"WINDIR"
|
|
1573
|
+
]);
|
|
1574
|
+
function inheritedSubprocessEnv(ambient = process.env) {
|
|
1575
|
+
const child = { ...ambient };
|
|
1576
|
+
delete child.NODE_TLS_REJECT_UNAUTHORIZED;
|
|
1577
|
+
return child;
|
|
1578
|
+
}
|
|
1579
|
+
function restrictedSubprocessEnv(explicit = {}, ambient = process.env) {
|
|
1580
|
+
const inherited = {};
|
|
1581
|
+
for (const [name, value] of Object.entries(ambient)) {
|
|
1582
|
+
if (value !== void 0 && INHERITED_ENV_ALLOWLIST.has(name.toUpperCase())) {
|
|
1583
|
+
inherited[name] = value;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
return { ...inherited, ...explicit };
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
// src/clipboard.ts
|
|
1544
1590
|
var FILE_MIMES = {
|
|
1545
1591
|
".png": "image/png",
|
|
1546
1592
|
".jpg": "image/jpeg",
|
|
@@ -1551,7 +1597,11 @@ var FILE_MIMES = {
|
|
|
1551
1597
|
var MAX_IMAGE_BYTES = 8 * 1024 * 1024;
|
|
1552
1598
|
function run(cmd, args, maxBuffer = MAX_IMAGE_BYTES * 2) {
|
|
1553
1599
|
return new Promise((resolve) => {
|
|
1554
|
-
execFile(cmd, args, {
|
|
1600
|
+
execFile(cmd, args, {
|
|
1601
|
+
encoding: "buffer",
|
|
1602
|
+
maxBuffer,
|
|
1603
|
+
env: inheritedSubprocessEnv()
|
|
1604
|
+
}, (err, stdout) => {
|
|
1555
1605
|
resolve({ ok: !err, stdout: stdout ?? Buffer.alloc(0) });
|
|
1556
1606
|
});
|
|
1557
1607
|
});
|
|
@@ -1560,9 +1610,9 @@ function fromFile(filePath) {
|
|
|
1560
1610
|
const mime = FILE_MIMES[path9.extname(filePath).toLowerCase()];
|
|
1561
1611
|
if (!mime) return null;
|
|
1562
1612
|
try {
|
|
1563
|
-
const stat =
|
|
1613
|
+
const stat = fs12.statSync(filePath);
|
|
1564
1614
|
if (!stat.isFile() || stat.size === 0 || stat.size > MAX_IMAGE_BYTES) return null;
|
|
1565
|
-
return { data:
|
|
1615
|
+
return { data: fs12.readFileSync(filePath).toString("base64"), mime };
|
|
1566
1616
|
} catch {
|
|
1567
1617
|
return null;
|
|
1568
1618
|
}
|
|
@@ -1580,7 +1630,7 @@ async function readDarwin() {
|
|
|
1580
1630
|
if (png.ok) {
|
|
1581
1631
|
const img = fromFile(tmp);
|
|
1582
1632
|
try {
|
|
1583
|
-
|
|
1633
|
+
fs12.unlinkSync(tmp);
|
|
1584
1634
|
} catch {
|
|
1585
1635
|
}
|
|
1586
1636
|
if (img) return img;
|
|
@@ -1614,7 +1664,7 @@ async function readWindows() {
|
|
|
1614
1664
|
await run("powershell", ["-NoProfile", "-STA", "-Command", ps]);
|
|
1615
1665
|
const img = fromFile(tmp);
|
|
1616
1666
|
try {
|
|
1617
|
-
|
|
1667
|
+
fs12.unlinkSync(tmp);
|
|
1618
1668
|
} catch {
|
|
1619
1669
|
}
|
|
1620
1670
|
return img;
|
|
@@ -3811,6 +3861,18 @@ __reExport(shared_messaging_exports, shared_messaging_star);
|
|
|
3811
3861
|
var history_exports = {};
|
|
3812
3862
|
__reExport(history_exports, history_star);
|
|
3813
3863
|
var LOG_DIR = path9.join(os6.homedir(), ".standardagents", "process-logs");
|
|
3864
|
+
function openPrivateProcessLog(logPath) {
|
|
3865
|
+
const directory = path9.dirname(logPath);
|
|
3866
|
+
fs12.mkdirSync(directory, { recursive: true, mode: 448 });
|
|
3867
|
+
fs12.chmodSync(directory, 448);
|
|
3868
|
+
const descriptor = fs12.openSync(
|
|
3869
|
+
logPath,
|
|
3870
|
+
fs12.constants.O_WRONLY | fs12.constants.O_CREAT | fs12.constants.O_APPEND,
|
|
3871
|
+
384
|
|
3872
|
+
);
|
|
3873
|
+
fs12.fchmodSync(descriptor, 384);
|
|
3874
|
+
return descriptor;
|
|
3875
|
+
}
|
|
3814
3876
|
function isAlive(pid) {
|
|
3815
3877
|
try {
|
|
3816
3878
|
process.kill(pid, 0);
|
|
@@ -3829,7 +3891,7 @@ function configFile() {
|
|
|
3829
3891
|
}
|
|
3830
3892
|
function loadMcpConfig() {
|
|
3831
3893
|
try {
|
|
3832
|
-
const raw =
|
|
3894
|
+
const raw = fs12.readFileSync(configFile(), "utf8");
|
|
3833
3895
|
const parsed = JSON.parse(raw);
|
|
3834
3896
|
if (!parsed.servers || typeof parsed.servers !== "object") parsed.servers = {};
|
|
3835
3897
|
return parsed;
|
|
@@ -3860,8 +3922,8 @@ function setMcpServerEnabled(name, enabled) {
|
|
|
3860
3922
|
}
|
|
3861
3923
|
function write(cfg) {
|
|
3862
3924
|
const file2 = configFile();
|
|
3863
|
-
|
|
3864
|
-
|
|
3925
|
+
fs12.mkdirSync(path9.dirname(file2), { recursive: true });
|
|
3926
|
+
fs12.writeFileSync(file2, JSON.stringify(cfg, null, 2), { mode: 384 });
|
|
3865
3927
|
}
|
|
3866
3928
|
function parseServerSpec(spec) {
|
|
3867
3929
|
const trimmed = spec.trim();
|
|
@@ -3932,7 +3994,11 @@ function openUrl(url) {
|
|
|
3932
3994
|
const cmd = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
3933
3995
|
const args = platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
3934
3996
|
try {
|
|
3935
|
-
const child = spawn(cmd, args, {
|
|
3997
|
+
const child = spawn(cmd, args, {
|
|
3998
|
+
stdio: "ignore",
|
|
3999
|
+
detached: true,
|
|
4000
|
+
env: inheritedSubprocessEnv()
|
|
4001
|
+
});
|
|
3936
4002
|
child.unref();
|
|
3937
4003
|
} catch {
|
|
3938
4004
|
}
|
|
@@ -3944,11 +4010,11 @@ __reExport(recorder_exports, recorder_star);
|
|
|
3944
4010
|
__reExport(recorder_exports, recorder_node_star);
|
|
3945
4011
|
function readVersion() {
|
|
3946
4012
|
try {
|
|
3947
|
-
const pkg = JSON.parse(
|
|
4013
|
+
const pkg = JSON.parse(fs12.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
3948
4014
|
if (typeof pkg.version === "string" && pkg.version) return pkg.version;
|
|
3949
4015
|
} catch {
|
|
3950
4016
|
}
|
|
3951
|
-
return "0.13.
|
|
4017
|
+
return "0.13.8" ;
|
|
3952
4018
|
}
|
|
3953
4019
|
function isLocalHost(host) {
|
|
3954
4020
|
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host.endsWith(".local") || host.endsWith(".localhost") || /^10\./.test(host) || /^192\.168\./.test(host) || /^172\.(1[6-9]|2\d|3[01])\./.test(host);
|
|
@@ -3974,7 +4040,7 @@ var dir = () => path9.join(os6.homedir(), ".standardagents");
|
|
|
3974
4040
|
var file = () => path9.join(dir(), "machine.json");
|
|
3975
4041
|
function loadMachineIdentity() {
|
|
3976
4042
|
try {
|
|
3977
|
-
const parsed = JSON.parse(
|
|
4043
|
+
const parsed = JSON.parse(fs12.readFileSync(file(), "utf8"));
|
|
3978
4044
|
if (typeof parsed.machine_id === "string" && parsed.machine_id.length > 0) {
|
|
3979
4045
|
return { machine_id: parsed.machine_id, created_at: parsed.created_at ?? Date.now() };
|
|
3980
4046
|
}
|
|
@@ -3988,8 +4054,8 @@ function loadMachineIdentity() {
|
|
|
3988
4054
|
return identity;
|
|
3989
4055
|
}
|
|
3990
4056
|
function saveMachineIdentity(identity) {
|
|
3991
|
-
|
|
3992
|
-
|
|
4057
|
+
fs12.mkdirSync(dir(), { recursive: true });
|
|
4058
|
+
fs12.writeFileSync(file(), JSON.stringify(identity, null, 2), { mode: 384 });
|
|
3993
4059
|
}
|
|
3994
4060
|
function daemonClientId(identity) {
|
|
3995
4061
|
return `daemon:${identity.machine_id}`;
|
|
@@ -4320,7 +4386,8 @@ function projectRepository(projectDir) {
|
|
|
4320
4386
|
const url = execFileSync("git", ["-C", projectDir, "remote", "get-url", "origin"], {
|
|
4321
4387
|
encoding: "utf8",
|
|
4322
4388
|
timeout: 3e3,
|
|
4323
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
4389
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
4390
|
+
env: inheritedSubprocessEnv()
|
|
4324
4391
|
}).trim();
|
|
4325
4392
|
return url || null;
|
|
4326
4393
|
} catch {
|
|
@@ -4499,7 +4566,7 @@ function markers(dirPath) {
|
|
|
4499
4566
|
for (const marker of PROJECT_MARKERS) {
|
|
4500
4567
|
let hit = false;
|
|
4501
4568
|
try {
|
|
4502
|
-
hit =
|
|
4569
|
+
hit = fs12.existsSync(path9.join(dirPath, marker));
|
|
4503
4570
|
} catch {
|
|
4504
4571
|
hit = false;
|
|
4505
4572
|
}
|
|
@@ -4521,11 +4588,11 @@ function browseDirectory(input3, opts = {}) {
|
|
|
4521
4588
|
};
|
|
4522
4589
|
let dirents;
|
|
4523
4590
|
try {
|
|
4524
|
-
const stat =
|
|
4591
|
+
const stat = fs12.statSync(abs);
|
|
4525
4592
|
if (!stat.isDirectory()) {
|
|
4526
4593
|
return { ...base, entries: [], truncated: false, error: "Not a directory" };
|
|
4527
4594
|
}
|
|
4528
|
-
dirents =
|
|
4595
|
+
dirents = fs12.readdirSync(abs, { withFileTypes: true });
|
|
4529
4596
|
} catch (err) {
|
|
4530
4597
|
const code = err?.code;
|
|
4531
4598
|
const message = code === "EACCES" || code === "EPERM" ? "Permission denied" : code === "ENOENT" ? "Folder not found" : "Could not read this folder";
|
|
@@ -4540,7 +4607,7 @@ function browseDirectory(input3, opts = {}) {
|
|
|
4540
4607
|
let isDir = d.isDirectory();
|
|
4541
4608
|
if (d.isSymbolicLink()) {
|
|
4542
4609
|
try {
|
|
4543
|
-
isDir =
|
|
4610
|
+
isDir = fs12.statSync(path9.join(abs, name)).isDirectory();
|
|
4544
4611
|
} catch {
|
|
4545
4612
|
isDir = false;
|
|
4546
4613
|
}
|
|
@@ -4571,7 +4638,7 @@ function mkdirDirectory(parentInput, name, opts = {}) {
|
|
|
4571
4638
|
return { ...listParent(), error: "Invalid folder name." };
|
|
4572
4639
|
}
|
|
4573
4640
|
try {
|
|
4574
|
-
|
|
4641
|
+
fs12.mkdirSync(target, { recursive: false });
|
|
4575
4642
|
} catch (err) {
|
|
4576
4643
|
const code = err?.code;
|
|
4577
4644
|
const message = code === "EEXIST" ? "A folder with that name already exists." : code === "EACCES" || code === "EPERM" ? "Permission denied." : code === "ENOENT" ? "The parent folder no longer exists." : "Could not create the folder.";
|
|
@@ -4786,7 +4853,10 @@ function probe(cmd) {
|
|
|
4786
4853
|
return new Promise((resolve) => {
|
|
4787
4854
|
let child;
|
|
4788
4855
|
try {
|
|
4789
|
-
child = spawn(cmd, ["--version"], {
|
|
4856
|
+
child = spawn(cmd, ["--version"], {
|
|
4857
|
+
stdio: "ignore",
|
|
4858
|
+
env: inheritedSubprocessEnv()
|
|
4859
|
+
});
|
|
4790
4860
|
} catch {
|
|
4791
4861
|
resolve(false);
|
|
4792
4862
|
return;
|
|
@@ -4822,7 +4892,7 @@ function download(url, dest, redirects = 5) {
|
|
|
4822
4892
|
reject(new Error(`HTTP ${status} for ${url}`));
|
|
4823
4893
|
return;
|
|
4824
4894
|
}
|
|
4825
|
-
const out =
|
|
4895
|
+
const out = fs12.createWriteStream(dest);
|
|
4826
4896
|
res.pipe(out);
|
|
4827
4897
|
out.on("finish", () => out.close(() => resolve()));
|
|
4828
4898
|
out.on("error", reject);
|
|
@@ -4833,7 +4903,7 @@ function download(url, dest, redirects = 5) {
|
|
|
4833
4903
|
async function sha256File(file2) {
|
|
4834
4904
|
const hash = crypto.createHash("sha256");
|
|
4835
4905
|
await new Promise((resolve, reject) => {
|
|
4836
|
-
const stream =
|
|
4906
|
+
const stream = fs12.createReadStream(file2);
|
|
4837
4907
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
4838
4908
|
stream.on("end", () => resolve());
|
|
4839
4909
|
stream.on("error", reject);
|
|
@@ -4844,7 +4914,11 @@ function runOk(cmd, args, cwd) {
|
|
|
4844
4914
|
return new Promise((resolve) => {
|
|
4845
4915
|
let child;
|
|
4846
4916
|
try {
|
|
4847
|
-
child = spawn(cmd, args, {
|
|
4917
|
+
child = spawn(cmd, args, {
|
|
4918
|
+
cwd,
|
|
4919
|
+
stdio: "ignore",
|
|
4920
|
+
env: inheritedSubprocessEnv()
|
|
4921
|
+
});
|
|
4848
4922
|
} catch {
|
|
4849
4923
|
resolve(false);
|
|
4850
4924
|
return;
|
|
@@ -4871,7 +4945,7 @@ async function provision(target) {
|
|
|
4871
4945
|
let extracted = null;
|
|
4872
4946
|
for (const entry of entries) {
|
|
4873
4947
|
const candidate = entry.isDirectory() ? path9.join(work, entry.name, binName) : entry.name === binName ? path9.join(work, entry.name) : null;
|
|
4874
|
-
if (candidate &&
|
|
4948
|
+
if (candidate && fs12.existsSync(candidate)) {
|
|
4875
4949
|
extracted = candidate;
|
|
4876
4950
|
break;
|
|
4877
4951
|
}
|
|
@@ -4896,7 +4970,7 @@ function resolveRg(log) {
|
|
|
4896
4970
|
const override = process.env.STANDARDCODE_RG_PATH;
|
|
4897
4971
|
if (override && await probe(override)) return override;
|
|
4898
4972
|
if (await probe("rg")) return "rg";
|
|
4899
|
-
if (
|
|
4973
|
+
if (fs12.existsSync(RG_BIN) && await probe(RG_BIN)) return RG_BIN;
|
|
4900
4974
|
const target = RG_TARGETS[`${process.platform}-${process.arch}`];
|
|
4901
4975
|
if (!target) return null;
|
|
4902
4976
|
try {
|
|
@@ -4955,16 +5029,36 @@ var HostTools = class {
|
|
|
4955
5029
|
mcp;
|
|
4956
5030
|
onMcpCatalogChange;
|
|
4957
5031
|
api;
|
|
4958
|
-
/** Resolve a user/model-supplied path against the project directory.
|
|
5032
|
+
/** Resolve a user/model-supplied path against the project directory.
|
|
5033
|
+
* A leading `~` expands to the host home directory — without this, a
|
|
5034
|
+
* model-supplied `~/Desktop/x` silently lands at `<project>/~/Desktop/x`.
|
|
5035
|
+
* Outside-project containment checks run on the resolved result, so an
|
|
5036
|
+
* expanded home path still requires a fresh human decision. */
|
|
4959
5037
|
resolve(p) {
|
|
4960
5038
|
if (!p || p === ".") return this.projectDir;
|
|
5039
|
+
if (p === "~" || p.startsWith("~/")) {
|
|
5040
|
+
p = path9.join(os6.homedir(), p.slice(1));
|
|
5041
|
+
}
|
|
4961
5042
|
return path9.resolve(this.projectDir, p);
|
|
4962
5043
|
}
|
|
4963
|
-
/**
|
|
5044
|
+
/** Resolve symlinks in an existing target or its nearest existing ancestor. */
|
|
5045
|
+
realPathForContainment(target) {
|
|
5046
|
+
const missing = [];
|
|
5047
|
+
let existing = path9.resolve(target);
|
|
5048
|
+
while (!fs12.existsSync(existing)) {
|
|
5049
|
+
const parent = path9.dirname(existing);
|
|
5050
|
+
if (parent === existing) return path9.resolve(target);
|
|
5051
|
+
missing.unshift(path9.basename(existing));
|
|
5052
|
+
existing = parent;
|
|
5053
|
+
}
|
|
5054
|
+
return path9.join(fs12.realpathSync.native(existing), ...missing);
|
|
5055
|
+
}
|
|
5056
|
+
/** True when the resolved path escapes the real project directory. */
|
|
4964
5057
|
isOutsideProject(p) {
|
|
4965
|
-
const
|
|
4966
|
-
const
|
|
4967
|
-
|
|
5058
|
+
const project = this.realPathForContainment(this.projectDir);
|
|
5059
|
+
const candidate = this.realPathForContainment(this.resolve(p));
|
|
5060
|
+
const rel = path9.relative(project, candidate);
|
|
5061
|
+
return rel === ".." || rel.startsWith(`..${path9.sep}`) || path9.isAbsolute(rel);
|
|
4968
5062
|
}
|
|
4969
5063
|
async execute(tool, args) {
|
|
4970
5064
|
try {
|
|
@@ -5060,7 +5154,7 @@ var HostTools = class {
|
|
|
5060
5154
|
const file2 = this.resolve(String(args.path || ""));
|
|
5061
5155
|
const content = String(args.content ?? "");
|
|
5062
5156
|
await fsp2.mkdir(path9.dirname(file2), { recursive: true });
|
|
5063
|
-
const existed =
|
|
5157
|
+
const existed = fs12.existsSync(file2);
|
|
5064
5158
|
await fsp2.writeFile(file2, content, "utf8");
|
|
5065
5159
|
return {
|
|
5066
5160
|
ok: true,
|
|
@@ -5102,7 +5196,7 @@ var HostTools = class {
|
|
|
5102
5196
|
if (!bytes) return { ok: false, error: `Could not download ${source} from the thread filesystem.` };
|
|
5103
5197
|
const dest = this.resolve(destArg);
|
|
5104
5198
|
await fsp2.mkdir(path9.dirname(dest), { recursive: true });
|
|
5105
|
-
const existed =
|
|
5199
|
+
const existed = fs12.existsSync(dest);
|
|
5106
5200
|
await fsp2.writeFile(dest, bytes);
|
|
5107
5201
|
return {
|
|
5108
5202
|
ok: true,
|
|
@@ -5179,7 +5273,7 @@ var HostTools = class {
|
|
|
5179
5273
|
return await new Promise((resolvePromise) => {
|
|
5180
5274
|
const child = spawn(cmd, argv, {
|
|
5181
5275
|
cwd: this.projectDir,
|
|
5182
|
-
env: {
|
|
5276
|
+
env: restrictedSubprocessEnv({ SKILL_DIR: skillDir }),
|
|
5183
5277
|
stdio: ["ignore", "pipe", "pipe"]
|
|
5184
5278
|
});
|
|
5185
5279
|
let out = "";
|
|
@@ -5232,30 +5326,34 @@ ${truncated}`
|
|
|
5232
5326
|
const command = String(args.command || "");
|
|
5233
5327
|
if (!command.trim()) return { ok: false, error: "command is required" };
|
|
5234
5328
|
const cwd = args.cwd ? this.resolve(String(args.cwd)) : this.projectDir;
|
|
5235
|
-
if (!
|
|
5329
|
+
if (!fs12.existsSync(cwd)) {
|
|
5236
5330
|
return { ok: false, error: `cwd does not exist: ${cwd}` };
|
|
5237
5331
|
}
|
|
5238
5332
|
const id = crypto.randomUUID().slice(0, 8);
|
|
5239
5333
|
const logPath = path9.join(LOG_DIR, `${id}.log`);
|
|
5240
5334
|
let out;
|
|
5241
5335
|
try {
|
|
5242
|
-
|
|
5243
|
-
out = fs11.openSync(logPath, "a");
|
|
5336
|
+
out = openPrivateProcessLog(logPath);
|
|
5244
5337
|
} catch (err) {
|
|
5245
5338
|
return { ok: false, error: `Could not open log file: ${err instanceof Error ? err.message : String(err)}` };
|
|
5246
5339
|
}
|
|
5247
5340
|
let child;
|
|
5248
5341
|
try {
|
|
5249
|
-
child = spawn("bash", ["-lc", command], {
|
|
5342
|
+
child = spawn("bash", ["-lc", command], {
|
|
5343
|
+
cwd,
|
|
5344
|
+
detached: true,
|
|
5345
|
+
stdio: ["ignore", out, out],
|
|
5346
|
+
env: inheritedSubprocessEnv()
|
|
5347
|
+
});
|
|
5250
5348
|
} catch (err) {
|
|
5251
|
-
|
|
5349
|
+
fs12.closeSync(out);
|
|
5252
5350
|
return { ok: false, error: `Failed to start: ${err instanceof Error ? err.message : String(err)}` };
|
|
5253
5351
|
}
|
|
5254
5352
|
let spawnError = null;
|
|
5255
5353
|
child.on("error", (err) => {
|
|
5256
5354
|
spawnError = err;
|
|
5257
5355
|
});
|
|
5258
|
-
|
|
5356
|
+
fs12.closeSync(out);
|
|
5259
5357
|
const pid = child.pid;
|
|
5260
5358
|
let earlyExit;
|
|
5261
5359
|
const onEarlyExit = (code) => {
|
|
@@ -5461,7 +5559,11 @@ ${tail2}` : " No output was captured.")
|
|
|
5461
5559
|
const MAX_OUTPUT = 256 * 1024;
|
|
5462
5560
|
let child;
|
|
5463
5561
|
try {
|
|
5464
|
-
child = spawn(cmd, args, {
|
|
5562
|
+
child = spawn(cmd, args, {
|
|
5563
|
+
cwd,
|
|
5564
|
+
detached: true,
|
|
5565
|
+
env: inheritedSubprocessEnv()
|
|
5566
|
+
});
|
|
5465
5567
|
} catch {
|
|
5466
5568
|
resolve({ stdout: "", stderr: "", code: 127, timedOut: false });
|
|
5467
5569
|
return;
|
|
@@ -5561,7 +5663,7 @@ var McpClient = class {
|
|
|
5561
5663
|
async connect(defaultCwd) {
|
|
5562
5664
|
const child = spawn(this.config.command, this.config.args, {
|
|
5563
5665
|
cwd: this.config.cwd || defaultCwd,
|
|
5564
|
-
env:
|
|
5666
|
+
env: restrictedSubprocessEnv(this.config.env),
|
|
5565
5667
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5566
5668
|
});
|
|
5567
5669
|
this.child = child;
|
|
@@ -6025,7 +6127,7 @@ var DaemonUserStream = class {
|
|
|
6025
6127
|
if (hooks.onConnection) this.stream.onConnection(hooks.onConnection);
|
|
6026
6128
|
}
|
|
6027
6129
|
start() {
|
|
6028
|
-
this.stream.start();
|
|
6130
|
+
return this.stream.start();
|
|
6029
6131
|
}
|
|
6030
6132
|
close() {
|
|
6031
6133
|
this.stream.close();
|
|
@@ -6068,7 +6170,7 @@ function cachePath() {
|
|
|
6068
6170
|
}
|
|
6069
6171
|
function readCache() {
|
|
6070
6172
|
try {
|
|
6071
|
-
const raw =
|
|
6173
|
+
const raw = fs12.readFileSync(cachePath(), "utf-8");
|
|
6072
6174
|
return JSON.parse(raw);
|
|
6073
6175
|
} catch {
|
|
6074
6176
|
return null;
|
|
@@ -6077,14 +6179,14 @@ function readCache() {
|
|
|
6077
6179
|
function writeCache(latest) {
|
|
6078
6180
|
try {
|
|
6079
6181
|
const dir2 = cacheDir();
|
|
6080
|
-
if (!
|
|
6081
|
-
|
|
6182
|
+
if (!fs12.existsSync(dir2)) fs12.mkdirSync(dir2, { recursive: true });
|
|
6183
|
+
fs12.writeFileSync(cachePath(), JSON.stringify({ latest, timestamp: Date.now() }));
|
|
6082
6184
|
} catch {
|
|
6083
6185
|
}
|
|
6084
6186
|
}
|
|
6085
6187
|
function readAutoUpdateState(dir2 = cacheDir()) {
|
|
6086
6188
|
try {
|
|
6087
|
-
const raw =
|
|
6189
|
+
const raw = fs12.readFileSync(path9.join(dir2, STATE_FILE), "utf-8");
|
|
6088
6190
|
const state = JSON.parse(raw);
|
|
6089
6191
|
return typeof state?.version === "string" ? state : null;
|
|
6090
6192
|
} catch {
|
|
@@ -6093,14 +6195,14 @@ function readAutoUpdateState(dir2 = cacheDir()) {
|
|
|
6093
6195
|
}
|
|
6094
6196
|
function writeAutoUpdateState(state, dir2 = cacheDir()) {
|
|
6095
6197
|
try {
|
|
6096
|
-
if (!
|
|
6097
|
-
|
|
6198
|
+
if (!fs12.existsSync(dir2)) fs12.mkdirSync(dir2, { recursive: true });
|
|
6199
|
+
fs12.writeFileSync(path9.join(dir2, STATE_FILE), JSON.stringify(state));
|
|
6098
6200
|
} catch {
|
|
6099
6201
|
}
|
|
6100
6202
|
}
|
|
6101
6203
|
function clearAutoUpdateState(dir2 = cacheDir()) {
|
|
6102
6204
|
try {
|
|
6103
|
-
|
|
6205
|
+
fs12.unlinkSync(path9.join(dir2, STATE_FILE));
|
|
6104
6206
|
} catch {
|
|
6105
6207
|
}
|
|
6106
6208
|
}
|
|
@@ -6147,7 +6249,11 @@ function startBackgroundUpdate(latest, pm, dir2 = cacheDir()) {
|
|
|
6147
6249
|
const { cmd, args } = updateCommand(pm);
|
|
6148
6250
|
const script = `const cp=require('child_process');const fs=require('fs');const r=cp.spawnSync(${JSON.stringify(cmd)},${JSON.stringify(args)},{shell:process.platform==='win32',encoding:'utf8'});const out=((r.stdout||'')+(r.stderr||'')).slice(-2000);fs.writeFileSync(${JSON.stringify(stateFile)},JSON.stringify({version:${JSON.stringify(latest)},startedAt:${startedAt},exitCode:r.status==null?-1:r.status,finishedAt:Date.now(),output:out}));`;
|
|
6149
6251
|
try {
|
|
6150
|
-
const child = spawn(process.execPath, ["-e", script], {
|
|
6252
|
+
const child = spawn(process.execPath, ["-e", script], {
|
|
6253
|
+
detached: true,
|
|
6254
|
+
stdio: "ignore",
|
|
6255
|
+
env: inheritedSubprocessEnv()
|
|
6256
|
+
});
|
|
6151
6257
|
child.unref();
|
|
6152
6258
|
return true;
|
|
6153
6259
|
} catch {
|
|
@@ -6219,7 +6325,8 @@ function runUpdate(pm) {
|
|
|
6219
6325
|
const { cmd, args } = updateCommand(pm);
|
|
6220
6326
|
const child = spawn(cmd, args, {
|
|
6221
6327
|
shell: process.platform === "win32",
|
|
6222
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
6328
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
6329
|
+
env: inheritedSubprocessEnv()
|
|
6223
6330
|
});
|
|
6224
6331
|
let out = "";
|
|
6225
6332
|
child.stdout?.on("data", (d) => out += d);
|
|
@@ -6235,22 +6342,30 @@ var UPDATE_CHECK_MS = 6 * 60 * 6e4;
|
|
|
6235
6342
|
var MAX_WORKERS = 30;
|
|
6236
6343
|
var BRIDGE_ATTACH_GRACE_MS = 15e3;
|
|
6237
6344
|
var BRIDGE_IDLE_MS = 2e3;
|
|
6345
|
+
var LIVE_FRAME_APPROVAL_TIMEOUT_MS = 45e3;
|
|
6238
6346
|
var LOG_MAX_BYTES = 1e6;
|
|
6239
6347
|
var LOG_FILE = path9.join(os6.homedir(), ".standardagents", "daemon.log");
|
|
6240
|
-
function
|
|
6348
|
+
function appendPrivateLog(file2, line, maxBytes) {
|
|
6241
6349
|
try {
|
|
6242
|
-
|
|
6350
|
+
const directory = path9.dirname(file2);
|
|
6351
|
+
fs12.mkdirSync(directory, { recursive: true, mode: 448 });
|
|
6352
|
+
fs12.chmodSync(directory, 448);
|
|
6243
6353
|
try {
|
|
6244
|
-
|
|
6245
|
-
|
|
6354
|
+
fs12.chmodSync(file2, 384);
|
|
6355
|
+
if (fs12.statSync(file2).size > maxBytes) {
|
|
6356
|
+
fs12.renameSync(file2, `${file2}.old`);
|
|
6246
6357
|
}
|
|
6247
6358
|
} catch {
|
|
6248
6359
|
}
|
|
6249
|
-
|
|
6250
|
-
|
|
6360
|
+
fs12.appendFileSync(file2, line, { mode: 384 });
|
|
6361
|
+
fs12.chmodSync(file2, 384);
|
|
6251
6362
|
} catch {
|
|
6252
6363
|
}
|
|
6253
6364
|
}
|
|
6365
|
+
function daemonLog(line) {
|
|
6366
|
+
appendPrivateLog(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
|
|
6367
|
+
`, LOG_MAX_BYTES);
|
|
6368
|
+
}
|
|
6254
6369
|
function pathFromTags(tags) {
|
|
6255
6370
|
const tag = tags.find((t) => t.startsWith("path:"));
|
|
6256
6371
|
if (!tag) return null;
|
|
@@ -6315,7 +6430,8 @@ var ThreadWorker = class {
|
|
|
6315
6430
|
const permKey = permissionKey(req);
|
|
6316
6431
|
const fresh = decide(this.perm, permKey, effectiveRisk, !!req.requestPermission);
|
|
6317
6432
|
if (fresh === "allow") return { choice: "allow" };
|
|
6318
|
-
|
|
6433
|
+
const relayId = req.toolCallId ?? req.id;
|
|
6434
|
+
if (!relayId) {
|
|
6319
6435
|
return { choice: "deny", reason: "No one is available to approve this right now." };
|
|
6320
6436
|
}
|
|
6321
6437
|
daemonLog(`[${threadId.slice(0, 8)}] relaying approval: ${summary} (risk ${effectiveRisk})`);
|
|
@@ -6326,7 +6442,7 @@ var ThreadWorker = class {
|
|
|
6326
6442
|
api,
|
|
6327
6443
|
threadId,
|
|
6328
6444
|
{
|
|
6329
|
-
tool_call_id:
|
|
6445
|
+
tool_call_id: relayId,
|
|
6330
6446
|
tool: req.tool,
|
|
6331
6447
|
summary,
|
|
6332
6448
|
permission: req.requestPermission,
|
|
@@ -6334,7 +6450,15 @@ var ThreadWorker = class {
|
|
|
6334
6450
|
machine: machineName,
|
|
6335
6451
|
requested_at: Date.now()
|
|
6336
6452
|
},
|
|
6337
|
-
{
|
|
6453
|
+
{
|
|
6454
|
+
subscribe: (wake) => approvalWakes.subscribe(threadId, wake),
|
|
6455
|
+
// A live frame is answered over the socket and the server fails
|
|
6456
|
+
// the call on its own frame timeout — bound the human wait so a
|
|
6457
|
+
// late "allow" can never execute a side effect into a frame the
|
|
6458
|
+
// server already gave up on. Durable calls park server-side and
|
|
6459
|
+
// keep the long default.
|
|
6460
|
+
timeoutMs: req.toolCallId ? void 0 : LIVE_FRAME_APPROVAL_TIMEOUT_MS
|
|
6461
|
+
}
|
|
6338
6462
|
);
|
|
6339
6463
|
if (!response) {
|
|
6340
6464
|
return { choice: "deny", reason: "The approval request timed out with no one to approve it." };
|
|
@@ -6509,7 +6633,7 @@ Run \`standardcode daemon install\` (or plain \`standardcode\`) once to sign in.
|
|
|
6509
6633
|
daemonLog(`detached ${oldest.threadId.slice(0, 8)} (worker cap)`);
|
|
6510
6634
|
}
|
|
6511
6635
|
try {
|
|
6512
|
-
|
|
6636
|
+
fs12.mkdirSync(projectDir, { recursive: true });
|
|
6513
6637
|
} catch (e) {
|
|
6514
6638
|
daemonLog(`cannot prepare project dir ${projectDir}: ${e instanceof Error ? e.message : String(e)}`);
|
|
6515
6639
|
return;
|
|
@@ -6812,7 +6936,7 @@ function resolveDaemonCommand(extraArgs = []) {
|
|
|
6812
6936
|
let tsx = null;
|
|
6813
6937
|
for (let i = 0; i < 6 && dir2 !== path9.dirname(dir2); i++) {
|
|
6814
6938
|
const candidate = path9.join(dir2, "node_modules", "tsx", "dist", "cli.mjs");
|
|
6815
|
-
if (
|
|
6939
|
+
if (fs12.existsSync(candidate)) {
|
|
6816
6940
|
tsx = candidate;
|
|
6817
6941
|
break;
|
|
6818
6942
|
}
|
|
@@ -6842,7 +6966,10 @@ function servicePath() {
|
|
|
6842
6966
|
return [.../* @__PURE__ */ new Set([...current, ...parts])].join(":");
|
|
6843
6967
|
}
|
|
6844
6968
|
function run2(cmd, args) {
|
|
6845
|
-
const res = spawnSync(cmd, args, {
|
|
6969
|
+
const res = spawnSync(cmd, args, {
|
|
6970
|
+
encoding: "utf8",
|
|
6971
|
+
env: inheritedSubprocessEnv()
|
|
6972
|
+
});
|
|
6846
6973
|
const output4 = `${res.stdout ?? ""}${res.stderr ?? ""}`.trim();
|
|
6847
6974
|
return { ok: res.status === 0, output: output4 };
|
|
6848
6975
|
}
|
|
@@ -6860,8 +6987,8 @@ function installService(command, endpoint) {
|
|
|
6860
6987
|
}
|
|
6861
6988
|
function installLaunchd(command, endpoint) {
|
|
6862
6989
|
const logDir = path9.join(os6.homedir(), ".standardagents");
|
|
6863
|
-
|
|
6864
|
-
|
|
6990
|
+
fs12.mkdirSync(logDir, { recursive: true });
|
|
6991
|
+
fs12.mkdirSync(path9.dirname(plistPath()), { recursive: true });
|
|
6865
6992
|
const envEntries = [
|
|
6866
6993
|
` <key>PATH</key><string>${xmlEscape(servicePath())}</string>`,
|
|
6867
6994
|
...endpoint ? [` <key>STANDARD_CODE_DAEMON_ENDPOINT</key><string>${xmlEscape(endpoint)}</string>`] : []
|
|
@@ -6887,7 +7014,7 @@ ${envEntries}
|
|
|
6887
7014
|
</dict>
|
|
6888
7015
|
</plist>
|
|
6889
7016
|
`;
|
|
6890
|
-
|
|
7017
|
+
fs12.writeFileSync(plistPath(), plist);
|
|
6891
7018
|
const uid = typeof process.getuid === "function" ? process.getuid() : 501;
|
|
6892
7019
|
run2("launchctl", ["bootout", `gui/${uid}`, plistPath()]);
|
|
6893
7020
|
const boot = run2("launchctl", ["bootstrap", `gui/${uid}`, plistPath()]);
|
|
@@ -6904,7 +7031,7 @@ ${envEntries}
|
|
|
6904
7031
|
return { ok: true, detail: `LaunchAgent installed (${plistPath()})` };
|
|
6905
7032
|
}
|
|
6906
7033
|
function installSystemd(command, endpoint) {
|
|
6907
|
-
|
|
7034
|
+
fs12.mkdirSync(path9.dirname(unitPath()), { recursive: true });
|
|
6908
7035
|
const unit = `[Unit]
|
|
6909
7036
|
Description=Standard Code daemon (headless coding-agent execution client)
|
|
6910
7037
|
After=network-online.target
|
|
@@ -6919,7 +7046,7 @@ ${endpoint ? `Environment=STANDARD_CODE_DAEMON_ENDPOINT=${endpoint}
|
|
|
6919
7046
|
[Install]
|
|
6920
7047
|
WantedBy=default.target
|
|
6921
7048
|
`;
|
|
6922
|
-
|
|
7049
|
+
fs12.writeFileSync(unitPath(), unit);
|
|
6923
7050
|
const reload = run2("systemctl", ["--user", "daemon-reload"]);
|
|
6924
7051
|
if (!reload.ok) {
|
|
6925
7052
|
return {
|
|
@@ -6943,7 +7070,7 @@ function uninstallService() {
|
|
|
6943
7070
|
const uid = typeof process.getuid === "function" ? process.getuid() : 501;
|
|
6944
7071
|
run2("launchctl", ["bootout", `gui/${uid}`, plistPath()]);
|
|
6945
7072
|
try {
|
|
6946
|
-
|
|
7073
|
+
fs12.unlinkSync(plistPath());
|
|
6947
7074
|
} catch {
|
|
6948
7075
|
}
|
|
6949
7076
|
return { ok: true, detail: "LaunchAgent removed" };
|
|
@@ -6951,7 +7078,7 @@ function uninstallService() {
|
|
|
6951
7078
|
if (process.platform === "linux") {
|
|
6952
7079
|
run2("systemctl", ["--user", "disable", "--now", SYSTEMD_UNIT]);
|
|
6953
7080
|
try {
|
|
6954
|
-
|
|
7081
|
+
fs12.unlinkSync(unitPath());
|
|
6955
7082
|
} catch {
|
|
6956
7083
|
}
|
|
6957
7084
|
run2("systemctl", ["--user", "daemon-reload"]);
|
|
@@ -6961,7 +7088,7 @@ function uninstallService() {
|
|
|
6961
7088
|
}
|
|
6962
7089
|
function serviceStatus() {
|
|
6963
7090
|
if (process.platform === "darwin") {
|
|
6964
|
-
const installed =
|
|
7091
|
+
const installed = fs12.existsSync(plistPath());
|
|
6965
7092
|
const list = run2("launchctl", ["list", SERVICE_LABEL]);
|
|
6966
7093
|
const pidMatch = list.output.match(/"PID"\s*=\s*(\d+)/);
|
|
6967
7094
|
return {
|
|
@@ -6971,7 +7098,7 @@ function serviceStatus() {
|
|
|
6971
7098
|
};
|
|
6972
7099
|
}
|
|
6973
7100
|
if (process.platform === "linux") {
|
|
6974
|
-
const installed =
|
|
7101
|
+
const installed = fs12.existsSync(unitPath());
|
|
6975
7102
|
const active = run2("systemctl", ["--user", "is-active", SYSTEMD_UNIT]);
|
|
6976
7103
|
return {
|
|
6977
7104
|
installed,
|
|
@@ -7194,7 +7321,7 @@ async function projectCommand(action, target) {
|
|
|
7194
7321
|
process.exit(1);
|
|
7195
7322
|
}
|
|
7196
7323
|
const dir2 = path9.resolve(target);
|
|
7197
|
-
if (action === "add" && !
|
|
7324
|
+
if (action === "add" && !fs12.existsSync(dir2)) {
|
|
7198
7325
|
stdout.write(`${c3.red}\u2717${c3.reset} ${dir2} does not exist on this machine.
|
|
7199
7326
|
`);
|
|
7200
7327
|
process.exit(1);
|
|
@@ -7263,15 +7390,15 @@ var DIR = path9.join(os6.homedir(), ".standardagents");
|
|
|
7263
7390
|
var FILE = path9.join(DIR, "prefs.json");
|
|
7264
7391
|
function loadPrefs(file2 = FILE) {
|
|
7265
7392
|
try {
|
|
7266
|
-
return JSON.parse(
|
|
7393
|
+
return JSON.parse(fs12.readFileSync(file2, "utf8"));
|
|
7267
7394
|
} catch {
|
|
7268
7395
|
return {};
|
|
7269
7396
|
}
|
|
7270
7397
|
}
|
|
7271
7398
|
function savePrefs(update, file2 = FILE) {
|
|
7272
7399
|
const merged = { ...loadPrefs(file2), ...update };
|
|
7273
|
-
|
|
7274
|
-
|
|
7400
|
+
fs12.mkdirSync(path9.dirname(file2), { recursive: true });
|
|
7401
|
+
fs12.writeFileSync(file2, JSON.stringify(merged, null, 2));
|
|
7275
7402
|
}
|
|
7276
7403
|
function shouldOfferDaemonInstall(facts) {
|
|
7277
7404
|
if (facts.optedOutEnv) return false;
|
|
@@ -8446,10 +8573,14 @@ async function runInteractive(tui, api, accountStream, threadId, projectDir, mac
|
|
|
8446
8573
|
let reconcileSharedMessaging = async () => {
|
|
8447
8574
|
};
|
|
8448
8575
|
let applySharedMessagingEvent = () => false;
|
|
8449
|
-
let refreshSessionProjection = async () => {
|
|
8450
|
-
};
|
|
8451
8576
|
let scheduleProjectionRefresh = () => {
|
|
8452
8577
|
};
|
|
8578
|
+
let connectionEpoch = 0;
|
|
8579
|
+
let projectionSnapshot = null;
|
|
8580
|
+
const sharedMessagingSnapshot = new snapshot_epoch_exports.EpochSnapshot(
|
|
8581
|
+
() => reconcileSharedMessaging(true),
|
|
8582
|
+
() => connectionEpoch
|
|
8583
|
+
);
|
|
8453
8584
|
const shownIds = /* @__PURE__ */ new Set();
|
|
8454
8585
|
const toolActivity = new ToolActivityFeed();
|
|
8455
8586
|
const pendingSent = /* @__PURE__ */ new Map();
|
|
@@ -8467,9 +8598,10 @@ async function runInteractive(tui, api, accountStream, threadId, projectDir, mac
|
|
|
8467
8598
|
tui.setStep(label, liveOut);
|
|
8468
8599
|
};
|
|
8469
8600
|
const stream = new stream_exports.MessageStream(api, threadId, {
|
|
8470
|
-
onOpen: () => {
|
|
8471
|
-
|
|
8472
|
-
void
|
|
8601
|
+
onOpen: (epoch) => {
|
|
8602
|
+
connectionEpoch = epoch;
|
|
8603
|
+
void sharedMessagingSnapshot.reconcile(epoch);
|
|
8604
|
+
void projectionSnapshot?.reconcile(epoch);
|
|
8473
8605
|
},
|
|
8474
8606
|
// Live streaming preview: answer text and (opt-in) internal reasoning feed
|
|
8475
8607
|
// the TUI's ephemeral preview; the committed message still renders from
|
|
@@ -8502,7 +8634,7 @@ async function runInteractive(tui, api, accountStream, threadId, projectDir, mac
|
|
|
8502
8634
|
void relayApprovals().catch(() => {
|
|
8503
8635
|
});
|
|
8504
8636
|
} else if (eventType === shared_messaging_exports.SHARED_MESSAGING_EVENT) {
|
|
8505
|
-
if (!applySharedMessagingEvent(data)) void
|
|
8637
|
+
if (!applySharedMessagingEvent(data)) void sharedMessagingSnapshot.refresh();
|
|
8506
8638
|
}
|
|
8507
8639
|
},
|
|
8508
8640
|
// A failed turn whose message is the lease service's at-limit denial → offer
|
|
@@ -8676,7 +8808,7 @@ async function runInteractive(tui, api, accountStream, threadId, projectDir, mac
|
|
|
8676
8808
|
applySharedMessaging({ version: 1, pending: sharedMessaging.pending, draft: event.draft }, true);
|
|
8677
8809
|
return true;
|
|
8678
8810
|
};
|
|
8679
|
-
const onTerminalResume = () => void
|
|
8811
|
+
const onTerminalResume = () => void sharedMessagingSnapshot.refresh();
|
|
8680
8812
|
process.on("SIGCONT", onTerminalResume);
|
|
8681
8813
|
const applySharedMutation = (promise) => promise.then((snapshot) => {
|
|
8682
8814
|
applySharedMessaging(snapshot, false);
|
|
@@ -8995,7 +9127,7 @@ ${c5.gray}Close another session (its slot frees within ~90s), then resend your m
|
|
|
8995
9127
|
]);
|
|
8996
9128
|
const history = await (0, history_exports.loadHistory)(api, threadId, historySeedThreadId);
|
|
8997
9129
|
tui.setHistory(history);
|
|
8998
|
-
await
|
|
9130
|
+
await sharedMessagingSnapshot.refresh();
|
|
8999
9131
|
let latestDraftPayload = null;
|
|
9000
9132
|
let draftDirty = false;
|
|
9001
9133
|
let draftInFlight = false;
|
|
@@ -9235,11 +9367,7 @@ ${c5.dim}runs on ${request.machine || runnerName}${c5.reset}`,
|
|
|
9235
9367
|
stalledNoticeShown = false;
|
|
9236
9368
|
}
|
|
9237
9369
|
} catch {
|
|
9238
|
-
|
|
9239
|
-
msgs = await api.getMessages(threadId, 60);
|
|
9240
|
-
} catch {
|
|
9241
|
-
return;
|
|
9242
|
-
}
|
|
9370
|
+
msgs = await api.getMessages(threadId, 60);
|
|
9243
9371
|
}
|
|
9244
9372
|
const sorted = [...msgs].sort((a, b) => (a.created_at ?? 0) - (b.created_at ?? 0));
|
|
9245
9373
|
for (const m of sorted) toolActivity.index(m);
|
|
@@ -9335,17 +9463,19 @@ ${c5.dim}runs on ${request.machine || runnerName}${c5.reset}`,
|
|
|
9335
9463
|
} catch {
|
|
9336
9464
|
}
|
|
9337
9465
|
};
|
|
9338
|
-
|
|
9339
|
-
|
|
9466
|
+
projectionSnapshot = new snapshot_epoch_exports.EpochSnapshot(
|
|
9467
|
+
reconcileProjection,
|
|
9468
|
+
() => connectionEpoch
|
|
9469
|
+
);
|
|
9340
9470
|
let projectionDebounce = null;
|
|
9341
9471
|
scheduleProjectionRefresh = () => {
|
|
9342
9472
|
if (projectionDebounce) return;
|
|
9343
9473
|
projectionDebounce = setTimeout(() => {
|
|
9344
9474
|
projectionDebounce = null;
|
|
9345
|
-
void
|
|
9475
|
+
void projectionSnapshot?.refresh();
|
|
9346
9476
|
}, 250);
|
|
9347
9477
|
};
|
|
9348
|
-
await
|
|
9478
|
+
await projectionSnapshot.reconcile(connectionEpoch);
|
|
9349
9479
|
await sessionEnded;
|
|
9350
9480
|
if (projectionDebounce) clearTimeout(projectionDebounce);
|
|
9351
9481
|
process.off("SIGCONT", onTerminalResume);
|