@brutalsystems/muster 0.7.14 → 0.7.15
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/identity-copy.js +60 -0
- package/dist/run.js +7 -1
- package/package.json +1 -1
package/dist/identity-copy.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
+
import TOML from "@iarna/toml";
|
|
3
4
|
import { identityPath } from "./identity-store.js";
|
|
4
5
|
/**
|
|
5
6
|
* What a copy must contain: enough to start authenticated, onboarded, and
|
|
@@ -122,3 +123,62 @@ export async function setWorkspaceTrust(copyPath, cwd) {
|
|
|
122
123
|
data.projects = projects;
|
|
123
124
|
await writeFile(file, JSON.stringify(data), { mode: 0o600 });
|
|
124
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Set Codex's directory-trust flag for one directory, inside a copy Muster just
|
|
128
|
+
* created. Codex has its own gate, unrelated to Claude's: without a
|
|
129
|
+
* `[projects."<dir>"] trust_level = "trusted"` entry in the config.toml it
|
|
130
|
+
* reads, the TUI stops on "Do you trust the contents of this directory?" before
|
|
131
|
+
* it ever opens a thread. No thread is opened, so no thread-writer lock is
|
|
132
|
+
* written, so `resolveCodex` finds nothing and the launch burns its whole
|
|
133
|
+
* deadline reporting `no descendant runtime identity found`.
|
|
134
|
+
*
|
|
135
|
+
* A fresh identity copy has no `projects` table at all, which made EVERY Codex
|
|
136
|
+
* identity launch fail exactly that way — measured, not inferred: the pane was
|
|
137
|
+
* captured mid-launch sitting on the prompt while the copy filled with Codex's
|
|
138
|
+
* own sqlite state and never grew a `thread-writer-locks/` directory.
|
|
139
|
+
*
|
|
140
|
+
* `-c projects."<dir>".trust_level="trusted"` does NOT satisfy the gate. It
|
|
141
|
+
* parses and is accepted, and the prompt still appears: the check reads
|
|
142
|
+
* persisted config, so the entry has to be in the file.
|
|
143
|
+
*
|
|
144
|
+
* The user's real `~/.codex/config.toml` is never touched, for the same reason
|
|
145
|
+
* `setWorkspaceTrust` leaves the live `~/.claude.json` alone.
|
|
146
|
+
*/
|
|
147
|
+
export async function setCodexWorkspaceTrust(copyPath, cwd) {
|
|
148
|
+
const file = join(copyPath, "config.toml");
|
|
149
|
+
let raw;
|
|
150
|
+
try {
|
|
151
|
+
raw = await readFile(file, "utf8");
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
// A template that has never been logged into has no config.toml; Codex
|
|
155
|
+
// runs on defaults. Anything else — EACCES, EISDIR — is a real failure,
|
|
156
|
+
// and swallowing it would hand the agent a config missing every setting
|
|
157
|
+
// the template's own login wrote.
|
|
158
|
+
if (e.code !== "ENOENT")
|
|
159
|
+
throw e;
|
|
160
|
+
}
|
|
161
|
+
let data = {};
|
|
162
|
+
if (raw !== undefined)
|
|
163
|
+
try {
|
|
164
|
+
data = TOML.parse(raw);
|
|
165
|
+
}
|
|
166
|
+
catch (e) {
|
|
167
|
+
// A file that EXISTS and does not parse is not "no file yet". Codex would
|
|
168
|
+
// refuse it too, so writing over it trades one clear failure for a silent
|
|
169
|
+
// loss of the template's settings.
|
|
170
|
+
throw new Error(`${file} exists but is not valid TOML: ${String(e)}`);
|
|
171
|
+
}
|
|
172
|
+
const projects = (data.projects ?? {});
|
|
173
|
+
const existing = (projects[cwd] ?? {});
|
|
174
|
+
if (existing.trust_level === "trusted")
|
|
175
|
+
return;
|
|
176
|
+
projects[cwd] = { ...existing, trust_level: "trusted" };
|
|
177
|
+
data.projects = projects;
|
|
178
|
+
// Re-serialised rather than appended, so an entry the template already
|
|
179
|
+
// carries with a different trust_level is corrected instead of duplicated —
|
|
180
|
+
// a duplicate table is a TOML error and Codex would refuse the whole file.
|
|
181
|
+
// Comments and key order in the copy are lost; the copy is per-launch and
|
|
182
|
+
// machine-read, and the template it came from is untouched.
|
|
183
|
+
await writeFile(file, TOML.stringify(data), { mode: 0o600 });
|
|
184
|
+
}
|
package/dist/run.js
CHANGED
|
@@ -9,7 +9,7 @@ import { enforcementGrade } from "./enforcement.js";
|
|
|
9
9
|
import { LOCAL } from "./requester.js";
|
|
10
10
|
import { assertEnforcementMeetsMinimum, assertLevelWithinCeiling, assertMayAct, resolveIdentityForRequest, resolveRequesterPolicy, RequesterPolicyRefusal, } from "./requester-policy.js";
|
|
11
11
|
import { IdentityError, readIdentity, } from "./identity-store.js";
|
|
12
|
-
import { copyIdentity, identityEnv, setWorkspaceTrust, } from "./identity-copy.js";
|
|
12
|
+
import { copyIdentity, identityEnv, setCodexWorkspaceTrust, setWorkspaceTrust, } from "./identity-copy.js";
|
|
13
13
|
import { Registry } from "./registry.js";
|
|
14
14
|
import { LaunchLog } from "./log.js";
|
|
15
15
|
import { hosts, selectHost } from "./hosts/index.js";
|
|
@@ -314,6 +314,12 @@ export class Muster {
|
|
|
314
314
|
// session never registers, and the launch burns its whole deadline.
|
|
315
315
|
// `assertAllowedWorkspace` already realpaths for containment.
|
|
316
316
|
await setWorkspaceTrust(copy, await realpath(req.cwd));
|
|
317
|
+
// Codex gates the same way behind a different file and a different key,
|
|
318
|
+
// and a fresh copy trusts nothing — so every Codex identity launch sat
|
|
319
|
+
// on "Do you trust the contents of this directory?" until the deadline.
|
|
320
|
+
// Resolved for the same reason: Codex keys `projects` by its own cwd.
|
|
321
|
+
else if (identityMeta.agent === "codex")
|
|
322
|
+
await setCodexWorkspaceTrust(copy, await realpath(req.cwd));
|
|
317
323
|
runtimeEnv = {
|
|
318
324
|
...runtimeEnv,
|
|
319
325
|
...identityEnv(identityMeta, copy, this.sourceEnv),
|