@lazehq/cli 0.1.1 → 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.
Files changed (3) hide show
  1. package/README.md +9 -5
  2. package/dist/laze.mjs +2094 -378
  3. package/package.json +1 -1
package/dist/laze.mjs CHANGED
@@ -1,14 +1,328 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __export = (target, all) => {
4
- for (var name in all)
5
- __defProp(target, name, { get: all[name], enumerable: true });
4
+ for (var name2 in all)
5
+ __defProp(target, name2, { get: all[name2], enumerable: true });
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 = (fieldName, val) => `Invalid ${fieldName}: ${val}`;
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 = (fieldName) => `Missing ${fieldName}`;
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 = (fieldName, val, choiceMap) => invalidEntity(fieldName, val) + "; must be " + Object.keys(choiceMap).join();
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" : "");
@@ -111,8 +425,8 @@ function memoize(generator, MapClass = Map) {
111
425
  return map2.set(key, val), val;
112
426
  };
113
427
  }
114
- var createNameDescriptors = (name) => createPropDescriptors({
115
- name
428
+ var createNameDescriptors = (name2) => createPropDescriptors({
429
+ name: name2
116
430
  }, 1);
117
431
  var createPropDescriptors = (propVals, readonly2) => mapProps((value) => ({
118
432
  value,
@@ -324,8 +638,8 @@ var maxValues = {
324
638
  };
325
639
  function constrainTimeFields(timeFields, overflow) {
326
640
  const constrainedFields = {};
327
- for (const fieldName of timeFieldNamesAsc) {
328
- constrainedFields[fieldName] = clampEntity(fieldName, timeFields[fieldName], 0, maxValues[fieldName] || 999, overflow);
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 fieldName of durationFieldNamesAsc) {
1483
- res[fieldName] = -1 * fields[fieldName] || 0;
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 fieldName of fieldNames) {
1490
- const fieldSign = Math.sign(fields[fieldName]);
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 fieldName of validFieldNames) {
1679
- let fieldVal = bag[fieldName];
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[fieldName];
1683
- refiner && (fieldVal = refiner(fieldVal, fieldName)), res[fieldName] = fieldVal;
1996
+ const refiner = fieldRefiners[fieldName3];
1997
+ refiner && (fieldVal = refiner(fieldVal, fieldName3)), res[fieldName3] = fieldVal;
1684
1998
  } else {
1685
- requiredFieldNames && requiredFieldNames.includes(fieldName) && throwTypeError(missingField(fieldName));
1999
+ requiredFieldNames && requiredFieldNames.includes(fieldName3) && throwTypeError(missingField(fieldName3));
1686
2000
  }
1687
2001
  }
1688
2002
  return disallowEmpty && !anyMatching && throwTypeError(noValidFields(validFieldNames)), res;
@@ -2392,8 +2706,8 @@ function organizeAnnotationParts(s) {
2392
2706
  const calendarIds = [];
2393
2707
  return s.replace(annotationRegExp, (whole, criticalStr, mainStr) => {
2394
2708
  const isCritical = Boolean(criticalStr);
2395
- const [val, name] = mainStr.split("=").reverse();
2396
- return name ? "u-ca" === name ? (calendarIds.push(val.toLowerCase()), calendarIsCritical || (calendarIsCritical = isCritical)) : (isCritical || /[A-Z]/.test(name)) && throwRangeError(invalidSubstring(whole)) : (timeZoneId && throwRangeError(invalidSubstring(whole)), timeZoneId = val), "";
2709
+ const [val, name2] = mainStr.split("=").reverse();
2710
+ return name2 ? "u-ca" === name2 ? (calendarIds.push(val.toLowerCase()), calendarIsCritical || (calendarIsCritical = isCritical)) : (isCritical || /[A-Z]/.test(name2)) && throwRangeError(invalidSubstring(whole)) : (timeZoneId && throwRangeError(invalidSubstring(whole)), timeZoneId = val), "";
2397
2711
  }), calendarIds.length > 1 && calendarIsCritical && throwRangeError(invalidSubstring(s)), {
2398
2712
  timeZoneId,
2399
2713
  calendarId: calendarIds[0] || "iso8601"
@@ -2583,9 +2897,9 @@ function createOptionsTransformer(shapeFieldNames, invalidShapeFieldNames, ignor
2583
2897
  const otherFields = {};
2584
2898
  let hasInvalidGranularShapeFields = 0;
2585
2899
  let hasInvalidStyleFields = 0;
2586
- for (const name of Object.keys(options)) {
2587
- const value = options[name];
2588
- void 0 === value || ignoredFieldNameSet.has(name) || (shapeFieldNameSet.has(name) ? "dateStyle" === name ? dateStyle = value : "timeStyle" === name ? timeStyle = value : granularShapeFields[name] = value : "era" === name ? modifierFields[name] = value : invalidShapeFieldNameSet.has(name) ? "dateStyle" === name || "timeStyle" === name ? hasInvalidStyleFields = 1 : hasInvalidGranularShapeFields = 1 : otherFields[name] = value);
2900
+ for (const name2 of Object.keys(options)) {
2901
+ const value = options[name2];
2902
+ void 0 === value || ignoredFieldNameSet.has(name2) || (shapeFieldNameSet.has(name2) ? "dateStyle" === name2 ? dateStyle = value : "timeStyle" === name2 ? timeStyle = value : granularShapeFields[name2] = value : "era" === name2 ? modifierFields[name2] = value : invalidShapeFieldNameSet.has(name2) ? "dateStyle" === name2 || "timeStyle" === name2 ? hasInvalidStyleFields = 1 : hasInvalidGranularShapeFields = 1 : otherFields[name2] = value);
2589
2903
  }
2590
2904
  const hasDateStyle = void 0 !== dateStyle;
2591
2905
  const hasTimeStyle = void 0 !== timeStyle;
@@ -3751,7 +4065,7 @@ function harnessOf({
3751
4065
  }) {
3752
4066
  if (env.CLAUDECODE === "1") return "claude-code";
3753
4067
  const names = Object.keys(env);
3754
- return names.some((name) => name.startsWith("CODEX_")) ? "codex" : "other";
4068
+ return names.some((name2) => name2.startsWith("CODEX_")) ? "codex" : "other";
3755
4069
  }
3756
4070
  function cliEnvironment({
3757
4071
  env = process.env
@@ -3796,27 +4110,27 @@ var ConfigStore = class _ConfigStore {
3796
4110
  await rename(temporary, this.path);
3797
4111
  }
3798
4112
  async saveProfile({
3799
- name,
4113
+ name: name2,
3800
4114
  profile,
3801
4115
  bindDirectory
3802
4116
  }) {
3803
4117
  const config2 = await this.read();
3804
4118
  await this.write({
3805
- current: bindDirectory ? config2.current ?? name : name,
3806
- profiles: { ...config2.profiles, [name]: profile },
3807
- bindings: bindDirectory ? { ...config2.bindings, [resolve(bindDirectory)]: name } : config2.bindings
4119
+ current: bindDirectory ? config2.current ?? name2 : name2,
4120
+ profiles: { ...config2.profiles, [name2]: profile },
4121
+ bindings: bindDirectory ? { ...config2.bindings, [resolve(bindDirectory)]: name2 } : config2.bindings
3808
4122
  });
3809
4123
  }
3810
- async removeProfile({ name }) {
4124
+ async removeProfile({ name: name2 }) {
3811
4125
  const config2 = await this.read();
3812
- if (!config2.profiles[name]) return false;
4126
+ if (!config2.profiles[name2]) return false;
3813
4127
  const profiles = Object.fromEntries(
3814
- Object.entries(config2.profiles).filter(([key]) => key !== name)
4128
+ Object.entries(config2.profiles).filter(([key]) => key !== name2)
3815
4129
  );
3816
4130
  const bindings = Object.fromEntries(
3817
- Object.entries(config2.bindings).filter(([, bound]) => bound !== name)
4131
+ Object.entries(config2.bindings).filter(([, bound]) => bound !== name2)
3818
4132
  );
3819
- const current = config2.current === name ? Object.keys(profiles)[0] : config2.current;
4133
+ const current = config2.current === name2 ? Object.keys(profiles)[0] : config2.current;
3820
4134
  await this.write({ current, profiles, bindings });
3821
4135
  return true;
3822
4136
  }
@@ -3828,9 +4142,9 @@ function chooseProfile({
3828
4142
  cwd
3829
4143
  }) {
3830
4144
  const bound = boundProfileOf({ bindings: config2.bindings, cwd });
3831
- const name = flag || environment || bound || config2.current;
3832
- const profile = name ? config2.profiles[name] : void 0;
3833
- return name && profile ? { name, profile } : { name: void 0, profile: void 0 };
4145
+ const name2 = flag || environment || bound || config2.current;
4146
+ const profile = name2 ? config2.profiles[name2] : void 0;
4147
+ return name2 && profile ? { name: name2, profile } : { name: void 0, profile: void 0 };
3834
4148
  }
3835
4149
  function boundProfileOf({
3836
4150
  bindings,
@@ -3857,15 +4171,16 @@ 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 = [];
3864
4179
  const flags = {};
3865
4180
  const lists = {};
3866
- const remember = (name, value) => {
3867
- flags[name] = value;
3868
- lists[name] = [...lists[name] ?? [], value];
4181
+ const remember = (name2, value) => {
4182
+ flags[name2] = value;
4183
+ lists[name2] = [...lists[name2] ?? [], value];
3869
4184
  };
3870
4185
  for (let index = 0; index < argv.length; index += 1) {
3871
4186
  const arg = argv[index] ?? "";
@@ -3874,12 +4189,12 @@ function parseArgs({ argv }) {
3874
4189
  words.push(arg);
3875
4190
  continue;
3876
4191
  }
3877
- const [name = "", inline] = arg.slice(2).split(/=(.*)/s, 2);
4192
+ const [name2 = "", inline] = arg.slice(2).split(/=(.*)/s, 2);
3878
4193
  const next = argv[index + 1];
3879
- if (inline !== void 0) remember(name, inline);
3880
- else if (SWITCHES.has(name) || next === void 0 || next.startsWith("--")) flags[name] = true;
4194
+ if (inline !== void 0) remember(name2, inline);
4195
+ else if (SWITCHES.has(name2) || next === void 0 || next.startsWith("--")) flags[name2] = true;
3881
4196
  else {
3882
- remember(name, next);
4197
+ remember(name2, next);
3883
4198
  index += 1;
3884
4199
  }
3885
4200
  }
@@ -3887,25 +4202,26 @@ function parseArgs({ argv }) {
3887
4202
  }
3888
4203
  function flagText({
3889
4204
  args,
3890
- name,
4205
+ name: name2,
3891
4206
  fallback = ""
3892
4207
  }) {
3893
- const value = args.flags[name];
4208
+ const value = args.flags[name2];
3894
4209
  return typeof value === "string" ? value : fallback;
3895
4210
  }
3896
4211
 
3897
4212
  // src/rules/cli-version.rules.ts
3898
- var STAMPED = "0.1.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 mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
3905
- import { join as join2 } from "node:path";
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
- function withStopHook({
3918
- settings,
4233
+ var TIMEOUTS = { Stop: 30, PreToolUse: 5 };
4234
+ function withHook({
4235
+ hooks,
4236
+ event,
3919
4237
  command
3920
4238
  }) {
3921
- const hooks = { ...settings.hooks };
3922
- const stop = Array.isArray(hooks.Stop) ? hooks.Stop : [];
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.Stop = [...others, { hooks: [{ type: "command", command, timeout: 30 }] }];
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 stopHookCommand({
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", "stop", "--profile", profile].map(quote).join(" ");
4261
+ const words = [...program, "hook", hook, "--profile", profile].map(quote).join(" ");
3935
4262
  return `${words} # ${LAZE_HOOK_MARKER}`;
3936
4263
  }
3937
4264
 
@@ -4023,19 +4350,16 @@ function readTranscript({ lines }) {
4023
4350
  return { contextTokens, contextWindow, compactions };
4024
4351
  }
4025
4352
 
4026
- // src/services/cli-context.ts
4027
- var CliUsageError = class extends Error {
4028
- constructor(message) {
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
4358
+ var CLI_VERSION_HEADER = "x-laze-cli-version";
4035
4359
  var LazeApiError = class extends Error {
4036
- constructor(status, code, message) {
4360
+ constructor(status2, code, message) {
4037
4361
  super(message);
4038
- this.status = status;
4362
+ this.status = status2;
4039
4363
  this.code = code;
4040
4364
  this.name = "LazeApiError";
4041
4365
  }
@@ -4043,20 +4367,20 @@ var LazeApiError = class extends Error {
4043
4367
  code;
4044
4368
  };
4045
4369
  var LazeClient = class _LazeClient {
4046
- constructor(baseUrl, token, fetcher) {
4047
- this.baseUrl = baseUrl;
4048
- this.token = token;
4049
- this.fetcher = fetcher;
4050
- }
4051
- baseUrl;
4052
- token;
4053
- fetcher;
4370
+ constructor(options) {
4371
+ this.options = options;
4372
+ }
4373
+ options;
4054
4374
  static create({
4055
4375
  baseUrl,
4056
4376
  token,
4057
4377
  fetcher
4058
4378
  }) {
4059
- 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 } });
4060
4384
  }
4061
4385
  get(path) {
4062
4386
  return this.send({ method: "GET", path });
@@ -4069,29 +4393,41 @@ var LazeClient = class _LazeClient {
4069
4393
  path,
4070
4394
  body
4071
4395
  }) {
4072
- const headers = { accept: "application/json" };
4396
+ const headers = {
4397
+ ...this.options.headers,
4398
+ accept: "application/json",
4399
+ [CLI_VERSION_HEADER]: cliVersionOf()
4400
+ };
4073
4401
  if (body !== void 0) headers["content-type"] = "application/json";
4074
- if (this.token) headers.authorization = `Bearer ${this.token}`;
4075
- 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}`, {
4076
4404
  method,
4077
4405
  headers,
4078
4406
  ...body !== void 0 ? { body: JSON.stringify(body) } : {}
4079
4407
  });
4080
- const text = await response.text();
4081
- const parsed = text ? JSON.parse(text) : void 0;
4408
+ const text2 = await response.text();
4409
+ const parsed = text2 ? JSON.parse(text2) : void 0;
4082
4410
  if (!response.ok) throw errorOf({ status: response.status, body: parsed });
4083
4411
  return parsed;
4084
4412
  }
4085
4413
  };
4086
- function errorOf({ status, body }) {
4414
+ function errorOf({ status: status2, body }) {
4087
4415
  const record4 = typeof body === "object" && body !== null ? body : {};
4088
4416
  const nested = typeof record4.error === "object" && record4.error !== null ? record4.error : record4;
4089
- const fallback = typeof record4.error === "string" ? record4.error : `http_${status}`;
4417
+ const fallback = typeof record4.error === "string" ? record4.error : `http_${status2}`;
4090
4418
  const code = typeof nested.code === "string" ? nested.code : fallback;
4091
- const message = typeof nested.message === "string" ? nested.message : `Laze answered ${status}`;
4092
- return new LazeApiError(status, code, message);
4419
+ const message = typeof nested.message === "string" ? nested.message : `Laze answered ${status2}`;
4420
+ return new LazeApiError(status2, code, message);
4093
4421
  }
4094
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
+
4095
4431
  // src/services/session.service.ts
4096
4432
  async function signedIn({
4097
4433
  context,
@@ -4122,6 +4458,85 @@ function serverUrlOf({ context, args }) {
4122
4458
  return flagText({ args, name: "url" }) || context.environment.url || "https://laze.langwatch.ai";
4123
4459
  }
4124
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
+
4125
4540
  // src/services/chat-commands.service.ts
4126
4541
  var REQUEST_WAIT_SECONDS = 50;
4127
4542
  async function listChannels({ context, args }) {
@@ -4130,9 +4545,9 @@ async function listChannels({ context, args }) {
4130
4545
  if (args.flags.json) return context.out(`${JSON.stringify(channels, null, 2)}
4131
4546
  `);
4132
4547
  for (const channel of channels) {
4133
- const name = channel.kind === "dm" || channel.kind === "group" ? "(direct)" : `#${channel.name}`;
4548
+ const name2 = channel.kind === "dm" || channel.kind === "group" ? "(direct)" : `#${channel.name}`;
4134
4549
  const unread = channel.unread > 0 ? ` ${channel.unread} unread` : "";
4135
- context.out(`${channel.id} ${name}${unread}
4550
+ context.out(`${channel.id} ${name2}${unread}
4136
4551
  `);
4137
4552
  }
4138
4553
  }
@@ -4142,9 +4557,9 @@ async function textOf({
4142
4557
  from
4143
4558
  }) {
4144
4559
  const words = args.words.slice(from);
4145
- const text = (words.join(" ") === "-" ? await context.readStdin() : words.join(" ")).trim();
4146
- if (!text) throw new CliUsageError("Say something: the message text is missing.");
4147
- return text;
4560
+ const text2 = (words.join(" ") === "-" ? await context.readStdin() : words.join(" ")).trim();
4561
+ if (!text2) throw new CliUsageError("Say something: the message text is missing.");
4562
+ return text2;
4148
4563
  }
4149
4564
  async function post({ context, args }) {
4150
4565
  const channel = args.words[1];
@@ -4194,9 +4609,12 @@ function waitSecondsOf({ args }) {
4194
4609
  return timeout > 0 ? timeout : Infinity;
4195
4610
  }
4196
4611
  async function inbox({ context, args }) {
4197
- const { client } = await signedIn({ context, args });
4612
+ const { client, name: name2, profile } = await signedIn({ context, args });
4198
4613
  const waitSeconds = waitSecondsOf({ args });
4199
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
+ }
4200
4618
  if (args.flags.json) return context.out(`${JSON.stringify(messages, null, 2)}
4201
4619
  `);
4202
4620
  if (messages.length === 0) return context.out("No new messages.\n");
@@ -4236,23 +4654,24 @@ function harnessOf2({ context, args }) {
4236
4654
  if (named === "claude-code" || named === "codex" || named === "other") return named;
4237
4655
  return context.environment.harness;
4238
4656
  }
4239
- function slugOf(name) {
4240
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "agent";
4657
+ function slugOf(name2) {
4658
+ return name2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "agent";
4241
4659
  }
4242
4660
  async function installStopHook({ context, profile }) {
4243
- const directory = join2(context.cwd, ".claude");
4244
- const path = join2(directory, "settings.local.json");
4245
- const current = await readFile2(path, "utf8").then(
4246
- (text) => JSON.parse(text),
4661
+ const directory = join3(context.cwd, ".claude");
4662
+ const path = join3(directory, "settings.local.json");
4663
+ const current = await readFile3(path, "utf8").then(
4664
+ (text2) => JSON.parse(text2),
4247
4665
  () => ({})
4248
4666
  );
4249
- const command = stopHookCommand({ program: context.program, profile });
4250
- await mkdir2(directory, { recursive: true });
4251
- await writeFile2(
4252
- path,
4253
- `${JSON.stringify(withStopHook({ settings: current, command }), null, 2)}
4254
- `
4255
- );
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
+ `);
4256
4675
  return path;
4257
4676
  }
4258
4677
  function nextStepsFor({
@@ -4283,9 +4702,9 @@ async function linkAgent({ context, args }) {
4283
4702
  const harness = harnessOf2({ context, args });
4284
4703
  const client = LazeClient.create({ baseUrl: url2, fetcher: context.fetcher });
4285
4704
  const linked = await client.post("/api/agents/links/redeem", { token, harness });
4286
- const name = flagText({ args, name: "profile" }) || `agent-${slugOf(linked.agent.name)}`;
4705
+ const name2 = flagText({ args, name: "profile" }) || `agent-${slugOf(linked.agent.name)}`;
4287
4706
  await context.store.saveProfile({
4288
- name,
4707
+ name: name2,
4289
4708
  bindDirectory: context.cwd,
4290
4709
  profile: {
4291
4710
  url: url2,
@@ -4296,13 +4715,13 @@ async function linkAgent({ context, args }) {
4296
4715
  agentId: linked.agent.id
4297
4716
  }
4298
4717
  });
4299
- const hookPath = harness === "claude-code" && !args.flags["no-hook"] ? await installStopHook({ context, profile: name }) : void 0;
4718
+ const hookPath = harness === "claude-code" && !args.flags["no-hook"] ? await installStopHook({ context, profile: name2 }) : void 0;
4300
4719
  context.out(
4301
4720
  [
4302
- `Linked as ${linked.agent.name} (${linked.agent.id}), profile "${name}" for ${context.cwd}.`,
4303
- ...hookPath ? [`Added the Laze Stop hook to ${hookPath}.`] : [],
4721
+ `Linked as ${linked.agent.name} (${linked.agent.id}), profile "${name2}" for ${context.cwd}.`,
4722
+ ...hookPath ? [`Added the Laze hooks to ${hookPath}.`] : [],
4304
4723
  "",
4305
- nextStepsFor({ harness, profile: name, laze: lazeCommandOf({ program: context.program }) }),
4724
+ nextStepsFor({ harness, profile: name2, laze: lazeCommandOf({ program: context.program }) }),
4306
4725
  ""
4307
4726
  ].join("\n")
4308
4727
  );
@@ -4312,7 +4731,7 @@ async function reportTranscript({
4312
4731
  input: input2
4313
4732
  }) {
4314
4733
  if (!input2.transcript_path || !input2.session_id) return;
4315
- const lines = (await readFile2(input2.transcript_path, "utf8")).split("\n");
4734
+ const lines = (await readFile3(input2.transcript_path, "utf8")).split("\n");
4316
4735
  const context = readTranscript({ lines });
4317
4736
  await client.post("/api/agents/me/activity", {
4318
4737
  sessionId: input2.session_id,
@@ -4324,14 +4743,15 @@ async function reportTranscript({
4324
4743
  async function handOver({ context, args }) {
4325
4744
  const raw = await context.readStdin();
4326
4745
  const input2 = raw.trim() ? JSON.parse(raw) : {};
4327
- const { client } = await signedIn({ context, args });
4746
+ const { client, name: agent } = await signedIn({ context, args });
4328
4747
  await reportTranscript({ client, input: input2 }).catch(
4329
4748
  (error62) => context.err(`laze: could not report context: ${String(error62)}
4330
4749
  `)
4331
4750
  );
4332
4751
  if (input2.stop_hook_active) return;
4333
4752
  const messages = await receiveMessages({ context, client, waitSeconds: 0 });
4334
- if (messages.length === 0) return;
4753
+ if (messages.length === 0) return turnEnded({ context, client, agent });
4754
+ await turnStarted({ context, client, agent, messages });
4335
4755
  context.out(
4336
4756
  JSON.stringify({
4337
4757
  hookSpecificOutput: { hookEventName: "Stop", additionalContext: hookContextOf({ messages }) }
@@ -4348,8 +4768,8 @@ async function stopHook({ context, args }) {
4348
4768
  }
4349
4769
 
4350
4770
  // src/services/app-commands.service.ts
4351
- import { mkdir as mkdir3, readdir, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
4352
- import { join as join3, relative, resolve as resolve2, sep } from "node:path";
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";
4353
4773
 
4354
4774
  // ../../packages/module/src/feature-names.generated.ts
4355
4775
  var FEATURE_NAMES = [
@@ -4362,18 +4782,21 @@ var FEATURE_NAMES = [
4362
4782
  "authz",
4363
4783
  "billing",
4364
4784
  "chat",
4785
+ "compute",
4365
4786
  "connector",
4366
4787
  "entitlement",
4367
4788
  "feature-flag",
4368
4789
  "feed",
4369
- "marketing",
4370
4790
  "files",
4791
+ "marketing",
4371
4792
  "memory",
4372
4793
  "model-gateway",
4373
4794
  "notification",
4795
+ "openclaw",
4374
4796
  "role",
4375
4797
  "schedule",
4376
4798
  "skill",
4799
+ "slack",
4377
4800
  "vault",
4378
4801
  "wiki",
4379
4802
  "workspace",
@@ -4415,50 +4838,50 @@ function isFeatureName(feature) {
4415
4838
 
4416
4839
  // ../../packages/module/src/module-api-token.ts
4417
4840
  var FeatureApiIdentity = class {
4418
- constructor(name) {
4419
- this.name = name;
4841
+ constructor(name2) {
4842
+ this.name = name2;
4420
4843
  }
4421
4844
  name;
4422
4845
  };
4423
4846
  var ModuleApiToken = class _ModuleApiToken extends FeatureApiIdentity {
4424
- constructor(name) {
4425
- super(name);
4847
+ constructor(name2) {
4848
+ super(name2);
4426
4849
  }
4427
- static create(name) {
4428
- publicNamespaceFromUnknown(name);
4429
- const token = new _ModuleApiToken(name);
4850
+ static create(name2) {
4851
+ publicNamespaceFromUnknown(name2);
4852
+ const token = new _ModuleApiToken(name2);
4430
4853
  Object.freeze(token);
4431
4854
  return token;
4432
4855
  }
4433
4856
  };
4434
- function moduleApi(name) {
4435
- if (name === void 0) {
4857
+ function moduleApi(name2) {
4858
+ if (name2 === void 0) {
4436
4859
  return (id) => ModuleApiToken.create(id);
4437
4860
  }
4438
- return ModuleApiToken.create(name);
4861
+ return ModuleApiToken.create(name2);
4439
4862
  }
4440
4863
 
4441
4864
  // ../../packages/module/src/contract/trpc-contract.ts
4442
4865
  function contractBuilder(namespace, members2) {
4443
- const member = (name, kind, read = {}) => ({
4866
+ const member = (name2, kind, read = {}) => ({
4444
4867
  withInput: (input2) => {
4445
- assertUndeclared(namespace, name, members2);
4868
+ assertUndeclared(namespace, name2, members2);
4446
4869
  const cached2 = {
4447
4870
  ...read.invalidatedBy ? { invalidatedBy: read.invalidatedBy } : {},
4448
4871
  ...read.fromProjection ? { fromProjection: read.fromProjection } : {},
4449
4872
  ...read.revision === void 0 ? {} : { revision: read.revision }
4450
4873
  };
4451
- const declared = { ...members2, [name]: { kind, input: input2, output: void 0, ...cached2 } };
4874
+ const declared = { ...members2, [name2]: { kind, input: input2, output: void 0, ...cached2 } };
4452
4875
  return {
4453
4876
  ...contractBuilder(namespace, declared),
4454
- withOutput: (output2) => contractBuilder(namespace, { ...members2, [name]: { kind, input: input2, output: output2, ...cached2 } })
4877
+ withOutput: (output2) => contractBuilder(namespace, { ...members2, [name2]: { kind, input: input2, output: output2, ...cached2 } })
4455
4878
  };
4456
4879
  }
4457
4880
  });
4458
4881
  return {
4459
- query: (name, options) => member(name, "query", options),
4460
- mutation: (name) => member(name, "mutation"),
4461
- subscription: (name) => member(name, "subscription"),
4882
+ query: (name2, options) => member(name2, "query", options),
4883
+ mutation: (name2) => member(name2, "mutation"),
4884
+ subscription: (name2) => member(name2, "subscription"),
4462
4885
  build: () => {
4463
4886
  assertQueriesAnswer(namespace, members2);
4464
4887
  const built = { namespace, members: Object.freeze({ ...members2 }) };
@@ -4466,15 +4889,15 @@ function contractBuilder(namespace, members2) {
4466
4889
  }
4467
4890
  };
4468
4891
  }
4469
- function assertUndeclared(namespace, name, members2) {
4470
- if (name in members2) {
4471
- throw new Error(`tRPC contract "${namespace}" declares procedure "${name}" twice`);
4892
+ function assertUndeclared(namespace, name2, members2) {
4893
+ if (name2 in members2) {
4894
+ throw new Error(`tRPC contract "${namespace}" declares procedure "${name2}" twice`);
4472
4895
  }
4473
4896
  }
4474
4897
  function assertQueriesAnswer(namespace, members2) {
4475
- for (const [name, member] of Object.entries(members2)) {
4898
+ for (const [name2, member] of Object.entries(members2)) {
4476
4899
  if (member.kind === "query" && member.output === void 0) {
4477
- throw new Error(`tRPC contract "${namespace}" declares query "${name}" without withOutput`);
4900
+ throw new Error(`tRPC contract "${namespace}" declares query "${name2}" without withOutput`);
4478
4901
  }
4479
4902
  }
4480
4903
  }
@@ -5600,12 +6023,12 @@ function merge(a, b) {
5600
6023
  });
5601
6024
  return clone(a, def);
5602
6025
  }
5603
- function partial(Class2, schema, mask, name = "partial") {
6026
+ function partial(Class2, schema, mask, name2 = "partial") {
5604
6027
  const currDef = schema._zod.def;
5605
6028
  const checks = currDef.checks;
5606
6029
  const hasChecks = checks && checks.length > 0;
5607
6030
  if (hasChecks) {
5608
- throw new Error(`.${name}() cannot be used on object schemas containing refinements`);
6031
+ throw new Error(`.${name2}() cannot be used on object schemas containing refinements`);
5609
6032
  }
5610
6033
  const selected = mask ? new Set(maskedKeys(schema, mask)) : void 0;
5611
6034
  const newShape = {};
@@ -5933,7 +6356,7 @@ function newError(Definition) {
5933
6356
  return new Definition();
5934
6357
  }
5935
6358
  // @__NO_SIDE_EFFECTS__
5936
- function $constructor(name, initializer3, proto, params) {
6359
+ function $constructor(name2, initializer3, proto, params) {
5937
6360
  const zodProto = {};
5938
6361
  function Internals(def) {
5939
6362
  this.def = def;
@@ -5951,10 +6374,10 @@ function $constructor(name, initializer3, proto, params) {
5951
6374
  } finally {
5952
6375
  _zodDesc.value = void 0;
5953
6376
  }
5954
- } else if (inst._zod.traits.has(name)) {
6377
+ } else if (inst._zod.traits.has(name2)) {
5955
6378
  return;
5956
6379
  }
5957
- inst._zod.traits.add(name);
6380
+ inst._zod.traits.add(name2);
5958
6381
  initializer3(inst, def);
5959
6382
  if (initialized) {
5960
6383
  const own2 = Object.getPrototypeOf(inst);
@@ -5980,7 +6403,7 @@ function $constructor(name, initializer3, proto, params) {
5980
6403
  const Parent = params?.Parent ?? Object;
5981
6404
  class Definition extends Parent {
5982
6405
  }
5983
- Object.defineProperty(Definition, "name", { value: name });
6406
+ Object.defineProperty(Definition, "name", { value: name2 });
5984
6407
  function _(def) {
5985
6408
  const inst = params?.Parent ? newError(Definition) : this;
5986
6409
  init(inst, def);
@@ -6001,10 +6424,10 @@ function $constructor(name, initializer3, proto, params) {
6001
6424
  value: (inst) => {
6002
6425
  if (params?.Parent && inst instanceof params.Parent)
6003
6426
  return true;
6004
- return inst?._zod?.traits?.has(name);
6427
+ return inst?._zod?.traits?.has(name2);
6005
6428
  }
6006
6429
  });
6007
- Object.defineProperty(_, "name", { value: name });
6430
+ Object.defineProperty(_, "name", { value: name2 });
6008
6431
  return _;
6009
6432
  }
6010
6433
  var $brand = /* @__PURE__ */ Symbol("zod_brand");
@@ -6014,8 +6437,8 @@ var $ZodAsyncError = class extends Error {
6014
6437
  }
6015
6438
  };
6016
6439
  var $ZodEncodeError = class extends Error {
6017
- constructor(name) {
6018
- super(`Encountered unidirectional transform during encode: ${name}`);
6440
+ constructor(name2) {
6441
+ super(`Encountered unidirectional transform during encode: ${name2}`);
6019
6442
  this.name = "ZodEncodeError";
6020
6443
  }
6021
6444
  };
@@ -13791,8 +14214,8 @@ function ko_default() {
13791
14214
  }
13792
14215
 
13793
14216
  // ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/lt.js
13794
- var capitalizeFirstCharacter = (text) => {
13795
- return text.charAt(0).toUpperCase() + text.slice(1);
14217
+ var capitalizeFirstCharacter = (text2) => {
14218
+ return text2.charAt(0).toUpperCase() + text2.slice(1);
13796
14219
  };
13797
14220
  function getUnitTypeFromNumber(number4) {
13798
14221
  const abs = Math.abs(number4);
@@ -17514,13 +17937,13 @@ ${code}
17514
17937
  return fn;
17515
17938
  }
17516
17939
  function addConstant(ctx, value) {
17517
- for (const [name2, v] of ctx.constants) {
17940
+ for (const [name3, v] of ctx.constants) {
17518
17941
  if (v === value)
17519
- return name2;
17942
+ return name3;
17520
17943
  }
17521
- const name = `c${ctx.constantCounter++}`;
17522
- ctx.constants.set(name, value);
17523
- return name;
17944
+ const name2 = `c${ctx.constantCounter++}`;
17945
+ ctx.constants.set(name2, value);
17946
+ return name2;
17524
17947
  }
17525
17948
  function addUserConstant(ctx, fn) {
17526
17949
  ctx.definite = false;
@@ -24152,10 +24575,10 @@ function date4(params) {
24152
24575
 
24153
24576
  // ../../packages/module/src/contract/ui-tokens.ts
24154
24577
  var UiTokenIdentity = class {
24155
- constructor(kind, owner, name) {
24578
+ constructor(kind, owner, name2) {
24156
24579
  this.kind = kind;
24157
24580
  this.owner = owner;
24158
- this.name = name;
24581
+ this.name = name2;
24159
24582
  }
24160
24583
  kind;
24161
24584
  owner;
@@ -24166,22 +24589,22 @@ var UiTokenIdentity = class {
24166
24589
  }
24167
24590
  };
24168
24591
  var UiToken = class _UiToken extends UiTokenIdentity {
24169
- constructor(kind, owner, name) {
24170
- super(kind, owner, name);
24592
+ constructor(kind, owner, name2) {
24593
+ super(kind, owner, name2);
24171
24594
  }
24172
- static create(kind, owner, name) {
24173
- const token = new _UiToken(kind, owner, name);
24595
+ static create(kind, owner, name2) {
24596
+ const token = new _UiToken(kind, owner, name2);
24174
24597
  Object.freeze(token);
24175
24598
  return token;
24176
24599
  }
24177
24600
  };
24178
24601
  function uiTokens(owner) {
24179
24602
  return {
24180
- component: (name) => UiToken.create("component", owner, name),
24181
- extension: (name) => UiToken.create("extension", owner, name),
24182
- operations: (name) => UiToken.create("operations", owner, name),
24183
- hooks: (name) => UiToken.create("hooks", owner, name),
24184
- drawer: (name) => UiToken.create("drawer", owner, name)
24603
+ component: (name2) => UiToken.create("component", owner, name2),
24604
+ extension: (name2) => UiToken.create("extension", owner, name2),
24605
+ operations: (name2) => UiToken.create("operations", owner, name2),
24606
+ hooks: (name2) => UiToken.create("hooks", owner, name2),
24607
+ drawer: (name2) => UiToken.create("drawer", owner, name2)
24185
24608
  };
24186
24609
  }
24187
24610
 
@@ -24203,6 +24626,8 @@ var publishRequestSchemaDefinition = external_exports.object({
24203
24626
  visibility: appVisibilitySchema,
24204
24627
  status: external_exports.enum(["pending", "approved", "denied"]),
24205
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(),
24206
24631
  decidedBy: appActorSchema.nullable(),
24207
24632
  createdAt: external_exports.iso.datetime(),
24208
24633
  decidedAt: external_exports.iso.datetime().nullable()
@@ -24226,6 +24651,8 @@ var appSchemaDefinition = external_exports.object({
24226
24651
  pendingPublish: publishRequestSchema.nullable(),
24227
24652
  /** The name of the person or agent who built it; absent when it can no longer be read. */
24228
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(),
24229
24656
  createdAt: external_exports.iso.datetime(),
24230
24657
  updatedAt: external_exports.iso.datetime()
24231
24658
  });
@@ -24298,6 +24725,23 @@ var createAppInputSchemaDefinition = external_exports.object({
24298
24725
  visibility: appVisibilitySchema.default("internal")
24299
24726
  });
24300
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;
24301
24745
  var commitInputSchemaDefinition = external_exports.object({
24302
24746
  ...appRefSchemaDefinition.shape,
24303
24747
  /** The whole static build: files left out are gone from this version. */
@@ -24420,7 +24864,7 @@ var appViewerSchemaDefinition = external_exports.object({
24420
24864
  var AppApi = moduleApi()("app");
24421
24865
 
24422
24866
  // ../../modules/app/contract/src/app.trpc.ts
24423
- var appTrpc = defineTrpcContract("app").query("list").withInput(external_exports.object({ workspaceId: external_exports.string().min(1) })).withOutput(external_exports.array(appSchema)).query("get").withInput(appRefSchema).withOutput(appSchema).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();
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();
24424
24868
 
24425
24869
  // ../../modules/app/contract/src/app.rest.ts
24426
24870
  var byKey = { workspaceId: true };
@@ -25110,7 +25554,7 @@ function wrapSpanContext(spanContext) {
25110
25554
  var contextApi = ContextAPI.getInstance();
25111
25555
  var NoopTracer = class {
25112
25556
  // startSpan starts a noop span.
25113
- startSpan(name, options, context = contextApi.active()) {
25557
+ startSpan(name2, options, context = contextApi.active()) {
25114
25558
  const root = Boolean(options === null || options === void 0 ? void 0 : options.root);
25115
25559
  if (root) {
25116
25560
  return new NonRecordingSpan();
@@ -25122,7 +25566,7 @@ var NoopTracer = class {
25122
25566
  return new NonRecordingSpan();
25123
25567
  }
25124
25568
  }
25125
- startActiveSpan(name, arg2, arg3, arg4) {
25569
+ startActiveSpan(name2, arg2, arg3, arg4) {
25126
25570
  let opts;
25127
25571
  let ctx;
25128
25572
  let fn;
@@ -25139,7 +25583,7 @@ var NoopTracer = class {
25139
25583
  fn = arg4;
25140
25584
  }
25141
25585
  const parentContext = ctx !== null && ctx !== void 0 ? ctx : contextApi.active();
25142
- const span = this.startSpan(name, opts, parentContext);
25586
+ const span = this.startSpan(name2, opts, parentContext);
25143
25587
  const contextWithSpanSet = setSpan(parentContext, span);
25144
25588
  return contextApi.with(contextWithSpanSet, fn, void 0, span);
25145
25589
  }
@@ -25151,14 +25595,14 @@ function isSpanContext(spanContext) {
25151
25595
  // ../../node_modules/.pnpm/@opentelemetry+api@1.9.1/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js
25152
25596
  var NOOP_TRACER = new NoopTracer();
25153
25597
  var ProxyTracer = class {
25154
- constructor(provider, name, version2, options) {
25598
+ constructor(provider, name2, version2, options) {
25155
25599
  this._provider = provider;
25156
- this.name = name;
25600
+ this.name = name2;
25157
25601
  this.version = version2;
25158
25602
  this.options = options;
25159
25603
  }
25160
- startSpan(name, options, context) {
25161
- return this._getTracer().startSpan(name, options, context);
25604
+ startSpan(name2, options, context) {
25605
+ return this._getTracer().startSpan(name2, options, context);
25162
25606
  }
25163
25607
  startActiveSpan(_name, _options, _context, _fn) {
25164
25608
  const tracer = this._getTracer();
@@ -25194,9 +25638,9 @@ var ProxyTracerProvider = class {
25194
25638
  /**
25195
25639
  * Get a {@link ProxyTracer}
25196
25640
  */
25197
- getTracer(name, version2, options) {
25641
+ getTracer(name2, version2, options) {
25198
25642
  var _a3;
25199
- return (_a3 = this.getDelegateTracer(name, version2, options)) !== null && _a3 !== void 0 ? _a3 : new ProxyTracer(this, name, version2, options);
25643
+ return (_a3 = this.getDelegateTracer(name2, version2, options)) !== null && _a3 !== void 0 ? _a3 : new ProxyTracer(this, name2, version2, options);
25200
25644
  }
25201
25645
  getDelegate() {
25202
25646
  var _a3;
@@ -25208,9 +25652,9 @@ var ProxyTracerProvider = class {
25208
25652
  setDelegate(delegate) {
25209
25653
  this._delegate = delegate;
25210
25654
  }
25211
- getDelegateTracer(name, version2, options) {
25655
+ getDelegateTracer(name2, version2, options) {
25212
25656
  var _a3;
25213
- return (_a3 = this._delegate) === null || _a3 === void 0 ? void 0 : _a3.getTracer(name, version2, options);
25657
+ return (_a3 = this._delegate) === null || _a3 === void 0 ? void 0 : _a3.getTracer(name2, version2, options);
25214
25658
  }
25215
25659
  };
25216
25660
 
@@ -25257,8 +25701,8 @@ var TraceAPI = class _TraceAPI {
25257
25701
  /**
25258
25702
  * Returns a tracer from the global tracer provider.
25259
25703
  */
25260
- getTracer(name, version2) {
25261
- return this.getTracerProvider().getTracer(name, version2);
25704
+ getTracer(name2, version2) {
25705
+ return this.getTracerProvider().getTracer(name2, version2);
25262
25706
  }
25263
25707
  /** Remove the global tracer provider */
25264
25708
  disable() {
@@ -26641,9 +27085,9 @@ function isSkippedPath({ path }) {
26641
27085
  return path.split("/").some((segment) => segment.startsWith(".") || segment === "node_modules");
26642
27086
  }
26643
27087
  function buildFileOf({ path, bytes }) {
26644
- const text = bytes.toString("utf8");
26645
- const isText = !text.includes("\0") && Buffer.from(text, "utf8").equals(bytes);
26646
- return isText ? { path, content: text, encoding: "utf8", bytes: bytes.length } : { path, content: bytes.toString("base64"), encoding: "base64", bytes: bytes.length };
27088
+ const text2 = bytes.toString("utf8");
27089
+ const isText = !text2.includes("\0") && Buffer.from(text2, "utf8").equals(bytes);
27090
+ return isText ? { path, content: text2, encoding: "utf8", bytes: bytes.length } : { path, content: bytes.toString("base64"), encoding: "base64", bytes: bytes.length };
26647
27091
  }
26648
27092
  function versionLine({ version: version2 }) {
26649
27093
  const at = version2.createdAt.slice(0, 16).replace("T", " ");
@@ -27209,10 +27653,10 @@ var STARTER_TEMPLATES = {
27209
27653
  };
27210
27654
  function templateFiles({
27211
27655
  template,
27212
- name
27656
+ name: name2
27213
27657
  }) {
27214
27658
  return {
27215
- "index.html": indexHtml({ title: name.replaceAll("&", "&amp;").replaceAll("<", "&lt;") }),
27659
+ "index.html": indexHtml({ title: name2.replaceAll("&", "&amp;").replaceAll("<", "&lt;") }),
27216
27660
  "app.js": template.appJs,
27217
27661
  "laze.js": LAZE_CLIENT_JS,
27218
27662
  "laze-kit.css": LAZE_KIT_CSS
@@ -27235,9 +27679,9 @@ function folderOf({ context, word }) {
27235
27679
  return resolve2(context.cwd, word ?? ".");
27236
27680
  }
27237
27681
  async function readManifest(folder) {
27238
- const text = await readFile3(join3(folder, APP_MANIFEST_FILE), "utf8").catch(() => void 0);
27239
- if (text === void 0) return void 0;
27240
- const parsed = appManifestSchema.safeParse(JSON.parse(text));
27682
+ const text2 = await readFile4(join4(folder, APP_MANIFEST_FILE), "utf8").catch(() => void 0);
27683
+ if (text2 === void 0) return void 0;
27684
+ const parsed = appManifestSchema.safeParse(JSON.parse(text2));
27241
27685
  if (!parsed.success) {
27242
27686
  throw new CliUsageError(`${APP_MANIFEST_FILE} is not valid: ${parsed.error.message}`);
27243
27687
  }
@@ -27266,15 +27710,15 @@ async function appIdOf({
27266
27710
  async function jsonFlag({
27267
27711
  context,
27268
27712
  args,
27269
- name
27713
+ name: name2
27270
27714
  }) {
27271
- const raw = flagText({ args, name });
27715
+ const raw = flagText({ args, name: name2 });
27272
27716
  if (!raw) return void 0;
27273
- const text = raw.startsWith("@") ? await readFile3(resolve2(context.cwd, raw.slice(1)), "utf8") : raw;
27717
+ const text2 = raw.startsWith("@") ? await readFile4(resolve2(context.cwd, raw.slice(1)), "utf8") : raw;
27274
27718
  try {
27275
- return JSON.parse(text);
27719
+ return JSON.parse(text2);
27276
27720
  } catch {
27277
- throw new CliUsageError(`--${name} must be JSON (or @file holding JSON)`);
27721
+ throw new CliUsageError(`--${name2} must be JSON (or @file holding JSON)`);
27278
27722
  }
27279
27723
  }
27280
27724
  async function listFiles(folder) {
@@ -27283,7 +27727,7 @@ async function listFiles(folder) {
27283
27727
  while (pending.length > 0 && found.length <= MAX_FILES) {
27284
27728
  const current = pending.pop() ?? folder;
27285
27729
  for (const entry of await readdir(current, { withFileTypes: true })) {
27286
- const path = join3(current, entry.name);
27730
+ const path = join4(current, entry.name);
27287
27731
  const rel = relative(folder, path).split(sep).join("/");
27288
27732
  if (isSkippedPath({ path: rel })) continue;
27289
27733
  if (entry.isDirectory()) pending.push(path);
@@ -27298,14 +27742,14 @@ function print({
27298
27742
  context,
27299
27743
  args,
27300
27744
  value,
27301
- text
27745
+ text: text2
27302
27746
  }) {
27303
27747
  context.out(args.flags.json ? `${JSON.stringify(value, null, 2)}
27304
- ` : text);
27748
+ ` : text2);
27305
27749
  }
27306
27750
  var appCreate = async ({ context, args }) => {
27307
- const name = args.words.slice(2).join(" ").trim();
27308
- if (!name) throw new CliUsageError(USAGE);
27751
+ const name2 = args.words.slice(2).join(" ").trim();
27752
+ if (!name2) throw new CliUsageError(USAGE);
27309
27753
  const templateName = flagText({ args, name: "template" });
27310
27754
  if (templateName && !APP_TEMPLATES.includes(templateName)) {
27311
27755
  throw new CliUsageError(
@@ -27318,23 +27762,23 @@ var appCreate = async ({ context, args }) => {
27318
27762
  const slug = flagText({ args, name: "slug" });
27319
27763
  const visibility = flagText({ args, name: "visibility" });
27320
27764
  const app2 = await client.post("/api/apps/create", {
27321
- name,
27765
+ name: name2,
27322
27766
  ...slug ? { slug } : {},
27323
27767
  ...channel ? { channel } : {},
27324
27768
  ...visibility ? { visibility } : {}
27325
27769
  });
27326
27770
  const folder = resolve2(context.cwd, flagText({ args, name: "dir", fallback: app2.slug }));
27327
- await mkdir3(folder, { recursive: true });
27328
- const files = template ? templateFiles({ template, name }) : {};
27771
+ await mkdir4(folder, { recursive: true });
27772
+ const files = template ? templateFiles({ template, name: name2 }) : {};
27329
27773
  for (const [path, content] of Object.entries(files)) {
27330
- await writeFile3(join3(folder, path), content);
27774
+ await writeFile4(join4(folder, path), content);
27331
27775
  }
27332
27776
  const manifest = {
27333
27777
  app: { id: app2.id, name: app2.name, slug: app2.slug },
27334
27778
  collections: template ? { ...template.collections } : {},
27335
27779
  seed: template ? { ...template.seed } : {}
27336
27780
  };
27337
- await writeFile3(join3(folder, APP_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
27781
+ await writeFile4(join4(folder, APP_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
27338
27782
  `);
27339
27783
  print({
27340
27784
  context,
@@ -27365,7 +27809,7 @@ var appPush = async ({ context, args }) => {
27365
27809
  paths.map(
27366
27810
  async (path) => buildFileOf({
27367
27811
  path: relative(folder, path).split(sep).join("/"),
27368
- bytes: await readFile3(path)
27812
+ bytes: await readFile4(path)
27369
27813
  })
27370
27814
  )
27371
27815
  );
@@ -27380,11 +27824,11 @@ var appPush = async ({ context, args }) => {
27380
27824
  if (files.length === 0) throw new CliUsageError(`No files to push in ${folder}`);
27381
27825
  const { client } = await signedIn({ context, args });
27382
27826
  const appId = await appIdOf({ client, args, folder });
27383
- for (const [name, collection] of Object.entries(manifest?.collections ?? {})) {
27827
+ for (const [name2, collection] of Object.entries(manifest?.collections ?? {})) {
27384
27828
  await client.post("/api/apps/collections/define", {
27385
27829
  appId,
27386
27830
  site: "draft",
27387
- name,
27831
+ name: name2,
27388
27832
  fields: collection.fields
27389
27833
  });
27390
27834
  }
@@ -27498,13 +27942,13 @@ var appCollections = async ({ context, args }) => {
27498
27942
  const { client } = await signedIn({ context, args });
27499
27943
  const appId = await appIdOf({ client, args, folder: folderOf({ context, word: void 0 }) });
27500
27944
  if (args.words[2] === "define") {
27501
- const name = args.words[3];
27945
+ const name2 = args.words[3];
27502
27946
  const fields = await jsonFlag({ context, args, name: "fields" });
27503
- if (!name || !Array.isArray(fields)) throw new CliUsageError(USAGE);
27947
+ if (!name2 || !Array.isArray(fields)) throw new CliUsageError(USAGE);
27504
27948
  const collection = await client.post("/api/apps/collections/define", {
27505
27949
  appId,
27506
27950
  site: siteOf(args, "draft"),
27507
- name,
27951
+ name: name2,
27508
27952
  fields
27509
27953
  });
27510
27954
  return print({
@@ -27596,7 +28040,7 @@ var appExport = async ({ context, args }) => {
27596
28040
  const out = flagText({ args, name: "out" });
27597
28041
  if (!out) return context.out(exported.body);
27598
28042
  const target = resolve2(context.cwd, out);
27599
- await writeFile3(target, exported.body);
28043
+ await writeFile4(target, exported.body);
27600
28044
  context.out(`Wrote ${exported.rows} records to ${relative(context.cwd, target)}
27601
28045
  `);
27602
28046
  };
@@ -27616,12 +28060,12 @@ var APP_COMMANDS = {
27616
28060
  export: appExport
27617
28061
  };
27618
28062
  async function app({ context, args }) {
27619
- const name = args.words[1] ?? "";
27620
- const command = Object.hasOwn(APP_COMMANDS, name) ? APP_COMMANDS[name] : void 0;
28063
+ const name2 = args.words[1] ?? "";
28064
+ const command = Object.hasOwn(APP_COMMANDS, name2) ? APP_COMMANDS[name2] : void 0;
27621
28065
  if (!command) {
27622
28066
  context.out(`${USAGE}
27623
28067
  `);
27624
- if (name) throw new CliUsageError(`laze app has no command ${name}`);
28068
+ if (name2) throw new CliUsageError(`laze app has no command ${name2}`);
27625
28069
  return;
27626
28070
  }
27627
28071
  await command({ context, args });
@@ -27646,12 +28090,12 @@ async function profileOf({
27646
28090
  }
27647
28091
  async function login({ context, args }) {
27648
28092
  const url2 = serverUrlOf({ context, args });
27649
- const name = flagText({ args, name: "profile", fallback: "default" });
28093
+ const name2 = flagText({ args, name: "profile", fallback: "default" });
27650
28094
  const given = flagText({ args, name: "token" });
27651
28095
  const token = given || await deviceToken({ context, url: url2, args });
27652
28096
  const profile = await profileOf({ context, url: url2, token });
27653
- await context.store.saveProfile({ name, profile });
27654
- context.out(`Signed in to ${url2} as ${profile.name} (profile "${name}").
28097
+ await context.store.saveProfile({ name: name2, profile });
28098
+ context.out(`Signed in to ${url2} as ${profile.name} (profile "${name2}").
27655
28099
  `);
27656
28100
  }
27657
28101
  async function deviceToken({
@@ -27682,18 +28126,18 @@ async function deviceToken({
27682
28126
  throw new CliUsageError("The sign-in code expired: run `laze login` again.");
27683
28127
  }
27684
28128
  async function logout({ context, args }) {
27685
- const { name } = await signedIn({ context, args });
27686
- await context.store.removeProfile({ name });
27687
- context.out(`Signed out of profile "${name}". Its key stays valid until revoked in Laze.
28129
+ const { name: name2 } = await signedIn({ context, args });
28130
+ await context.store.removeProfile({ name: name2 });
28131
+ context.out(`Signed out of profile "${name2}". Its key stays valid until revoked in Laze.
27688
28132
  `);
27689
28133
  }
27690
28134
  async function whoami({ context, args }) {
27691
- const { client, name, profile } = await signedIn({ context, args });
28135
+ const { client, name: name2, profile } = await signedIn({ context, args });
27692
28136
  const me = await client.get("/api/agents/me");
27693
28137
  if (args.flags.json) return context.out(`${JSON.stringify(me, null, 2)}
27694
28138
  `);
27695
28139
  const who = me.kind === "agent" ? `agent ${me.name} (${me.id})` : `${me.name} (${me.id})`;
27696
- context.out(`${who} in workspace ${me.workspaceId} at ${profile.url}, profile "${name}"
28140
+ context.out(`${who} in workspace ${me.workspaceId} at ${profile.url}, profile "${name2}"
27697
28141
  `);
27698
28142
  }
27699
28143
  async function workspaces({ context, args }) {
@@ -27701,20 +28145,172 @@ async function workspaces({ context, args }) {
27701
28145
  const entries = Object.entries(config2.profiles);
27702
28146
  if (entries.length === 0) return context.out("Not signed in: run `laze login` first.\n");
27703
28147
  const active = await signedIn({ context, args }).catch(() => void 0);
27704
- for (const [name, profile] of entries) {
27705
- const star = active?.name === name ? "*" : " ";
28148
+ for (const [name2, profile] of entries) {
28149
+ const star = active?.name === name2 ? "*" : " ";
27706
28150
  context.out(
27707
- `${star} ${name} ${profile.workspaceId} ${profile.kind} ${profile.name} ${profile.url}
28151
+ `${star} ${name2} ${profile.workspaceId} ${profile.kind} ${profile.name} ${profile.url}
27708
28152
  `
27709
28153
  );
27710
28154
  }
27711
28155
  }
27712
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
+
27713
28288
  // src/services/codex-adopt.service.ts
27714
- import { spawn } from "node:child_process";
28289
+ import { spawn as spawn2 } from "node:child_process";
27715
28290
  import { readdir as readdir2, stat } from "node:fs/promises";
27716
- import { join as join4 } from "node:path";
28291
+ import { join as join5 } from "node:path";
27717
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
27718
28314
  function record3(value) {
27719
28315
  return typeof value === "object" && value !== null ? value : {};
27720
28316
  }
@@ -27732,6 +28328,7 @@ function absorbTurnEvent({ result, message }) {
27732
28328
  const window2 = usage.modelContextWindow;
27733
28329
  if (typeof window2 === "number" && window2 > 0) result.contextWindow = window2;
27734
28330
  }
28331
+ var TURN_HEARTBEAT_MS = 1e4;
27735
28332
  var CodexAppServer = class _CodexAppServer {
27736
28333
  constructor(child) {
27737
28334
  this.child = child;
@@ -27746,7 +28343,7 @@ var CodexAppServer = class _CodexAppServer {
27746
28343
  inherited
27747
28344
  }) {
27748
28345
  const env = { ...inherited, CODEX_HOME: codexHome };
27749
- return new _CodexAppServer(spawn("codex", ["app-server"], { env, stdio: "pipe" }));
28346
+ return new _CodexAppServer(spawn2("codex", ["app-server"], { env, stdio: "pipe" }));
27750
28347
  }
27751
28348
  async call(method, params) {
27752
28349
  const id = ++this.#nextId;
@@ -27760,24 +28357,24 @@ var CodexAppServer = class _CodexAppServer {
27760
28357
  notify(method) {
27761
28358
  this.write({ method });
27762
28359
  }
27763
- /** Runs one turn and waits for it to complete, keeping its last agent message. */
27764
- async turn({ threadId, text }) {
28360
+ /** Starts one turn; `done` settles when it completes, keeping its last agent message. */
28361
+ async startTurn({ threadId, text: text2 }) {
27765
28362
  const result = { answer: "" };
27766
28363
  const done = new Promise((resolve6) => {
27767
28364
  const listen = (message) => {
27768
28365
  absorbTurnEvent({ result, message });
27769
28366
  if (message.method !== "turn/completed") return;
27770
28367
  this.#listeners.delete(listen);
27771
- resolve6();
28368
+ resolve6(result);
27772
28369
  };
27773
28370
  this.#listeners.add(listen);
27774
28371
  });
27775
- await this.call("turn/start", {
28372
+ const started = await this.call("turn/start", {
27776
28373
  threadId,
27777
- input: [{ type: "text", text, text_elements: [] }]
28374
+ input: [{ type: "text", text: text2, text_elements: [] }]
27778
28375
  });
27779
- await done;
27780
- return result;
28376
+ const turnId = record3(started.turn).id;
28377
+ return { turnId: typeof turnId === "string" ? turnId : null, done };
27781
28378
  }
27782
28379
  stop() {
27783
28380
  this.child.kill("SIGTERM");
@@ -27799,18 +28396,23 @@ var CodexAppServer = class _CodexAppServer {
27799
28396
  return;
27800
28397
  }
27801
28398
  if (message.method !== void 0 && message.id !== void 0) {
27802
- this.write({ id: message.id, result: { decision: "approved" } });
28399
+ this.write({
28400
+ id: message.id,
28401
+ ...codexRequestReplyOf({
28402
+ method: typeof message.method === "string" ? message.method : ""
28403
+ })
28404
+ });
27803
28405
  return;
27804
28406
  }
27805
28407
  for (const listen of this.#listeners) listen(message);
27806
28408
  }
27807
28409
  };
27808
28410
  async function newestThreadId({ codexHome }) {
27809
- const root = join4(codexHome, "sessions");
28411
+ const root = join5(codexHome, "sessions");
27810
28412
  const files = await readdir2(root, { recursive: true }).catch(() => []);
27811
28413
  const rollouts = files.filter((file2) => /rollout-.*\.jsonl$/.test(file2));
27812
28414
  const dated = await Promise.all(
27813
- rollouts.map(async (file2) => ({ file: file2, at: (await stat(join4(root, file2))).mtimeMs }))
28415
+ rollouts.map(async (file2) => ({ file: file2, at: (await stat(join5(root, file2))).mtimeMs }))
27814
28416
  );
27815
28417
  const newest = dated.toSorted((a, b) => b.at - a.at)[0]?.file ?? "";
27816
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);
@@ -27825,13 +28427,49 @@ function promptOf({ message }) {
27825
28427
  formatInboxMessage({ message }).split("\n").slice(0, -1).join("\n")
27826
28428
  ].join("\n");
27827
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
+ }
27828
28461
  async function answer({
28462
+ context,
27829
28463
  codex,
27830
28464
  client,
27831
28465
  threadId,
27832
28466
  message
27833
28467
  }) {
27834
- const turn = await codex.turn({ threadId, text: promptOf({ message }) });
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})`;
27835
28473
  const body = turn.answer.trim() || "(no answer)";
27836
28474
  await client.post("/api/agents/me/replies", { messageId: message.messageId, body });
27837
28475
  if (turn.contextTokens !== void 0) {
@@ -27867,7 +28505,7 @@ async function adoptCodex({ context, args }) {
27867
28505
  waitSeconds: timeout > 0 ? timeout : Infinity
27868
28506
  });
27869
28507
  for (const message of messages) {
27870
- const body = await answer({ codex, client, threadId, message });
28508
+ const body = await answer({ context, codex, client, threadId, message });
27871
28509
  context.out(`Answered ${message.messageId}: ${body.slice(0, 120)}
27872
28510
  `);
27873
28511
  }
@@ -27879,7 +28517,7 @@ async function adoptCodex({ context, args }) {
27879
28517
  }
27880
28518
 
27881
28519
  // src/services/feed-commands.service.ts
27882
- import { readFile as readFile4 } from "node:fs/promises";
28520
+ import { readFile as readFile6 } from "node:fs/promises";
27883
28521
  import { resolve as resolve3 } from "node:path";
27884
28522
 
27885
28523
  // src/rules/feed-input.rules.ts
@@ -27938,7 +28576,7 @@ function feedFlagsOf({ args }) {
27938
28576
  }
27939
28577
 
27940
28578
  // src/services/feed-commands.service.ts
27941
- var USAGE2 = `Usage:
28579
+ var USAGE3 = `Usage:
27942
28580
  laze feed post <title> [--channel <channel>] [--tag <tag>] [--summary <line>]
27943
28581
  [--body <text|@file>] [--draft <text|@file>] [--draft-header "To: ...\\nRe: ..."]
27944
28582
  [--link <label>=<url>]... [--action <label>=<message>]... [--to <userId>]...
@@ -27962,7 +28600,7 @@ async function bodyOf({
27962
28600
  }) {
27963
28601
  const body = { ...flags.fields };
27964
28602
  for (const [field, source] of Object.entries(flags.texts)) {
27965
- body[field] = "file" in source ? await readFile4(resolve3(context.cwd, source.file), "utf8") : source.text;
28603
+ body[field] = "file" in source ? await readFile6(resolve3(context.cwd, source.file), "utf8") : source.text;
27966
28604
  }
27967
28605
  return body;
27968
28606
  }
@@ -27981,7 +28619,7 @@ function printItem({
27981
28619
  }
27982
28620
  async function feedPost({ context, args }) {
27983
28621
  const title = args.words.slice(2).join(" ").trim();
27984
- if (!title) throw new CliUsageError(USAGE2);
28622
+ if (!title) throw new CliUsageError(USAGE3);
27985
28623
  const flags = flagsOf(args);
27986
28624
  const { client } = await signedIn({ context, args });
27987
28625
  const channel = flagText({ args, name: "channel" });
@@ -27998,7 +28636,7 @@ async function feedPost({ context, args }) {
27998
28636
  }
27999
28637
  async function feedUpdate({ context, args }) {
28000
28638
  const itemId = args.words[2];
28001
- if (!itemId) throw new CliUsageError(USAGE2);
28639
+ if (!itemId) throw new CliUsageError(USAGE3);
28002
28640
  const flags = flagsOf(args);
28003
28641
  const { client } = await signedIn({ context, args });
28004
28642
  const body = await bodyOf({ context, flags });
@@ -28013,19 +28651,19 @@ async function feedUpdate({ context, args }) {
28013
28651
  }
28014
28652
  async function feedReply({ context, args }) {
28015
28653
  const itemId = args.words[2];
28016
- const text = args.words.slice(3).join(" ").trim();
28017
- if (!itemId || !text) throw new CliUsageError(USAGE2);
28654
+ const text2 = args.words.slice(3).join(" ").trim();
28655
+ if (!itemId || !text2) throw new CliUsageError(USAGE3);
28018
28656
  const { client } = await signedIn({ context, args });
28019
28657
  const replied = await client.post("/api/feed/items/reply", {
28020
28658
  itemId,
28021
- body: text,
28659
+ body: text2,
28022
28660
  urgent: Boolean(args.flags.urgent)
28023
28661
  });
28024
28662
  printItem({ context, args, item: replied });
28025
28663
  }
28026
28664
  async function feedRead({ context, args }) {
28027
28665
  const itemId = args.words[2];
28028
- if (!itemId) throw new CliUsageError(USAGE2);
28666
+ if (!itemId) throw new CliUsageError(USAGE3);
28029
28667
  const { client } = await signedIn({ context, args });
28030
28668
  const read = await client.post("/api/feed/items/read", { itemId });
28031
28669
  printItem({ context, args, item: read });
@@ -28048,14 +28686,14 @@ var FEED_COMMANDS = {
28048
28686
  inbox: feedInbox
28049
28687
  };
28050
28688
  async function feed({ context, args }) {
28051
- const name = args.words[1] ?? "";
28052
- const command = Object.hasOwn(FEED_COMMANDS, name) ? FEED_COMMANDS[name] : void 0;
28053
- if (!command) throw new CliUsageError(USAGE2);
28689
+ const name2 = args.words[1] ?? "";
28690
+ const command = Object.hasOwn(FEED_COMMANDS, name2) ? FEED_COMMANDS[name2] : void 0;
28691
+ if (!command) throw new CliUsageError(USAGE3);
28054
28692
  await command({ context, args });
28055
28693
  }
28056
28694
 
28057
28695
  // src/services/github-commands.service.ts
28058
- import { readFile as readFile5 } from "node:fs/promises";
28696
+ import { readFile as readFile7 } from "node:fs/promises";
28059
28697
 
28060
28698
  // src/rules/github-signature.rules.ts
28061
28699
  var TURN_SEPARATOR = "~";
@@ -28123,13 +28761,17 @@ function isLocalGhCall(args) {
28123
28761
  // src/services/github-commands.service.ts
28124
28762
  var REAL_GH = "/usr/bin/gh";
28125
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
+ }
28126
28771
  async function credentialOf({ env }) {
28127
28772
  const placeholder = (env.GH_TOKEN ?? "").split(TURN_SEPARATOR)[0] ?? "";
28128
28773
  if (!placeholder.startsWith("laze-ph-")) throw new CliUsageError(NOT_SET);
28129
- const turn = env.LAZE_TURN_FILE ? await readFile5(env.LAZE_TURN_FILE, "utf8").then(
28130
- (text) => text.trim(),
28131
- () => ""
28132
- ) : "";
28774
+ const turn = env.LAZE_TURN_TOKEN?.trim() || await turnFileToken({ env });
28133
28775
  return turn ? `${placeholder}${TURN_SEPARATOR}${turn}` : placeholder;
28134
28776
  }
28135
28777
  function threadUrlOf({ env, workspaceId }) {
@@ -28155,7 +28797,7 @@ async function githubGh({
28155
28797
  args: args.rest,
28156
28798
  agentName: profile.name ?? "An agent",
28157
28799
  threadUrl: threadUrlOf({ env, workspaceId: profile.workspaceId }),
28158
- readBodyFile: (path) => path === "-" ? context.readStdin() : readFile5(path, "utf8")
28800
+ readBodyFile: (path) => path === "-" ? context.readStdin() : readFile7(path, "utf8")
28159
28801
  });
28160
28802
  return context.runCommand({
28161
28803
  command: [REAL_GH, ...ghArgs],
@@ -28254,7 +28896,7 @@ async function setAgentGithub({
28254
28896
  }
28255
28897
 
28256
28898
  // src/services/mcp-gateway.service.ts
28257
- import { readFile as readFile6 } from "node:fs/promises";
28899
+ import { readFile as readFile8 } from "node:fs/promises";
28258
28900
  import { createInterface as createInterface2 } from "node:readline";
28259
28901
  var TURN_HEADER = "x-laze-turn";
28260
28902
  function serveMcpGateway({
@@ -28268,6 +28910,7 @@ async function relayMcpLines({
28268
28910
  args,
28269
28911
  lines
28270
28912
  }) {
28913
+ const pending = lines[Symbol.asyncIterator]();
28271
28914
  const { profile } = await signedIn({ context, args });
28272
28915
  const env = context.environment.inherited;
28273
28916
  if (!profile.agentId || !env.LAZE_TURN_FILE)
@@ -28275,10 +28918,11 @@ async function relayMcpLines({
28275
28918
  const github2 = env.LAZE_GITHUB_CONNECTION;
28276
28919
  const url2 = `${profile.url.replace(/\/+$/, "")}/api/connectors/mcp/${encodeURIComponent(profile.agentId)}${github2 ? `?github=${encodeURIComponent(github2)}` : ""}`;
28277
28920
  const turnFile = env.LAZE_TURN_FILE;
28278
- for await (const line of lines) {
28921
+ for (let next = await pending.next(); !next.done; next = await pending.next()) {
28922
+ const line = next.value;
28279
28923
  if (!line.trim()) continue;
28280
- const turn = await readFile6(turnFile, "utf8").then(
28281
- (text2) => text2.trim(),
28924
+ const turn = await readFile8(turnFile, "utf8").then(
28925
+ (text3) => text3.trim(),
28282
28926
  () => ""
28283
28927
  );
28284
28928
  const response = await context.fetcher(url2, {
@@ -28291,8 +28935,8 @@ async function relayMcpLines({
28291
28935
  },
28292
28936
  body: line
28293
28937
  });
28294
- const text = await response.text();
28295
- if (text.trim()) context.out(`${text.trim()}
28938
+ const text2 = await response.text();
28939
+ if (text2.trim()) context.out(`${text2.trim()}
28296
28940
  `);
28297
28941
  }
28298
28942
  }
@@ -28343,10 +28987,10 @@ function textOf2(value) {
28343
28987
  async function callTool({
28344
28988
  context,
28345
28989
  client,
28346
- name,
28990
+ name: name2,
28347
28991
  input: input2
28348
28992
  }) {
28349
- switch (name) {
28993
+ switch (name2) {
28350
28994
  case "whoami":
28351
28995
  return JSON.stringify(await client.get("/api/agents/me"));
28352
28996
  case "list_channels":
@@ -28376,7 +29020,7 @@ async function callTool({
28376
29020
  return `Replied ${posted.messageId}.`;
28377
29021
  }
28378
29022
  default:
28379
- throw new Error(`Unknown tool ${name}`);
29023
+ throw new Error(`Unknown tool ${name2}`);
28380
29024
  }
28381
29025
  }
28382
29026
  async function answer2({
@@ -28395,13 +29039,13 @@ async function answer2({
28395
29039
  if (request.method === "tools/list") return { tools: TOOLS };
28396
29040
  if (request.method === "tools/call") {
28397
29041
  try {
28398
- const text = await callTool({
29042
+ const text2 = await callTool({
28399
29043
  context,
28400
29044
  client,
28401
29045
  name: textOf2(params.name),
28402
29046
  input: params.arguments ?? {}
28403
29047
  });
28404
- return { content: [{ type: "text", text }] };
29048
+ return { content: [{ type: "text", text: text2 }] };
28405
29049
  } catch (error62) {
28406
29050
  return { content: [{ type: "text", text: String(error62) }], isError: true };
28407
29051
  }
@@ -28422,14 +29066,14 @@ async function serveMcp({ context, args }) {
28422
29066
  }
28423
29067
 
28424
29068
  // src/services/mount-files.service.ts
28425
- import { mkdir as mkdir4, readFile as readFile7, rm, writeFile as writeFile4 } from "node:fs/promises";
28426
- import { dirname as dirname2, relative as relative2, resolve as resolve4 } from "node:path";
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";
28427
29071
  async function textArgument({
28428
29072
  context,
28429
29073
  value
28430
29074
  }) {
28431
29075
  if (value === "-") return context.readStdin();
28432
- if (value.startsWith("@")) return readFile7(resolve4(context.cwd, value.slice(1)), "utf8");
29076
+ if (value.startsWith("@")) return readFile9(resolve4(context.cwd, value.slice(1)), "utf8");
28433
29077
  return value;
28434
29078
  }
28435
29079
  function turnChannel({ context, args }) {
@@ -28442,21 +29086,21 @@ async function writeMount({
28442
29086
  files
28443
29087
  }) {
28444
29088
  const root = resolve4(context.cwd, flagText({ args, name: "dir", fallback: ".laze" }), folder);
28445
- await rm(root, { recursive: true, force: true });
28446
- await mkdir4(root, { recursive: true });
29089
+ await rm2(root, { recursive: true, force: true });
29090
+ await mkdir5(root, { recursive: true });
28447
29091
  for (const file2 of files) {
28448
29092
  const target = resolve4(root, file2.path);
28449
29093
  const inside = relative2(root, target);
28450
29094
  if (!inside || inside.startsWith(".."))
28451
29095
  throw new Error(`Refusing to write outside ${root}: ${file2.path}`);
28452
- await mkdir4(dirname2(target), { recursive: true });
28453
- await writeFile4(target, file2.content);
29096
+ await mkdir5(dirname3(target), { recursive: true });
29097
+ await writeFile5(target, file2.content);
28454
29098
  }
28455
29099
  return root;
28456
29100
  }
28457
29101
 
28458
29102
  // src/services/memory-commands.service.ts
28459
- var USAGE3 = `Usage:
29103
+ var USAGE4 = `Usage:
28460
29104
  laze memory get SOUL.md|AGENTS.md|MEMORY.md [--channel <channel>]
28461
29105
  laze memory set <file> <text|@file|-> [--channel <channel>] [--base <version>]
28462
29106
  laze memory append MEMORY.md <text|@file|-> [--channel <channel>]
@@ -28467,7 +29111,7 @@ MEMORY.md is the file of the turn's channel (LAZE_CHANNEL), or of --channel when
28467
29111
  var FILES = /* @__PURE__ */ new Set(["SOUL.md", "AGENTS.md", "MEMORY.md"]);
28468
29112
  function fileRef({ context, args }) {
28469
29113
  const file2 = args.words[2] ?? "";
28470
- if (!FILES.has(file2)) throw new CliUsageError(USAGE3);
29114
+ if (!FILES.has(file2)) throw new CliUsageError(USAGE4);
28471
29115
  const channel = turnChannel({ context, args });
28472
29116
  return { file: file2, ...channel ? { channel } : {} };
28473
29117
  }
@@ -28495,7 +29139,7 @@ async function memoryGet({ context, args }) {
28495
29139
  async function memorySet({ context, args }) {
28496
29140
  const ref = fileRef({ context, args });
28497
29141
  const value = args.words.slice(3).join(" ");
28498
- if (!value) throw new CliUsageError(USAGE3);
29142
+ if (!value) throw new CliUsageError(USAGE4);
28499
29143
  const content = await textArgument({ context, value });
28500
29144
  const base = args.flags.base;
28501
29145
  const { client } = await signedIn({ context, args });
@@ -28511,17 +29155,17 @@ async function memorySet({ context, args }) {
28511
29155
  async function memoryAppend({ context, args }) {
28512
29156
  const ref = fileRef({ context, args });
28513
29157
  const value = args.words.slice(3).join(" ");
28514
- if (!value) throw new CliUsageError(USAGE3);
28515
- const text = await textArgument({ context, value });
29158
+ if (!value) throw new CliUsageError(USAGE4);
29159
+ const text2 = await textArgument({ context, value });
28516
29160
  const { client } = await signedIn({ context, args });
28517
- const saved = await client.post("/api/memory/append", { ...ref, text });
29161
+ const saved = await client.post("/api/memory/append", { ...ref, text: text2 });
28518
29162
  if (args.flags.json) return printDocument({ context, args, document: saved });
28519
29163
  context.out(`Saved ${saved.file} version ${saved.version}
28520
29164
  `);
28521
29165
  }
28522
29166
  async function memorySearch({ context, args }) {
28523
29167
  const query = args.words.slice(2).join(" ").trim();
28524
- if (!query) throw new CliUsageError(USAGE3);
29168
+ if (!query) throw new CliUsageError(USAGE4);
28525
29169
  const { client } = await signedIn({ context, args });
28526
29170
  const hits = await client.post("/api/memory/search", { query });
28527
29171
  if (args.flags.json) return context.out(`${JSON.stringify(hits, null, 2)}
@@ -28552,14 +29196,14 @@ var MEMORY_COMMANDS = {
28552
29196
  pull: memoryPull
28553
29197
  };
28554
29198
  async function memory({ context, args }) {
28555
- const name = args.words[1] ?? "";
28556
- const command = Object.hasOwn(MEMORY_COMMANDS, name) ? MEMORY_COMMANDS[name] : void 0;
28557
- if (!command) throw new CliUsageError(USAGE3);
29199
+ const name2 = args.words[1] ?? "";
29200
+ const command = Object.hasOwn(MEMORY_COMMANDS, name2) ? MEMORY_COMMANDS[name2] : void 0;
29201
+ if (!command) throw new CliUsageError(USAGE4);
28558
29202
  await command({ context, args });
28559
29203
  }
28560
29204
 
28561
29205
  // src/services/schedule-commands.service.ts
28562
- var USAGE4 = `Usage:
29206
+ var USAGE5 = `Usage:
28563
29207
  laze schedule add <name> --prompt <text> (--cron "<m h dom mon dow>" | --rrule "<RRULE>" | --at <local time>)
28564
29208
  [--tz <IANA zone>] [--channel <channelId>] [--agent <agentId>]
28565
29209
  laze schedule list
@@ -28571,7 +29215,7 @@ function timingOf(args) {
28571
29215
  const given = [cron, rrule, at].filter(Boolean);
28572
29216
  if (given.length !== 1)
28573
29217
  throw new CliUsageError(`Give exactly one of --cron, --rrule or --at.
28574
- ${USAGE4}`);
29218
+ ${USAGE5}`);
28575
29219
  if (cron) return { kind: "cron", cron };
28576
29220
  if (rrule) return { kind: "rrule", rrule };
28577
29221
  return { kind: "once", at };
@@ -28584,15 +29228,15 @@ function printSchedule({ context, schedule: schedule2 }) {
28584
29228
  );
28585
29229
  }
28586
29230
  async function scheduleAdd({ context, args }) {
28587
- const name = args.words.slice(2).join(" ").trim();
29231
+ const name2 = args.words.slice(2).join(" ").trim();
28588
29232
  const prompt = flagText({ args, name: "prompt" });
28589
- if (!name || !prompt) throw new CliUsageError(USAGE4);
29233
+ if (!name2 || !prompt) throw new CliUsageError(USAGE5);
28590
29234
  const timing = timingOf(args);
28591
29235
  const { client } = await signedIn({ context, args });
28592
29236
  const channelId = flagText({ args, name: "channel" });
28593
29237
  const agentId = flagText({ args, name: "agent" });
28594
29238
  const schedule2 = await client.post("/api/schedules", {
28595
- name,
29239
+ name: name2,
28596
29240
  prompt,
28597
29241
  timing,
28598
29242
  timezone: flagText({ args, name: "tz", fallback: "UTC" }),
@@ -28613,7 +29257,7 @@ async function scheduleList({ context, args }) {
28613
29257
  function byId(path) {
28614
29258
  return async ({ context, args }) => {
28615
29259
  const scheduleId = args.words[2];
28616
- if (!scheduleId) throw new CliUsageError(USAGE4);
29260
+ if (!scheduleId) throw new CliUsageError(USAGE5);
28617
29261
  const { client } = await signedIn({ context, args });
28618
29262
  const answer3 = await client.post(`/api/schedules/${path}`, {
28619
29263
  scheduleId
@@ -28627,7 +29271,7 @@ function byId(path) {
28627
29271
  }
28628
29272
  async function scheduleRuns({ context, args }) {
28629
29273
  const scheduleId = args.words[2];
28630
- if (!scheduleId) throw new CliUsageError(USAGE4);
29274
+ if (!scheduleId) throw new CliUsageError(USAGE5);
28631
29275
  const { client } = await signedIn({ context, args });
28632
29276
  const runs = await client.post("/api/schedules/runs", { scheduleId });
28633
29277
  if (args.flags.json) return context.out(`${JSON.stringify(runs, null, 2)}
@@ -28648,16 +29292,16 @@ var SCHEDULE_COMMANDS = {
28648
29292
  runs: scheduleRuns
28649
29293
  };
28650
29294
  async function schedule({ context, args }) {
28651
- const name = args.words[1] ?? "";
28652
- const command = Object.hasOwn(SCHEDULE_COMMANDS, name) ? SCHEDULE_COMMANDS[name] : void 0;
28653
- if (!command) throw new CliUsageError(USAGE4);
29295
+ const name2 = args.words[1] ?? "";
29296
+ const command = Object.hasOwn(SCHEDULE_COMMANDS, name2) ? SCHEDULE_COMMANDS[name2] : void 0;
29297
+ if (!command) throw new CliUsageError(USAGE5);
28654
29298
  await command({ context, args });
28655
29299
  }
28656
29300
 
28657
29301
  // src/services/skill-commands.service.ts
28658
- import { readdir as readdir3, readFile as readFile8 } from "node:fs/promises";
28659
- import { join as join5, relative as relative3, resolve as resolve5 } from "node:path";
28660
- var USAGE5 = `Usage:
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:
28661
29305
  laze skill list
28662
29306
  laze skill install <catalogue-id> [--as <name>]
28663
29307
  laze skill install --from <folder> [--as <name>] a folder with a SKILL.md
@@ -28668,8 +29312,8 @@ async function folderFiles({ root }) {
28668
29312
  const files = [];
28669
29313
  for (const entry of entries) {
28670
29314
  if (!entry.isFile()) continue;
28671
- const full = join5(entry.parentPath, entry.name);
28672
- files.push({ path: relative3(root, full), content: await readFile8(full, "utf8") });
29315
+ const full = join6(entry.parentPath, entry.name);
29316
+ files.push({ path: relative3(root, full), content: await readFile10(full, "utf8") });
28673
29317
  }
28674
29318
  return files.toSorted((a, b) => a.path.localeCompare(b.path));
28675
29319
  }
@@ -28688,13 +29332,13 @@ async function skillList({ context, args }) {
28688
29332
  async function skillInstall({ context, args }) {
28689
29333
  const catalogueId = args.words[2];
28690
29334
  const from = flagText({ args, name: "from" });
28691
- if (!catalogueId === !from) throw new CliUsageError(USAGE5);
28692
- const name = flagText({ args, name: "as" });
29335
+ if (!catalogueId === !from) throw new CliUsageError(USAGE6);
29336
+ const name2 = flagText({ args, name: "as" });
28693
29337
  const files = from ? await folderFiles({ root: resolve5(context.cwd, from) }) : void 0;
28694
29338
  const { client } = await signedIn({ context, args });
28695
29339
  const installed = await client.post("/api/skills/install", {
28696
29340
  ...catalogueId ? { catalogueId } : {},
28697
- ...name ? { name } : {},
29341
+ ...name2 ? { name: name2 } : {},
28698
29342
  ...files ? { files } : {}
28699
29343
  });
28700
29344
  if (args.flags.json) return context.out(`${JSON.stringify(installed, null, 2)}
@@ -28703,10 +29347,10 @@ async function skillInstall({ context, args }) {
28703
29347
  `);
28704
29348
  }
28705
29349
  async function skillShow({ context, args }) {
28706
- const name = args.words[2];
28707
- if (!name) throw new CliUsageError(USAGE5);
29350
+ const name2 = args.words[2];
29351
+ if (!name2) throw new CliUsageError(USAGE6);
28708
29352
  const { client } = await signedIn({ context, args });
28709
- const skill2 = await client.post("/api/skills/show", { name });
29353
+ const skill2 = await client.post("/api/skills/show", { name: name2 });
28710
29354
  if (args.flags.json) return context.out(`${JSON.stringify(skill2, null, 2)}
28711
29355
  `);
28712
29356
  context.out(`${skill2.name}${skill2.installed ? "" : " (not installed)"}: ${skill2.description}
@@ -28734,18 +29378,937 @@ var SKILL_COMMANDS = {
28734
29378
  pull: skillPull
28735
29379
  };
28736
29380
  async function skill({ context, args }) {
28737
- const name = args.words[1] ?? "";
28738
- const command = Object.hasOwn(SKILL_COMMANDS, name) ? SKILL_COMMANDS[name] : void 0;
28739
- if (!command) throw new CliUsageError(USAGE5);
29381
+ const name2 = args.words[1] ?? "";
29382
+ const command = Object.hasOwn(SKILL_COMMANDS, name2) ? SKILL_COMMANDS[name2] : void 0;
29383
+ if (!command) throw new CliUsageError(USAGE6);
28740
29384
  await command({ context, args });
28741
29385
  }
28742
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
+
28743
29460
  // src/services/vault-commands.service.ts
28744
- import { readFile as readFile9 } from "node:fs/promises";
28745
- var USAGE6 = `Usage: laze vault run <connection> --reason "<one plain sentence>" [--wait <s>] -- <command> [args...]
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));
29473
+
29474
+ // ../../modules/vault/contract/src/vault-devices.ts
29475
+ var base64Url = external_exports.string().regex(/^[A-Za-z0-9_-]+$/).max(16384);
29476
+ var name = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,62}$/);
29477
+ var fieldName = external_exports.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/);
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"];
29484
+ var vaultDeviceStateSchema = external_exports.enum(["pending", "active"]);
29485
+ var vaultDevicePasskeySchemaDefinition = external_exports.object({
29486
+ credentialId: base64Url,
29487
+ prfSalt: base64Url,
29488
+ wrappedPrivateKey: base64Url
29489
+ });
29490
+ var vaultDeviceSchemaDefinition = external_exports.object({
29491
+ id: external_exports.string().min(1),
29492
+ workspaceId: external_exports.string().min(1),
29493
+ userId: external_exports.string().min(1),
29494
+ label: external_exports.string(),
29495
+ kind: vaultDeviceKindSchema,
29496
+ state: vaultDeviceStateSchema,
29497
+ /** P-256 uncompressed point, base64url. */
29498
+ publicKey: base64Url,
29499
+ /** `4F2A 91C0`: the first four bytes of sha256(publicKey). */
29500
+ fingerprint: external_exports.string(),
29501
+ /** What the browser needs to unlock the device's key with its passkey; null for native. */
29502
+ passkey: vaultDevicePasskeySchemaDefinition.nullable(),
29503
+ createdAt: external_exports.iso.datetime(),
29504
+ activatedAt: external_exports.iso.datetime().nullable()
29505
+ });
29506
+ var vaultDeviceSchema = vaultDeviceSchemaDefinition;
29507
+ var vaultDeviceEnrolmentSchemaDefinition = external_exports.object({
29508
+ deviceId: external_exports.string(),
29509
+ /** Signed by the vault: the WebAuthn challenge is its UTF-8 bytes. */
29510
+ challenge: external_exports.string(),
29511
+ /** The passkey's user handle and names. */
29512
+ userId: external_exports.string(),
29513
+ /** True when this person has no active device, so the new one is active at once. */
29514
+ first: external_exports.boolean()
29515
+ });
29516
+ var vaultDeviceEnrolmentSchema = vaultDeviceEnrolmentSchemaDefinition;
29517
+ var finishVaultDeviceEnrolmentInputSchemaDefinition = external_exports.object({
29518
+ workspaceId: external_exports.string().min(1),
29519
+ deviceId: external_exports.string().min(1),
29520
+ challenge: external_exports.string().min(1),
29521
+ label: external_exports.string().trim().min(1).max(80),
29522
+ publicKey: base64Url,
29523
+ passkey: external_exports.object({
29524
+ ...vaultDevicePasskeySchemaDefinition.shape,
29525
+ /** The passkey's own public key, SPKI DER, ES256 only. */
29526
+ credentialPublicKey: base64Url,
29527
+ credentialAlgorithm: external_exports.literal(-7),
29528
+ clientDataJSON: base64Url
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()
29538
+ });
29539
+ var finishVaultDeviceEnrolmentInputSchema = finishVaultDeviceEnrolmentInputSchemaDefinition;
29540
+ var sealedRecipientSchema = external_exports.object({
29541
+ deviceId: external_exports.string().min(1),
29542
+ epk: base64Url,
29543
+ wrappedKey: base64Url
29544
+ });
29545
+ var sealedSecretSchemaDefinition = external_exports.object({
29546
+ blob: base64Url,
29547
+ recipients: external_exports.array(sealedRecipientSchema).min(1).max(32)
29548
+ });
29549
+ var vaultDeviceAssertionSchemaDefinition = external_exports.object({
29550
+ credentialId: base64Url,
29551
+ clientDataJSON: base64Url,
29552
+ authenticatorData: base64Url,
29553
+ signature: base64Url
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
+ });
29560
+ var approveVaultDeviceInputSchemaDefinition = external_exports.object({
29561
+ workspaceId: external_exports.string().min(1),
29562
+ deviceId: external_exports.string().min(1),
29563
+ challenge: external_exports.string().min(1),
29564
+ assertion: external_exports.union([vaultDeviceAssertionSchemaDefinition, vaultNativeAssertionSchemaDefinition]),
29565
+ /** The new device's recipient for every sealed secret of the owner. */
29566
+ recipients: external_exports.array(
29567
+ external_exports.object({ connectionId: external_exports.string().min(1), recipient: sealedRecipientSchema })
29568
+ )
29569
+ });
29570
+ var approveVaultDeviceInputSchema = approveVaultDeviceInputSchemaDefinition;
29571
+ var createSealedConnectionInputSchemaDefinition = external_exports.object({
29572
+ workspaceId: external_exports.string().min(1),
29573
+ name,
29574
+ label: external_exports.string().trim().min(1).max(120),
29575
+ sensitivity: external_exports.enum(["ask", "human_only"]).default("ask"),
29576
+ rules: external_exports.string().max(2e3).default(""),
29577
+ fieldNames: external_exports.array(fieldName).min(1).max(32),
29578
+ sealed: sealedSecretSchemaDefinition,
29579
+ /** Only a personal API key set is sealed for now; anything else is refused, not ignored. */
29580
+ keychain: external_exports.enum(["personal", "workspace", "agent"]).default("personal"),
29581
+ kind: external_exports.enum(["api_key_set", "oauth", "mcp"]).default("api_key_set")
29582
+ });
29583
+ var createSealedConnectionInputSchema = createSealedConnectionInputSchemaDefinition;
29584
+ var resealConnectionInputSchemaDefinition = external_exports.object({
29585
+ workspaceId: external_exports.string().min(1),
29586
+ connectionId: external_exports.string().min(1),
29587
+ fieldNames: external_exports.array(fieldName).min(1).max(32),
29588
+ sealed: sealedSecretSchemaDefinition
29589
+ });
29590
+ var resealConnectionInputSchema = resealConnectionInputSchemaDefinition;
29591
+ var vaultSealedMaterialSchemaDefinition = external_exports.object({
29592
+ connectionId: external_exports.string(),
29593
+ workspaceId: external_exports.string(),
29594
+ ownerUserId: external_exports.string(),
29595
+ name,
29596
+ label: external_exports.string(),
29597
+ fieldNames: external_exports.array(external_exports.string()),
29598
+ blob: base64Url,
29599
+ recipients: external_exports.array(sealedRecipientSchema)
29600
+ });
29601
+ var vaultSealedMaterialSchema = vaultSealedMaterialSchemaDefinition;
29602
+ var vaultSealedApprovalSchemaDefinition = external_exports.object({
29603
+ requestId: external_exports.string(),
29604
+ agentId: external_exports.string(),
29605
+ reason: external_exports.string(),
29606
+ command: external_exports.array(external_exports.string()),
29607
+ /** The run's public key; the opened value is encrypted to it and nothing else. */
29608
+ runPublicKey: base64Url,
29609
+ material: vaultSealedMaterialSchemaDefinition
29610
+ });
29611
+ var vaultSealedApprovalSchema = vaultSealedApprovalSchemaDefinition;
29612
+ var vaultUi = uiTokens("vault");
29613
+ var VaultSealedApprovalSlot = vaultUi.component("sealedApproval");
29614
+ var VaultNavSlot = vaultUi.component("nav");
29615
+ var answerSealedApprovalInputSchemaDefinition = external_exports.object({
29616
+ workspaceId: external_exports.string().min(1),
29617
+ requestId: external_exports.string().min(1),
29618
+ release: external_exports.object({ epk: base64Url, ciphertext: base64Url }),
29619
+ via: external_exports.enum(["feed", "channel", "ios", "desktop", "web"]).default("web")
29620
+ });
29621
+ var answerSealedApprovalInputSchema = answerSealedApprovalInputSchemaDefinition;
29622
+ var vaultRunSealedReleaseSchemaDefinition = external_exports.object({
29623
+ requestId: external_exports.string(),
29624
+ epk: base64Url,
29625
+ ciphertext: base64Url
29626
+ });
29627
+ var vaultRunSealedReleaseSchema = vaultRunSealedReleaseSchemaDefinition;
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
+
29654
+ // ../../modules/vault/contract/src/vault-reason.ts
29655
+ var COMMAND_STARTS = new Set(
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(
29657
+ " "
29658
+ )
29659
+ );
29660
+ function checkVaultReason(reason) {
29661
+ const text2 = (reason ?? "").trim();
29662
+ if (text2 === "") return "missing";
29663
+ if (text2.includes("\n") || Array.from(text2).length > 200) return "too_long";
29664
+ const words = text2.split(/\s+/);
29665
+ if (COMMAND_STARTS.has((words[0] ?? "").toLowerCase())) return "looks_like_command";
29666
+ if (/(^|\s)--?[A-Za-z]/.test(text2) || /[|;&`$<>{}]/.test(text2)) return "looks_like_command";
29667
+ if (words.length < 4) return "too_short";
29668
+ return "ok";
29669
+ }
29670
+ var vaultReasonSchema = external_exports.string().transform((reason) => reason.trim()).superRefine((reason, context) => {
29671
+ const problem = checkVaultReason(reason);
29672
+ if (problem !== "ok")
29673
+ context.addIssue({ code: "custom", message: problem, params: { problem } });
29674
+ });
29675
+
29676
+ // ../../modules/vault/contract/src/vault.ts
29677
+ var vaultSensitivitySchema = external_exports.enum(["auto", "checked", "ask", "human_only"]);
29678
+ var vaultKeychainSchemaDefinition = external_exports.discriminatedUnion("kind", [
29679
+ external_exports.object({ kind: external_exports.literal("personal"), ownerUserId: external_exports.string().min(1) }),
29680
+ external_exports.object({ kind: external_exports.literal("workspace") }),
29681
+ external_exports.object({ kind: external_exports.literal("agent"), agentId: external_exports.string().min(1) })
29682
+ ]);
29683
+ var vaultKeychainSchema = vaultKeychainSchemaDefinition;
29684
+ var vaultConnectionKindSchema = external_exports.enum(["api_key_set", "oauth", "mcp"]);
29685
+ var vaultConnectionStatusSchema = external_exports.enum(["active", "needs_reconnect"]);
29686
+ var vaultFieldNameSchema = external_exports.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).max(64);
29687
+ var vaultConnectionNameSchema = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,62}$/);
29688
+ var vaultOAuthRevokeStyleSchema = external_exports.enum(["rfc7009", "github_grant", "slack"]);
29689
+ var vaultOAuthClientSchemaDefinition = external_exports.object({
29690
+ tokenUrl: external_exports.url(),
29691
+ clientId: external_exports.string().min(1),
29692
+ clientSecret: external_exports.string().min(1).nullable().default(null),
29693
+ authMethod: external_exports.enum(["client_secret_post", "client_secret_basic", "none", "github_app"]).default("client_secret_post"),
29694
+ /** How the token endpoint reads its body. */
29695
+ bodyFormat: external_exports.enum(["form", "json"]).default("form"),
29696
+ /** Where a nested provider answer keeps the person's token, Slack's `authed_user`. */
29697
+ tokenPath: external_exports.enum(["authed_user"]).nullable().default(null),
29698
+ revoke: external_exports.object({ style: vaultOAuthRevokeStyleSchema, url: external_exports.url() }).nullable().default(null)
29699
+ });
29700
+ var vaultOAuthClientSchema = vaultOAuthClientSchemaDefinition;
29701
+ var vaultOAuthTokensSchemaDefinition = external_exports.object({
29702
+ accessToken: external_exports.string().min(1),
29703
+ refreshToken: external_exports.string().min(1).nullable().default(null),
29704
+ /** ISO 8601; null when the provider's access tokens do not expire. */
29705
+ expiresAt: external_exports.iso.datetime().nullable().default(null),
29706
+ scopes: external_exports.array(external_exports.string().min(1)).default([]),
29707
+ client: vaultOAuthClientSchema
29708
+ });
29709
+ var vaultOAuthTokensSchema = vaultOAuthTokensSchemaDefinition;
29710
+ var vaultSecretBundleSchemaDefinition = external_exports.discriminatedUnion("kind", [
29711
+ external_exports.object({
29712
+ kind: external_exports.literal("api_key_set"),
29713
+ fields: external_exports.record(vaultFieldNameSchema, external_exports.string().min(1))
29714
+ }),
29715
+ /** A grant from a provider in the connector registry: Gmail, GitHub, Slack and the rest. */
29716
+ external_exports.object({
29717
+ kind: external_exports.literal("oauth"),
29718
+ provider: external_exports.string().min(1),
29719
+ /** Who the grant is for at the provider, shown to the owner: an address or a login. */
29720
+ account: external_exports.string().min(1).nullable().default(null),
29721
+ tokens: vaultOAuthTokensSchema
29722
+ }),
29723
+ /** A remote MCP server: the headers it takes, and its OAuth tokens when it signs people in. */
29724
+ external_exports.object({
29725
+ kind: external_exports.literal("mcp"),
29726
+ serverUrl: external_exports.url(),
29727
+ headers: external_exports.record(external_exports.string().regex(/^[A-Za-z0-9-]{1,64}$/), external_exports.string().min(1)).default({}),
29728
+ tokens: vaultOAuthTokensSchema.nullable().default(null)
29729
+ })
29730
+ ]);
29731
+ var vaultSecretBundleSchema = vaultSecretBundleSchemaDefinition;
29732
+ var vaultConnectorDetailsSchemaDefinition = external_exports.object({
29733
+ provider: external_exports.string().nullable(),
29734
+ serverUrl: external_exports.string().nullable(),
29735
+ account: external_exports.string().nullable(),
29736
+ scopes: external_exports.array(external_exports.string()),
29737
+ /** When the access token runs out; the vault refreshes it on the next use. */
29738
+ expiresAt: external_exports.iso.datetime().nullable()
29739
+ });
29740
+ var vaultConnectorDetailsSchema = vaultConnectorDetailsSchemaDefinition;
29741
+ var vaultEgressTargetSchemaDefinition = external_exports.object({
29742
+ upstream: external_exports.url(),
29743
+ header: external_exports.string().min(1).default("Authorization"),
29744
+ prefix: external_exports.string().default("Bearer "),
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([])
29748
+ });
29749
+ var vaultEgressTargetSchema = vaultEgressTargetSchemaDefinition;
29750
+ var VAULT_MAX_LEASE_SECONDS = 2 * 86400;
29751
+ var vaultConnectionSchemaDefinition = external_exports.object({
29752
+ id: external_exports.string().min(1),
29753
+ workspaceId: external_exports.string().min(1),
29754
+ name: vaultConnectionNameSchema,
29755
+ label: external_exports.string(),
29756
+ kind: vaultConnectionKindSchema,
29757
+ keychain: vaultKeychainSchema,
29758
+ sensitivity: vaultSensitivitySchema,
29759
+ /** Plain-language rules the judge reads: "Read only; never send mail." */
29760
+ rules: external_exports.string(),
29761
+ /** Who answers an ask on a workspace or agent keychain; a personal one asks its owner. */
29762
+ approverUserIds: external_exports.array(external_exports.string().min(1)),
29763
+ /** The longest lease an approver may give, set by an admin. */
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),
29767
+ fieldNames: external_exports.array(vaultFieldNameSchema),
29768
+ egress: vaultEgressTargetSchema.nullable(),
29769
+ status: vaultConnectionStatusSchema,
29770
+ /** Provider, account, scopes and expiry of an OAuth or MCP connection; null for API keys. */
29771
+ connector: vaultConnectorDetailsSchema.nullable(),
29772
+ /** Sealed to its owner's devices: the server cannot open it. */
29773
+ sealed: external_exports.boolean().default(false),
29774
+ /** False for a sealed connection no enrolled device can open any more. */
29775
+ openable: external_exports.boolean().default(true),
29776
+ createdByUserId: external_exports.string(),
29777
+ /** ISO 8601 */
29778
+ createdAt: external_exports.iso.datetime(),
29779
+ updatedAt: external_exports.iso.datetime()
29780
+ });
29781
+ var vaultConnectionSchema = vaultConnectionSchemaDefinition;
29782
+ var createVaultConnectionInputSchemaDefinition = external_exports.object({
29783
+ workspaceId: external_exports.string().min(1),
29784
+ name: vaultConnectionNameSchema,
29785
+ label: external_exports.string().trim().min(1).max(120),
29786
+ keychain: vaultKeychainSchema,
29787
+ sensitivity: vaultSensitivitySchema,
29788
+ rules: external_exports.string().max(2e3).default(""),
29789
+ approverUserIds: external_exports.array(external_exports.string().min(1)).default([]),
29790
+ maxLeaseSeconds: external_exports.number().int().positive().max(VAULT_MAX_LEASE_SECONDS).nullable().default(null),
29791
+ everyUseAsks: external_exports.boolean().default(false),
29792
+ secret: vaultSecretBundleSchema,
29793
+ egress: vaultEgressTargetSchema.nullable().default(null)
29794
+ });
29795
+ var createVaultConnectionInputSchema = createVaultConnectionInputSchemaDefinition;
29796
+ var updateVaultConnectionInputSchemaDefinition = external_exports.object({
29797
+ workspaceId: external_exports.string().min(1),
29798
+ connectionId: external_exports.string().min(1),
29799
+ label: external_exports.string().trim().min(1).max(120).optional(),
29800
+ sensitivity: vaultSensitivitySchema.optional(),
29801
+ rules: external_exports.string().max(2e3).optional(),
29802
+ approverUserIds: external_exports.array(external_exports.string().min(1)).optional(),
29803
+ maxLeaseSeconds: external_exports.number().int().positive().max(VAULT_MAX_LEASE_SECONDS).nullable().optional(),
29804
+ everyUseAsks: external_exports.boolean().optional(),
29805
+ secret: vaultSecretBundleSchema.optional(),
29806
+ egress: vaultEgressTargetSchema.nullable().optional()
29807
+ });
29808
+ var updateVaultConnectionInputSchema = updateVaultConnectionInputSchemaDefinition;
29809
+ var vaultGrantSubjectSchemaDefinition = external_exports.object({
29810
+ kind: external_exports.enum(["person", "group", "channel", "agent"]),
29811
+ id: external_exports.string().min(1)
29812
+ });
29813
+ var vaultGrantSubjectSchema = vaultGrantSubjectSchemaDefinition;
29814
+ var vaultGrantSchemaDefinition = external_exports.object({
29815
+ id: external_exports.string().min(1),
29816
+ connectionId: external_exports.string().min(1),
29817
+ subject: vaultGrantSubjectSchema,
29818
+ /** A lend: a personal connection opened to one channel's members through its owner's agent. */
29819
+ lend: external_exports.boolean(),
29820
+ grantedByUserId: external_exports.string(),
29821
+ expiresAt: external_exports.iso.datetime().nullable(),
29822
+ createdAt: external_exports.iso.datetime()
29823
+ });
29824
+ var vaultGrantSchema = vaultGrantSchemaDefinition;
29825
+ var grantVaultConnectionInputSchemaDefinition = external_exports.object({
29826
+ workspaceId: external_exports.string().min(1),
29827
+ connectionId: external_exports.string().min(1),
29828
+ subject: vaultGrantSubjectSchema,
29829
+ /** No end when null. */
29830
+ durationSeconds: external_exports.number().int().positive().nullable().default(null)
29831
+ });
29832
+ var grantVaultConnectionInputSchema = grantVaultConnectionInputSchemaDefinition;
29833
+ var lendVaultConnectionInputSchemaDefinition = external_exports.object({
29834
+ workspaceId: external_exports.string().min(1),
29835
+ connectionId: external_exports.string().min(1),
29836
+ channelId: external_exports.string().min(1),
29837
+ durationSeconds: external_exports.number().int().positive().nullable().default(null)
29838
+ });
29839
+ var lendVaultConnectionInputSchema = lendVaultConnectionInputSchemaDefinition;
29840
+ var vaultAgentKindSchema = external_exports.enum(["personal", "team"]);
29841
+ var openVaultTurnInputSchemaDefinition = external_exports.object({
29842
+ workspaceId: external_exports.string().min(1),
29843
+ agent: external_exports.object({
29844
+ id: external_exports.string().min(1),
29845
+ kind: vaultAgentKindSchema,
29846
+ ownerUserId: external_exports.string().min(1)
29847
+ }),
29848
+ requesterUserId: external_exports.string().min(1),
29849
+ requesterGroupIds: external_exports.array(external_exports.string().min(1)).default([]),
29850
+ channel: external_exports.object({ id: external_exports.string().min(1), kind: external_exports.enum(["public", "private", "dm"]) }),
29851
+ /** False when the requester can no longer see the channel (a schedule's creator who left). */
29852
+ requesterSeesChannel: external_exports.boolean().default(true),
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([])
29861
+ });
29862
+ var vaultAlwaysApprovalActionSchema = external_exports.enum([
29863
+ "send_external",
29864
+ "publish_app_public",
29865
+ "rent_compute_above_budget",
29866
+ "create_agent_with_workspace_access",
29867
+ "invite_people"
29868
+ ]);
29869
+ var VAULT_ALWAYS_APPROVAL_ACTIONS = vaultAlwaysApprovalActionSchema.options;
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;
29876
+ var vaultUseInputSchemaDefinition = external_exports.object({
29877
+ turnToken: external_exports.string().min(1),
29878
+ /** The connection's name as the agent asks for it, or its id. */
29879
+ connection: external_exports.string().min(1),
29880
+ purpose: vaultPurposeSchema.default("use"),
29881
+ reason: vaultReasonSchema,
29882
+ command: external_exports.array(external_exports.string()).default([]),
29883
+ /** OAuth scopes this use needs; a grant without them is refused with the missing ones. */
29884
+ requiredScopes: external_exports.array(external_exports.string().min(1)).default([]),
29885
+ /** A floor on the connection's sensitivity, for a tool its owner marked more guarded. */
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()
29893
+ });
29894
+ var vaultRunReleaseSchemaDefinition = external_exports.discriminatedUnion("outcome", [
29895
+ external_exports.object({
29896
+ outcome: external_exports.literal("allow"),
29897
+ env: external_exports.record(external_exports.string(), external_exports.string()),
29898
+ /** A sealed connection's values, encrypted to the run's own key. */
29899
+ sealed: vaultRunSealedReleaseSchema.optional(),
29900
+ /** What the approver told the agent, for the run to print. */
29901
+ message: external_exports.string().optional()
29902
+ }),
29903
+ external_exports.object({
29904
+ outcome: external_exports.literal("ask"),
29905
+ requestId: external_exports.string(),
29906
+ message: external_exports.string()
29907
+ }),
29908
+ external_exports.object({ outcome: external_exports.literal("deny"), exitCode: external_exports.number().int(), message: external_exports.string() })
29909
+ ]);
29910
+ var vaultEgressResolveInputSchemaDefinition = external_exports.object({
29911
+ agentId: external_exports.string().min(1),
29912
+ connectionId: external_exports.string().min(1),
29913
+ method: external_exports.string().default("GET"),
29914
+ host: external_exports.string().default(""),
29915
+ path: external_exports.string().default("/"),
29916
+ /** A floor the proxy sets for a guarded request, such as a git push asking before it goes. */
29917
+ atLeast: vaultSensitivitySchema.optional(),
29918
+ /** What the proxy knows the request is, such as "git push to github.com/acme/widgets". */
29919
+ reason: external_exports.string().max(300).optional()
29920
+ });
29921
+ var vaultEgressResolutionSchemaDefinition = external_exports.discriminatedUnion("decision", [
29922
+ external_exports.object({ decision: external_exports.literal("allow"), value: external_exports.string() }),
29923
+ external_exports.object({ decision: external_exports.literal("pending"), requestId: external_exports.string() }),
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
+ })
29930
+ ]);
29931
+ var vaultEgressReleaseInputSchemaDefinition = external_exports.object({
29932
+ agentId: external_exports.string().min(1),
29933
+ connection: external_exports.string().min(1),
29934
+ reason: external_exports.string(),
29935
+ command: external_exports.array(external_exports.string()).default([]),
29936
+ /** The run's P-256 public key, base64url; a sealed connection is released only to it. */
29937
+ recipient: external_exports.string().max(200).optional()
29938
+ });
29939
+ var vaultEgressStatusInputSchemaDefinition = external_exports.object({
29940
+ agentId: external_exports.string().min(1),
29941
+ requestId: external_exports.string().min(1)
29942
+ });
29943
+ var vaultApprovalStateSchema = external_exports.enum([
29944
+ "pending",
29945
+ "approved_once",
29946
+ "approved_for_agent",
29947
+ "denied",
29948
+ "expired"
29949
+ ]);
29950
+ var vaultAnswerViaSchema = external_exports.enum(["feed", "channel", "ios", "desktop", "web"]);
29951
+ var vaultApprovalRequestSchemaDefinition = external_exports.object({
29952
+ id: external_exports.string(),
29953
+ workspaceId: external_exports.string(),
29954
+ /** Null for an always-approval action that uses no connection. */
29955
+ connectionId: external_exports.string().nullable(),
29956
+ action: external_exports.string(),
29957
+ agentId: external_exports.string(),
29958
+ agentKind: vaultAgentKindSchema,
29959
+ requesterUserId: external_exports.string(),
29960
+ channelId: external_exports.string(),
29961
+ reason: external_exports.string(),
29962
+ command: external_exports.array(external_exports.string()),
29963
+ why: external_exports.string(),
29964
+ approverUserIds: external_exports.array(external_exports.string()),
29965
+ state: vaultApprovalStateSchema,
29966
+ /** How many asks joined this card. */
29967
+ joinCount: external_exports.number().int().positive(),
29968
+ createdAt: external_exports.iso.datetime(),
29969
+ expiresAt: external_exports.iso.datetime(),
29970
+ answeredByUserId: external_exports.string().nullable(),
29971
+ answeredVia: vaultAnswerViaSchema.nullable(),
29972
+ answeredAt: 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("")
29976
+ });
29977
+ var vaultApprovalRequestSchema = vaultApprovalRequestSchemaDefinition;
29978
+ var answerVaultApprovalInputSchemaDefinition = external_exports.object({
29979
+ workspaceId: external_exports.string().min(1),
29980
+ requestId: external_exports.string().min(1),
29981
+ answer: external_exports.enum(["approve_once", "approve_for_agent", "deny"]),
29982
+ /** Approve for this agent only: up to the connection's admin maximum. */
29983
+ durationSeconds: external_exports.number().int().positive().optional(),
29984
+ via: vaultAnswerViaSchema,
29985
+ /** A short reason, question or steer for the agent, sent with the answer. */
29986
+ resolutionNote: resolutionNoteSchema
29987
+ });
29988
+ var answerVaultApprovalInputSchema = answerVaultApprovalInputSchemaDefinition;
29989
+ var requestVaultActionInputSchemaDefinition = external_exports.object({
29990
+ turnToken: external_exports.string().min(1),
29991
+ action: vaultAlwaysApprovalActionSchema,
29992
+ reason: vaultReasonSchema,
29993
+ /** The people the owning module says decide; the requester when empty. */
29994
+ approverUserIds: external_exports.array(external_exports.string().min(1)).default([])
29995
+ });
29996
+ var vaultAuditEntrySchemaDefinition = external_exports.object({
29997
+ id: external_exports.string(),
29998
+ seq: external_exports.number().int().positive(),
29999
+ at: external_exports.iso.datetime(),
30000
+ actorKind: external_exports.enum(["user", "agent", "system"]),
30001
+ actorId: external_exports.string().nullable(),
30002
+ action: external_exports.string(),
30003
+ connectionId: external_exports.string().nullable(),
30004
+ outcome: external_exports.string(),
30005
+ decider: external_exports.string().nullable(),
30006
+ requesterUserId: external_exports.string().nullable(),
30007
+ agentId: external_exports.string().nullable(),
30008
+ channelId: external_exports.string().nullable(),
30009
+ requestId: external_exports.string().nullable(),
30010
+ reason: external_exports.string().nullable(),
30011
+ detail: external_exports.record(external_exports.string(), external_exports.unknown()),
30012
+ prevHash: external_exports.string(),
30013
+ hash: external_exports.string()
30014
+ });
30015
+ var vaultAuditEntrySchema = vaultAuditEntrySchemaDefinition;
30016
+ var vaultAuditPageSchemaDefinition = external_exports.object({
30017
+ entries: external_exports.array(vaultAuditEntrySchema),
30018
+ /** The chain re-hashed: when broken, the first entry that does not follow from the last. */
30019
+ chain: external_exports.object({ intact: external_exports.boolean(), brokenAtSeq: external_exports.number().int().nullable() })
30020
+ });
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;
30056
+ var vaultConnectionUseSchemaDefinition = external_exports.object({
30057
+ at: external_exports.iso.datetime(),
30058
+ action: external_exports.string(),
30059
+ outcome: external_exports.string(),
30060
+ agentId: external_exports.string().nullable(),
30061
+ requesterUserId: external_exports.string().nullable(),
30062
+ channelId: external_exports.string().nullable(),
30063
+ reason: external_exports.string().nullable(),
30064
+ /** The command or tool, as the use named it. */
30065
+ command: external_exports.array(external_exports.string())
30066
+ });
30067
+ var vaultConnectionUseSchema = vaultConnectionUseSchemaDefinition;
30068
+ var vaultRevokeAtProviderSchema = external_exports.enum(["revoked", "failed", "not_supported"]);
30069
+ var saveGithubInstallationInputSchemaDefinition = external_exports.object({
30070
+ workspaceId: external_exports.string().min(1),
30071
+ installationId: external_exports.string().regex(/^\d{1,20}$/),
30072
+ account: external_exports.string().min(1).max(100),
30073
+ name: external_exports.string().min(1).max(64),
30074
+ label: external_exports.string().min(1).max(200),
30075
+ approverUserIds: external_exports.array(external_exports.string()).default([]),
30076
+ /** The connection to point at this installation again, after a reinstall. */
30077
+ connectionId: external_exports.string().optional()
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;
30095
+ var VaultApi = moduleApi()("vault");
30096
+ var workspaceInput = external_exports.object({ workspaceId: external_exports.string().min(1) });
30097
+ var connectionInput = external_exports.object({
30098
+ workspaceId: external_exports.string().min(1),
30099
+ connectionId: external_exports.string().min(1)
30100
+ });
30101
+ var vaultTrpc = defineTrpcContract("vault").mutation("createConnection").withInput(createVaultConnectionInputSchema).withOutput(vaultConnectionSchema).query("listConnections").withInput(workspaceInput).withOutput(external_exports.array(vaultConnectionSchema)).mutation("updateConnection").withInput(updateVaultConnectionInputSchema).withOutput(vaultConnectionSchema).mutation("deleteConnection").withInput(connectionInput).withOutput(external_exports.object({ deleted: external_exports.literal(true) })).mutation("revokeConnection").withInput(connectionInput).withOutput(external_exports.object({ atProvider: vaultRevokeAtProviderSchema })).query("listConnectionUses").withInput(
30102
+ external_exports.object({ ...connectionInput.shape, limit: external_exports.number().int().min(1).max(200).optional() })
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(
30104
+ external_exports.object({ ...workspaceInput.shape, limit: external_exports.number().int().min(1).max(500).optional() })
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();
30106
+
30107
+ // ../../modules/vault/contract/src/vault.config.ts
30108
+ var positiveInt = external_exports.coerce.number().int().positive();
30109
+ var vaultConfig = Config.define((c) => ({
30110
+ approvalTimeoutMinutes: c.env("VAULT_APPROVAL_TIMEOUT_MINUTES", positiveInt.default(720)),
30111
+ /** How long an approve-once answer waits for the same ask to come back for it. */
30112
+ approveOnceWindowMinutes: c.env("VAULT_APPROVE_ONCE_WINDOW_MINUTES", positiveInt.default(10)),
30113
+ /** The lease cap when an admin set none on the connection. */
30114
+ defaultMaxLeaseHours: c.env("VAULT_DEFAULT_MAX_LEASE_HOURS", positiveInt.default(48)),
30115
+ turnTtlMinutes: c.env("VAULT_TURN_TTL_MINUTES", positiveInt.default(720)),
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
+ ),
30124
+ /** How long after a process starts it still accepts turn tokens signed under the previous key. */
30125
+ previousKeyGraceMinutes: c.env(
30126
+ "VAULT_PREVIOUS_KEY_GRACE_MINUTES",
30127
+ external_exports.coerce.number().int().min(0).default(30)
30128
+ ),
30129
+ /** The origin passkeys are made on; unset accepts any localhost origin, for development. */
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())
30133
+ }));
30134
+
30135
+ // ../../modules/vault/contract/src/vault.errors.ts
30136
+ var VaultSealMismatchError = class extends HandledError {
30137
+ constructor() {
30138
+ super("vault_seal_mismatch", "This sealed value does not belong to the secret it names", {
30139
+ httpStatus: 422
30140
+ });
30141
+ this.name = "VaultSealMismatchError";
30142
+ }
30143
+ };
30144
+
30145
+ // ../../modules/vault/contract/src/vault.events.ts
30146
+ var vaultApprovalRequestedPayloadSchemaDefinition = external_exports.object({
30147
+ workspaceId: external_exports.string().min(1),
30148
+ requestId: external_exports.string().min(1),
30149
+ connectionId: external_exports.string().nullable(),
30150
+ connectionLabel: external_exports.string().nullable(),
30151
+ action: external_exports.string(),
30152
+ agentId: external_exports.string(),
30153
+ requesterUserId: external_exports.string(),
30154
+ channelId: external_exports.string(),
30155
+ approverUserIds: external_exports.array(external_exports.string()),
30156
+ reason: external_exports.string(),
30157
+ why: external_exports.string(),
30158
+ /** The longest lease the card may offer; null offers only once and deny. */
30159
+ maxLeaseSeconds: external_exports.number().int().positive().nullable(),
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)
30174
+ });
30175
+ var vaultApprovalResolvedPayloadSchemaDefinition = external_exports.object({
30176
+ workspaceId: external_exports.string().min(1),
30177
+ requestId: external_exports.string().min(1),
30178
+ state: external_exports.enum(["approved_once", "approved_for_agent", "denied", "expired"]),
30179
+ answeredByUserId: external_exports.string().nullable(),
30180
+ answeredVia: external_exports.string().nullable(),
30181
+ leaseExpiresAt: external_exports.iso.datetime().nullable(),
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)
30192
+ });
30193
+
30194
+ // ../../modules/vault/contract/src/vault-oauth.ts
30195
+ var tokenFieldsSchema = external_exports.object({
30196
+ access_token: external_exports.string().min(1).optional(),
30197
+ refresh_token: external_exports.string().min(1).optional(),
30198
+ expires_in: external_exports.coerce.number().positive().optional(),
30199
+ scope: external_exports.string().optional(),
30200
+ token_type: external_exports.string().optional()
30201
+ });
30202
+ var oauthTokenResponseSchemaDefinition = external_exports.object({
30203
+ ...tokenFieldsSchema.shape,
30204
+ ok: external_exports.boolean().optional(),
30205
+ error: external_exports.string().optional(),
30206
+ error_description: external_exports.string().optional(),
30207
+ authed_user: tokenFieldsSchema.optional()
30208
+ });
30209
+
30210
+ // ../../modules/vault/contract/src/sealing.ts
30211
+ var subtle = () => globalThis.crypto.subtle;
30212
+ var IV_BYTES = 12;
30213
+ var P256 = { name: "ECDH", namedCurve: "P-256" };
30214
+ var text = new TextEncoder();
30215
+ function toBase64Url(bytes) {
30216
+ let binary = "";
30217
+ for (const byte of bytes) binary += String.fromCharCode(byte);
30218
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
30219
+ }
30220
+ function fromBase64Url(value) {
30221
+ const binary = atob(value.replaceAll("-", "+").replaceAll("_", "/"));
30222
+ const bytes = new Uint8Array(binary.length);
30223
+ for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
30224
+ return bytes;
30225
+ }
30226
+ var concat = (...parts) => {
30227
+ const out = new Uint8Array(parts.reduce((sum, part) => sum + part.length, 0));
30228
+ let offset = 0;
30229
+ for (const part of parts) {
30230
+ out.set(part, offset);
30231
+ offset += part.length;
30232
+ }
30233
+ return out;
30234
+ };
30235
+ async function hkdfKey(input2) {
30236
+ const base = await subtle().importKey("raw", input2.ikm, "HKDF", false, ["deriveKey"]);
30237
+ return subtle().deriveKey(
30238
+ { name: "HKDF", hash: "SHA-256", salt: input2.salt, info: text.encode(input2.info) },
30239
+ base,
30240
+ { name: "AES-GCM", length: 256 },
30241
+ false,
30242
+ ["encrypt", "decrypt"]
30243
+ );
30244
+ }
30245
+ async function gcmOpen(input2) {
30246
+ try {
30247
+ const plain = await subtle().decrypt(
30248
+ {
30249
+ name: "AES-GCM",
30250
+ iv: input2.sealed.subarray(0, IV_BYTES),
30251
+ additionalData: text.encode(input2.aad)
30252
+ },
30253
+ input2.key,
30254
+ input2.sealed.subarray(IV_BYTES)
30255
+ );
30256
+ return new Uint8Array(plain);
30257
+ } catch {
30258
+ throw new VaultSealMismatchError();
30259
+ }
30260
+ }
30261
+ var importPublic = (raw) => subtle().importKey("raw", raw, P256, true, []);
30262
+ async function sharedSecret(input2) {
30263
+ const bits = await subtle().deriveBits(
30264
+ { name: "ECDH", public: await importPublic(input2.publicKey) },
30265
+ input2.privateKey,
30266
+ 256
30267
+ );
30268
+ return new Uint8Array(bits);
30269
+ }
30270
+ function agreementOf(privateKey) {
30271
+ return (publicKey) => sharedSecret({ privateKey, publicKey });
30272
+ }
30273
+ async function decryptFrom(input2) {
30274
+ const epk = fromBase64Url(input2.epk);
30275
+ const ikm = await input2.agree(epk);
30276
+ const key = await hkdfKey({ ikm, salt: concat(epk, input2.publicKey), info: input2.info });
30277
+ return gcmOpen({ key, sealed: fromBase64Url(input2.sealed), aad: input2.aad });
30278
+ }
30279
+ async function generateEcdhKeys() {
30280
+ const pair = await subtle().generateKey(P256, true, ["deriveBits"]);
30281
+ const raw = new Uint8Array(await subtle().exportKey("raw", pair.publicKey));
30282
+ return { publicKey: toBase64Url(raw), privateKey: pair.privateKey };
30283
+ }
30284
+ function fieldsOf(value) {
30285
+ if (typeof value !== "object" || value === null) throw new VaultSealMismatchError();
30286
+ const entries = Object.entries(value);
30287
+ if (entries.some(([, field]) => typeof field !== "string")) throw new VaultSealMismatchError();
30288
+ return Object.fromEntries(entries);
30289
+ }
30290
+ var releaseLabel = (requestId) => `laze-vault/release/v1/${requestId}`;
30291
+ async function openRunRelease(input2) {
30292
+ const plain = await decryptFrom({
30293
+ agree: agreementOf(input2.runPrivateKey),
30294
+ publicKey: fromBase64Url(input2.runPublicKey),
30295
+ epk: input2.release.epk,
30296
+ sealed: input2.release.ciphertext,
30297
+ info: releaseLabel(input2.requestId),
30298
+ aad: releaseLabel(input2.requestId)
30299
+ });
30300
+ return fieldsOf(JSON.parse(new TextDecoder().decode(plain)).fields);
30301
+ }
30302
+
30303
+ // src/services/vault-commands.service.ts
30304
+ var USAGE7 = `Usage: laze vault run <connection> --reason "<one plain sentence>" [--wait <s>] -- <command> [args...]
28746
30305
  Runs the command with the connection's values in its environment, inside a Laze agent's sandbox.`;
28747
30306
  var POLL_MS = 3e3;
28748
- var DEFAULT_WAIT_SECONDS = 120;
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
+ };
28749
30312
  function proxyOf({ env }) {
28750
30313
  const raw = env.HTTP_PROXY ?? env.http_proxy;
28751
30314
  if (!raw) throw new CliUsageError("laze vault run works only inside a Laze agent's sandbox");
@@ -28757,44 +30320,152 @@ function proxyOf({ env }) {
28757
30320
  authorization: `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`
28758
30321
  };
28759
30322
  }
28760
- async function turnTokenOf({
30323
+ function turnFileOf({
28761
30324
  env
28762
30325
  }) {
28763
- const path = env.LAZE_TURN_FILE;
28764
- if (!path) throw new CliUsageError("laze vault run works only during an agent's turn");
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");
28765
30335
  try {
28766
- return (await readFile9(path, "utf8")).trim();
30336
+ return (await readFile11(turnFile, "utf8")).trim();
28767
30337
  } catch {
28768
30338
  throw new CliUsageError("laze vault run works only during an agent's turn");
28769
30339
  }
28770
30340
  }
28771
- async function askRelease({
28772
- context,
28773
- connection,
28774
- reason,
28775
- command
30341
+ function runKeyPathOf({
30342
+ turnFile,
30343
+ connection
28776
30344
  }) {
28777
- const env = context.environment.inherited;
28778
- const proxy = proxyOf({ env });
28779
- const response = await context.fetcher(`${proxy.origin}/vault/release`, {
28780
- method: "POST",
28781
- headers: {
28782
- "content-type": "application/json",
28783
- "proxy-authorization": proxy.authorization,
28784
- "x-laze-turn": await turnTokenOf({ env })
28785
- },
28786
- body: JSON.stringify({ connection, reason, command })
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
28787
30363
  });
28788
- const text = await response.text();
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 }) {
30414
+ const text2 = await response.text();
28789
30415
  if (!response.ok) {
28790
- const code = /"code"\s*:\s*"([^"]+)"/.exec(text)?.[1] ?? `status ${response.status}`;
28791
30416
  return {
28792
30417
  outcome: "deny",
28793
30418
  exitCode: 1,
28794
- message: `laze vault: the release was refused (${code})`
30419
+ message: `laze vault: the release was refused (${codeOf(text2) ?? `status ${response.status}`})`
28795
30420
  };
28796
30421
  }
28797
- return JSON.parse(text);
30422
+ return JSON.parse(text2);
30423
+ }
30424
+ async function envOf({
30425
+ release,
30426
+ run
30427
+ }) {
30428
+ if (!release.sealed) return release.env;
30429
+ const sealed = await openRunRelease({
30430
+ release: release.sealed,
30431
+ runPrivateKey: run.privateKey,
30432
+ runPublicKey: run.publicKey,
30433
+ requestId: release.sealed.requestId
30434
+ });
30435
+ return { ...release.env, ...sealed };
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;
28798
30469
  }
28799
30470
  async function vaultRun({
28800
30471
  context,
@@ -28802,36 +30473,52 @@ async function vaultRun({
28802
30473
  }) {
28803
30474
  const connection = args.words[2];
28804
30475
  const reason = flagText({ args, name: "reason" });
28805
- if (!connection || args.rest.length === 0) throw new CliUsageError(USAGE6);
30476
+ if (!connection || args.rest.length === 0) throw new CliUsageError(USAGE7);
28806
30477
  if (!reason) throw new CliUsageError(`Say why with --reason "<one plain sentence>"
28807
- ${USAGE6}`);
28808
- const waitSeconds = Number(flagText({ args, name: "wait", fallback: `${DEFAULT_WAIT_SECONDS}` }));
28809
- const deadline = context.nowMs() + Math.max(0, waitSeconds) * 1e3;
28810
- let told = false;
28811
- for (; ; ) {
28812
- const release = await askRelease({ context, connection, reason, command: args.rest });
28813
- if (release.outcome === "allow") {
28814
- return context.runCommand({ command: args.rest, env: release.env });
28815
- }
28816
- if (release.outcome === "deny") {
28817
- context.err(`${release.message}
28818
- `);
28819
- return release.exitCode || 1;
28820
- }
28821
- if (context.nowMs() + POLL_MS > deadline) {
28822
- context.err(`${release.message}. Not approved yet; ask again later.
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
+ })
30498
+ });
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.
28823
30503
  `);
28824
- return 75;
28825
- }
28826
- if (!told) context.err(`${release.message}...
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}
28827
30510
  `);
28828
- told = true;
28829
- await context.sleep(POLL_MS);
30511
+ return release.exitCode || 1;
28830
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 });
28831
30518
  }
28832
30519
 
28833
30520
  // src/services/wiki-commands.service.ts
28834
- var USAGE7 = `Usage:
30521
+ var USAGE8 = `Usage:
28835
30522
  laze wiki list
28836
30523
  laze wiki get <path>
28837
30524
  laze wiki put <path> <markdown|@file|-> [--title <title>] [--channel <channel>] [--base <version>]
@@ -28848,7 +30535,7 @@ async function wikiList({ context, args }) {
28848
30535
  }
28849
30536
  async function wikiGet({ context, args }) {
28850
30537
  const path = args.words[2];
28851
- if (!path) throw new CliUsageError(USAGE7);
30538
+ if (!path) throw new CliUsageError(USAGE8);
28852
30539
  const { client } = await signedIn({ context, args });
28853
30540
  const page = await client.post("/api/wiki/get", { path });
28854
30541
  if (args.flags.json) return context.out(`${JSON.stringify(page, null, 2)}
@@ -28865,7 +30552,7 @@ Linked from: ${page.backlinks.map((link) => link.path).join(", ")}
28865
30552
  async function wikiPut({ context, args }) {
28866
30553
  const path = args.words[2];
28867
30554
  const value = args.words.slice(3).join(" ");
28868
- if (!path || !value) throw new CliUsageError(USAGE7);
30555
+ if (!path || !value) throw new CliUsageError(USAGE8);
28869
30556
  const body = await textArgument({ context, value });
28870
30557
  const title = flagText({ args, name: "title" });
28871
30558
  const channel = flagText({ args, name: "channel" });
@@ -28885,7 +30572,7 @@ async function wikiPut({ context, args }) {
28885
30572
  }
28886
30573
  async function wikiSearch({ context, args }) {
28887
30574
  const query = args.words.slice(2).join(" ").trim();
28888
- if (!query) throw new CliUsageError(USAGE7);
30575
+ if (!query) throw new CliUsageError(USAGE8);
28889
30576
  const { client } = await signedIn({ context, args });
28890
30577
  const hits = await client.post("/api/wiki/search", { query });
28891
30578
  if (args.flags.json) return context.out(`${JSON.stringify(hits, null, 2)}
@@ -28895,9 +30582,9 @@ async function wikiSearch({ context, args }) {
28895
30582
  }
28896
30583
  var WIKI_COMMANDS = { list: wikiList, get: wikiGet, put: wikiPut, search: wikiSearch };
28897
30584
  async function wiki({ context, args }) {
28898
- const name = args.words[1] ?? "";
28899
- const command = Object.hasOwn(WIKI_COMMANDS, name) ? WIKI_COMMANDS[name] : void 0;
28900
- if (!command) throw new CliUsageError(USAGE7);
30585
+ const name2 = args.words[1] ?? "";
30586
+ const command = Object.hasOwn(WIKI_COMMANDS, name2) ? WIKI_COMMANDS[name2] : void 0;
30587
+ if (!command) throw new CliUsageError(USAGE8);
28901
30588
  await command({ context, args });
28902
30589
  }
28903
30590
 
@@ -28906,6 +30593,7 @@ var HELP = `laze: work in a Laze workspace from your terminal or your agent.
28906
30593
 
28907
30594
  laze login [--url <server>] [--token lz_...] sign in (opens a browser code)
28908
30595
  laze --version the version of this CLI
30596
+ laze update [--dry-run] install the latest release (npm, pnpm, bun or yarn)
28909
30597
  laze logout forget this profile
28910
30598
  laze whoami who this key speaks for
28911
30599
  laze workspaces your signed-in profiles
@@ -28926,6 +30614,8 @@ var HELP = `laze: work in a Laze workspace from your terminal or your agent.
28926
30614
  laze agent link --token <token> connect this Claude Code or Codex session
28927
30615
  laze adopt codex [--thread <id>] answer Laze messages in a Codex thread
28928
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
28929
30619
  laze github whoami | watch <owner/repo> | unwatch | watches the agent's GitHub identity and watches
28930
30620
  laze agent set-github <agent> <connection|none> [--ask-before-push] pick an agent's GitHub
28931
30621
  laze mcp the same as an MCP server on stdio
@@ -28938,6 +30628,7 @@ var COMMANDS = {
28938
30628
  logout,
28939
30629
  whoami,
28940
30630
  workspaces,
30631
+ update,
28941
30632
  "channels list": listChannels,
28942
30633
  channels: listChannels,
28943
30634
  post,
@@ -28948,6 +30639,7 @@ var COMMANDS = {
28948
30639
  agents: listAgents,
28949
30640
  "agent link": linkAgent,
28950
30641
  "hook stop": stopHook,
30642
+ "hook pre-tool": preToolHook,
28951
30643
  adopt: adoptCodex,
28952
30644
  feed,
28953
30645
  schedule,
@@ -28956,6 +30648,7 @@ var COMMANDS = {
28956
30648
  skill,
28957
30649
  app,
28958
30650
  "vault run": vaultRun,
30651
+ browser,
28959
30652
  github,
28960
30653
  "agent set-github": setAgentGithub,
28961
30654
  "mcp gateway": serveMcpGateway,
@@ -28993,21 +30686,27 @@ async function runCli({
28993
30686
  }
28994
30687
 
28995
30688
  // src/main.ts
28996
- function runCommand({
30689
+ async function runCommand({
28997
30690
  command,
28998
30691
  inherited,
28999
- env
30692
+ env,
30693
+ stdout = process.stdout,
30694
+ stderr = process.stderr
29000
30695
  }) {
29001
30696
  const [program = "", ...rest] = command;
29002
- return new Promise((resolve6) => {
29003
- const child = spawn2(program, rest, { stdio: "inherit", env: { ...inherited, ...env } });
29004
- child.on("error", (error62) => {
29005
- process.stderr.write(`laze vault: ${error62.message}
29006
- `);
29007
- resolve6(127);
30697
+ try {
30698
+ return await runRedacted({
30699
+ command: [program, ...rest],
30700
+ env,
30701
+ baseEnv: inherited,
30702
+ stdout,
30703
+ stderr
29008
30704
  });
29009
- child.on("exit", (code, signal) => resolve6(code ?? (signal ? 128 : 1)));
29010
- });
30705
+ } catch (error62) {
30706
+ stderr.write(`laze vault: ${error62 instanceof Error ? error62.message : String(error62)}
30707
+ `);
30708
+ return 127;
30709
+ }
29011
30710
  }
29012
30711
  async function readStdin() {
29013
30712
  if (stdin.isTTY) return "";
@@ -29015,6 +30714,20 @@ async function readStdin() {
29015
30714
  for await (const chunk of stdin) chunks.push(chunk);
29016
30715
  return Buffer.concat(chunks).toString("utf8");
29017
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
+ }
29018
30731
  if (true) {
29019
30732
  const environment = cliEnvironment();
29020
30733
  process.exitCode = await runCli({
@@ -29025,12 +30738,15 @@ if (true) {
29025
30738
  program: [process.execPath, ...process.execArgv, process.argv[1] ?? ""],
29026
30739
  store: ConfigStore.create({ path: environment.configPath }),
29027
30740
  fetcher: (input2, init) => fetch(input2, init),
29028
- out: (text) => void process.stdout.write(text),
29029
- err: (text) => void process.stderr.write(text),
30741
+ out: (text2) => void process.stdout.write(text2),
30742
+ err: (text2) => void process.stderr.write(text2),
29030
30743
  readStdin,
29031
- sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
30744
+ sleep,
29032
30745
  nowMs: () => nowInstant().epochMilliseconds,
29033
30746
  runCommand: (input2) => runCommand({ ...input2, inherited: environment.inherited })
29034
30747
  }
29035
30748
  });
29036
30749
  }
30750
+ export {
30751
+ runCommand
30752
+ };