@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.
- package/README.md +9 -5
- package/dist/laze.mjs +2094 -378
- 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
|
|
5
|
-
__defProp(target,
|
|
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 = (
|
|
335
|
+
var invalidEntity = (fieldName3, val) => `Invalid ${fieldName3}: ${val}`;
|
|
22
336
|
|
|
23
337
|
// ../../node_modules/.pnpm/temporal-utils@1.0.2/node_modules/temporal-utils/dist/utils.js
|
|
24
338
|
var nanoInMicro = 1e3;
|
|
@@ -69,10 +383,10 @@ function requireObjectLike(arg) {
|
|
|
69
383
|
|
|
70
384
|
// ../../node_modules/.pnpm/temporal-polyfill@1.0.4/node_modules/temporal-polyfill/chunks/internal.js
|
|
71
385
|
var invalidEntity2 = invalidEntity;
|
|
72
|
-
var missingField = (
|
|
386
|
+
var missingField = (fieldName3) => `Missing ${fieldName3}`;
|
|
73
387
|
var noValidFields = (validFields) => "No valid fields: " + validFields.join();
|
|
74
388
|
var invalidBag = "Invalid bag";
|
|
75
|
-
var invalidChoice = (
|
|
389
|
+
var invalidChoice = (fieldName3, val, choiceMap) => invalidEntity(fieldName3, val) + "; must be " + Object.keys(choiceMap).join();
|
|
76
390
|
var forbiddenValueOf = "Cannot use valueOf";
|
|
77
391
|
var invalidCallingContext = "Invalid calling context";
|
|
78
392
|
var missingYear = (allowEra) => "Missing year" + (allowEra ? "/era/eraYear" : "");
|
|
@@ -111,8 +425,8 @@ function memoize(generator, MapClass = Map) {
|
|
|
111
425
|
return map2.set(key, val), val;
|
|
112
426
|
};
|
|
113
427
|
}
|
|
114
|
-
var createNameDescriptors = (
|
|
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
|
|
328
|
-
constrainedFields[
|
|
641
|
+
for (const fieldName3 of timeFieldNamesAsc) {
|
|
642
|
+
constrainedFields[fieldName3] = clampEntity(fieldName3, timeFields[fieldName3], 0, maxValues[fieldName3] || 999, overflow);
|
|
329
643
|
}
|
|
330
644
|
return constrainedFields;
|
|
331
645
|
}
|
|
@@ -1479,15 +1793,15 @@ function negateDuration(slots) {
|
|
|
1479
1793
|
}
|
|
1480
1794
|
function negateDurationFields(fields) {
|
|
1481
1795
|
const res = {};
|
|
1482
|
-
for (const
|
|
1483
|
-
res[
|
|
1796
|
+
for (const fieldName3 of durationFieldNamesAsc) {
|
|
1797
|
+
res[fieldName3] = -1 * fields[fieldName3] || 0;
|
|
1484
1798
|
}
|
|
1485
1799
|
return res;
|
|
1486
1800
|
}
|
|
1487
1801
|
function computeDurationSign(fields, fieldNames = durationFieldNamesAsc) {
|
|
1488
1802
|
let sign = 0;
|
|
1489
|
-
for (const
|
|
1490
|
-
const fieldSign = Math.sign(fields[
|
|
1803
|
+
for (const fieldName3 of fieldNames) {
|
|
1804
|
+
const fieldSign = Math.sign(fields[fieldName3]);
|
|
1491
1805
|
fieldSign && (sign && sign !== fieldSign && throwRangeError("Cannot mix duration signs"), sign = fieldSign);
|
|
1492
1806
|
}
|
|
1493
1807
|
return sign;
|
|
@@ -1675,14 +1989,14 @@ var zonedDateTimeFieldRefiners = {
|
|
|
1675
1989
|
function readAndRefineBagFields(bag, validFieldNames, fieldRefiners, requiredFieldNames, disallowEmpty = !requiredFieldNames) {
|
|
1676
1990
|
const res = {};
|
|
1677
1991
|
let anyMatching = 0;
|
|
1678
|
-
for (const
|
|
1679
|
-
let fieldVal = bag[
|
|
1992
|
+
for (const fieldName3 of validFieldNames) {
|
|
1993
|
+
let fieldVal = bag[fieldName3];
|
|
1680
1994
|
if (void 0 !== fieldVal) {
|
|
1681
1995
|
anyMatching = 1;
|
|
1682
|
-
const refiner = fieldRefiners[
|
|
1683
|
-
refiner && (fieldVal = refiner(fieldVal,
|
|
1996
|
+
const refiner = fieldRefiners[fieldName3];
|
|
1997
|
+
refiner && (fieldVal = refiner(fieldVal, fieldName3)), res[fieldName3] = fieldVal;
|
|
1684
1998
|
} else {
|
|
1685
|
-
requiredFieldNames && requiredFieldNames.includes(
|
|
1999
|
+
requiredFieldNames && requiredFieldNames.includes(fieldName3) && throwTypeError(missingField(fieldName3));
|
|
1686
2000
|
}
|
|
1687
2001
|
}
|
|
1688
2002
|
return disallowEmpty && !anyMatching && throwTypeError(noValidFields(validFieldNames)), res;
|
|
@@ -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,
|
|
2396
|
-
return
|
|
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
|
|
2587
|
-
const value = options[
|
|
2588
|
-
void 0 === value || ignoredFieldNameSet.has(
|
|
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((
|
|
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 ??
|
|
3806
|
-
profiles: { ...config2.profiles, [
|
|
3807
|
-
bindings: bindDirectory ? { ...config2.bindings, [resolve(bindDirectory)]:
|
|
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[
|
|
4126
|
+
if (!config2.profiles[name2]) return false;
|
|
3813
4127
|
const profiles = Object.fromEntries(
|
|
3814
|
-
Object.entries(config2.profiles).filter(([key]) => key !==
|
|
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 !==
|
|
4131
|
+
Object.entries(config2.bindings).filter(([, bound]) => bound !== name2)
|
|
3818
4132
|
);
|
|
3819
|
-
const current = 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
|
|
3832
|
-
const profile =
|
|
3833
|
-
return
|
|
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 = (
|
|
3867
|
-
flags[
|
|
3868
|
-
lists[
|
|
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 [
|
|
4192
|
+
const [name2 = "", inline] = arg.slice(2).split(/=(.*)/s, 2);
|
|
3878
4193
|
const next = argv[index + 1];
|
|
3879
|
-
if (inline !== void 0) remember(
|
|
3880
|
-
else if (SWITCHES.has(
|
|
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(
|
|
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[
|
|
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.
|
|
4213
|
+
var STAMPED = "0.1.3";
|
|
3899
4214
|
function cliVersionOf({ stamped = STAMPED } = {}) {
|
|
3900
4215
|
return stamped.startsWith("__") ? "dev" : stamped;
|
|
3901
4216
|
}
|
|
3902
4217
|
|
|
3903
4218
|
// src/services/agent-commands.service.ts
|
|
3904
|
-
import { mkdir as
|
|
3905
|
-
import { join as
|
|
4219
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
4220
|
+
import { join as join3 } from "node:path";
|
|
3906
4221
|
|
|
3907
4222
|
// src/rules/cli-invocation.rules.ts
|
|
3908
4223
|
var NPX_CACHE = /[\\/]_npx[\\/]/;
|
|
4224
|
+
var SANDBOX_CLI_PATH = "/opt/laze/laze.mjs";
|
|
3909
4225
|
function lazeCommandOf({ program }) {
|
|
3910
4226
|
const script = program.at(-1) ?? "";
|
|
3911
4227
|
if (!NPX_CACHE.test(script)) return "laze";
|
|
@@ -3914,24 +4230,35 @@ function lazeCommandOf({ program }) {
|
|
|
3914
4230
|
|
|
3915
4231
|
// src/rules/hook-settings.rules.ts
|
|
3916
4232
|
var LAZE_HOOK_MARKER = "laze-cli-hook";
|
|
3917
|
-
|
|
3918
|
-
|
|
4233
|
+
var TIMEOUTS = { Stop: 30, PreToolUse: 5 };
|
|
4234
|
+
function withHook({
|
|
4235
|
+
hooks,
|
|
4236
|
+
event,
|
|
3919
4237
|
command
|
|
3920
4238
|
}) {
|
|
3921
|
-
const
|
|
3922
|
-
const
|
|
3923
|
-
const others = stop.filter(
|
|
4239
|
+
const current = Array.isArray(hooks[event]) ? hooks[event] : [];
|
|
4240
|
+
const others = current.filter(
|
|
3924
4241
|
(entry) => !entry.hooks?.some((hook) => hook.command?.includes(LAZE_HOOK_MARKER))
|
|
3925
4242
|
);
|
|
3926
|
-
hooks
|
|
4243
|
+
hooks[event] = [...others, { hooks: [{ type: "command", command, timeout: TIMEOUTS[event] }] }];
|
|
4244
|
+
}
|
|
4245
|
+
function withLazeHooks({
|
|
4246
|
+
settings,
|
|
4247
|
+
stopCommand,
|
|
4248
|
+
preToolCommand
|
|
4249
|
+
}) {
|
|
4250
|
+
const hooks = { ...settings.hooks };
|
|
4251
|
+
withHook({ hooks, event: "Stop", command: stopCommand });
|
|
4252
|
+
withHook({ hooks, event: "PreToolUse", command: preToolCommand });
|
|
3927
4253
|
return { ...settings, hooks };
|
|
3928
4254
|
}
|
|
3929
|
-
function
|
|
4255
|
+
function hookCommand({
|
|
3930
4256
|
program,
|
|
3931
|
-
profile
|
|
4257
|
+
profile,
|
|
4258
|
+
hook
|
|
3932
4259
|
}) {
|
|
3933
4260
|
const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
3934
|
-
const words = [...program, "hook",
|
|
4261
|
+
const words = [...program, "hook", hook, "--profile", profile].map(quote).join(" ");
|
|
3935
4262
|
return `${words} # ${LAZE_HOOK_MARKER}`;
|
|
3936
4263
|
}
|
|
3937
4264
|
|
|
@@ -4023,19 +4350,16 @@ function readTranscript({ lines }) {
|
|
|
4023
4350
|
return { contextTokens, contextWindow, compactions };
|
|
4024
4351
|
}
|
|
4025
4352
|
|
|
4026
|
-
// src/services/
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
super(message);
|
|
4030
|
-
this.name = "CliUsageError";
|
|
4031
|
-
}
|
|
4032
|
-
};
|
|
4353
|
+
// src/services/claude-turn.service.ts
|
|
4354
|
+
import { mkdir as mkdir2, readFile as readFile2, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
4355
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
4033
4356
|
|
|
4034
4357
|
// src/services/laze-client.service.ts
|
|
4358
|
+
var CLI_VERSION_HEADER = "x-laze-cli-version";
|
|
4035
4359
|
var LazeApiError = class extends Error {
|
|
4036
|
-
constructor(
|
|
4360
|
+
constructor(status2, code, message) {
|
|
4037
4361
|
super(message);
|
|
4038
|
-
this.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(
|
|
4047
|
-
this.
|
|
4048
|
-
|
|
4049
|
-
|
|
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 = {
|
|
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
|
|
4081
|
-
const parsed =
|
|
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_${
|
|
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 ${
|
|
4092
|
-
return new LazeApiError(
|
|
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
|
|
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} ${
|
|
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
|
|
4146
|
-
if (!
|
|
4147
|
-
return
|
|
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(
|
|
4240
|
-
return
|
|
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 =
|
|
4244
|
-
const path =
|
|
4245
|
-
const current = await
|
|
4246
|
-
(
|
|
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
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
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
|
|
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:
|
|
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 "${
|
|
4303
|
-
...hookPath ? [`Added the Laze
|
|
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:
|
|
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
|
|
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
|
|
4352
|
-
import { join as
|
|
4771
|
+
import { mkdir as mkdir4, readdir, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
|
|
4772
|
+
import { join as join4, relative, resolve as resolve2, sep } from "node:path";
|
|
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(
|
|
4419
|
-
this.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(
|
|
4425
|
-
super(
|
|
4847
|
+
constructor(name2) {
|
|
4848
|
+
super(name2);
|
|
4426
4849
|
}
|
|
4427
|
-
static create(
|
|
4428
|
-
publicNamespaceFromUnknown(
|
|
4429
|
-
const token = new _ModuleApiToken(
|
|
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(
|
|
4435
|
-
if (
|
|
4857
|
+
function moduleApi(name2) {
|
|
4858
|
+
if (name2 === void 0) {
|
|
4436
4859
|
return (id) => ModuleApiToken.create(id);
|
|
4437
4860
|
}
|
|
4438
|
-
return ModuleApiToken.create(
|
|
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 = (
|
|
4866
|
+
const member = (name2, kind, read = {}) => ({
|
|
4444
4867
|
withInput: (input2) => {
|
|
4445
|
-
assertUndeclared(namespace,
|
|
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, [
|
|
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, [
|
|
4877
|
+
withOutput: (output2) => contractBuilder(namespace, { ...members2, [name2]: { kind, input: input2, output: output2, ...cached2 } })
|
|
4455
4878
|
};
|
|
4456
4879
|
}
|
|
4457
4880
|
});
|
|
4458
4881
|
return {
|
|
4459
|
-
query: (
|
|
4460
|
-
mutation: (
|
|
4461
|
-
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,
|
|
4470
|
-
if (
|
|
4471
|
-
throw new Error(`tRPC contract "${namespace}" declares procedure "${
|
|
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 [
|
|
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 "${
|
|
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,
|
|
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(`.${
|
|
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(
|
|
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(
|
|
6377
|
+
} else if (inst._zod.traits.has(name2)) {
|
|
5955
6378
|
return;
|
|
5956
6379
|
}
|
|
5957
|
-
inst._zod.traits.add(
|
|
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:
|
|
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(
|
|
6427
|
+
return inst?._zod?.traits?.has(name2);
|
|
6005
6428
|
}
|
|
6006
6429
|
});
|
|
6007
|
-
Object.defineProperty(_, "name", { value:
|
|
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(
|
|
6018
|
-
super(`Encountered unidirectional transform during encode: ${
|
|
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 = (
|
|
13795
|
-
return
|
|
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 [
|
|
17940
|
+
for (const [name3, v] of ctx.constants) {
|
|
17518
17941
|
if (v === value)
|
|
17519
|
-
return
|
|
17942
|
+
return name3;
|
|
17520
17943
|
}
|
|
17521
|
-
const
|
|
17522
|
-
ctx.constants.set(
|
|
17523
|
-
return
|
|
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,
|
|
24578
|
+
constructor(kind, owner, name2) {
|
|
24156
24579
|
this.kind = kind;
|
|
24157
24580
|
this.owner = owner;
|
|
24158
|
-
this.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,
|
|
24170
|
-
super(kind, owner,
|
|
24592
|
+
constructor(kind, owner, name2) {
|
|
24593
|
+
super(kind, owner, name2);
|
|
24171
24594
|
}
|
|
24172
|
-
static create(kind, owner,
|
|
24173
|
-
const token = new _UiToken(kind, owner,
|
|
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: (
|
|
24181
|
-
extension: (
|
|
24182
|
-
operations: (
|
|
24183
|
-
hooks: (
|
|
24184
|
-
drawer: (
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
25598
|
+
constructor(provider, name2, version2, options) {
|
|
25155
25599
|
this._provider = provider;
|
|
25156
|
-
this.name =
|
|
25600
|
+
this.name = name2;
|
|
25157
25601
|
this.version = version2;
|
|
25158
25602
|
this.options = options;
|
|
25159
25603
|
}
|
|
25160
|
-
startSpan(
|
|
25161
|
-
return this._getTracer().startSpan(
|
|
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(
|
|
25641
|
+
getTracer(name2, version2, options) {
|
|
25198
25642
|
var _a3;
|
|
25199
|
-
return (_a3 = this.getDelegateTracer(
|
|
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(
|
|
25655
|
+
getDelegateTracer(name2, version2, options) {
|
|
25212
25656
|
var _a3;
|
|
25213
|
-
return (_a3 = this._delegate) === null || _a3 === void 0 ? void 0 : _a3.getTracer(
|
|
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(
|
|
25261
|
-
return this.getTracerProvider().getTracer(
|
|
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
|
|
26645
|
-
const isText = !
|
|
26646
|
-
return isText ? { path, content:
|
|
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:
|
|
27659
|
+
"index.html": indexHtml({ title: name2.replaceAll("&", "&").replaceAll("<", "<") }),
|
|
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
|
|
27239
|
-
if (
|
|
27240
|
-
const parsed = appManifestSchema.safeParse(JSON.parse(
|
|
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
|
|
27717
|
+
const text2 = raw.startsWith("@") ? await readFile4(resolve2(context.cwd, raw.slice(1)), "utf8") : raw;
|
|
27274
27718
|
try {
|
|
27275
|
-
return JSON.parse(
|
|
27719
|
+
return JSON.parse(text2);
|
|
27276
27720
|
} catch {
|
|
27277
|
-
throw new CliUsageError(`--${
|
|
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 =
|
|
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
|
-
` :
|
|
27748
|
+
` : text2);
|
|
27305
27749
|
}
|
|
27306
27750
|
var appCreate = async ({ context, args }) => {
|
|
27307
|
-
const
|
|
27308
|
-
if (!
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 [
|
|
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
|
|
27945
|
+
const name2 = args.words[3];
|
|
27502
27946
|
const fields = await jsonFlag({ context, args, name: "fields" });
|
|
27503
|
-
if (!
|
|
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
|
|
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
|
|
27620
|
-
const command = Object.hasOwn(APP_COMMANDS,
|
|
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 (
|
|
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
|
|
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 "${
|
|
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 "${
|
|
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 "${
|
|
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 [
|
|
27705
|
-
const star = active?.name ===
|
|
28148
|
+
for (const [name2, profile] of entries) {
|
|
28149
|
+
const star = active?.name === name2 ? "*" : " ";
|
|
27706
28150
|
context.out(
|
|
27707
|
-
`${star} ${
|
|
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
|
|
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(
|
|
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
|
-
/**
|
|
27764
|
-
async
|
|
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
|
-
|
|
27780
|
-
return
|
|
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({
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
28017
|
-
if (!itemId || !
|
|
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:
|
|
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(
|
|
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
|
|
28052
|
-
const command = Object.hasOwn(FEED_COMMANDS,
|
|
28053
|
-
if (!command) throw new CliUsageError(
|
|
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
|
|
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.
|
|
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() :
|
|
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
|
|
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 (
|
|
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
|
|
28281
|
-
(
|
|
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
|
|
28295
|
-
if (
|
|
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 (
|
|
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 ${
|
|
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
|
|
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
|
|
28426
|
-
import { dirname as
|
|
29069
|
+
import { mkdir as mkdir5, readFile as readFile9, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
|
|
29070
|
+
import { dirname as dirname3, relative as relative2, resolve as resolve4 } from "node:path";
|
|
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
|
|
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
|
|
28446
|
-
await
|
|
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
|
|
28453
|
-
await
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
28515
|
-
const
|
|
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(
|
|
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
|
|
28556
|
-
const command = Object.hasOwn(MEMORY_COMMANDS,
|
|
28557
|
-
if (!command) throw new CliUsageError(
|
|
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
|
|
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
|
-
${
|
|
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
|
|
29231
|
+
const name2 = args.words.slice(2).join(" ").trim();
|
|
28588
29232
|
const prompt = flagText({ args, name: "prompt" });
|
|
28589
|
-
if (!
|
|
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(
|
|
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(
|
|
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
|
|
28652
|
-
const command = Object.hasOwn(SCHEDULE_COMMANDS,
|
|
28653
|
-
if (!command) throw new CliUsageError(
|
|
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
|
|
28659
|
-
import { join as
|
|
28660
|
-
var
|
|
29302
|
+
import { readdir as readdir3, readFile as readFile10 } from "node:fs/promises";
|
|
29303
|
+
import { join as join6, relative as relative3, resolve as resolve5 } from "node:path";
|
|
29304
|
+
var USAGE6 = `Usage:
|
|
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 =
|
|
28672
|
-
files.push({ path: relative3(root, full), content: await
|
|
29315
|
+
const full = join6(entry.parentPath, entry.name);
|
|
29316
|
+
files.push({ path: relative3(root, full), content: await readFile10(full, "utf8") });
|
|
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(
|
|
28692
|
-
const
|
|
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
|
-
...
|
|
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
|
|
28707
|
-
if (!
|
|
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
|
|
28738
|
-
const command = Object.hasOwn(SKILL_COMMANDS,
|
|
28739
|
-
if (!command) throw new CliUsageError(
|
|
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 {
|
|
28745
|
-
|
|
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
|
|
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
|
-
|
|
30323
|
+
function turnFileOf({
|
|
28761
30324
|
env
|
|
28762
30325
|
}) {
|
|
28763
|
-
|
|
28764
|
-
|
|
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
|
|
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
|
-
|
|
28772
|
-
|
|
28773
|
-
connection
|
|
28774
|
-
reason,
|
|
28775
|
-
command
|
|
30341
|
+
function runKeyPathOf({
|
|
30342
|
+
turnFile,
|
|
30343
|
+
connection
|
|
28776
30344
|
}) {
|
|
28777
|
-
const
|
|
28778
|
-
const
|
|
28779
|
-
|
|
28780
|
-
|
|
28781
|
-
|
|
28782
|
-
|
|
28783
|
-
|
|
28784
|
-
|
|
28785
|
-
|
|
28786
|
-
|
|
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
|
-
|
|
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 (${
|
|
30419
|
+
message: `laze vault: the release was refused (${codeOf(text2) ?? `status ${response.status}`})`
|
|
28795
30420
|
};
|
|
28796
30421
|
}
|
|
28797
|
-
return JSON.parse(
|
|
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(
|
|
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
|
-
${
|
|
28808
|
-
const
|
|
28809
|
-
const
|
|
28810
|
-
|
|
28811
|
-
|
|
28812
|
-
|
|
28813
|
-
|
|
28814
|
-
|
|
28815
|
-
|
|
28816
|
-
|
|
28817
|
-
|
|
28818
|
-
|
|
28819
|
-
|
|
28820
|
-
|
|
28821
|
-
|
|
28822
|
-
|
|
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
|
-
|
|
28825
|
-
|
|
28826
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
28899
|
-
const command = Object.hasOwn(WIKI_COMMANDS,
|
|
28900
|
-
if (!command) throw new CliUsageError(
|
|
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
|
-
|
|
29003
|
-
|
|
29004
|
-
|
|
29005
|
-
|
|
29006
|
-
|
|
29007
|
-
|
|
30697
|
+
try {
|
|
30698
|
+
return await runRedacted({
|
|
30699
|
+
command: [program, ...rest],
|
|
30700
|
+
env,
|
|
30701
|
+
baseEnv: inherited,
|
|
30702
|
+
stdout,
|
|
30703
|
+
stderr
|
|
29008
30704
|
});
|
|
29009
|
-
|
|
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: (
|
|
29029
|
-
err: (
|
|
30741
|
+
out: (text2) => void process.stdout.write(text2),
|
|
30742
|
+
err: (text2) => void process.stderr.write(text2),
|
|
29030
30743
|
readStdin,
|
|
29031
|
-
sleep
|
|
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
|
+
};
|