@lazehq/cli 0.1.2 → 0.1.3
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 +9 -5
- package/dist/laze.mjs +1256 -227
- package/package.json +1 -1
package/dist/laze.mjs
CHANGED
|
@@ -6,9 +6,323 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/main.ts
|
|
9
|
-
import { spawn as spawn2 } from "node:child_process";
|
|
10
9
|
import { stdin } from "node:process";
|
|
11
10
|
|
|
11
|
+
// ../../packages/secret-guard/src/detector/secret-detector.ts
|
|
12
|
+
var REDACTION_MARKER = "[SECRET]";
|
|
13
|
+
function charClasses(value) {
|
|
14
|
+
let lower = 0;
|
|
15
|
+
let upper = 0;
|
|
16
|
+
let digit = 0;
|
|
17
|
+
for (let index = 0; index < value.length; index++) {
|
|
18
|
+
const code = value.charCodeAt(index);
|
|
19
|
+
if (code >= 97 && code <= 122) lower++;
|
|
20
|
+
else if (code >= 65 && code <= 90) upper++;
|
|
21
|
+
else if (code >= 48 && code <= 57) digit++;
|
|
22
|
+
}
|
|
23
|
+
return { lower, upper, digit };
|
|
24
|
+
}
|
|
25
|
+
function shannonEntropyBits(value) {
|
|
26
|
+
const sample = value.slice(0, 256).split("");
|
|
27
|
+
if (sample.length === 0) return 0;
|
|
28
|
+
const counts = /* @__PURE__ */ new Map();
|
|
29
|
+
for (const char of sample) counts.set(char, (counts.get(char) ?? 0) + 1);
|
|
30
|
+
let entropy = 0;
|
|
31
|
+
for (const count2 of counts.values()) {
|
|
32
|
+
const p = count2 / sample.length;
|
|
33
|
+
entropy -= p * Math.log2(p);
|
|
34
|
+
}
|
|
35
|
+
return entropy;
|
|
36
|
+
}
|
|
37
|
+
var SHAPED_MIN_BODY = 26;
|
|
38
|
+
var SHAPED_MAX_BODY = 120;
|
|
39
|
+
function isKeyShapedBody(body) {
|
|
40
|
+
if (body.length < SHAPED_MIN_BODY || body.length > SHAPED_MAX_BODY) return false;
|
|
41
|
+
const c = charClasses(body);
|
|
42
|
+
if (c.lower < 2 || c.upper < 2 || c.digit < 2) return false;
|
|
43
|
+
return shannonEntropyBits(body) >= 3.9;
|
|
44
|
+
}
|
|
45
|
+
var DIGEST_PREFIXES = new Set(
|
|
46
|
+
"sha1 sha224 sha256 sha384 sha512 sha3 md4 md5 blake2b blake2s blake3 crc32 xxh3 xxh64 base32 base58 base64 hex uuid urn cid etag hash digest checksum integrity".split(
|
|
47
|
+
" "
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
var HEX_BODY_CREDENTIAL_SEGMENTS = ["live", "test", "prod", "sk", "pk", "key", "secret", "token"];
|
|
51
|
+
var IDENTIFIER_PREFIXES = new Set(
|
|
52
|
+
"commit sha sha1 sha256 md5 hash digest trace span id uuid rev blob tree etag checksum".split(
|
|
53
|
+
" "
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
var RECORD_ID_PREFIXES = new Set(
|
|
57
|
+
"project provider card eval monitor scenario ses sess session thread conv span trace run msg task job step node team org user call req resp chatcmpl toolu asst file batch evt acct cus sub".split(
|
|
58
|
+
" "
|
|
59
|
+
)
|
|
60
|
+
);
|
|
61
|
+
var PUBLIC_KEY_PREFIXES = /* @__PURE__ */ new Set(["phc"]);
|
|
62
|
+
function isNonCredentialPrefix(prefix) {
|
|
63
|
+
const lower = prefix.toLowerCase();
|
|
64
|
+
return DIGEST_PREFIXES.has(lower) || IDENTIFIER_PREFIXES.has(lower) || RECORD_ID_PREFIXES.has(lower) || PUBLIC_KEY_PREFIXES.has(lower);
|
|
65
|
+
}
|
|
66
|
+
var PLACEHOLDER_VALUE = /^(?:x+|\*+|\.+|-+|_+|0+|(?:your|my|our|insert|replace|example|sample|dummy|fake|placeholder|changeme|redacted|removed|hidden|none|null|nil|undefined|todo|tbd|fixme)[a-z0-9_\- ]*)$/i;
|
|
67
|
+
var ENV_REFERENCE = /^(?:\$[A-Za-z_][A-Za-z0-9_]*|[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+)$/;
|
|
68
|
+
var CODE_EXPRESSION = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)+$/;
|
|
69
|
+
var PATH_LIKE = /^[~.]{0,2}\/|\/[^/\s]*\.[a-z]{1,5}$/;
|
|
70
|
+
var URL_LIKE = /^[a-z][a-z0-9+.-]*:\/\//i;
|
|
71
|
+
var VERSION_LIKE = /^v?\d+(?:[._-]\d+)+/;
|
|
72
|
+
var HEX = /^[0-9a-f]{32,}$/i;
|
|
73
|
+
var BASE32 = /^[A-Z2-7]{32,}={0,6}$/;
|
|
74
|
+
var STRICT_INTRODUCTION = /[:=]\s*["'`]?$/;
|
|
75
|
+
var NOT_A_CREDENTIAL = [PLACEHOLDER_VALUE, ENV_REFERENCE, CODE_EXPRESSION, PATH_LIKE, URL_LIKE];
|
|
76
|
+
function isCredentialValue(value) {
|
|
77
|
+
if (value.length < 16) return false;
|
|
78
|
+
const looksLikeSomethingElse = NOT_A_CREDENTIAL.some((shape) => shape.test(value));
|
|
79
|
+
if (looksLikeSomethingElse) return false;
|
|
80
|
+
if (value.includes(REDACTION_MARKER)) return false;
|
|
81
|
+
return shannonEntropyBits(value) >= 2.9;
|
|
82
|
+
}
|
|
83
|
+
function isKeyMaterial(value) {
|
|
84
|
+
if (value.length < 20 || !isCredentialValue(value) || VERSION_LIKE.test(value)) return false;
|
|
85
|
+
if (shannonEntropyBits(value) < 3.4) return false;
|
|
86
|
+
if (HEX.test(value) || BASE32.test(value)) return true;
|
|
87
|
+
const c = charClasses(value);
|
|
88
|
+
return c.digit >= 2 && (c.lower >= 2 || c.upper >= 2);
|
|
89
|
+
}
|
|
90
|
+
function isBasicAuthPayload(value) {
|
|
91
|
+
if (value.endsWith("=")) return true;
|
|
92
|
+
const c = charClasses(value);
|
|
93
|
+
return c.digit > 0 || c.lower > 0 && c.upper > 0;
|
|
94
|
+
}
|
|
95
|
+
var CREDENTIAL_QUALIFIERS = "master|encryption|signing|private|access|api|auth|secret|refresh|session|bearer|verification|webhook|client|service|personal|root|admin";
|
|
96
|
+
var CREDENTIAL_KEYWORD = `(?:x[_.\\- ]?)?(?:(?:${CREDENTIAL_QUALIFIERS})[_.\\- ]?(?:api[_.\\- ]?)?key|(?:${CREDENTIAL_QUALIFIERS})?[_.\\- ]?(?:api[_.\\- ]?)?(?:token|secret|password|passwd|pwd|credentials?|authorization|cookie))`;
|
|
97
|
+
var TOKEN_START = "(?<![A-Za-z0-9_-])";
|
|
98
|
+
var TOKEN_END = "(?![A-Za-z0-9_-])";
|
|
99
|
+
var VENDOR_KEY_PATTERNS = [
|
|
100
|
+
String.raw`(?:sk|ik|pat|vk)-lw-[A-Za-z0-9_-]{3,}`,
|
|
101
|
+
String.raw`gl(?:pat|rt|dt|soat|ptt|cbt|imt|agent|ffct)-[A-Za-z0-9_-]{20,}`,
|
|
102
|
+
String.raw`npm_[A-Za-z0-9]{36}`,
|
|
103
|
+
String.raw`GOCSPX-[A-Za-z0-9_-]{20,}`,
|
|
104
|
+
String.raw`mb_[A-Za-z0-9+/=]{40,}`,
|
|
105
|
+
String.raw`dckr_pat_[A-Za-z0-9_-]{20,}`,
|
|
106
|
+
String.raw`shp(?:at|ss|ca|pa)_[0-9a-fA-F]{32}`,
|
|
107
|
+
String.raw`SG\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}`,
|
|
108
|
+
String.raw`hf_[A-Za-z0-9]{30,}`,
|
|
109
|
+
String.raw`gsk_[A-Za-z0-9]{40,}`,
|
|
110
|
+
String.raw`pplx-[A-Za-z0-9]{30,}`,
|
|
111
|
+
String.raw`nvapi-[A-Za-z0-9_-]{40,}`,
|
|
112
|
+
String.raw`r8_[A-Za-z0-9]{30,}`,
|
|
113
|
+
String.raw`xai-[A-Za-z0-9]{40,}`,
|
|
114
|
+
String.raw`ntn_[A-Za-z0-9]{30,}`,
|
|
115
|
+
String.raw`secret_[A-Za-z0-9]{40,}`,
|
|
116
|
+
String.raw`dop_v1_[0-9a-f]{64}`,
|
|
117
|
+
String.raw`figd_[A-Za-z0-9_-]{30,}`,
|
|
118
|
+
String.raw`ATATT[A-Za-z0-9_=-]{100,}`,
|
|
119
|
+
String.raw`sq0(?:atp|csp)-[A-Za-z0-9_-]{20,}`,
|
|
120
|
+
String.raw`EAAG[A-Za-z0-9]{60,}`,
|
|
121
|
+
String.raw`key-[0-9a-f]{32}`,
|
|
122
|
+
String.raw`re_[A-Za-z0-9_-]{20,}`,
|
|
123
|
+
String.raw`phx_[A-Za-z0-9]{30,}`,
|
|
124
|
+
String.raw`lin_api_[A-Za-z0-9]{30,}`,
|
|
125
|
+
String.raw`sl\.[A-Za-z0-9_-]{60,}`,
|
|
126
|
+
String.raw`ya29\.[A-Za-z0-9_-]{20,}`,
|
|
127
|
+
String.raw`sbp_[0-9a-f]{40,}`,
|
|
128
|
+
String.raw`sntry(?:s|u)_[A-Za-z0-9_.-]{30,}`,
|
|
129
|
+
String.raw`fw_[A-Za-z0-9]{20,}`,
|
|
130
|
+
String.raw`gl(?:c|sa)_[A-Za-z0-9]{30,}`,
|
|
131
|
+
String.raw`NRAK-[A-Za-z0-9]{20,}`,
|
|
132
|
+
String.raw`PMAK-[A-Za-z0-9]{20,}-[A-Za-z0-9]{20,}`,
|
|
133
|
+
String.raw`dp\.(?:pt|st|ct|sa)\.[A-Za-z0-9_-]{20,}`,
|
|
134
|
+
String.raw`pat[A-Za-z0-9]{14}\.[0-9a-f]{64}`,
|
|
135
|
+
String.raw`[0-9]{8,10}:AA[A-Za-z0-9_-]{33}`
|
|
136
|
+
];
|
|
137
|
+
function rx(pattern, flags = "") {
|
|
138
|
+
return new RegExp(pattern, `gd${flags}`);
|
|
139
|
+
}
|
|
140
|
+
function groupOf(match, index) {
|
|
141
|
+
return match[index] ?? "";
|
|
142
|
+
}
|
|
143
|
+
var RULES = [
|
|
144
|
+
{
|
|
145
|
+
id: "pem_private_key",
|
|
146
|
+
regex: rx(
|
|
147
|
+
String.raw`-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP |ENCRYPTED )?PRIVATE KEY(?: BLOCK)?-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP |ENCRYPTED )?PRIVATE KEY(?: BLOCK)?-----`
|
|
148
|
+
)
|
|
149
|
+
},
|
|
150
|
+
{ id: "putty_private_key", regex: rx(String.raw`PuTTY-User-Key-File-\d+:[\s\S]*?(?:\n\s*\n|$)`) },
|
|
151
|
+
{
|
|
152
|
+
id: "kubeconfig_client_credentials",
|
|
153
|
+
regex: rx(String.raw`\b(client-(?:key|certificate)-data:\s*)[A-Za-z0-9+/=]{40,}`),
|
|
154
|
+
value: { kind: "after", group: 1 }
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: "aws_access_key_id",
|
|
158
|
+
regex: rx(String.raw`\b(?:AKIA|ASIA|AGPA|AIDA|AROA|ANPA|ANVA)[0-9A-Z]{16}\b`)
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: "github_token",
|
|
162
|
+
regex: rx(String.raw`\b(?:gh[posru]_[A-Za-z0-9]{36,}|github_pat_[A-Za-z0-9_]{60,})\b`)
|
|
163
|
+
},
|
|
164
|
+
{ id: "provider_api_key", regex: rx(String.raw`\bsk-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])`) },
|
|
165
|
+
{ id: "stripe_secret_key", regex: rx(String.raw`\b[rs]k_(?:live|test)_[A-Za-z0-9]{16,}\b`) },
|
|
166
|
+
{ id: "slack_token", regex: rx(String.raw`\bxox[abposr]-[A-Za-z0-9-]{10,}\b`) },
|
|
167
|
+
{ id: "google_api_key", regex: rx(String.raw`\bAIza[0-9A-Za-z_-]{35}\b`) },
|
|
168
|
+
{
|
|
169
|
+
id: "vendor_api_key",
|
|
170
|
+
regex: rx(`${TOKEN_START}(?:${VENDOR_KEY_PATTERNS.join("|")})${TOKEN_END}`)
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: "jwt",
|
|
174
|
+
regex: rx(String.raw`\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b`)
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: "url_credentials",
|
|
178
|
+
regex: rx(String.raw`(?<=[a-z][a-z0-9+.-]{0,30})(:\/\/[^\s:@/]+:)([^\s:@/]+)(@)`, "i"),
|
|
179
|
+
value: { kind: "group", group: 2 },
|
|
180
|
+
precededBy: /[a-z][a-z0-9+.-]{0,30}$/i
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
id: "bearer_token",
|
|
184
|
+
regex: rx(String.raw`\b(Bearer\s+)[A-Za-z0-9._~+/-]{10,}=*`, "i"),
|
|
185
|
+
value: { kind: "after", group: 1 }
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: "authorization_scheme_token",
|
|
189
|
+
regex: rx(
|
|
190
|
+
String.raw`\b(Authorization:\s*(?:Token|SSWS|GenieKey|Splunk|OAuth)\s+)[A-Za-z0-9._~+/-]{10,}=*`,
|
|
191
|
+
"i"
|
|
192
|
+
),
|
|
193
|
+
value: { kind: "after", group: 1 }
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: "basic_auth_credentials",
|
|
197
|
+
regex: rx(String.raw`\b(Basic\s+)([A-Za-z0-9+/]{16,}={0,2})(?![A-Za-z0-9+/=])`),
|
|
198
|
+
value: { kind: "after", group: 1 },
|
|
199
|
+
accept: (match) => isBasicAuthPayload(groupOf(match, 2))
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: "prefixed_hex_api_key",
|
|
203
|
+
regex: rx(
|
|
204
|
+
`${TOKEN_START}([A-Za-z][A-Za-z0-9]{1,11})_(?:${HEX_BODY_CREDENTIAL_SEGMENTS.join("|")})_([0-9a-f]{24,128})${TOKEN_END}`,
|
|
205
|
+
"i"
|
|
206
|
+
),
|
|
207
|
+
accept: (match) => !IDENTIFIER_PREFIXES.has(groupOf(match, 1).toLowerCase()),
|
|
208
|
+
precondition: (text2) => text2.includes("_")
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: "shaped_api_key",
|
|
212
|
+
regex: rx(
|
|
213
|
+
`${TOKEN_START}([A-Za-z][A-Za-z0-9]{1,11})[_-]([A-Za-z0-9_+/-]{${SHAPED_MIN_BODY},})${TOKEN_END}`
|
|
214
|
+
),
|
|
215
|
+
accept: (match) => !isNonCredentialPrefix(groupOf(match, 1)) && isKeyShapedBody(groupOf(match, 2)),
|
|
216
|
+
precondition: (text2) => text2.includes("_") || text2.includes("-")
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
id: "sensitive_assignment",
|
|
220
|
+
regex: rx(
|
|
221
|
+
String.raw`((?:^|[\W_])(?:${CREDENTIAL_KEYWORD})(?:\s+[A-Za-z]{1,8}){0,2}["'` + "`" + String.raw`]?(?:\s*[:=]{1,2}\s*|[ \t?-]+)["'` + "`" + String.raw`]?)([^\s"'` + "`" + String.raw`,;<>(){}\[\]\\]{16,})`,
|
|
222
|
+
"i"
|
|
223
|
+
),
|
|
224
|
+
value: { kind: "group", group: 2 },
|
|
225
|
+
accept: (match) => {
|
|
226
|
+
const introduction = groupOf(match, 1);
|
|
227
|
+
const value = groupOf(match, 2);
|
|
228
|
+
return STRICT_INTRODUCTION.test(introduction) ? isCredentialValue(value) : isKeyMaterial(value);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
];
|
|
232
|
+
var SECRET_RULE_IDS = RULES.map((rule) => rule.id);
|
|
233
|
+
|
|
234
|
+
// ../../packages/secret-guard/src/redaction/redactor.ts
|
|
235
|
+
var REDACTED = "****";
|
|
236
|
+
var MIN_REDACTED_LENGTH = 4;
|
|
237
|
+
function redactionVariants({ values }) {
|
|
238
|
+
const variants = /* @__PURE__ */ new Set();
|
|
239
|
+
for (const value of values) {
|
|
240
|
+
if (value.length < MIN_REDACTED_LENGTH) continue;
|
|
241
|
+
variants.add(value);
|
|
242
|
+
variants.add(Buffer.from(value, "utf8").toString("base64"));
|
|
243
|
+
variants.add(encodeURIComponent(value));
|
|
244
|
+
}
|
|
245
|
+
return [...variants].toSorted((a, b) => b.length - a.length);
|
|
246
|
+
}
|
|
247
|
+
function escapeRegExp(value) {
|
|
248
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
249
|
+
}
|
|
250
|
+
function createRedactor({ values }) {
|
|
251
|
+
const variants = redactionVariants({ values });
|
|
252
|
+
if (variants.length === 0) return { push: (chunk) => chunk, flush: () => "" };
|
|
253
|
+
const pattern = new RegExp(variants.map(escapeRegExp).join("|"), "g");
|
|
254
|
+
const hold = Math.max(...variants.map((variant) => variant.length)) - 1;
|
|
255
|
+
let carry = "";
|
|
256
|
+
const scan = (text2, limit) => {
|
|
257
|
+
let out = "";
|
|
258
|
+
let at = 0;
|
|
259
|
+
pattern.lastIndex = 0;
|
|
260
|
+
for (const match of text2.matchAll(pattern)) {
|
|
261
|
+
if (match.index >= limit) break;
|
|
262
|
+
if (match.index < at) continue;
|
|
263
|
+
out += text2.slice(at, match.index) + REDACTED;
|
|
264
|
+
at = match.index + match[0].length;
|
|
265
|
+
}
|
|
266
|
+
const emitUntil = Math.max(at, limit);
|
|
267
|
+
carry = text2.slice(emitUntil);
|
|
268
|
+
return out + text2.slice(at, emitUntil);
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
push(chunk) {
|
|
272
|
+
const text2 = carry + chunk;
|
|
273
|
+
return scan(text2, Math.max(0, text2.length - hold));
|
|
274
|
+
},
|
|
275
|
+
flush() {
|
|
276
|
+
const text2 = carry;
|
|
277
|
+
const out = scan(text2, text2.length);
|
|
278
|
+
carry = "";
|
|
279
|
+
return out;
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ../../packages/secret-guard/src/run/run-redacted.ts
|
|
285
|
+
import { spawn } from "node:child_process";
|
|
286
|
+
import { StringDecoder } from "node:string_decoder";
|
|
287
|
+
function runRedacted({
|
|
288
|
+
command,
|
|
289
|
+
env,
|
|
290
|
+
baseEnv,
|
|
291
|
+
stdout,
|
|
292
|
+
stderr,
|
|
293
|
+
cwd
|
|
294
|
+
}) {
|
|
295
|
+
const values = Object.values(env);
|
|
296
|
+
return new Promise((resolve6, reject) => {
|
|
297
|
+
const [file2, ...args] = command;
|
|
298
|
+
const child = spawn(file2, args, {
|
|
299
|
+
env: { ...baseEnv, ...env },
|
|
300
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
301
|
+
...cwd ? { cwd } : {}
|
|
302
|
+
});
|
|
303
|
+
const pipe2 = (stream, sink) => {
|
|
304
|
+
const decoder = new StringDecoder("utf8");
|
|
305
|
+
const redactor = createRedactor({ values });
|
|
306
|
+
stream.on("data", (chunk) => sink.write(redactor.push(decoder.write(chunk))));
|
|
307
|
+
return new Promise(
|
|
308
|
+
(done) => stream.on("end", () => {
|
|
309
|
+
sink.write(redactor.push(decoder.end()) + redactor.flush());
|
|
310
|
+
done();
|
|
311
|
+
})
|
|
312
|
+
);
|
|
313
|
+
};
|
|
314
|
+
const drained = Promise.all([pipe2(child.stdout, stdout), pipe2(child.stderr, stderr)]);
|
|
315
|
+
child.on("error", reject);
|
|
316
|
+
child.on("close", (code, signal) => {
|
|
317
|
+
void drained.then(() => resolve6(code ?? (signal ? 128 + signalNumber(signal) : 1)));
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
function signalNumber(signal) {
|
|
322
|
+
const numbers = { SIGINT: 2, SIGKILL: 9, SIGTERM: 15 };
|
|
323
|
+
return numbers[signal] ?? 1;
|
|
324
|
+
}
|
|
325
|
+
|
|
12
326
|
// ../../node_modules/.pnpm/temporal-polyfill@1.0.4/node_modules/temporal-polyfill/chunks/root.js
|
|
13
327
|
var NativeTemporal = globalThis.Temporal;
|
|
14
328
|
|
|
@@ -18,7 +332,7 @@ var expectedFinite = (entityName, num) => `Non-finite ${entityName}: ${num}`;
|
|
|
18
332
|
var forbiddenBigIntToNumber = (entityName) => `Cannot convert bigint to ${entityName}`;
|
|
19
333
|
var invalidObject = "Invalid object";
|
|
20
334
|
var numberOutOfRange = (entityName, val, min, max) => invalidEntity(entityName, val) + `; must be between ${min}-${max}`;
|
|
21
|
-
var invalidEntity = (
|
|
335
|
+
var invalidEntity = (fieldName3, val) => `Invalid ${fieldName3}: ${val}`;
|
|
22
336
|
|
|
23
337
|
// ../../node_modules/.pnpm/temporal-utils@1.0.2/node_modules/temporal-utils/dist/utils.js
|
|
24
338
|
var nanoInMicro = 1e3;
|
|
@@ -69,10 +383,10 @@ function requireObjectLike(arg) {
|
|
|
69
383
|
|
|
70
384
|
// ../../node_modules/.pnpm/temporal-polyfill@1.0.4/node_modules/temporal-polyfill/chunks/internal.js
|
|
71
385
|
var invalidEntity2 = invalidEntity;
|
|
72
|
-
var missingField = (
|
|
386
|
+
var missingField = (fieldName3) => `Missing ${fieldName3}`;
|
|
73
387
|
var noValidFields = (validFields) => "No valid fields: " + validFields.join();
|
|
74
388
|
var invalidBag = "Invalid bag";
|
|
75
|
-
var invalidChoice = (
|
|
389
|
+
var invalidChoice = (fieldName3, val, choiceMap) => invalidEntity(fieldName3, val) + "; must be " + Object.keys(choiceMap).join();
|
|
76
390
|
var forbiddenValueOf = "Cannot use valueOf";
|
|
77
391
|
var invalidCallingContext = "Invalid calling context";
|
|
78
392
|
var missingYear = (allowEra) => "Missing year" + (allowEra ? "/era/eraYear" : "");
|
|
@@ -324,8 +638,8 @@ var maxValues = {
|
|
|
324
638
|
};
|
|
325
639
|
function constrainTimeFields(timeFields, overflow) {
|
|
326
640
|
const constrainedFields = {};
|
|
327
|
-
for (const
|
|
328
|
-
constrainedFields[
|
|
641
|
+
for (const fieldName3 of timeFieldNamesAsc) {
|
|
642
|
+
constrainedFields[fieldName3] = clampEntity(fieldName3, timeFields[fieldName3], 0, maxValues[fieldName3] || 999, overflow);
|
|
329
643
|
}
|
|
330
644
|
return constrainedFields;
|
|
331
645
|
}
|
|
@@ -1479,15 +1793,15 @@ function negateDuration(slots) {
|
|
|
1479
1793
|
}
|
|
1480
1794
|
function negateDurationFields(fields) {
|
|
1481
1795
|
const res = {};
|
|
1482
|
-
for (const
|
|
1483
|
-
res[
|
|
1796
|
+
for (const fieldName3 of durationFieldNamesAsc) {
|
|
1797
|
+
res[fieldName3] = -1 * fields[fieldName3] || 0;
|
|
1484
1798
|
}
|
|
1485
1799
|
return res;
|
|
1486
1800
|
}
|
|
1487
1801
|
function computeDurationSign(fields, fieldNames = durationFieldNamesAsc) {
|
|
1488
1802
|
let sign = 0;
|
|
1489
|
-
for (const
|
|
1490
|
-
const fieldSign = Math.sign(fields[
|
|
1803
|
+
for (const fieldName3 of fieldNames) {
|
|
1804
|
+
const fieldSign = Math.sign(fields[fieldName3]);
|
|
1491
1805
|
fieldSign && (sign && sign !== fieldSign && throwRangeError("Cannot mix duration signs"), sign = fieldSign);
|
|
1492
1806
|
}
|
|
1493
1807
|
return sign;
|
|
@@ -1675,14 +1989,14 @@ var zonedDateTimeFieldRefiners = {
|
|
|
1675
1989
|
function readAndRefineBagFields(bag, validFieldNames, fieldRefiners, requiredFieldNames, disallowEmpty = !requiredFieldNames) {
|
|
1676
1990
|
const res = {};
|
|
1677
1991
|
let anyMatching = 0;
|
|
1678
|
-
for (const
|
|
1679
|
-
let fieldVal = bag[
|
|
1992
|
+
for (const fieldName3 of validFieldNames) {
|
|
1993
|
+
let fieldVal = bag[fieldName3];
|
|
1680
1994
|
if (void 0 !== fieldVal) {
|
|
1681
1995
|
anyMatching = 1;
|
|
1682
|
-
const refiner = fieldRefiners[
|
|
1683
|
-
refiner && (fieldVal = refiner(fieldVal,
|
|
1996
|
+
const refiner = fieldRefiners[fieldName3];
|
|
1997
|
+
refiner && (fieldVal = refiner(fieldVal, fieldName3)), res[fieldName3] = fieldVal;
|
|
1684
1998
|
} else {
|
|
1685
|
-
requiredFieldNames && requiredFieldNames.includes(
|
|
1999
|
+
requiredFieldNames && requiredFieldNames.includes(fieldName3) && throwTypeError(missingField(fieldName3));
|
|
1686
2000
|
}
|
|
1687
2001
|
}
|
|
1688
2002
|
return disallowEmpty && !anyMatching && throwTypeError(noValidFields(validFieldNames)), res;
|
|
@@ -3857,7 +4171,8 @@ var SWITCHES = /* @__PURE__ */ new Set([
|
|
|
3857
4171
|
"once",
|
|
3858
4172
|
"urgent",
|
|
3859
4173
|
"reopen",
|
|
3860
|
-
"ask-before-push"
|
|
4174
|
+
"ask-before-push",
|
|
4175
|
+
"dry-run"
|
|
3861
4176
|
]);
|
|
3862
4177
|
function parseArgs({ argv }) {
|
|
3863
4178
|
const words = [];
|
|
@@ -3895,17 +4210,18 @@ function flagText({
|
|
|
3895
4210
|
}
|
|
3896
4211
|
|
|
3897
4212
|
// src/rules/cli-version.rules.ts
|
|
3898
|
-
var STAMPED = "0.1.
|
|
4213
|
+
var STAMPED = "0.1.3";
|
|
3899
4214
|
function cliVersionOf({ stamped = STAMPED } = {}) {
|
|
3900
4215
|
return stamped.startsWith("__") ? "dev" : stamped;
|
|
3901
4216
|
}
|
|
3902
4217
|
|
|
3903
4218
|
// src/services/agent-commands.service.ts
|
|
3904
|
-
import { mkdir as
|
|
3905
|
-
import { join as
|
|
4219
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
4220
|
+
import { join as join3 } from "node:path";
|
|
3906
4221
|
|
|
3907
4222
|
// src/rules/cli-invocation.rules.ts
|
|
3908
4223
|
var NPX_CACHE = /[\\/]_npx[\\/]/;
|
|
4224
|
+
var SANDBOX_CLI_PATH = "/opt/laze/laze.mjs";
|
|
3909
4225
|
function lazeCommandOf({ program }) {
|
|
3910
4226
|
const script = program.at(-1) ?? "";
|
|
3911
4227
|
if (!NPX_CACHE.test(script)) return "laze";
|
|
@@ -3914,24 +4230,35 @@ function lazeCommandOf({ program }) {
|
|
|
3914
4230
|
|
|
3915
4231
|
// src/rules/hook-settings.rules.ts
|
|
3916
4232
|
var LAZE_HOOK_MARKER = "laze-cli-hook";
|
|
3917
|
-
|
|
3918
|
-
|
|
4233
|
+
var TIMEOUTS = { Stop: 30, PreToolUse: 5 };
|
|
4234
|
+
function withHook({
|
|
4235
|
+
hooks,
|
|
4236
|
+
event,
|
|
3919
4237
|
command
|
|
3920
4238
|
}) {
|
|
3921
|
-
const
|
|
3922
|
-
const
|
|
3923
|
-
const others = stop.filter(
|
|
4239
|
+
const current = Array.isArray(hooks[event]) ? hooks[event] : [];
|
|
4240
|
+
const others = current.filter(
|
|
3924
4241
|
(entry) => !entry.hooks?.some((hook) => hook.command?.includes(LAZE_HOOK_MARKER))
|
|
3925
4242
|
);
|
|
3926
|
-
hooks
|
|
4243
|
+
hooks[event] = [...others, { hooks: [{ type: "command", command, timeout: TIMEOUTS[event] }] }];
|
|
4244
|
+
}
|
|
4245
|
+
function withLazeHooks({
|
|
4246
|
+
settings,
|
|
4247
|
+
stopCommand,
|
|
4248
|
+
preToolCommand
|
|
4249
|
+
}) {
|
|
4250
|
+
const hooks = { ...settings.hooks };
|
|
4251
|
+
withHook({ hooks, event: "Stop", command: stopCommand });
|
|
4252
|
+
withHook({ hooks, event: "PreToolUse", command: preToolCommand });
|
|
3927
4253
|
return { ...settings, hooks };
|
|
3928
4254
|
}
|
|
3929
|
-
function
|
|
4255
|
+
function hookCommand({
|
|
3930
4256
|
program,
|
|
3931
|
-
profile
|
|
4257
|
+
profile,
|
|
4258
|
+
hook
|
|
3932
4259
|
}) {
|
|
3933
4260
|
const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
3934
|
-
const words = [...program, "hook",
|
|
4261
|
+
const words = [...program, "hook", hook, "--profile", profile].map(quote).join(" ");
|
|
3935
4262
|
return `${words} # ${LAZE_HOOK_MARKER}`;
|
|
3936
4263
|
}
|
|
3937
4264
|
|
|
@@ -4023,20 +4350,16 @@ function readTranscript({ lines }) {
|
|
|
4023
4350
|
return { contextTokens, contextWindow, compactions };
|
|
4024
4351
|
}
|
|
4025
4352
|
|
|
4026
|
-
// src/services/
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
super(message);
|
|
4030
|
-
this.name = "CliUsageError";
|
|
4031
|
-
}
|
|
4032
|
-
};
|
|
4353
|
+
// src/services/claude-turn.service.ts
|
|
4354
|
+
import { mkdir as mkdir2, readFile as readFile2, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
4355
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
4033
4356
|
|
|
4034
4357
|
// src/services/laze-client.service.ts
|
|
4035
4358
|
var CLI_VERSION_HEADER = "x-laze-cli-version";
|
|
4036
4359
|
var LazeApiError = class extends Error {
|
|
4037
|
-
constructor(
|
|
4360
|
+
constructor(status2, code, message) {
|
|
4038
4361
|
super(message);
|
|
4039
|
-
this.status =
|
|
4362
|
+
this.status = status2;
|
|
4040
4363
|
this.code = code;
|
|
4041
4364
|
this.name = "LazeApiError";
|
|
4042
4365
|
}
|
|
@@ -4044,20 +4367,20 @@ var LazeApiError = class extends Error {
|
|
|
4044
4367
|
code;
|
|
4045
4368
|
};
|
|
4046
4369
|
var LazeClient = class _LazeClient {
|
|
4047
|
-
constructor(
|
|
4048
|
-
this.
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
}
|
|
4052
|
-
baseUrl;
|
|
4053
|
-
token;
|
|
4054
|
-
fetcher;
|
|
4370
|
+
constructor(options) {
|
|
4371
|
+
this.options = options;
|
|
4372
|
+
}
|
|
4373
|
+
options;
|
|
4055
4374
|
static create({
|
|
4056
4375
|
baseUrl,
|
|
4057
4376
|
token,
|
|
4058
4377
|
fetcher
|
|
4059
4378
|
}) {
|
|
4060
|
-
return new _LazeClient(baseUrl.replace(/\/+$/, ""), token, fetcher);
|
|
4379
|
+
return new _LazeClient({ baseUrl: baseUrl.replace(/\/+$/, ""), token, fetcher, headers: {} });
|
|
4380
|
+
}
|
|
4381
|
+
/** The same client, sending these headers too on every call. */
|
|
4382
|
+
withHeaders(headers) {
|
|
4383
|
+
return new _LazeClient({ ...this.options, headers: { ...this.options.headers, ...headers } });
|
|
4061
4384
|
}
|
|
4062
4385
|
get(path) {
|
|
4063
4386
|
return this.send({ method: "GET", path });
|
|
@@ -4071,12 +4394,13 @@ var LazeClient = class _LazeClient {
|
|
|
4071
4394
|
body
|
|
4072
4395
|
}) {
|
|
4073
4396
|
const headers = {
|
|
4397
|
+
...this.options.headers,
|
|
4074
4398
|
accept: "application/json",
|
|
4075
4399
|
[CLI_VERSION_HEADER]: cliVersionOf()
|
|
4076
4400
|
};
|
|
4077
4401
|
if (body !== void 0) headers["content-type"] = "application/json";
|
|
4078
|
-
if (this.token) headers.authorization = `Bearer ${this.token}`;
|
|
4079
|
-
const response = await this.fetcher(`${this.baseUrl}${path}`, {
|
|
4402
|
+
if (this.options.token) headers.authorization = `Bearer ${this.options.token}`;
|
|
4403
|
+
const response = await this.options.fetcher(`${this.options.baseUrl}${path}`, {
|
|
4080
4404
|
method,
|
|
4081
4405
|
headers,
|
|
4082
4406
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
@@ -4087,15 +4411,23 @@ var LazeClient = class _LazeClient {
|
|
|
4087
4411
|
return parsed;
|
|
4088
4412
|
}
|
|
4089
4413
|
};
|
|
4090
|
-
function errorOf({ status, body }) {
|
|
4414
|
+
function errorOf({ status: status2, body }) {
|
|
4091
4415
|
const record4 = typeof body === "object" && body !== null ? body : {};
|
|
4092
4416
|
const nested = typeof record4.error === "object" && record4.error !== null ? record4.error : record4;
|
|
4093
|
-
const fallback = typeof record4.error === "string" ? record4.error : `http_${
|
|
4417
|
+
const fallback = typeof record4.error === "string" ? record4.error : `http_${status2}`;
|
|
4094
4418
|
const code = typeof nested.code === "string" ? nested.code : fallback;
|
|
4095
|
-
const message = typeof nested.message === "string" ? nested.message : `Laze answered ${
|
|
4096
|
-
return new LazeApiError(
|
|
4419
|
+
const message = typeof nested.message === "string" ? nested.message : `Laze answered ${status2}`;
|
|
4420
|
+
return new LazeApiError(status2, code, message);
|
|
4097
4421
|
}
|
|
4098
4422
|
|
|
4423
|
+
// src/services/cli-context.ts
|
|
4424
|
+
var CliUsageError = class extends Error {
|
|
4425
|
+
constructor(message) {
|
|
4426
|
+
super(message);
|
|
4427
|
+
this.name = "CliUsageError";
|
|
4428
|
+
}
|
|
4429
|
+
};
|
|
4430
|
+
|
|
4099
4431
|
// src/services/session.service.ts
|
|
4100
4432
|
async function signedIn({
|
|
4101
4433
|
context,
|
|
@@ -4126,6 +4458,85 @@ function serverUrlOf({ context, args }) {
|
|
|
4126
4458
|
return flagText({ args, name: "url" }) || context.environment.url || "https://laze.langwatch.ai";
|
|
4127
4459
|
}
|
|
4128
4460
|
|
|
4461
|
+
// src/services/claude-turn.service.ts
|
|
4462
|
+
var PRE_TOOL_TIMEOUT_MS = 3e3;
|
|
4463
|
+
function statePath({ context, agent }) {
|
|
4464
|
+
const safe = agent.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
4465
|
+
return join2(dirname2(context.environment.configPath), "turns", `${safe}.json`);
|
|
4466
|
+
}
|
|
4467
|
+
async function readState({ context, agent }) {
|
|
4468
|
+
return readFile2(statePath({ context, agent }), "utf8").then(
|
|
4469
|
+
(text2) => JSON.parse(text2),
|
|
4470
|
+
() => void 0
|
|
4471
|
+
);
|
|
4472
|
+
}
|
|
4473
|
+
function beat({
|
|
4474
|
+
client,
|
|
4475
|
+
state,
|
|
4476
|
+
working
|
|
4477
|
+
}) {
|
|
4478
|
+
const reported = working ? "working" : "idle";
|
|
4479
|
+
return client.post("/api/agents/me/turn", {
|
|
4480
|
+
channelId: state?.channelId ?? null,
|
|
4481
|
+
threadRootId: state?.threadRootId ?? null,
|
|
4482
|
+
state: state ? reported : null
|
|
4483
|
+
});
|
|
4484
|
+
}
|
|
4485
|
+
async function turnStarted({
|
|
4486
|
+
context,
|
|
4487
|
+
client,
|
|
4488
|
+
agent,
|
|
4489
|
+
messages
|
|
4490
|
+
}) {
|
|
4491
|
+
const last = messages.at(-1);
|
|
4492
|
+
if (!last) return;
|
|
4493
|
+
const state = { channelId: last.channelId, threadRootId: last.threadRootId ?? last.messageId };
|
|
4494
|
+
const path = statePath({ context, agent });
|
|
4495
|
+
await mkdir2(dirname2(path), { recursive: true, mode: 448 });
|
|
4496
|
+
await writeFile2(path, JSON.stringify(state));
|
|
4497
|
+
await beat({ client, state, working: true }).catch(() => void 0);
|
|
4498
|
+
}
|
|
4499
|
+
async function turnEnded({
|
|
4500
|
+
context,
|
|
4501
|
+
client,
|
|
4502
|
+
agent
|
|
4503
|
+
}) {
|
|
4504
|
+
const state = await readState({ context, agent });
|
|
4505
|
+
if (!state) return;
|
|
4506
|
+
await rm(statePath({ context, agent }), { force: true });
|
|
4507
|
+
await beat({ client, state, working: false }).catch(() => void 0);
|
|
4508
|
+
}
|
|
4509
|
+
async function preToolHook({ context, args }) {
|
|
4510
|
+
try {
|
|
4511
|
+
await context.readStdin();
|
|
4512
|
+
const { name: name2, profile } = await signedIn({ context, args });
|
|
4513
|
+
const client = LazeClient.create({
|
|
4514
|
+
baseUrl: profile.url,
|
|
4515
|
+
token: profile.token,
|
|
4516
|
+
fetcher: (input2, init) => context.fetcher(input2, { ...init, signal: AbortSignal.timeout(PRE_TOOL_TIMEOUT_MS) })
|
|
4517
|
+
});
|
|
4518
|
+
const state = await readState({ context, agent: name2 });
|
|
4519
|
+
const answer3 = await beat({ client, state, working: true });
|
|
4520
|
+
if (!answer3.stop) return;
|
|
4521
|
+
await turnEnded({ context, client, agent: name2 });
|
|
4522
|
+
const reason = `Stopped by ${answer3.stoppedBy ?? "someone"} in Laze.`;
|
|
4523
|
+
context.out(
|
|
4524
|
+
JSON.stringify({
|
|
4525
|
+
continue: false,
|
|
4526
|
+
stopReason: reason,
|
|
4527
|
+
hookSpecificOutput: {
|
|
4528
|
+
hookEventName: "PreToolUse",
|
|
4529
|
+
permissionDecision: "deny",
|
|
4530
|
+
permissionDecisionReason: reason
|
|
4531
|
+
}
|
|
4532
|
+
})
|
|
4533
|
+
);
|
|
4534
|
+
} catch (error62) {
|
|
4535
|
+
context.err(`laze: the PreToolUse hook skipped: ${String(error62)}
|
|
4536
|
+
`);
|
|
4537
|
+
}
|
|
4538
|
+
}
|
|
4539
|
+
|
|
4129
4540
|
// src/services/chat-commands.service.ts
|
|
4130
4541
|
var REQUEST_WAIT_SECONDS = 50;
|
|
4131
4542
|
async function listChannels({ context, args }) {
|
|
@@ -4198,9 +4609,12 @@ function waitSecondsOf({ args }) {
|
|
|
4198
4609
|
return timeout > 0 ? timeout : Infinity;
|
|
4199
4610
|
}
|
|
4200
4611
|
async function inbox({ context, args }) {
|
|
4201
|
-
const { client } = await signedIn({ context, args });
|
|
4612
|
+
const { client, name: name2, profile } = await signedIn({ context, args });
|
|
4202
4613
|
const waitSeconds = waitSecondsOf({ args });
|
|
4203
4614
|
const messages = await receiveMessages({ context, client, waitSeconds });
|
|
4615
|
+
if (profile.kind === "agent" && context.environment.harness === "claude-code") {
|
|
4616
|
+
await turnStarted({ context, client, agent: name2, messages }).catch(() => void 0);
|
|
4617
|
+
}
|
|
4204
4618
|
if (args.flags.json) return context.out(`${JSON.stringify(messages, null, 2)}
|
|
4205
4619
|
`);
|
|
4206
4620
|
if (messages.length === 0) return context.out("No new messages.\n");
|
|
@@ -4244,19 +4658,20 @@ function slugOf(name2) {
|
|
|
4244
4658
|
return name2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "agent";
|
|
4245
4659
|
}
|
|
4246
4660
|
async function installStopHook({ context, profile }) {
|
|
4247
|
-
const directory =
|
|
4248
|
-
const path =
|
|
4249
|
-
const current = await
|
|
4661
|
+
const directory = join3(context.cwd, ".claude");
|
|
4662
|
+
const path = join3(directory, "settings.local.json");
|
|
4663
|
+
const current = await readFile3(path, "utf8").then(
|
|
4250
4664
|
(text2) => JSON.parse(text2),
|
|
4251
4665
|
() => ({})
|
|
4252
4666
|
);
|
|
4253
|
-
const
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
)
|
|
4667
|
+
const settings = withLazeHooks({
|
|
4668
|
+
settings: current,
|
|
4669
|
+
stopCommand: hookCommand({ program: context.program, profile, hook: "stop" }),
|
|
4670
|
+
preToolCommand: hookCommand({ program: context.program, profile, hook: "pre-tool" })
|
|
4671
|
+
});
|
|
4672
|
+
await mkdir3(directory, { recursive: true });
|
|
4673
|
+
await writeFile3(path, `${JSON.stringify(settings, null, 2)}
|
|
4674
|
+
`);
|
|
4260
4675
|
return path;
|
|
4261
4676
|
}
|
|
4262
4677
|
function nextStepsFor({
|
|
@@ -4304,7 +4719,7 @@ async function linkAgent({ context, args }) {
|
|
|
4304
4719
|
context.out(
|
|
4305
4720
|
[
|
|
4306
4721
|
`Linked as ${linked.agent.name} (${linked.agent.id}), profile "${name2}" for ${context.cwd}.`,
|
|
4307
|
-
...hookPath ? [`Added the Laze
|
|
4722
|
+
...hookPath ? [`Added the Laze hooks to ${hookPath}.`] : [],
|
|
4308
4723
|
"",
|
|
4309
4724
|
nextStepsFor({ harness, profile: name2, laze: lazeCommandOf({ program: context.program }) }),
|
|
4310
4725
|
""
|
|
@@ -4316,7 +4731,7 @@ async function reportTranscript({
|
|
|
4316
4731
|
input: input2
|
|
4317
4732
|
}) {
|
|
4318
4733
|
if (!input2.transcript_path || !input2.session_id) return;
|
|
4319
|
-
const lines = (await
|
|
4734
|
+
const lines = (await readFile3(input2.transcript_path, "utf8")).split("\n");
|
|
4320
4735
|
const context = readTranscript({ lines });
|
|
4321
4736
|
await client.post("/api/agents/me/activity", {
|
|
4322
4737
|
sessionId: input2.session_id,
|
|
@@ -4328,14 +4743,15 @@ async function reportTranscript({
|
|
|
4328
4743
|
async function handOver({ context, args }) {
|
|
4329
4744
|
const raw = await context.readStdin();
|
|
4330
4745
|
const input2 = raw.trim() ? JSON.parse(raw) : {};
|
|
4331
|
-
const { client } = await signedIn({ context, args });
|
|
4746
|
+
const { client, name: agent } = await signedIn({ context, args });
|
|
4332
4747
|
await reportTranscript({ client, input: input2 }).catch(
|
|
4333
4748
|
(error62) => context.err(`laze: could not report context: ${String(error62)}
|
|
4334
4749
|
`)
|
|
4335
4750
|
);
|
|
4336
4751
|
if (input2.stop_hook_active) return;
|
|
4337
4752
|
const messages = await receiveMessages({ context, client, waitSeconds: 0 });
|
|
4338
|
-
if (messages.length === 0) return;
|
|
4753
|
+
if (messages.length === 0) return turnEnded({ context, client, agent });
|
|
4754
|
+
await turnStarted({ context, client, agent, messages });
|
|
4339
4755
|
context.out(
|
|
4340
4756
|
JSON.stringify({
|
|
4341
4757
|
hookSpecificOutput: { hookEventName: "Stop", additionalContext: hookContextOf({ messages }) }
|
|
@@ -4352,8 +4768,8 @@ async function stopHook({ context, args }) {
|
|
|
4352
4768
|
}
|
|
4353
4769
|
|
|
4354
4770
|
// src/services/app-commands.service.ts
|
|
4355
|
-
import { mkdir as
|
|
4356
|
-
import { join as
|
|
4771
|
+
import { mkdir as mkdir4, readdir, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
|
|
4772
|
+
import { join as join4, relative, resolve as resolve2, sep } from "node:path";
|
|
4357
4773
|
|
|
4358
4774
|
// ../../packages/module/src/feature-names.generated.ts
|
|
4359
4775
|
var FEATURE_NAMES = [
|
|
@@ -4366,18 +4782,21 @@ var FEATURE_NAMES = [
|
|
|
4366
4782
|
"authz",
|
|
4367
4783
|
"billing",
|
|
4368
4784
|
"chat",
|
|
4785
|
+
"compute",
|
|
4369
4786
|
"connector",
|
|
4370
4787
|
"entitlement",
|
|
4371
4788
|
"feature-flag",
|
|
4372
4789
|
"feed",
|
|
4373
|
-
"marketing",
|
|
4374
4790
|
"files",
|
|
4791
|
+
"marketing",
|
|
4375
4792
|
"memory",
|
|
4376
4793
|
"model-gateway",
|
|
4377
4794
|
"notification",
|
|
4795
|
+
"openclaw",
|
|
4378
4796
|
"role",
|
|
4379
4797
|
"schedule",
|
|
4380
4798
|
"skill",
|
|
4799
|
+
"slack",
|
|
4381
4800
|
"vault",
|
|
4382
4801
|
"wiki",
|
|
4383
4802
|
"workspace",
|
|
@@ -24207,6 +24626,8 @@ var publishRequestSchemaDefinition = external_exports.object({
|
|
|
24207
24626
|
visibility: appVisibilitySchema,
|
|
24208
24627
|
status: external_exports.enum(["pending", "approved", "denied"]),
|
|
24209
24628
|
requestedBy: appActorSchema,
|
|
24629
|
+
/** The name of who asked, on an app's waiting publish; absent where it is not read. */
|
|
24630
|
+
requestedByName: external_exports.string().nullable().optional(),
|
|
24210
24631
|
decidedBy: appActorSchema.nullable(),
|
|
24211
24632
|
createdAt: external_exports.iso.datetime(),
|
|
24212
24633
|
decidedAt: external_exports.iso.datetime().nullable()
|
|
@@ -24230,6 +24651,8 @@ var appSchemaDefinition = external_exports.object({
|
|
|
24230
24651
|
pendingPublish: publishRequestSchema.nullable(),
|
|
24231
24652
|
/** The name of the person or agent who built it; absent when it can no longer be read. */
|
|
24232
24653
|
ownerName: external_exports.string().nullable().optional(),
|
|
24654
|
+
/** Set while the app is archived: it serves nothing and leaves the app list. */
|
|
24655
|
+
archivedAt: external_exports.iso.datetime().nullable().optional(),
|
|
24233
24656
|
createdAt: external_exports.iso.datetime(),
|
|
24234
24657
|
updatedAt: external_exports.iso.datetime()
|
|
24235
24658
|
});
|
|
@@ -24302,6 +24725,23 @@ var createAppInputSchemaDefinition = external_exports.object({
|
|
|
24302
24725
|
visibility: appVisibilitySchema.default("internal")
|
|
24303
24726
|
});
|
|
24304
24727
|
var createAppInputSchema = createAppInputSchemaDefinition;
|
|
24728
|
+
var listAppsInputSchemaDefinition = external_exports.object({
|
|
24729
|
+
workspaceId: external_exports.string().min(1),
|
|
24730
|
+
/** True lists only archived apps; absent or false lists the others. */
|
|
24731
|
+
archived: external_exports.boolean().optional()
|
|
24732
|
+
});
|
|
24733
|
+
var listAppsInputSchema = listAppsInputSchemaDefinition;
|
|
24734
|
+
var renameAppInputSchemaDefinition = external_exports.object({
|
|
24735
|
+
...appRefSchemaDefinition.shape,
|
|
24736
|
+
name: external_exports.string().trim().min(1).max(80)
|
|
24737
|
+
});
|
|
24738
|
+
var renameAppInputSchema = renameAppInputSchemaDefinition;
|
|
24739
|
+
var deleteAppInputSchemaDefinition = external_exports.object({
|
|
24740
|
+
...appRefSchemaDefinition.shape,
|
|
24741
|
+
/** The app's name, typed by the person to confirm. */
|
|
24742
|
+
confirmName: external_exports.string().max(200)
|
|
24743
|
+
});
|
|
24744
|
+
var deleteAppInputSchema = deleteAppInputSchemaDefinition;
|
|
24305
24745
|
var commitInputSchemaDefinition = external_exports.object({
|
|
24306
24746
|
...appRefSchemaDefinition.shape,
|
|
24307
24747
|
/** The whole static build: files left out are gone from this version. */
|
|
@@ -24424,7 +24864,7 @@ var appViewerSchemaDefinition = external_exports.object({
|
|
|
24424
24864
|
var AppApi = moduleApi()("app");
|
|
24425
24865
|
|
|
24426
24866
|
// ../../modules/app/contract/src/app.trpc.ts
|
|
24427
|
-
var appTrpc = defineTrpcContract("app").query("list").withInput(
|
|
24867
|
+
var appTrpc = defineTrpcContract("app").query("list").withInput(listAppsInputSchema).withOutput(external_exports.array(appSchema)).query("get").withInput(appRefSchema).withOutput(appSchema).mutation("create").withInput(createAppInputSchema).withOutput(appSchema).mutation("rename").withInput(renameAppInputSchema).withOutput(appSchema).mutation("archive").withInput(appRefSchema).withOutput(appSchema).mutation("unarchive").withInput(appRefSchema).withOutput(appSchema).mutation("delete").withInput(deleteAppInputSchema).withOutput(external_exports.object({ deleted: external_exports.literal(true) })).query("versions").withInput(appRefSchema).withOutput(external_exports.array(appVersionSchema)).mutation("revert").withInput(revertInputSchema).withOutput(appVersionSchema).mutation("publish").withInput(publishInputSchema).withOutput(publishOutcomeSchema).query("collections").withInput(siteRefSchema).withOutput(external_exports.array(collectionSchema)).query("records").withInput(listRecordsInputSchema).withOutput(recordPageSchema).mutation("writeRecord").withInput(writeRecordInputSchema).withOutput(appRecordSchema).mutation("deleteRecord").withInput(deleteRecordInputSchema).withOutput(external_exports.object({ deleted: external_exports.literal(true) })).query("exportRecords").withInput(exportRecordsInputSchema).withOutput(recordExportSchema).mutation("decidePublish").withInput(decidePublishInputSchema).withOutput(publishOutcomeSchema).mutation("signInHandoff").withInput(signInHandoffInputSchema).withOutput(signInHandoffSchema).build();
|
|
24428
24868
|
|
|
24429
24869
|
// ../../modules/app/contract/src/app.rest.ts
|
|
24430
24870
|
var byKey = { workspaceId: true };
|
|
@@ -27239,7 +27679,7 @@ function folderOf({ context, word }) {
|
|
|
27239
27679
|
return resolve2(context.cwd, word ?? ".");
|
|
27240
27680
|
}
|
|
27241
27681
|
async function readManifest(folder) {
|
|
27242
|
-
const text2 = await
|
|
27682
|
+
const text2 = await readFile4(join4(folder, APP_MANIFEST_FILE), "utf8").catch(() => void 0);
|
|
27243
27683
|
if (text2 === void 0) return void 0;
|
|
27244
27684
|
const parsed = appManifestSchema.safeParse(JSON.parse(text2));
|
|
27245
27685
|
if (!parsed.success) {
|
|
@@ -27274,7 +27714,7 @@ async function jsonFlag({
|
|
|
27274
27714
|
}) {
|
|
27275
27715
|
const raw = flagText({ args, name: name2 });
|
|
27276
27716
|
if (!raw) return void 0;
|
|
27277
|
-
const text2 = raw.startsWith("@") ? await
|
|
27717
|
+
const text2 = raw.startsWith("@") ? await readFile4(resolve2(context.cwd, raw.slice(1)), "utf8") : raw;
|
|
27278
27718
|
try {
|
|
27279
27719
|
return JSON.parse(text2);
|
|
27280
27720
|
} catch {
|
|
@@ -27287,7 +27727,7 @@ async function listFiles(folder) {
|
|
|
27287
27727
|
while (pending.length > 0 && found.length <= MAX_FILES) {
|
|
27288
27728
|
const current = pending.pop() ?? folder;
|
|
27289
27729
|
for (const entry of await readdir(current, { withFileTypes: true })) {
|
|
27290
|
-
const path =
|
|
27730
|
+
const path = join4(current, entry.name);
|
|
27291
27731
|
const rel = relative(folder, path).split(sep).join("/");
|
|
27292
27732
|
if (isSkippedPath({ path: rel })) continue;
|
|
27293
27733
|
if (entry.isDirectory()) pending.push(path);
|
|
@@ -27328,17 +27768,17 @@ var appCreate = async ({ context, args }) => {
|
|
|
27328
27768
|
...visibility ? { visibility } : {}
|
|
27329
27769
|
});
|
|
27330
27770
|
const folder = resolve2(context.cwd, flagText({ args, name: "dir", fallback: app2.slug }));
|
|
27331
|
-
await
|
|
27771
|
+
await mkdir4(folder, { recursive: true });
|
|
27332
27772
|
const files = template ? templateFiles({ template, name: name2 }) : {};
|
|
27333
27773
|
for (const [path, content] of Object.entries(files)) {
|
|
27334
|
-
await
|
|
27774
|
+
await writeFile4(join4(folder, path), content);
|
|
27335
27775
|
}
|
|
27336
27776
|
const manifest = {
|
|
27337
27777
|
app: { id: app2.id, name: app2.name, slug: app2.slug },
|
|
27338
27778
|
collections: template ? { ...template.collections } : {},
|
|
27339
27779
|
seed: template ? { ...template.seed } : {}
|
|
27340
27780
|
};
|
|
27341
|
-
await
|
|
27781
|
+
await writeFile4(join4(folder, APP_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
|
|
27342
27782
|
`);
|
|
27343
27783
|
print({
|
|
27344
27784
|
context,
|
|
@@ -27369,7 +27809,7 @@ var appPush = async ({ context, args }) => {
|
|
|
27369
27809
|
paths.map(
|
|
27370
27810
|
async (path) => buildFileOf({
|
|
27371
27811
|
path: relative(folder, path).split(sep).join("/"),
|
|
27372
|
-
bytes: await
|
|
27812
|
+
bytes: await readFile4(path)
|
|
27373
27813
|
})
|
|
27374
27814
|
)
|
|
27375
27815
|
);
|
|
@@ -27600,7 +28040,7 @@ var appExport = async ({ context, args }) => {
|
|
|
27600
28040
|
const out = flagText({ args, name: "out" });
|
|
27601
28041
|
if (!out) return context.out(exported.body);
|
|
27602
28042
|
const target = resolve2(context.cwd, out);
|
|
27603
|
-
await
|
|
28043
|
+
await writeFile4(target, exported.body);
|
|
27604
28044
|
context.out(`Wrote ${exported.rows} records to ${relative(context.cwd, target)}
|
|
27605
28045
|
`);
|
|
27606
28046
|
};
|
|
@@ -27714,11 +28154,163 @@ async function workspaces({ context, args }) {
|
|
|
27714
28154
|
}
|
|
27715
28155
|
}
|
|
27716
28156
|
|
|
28157
|
+
// src/services/browser-commands.service.ts
|
|
28158
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
28159
|
+
var PATHS = {
|
|
28160
|
+
machines: "/api/compute/machines",
|
|
28161
|
+
setup: "/api/compute/browser/setup",
|
|
28162
|
+
cdp: "/api/compute/browser/cdp",
|
|
28163
|
+
screen: "/api/compute/browser/screen",
|
|
28164
|
+
sleep: "/api/compute/machines/sleep",
|
|
28165
|
+
wake: "/api/compute/machines/wake",
|
|
28166
|
+
delete: "/api/compute/machines/delete"
|
|
28167
|
+
};
|
|
28168
|
+
var USAGE2 = [
|
|
28169
|
+
"Usage: laze browser setup <site> [--name <machine>] a machine with Chrome a person signs in on",
|
|
28170
|
+
" laze browser cdp <machine> a CDP address for this turn (Playwright connectOverCDP)",
|
|
28171
|
+
" laze browser screen <machine> [--site <site>] send the sign-in screen link again",
|
|
28172
|
+
" laze browser status [<machine>] the machines, their state, sites and cost",
|
|
28173
|
+
" laze browser sleep|wake|delete <machine>"
|
|
28174
|
+
].join("\n");
|
|
28175
|
+
async function turnTokenOf({ context }) {
|
|
28176
|
+
const env = context.environment.inherited;
|
|
28177
|
+
const pinned = env.LAZE_TURN_TOKEN?.trim();
|
|
28178
|
+
if (pinned) return pinned;
|
|
28179
|
+
if (!env.LAZE_TURN_FILE) return "";
|
|
28180
|
+
return readFile5(env.LAZE_TURN_FILE, "utf8").then(
|
|
28181
|
+
(text2) => text2.trim(),
|
|
28182
|
+
() => ""
|
|
28183
|
+
);
|
|
28184
|
+
}
|
|
28185
|
+
async function computeClient({
|
|
28186
|
+
context,
|
|
28187
|
+
args
|
|
28188
|
+
}) {
|
|
28189
|
+
const { client } = await signedIn({ context, args });
|
|
28190
|
+
const turn = await turnTokenOf({ context });
|
|
28191
|
+
return turn ? client.withHeaders({ "x-laze-turn": turn }) : client;
|
|
28192
|
+
}
|
|
28193
|
+
function siteLine(machine) {
|
|
28194
|
+
return machine.sites.map((entry) => `${entry.site} (${entry.status.replaceAll("_", " ")})`).join(", ");
|
|
28195
|
+
}
|
|
28196
|
+
function statusLine(machine) {
|
|
28197
|
+
const cost = `${machine.monthCostUsd.toFixed(2)} of ${machine.monthlyBudgetUsd} USD this month`;
|
|
28198
|
+
const use = machine.inHumanUse ? ", a person has the screen" : "";
|
|
28199
|
+
return `${machine.name} ${machine.state}${use} ${siteLine(machine) || "no sites"} ${cost}
|
|
28200
|
+
`;
|
|
28201
|
+
}
|
|
28202
|
+
function machineArg({ args }) {
|
|
28203
|
+
const machine = args.words[2];
|
|
28204
|
+
if (!machine) throw new CliUsageError(USAGE2);
|
|
28205
|
+
return machine;
|
|
28206
|
+
}
|
|
28207
|
+
async function setup({ context, args }) {
|
|
28208
|
+
const site = args.words[2];
|
|
28209
|
+
if (!site) throw new CliUsageError(USAGE2);
|
|
28210
|
+
const name2 = flagText({ args, name: "name" }) || void 0;
|
|
28211
|
+
const client = await computeClient({ context, args });
|
|
28212
|
+
const machine = await client.post(PATHS.setup, { site, ...name2 ? { name: name2 } : {} });
|
|
28213
|
+
if (args.flags.json) return context.out(`${JSON.stringify(machine, null, 2)}
|
|
28214
|
+
`);
|
|
28215
|
+
context.out(
|
|
28216
|
+
`${machine.name} is ${machine.state} (${siteLine(machine)}).
|
|
28217
|
+
The screen link goes to your requester's DM once it is ready. Wait for their message that they signed in, then run \`laze browser cdp ${machine.name}\`.
|
|
28218
|
+
`
|
|
28219
|
+
);
|
|
28220
|
+
}
|
|
28221
|
+
async function cdp({ context, args }) {
|
|
28222
|
+
const client = await computeClient({ context, args });
|
|
28223
|
+
const access = await client.post(PATHS.cdp, { machine: machineArg({ args }) });
|
|
28224
|
+
if (args.flags.json) return context.out(`${JSON.stringify(access, null, 2)}
|
|
28225
|
+
`);
|
|
28226
|
+
if (access.status === "waking")
|
|
28227
|
+
return context.out(
|
|
28228
|
+
`${access.machine} is waking up. Run this again in ${access.retryAfterSeconds} seconds.
|
|
28229
|
+
`
|
|
28230
|
+
);
|
|
28231
|
+
context.out(`${access.url}
|
|
28232
|
+
`);
|
|
28233
|
+
context.err(`Valid until ${access.expiresAt}. Use it with chromium.connectOverCDP(url).
|
|
28234
|
+
`);
|
|
28235
|
+
}
|
|
28236
|
+
async function screen({ context, args }) {
|
|
28237
|
+
const client = await computeClient({ context, args });
|
|
28238
|
+
const site = flagText({ args, name: "site" }) || void 0;
|
|
28239
|
+
const link = await client.post(PATHS.screen, {
|
|
28240
|
+
machine: machineArg({ args }),
|
|
28241
|
+
...site ? { site } : {}
|
|
28242
|
+
});
|
|
28243
|
+
if (args.flags.json) return context.out(`${JSON.stringify(link, null, 2)}
|
|
28244
|
+
`);
|
|
28245
|
+
context.out(
|
|
28246
|
+
link.url ? `${link.url}
|
|
28247
|
+
` : `Sent a fresh screen link for ${link.machine.name} to your requester's DM.
|
|
28248
|
+
`
|
|
28249
|
+
);
|
|
28250
|
+
}
|
|
28251
|
+
async function status({ context, args }) {
|
|
28252
|
+
const client = await computeClient({ context, args });
|
|
28253
|
+
const wanted = args.words[2];
|
|
28254
|
+
const machines = (await client.get(PATHS.machines)).filter(
|
|
28255
|
+
(machine) => !wanted || machine.name === wanted
|
|
28256
|
+
);
|
|
28257
|
+
if (args.flags.json) return context.out(`${JSON.stringify(machines, null, 2)}
|
|
28258
|
+
`);
|
|
28259
|
+
if (machines.length === 0)
|
|
28260
|
+
return context.out(
|
|
28261
|
+
wanted ? `No machine named ${wanted}.
|
|
28262
|
+
` : "No machines. `laze browser setup <site>` makes one.\n"
|
|
28263
|
+
);
|
|
28264
|
+
for (const machine of machines) context.out(statusLine(machine));
|
|
28265
|
+
}
|
|
28266
|
+
async function change({
|
|
28267
|
+
context,
|
|
28268
|
+
args,
|
|
28269
|
+
path
|
|
28270
|
+
}) {
|
|
28271
|
+
const client = await computeClient({ context, args });
|
|
28272
|
+
const machine = await client.post(path, { machine: machineArg({ args }) });
|
|
28273
|
+
if (args.flags.json) return context.out(`${JSON.stringify(machine, null, 2)}
|
|
28274
|
+
`);
|
|
28275
|
+
context.out(statusLine(machine));
|
|
28276
|
+
}
|
|
28277
|
+
async function browser({ context, args }) {
|
|
28278
|
+
const command = args.words[1];
|
|
28279
|
+
if (command === "setup") return setup({ context, args });
|
|
28280
|
+
if (command === "cdp") return cdp({ context, args });
|
|
28281
|
+
if (command === "screen") return screen({ context, args });
|
|
28282
|
+
if (command === "status") return status({ context, args });
|
|
28283
|
+
if (command === "sleep" || command === "wake" || command === "delete")
|
|
28284
|
+
return change({ context, args, path: PATHS[command] });
|
|
28285
|
+
throw new CliUsageError(USAGE2);
|
|
28286
|
+
}
|
|
28287
|
+
|
|
27717
28288
|
// src/services/codex-adopt.service.ts
|
|
27718
|
-
import { spawn } from "node:child_process";
|
|
28289
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
27719
28290
|
import { readdir as readdir2, stat } from "node:fs/promises";
|
|
27720
|
-
import { join as
|
|
28291
|
+
import { join as join5 } from "node:path";
|
|
27721
28292
|
import { createInterface } from "node:readline";
|
|
28293
|
+
|
|
28294
|
+
// src/rules/codex-requests.rules.ts
|
|
28295
|
+
var DECLINED_DECISION = {
|
|
28296
|
+
"item/commandExecution/requestApproval": "decline",
|
|
28297
|
+
"item/fileChange/requestApproval": "decline",
|
|
28298
|
+
execCommandApproval: "denied",
|
|
28299
|
+
applyPatchApproval: "denied"
|
|
28300
|
+
};
|
|
28301
|
+
function codexRequestReplyOf({ method }) {
|
|
28302
|
+
const decision = DECLINED_DECISION[method];
|
|
28303
|
+
if (decision) return { result: { decision } };
|
|
28304
|
+
if (method === "item/permissions/requestApproval") {
|
|
28305
|
+
return { result: { permissions: {}, scope: "turn" } };
|
|
28306
|
+
}
|
|
28307
|
+
if (method === "mcpServer/elicitation/request") {
|
|
28308
|
+
return { result: { action: "decline", content: null } };
|
|
28309
|
+
}
|
|
28310
|
+
return { error: { code: -32601, message: `${method} is not supported here` } };
|
|
28311
|
+
}
|
|
28312
|
+
|
|
28313
|
+
// src/services/codex-adopt.service.ts
|
|
27722
28314
|
function record3(value) {
|
|
27723
28315
|
return typeof value === "object" && value !== null ? value : {};
|
|
27724
28316
|
}
|
|
@@ -27736,6 +28328,7 @@ function absorbTurnEvent({ result, message }) {
|
|
|
27736
28328
|
const window2 = usage.modelContextWindow;
|
|
27737
28329
|
if (typeof window2 === "number" && window2 > 0) result.contextWindow = window2;
|
|
27738
28330
|
}
|
|
28331
|
+
var TURN_HEARTBEAT_MS = 1e4;
|
|
27739
28332
|
var CodexAppServer = class _CodexAppServer {
|
|
27740
28333
|
constructor(child) {
|
|
27741
28334
|
this.child = child;
|
|
@@ -27750,7 +28343,7 @@ var CodexAppServer = class _CodexAppServer {
|
|
|
27750
28343
|
inherited
|
|
27751
28344
|
}) {
|
|
27752
28345
|
const env = { ...inherited, CODEX_HOME: codexHome };
|
|
27753
|
-
return new _CodexAppServer(
|
|
28346
|
+
return new _CodexAppServer(spawn2("codex", ["app-server"], { env, stdio: "pipe" }));
|
|
27754
28347
|
}
|
|
27755
28348
|
async call(method, params) {
|
|
27756
28349
|
const id = ++this.#nextId;
|
|
@@ -27764,24 +28357,24 @@ var CodexAppServer = class _CodexAppServer {
|
|
|
27764
28357
|
notify(method) {
|
|
27765
28358
|
this.write({ method });
|
|
27766
28359
|
}
|
|
27767
|
-
/**
|
|
27768
|
-
async
|
|
28360
|
+
/** Starts one turn; `done` settles when it completes, keeping its last agent message. */
|
|
28361
|
+
async startTurn({ threadId, text: text2 }) {
|
|
27769
28362
|
const result = { answer: "" };
|
|
27770
28363
|
const done = new Promise((resolve6) => {
|
|
27771
28364
|
const listen = (message) => {
|
|
27772
28365
|
absorbTurnEvent({ result, message });
|
|
27773
28366
|
if (message.method !== "turn/completed") return;
|
|
27774
28367
|
this.#listeners.delete(listen);
|
|
27775
|
-
resolve6();
|
|
28368
|
+
resolve6(result);
|
|
27776
28369
|
};
|
|
27777
28370
|
this.#listeners.add(listen);
|
|
27778
28371
|
});
|
|
27779
|
-
await this.call("turn/start", {
|
|
28372
|
+
const started = await this.call("turn/start", {
|
|
27780
28373
|
threadId,
|
|
27781
28374
|
input: [{ type: "text", text: text2, text_elements: [] }]
|
|
27782
28375
|
});
|
|
27783
|
-
|
|
27784
|
-
return
|
|
28376
|
+
const turnId = record3(started.turn).id;
|
|
28377
|
+
return { turnId: typeof turnId === "string" ? turnId : null, done };
|
|
27785
28378
|
}
|
|
27786
28379
|
stop() {
|
|
27787
28380
|
this.child.kill("SIGTERM");
|
|
@@ -27803,18 +28396,23 @@ var CodexAppServer = class _CodexAppServer {
|
|
|
27803
28396
|
return;
|
|
27804
28397
|
}
|
|
27805
28398
|
if (message.method !== void 0 && message.id !== void 0) {
|
|
27806
|
-
this.write({
|
|
28399
|
+
this.write({
|
|
28400
|
+
id: message.id,
|
|
28401
|
+
...codexRequestReplyOf({
|
|
28402
|
+
method: typeof message.method === "string" ? message.method : ""
|
|
28403
|
+
})
|
|
28404
|
+
});
|
|
27807
28405
|
return;
|
|
27808
28406
|
}
|
|
27809
28407
|
for (const listen of this.#listeners) listen(message);
|
|
27810
28408
|
}
|
|
27811
28409
|
};
|
|
27812
28410
|
async function newestThreadId({ codexHome }) {
|
|
27813
|
-
const root =
|
|
28411
|
+
const root = join5(codexHome, "sessions");
|
|
27814
28412
|
const files = await readdir2(root, { recursive: true }).catch(() => []);
|
|
27815
28413
|
const rollouts = files.filter((file2) => /rollout-.*\.jsonl$/.test(file2));
|
|
27816
28414
|
const dated = await Promise.all(
|
|
27817
|
-
rollouts.map(async (file2) => ({ file: file2, at: (await stat(
|
|
28415
|
+
rollouts.map(async (file2) => ({ file: file2, at: (await stat(join5(root, file2))).mtimeMs }))
|
|
27818
28416
|
);
|
|
27819
28417
|
const newest = dated.toSorted((a, b) => b.at - a.at)[0]?.file ?? "";
|
|
27820
28418
|
const id = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/.exec(newest);
|
|
@@ -27829,13 +28427,49 @@ function promptOf({ message }) {
|
|
|
27829
28427
|
formatInboxMessage({ message }).split("\n").slice(0, -1).join("\n")
|
|
27830
28428
|
].join("\n");
|
|
27831
28429
|
}
|
|
28430
|
+
async function heartbeat({
|
|
28431
|
+
client,
|
|
28432
|
+
message,
|
|
28433
|
+
state
|
|
28434
|
+
}) {
|
|
28435
|
+
return client.post("/api/agents/me/turn", {
|
|
28436
|
+
channelId: message.channelId,
|
|
28437
|
+
threadRootId: message.threadRootId ?? message.messageId,
|
|
28438
|
+
state
|
|
28439
|
+
}).catch(() => void 0);
|
|
28440
|
+
}
|
|
28441
|
+
async function watchTurn({
|
|
28442
|
+
context,
|
|
28443
|
+
client,
|
|
28444
|
+
codex,
|
|
28445
|
+
threadId,
|
|
28446
|
+
turn,
|
|
28447
|
+
message
|
|
28448
|
+
}) {
|
|
28449
|
+
const finished = new AbortController();
|
|
28450
|
+
void turn.done.then(() => finished.abort());
|
|
28451
|
+
while (!finished.signal.aborted) {
|
|
28452
|
+
const beat2 = await heartbeat({ client, message, state: "working" });
|
|
28453
|
+
if (beat2?.stop && turn.turnId) {
|
|
28454
|
+
await codex.call("turn/interrupt", { threadId, turnId: turn.turnId }).catch(() => void 0);
|
|
28455
|
+
return beat2.stoppedBy ?? "someone";
|
|
28456
|
+
}
|
|
28457
|
+
await context.sleep(TURN_HEARTBEAT_MS, finished.signal);
|
|
28458
|
+
}
|
|
28459
|
+
return void 0;
|
|
28460
|
+
}
|
|
27832
28461
|
async function answer({
|
|
28462
|
+
context,
|
|
27833
28463
|
codex,
|
|
27834
28464
|
client,
|
|
27835
28465
|
threadId,
|
|
27836
28466
|
message
|
|
27837
28467
|
}) {
|
|
27838
|
-
const
|
|
28468
|
+
const running = await codex.startTurn({ threadId, text: promptOf({ message }) });
|
|
28469
|
+
const stoppedBy = await watchTurn({ context, client, codex, threadId, turn: running, message });
|
|
28470
|
+
const turn = await running.done;
|
|
28471
|
+
await heartbeat({ client, message, state: "idle" });
|
|
28472
|
+
if (stoppedBy !== void 0) return `(stopped by ${stoppedBy})`;
|
|
27839
28473
|
const body = turn.answer.trim() || "(no answer)";
|
|
27840
28474
|
await client.post("/api/agents/me/replies", { messageId: message.messageId, body });
|
|
27841
28475
|
if (turn.contextTokens !== void 0) {
|
|
@@ -27871,7 +28505,7 @@ async function adoptCodex({ context, args }) {
|
|
|
27871
28505
|
waitSeconds: timeout > 0 ? timeout : Infinity
|
|
27872
28506
|
});
|
|
27873
28507
|
for (const message of messages) {
|
|
27874
|
-
const body = await answer({ codex, client, threadId, message });
|
|
28508
|
+
const body = await answer({ context, codex, client, threadId, message });
|
|
27875
28509
|
context.out(`Answered ${message.messageId}: ${body.slice(0, 120)}
|
|
27876
28510
|
`);
|
|
27877
28511
|
}
|
|
@@ -27883,7 +28517,7 @@ async function adoptCodex({ context, args }) {
|
|
|
27883
28517
|
}
|
|
27884
28518
|
|
|
27885
28519
|
// src/services/feed-commands.service.ts
|
|
27886
|
-
import { readFile as
|
|
28520
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
27887
28521
|
import { resolve as resolve3 } from "node:path";
|
|
27888
28522
|
|
|
27889
28523
|
// src/rules/feed-input.rules.ts
|
|
@@ -27942,7 +28576,7 @@ function feedFlagsOf({ args }) {
|
|
|
27942
28576
|
}
|
|
27943
28577
|
|
|
27944
28578
|
// src/services/feed-commands.service.ts
|
|
27945
|
-
var
|
|
28579
|
+
var USAGE3 = `Usage:
|
|
27946
28580
|
laze feed post <title> [--channel <channel>] [--tag <tag>] [--summary <line>]
|
|
27947
28581
|
[--body <text|@file>] [--draft <text|@file>] [--draft-header "To: ...\\nRe: ..."]
|
|
27948
28582
|
[--link <label>=<url>]... [--action <label>=<message>]... [--to <userId>]...
|
|
@@ -27966,7 +28600,7 @@ async function bodyOf({
|
|
|
27966
28600
|
}) {
|
|
27967
28601
|
const body = { ...flags.fields };
|
|
27968
28602
|
for (const [field, source] of Object.entries(flags.texts)) {
|
|
27969
|
-
body[field] = "file" in source ? await
|
|
28603
|
+
body[field] = "file" in source ? await readFile6(resolve3(context.cwd, source.file), "utf8") : source.text;
|
|
27970
28604
|
}
|
|
27971
28605
|
return body;
|
|
27972
28606
|
}
|
|
@@ -27985,7 +28619,7 @@ function printItem({
|
|
|
27985
28619
|
}
|
|
27986
28620
|
async function feedPost({ context, args }) {
|
|
27987
28621
|
const title = args.words.slice(2).join(" ").trim();
|
|
27988
|
-
if (!title) throw new CliUsageError(
|
|
28622
|
+
if (!title) throw new CliUsageError(USAGE3);
|
|
27989
28623
|
const flags = flagsOf(args);
|
|
27990
28624
|
const { client } = await signedIn({ context, args });
|
|
27991
28625
|
const channel = flagText({ args, name: "channel" });
|
|
@@ -28002,7 +28636,7 @@ async function feedPost({ context, args }) {
|
|
|
28002
28636
|
}
|
|
28003
28637
|
async function feedUpdate({ context, args }) {
|
|
28004
28638
|
const itemId = args.words[2];
|
|
28005
|
-
if (!itemId) throw new CliUsageError(
|
|
28639
|
+
if (!itemId) throw new CliUsageError(USAGE3);
|
|
28006
28640
|
const flags = flagsOf(args);
|
|
28007
28641
|
const { client } = await signedIn({ context, args });
|
|
28008
28642
|
const body = await bodyOf({ context, flags });
|
|
@@ -28018,7 +28652,7 @@ async function feedUpdate({ context, args }) {
|
|
|
28018
28652
|
async function feedReply({ context, args }) {
|
|
28019
28653
|
const itemId = args.words[2];
|
|
28020
28654
|
const text2 = args.words.slice(3).join(" ").trim();
|
|
28021
|
-
if (!itemId || !text2) throw new CliUsageError(
|
|
28655
|
+
if (!itemId || !text2) throw new CliUsageError(USAGE3);
|
|
28022
28656
|
const { client } = await signedIn({ context, args });
|
|
28023
28657
|
const replied = await client.post("/api/feed/items/reply", {
|
|
28024
28658
|
itemId,
|
|
@@ -28029,7 +28663,7 @@ async function feedReply({ context, args }) {
|
|
|
28029
28663
|
}
|
|
28030
28664
|
async function feedRead({ context, args }) {
|
|
28031
28665
|
const itemId = args.words[2];
|
|
28032
|
-
if (!itemId) throw new CliUsageError(
|
|
28666
|
+
if (!itemId) throw new CliUsageError(USAGE3);
|
|
28033
28667
|
const { client } = await signedIn({ context, args });
|
|
28034
28668
|
const read = await client.post("/api/feed/items/read", { itemId });
|
|
28035
28669
|
printItem({ context, args, item: read });
|
|
@@ -28054,12 +28688,12 @@ var FEED_COMMANDS = {
|
|
|
28054
28688
|
async function feed({ context, args }) {
|
|
28055
28689
|
const name2 = args.words[1] ?? "";
|
|
28056
28690
|
const command = Object.hasOwn(FEED_COMMANDS, name2) ? FEED_COMMANDS[name2] : void 0;
|
|
28057
|
-
if (!command) throw new CliUsageError(
|
|
28691
|
+
if (!command) throw new CliUsageError(USAGE3);
|
|
28058
28692
|
await command({ context, args });
|
|
28059
28693
|
}
|
|
28060
28694
|
|
|
28061
28695
|
// src/services/github-commands.service.ts
|
|
28062
|
-
import { readFile as
|
|
28696
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
28063
28697
|
|
|
28064
28698
|
// src/rules/github-signature.rules.ts
|
|
28065
28699
|
var TURN_SEPARATOR = "~";
|
|
@@ -28127,13 +28761,17 @@ function isLocalGhCall(args) {
|
|
|
28127
28761
|
// src/services/github-commands.service.ts
|
|
28128
28762
|
var REAL_GH = "/usr/bin/gh";
|
|
28129
28763
|
var NOT_SET = "laze: agent_github_not_set: this agent has no GitHub connection. Its owner sets one on the agent's settings page or with `laze agent set-github <agent> <connection>`.";
|
|
28764
|
+
async function turnFileToken({ env }) {
|
|
28765
|
+
if (!env.LAZE_TURN_FILE) return "";
|
|
28766
|
+
return readFile7(env.LAZE_TURN_FILE, "utf8").then(
|
|
28767
|
+
(text2) => text2.trim(),
|
|
28768
|
+
() => ""
|
|
28769
|
+
);
|
|
28770
|
+
}
|
|
28130
28771
|
async function credentialOf({ env }) {
|
|
28131
28772
|
const placeholder = (env.GH_TOKEN ?? "").split(TURN_SEPARATOR)[0] ?? "";
|
|
28132
28773
|
if (!placeholder.startsWith("laze-ph-")) throw new CliUsageError(NOT_SET);
|
|
28133
|
-
const turn = env.
|
|
28134
|
-
(text2) => text2.trim(),
|
|
28135
|
-
() => ""
|
|
28136
|
-
) : "";
|
|
28774
|
+
const turn = env.LAZE_TURN_TOKEN?.trim() || await turnFileToken({ env });
|
|
28137
28775
|
return turn ? `${placeholder}${TURN_SEPARATOR}${turn}` : placeholder;
|
|
28138
28776
|
}
|
|
28139
28777
|
function threadUrlOf({ env, workspaceId }) {
|
|
@@ -28159,7 +28797,7 @@ async function githubGh({
|
|
|
28159
28797
|
args: args.rest,
|
|
28160
28798
|
agentName: profile.name ?? "An agent",
|
|
28161
28799
|
threadUrl: threadUrlOf({ env, workspaceId: profile.workspaceId }),
|
|
28162
|
-
readBodyFile: (path) => path === "-" ? context.readStdin() :
|
|
28800
|
+
readBodyFile: (path) => path === "-" ? context.readStdin() : readFile7(path, "utf8")
|
|
28163
28801
|
});
|
|
28164
28802
|
return context.runCommand({
|
|
28165
28803
|
command: [REAL_GH, ...ghArgs],
|
|
@@ -28258,7 +28896,7 @@ async function setAgentGithub({
|
|
|
28258
28896
|
}
|
|
28259
28897
|
|
|
28260
28898
|
// src/services/mcp-gateway.service.ts
|
|
28261
|
-
import { readFile as
|
|
28899
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
28262
28900
|
import { createInterface as createInterface2 } from "node:readline";
|
|
28263
28901
|
var TURN_HEADER = "x-laze-turn";
|
|
28264
28902
|
function serveMcpGateway({
|
|
@@ -28272,6 +28910,7 @@ async function relayMcpLines({
|
|
|
28272
28910
|
args,
|
|
28273
28911
|
lines
|
|
28274
28912
|
}) {
|
|
28913
|
+
const pending = lines[Symbol.asyncIterator]();
|
|
28275
28914
|
const { profile } = await signedIn({ context, args });
|
|
28276
28915
|
const env = context.environment.inherited;
|
|
28277
28916
|
if (!profile.agentId || !env.LAZE_TURN_FILE)
|
|
@@ -28279,9 +28918,10 @@ async function relayMcpLines({
|
|
|
28279
28918
|
const github2 = env.LAZE_GITHUB_CONNECTION;
|
|
28280
28919
|
const url2 = `${profile.url.replace(/\/+$/, "")}/api/connectors/mcp/${encodeURIComponent(profile.agentId)}${github2 ? `?github=${encodeURIComponent(github2)}` : ""}`;
|
|
28281
28920
|
const turnFile = env.LAZE_TURN_FILE;
|
|
28282
|
-
for await (
|
|
28921
|
+
for (let next = await pending.next(); !next.done; next = await pending.next()) {
|
|
28922
|
+
const line = next.value;
|
|
28283
28923
|
if (!line.trim()) continue;
|
|
28284
|
-
const turn = await
|
|
28924
|
+
const turn = await readFile8(turnFile, "utf8").then(
|
|
28285
28925
|
(text3) => text3.trim(),
|
|
28286
28926
|
() => ""
|
|
28287
28927
|
);
|
|
@@ -28426,14 +29066,14 @@ async function serveMcp({ context, args }) {
|
|
|
28426
29066
|
}
|
|
28427
29067
|
|
|
28428
29068
|
// src/services/mount-files.service.ts
|
|
28429
|
-
import { mkdir as
|
|
28430
|
-
import { dirname as
|
|
29069
|
+
import { mkdir as mkdir5, readFile as readFile9, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
|
|
29070
|
+
import { dirname as dirname3, relative as relative2, resolve as resolve4 } from "node:path";
|
|
28431
29071
|
async function textArgument({
|
|
28432
29072
|
context,
|
|
28433
29073
|
value
|
|
28434
29074
|
}) {
|
|
28435
29075
|
if (value === "-") return context.readStdin();
|
|
28436
|
-
if (value.startsWith("@")) return
|
|
29076
|
+
if (value.startsWith("@")) return readFile9(resolve4(context.cwd, value.slice(1)), "utf8");
|
|
28437
29077
|
return value;
|
|
28438
29078
|
}
|
|
28439
29079
|
function turnChannel({ context, args }) {
|
|
@@ -28446,21 +29086,21 @@ async function writeMount({
|
|
|
28446
29086
|
files
|
|
28447
29087
|
}) {
|
|
28448
29088
|
const root = resolve4(context.cwd, flagText({ args, name: "dir", fallback: ".laze" }), folder);
|
|
28449
|
-
await
|
|
28450
|
-
await
|
|
29089
|
+
await rm2(root, { recursive: true, force: true });
|
|
29090
|
+
await mkdir5(root, { recursive: true });
|
|
28451
29091
|
for (const file2 of files) {
|
|
28452
29092
|
const target = resolve4(root, file2.path);
|
|
28453
29093
|
const inside = relative2(root, target);
|
|
28454
29094
|
if (!inside || inside.startsWith(".."))
|
|
28455
29095
|
throw new Error(`Refusing to write outside ${root}: ${file2.path}`);
|
|
28456
|
-
await
|
|
28457
|
-
await
|
|
29096
|
+
await mkdir5(dirname3(target), { recursive: true });
|
|
29097
|
+
await writeFile5(target, file2.content);
|
|
28458
29098
|
}
|
|
28459
29099
|
return root;
|
|
28460
29100
|
}
|
|
28461
29101
|
|
|
28462
29102
|
// src/services/memory-commands.service.ts
|
|
28463
|
-
var
|
|
29103
|
+
var USAGE4 = `Usage:
|
|
28464
29104
|
laze memory get SOUL.md|AGENTS.md|MEMORY.md [--channel <channel>]
|
|
28465
29105
|
laze memory set <file> <text|@file|-> [--channel <channel>] [--base <version>]
|
|
28466
29106
|
laze memory append MEMORY.md <text|@file|-> [--channel <channel>]
|
|
@@ -28471,7 +29111,7 @@ MEMORY.md is the file of the turn's channel (LAZE_CHANNEL), or of --channel when
|
|
|
28471
29111
|
var FILES = /* @__PURE__ */ new Set(["SOUL.md", "AGENTS.md", "MEMORY.md"]);
|
|
28472
29112
|
function fileRef({ context, args }) {
|
|
28473
29113
|
const file2 = args.words[2] ?? "";
|
|
28474
|
-
if (!FILES.has(file2)) throw new CliUsageError(
|
|
29114
|
+
if (!FILES.has(file2)) throw new CliUsageError(USAGE4);
|
|
28475
29115
|
const channel = turnChannel({ context, args });
|
|
28476
29116
|
return { file: file2, ...channel ? { channel } : {} };
|
|
28477
29117
|
}
|
|
@@ -28499,7 +29139,7 @@ async function memoryGet({ context, args }) {
|
|
|
28499
29139
|
async function memorySet({ context, args }) {
|
|
28500
29140
|
const ref = fileRef({ context, args });
|
|
28501
29141
|
const value = args.words.slice(3).join(" ");
|
|
28502
|
-
if (!value) throw new CliUsageError(
|
|
29142
|
+
if (!value) throw new CliUsageError(USAGE4);
|
|
28503
29143
|
const content = await textArgument({ context, value });
|
|
28504
29144
|
const base = args.flags.base;
|
|
28505
29145
|
const { client } = await signedIn({ context, args });
|
|
@@ -28515,7 +29155,7 @@ async function memorySet({ context, args }) {
|
|
|
28515
29155
|
async function memoryAppend({ context, args }) {
|
|
28516
29156
|
const ref = fileRef({ context, args });
|
|
28517
29157
|
const value = args.words.slice(3).join(" ");
|
|
28518
|
-
if (!value) throw new CliUsageError(
|
|
29158
|
+
if (!value) throw new CliUsageError(USAGE4);
|
|
28519
29159
|
const text2 = await textArgument({ context, value });
|
|
28520
29160
|
const { client } = await signedIn({ context, args });
|
|
28521
29161
|
const saved = await client.post("/api/memory/append", { ...ref, text: text2 });
|
|
@@ -28525,7 +29165,7 @@ async function memoryAppend({ context, args }) {
|
|
|
28525
29165
|
}
|
|
28526
29166
|
async function memorySearch({ context, args }) {
|
|
28527
29167
|
const query = args.words.slice(2).join(" ").trim();
|
|
28528
|
-
if (!query) throw new CliUsageError(
|
|
29168
|
+
if (!query) throw new CliUsageError(USAGE4);
|
|
28529
29169
|
const { client } = await signedIn({ context, args });
|
|
28530
29170
|
const hits = await client.post("/api/memory/search", { query });
|
|
28531
29171
|
if (args.flags.json) return context.out(`${JSON.stringify(hits, null, 2)}
|
|
@@ -28558,12 +29198,12 @@ var MEMORY_COMMANDS = {
|
|
|
28558
29198
|
async function memory({ context, args }) {
|
|
28559
29199
|
const name2 = args.words[1] ?? "";
|
|
28560
29200
|
const command = Object.hasOwn(MEMORY_COMMANDS, name2) ? MEMORY_COMMANDS[name2] : void 0;
|
|
28561
|
-
if (!command) throw new CliUsageError(
|
|
29201
|
+
if (!command) throw new CliUsageError(USAGE4);
|
|
28562
29202
|
await command({ context, args });
|
|
28563
29203
|
}
|
|
28564
29204
|
|
|
28565
29205
|
// src/services/schedule-commands.service.ts
|
|
28566
|
-
var
|
|
29206
|
+
var USAGE5 = `Usage:
|
|
28567
29207
|
laze schedule add <name> --prompt <text> (--cron "<m h dom mon dow>" | --rrule "<RRULE>" | --at <local time>)
|
|
28568
29208
|
[--tz <IANA zone>] [--channel <channelId>] [--agent <agentId>]
|
|
28569
29209
|
laze schedule list
|
|
@@ -28575,7 +29215,7 @@ function timingOf(args) {
|
|
|
28575
29215
|
const given = [cron, rrule, at].filter(Boolean);
|
|
28576
29216
|
if (given.length !== 1)
|
|
28577
29217
|
throw new CliUsageError(`Give exactly one of --cron, --rrule or --at.
|
|
28578
|
-
${
|
|
29218
|
+
${USAGE5}`);
|
|
28579
29219
|
if (cron) return { kind: "cron", cron };
|
|
28580
29220
|
if (rrule) return { kind: "rrule", rrule };
|
|
28581
29221
|
return { kind: "once", at };
|
|
@@ -28590,7 +29230,7 @@ function printSchedule({ context, schedule: schedule2 }) {
|
|
|
28590
29230
|
async function scheduleAdd({ context, args }) {
|
|
28591
29231
|
const name2 = args.words.slice(2).join(" ").trim();
|
|
28592
29232
|
const prompt = flagText({ args, name: "prompt" });
|
|
28593
|
-
if (!name2 || !prompt) throw new CliUsageError(
|
|
29233
|
+
if (!name2 || !prompt) throw new CliUsageError(USAGE5);
|
|
28594
29234
|
const timing = timingOf(args);
|
|
28595
29235
|
const { client } = await signedIn({ context, args });
|
|
28596
29236
|
const channelId = flagText({ args, name: "channel" });
|
|
@@ -28617,7 +29257,7 @@ async function scheduleList({ context, args }) {
|
|
|
28617
29257
|
function byId(path) {
|
|
28618
29258
|
return async ({ context, args }) => {
|
|
28619
29259
|
const scheduleId = args.words[2];
|
|
28620
|
-
if (!scheduleId) throw new CliUsageError(
|
|
29260
|
+
if (!scheduleId) throw new CliUsageError(USAGE5);
|
|
28621
29261
|
const { client } = await signedIn({ context, args });
|
|
28622
29262
|
const answer3 = await client.post(`/api/schedules/${path}`, {
|
|
28623
29263
|
scheduleId
|
|
@@ -28631,7 +29271,7 @@ function byId(path) {
|
|
|
28631
29271
|
}
|
|
28632
29272
|
async function scheduleRuns({ context, args }) {
|
|
28633
29273
|
const scheduleId = args.words[2];
|
|
28634
|
-
if (!scheduleId) throw new CliUsageError(
|
|
29274
|
+
if (!scheduleId) throw new CliUsageError(USAGE5);
|
|
28635
29275
|
const { client } = await signedIn({ context, args });
|
|
28636
29276
|
const runs = await client.post("/api/schedules/runs", { scheduleId });
|
|
28637
29277
|
if (args.flags.json) return context.out(`${JSON.stringify(runs, null, 2)}
|
|
@@ -28654,14 +29294,14 @@ var SCHEDULE_COMMANDS = {
|
|
|
28654
29294
|
async function schedule({ context, args }) {
|
|
28655
29295
|
const name2 = args.words[1] ?? "";
|
|
28656
29296
|
const command = Object.hasOwn(SCHEDULE_COMMANDS, name2) ? SCHEDULE_COMMANDS[name2] : void 0;
|
|
28657
|
-
if (!command) throw new CliUsageError(
|
|
29297
|
+
if (!command) throw new CliUsageError(USAGE5);
|
|
28658
29298
|
await command({ context, args });
|
|
28659
29299
|
}
|
|
28660
29300
|
|
|
28661
29301
|
// src/services/skill-commands.service.ts
|
|
28662
|
-
import { readdir as readdir3, readFile as
|
|
28663
|
-
import { join as
|
|
28664
|
-
var
|
|
29302
|
+
import { readdir as readdir3, readFile as readFile10 } from "node:fs/promises";
|
|
29303
|
+
import { join as join6, relative as relative3, resolve as resolve5 } from "node:path";
|
|
29304
|
+
var USAGE6 = `Usage:
|
|
28665
29305
|
laze skill list
|
|
28666
29306
|
laze skill install <catalogue-id> [--as <name>]
|
|
28667
29307
|
laze skill install --from <folder> [--as <name>] a folder with a SKILL.md
|
|
@@ -28672,8 +29312,8 @@ async function folderFiles({ root }) {
|
|
|
28672
29312
|
const files = [];
|
|
28673
29313
|
for (const entry of entries) {
|
|
28674
29314
|
if (!entry.isFile()) continue;
|
|
28675
|
-
const full =
|
|
28676
|
-
files.push({ path: relative3(root, full), content: await
|
|
29315
|
+
const full = join6(entry.parentPath, entry.name);
|
|
29316
|
+
files.push({ path: relative3(root, full), content: await readFile10(full, "utf8") });
|
|
28677
29317
|
}
|
|
28678
29318
|
return files.toSorted((a, b) => a.path.localeCompare(b.path));
|
|
28679
29319
|
}
|
|
@@ -28692,7 +29332,7 @@ async function skillList({ context, args }) {
|
|
|
28692
29332
|
async function skillInstall({ context, args }) {
|
|
28693
29333
|
const catalogueId = args.words[2];
|
|
28694
29334
|
const from = flagText({ args, name: "from" });
|
|
28695
|
-
if (!catalogueId === !from) throw new CliUsageError(
|
|
29335
|
+
if (!catalogueId === !from) throw new CliUsageError(USAGE6);
|
|
28696
29336
|
const name2 = flagText({ args, name: "as" });
|
|
28697
29337
|
const files = from ? await folderFiles({ root: resolve5(context.cwd, from) }) : void 0;
|
|
28698
29338
|
const { client } = await signedIn({ context, args });
|
|
@@ -28708,7 +29348,7 @@ async function skillInstall({ context, args }) {
|
|
|
28708
29348
|
}
|
|
28709
29349
|
async function skillShow({ context, args }) {
|
|
28710
29350
|
const name2 = args.words[2];
|
|
28711
|
-
if (!name2) throw new CliUsageError(
|
|
29351
|
+
if (!name2) throw new CliUsageError(USAGE6);
|
|
28712
29352
|
const { client } = await signedIn({ context, args });
|
|
28713
29353
|
const skill2 = await client.post("/api/skills/show", { name: name2 });
|
|
28714
29354
|
if (args.flags.json) return context.out(`${JSON.stringify(skill2, null, 2)}
|
|
@@ -28740,18 +29380,107 @@ var SKILL_COMMANDS = {
|
|
|
28740
29380
|
async function skill({ context, args }) {
|
|
28741
29381
|
const name2 = args.words[1] ?? "";
|
|
28742
29382
|
const command = Object.hasOwn(SKILL_COMMANDS, name2) ? SKILL_COMMANDS[name2] : void 0;
|
|
28743
|
-
if (!command) throw new CliUsageError(
|
|
29383
|
+
if (!command) throw new CliUsageError(USAGE6);
|
|
28744
29384
|
await command({ context, args });
|
|
28745
29385
|
}
|
|
28746
29386
|
|
|
29387
|
+
// src/services/update-commands.service.ts
|
|
29388
|
+
import { realpath } from "node:fs/promises";
|
|
29389
|
+
|
|
29390
|
+
// src/rules/cli-update.rules.ts
|
|
29391
|
+
var CLI_PACKAGE_LATEST = "@lazehq/cli@latest";
|
|
29392
|
+
var MANAGERS = [
|
|
29393
|
+
{ manager: "bun", pattern: /[\\/]\.?bun[\\/]/, command: ["bun", "add", "-g"] },
|
|
29394
|
+
{ manager: "pnpm", pattern: /[\\/]\.?pnpm[\\/]/, command: ["pnpm", "add", "-g"] },
|
|
29395
|
+
{ manager: "yarn", pattern: /[\\/]yarn[\\/]global[\\/]/, command: ["yarn", "global", "add"] },
|
|
29396
|
+
{
|
|
29397
|
+
manager: "npm",
|
|
29398
|
+
pattern: /[\\/]_npx[\\/]|[\\/]node_modules[\\/]@lazehq[\\/]cli[\\/]/,
|
|
29399
|
+
command: ["npm", "install", "-g"]
|
|
29400
|
+
}
|
|
29401
|
+
];
|
|
29402
|
+
var NPM_PREFIX = /^(.+)[\\/]lib[\\/]node_modules[\\/]@lazehq[\\/]cli[\\/]/;
|
|
29403
|
+
var NPX_CACHE2 = /[\\/]_npx[\\/]/;
|
|
29404
|
+
function updatePlanOf({ script }) {
|
|
29405
|
+
if (script === SANDBOX_CLI_PATH) return { kind: "sandbox" };
|
|
29406
|
+
const found = MANAGERS.find(({ pattern }) => pattern.test(script));
|
|
29407
|
+
if (!found) return { kind: "unmanaged", script };
|
|
29408
|
+
const prefix = found.manager === "npm" && !NPX_CACHE2.test(script) ? NPM_PREFIX.exec(script)?.[1] : void 0;
|
|
29409
|
+
return {
|
|
29410
|
+
kind: "install",
|
|
29411
|
+
manager: found.manager,
|
|
29412
|
+
command: [...found.command, ...prefix ? ["--prefix", prefix] : [], CLI_PACKAGE_LATEST]
|
|
29413
|
+
};
|
|
29414
|
+
}
|
|
29415
|
+
|
|
29416
|
+
// src/services/update-commands.service.ts
|
|
29417
|
+
var BY_HAND = `npm install -g ${CLI_PACKAGE_LATEST}`;
|
|
29418
|
+
async function realScriptOf({ program }) {
|
|
29419
|
+
const script = program.at(-1) ?? "";
|
|
29420
|
+
try {
|
|
29421
|
+
return await realpath(script);
|
|
29422
|
+
} catch {
|
|
29423
|
+
return script;
|
|
29424
|
+
}
|
|
29425
|
+
}
|
|
29426
|
+
async function update({
|
|
29427
|
+
context,
|
|
29428
|
+
args
|
|
29429
|
+
}) {
|
|
29430
|
+
const plan = updatePlanOf({ script: await realScriptOf({ program: context.program }) });
|
|
29431
|
+
if (plan.kind === "sandbox") {
|
|
29432
|
+
context.out("This laze comes with the Laze sandbox and updates with every Laze release.\n");
|
|
29433
|
+
return 0;
|
|
29434
|
+
}
|
|
29435
|
+
if (plan.kind === "unmanaged") {
|
|
29436
|
+
context.err(
|
|
29437
|
+
`This laze (${plan.script}) was not installed by a package manager. Install the published one with: ${BY_HAND}
|
|
29438
|
+
`
|
|
29439
|
+
);
|
|
29440
|
+
return 1;
|
|
29441
|
+
}
|
|
29442
|
+
const line = plan.command.join(" ");
|
|
29443
|
+
if (args.flags["dry-run"]) {
|
|
29444
|
+
context.out(`laze ${cliVersionOf()}, installed with ${plan.manager}. Would run: ${line}
|
|
29445
|
+
`);
|
|
29446
|
+
return 0;
|
|
29447
|
+
}
|
|
29448
|
+
context.out(`Updating laze ${cliVersionOf()} with ${plan.manager}: ${line}
|
|
29449
|
+
`);
|
|
29450
|
+
const code = await context.runCommand({ command: plan.command, env: {} });
|
|
29451
|
+
if (code !== 0) {
|
|
29452
|
+
context.err(`${plan.manager} exited ${code}. Update by hand with: ${line}
|
|
29453
|
+
`);
|
|
29454
|
+
return code;
|
|
29455
|
+
}
|
|
29456
|
+
context.out("Updated. `laze --version` names the new version.\n");
|
|
29457
|
+
return 0;
|
|
29458
|
+
}
|
|
29459
|
+
|
|
28747
29460
|
// src/services/vault-commands.service.ts
|
|
28748
|
-
import {
|
|
29461
|
+
import { createHash } from "node:crypto";
|
|
29462
|
+
import { mkdir as mkdir6, readFile as readFile11, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
|
|
29463
|
+
import { tmpdir } from "node:os";
|
|
29464
|
+
import { dirname as dirname4, join as join7 } from "node:path";
|
|
29465
|
+
|
|
29466
|
+
// ../../modules/vault/contract/src/resolution-note.ts
|
|
29467
|
+
var RESOLUTION_NOTE_MAX_CHARS = 500;
|
|
29468
|
+
function cleanResolutionNote(text2) {
|
|
29469
|
+
const oneLine = (text2 ?? "").replace(/[\r\n\u2028\u2029]+/g, " ").replace(/[\p{Cc}\p{Cf}]/gu, "").trim();
|
|
29470
|
+
return Array.from(oneLine).slice(0, RESOLUTION_NOTE_MAX_CHARS).join("").trim();
|
|
29471
|
+
}
|
|
29472
|
+
var resolutionNoteSchema = external_exports.string().max(4e3).default("").transform((text2) => cleanResolutionNote(text2));
|
|
28749
29473
|
|
|
28750
29474
|
// ../../modules/vault/contract/src/vault-devices.ts
|
|
28751
29475
|
var base64Url = external_exports.string().regex(/^[A-Za-z0-9_-]+$/).max(16384);
|
|
28752
29476
|
var name = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,62}$/);
|
|
28753
29477
|
var fieldName = external_exports.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/);
|
|
28754
|
-
var vaultDeviceKindSchema = external_exports.enum([
|
|
29478
|
+
var vaultDeviceKindSchema = external_exports.enum([
|
|
29479
|
+
"passkey",
|
|
29480
|
+
"ios_secure_enclave",
|
|
29481
|
+
"macos_secure_enclave"
|
|
29482
|
+
]);
|
|
29483
|
+
var NATIVE_DEVICE_KINDS = ["ios_secure_enclave", "macos_secure_enclave"];
|
|
28755
29484
|
var vaultDeviceStateSchema = external_exports.enum(["pending", "active"]);
|
|
28756
29485
|
var vaultDevicePasskeySchemaDefinition = external_exports.object({
|
|
28757
29486
|
credentialId: base64Url,
|
|
@@ -28797,7 +29526,15 @@ var finishVaultDeviceEnrolmentInputSchemaDefinition = external_exports.object({
|
|
|
28797
29526
|
credentialPublicKey: base64Url,
|
|
28798
29527
|
credentialAlgorithm: external_exports.literal(-7),
|
|
28799
29528
|
clientDataJSON: base64Url
|
|
28800
|
-
})
|
|
29529
|
+
}).optional(),
|
|
29530
|
+
/** A Secure Enclave device instead of a passkey: its signing key and proof of holding it. */
|
|
29531
|
+
native: external_exports.object({
|
|
29532
|
+
kind: external_exports.enum(NATIVE_DEVICE_KINDS),
|
|
29533
|
+
/** P-256 SPKI DER; signs approvals of later devices. */
|
|
29534
|
+
signingPublicKey: base64Url,
|
|
29535
|
+
/** DER ECDSA over nativeSignedMessage({ purpose: "enrol", challenge }). */
|
|
29536
|
+
signature: base64Url
|
|
29537
|
+
}).optional()
|
|
28801
29538
|
});
|
|
28802
29539
|
var finishVaultDeviceEnrolmentInputSchema = finishVaultDeviceEnrolmentInputSchemaDefinition;
|
|
28803
29540
|
var sealedRecipientSchema = external_exports.object({
|
|
@@ -28815,11 +29552,16 @@ var vaultDeviceAssertionSchemaDefinition = external_exports.object({
|
|
|
28815
29552
|
authenticatorData: base64Url,
|
|
28816
29553
|
signature: base64Url
|
|
28817
29554
|
});
|
|
29555
|
+
var vaultNativeAssertionSchemaDefinition = external_exports.object({
|
|
29556
|
+
approverDeviceId: external_exports.string().min(1),
|
|
29557
|
+
/** DER ECDSA over nativeSignedMessage({ purpose: "approve", challenge }). */
|
|
29558
|
+
nativeSignature: base64Url
|
|
29559
|
+
});
|
|
28818
29560
|
var approveVaultDeviceInputSchemaDefinition = external_exports.object({
|
|
28819
29561
|
workspaceId: external_exports.string().min(1),
|
|
28820
29562
|
deviceId: external_exports.string().min(1),
|
|
28821
29563
|
challenge: external_exports.string().min(1),
|
|
28822
|
-
assertion: vaultDeviceAssertionSchemaDefinition,
|
|
29564
|
+
assertion: external_exports.union([vaultDeviceAssertionSchemaDefinition, vaultNativeAssertionSchemaDefinition]),
|
|
28823
29565
|
/** The new device's recipient for every sealed secret of the owner. */
|
|
28824
29566
|
recipients: external_exports.array(
|
|
28825
29567
|
external_exports.object({ connectionId: external_exports.string().min(1), recipient: sealedRecipientSchema })
|
|
@@ -28867,6 +29609,9 @@ var vaultSealedApprovalSchemaDefinition = external_exports.object({
|
|
|
28867
29609
|
material: vaultSealedMaterialSchemaDefinition
|
|
28868
29610
|
});
|
|
28869
29611
|
var vaultSealedApprovalSchema = vaultSealedApprovalSchemaDefinition;
|
|
29612
|
+
var vaultUi = uiTokens("vault");
|
|
29613
|
+
var VaultSealedApprovalSlot = vaultUi.component("sealedApproval");
|
|
29614
|
+
var VaultNavSlot = vaultUi.component("nav");
|
|
28870
29615
|
var answerSealedApprovalInputSchemaDefinition = external_exports.object({
|
|
28871
29616
|
workspaceId: external_exports.string().min(1),
|
|
28872
29617
|
requestId: external_exports.string().min(1),
|
|
@@ -28881,6 +29626,31 @@ var vaultRunSealedReleaseSchemaDefinition = external_exports.object({
|
|
|
28881
29626
|
});
|
|
28882
29627
|
var vaultRunSealedReleaseSchema = vaultRunSealedReleaseSchemaDefinition;
|
|
28883
29628
|
|
|
29629
|
+
// ../../modules/vault/contract/src/vault-paste.ts
|
|
29630
|
+
var connectionName = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,62}$/);
|
|
29631
|
+
var fieldName2 = external_exports.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).max(64);
|
|
29632
|
+
var compareVaultSecretInputSchemaDefinition = external_exports.object({
|
|
29633
|
+
workspaceId: external_exports.string().min(1),
|
|
29634
|
+
name: connectionName,
|
|
29635
|
+
/** One field of the bundle; without it any field holding the value reads as `same`. */
|
|
29636
|
+
field: fieldName2.optional(),
|
|
29637
|
+
value: external_exports.string().min(1).max(2e4)
|
|
29638
|
+
});
|
|
29639
|
+
var compareVaultSecretInputSchema = compareVaultSecretInputSchemaDefinition;
|
|
29640
|
+
var vaultSecretComparisonSchemaDefinition = external_exports.object({
|
|
29641
|
+
result: external_exports.enum(["absent", "same", "different"]),
|
|
29642
|
+
connectionId: external_exports.string().nullable()
|
|
29643
|
+
});
|
|
29644
|
+
var vaultSecretComparisonSchema = vaultSecretComparisonSchemaDefinition;
|
|
29645
|
+
var replaceVaultSecretValueInputSchemaDefinition = external_exports.object({
|
|
29646
|
+
workspaceId: external_exports.string().min(1),
|
|
29647
|
+
connectionId: external_exports.string().min(1),
|
|
29648
|
+
/** The field to replace; without it, the connection's only field. */
|
|
29649
|
+
field: fieldName2.optional(),
|
|
29650
|
+
value: external_exports.string().min(1).max(2e4)
|
|
29651
|
+
});
|
|
29652
|
+
var replaceVaultSecretValueInputSchema = replaceVaultSecretValueInputSchemaDefinition;
|
|
29653
|
+
|
|
28884
29654
|
// ../../modules/vault/contract/src/vault-reason.ts
|
|
28885
29655
|
var COMMAND_STARTS = new Set(
|
|
28886
29656
|
"sudo laze kv aws curl wget npm pnpm yarn npx git gh kubectl helm docker terraform python python3 node bash sh zsh export cd make cargo go ssh scp psql uv pip echo cat env clickhouse-client".split(
|
|
@@ -28972,9 +29742,12 @@ var vaultEgressTargetSchemaDefinition = external_exports.object({
|
|
|
28972
29742
|
upstream: external_exports.url(),
|
|
28973
29743
|
header: external_exports.string().min(1).default("Authorization"),
|
|
28974
29744
|
prefix: external_exports.string().default("Bearer "),
|
|
28975
|
-
field: vaultFieldNameSchema
|
|
29745
|
+
field: vaultFieldNameSchema,
|
|
29746
|
+
/** Paths whose writes ask a person at any level, such as sending mail; `*` is one segment. */
|
|
29747
|
+
askPaths: external_exports.array(external_exports.string().regex(/^\/[^?\s]*$/)).default([])
|
|
28976
29748
|
});
|
|
28977
29749
|
var vaultEgressTargetSchema = vaultEgressTargetSchemaDefinition;
|
|
29750
|
+
var VAULT_MAX_LEASE_SECONDS = 2 * 86400;
|
|
28978
29751
|
var vaultConnectionSchemaDefinition = external_exports.object({
|
|
28979
29752
|
id: external_exports.string().min(1),
|
|
28980
29753
|
workspaceId: external_exports.string().min(1),
|
|
@@ -28989,6 +29762,8 @@ var vaultConnectionSchemaDefinition = external_exports.object({
|
|
|
28989
29762
|
approverUserIds: external_exports.array(external_exports.string().min(1)),
|
|
28990
29763
|
/** The longest lease an approver may give, set by an admin. */
|
|
28991
29764
|
maxLeaseSeconds: external_exports.number().int().positive().nullable(),
|
|
29765
|
+
/** Every use asks a person: no lease is offered and none covers it. */
|
|
29766
|
+
everyUseAsks: external_exports.boolean().default(false),
|
|
28992
29767
|
fieldNames: external_exports.array(vaultFieldNameSchema),
|
|
28993
29768
|
egress: vaultEgressTargetSchema.nullable(),
|
|
28994
29769
|
status: vaultConnectionStatusSchema,
|
|
@@ -29012,7 +29787,8 @@ var createVaultConnectionInputSchemaDefinition = external_exports.object({
|
|
|
29012
29787
|
sensitivity: vaultSensitivitySchema,
|
|
29013
29788
|
rules: external_exports.string().max(2e3).default(""),
|
|
29014
29789
|
approverUserIds: external_exports.array(external_exports.string().min(1)).default([]),
|
|
29015
|
-
maxLeaseSeconds: external_exports.number().int().positive().nullable().default(null),
|
|
29790
|
+
maxLeaseSeconds: external_exports.number().int().positive().max(VAULT_MAX_LEASE_SECONDS).nullable().default(null),
|
|
29791
|
+
everyUseAsks: external_exports.boolean().default(false),
|
|
29016
29792
|
secret: vaultSecretBundleSchema,
|
|
29017
29793
|
egress: vaultEgressTargetSchema.nullable().default(null)
|
|
29018
29794
|
});
|
|
@@ -29024,7 +29800,8 @@ var updateVaultConnectionInputSchemaDefinition = external_exports.object({
|
|
|
29024
29800
|
sensitivity: vaultSensitivitySchema.optional(),
|
|
29025
29801
|
rules: external_exports.string().max(2e3).optional(),
|
|
29026
29802
|
approverUserIds: external_exports.array(external_exports.string().min(1)).optional(),
|
|
29027
|
-
maxLeaseSeconds: external_exports.number().int().positive().nullable().optional(),
|
|
29803
|
+
maxLeaseSeconds: external_exports.number().int().positive().max(VAULT_MAX_LEASE_SECONDS).nullable().optional(),
|
|
29804
|
+
everyUseAsks: external_exports.boolean().optional(),
|
|
29028
29805
|
secret: vaultSecretBundleSchema.optional(),
|
|
29029
29806
|
egress: vaultEgressTargetSchema.nullable().optional()
|
|
29030
29807
|
});
|
|
@@ -29073,8 +29850,14 @@ var openVaultTurnInputSchemaDefinition = external_exports.object({
|
|
|
29073
29850
|
channel: external_exports.object({ id: external_exports.string().min(1), kind: external_exports.enum(["public", "private", "dm"]) }),
|
|
29074
29851
|
/** False when the requester can no longer see the channel (a schedule's creator who left). */
|
|
29075
29852
|
requesterSeesChannel: external_exports.boolean().default(true),
|
|
29076
|
-
/** The
|
|
29077
|
-
|
|
29853
|
+
/** The thread the agent answers in, so its approval cards show there; null for the channel. */
|
|
29854
|
+
threadRootId: external_exports.string().min(1).nullable().default(null),
|
|
29855
|
+
/** Where the agent runs: a Laze sandbox, or a machine that reaches Laze over the network. */
|
|
29856
|
+
origin: external_exports.enum(["sandbox", "network"]).default("sandbox"),
|
|
29857
|
+
/** The requester's messages in this conversation, oldest first: the judge's permission. */
|
|
29858
|
+
requesterMessages: external_exports.array(external_exports.string()).default([]),
|
|
29859
|
+
/** Everyone else's messages, oldest first: context for the judge, never permission. */
|
|
29860
|
+
otherMessages: external_exports.array(external_exports.object({ sender: external_exports.string().min(1), text: external_exports.string() })).default([])
|
|
29078
29861
|
});
|
|
29079
29862
|
var vaultAlwaysApprovalActionSchema = external_exports.enum([
|
|
29080
29863
|
"send_external",
|
|
@@ -29085,6 +29868,11 @@ var vaultAlwaysApprovalActionSchema = external_exports.enum([
|
|
|
29085
29868
|
]);
|
|
29086
29869
|
var VAULT_ALWAYS_APPROVAL_ACTIONS = vaultAlwaysApprovalActionSchema.options;
|
|
29087
29870
|
var vaultPurposeSchema = external_exports.enum(["use", "send_external"]);
|
|
29871
|
+
var vaultDraftPreviewSchemaDefinition = external_exports.object({
|
|
29872
|
+
header: external_exports.string().max(2e3),
|
|
29873
|
+
body: external_exports.string().max(2e4)
|
|
29874
|
+
});
|
|
29875
|
+
var vaultDraftPreviewSchema = vaultDraftPreviewSchemaDefinition;
|
|
29088
29876
|
var vaultUseInputSchemaDefinition = external_exports.object({
|
|
29089
29877
|
turnToken: external_exports.string().min(1),
|
|
29090
29878
|
/** The connection's name as the agent asks for it, or its id. */
|
|
@@ -29095,14 +29883,22 @@ var vaultUseInputSchemaDefinition = external_exports.object({
|
|
|
29095
29883
|
/** OAuth scopes this use needs; a grant without them is refused with the missing ones. */
|
|
29096
29884
|
requiredScopes: external_exports.array(external_exports.string().min(1)).default([]),
|
|
29097
29885
|
/** A floor on the connection's sensitivity, for a tool its owner marked more guarded. */
|
|
29098
|
-
atLeast: vaultSensitivitySchema.optional()
|
|
29886
|
+
atLeast: vaultSensitivitySchema.optional(),
|
|
29887
|
+
/** The caller knows the use only reads, such as an MCP tool marked read-only. */
|
|
29888
|
+
readOnly: external_exports.boolean().default(false),
|
|
29889
|
+
/** A use that would ask comes back denied with no card: a lookup made only for another card. */
|
|
29890
|
+
withoutAsking: external_exports.boolean().default(false),
|
|
29891
|
+
/** What a send would send, shown on its card; never stored. */
|
|
29892
|
+
preview: vaultDraftPreviewSchema.optional()
|
|
29099
29893
|
});
|
|
29100
29894
|
var vaultRunReleaseSchemaDefinition = external_exports.discriminatedUnion("outcome", [
|
|
29101
29895
|
external_exports.object({
|
|
29102
29896
|
outcome: external_exports.literal("allow"),
|
|
29103
29897
|
env: external_exports.record(external_exports.string(), external_exports.string()),
|
|
29104
29898
|
/** A sealed connection's values, encrypted to the run's own key. */
|
|
29105
|
-
sealed: vaultRunSealedReleaseSchema.optional()
|
|
29899
|
+
sealed: vaultRunSealedReleaseSchema.optional(),
|
|
29900
|
+
/** What the approver told the agent, for the run to print. */
|
|
29901
|
+
message: external_exports.string().optional()
|
|
29106
29902
|
}),
|
|
29107
29903
|
external_exports.object({
|
|
29108
29904
|
outcome: external_exports.literal("ask"),
|
|
@@ -29125,7 +29921,12 @@ var vaultEgressResolveInputSchemaDefinition = external_exports.object({
|
|
|
29125
29921
|
var vaultEgressResolutionSchemaDefinition = external_exports.discriminatedUnion("decision", [
|
|
29126
29922
|
external_exports.object({ decision: external_exports.literal("allow"), value: external_exports.string() }),
|
|
29127
29923
|
external_exports.object({ decision: external_exports.literal("pending"), requestId: external_exports.string() }),
|
|
29128
|
-
external_exports.object({
|
|
29924
|
+
external_exports.object({
|
|
29925
|
+
decision: external_exports.literal("deny"),
|
|
29926
|
+
code: external_exports.string(),
|
|
29927
|
+
/** Who denied it and the note they sent the agent, for the proxy to pass on. */
|
|
29928
|
+
message: external_exports.string().optional()
|
|
29929
|
+
})
|
|
29129
29930
|
]);
|
|
29130
29931
|
var vaultEgressReleaseInputSchemaDefinition = external_exports.object({
|
|
29131
29932
|
agentId: external_exports.string().min(1),
|
|
@@ -29135,6 +29936,10 @@ var vaultEgressReleaseInputSchemaDefinition = external_exports.object({
|
|
|
29135
29936
|
/** The run's P-256 public key, base64url; a sealed connection is released only to it. */
|
|
29136
29937
|
recipient: external_exports.string().max(200).optional()
|
|
29137
29938
|
});
|
|
29939
|
+
var vaultEgressStatusInputSchemaDefinition = external_exports.object({
|
|
29940
|
+
agentId: external_exports.string().min(1),
|
|
29941
|
+
requestId: external_exports.string().min(1)
|
|
29942
|
+
});
|
|
29138
29943
|
var vaultApprovalStateSchema = external_exports.enum([
|
|
29139
29944
|
"pending",
|
|
29140
29945
|
"approved_once",
|
|
@@ -29165,7 +29970,9 @@ var vaultApprovalRequestSchemaDefinition = external_exports.object({
|
|
|
29165
29970
|
answeredByUserId: external_exports.string().nullable(),
|
|
29166
29971
|
answeredVia: vaultAnswerViaSchema.nullable(),
|
|
29167
29972
|
answeredAt: external_exports.iso.datetime().nullable(),
|
|
29168
|
-
leaseExpiresAt: external_exports.iso.datetime().nullable()
|
|
29973
|
+
leaseExpiresAt: external_exports.iso.datetime().nullable(),
|
|
29974
|
+
/** What the person who answered told the agent; empty when nothing. */
|
|
29975
|
+
resolutionNote: external_exports.string().default("")
|
|
29169
29976
|
});
|
|
29170
29977
|
var vaultApprovalRequestSchema = vaultApprovalRequestSchemaDefinition;
|
|
29171
29978
|
var answerVaultApprovalInputSchemaDefinition = external_exports.object({
|
|
@@ -29174,7 +29981,9 @@ var answerVaultApprovalInputSchemaDefinition = external_exports.object({
|
|
|
29174
29981
|
answer: external_exports.enum(["approve_once", "approve_for_agent", "deny"]),
|
|
29175
29982
|
/** Approve for this agent only: up to the connection's admin maximum. */
|
|
29176
29983
|
durationSeconds: external_exports.number().int().positive().optional(),
|
|
29177
|
-
via: vaultAnswerViaSchema
|
|
29984
|
+
via: vaultAnswerViaSchema,
|
|
29985
|
+
/** A short reason, question or steer for the agent, sent with the answer. */
|
|
29986
|
+
resolutionNote: resolutionNoteSchema
|
|
29178
29987
|
});
|
|
29179
29988
|
var answerVaultApprovalInputSchema = answerVaultApprovalInputSchemaDefinition;
|
|
29180
29989
|
var requestVaultActionInputSchemaDefinition = external_exports.object({
|
|
@@ -29210,6 +30019,40 @@ var vaultAuditPageSchemaDefinition = external_exports.object({
|
|
|
29210
30019
|
chain: external_exports.object({ intact: external_exports.boolean(), brokenAtSeq: external_exports.number().int().nullable() })
|
|
29211
30020
|
});
|
|
29212
30021
|
var vaultAuditPageSchema = vaultAuditPageSchemaDefinition;
|
|
30022
|
+
var vaultMostAskedInputSchemaDefinition = external_exports.object({
|
|
30023
|
+
workspaceId: external_exports.string().min(1),
|
|
30024
|
+
days: external_exports.number().int().min(1).max(365).default(30)
|
|
30025
|
+
});
|
|
30026
|
+
var vaultMostAskedInputSchema = vaultMostAskedInputSchemaDefinition;
|
|
30027
|
+
var vaultMostAskedSchemaDefinition = external_exports.object({
|
|
30028
|
+
days: external_exports.number().int().positive(),
|
|
30029
|
+
since: external_exports.iso.datetime(),
|
|
30030
|
+
/** Per connection, the cards that reached a person, most first; owner actions are left out. */
|
|
30031
|
+
connections: external_exports.array(
|
|
30032
|
+
external_exports.object({
|
|
30033
|
+
connectionId: external_exports.string(),
|
|
30034
|
+
cards: external_exports.number().int().nonnegative(),
|
|
30035
|
+
/** Every ask that joined one of those cards. */
|
|
30036
|
+
asks: external_exports.number().int().nonnegative(),
|
|
30037
|
+
approved: external_exports.number().int().nonnegative(),
|
|
30038
|
+
denied: external_exports.number().int().nonnegative(),
|
|
30039
|
+
expired: external_exports.number().int().nonnegative(),
|
|
30040
|
+
pending: external_exports.number().int().nonnegative(),
|
|
30041
|
+
/** Cards by why the vault asked: `sensitivity_ask`, `judge_unsure`, `rate_limited`... */
|
|
30042
|
+
why: external_exports.record(external_exports.string(), external_exports.number().int().nonnegative()),
|
|
30043
|
+
/** The newest distinct reasons and commands callers gave, redacted like every audit line. */
|
|
30044
|
+
samples: external_exports.array(
|
|
30045
|
+
external_exports.object({
|
|
30046
|
+
at: external_exports.iso.datetime(),
|
|
30047
|
+
agentId: external_exports.string().nullable(),
|
|
30048
|
+
reason: external_exports.string().nullable(),
|
|
30049
|
+
command: external_exports.array(external_exports.string())
|
|
30050
|
+
})
|
|
30051
|
+
)
|
|
30052
|
+
})
|
|
30053
|
+
)
|
|
30054
|
+
});
|
|
30055
|
+
var vaultMostAskedSchema = vaultMostAskedSchemaDefinition;
|
|
29213
30056
|
var vaultConnectionUseSchemaDefinition = external_exports.object({
|
|
29214
30057
|
at: external_exports.iso.datetime(),
|
|
29215
30058
|
action: external_exports.string(),
|
|
@@ -29233,6 +30076,22 @@ var saveGithubInstallationInputSchemaDefinition = external_exports.object({
|
|
|
29233
30076
|
/** The connection to point at this installation again, after a reinstall. */
|
|
29234
30077
|
connectionId: external_exports.string().optional()
|
|
29235
30078
|
});
|
|
30079
|
+
var vaultJudgeStatusSchemaDefinition = external_exports.object({ configured: external_exports.boolean() });
|
|
30080
|
+
var vaultJudgeStatusSchema = vaultJudgeStatusSchemaDefinition;
|
|
30081
|
+
var vaultLimitSubjectSchema = external_exports.string().regex(/^[a-z0-9-]+(\.[a-z]+)?$/);
|
|
30082
|
+
var vaultLevelLimitSchemaDefinition = external_exports.object({
|
|
30083
|
+
subject: vaultLimitSubjectSchema,
|
|
30084
|
+
most: vaultSensitivitySchema.exclude(["auto"]),
|
|
30085
|
+
updatedByUserId: external_exports.string(),
|
|
30086
|
+
updatedAt: external_exports.iso.datetime()
|
|
30087
|
+
});
|
|
30088
|
+
var vaultLevelLimitSchema = vaultLevelLimitSchemaDefinition;
|
|
30089
|
+
var setVaultLevelLimitInputSchemaDefinition = external_exports.object({
|
|
30090
|
+
workspaceId: external_exports.string().min(1),
|
|
30091
|
+
subject: vaultLimitSubjectSchema,
|
|
30092
|
+
most: vaultSensitivitySchema.exclude(["auto"]).nullable()
|
|
30093
|
+
});
|
|
30094
|
+
var setVaultLevelLimitInputSchema = setVaultLevelLimitInputSchemaDefinition;
|
|
29236
30095
|
var VaultApi = moduleApi()("vault");
|
|
29237
30096
|
var workspaceInput = external_exports.object({ workspaceId: external_exports.string().min(1) });
|
|
29238
30097
|
var connectionInput = external_exports.object({
|
|
@@ -29243,25 +30102,34 @@ var vaultTrpc = defineTrpcContract("vault").mutation("createConnection").withInp
|
|
|
29243
30102
|
external_exports.object({ ...connectionInput.shape, limit: external_exports.number().int().min(1).max(200).optional() })
|
|
29244
30103
|
).withOutput(external_exports.array(vaultConnectionUseSchema)).mutation("revealConnection").withInput(external_exports.object({ ...connectionInput.shape, reason: external_exports.string().trim().min(1).max(200) })).withOutput(external_exports.object({ fields: external_exports.record(external_exports.string(), external_exports.string()) })).mutation("grantConnection").withInput(grantVaultConnectionInputSchema).withOutput(vaultGrantSchema).mutation("lendToChannel").withInput(lendVaultConnectionInputSchema).withOutput(vaultGrantSchema).mutation("revokeGrant").withInput(external_exports.object({ workspaceId: external_exports.string().min(1), grantId: external_exports.string().min(1) })).withOutput(external_exports.object({ revoked: external_exports.literal(true) })).query("listGrants").withInput(connectionInput).withOutput(external_exports.array(vaultGrantSchema)).query("listApprovals").withInput(external_exports.object({ ...workspaceInput.shape, state: vaultApprovalStateSchema.optional() })).withOutput(external_exports.array(vaultApprovalRequestSchema)).mutation("answerApproval").withInput(answerVaultApprovalInputSchema).withOutput(vaultApprovalRequestSchema).query("listAudit").withInput(
|
|
29245
30104
|
external_exports.object({ ...workspaceInput.shape, limit: external_exports.number().int().min(1).max(500).optional() })
|
|
29246
|
-
).withOutput(vaultAuditPageSchema).query("listDevices").withInput(workspaceInput).withOutput(external_exports.array(vaultDeviceSchema)).mutation("beginDeviceEnrolment").withInput(workspaceInput).withOutput(vaultDeviceEnrolmentSchema).mutation("finishDeviceEnrolment").withInput(finishVaultDeviceEnrolmentInputSchema).withOutput(vaultDeviceSchema).mutation("beginDeviceApproval").withInput(external_exports.object({ ...workspaceInput.shape, deviceId: external_exports.string().min(1) })).withOutput(external_exports.object({ challenge: external_exports.string(), sealed: external_exports.array(vaultSealedMaterialSchema) })).mutation("approveDevice").withInput(approveVaultDeviceInputSchema).withOutput(vaultDeviceSchema).mutation("removeDevice").withInput(external_exports.object({ ...workspaceInput.shape, deviceId: external_exports.string().min(1) })).withOutput(external_exports.object({ removed: external_exports.literal(true) })).mutation("createSealedConnection").withInput(createSealedConnectionInputSchema).withOutput(vaultConnectionSchema).mutation("resealConnection").withInput(resealConnectionInputSchema).withOutput(vaultConnectionSchema).mutation("openSealedConnection").withInput(external_exports.object({ ...connectionInput.shape, reason: external_exports.string().trim().min(1).max(200) })).withOutput(vaultSealedMaterialSchema).query("getSealedApproval").withInput(external_exports.object({ ...workspaceInput.shape, requestId: external_exports.string().min(1) })).withOutput(vaultSealedApprovalSchema).mutation("answerSealedApproval").withInput(answerSealedApprovalInputSchema).withOutput(vaultApprovalRequestSchema).build();
|
|
30105
|
+
).withOutput(vaultAuditPageSchema).query("mostAsked").withInput(vaultMostAskedInputSchema).withOutput(vaultMostAskedSchema).query("judgeStatus").withInput(workspaceInput).withOutput(vaultJudgeStatusSchema).query("listLevelLimits").withInput(workspaceInput).withOutput(external_exports.array(vaultLevelLimitSchema)).mutation("setLevelLimit").withInput(setVaultLevelLimitInputSchema).withOutput(external_exports.array(vaultLevelLimitSchema)).query("listDevices").withInput(workspaceInput).withOutput(external_exports.array(vaultDeviceSchema)).mutation("beginDeviceEnrolment").withInput(workspaceInput).withOutput(vaultDeviceEnrolmentSchema).mutation("finishDeviceEnrolment").withInput(finishVaultDeviceEnrolmentInputSchema).withOutput(vaultDeviceSchema).mutation("beginDeviceApproval").withInput(external_exports.object({ ...workspaceInput.shape, deviceId: external_exports.string().min(1) })).withOutput(external_exports.object({ challenge: external_exports.string(), sealed: external_exports.array(vaultSealedMaterialSchema) })).mutation("approveDevice").withInput(approveVaultDeviceInputSchema).withOutput(vaultDeviceSchema).mutation("removeDevice").withInput(external_exports.object({ ...workspaceInput.shape, deviceId: external_exports.string().min(1) })).withOutput(external_exports.object({ removed: external_exports.literal(true) })).mutation("createSealedConnection").withInput(createSealedConnectionInputSchema).withOutput(vaultConnectionSchema).mutation("resealConnection").withInput(resealConnectionInputSchema).withOutput(vaultConnectionSchema).mutation("openSealedConnection").withInput(external_exports.object({ ...connectionInput.shape, reason: external_exports.string().trim().min(1).max(200) })).withOutput(vaultSealedMaterialSchema).query("getSealedApproval").withInput(external_exports.object({ ...workspaceInput.shape, requestId: external_exports.string().min(1) })).withOutput(vaultSealedApprovalSchema).mutation("answerSealedApproval").withInput(answerSealedApprovalInputSchema).withOutput(vaultApprovalRequestSchema).mutation("compareSecret").withInput(compareVaultSecretInputSchema).withOutput(vaultSecretComparisonSchema).mutation("replaceSecretValue").withInput(replaceVaultSecretValueInputSchema).withOutput(vaultConnectionSchema).build();
|
|
29247
30106
|
|
|
29248
30107
|
// ../../modules/vault/contract/src/vault.config.ts
|
|
29249
30108
|
var positiveInt = external_exports.coerce.number().int().positive();
|
|
29250
30109
|
var vaultConfig = Config.define((c) => ({
|
|
29251
|
-
approvalTimeoutMinutes: c.env("VAULT_APPROVAL_TIMEOUT_MINUTES", positiveInt.default(
|
|
30110
|
+
approvalTimeoutMinutes: c.env("VAULT_APPROVAL_TIMEOUT_MINUTES", positiveInt.default(720)),
|
|
29252
30111
|
/** How long an approve-once answer waits for the same ask to come back for it. */
|
|
29253
30112
|
approveOnceWindowMinutes: c.env("VAULT_APPROVE_ONCE_WINDOW_MINUTES", positiveInt.default(10)),
|
|
29254
30113
|
/** The lease cap when an admin set none on the connection. */
|
|
29255
|
-
defaultMaxLeaseHours: c.env("VAULT_DEFAULT_MAX_LEASE_HOURS", positiveInt.default(
|
|
30114
|
+
defaultMaxLeaseHours: c.env("VAULT_DEFAULT_MAX_LEASE_HOURS", positiveInt.default(48)),
|
|
29256
30115
|
turnTtlMinutes: c.env("VAULT_TURN_TTL_MINUTES", positiveInt.default(720)),
|
|
29257
30116
|
judgeTimeoutMs: c.env("VAULT_JUDGE_TIMEOUT_MS", positiveInt.default(2e4)),
|
|
30117
|
+
/** How long one judge answer is reused for the same question. */
|
|
30118
|
+
judgeCacheMinutes: c.env("VAULT_JUDGE_CACHE_MINUTES", positiveInt.default(10)),
|
|
30119
|
+
/** The judge's price per input token in nano-USD, metered on the workspace's usage. */
|
|
30120
|
+
judgeNanoUsdPerInputToken: c.env(
|
|
30121
|
+
"VAULT_JUDGE_NANO_USD_PER_INPUT_TOKEN",
|
|
30122
|
+
positiveInt.default(100)
|
|
30123
|
+
),
|
|
29258
30124
|
/** How long after a process starts it still accepts turn tokens signed under the previous key. */
|
|
29259
30125
|
previousKeyGraceMinutes: c.env(
|
|
29260
30126
|
"VAULT_PREVIOUS_KEY_GRACE_MINUTES",
|
|
29261
30127
|
external_exports.coerce.number().int().min(0).default(30)
|
|
29262
30128
|
),
|
|
29263
30129
|
/** The origin passkeys are made on; unset accepts any localhost origin, for development. */
|
|
29264
|
-
publicBaseUrl
|
|
30130
|
+
publicBaseUrl,
|
|
30131
|
+
/** A file each audit chain head is appended to as a JSON line; unset only logs the heads. */
|
|
30132
|
+
auditHeadFile: c.env("VAULT_AUDIT_HEAD_FILE", external_exports.string().min(1).optional())
|
|
29265
30133
|
}));
|
|
29266
30134
|
|
|
29267
30135
|
// ../../modules/vault/contract/src/vault.errors.ts
|
|
@@ -29289,7 +30157,20 @@ var vaultApprovalRequestedPayloadSchemaDefinition = external_exports.object({
|
|
|
29289
30157
|
why: external_exports.string(),
|
|
29290
30158
|
/** The longest lease the card may offer; null offers only once and deny. */
|
|
29291
30159
|
maxLeaseSeconds: external_exports.number().int().positive().nullable(),
|
|
29292
|
-
expiresAt: external_exports.iso.datetime()
|
|
30160
|
+
expiresAt: external_exports.iso.datetime(),
|
|
30161
|
+
/** The thread the agent was answering in; null when it answered in the channel. */
|
|
30162
|
+
threadRootId: external_exports.string().nullable().default(null),
|
|
30163
|
+
/** What the agent asked to do, as one line: a command, a request line or a tool. */
|
|
30164
|
+
line: external_exports.string().default(""),
|
|
30165
|
+
/** For a relay call, the host and method it goes to. */
|
|
30166
|
+
host: external_exports.string().nullable().default(null),
|
|
30167
|
+
method: external_exports.string().nullable().default(null),
|
|
30168
|
+
/** The automatic check's plain line on a Checked use; null when none ran. Odds stay in audit. */
|
|
30169
|
+
judgeLine: external_exports.string().nullable().default(null),
|
|
30170
|
+
/** Sealed to the owner's devices: Allow goes through the device's passkey, deny does not. */
|
|
30171
|
+
sealed: external_exports.boolean().default(false),
|
|
30172
|
+
/** For a send, the message it would send, read from the provider. */
|
|
30173
|
+
draft: vaultDraftPreviewSchema.nullable().default(null)
|
|
29293
30174
|
});
|
|
29294
30175
|
var vaultApprovalResolvedPayloadSchemaDefinition = external_exports.object({
|
|
29295
30176
|
workspaceId: external_exports.string().min(1),
|
|
@@ -29298,7 +30179,16 @@ var vaultApprovalResolvedPayloadSchemaDefinition = external_exports.object({
|
|
|
29298
30179
|
answeredByUserId: external_exports.string().nullable(),
|
|
29299
30180
|
answeredVia: external_exports.string().nullable(),
|
|
29300
30181
|
leaseExpiresAt: external_exports.iso.datetime().nullable(),
|
|
29301
|
-
at: external_exports.iso.datetime()
|
|
30182
|
+
at: external_exports.iso.datetime(),
|
|
30183
|
+
/** Where the agent asked, so a note can steer its next turn there. */
|
|
30184
|
+
agentId: external_exports.string().default(""),
|
|
30185
|
+
channelId: external_exports.string().default(""),
|
|
30186
|
+
/** What the person who answered told the agent; empty when nothing. */
|
|
30187
|
+
resolutionNote: external_exports.string().default(""),
|
|
30188
|
+
/** The display name of who answered; empty for a timeout. */
|
|
30189
|
+
answeredByName: external_exports.string().default(""),
|
|
30190
|
+
/** A deny or a timeout: until when the same action is refused without a new card. */
|
|
30191
|
+
blockedUntil: external_exports.iso.datetime().nullable().default(null)
|
|
29302
30192
|
});
|
|
29303
30193
|
|
|
29304
30194
|
// ../../modules/vault/contract/src/vault-oauth.ts
|
|
@@ -29377,9 +30267,12 @@ async function sharedSecret(input2) {
|
|
|
29377
30267
|
);
|
|
29378
30268
|
return new Uint8Array(bits);
|
|
29379
30269
|
}
|
|
30270
|
+
function agreementOf(privateKey) {
|
|
30271
|
+
return (publicKey) => sharedSecret({ privateKey, publicKey });
|
|
30272
|
+
}
|
|
29380
30273
|
async function decryptFrom(input2) {
|
|
29381
30274
|
const epk = fromBase64Url(input2.epk);
|
|
29382
|
-
const ikm = await
|
|
30275
|
+
const ikm = await input2.agree(epk);
|
|
29383
30276
|
const key = await hkdfKey({ ikm, salt: concat(epk, input2.publicKey), info: input2.info });
|
|
29384
30277
|
return gcmOpen({ key, sealed: fromBase64Url(input2.sealed), aad: input2.aad });
|
|
29385
30278
|
}
|
|
@@ -29397,7 +30290,7 @@ function fieldsOf(value) {
|
|
|
29397
30290
|
var releaseLabel = (requestId) => `laze-vault/release/v1/${requestId}`;
|
|
29398
30291
|
async function openRunRelease(input2) {
|
|
29399
30292
|
const plain = await decryptFrom({
|
|
29400
|
-
|
|
30293
|
+
agree: agreementOf(input2.runPrivateKey),
|
|
29401
30294
|
publicKey: fromBase64Url(input2.runPublicKey),
|
|
29402
30295
|
epk: input2.release.epk,
|
|
29403
30296
|
sealed: input2.release.ciphertext,
|
|
@@ -29408,10 +30301,14 @@ async function openRunRelease(input2) {
|
|
|
29408
30301
|
}
|
|
29409
30302
|
|
|
29410
30303
|
// src/services/vault-commands.service.ts
|
|
29411
|
-
var
|
|
30304
|
+
var USAGE7 = `Usage: laze vault run <connection> --reason "<one plain sentence>" [--wait <s>] -- <command> [args...]
|
|
29412
30305
|
Runs the command with the connection's values in its environment, inside a Laze agent's sandbox.`;
|
|
29413
30306
|
var POLL_MS = 3e3;
|
|
29414
|
-
var
|
|
30307
|
+
var RESTART_WAIT_MS = 12e4;
|
|
30308
|
+
var RESTART_BACKOFF_MS = [1e3, 2e3, 4e3, 8e3, 1e4];
|
|
30309
|
+
var P2562 = { name: "ECDH", namedCurve: "P-256" };
|
|
30310
|
+
var ServerGoneError = class extends Error {
|
|
30311
|
+
};
|
|
29415
30312
|
function proxyOf({ env }) {
|
|
29416
30313
|
const raw = env.HTTP_PROXY ?? env.http_proxy;
|
|
29417
30314
|
if (!raw) throw new CliUsageError("laze vault run works only inside a Laze agent's sandbox");
|
|
@@ -29423,42 +30320,103 @@ function proxyOf({ env }) {
|
|
|
29423
30320
|
authorization: `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`
|
|
29424
30321
|
};
|
|
29425
30322
|
}
|
|
29426
|
-
|
|
30323
|
+
function turnFileOf({
|
|
29427
30324
|
env
|
|
29428
30325
|
}) {
|
|
29429
|
-
|
|
29430
|
-
|
|
30326
|
+
return env.LAZE_TURN_FILE || void 0;
|
|
30327
|
+
}
|
|
30328
|
+
async function turnTokenOf2({
|
|
30329
|
+
env,
|
|
30330
|
+
turnFile
|
|
30331
|
+
}) {
|
|
30332
|
+
const pinned = env.LAZE_TURN_TOKEN?.trim();
|
|
30333
|
+
if (pinned) return pinned;
|
|
30334
|
+
if (!turnFile) throw new CliUsageError("laze vault run works only during an agent's turn");
|
|
29431
30335
|
try {
|
|
29432
|
-
return (await
|
|
30336
|
+
return (await readFile11(turnFile, "utf8")).trim();
|
|
29433
30337
|
} catch {
|
|
29434
30338
|
throw new CliUsageError("laze vault run works only during an agent's turn");
|
|
29435
30339
|
}
|
|
29436
30340
|
}
|
|
29437
|
-
|
|
29438
|
-
|
|
29439
|
-
connection
|
|
29440
|
-
reason,
|
|
29441
|
-
command,
|
|
29442
|
-
recipient
|
|
30341
|
+
function runKeyPathOf({
|
|
30342
|
+
turnFile,
|
|
30343
|
+
connection
|
|
29443
30344
|
}) {
|
|
29444
|
-
const
|
|
29445
|
-
const
|
|
29446
|
-
|
|
29447
|
-
|
|
29448
|
-
|
|
29449
|
-
|
|
29450
|
-
|
|
29451
|
-
|
|
29452
|
-
|
|
29453
|
-
|
|
30345
|
+
const name2 = createHash("sha256").update(connection).digest("hex");
|
|
30346
|
+
const base = turnFile ? dirname4(turnFile) : join7(tmpdir(), "laze-vault");
|
|
30347
|
+
return join7(base, "vault-run-keys", `${name2}.json`);
|
|
30348
|
+
}
|
|
30349
|
+
async function runKeyAt({ path }) {
|
|
30350
|
+
const saved = await readFile11(path, "utf8").then(
|
|
30351
|
+
(text2) => JSON.parse(text2),
|
|
30352
|
+
() => void 0
|
|
30353
|
+
);
|
|
30354
|
+
if (saved && typeof saved.publicKey === "string" && saved.privateKey) {
|
|
30355
|
+
const privateKey = await globalThis.crypto.subtle.importKey("jwk", saved.privateKey, P2562, false, ["deriveBits"]).catch(() => void 0);
|
|
30356
|
+
if (privateKey) return { privateKey, publicKey: saved.publicKey };
|
|
30357
|
+
}
|
|
30358
|
+
const fresh = await generateEcdhKeys();
|
|
30359
|
+
const jwk = await globalThis.crypto.subtle.exportKey("jwk", fresh.privateKey);
|
|
30360
|
+
await mkdir6(dirname4(path), { recursive: true, mode: 448 });
|
|
30361
|
+
await writeFile6(path, JSON.stringify({ publicKey: fresh.publicKey, privateKey: jwk }), {
|
|
30362
|
+
mode: 384
|
|
29454
30363
|
});
|
|
30364
|
+
return fresh;
|
|
30365
|
+
}
|
|
30366
|
+
function connectionRefused(error62) {
|
|
30367
|
+
const cause = error62.cause;
|
|
30368
|
+
if (cause?.code === "ECONNREFUSED") return true;
|
|
30369
|
+
return cause?.errors?.some((inner) => inner.code === "ECONNREFUSED") ?? false;
|
|
30370
|
+
}
|
|
30371
|
+
async function sendOnce({
|
|
30372
|
+
context,
|
|
30373
|
+
url: url2,
|
|
30374
|
+
init
|
|
30375
|
+
}) {
|
|
30376
|
+
let response;
|
|
30377
|
+
try {
|
|
30378
|
+
response = await context.fetcher(url2, init);
|
|
30379
|
+
} catch (error62) {
|
|
30380
|
+
const wasRefused = connectionRefused(error62);
|
|
30381
|
+
if (init.method === "POST" && !wasRefused) throw error62;
|
|
30382
|
+
return { restarting: wasRefused ? "connection refused" : String(error62) };
|
|
30383
|
+
}
|
|
30384
|
+
if (response.status !== 502 && response.status !== 503) return { response };
|
|
30385
|
+
const code = codeOf(await response.clone().text());
|
|
30386
|
+
const neverReached = response.status === 503 && code === "vault_not_answering";
|
|
30387
|
+
if (init.method === "POST" && !neverReached) return { response };
|
|
30388
|
+
return { restarting: `status ${response.status}${code ? ` ${code}` : ""}` };
|
|
30389
|
+
}
|
|
30390
|
+
async function reach(input2) {
|
|
30391
|
+
const { context } = input2;
|
|
30392
|
+
const started = context.nowMs();
|
|
30393
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
30394
|
+
const sent = await sendOnce(input2);
|
|
30395
|
+
if ("response" in sent) return sent.response;
|
|
30396
|
+
if (context.nowMs() - started >= RESTART_WAIT_MS) {
|
|
30397
|
+
throw new ServerGoneError(
|
|
30398
|
+
`laze vault: the Laze server did not come back (${sent.restarting})`
|
|
30399
|
+
);
|
|
30400
|
+
}
|
|
30401
|
+
if (attempt === 0) {
|
|
30402
|
+
context.err(
|
|
30403
|
+
`laze vault: the Laze server is not answering (${sent.restarting}), probably restarting; waiting up to 2 min...
|
|
30404
|
+
`
|
|
30405
|
+
);
|
|
30406
|
+
}
|
|
30407
|
+
await context.sleep(RESTART_BACKOFF_MS[Math.min(attempt, RESTART_BACKOFF_MS.length - 1)] ?? 0);
|
|
30408
|
+
}
|
|
30409
|
+
}
|
|
30410
|
+
function codeOf(text2) {
|
|
30411
|
+
return /"code"\s*:\s*"([^"]+)"/.exec(text2)?.[1];
|
|
30412
|
+
}
|
|
30413
|
+
async function releaseOf({ response }) {
|
|
29455
30414
|
const text2 = await response.text();
|
|
29456
30415
|
if (!response.ok) {
|
|
29457
|
-
const code = /"code"\s*:\s*"([^"]+)"/.exec(text2)?.[1] ?? `status ${response.status}`;
|
|
29458
30416
|
return {
|
|
29459
30417
|
outcome: "deny",
|
|
29460
30418
|
exitCode: 1,
|
|
29461
|
-
message: `laze vault: the release was refused (${
|
|
30419
|
+
message: `laze vault: the release was refused (${codeOf(text2) ?? `status ${response.status}`})`
|
|
29462
30420
|
};
|
|
29463
30421
|
}
|
|
29464
30422
|
return JSON.parse(text2);
|
|
@@ -29476,49 +30434,91 @@ async function envOf({
|
|
|
29476
30434
|
});
|
|
29477
30435
|
return { ...release.env, ...sealed };
|
|
29478
30436
|
}
|
|
30437
|
+
function deadlineOf({ args, nowMs }) {
|
|
30438
|
+
const wait = flagText({ args, name: "wait" }) || (args.flags.wait === true ? args.words[3] : "");
|
|
30439
|
+
if (!wait) return Infinity;
|
|
30440
|
+
if (!(Number(wait) >= 0)) throw new CliUsageError(`--wait takes a number of seconds
|
|
30441
|
+
${USAGE7}`);
|
|
30442
|
+
return nowMs + Number(wait) * 1e3;
|
|
30443
|
+
}
|
|
30444
|
+
async function untilAnswered({
|
|
30445
|
+
context,
|
|
30446
|
+
first,
|
|
30447
|
+
origin,
|
|
30448
|
+
headers,
|
|
30449
|
+
deadline
|
|
30450
|
+
}) {
|
|
30451
|
+
let release = first;
|
|
30452
|
+
while (release.outcome === "ask") {
|
|
30453
|
+
if (context.nowMs() + POLL_MS > deadline) {
|
|
30454
|
+
context.err(`${release.message}. Not approved yet; ask again later.
|
|
30455
|
+
`);
|
|
30456
|
+
return "capped";
|
|
30457
|
+
}
|
|
30458
|
+
if (release === first) {
|
|
30459
|
+
context.err(`${release.message}. Waiting for an answer (cards expire after 12 hours)...
|
|
30460
|
+
`);
|
|
30461
|
+
}
|
|
30462
|
+
await context.sleep(POLL_MS);
|
|
30463
|
+
const url2 = `${origin}/vault/release/${encodeURIComponent(release.requestId)}`;
|
|
30464
|
+
release = await releaseOf({
|
|
30465
|
+
response: await reach({ context, url: url2, init: { method: "GET", headers } })
|
|
30466
|
+
});
|
|
30467
|
+
}
|
|
30468
|
+
return release;
|
|
30469
|
+
}
|
|
29479
30470
|
async function vaultRun({
|
|
29480
30471
|
context,
|
|
29481
30472
|
args
|
|
29482
30473
|
}) {
|
|
29483
30474
|
const connection = args.words[2];
|
|
29484
30475
|
const reason = flagText({ args, name: "reason" });
|
|
29485
|
-
if (!connection || args.rest.length === 0) throw new CliUsageError(
|
|
30476
|
+
if (!connection || args.rest.length === 0) throw new CliUsageError(USAGE7);
|
|
29486
30477
|
if (!reason) throw new CliUsageError(`Say why with --reason "<one plain sentence>"
|
|
29487
|
-
${
|
|
29488
|
-
const
|
|
29489
|
-
const
|
|
29490
|
-
|
|
29491
|
-
const
|
|
29492
|
-
|
|
29493
|
-
|
|
29494
|
-
|
|
29495
|
-
|
|
29496
|
-
|
|
29497
|
-
|
|
29498
|
-
|
|
30478
|
+
${USAGE7}`);
|
|
30479
|
+
const deadline = deadlineOf({ args, nowMs: context.nowMs() });
|
|
30480
|
+
const env = context.environment.inherited;
|
|
30481
|
+
const proxy = proxyOf({ env });
|
|
30482
|
+
const turnFile = turnFileOf({ env });
|
|
30483
|
+
const headers = {
|
|
30484
|
+
"proxy-authorization": proxy.authorization,
|
|
30485
|
+
"x-laze-turn": await turnTokenOf2({ env, turnFile })
|
|
30486
|
+
};
|
|
30487
|
+
const keyPath = runKeyPathOf({ turnFile, connection });
|
|
30488
|
+
const run = await runKeyAt({ path: keyPath });
|
|
30489
|
+
const body = JSON.stringify({ connection, reason, command: args.rest, recipient: run.publicKey });
|
|
30490
|
+
let release;
|
|
30491
|
+
try {
|
|
30492
|
+
const first = await releaseOf({
|
|
30493
|
+
response: await reach({
|
|
30494
|
+
context,
|
|
30495
|
+
url: `${proxy.origin}/vault/release`,
|
|
30496
|
+
init: { method: "POST", headers: { ...headers, "content-type": "application/json" }, body }
|
|
30497
|
+
})
|
|
29499
30498
|
});
|
|
29500
|
-
|
|
29501
|
-
|
|
29502
|
-
|
|
29503
|
-
|
|
29504
|
-
context.err(`${release.message}
|
|
29505
|
-
`);
|
|
29506
|
-
return release.exitCode || 1;
|
|
29507
|
-
}
|
|
29508
|
-
if (context.nowMs() + POLL_MS > deadline) {
|
|
29509
|
-
context.err(`${release.message}. Not approved yet; ask again later.
|
|
30499
|
+
release = await untilAnswered({ context, first, origin: proxy.origin, headers, deadline });
|
|
30500
|
+
} catch (error62) {
|
|
30501
|
+
if (!(error62 instanceof ServerGoneError)) throw error62;
|
|
30502
|
+
context.err(`${error62.message}. Run the command again to keep waiting.
|
|
29510
30503
|
`);
|
|
29511
|
-
|
|
29512
|
-
|
|
29513
|
-
|
|
30504
|
+
return 75;
|
|
30505
|
+
}
|
|
30506
|
+
if (release === "capped") return 75;
|
|
30507
|
+
if (release.outcome === "deny") {
|
|
30508
|
+
await rm3(keyPath, { force: true });
|
|
30509
|
+
context.err(`${release.message}
|
|
29514
30510
|
`);
|
|
29515
|
-
|
|
29516
|
-
await context.sleep(POLL_MS);
|
|
30511
|
+
return release.exitCode || 1;
|
|
29517
30512
|
}
|
|
30513
|
+
const childEnv = await envOf({ release, run });
|
|
30514
|
+
await rm3(keyPath, { force: true });
|
|
30515
|
+
if (release.message) context.err(`${release.message}
|
|
30516
|
+
`);
|
|
30517
|
+
return context.runCommand({ command: args.rest, env: childEnv });
|
|
29518
30518
|
}
|
|
29519
30519
|
|
|
29520
30520
|
// src/services/wiki-commands.service.ts
|
|
29521
|
-
var
|
|
30521
|
+
var USAGE8 = `Usage:
|
|
29522
30522
|
laze wiki list
|
|
29523
30523
|
laze wiki get <path>
|
|
29524
30524
|
laze wiki put <path> <markdown|@file|-> [--title <title>] [--channel <channel>] [--base <version>]
|
|
@@ -29535,7 +30535,7 @@ async function wikiList({ context, args }) {
|
|
|
29535
30535
|
}
|
|
29536
30536
|
async function wikiGet({ context, args }) {
|
|
29537
30537
|
const path = args.words[2];
|
|
29538
|
-
if (!path) throw new CliUsageError(
|
|
30538
|
+
if (!path) throw new CliUsageError(USAGE8);
|
|
29539
30539
|
const { client } = await signedIn({ context, args });
|
|
29540
30540
|
const page = await client.post("/api/wiki/get", { path });
|
|
29541
30541
|
if (args.flags.json) return context.out(`${JSON.stringify(page, null, 2)}
|
|
@@ -29552,7 +30552,7 @@ Linked from: ${page.backlinks.map((link) => link.path).join(", ")}
|
|
|
29552
30552
|
async function wikiPut({ context, args }) {
|
|
29553
30553
|
const path = args.words[2];
|
|
29554
30554
|
const value = args.words.slice(3).join(" ");
|
|
29555
|
-
if (!path || !value) throw new CliUsageError(
|
|
30555
|
+
if (!path || !value) throw new CliUsageError(USAGE8);
|
|
29556
30556
|
const body = await textArgument({ context, value });
|
|
29557
30557
|
const title = flagText({ args, name: "title" });
|
|
29558
30558
|
const channel = flagText({ args, name: "channel" });
|
|
@@ -29572,7 +30572,7 @@ async function wikiPut({ context, args }) {
|
|
|
29572
30572
|
}
|
|
29573
30573
|
async function wikiSearch({ context, args }) {
|
|
29574
30574
|
const query = args.words.slice(2).join(" ").trim();
|
|
29575
|
-
if (!query) throw new CliUsageError(
|
|
30575
|
+
if (!query) throw new CliUsageError(USAGE8);
|
|
29576
30576
|
const { client } = await signedIn({ context, args });
|
|
29577
30577
|
const hits = await client.post("/api/wiki/search", { query });
|
|
29578
30578
|
if (args.flags.json) return context.out(`${JSON.stringify(hits, null, 2)}
|
|
@@ -29584,7 +30584,7 @@ var WIKI_COMMANDS = { list: wikiList, get: wikiGet, put: wikiPut, search: wikiSe
|
|
|
29584
30584
|
async function wiki({ context, args }) {
|
|
29585
30585
|
const name2 = args.words[1] ?? "";
|
|
29586
30586
|
const command = Object.hasOwn(WIKI_COMMANDS, name2) ? WIKI_COMMANDS[name2] : void 0;
|
|
29587
|
-
if (!command) throw new CliUsageError(
|
|
30587
|
+
if (!command) throw new CliUsageError(USAGE8);
|
|
29588
30588
|
await command({ context, args });
|
|
29589
30589
|
}
|
|
29590
30590
|
|
|
@@ -29593,6 +30593,7 @@ var HELP = `laze: work in a Laze workspace from your terminal or your agent.
|
|
|
29593
30593
|
|
|
29594
30594
|
laze login [--url <server>] [--token lz_...] sign in (opens a browser code)
|
|
29595
30595
|
laze --version the version of this CLI
|
|
30596
|
+
laze update [--dry-run] install the latest release (npm, pnpm, bun or yarn)
|
|
29596
30597
|
laze logout forget this profile
|
|
29597
30598
|
laze whoami who this key speaks for
|
|
29598
30599
|
laze workspaces your signed-in profiles
|
|
@@ -29613,6 +30614,8 @@ var HELP = `laze: work in a Laze workspace from your terminal or your agent.
|
|
|
29613
30614
|
laze agent link --token <token> connect this Claude Code or Codex session
|
|
29614
30615
|
laze adopt codex [--thread <id>] answer Laze messages in a Codex thread
|
|
29615
30616
|
laze vault run <name> --reason "<why>" -- <cmd> run a command with a vault connection (agents)
|
|
30617
|
+
laze browser setup|cdp|screen|status <machine> a machine with Chrome a person signs in on, for agents
|
|
30618
|
+
Sites without an API need a person's login: offer a browser machine, never ask for a password
|
|
29616
30619
|
laze github whoami | watch <owner/repo> | unwatch | watches the agent's GitHub identity and watches
|
|
29617
30620
|
laze agent set-github <agent> <connection|none> [--ask-before-push] pick an agent's GitHub
|
|
29618
30621
|
laze mcp the same as an MCP server on stdio
|
|
@@ -29625,6 +30628,7 @@ var COMMANDS = {
|
|
|
29625
30628
|
logout,
|
|
29626
30629
|
whoami,
|
|
29627
30630
|
workspaces,
|
|
30631
|
+
update,
|
|
29628
30632
|
"channels list": listChannels,
|
|
29629
30633
|
channels: listChannels,
|
|
29630
30634
|
post,
|
|
@@ -29635,6 +30639,7 @@ var COMMANDS = {
|
|
|
29635
30639
|
agents: listAgents,
|
|
29636
30640
|
"agent link": linkAgent,
|
|
29637
30641
|
"hook stop": stopHook,
|
|
30642
|
+
"hook pre-tool": preToolHook,
|
|
29638
30643
|
adopt: adoptCodex,
|
|
29639
30644
|
feed,
|
|
29640
30645
|
schedule,
|
|
@@ -29643,6 +30648,7 @@ var COMMANDS = {
|
|
|
29643
30648
|
skill,
|
|
29644
30649
|
app,
|
|
29645
30650
|
"vault run": vaultRun,
|
|
30651
|
+
browser,
|
|
29646
30652
|
github,
|
|
29647
30653
|
"agent set-github": setAgentGithub,
|
|
29648
30654
|
"mcp gateway": serveMcpGateway,
|
|
@@ -29680,21 +30686,27 @@ async function runCli({
|
|
|
29680
30686
|
}
|
|
29681
30687
|
|
|
29682
30688
|
// src/main.ts
|
|
29683
|
-
function runCommand({
|
|
30689
|
+
async function runCommand({
|
|
29684
30690
|
command,
|
|
29685
30691
|
inherited,
|
|
29686
|
-
env
|
|
30692
|
+
env,
|
|
30693
|
+
stdout = process.stdout,
|
|
30694
|
+
stderr = process.stderr
|
|
29687
30695
|
}) {
|
|
29688
30696
|
const [program = "", ...rest] = command;
|
|
29689
|
-
|
|
29690
|
-
|
|
29691
|
-
|
|
29692
|
-
|
|
29693
|
-
|
|
29694
|
-
|
|
30697
|
+
try {
|
|
30698
|
+
return await runRedacted({
|
|
30699
|
+
command: [program, ...rest],
|
|
30700
|
+
env,
|
|
30701
|
+
baseEnv: inherited,
|
|
30702
|
+
stdout,
|
|
30703
|
+
stderr
|
|
29695
30704
|
});
|
|
29696
|
-
|
|
29697
|
-
|
|
30705
|
+
} catch (error62) {
|
|
30706
|
+
stderr.write(`laze vault: ${error62 instanceof Error ? error62.message : String(error62)}
|
|
30707
|
+
`);
|
|
30708
|
+
return 127;
|
|
30709
|
+
}
|
|
29698
30710
|
}
|
|
29699
30711
|
async function readStdin() {
|
|
29700
30712
|
if (stdin.isTTY) return "";
|
|
@@ -29702,6 +30714,20 @@ async function readStdin() {
|
|
|
29702
30714
|
for await (const chunk of stdin) chunks.push(chunk);
|
|
29703
30715
|
return Buffer.concat(chunks).toString("utf8");
|
|
29704
30716
|
}
|
|
30717
|
+
function sleep(ms, signal) {
|
|
30718
|
+
return new Promise((resolve6) => {
|
|
30719
|
+
if (signal?.aborted) return resolve6();
|
|
30720
|
+
const stop = () => {
|
|
30721
|
+
clearTimeout(timer);
|
|
30722
|
+
resolve6();
|
|
30723
|
+
};
|
|
30724
|
+
const timer = setTimeout(() => {
|
|
30725
|
+
signal?.removeEventListener("abort", stop);
|
|
30726
|
+
resolve6();
|
|
30727
|
+
}, ms);
|
|
30728
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
30729
|
+
});
|
|
30730
|
+
}
|
|
29705
30731
|
if (true) {
|
|
29706
30732
|
const environment = cliEnvironment();
|
|
29707
30733
|
process.exitCode = await runCli({
|
|
@@ -29715,9 +30741,12 @@ if (true) {
|
|
|
29715
30741
|
out: (text2) => void process.stdout.write(text2),
|
|
29716
30742
|
err: (text2) => void process.stderr.write(text2),
|
|
29717
30743
|
readStdin,
|
|
29718
|
-
sleep
|
|
30744
|
+
sleep,
|
|
29719
30745
|
nowMs: () => nowInstant().epochMilliseconds,
|
|
29720
30746
|
runCommand: (input2) => runCommand({ ...input2, inherited: environment.inherited })
|
|
29721
30747
|
}
|
|
29722
30748
|
});
|
|
29723
30749
|
}
|
|
30750
|
+
export {
|
|
30751
|
+
runCommand
|
|
30752
|
+
};
|