@lazehq/cli 0.1.49 → 0.1.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/laze.mjs +902 -503
  2. package/package.json +1 -1
package/dist/laze.mjs CHANGED
@@ -18733,7 +18733,7 @@ var require_snapshot_utils = __commonJS({
18733
18733
  var require_snapshot_recorder = __commonJS({
18734
18734
  "../../node_modules/.pnpm/undici@8.10.0/node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) {
18735
18735
  "use strict";
18736
- var { writeFile: writeFile23, readFile: readFile40, mkdir: mkdir22 } = __require("node:fs/promises");
18736
+ var { writeFile: writeFile24, readFile: readFile40, mkdir: mkdir23 } = __require("node:fs/promises");
18737
18737
  var { dirname: dirname24, resolve: resolve19 } = __require("node:path");
18738
18738
  var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("node:timers");
18739
18739
  var { InvalidArgumentError, UndiciError } = require_errors();
@@ -18980,12 +18980,12 @@ var require_snapshot_recorder = __commonJS({
18980
18980
  throw new InvalidArgumentError("Snapshot path is required");
18981
18981
  }
18982
18982
  const resolvedPath = resolve19(path);
18983
- await mkdir22(dirname24(resolvedPath), { recursive: true });
18983
+ await mkdir23(dirname24(resolvedPath), { recursive: true });
18984
18984
  const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot]) => ({
18985
18985
  hash: hash2,
18986
18986
  snapshot
18987
18987
  }));
18988
- await writeFile23(resolvedPath, JSON.stringify(data, null, 2), { flush: true });
18988
+ await writeFile24(resolvedPath, JSON.stringify(data, null, 2), { flush: true });
18989
18989
  }
18990
18990
  /**
18991
18991
  * Clears all recorded snapshots
@@ -30914,6 +30914,14 @@ function isLazeIdText(text2) {
30914
30914
  var REDACTION_MARKER = "[SECRET]";
30915
30915
  var MAX_SCAN_LENGTH = 25e4;
30916
30916
  var NAME_LOOKBACK = 200;
30917
+ var VENDOR_FORMAT_RULE_IDS = /* @__PURE__ */ new Set([
30918
+ "github_token",
30919
+ "provider_api_key",
30920
+ "stripe_secret_key",
30921
+ "slack_token",
30922
+ "google_api_key",
30923
+ "vendor_api_key"
30924
+ ]);
30917
30925
  function charClasses(value) {
30918
30926
  let lower = 0;
30919
30927
  let upper = 0;
@@ -31482,13 +31490,49 @@ function findSecrets({
31482
31490
  );
31483
31491
  }
31484
31492
 
31493
+ // ../../packages/secret-guard/src/detector/one-time-links.ts
31494
+ var URL_PATTERN = /https?:\/\/[^\s<>"'`)\]]+/g;
31495
+ var ONE_TIME_WORDS = /(?:^|[^a-z])(?:magic|verify|verification|confirm|login|log-in|signin|sign-in|sign_in|auth|2fa|mfa|otp|token|code|reset|invite|passwordless|one-time|onetime|callback)(?:$|[^a-z])/i;
31496
+ var KEPT_IN_LINKS = /* @__PURE__ */ new Set([
31497
+ ...VENDOR_FORMAT_RULE_IDS,
31498
+ "aws_access_key_id",
31499
+ "url_credentials",
31500
+ "pem_private_key"
31501
+ ]);
31502
+ function isOneTime(url2) {
31503
+ try {
31504
+ const parsed = new URL(url2);
31505
+ const names = [...parsed.searchParams.keys()].join(" ");
31506
+ return ONE_TIME_WORDS.test(`${parsed.pathname} ${names} ${parsed.hash}`);
31507
+ } catch {
31508
+ return false;
31509
+ }
31510
+ }
31511
+ function oneTimeLinksIn({ text: text2 }) {
31512
+ return [...text2.matchAll(URL_PATTERN)].flatMap((match) => {
31513
+ const url2 = match[0].replace(/[.,;:!?]+$/, "");
31514
+ return isOneTime(url2) ? [{ url: url2, start: match.index, end: match.index + url2.length }] : [];
31515
+ });
31516
+ }
31517
+ function withoutOneTimeLinkTokens({
31518
+ text: text2,
31519
+ secrets
31520
+ }) {
31521
+ const links = oneTimeLinksIn({ text: text2 });
31522
+ if (links.length === 0) return [...secrets];
31523
+ return secrets.filter(
31524
+ (secret) => KEPT_IN_LINKS.has(secret.kind) || !links.some((link) => secret.start >= link.start && secret.end <= link.end)
31525
+ );
31526
+ }
31527
+
31485
31528
  // ../../packages/secret-guard/src/detector/draft-secrets.ts
31486
31529
  var MESSAGE_TOKEN = /<@(?:person|agent):[A-Za-z0-9_-]{1,64}>|<!(?:channel|here)>|<file:[A-Za-z0-9_-]{1,64}>/g;
31487
31530
  function withoutMessageTokens(text2) {
31488
31531
  return text2.replace(MESSAGE_TOKEN, (token2) => " ".repeat(token2.length));
31489
31532
  }
31490
31533
  function draftSecretsIn({ text: text2 }) {
31491
- return findSecrets({ text: withoutMessageTokens(text2) });
31534
+ const scanned = withoutMessageTokens(text2);
31535
+ return withoutOneTimeLinkTokens({ text: scanned, secrets: findSecrets({ text: scanned }) });
31492
31536
  }
31493
31537
 
31494
31538
  // ../../packages/secret-guard/src/detector/vault-reference.ts
@@ -31523,6 +31567,19 @@ function applySavedProposals({
31523
31567
  );
31524
31568
  }
31525
31569
 
31570
+ // ../../packages/secret-guard/src/fields/identifier-fields.ts
31571
+ var IDENTIFIER_WORDS = /(?:^|[^A-Z])(?:USER|USERNAME|USER_NAME|EMAIL|E_MAIL|MAIL|LOGIN|ACCOUNT)(?:$|[^A-Z])/;
31572
+ var SECRET_WORDS = /PASS|SECRET|TOKEN|KEY|PIN|OTP|CREDENTIAL|PRIVATE/;
31573
+ function isIdentifierField({ name: name3 }) {
31574
+ const upper = name3.toUpperCase();
31575
+ return IDENTIFIER_WORDS.test(upper) && !SECRET_WORDS.test(upper);
31576
+ }
31577
+ function secretValuesOf({
31578
+ fields
31579
+ }) {
31580
+ return Object.entries(fields).filter(([name3]) => !isIdentifierField({ name: name3 })).map(([, value]) => value);
31581
+ }
31582
+
31526
31583
  // ../../packages/secret-guard/src/redaction/redactor.ts
31527
31584
  var REDACTED = "****";
31528
31585
  var MIN_REDACTED_LENGTH = 4;
@@ -35718,7 +35775,7 @@ function flagText({
35718
35775
  }
35719
35776
 
35720
35777
  // src/rules/cli-version.rules.ts
35721
- var STAMPED = "0.1.49";
35778
+ var STAMPED = "0.1.51";
35722
35779
  function cliVersionOf({ stamped = STAMPED } = {}) {
35723
35780
  return stamped.startsWith("__") ? "dev" : stamped;
35724
35781
  }
@@ -57814,6 +57871,29 @@ var deviceGrantSummarySchema = deviceGrantSummarySchemaDefinition;
57814
57871
  var ApiKeyApi = moduleApi()("api-key");
57815
57872
  var apiKeyTrpc = defineTrpcContract("apiKey").mutation("create").withInput(createApiKeyInputSchema).withOutput(createdApiKeySchema).query("list").withInput(external_exports.object({ workspaceId: external_exports.string().min(1) })).withOutput(external_exports.array(apiKeySummarySchema)).mutation("revoke").withInput(revokeApiKeyInputSchema).withOutput(external_exports.object({ revoked: external_exports.literal(true) })).query("listMine").withInput(external_exports.object({ workspaceId: external_exports.string().min(1) })).withOutput(external_exports.array(personalApiKeySchema)).mutation("revokeMine").withInput(revokeApiKeyInputSchema).withOutput(external_exports.object({ revoked: external_exports.literal(true) })).query("deviceGrant").withInput(external_exports.object({ workspaceId: external_exports.string().min(1), userCode: external_exports.string().min(1).max(20) })).withOutput(deviceGrantSummarySchema).mutation("approveDevice").withInput(decideDeviceGrantInputSchema).withOutput(external_exports.object({ approved: external_exports.literal(true) })).mutation("denyDevice").withInput(decideDeviceGrantInputSchema).withOutput(external_exports.object({ denied: external_exports.literal(true) })).build();
57816
57873
 
57874
+ // ../../modules/chat/contract/src/chat.gifs.ts
57875
+ var GIF_QUERY_MAX = 100;
57876
+ var searchGifsInputSchemaDefinition = external_exports.object({
57877
+ workspaceId: external_exports.string().min(1),
57878
+ query: external_exports.string().trim().min(1).max(GIF_QUERY_MAX),
57879
+ page: external_exports.number().int().min(1).max(50).default(1)
57880
+ });
57881
+ var searchGifsInputSchema = searchGifsInputSchemaDefinition;
57882
+ var gifSchemaDefinition = external_exports.object({
57883
+ id: external_exports.string(),
57884
+ title: external_exports.string(),
57885
+ /** The animated GIF a sent message shows. */
57886
+ url: external_exports.string().url(),
57887
+ width: external_exports.number().int().nonnegative(),
57888
+ height: external_exports.number().int().nonnegative()
57889
+ });
57890
+ var gifSchema = gifSchemaDefinition;
57891
+ var gifResultsSchemaDefinition = external_exports.object({
57892
+ gifs: external_exports.array(gifSchema),
57893
+ hasNext: external_exports.boolean()
57894
+ });
57895
+ var gifResultsSchema = gifResultsSchemaDefinition;
57896
+
57817
57897
  // ../../modules/chat/contract/src/chat.layout.ts
57818
57898
  var LAYOUT_BLOCKS_MAX = 50;
57819
57899
  var LAYOUT_TEXT_MAX = 3e3;
@@ -58103,6 +58183,7 @@ var NOTICE_DETAILS_MAX = 2e3;
58103
58183
  var workspaceIdSchema = external_exports.string().min(1);
58104
58184
  var idSchema4 = external_exports.string().min(1).max(64);
58105
58185
  var chatActorKindSchema = external_exports.enum(["person", "agent"]);
58186
+ var agentLimitCauseSchema = external_exports.enum(["usage", "budget"]);
58106
58187
  var chatActorSchemaDefinition = external_exports.object({ kind: chatActorKindSchema, id: idSchema4 });
58107
58188
  var chatActorSchema = chatActorSchemaDefinition;
58108
58189
  var messageAuthorSchemaDefinition = external_exports.object({
@@ -58229,6 +58310,8 @@ var attentionCardSchemaDefinition = external_exports.object({
58229
58310
  canAlwaysAllow: external_exports.boolean(),
58230
58311
  /** How long "Allow for this agent" lasts, shown on the button; null when not known. */
58231
58312
  alwaysLeaseSeconds: external_exports.number().int().positive().nullable().default(null),
58313
+ /** A vault card whose Allow covers the rest of the agent's turn: "Allow for this task". */
58314
+ allowCoversTask: external_exports.boolean().optional(),
58232
58315
  /** The vault's request id when the card is a vault approval; null for a harness question. */
58233
58316
  vaultRequestId: external_exports.string().nullable().default(null),
58234
58317
  /** A vault approval whose Allow goes through the owner's device passkey. */
@@ -58578,11 +58661,15 @@ var directoryEntrySchemaDefinition = external_exports.object({
58578
58661
  email: external_exports.string().nullable(),
58579
58662
  /** An agent out of usage until then; null for people and agents that can work. */
58580
58663
  limitedUntil: external_exports.iso.datetime().nullable().default(null),
58664
+ /** Why the agent is limited while `limitedUntil` lasts; absent reads as "usage". */
58665
+ limitedBy: agentLimitCauseSchema.optional(),
58581
58666
  /** An agent removed from the workspace, when and by whom; null while it is active. */
58582
58667
  removedAt: external_exports.iso.datetime().nullable().default(null),
58583
58668
  removedByName: external_exports.string().nullable().default(null),
58584
58669
  /** An agent that runs outside Laze: what it reads leaves Laze. False for people. */
58585
- runsOutside: external_exports.boolean().default(false)
58670
+ runsOutside: external_exports.boolean().default(false),
58671
+ /** Other names a person goes by, such as "Drew" or their Slack name; mentions match them. */
58672
+ aliases: external_exports.array(external_exports.string()).optional()
58586
58673
  });
58587
58674
  var chatOverviewSchemaDefinition = external_exports.object({
58588
58675
  viewer: chatActorSchemaDefinition,
@@ -58998,7 +59085,9 @@ var signalActivityInputSchemaDefinition = external_exports.object({
58998
59085
  });
58999
59086
  var setAgentLimitInputSchemaDefinition = external_exports.object({
59000
59087
  workspaceId: workspaceIdSchema,
59001
- limitedUntil: external_exports.iso.datetime().nullable()
59088
+ limitedUntil: external_exports.iso.datetime().nullable(),
59089
+ /** Why it is limited: its login or its budget. */
59090
+ limitedBy: agentLimitCauseSchema.default("usage")
59002
59091
  });
59003
59092
  var setAgentNameInputSchemaDefinition = external_exports.object({
59004
59093
  workspaceId: workspaceIdSchema,
@@ -59448,7 +59537,7 @@ var ChatApi = moduleApi()("chat");
59448
59537
  var chatConversationsTrpc = defineTrpcContract("chat").query("overview").withInput(workspaceInputSchema).withOutput(chatOverviewSchema).query("unreadSummary").withInput(external_exports.object({})).withOutput(external_exports.array(workspaceUnreadSchema)).query("browse").withInput(workspaceInputSchema).withOutput(external_exports.array(browsableChannelSchema)).mutation("createChannel").withInput(createChannelInputSchema).withOutput(conversationSchema).mutation("join").withInput(channelInputSchema).withOutput(conversationSchema).mutation("leave").withInput(channelInputSchema).withOutput(external_exports.object({ left: external_exports.literal(true) })).mutation("updateChannel").withInput(updateChannelInputSchema).withOutput(conversationSchema).mutation("setDefaultAgent").withInput(setDefaultAgentInputSchema).withOutput(conversationSchema).query("logChannelHint").withInput(channelInputSchema).withOutput(logChannelHintSchema).mutation("dismissLogChannelHint").withInput(channelInputSchema).withOutput(external_exports.object({ dismissed: external_exports.literal(true) })).mutation("archiveChannel").withInput(channelInputSchema).withOutput(conversationSchema).mutation("unarchiveChannel").withInput(channelInputSchema).withOutput(conversationSchema).mutation("addMembers").withInput(addMembersInputSchema).withOutput(conversationSchema).mutation("removeMember").withInput(removeMemberInputSchema).withOutput(conversationSchema).mutation("openDirect").withInput(openDirectInputSchema).withOutput(conversationSchema).query("conversation").withInput(channelInputSchema).withOutput(conversationSchema).build();
59449
59538
  var chatChannelRolesTrpc = defineTrpcContract("chat").mutation("setChannelRole").withInput(setChannelRoleInputSchema).withOutput(conversationSchema).mutation("extendChannel").withInput(extendChannelInputSchema).withOutput(conversationSchema).build();
59450
59539
  var chatMessagesTrpc = defineTrpcContract("chat").query("history").withInput(historyInputSchema).withOutput(historyPageSchema).query("thread").withInput(messageInputSchema).withOutput(threadSchema).mutation("post").withInput(postMessageInputSchema).withOutput(messageSchema).mutation("forward").withInput(forwardMessageInputSchema).withOutput(messageSchema).mutation("addMentioned").withInput(addMentionedInputSchema).withOutput(messageSchema).mutation("edit").withInput(editMessageInputSchema).withOutput(messageSchema).mutation("delete").withInput(messageInputSchema).withOutput(messageSchema).mutation("remove").withInput(messageInputSchema).withOutput(messageSchema).mutation("react").withInput(reactInputSchema).withOutput(messageSchema).mutation("signalTyping").withInput(signalTypingInputSchema).withOutput(external_exports.object({ sent: external_exports.literal(true) })).mutation("markRead").withInput(markReadInputSchema).withOutput(external_exports.object({ lastReadSeq: external_exports.number().int().nonnegative() })).mutation("markUnread").withInput(markUnreadInputSchema).withOutput(external_exports.object({ lastReadSeq: external_exports.number().int().nonnegative() })).query("search").withInput(searchInputSchema).withOutput(searchResultSchema).build();
59451
- var chatFilesTrpc = defineTrpcContract("chat").mutation("startUpload").withInput(startUploadInputSchema).withOutput(uploadTicketSchema).mutation("completeUpload").withInput(completeUploadInputSchema).withOutput(attachmentSchema).mutation("abortUpload").withInput(fileInputSchema).withOutput(external_exports.object({ aborted: external_exports.literal(true) })).query("fileLink").withInput(fileLinkInputSchema).withOutput(fileLinkSchema).query("channelFiles").withInput(channelFilesInputSchema).withOutput(channelFilesSchema).mutation("renameAttachment").withInput(renameAttachmentInputSchema).withOutput(attachmentSchema).mutation("hideUnfurl").withInput(hideUnfurlInputSchema).withOutput(messageSchema).query("unfurlImage").withInput(hideUnfurlInputSchema).withOutput(fileLinkSchema).build();
59540
+ var chatFilesTrpc = defineTrpcContract("chat").mutation("startUpload").withInput(startUploadInputSchema).withOutput(uploadTicketSchema).mutation("completeUpload").withInput(completeUploadInputSchema).withOutput(attachmentSchema).mutation("abortUpload").withInput(fileInputSchema).withOutput(external_exports.object({ aborted: external_exports.literal(true) })).query("fileLink").withInput(fileLinkInputSchema).withOutput(fileLinkSchema).query("channelFiles").withInput(channelFilesInputSchema).withOutput(channelFilesSchema).mutation("renameAttachment").withInput(renameAttachmentInputSchema).withOutput(attachmentSchema).mutation("hideUnfurl").withInput(hideUnfurlInputSchema).withOutput(messageSchema).query("unfurlImage").withInput(hideUnfurlInputSchema).withOutput(fileLinkSchema).query("searchGifs").withInput(searchGifsInputSchema).withOutput(gifResultsSchema).build();
59452
59541
  var chatFollowingTrpc = defineTrpcContract("chat").mutation("setNotify").withInput(setNotifyInputSchema).withOutput(conversationSummarySchema).mutation("hideConversation").withInput(channelInputSchema).withOutput(external_exports.object({ hidden: external_exports.literal(true) })).mutation("followThread").withInput(followThreadInputSchema).withOutput(threadFollowSchema).query("threadFollow").withInput(messageInputSchema).withOutput(threadFollowSchema).query("threads").withInput(threadsInputSchema).withOutput(threadsPageSchema).query("threadsUnread").withInput(workspaceInputSchema).withOutput(threadsUnreadSchema).query("notificationCount").withInput(workspaceInputSchema).withOutput(external_exports.object({ count: external_exports.number().int().nonnegative() })).mutation("markThreadRead").withInput(messageInputSchema).withOutput(external_exports.object({ read: external_exports.literal(true) })).mutation("pin").withInput(pinMessageInputSchema).withOutput(messageSchema).query("pins").withInput(channelInputSchema).withOutput(pinsPageSchema).query("saved").withInput(savedInputSchema).withOutput(savedPageSchema).query("savedMarks").withInput(workspaceInputSchema).withOutput(savedMarksSchema).mutation("saveMessage").withInput(saveMessageInputSchema).withOutput(savedStatusSchema).mutation("markSavedDone").withInput(markSavedDoneInputSchema).withOutput(savedStatusSchema).mutation("setReminder").withInput(setReminderInputSchema).withOutput(savedStatusSchema).query("activity").withInput(activityInputSchema).withOutput(activityPageSchema).mutation("markActivityRead").withInput(markActivityReadInputSchema).withOutput(external_exports.object({ read: external_exports.literal(true) })).build();
59453
59542
  var chatSessionTrpc = defineTrpcContract("chat").mutation("realtimeToken").withInput(workspaceInputSchema).withOutput(realtimeTokenSchema).query("drafts").withInput(workspaceInputSchema).withOutput(draftListSchema).mutation("saveDraft").withInput(saveDraftInputSchema).withOutput(draftSavedSchema).mutation("deleteDraft").withInput(deleteDraftInputSchema).withOutput(draftSavedSchema).query("sent").withInput(listSentInputSchema).withOutput(sentPageSchema).query("sidebarLayout").withInput(workspaceInputSchema).withOutput(sidebarLayoutSchema).mutation("editSidebar").withInput(editSidebarInputSchema).withOutput(sidebarLayoutSchema).mutation("star").withInput(starInputSchema).withOutput(starStatusSchema).query("starred").withInput(workspaceInputSchema).withOutput(starredListSchema).mutation("scrubSecrets").withInput(scrubChatInputSchema).withOutput(chatScrubReportSchema).mutation("restoreScrubbed").withInput(messageInputSchema).withOutput(messageSchema).build();
59454
59543
  var chatScheduledTrpc = defineTrpcContract("chat").mutation("scheduleMessage").withInput(scheduleMessageInputSchema).withOutput(scheduledMessageSchema).query("scheduled").withInput(listScheduledInputSchema).withOutput(scheduledListSchema).mutation("editScheduled").withInput(editScheduledInputSchema).withOutput(scheduledMessageSchema).mutation("sendScheduledNow").withInput(scheduledInputSchema).withOutput(scheduledMessageSchema).mutation("cancelScheduled").withInput(scheduledInputSchema).withOutput(scheduledMessageSchema).build();
@@ -60450,7 +60539,9 @@ var realtimePublicationSchemaDefinition = external_exports.discriminatedUnion("t
60450
60539
  type: external_exports.literal("agent_limit"),
60451
60540
  workspaceId: external_exports.string(),
60452
60541
  agentId: external_exports.string(),
60453
- limitedUntil: external_exports.iso.datetime().nullable()
60542
+ limitedUntil: external_exports.iso.datetime().nullable(),
60543
+ /** Why it is limited; absent reads as "usage". */
60544
+ limitedBy: agentLimitCauseSchema.optional()
60454
60545
  }),
60455
60546
  /** An agent was removed from the workspace; its direct messages stay as history. */
60456
60547
  external_exports.object({
@@ -60582,8 +60673,21 @@ var finishVaultDeviceEnrolmentInputSchemaDefinition = external_exports.object({
60582
60673
  /** P-256 SPKI DER; signs approvals of later devices. */
60583
60674
  signingPublicKey: base64Url,
60584
60675
  /** DER ECDSA over nativeSignedMessage({ purpose: "enrol", challenge }). */
60585
- signature: base64Url
60586
- }).optional()
60676
+ signature: base64Url,
60677
+ /** The same for one install of the app, through Face ID changes; named on a re-enrol. */
60678
+ installId: external_exports.string().min(8).max(128).optional(),
60679
+ /** Required for ios_secure_enclave: DCAppAttestService over appAttestClientData(...). */
60680
+ appAttest: external_exports.object({
60681
+ /** The App Attest key id as iOS returns it (standard base64 of the key's SHA-256). */
60682
+ keyId: external_exports.string().min(1).max(64),
60683
+ /** The CBOR attestation object, base64url. */
60684
+ attestation: base64Url
60685
+ }).optional()
60686
+ }).optional(),
60687
+ /** A re-enrol from the same install: the device it replaces, retired when this one is stored. */
60688
+ replacesDeviceId: external_exports.string().min(1).optional(),
60689
+ /** A fresh reauth proof; required with replacesDeviceId and spent by it. */
60690
+ reauthToken: external_exports.string().min(1).optional()
60587
60691
  });
60588
60692
  var finishVaultDeviceEnrolmentInputSchema = finishVaultDeviceEnrolmentInputSchemaDefinition;
60589
60693
  var sealedRecipientSchema = external_exports.object({
@@ -60673,7 +60777,9 @@ var answerSealedApprovalInputSchemaDefinition = external_exports.object({
60673
60777
  release: external_exports.object({ epk: base64Url, ciphertext: base64Url }),
60674
60778
  via: external_exports.enum(["feed", "channel", "ios", "desktop", "web"]).default("web"),
60675
60779
  /** Allow for this agent for this long: runs with the same key reuse the release until then. */
60676
- durationSeconds: external_exports.number().int().positive().optional()
60780
+ durationSeconds: external_exports.number().int().positive().optional(),
60781
+ /** The active device that opened the secret; removing it ends this release and its lease. */
60782
+ approverDeviceId: external_exports.string().min(1).optional()
60677
60783
  });
60678
60784
  var answerSealedApprovalInputSchema = answerSealedApprovalInputSchemaDefinition;
60679
60785
  var vaultRunSealedReleaseSchemaDefinition = external_exports.object({
@@ -61107,7 +61213,12 @@ var openVaultTurnInputSchemaDefinition = external_exports.object({
61107
61213
  /** Everyone else's messages, oldest first: context for the judge, never permission. */
61108
61214
  otherMessages: external_exports.array(external_exports.object({ sender: external_exports.string().min(1), text: external_exports.string() })).default([]),
61109
61215
  /** A shorter life than the deployment's turn TTL, for a token made for one command. */
61110
- ttlMinutes: external_exports.number().int().positive().optional()
61216
+ ttlMinutes: external_exports.number().int().positive().optional(),
61217
+ /**
61218
+ * The task an "Allow for this task" covers: left out, the turn is its own task; null asks for
61219
+ * each command; named, every turn opened for it shares one task, which `scope` describes.
61220
+ */
61221
+ task: external_exports.object({ id: external_exports.string().min(1).max(200), scope: external_exports.string().max(300).nullable() }).nullable().optional()
61111
61222
  });
61112
61223
  var vaultAlwaysApprovalActionSchema = external_exports.enum([
61113
61224
  "send_external",
@@ -61199,6 +61310,8 @@ var vaultApprovalStateSchema = external_exports.enum([
61199
61310
  "denied",
61200
61311
  "expired"
61201
61312
  ]);
61313
+ var vaultApprovalListStateSchemaDefinition = external_exports.union([vaultApprovalStateSchema, external_exports.literal("withdrawn")]).transform((state) => state === "withdrawn" ? "expired" : state);
61314
+ var vaultApprovalListStateSchema = vaultApprovalListStateSchemaDefinition;
61202
61315
  var vaultAnswerViaSchema = external_exports.enum(["feed", "channel", "ios", "desktop", "web"]);
61203
61316
  var vaultApprovalRequestSchemaDefinition = external_exports.object({
61204
61317
  id: external_exports.string(),
@@ -61228,7 +61341,9 @@ var vaultApprovalRequestSchemaDefinition = external_exports.object({
61228
61341
  /** The connection's title, so an approver who cannot list it still knows what is asked. */
61229
61342
  connectionTitle: external_exports.string().nullable().default(null),
61230
61343
  /** The longest lease Allow for this agent offers; null offers only once and deny. */
61231
- maxLeaseSeconds: external_exports.number().int().positive().nullable().default(null)
61344
+ maxLeaseSeconds: external_exports.number().int().positive().nullable().default(null),
61345
+ /** Allow covers the rest of the agent's turn ("Allow for this task"), not one command. */
61346
+ coversTask: external_exports.boolean().optional()
61232
61347
  });
61233
61348
  var vaultApprovalRequestSchema = vaultApprovalRequestSchemaDefinition;
61234
61349
  var answerVaultApprovalInputSchemaDefinition = external_exports.object({
@@ -61446,7 +61561,7 @@ var vaultTrpc = defineTrpcContract("vault").mutation("createConnection").withInp
61446
61561
  reason: external_exports.string().trim().min(1).max(200),
61447
61562
  reauthToken: external_exports.string().min(1).max(200).optional()
61448
61563
  })
61449
- ).withOutput(external_exports.object({ fields: external_exports.record(external_exports.string(), external_exports.string()) })).mutation("beginReauth").withInput(workspaceInput).withOutput(vaultReauthChallengeSchema).mutation("confirmReauth").withInput(confirmVaultReauthInputSchema).withOutput(vaultReauthProofSchema).mutation("grantConnection").withInput(grantVaultConnectionInputSchema).withOutput(vaultGrantSchema).mutation("lendToChannel").withInput(lendVaultConnectionInputSchema).withOutput(vaultGrantSchema).mutation("revokeGrant").withInput(revokeVaultGrantInputSchema).withOutput(external_exports.object({ revoked: external_exports.literal(true) })).query("listGrants").withInput(connectionInput).withOutput(external_exports.array(vaultGrantSchema)).mutation("shareConnection").withInput(shareVaultConnectionInputSchema).withOutput(vaultGrantSchema).mutation("approveShare").withInput(approveVaultShareInputSchema).withOutput(vaultGrantSchema).mutation("sealConnection").withInput(sealVaultConnectionInputSchema).withOutput(vaultConnectionSchema).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(vaultAuditReadInputSchema).withOutput(vaultAuditPageSchema).query("listActivity").withInput(vaultAuditReadInputSchema).withOutput(external_exports.array(vaultAuditEntrySchema)).query("listLeases").withInput(workspaceInput).withOutput(external_exports.array(vaultLeaseSchema)).mutation("endLease").withInput(endVaultLeaseInputSchema).withOutput(external_exports.object({ ended: external_exports.literal(true) })).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(
61564
+ ).withOutput(external_exports.object({ fields: external_exports.record(external_exports.string(), external_exports.string()) })).mutation("beginReauth").withInput(workspaceInput).withOutput(vaultReauthChallengeSchema).mutation("confirmReauth").withInput(confirmVaultReauthInputSchema).withOutput(vaultReauthProofSchema).mutation("grantConnection").withInput(grantVaultConnectionInputSchema).withOutput(vaultGrantSchema).mutation("lendToChannel").withInput(lendVaultConnectionInputSchema).withOutput(vaultGrantSchema).mutation("revokeGrant").withInput(revokeVaultGrantInputSchema).withOutput(external_exports.object({ revoked: external_exports.literal(true) })).query("listGrants").withInput(connectionInput).withOutput(external_exports.array(vaultGrantSchema)).mutation("shareConnection").withInput(shareVaultConnectionInputSchema).withOutput(vaultGrantSchema).mutation("approveShare").withInput(approveVaultShareInputSchema).withOutput(vaultGrantSchema).mutation("sealConnection").withInput(sealVaultConnectionInputSchema).withOutput(vaultConnectionSchema).query("listApprovals").withInput(external_exports.object({ ...workspaceInput.shape, state: vaultApprovalListStateSchema.optional() })).withOutput(external_exports.array(vaultApprovalRequestSchema)).mutation("answerApproval").withInput(answerVaultApprovalInputSchema).withOutput(vaultApprovalRequestSchema).query("listAudit").withInput(vaultAuditReadInputSchema).withOutput(vaultAuditPageSchema).query("listActivity").withInput(vaultAuditReadInputSchema).withOutput(external_exports.array(vaultAuditEntrySchema)).query("listLeases").withInput(workspaceInput).withOutput(external_exports.array(vaultLeaseSchema)).mutation("endLease").withInput(endVaultLeaseInputSchema).withOutput(external_exports.object({ ended: external_exports.literal(true) })).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(
61450
61565
  external_exports.object({
61451
61566
  ...connectionInput.shape,
61452
61567
  reason: external_exports.string().trim().min(1).max(200),
@@ -61478,6 +61593,8 @@ var vaultConfig = Config.define((c) => ({
61478
61593
  "VAULT_PREVIOUS_KEY_GRACE_MINUTES",
61479
61594
  external_exports.coerce.number().int().min(0).default(30)
61480
61595
  ),
61596
+ /** iPhone enrolment without App Attest (simulator); applies only off a public origin. */
61597
+ appAttestDev: c.env("VAULT_APP_ATTEST_DEV", environmentBooleanSchema.default(false)),
61481
61598
  /** The origin passkeys are made on; unset accepts any localhost origin, for development. */
61482
61599
  publicBaseUrl,
61483
61600
  /** A file each audit chain head is appended to as a JSON line; unset only logs the heads. */
@@ -61561,7 +61678,11 @@ var vaultApprovalRequestedPayloadSchemaDefinition = external_exports.object({
61561
61678
  /** Sealed to the owner's devices: Allow goes through the device's passkey, deny does not. */
61562
61679
  sealed: external_exports.boolean().default(false),
61563
61680
  /** For a send, the message it would send, read from the provider. */
61564
- draft: vaultDraftPreviewSchema.nullable().default(null)
61681
+ draft: vaultDraftPreviewSchema.nullable().default(null),
61682
+ /** Allow covers the rest of the agent's turn ("Allow for this task"), not one command. */
61683
+ coversTask: external_exports.boolean().optional(),
61684
+ /** What a task card's Allow covers when it is wider than one turn: "this session of ...". */
61685
+ taskScope: external_exports.string().nullable().optional()
61565
61686
  });
61566
61687
  var vaultApprovalResolvedPayloadSchemaDefinition = external_exports.object({
61567
61688
  workspaceId: external_exports.string().min(1),
@@ -61580,6 +61701,10 @@ var vaultApprovalResolvedPayloadSchemaDefinition = external_exports.object({
61580
61701
  answeredByName: external_exports.string().default(""),
61581
61702
  /** A deny or a timeout: until when the same action is refused without a new card. */
61582
61703
  blockedUntil: external_exports.iso.datetime().nullable().default(null),
61704
+ /** An expired card closed because the agent's turn that asked ended; nothing is blocked. */
61705
+ endedWithTurn: external_exports.boolean().optional(),
61706
+ /** A task card: its Allow covered the rest of the agent's turn. */
61707
+ coversTask: external_exports.boolean().optional(),
61583
61708
  /** Who decides the card, so their open approvals lists refresh. */
61584
61709
  approverUserIds: external_exports.array(external_exports.string()).readonly().default([])
61585
61710
  });
@@ -65219,6 +65344,8 @@ var agentSchemaDefinition = external_exports.object({
65219
65344
  github: agentGithubSchema.nullable().default(null),
65220
65345
  /** Out of usage (its login or its Laze models budget) until this time; null when it can work. */
65221
65346
  limitedUntil: external_exports.iso.datetime().nullable().default(null),
65347
+ /** Why it is limited: "usage" (its login; also when absent) or "budget" (Laze models). */
65348
+ limitedBy: agentLimitCauseSchema.optional(),
65222
65349
  /** Paused by a person since this time: it does not wake until resumed; null when it runs. */
65223
65350
  pausedAt: external_exports.iso.datetime().nullable().default(null),
65224
65351
  /** Who paused it and the reason they gave; null when it runs or no reason was given. */
@@ -65520,7 +65647,9 @@ var postedMessageSchemaDefinition = external_exports.object({
65520
65647
  name: external_exports.string(),
65521
65648
  cause: external_exports.enum(["paused", "out_of_usage"]),
65522
65649
  /** When an agent out of usage gets its usage back; null while paused. */
65523
- until: external_exports.iso.datetime().nullable()
65650
+ until: external_exports.iso.datetime().nullable(),
65651
+ /** Why an agent out of usage is limited: its login or budget; absent reads as "usage". */
65652
+ limitedBy: agentLimitCauseSchema.optional()
65524
65653
  })
65525
65654
  ).default([])
65526
65655
  });
@@ -66131,7 +66260,9 @@ var callerWorkspaceMemberSchemaDefinition = external_exports.object({
66131
66260
  email: external_exports.string(),
66132
66261
  name: external_exports.string(),
66133
66262
  role: roleSchema,
66134
- joinedAt: external_exports.iso.datetime()
66263
+ joinedAt: external_exports.iso.datetime(),
66264
+ /** Other names they go by in the workspace; absent or empty without any. */
66265
+ aliases: external_exports.array(external_exports.string()).optional()
66135
66266
  });
66136
66267
  var callerWorkspaceInviteSchemaDefinition = external_exports.object({
66137
66268
  id: external_exports.string().min(1),
@@ -66173,6 +66304,9 @@ var decideRequestAsCallerInputSchemaDefinition = external_exports.object({
66173
66304
  requestId: external_exports.string().trim().min(1).max(80),
66174
66305
  decision: external_exports.enum(["approved", "denied"])
66175
66306
  });
66307
+ var setAliasesAsCallerInputSchemaDefinition = external_exports.object({
66308
+ aliases: external_exports.array(external_exports.string().trim().max(40)).max(5)
66309
+ });
66176
66310
  var renameWorkspaceAsCallerInputSchemaDefinition = external_exports.object({
66177
66311
  name: external_exports.string().trim().min(1).max(80)
66178
66312
  });
@@ -66736,7 +66870,8 @@ function howItRunsOf({ agent: agent2, owner }) {
66736
66870
  function statusOf({ agent: agent2 }) {
66737
66871
  if (agent2.pausedAt) return `Paused since ${agent2.pausedAt.slice(0, 16).replace("T", " ")} UTC`;
66738
66872
  if (agent2.limitedUntil) {
66739
- return `Out of usage until ${agent2.limitedUntil.slice(0, 16).replace("T", " ")} UTC`;
66873
+ const until = `${agent2.limitedUntil.slice(0, 16).replace("T", " ")} UTC`;
66874
+ return agent2.limitedBy === "budget" ? `At its budget until ${until}` : `Out of usage until ${until}`;
66740
66875
  }
66741
66876
  if (agent2.status === "disconnected") return "Disconnected";
66742
66877
  return agent2.online ? "Working" : "Ready";
@@ -67240,6 +67375,10 @@ var slackProfilesSchemaDefinition = external_exports.object({
67240
67375
  profiles: external_exports.array(slackProfileSchemaDefinition)
67241
67376
  });
67242
67377
  var slackProfilesSchema = slackProfilesSchemaDefinition;
67378
+ var slackLinkedNamesSchemaDefinition = external_exports.object({
67379
+ people: external_exports.array(external_exports.object({ personId: external_exports.string().min(1), names: external_exports.array(external_exports.string()) }))
67380
+ });
67381
+ var slackLinkedNamesSchema = slackLinkedNamesSchemaDefinition;
67243
67382
 
67244
67383
  // ../../modules/slack/contract/src/slack-setup.ts
67245
67384
  var workspaceIdSchema13 = external_exports.string().min(1);
@@ -67608,7 +67747,7 @@ var slackSearchAnswerSchemaDefinition = external_exports.object({
67608
67747
  var slackSearchAnswerSchema = slackSearchAnswerSchemaDefinition;
67609
67748
  var SlackApi = moduleApi()("slack");
67610
67749
  var workspaceInput3 = external_exports.object({ workspaceId: workspaceIdSchema14 });
67611
- var slackTrpc = defineTrpcContract("slack").query("overview").withInput(workspaceInput3).withOutput(slackOverviewSchema).mutation("startSetup").withInput(startSlackSetupInputSchema).withOutput(startedSlackAuthorizeSchema).mutation("beginSetup").withInput(beginSlackSetupInputSchema).withOutput(slackSetupSchema).mutation("saveAppCredentials").withInput(saveSlackAppCredentialsInputSchema).withOutput(startedSlackAuthorizeSchema).mutation("installApp").withInput(installSlackAppInputSchema).withOutput(startedSlackAuthorizeSchema).mutation("startInstall").withInput(startSlackInstallInputSchema).withOutput(startedSlackAuthorizeSchema).mutation("startLink").withInput(startSlackLinkInputSchema).withOutput(startedSlackAuthorizeSchema).query("channels").withInput(slackTeamInputSchema).withOutput(external_exports.array(slackChannelViewSchema)).mutation("setMirror").withInput(setSlackMirrorInputSchema).withOutput(slackConnectionViewSchema).mutation("updateConnection").withInput(updateSlackConnectionInputSchema).withOutput(slackConnectionViewSchema).mutation("disconnect").withInput(slackTeamInputSchema).withOutput(external_exports.object({ disconnected: external_exports.literal(true) })).mutation("unlink").withInput(slackTeamInputSchema).withOutput(slackConnectionViewSchema).query("linkPrompts").withInput(workspaceInput3).withOutput(slackLinkPromptsSchema).mutation("dismissLinkPrompt").withInput(dismissSlackLinkPromptInputSchema).withOutput(slackLinkPromptsSchema).query("people").withInput(slackPeopleInputSchema).withOutput(slackPeopleSchema).query("bookmarks").withInput(slackBookmarksInputSchema).withOutput(slackBookmarksSchema).query("profiles").withInput(slackProfilesInputSchema).withOutput(slackProfilesSchema).mutation("openDirect").withInput(openSlackDirectInputSchema).withOutput(openedSlackDirectSchema).mutation("updateApp").withInput(updateSlackAppInputSchema).withOutput(external_exports.object({ updated: external_exports.literal(true) })).query("history").withInput(slackHistoryInputSchema).withOutput(slackHistoryPageSchema).query("search").withInput(slackSearchInputSchema).withOutput(slackSearchAnswerSchema).query("movePreview").withInput(slackMoveChannelInputSchema).withOutput(slackMovePreviewSchema).mutation("startMoves").withInput(startSlackMovesInputSchema).withOutput(startedSlackMovesSchema).mutation("cancelMove").withInput(slackMoveInputSchema).withOutput(slackMoveViewSchema).query("moves").withInput(workspaceInput3).withOutput(slackMovesSchema).build();
67750
+ var slackTrpc = defineTrpcContract("slack").query("overview").withInput(workspaceInput3).withOutput(slackOverviewSchema).mutation("startSetup").withInput(startSlackSetupInputSchema).withOutput(startedSlackAuthorizeSchema).mutation("beginSetup").withInput(beginSlackSetupInputSchema).withOutput(slackSetupSchema).mutation("saveAppCredentials").withInput(saveSlackAppCredentialsInputSchema).withOutput(startedSlackAuthorizeSchema).mutation("installApp").withInput(installSlackAppInputSchema).withOutput(startedSlackAuthorizeSchema).mutation("startInstall").withInput(startSlackInstallInputSchema).withOutput(startedSlackAuthorizeSchema).mutation("startLink").withInput(startSlackLinkInputSchema).withOutput(startedSlackAuthorizeSchema).query("channels").withInput(slackTeamInputSchema).withOutput(external_exports.array(slackChannelViewSchema)).mutation("setMirror").withInput(setSlackMirrorInputSchema).withOutput(slackConnectionViewSchema).mutation("updateConnection").withInput(updateSlackConnectionInputSchema).withOutput(slackConnectionViewSchema).mutation("disconnect").withInput(slackTeamInputSchema).withOutput(external_exports.object({ disconnected: external_exports.literal(true) })).mutation("unlink").withInput(slackTeamInputSchema).withOutput(slackConnectionViewSchema).query("linkPrompts").withInput(workspaceInput3).withOutput(slackLinkPromptsSchema).mutation("dismissLinkPrompt").withInput(dismissSlackLinkPromptInputSchema).withOutput(slackLinkPromptsSchema).query("people").withInput(slackPeopleInputSchema).withOutput(slackPeopleSchema).query("bookmarks").withInput(slackBookmarksInputSchema).withOutput(slackBookmarksSchema).query("profiles").withInput(slackProfilesInputSchema).withOutput(slackProfilesSchema).query("linkedNames").withInput(external_exports.object({ workspaceId: external_exports.string().min(1) })).withOutput(slackLinkedNamesSchema).mutation("openDirect").withInput(openSlackDirectInputSchema).withOutput(openedSlackDirectSchema).mutation("updateApp").withInput(updateSlackAppInputSchema).withOutput(external_exports.object({ updated: external_exports.literal(true) })).query("history").withInput(slackHistoryInputSchema).withOutput(slackHistoryPageSchema).query("search").withInput(slackSearchInputSchema).withOutput(slackSearchAnswerSchema).query("movePreview").withInput(slackMoveChannelInputSchema).withOutput(slackMovePreviewSchema).mutation("startMoves").withInput(startSlackMovesInputSchema).withOutput(startedSlackMovesSchema).mutation("cancelMove").withInput(slackMoveInputSchema).withOutput(slackMoveViewSchema).query("moves").withInput(workspaceInput3).withOutput(slackMovesSchema).build();
67612
67751
 
67613
67752
  // ../../modules/slack/contract/src/slack-keys.ts
67614
67753
  var SLACK_KEY_PATHS = {
@@ -67714,11 +67853,13 @@ function notInChannelLineOf({
67714
67853
  `;
67715
67854
  }
67716
67855
  function waitsForLinesOf({ posted }) {
67717
- return (posted.waitsFor ?? []).map(
67718
- ({ name: name3, cause, until }) => cause === "paused" ? `${name3} is paused; your message waits until it is resumed.
67719
- ` : `${name3} is out of usage until ${until}; your message waits for it.
67720
- `
67721
- ).join("");
67856
+ return (posted.waitsFor ?? []).map(({ name: name3, cause, until, limitedBy }) => {
67857
+ if (cause === "paused") return `${name3} is paused; your message waits until it is resumed.
67858
+ `;
67859
+ const state = limitedBy === "budget" ? "at its budget" : "out of usage";
67860
+ return `${name3} is ${state} until ${until}; your message waits for it.
67861
+ `;
67862
+ }).join("");
67722
67863
  }
67723
67864
 
67724
67865
  // src/rules/search-format.rules.ts
@@ -71069,6 +71210,16 @@ someone an action cannot be done because Laze refused it earlier, run \`laze cha
71069
71210
  again. When a change lifts a refusal you hit in a conversation, tell the people there once that
71070
71211
  it works now.
71071
71212
 
71213
+ ## Browser tabs and sign-ins
71214
+
71215
+ - \`laze browser tabs\` lists the live browser tabs of your conversations. You drive every tab
71216
+ your owner owns from this session (\`laze browser goto|read|cdp <tab>\`); you need no Laze
71217
+ computer and no helper agent. Reuse an open tab by its title instead of opening another.
71218
+ - A site needs a sign-in: \`laze browser ask <tab> "Sign in to <site>"\`. The person signs in on
71219
+ the tab's screen and presses Done, which reaches you as a message (\`--wait\` waits for it).
71220
+ - Only when the person says to use a saved key: \`laze browser login <tab> --vault <connection>\`.
71221
+ Never ask for a password and never write scripts that type one.
71222
+
71072
71223
  If \`laze\` is not on the PATH, run the same commands through \`npx -y @lazehq/cli@latest\`.
71073
71224
  Never print or repeat your Laze key.
71074
71225
  `;
@@ -73787,7 +73938,9 @@ var appPinSchemaDefinition = external_exports.object({
73787
73938
  /** Set for a browser tab, null for an app. */
73788
73939
  browser: browserPinSchemaDefinition.nullable(),
73789
73940
  /** Whether the reader may unpin it; a browser tab only its owner, their agents or an Admin. */
73790
- canUnpin: external_exports.boolean().default(true)
73941
+ canUnpin: external_exports.boolean().default(true),
73942
+ /** The app's own origin, so links to it open in the panel; null for a browser tab. */
73943
+ url: external_exports.string().nullable().default(null)
73791
73944
  });
73792
73945
  var appPinViewSchemaDefinition = external_exports.object({
73793
73946
  activeAppId: external_exports.string().nullable(),
@@ -74312,6 +74465,7 @@ var AppNavSlot = appUi.component("nav");
74312
74465
  var AppPanelSlot = appUi.component("panel");
74313
74466
  var AppCardSlot = appUi.component("card");
74314
74467
  var AppPinStripSlot = appUi.component("pin-strip");
74468
+ var AppLinkHooksToken = appUi.hooks("links");
74315
74469
  var AppPinListSlot = appUi.component("pin-list");
74316
74470
 
74317
74471
  // ../../modules/app/contract/src/app.config.ts
@@ -76620,8 +76774,374 @@ async function billing({ context, args }) {
76620
76774
 
76621
76775
  // src/services/browser-commands.service.ts
76622
76776
  import { randomBytes } from "node:crypto";
76623
- import { mkdir as mkdir17, readFile as readFile17, writeFile as writeFile17 } from "node:fs/promises";
76777
+ import { mkdir as mkdir19, readFile as readFile18, writeFile as writeFile19 } from "node:fs/promises";
76778
+ import { dirname as dirname18, join as join21 } from "node:path";
76779
+
76780
+ // src/services/browser-tab-commands.service.ts
76781
+ import { mkdir as mkdir18, writeFile as writeFile18 } from "node:fs/promises";
76782
+ import { tmpdir as tmpdir3 } from "node:os";
76783
+ import { join as join20 } from "node:path";
76784
+
76785
+ // src/rules/browser-login.rules.ts
76786
+ var PASSWORD_NAME = /pass|pwd/i;
76787
+ var USER_NAME = /user|email|e-mail|login|account|name|^id$|_id$/i;
76788
+ function loginValuesOf({
76789
+ connection,
76790
+ values,
76791
+ userField,
76792
+ passField
76793
+ }) {
76794
+ const names = Object.keys(values).toSorted();
76795
+ const listed = names.join(", ") || "no fields";
76796
+ const refusal = (why) => ({
76797
+ refusal: `laze browser login: ${why}; ${connection} holds ${listed}. Pass --user-field <field> and --pass-field <field>.`
76798
+ });
76799
+ if (userField && values[userField] === void 0)
76800
+ return refusal(`${connection} has no field ${userField}`);
76801
+ if (passField && values[passField] === void 0)
76802
+ return refusal(`${connection} has no field ${passField}`);
76803
+ const passName = passField ?? names.find((name3) => PASSWORD_NAME.test(name3)) ?? (names.length === 1 ? names[0] : void 0);
76804
+ if (passName === void 0) return refusal("no field reads as the password");
76805
+ const userName = userField ?? names.find((name3) => name3 !== passName && USER_NAME.test(name3)) ?? void 0;
76806
+ const password = values[passName] ?? "";
76807
+ if (!password) return refusal(`${passName} is empty`);
76808
+ const username = userName === void 0 ? void 0 : values[userName];
76809
+ return username ? { username, password } : { password };
76810
+ }
76811
+
76812
+ // src/services/vault-commands.service.ts
76813
+ import { createHash as createHash2 } from "node:crypto";
76814
+ import { mkdir as mkdir17, readFile as readFile17, rm as rm9, writeFile as writeFile17 } from "node:fs/promises";
76815
+ import { tmpdir as tmpdir2 } from "node:os";
76624
76816
  import { dirname as dirname17, join as join19 } from "node:path";
76817
+ var USAGE6 = `Usage: laze vault run <connection> --reason "<one plain sentence>" [--wait <s>] -- <command> [args...]
76818
+ Runs the command with the connection's values in its environment, on a Laze agent's computer,
76819
+ on a machine it runs on, or where a connected agent runs, with its own key.
76820
+ --channel <id> the conversation whose turn it runs in, when the agent answers in several`;
76821
+ var POLL_MS = 3e3;
76822
+ var RESTART_WAIT_MS = 12e4;
76823
+ var RESTART_BACKOFF_MS = [1e3, 2e3, 4e3, 8e3, 1e4];
76824
+ var P2562 = { name: "ECDH", namedCurve: "P-256" };
76825
+ var ServerGoneError = class extends Error {
76826
+ };
76827
+ function proxyOf({ env }) {
76828
+ const raw = env.LAZE_VAULT_PROXY || env.HTTP_PROXY || env.http_proxy;
76829
+ if (!raw) return null;
76830
+ const url2 = new URL(raw);
76831
+ const user = decodeURIComponent(url2.username);
76832
+ const password = decodeURIComponent(url2.password);
76833
+ return {
76834
+ origin: url2.origin,
76835
+ authorization: `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`
76836
+ };
76837
+ }
76838
+ function turnFileOf({
76839
+ env
76840
+ }) {
76841
+ return env.LAZE_TURN_FILE || void 0;
76842
+ }
76843
+ async function turnTokenOf2({
76844
+ env,
76845
+ turnFile,
76846
+ command = "laze vault run"
76847
+ }) {
76848
+ const pinned = env.LAZE_TURN_TOKEN?.trim();
76849
+ if (pinned) return pinned;
76850
+ if (!turnFile) throw new CliUsageError(`${command} works only during an agent's turn`);
76851
+ try {
76852
+ return (await readFile17(turnFile, "utf8")).trim();
76853
+ } catch {
76854
+ throw new CliUsageError(`${command} works only during an agent's turn`);
76855
+ }
76856
+ }
76857
+ function runKeyPathOf({
76858
+ turnFile,
76859
+ connection,
76860
+ profile = ""
76861
+ }) {
76862
+ const name3 = createHash2("sha256").update(connection).digest("hex");
76863
+ const base = turnFile ? dirname17(turnFile) : join19(tmpdir2(), "laze-vault", profile);
76864
+ return join19(base, "vault-run-keys", `${name3}.json`);
76865
+ }
76866
+ async function runKeyAt({ path }) {
76867
+ const saved3 = await readFile17(path, "utf8").then(
76868
+ (text2) => JSON.parse(text2),
76869
+ () => void 0
76870
+ );
76871
+ if (saved3 && typeof saved3.publicKey === "string" && saved3.privateKey) {
76872
+ const privateKey = await globalThis.crypto.subtle.importKey("jwk", saved3.privateKey, P2562, false, ["deriveBits"]).catch(() => void 0);
76873
+ if (privateKey) return { privateKey, publicKey: saved3.publicKey };
76874
+ }
76875
+ const fresh = await generateEcdhKeys();
76876
+ const jwk = await globalThis.crypto.subtle.exportKey("jwk", fresh.privateKey);
76877
+ await mkdir17(dirname17(path), { recursive: true, mode: 448 });
76878
+ await writeFile17(path, JSON.stringify({ publicKey: fresh.publicKey, privateKey: jwk }), {
76879
+ mode: 384
76880
+ });
76881
+ return fresh;
76882
+ }
76883
+ function connectionRefused(error62) {
76884
+ const cause = error62.cause;
76885
+ if (cause?.code === "ECONNREFUSED") return true;
76886
+ return cause?.errors?.some((inner) => inner.code === "ECONNREFUSED") ?? false;
76887
+ }
76888
+ async function sendOnce({
76889
+ context,
76890
+ url: url2,
76891
+ init
76892
+ }) {
76893
+ let response;
76894
+ try {
76895
+ response = await context.fetcher(url2, init);
76896
+ } catch (error62) {
76897
+ const wasRefused = connectionRefused(error62);
76898
+ if (init.method === "POST" && !wasRefused) throw error62;
76899
+ return { restarting: wasRefused ? "connection refused" : String(error62) };
76900
+ }
76901
+ if (response.status !== 502 && response.status !== 503) return { response };
76902
+ const code = codeOf(await response.clone().text());
76903
+ const neverReached = response.status === 503 && code === "vault_not_answering";
76904
+ if (init.method === "POST" && !neverReached) return { response };
76905
+ return { restarting: `status ${response.status}${code ? ` ${code}` : ""}` };
76906
+ }
76907
+ async function reach(input2) {
76908
+ const { context } = input2;
76909
+ const started = context.nowMs();
76910
+ for (let attempt = 0; ; attempt += 1) {
76911
+ const sent = await sendOnce(input2);
76912
+ if ("response" in sent) return sent.response;
76913
+ if (context.nowMs() - started >= RESTART_WAIT_MS) {
76914
+ throw new ServerGoneError(
76915
+ `laze vault: the Laze server did not come back (${sent.restarting})`
76916
+ );
76917
+ }
76918
+ if (attempt === 0) {
76919
+ context.err(
76920
+ `laze vault: the Laze server is not answering (${sent.restarting}), probably restarting; waiting up to 2 min...
76921
+ `
76922
+ );
76923
+ }
76924
+ await context.sleep(RESTART_BACKOFF_MS[Math.min(attempt, RESTART_BACKOFF_MS.length - 1)] ?? 0);
76925
+ }
76926
+ }
76927
+ function codeOf(text2) {
76928
+ return /"code"\s*:\s*"([^"]+)"/.exec(text2)?.[1];
76929
+ }
76930
+ async function releaseOf({ response }) {
76931
+ const text2 = await response.text();
76932
+ if (!response.ok) {
76933
+ return {
76934
+ outcome: "deny",
76935
+ exitCode: 1,
76936
+ message: `laze vault: the release was refused (${codeOf(text2) ?? `status ${response.status}`})`
76937
+ };
76938
+ }
76939
+ return JSON.parse(text2);
76940
+ }
76941
+ async function envOf({
76942
+ release: release2,
76943
+ run: run4
76944
+ }) {
76945
+ if (!release2.sealed) return release2.env;
76946
+ const sealed = await openRunRelease({
76947
+ release: release2.sealed,
76948
+ runPrivateKey: run4.privateKey,
76949
+ runPublicKey: run4.publicKey,
76950
+ requestId: release2.sealed.requestId
76951
+ });
76952
+ return { ...release2.env, ...sealed };
76953
+ }
76954
+ function deadlineOf({ args, nowMs }) {
76955
+ const wait = flagText({ args, name: "wait" }) || (args.flags.wait === true ? args.words[3] : "");
76956
+ if (!wait) return Infinity;
76957
+ if (!(Number(wait) >= 0)) throw new CliUsageError(`--wait takes a number of seconds
76958
+ ${USAGE6}`);
76959
+ return nowMs + Number(wait) * 1e3;
76960
+ }
76961
+ async function untilAnswered({
76962
+ context,
76963
+ first,
76964
+ next,
76965
+ deadline
76966
+ }) {
76967
+ let release2 = first;
76968
+ while (release2.outcome === "ask") {
76969
+ if (context.nowMs() + POLL_MS > deadline) {
76970
+ context.err(`${release2.message}. Not approved yet; ask again later.
76971
+ `);
76972
+ return "capped";
76973
+ }
76974
+ if (release2 === first) {
76975
+ context.err(`${release2.message}. Waiting for an answer (cards expire after 12 hours)...
76976
+ `);
76977
+ }
76978
+ await context.sleep(POLL_MS);
76979
+ release2 = await next(release2.requestId);
76980
+ }
76981
+ return release2;
76982
+ }
76983
+ function leaseHolds({
76984
+ release: release2,
76985
+ nowMs
76986
+ }) {
76987
+ const ends = release2.sealed?.leaseEndsAt;
76988
+ return ends !== void 0 && Temporal3.Instant.from(ends).epochMilliseconds > nowMs;
76989
+ }
76990
+ async function vaultRelease({
76991
+ context,
76992
+ args,
76993
+ connection,
76994
+ reason,
76995
+ command
76996
+ }) {
76997
+ const deadline = deadlineOf({ args, nowMs: context.nowMs() });
76998
+ const env = context.environment.inherited;
76999
+ const proxy = proxyOf({ env });
77000
+ if (!proxy) return keyRelease({ context, args, connection, reason, command, deadline });
77001
+ const turnFile = turnFileOf({ env });
77002
+ const headers = {
77003
+ "proxy-authorization": proxy.authorization,
77004
+ "x-laze-turn": await turnTokenOf2({ env, turnFile })
77005
+ };
77006
+ const keyPath = runKeyPathOf({ turnFile, connection });
77007
+ const run4 = await runKeyAt({ path: keyPath });
77008
+ const body = JSON.stringify({ connection, reason, command, recipient: run4.publicKey });
77009
+ let release2;
77010
+ try {
77011
+ const first = await releaseOf({
77012
+ response: await reach({
77013
+ context,
77014
+ url: `${proxy.origin}/vault/release`,
77015
+ init: { method: "POST", headers: { ...headers, "content-type": "application/json" }, body }
77016
+ })
77017
+ });
77018
+ const next = async (requestId) => releaseOf({
77019
+ response: await reach({
77020
+ context,
77021
+ url: `${proxy.origin}/vault/release/${encodeURIComponent(requestId)}`,
77022
+ init: { method: "GET", headers }
77023
+ })
77024
+ });
77025
+ release2 = await untilAnswered({ context, first, next, deadline });
77026
+ } catch (error62) {
77027
+ if (!(error62 instanceof ServerGoneError)) throw error62;
77028
+ context.err(`${error62.message}. Run the command again to keep waiting.
77029
+ `);
77030
+ return { exitCode: 75 };
77031
+ }
77032
+ return settled({ context, release: release2, run: run4, keyPath });
77033
+ }
77034
+ async function settled({
77035
+ context,
77036
+ release: release2,
77037
+ run: run4,
77038
+ keyPath
77039
+ }) {
77040
+ if (release2 === "capped") return { exitCode: 75 };
77041
+ if (release2.outcome === "deny") {
77042
+ await rm9(keyPath, { force: true });
77043
+ context.err(`${release2.message}
77044
+ `);
77045
+ return { exitCode: release2.exitCode || 1 };
77046
+ }
77047
+ const values = await envOf({ release: release2, run: run4 });
77048
+ if (!leaseHolds({ release: release2, nowMs: context.nowMs() })) await rm9(keyPath, { force: true });
77049
+ if (release2.message) context.err(`${release2.message}
77050
+ `);
77051
+ return { env: values };
77052
+ }
77053
+ function refusedRelease(error62) {
77054
+ if (!(error62 instanceof LazeApiError)) throw error62;
77055
+ return {
77056
+ outcome: "deny",
77057
+ exitCode: 1,
77058
+ message: `laze vault: the release was refused: ${error62.message} (${error62.code})`
77059
+ };
77060
+ }
77061
+ async function keyRelease({
77062
+ context,
77063
+ args,
77064
+ connection,
77065
+ reason,
77066
+ command,
77067
+ deadline
77068
+ }) {
77069
+ const where = new CliUsageError(
77070
+ "laze vault run works only on a Laze agent's computer, on a machine it runs on, or signed in as a connected agent"
77071
+ );
77072
+ const signed2 = await signedIn({ context, args }).catch(() => null);
77073
+ if (signed2?.profile.kind !== "agent") throw where;
77074
+ const { name: name3 } = signed2;
77075
+ const client = forSession({
77076
+ client: signed2.client,
77077
+ session: await currentSessionOf({ context, args })
77078
+ });
77079
+ const channelId = flagText({ args, name: "channel" }) || null;
77080
+ const keyPath = runKeyPathOf({ turnFile: void 0, connection, profile: name3 });
77081
+ const run4 = await runKeyAt({ path: keyPath });
77082
+ const first = await client.post("/api/agents/me/vault/release", {
77083
+ connection,
77084
+ reason,
77085
+ command,
77086
+ recipient: run4.publicKey,
77087
+ channelId
77088
+ }).catch(refusedRelease);
77089
+ const next = (requestId) => client.post("/api/agents/me/vault/release-status", { requestId, channelId }).catch(refusedRelease);
77090
+ const release2 = await untilAnswered({ context, first, next, deadline });
77091
+ return settled({ context, release: release2, run: run4, keyPath });
77092
+ }
77093
+ async function vaultRun({
77094
+ context,
77095
+ args
77096
+ }) {
77097
+ const connection = args.words[2];
77098
+ const reason = flagText({ args, name: "reason" });
77099
+ if (!connection || args.rest.length === 0) throw new CliUsageError(USAGE6);
77100
+ if (!reason) throw new CliUsageError(`Say why with --reason "<one plain sentence>"
77101
+ ${USAGE6}`);
77102
+ const foreign = commandReferenceNames({ command: args.rest }).find(
77103
+ (name3) => vaultReferenceConnectionName({ name: name3 }) !== connection
77104
+ );
77105
+ if (foreign !== void 0) {
77106
+ const named = vaultReferenceConnectionName({ name: foreign });
77107
+ context.err(
77108
+ `laze vault: the command names {{vault:${foreign}}}, but this run releases only ${connection}, not ${named}. Nothing was asked and the command did not run.
77109
+ `
77110
+ );
77111
+ return 1;
77112
+ }
77113
+ const released = await vaultRelease({ context, args, connection, reason, command: args.rest });
77114
+ if ("exitCode" in released) return released.exitCode;
77115
+ const prepared = preparedCommand({
77116
+ command: args.rest,
77117
+ released: /* @__PURE__ */ new Map([[connection, released.env]])
77118
+ });
77119
+ if ("refusal" in prepared) {
77120
+ context.err(`${prepared.refusal}
77121
+ `);
77122
+ return 1;
77123
+ }
77124
+ const redact = secretValuesOf({ fields: released.env });
77125
+ return context.runCommand({ command: prepared.command, env: released.env, redact });
77126
+ }
77127
+ function preparedCommand({
77128
+ command,
77129
+ released
77130
+ }) {
77131
+ for (const [name3, fields] of released) {
77132
+ const [problem] = unusableFieldProblems({ fields });
77133
+ if (problem !== void 0) {
77134
+ return {
77135
+ refusal: `laze vault: ${name3}: ${problem}, so the command did not run. Ask its owner to save the real value on the vault page.`
77136
+ };
77137
+ }
77138
+ }
77139
+ const filled = fillCommandReferences({ command, released });
77140
+ if ("refusal" in filled) {
77141
+ return { refusal: `laze vault: ${filled.refusal}. The command did not run.` };
77142
+ }
77143
+ return filled;
77144
+ }
76625
77145
 
76626
77146
  // src/services/browser-tab-commands.service.ts
76627
77147
  var BROWSER_TAB_PATHS = {
@@ -76633,19 +77153,30 @@ var BROWSER_TAB_PATHS = {
76633
77153
  ask: "/api/compute/browser-tabs/ask",
76634
77154
  share: "/api/compute/browser-tabs/share",
76635
77155
  close: "/api/compute/browser-tabs/close",
76636
- cdp: "/api/compute/browser-tabs/cdp"
77156
+ cdp: "/api/compute/browser-tabs/cdp",
77157
+ login: "/api/compute/browser-tabs/login"
76637
77158
  };
77159
+ var ASK_WAIT_SECONDS = 15 * 60;
77160
+ var ASK_POLL_MS = 3e3;
76638
77161
  var BROWSER_TAB_USAGE = [
76639
77162
  "Usage: laze browser open <url> [--title <title>] [--channel <channel>] a live browser tab in the conversation",
76640
77163
  " laze browser tabs [--channel <channel>] the conversation's browser tabs",
76641
77164
  " laze browser tab <tab> one tab: its owner, sharing and page",
76642
77165
  " laze browser goto <tab> <url> send the tab to another page",
76643
77166
  " laze browser read <tab> the page's address, title and text",
76644
- " laze browser ask <tab> <what> ask the person you work for to sign in or click something there",
77167
+ " laze browser ask <tab> <what> [--wait[=<seconds>]] ask the person you work for to sign in or click something there",
77168
+ " laze browser login <tab> --vault <connection> [--reason <why>] [--user-field <field> --pass-field <field>]",
77169
+ " [--user-input <css> --pass-input <css>] type a saved sign-in into the page and submit it",
76645
77170
  " laze browser cdp <tab> a CDP address on the tab's browser",
76646
77171
  " laze browser share <tab> private|watch|use who sees the screen and who types into it",
76647
77172
  " laze browser close <tab> unpin the tab and close its browser",
76648
- "A tab is named by its id or its title."
77173
+ "A tab is named by its id or its title. Opening a title that is already open reuses that tab.",
77174
+ "Any agent working for the tab's owner drives it, connected agents (Claude Code, Codex) from",
77175
+ "their own session included; no Laze computer is needed. Another person's agent cannot.",
77176
+ "Sign-ins: ask the person in the tab first (`laze browser ask`); they sign in on the screen and",
77177
+ "press Done, which reaches you at once. Use `laze browser login --vault` only when the person",
77178
+ "says to use a saved key; a code or emailed link it meets becomes a request to them in the tab.",
77179
+ "Never write scripts that type passwords."
76649
77180
  ].join("\n");
76650
77181
  var SHARING = /* @__PURE__ */ new Set(["private", "watch", "use"]);
76651
77182
  function channelOf({ context, args }) {
@@ -76677,6 +77208,12 @@ async function openTab({ args, client, channel, print: print9 }) {
76677
77208
  ...title ? { title } : {},
76678
77209
  ...channel
76679
77210
  });
77211
+ if (tab.reused)
77212
+ return print9(
77213
+ tab,
77214
+ `Reused ${tab.title} (${tab.id}), ${tab.ownerName}'s browser tab already open, and sent it to ${tab.url}
77215
+ `
77216
+ );
76680
77217
  print9(
76681
77218
  tab,
76682
77219
  `Opened ${tab.title} (${tab.id}) in ${tab.ownerName}'s browser, pinned as a tab of the conversation.
@@ -76714,17 +77251,134 @@ async function readTab({ args, client, channel, print: print9 }) {
76714
77251
  });
76715
77252
  print9(page, pageText({ page }));
76716
77253
  }
76717
- async function askOnTab({ args, client, channel, print: print9 }) {
77254
+ async function askOnTab(run4) {
77255
+ const { args, client, channel, print: print9 } = run4;
76718
77256
  const tab = word({ args, at: 2 });
76719
77257
  const text2 = args.words.slice(3).join(" ").trim();
76720
77258
  if (!text2) throw new CliUsageError(BROWSER_TAB_USAGE);
76721
77259
  const asked = await client.post(BROWSER_TAB_PATHS.ask, { tab, text: text2, ...channel });
76722
- print9(
76723
- asked,
76724
- `Asked ${asked.ask?.userName ?? asked.ownerName} in the conversation; the tab shows them your request with Done.
77260
+ const who = asked.ask?.userName ?? asked.ownerName;
77261
+ if (args.flags.wait === void 0)
77262
+ return print9(
77263
+ asked,
77264
+ `Asked ${who} in the conversation; the tab shows them your request full screen with "Done, hand back".
76725
77265
  Wait for their "Done" message before you go on in ${asked.title}.
77266
+ `
77267
+ );
77268
+ run4.context.err(`Asked ${who} in the conversation; waiting for their Done...
77269
+ `);
77270
+ return waitForDone({ run: run4, tab: asked, who });
77271
+ }
77272
+ async function waitForDone({
77273
+ run: run4,
77274
+ tab,
77275
+ who
77276
+ }) {
77277
+ const { context, args, client, channel, print: print9 } = run4;
77278
+ const seconds = Number(flagText({ args, name: "wait" }) || ASK_WAIT_SECONDS);
77279
+ if (!(seconds > 0)) throw new CliUsageError(BROWSER_TAB_USAGE);
77280
+ const deadline = context.nowMs() + seconds * 1e3;
77281
+ while (context.nowMs() < deadline) {
77282
+ await context.sleep(Math.min(ASK_POLL_MS, Math.max(0, deadline - context.nowMs())));
77283
+ const now = await client.post(BROWSER_TAB_PATHS.get, { tab: tab.id, ...channel });
77284
+ if (!now.ask) return print9(now, `${who} pressed Done. ${now.title} shows ${now.url}
77285
+ `);
77286
+ }
77287
+ print9(
77288
+ tab,
77289
+ `${who} has not pressed Done yet; the request stays open. Wait for their "Done" message.
76726
77290
  `
76727
77291
  );
77292
+ return 75;
77293
+ }
77294
+ async function loginOnTab(run4) {
77295
+ const { context, args, client, channel, json: json5 } = run4;
77296
+ const tab = word({ args, at: 2 });
77297
+ const connection = flagText({ args, name: "vault" });
77298
+ if (!connection)
77299
+ throw new CliUsageError(
77300
+ `Name the saved sign-in with --vault <connection>
77301
+ ${BROWSER_TAB_USAGE}`
77302
+ );
77303
+ const reason = flagText({ args, name: "reason" }) || `Sign in on the ${tab} browser tab of the conversation`;
77304
+ const released = await vaultRelease({
77305
+ context,
77306
+ args,
77307
+ connection,
77308
+ reason,
77309
+ command: ["laze", "browser", "login", tab]
77310
+ });
77311
+ if ("exitCode" in released) return released.exitCode;
77312
+ const [problem] = unusableFieldProblems({ fields: released.env });
77313
+ if (problem !== void 0) {
77314
+ context.err(`laze browser login: ${connection}: ${problem}. Nothing was typed.
77315
+ `);
77316
+ return 1;
77317
+ }
77318
+ const values = loginValuesOf({
77319
+ connection,
77320
+ values: released.env,
77321
+ userField: flagText({ args, name: "user-field" }) || void 0,
77322
+ passField: flagText({ args, name: "pass-field" }) || void 0
77323
+ });
77324
+ if ("refusal" in values) {
77325
+ context.err(`${values.refusal}
77326
+ `);
77327
+ return 1;
77328
+ }
77329
+ const userInput = flagText({ args, name: "user-input" });
77330
+ const passInput = flagText({ args, name: "pass-input" });
77331
+ const answer4 = await client.post(BROWSER_TAB_PATHS.login, {
77332
+ tab,
77333
+ ...values,
77334
+ ...userInput ? { userInput } : {},
77335
+ ...passInput ? { passInput } : {},
77336
+ ...channel
77337
+ });
77338
+ const screenshotPath = answer4.screenshot ? await savedScreenshot({
77339
+ tabId: answer4.tabId,
77340
+ data: answer4.screenshot,
77341
+ nowMs: context.nowMs()
77342
+ }) : null;
77343
+ const { screenshot: _shown, ...rest } = answer4;
77344
+ if (json5) context.out(`${JSON.stringify({ ...rest, screenshotPath }, null, 2)}
77345
+ `);
77346
+ else context.out(loginText({ answer: answer4, tab, screenshotPath }));
77347
+ return answer4.state === "refused" || answer4.state === "still_on_form" ? 1 : 0;
77348
+ }
77349
+ function loginText({
77350
+ answer: answer4,
77351
+ tab,
77352
+ screenshotPath
77353
+ }) {
77354
+ const page = `${answer4.title || "(no title)"}
77355
+ ${answer4.url}
77356
+ `;
77357
+ const shot = screenshotPath ? `Screenshot: ${screenshotPath}
77358
+ ` : "";
77359
+ if (answer4.state === "signed_in") return `Signed in.
77360
+ ${page}${shot}`;
77361
+ if (answer4.state === "second_step")
77362
+ return `The site asks for a second step (a code or an emailed link). Asked ${answer4.askedUserName ?? "the person"} in the conversation to finish it in the tab;
77363
+ wait for their "Done" message before you go on.
77364
+ ${page}${shot}`;
77365
+ if (answer4.state === "refused")
77366
+ return `The site refused the sign-in: ${answer4.error ?? "no reason shown"}
77367
+ ${page}${shot}`;
77368
+ return `Still on the sign-in page after submitting. Look at the screenshot, then ask the person in the tab:
77369
+ laze browser ask ${tab} "Finish signing in"
77370
+ ${page}${shot}`;
77371
+ }
77372
+ async function savedScreenshot({
77373
+ tabId,
77374
+ data,
77375
+ nowMs
77376
+ }) {
77377
+ const folder = join20(tmpdir3(), "laze-browser");
77378
+ await mkdir18(folder, { recursive: true, mode: 448 });
77379
+ const path = join20(folder, `${tabId.replace(/[^a-zA-Z0-9_-]/g, "_")}-login-${nowMs}.jpg`);
77380
+ await writeFile18(path, Buffer.from(data, "base64"), { mode: 384 });
77381
+ return path;
76728
77382
  }
76729
77383
  async function shareTab({ args, client, channel, print: print9 }) {
76730
77384
  const tab = word({ args, at: 2 });
@@ -76750,6 +77404,7 @@ var TAB_RUNS = {
76750
77404
  goto: gotoTab,
76751
77405
  read: readTab,
76752
77406
  ask: askOnTab,
77407
+ login: loginOnTab,
76753
77408
  share: shareTab,
76754
77409
  close: closeTab
76755
77410
  };
@@ -76763,7 +77418,7 @@ async function browserTab({
76763
77418
  const json5 = Boolean(args.flags.json);
76764
77419
  const print9 = (value, text2) => context.out(json5 ? `${JSON.stringify(value, null, 2)}
76765
77420
  ` : text2);
76766
- await handler({ context, args, client, channel: channelOf({ context, args }), json: json5, print: print9 });
77421
+ return handler({ context, args, client, channel: channelOf({ context, args }), json: json5, print: print9 });
76767
77422
  }
76768
77423
  async function browserTabCdp({
76769
77424
  context,
@@ -77178,7 +77833,7 @@ var PATHS2 = {
77178
77833
  wake: "/api/compute/machines/wake",
77179
77834
  delete: "/api/compute/machines/delete"
77180
77835
  };
77181
- var USAGE6 = [
77836
+ var BROWSER_USAGE = [
77182
77837
  "Usage: laze browser setup <site> [--name <machine>] a machine with Chrome a person signs in on",
77183
77838
  " laze browser setup <site> --on <machine> the same on a person's own machine (laze machine list)",
77184
77839
  " laze browser cdp <machine> a CDP address for this turn (Playwright connectOverCDP)",
@@ -77188,7 +77843,7 @@ var USAGE6 = [
77188
77843
  "",
77189
77844
  BROWSER_TAB_USAGE
77190
77845
  ].join("\n");
77191
- async function turnTokenOf2({
77846
+ async function turnTokenOf3({
77192
77847
  context,
77193
77848
  args,
77194
77849
  client,
@@ -77198,7 +77853,7 @@ async function turnTokenOf2({
77198
77853
  const pinned = env.LAZE_TURN_TOKEN?.trim();
77199
77854
  if (pinned) return pinned;
77200
77855
  if (env.LAZE_TURN_FILE) {
77201
- return readFile17(env.LAZE_TURN_FILE, "utf8").then(
77856
+ return readFile18(env.LAZE_TURN_FILE, "utf8").then(
77202
77857
  (text2) => text2.trim(),
77203
77858
  () => ""
77204
77859
  );
@@ -77211,7 +77866,7 @@ async function computeClient({
77211
77866
  args
77212
77867
  }) {
77213
77868
  const { client, profile } = await signedIn({ context, args });
77214
- const turn = await turnTokenOf2({ context, args, client, agent: profile.kind === "agent" });
77869
+ const turn = await turnTokenOf3({ context, args, client, agent: profile.kind === "agent" });
77215
77870
  return turn ? client.withHeaders({ "x-laze-turn": turn }) : client;
77216
77871
  }
77217
77872
  function siteLine(machine2) {
@@ -77225,12 +77880,12 @@ function statusLine(machine2) {
77225
77880
  }
77226
77881
  function machineArg({ args }) {
77227
77882
  const machine2 = args.words[2];
77228
- if (!machine2) throw new CliUsageError(USAGE6);
77883
+ if (!machine2) throw new CliUsageError(BROWSER_USAGE);
77229
77884
  return machine2;
77230
77885
  }
77231
77886
  async function setup({ context, args }) {
77232
77887
  const site = args.words[2];
77233
- if (!site) throw new CliUsageError(USAGE6);
77888
+ if (!site) throw new CliUsageError(BROWSER_USAGE);
77234
77889
  const name3 = flagText({ args, name: "name" }) || void 0;
77235
77890
  const on = flagText({ args, name: "on" }) || void 0;
77236
77891
  const client = await computeClient({ context, args });
@@ -77288,7 +77943,7 @@ async function answering({
77288
77943
  }
77289
77944
  function bridgeStatePath({ context, machine: machine2 }) {
77290
77945
  const safe = machine2.replace(/[^a-zA-Z0-9_-]/g, "_");
77291
- return join19(dirname17(context.environment.configPath), "bridges", `${safe}.json`);
77946
+ return join21(dirname18(context.environment.configPath), "bridges", `${safe}.json`);
77292
77947
  }
77293
77948
  async function bridgePort({
77294
77949
  context,
@@ -77296,7 +77951,7 @@ async function bridgePort({
77296
77951
  access
77297
77952
  }) {
77298
77953
  const path = bridgeStatePath({ context, machine: machine2 });
77299
- const live = await readFile17(path, "utf8").then(
77954
+ const live = await readFile18(path, "utf8").then(
77300
77955
  (text2) => JSON.parse(text2),
77301
77956
  () => void 0
77302
77957
  );
@@ -77309,15 +77964,15 @@ async function bridgePort({
77309
77964
  key,
77310
77965
  ...target
77311
77966
  });
77312
- await mkdir17(dirname17(path), { recursive: true, mode: 448 });
77313
- await writeFile17(path, JSON.stringify({ port, key }), { mode: 384 });
77967
+ await mkdir19(dirname18(path), { recursive: true, mode: 448 });
77968
+ await writeFile19(path, JSON.stringify({ port, key }), { mode: 384 });
77314
77969
  return port;
77315
77970
  }
77316
77971
  async function bridge({ context }) {
77317
77972
  const env = context.environment.inherited;
77318
77973
  const target = env.LAZE_CDP_TARGET;
77319
77974
  const expiresAt = env.LAZE_CDP_EXPIRES_AT;
77320
- if (!target || !expiresAt) throw new CliUsageError(USAGE6);
77975
+ if (!target || !expiresAt) throw new CliUsageError(BROWSER_USAGE);
77321
77976
  let until = Temporal3.Instant.from(expiresAt).epochMilliseconds;
77322
77977
  const running = await startCdpBridge({
77323
77978
  target,
@@ -77374,8 +78029,21 @@ async function change({
77374
78029
  `);
77375
78030
  context.out(statusLine(machine2));
77376
78031
  }
77377
- var TAB_COMMANDS = /* @__PURE__ */ new Set(["open", "tabs", "tab", "goto", "read", "ask", "share", "close"]);
77378
- async function browser({ context, args }) {
78032
+ var TAB_COMMANDS = /* @__PURE__ */ new Set([
78033
+ "open",
78034
+ "tabs",
78035
+ "tab",
78036
+ "goto",
78037
+ "read",
78038
+ "ask",
78039
+ "login",
78040
+ "share",
78041
+ "close"
78042
+ ]);
78043
+ async function browser({
78044
+ context,
78045
+ args
78046
+ }) {
77379
78047
  const command = args.words[1];
77380
78048
  if (command && TAB_COMMANDS.has(command))
77381
78049
  return browserTab({ context, args, client: await computeClient({ context, args }) });
@@ -77386,7 +78054,7 @@ async function browser({ context, args }) {
77386
78054
  if (command === "status") return status3({ context, args });
77387
78055
  if (command === "sleep" || command === "wake" || command === "delete")
77388
78056
  return change({ context, args, path: PATHS2[command] });
77389
- throw new CliUsageError(USAGE6);
78057
+ throw new CliUsageError(BROWSER_USAGE);
77390
78058
  }
77391
78059
 
77392
78060
  // src/rules/channel-format.rules.ts
@@ -77958,7 +78626,7 @@ async function channelSettings({ context, args }) {
77958
78626
  }
77959
78627
 
77960
78628
  // src/services/chat-actions-commands.service.ts
77961
- import { readFile as readFile18 } from "node:fs/promises";
78629
+ import { readFile as readFile19 } from "node:fs/promises";
77962
78630
  import { basename as basename3, isAbsolute as isAbsolute2, relative as relative4, resolve as resolve7 } from "node:path";
77963
78631
 
77964
78632
  // src/rules/file-types.rules.ts
@@ -78040,7 +78708,7 @@ async function uploadFile({
78040
78708
 
78041
78709
  // src/services/thread-wait-commands.service.ts
78042
78710
  var USAGE7 = "Usage: laze thread <message-id> --wait-reply [--timeout <1-3600 seconds>]";
78043
- var POLL_MS = 3e3;
78711
+ var POLL_MS2 = 3e3;
78044
78712
  function timeoutOf({ args }) {
78045
78713
  const seconds = Number(flagText({ args, name: "timeout", fallback: "600" }));
78046
78714
  if (!Number.isInteger(seconds) || seconds < 1 || seconds > 3600) throw new CliUsageError(USAGE7);
@@ -78057,8 +78725,8 @@ async function threadWaitReply({
78057
78725
  const read3 = () => client.post(CHAT_KEY_PATHS.thread, { messageId });
78058
78726
  const seen = new Set((await read3()).replies.map((reply2) => reply2.id));
78059
78727
  const isNew = (reply2) => reply2.author.kind === "person" && !seen.has(reply2.id);
78060
- for (let waited = 0; waited < seconds * 1e3; waited += POLL_MS) {
78061
- await context.sleep(POLL_MS);
78728
+ for (let waited = 0; waited < seconds * 1e3; waited += POLL_MS2) {
78729
+ await context.sleep(POLL_MS2);
78062
78730
  const reply2 = (await read3()).replies.find(isNew);
78063
78731
  if (!reply2) continue;
78064
78732
  const line = `${reply2.seq} ${reply2.id} person ${reply2.author.id} ${reply2.body}
@@ -78296,7 +78964,7 @@ function uploadNameOf({ cwd, path }) {
78296
78964
  }
78297
78965
  var fileUpload = async ({ context, args, client }) => {
78298
78966
  const path = resolve7(context.cwd, wordAt(args, 3));
78299
- const bytes = new Uint8Array(await readFile18(path));
78967
+ const bytes = new Uint8Array(await readFile19(path));
78300
78968
  const answer4 = await uploadFile({
78301
78969
  context,
78302
78970
  client,
@@ -78469,7 +79137,7 @@ async function chatActions({
78469
79137
  }
78470
79138
 
78471
79139
  // src/services/claude-monitor.service.ts
78472
- import { readFile as readFile19, rm as rm9 } from "node:fs/promises";
79140
+ import { readFile as readFile20, rm as rm10 } from "node:fs/promises";
78473
79141
  var MONITOR_IDLE_MS = 3e4;
78474
79142
  var MONITOR_OUTRANKED_MS = 3e3;
78475
79143
  async function deliverOnce({
@@ -78531,7 +79199,7 @@ async function monitorRound(turn) {
78531
79199
  async function release({ context, profile }) {
78532
79200
  const lock = statePathOf({ context, kind: "waiters", profile });
78533
79201
  if ((await holderOf({ path: lock }))?.pid === context.processes.pid)
78534
- await rm9(lock, { force: true });
79202
+ await rm10(lock, { force: true });
78535
79203
  }
78536
79204
  async function monitorHook({ context, args }) {
78537
79205
  const claudePid = await claudePidOf({ context });
@@ -78570,7 +79238,7 @@ async function monitorSessionOf({
78570
79238
  const fromEnv = sessionOf({ context, harness: "claude-code", sessionId });
78571
79239
  if (fromEnv || !claudePid) return fromEnv;
78572
79240
  const path = statePathOf({ context, kind: "sessions", profile: String(claudePid) });
78573
- return readFile19(path, "utf8").then(
79241
+ return readFile20(path, "utf8").then(
78574
79242
  (text2) => JSON.parse(text2),
78575
79243
  () => void 0
78576
79244
  );
@@ -78607,6 +79275,8 @@ var browserTabDefinition = external_exports.object({
78607
79275
  /** What an agent asked a person to do in the tab, until someone who may answer presses Done. */
78608
79276
  ask: browserTabAskDefinition.nullable(),
78609
79277
  createdAt: external_exports.iso.datetime(),
79278
+ /** Only on an open: an open tab of that title was reused instead of making a second one. */
79279
+ reused: external_exports.boolean().optional(),
78610
79280
  /** What the reader may do: see the screen, type into it, change the tab; asked: the open
78611
79281
  * request names them. */
78612
79282
  you: external_exports.object({
@@ -78654,6 +79324,31 @@ var shareDefinition = external_exports.object({
78654
79324
  sharing: browserTabSharingSchema
78655
79325
  });
78656
79326
  var browserTabShareInputSchema = shareDefinition;
79327
+ var loginDefinition = external_exports.object({
79328
+ ...browserTabRefDefinition.shape,
79329
+ username: external_exports.string().min(1).max(1e3).optional(),
79330
+ password: external_exports.string().min(1).max(1e3),
79331
+ userInput: external_exports.string().trim().min(1).max(300).optional(),
79332
+ passInput: external_exports.string().trim().min(1).max(300).optional()
79333
+ });
79334
+ var browserLoginStateSchema = external_exports.enum([
79335
+ "signed_in",
79336
+ "second_step",
79337
+ "refused",
79338
+ "still_on_form"
79339
+ ]);
79340
+ var loginAnswerDefinition = external_exports.object({
79341
+ tabId: external_exports.string().min(1),
79342
+ url: external_exports.string(),
79343
+ title: external_exports.string(),
79344
+ state: browserLoginStateSchema,
79345
+ /** The page's error line when it refused the sign-in. */
79346
+ error: external_exports.string().nullable(),
79347
+ /** The screen after submitting, a JPEG in base64; null when the browser gave none. */
79348
+ screenshot: external_exports.string().nullable(),
79349
+ /** On a second step: the person the tab now asks to finish it. */
79350
+ askedUserName: external_exports.string().nullable()
79351
+ });
78657
79352
  var browserTabPageDefinition = external_exports.object({
78658
79353
  tabId: external_exports.string().min(1),
78659
79354
  url: external_exports.string(),
@@ -78693,6 +79388,7 @@ var restBrowserTabInputDefinition = browserTabRefDefinition.omit({ workspaceId:
78693
79388
  var restBrowserTabGotoInputDefinition = gotoDefinition.omit({ workspaceId: true });
78694
79389
  var restBrowserTabAskInputDefinition = askDefinition.omit({ workspaceId: true });
78695
79390
  var restBrowserTabShareInputDefinition = shareDefinition.omit({ workspaceId: true });
79391
+ var restBrowserTabLoginInputDefinition = loginDefinition.omit({ workspaceId: true });
78696
79392
 
78697
79393
  // ../../modules/compute/contract/src/compute.config.ts
78698
79394
  var computeConfig = Config.define((c) => ({
@@ -80005,6 +80701,7 @@ var machineWatchStateDefinition = external_exports.object({
80005
80701
  var computeUi = uiTokens("compute");
80006
80702
  var ComputeBrowserTabSlot = computeUi.component("browser-tab");
80007
80703
  var ComputeOpenBrowserSlot = computeUi.component("open-browser");
80704
+ var ComputeBrowserLinkOfferSlot = computeUi.component("browser-link-offer");
80008
80705
 
80009
80706
  // src/services/computer-fleet-commands.service.ts
80010
80707
  var COMPUTER_FLEET_USAGE = ` laze computer mine [--json] every Laze computer your agents may run on, your default one first
@@ -80278,10 +80975,10 @@ async function computer({ context, args }) {
80278
80975
  }
80279
80976
 
80280
80977
  // src/services/connect-commands.service.ts
80281
- import { readFile as readFile21 } from "node:fs/promises";
80978
+ import { readFile as readFile22 } from "node:fs/promises";
80282
80979
 
80283
80980
  // src/services/mcp-gateway.service.ts
80284
- import { readFile as readFile20 } from "node:fs/promises";
80981
+ import { readFile as readFile21 } from "node:fs/promises";
80285
80982
  import { createInterface as createInterface3 } from "node:readline";
80286
80983
  var TURN_HEADER = "x-laze-turn";
80287
80984
  function serveMcpGateway({
@@ -80324,7 +81021,7 @@ async function relayMcpLines({
80324
81021
  const github3 = env.LAZE_GITHUB_CONNECTION;
80325
81022
  const url2 = `${profile.url.replace(/\/+$/, "")}/api/connectors/mcp/${encodeURIComponent(profile.agentId)}${github3 ? `?github=${encodeURIComponent(github3)}` : ""}`;
80326
81023
  const turnFile = env.LAZE_TURN_FILE;
80327
- const readTurn = () => readFile20(turnFile, "utf8").then(
81024
+ const readTurn = () => readFile21(turnFile, "utf8").then(
80328
81025
  (text2) => text2.trim(),
80329
81026
  () => ""
80330
81027
  );
@@ -80414,7 +81111,7 @@ async function turnOf({ context }) {
80414
81111
  const pinned = env.LAZE_TURN_TOKEN?.trim();
80415
81112
  if (pinned) return pinned;
80416
81113
  const file3 = env.LAZE_TURN_FILE;
80417
- const turn = file3 ? await readFile21(file3, "utf8").then(
81114
+ const turn = file3 ? await readFile22(file3, "utf8").then(
80418
81115
  (text2) => text2.trim(),
80419
81116
  () => ""
80420
81117
  ) : "";
@@ -80747,335 +81444,6 @@ var listDevices = async ({ context, args }) => {
80747
81444
  }
80748
81445
  };
80749
81446
 
80750
- // src/services/vault-commands.service.ts
80751
- import { createHash as createHash2 } from "node:crypto";
80752
- import { mkdir as mkdir18, readFile as readFile22, rm as rm10, writeFile as writeFile18 } from "node:fs/promises";
80753
- import { tmpdir as tmpdir2 } from "node:os";
80754
- import { dirname as dirname18, join as join20 } from "node:path";
80755
- var USAGE8 = `Usage: laze vault run <connection> --reason "<one plain sentence>" [--wait <s>] -- <command> [args...]
80756
- Runs the command with the connection's values in its environment, on a Laze agent's computer,
80757
- on a machine it runs on, or where a connected agent runs, with its own key.
80758
- --channel <id> the conversation whose turn it runs in, when the agent answers in several`;
80759
- var POLL_MS2 = 3e3;
80760
- var RESTART_WAIT_MS = 12e4;
80761
- var RESTART_BACKOFF_MS = [1e3, 2e3, 4e3, 8e3, 1e4];
80762
- var P2562 = { name: "ECDH", namedCurve: "P-256" };
80763
- var ServerGoneError = class extends Error {
80764
- };
80765
- function proxyOf({ env }) {
80766
- const raw = env.LAZE_VAULT_PROXY || env.HTTP_PROXY || env.http_proxy;
80767
- if (!raw) return null;
80768
- const url2 = new URL(raw);
80769
- const user = decodeURIComponent(url2.username);
80770
- const password = decodeURIComponent(url2.password);
80771
- return {
80772
- origin: url2.origin,
80773
- authorization: `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`
80774
- };
80775
- }
80776
- function turnFileOf({
80777
- env
80778
- }) {
80779
- return env.LAZE_TURN_FILE || void 0;
80780
- }
80781
- async function turnTokenOf3({
80782
- env,
80783
- turnFile,
80784
- command = "laze vault run"
80785
- }) {
80786
- const pinned = env.LAZE_TURN_TOKEN?.trim();
80787
- if (pinned) return pinned;
80788
- if (!turnFile) throw new CliUsageError(`${command} works only during an agent's turn`);
80789
- try {
80790
- return (await readFile22(turnFile, "utf8")).trim();
80791
- } catch {
80792
- throw new CliUsageError(`${command} works only during an agent's turn`);
80793
- }
80794
- }
80795
- function runKeyPathOf({
80796
- turnFile,
80797
- connection,
80798
- profile = ""
80799
- }) {
80800
- const name3 = createHash2("sha256").update(connection).digest("hex");
80801
- const base = turnFile ? dirname18(turnFile) : join20(tmpdir2(), "laze-vault", profile);
80802
- return join20(base, "vault-run-keys", `${name3}.json`);
80803
- }
80804
- async function runKeyAt({ path }) {
80805
- const saved3 = await readFile22(path, "utf8").then(
80806
- (text2) => JSON.parse(text2),
80807
- () => void 0
80808
- );
80809
- if (saved3 && typeof saved3.publicKey === "string" && saved3.privateKey) {
80810
- const privateKey = await globalThis.crypto.subtle.importKey("jwk", saved3.privateKey, P2562, false, ["deriveBits"]).catch(() => void 0);
80811
- if (privateKey) return { privateKey, publicKey: saved3.publicKey };
80812
- }
80813
- const fresh = await generateEcdhKeys();
80814
- const jwk = await globalThis.crypto.subtle.exportKey("jwk", fresh.privateKey);
80815
- await mkdir18(dirname18(path), { recursive: true, mode: 448 });
80816
- await writeFile18(path, JSON.stringify({ publicKey: fresh.publicKey, privateKey: jwk }), {
80817
- mode: 384
80818
- });
80819
- return fresh;
80820
- }
80821
- function connectionRefused(error62) {
80822
- const cause = error62.cause;
80823
- if (cause?.code === "ECONNREFUSED") return true;
80824
- return cause?.errors?.some((inner) => inner.code === "ECONNREFUSED") ?? false;
80825
- }
80826
- async function sendOnce({
80827
- context,
80828
- url: url2,
80829
- init
80830
- }) {
80831
- let response;
80832
- try {
80833
- response = await context.fetcher(url2, init);
80834
- } catch (error62) {
80835
- const wasRefused = connectionRefused(error62);
80836
- if (init.method === "POST" && !wasRefused) throw error62;
80837
- return { restarting: wasRefused ? "connection refused" : String(error62) };
80838
- }
80839
- if (response.status !== 502 && response.status !== 503) return { response };
80840
- const code = codeOf(await response.clone().text());
80841
- const neverReached = response.status === 503 && code === "vault_not_answering";
80842
- if (init.method === "POST" && !neverReached) return { response };
80843
- return { restarting: `status ${response.status}${code ? ` ${code}` : ""}` };
80844
- }
80845
- async function reach(input2) {
80846
- const { context } = input2;
80847
- const started = context.nowMs();
80848
- for (let attempt = 0; ; attempt += 1) {
80849
- const sent = await sendOnce(input2);
80850
- if ("response" in sent) return sent.response;
80851
- if (context.nowMs() - started >= RESTART_WAIT_MS) {
80852
- throw new ServerGoneError(
80853
- `laze vault: the Laze server did not come back (${sent.restarting})`
80854
- );
80855
- }
80856
- if (attempt === 0) {
80857
- context.err(
80858
- `laze vault: the Laze server is not answering (${sent.restarting}), probably restarting; waiting up to 2 min...
80859
- `
80860
- );
80861
- }
80862
- await context.sleep(RESTART_BACKOFF_MS[Math.min(attempt, RESTART_BACKOFF_MS.length - 1)] ?? 0);
80863
- }
80864
- }
80865
- function codeOf(text2) {
80866
- return /"code"\s*:\s*"([^"]+)"/.exec(text2)?.[1];
80867
- }
80868
- async function releaseOf({ response }) {
80869
- const text2 = await response.text();
80870
- if (!response.ok) {
80871
- return {
80872
- outcome: "deny",
80873
- exitCode: 1,
80874
- message: `laze vault: the release was refused (${codeOf(text2) ?? `status ${response.status}`})`
80875
- };
80876
- }
80877
- return JSON.parse(text2);
80878
- }
80879
- async function envOf({
80880
- release: release2,
80881
- run: run4
80882
- }) {
80883
- if (!release2.sealed) return release2.env;
80884
- const sealed = await openRunRelease({
80885
- release: release2.sealed,
80886
- runPrivateKey: run4.privateKey,
80887
- runPublicKey: run4.publicKey,
80888
- requestId: release2.sealed.requestId
80889
- });
80890
- return { ...release2.env, ...sealed };
80891
- }
80892
- function deadlineOf({ args, nowMs }) {
80893
- const wait = flagText({ args, name: "wait" }) || (args.flags.wait === true ? args.words[3] : "");
80894
- if (!wait) return Infinity;
80895
- if (!(Number(wait) >= 0)) throw new CliUsageError(`--wait takes a number of seconds
80896
- ${USAGE8}`);
80897
- return nowMs + Number(wait) * 1e3;
80898
- }
80899
- async function untilAnswered({
80900
- context,
80901
- first,
80902
- next,
80903
- deadline
80904
- }) {
80905
- let release2 = first;
80906
- while (release2.outcome === "ask") {
80907
- if (context.nowMs() + POLL_MS2 > deadline) {
80908
- context.err(`${release2.message}. Not approved yet; ask again later.
80909
- `);
80910
- return "capped";
80911
- }
80912
- if (release2 === first) {
80913
- context.err(`${release2.message}. Waiting for an answer (cards expire after 12 hours)...
80914
- `);
80915
- }
80916
- await context.sleep(POLL_MS2);
80917
- release2 = await next(release2.requestId);
80918
- }
80919
- return release2;
80920
- }
80921
- function leaseHolds({
80922
- release: release2,
80923
- nowMs
80924
- }) {
80925
- const ends = release2.sealed?.leaseEndsAt;
80926
- return ends !== void 0 && Temporal3.Instant.from(ends).epochMilliseconds > nowMs;
80927
- }
80928
- async function vaultRelease({
80929
- context,
80930
- args,
80931
- connection,
80932
- reason,
80933
- command
80934
- }) {
80935
- const deadline = deadlineOf({ args, nowMs: context.nowMs() });
80936
- const env = context.environment.inherited;
80937
- const proxy = proxyOf({ env });
80938
- if (!proxy) return keyRelease({ context, args, connection, reason, command, deadline });
80939
- const turnFile = turnFileOf({ env });
80940
- const headers = {
80941
- "proxy-authorization": proxy.authorization,
80942
- "x-laze-turn": await turnTokenOf3({ env, turnFile })
80943
- };
80944
- const keyPath = runKeyPathOf({ turnFile, connection });
80945
- const run4 = await runKeyAt({ path: keyPath });
80946
- const body = JSON.stringify({ connection, reason, command, recipient: run4.publicKey });
80947
- let release2;
80948
- try {
80949
- const first = await releaseOf({
80950
- response: await reach({
80951
- context,
80952
- url: `${proxy.origin}/vault/release`,
80953
- init: { method: "POST", headers: { ...headers, "content-type": "application/json" }, body }
80954
- })
80955
- });
80956
- const next = async (requestId) => releaseOf({
80957
- response: await reach({
80958
- context,
80959
- url: `${proxy.origin}/vault/release/${encodeURIComponent(requestId)}`,
80960
- init: { method: "GET", headers }
80961
- })
80962
- });
80963
- release2 = await untilAnswered({ context, first, next, deadline });
80964
- } catch (error62) {
80965
- if (!(error62 instanceof ServerGoneError)) throw error62;
80966
- context.err(`${error62.message}. Run the command again to keep waiting.
80967
- `);
80968
- return { exitCode: 75 };
80969
- }
80970
- return settled({ context, release: release2, run: run4, keyPath });
80971
- }
80972
- async function settled({
80973
- context,
80974
- release: release2,
80975
- run: run4,
80976
- keyPath
80977
- }) {
80978
- if (release2 === "capped") return { exitCode: 75 };
80979
- if (release2.outcome === "deny") {
80980
- await rm10(keyPath, { force: true });
80981
- context.err(`${release2.message}
80982
- `);
80983
- return { exitCode: release2.exitCode || 1 };
80984
- }
80985
- const values = await envOf({ release: release2, run: run4 });
80986
- if (!leaseHolds({ release: release2, nowMs: context.nowMs() })) await rm10(keyPath, { force: true });
80987
- if (release2.message) context.err(`${release2.message}
80988
- `);
80989
- return { env: values };
80990
- }
80991
- function refusedRelease(error62) {
80992
- if (!(error62 instanceof LazeApiError)) throw error62;
80993
- return {
80994
- outcome: "deny",
80995
- exitCode: 1,
80996
- message: `laze vault: the release was refused: ${error62.message} (${error62.code})`
80997
- };
80998
- }
80999
- async function keyRelease({
81000
- context,
81001
- args,
81002
- connection,
81003
- reason,
81004
- command,
81005
- deadline
81006
- }) {
81007
- const where = new CliUsageError(
81008
- "laze vault run works only on a Laze agent's computer, on a machine it runs on, or signed in as a connected agent"
81009
- );
81010
- const signed2 = await signedIn({ context, args }).catch(() => null);
81011
- if (signed2?.profile.kind !== "agent") throw where;
81012
- const { client, name: name3 } = signed2;
81013
- const channelId = flagText({ args, name: "channel" }) || null;
81014
- const keyPath = runKeyPathOf({ turnFile: void 0, connection, profile: name3 });
81015
- const run4 = await runKeyAt({ path: keyPath });
81016
- const first = await client.post("/api/agents/me/vault/release", {
81017
- connection,
81018
- reason,
81019
- command,
81020
- recipient: run4.publicKey,
81021
- channelId
81022
- }).catch(refusedRelease);
81023
- const next = (requestId) => client.post("/api/agents/me/vault/release-status", { requestId, channelId }).catch(refusedRelease);
81024
- const release2 = await untilAnswered({ context, first, next, deadline });
81025
- return settled({ context, release: release2, run: run4, keyPath });
81026
- }
81027
- async function vaultRun({
81028
- context,
81029
- args
81030
- }) {
81031
- const connection = args.words[2];
81032
- const reason = flagText({ args, name: "reason" });
81033
- if (!connection || args.rest.length === 0) throw new CliUsageError(USAGE8);
81034
- if (!reason) throw new CliUsageError(`Say why with --reason "<one plain sentence>"
81035
- ${USAGE8}`);
81036
- const foreign = commandReferenceNames({ command: args.rest }).find(
81037
- (name3) => vaultReferenceConnectionName({ name: name3 }) !== connection
81038
- );
81039
- if (foreign !== void 0) {
81040
- const named = vaultReferenceConnectionName({ name: foreign });
81041
- context.err(
81042
- `laze vault: the command names {{vault:${foreign}}}, but this run releases only ${connection}, not ${named}. Nothing was asked and the command did not run.
81043
- `
81044
- );
81045
- return 1;
81046
- }
81047
- const released = await vaultRelease({ context, args, connection, reason, command: args.rest });
81048
- if ("exitCode" in released) return released.exitCode;
81049
- const prepared = preparedCommand({
81050
- command: args.rest,
81051
- released: /* @__PURE__ */ new Map([[connection, released.env]])
81052
- });
81053
- if ("refusal" in prepared) {
81054
- context.err(`${prepared.refusal}
81055
- `);
81056
- return 1;
81057
- }
81058
- return context.runCommand({ command: prepared.command, env: released.env });
81059
- }
81060
- function preparedCommand({
81061
- command,
81062
- released
81063
- }) {
81064
- for (const [name3, fields] of released) {
81065
- const [problem] = unusableFieldProblems({ fields });
81066
- if (problem !== void 0) {
81067
- return {
81068
- refusal: `laze vault: ${name3}: ${problem}, so the command did not run. Ask its owner to save the real value on the vault page.`
81069
- };
81070
- }
81071
- }
81072
- const filled = fillCommandReferences({ command, released });
81073
- if ("refusal" in filled) {
81074
- return { refusal: `laze vault: ${filled.refusal}. The command did not run.` };
81075
- }
81076
- return filled;
81077
- }
81078
-
81079
81447
  // src/services/vault-share-commands.service.ts
81080
81448
  var SHARE_USAGE2 = "Usage: laze vault share <connection> --with <email|userId> [--for 1h]";
81081
81449
  var WAITING_LINE = "It waits for the owner's approval with a passkey or Face ID, in Settings > Vault.";
@@ -81094,7 +81462,7 @@ async function inTurn({
81094
81462
  command
81095
81463
  }) {
81096
81464
  const env = context.environment.inherited;
81097
- const turn = await turnTokenOf3({ env, turnFile: turnFileOf({ env }), command });
81465
+ const turn = await turnTokenOf2({ env, turnFile: turnFileOf({ env }), command });
81098
81466
  return client.withHeaders({ "x-laze-turn": turn });
81099
81467
  }
81100
81468
  function printShare({ context, grant }) {
@@ -81778,16 +82146,16 @@ function dndLine({ pausedUntil }) {
81778
82146
  }
81779
82147
 
81780
82148
  // src/services/dnd-commands.service.ts
81781
- var USAGE9 = "Usage: laze dnd 30m|1h|2h|until <HH:mm|ISO time> [--tz <zone>], laze dnd off";
82149
+ var USAGE8 = "Usage: laze dnd 30m|1h|2h|until <HH:mm|ISO time> [--tz <zone>], laze dnd off";
81782
82150
  async function dnd({ context, args }) {
81783
82151
  const timeZone = flagText({ args, name: "tz" }) || Intl.DateTimeFormat().resolvedOptions().timeZone;
81784
82152
  let input2;
81785
82153
  try {
81786
82154
  input2 = dndInputOf({ words: args.words.slice(1), now: nowInstant(), timeZone });
81787
82155
  } catch {
81788
- throw new CliUsageError(USAGE9);
82156
+ throw new CliUsageError(USAGE8);
81789
82157
  }
81790
- if (!input2) throw new CliUsageError(USAGE9);
82158
+ if (!input2) throw new CliUsageError(USAGE8);
81791
82159
  const { client } = await signedIn({ context, args });
81792
82160
  const settings2 = await client.post(
81793
82161
  "/api/agents/me/notifications/snooze",
@@ -81806,8 +82174,8 @@ var DOMAINS_USAGE = `Usage:
81806
82174
  var printJson5 = (context, data) => context.out(`${JSON.stringify(data, null, 2)}
81807
82175
  `);
81808
82176
  function printDomain(context, row) {
81809
- const join25 = row.autoJoin ? "auto-join on" : "auto-join off";
81810
- context.out(`${row.domain} ${join25}${row.enforced ? " single sign-on enforced" : ""}
82177
+ const join26 = row.autoJoin ? "auto-join on" : "auto-join off";
82178
+ context.out(`${row.domain} ${join26}${row.enforced ? " single sign-on enforced" : ""}
81811
82179
  `);
81812
82180
  }
81813
82181
  async function list4({ context, args }) {
@@ -82036,6 +82404,8 @@ var feedApprovalSchemaDefinition = external_exports.object({
82036
82404
  why: external_exports.string(),
82037
82405
  /** The longest lease Allow for this agent may give; null offers only once and deny. */
82038
82406
  maxLeaseSeconds: external_exports.number().int().positive().nullable(),
82407
+ /** A vault card whose Allow covers the rest of the agent's turn: "Allow for this task". */
82408
+ coversTask: external_exports.boolean().optional(),
82039
82409
  /** The card's timeout; a publish waits without one. */
82040
82410
  expiresAt: external_exports.iso.datetime().nullable(),
82041
82411
  state: feedApprovalStateSchema,
@@ -82612,7 +82982,7 @@ async function feedAttachmentIdsOf({
82612
82982
  }
82613
82983
 
82614
82984
  // src/services/feed-commands.service.ts
82615
- var USAGE10 = `Usage:
82985
+ var USAGE9 = `Usage:
82616
82986
  laze feed post <title> [--channel <channel>] [--tag <tag>] [--summary <line>]
82617
82987
  [--draft <text|@file>] [--draft-header "To: ...\\nRe: ..."]
82618
82988
  [--metric <json|@file.json> | --table <csv|@file.csv>]
@@ -82683,7 +83053,7 @@ function printItem({
82683
83053
  }
82684
83054
  async function feedPost({ context, args }) {
82685
83055
  const title = args.words.slice(2).join(" ").trim();
82686
- if (!title) throw new CliUsageError(USAGE10);
83056
+ if (!title) throw new CliUsageError(USAGE9);
82687
83057
  const flags2 = flagsOf(args);
82688
83058
  const { client } = await signedIn({ context, args });
82689
83059
  const channel = flagText({ args, name: "channel" });
@@ -82705,7 +83075,7 @@ async function feedPost({ context, args }) {
82705
83075
  }
82706
83076
  async function feedUpdate({ context, args }) {
82707
83077
  const itemId = args.words[2];
82708
- if (!itemId) throw new CliUsageError(USAGE10);
83078
+ if (!itemId) throw new CliUsageError(USAGE9);
82709
83079
  const flags2 = flagsOf(args);
82710
83080
  const { client } = await signedIn({ context, args });
82711
83081
  const body = await bodyOf2({ context, flags: flags2 });
@@ -82721,7 +83091,7 @@ async function feedUpdate({ context, args }) {
82721
83091
  async function feedReply({ context, args }) {
82722
83092
  const itemId = args.words[2];
82723
83093
  const text2 = args.words.slice(3).join(" ").trim();
82724
- if (!itemId || !text2) throw new CliUsageError(USAGE10);
83094
+ if (!itemId || !text2) throw new CliUsageError(USAGE9);
82725
83095
  const { client } = await signedIn({ context, args });
82726
83096
  const replied = await client.post("/api/feed/items/reply", {
82727
83097
  itemId,
@@ -82734,7 +83104,7 @@ async function feedReply({ context, args }) {
82734
83104
  }
82735
83105
  async function feedRead({ context, args }) {
82736
83106
  const itemId = args.words[2];
82737
- if (!itemId) throw new CliUsageError(USAGE10);
83107
+ if (!itemId) throw new CliUsageError(USAGE9);
82738
83108
  const { client } = await signedIn({ context, args });
82739
83109
  const read3 = await client.post("/api/feed/items/read", { itemId });
82740
83110
  printItem({ context, args, item: read3 });
@@ -82753,7 +83123,7 @@ async function feedClose({ context, args }) {
82753
83123
  const itemId = args.words[2];
82754
83124
  const loop = flagText({ args, name: "loop" });
82755
83125
  const note = flagText({ args, name: "note" });
82756
- if (!note || Boolean(itemId) === Boolean(loop)) throw new CliUsageError(USAGE10);
83126
+ if (!note || Boolean(itemId) === Boolean(loop)) throw new CliUsageError(USAGE9);
82757
83127
  const { client } = await signedIn({ context, args });
82758
83128
  const closed = await client.post("/api/feed/items/close", {
82759
83129
  ...itemId ? { itemId } : { loop },
@@ -82779,7 +83149,7 @@ async function feedLoops({ context, args }) {
82779
83149
  }
82780
83150
  async function feedGroupSummary({ context, args }) {
82781
83151
  const group = args.words.slice(2).join(" ").trim();
82782
- if (!group) throw new CliUsageError(USAGE10);
83152
+ if (!group) throw new CliUsageError(USAGE9);
82783
83153
  const { client } = await signedIn({ context, args });
82784
83154
  const pointer = await client.post("/api/feed/group-summary", { group });
82785
83155
  if (args.flags.json) return context.out(`${JSON.stringify(pointer, null, 2)}
@@ -82859,7 +83229,7 @@ async function feedDecisions({ context, args }) {
82859
83229
  }
82860
83230
  async function feedAct({ context, args }) {
82861
83231
  const [itemId, actionId] = [args.words[2], args.words[3]];
82862
- if (!itemId || !actionId) throw new CliUsageError(USAGE10);
83232
+ if (!itemId || !actionId) throw new CliUsageError(USAGE9);
82863
83233
  const draft = await textFlag({ context, args, name: "draft" });
82864
83234
  const { client } = await signedIn({ context, args });
82865
83235
  const item = await client.post("/api/feed/mine/act", {
@@ -82872,7 +83242,7 @@ async function feedAct({ context, args }) {
82872
83242
  async function feedComment({ context, args }) {
82873
83243
  const itemId = args.words[2];
82874
83244
  const text2 = args.words.slice(3).join(" ").trim();
82875
- if (!itemId || !text2) throw new CliUsageError(USAGE10);
83245
+ if (!itemId || !text2) throw new CliUsageError(USAGE9);
82876
83246
  const draft = await textFlag({ context, args, name: "draft" });
82877
83247
  const { client } = await signedIn({ context, args });
82878
83248
  const item = await client.post("/api/feed/mine/comment", {
@@ -82886,7 +83256,7 @@ async function feedComment({ context, args }) {
82886
83256
  function moveItem(path) {
82887
83257
  return async ({ context, args }) => {
82888
83258
  const itemId = args.words[2];
82889
- if (!itemId) throw new CliUsageError(USAGE10);
83259
+ if (!itemId) throw new CliUsageError(USAGE9);
82890
83260
  const { client } = await signedIn({ context, args });
82891
83261
  const item = await client.post(`/api/feed/mine/${path}`, { itemId });
82892
83262
  printMoved({ context, args, item });
@@ -82895,14 +83265,14 @@ function moveItem(path) {
82895
83265
  async function feedSnooze({ context, args }) {
82896
83266
  const itemId = args.words[2];
82897
83267
  const until = flagText({ args, name: "until" });
82898
- if (!itemId || !until) throw new CliUsageError(USAGE10);
83268
+ if (!itemId || !until) throw new CliUsageError(USAGE9);
82899
83269
  const { client } = await signedIn({ context, args });
82900
83270
  const item = await client.post("/api/feed/mine/snooze", { itemId, until });
82901
83271
  printMoved({ context, args, item });
82902
83272
  }
82903
83273
  async function feedChannel({ context, args }) {
82904
83274
  const channelId = args.words[2];
82905
- if (!channelId) throw new CliUsageError(USAGE10);
83275
+ if (!channelId) throw new CliUsageError(USAGE9);
82906
83276
  const { client } = await signedIn({ context, args });
82907
83277
  const items = await client.post("/api/feed/channel", { channelId });
82908
83278
  if (args.flags.json) return context.out(`${JSON.stringify(items, null, 2)}
@@ -82933,7 +83303,7 @@ var FEED_COMMANDS = {
82933
83303
  async function feed({ context, args }) {
82934
83304
  const name3 = args.words[1] ?? "";
82935
83305
  const command = Object.hasOwn(FEED_COMMANDS, name3) ? FEED_COMMANDS[name3] : void 0;
82936
- if (!command) throw new CliUsageError(USAGE10);
83306
+ if (!command) throw new CliUsageError(USAGE9);
82937
83307
  await command({ context, args });
82938
83308
  }
82939
83309
 
@@ -83429,12 +83799,12 @@ async function ip({ context, args }) {
83429
83799
  }
83430
83800
 
83431
83801
  // src/services/join-commands.service.ts
83432
- import { mkdir as mkdir19, readFile as readFile29, rename as rename5, rm as rm11, writeFile as writeFile19 } from "node:fs/promises";
83433
- import { dirname as dirname19, join as join21 } from "node:path";
83802
+ import { mkdir as mkdir20, readFile as readFile29, rename as rename5, rm as rm11, writeFile as writeFile20 } from "node:fs/promises";
83803
+ import { dirname as dirname19, join as join22 } from "node:path";
83434
83804
  var DEFAULT_WAIT_SECONDS2 = 100;
83435
83805
  var JOIN_USAGE = "Usage: laze join [--workspace <name|id|invite link>] [--for <email>] [--name <name>] [--note <text>] [--timeout <seconds>] [--project <folder>]";
83436
83806
  function pendingPathOf({ context }) {
83437
- return join21(dirname19(context.environment.configPath), "join", "pending.json");
83807
+ return join22(dirname19(context.environment.configPath), "join", "pending.json");
83438
83808
  }
83439
83809
  async function readPending({
83440
83810
  context,
@@ -83451,9 +83821,9 @@ async function readPending({
83451
83821
  }
83452
83822
  async function keepPending({ context, pending }) {
83453
83823
  const path = pendingPathOf({ context });
83454
- await mkdir19(dirname19(path), { recursive: true, mode: 448 });
83824
+ await mkdir20(dirname19(path), { recursive: true, mode: 448 });
83455
83825
  const temporary = `${path}.${process.pid}.tmp`;
83456
- await writeFile19(temporary, JSON.stringify(pending), { mode: 384 });
83826
+ await writeFile20(temporary, JSON.stringify(pending), { mode: 384 });
83457
83827
  await rename5(temporary, path);
83458
83828
  }
83459
83829
  async function dropPending({ context }) {
@@ -83770,7 +84140,7 @@ function machineAccessCommand(name3) {
83770
84140
  }
83771
84141
 
83772
84142
  // src/services/machine-commands.service.ts
83773
- var USAGE11 = [
84143
+ var USAGE10 = [
83774
84144
  "Usage: laze machine connect <name> the command to run on your own machine (people)",
83775
84145
  " laze machine connect <name> --again a new command for a machine you connected; the old code stops working",
83776
84146
  " laze machine connect <name> --ssh <user>@<host>[:port] a machine that cannot run the connector, over SSH (people)",
@@ -83816,7 +84186,7 @@ function listLine(machine2) {
83816
84186
  var EXEC_ENV_MAX = 32;
83817
84187
  function machineArg2({ args }) {
83818
84188
  const machine2 = args.words[2];
83819
- if (!machine2) throw new CliUsageError(USAGE11);
84189
+ if (!machine2) throw new CliUsageError(USAGE10);
83820
84190
  return machine2;
83821
84191
  }
83822
84192
  async function connect2({ context, args }) {
@@ -83842,7 +84212,7 @@ async function connectSsh({
83842
84212
  }) {
83843
84213
  const ssh = flagText({ args, name: "ssh" });
83844
84214
  if (!ssh) throw new CliUsageError(`--ssh takes <user>@<host>[:port]
83845
- ${USAGE11}`);
84215
+ ${USAGE10}`);
83846
84216
  const client = await computeClient({ context, args });
83847
84217
  const made = await client.post(COMPUTE_REST_PATHS.connectSsh, {
83848
84218
  name: name3,
@@ -83918,11 +84288,11 @@ async function exec({
83918
84288
  }) {
83919
84289
  const machine2 = machineArg2({ args });
83920
84290
  const command = commandText({ rest: args.rest });
83921
- if (!command.trim()) throw new CliUsageError(USAGE11);
84291
+ if (!command.trim()) throw new CliUsageError(USAGE10);
83922
84292
  const timeout = flagText({ args, name: "timeout" });
83923
84293
  if (timeout && !(Number(timeout) >= 1))
83924
84294
  throw new CliUsageError(`--timeout takes a number of seconds
83925
- ${USAGE11}`);
84295
+ ${USAGE10}`);
83926
84296
  const released = await vaultEnv({ context, args });
83927
84297
  if ("exitCode" in released) return released.exitCode;
83928
84298
  const client = await computeClient({ context, args });
@@ -83950,11 +84320,11 @@ async function vaultEnv({
83950
84320
  const connections = args.lists.vault ?? [];
83951
84321
  if (args.flags.vault === true)
83952
84322
  throw new CliUsageError(`--vault takes a connection name
83953
- ${USAGE11}`);
84323
+ ${USAGE10}`);
83954
84324
  if (connections.length === 0) return {};
83955
84325
  const reason = flagText({ args, name: "reason" });
83956
84326
  if (!reason) throw new CliUsageError(`Say why with --reason "<one plain sentence>"
83957
- ${USAGE11}`);
84327
+ ${USAGE10}`);
83958
84328
  const env = {};
83959
84329
  for (const connection of new Set(connections)) {
83960
84330
  const released = await vaultRelease({ context, args, connection, reason, command: args.rest });
@@ -83974,11 +84344,11 @@ ${USAGE11}`);
83974
84344
  async function host({ context, args }) {
83975
84345
  const machineName = args.words[2];
83976
84346
  const agent2 = args.words[3];
83977
- if (!machineName || !agent2) throw new CliUsageError(USAGE11);
84347
+ if (!machineName || !agent2) throw new CliUsageError(USAGE10);
83978
84348
  const whenOffline = flagText({ args, name: "when-offline", fallback: "wait" });
83979
84349
  if (whenOffline !== "wait" && whenOffline !== "computer" && whenOffline !== "sandbox")
83980
84350
  throw new CliUsageError(`--when-offline takes wait or computer
83981
- ${USAGE11}`);
84351
+ ${USAGE10}`);
83982
84352
  const client = await computeClient({ context, args });
83983
84353
  const machine2 = await client.post(COMPUTE_REST_PATHS.host, {
83984
84354
  machine: machineName,
@@ -83995,7 +84365,7 @@ ${USAGE11}`);
83995
84365
  }
83996
84366
  async function unhost({ context, args }) {
83997
84367
  const agent2 = args.words[2];
83998
- if (!agent2) throw new CliUsageError(USAGE11);
84368
+ if (!agent2) throw new CliUsageError(USAGE10);
83999
84369
  const client = await computeClient({ context, args });
84000
84370
  const done = await client.post(COMPUTE_REST_PATHS.unhost, { agent: agent2 });
84001
84371
  if (args.flags.json) return context.out(`${JSON.stringify(done, null, 2)}
@@ -84032,7 +84402,7 @@ async function machine({ context, args }) {
84032
84402
  if (command === "unhost") return unhost({ context, args });
84033
84403
  const access = machineAccessCommand(command);
84034
84404
  if (access) return access({ context, args });
84035
- throw new CliUsageError(USAGE11);
84405
+ throw new CliUsageError(USAGE10);
84036
84406
  }
84037
84407
 
84038
84408
  // src/services/mcp-server.service.ts
@@ -84271,7 +84641,7 @@ async function serveMcp({
84271
84641
  }
84272
84642
 
84273
84643
  // src/services/mount-files.service.ts
84274
- import { mkdir as mkdir20, readFile as readFile30, rm as rm12, writeFile as writeFile20 } from "node:fs/promises";
84644
+ import { mkdir as mkdir21, readFile as readFile30, rm as rm12, writeFile as writeFile21 } from "node:fs/promises";
84275
84645
  import { dirname as dirname20, relative as relative5, resolve as resolve11 } from "node:path";
84276
84646
  async function textArgument({
84277
84647
  context,
@@ -84292,20 +84662,20 @@ async function writeMount({
84292
84662
  }) {
84293
84663
  const root = resolve11(context.cwd, flagText({ args, name: "dir", fallback: ".laze" }), folder);
84294
84664
  await rm12(root, { recursive: true, force: true });
84295
- await mkdir20(root, { recursive: true });
84665
+ await mkdir21(root, { recursive: true });
84296
84666
  for (const file3 of files2) {
84297
84667
  const target = resolve11(root, file3.path);
84298
84668
  const inside = relative5(root, target);
84299
84669
  if (!inside || inside.startsWith(".."))
84300
84670
  throw new Error(`Refusing to write outside ${root}: ${file3.path}`);
84301
- await mkdir20(dirname20(target), { recursive: true });
84302
- await writeFile20(target, file3.content);
84671
+ await mkdir21(dirname20(target), { recursive: true });
84672
+ await writeFile21(target, file3.content);
84303
84673
  }
84304
84674
  return root;
84305
84675
  }
84306
84676
 
84307
84677
  // src/services/memory-commands.service.ts
84308
- var USAGE12 = `Usage:
84678
+ var USAGE11 = `Usage:
84309
84679
  laze memory get SOUL.md|AGENTS.md|MEMORY.md [--channel <channel>]
84310
84680
  laze memory set <file> <text|@file|-> [--channel <channel>] [--base <version>]
84311
84681
  laze memory append MEMORY.md <text|@file|-> [--channel <channel>]
@@ -84317,7 +84687,7 @@ MEMORY.md is the file of the turn's channel (LAZE_CHANNEL), or of --channel when
84317
84687
  var FILES = /* @__PURE__ */ new Set(["SOUL.md", "AGENTS.md", "MEMORY.md"]);
84318
84688
  function fileRef({ context, args }) {
84319
84689
  const file3 = args.words[2] ?? "";
84320
- if (!FILES.has(file3)) throw new CliUsageError(USAGE12);
84690
+ if (!FILES.has(file3)) throw new CliUsageError(USAGE11);
84321
84691
  const channel = turnChannel({ context, args });
84322
84692
  return { file: file3, ...channel ? { channel } : {} };
84323
84693
  }
@@ -84356,7 +84726,7 @@ async function memoryHistory({ context, args }) {
84356
84726
  async function memorySet({ context, args }) {
84357
84727
  const ref = fileRef({ context, args });
84358
84728
  const value = args.words.slice(3).join(" ");
84359
- if (!value) throw new CliUsageError(USAGE12);
84729
+ if (!value) throw new CliUsageError(USAGE11);
84360
84730
  const content = await textArgument({ context, value });
84361
84731
  const base = args.flags.base;
84362
84732
  const { client } = await signedIn({ context, args });
@@ -84372,7 +84742,7 @@ async function memorySet({ context, args }) {
84372
84742
  async function memoryAppend({ context, args }) {
84373
84743
  const ref = fileRef({ context, args });
84374
84744
  const value = args.words.slice(3).join(" ");
84375
- if (!value) throw new CliUsageError(USAGE12);
84745
+ if (!value) throw new CliUsageError(USAGE11);
84376
84746
  const text2 = await textArgument({ context, value });
84377
84747
  const { client } = await signedIn({ context, args });
84378
84748
  const saved3 = await client.post("/api/memory/append", { ...ref, text: text2 });
@@ -84382,7 +84752,7 @@ async function memoryAppend({ context, args }) {
84382
84752
  }
84383
84753
  async function memorySearch({ context, args }) {
84384
84754
  const query = args.words.slice(2).join(" ").trim();
84385
- if (!query) throw new CliUsageError(USAGE12);
84755
+ if (!query) throw new CliUsageError(USAGE11);
84386
84756
  const { client } = await signedIn({ context, args });
84387
84757
  const hits = await client.post("/api/memory/search", { query });
84388
84758
  if (args.flags.json) return context.out(`${JSON.stringify(hits, null, 2)}
@@ -84416,13 +84786,13 @@ var MEMORY_COMMANDS = {
84416
84786
  async function memory({ context, args }) {
84417
84787
  const name3 = args.words[1] ?? "";
84418
84788
  const command = Object.hasOwn(MEMORY_COMMANDS, name3) ? MEMORY_COMMANDS[name3] : void 0;
84419
- if (!command) throw new CliUsageError(USAGE12);
84789
+ if (!command) throw new CliUsageError(USAGE11);
84420
84790
  await command({ context, args });
84421
84791
  }
84422
84792
 
84423
84793
  // src/services/models-commands.service.ts
84424
84794
  var WINDOWS = ["day", "week", "month"];
84425
- var USAGE13 = `Usage:
84795
+ var USAGE12 = `Usage:
84426
84796
  laze models policy whether Laze models are on, the default budget and the cap
84427
84797
  laze models set-policy [on|off] [--default-day <usd|none>] [--cap-day <usd|none>] ... (admins)
84428
84798
  --default-week, --default-month, --cap-week and --cap-month set the other windows
@@ -84447,7 +84817,7 @@ function limitsFrom({
84447
84817
  const value = text2 === "none" ? null : Number(text2);
84448
84818
  if (value !== null && (!Number.isFinite(value) || value < 0))
84449
84819
  throw new CliUsageError(`--${prefix}${window2} takes an amount in USD or none.
84450
- ${USAGE13}`);
84820
+ ${USAGE12}`);
84451
84821
  next[window2] = value;
84452
84822
  changed = true;
84453
84823
  }
@@ -84472,12 +84842,12 @@ async function showPolicy({ context, args }) {
84472
84842
  }
84473
84843
  async function setPolicy({ context, args }) {
84474
84844
  const state = args.words[2];
84475
- if (state !== void 0 && state !== "on" && state !== "off") throw new CliUsageError(USAGE13);
84845
+ if (state !== void 0 && state !== "on" && state !== "off") throw new CliUsageError(USAGE12);
84476
84846
  const { client } = await signedIn({ context, args });
84477
84847
  const current2 = await client.get("/api/models/policy");
84478
84848
  const defaultBudget = limitsFrom({ args, prefix: "default-", current: current2.defaultBudget });
84479
84849
  const cap = limitsFrom({ args, prefix: "cap-", current: current2.cap });
84480
- if (!state && !defaultBudget && !cap) throw new CliUsageError(USAGE13);
84850
+ if (!state && !defaultBudget && !cap) throw new CliUsageError(USAGE12);
84481
84851
  const updated = await client.post("/api/models/policy", {
84482
84852
  ...state ? { lazeModels: state === "on" } : {},
84483
84853
  ...defaultBudget ? { defaultBudget } : {},
@@ -84518,11 +84888,11 @@ async function agentNamed({ client, name: name3 }) {
84518
84888
  }
84519
84889
  async function setBudget({ context, args }) {
84520
84890
  const name3 = args.words[2];
84521
- if (!name3) throw new CliUsageError(USAGE13);
84891
+ if (!name3) throw new CliUsageError(USAGE12);
84522
84892
  const { client } = await signedIn({ context, args });
84523
84893
  const agent2 = await agentNamed({ client, name: name3 });
84524
84894
  const next = limitsFrom({ args, prefix: "", current: agent2.budget });
84525
- if (!next) throw new CliUsageError(USAGE13);
84895
+ if (!next) throw new CliUsageError(USAGE12);
84526
84896
  const updated = await client.post("/api/models/agents/budget", {
84527
84897
  agentId: agent2.agentId,
84528
84898
  budget: next
@@ -84555,7 +84925,7 @@ var MODEL_COMMANDS = {
84555
84925
  async function models({ context, args }) {
84556
84926
  const name3 = args.words[1] ?? "policy";
84557
84927
  const command = Object.hasOwn(MODEL_COMMANDS, name3) ? MODEL_COMMANDS[name3] : void 0;
84558
- if (!command) throw new CliUsageError(USAGE13);
84928
+ if (!command) throw new CliUsageError(USAGE12);
84559
84929
  await command({ context, args });
84560
84930
  }
84561
84931
 
@@ -84633,7 +85003,7 @@ var monitorResume = stateRun("/api/agents/monitors/resume", "resume");
84633
85003
  var monitorRemove = stateRun("/api/agents/monitors/remove", "rm");
84634
85004
 
84635
85005
  // src/services/notification-commands.service.ts
84636
- var USAGE14 = `Usage:
85006
+ var USAGE13 = `Usage:
84637
85007
  laze notifications [show] your notification settings (people)
84638
85008
  laze notifications set [--channels all|mentions|nothing] [--keywords a,b] [--dnd on|off]
84639
85009
  [--dnd-from 22:00] [--dnd-to 08:00] [--tz <IANA zone>] [--push on|off] [--email on|off]
@@ -84662,14 +85032,14 @@ function switchOf({ args, name: name3 }) {
84662
85032
  if (!text2) return void 0;
84663
85033
  if (text2 !== "on" && text2 !== "off")
84664
85034
  throw new CliUsageError(`--${name3} takes on or off.
84665
- ${USAGE14}`);
85035
+ ${USAGE13}`);
84666
85036
  return text2 === "on";
84667
85037
  }
84668
85038
  function changesOf(args) {
84669
85039
  const channels2 = flagText({ args, name: "channels" });
84670
85040
  if (channels2 && !["all", "mentions", "nothing"].includes(channels2))
84671
85041
  throw new CliUsageError(`--channels takes all, mentions or nothing.
84672
- ${USAGE14}`);
85042
+ ${USAGE13}`);
84673
85043
  const keywords = typeof args.flags.keywords === "string" ? args.flags.keywords : void 0;
84674
85044
  const emailAfter = flagText({ args, name: "email-after" });
84675
85045
  const changes2 = {
@@ -84691,7 +85061,7 @@ async function showSettings({ context, args }) {
84691
85061
  }
84692
85062
  async function setSettings({ context, args }) {
84693
85063
  const changes2 = changesOf(args);
84694
- if (Object.keys(changes2).length === 0) throw new CliUsageError(USAGE14);
85064
+ if (Object.keys(changes2).length === 0) throw new CliUsageError(USAGE13);
84695
85065
  const { client } = await signedIn({ context, args });
84696
85066
  print7({
84697
85067
  context,
@@ -84702,7 +85072,7 @@ async function setSettings({ context, args }) {
84702
85072
  async function snoozeFor({ context, args }) {
84703
85073
  const word3 = args.words[2];
84704
85074
  const minutes = word3 === "off" ? 0 : Number(word3);
84705
- if (!word3 || !Number.isInteger(minutes) || minutes < 0) throw new CliUsageError(USAGE14);
85075
+ if (!word3 || !Number.isInteger(minutes) || minutes < 0) throw new CliUsageError(USAGE13);
84706
85076
  const { client } = await signedIn({ context, args });
84707
85077
  print7({
84708
85078
  context,
@@ -84720,7 +85090,7 @@ var NOTIFICATION_COMMANDS = {
84720
85090
  async function notifications({ context, args }) {
84721
85091
  const name3 = args.words[1] ?? "show";
84722
85092
  const command = Object.hasOwn(NOTIFICATION_COMMANDS, name3) ? NOTIFICATION_COMMANDS[name3] : void 0;
84723
- if (!command) throw new CliUsageError(USAGE14);
85093
+ if (!command) throw new CliUsageError(USAGE13);
84724
85094
  await command({ context, args });
84725
85095
  }
84726
85096
 
@@ -84957,8 +85327,8 @@ ${OPS_USAGE}`);
84957
85327
  }
84958
85328
 
84959
85329
  // src/services/release-watch.service.ts
84960
- import { mkdir as mkdir21, readFile as readFile31, realpath, writeFile as writeFile21 } from "node:fs/promises";
84961
- import { dirname as dirname21, join as join22 } from "node:path";
85330
+ import { mkdir as mkdir22, readFile as readFile31, realpath, writeFile as writeFile22 } from "node:fs/promises";
85331
+ import { dirname as dirname21, join as join23 } from "node:path";
84962
85332
 
84963
85333
  // src/rules/cli-update.rules.ts
84964
85334
  var CLI_PACKAGE = "@lazehq/cli";
@@ -85105,15 +85475,15 @@ async function startedUpdate({
85105
85475
  const plan2 = updatePlanOf({ script: await scriptOf(context) });
85106
85476
  if (plan2.kind !== "install") return null;
85107
85477
  const folder = dirname21(context.environment.configPath);
85108
- const stamp = join22(folder, "auto-update.json");
85478
+ const stamp = join23(folder, "auto-update.json");
85109
85479
  const last = await readFile31(stamp, "utf8").then((text2) => JSON.parse(text2)).catch(() => null);
85110
85480
  const now = context.nowMs();
85111
85481
  if (last?.server === server && now - last.atMs < RETRY_AFTER_MS) return null;
85112
- await mkdir21(folder, { recursive: true, mode: 448 });
85113
- await writeFile21(stamp, JSON.stringify({ server, atMs: now }), { mode: 384 });
85482
+ await mkdir22(folder, { recursive: true, mode: 448 });
85483
+ await writeFile22(stamp, JSON.stringify({ server, atMs: now }), { mode: 384 });
85114
85484
  context.processes.spawnDetached({
85115
85485
  argv: [...context.program, "update"],
85116
- logPath: join22(folder, "auto-update.log")
85486
+ logPath: join23(folder, "auto-update.log")
85117
85487
  });
85118
85488
  return { manager: plan2.manager };
85119
85489
  }
@@ -85224,7 +85594,7 @@ async function rushWakeHook({ context, args }) {
85224
85594
  }
85225
85595
 
85226
85596
  // src/services/schedule-commands.service.ts
85227
- var USAGE15 = `Usage:
85597
+ var USAGE14 = `Usage:
85228
85598
  laze schedule add <name> --prompt <text> (--cron "<m h dom mon dow>" | --rrule "<RRULE>" | --at <local time>)
85229
85599
  [--tz <IANA zone>] [--channel <channelId>] [--agent <agentId>]
85230
85600
  laze schedule list
@@ -85239,7 +85609,7 @@ function timingOf(args) {
85239
85609
  const given = [cron, rrule, at].filter(Boolean);
85240
85610
  if (given.length !== 1)
85241
85611
  throw new CliUsageError(`Give exactly one of --cron, --rrule or --at.
85242
- ${USAGE15}`);
85612
+ ${USAGE14}`);
85243
85613
  if (cron) return { kind: "cron", cron };
85244
85614
  if (rrule) return { kind: "rrule", rrule };
85245
85615
  return { kind: "once", at };
@@ -85254,7 +85624,7 @@ function printSchedule({ context, schedule: schedule2 }) {
85254
85624
  async function scheduleAdd({ context, args }) {
85255
85625
  const name3 = args.words.slice(2).join(" ").trim();
85256
85626
  const prompt = flagText({ args, name: "prompt" });
85257
- if (!name3 || !prompt) throw new CliUsageError(USAGE15);
85627
+ if (!name3 || !prompt) throw new CliUsageError(USAGE14);
85258
85628
  const timing = timingOf(args);
85259
85629
  const { client } = await signedIn({ context, args });
85260
85630
  const channelId = flagText({ args, name: "channel" });
@@ -85291,7 +85661,7 @@ function changesOf2(args) {
85291
85661
  async function scheduleUpdate({ context, args }) {
85292
85662
  const scheduleId = args.words[2];
85293
85663
  const changes2 = changesOf2(args);
85294
- if (!scheduleId || Object.keys(changes2).length === 0) throw new CliUsageError(USAGE15);
85664
+ if (!scheduleId || Object.keys(changes2).length === 0) throw new CliUsageError(USAGE14);
85295
85665
  const { client } = await signedIn({ context, args });
85296
85666
  const schedule2 = await client.post("/api/schedules/update", { scheduleId, ...changes2 });
85297
85667
  if (args.flags.json) return context.out(`${JSON.stringify(schedule2, null, 2)}
@@ -85308,7 +85678,7 @@ async function scheduleList({ context, args }) {
85308
85678
  function byId(path) {
85309
85679
  return async ({ context, args }) => {
85310
85680
  const scheduleId = args.words[2];
85311
- if (!scheduleId) throw new CliUsageError(USAGE15);
85681
+ if (!scheduleId) throw new CliUsageError(USAGE14);
85312
85682
  const { client } = await signedIn({ context, args });
85313
85683
  const answer4 = await client.post(`/api/schedules/${path}`, {
85314
85684
  scheduleId
@@ -85322,7 +85692,7 @@ function byId(path) {
85322
85692
  }
85323
85693
  async function scheduleRuns({ context, args }) {
85324
85694
  const scheduleId = args.words[2];
85325
- if (!scheduleId) throw new CliUsageError(USAGE15);
85695
+ if (!scheduleId) throw new CliUsageError(USAGE14);
85326
85696
  const { client } = await signedIn({ context, args });
85327
85697
  const runs = await client.post("/api/schedules/runs", { scheduleId });
85328
85698
  if (args.flags.json) return context.out(`${JSON.stringify(runs, null, 2)}
@@ -85336,7 +85706,7 @@ async function scheduleRuns({ context, args }) {
85336
85706
  }
85337
85707
  async function scheduleRun({ context, args }) {
85338
85708
  const scheduleId = args.words[2];
85339
- if (!scheduleId) throw new CliUsageError(USAGE15);
85709
+ if (!scheduleId) throw new CliUsageError(USAGE14);
85340
85710
  const { client } = await signedIn({ context, args });
85341
85711
  const run4 = await client.post("/api/schedules/run", { scheduleId });
85342
85712
  if (args.flags.json) return context.out(`${JSON.stringify(run4, null, 2)}
@@ -85357,14 +85727,14 @@ var SCHEDULE_COMMANDS = {
85357
85727
  async function schedule({ context, args }) {
85358
85728
  const name3 = args.words[1] ?? "";
85359
85729
  const command = Object.hasOwn(SCHEDULE_COMMANDS, name3) ? SCHEDULE_COMMANDS[name3] : void 0;
85360
- if (!command) throw new CliUsageError(USAGE15);
85730
+ if (!command) throw new CliUsageError(USAGE14);
85361
85731
  await command({ context, args });
85362
85732
  }
85363
85733
 
85364
85734
  // src/services/skill-commands.service.ts
85365
85735
  import { readdir as readdir7, readFile as readFile33 } from "node:fs/promises";
85366
- import { join as join23, relative as relative6, resolve as resolve13 } from "node:path";
85367
- var USAGE16 = `Usage:
85736
+ import { join as join24, relative as relative6, resolve as resolve13 } from "node:path";
85737
+ var USAGE15 = `Usage:
85368
85738
  laze skill list [--agent <agentId>]
85369
85739
  laze skill install <catalogue-id> [--as <name>] [--agent <agentId>]
85370
85740
  laze skill install --from <folder> [--as <name>] [--agent <agentId>] a folder with a SKILL.md
@@ -85384,7 +85754,7 @@ async function folderFiles({ root }) {
85384
85754
  const files2 = [];
85385
85755
  for (const entry of entries) {
85386
85756
  if (!entry.isFile()) continue;
85387
- const full = join23(entry.parentPath, entry.name);
85757
+ const full = join24(entry.parentPath, entry.name);
85388
85758
  files2.push({ path: relative6(root, full), content: await readFile33(full, "utf8") });
85389
85759
  }
85390
85760
  return files2.toSorted((a, b) => a.path.localeCompare(b.path));
@@ -85413,7 +85783,7 @@ async function skillList({ context, args }) {
85413
85783
  async function skillInstall({ context, args }) {
85414
85784
  const catalogueId = args.words[2];
85415
85785
  const from = flagText({ args, name: "from" });
85416
- if (!catalogueId === !from) throw new CliUsageError(USAGE16);
85786
+ if (!catalogueId === !from) throw new CliUsageError(USAGE15);
85417
85787
  const name3 = flagText({ args, name: "as" });
85418
85788
  const agent2 = flagText({ args, name: "agent" });
85419
85789
  const files2 = from ? await folderFiles({ root: resolve13(context.cwd, from) }) : void 0;
@@ -85431,7 +85801,7 @@ async function skillInstall({ context, args }) {
85431
85801
  }
85432
85802
  async function skillShow({ context, args }) {
85433
85803
  const name3 = args.words[2];
85434
- if (!name3) throw new CliUsageError(USAGE16);
85804
+ if (!name3) throw new CliUsageError(USAGE15);
85435
85805
  const agent2 = flagText({ args, name: "agent" });
85436
85806
  const { client } = await signedIn({ context, args });
85437
85807
  const skill2 = await client.post("/api/skills/show", {
@@ -85464,7 +85834,7 @@ function agentFlag(args) {
85464
85834
  }
85465
85835
  async function skillRemove({ context, args }) {
85466
85836
  const name3 = args.words[2];
85467
- if (!name3) throw new CliUsageError(USAGE16);
85837
+ if (!name3) throw new CliUsageError(USAGE15);
85468
85838
  const { client } = await signedIn({ context, args });
85469
85839
  const removed = await client.post("/api/skills/remove", {
85470
85840
  name: name3,
@@ -85481,7 +85851,7 @@ async function skillUpdate({ context, args }) {
85481
85851
  const description = typeof args.flags.description === "string" ? args.flags.description : void 0;
85482
85852
  const skillMdFile = flagText({ args, name: "skill-md" });
85483
85853
  if (!name3 || !newName && description === void 0 && !skillMdFile) {
85484
- throw new CliUsageError(USAGE16);
85854
+ throw new CliUsageError(USAGE15);
85485
85855
  }
85486
85856
  const skillMd = skillMdFile ? await readFile33(resolve13(context.cwd, skillMdFile), "utf8") : void 0;
85487
85857
  const { client } = await signedIn({ context, args });
@@ -85500,7 +85870,7 @@ async function skillUpdate({ context, args }) {
85500
85870
  function pinning({ unpin }) {
85501
85871
  return async ({ context, args }) => {
85502
85872
  const name3 = args.words[2];
85503
- if (!name3) throw new CliUsageError(USAGE16);
85873
+ if (!name3) throw new CliUsageError(USAGE15);
85504
85874
  const { client } = await signedIn({ context, args });
85505
85875
  const path = unpin ? "/api/skills/unpin" : "/api/skills/pin";
85506
85876
  const skill2 = await client.post(path, { name: name3, ...agentFlag(args) });
@@ -85524,7 +85894,7 @@ var SKILL_COMMANDS = {
85524
85894
  async function skill({ context, args }) {
85525
85895
  const name3 = args.words[1] ?? "";
85526
85896
  const command = Object.hasOwn(SKILL_COMMANDS, name3) ? SKILL_COMMANDS[name3] : void 0;
85527
- if (!command) throw new CliUsageError(USAGE16);
85897
+ if (!command) throw new CliUsageError(USAGE15);
85528
85898
  await command({ context, args });
85529
85899
  }
85530
85900
 
@@ -86135,11 +86505,11 @@ function statusLine2({ presence: presence2 }) {
86135
86505
  }
86136
86506
 
86137
86507
  // src/services/status-commands.service.ts
86138
- var USAGE17 = "Usage: laze status set <emoji> [text] [--for 30m|1h|4h|today|week|never] [--tz <zone>], laze status clear|away|active";
86508
+ var USAGE16 = "Usage: laze status set <emoji> [text] [--for 30m|1h|4h|today|week|never] [--tz <zone>], laze status clear|away|active";
86139
86509
  function clearAfterOf({ args }) {
86140
86510
  const wanted = flagText({ args, name: "for", fallback: "never" });
86141
86511
  const known = STATUS_CLEAR_AFTER.find((candidate) => candidate === wanted);
86142
- if (!known) throw new CliUsageError(USAGE17);
86512
+ if (!known) throw new CliUsageError(USAGE16);
86143
86513
  return known;
86144
86514
  }
86145
86515
  function answer3({
@@ -86153,7 +86523,7 @@ function answer3({
86153
86523
  }
86154
86524
  async function statusSet({ context, args }) {
86155
86525
  const [, , emoji3, ...words] = args.words;
86156
- if (!emoji3) throw new CliUsageError(USAGE17);
86526
+ if (!emoji3) throw new CliUsageError(USAGE16);
86157
86527
  const clearAfter = clearAfterOf({ args });
86158
86528
  const timeZone = flagText({ args, name: "tz" }) || Intl.DateTimeFormat().resolvedOptions().timeZone;
86159
86529
  const { client } = await signedIn({ context, args });
@@ -86177,7 +86547,7 @@ async function statusAway({ context, args }) {
86177
86547
  answer3({ context, args, presence: presence2 });
86178
86548
  }
86179
86549
  async function statusUsage() {
86180
- throw new CliUsageError(USAGE17);
86550
+ throw new CliUsageError(USAGE16);
86181
86551
  }
86182
86552
 
86183
86553
  // src/services/update-commands.service.ts
@@ -86301,7 +86671,7 @@ async function update2({
86301
86671
 
86302
86672
  // src/services/vault-env-commands.service.ts
86303
86673
  import { readFile as readFile36, stat as stat5 } from "node:fs/promises";
86304
- import { dirname as dirname22, join as join24, resolve as resolve15 } from "node:path";
86674
+ import { dirname as dirname22, join as join25, resolve as resolve15 } from "node:path";
86305
86675
 
86306
86676
  // src/rules/vault-manifest.rules.ts
86307
86677
  var VARIABLE = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -86410,7 +86780,7 @@ async function doorOf({
86410
86780
  const turnFile = turnFileOf({ env });
86411
86781
  const headers = {
86412
86782
  "proxy-authorization": proxy.authorization,
86413
- "x-laze-turn": await turnTokenOf3({ env, turnFile, command: "laze vault env" })
86783
+ "x-laze-turn": await turnTokenOf2({ env, turnFile, command: "laze vault env" })
86414
86784
  };
86415
86785
  return {
86416
86786
  keyPath: runKeyPathOf({ turnFile, connection: keyName }),
@@ -86436,7 +86806,11 @@ async function doorOf({
86436
86806
  }
86437
86807
  const signed2 = await signedIn({ context, args }).catch(() => null);
86438
86808
  if (signed2?.profile.kind !== "agent") throw new CliUsageError(WHERE);
86439
- const { client, name: name3 } = signed2;
86809
+ const { name: name3 } = signed2;
86810
+ const client = forSession({
86811
+ client: signed2.client,
86812
+ session: await currentSessionOf({ context, args })
86813
+ });
86440
86814
  const channelId = flagText({ args, name: "channel" }) || null;
86441
86815
  return {
86442
86816
  keyPath: runKeyPathOf({ turnFile: void 0, connection: keyName, profile: name3 }),
@@ -86480,14 +86854,14 @@ async function untilAllAnswered({
86480
86854
  `
86481
86855
  );
86482
86856
  while (waiting.size > 0) {
86483
- if (context.nowMs() + POLL_MS2 > deadline) {
86857
+ if (context.nowMs() + POLL_MS > deadline) {
86484
86858
  context.err(
86485
86859
  `laze vault: ${[...waiting.keys()].join(", ")} not approved yet; ask again later.
86486
86860
  `
86487
86861
  );
86488
86862
  return "capped";
86489
86863
  }
86490
- await context.sleep(POLL_MS2);
86864
+ await context.sleep(POLL_MS);
86491
86865
  for (const [key, pending] of waiting) {
86492
86866
  const next = await door.status(pending.requestId);
86493
86867
  if (next.outcome === "ask") waiting.set(key, next);
@@ -86642,7 +87016,7 @@ async function manifestPathOf({
86642
87016
  const environment = flagText({ args, name: "env" });
86643
87017
  const file3 = environment ? `.env.${environment}.vault` : ".env.vault";
86644
87018
  for (let dir = resolve15(context.cwd); ; dir = dirname22(dir)) {
86645
- if (await isFile(join24(dir, file3))) return join24(dir, file3);
87019
+ if (await isFile(join25(dir, file3))) return join25(dir, file3);
86646
87020
  if (dirname22(dir) === dir) break;
86647
87021
  }
86648
87022
  throw new CliUsageError(`laze vault: no ${file3} here or in a parent folder
@@ -86753,7 +87127,7 @@ ${ENV_USAGE}`);
86753
87127
  `);
86754
87128
  return 0;
86755
87129
  }
86756
- const redact = [...released.values()].flatMap(({ fields }) => Object.values(fields));
87130
+ const redact = [...released.values()].flatMap(({ fields }) => secretValuesOf({ fields }));
86757
87131
  return context.runCommand({ command: prepared.command, env, redact });
86758
87132
  }
86759
87133
  async function vaultAws({
@@ -86802,7 +87176,7 @@ async function postInTurn({
86802
87176
  body
86803
87177
  }) {
86804
87178
  const env = context.environment.inherited;
86805
- const turn = await turnTokenOf3({
87179
+ const turn = await turnTokenOf2({
86806
87180
  env,
86807
87181
  turnFile: turnFileOf({ env }),
86808
87182
  command: "laze vault save"
@@ -87505,7 +87879,7 @@ async function whatsappBusiness({
87505
87879
  }
87506
87880
 
87507
87881
  // src/services/whatsapp-pairing-commands.service.ts
87508
- import { writeFile as writeFile22 } from "node:fs/promises";
87882
+ import { writeFile as writeFile23 } from "node:fs/promises";
87509
87883
  import { resolve as resolve17 } from "node:path";
87510
87884
  var WHATSAPP_PAIRING_USAGE = [
87511
87885
  " laze whatsapp pair <machine> [--qr <file.svg>] link WhatsApp on your machine; scan the code (owner)",
@@ -87526,7 +87900,7 @@ function svgOf(dataUrl) {
87526
87900
  }
87527
87901
  async function report({ context, args, pairing: pairing2 }) {
87528
87902
  const qrFile = pairing2.qrSvg ? resolve17(context.cwd, flagText({ args, name: "qr", fallback: "whatsapp-qr.svg" })) : null;
87529
- if (qrFile && pairing2.qrSvg) await writeFile22(qrFile, svgOf(pairing2.qrSvg), "utf8");
87903
+ if (qrFile && pairing2.qrSvg) await writeFile23(qrFile, svgOf(pairing2.qrSvg), "utf8");
87530
87904
  if (args.flags.json) return context.out(`${JSON.stringify({ ...pairing2, qrFile }, null, 2)}
87531
87905
  `);
87532
87906
  context.out(`${pairing2.pairingId} ${pairing2.state}
@@ -87591,7 +87965,7 @@ var PATHS3 = {
87591
87965
  var STATUS_WAIT_SECONDS2 = 50;
87592
87966
  var STATUS_CALLS2 = 2;
87593
87967
  var SETTLED = /* @__PURE__ */ new Set(["sent", "denied", "expired", "failed"]);
87594
- var USAGE18 = [
87968
+ var USAGE17 = [
87595
87969
  "Usage: laze whatsapp chats <machine> [--limit <n>] the chats on the machine, newest first",
87596
87970
  " laze whatsapp read <machine> <chat> [--limit <n>] a chat's last messages, oldest first",
87597
87971
  ' laze whatsapp send <machine> <chat> "<text>" send as the owner; an agent waits for their approval',
@@ -87601,14 +87975,14 @@ var USAGE18 = [
87601
87975
  ].join("\n");
87602
87976
  function word2({ args, at }) {
87603
87977
  const value = args.words[at];
87604
- if (!value) throw new CliUsageError(USAGE18);
87978
+ if (!value) throw new CliUsageError(USAGE17);
87605
87979
  return value;
87606
87980
  }
87607
87981
  function limitOf5({ args }) {
87608
87982
  const text2 = flagText({ args, name: "limit" });
87609
87983
  if (!text2) return {};
87610
87984
  const limit = Number(text2);
87611
- if (!Number.isInteger(limit) || limit < 1) throw new CliUsageError(USAGE18);
87985
+ if (!Number.isInteger(limit) || limit < 1) throw new CliUsageError(USAGE17);
87612
87986
  return { limit };
87613
87987
  }
87614
87988
  async function chats({ context, args }) {
@@ -87670,7 +88044,7 @@ Still waiting. Run \`laze whatsapp status ${send4.id}\` later to see the answer.
87670
88044
  }
87671
88045
  async function send3({ context, args }) {
87672
88046
  const text2 = args.words.slice(4).join(" ") || args.rest.join(" ");
87673
- if (!text2) throw new CliUsageError(USAGE18);
88047
+ if (!text2) throw new CliUsageError(USAGE17);
87674
88048
  const client = await computeClient({ context, args });
87675
88049
  const asked = await client.post(PATHS3.send, {
87676
88050
  machine: word2({ args, at: 2 }),
@@ -87700,11 +88074,11 @@ async function whatsapp({
87700
88074
  if (command === "status") return status8({ context, args });
87701
88075
  const linking = whatsappPairingCommand(command);
87702
88076
  if (linking) return linking({ context, args });
87703
- throw new CliUsageError(USAGE18);
88077
+ throw new CliUsageError(USAGE17);
87704
88078
  }
87705
88079
 
87706
88080
  // src/services/wiki-commands.service.ts
87707
- var USAGE19 = `Usage:
88081
+ var USAGE18 = `Usage:
87708
88082
  laze wiki list
87709
88083
  laze wiki get <path>
87710
88084
  laze wiki put <path> <markdown|@file|-> [--title <title>] [--channel <channel>] [--base <version>]
@@ -87724,7 +88098,7 @@ async function wikiList({ context, args }) {
87724
88098
  }
87725
88099
  async function wikiGet({ context, args }) {
87726
88100
  const path = args.words[2];
87727
- if (!path) throw new CliUsageError(USAGE19);
88101
+ if (!path) throw new CliUsageError(USAGE18);
87728
88102
  const { client } = await signedIn({ context, args });
87729
88103
  const page = await client.post("/api/wiki/get", { path });
87730
88104
  if (args.flags.json) return context.out(`${JSON.stringify(page, null, 2)}
@@ -87741,7 +88115,7 @@ Linked from: ${page.backlinks.map((link) => link.path).join(", ")}
87741
88115
  async function wikiPut({ context, args }) {
87742
88116
  const path = args.words[2];
87743
88117
  const value = args.words.slice(3).join(" ");
87744
- if (!path || !value) throw new CliUsageError(USAGE19);
88118
+ if (!path || !value) throw new CliUsageError(USAGE18);
87745
88119
  const body = await textArgument({ context, value });
87746
88120
  const title = flagText({ args, name: "title" });
87747
88121
  const channel = flagText({ args, name: "channel" });
@@ -87761,7 +88135,7 @@ async function wikiPut({ context, args }) {
87761
88135
  }
87762
88136
  async function wikiSearch({ context, args }) {
87763
88137
  const query = args.words.slice(2).join(" ").trim();
87764
- if (!query) throw new CliUsageError(USAGE19);
88138
+ if (!query) throw new CliUsageError(USAGE18);
87765
88139
  const { client } = await signedIn({ context, args });
87766
88140
  const hits = await client.post("/api/wiki/search", { query });
87767
88141
  if (args.flags.json) return context.out(`${JSON.stringify(hits, null, 2)}
@@ -87771,7 +88145,7 @@ async function wikiSearch({ context, args }) {
87771
88145
  }
87772
88146
  async function wikiHistory({ context, args }) {
87773
88147
  const path = args.words[2];
87774
- if (!path) throw new CliUsageError(USAGE19);
88148
+ if (!path) throw new CliUsageError(USAGE18);
87775
88149
  const { client } = await signedIn({ context, args });
87776
88150
  const revisions = await client.post("/api/wiki/history", { path });
87777
88151
  if (args.flags.json) return context.out(`${JSON.stringify(revisions, null, 2)}
@@ -87785,7 +88159,7 @@ async function wikiHistory({ context, args }) {
87785
88159
  }
87786
88160
  async function wikiMove({ context, args }) {
87787
88161
  const [, , path, to] = args.words;
87788
- if (!path || !to) throw new CliUsageError(USAGE19);
88162
+ if (!path || !to) throw new CliUsageError(USAGE18);
87789
88163
  const { client } = await signedIn({ context, args });
87790
88164
  const page = await client.post("/api/wiki/move", { path, to });
87791
88165
  if (args.flags.json) return context.out(`${JSON.stringify(page, null, 2)}
@@ -87795,7 +88169,7 @@ async function wikiMove({ context, args }) {
87795
88169
  }
87796
88170
  async function wikiRemove({ context, args }) {
87797
88171
  const path = args.words[2];
87798
- if (!path) throw new CliUsageError(USAGE19);
88172
+ if (!path) throw new CliUsageError(USAGE18);
87799
88173
  const { client } = await signedIn({ context, args });
87800
88174
  const removed = await client.post("/api/wiki/remove", { path });
87801
88175
  if (args.flags.json) return context.out(`${JSON.stringify(removed)}
@@ -87815,7 +88189,7 @@ var WIKI_COMMANDS = {
87815
88189
  async function wiki({ context, args }) {
87816
88190
  const name3 = args.words[1] ?? "";
87817
88191
  const command = Object.hasOwn(WIKI_COMMANDS, name3) ? WIKI_COMMANDS[name3] : void 0;
87818
- if (!command) throw new CliUsageError(USAGE19);
88192
+ if (!command) throw new CliUsageError(USAGE18);
87819
88193
  await command({ context, args });
87820
88194
  }
87821
88195
 
@@ -88131,8 +88505,27 @@ async function list9({ context, args }) {
88131
88505
  context,
88132
88506
  args,
88133
88507
  answer: answer4,
88134
- text: (members3) => members3.map((it) => `${ROLE_NAMES2[it.role]} ${it.name} ${it.email} ${it.userId}
88135
- `).join("")
88508
+ text: (members3) => members3.map((it) => {
88509
+ const aka2 = it.aliases?.length ? ` aka ${it.aliases.join(", ")}` : "";
88510
+ return `${ROLE_NAMES2[it.role]} ${it.name} ${it.email} ${it.userId}${aka2}
88511
+ `;
88512
+ }).join("")
88513
+ });
88514
+ }
88515
+ async function aka({ context, args }) {
88516
+ const { client } = await signedIn({ context, args });
88517
+ const names = args.words.slice(2);
88518
+ const clear = Boolean(args.flags.clear);
88519
+ const answer4 = names.length > 0 || clear ? await client.post("/api/agents/me/workspace/aka/set", {
88520
+ aliases: clear ? [] : names
88521
+ }) : await client.post("/api/agents/me/workspace/aka", {});
88522
+ print8({
88523
+ context,
88524
+ args,
88525
+ answer: answer4,
88526
+ text: (it) => it.aliases?.length ? `${it.name}, also known as ${it.aliases.join(", ")}
88527
+ ` : `${it.name} goes by no other name. Add some with laze members aka <name>...
88528
+ `
88136
88529
  });
88137
88530
  }
88138
88531
  async function invite({ context, args }) {
@@ -88264,6 +88657,7 @@ var MEMBERS_COMMANDS = {
88264
88657
  "revoke-invite": revokeInvite,
88265
88658
  "invite-link": inviteLink,
88266
88659
  role,
88660
+ aka,
88267
88661
  remove: remove5,
88268
88662
  requests,
88269
88663
  approve: deciding("approved"),
@@ -88275,7 +88669,7 @@ async function members2({ context, args }) {
88275
88669
  const command = MEMBERS_COMMANDS[sub];
88276
88670
  if (!command) {
88277
88671
  throw new CliUsageError(
88278
- "Usage: laze members [invite | invites | revoke-invite | invite-link | role | remove | requests | approve | deny]"
88672
+ "Usage: laze members [invite | invites | revoke-invite | invite-link | role | aka | remove | requests | approve | deny]"
88279
88673
  );
88280
88674
  }
88281
88675
  return command({ context, args });
@@ -88327,6 +88721,7 @@ var HELP = `laze: work in a Laze workspace from your terminal or your agent.
88327
88721
  laze members invite <email> [--role owner|admin|member|guest] invite someone (admins)
88328
88722
  laze members invites | revoke-invite <email|id> invitations waiting, or take one back (admins)
88329
88723
  laze members invite-link <email|id> a fresh link for an invitation, shown once (admins)
88724
+ laze members aka [<name>...] [--clear] the other names you go by, such as a nickname
88330
88725
  laze members role <member> owner|admin|member|guest change a member's role (admins)
88331
88726
  laze members remove <member> take someone out of the workspace (admins)
88332
88727
  laze members requests | approve <id> | deny <id> access requests waiting for an admin
@@ -88458,8 +88853,10 @@ var HELP = `laze: work in a Laze workspace from your terminal or your agent.
88458
88853
  laze connect providers|start|search|mcp|mcp-key|github|card|card-key connect services as yourself
88459
88854
  laze connect install|status|stop|uninstall the service that hands linked Codex sessions their messages
88460
88855
  laze openclaw list|connect|agent|agent-key|feed|disconnect your OpenClaw gateways and their agents
88461
- laze browser open|tabs|goto|read|ask|cdp|share|close a live browser tab pinned to the conversation
88856
+ laze browser open|tabs|goto|read|ask|login|cdp|share|close a live browser tab pinned to the conversation
88462
88857
  Show your work: open pages in a browser tab of the conversation; ask the person you work for to sign in there, never ask for a password
88858
+ Any agent working for the tab's owner drives it, connected agents (Claude Code, Codex) from their own session included
88859
+ laze browser login <tab> --vault <connection> types a saved sign-in only when the person says to use it; laze browser --help for all
88463
88860
  laze browser setup|cdp|screen|status <machine> a machine with Chrome a person signs in on, for agents
88464
88861
  Sites without an API need a person's login: open a browser tab and ask there, never ask for a password; a browser machine only when the person asks for one
88465
88862
  laze browser setup <site> --on <machine> the browser on a person's own machine instead, at no Laze compute cost
@@ -88723,7 +89120,9 @@ async function runCli({
88723
89120
  [openclaw, OPENCLAW_USAGE],
88724
89121
  [chatActions, CHAT_ACTIONS_USAGE],
88725
89122
  [agentLogins, LOGINS_HELP],
88726
- [agentPools, POOLS_HELP]
89123
+ [agentPools, POOLS_HELP],
89124
+ [browser, `${BROWSER_USAGE}
89125
+ `]
88727
89126
  ]);
88728
89127
  if (command && args.flags.help && ownHelp.has(command)) {
88729
89128
  context.out(ownHelp.get(command) ?? HELP);