@standardagents/code 0.13.7 → 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 +16 -3
- package/dist/index.js +206 -84
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import * as transcript_delivery_star from '@standardagents/code-network/transcri
|
|
|
13
13
|
import * as approvals_star from '@standardagents/code-network/approvals';
|
|
14
14
|
import net from 'net';
|
|
15
15
|
import { setImmediate } from 'timers';
|
|
16
|
-
import
|
|
16
|
+
import fs12 from 'fs';
|
|
17
17
|
import { permissionKey, Bridge as Bridge$1 } from '@standardagents/code-network/bridge';
|
|
18
18
|
import readline from 'readline';
|
|
19
19
|
import * as types_star from '@standardagents/code-network/types';
|
|
@@ -103,10 +103,10 @@ var AccountUserStream = class {
|
|
|
103
103
|
options.uniqueConnectionId
|
|
104
104
|
);
|
|
105
105
|
}
|
|
106
|
-
start() {
|
|
106
|
+
async start() {
|
|
107
107
|
if (this.started) return;
|
|
108
108
|
this.started = true;
|
|
109
|
-
this.hub.start();
|
|
109
|
+
await this.hub.start();
|
|
110
110
|
}
|
|
111
111
|
onEvent(listener) {
|
|
112
112
|
this.eventListeners.add(listener);
|
|
@@ -119,7 +119,7 @@ var AccountUserStream = class {
|
|
|
119
119
|
/** Wait for a live socket. The timeout is local and performs no network work. */
|
|
120
120
|
waitUntilConnected(timeoutMs = 15e3) {
|
|
121
121
|
if (this.connected) return Promise.resolve();
|
|
122
|
-
this.start();
|
|
122
|
+
void this.start();
|
|
123
123
|
return new Promise((resolve, reject) => {
|
|
124
124
|
let timer;
|
|
125
125
|
const remove = this.onConnection((state) => {
|
|
@@ -217,6 +217,7 @@ function riskCeiling(state) {
|
|
|
217
217
|
function decide(state, tool, risk, hasPermissionRequest) {
|
|
218
218
|
const effectiveRisk = typeof risk === "number" ? Math.min(5, Math.max(1, risk)) : hasPermissionRequest ? 3 : 1;
|
|
219
219
|
if (state.alwaysAllow.has(tool)) return "allow";
|
|
220
|
+
if (hasPermissionRequest) return "ask";
|
|
220
221
|
return effectiveRisk <= riskCeiling(state) ? "allow" : "ask";
|
|
221
222
|
}
|
|
222
223
|
var CATASTROPHIC_PATTERNS = [
|
|
@@ -420,7 +421,7 @@ var ToolLedger = class {
|
|
|
420
421
|
if (this.loaded) return;
|
|
421
422
|
this.loaded = true;
|
|
422
423
|
try {
|
|
423
|
-
const raw =
|
|
424
|
+
const raw = fs12.readFileSync(this.file, "utf8");
|
|
424
425
|
const parsed = JSON.parse(raw);
|
|
425
426
|
for (const [id, entry] of Object.entries(parsed)) {
|
|
426
427
|
if (entry && typeof entry.ok === "boolean") this.entries.set(id, entry);
|
|
@@ -452,13 +453,13 @@ var ToolLedger = class {
|
|
|
452
453
|
}
|
|
453
454
|
persist() {
|
|
454
455
|
try {
|
|
455
|
-
|
|
456
|
+
fs12.mkdirSync(ledgerDir(), { recursive: true });
|
|
456
457
|
const out = {};
|
|
457
458
|
for (const [id, entry] of this.entries) {
|
|
458
459
|
const size = entry.result ? Buffer.byteLength(entry.result) : 0;
|
|
459
460
|
out[id] = size > MAX_RESULT_BYTES ? { ...entry, result: void 0 } : entry;
|
|
460
461
|
}
|
|
461
|
-
|
|
462
|
+
fs12.writeFileSync(this.file, JSON.stringify(out), { mode: 384 });
|
|
462
463
|
} catch {
|
|
463
464
|
}
|
|
464
465
|
}
|
|
@@ -1546,6 +1547,46 @@ var WordMill = class {
|
|
|
1546
1547
|
// src/types.ts
|
|
1547
1548
|
var types_exports = {};
|
|
1548
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
|
|
1549
1590
|
var FILE_MIMES = {
|
|
1550
1591
|
".png": "image/png",
|
|
1551
1592
|
".jpg": "image/jpeg",
|
|
@@ -1556,7 +1597,11 @@ var FILE_MIMES = {
|
|
|
1556
1597
|
var MAX_IMAGE_BYTES = 8 * 1024 * 1024;
|
|
1557
1598
|
function run(cmd, args, maxBuffer = MAX_IMAGE_BYTES * 2) {
|
|
1558
1599
|
return new Promise((resolve) => {
|
|
1559
|
-
execFile(cmd, args, {
|
|
1600
|
+
execFile(cmd, args, {
|
|
1601
|
+
encoding: "buffer",
|
|
1602
|
+
maxBuffer,
|
|
1603
|
+
env: inheritedSubprocessEnv()
|
|
1604
|
+
}, (err, stdout) => {
|
|
1560
1605
|
resolve({ ok: !err, stdout: stdout ?? Buffer.alloc(0) });
|
|
1561
1606
|
});
|
|
1562
1607
|
});
|
|
@@ -1565,9 +1610,9 @@ function fromFile(filePath) {
|
|
|
1565
1610
|
const mime = FILE_MIMES[path9.extname(filePath).toLowerCase()];
|
|
1566
1611
|
if (!mime) return null;
|
|
1567
1612
|
try {
|
|
1568
|
-
const stat =
|
|
1613
|
+
const stat = fs12.statSync(filePath);
|
|
1569
1614
|
if (!stat.isFile() || stat.size === 0 || stat.size > MAX_IMAGE_BYTES) return null;
|
|
1570
|
-
return { data:
|
|
1615
|
+
return { data: fs12.readFileSync(filePath).toString("base64"), mime };
|
|
1571
1616
|
} catch {
|
|
1572
1617
|
return null;
|
|
1573
1618
|
}
|
|
@@ -1585,7 +1630,7 @@ async function readDarwin() {
|
|
|
1585
1630
|
if (png.ok) {
|
|
1586
1631
|
const img = fromFile(tmp);
|
|
1587
1632
|
try {
|
|
1588
|
-
|
|
1633
|
+
fs12.unlinkSync(tmp);
|
|
1589
1634
|
} catch {
|
|
1590
1635
|
}
|
|
1591
1636
|
if (img) return img;
|
|
@@ -1619,7 +1664,7 @@ async function readWindows() {
|
|
|
1619
1664
|
await run("powershell", ["-NoProfile", "-STA", "-Command", ps]);
|
|
1620
1665
|
const img = fromFile(tmp);
|
|
1621
1666
|
try {
|
|
1622
|
-
|
|
1667
|
+
fs12.unlinkSync(tmp);
|
|
1623
1668
|
} catch {
|
|
1624
1669
|
}
|
|
1625
1670
|
return img;
|
|
@@ -3816,6 +3861,18 @@ __reExport(shared_messaging_exports, shared_messaging_star);
|
|
|
3816
3861
|
var history_exports = {};
|
|
3817
3862
|
__reExport(history_exports, history_star);
|
|
3818
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
|
+
}
|
|
3819
3876
|
function isAlive(pid) {
|
|
3820
3877
|
try {
|
|
3821
3878
|
process.kill(pid, 0);
|
|
@@ -3834,7 +3891,7 @@ function configFile() {
|
|
|
3834
3891
|
}
|
|
3835
3892
|
function loadMcpConfig() {
|
|
3836
3893
|
try {
|
|
3837
|
-
const raw =
|
|
3894
|
+
const raw = fs12.readFileSync(configFile(), "utf8");
|
|
3838
3895
|
const parsed = JSON.parse(raw);
|
|
3839
3896
|
if (!parsed.servers || typeof parsed.servers !== "object") parsed.servers = {};
|
|
3840
3897
|
return parsed;
|
|
@@ -3865,8 +3922,8 @@ function setMcpServerEnabled(name, enabled) {
|
|
|
3865
3922
|
}
|
|
3866
3923
|
function write(cfg) {
|
|
3867
3924
|
const file2 = configFile();
|
|
3868
|
-
|
|
3869
|
-
|
|
3925
|
+
fs12.mkdirSync(path9.dirname(file2), { recursive: true });
|
|
3926
|
+
fs12.writeFileSync(file2, JSON.stringify(cfg, null, 2), { mode: 384 });
|
|
3870
3927
|
}
|
|
3871
3928
|
function parseServerSpec(spec) {
|
|
3872
3929
|
const trimmed = spec.trim();
|
|
@@ -3937,7 +3994,11 @@ function openUrl(url) {
|
|
|
3937
3994
|
const cmd = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
3938
3995
|
const args = platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
3939
3996
|
try {
|
|
3940
|
-
const child = spawn(cmd, args, {
|
|
3997
|
+
const child = spawn(cmd, args, {
|
|
3998
|
+
stdio: "ignore",
|
|
3999
|
+
detached: true,
|
|
4000
|
+
env: inheritedSubprocessEnv()
|
|
4001
|
+
});
|
|
3941
4002
|
child.unref();
|
|
3942
4003
|
} catch {
|
|
3943
4004
|
}
|
|
@@ -3949,11 +4010,11 @@ __reExport(recorder_exports, recorder_star);
|
|
|
3949
4010
|
__reExport(recorder_exports, recorder_node_star);
|
|
3950
4011
|
function readVersion() {
|
|
3951
4012
|
try {
|
|
3952
|
-
const pkg = JSON.parse(
|
|
4013
|
+
const pkg = JSON.parse(fs12.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
3953
4014
|
if (typeof pkg.version === "string" && pkg.version) return pkg.version;
|
|
3954
4015
|
} catch {
|
|
3955
4016
|
}
|
|
3956
|
-
return "0.13.
|
|
4017
|
+
return "0.13.8" ;
|
|
3957
4018
|
}
|
|
3958
4019
|
function isLocalHost(host) {
|
|
3959
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);
|
|
@@ -3979,7 +4040,7 @@ var dir = () => path9.join(os6.homedir(), ".standardagents");
|
|
|
3979
4040
|
var file = () => path9.join(dir(), "machine.json");
|
|
3980
4041
|
function loadMachineIdentity() {
|
|
3981
4042
|
try {
|
|
3982
|
-
const parsed = JSON.parse(
|
|
4043
|
+
const parsed = JSON.parse(fs12.readFileSync(file(), "utf8"));
|
|
3983
4044
|
if (typeof parsed.machine_id === "string" && parsed.machine_id.length > 0) {
|
|
3984
4045
|
return { machine_id: parsed.machine_id, created_at: parsed.created_at ?? Date.now() };
|
|
3985
4046
|
}
|
|
@@ -3993,8 +4054,8 @@ function loadMachineIdentity() {
|
|
|
3993
4054
|
return identity;
|
|
3994
4055
|
}
|
|
3995
4056
|
function saveMachineIdentity(identity) {
|
|
3996
|
-
|
|
3997
|
-
|
|
4057
|
+
fs12.mkdirSync(dir(), { recursive: true });
|
|
4058
|
+
fs12.writeFileSync(file(), JSON.stringify(identity, null, 2), { mode: 384 });
|
|
3998
4059
|
}
|
|
3999
4060
|
function daemonClientId(identity) {
|
|
4000
4061
|
return `daemon:${identity.machine_id}`;
|
|
@@ -4325,7 +4386,8 @@ function projectRepository(projectDir) {
|
|
|
4325
4386
|
const url = execFileSync("git", ["-C", projectDir, "remote", "get-url", "origin"], {
|
|
4326
4387
|
encoding: "utf8",
|
|
4327
4388
|
timeout: 3e3,
|
|
4328
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
4389
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
4390
|
+
env: inheritedSubprocessEnv()
|
|
4329
4391
|
}).trim();
|
|
4330
4392
|
return url || null;
|
|
4331
4393
|
} catch {
|
|
@@ -4504,7 +4566,7 @@ function markers(dirPath) {
|
|
|
4504
4566
|
for (const marker of PROJECT_MARKERS) {
|
|
4505
4567
|
let hit = false;
|
|
4506
4568
|
try {
|
|
4507
|
-
hit =
|
|
4569
|
+
hit = fs12.existsSync(path9.join(dirPath, marker));
|
|
4508
4570
|
} catch {
|
|
4509
4571
|
hit = false;
|
|
4510
4572
|
}
|
|
@@ -4526,11 +4588,11 @@ function browseDirectory(input3, opts = {}) {
|
|
|
4526
4588
|
};
|
|
4527
4589
|
let dirents;
|
|
4528
4590
|
try {
|
|
4529
|
-
const stat =
|
|
4591
|
+
const stat = fs12.statSync(abs);
|
|
4530
4592
|
if (!stat.isDirectory()) {
|
|
4531
4593
|
return { ...base, entries: [], truncated: false, error: "Not a directory" };
|
|
4532
4594
|
}
|
|
4533
|
-
dirents =
|
|
4595
|
+
dirents = fs12.readdirSync(abs, { withFileTypes: true });
|
|
4534
4596
|
} catch (err) {
|
|
4535
4597
|
const code = err?.code;
|
|
4536
4598
|
const message = code === "EACCES" || code === "EPERM" ? "Permission denied" : code === "ENOENT" ? "Folder not found" : "Could not read this folder";
|
|
@@ -4545,7 +4607,7 @@ function browseDirectory(input3, opts = {}) {
|
|
|
4545
4607
|
let isDir = d.isDirectory();
|
|
4546
4608
|
if (d.isSymbolicLink()) {
|
|
4547
4609
|
try {
|
|
4548
|
-
isDir =
|
|
4610
|
+
isDir = fs12.statSync(path9.join(abs, name)).isDirectory();
|
|
4549
4611
|
} catch {
|
|
4550
4612
|
isDir = false;
|
|
4551
4613
|
}
|
|
@@ -4576,7 +4638,7 @@ function mkdirDirectory(parentInput, name, opts = {}) {
|
|
|
4576
4638
|
return { ...listParent(), error: "Invalid folder name." };
|
|
4577
4639
|
}
|
|
4578
4640
|
try {
|
|
4579
|
-
|
|
4641
|
+
fs12.mkdirSync(target, { recursive: false });
|
|
4580
4642
|
} catch (err) {
|
|
4581
4643
|
const code = err?.code;
|
|
4582
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.";
|
|
@@ -4791,7 +4853,10 @@ function probe(cmd) {
|
|
|
4791
4853
|
return new Promise((resolve) => {
|
|
4792
4854
|
let child;
|
|
4793
4855
|
try {
|
|
4794
|
-
child = spawn(cmd, ["--version"], {
|
|
4856
|
+
child = spawn(cmd, ["--version"], {
|
|
4857
|
+
stdio: "ignore",
|
|
4858
|
+
env: inheritedSubprocessEnv()
|
|
4859
|
+
});
|
|
4795
4860
|
} catch {
|
|
4796
4861
|
resolve(false);
|
|
4797
4862
|
return;
|
|
@@ -4827,7 +4892,7 @@ function download(url, dest, redirects = 5) {
|
|
|
4827
4892
|
reject(new Error(`HTTP ${status} for ${url}`));
|
|
4828
4893
|
return;
|
|
4829
4894
|
}
|
|
4830
|
-
const out =
|
|
4895
|
+
const out = fs12.createWriteStream(dest);
|
|
4831
4896
|
res.pipe(out);
|
|
4832
4897
|
out.on("finish", () => out.close(() => resolve()));
|
|
4833
4898
|
out.on("error", reject);
|
|
@@ -4838,7 +4903,7 @@ function download(url, dest, redirects = 5) {
|
|
|
4838
4903
|
async function sha256File(file2) {
|
|
4839
4904
|
const hash = crypto.createHash("sha256");
|
|
4840
4905
|
await new Promise((resolve, reject) => {
|
|
4841
|
-
const stream =
|
|
4906
|
+
const stream = fs12.createReadStream(file2);
|
|
4842
4907
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
4843
4908
|
stream.on("end", () => resolve());
|
|
4844
4909
|
stream.on("error", reject);
|
|
@@ -4849,7 +4914,11 @@ function runOk(cmd, args, cwd) {
|
|
|
4849
4914
|
return new Promise((resolve) => {
|
|
4850
4915
|
let child;
|
|
4851
4916
|
try {
|
|
4852
|
-
child = spawn(cmd, args, {
|
|
4917
|
+
child = spawn(cmd, args, {
|
|
4918
|
+
cwd,
|
|
4919
|
+
stdio: "ignore",
|
|
4920
|
+
env: inheritedSubprocessEnv()
|
|
4921
|
+
});
|
|
4853
4922
|
} catch {
|
|
4854
4923
|
resolve(false);
|
|
4855
4924
|
return;
|
|
@@ -4876,7 +4945,7 @@ async function provision(target) {
|
|
|
4876
4945
|
let extracted = null;
|
|
4877
4946
|
for (const entry of entries) {
|
|
4878
4947
|
const candidate = entry.isDirectory() ? path9.join(work, entry.name, binName) : entry.name === binName ? path9.join(work, entry.name) : null;
|
|
4879
|
-
if (candidate &&
|
|
4948
|
+
if (candidate && fs12.existsSync(candidate)) {
|
|
4880
4949
|
extracted = candidate;
|
|
4881
4950
|
break;
|
|
4882
4951
|
}
|
|
@@ -4901,7 +4970,7 @@ function resolveRg(log) {
|
|
|
4901
4970
|
const override = process.env.STANDARDCODE_RG_PATH;
|
|
4902
4971
|
if (override && await probe(override)) return override;
|
|
4903
4972
|
if (await probe("rg")) return "rg";
|
|
4904
|
-
if (
|
|
4973
|
+
if (fs12.existsSync(RG_BIN) && await probe(RG_BIN)) return RG_BIN;
|
|
4905
4974
|
const target = RG_TARGETS[`${process.platform}-${process.arch}`];
|
|
4906
4975
|
if (!target) return null;
|
|
4907
4976
|
try {
|
|
@@ -4960,16 +5029,36 @@ var HostTools = class {
|
|
|
4960
5029
|
mcp;
|
|
4961
5030
|
onMcpCatalogChange;
|
|
4962
5031
|
api;
|
|
4963
|
-
/** 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. */
|
|
4964
5037
|
resolve(p) {
|
|
4965
5038
|
if (!p || p === ".") return this.projectDir;
|
|
5039
|
+
if (p === "~" || p.startsWith("~/")) {
|
|
5040
|
+
p = path9.join(os6.homedir(), p.slice(1));
|
|
5041
|
+
}
|
|
4966
5042
|
return path9.resolve(this.projectDir, p);
|
|
4967
5043
|
}
|
|
4968
|
-
/**
|
|
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. */
|
|
4969
5057
|
isOutsideProject(p) {
|
|
4970
|
-
const
|
|
4971
|
-
const
|
|
4972
|
-
|
|
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);
|
|
4973
5062
|
}
|
|
4974
5063
|
async execute(tool, args) {
|
|
4975
5064
|
try {
|
|
@@ -5065,7 +5154,7 @@ var HostTools = class {
|
|
|
5065
5154
|
const file2 = this.resolve(String(args.path || ""));
|
|
5066
5155
|
const content = String(args.content ?? "");
|
|
5067
5156
|
await fsp2.mkdir(path9.dirname(file2), { recursive: true });
|
|
5068
|
-
const existed =
|
|
5157
|
+
const existed = fs12.existsSync(file2);
|
|
5069
5158
|
await fsp2.writeFile(file2, content, "utf8");
|
|
5070
5159
|
return {
|
|
5071
5160
|
ok: true,
|
|
@@ -5107,7 +5196,7 @@ var HostTools = class {
|
|
|
5107
5196
|
if (!bytes) return { ok: false, error: `Could not download ${source} from the thread filesystem.` };
|
|
5108
5197
|
const dest = this.resolve(destArg);
|
|
5109
5198
|
await fsp2.mkdir(path9.dirname(dest), { recursive: true });
|
|
5110
|
-
const existed =
|
|
5199
|
+
const existed = fs12.existsSync(dest);
|
|
5111
5200
|
await fsp2.writeFile(dest, bytes);
|
|
5112
5201
|
return {
|
|
5113
5202
|
ok: true,
|
|
@@ -5184,7 +5273,7 @@ var HostTools = class {
|
|
|
5184
5273
|
return await new Promise((resolvePromise) => {
|
|
5185
5274
|
const child = spawn(cmd, argv, {
|
|
5186
5275
|
cwd: this.projectDir,
|
|
5187
|
-
env: {
|
|
5276
|
+
env: restrictedSubprocessEnv({ SKILL_DIR: skillDir }),
|
|
5188
5277
|
stdio: ["ignore", "pipe", "pipe"]
|
|
5189
5278
|
});
|
|
5190
5279
|
let out = "";
|
|
@@ -5237,30 +5326,34 @@ ${truncated}`
|
|
|
5237
5326
|
const command = String(args.command || "");
|
|
5238
5327
|
if (!command.trim()) return { ok: false, error: "command is required" };
|
|
5239
5328
|
const cwd = args.cwd ? this.resolve(String(args.cwd)) : this.projectDir;
|
|
5240
|
-
if (!
|
|
5329
|
+
if (!fs12.existsSync(cwd)) {
|
|
5241
5330
|
return { ok: false, error: `cwd does not exist: ${cwd}` };
|
|
5242
5331
|
}
|
|
5243
5332
|
const id = crypto.randomUUID().slice(0, 8);
|
|
5244
5333
|
const logPath = path9.join(LOG_DIR, `${id}.log`);
|
|
5245
5334
|
let out;
|
|
5246
5335
|
try {
|
|
5247
|
-
|
|
5248
|
-
out = fs11.openSync(logPath, "a");
|
|
5336
|
+
out = openPrivateProcessLog(logPath);
|
|
5249
5337
|
} catch (err) {
|
|
5250
5338
|
return { ok: false, error: `Could not open log file: ${err instanceof Error ? err.message : String(err)}` };
|
|
5251
5339
|
}
|
|
5252
5340
|
let child;
|
|
5253
5341
|
try {
|
|
5254
|
-
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
|
+
});
|
|
5255
5348
|
} catch (err) {
|
|
5256
|
-
|
|
5349
|
+
fs12.closeSync(out);
|
|
5257
5350
|
return { ok: false, error: `Failed to start: ${err instanceof Error ? err.message : String(err)}` };
|
|
5258
5351
|
}
|
|
5259
5352
|
let spawnError = null;
|
|
5260
5353
|
child.on("error", (err) => {
|
|
5261
5354
|
spawnError = err;
|
|
5262
5355
|
});
|
|
5263
|
-
|
|
5356
|
+
fs12.closeSync(out);
|
|
5264
5357
|
const pid = child.pid;
|
|
5265
5358
|
let earlyExit;
|
|
5266
5359
|
const onEarlyExit = (code) => {
|
|
@@ -5466,7 +5559,11 @@ ${tail2}` : " No output was captured.")
|
|
|
5466
5559
|
const MAX_OUTPUT = 256 * 1024;
|
|
5467
5560
|
let child;
|
|
5468
5561
|
try {
|
|
5469
|
-
child = spawn(cmd, args, {
|
|
5562
|
+
child = spawn(cmd, args, {
|
|
5563
|
+
cwd,
|
|
5564
|
+
detached: true,
|
|
5565
|
+
env: inheritedSubprocessEnv()
|
|
5566
|
+
});
|
|
5470
5567
|
} catch {
|
|
5471
5568
|
resolve({ stdout: "", stderr: "", code: 127, timedOut: false });
|
|
5472
5569
|
return;
|
|
@@ -5566,7 +5663,7 @@ var McpClient = class {
|
|
|
5566
5663
|
async connect(defaultCwd) {
|
|
5567
5664
|
const child = spawn(this.config.command, this.config.args, {
|
|
5568
5665
|
cwd: this.config.cwd || defaultCwd,
|
|
5569
|
-
env:
|
|
5666
|
+
env: restrictedSubprocessEnv(this.config.env),
|
|
5570
5667
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5571
5668
|
});
|
|
5572
5669
|
this.child = child;
|
|
@@ -6030,7 +6127,7 @@ var DaemonUserStream = class {
|
|
|
6030
6127
|
if (hooks.onConnection) this.stream.onConnection(hooks.onConnection);
|
|
6031
6128
|
}
|
|
6032
6129
|
start() {
|
|
6033
|
-
this.stream.start();
|
|
6130
|
+
return this.stream.start();
|
|
6034
6131
|
}
|
|
6035
6132
|
close() {
|
|
6036
6133
|
this.stream.close();
|
|
@@ -6073,7 +6170,7 @@ function cachePath() {
|
|
|
6073
6170
|
}
|
|
6074
6171
|
function readCache() {
|
|
6075
6172
|
try {
|
|
6076
|
-
const raw =
|
|
6173
|
+
const raw = fs12.readFileSync(cachePath(), "utf-8");
|
|
6077
6174
|
return JSON.parse(raw);
|
|
6078
6175
|
} catch {
|
|
6079
6176
|
return null;
|
|
@@ -6082,14 +6179,14 @@ function readCache() {
|
|
|
6082
6179
|
function writeCache(latest) {
|
|
6083
6180
|
try {
|
|
6084
6181
|
const dir2 = cacheDir();
|
|
6085
|
-
if (!
|
|
6086
|
-
|
|
6182
|
+
if (!fs12.existsSync(dir2)) fs12.mkdirSync(dir2, { recursive: true });
|
|
6183
|
+
fs12.writeFileSync(cachePath(), JSON.stringify({ latest, timestamp: Date.now() }));
|
|
6087
6184
|
} catch {
|
|
6088
6185
|
}
|
|
6089
6186
|
}
|
|
6090
6187
|
function readAutoUpdateState(dir2 = cacheDir()) {
|
|
6091
6188
|
try {
|
|
6092
|
-
const raw =
|
|
6189
|
+
const raw = fs12.readFileSync(path9.join(dir2, STATE_FILE), "utf-8");
|
|
6093
6190
|
const state = JSON.parse(raw);
|
|
6094
6191
|
return typeof state?.version === "string" ? state : null;
|
|
6095
6192
|
} catch {
|
|
@@ -6098,14 +6195,14 @@ function readAutoUpdateState(dir2 = cacheDir()) {
|
|
|
6098
6195
|
}
|
|
6099
6196
|
function writeAutoUpdateState(state, dir2 = cacheDir()) {
|
|
6100
6197
|
try {
|
|
6101
|
-
if (!
|
|
6102
|
-
|
|
6198
|
+
if (!fs12.existsSync(dir2)) fs12.mkdirSync(dir2, { recursive: true });
|
|
6199
|
+
fs12.writeFileSync(path9.join(dir2, STATE_FILE), JSON.stringify(state));
|
|
6103
6200
|
} catch {
|
|
6104
6201
|
}
|
|
6105
6202
|
}
|
|
6106
6203
|
function clearAutoUpdateState(dir2 = cacheDir()) {
|
|
6107
6204
|
try {
|
|
6108
|
-
|
|
6205
|
+
fs12.unlinkSync(path9.join(dir2, STATE_FILE));
|
|
6109
6206
|
} catch {
|
|
6110
6207
|
}
|
|
6111
6208
|
}
|
|
@@ -6152,7 +6249,11 @@ function startBackgroundUpdate(latest, pm, dir2 = cacheDir()) {
|
|
|
6152
6249
|
const { cmd, args } = updateCommand(pm);
|
|
6153
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}));`;
|
|
6154
6251
|
try {
|
|
6155
|
-
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
|
+
});
|
|
6156
6257
|
child.unref();
|
|
6157
6258
|
return true;
|
|
6158
6259
|
} catch {
|
|
@@ -6224,7 +6325,8 @@ function runUpdate(pm) {
|
|
|
6224
6325
|
const { cmd, args } = updateCommand(pm);
|
|
6225
6326
|
const child = spawn(cmd, args, {
|
|
6226
6327
|
shell: process.platform === "win32",
|
|
6227
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
6328
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
6329
|
+
env: inheritedSubprocessEnv()
|
|
6228
6330
|
});
|
|
6229
6331
|
let out = "";
|
|
6230
6332
|
child.stdout?.on("data", (d) => out += d);
|
|
@@ -6240,22 +6342,30 @@ var UPDATE_CHECK_MS = 6 * 60 * 6e4;
|
|
|
6240
6342
|
var MAX_WORKERS = 30;
|
|
6241
6343
|
var BRIDGE_ATTACH_GRACE_MS = 15e3;
|
|
6242
6344
|
var BRIDGE_IDLE_MS = 2e3;
|
|
6345
|
+
var LIVE_FRAME_APPROVAL_TIMEOUT_MS = 45e3;
|
|
6243
6346
|
var LOG_MAX_BYTES = 1e6;
|
|
6244
6347
|
var LOG_FILE = path9.join(os6.homedir(), ".standardagents", "daemon.log");
|
|
6245
|
-
function
|
|
6348
|
+
function appendPrivateLog(file2, line, maxBytes) {
|
|
6246
6349
|
try {
|
|
6247
|
-
|
|
6350
|
+
const directory = path9.dirname(file2);
|
|
6351
|
+
fs12.mkdirSync(directory, { recursive: true, mode: 448 });
|
|
6352
|
+
fs12.chmodSync(directory, 448);
|
|
6248
6353
|
try {
|
|
6249
|
-
|
|
6250
|
-
|
|
6354
|
+
fs12.chmodSync(file2, 384);
|
|
6355
|
+
if (fs12.statSync(file2).size > maxBytes) {
|
|
6356
|
+
fs12.renameSync(file2, `${file2}.old`);
|
|
6251
6357
|
}
|
|
6252
6358
|
} catch {
|
|
6253
6359
|
}
|
|
6254
|
-
|
|
6255
|
-
|
|
6360
|
+
fs12.appendFileSync(file2, line, { mode: 384 });
|
|
6361
|
+
fs12.chmodSync(file2, 384);
|
|
6256
6362
|
} catch {
|
|
6257
6363
|
}
|
|
6258
6364
|
}
|
|
6365
|
+
function daemonLog(line) {
|
|
6366
|
+
appendPrivateLog(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
|
|
6367
|
+
`, LOG_MAX_BYTES);
|
|
6368
|
+
}
|
|
6259
6369
|
function pathFromTags(tags) {
|
|
6260
6370
|
const tag = tags.find((t) => t.startsWith("path:"));
|
|
6261
6371
|
if (!tag) return null;
|
|
@@ -6320,7 +6430,8 @@ var ThreadWorker = class {
|
|
|
6320
6430
|
const permKey = permissionKey(req);
|
|
6321
6431
|
const fresh = decide(this.perm, permKey, effectiveRisk, !!req.requestPermission);
|
|
6322
6432
|
if (fresh === "allow") return { choice: "allow" };
|
|
6323
|
-
|
|
6433
|
+
const relayId = req.toolCallId ?? req.id;
|
|
6434
|
+
if (!relayId) {
|
|
6324
6435
|
return { choice: "deny", reason: "No one is available to approve this right now." };
|
|
6325
6436
|
}
|
|
6326
6437
|
daemonLog(`[${threadId.slice(0, 8)}] relaying approval: ${summary} (risk ${effectiveRisk})`);
|
|
@@ -6331,7 +6442,7 @@ var ThreadWorker = class {
|
|
|
6331
6442
|
api,
|
|
6332
6443
|
threadId,
|
|
6333
6444
|
{
|
|
6334
|
-
tool_call_id:
|
|
6445
|
+
tool_call_id: relayId,
|
|
6335
6446
|
tool: req.tool,
|
|
6336
6447
|
summary,
|
|
6337
6448
|
permission: req.requestPermission,
|
|
@@ -6339,7 +6450,15 @@ var ThreadWorker = class {
|
|
|
6339
6450
|
machine: machineName,
|
|
6340
6451
|
requested_at: Date.now()
|
|
6341
6452
|
},
|
|
6342
|
-
{
|
|
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
|
+
}
|
|
6343
6462
|
);
|
|
6344
6463
|
if (!response) {
|
|
6345
6464
|
return { choice: "deny", reason: "The approval request timed out with no one to approve it." };
|
|
@@ -6514,7 +6633,7 @@ Run \`standardcode daemon install\` (or plain \`standardcode\`) once to sign in.
|
|
|
6514
6633
|
daemonLog(`detached ${oldest.threadId.slice(0, 8)} (worker cap)`);
|
|
6515
6634
|
}
|
|
6516
6635
|
try {
|
|
6517
|
-
|
|
6636
|
+
fs12.mkdirSync(projectDir, { recursive: true });
|
|
6518
6637
|
} catch (e) {
|
|
6519
6638
|
daemonLog(`cannot prepare project dir ${projectDir}: ${e instanceof Error ? e.message : String(e)}`);
|
|
6520
6639
|
return;
|
|
@@ -6817,7 +6936,7 @@ function resolveDaemonCommand(extraArgs = []) {
|
|
|
6817
6936
|
let tsx = null;
|
|
6818
6937
|
for (let i = 0; i < 6 && dir2 !== path9.dirname(dir2); i++) {
|
|
6819
6938
|
const candidate = path9.join(dir2, "node_modules", "tsx", "dist", "cli.mjs");
|
|
6820
|
-
if (
|
|
6939
|
+
if (fs12.existsSync(candidate)) {
|
|
6821
6940
|
tsx = candidate;
|
|
6822
6941
|
break;
|
|
6823
6942
|
}
|
|
@@ -6847,7 +6966,10 @@ function servicePath() {
|
|
|
6847
6966
|
return [.../* @__PURE__ */ new Set([...current, ...parts])].join(":");
|
|
6848
6967
|
}
|
|
6849
6968
|
function run2(cmd, args) {
|
|
6850
|
-
const res = spawnSync(cmd, args, {
|
|
6969
|
+
const res = spawnSync(cmd, args, {
|
|
6970
|
+
encoding: "utf8",
|
|
6971
|
+
env: inheritedSubprocessEnv()
|
|
6972
|
+
});
|
|
6851
6973
|
const output4 = `${res.stdout ?? ""}${res.stderr ?? ""}`.trim();
|
|
6852
6974
|
return { ok: res.status === 0, output: output4 };
|
|
6853
6975
|
}
|
|
@@ -6865,8 +6987,8 @@ function installService(command, endpoint) {
|
|
|
6865
6987
|
}
|
|
6866
6988
|
function installLaunchd(command, endpoint) {
|
|
6867
6989
|
const logDir = path9.join(os6.homedir(), ".standardagents");
|
|
6868
|
-
|
|
6869
|
-
|
|
6990
|
+
fs12.mkdirSync(logDir, { recursive: true });
|
|
6991
|
+
fs12.mkdirSync(path9.dirname(plistPath()), { recursive: true });
|
|
6870
6992
|
const envEntries = [
|
|
6871
6993
|
` <key>PATH</key><string>${xmlEscape(servicePath())}</string>`,
|
|
6872
6994
|
...endpoint ? [` <key>STANDARD_CODE_DAEMON_ENDPOINT</key><string>${xmlEscape(endpoint)}</string>`] : []
|
|
@@ -6892,7 +7014,7 @@ ${envEntries}
|
|
|
6892
7014
|
</dict>
|
|
6893
7015
|
</plist>
|
|
6894
7016
|
`;
|
|
6895
|
-
|
|
7017
|
+
fs12.writeFileSync(plistPath(), plist);
|
|
6896
7018
|
const uid = typeof process.getuid === "function" ? process.getuid() : 501;
|
|
6897
7019
|
run2("launchctl", ["bootout", `gui/${uid}`, plistPath()]);
|
|
6898
7020
|
const boot = run2("launchctl", ["bootstrap", `gui/${uid}`, plistPath()]);
|
|
@@ -6909,7 +7031,7 @@ ${envEntries}
|
|
|
6909
7031
|
return { ok: true, detail: `LaunchAgent installed (${plistPath()})` };
|
|
6910
7032
|
}
|
|
6911
7033
|
function installSystemd(command, endpoint) {
|
|
6912
|
-
|
|
7034
|
+
fs12.mkdirSync(path9.dirname(unitPath()), { recursive: true });
|
|
6913
7035
|
const unit = `[Unit]
|
|
6914
7036
|
Description=Standard Code daemon (headless coding-agent execution client)
|
|
6915
7037
|
After=network-online.target
|
|
@@ -6924,7 +7046,7 @@ ${endpoint ? `Environment=STANDARD_CODE_DAEMON_ENDPOINT=${endpoint}
|
|
|
6924
7046
|
[Install]
|
|
6925
7047
|
WantedBy=default.target
|
|
6926
7048
|
`;
|
|
6927
|
-
|
|
7049
|
+
fs12.writeFileSync(unitPath(), unit);
|
|
6928
7050
|
const reload = run2("systemctl", ["--user", "daemon-reload"]);
|
|
6929
7051
|
if (!reload.ok) {
|
|
6930
7052
|
return {
|
|
@@ -6948,7 +7070,7 @@ function uninstallService() {
|
|
|
6948
7070
|
const uid = typeof process.getuid === "function" ? process.getuid() : 501;
|
|
6949
7071
|
run2("launchctl", ["bootout", `gui/${uid}`, plistPath()]);
|
|
6950
7072
|
try {
|
|
6951
|
-
|
|
7073
|
+
fs12.unlinkSync(plistPath());
|
|
6952
7074
|
} catch {
|
|
6953
7075
|
}
|
|
6954
7076
|
return { ok: true, detail: "LaunchAgent removed" };
|
|
@@ -6956,7 +7078,7 @@ function uninstallService() {
|
|
|
6956
7078
|
if (process.platform === "linux") {
|
|
6957
7079
|
run2("systemctl", ["--user", "disable", "--now", SYSTEMD_UNIT]);
|
|
6958
7080
|
try {
|
|
6959
|
-
|
|
7081
|
+
fs12.unlinkSync(unitPath());
|
|
6960
7082
|
} catch {
|
|
6961
7083
|
}
|
|
6962
7084
|
run2("systemctl", ["--user", "daemon-reload"]);
|
|
@@ -6966,7 +7088,7 @@ function uninstallService() {
|
|
|
6966
7088
|
}
|
|
6967
7089
|
function serviceStatus() {
|
|
6968
7090
|
if (process.platform === "darwin") {
|
|
6969
|
-
const installed =
|
|
7091
|
+
const installed = fs12.existsSync(plistPath());
|
|
6970
7092
|
const list = run2("launchctl", ["list", SERVICE_LABEL]);
|
|
6971
7093
|
const pidMatch = list.output.match(/"PID"\s*=\s*(\d+)/);
|
|
6972
7094
|
return {
|
|
@@ -6976,7 +7098,7 @@ function serviceStatus() {
|
|
|
6976
7098
|
};
|
|
6977
7099
|
}
|
|
6978
7100
|
if (process.platform === "linux") {
|
|
6979
|
-
const installed =
|
|
7101
|
+
const installed = fs12.existsSync(unitPath());
|
|
6980
7102
|
const active = run2("systemctl", ["--user", "is-active", SYSTEMD_UNIT]);
|
|
6981
7103
|
return {
|
|
6982
7104
|
installed,
|
|
@@ -7199,7 +7321,7 @@ async function projectCommand(action, target) {
|
|
|
7199
7321
|
process.exit(1);
|
|
7200
7322
|
}
|
|
7201
7323
|
const dir2 = path9.resolve(target);
|
|
7202
|
-
if (action === "add" && !
|
|
7324
|
+
if (action === "add" && !fs12.existsSync(dir2)) {
|
|
7203
7325
|
stdout.write(`${c3.red}\u2717${c3.reset} ${dir2} does not exist on this machine.
|
|
7204
7326
|
`);
|
|
7205
7327
|
process.exit(1);
|
|
@@ -7268,15 +7390,15 @@ var DIR = path9.join(os6.homedir(), ".standardagents");
|
|
|
7268
7390
|
var FILE = path9.join(DIR, "prefs.json");
|
|
7269
7391
|
function loadPrefs(file2 = FILE) {
|
|
7270
7392
|
try {
|
|
7271
|
-
return JSON.parse(
|
|
7393
|
+
return JSON.parse(fs12.readFileSync(file2, "utf8"));
|
|
7272
7394
|
} catch {
|
|
7273
7395
|
return {};
|
|
7274
7396
|
}
|
|
7275
7397
|
}
|
|
7276
7398
|
function savePrefs(update, file2 = FILE) {
|
|
7277
7399
|
const merged = { ...loadPrefs(file2), ...update };
|
|
7278
|
-
|
|
7279
|
-
|
|
7400
|
+
fs12.mkdirSync(path9.dirname(file2), { recursive: true });
|
|
7401
|
+
fs12.writeFileSync(file2, JSON.stringify(merged, null, 2));
|
|
7280
7402
|
}
|
|
7281
7403
|
function shouldOfferDaemonInstall(facts) {
|
|
7282
7404
|
if (facts.optedOutEnv) return false;
|