@lazehq/cli 0.1.30 → 0.1.32

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 +1112 -816
  2. package/package.json +1 -1
package/dist/laze.mjs CHANGED
@@ -18733,8 +18733,8 @@ 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: readFile38, mkdir: mkdir21 } = __require("node:fs/promises");
18737
- var { dirname: dirname21, resolve: resolve17 } = __require("node:path");
18736
+ var { writeFile: writeFile23, readFile: readFile39, mkdir: mkdir21 } = __require("node:fs/promises");
18737
+ var { dirname: dirname22, resolve: resolve17 } = __require("node:path");
18738
18738
  var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("node:timers");
18739
18739
  var { InvalidArgumentError, UndiciError } = require_errors();
18740
18740
  var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
@@ -18950,7 +18950,7 @@ var require_snapshot_recorder = __commonJS({
18950
18950
  throw new InvalidArgumentError("Snapshot path is required");
18951
18951
  }
18952
18952
  try {
18953
- const data = await readFile38(resolve17(path), "utf8");
18953
+ const data = await readFile39(resolve17(path), "utf8");
18954
18954
  const parsed = JSON.parse(data);
18955
18955
  if (Array.isArray(parsed)) {
18956
18956
  this.#snapshots.clear();
@@ -18980,7 +18980,7 @@ var require_snapshot_recorder = __commonJS({
18980
18980
  throw new InvalidArgumentError("Snapshot path is required");
18981
18981
  }
18982
18982
  const resolvedPath = resolve17(path);
18983
- await mkdir21(dirname21(resolvedPath), { recursive: true });
18983
+ await mkdir21(dirname22(resolvedPath), { recursive: true });
18984
18984
  const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot]) => ({
18985
18985
  hash: hash2,
18986
18986
  snapshot
@@ -35645,6 +35645,7 @@ function boundProfileOf({
35645
35645
  // src/rules/args.rules.ts
35646
35646
  var SWITCHES = /* @__PURE__ */ new Set([
35647
35647
  "wait",
35648
+ "take",
35648
35649
  "json",
35649
35650
  "no-hook",
35650
35651
  "help",
@@ -35707,7 +35708,7 @@ function flagText({
35707
35708
  }
35708
35709
 
35709
35710
  // src/rules/cli-version.rules.ts
35710
- var STAMPED = "0.1.30";
35711
+ var STAMPED = "0.1.32";
35711
35712
  function cliVersionOf({ stamped = STAMPED } = {}) {
35712
35713
  return stamped.startsWith("__") ? "dev" : stamped;
35713
35714
  }
@@ -57981,6 +57982,7 @@ var deleteDraftInputSchema = deleteDraftInputSchemaDefinition;
57981
57982
  var GROUP_DM_MAX_MEMBERS = 8;
57982
57983
  var MESSAGE_BODY_MAX = 4e4;
57983
57984
  var HISTORY_PAGE_MAX = 100;
57985
+ var NOTICE_DETAILS_MAX = 2e3;
57984
57986
  var workspaceIdSchema = external_exports.string().min(1);
57985
57987
  var idSchema4 = external_exports.string().min(1).max(64);
57986
57988
  var chatActorKindSchema = external_exports.enum(["person", "agent"]);
@@ -58275,6 +58277,10 @@ var feedCardSchemaDefinition = external_exports.object({
58275
58277
  itemId: idSchema4,
58276
58278
  changeId: idSchema4
58277
58279
  });
58280
+ var failureCardSchemaDefinition = external_exports.object({
58281
+ type: external_exports.literal("failure"),
58282
+ details: external_exports.string().min(1).max(NOTICE_DETAILS_MAX)
58283
+ });
58278
58284
  var messageCardSchemaDefinition = external_exports.discriminatedUnion("type", [
58279
58285
  attentionCardSchemaDefinition,
58280
58286
  connectCardSchemaDefinition,
@@ -58285,7 +58291,8 @@ var messageCardSchemaDefinition = external_exports.discriminatedUnion("type", [
58285
58291
  heldCardSchemaDefinition,
58286
58292
  hopLimitCardSchemaDefinition,
58287
58293
  budgetCardSchemaDefinition,
58288
- feedCardSchemaDefinition
58294
+ feedCardSchemaDefinition,
58295
+ failureCardSchemaDefinition
58289
58296
  ]);
58290
58297
  var messageRefSchemaDefinition = external_exports.object({
58291
58298
  /** `conversation` points at a conversation with the agent, by its channel. */
@@ -58680,6 +58687,8 @@ var postNoticeInputSchemaDefinition = external_exports.object({
58680
58687
  ref: messageRefSchemaDefinition.optional(),
58681
58688
  /** Set on the notice a compaction leaves, so it draws as a divider. */
58682
58689
  compaction: messageCompactionSchemaDefinition.optional(),
58690
+ /** The raw reason behind the line, such as a provider's error, shown only under Details. */
58691
+ details: external_exports.string().trim().min(1).max(NOTICE_DETAILS_MAX).optional(),
58683
58692
  /** One notice per key: a second post with it answers the first. */
58684
58693
  clientKey: external_exports.string().regex(/^[A-Za-z0-9_-]{8,64}$/).optional()
58685
58694
  });
@@ -60342,6 +60351,25 @@ var attentionClosedReasonSchema = external_exports.enum([
60342
60351
  ]);
60343
60352
  var permissionDecisionSchema2 = external_exports.enum(["allowed", "skipped"]);
60344
60353
  var permissionSkipReasonSchema = external_exports.enum(["question", "plan", "plan_mode"]);
60354
+ var liveStepKindSchema = external_exports.enum(["tool", "subagent", "shell"]);
60355
+ var liveStepStatusSchema = external_exports.enum(["running", "done", "failed"]);
60356
+ var LIVE_STEP_LABEL_MAX = 160;
60357
+ var LIVE_STEPS_BATCH_MAX = 100;
60358
+ var liveStepSchemaDefinition = external_exports.object({
60359
+ id: external_exports.string().min(1).max(200),
60360
+ kind: liveStepKindSchema,
60361
+ /** `Bash(Run the tests)` for a tool; the task for a subagent; what a shell runs. */
60362
+ label: external_exports.string().max(LIVE_STEP_LABEL_MAX),
60363
+ status: liveStepStatusSchema,
60364
+ /** Epoch ms. */
60365
+ startedAt: external_exports.number().int().nonnegative(),
60366
+ endedAt: external_exports.number().int().nonnegative().optional(),
60367
+ /** A subagent's type or model, such as `Explore` or `claude-haiku-4-5`. */
60368
+ agent: external_exports.string().max(80).optional(),
60369
+ /** A subagent's tool calls so far. */
60370
+ steps: external_exports.number().int().nonnegative().optional()
60371
+ });
60372
+ var liveStepSchema = liveStepSchemaDefinition;
60345
60373
  var lazeAgentEventSchemaDefinition = external_exports.discriminatedUnion("type", [
60346
60374
  external_exports.object({
60347
60375
  type: external_exports.literal("harness_started"),
@@ -60375,6 +60403,12 @@ var lazeAgentEventSchemaDefinition = external_exports.discriminatedUnion("type",
60375
60403
  failure: external_exports.object({ code: external_exports.string().min(1), message: external_exports.string() }).optional()
60376
60404
  }),
60377
60405
  external_exports.object({ type: external_exports.literal("text_delta"), messageId: external_exports.string().optional(), text: external_exports.string() }),
60406
+ /** Steps that changed since the last batch, coalesced on the computer; streamed, never stored. */
60407
+ external_exports.object({
60408
+ type: external_exports.literal("steps"),
60409
+ turnId: external_exports.string().min(1),
60410
+ steps: external_exports.array(liveStepSchemaDefinition).max(LIVE_STEPS_BATCH_MAX)
60411
+ }),
60378
60412
  external_exports.object({
60379
60413
  type: external_exports.literal("message"),
60380
60414
  role: external_exports.enum(["user", "assistant"]),
@@ -60750,7 +60784,9 @@ var hostFrameSchemaDefinition = external_exports.discriminatedUnion("type", [
60750
60784
  external_exports.object({
60751
60785
  type: external_exports.literal("hello"),
60752
60786
  agentToken: external_exports.string().min(1),
60753
- lastAckedSeq: external_exports.number().int()
60787
+ lastAckedSeq: external_exports.number().int(),
60788
+ /** This host takes `steps` events; a supervisor sends none to a host that does not say so. */
60789
+ liveSteps: external_exports.boolean().optional()
60754
60790
  }),
60755
60791
  external_exports.object({
60756
60792
  type: external_exports.literal("deliver"),
@@ -63619,6 +63655,66 @@ var linkRedemptionSchemaDefinition = external_exports.discriminatedUnion("status
63619
63655
  ]);
63620
63656
  var linkRedemptionSchema = linkRedemptionSchemaDefinition;
63621
63657
 
63658
+ // ../../modules/agent/contract/src/agent-live-steps.ts
63659
+ var liveTurnStateSchema = external_exports.enum(["working", "done", "stopped", "failed"]);
63660
+ var sequencedStepSchemaDefinition = external_exports.object({
63661
+ ...liveStepSchema.shape,
63662
+ seq: external_exports.number().int().positive()
63663
+ });
63664
+ var liveTurnSchemaDefinition = external_exports.object({
63665
+ turnKey: external_exports.string().min(1),
63666
+ state: liveTurnStateSchema,
63667
+ startedAt: external_exports.number().int().nonnegative(),
63668
+ endedAt: external_exports.number().int().nonnegative().nullable(),
63669
+ /** Every tool call of the turn, also those past the kept lines. */
63670
+ tools: external_exports.number().int().nonnegative()
63671
+ });
63672
+ var liveStepsPublicationSchemaDefinition = external_exports.discriminatedUnion("type", [
63673
+ external_exports.object({
63674
+ type: external_exports.literal("step"),
63675
+ turnKey: external_exports.string().min(1),
63676
+ step: sequencedStepSchemaDefinition
63677
+ }),
63678
+ external_exports.object({
63679
+ type: external_exports.literal("turn"),
63680
+ turnKey: external_exports.string().min(1),
63681
+ seq: external_exports.number().int().positive(),
63682
+ turn: liveTurnSchemaDefinition
63683
+ })
63684
+ ]);
63685
+ var liveStepsInputSchemaDefinition = external_exports.object({
63686
+ workspaceId: external_exports.string().min(1),
63687
+ agentId: external_exports.string().min(1),
63688
+ channelId: external_exports.string().min(1),
63689
+ /** A finished turn's key, as a reply names it; the running turn when left out. */
63690
+ turnKey: external_exports.string().min(1).optional()
63691
+ });
63692
+ var liveStepsInputSchema = liveStepsInputSchemaDefinition;
63693
+ var liveStepsSchemaDefinition = external_exports.object({
63694
+ turn: liveTurnSchemaDefinition.nullable(),
63695
+ steps: external_exports.array(sequencedStepSchemaDefinition),
63696
+ lastSeq: external_exports.number().int().nonnegative(),
63697
+ /** Null where the realtime edge is not configured: the panel says live steps are unavailable. */
63698
+ stream: realtimeTokenSchema.nullable()
63699
+ });
63700
+ var liveStepsSchema = liveStepsSchemaDefinition;
63701
+ var replyStepsInputSchemaDefinition = external_exports.object({
63702
+ workspaceId: external_exports.string().min(1),
63703
+ channelId: external_exports.string().min(1),
63704
+ messageIds: external_exports.array(external_exports.string().min(1)).max(200)
63705
+ });
63706
+ var replyStepsInputSchema = replyStepsInputSchemaDefinition;
63707
+ var replyStepsSchemaDefinition = external_exports.array(
63708
+ external_exports.object({
63709
+ messageId: external_exports.string().min(1),
63710
+ agentId: external_exports.string().min(1),
63711
+ turnKey: external_exports.string().min(1),
63712
+ state: liveTurnStateSchema,
63713
+ tools: external_exports.number().int().nonnegative()
63714
+ })
63715
+ );
63716
+ var replyStepsSchema = replyStepsSchemaDefinition;
63717
+
63622
63718
  // ../../modules/agent/contract/src/agent-login-trouble.ts
63623
63719
  var loginCardActionInputSchemaDefinition = external_exports.object({
63624
63720
  workspaceId: external_exports.string().min(1),
@@ -64268,6 +64364,8 @@ var harnessLoginsSchemaDefinition = external_exports.object({
64268
64364
  codex: external_exports.boolean()
64269
64365
  });
64270
64366
  var harnessLoginsSchema = harnessLoginsSchemaDefinition;
64367
+ var lastRuntimeSchemaDefinition = external_exports.object({ harness: hostedHarnessSchema.nullable() });
64368
+ var lastRuntimeSchema = lastRuntimeSchemaDefinition;
64271
64369
  var mintLinkInputSchemaDefinition = external_exports.object({
64272
64370
  workspaceId: workspaceIdSchema10,
64273
64371
  /** Left out, the agent names itself when it joins, else it takes its harness's name. */
@@ -64555,11 +64653,12 @@ var codexLoginRefreshInputSchemaDefinition = external_exports.object({
64555
64653
  });
64556
64654
  var AgentApi = moduleApi()("agent");
64557
64655
  var agentCoreTrpc = defineTrpcContract("agents").query("list").withInput(external_exports.object({ workspaceId: workspaceIdSchema10 })).withOutput(external_exports.array(agentListEntrySchema)).mutation("create").withInput(createAgentInputSchema).withOutput(agentSchema).mutation("update").withInput(updateAgentInputSchema).withOutput(agentSchema).mutation("remove").withInput(external_exports.object({ workspaceId: workspaceIdSchema10, agentId: idSchema14 })).withOutput(external_exports.object({ removed: external_exports.literal(true) })).mutation("transfer").withInput(transferAgentInputSchema).withOutput(agentSchema).mutation("resetSession").withInput(resetAgentSessionInputSchema).withOutput(agentSchema).query("faces").withInput(external_exports.object({ workspaceId: workspaceIdSchema10 })).withOutput(external_exports.array(agentFaceSchema)).query("presence").withInput(external_exports.object({ workspaceId: workspaceIdSchema10 })).withOutput(external_exports.array(agentPresenceSchema)).mutation("uploadAvatar").withInput(uploadAgentAvatarInputSchema).withOutput(uploadedAgentAvatarSchema).query("access").withInput(external_exports.object({ workspaceId: workspaceIdSchema10, agentId: idSchema14 })).withOutput(agentAccessSchema).query("loginActivity").withInput(external_exports.object({ workspaceId: workspaceIdSchema10, agentId: idSchema14 })).withOutput(loginActivitySchema).mutation("raiseBudget").withInput(raiseBudgetInputSchema).withOutput(external_exports.object({ limitUsd: external_exports.number() })).query("permissionPrompts").withInput(external_exports.object({ workspaceId: workspaceIdSchema10, agentId: idSchema14 })).withOutput(external_exports.array(agentPermissionPromptSchema)).mutation("share").withInput(shareAgentInputSchema).withOutput(agentAccessSchema).mutation("unshare").withInput(shareAgentInputSchema).withOutput(agentAccessSchema).query("harnessLogins").withInput(external_exports.object({ workspaceId: workspaceIdSchema10 })).withOutput(harnessLoginsSchema).mutation("saveHarnessLogin").withInput(saveHarnessLoginInputSchema).withOutput(harnessLoginsSchema).mutation("removeHarnessLogin").withInput(removeHarnessLoginInputSchema).withOutput(harnessLoginsSchema).query("listHarnessLogins").withInput(external_exports.object({ workspaceId: workspaceIdSchema10 })).withOutput(harnessLoginListSchema).mutation("addHarnessLogin").withInput(addHarnessLoginInputSchema).withOutput(harnessLoginListSchema).mutation("renameHarnessLogin").withInput(renameHarnessLoginInputSchema).withOutput(harnessLoginListSchema).mutation("deleteHarnessLogin").withInput(deleteHarnessLoginInputSchema).withOutput(harnessLoginListSchema).mutation("checkLoginUsage").withInput(checkLoginUsageInputSchema).withOutput(loginUsageCheckSchema).query("loginPools").withInput(external_exports.object({ workspaceId: workspaceIdSchema10 })).withOutput(loginPoolsSchema).mutation("createLoginPool").withInput(createLoginPoolInputSchema).withOutput(loginPoolsSchema).mutation("renameLoginPool").withInput(renameLoginPoolInputSchema).withOutput(loginPoolsSchema).mutation("deleteLoginPool").withInput(loginPoolRefInputSchema).withOutput(loginPoolsSchema).mutation("addPoolLogin").withInput(addPoolLoginInputSchema).withOutput(loginPoolsSchema).mutation("removePoolLogin").withInput(removePoolLoginInputSchema).withOutput(loginPoolsSchema).mutation("setPoolMember").withInput(setPoolMemberInputSchema).withOutput(loginPoolsSchema).mutation("removePoolMember").withInput(removePoolMemberInputSchema).withOutput(loginPoolsSchema).mutation("setAgentPool").withInput(setAgentPoolInputSchema).withOutput(agentSchema).mutation("openDirect").withInput(external_exports.object({ workspaceId: workspaceIdSchema10, agentId: idSchema14 })).withOutput(external_exports.object({ channelId: idSchema14 })).mutation("startConversation").withInput(startConversationInputSchema).withOutput(startedConversationSchema).query("conversations").withInput(listConversationsInputSchema).withOutput(external_exports.array(conversationSummarySchema2)).mutation("joinConversation").withInput(conversationInputSchema).withOutput(conversationSummarySchema2).mutation("renameConversation").withInput(renameConversationInputSchema).withOutput(conversationSummarySchema2).mutation("leaveConversation").withInput(conversationInputSchema).withOutput(external_exports.object({ left: external_exports.literal(true) })).mutation("deleteConversation").withInput(conversationInputSchema).withOutput(external_exports.object({ deleted: external_exports.literal(true) })).mutation("mintLink").withInput(mintLinkInputSchema).withOutput(mintedLinkSchema).query("linkRedemption").withInput(linkRedemptionInputSchema).withOutput(linkRedemptionSchema).query("oauthRequest").withInput(oauthRequestInputSchema).withOutput(oauthRequestViewSchema).mutation("oauthApprove").withInput(approveOAuthInputSchema).withOutput(oauthRedirectSchema).mutation("oauthDeny").withInput(oauthRequestInputSchema).withOutput(oauthRedirectSchema).mutation("disconnect").withInput(external_exports.object({ workspaceId: workspaceIdSchema10, agentId: idSchema14 })).withOutput(external_exports.object({ disconnected: external_exports.literal(true) })).mutation("setGithub").withInput(setAgentGithubInputSchema).withOutput(agentSchema).query("githubWatches").withInput(external_exports.object({ workspaceId: workspaceIdSchema10, agentId: idSchema14 })).withOutput(external_exports.array(agentGithubWatchSchema)).mutation("watchGithub").withInput(watchGithubInputSchema).withOutput(agentGithubWatchSchema).mutation("unwatchGithub").withInput(unwatchGithubInputSchema).withOutput(external_exports.object({ removed: external_exports.literal(true) })).build();
64558
- var agentTurnTrpc = defineTrpcContract("agents").mutation("answerAttention").withInput(answerAttentionInputSchema).withOutput(external_exports.object({ answered: external_exports.literal(true) })).mutation("stopTurn").withInput(stopAgentTurnInputSchema).withOutput(external_exports.object({ stopped: external_exports.literal(true) })).query("mayStopTurn").withInput(stopAgentTurnInputSchema).withOutput(external_exports.object({ allowed: external_exports.boolean() })).mutation("compactSession").withInput(compactAgentSessionInputSchema).withOutput(external_exports.object({ requested: external_exports.literal(true) })).mutation("restartComputer").withInput(restartAgentComputerInputSchema).withOutput(external_exports.object({ restarted: external_exports.boolean() })).build();
64656
+ var agentTurnTrpc = defineTrpcContract("agents").mutation("answerAttention").withInput(answerAttentionInputSchema).withOutput(external_exports.object({ answered: external_exports.literal(true) })).mutation("stopTurn").withInput(stopAgentTurnInputSchema).withOutput(external_exports.object({ stopped: external_exports.literal(true) })).query("mayStopTurn").withInput(stopAgentTurnInputSchema).withOutput(external_exports.object({ allowed: external_exports.boolean() })).query("liveSteps").withInput(liveStepsInputSchema).withOutput(liveStepsSchema).query("replySteps").withInput(replyStepsInputSchema).withOutput(replyStepsSchema).mutation("compactSession").withInput(compactAgentSessionInputSchema).withOutput(external_exports.object({ requested: external_exports.literal(true) })).mutation("restartComputer").withInput(restartAgentComputerInputSchema).withOutput(external_exports.object({ restarted: external_exports.boolean() })).build();
64559
64657
  var agentChannelSettingsTrpc = defineTrpcContract("agents").query("monitors").withInput(external_exports.object({ workspaceId: workspaceIdSchema10, agentId: idSchema14 })).withOutput(external_exports.array(agentMonitorSchema)).query("channelLevel").withInput(external_exports.object({ workspaceId: workspaceIdSchema10, agentId: idSchema14, channelId: idSchema14 })).withOutput(channelLevelSchema).mutation("setChannelLevel").withInput(setChannelLevelInputSchema).withOutput(channelLevelSchema).mutation("unmuteChannel").withInput(unmuteAgentChannelInputSchema).withOutput(channelLevelSchema).mutation("cancelHeld").withInput(cancelHeldInputSchema).withOutput(cancelHeldResultSchema).build();
64560
64658
  var agentJoinTrpc = defineTrpcContract("agents").query("joinRequest").withInput(joinRequestInputSchema).withOutput(joinRequestViewSchema).mutation("approveJoinRequest").withInput(approveJoinRequestInputSchema).withOutput(joinRequestViewSchema).mutation("denyJoinRequest").withInput(joinRequestInputSchema).withOutput(joinRequestViewSchema).build();
64561
64659
  var agentLoginTroubleTrpc = defineTrpcContract("agents").mutation("replaceHarnessLogin").withInput(replaceHarnessLoginInputSchema).withOutput(harnessLoginListSchema).mutation("startHarnessSignIn").withInput(startHarnessSignInInputSchema).withOutput(harnessSignInSchema).mutation("pollHarnessSignIn").withInput(pollHarnessSignInInputSchema).withOutput(harnessSignInPollSchema).mutation("waitForLogins").withInput(loginCardActionInputSchema).withOutput(external_exports.object({ waiting: external_exports.boolean() })).mutation("useAnotherLogin").withInput(loginCardActionInputSchema).withOutput(external_exports.object({ loginName: external_exports.string() })).build();
64562
64660
  var agentWorkspaceDefaultTrpc = defineTrpcContract("agents").query("workspaceDefault").withInput(external_exports.object({ workspaceId: workspaceIdSchema10 })).withOutput(workspaceDefaultAgentSchema).mutation("setWorkspaceDefault").withInput(setWorkspaceDefaultAgentInputSchema).withOutput(workspaceDefaultAgentSchema).build();
64661
+ var agentRuntimeChoiceTrpc = defineTrpcContract("agents").query("lastRuntime").withInput(external_exports.object({ workspaceId: workspaceIdSchema10 })).withOutput(lastRuntimeSchema).build();
64563
64662
  var agentArchiveTrpc = defineTrpcContract("agents").query("archived").withInput(external_exports.object({ workspaceId: workspaceIdSchema10 })).withOutput(external_exports.array(archivedAgentSchema)).mutation("restore").withInput(restoreAgentInputSchema).withOutput(agentSchema).mutation("copy").withInput(copyAgentInputSchema).withOutput(agentSchema).mutation("deleteArchived").withInput(restoreAgentInputSchema).withOutput(external_exports.object({ deleted: external_exports.literal(true) })).build();
64564
64663
  var agentTrpc = joinTrpcContracts(
64565
64664
  "agents",
@@ -64569,6 +64668,7 @@ var agentTrpc = joinTrpcContracts(
64569
64668
  agentJoinTrpc,
64570
64669
  agentLoginTroubleTrpc,
64571
64670
  agentWorkspaceDefaultTrpc,
64671
+ agentRuntimeChoiceTrpc,
64572
64672
  agentArchiveTrpc
64573
64673
  );
64574
64674
  var agentUi = uiTokens("agent");
@@ -64578,6 +64678,8 @@ var AgentComputerCardSlot = agentUi.component("computerCard");
64578
64678
  var AgentLoginCardSlot = agentUi.component("loginCard");
64579
64679
  var AgentBudgetCardSlot = agentUi.component("budgetCard");
64580
64680
  var AgentStopTurnSlot = agentUi.component("stopTurn");
64681
+ var AgentLiveStepsSlot = agentUi.component("liveSteps");
64682
+ var AgentReplyStepsSlot = agentUi.component("replySteps");
64581
64683
  var AgentSessionHooksToken = agentUi.hooks("session");
64582
64684
  var AgentCreateDialogSlot = agentUi.component("createDialog");
64583
64685
  var AgentEditDialogSlot = agentUi.component("editDialog");
@@ -64616,8 +64718,6 @@ var agentConfig = Config.define((c) => ({
64616
64718
  "AGENT_CLAUDE_GATEWAY_THINKING",
64617
64719
  external_exports.enum(["on", "off"]).default("on")
64618
64720
  ),
64619
- claudeModel: c.env("AGENT_CLAUDE_MODEL", external_exports.string().min(1).default("sonnet")),
64620
- codexModel: c.env("AGENT_CODEX_MODEL", external_exports.string().min(1).default("gpt-5.5")),
64621
64721
  /** The Codex model's window, which caps a Codex agent's context window setting. */
64622
64722
  codexContextWindow: c.env("AGENT_CODEX_CONTEXT", positiveInt3.default(4e5)),
64623
64723
  /** A harness prompt or question no one answers is denied or dismissed after this long. */
@@ -65572,8 +65672,8 @@ async function copyAgent({
65572
65672
  }
65573
65673
 
65574
65674
  // src/services/agent-commands.service.ts
65575
- import { mkdir as mkdir14, readFile as readFile13, writeFile as writeFile14 } from "node:fs/promises";
65576
- import { join as join14, resolve as resolve4 } from "node:path";
65675
+ import { mkdir as mkdir14, readFile as readFile14, writeFile as writeFile14 } from "node:fs/promises";
65676
+ import { join as join15, resolve as resolve4 } from "node:path";
65577
65677
 
65578
65678
  // src/rules/agent-profile.rules.ts
65579
65679
  var LEVELS = { fast: "Laze Fast", frontier: "Laze Frontier" };
@@ -66748,14 +66848,32 @@ function rushSessionOf({
66748
66848
  function rushSendCommand({ program, id }) {
66749
66849
  return ["sh", "-c", 'printf "%s\\n" "$LAZE_WAKE_TEXT" | "$0" session send "$1"', program, id];
66750
66850
  }
66751
- function rushListsLive({ listed, sessionId }) {
66851
+ function rushListedOf({ listed }) {
66752
66852
  try {
66753
66853
  const sessions = JSON.parse(listed);
66754
- return sessions.some((one) => one.sessionId === sessionId && one.state !== "stopped");
66854
+ return Array.isArray(sessions) ? sessions : [];
66755
66855
  } catch {
66756
- return false;
66856
+ return [];
66757
66857
  }
66758
66858
  }
66859
+ function rushListsLive({ listed, sessionId }) {
66860
+ return rushListedOf({ listed }).some(
66861
+ (one) => one.sessionId === sessionId && one.state !== "stopped"
66862
+ );
66863
+ }
66864
+ function rushRunsElsewhere({
66865
+ listed,
66866
+ sessionId,
66867
+ claudePid
66868
+ }) {
66869
+ return rushListedOf({ listed }).some(
66870
+ (one) => one.sessionId === sessionId && one.state !== "stopped" && one.alive === true && one.claudePid !== claudePid
66871
+ );
66872
+ }
66873
+ function rushStandingOf({ one }) {
66874
+ if (!one || one.state === "stopped") return "stopped";
66875
+ return one.alive === false ? "asleep" : "awake";
66876
+ }
66759
66877
 
66760
66878
  // src/services/claude-project.service.ts
66761
66879
  import { basename as basename2, isAbsolute, relative as relative2, resolve as resolve2 } from "node:path";
@@ -66949,8 +67067,7 @@ async function sessionProfileArgs({
66949
67067
  }
66950
67068
  return args;
66951
67069
  }
66952
- async function rushKeeps({ context, key }) {
66953
- const sessionId = key.slice(key.indexOf(":") + 1);
67070
+ async function rushListingOf({ context }) {
66954
67071
  let listed = "";
66955
67072
  const code = await context.runCommand({
66956
67073
  command: ["sh", "-c", "command -v rush >/dev/null && rush session list --json"],
@@ -66958,15 +67075,27 @@ async function rushKeeps({ context, key }) {
66958
67075
  stdout: { write: (chunk) => listed += chunk },
66959
67076
  stderr: { write: () => true }
66960
67077
  }).catch(() => 1);
66961
- if (code !== 0) return false;
66962
- return rushListsLive({ listed, sessionId });
67078
+ return code === 0 ? listed : void 0;
67079
+ }
67080
+ async function rushKeeps({
67081
+ context,
67082
+ key,
67083
+ claudePid,
67084
+ asleepCounts
67085
+ }) {
67086
+ const sessionId = key.slice(key.indexOf(":") + 1);
67087
+ const listed = await rushListingOf({ context });
67088
+ if (listed === void 0) return false;
67089
+ if (asleepCounts) return rushListsLive({ listed, sessionId });
67090
+ return rushRunsElsewhere({ listed, sessionId, claudePid });
66963
67091
  }
66964
67092
  async function liveElsewhere({
66965
67093
  context,
66966
67094
  key,
66967
- claudePid
67095
+ claudePid,
67096
+ asleepCounts = true
66968
67097
  }) {
66969
- if (await rushKeeps({ context, key })) return true;
67098
+ if (await rushKeeps({ context, key, claudePid, asleepCounts })) return true;
66970
67099
  const folder = dirname3(statePathOf({ context, kind: "sessions", profile: "x" }));
66971
67100
  for (const file3 of await readdir(folder).catch(() => [])) {
66972
67101
  const pid = Number(file3.replace(/\.json$/, ""));
@@ -67612,8 +67741,23 @@ function waitSecondsOf({ args }) {
67612
67741
  const timeout = Number(flagText({ args, name: "timeout", fallback: "0" }));
67613
67742
  return timeout > 0 ? timeout : Infinity;
67614
67743
  }
67744
+ async function refuseOtherSessionsInbox({
67745
+ context,
67746
+ args,
67747
+ name: name2
67748
+ }) {
67749
+ if (args.flags.take) return;
67750
+ const bound = Object.entries((await context.store.read()).sessions ?? {}).filter(([, profile]) => profile === name2).map(([key]) => key);
67751
+ if (bound.length === 0) return;
67752
+ const here = await currentSessionOf({ context, args });
67753
+ if (here && bound.includes(sessionKeyOf({ session: here }))) return;
67754
+ throw new CliUsageError(
67755
+ `${name2} is bound to the session ${bound.join(", ")}, and reading its inbox here would take those messages away from it. Read the channel with \`laze history <channel>\` instead, or pass --take to take them anyway.`
67756
+ );
67757
+ }
67615
67758
  async function inbox({ context, args }) {
67616
67759
  const { client, name: name2, profile } = await signedIn({ context, args });
67760
+ if (profile.kind === "agent") await refuseOtherSessionsInbox({ context, args, name: name2 });
67617
67761
  const waitSeconds = waitSecondsOf({ args });
67618
67762
  const messages = await receiveMessages({ context, client, waitSeconds });
67619
67763
  if (profile.kind === "agent" && context.environment.harness === "claude-code") {
@@ -67697,238 +67841,13 @@ function channelLabelIn(channel) {
67697
67841
  }
67698
67842
 
67699
67843
  // src/services/claude-wait.service.ts
67700
- import { readFile as readFile7, rm as rm2, writeFile as writeFile6, mkdir as mkdir6 } from "node:fs/promises";
67701
- import { dirname as dirname6 } from "node:path";
67702
-
67703
- // src/services/rush-host.service.ts
67704
- import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile5 } from "node:fs/promises";
67705
- import { dirname as dirname5, join as join6 } from "node:path";
67706
- async function rushAboveOf({
67707
- context,
67708
- from = context.processes.pid
67709
- }) {
67710
- let pid = await context.processes.parentOf(from);
67711
- for (let depth = 0; pid !== void 0 && pid > 1 && depth < 16; depth += 1) {
67712
- const rush = rushSessionOf({ parentArgs: await context.processes.argsOf(pid) });
67713
- if (rush) return rush;
67714
- pid = await context.processes.parentOf(pid);
67715
- }
67716
- return void 0;
67717
- }
67718
- function guardPathOf({ context, claudePid }) {
67719
- return join6(dirname5(context.environment.configPath), "rush-guards", `${claudePid}.json`);
67720
- }
67721
- async function startRushGuard({
67722
- context,
67723
- profile,
67724
- claudePid,
67725
- rush
67726
- }) {
67727
- const path = guardPathOf({ context, claudePid });
67728
- const holder = await guardHolderOf({ path });
67729
- if (holder && context.processes.alive(holder.pid)) return;
67730
- const flags2 = ["--profile", profile, "--claude-pid", String(claudePid), "--rush-id", rush.id];
67731
- const argv = [...context.program, "hook", "rush-wake", ...flags2, "--rush-program", rush.program];
67732
- const logPath = join6(dirname5(context.environment.configPath), "rush-guards", "guard.log");
67733
- context.processes.spawnDetached({ argv: ["sh", "-c", '"$@" &', "sh", ...argv], logPath });
67734
- }
67735
- async function claimRushGuard({
67736
- context,
67737
- claudePid
67738
- }) {
67739
- const path = guardPathOf({ context, claudePid });
67740
- const holder = await guardHolderOf({ path });
67741
- const self2 = context.processes.pid;
67742
- if (holder && holder.pid !== self2 && context.processes.alive(holder.pid)) return false;
67743
- await mkdir5(dirname5(path), { recursive: true, mode: 448 });
67744
- await writeFile5(path, JSON.stringify({ pid: self2, claudePid }), { mode: 384 });
67745
- return true;
67746
- }
67747
- function guardHolderOf({ path }) {
67748
- return readFile6(path, "utf8").then(
67749
- (text2) => JSON.parse(text2),
67750
- () => void 0
67751
- );
67752
- }
67753
-
67754
- // src/services/claude-wait.service.ts
67755
- var ROUND_SECONDS = 50;
67756
- var WATCH_MS = 2e3;
67757
- var CHANNEL_CHECK_MS = 5e3;
67758
- async function holderOf({ path }) {
67759
- return readFile7(path, "utf8").then(
67760
- (text2) => JSON.parse(text2),
67761
- () => void 0
67762
- );
67763
- }
67764
- async function holderClaudeOf({ context, holder }) {
67765
- if (holder.claudePid) return holder.claudePid;
67766
- return (await nearestHarnessOf({ context, from: holder.pid }))?.pid;
67767
- }
67768
- async function takeLock({
67769
- context,
67770
- path,
67771
- sessionId,
67772
- claudePid,
67773
- preempt = false
67774
- }) {
67775
- const holder = await holderOf({ path });
67776
- const self2 = context.processes.pid;
67777
- if (holder && holder.pid !== self2 && context.processes.alive(holder.pid)) {
67778
- const served = await holderClaudeOf({ context, holder });
67779
- const mine4 = preempt && served === claudePid && !holder.monitor;
67780
- if (served && context.processes.alive(served) && !mine4) return false;
67781
- context.processes.stop(holder.pid);
67782
- }
67783
- await mkdir6(dirname6(path), { recursive: true, mode: 448 });
67784
- await writeFile6(
67785
- path,
67786
- JSON.stringify({
67787
- pid: self2,
67788
- claudePid,
67789
- ...sessionId ? { sessionId } : {},
67790
- ...preempt ? { monitor: true } : {}
67791
- })
67792
- );
67793
- return true;
67794
- }
67795
- async function channelLive({ context, profile }) {
67796
- const holder = await holderOf({ path: statePathOf({ context, kind: "channels", profile }) });
67797
- return holder !== void 0 && context.processes.alive(holder.pid);
67798
- }
67799
- async function takeRound({
67800
- context,
67801
- client,
67802
- claudePid,
67803
- session
67804
- }) {
67805
- const controller = new AbortController();
67806
- const { signal } = controller;
67807
- const watch = (async () => {
67808
- while (!signal.aborted) {
67809
- await context.sleep(WATCH_MS, signal);
67810
- if (claudePid && !context.processes.alive(claudePid)) controller.abort();
67811
- }
67812
- })();
67813
- try {
67814
- return await forSession({ client, session }).post(
67815
- "/api/agents/me/inbox",
67816
- { waitSeconds: ROUND_SECONDS },
67817
- { signal }
67818
- );
67819
- } catch (error62) {
67820
- if (signal.aborted) return [];
67821
- throw error62;
67822
- } finally {
67823
- controller.abort();
67824
- await watch;
67825
- }
67826
- }
67827
- async function roundOf({ context, client, name: name2, lock, claudePid, session, seen }) {
67828
- if ((await holderOf({ path: lock }))?.pid !== context.processes.pid) return void 0;
67829
- if (claudePid && !context.processes.alive(claudePid)) return void 0;
67830
- const due = await dueFromSpool({ context, profile: name2, seen, pushedToo: true });
67831
- if (due.length > 0) return due;
67832
- if (await channelLive({ context, profile: name2 })) {
67833
- await context.sleep(CHANNEL_CHECK_MS);
67834
- return [];
67835
- }
67836
- const taken = await takeRound({ context, client, claudePid, session });
67837
- if (taken.length === 0) {
67838
- await context.sleep(1e3);
67839
- return [];
67840
- }
67841
- await keepTaken({ context, profile: name2, messages: taken });
67842
- return taken;
67843
- }
67844
- async function claudePidOf({ context }) {
67845
- const harness = await nearestHarnessOf({ context });
67846
- if (harness?.harness === "claude-code") return harness.pid;
67847
- return await context.processes.parentOf(context.processes.pid) ?? 0;
67848
- }
67849
- async function settleRound(round) {
67850
- const { context, client, name: name2, session } = round;
67851
- const messages = await roundOf(round).catch(async (error62) => {
67852
- const refused = await notBoundNotice({
67853
- context,
67854
- client: forSession({ client, session }),
67855
- session,
67856
- error: error62,
67857
- profile: name2
67858
- });
67859
- if (!refused) throw error62;
67860
- return refused;
67861
- });
67862
- if (messages === void 0) return 0;
67863
- if (!Array.isArray(messages)) {
67864
- if (messages.rebound) return "again";
67865
- if (!messages.notice) return 0;
67866
- context.err(`${messages.notice}
67867
- `);
67868
- return 2;
67869
- }
67870
- if (messages.length === 0) return "again";
67871
- await turnStarted({ context, client, agent: name2, messages }).catch(() => void 0);
67872
- const self2 = await currentNameOf({ context, client, profile: name2 });
67873
- context.err(`${hookContextOf({ messages, self: self2 })}
67874
- `);
67875
- const messageIds = messages.map((message2) => message2.messageId);
67876
- await dropFromSpool({ context, profile: name2, messageIds });
67877
- return 2;
67878
- }
67879
- async function waitForMessages({ context, args }) {
67880
- const raw = await context.readStdin();
67881
- const input2 = raw.trim() ? JSON.parse(raw) : {};
67882
- const session = sessionOf({ context, harness: "claude-code", sessionId: input2.session_id });
67883
- const claudePid = await claudePidOf({ context });
67884
- const asked = await pluginHookArgs({ context, args, session, claudePid });
67885
- if (!asked) return 0;
67886
- const named = await sessionProfileArgs({ context, args: asked, session });
67887
- const { client, name: name2 } = await signedIn({ context, args: named });
67888
- await rememberSession({ context, claudePid, session });
67889
- const rush = rushSessionOf({
67890
- parentArgs: await context.processes.argsOf(await context.processes.parentOf(claudePid) ?? 0)
67891
- });
67892
- if (rush) await startRushGuard({ context, profile: name2, claudePid, rush });
67893
- const lock = statePathOf({ context, kind: "waiters", profile: name2 });
67894
- if (!await takeLock({ context, path: lock, sessionId: input2.session_id, claudePid })) return 0;
67895
- const seen = () => input2.transcript_path ? readFile7(input2.transcript_path, "utf8") : Promise.resolve("");
67896
- const deadline = context.nowMs() + (WAIT_HOOK_TIMEOUT_SECONDS - 60) * 1e3;
67897
- try {
67898
- while (context.nowMs() < deadline) {
67899
- const code = await settleRound({ context, client, name: name2, lock, claudePid, session, seen });
67900
- if (code !== "again") return code;
67901
- }
67902
- return 0;
67903
- } finally {
67904
- if ((await holderOf({ path: lock }))?.pid === context.processes.pid)
67905
- await rm2(lock, { force: true });
67906
- }
67907
- }
67908
- async function waitHook({ context, args }) {
67909
- try {
67910
- return await waitForMessages({ context, args });
67911
- } catch (error62) {
67912
- context.err(`laze: the background waiter stopped: ${String(error62)}
67913
- `);
67914
- return 0;
67915
- }
67916
- }
67917
- async function monitorServes({
67918
- context,
67919
- profile,
67920
- claudePid
67921
- }) {
67922
- const holder = await holderOf({ path: statePathOf({ context, kind: "waiters", profile }) });
67923
- if (!holder?.monitor || !context.processes.alive(holder.pid)) return false;
67924
- return await holderClaudeOf({ context, holder }) === claudePid;
67925
- }
67844
+ import { readFile as readFile10, rm as rm4, writeFile as writeFile9, mkdir as mkdir9 } from "node:fs/promises";
67845
+ import { dirname as dirname10 } from "node:path";
67926
67846
 
67927
- // src/services/codex-link.service.ts
67928
- import { createReadStream } from "node:fs";
67929
- import { readdir as readdir4, rm as rm6, stat as stat2 } from "node:fs/promises";
67930
- import { join as join12, resolve as resolve3 } from "node:path";
67931
- import { createInterface as createInterface2 } from "node:readline";
67847
+ // src/services/connect-service.service.ts
67848
+ import { createHash } from "node:crypto";
67849
+ import { mkdir as mkdir8, rm as rm3, writeFile as writeFile8 } from "node:fs/promises";
67850
+ import { dirname as dirname9, join as join11 } from "node:path";
67932
67851
 
67933
67852
  // src/rules/connect-service.rules.ts
67934
67853
  function systemdWordOf(word3) {
@@ -67952,6 +67871,8 @@ function systemdUnitOf({
67952
67871
  ...environment,
67953
67872
  "Restart=on-failure",
67954
67873
  "RestartSec=5",
67874
+ // The rush guards it starts outlive a restart, such as the one after a CLI update.
67875
+ "KillMode=process",
67955
67876
  "",
67956
67877
  "[Install]",
67957
67878
  "WantedBy=default.target",
@@ -67991,6 +67912,8 @@ function launchAgentOf({
67991
67912
  " <true/>",
67992
67913
  " <key>KeepAlive</key>",
67993
67914
  " <true/>",
67915
+ " <key>AbandonProcessGroup</key>",
67916
+ " <true/>",
67994
67917
  " <key>StandardOutPath</key>",
67995
67918
  ` <string>${xmlOf(logPath)}</string>`,
67996
67919
  " <key>StandardErrorPath</key>",
@@ -68045,396 +67968,21 @@ function rolloutEventOf({
68045
67968
  return held.length > 0 ? { kind: "holds", messageIds: held } : void 0;
68046
67969
  }
68047
67970
 
68048
- // src/services/codex-adopt.service.ts
68049
- import { spawn as spawn2 } from "node:child_process";
68050
- import { mkdir as mkdir7, readdir as readdir2, readFile as readFile8, rm as rm3, stat, writeFile as writeFile7 } from "node:fs/promises";
68051
- import { dirname as dirname7, join as join7 } from "node:path";
68052
- import { createInterface } from "node:readline";
68053
-
68054
- // src/rules/codex-requests.rules.ts
68055
- var DECLINED_DECISION = {
68056
- "item/commandExecution/requestApproval": "decline",
68057
- "item/fileChange/requestApproval": "decline",
68058
- execCommandApproval: "denied",
68059
- applyPatchApproval: "denied"
68060
- };
68061
- function codexRequestReplyOf({ method }) {
68062
- const decision = DECLINED_DECISION[method];
68063
- if (decision) return { result: { decision } };
68064
- if (method === "item/permissions/requestApproval") {
68065
- return { result: { permissions: {}, scope: "turn" } };
68066
- }
68067
- if (method === "mcpServer/elicitation/request") {
68068
- return { result: { action: "decline", content: null } };
68069
- }
68070
- return { error: { code: -32601, message: `${method} is not supported here` } };
68071
- }
68072
-
68073
- // src/services/codex-adopt.service.ts
68074
- function record3(value) {
68075
- return typeof value === "object" && value !== null ? value : {};
68076
- }
68077
- function absorbTurnEvent({ result, message: message2 }) {
68078
- const params = record3(message2.params);
68079
- if (message2.method === "item/completed") {
68080
- const item = record3(params.item);
68081
- if (item.type === "agentMessage" && typeof item.text === "string") result.answer = item.text;
68082
- return;
68083
- }
68084
- if (message2.method !== "thread/tokenUsage/updated") return;
68085
- const usage = record3(params.tokenUsage);
68086
- const total = record3(usage.last).totalTokens;
68087
- if (typeof total === "number") result.contextTokens = total;
68088
- const window2 = usage.modelContextWindow;
68089
- if (typeof window2 === "number" && window2 > 0) result.contextWindow = window2;
68090
- }
68091
- var TURN_HEARTBEAT_MS = 1e4;
68092
- var CodexAppServer = class _CodexAppServer {
68093
- constructor(child) {
68094
- this.child = child;
68095
- createInterface({ input: child.stdout }).on("line", (line) => this.receive(line));
68096
- }
68097
- child;
68098
- #nextId = 0;
68099
- #pending = /* @__PURE__ */ new Map();
68100
- #listeners = /* @__PURE__ */ new Set();
68101
- static start({
68102
- codexHome,
68103
- inherited
68104
- }) {
68105
- const env = { ...inherited, CODEX_HOME: codexHome };
68106
- return new _CodexAppServer(spawn2("codex", ["app-server"], { env, stdio: "pipe" }));
68107
- }
68108
- async call(method, params) {
68109
- const id = ++this.#nextId;
68110
- const reply2 = await new Promise((resolve17) => {
68111
- this.#pending.set(id, resolve17);
68112
- this.write({ id, method, params });
68113
- });
68114
- if (reply2.error !== void 0) throw new Error(`${method}: ${JSON.stringify(reply2.error)}`);
68115
- return record3(reply2.result);
68116
- }
68117
- notify(method) {
68118
- this.write({ method });
68119
- }
68120
- /** Starts one turn; `done` settles when it completes, keeping its last agent message. */
68121
- async startTurn({ threadId, text: text2 }) {
68122
- const result = { answer: "" };
68123
- const done = new Promise((resolve17) => {
68124
- const listen = (message2) => {
68125
- absorbTurnEvent({ result, message: message2 });
68126
- if (message2.method !== "turn/completed") return;
68127
- this.#listeners.delete(listen);
68128
- resolve17(result);
68129
- };
68130
- this.#listeners.add(listen);
68131
- });
68132
- const started = await this.call("turn/start", {
68133
- threadId,
68134
- input: [{ type: "text", text: text2, text_elements: [] }]
68135
- });
68136
- const turnId = record3(started.turn).id;
68137
- return { turnId: typeof turnId === "string" ? turnId : null, done };
68138
- }
68139
- stop() {
68140
- this.child.kill("SIGTERM");
68141
- }
68142
- write(message2) {
68143
- this.child.stdin.write(`${JSON.stringify(message2)}
68144
- `);
68145
- }
68146
- receive(line) {
68147
- let message2;
68148
- try {
68149
- message2 = record3(JSON.parse(line));
68150
- } catch {
68151
- return;
68152
- }
68153
- if (typeof message2.id === "number" && message2.method === void 0) {
68154
- this.#pending.get(message2.id)?.(message2);
68155
- this.#pending.delete(message2.id);
68156
- return;
68157
- }
68158
- if (message2.method !== void 0 && message2.id !== void 0) {
68159
- this.write({
68160
- id: message2.id,
68161
- ...codexRequestReplyOf({
68162
- method: typeof message2.method === "string" ? message2.method : ""
68163
- })
68164
- });
68165
- return;
68166
- }
68167
- for (const listen of this.#listeners) listen(message2);
68168
- }
68169
- };
68170
- async function newestThreadId({ codexHome }) {
68171
- const root = join7(codexHome, "sessions");
68172
- const files2 = await readdir2(root, { recursive: true }).catch(() => []);
68173
- const rollouts = files2.filter((file3) => /rollout-.*\.jsonl$/.test(file3));
68174
- const dated = await Promise.all(
68175
- rollouts.map(async (file3) => ({ file: file3, at: (await stat(join7(root, file3))).mtimeMs }))
68176
- );
68177
- const newest = dated.toSorted((a, b) => b.at - a.at)[0]?.file ?? "";
68178
- const id = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/.exec(newest);
68179
- if (!id?.[1]) throw new CliUsageError("No Codex session found: pass --thread <id>.");
68180
- return id[1];
68181
- }
68182
- function promptOf({ message: message2, self: self2 }) {
68183
- return [
68184
- `A message reached you in the Laze workspace${selfClauseOf({ self: self2 })}. Answer it; your final`,
68185
- "message is posted as your reply in its thread.",
68186
- "",
68187
- formatInboxMessage({ message: message2 }).split("\n").slice(0, -1).join("\n")
68188
- ].join("\n");
68189
- }
68190
- async function heartbeat({
68191
- client,
68192
- message: message2,
68193
- state
68194
- }) {
68195
- return client.post("/api/agents/me/turn", {
68196
- channelId: message2.channelId,
68197
- threadRootId: message2.threadRootId,
68198
- state,
68199
- ...state === "working" ? { messageId: message2.messageId } : {}
68200
- }).catch(() => void 0);
68201
- }
68202
- async function watchTurn({
68203
- context,
68204
- client,
68205
- codex,
68206
- threadId,
68207
- turn,
68208
- message: message2
68209
- }) {
68210
- const finished = new AbortController();
68211
- void turn.done.then(() => finished.abort());
68212
- while (!finished.signal.aborted) {
68213
- const beat2 = await heartbeat({ client, message: message2, state: "working" });
68214
- if (beat2?.stop && turn.turnId) {
68215
- await codex.call("turn/interrupt", { threadId, turnId: turn.turnId }).catch(() => void 0);
68216
- return beat2.stoppedBy ?? "someone";
68217
- }
68218
- await context.sleep(TURN_HEARTBEAT_MS, finished.signal);
68219
- }
68220
- return void 0;
68221
- }
68222
- async function answer({
68223
- context,
68224
- codex,
68225
- client,
68226
- threadId,
68227
- message: message2,
68228
- profile
68229
- }) {
68230
- const self2 = await currentNameOf({ context, client, profile });
68231
- const running = await codex.startTurn({ threadId, text: promptOf({ message: message2, self: self2 }) });
68232
- const stoppedBy = await watchTurn({ context, client, codex, threadId, turn: running, message: message2 });
68233
- const turn = await running.done;
68234
- await heartbeat({ client, message: message2, state: "idle" });
68235
- if (stoppedBy !== void 0) return `(stopped by ${stoppedBy})`;
68236
- const body = turn.answer.trim() || "(no answer)";
68237
- await client.post("/api/agents/me/replies", { messageId: message2.messageId, body });
68238
- if (turn.contextTokens !== void 0) {
68239
- await client.post("/api/agents/me/activity", {
68240
- sessionId: threadId,
68241
- contextTokens: turn.contextTokens,
68242
- ...turn.contextWindow ? { contextWindow: turn.contextWindow } : {}
68243
- });
68244
- }
68245
- return body;
68246
- }
68247
- var MAX_RESTART_WAIT_SECONDS = 60;
68248
- var HEALTHY_RUN_MS = 6e4;
68249
- async function recordOf({ path }) {
68250
- return readFile8(path, "utf8").then(
68251
- (text2) => JSON.parse(text2),
68252
- () => void 0
68253
- );
68254
- }
68255
- function threadFlag({ thread: thread2 }) {
68256
- return thread2 ? ["--thread", thread2] : [];
68257
- }
68258
- async function startAdoptInBackground({
68259
- context,
68260
- args,
68261
- profile,
68262
- laze
68263
- }) {
68264
- const thread2 = flagText({ args, name: "thread" }) || context.environment.inherited.CODEX_THREAD_ID || null;
68265
- const path = statePathOf({ context, kind: "adopt", profile });
68266
- const log = statePathOf({ context, kind: "adopt", profile, extension: "log" });
68267
- const running = await recordOf({ path });
68268
- if (running) context.processes.stop(running.pid);
68269
- const adopt = ["adopt", "codex", "--profile", profile, ...threadFlag({ thread: thread2 })];
68270
- const argv = [...context.program, ...adopt, "--supervise"];
68271
- const pid = context.processes.spawnDetached({ argv, logPath: log });
68272
- await mkdir7(dirname7(path), { recursive: true, mode: 448 });
68273
- await writeFile7(path, JSON.stringify({ pid, thread: thread2, log, startedAt: context.nowMs() }));
68274
- return [
68275
- `Started \`${laze} adopt codex\` in the background (pid ${pid}). It answers each Laze message`,
68276
- `as a turn in ${thread2 ? `this Codex thread (${thread2})` : "the newest Codex thread"}, and starts again if it stops.`,
68277
- `Log: ${log}`,
68278
- ` ${laze} adopt codex --status --profile ${profile} shows whether it runs`,
68279
- ` ${laze} adopt codex --stop --profile ${profile} stops it`,
68280
- "Nothing else needs to run. While this Codex window stays open, Codex lets only it write the",
68281
- "thread, so adopt answers in a fork of it (the same history so far; `codex resume <fork id>`",
68282
- "from the log opens it). Started again with this window closed, it answers in the thread itself."
68283
- ].join("\n");
68284
- }
68285
- async function supervise({
68286
- context,
68287
- args,
68288
- profile
68289
- }) {
68290
- const path = statePathOf({ context, kind: "adopt", profile });
68291
- const thread2 = flagText({ args, name: "thread" });
68292
- const adopt = ["adopt", "codex", "--profile", profile, ...threadFlag({ thread: thread2 })];
68293
- const command = [...context.program, ...adopt];
68294
- let wait = 1;
68295
- while ((await recordOf({ path }))?.pid === context.processes.pid) {
68296
- const started = context.nowMs();
68297
- context.out(
68298
- `${Temporal3.Instant.fromEpochMilliseconds(started).toString()} starting laze adopt codex
68299
- `
68300
- );
68301
- const code = await context.runCommand({ command, env: {} }).catch(() => 1);
68302
- if (context.nowMs() - started > HEALTHY_RUN_MS) wait = 1;
68303
- if ((await recordOf({ path }))?.pid !== context.processes.pid) break;
68304
- context.out(`laze adopt codex exited ${code}; starting it again in ${wait}s
68305
- `);
68306
- await context.sleep(wait * 1e3);
68307
- wait = Math.min(MAX_RESTART_WAIT_SECONDS, wait * 2);
68308
- }
68309
- return 0;
68310
- }
68311
- async function adoptStatus({ context, profile }) {
68312
- const record4 = await recordOf({ path: statePathOf({ context, kind: "adopt", profile }) });
68313
- if (!record4 || !context.processes.alive(record4.pid)) {
68314
- context.out(`laze adopt codex does not run in the background for profile "${profile}".
68315
- `);
68316
- return;
68317
- }
68318
- const thread2 = record4.thread ?? "the newest thread";
68319
- context.out(
68320
- `laze adopt codex runs in the background for profile "${profile}" (pid ${record4.pid}), thread ${thread2}.
68321
- Log: ${record4.log}
68322
- `
68323
- );
68324
- }
68325
- async function adoptStop({ context, profile }) {
68326
- const path = statePathOf({ context, kind: "adopt", profile });
68327
- const record4 = await recordOf({ path });
68328
- await rm3(path, { force: true });
68329
- if (!record4 || !context.processes.stop(record4.pid)) {
68330
- context.out(`laze adopt codex was not running in the background for profile "${profile}".
68331
- `);
68332
- return;
68333
- }
68334
- context.out(`Stopped laze adopt codex (pid ${record4.pid}) for profile "${profile}".
68335
- `);
68336
- }
68337
- var HELD_THREAD = /active writer/;
68338
- async function adoptedThreadOf({
68339
- context,
68340
- codex,
68341
- threadId,
68342
- profile
68343
- }) {
68344
- const held = await codex.call("thread/resume", { threadId }).then(
68345
- () => false,
68346
- (error62) => {
68347
- if (HELD_THREAD.test(String(error62))) return true;
68348
- throw error62;
68349
- }
68350
- );
68351
- if (!held) return threadId;
68352
- const path = statePathOf({ context, kind: "adopt", profile, extension: "forks.json" });
68353
- const forks = await readFile8(path, "utf8").then(
68354
- (text2) => JSON.parse(text2),
68355
- () => ({})
68356
- );
68357
- const known = forks[threadId];
68358
- if (known && await codex.call("thread/resume", { threadId: known }).then(
68359
- () => true,
68360
- () => false
68361
- )) {
68362
- context.out(`Codex holds thread ${threadId} open elsewhere; answering in its fork ${known}.
68363
- `);
68364
- return known;
68365
- }
68366
- const forked = record3((await codex.call("thread/fork", { threadId })).thread).id;
68367
- if (typeof forked !== "string") throw new Error("thread/fork answered no thread id");
68368
- await mkdir7(dirname7(path), { recursive: true, mode: 448 });
68369
- await writeFile7(path, JSON.stringify({ ...forks, [threadId]: forked }));
68370
- context.out(
68371
- `Codex holds thread ${threadId} open elsewhere; answering in its new fork ${forked}.
68372
- `
68373
- );
68374
- return forked;
68375
- }
68376
- async function adoptCodex({ context, args }) {
68377
- if (args.words[1] !== "codex") {
68378
- throw new CliUsageError("Usage: laze adopt codex [--thread <id>] | --status | --stop");
68379
- }
68380
- const { client, name: name2 } = await signedIn({ context, args });
68381
- if (args.flags.status) return adoptStatus({ context, profile: name2 });
68382
- if (args.flags.stop) return adoptStop({ context, profile: name2 });
68383
- if (args.flags.supervise) return supervise({ context, args, profile: name2 });
68384
- const { codexHome } = context.environment;
68385
- const threadId = flagText({ args, name: "thread" }) || context.environment.inherited.CODEX_THREAD_ID || await newestThreadId({ codexHome });
68386
- const once = Boolean(args.flags.once);
68387
- const codex = CodexAppServer.start({ codexHome, inherited: context.environment.inherited });
68388
- try {
68389
- await codex.call("initialize", {
68390
- clientInfo: { name: "laze", title: "Laze", version: "1" },
68391
- capabilities: null
68392
- });
68393
- codex.notify("initialized");
68394
- const adopted = await adoptedThreadOf({ context, codex, threadId, profile: name2 });
68395
- context.out(`Adopted Codex thread ${adopted}; answering Laze messages.
68396
- `);
68397
- const timeout = Number(flagText({ args, name: "timeout", fallback: "0" }));
68398
- do {
68399
- const messages = await receiveMessages({
68400
- context,
68401
- client,
68402
- waitSeconds: timeout > 0 ? timeout : Infinity
68403
- });
68404
- for (const message2 of messages) {
68405
- const body = await answer({
68406
- context,
68407
- codex,
68408
- client,
68409
- threadId: adopted,
68410
- message: message2,
68411
- profile: name2
68412
- });
68413
- context.out(`Answered ${message2.messageId}: ${body.slice(0, 120)}
68414
- `);
68415
- }
68416
- if (messages.length === 0 && timeout > 0) break;
68417
- } while (!once);
68418
- } finally {
68419
- codex.stop();
68420
- }
68421
- }
68422
-
68423
67971
  // src/services/connect-delivery.service.ts
68424
- import { mkdir as mkdir9, readFile as readFile10, rename as rename3, rm as rm4, writeFile as writeFile9 } from "node:fs/promises";
67972
+ import { mkdir as mkdir7, readFile as readFile9, rename as rename3, rm as rm2, stat as stat2, writeFile as writeFile7 } from "node:fs/promises";
68425
67973
  import { homedir as homedir2, hostname as hostname4 } from "node:os";
68426
- import { dirname as dirname9, join as join10 } from "node:path";
67974
+ import { dirname as dirname8, join as join10 } from "node:path";
68427
67975
 
68428
67976
  // src/services/codex-turn-watch.service.ts
68429
- import { open as open2, readdir as readdir3 } from "node:fs/promises";
68430
- import { join as join8 } from "node:path";
67977
+ import { open as open2, readdir as readdir2 } from "node:fs/promises";
67978
+ import { join as join6 } from "node:path";
68431
67979
  var READ_MS = 1500;
68432
67980
  var KEEP_WORKING_MS = 3e4;
68433
67981
  async function rolloutPathOf({ delivery }) {
68434
- const root = join8(delivery.codexHome, "sessions");
68435
- const files2 = await readdir3(root, { recursive: true }).catch(() => []);
67982
+ const root = join6(delivery.codexHome, "sessions");
67983
+ const files2 = await readdir2(root, { recursive: true }).catch(() => []);
68436
67984
  const file3 = files2.find((name2) => name2.endsWith(`-${delivery.threadId}.jsonl`));
68437
- return file3 ? join8(root, file3) : void 0;
67985
+ return file3 ? join6(root, file3) : void 0;
68438
67986
  }
68439
67987
  async function readFrom({ path, offset }) {
68440
67988
  const handle = await open2(path, "r");
@@ -68520,8 +68068,8 @@ var CodexTurnWatch = class _CodexTurnWatch {
68520
68068
  };
68521
68069
 
68522
68070
  // src/services/openclaw-relay.service.ts
68523
- import { chmod as chmod2, mkdir as mkdir8, readFile as readFile9, writeFile as writeFile8 } from "node:fs/promises";
68524
- import { dirname as dirname8, join as join9 } from "node:path";
68071
+ import { chmod as chmod2, mkdir as mkdir5, readFile as readFile6, writeFile as writeFile5 } from "node:fs/promises";
68072
+ import { dirname as dirname5, join as join7 } from "node:path";
68525
68073
 
68526
68074
  // ../../modules/openclaw/contract/src/openclaw.ts
68527
68075
  var workspaceIdSchema14 = external_exports.string().min(1);
@@ -68749,11 +68297,11 @@ var STOPS = /* @__PURE__ */ new Map([
68749
68297
  [OPENCLAW_RELAY_CLOSE.replaced.code, "another relay for this gateway took over"]
68750
68298
  ]);
68751
68299
  function relaysPathOf({ context }) {
68752
- return join9(dirname8(context.environment.configPath), "connect", "openclaw-relays.json");
68300
+ return join7(dirname5(context.environment.configPath), "connect", "openclaw-relays.json");
68753
68301
  }
68754
68302
  async function readRelays({ context }) {
68755
68303
  try {
68756
- return JSON.parse(await readFile9(relaysPathOf({ context }), "utf8"));
68304
+ return JSON.parse(await readFile6(relaysPathOf({ context }), "utf8"));
68757
68305
  } catch {
68758
68306
  return {};
68759
68307
  }
@@ -68763,8 +68311,8 @@ async function saveRelays({
68763
68311
  relays
68764
68312
  }) {
68765
68313
  const path = relaysPathOf({ context });
68766
- await mkdir8(dirname8(path), { recursive: true, mode: 448 });
68767
- await writeFile8(path, `${JSON.stringify(relays, null, 2)}
68314
+ await mkdir5(dirname5(path), { recursive: true, mode: 448 });
68315
+ await writeFile5(path, `${JSON.stringify(relays, null, 2)}
68768
68316
  `, { mode: 384 });
68769
68317
  await chmod2(path, 384);
68770
68318
  }
@@ -68948,16 +68496,148 @@ var RelayLoops = class _RelayLoops {
68948
68496
  }
68949
68497
  };
68950
68498
 
68499
+ // src/services/rush-listeners.service.ts
68500
+ import { readFile as readFile8, readdir as readdir3, stat } from "node:fs/promises";
68501
+ import { dirname as dirname7, join as join9 } from "node:path";
68502
+
68503
+ // src/services/rush-host.service.ts
68504
+ import { mkdir as mkdir6, readFile as readFile7, writeFile as writeFile6 } from "node:fs/promises";
68505
+ import { dirname as dirname6, join as join8 } from "node:path";
68506
+ async function rushAboveOf({
68507
+ context,
68508
+ from = context.processes.pid
68509
+ }) {
68510
+ let pid = await context.processes.parentOf(from);
68511
+ for (let depth = 0; pid !== void 0 && pid > 1 && depth < 16; depth += 1) {
68512
+ const rush = rushSessionOf({ parentArgs: await context.processes.argsOf(pid) });
68513
+ if (rush) return rush;
68514
+ pid = await context.processes.parentOf(pid);
68515
+ }
68516
+ return void 0;
68517
+ }
68518
+ function guardPathOf({ context, claudePid }) {
68519
+ return join8(dirname6(context.environment.configPath), "rush-guards", `${claudePid}.json`);
68520
+ }
68521
+ async function startRushGuard({
68522
+ context,
68523
+ profile,
68524
+ claudePid,
68525
+ rush
68526
+ }) {
68527
+ const path = guardPathOf({ context, claudePid });
68528
+ const holder = await guardHolderOf({ path });
68529
+ if (holder && context.processes.alive(holder.pid)) return;
68530
+ const flags2 = ["--profile", profile, "--claude-pid", String(claudePid), "--rush-id", rush.id];
68531
+ const argv = [...context.program, "hook", "rush-wake", ...flags2, "--rush-program", rush.program];
68532
+ const logPath = join8(dirname6(context.environment.configPath), "rush-guards", "guard.log");
68533
+ context.processes.spawnDetached({ argv: ["sh", "-c", '"$@" &', "sh", ...argv], logPath });
68534
+ }
68535
+ async function claimRushGuard({
68536
+ context,
68537
+ claudePid
68538
+ }) {
68539
+ const path = guardPathOf({ context, claudePid });
68540
+ const holder = await guardHolderOf({ path });
68541
+ const self2 = context.processes.pid;
68542
+ if (holder && holder.pid !== self2 && context.processes.alive(holder.pid)) return false;
68543
+ await mkdir6(dirname6(path), { recursive: true, mode: 448 });
68544
+ await writeFile6(path, JSON.stringify({ pid: self2, claudePid }), { mode: 384 });
68545
+ return true;
68546
+ }
68547
+ function guardHolderOf({ path }) {
68548
+ return readFile7(path, "utf8").then(
68549
+ (text2) => JSON.parse(text2),
68550
+ () => void 0
68551
+ );
68552
+ }
68553
+
68554
+ // src/services/rush-listeners.service.ts
68555
+ async function jsonOf(path) {
68556
+ return readFile8(path, "utf8").then(
68557
+ (text2) => JSON.parse(text2),
68558
+ () => void 0
68559
+ );
68560
+ }
68561
+ async function notesOf({ context }) {
68562
+ const folder = dirname7(statePathOf({ context, kind: "sessions", profile: "x" }));
68563
+ const files2 = await readdir3(folder).catch(() => []);
68564
+ const notes = await Promise.all(
68565
+ files2.map(async (file3) => {
68566
+ const pid = Number(file3.replace(/\.json$/, ""));
68567
+ const session = await jsonOf(join9(folder, file3));
68568
+ const at = await stat(join9(folder, file3)).then(
68569
+ (info) => info.mtimeMs,
68570
+ () => 0
68571
+ );
68572
+ return pid && session ? [{ pid, key: sessionKeyOf({ session }), at }] : [];
68573
+ })
68574
+ );
68575
+ return notes.flat().toSorted((a, b) => b.at - a.at);
68576
+ }
68577
+ async function rushListenersOf({
68578
+ context
68579
+ }) {
68580
+ const bound = Object.entries((await context.store.read()).sessions ?? {}).filter(
68581
+ ([key]) => key.startsWith("claude-code:")
68582
+ );
68583
+ if (bound.length === 0) return [];
68584
+ const listed = await rushListingOf({ context });
68585
+ if (listed === void 0) return [];
68586
+ const sessions = rushListedOf({ listed });
68587
+ const notes = await notesOf({ context });
68588
+ const rows = [];
68589
+ for (const [key, profile] of bound) {
68590
+ const one = sessions.find((each) => `claude-code:${each.sessionId}` === key);
68591
+ if (!one?.id) continue;
68592
+ const pids = notes.filter((note) => note.key === key).map((note) => note.pid);
68593
+ const listenerPid = await listenerOf({ context, key, profile, pids });
68594
+ const lastClaudePid = pids.find((pid) => !context.processes.alive(pid));
68595
+ rows.push({
68596
+ profile,
68597
+ rushId: one.id,
68598
+ standing: rushStandingOf({ one }),
68599
+ ...listenerPid ? { listenerPid } : {},
68600
+ ...lastClaudePid ? { lastClaudePid } : {}
68601
+ });
68602
+ }
68603
+ return rows;
68604
+ }
68605
+ async function listenerOf({
68606
+ context,
68607
+ key,
68608
+ profile,
68609
+ pids
68610
+ }) {
68611
+ for (const claudePid of pids) {
68612
+ const guard = await jsonOf(guardPathOf({ context, claudePid }));
68613
+ if (guard && context.processes.alive(guard.pid)) return guard.pid;
68614
+ }
68615
+ const lock = statePathOf({ context, kind: "waiters", profile });
68616
+ const waiter = await jsonOf(lock);
68617
+ const mine4 = waiter?.sessionId === key.slice(key.indexOf(":") + 1);
68618
+ return waiter && mine4 && context.processes.alive(waiter.pid) ? waiter.pid : void 0;
68619
+ }
68620
+ async function rearmRushGuards({ context }) {
68621
+ let started = 0;
68622
+ for (const row of await rushListenersOf({ context })) {
68623
+ if (row.standing !== "asleep" || row.listenerPid || !row.lastClaudePid) continue;
68624
+ const rush = { id: row.rushId, program: "rush" };
68625
+ await startRushGuard({ context, profile: row.profile, claudePid: row.lastClaudePid, rush });
68626
+ started += 1;
68627
+ }
68628
+ return started;
68629
+ }
68630
+
68951
68631
  // src/services/connect-delivery.service.ts
68952
68632
  function connectFolderOf({ context }) {
68953
- return join10(dirname9(context.environment.configPath), "connect");
68633
+ return join10(dirname8(context.environment.configPath), "connect");
68954
68634
  }
68955
68635
  function runStatePathOf({ context }) {
68956
68636
  return join10(connectFolderOf({ context }), "run.json");
68957
68637
  }
68958
68638
  async function readJson({ path }) {
68959
68639
  try {
68960
- return JSON.parse(await readFile10(path, "utf8"));
68640
+ return JSON.parse(await readFile9(path, "utf8"));
68961
68641
  } catch {
68962
68642
  return void 0;
68963
68643
  }
@@ -68965,9 +68645,18 @@ async function readJson({ path }) {
68965
68645
  async function runStateOf({ context }) {
68966
68646
  return readJson({ path: runStatePathOf({ context }) });
68967
68647
  }
68968
- var ROUND_SECONDS2 = 50;
68648
+ var ROUND_SECONDS = 50;
68969
68649
  var REFRESH_MS = 3e4;
68970
68650
  var MAX_RETRY_SECONDS2 = 60;
68651
+ var CLI_CHANGED_EXIT = 75;
68652
+ async function cliStampOf({ context }) {
68653
+ const file3 = context.program.at(-1);
68654
+ if (!file3) return "";
68655
+ return stat2(file3).then(
68656
+ (info) => `${info.mtimeMs}:${info.size}`,
68657
+ () => ""
68658
+ );
68659
+ }
68971
68660
  var CodexQueueError = class extends Error {
68972
68661
  constructor(reason, detail) {
68973
68662
  super(detail);
@@ -68998,7 +68687,7 @@ async function queueInCodex({
68998
68687
  throw new CodexQueueError(codexQueueFailureOf({ stderr: stderr2 }), stderr2.trim() || `exit ${code}`);
68999
68688
  }
69000
68689
  }
69001
- async function takeRound2({
68690
+ async function takeRound({
69002
68691
  client,
69003
68692
  signal,
69004
68693
  delivery
@@ -69010,7 +68699,7 @@ async function takeRound2({
69010
68699
  host: hostname4()
69011
68700
  };
69012
68701
  try {
69013
- return await client.withHeaders(sessionHeadersOf({ session })).post("/api/agents/me/inbox", { waitSeconds: ROUND_SECONDS2 }, { signal });
68702
+ return await client.withHeaders(sessionHeadersOf({ session })).post("/api/agents/me/inbox", { waitSeconds: ROUND_SECONDS }, { signal });
69014
68703
  } catch (error62) {
69015
68704
  if (signal.aborted) return [];
69016
68705
  throw error62;
@@ -69025,7 +68714,7 @@ async function deliverRound({
69025
68714
  watch
69026
68715
  }) {
69027
68716
  const kept = await dueFromSpool({ context, profile, seen: async () => "", pushedToo: true });
69028
- const messages = kept.length > 0 ? kept : await takeRound2({ client, signal, delivery });
68717
+ const messages = kept.length > 0 ? kept : await takeRound({ client, signal, delivery });
69029
68718
  if (messages.length === 0) return 0;
69030
68719
  if (kept.length === 0) await keepTaken({ context, profile, messages });
69031
68720
  const self2 = await currentNameOf({ context, client, profile });
@@ -69108,9 +68797,9 @@ async function serveRounds({
69108
68797
  }
69109
68798
  var saves = 0;
69110
68799
  async function save(run4) {
69111
- await mkdir9(dirname9(run4.path), { recursive: true, mode: 448 });
68800
+ await mkdir7(dirname8(run4.path), { recursive: true, mode: 448 });
69112
68801
  const temporary = `${run4.path}.${run4.self}.${saves += 1}.tmp`;
69113
- await writeFile9(temporary, JSON.stringify(run4.state));
68802
+ await writeFile7(temporary, JSON.stringify(run4.state));
69114
68803
  await rename3(temporary, run4.path);
69115
68804
  }
69116
68805
  async function holdsLock(run4) {
@@ -69165,6 +68854,7 @@ async function runConnectLoop({ context }) {
69165
68854
  await save(run4);
69166
68855
  context.out(`laze connect run: pid ${self2}
69167
68856
  `);
68857
+ const startedFrom = await cliStampOf({ context });
69168
68858
  const relays = RelayLoops.create({
69169
68859
  context,
69170
68860
  report: async (connectionId, relay2) => {
@@ -69177,26 +68867,31 @@ async function runConnectLoop({ context }) {
69177
68867
  while (await holdsLock(run4)) {
69178
68868
  await syncLoops(run4);
69179
68869
  await relays.sync();
68870
+ await rearmRushGuards({ context }).catch((error62) => {
68871
+ context.err(`laze connect: no rush guard check this round: ${String(error62)}
68872
+ `);
68873
+ });
69180
68874
  await save(run4);
69181
68875
  await context.sleep(REFRESH_MS);
68876
+ if (await cliStampOf({ context }) !== startedFrom) {
68877
+ context.out("laze connect run: the CLI changed on disk, exiting so the new one starts\n");
68878
+ return CLI_CHANGED_EXIT;
68879
+ }
69182
68880
  }
69183
68881
  } finally {
69184
68882
  await relays.stopAll();
69185
68883
  for (const current2 of run4.served.values()) current2.stop.abort();
69186
68884
  await Promise.all([...run4.served.values()].map((current2) => current2.done));
69187
- if (await holdsLock(run4)) await rm4(run4.path, { force: true });
68885
+ if (await holdsLock(run4)) await rm2(run4.path, { force: true });
69188
68886
  }
69189
68887
  return 0;
69190
68888
  }
69191
68889
 
69192
68890
  // src/services/connect-service.service.ts
69193
- import { createHash } from "node:crypto";
69194
- import { mkdir as mkdir10, rm as rm5, writeFile as writeFile10 } from "node:fs/promises";
69195
- import { dirname as dirname10, join as join11 } from "node:path";
69196
- var CONNECT_SERVICE_USAGE = `laze connect install|status|stop|uninstall|run: the service that delivers to linked Codex sessions.
68891
+ var CONNECT_SERVICE_USAGE = `laze connect install|status|stop|uninstall|run: the service that delivers to linked Codex sessions and keeps a guard on every Claude Code session rush put to sleep.
69197
68892
 
69198
68893
  laze connect install install and start it (systemd --user, a LaunchAgent, or detached)
69199
- laze connect status whether it runs and which agents it serves
68894
+ laze connect status whether it runs, which agents it serves, who listens per rush session
69200
68895
  laze connect stop stop it until the next login or install
69201
68896
  laze connect uninstall stop it and remove it
69202
68897
  laze connect run the service itself, in the foreground
@@ -69211,7 +68906,7 @@ function logPathOf({ context }) {
69211
68906
  return join11(connectFolderOf({ context }), "connect.log");
69212
68907
  }
69213
68908
  function homeOf({ context }) {
69214
- return context.environment.inherited.HOME ?? dirname10(dirname10(context.environment.configPath));
68909
+ return context.environment.inherited.HOME ?? dirname9(dirname9(context.environment.configPath));
69215
68910
  }
69216
68911
  function serviceNameOf({ context }) {
69217
68912
  const { configPath } = context.environment;
@@ -69240,8 +68935,8 @@ async function installSystemd({ context }) {
69240
68935
  const env = context.environment.inherited;
69241
68936
  const base = env.XDG_CONFIG_HOME || join11(homeOf({ context }), ".config");
69242
68937
  const file3 = join11(base, "systemd", "user", `${name2}.service`);
69243
- await mkdir10(dirname10(file3), { recursive: true });
69244
- await writeFile10(
68938
+ await mkdir8(dirname9(file3), { recursive: true });
68939
+ await writeFile8(
69245
68940
  file3,
69246
68941
  systemdUnitOf({ argv: runArgvOf({ context }), env: serviceEnvOf({ context }) })
69247
68942
  );
@@ -69256,8 +68951,8 @@ async function installLaunchd({ context }) {
69256
68951
  const label2 = `ai.laze.${name2}`;
69257
68952
  const file3 = join11(homeOf({ context }), "Library", "LaunchAgents", `${label2}.plist`);
69258
68953
  const log = logPathOf({ context });
69259
- await mkdir10(dirname10(file3), { recursive: true });
69260
- await writeFile10(
68954
+ await mkdir8(dirname9(file3), { recursive: true });
68955
+ await writeFile8(
69261
68956
  file3,
69262
68957
  launchAgentOf({
69263
68958
  label: label2,
@@ -69309,10 +69004,16 @@ async function installConnectService({ context }) {
69309
69004
  const manager = await managerOf({ context });
69310
69005
  const install = { systemd: installSystemd, launchd: installLaunchd, detached: installDetached };
69311
69006
  const installed = await install[manager]({ context });
69312
- await mkdir10(dirname10(path), { recursive: true, mode: 448 });
69313
- await writeFile10(path, JSON.stringify(installed));
69007
+ await mkdir8(dirname9(path), { recursive: true, mode: 448 });
69008
+ await writeFile8(path, JSON.stringify(installed));
69314
69009
  return describeInstalled({ installed });
69315
69010
  }
69011
+ async function ensureConnectService({ context }) {
69012
+ const running = await runStateOf({ context });
69013
+ if (running && context.processes.alive(running.pid)) return false;
69014
+ await installConnectService({ context });
69015
+ return true;
69016
+ }
69316
69017
  function describeInstalled({ installed }) {
69317
69018
  switch (installed.manager) {
69318
69019
  case "systemd":
@@ -69340,6 +69041,8 @@ async function status({ context }) {
69340
69041
  `
69341
69042
  );
69342
69043
  }
69044
+ for (const row of await rushListenersOf({ context })) context.out(`${rushLineOf({ row })}
69045
+ `);
69343
69046
  const config2 = await context.store.read();
69344
69047
  const linked = Object.entries(config2.profiles).filter(([, profile]) => profile.delivery);
69345
69048
  if (linked.length === 0) {
@@ -69352,6 +69055,13 @@ async function status({ context }) {
69352
69055
  `);
69353
69056
  }
69354
69057
  }
69058
+ function rushLineOf({ row }) {
69059
+ const head = `${row.profile} Claude Code in rush ${row.rushId} ${row.standing}`;
69060
+ if (row.standing === "awake") return `${head}, its Claude Code delivers`;
69061
+ if (row.standing === "stopped") return `${head}, gets messages when rush starts it again`;
69062
+ if (row.listenerPid) return `${head}, guard pid ${row.listenerPid}`;
69063
+ return `${head}, NO LISTENER: messages wait in Laze; \`laze connect install\` brings a guard back`;
69064
+ }
69355
69065
  async function stop({ context }) {
69356
69066
  const installed = await readJson({ path: installedPathOf({ context }) });
69357
69067
  if (!installed) {
@@ -69376,11 +69086,11 @@ async function uninstall({ context }) {
69376
69086
  command: ["systemctl", "--user", "disable", `${installed.name}.service`]
69377
69087
  });
69378
69088
  }
69379
- if (installed.file) await rm5(installed.file, { force: true });
69089
+ if (installed.file) await rm3(installed.file, { force: true });
69380
69090
  if (installed.manager === "systemd") {
69381
69091
  await run({ context, command: ["systemctl", "--user", "daemon-reload"] });
69382
69092
  }
69383
- await rm5(path, { force: true });
69093
+ await rm3(path, { force: true });
69384
69094
  context.out(
69385
69095
  `Removed the connect service (${installed.manager}, ${installed.name}). Linked Codex agents get no messages until \`laze connect install\`.
69386
69096
  `
@@ -69405,6 +69115,571 @@ async function connectService({ context, args }) {
69405
69115
  }
69406
69116
  }
69407
69117
 
69118
+ // src/services/claude-wait.service.ts
69119
+ var ROUND_SECONDS2 = 50;
69120
+ var WATCH_MS = 2e3;
69121
+ var CHANNEL_CHECK_MS = 5e3;
69122
+ async function holderOf({ path }) {
69123
+ return readFile10(path, "utf8").then(
69124
+ (text2) => JSON.parse(text2),
69125
+ () => void 0
69126
+ );
69127
+ }
69128
+ async function holderClaudeOf({ context, holder }) {
69129
+ if (holder.claudePid) return holder.claudePid;
69130
+ return (await nearestHarnessOf({ context, from: holder.pid }))?.pid;
69131
+ }
69132
+ async function takeLock({
69133
+ context,
69134
+ path,
69135
+ sessionId,
69136
+ claudePid,
69137
+ preempt = false
69138
+ }) {
69139
+ const holder = await holderOf({ path });
69140
+ const self2 = context.processes.pid;
69141
+ if (holder && holder.pid !== self2 && context.processes.alive(holder.pid)) {
69142
+ const served = await holderClaudeOf({ context, holder });
69143
+ const mine4 = preempt && served === claudePid && !holder.monitor;
69144
+ if (served && context.processes.alive(served) && !mine4) return false;
69145
+ context.processes.stop(holder.pid);
69146
+ }
69147
+ await mkdir9(dirname10(path), { recursive: true, mode: 448 });
69148
+ await writeFile9(
69149
+ path,
69150
+ JSON.stringify({
69151
+ pid: self2,
69152
+ claudePid,
69153
+ ...sessionId ? { sessionId } : {},
69154
+ ...preempt ? { monitor: true } : {}
69155
+ })
69156
+ );
69157
+ return true;
69158
+ }
69159
+ async function channelLive({ context, profile }) {
69160
+ const holder = await holderOf({ path: statePathOf({ context, kind: "channels", profile }) });
69161
+ return holder !== void 0 && context.processes.alive(holder.pid);
69162
+ }
69163
+ async function takeRound2({
69164
+ context,
69165
+ client,
69166
+ claudePid,
69167
+ session
69168
+ }) {
69169
+ const controller = new AbortController();
69170
+ const { signal } = controller;
69171
+ const watch = (async () => {
69172
+ while (!signal.aborted) {
69173
+ await context.sleep(WATCH_MS, signal);
69174
+ if (claudePid && !context.processes.alive(claudePid)) controller.abort();
69175
+ }
69176
+ })();
69177
+ try {
69178
+ return await forSession({ client, session }).post(
69179
+ "/api/agents/me/inbox",
69180
+ { waitSeconds: ROUND_SECONDS2 },
69181
+ { signal }
69182
+ );
69183
+ } catch (error62) {
69184
+ if (signal.aborted) return [];
69185
+ throw error62;
69186
+ } finally {
69187
+ controller.abort();
69188
+ await watch;
69189
+ }
69190
+ }
69191
+ async function roundOf({ context, client, name: name2, lock, claudePid, session, seen }) {
69192
+ if ((await holderOf({ path: lock }))?.pid !== context.processes.pid) return void 0;
69193
+ if (claudePid && !context.processes.alive(claudePid)) return void 0;
69194
+ const due = await dueFromSpool({ context, profile: name2, seen, pushedToo: true });
69195
+ if (due.length > 0) return due;
69196
+ if (await channelLive({ context, profile: name2 })) {
69197
+ await context.sleep(CHANNEL_CHECK_MS);
69198
+ return [];
69199
+ }
69200
+ const taken = await takeRound2({ context, client, claudePid, session });
69201
+ if (taken.length === 0) {
69202
+ await context.sleep(1e3);
69203
+ return [];
69204
+ }
69205
+ await keepTaken({ context, profile: name2, messages: taken });
69206
+ return taken;
69207
+ }
69208
+ async function claudePidOf({ context }) {
69209
+ const harness = await nearestHarnessOf({ context });
69210
+ if (harness?.harness === "claude-code") return harness.pid;
69211
+ return await context.processes.parentOf(context.processes.pid) ?? 0;
69212
+ }
69213
+ async function settleRound(round) {
69214
+ const { context, client, name: name2, session } = round;
69215
+ const messages = await roundOf(round).catch(async (error62) => {
69216
+ const refused = await notBoundNotice({
69217
+ context,
69218
+ client: forSession({ client, session }),
69219
+ session,
69220
+ error: error62,
69221
+ profile: name2
69222
+ });
69223
+ if (!refused) throw error62;
69224
+ return refused;
69225
+ });
69226
+ if (messages === void 0) return 0;
69227
+ if (!Array.isArray(messages)) {
69228
+ if (messages.rebound) return "again";
69229
+ if (!messages.notice) return 0;
69230
+ context.err(`${messages.notice}
69231
+ `);
69232
+ return 2;
69233
+ }
69234
+ if (messages.length === 0) return "again";
69235
+ await turnStarted({ context, client, agent: name2, messages }).catch(() => void 0);
69236
+ const self2 = await currentNameOf({ context, client, profile: name2 });
69237
+ context.err(`${hookContextOf({ messages, self: self2 })}
69238
+ `);
69239
+ const messageIds = messages.map((message2) => message2.messageId);
69240
+ await dropFromSpool({ context, profile: name2, messageIds });
69241
+ return 2;
69242
+ }
69243
+ async function waitForMessages({ context, args }) {
69244
+ const raw = await context.readStdin();
69245
+ const input2 = raw.trim() ? JSON.parse(raw) : {};
69246
+ const session = sessionOf({ context, harness: "claude-code", sessionId: input2.session_id });
69247
+ const claudePid = await claudePidOf({ context });
69248
+ const asked = await pluginHookArgs({ context, args, session, claudePid });
69249
+ if (!asked) return 0;
69250
+ const named = await sessionProfileArgs({ context, args: asked, session });
69251
+ const { client, name: name2 } = await signedIn({ context, args: named });
69252
+ await rememberSession({ context, claudePid, session });
69253
+ const rush = rushSessionOf({
69254
+ parentArgs: await context.processes.argsOf(await context.processes.parentOf(claudePid) ?? 0)
69255
+ });
69256
+ if (rush) await startRushGuard({ context, profile: name2, claudePid, rush });
69257
+ if (rush) await healRushDelivery({ context });
69258
+ const lock = statePathOf({ context, kind: "waiters", profile: name2 });
69259
+ if (!await takeLock({ context, path: lock, sessionId: input2.session_id, claudePid })) return 0;
69260
+ const seen = () => input2.transcript_path ? readFile10(input2.transcript_path, "utf8") : Promise.resolve("");
69261
+ const deadline = context.nowMs() + (WAIT_HOOK_TIMEOUT_SECONDS - 60) * 1e3;
69262
+ try {
69263
+ while (context.nowMs() < deadline) {
69264
+ const code = await settleRound({ context, client, name: name2, lock, claudePid, session, seen });
69265
+ if (code !== "again") return code;
69266
+ }
69267
+ return 0;
69268
+ } finally {
69269
+ if ((await holderOf({ path: lock }))?.pid === context.processes.pid)
69270
+ await rm4(lock, { force: true });
69271
+ }
69272
+ }
69273
+ async function healRushDelivery({ context }) {
69274
+ await rearmRushGuards({ context }).catch((error62) => {
69275
+ context.err(`laze: could not check the other rush sessions: ${String(error62)}
69276
+ `);
69277
+ });
69278
+ await ensureConnectService({ context }).catch((error62) => {
69279
+ context.err(`laze: could not start the connect service: ${String(error62)}
69280
+ `);
69281
+ });
69282
+ }
69283
+ async function waitHook({ context, args }) {
69284
+ try {
69285
+ return await waitForMessages({ context, args });
69286
+ } catch (error62) {
69287
+ context.err(`laze: the background waiter stopped: ${String(error62)}
69288
+ `);
69289
+ return 0;
69290
+ }
69291
+ }
69292
+ async function monitorServes({
69293
+ context,
69294
+ profile,
69295
+ claudePid
69296
+ }) {
69297
+ const holder = await holderOf({ path: statePathOf({ context, kind: "waiters", profile }) });
69298
+ if (!holder?.monitor || !context.processes.alive(holder.pid)) return false;
69299
+ return await holderClaudeOf({ context, holder }) === claudePid;
69300
+ }
69301
+
69302
+ // src/services/codex-link.service.ts
69303
+ import { createReadStream } from "node:fs";
69304
+ import { readdir as readdir5, rm as rm6, stat as stat4 } from "node:fs/promises";
69305
+ import { join as join13, resolve as resolve3 } from "node:path";
69306
+ import { createInterface as createInterface2 } from "node:readline";
69307
+
69308
+ // src/services/codex-adopt.service.ts
69309
+ import { spawn as spawn2 } from "node:child_process";
69310
+ import { mkdir as mkdir10, readdir as readdir4, readFile as readFile11, rm as rm5, stat as stat3, writeFile as writeFile10 } from "node:fs/promises";
69311
+ import { dirname as dirname11, join as join12 } from "node:path";
69312
+ import { createInterface } from "node:readline";
69313
+
69314
+ // src/rules/codex-requests.rules.ts
69315
+ var DECLINED_DECISION = {
69316
+ "item/commandExecution/requestApproval": "decline",
69317
+ "item/fileChange/requestApproval": "decline",
69318
+ execCommandApproval: "denied",
69319
+ applyPatchApproval: "denied"
69320
+ };
69321
+ function codexRequestReplyOf({ method }) {
69322
+ const decision = DECLINED_DECISION[method];
69323
+ if (decision) return { result: { decision } };
69324
+ if (method === "item/permissions/requestApproval") {
69325
+ return { result: { permissions: {}, scope: "turn" } };
69326
+ }
69327
+ if (method === "mcpServer/elicitation/request") {
69328
+ return { result: { action: "decline", content: null } };
69329
+ }
69330
+ return { error: { code: -32601, message: `${method} is not supported here` } };
69331
+ }
69332
+
69333
+ // src/services/codex-adopt.service.ts
69334
+ function record3(value) {
69335
+ return typeof value === "object" && value !== null ? value : {};
69336
+ }
69337
+ function absorbTurnEvent({ result, message: message2 }) {
69338
+ const params = record3(message2.params);
69339
+ if (message2.method === "item/completed") {
69340
+ const item = record3(params.item);
69341
+ if (item.type === "agentMessage" && typeof item.text === "string") result.answer = item.text;
69342
+ return;
69343
+ }
69344
+ if (message2.method !== "thread/tokenUsage/updated") return;
69345
+ const usage = record3(params.tokenUsage);
69346
+ const total = record3(usage.last).totalTokens;
69347
+ if (typeof total === "number") result.contextTokens = total;
69348
+ const window2 = usage.modelContextWindow;
69349
+ if (typeof window2 === "number" && window2 > 0) result.contextWindow = window2;
69350
+ }
69351
+ var TURN_HEARTBEAT_MS = 1e4;
69352
+ var CodexAppServer = class _CodexAppServer {
69353
+ constructor(child) {
69354
+ this.child = child;
69355
+ createInterface({ input: child.stdout }).on("line", (line) => this.receive(line));
69356
+ }
69357
+ child;
69358
+ #nextId = 0;
69359
+ #pending = /* @__PURE__ */ new Map();
69360
+ #listeners = /* @__PURE__ */ new Set();
69361
+ static start({
69362
+ codexHome,
69363
+ inherited
69364
+ }) {
69365
+ const env = { ...inherited, CODEX_HOME: codexHome };
69366
+ return new _CodexAppServer(spawn2("codex", ["app-server"], { env, stdio: "pipe" }));
69367
+ }
69368
+ async call(method, params) {
69369
+ const id = ++this.#nextId;
69370
+ const reply2 = await new Promise((resolve17) => {
69371
+ this.#pending.set(id, resolve17);
69372
+ this.write({ id, method, params });
69373
+ });
69374
+ if (reply2.error !== void 0) throw new Error(`${method}: ${JSON.stringify(reply2.error)}`);
69375
+ return record3(reply2.result);
69376
+ }
69377
+ notify(method) {
69378
+ this.write({ method });
69379
+ }
69380
+ /** Starts one turn; `done` settles when it completes, keeping its last agent message. */
69381
+ async startTurn({ threadId, text: text2 }) {
69382
+ const result = { answer: "" };
69383
+ const done = new Promise((resolve17) => {
69384
+ const listen = (message2) => {
69385
+ absorbTurnEvent({ result, message: message2 });
69386
+ if (message2.method !== "turn/completed") return;
69387
+ this.#listeners.delete(listen);
69388
+ resolve17(result);
69389
+ };
69390
+ this.#listeners.add(listen);
69391
+ });
69392
+ const started = await this.call("turn/start", {
69393
+ threadId,
69394
+ input: [{ type: "text", text: text2, text_elements: [] }]
69395
+ });
69396
+ const turnId = record3(started.turn).id;
69397
+ return { turnId: typeof turnId === "string" ? turnId : null, done };
69398
+ }
69399
+ stop() {
69400
+ this.child.kill("SIGTERM");
69401
+ }
69402
+ write(message2) {
69403
+ this.child.stdin.write(`${JSON.stringify(message2)}
69404
+ `);
69405
+ }
69406
+ receive(line) {
69407
+ let message2;
69408
+ try {
69409
+ message2 = record3(JSON.parse(line));
69410
+ } catch {
69411
+ return;
69412
+ }
69413
+ if (typeof message2.id === "number" && message2.method === void 0) {
69414
+ this.#pending.get(message2.id)?.(message2);
69415
+ this.#pending.delete(message2.id);
69416
+ return;
69417
+ }
69418
+ if (message2.method !== void 0 && message2.id !== void 0) {
69419
+ this.write({
69420
+ id: message2.id,
69421
+ ...codexRequestReplyOf({
69422
+ method: typeof message2.method === "string" ? message2.method : ""
69423
+ })
69424
+ });
69425
+ return;
69426
+ }
69427
+ for (const listen of this.#listeners) listen(message2);
69428
+ }
69429
+ };
69430
+ async function newestThreadId({ codexHome }) {
69431
+ const root = join12(codexHome, "sessions");
69432
+ const files2 = await readdir4(root, { recursive: true }).catch(() => []);
69433
+ const rollouts = files2.filter((file3) => /rollout-.*\.jsonl$/.test(file3));
69434
+ const dated = await Promise.all(
69435
+ rollouts.map(async (file3) => ({ file: file3, at: (await stat3(join12(root, file3))).mtimeMs }))
69436
+ );
69437
+ const newest = dated.toSorted((a, b) => b.at - a.at)[0]?.file ?? "";
69438
+ const id = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/.exec(newest);
69439
+ if (!id?.[1]) throw new CliUsageError("No Codex session found: pass --thread <id>.");
69440
+ return id[1];
69441
+ }
69442
+ function promptOf({ message: message2, self: self2 }) {
69443
+ return [
69444
+ `A message reached you in the Laze workspace${selfClauseOf({ self: self2 })}. Answer it; your final`,
69445
+ "message is posted as your reply in its thread.",
69446
+ "",
69447
+ formatInboxMessage({ message: message2 }).split("\n").slice(0, -1).join("\n")
69448
+ ].join("\n");
69449
+ }
69450
+ async function heartbeat({
69451
+ client,
69452
+ message: message2,
69453
+ state
69454
+ }) {
69455
+ return client.post("/api/agents/me/turn", {
69456
+ channelId: message2.channelId,
69457
+ threadRootId: message2.threadRootId,
69458
+ state,
69459
+ ...state === "working" ? { messageId: message2.messageId } : {}
69460
+ }).catch(() => void 0);
69461
+ }
69462
+ async function watchTurn({
69463
+ context,
69464
+ client,
69465
+ codex,
69466
+ threadId,
69467
+ turn,
69468
+ message: message2
69469
+ }) {
69470
+ const finished = new AbortController();
69471
+ void turn.done.then(() => finished.abort());
69472
+ while (!finished.signal.aborted) {
69473
+ const beat2 = await heartbeat({ client, message: message2, state: "working" });
69474
+ if (beat2?.stop && turn.turnId) {
69475
+ await codex.call("turn/interrupt", { threadId, turnId: turn.turnId }).catch(() => void 0);
69476
+ return beat2.stoppedBy ?? "someone";
69477
+ }
69478
+ await context.sleep(TURN_HEARTBEAT_MS, finished.signal);
69479
+ }
69480
+ return void 0;
69481
+ }
69482
+ async function answer({
69483
+ context,
69484
+ codex,
69485
+ client,
69486
+ threadId,
69487
+ message: message2,
69488
+ profile
69489
+ }) {
69490
+ const self2 = await currentNameOf({ context, client, profile });
69491
+ const running = await codex.startTurn({ threadId, text: promptOf({ message: message2, self: self2 }) });
69492
+ const stoppedBy = await watchTurn({ context, client, codex, threadId, turn: running, message: message2 });
69493
+ const turn = await running.done;
69494
+ await heartbeat({ client, message: message2, state: "idle" });
69495
+ if (stoppedBy !== void 0) return `(stopped by ${stoppedBy})`;
69496
+ const body = turn.answer.trim() || "(no answer)";
69497
+ await client.post("/api/agents/me/replies", { messageId: message2.messageId, body });
69498
+ if (turn.contextTokens !== void 0) {
69499
+ await client.post("/api/agents/me/activity", {
69500
+ sessionId: threadId,
69501
+ contextTokens: turn.contextTokens,
69502
+ ...turn.contextWindow ? { contextWindow: turn.contextWindow } : {}
69503
+ });
69504
+ }
69505
+ return body;
69506
+ }
69507
+ var MAX_RESTART_WAIT_SECONDS = 60;
69508
+ var HEALTHY_RUN_MS = 6e4;
69509
+ async function recordOf({ path }) {
69510
+ return readFile11(path, "utf8").then(
69511
+ (text2) => JSON.parse(text2),
69512
+ () => void 0
69513
+ );
69514
+ }
69515
+ function threadFlag({ thread: thread2 }) {
69516
+ return thread2 ? ["--thread", thread2] : [];
69517
+ }
69518
+ async function startAdoptInBackground({
69519
+ context,
69520
+ args,
69521
+ profile,
69522
+ laze
69523
+ }) {
69524
+ const thread2 = flagText({ args, name: "thread" }) || context.environment.inherited.CODEX_THREAD_ID || null;
69525
+ const path = statePathOf({ context, kind: "adopt", profile });
69526
+ const log = statePathOf({ context, kind: "adopt", profile, extension: "log" });
69527
+ const running = await recordOf({ path });
69528
+ if (running) context.processes.stop(running.pid);
69529
+ const adopt = ["adopt", "codex", "--profile", profile, ...threadFlag({ thread: thread2 })];
69530
+ const argv = [...context.program, ...adopt, "--supervise"];
69531
+ const pid = context.processes.spawnDetached({ argv, logPath: log });
69532
+ await mkdir10(dirname11(path), { recursive: true, mode: 448 });
69533
+ await writeFile10(path, JSON.stringify({ pid, thread: thread2, log, startedAt: context.nowMs() }));
69534
+ return [
69535
+ `Started \`${laze} adopt codex\` in the background (pid ${pid}). It answers each Laze message`,
69536
+ `as a turn in ${thread2 ? `this Codex thread (${thread2})` : "the newest Codex thread"}, and starts again if it stops.`,
69537
+ `Log: ${log}`,
69538
+ ` ${laze} adopt codex --status --profile ${profile} shows whether it runs`,
69539
+ ` ${laze} adopt codex --stop --profile ${profile} stops it`,
69540
+ "Nothing else needs to run. While this Codex window stays open, Codex lets only it write the",
69541
+ "thread, so adopt answers in a fork of it (the same history so far; `codex resume <fork id>`",
69542
+ "from the log opens it). Started again with this window closed, it answers in the thread itself."
69543
+ ].join("\n");
69544
+ }
69545
+ async function supervise({
69546
+ context,
69547
+ args,
69548
+ profile
69549
+ }) {
69550
+ const path = statePathOf({ context, kind: "adopt", profile });
69551
+ const thread2 = flagText({ args, name: "thread" });
69552
+ const adopt = ["adopt", "codex", "--profile", profile, ...threadFlag({ thread: thread2 })];
69553
+ const command = [...context.program, ...adopt];
69554
+ let wait = 1;
69555
+ while ((await recordOf({ path }))?.pid === context.processes.pid) {
69556
+ const started = context.nowMs();
69557
+ context.out(
69558
+ `${Temporal3.Instant.fromEpochMilliseconds(started).toString()} starting laze adopt codex
69559
+ `
69560
+ );
69561
+ const code = await context.runCommand({ command, env: {} }).catch(() => 1);
69562
+ if (context.nowMs() - started > HEALTHY_RUN_MS) wait = 1;
69563
+ if ((await recordOf({ path }))?.pid !== context.processes.pid) break;
69564
+ context.out(`laze adopt codex exited ${code}; starting it again in ${wait}s
69565
+ `);
69566
+ await context.sleep(wait * 1e3);
69567
+ wait = Math.min(MAX_RESTART_WAIT_SECONDS, wait * 2);
69568
+ }
69569
+ return 0;
69570
+ }
69571
+ async function adoptStatus({ context, profile }) {
69572
+ const record4 = await recordOf({ path: statePathOf({ context, kind: "adopt", profile }) });
69573
+ if (!record4 || !context.processes.alive(record4.pid)) {
69574
+ context.out(`laze adopt codex does not run in the background for profile "${profile}".
69575
+ `);
69576
+ return;
69577
+ }
69578
+ const thread2 = record4.thread ?? "the newest thread";
69579
+ context.out(
69580
+ `laze adopt codex runs in the background for profile "${profile}" (pid ${record4.pid}), thread ${thread2}.
69581
+ Log: ${record4.log}
69582
+ `
69583
+ );
69584
+ }
69585
+ async function adoptStop({ context, profile }) {
69586
+ const path = statePathOf({ context, kind: "adopt", profile });
69587
+ const record4 = await recordOf({ path });
69588
+ await rm5(path, { force: true });
69589
+ if (!record4 || !context.processes.stop(record4.pid)) {
69590
+ context.out(`laze adopt codex was not running in the background for profile "${profile}".
69591
+ `);
69592
+ return;
69593
+ }
69594
+ context.out(`Stopped laze adopt codex (pid ${record4.pid}) for profile "${profile}".
69595
+ `);
69596
+ }
69597
+ var HELD_THREAD = /active writer/;
69598
+ async function adoptedThreadOf({
69599
+ context,
69600
+ codex,
69601
+ threadId,
69602
+ profile
69603
+ }) {
69604
+ const held = await codex.call("thread/resume", { threadId }).then(
69605
+ () => false,
69606
+ (error62) => {
69607
+ if (HELD_THREAD.test(String(error62))) return true;
69608
+ throw error62;
69609
+ }
69610
+ );
69611
+ if (!held) return threadId;
69612
+ const path = statePathOf({ context, kind: "adopt", profile, extension: "forks.json" });
69613
+ const forks = await readFile11(path, "utf8").then(
69614
+ (text2) => JSON.parse(text2),
69615
+ () => ({})
69616
+ );
69617
+ const known = forks[threadId];
69618
+ if (known && await codex.call("thread/resume", { threadId: known }).then(
69619
+ () => true,
69620
+ () => false
69621
+ )) {
69622
+ context.out(`Codex holds thread ${threadId} open elsewhere; answering in its fork ${known}.
69623
+ `);
69624
+ return known;
69625
+ }
69626
+ const forked = record3((await codex.call("thread/fork", { threadId })).thread).id;
69627
+ if (typeof forked !== "string") throw new Error("thread/fork answered no thread id");
69628
+ await mkdir10(dirname11(path), { recursive: true, mode: 448 });
69629
+ await writeFile10(path, JSON.stringify({ ...forks, [threadId]: forked }));
69630
+ context.out(
69631
+ `Codex holds thread ${threadId} open elsewhere; answering in its new fork ${forked}.
69632
+ `
69633
+ );
69634
+ return forked;
69635
+ }
69636
+ async function adoptCodex({ context, args }) {
69637
+ if (args.words[1] !== "codex") {
69638
+ throw new CliUsageError("Usage: laze adopt codex [--thread <id>] | --status | --stop");
69639
+ }
69640
+ const { client, name: name2 } = await signedIn({ context, args });
69641
+ if (args.flags.status) return adoptStatus({ context, profile: name2 });
69642
+ if (args.flags.stop) return adoptStop({ context, profile: name2 });
69643
+ if (args.flags.supervise) return supervise({ context, args, profile: name2 });
69644
+ const { codexHome } = context.environment;
69645
+ const threadId = flagText({ args, name: "thread" }) || context.environment.inherited.CODEX_THREAD_ID || await newestThreadId({ codexHome });
69646
+ const once = Boolean(args.flags.once);
69647
+ const codex = CodexAppServer.start({ codexHome, inherited: context.environment.inherited });
69648
+ try {
69649
+ await codex.call("initialize", {
69650
+ clientInfo: { name: "laze", title: "Laze", version: "1" },
69651
+ capabilities: null
69652
+ });
69653
+ codex.notify("initialized");
69654
+ const adopted = await adoptedThreadOf({ context, codex, threadId, profile: name2 });
69655
+ context.out(`Adopted Codex thread ${adopted}; answering Laze messages.
69656
+ `);
69657
+ const timeout = Number(flagText({ args, name: "timeout", fallback: "0" }));
69658
+ do {
69659
+ const messages = await receiveMessages({
69660
+ context,
69661
+ client,
69662
+ waitSeconds: timeout > 0 ? timeout : Infinity
69663
+ });
69664
+ for (const message2 of messages) {
69665
+ const body = await answer({
69666
+ context,
69667
+ codex,
69668
+ client,
69669
+ threadId: adopted,
69670
+ message: message2,
69671
+ profile: name2
69672
+ });
69673
+ context.out(`Answered ${message2.messageId}: ${body.slice(0, 120)}
69674
+ `);
69675
+ }
69676
+ if (messages.length === 0 && timeout > 0) break;
69677
+ } while (!once);
69678
+ } finally {
69679
+ codex.stop();
69680
+ }
69681
+ }
69682
+
69408
69683
  // src/services/codex-link.service.ts
69409
69684
  var ROLLOUTS_READ = 200;
69410
69685
  async function firstLineOf({ path }) {
@@ -69422,13 +69697,13 @@ async function newestThreadIn({
69422
69697
  codexHome,
69423
69698
  directory
69424
69699
  }) {
69425
- const root = join12(codexHome, "sessions");
69426
- const files2 = await readdir4(root, { recursive: true }).catch(() => []);
69700
+ const root = join13(codexHome, "sessions");
69701
+ const files2 = await readdir5(root, { recursive: true }).catch(() => []);
69427
69702
  const rollouts = files2.filter((file3) => /rollout-.*\.jsonl$/.test(file3));
69428
69703
  const dated = await Promise.all(
69429
69704
  rollouts.map(async (file3) => ({
69430
- path: join12(root, file3),
69431
- at: await stat2(join12(root, file3)).then(
69705
+ path: join13(root, file3),
69706
+ at: await stat4(join13(root, file3)).then(
69432
69707
  (info) => info.mtimeMs,
69433
69708
  () => 0
69434
69709
  )
@@ -69498,9 +69773,9 @@ async function linkCodexSession({
69498
69773
  }
69499
69774
 
69500
69775
  // src/services/laze-plugin.service.ts
69501
- import { mkdir as mkdir11, readFile as readFile11, writeFile as writeFile11 } from "node:fs/promises";
69776
+ import { mkdir as mkdir11, readFile as readFile12, writeFile as writeFile11 } from "node:fs/promises";
69502
69777
  import { homedir as homedir3 } from "node:os";
69503
- import { dirname as dirname11, join as join13 } from "node:path";
69778
+ import { dirname as dirname12, join as join14 } from "node:path";
69504
69779
 
69505
69780
  // src/rules/laze-plugin.rules.ts
69506
69781
  var LAZE_PLUGIN = "laze";
@@ -69616,11 +69891,11 @@ function lazePluginFiles({
69616
69891
  var REGISTER_LIMIT_MS = 6e4;
69617
69892
  var quote2 = (value) => `'${value.replaceAll("'", "'\\''")}'`;
69618
69893
  function pluginFolderOf({ context }) {
69619
- return join13(dirname11(context.environment.configPath), "plugins");
69894
+ return join14(dirname12(context.environment.configPath), "plugins");
69620
69895
  }
69621
69896
  async function pluginIsCurrent({ context }) {
69622
- const manifest = join13(pluginFolderOf({ context }), LAZE_PLUGIN, ".claude-plugin", "plugin.json");
69623
- const written = await readFile11(manifest, "utf8").then(
69897
+ const manifest = join14(pluginFolderOf({ context }), LAZE_PLUGIN, ".claude-plugin", "plugin.json");
69898
+ const written = await readFile12(manifest, "utf8").then(
69624
69899
  (text2) => JSON.parse(text2).version,
69625
69900
  () => void 0
69626
69901
  );
@@ -69634,8 +69909,8 @@ async function writeLazePlugin({ context }) {
69634
69909
  configPath: context.environment.configPath
69635
69910
  });
69636
69911
  for (const [path, text2] of Object.entries(files2)) {
69637
- const target = join13(folder, path);
69638
- await mkdir11(dirname11(target), { recursive: true });
69912
+ const target = join14(folder, path);
69913
+ await mkdir11(dirname12(target), { recursive: true });
69639
69914
  await writeFile11(target, text2);
69640
69915
  }
69641
69916
  return folder;
@@ -69666,8 +69941,8 @@ var RUN_FILES = ["hooks/hooks.json", "monitors/monitors.json"];
69666
69941
  async function cachedPluginOf({ context }) {
69667
69942
  const inherited = context.environment.inherited;
69668
69943
  const home = inherited.HOME || homedir3();
69669
- const claude = inherited.CLAUDE_CONFIG_DIR || join13(home, ".claude");
69670
- const listed = await readFile11(join13(claude, "plugins", "installed_plugins.json"), "utf8").then(
69944
+ const claude = inherited.CLAUDE_CONFIG_DIR || join14(home, ".claude");
69945
+ const listed = await readFile12(join14(claude, "plugins", "installed_plugins.json"), "utf8").then(
69671
69946
  (text2) => JSON.parse(text2),
69672
69947
  () => void 0
69673
69948
  );
@@ -69676,10 +69951,10 @@ async function cachedPluginOf({ context }) {
69676
69951
  async function refreshStaleCache({ context, folder }) {
69677
69952
  const cached2 = await cachedPluginOf({ context });
69678
69953
  if (!cached2) return true;
69679
- const read3 = (path) => readFile11(path, "utf8").catch(() => "");
69954
+ const read3 = (path) => readFile12(path, "utf8").catch(() => "");
69680
69955
  for (const file3 of RUN_FILES) {
69681
- const ours = await read3(join13(folder, LAZE_PLUGIN, file3));
69682
- if (ours === await read3(join13(cached2, file3))) continue;
69956
+ const ours = await read3(join14(folder, LAZE_PLUGIN, file3));
69957
+ if (ours === await read3(join14(cached2, file3))) continue;
69683
69958
  const plugin2 = `${LAZE_PLUGIN}@${LAZE_PLUGIN}`;
69684
69959
  const script = [
69685
69960
  `claude plugin uninstall ${plugin2} --scope user ${QUIET}`,
@@ -69690,10 +69965,10 @@ async function refreshStaleCache({ context, folder }) {
69690
69965
  return true;
69691
69966
  }
69692
69967
  function registeredMarkOf({ context }) {
69693
- return join13(pluginFolderOf({ context }), "registered");
69968
+ return join14(pluginFolderOf({ context }), "registered");
69694
69969
  }
69695
69970
  async function pluginRegistered({ context }) {
69696
- return readFile11(registeredMarkOf({ context }), "utf8").then(
69971
+ return readFile12(registeredMarkOf({ context }), "utf8").then(
69697
69972
  () => true,
69698
69973
  () => false
69699
69974
  );
@@ -69707,7 +69982,7 @@ async function installLazePlugin({ context }) {
69707
69982
  async function plugin({ context, args }) {
69708
69983
  const action = args.words[1] ?? "install";
69709
69984
  if (action === "path") {
69710
- context.out(`${join13(pluginFolderOf({ context }), LAZE_PLUGIN)}
69985
+ context.out(`${join14(pluginFolderOf({ context }), LAZE_PLUGIN)}
69711
69986
  `);
69712
69987
  return 0;
69713
69988
  }
@@ -69726,7 +70001,7 @@ async function plugin({ context, args }) {
69726
70001
 
69727
70002
  // src/services/mcp-channel.service.ts
69728
70003
  import { mkdir as mkdir12, rm as rm7, writeFile as writeFile12 } from "node:fs/promises";
69729
- import { dirname as dirname12 } from "node:path";
70004
+ import { dirname as dirname13 } from "node:path";
69730
70005
  var LAZE_MCP_SERVER = "laze";
69731
70006
  var DEV_CHANNELS_FLAG = "--dangerously-load-development-channels";
69732
70007
  var ROUND_SECONDS3 = 50;
@@ -69816,7 +70091,7 @@ async function pushInbox({
69816
70091
  signal
69817
70092
  }) {
69818
70093
  const marker = statePathOf({ context, kind: "channels", profile });
69819
- await mkdir12(dirname12(marker), { recursive: true, mode: 448 });
70094
+ await mkdir12(dirname13(marker), { recursive: true, mode: 448 });
69820
70095
  await writeFile12(marker, JSON.stringify({ pid: context.processes.pid }));
69821
70096
  try {
69822
70097
  while (!signal.aborted) {
@@ -69844,8 +70119,8 @@ async function pushInbox({
69844
70119
  }
69845
70120
 
69846
70121
  // src/services/plugin-tip.service.ts
69847
- import { mkdir as mkdir13, readFile as readFile12, writeFile as writeFile13 } from "node:fs/promises";
69848
- import { dirname as dirname13 } from "node:path";
70122
+ import { mkdir as mkdir13, readFile as readFile13, writeFile as writeFile13 } from "node:fs/promises";
70123
+ import { dirname as dirname14 } from "node:path";
69849
70124
  var RELOAD_TIP = "Laze: the Laze plugin is installed in Claude Code, and this session has not loaded it yet. Tell the user once, in one plain line, that it is optional: typing /reload-plugins makes Laze messages arrive right away; until then they still arrive through the hooks.";
69850
70125
  var LINK_RELOAD_TIP = "Tell the user once, in one plain line, that it is optional: typing /reload-plugins makes Laze messages arrive right away; until then they still arrive through the hooks.";
69851
70126
  function monitorsRunHere({ context }) {
@@ -69879,7 +70154,7 @@ async function markReloadTipTold({
69879
70154
  }) {
69880
70155
  if (!session) return;
69881
70156
  const path = toldPathOf({ context, session });
69882
- await mkdir13(dirname13(path), { recursive: true, mode: 448 });
70157
+ await mkdir13(dirname14(path), { recursive: true, mode: 448 });
69883
70158
  await writeFile13(path, String(context.nowMs()), { mode: 384 });
69884
70159
  }
69885
70160
  async function reloadTipOnce({
@@ -69888,7 +70163,7 @@ async function reloadTipOnce({
69888
70163
  }) {
69889
70164
  if (!session || !monitorsRunHere({ context })) return void 0;
69890
70165
  if (!await pluginRegistered({ context })) return void 0;
69891
- const told = await readFile12(toldPathOf({ context, session }), "utf8").then(
70166
+ const told = await readFile13(toldPathOf({ context, session }), "utf8").then(
69892
70167
  () => true,
69893
70168
  () => false
69894
70169
  );
@@ -69954,9 +70229,9 @@ async function installHooks({
69954
70229
  directory,
69955
70230
  profile
69956
70231
  }) {
69957
- const folder = join14(directory, ".claude");
69958
- const path = join14(folder, "settings.local.json");
69959
- const current2 = await readFile13(path, "utf8").then(
70232
+ const folder = join15(directory, ".claude");
70233
+ const path = join15(folder, "settings.local.json");
70234
+ const current2 = await readFile14(path, "utf8").then(
69960
70235
  (text2) => JSON.parse(text2),
69961
70236
  () => ({})
69962
70237
  );
@@ -70158,7 +70433,7 @@ async function reportTranscript({
70158
70433
  input: input2
70159
70434
  }) {
70160
70435
  if (!input2.transcript_path || !input2.session_id) return;
70161
- const lines = (await readFile13(input2.transcript_path, "utf8")).split("\n");
70436
+ const lines = (await readFile14(input2.transcript_path, "utf8")).split("\n");
70162
70437
  const context = readTranscript({ lines });
70163
70438
  await client.post("/api/agents/me/activity", {
70164
70439
  sessionId: input2.session_id,
@@ -70191,7 +70466,7 @@ async function handOver({ context, args }) {
70191
70466
  const kept = await dueFromSpool({
70192
70467
  context,
70193
70468
  profile: agent2,
70194
- seen: () => input2.transcript_path ? readFile13(input2.transcript_path, "utf8") : Promise.resolve(""),
70469
+ seen: () => input2.transcript_path ? readFile14(input2.transcript_path, "utf8") : Promise.resolve(""),
70195
70470
  pushedToo: false
70196
70471
  });
70197
70472
  const claim3 = forSession({ client, session });
@@ -70231,8 +70506,8 @@ async function addSessionStartWaiter({ context, args }) {
70231
70506
  const directory = context.environment.inherited.CLAUDE_PROJECT_DIR;
70232
70507
  const profile = flagText({ args, name: "profile" });
70233
70508
  if (!directory || !profile) return;
70234
- const path = join14(directory, ".claude", "settings.local.json");
70235
- const settings2 = await readFile13(path, "utf8").then(
70509
+ const path = join15(directory, ".claude", "settings.local.json");
70510
+ const settings2 = await readFile14(path, "utf8").then(
70236
70511
  (text2) => JSON.parse(text2),
70237
70512
  () => void 0
70238
70513
  );
@@ -70241,7 +70516,7 @@ async function addSessionStartWaiter({ context, args }) {
70241
70516
  }
70242
70517
  async function refreshPlugin({ context }) {
70243
70518
  if (await pluginIsCurrent({ context })) return;
70244
- const logPath = join14(pluginFolderOf({ context }), "install.log");
70519
+ const logPath = join15(pluginFolderOf({ context }), "install.log");
70245
70520
  context.processes.spawnDetached({ argv: [...context.program, "plugin", "install"], logPath });
70246
70521
  }
70247
70522
  async function stopHook({ context, args }) {
@@ -70259,7 +70534,7 @@ async function stopHook({ context, args }) {
70259
70534
  }
70260
70535
 
70261
70536
  // src/services/agent-manage-commands.service.ts
70262
- import { readFile as readFile14 } from "node:fs/promises";
70537
+ import { readFile as readFile15 } from "node:fs/promises";
70263
70538
  import { extname, resolve as resolve5 } from "node:path";
70264
70539
 
70265
70540
  // src/rules/login-format.rules.ts
@@ -70388,7 +70663,7 @@ async function avatarOf({
70388
70663
  }) {
70389
70664
  const path = flagText({ args, name: "avatar" });
70390
70665
  if (!path) return void 0;
70391
- const bytes = await readFile14(resolve5(context.cwd, path)).catch(() => {
70666
+ const bytes = await readFile15(resolve5(context.cwd, path)).catch(() => {
70392
70667
  throw new CliUsageError(`laze: cannot read the avatar file ${path}.`);
70393
70668
  });
70394
70669
  const uploaded = await client.post("/api/agents/avatars", {
@@ -71091,8 +71366,8 @@ async function requestAgent({ context, args }) {
71091
71366
  }
71092
71367
 
71093
71368
  // src/services/app-commands.service.ts
71094
- import { mkdir as mkdir15, readdir as readdir5, readFile as readFile15, writeFile as writeFile16 } from "node:fs/promises";
71095
- import { dirname as dirname14, join as join16, relative as relative3, resolve as resolve6, sep as sep2 } from "node:path";
71369
+ import { mkdir as mkdir15, readdir as readdir6, readFile as readFile16, writeFile as writeFile16 } from "node:fs/promises";
71370
+ import { dirname as dirname15, join as join17, relative as relative3, resolve as resolve6, sep as sep2 } from "node:path";
71096
71371
 
71097
71372
  // ../../modules/app/contract/src/app.connections.ts
71098
71373
  var appFunctionNameSchema = external_exports.string().regex(/^[a-z0-9][a-z0-9_-]{0,63}$/);
@@ -73487,7 +73762,7 @@ async function appPinsCommand({
73487
73762
  import { execFile } from "node:child_process";
73488
73763
  import { mkdtemp, rm as rm8, writeFile as writeFile15 } from "node:fs/promises";
73489
73764
  import { tmpdir } from "node:os";
73490
- import { join as join15 } from "node:path";
73765
+ import { join as join16 } from "node:path";
73491
73766
  import { promisify } from "node:util";
73492
73767
  var run2 = promisify(execFile);
73493
73768
  var MODULE_SYNTAX = /^\s*(import|export)\s/m;
@@ -73516,11 +73791,11 @@ async function scriptErrorsOf({
73516
73791
  const unknown2 = unknownCollectionsOf({ files: files2, collections });
73517
73792
  const scripts = files2.flatMap(scriptsOf);
73518
73793
  if (scripts.length === 0) return unknown2;
73519
- const dir = await mkdtemp(join15(tmpdir(), "laze-app-check-"));
73794
+ const dir = await mkdtemp(join16(tmpdir(), "laze-app-check-"));
73520
73795
  try {
73521
73796
  const errors = await Promise.all(
73522
73797
  scripts.map(async (script, index) => {
73523
- const file3 = join15(dir, `${index}.${script.module ? "mjs" : "cjs"}`);
73798
+ const file3 = join16(dir, `${index}.${script.module ? "mjs" : "cjs"}`);
73524
73799
  await writeFile15(file3, script.code);
73525
73800
  try {
73526
73801
  await run2(process.execPath, ["--check", file3]);
@@ -73670,7 +73945,7 @@ async function turnTokenOf({
73670
73945
  const pinned = env.LAZE_TURN_TOKEN?.trim();
73671
73946
  if (pinned) return pinned;
73672
73947
  if (env.LAZE_TURN_FILE) {
73673
- return readFile15(env.LAZE_TURN_FILE, "utf8").then(
73948
+ return readFile16(env.LAZE_TURN_FILE, "utf8").then(
73674
73949
  (text2) => text2.trim(),
73675
73950
  () => ""
73676
73951
  );
@@ -73696,7 +73971,7 @@ function folderOf({ context, word: word3 }) {
73696
73971
  return resolve6(context.cwd, word3 ?? ".");
73697
73972
  }
73698
73973
  async function readManifest(folder) {
73699
- const text2 = await readFile15(join16(folder, APP_MANIFEST_FILE), "utf8").catch(() => void 0);
73974
+ const text2 = await readFile16(join17(folder, APP_MANIFEST_FILE), "utf8").catch(() => void 0);
73700
73975
  if (text2 === void 0) return void 0;
73701
73976
  const parsed = appManifestSchema.safeParse(JSON.parse(text2));
73702
73977
  if (!parsed.success) {
@@ -73731,7 +74006,7 @@ async function jsonFlag({
73731
74006
  }) {
73732
74007
  const raw = flagText({ args, name: name2 });
73733
74008
  if (!raw) return void 0;
73734
- const text2 = raw.startsWith("@") ? await readFile15(resolve6(context.cwd, raw.slice(1)), "utf8") : raw;
74009
+ const text2 = raw.startsWith("@") ? await readFile16(resolve6(context.cwd, raw.slice(1)), "utf8") : raw;
73735
74010
  try {
73736
74011
  return JSON.parse(text2);
73737
74012
  } catch {
@@ -73743,8 +74018,8 @@ async function listFiles(folder) {
73743
74018
  const pending = [folder];
73744
74019
  while (pending.length > 0 && found.length <= MAX_FILES) {
73745
74020
  const current2 = pending.pop() ?? folder;
73746
- for (const entry of await readdir5(current2, { withFileTypes: true })) {
73747
- const path = join16(current2, entry.name);
74021
+ for (const entry of await readdir6(current2, { withFileTypes: true })) {
74022
+ const path = join17(current2, entry.name);
73748
74023
  const rel = relative3(folder, path).split(sep2).join("/");
73749
74024
  if (isSkippedPath({ path: rel })) continue;
73750
74025
  if (entry.isDirectory()) pending.push(path);
@@ -73788,8 +74063,8 @@ var appCreate = async ({ context, args }) => {
73788
74063
  await mkdir15(folder, { recursive: true });
73789
74064
  const files2 = template ? templateFiles({ template, name: name2 }) : {};
73790
74065
  for (const [path, content] of Object.entries(files2)) {
73791
- await mkdir15(dirname14(join16(folder, path)), { recursive: true });
73792
- await writeFile16(join16(folder, path), content);
74066
+ await mkdir15(dirname15(join17(folder, path)), { recursive: true });
74067
+ await writeFile16(join17(folder, path), content);
73793
74068
  }
73794
74069
  const manifest = {
73795
74070
  app: { id: app2.id, name: app2.name, slug: app2.slug },
@@ -73797,7 +74072,7 @@ var appCreate = async ({ context, args }) => {
73797
74072
  views: template?.views ? [...template.views] : [],
73798
74073
  seed: template ? { ...template.seed } : {}
73799
74074
  };
73800
- await writeFile16(join16(folder, APP_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
74075
+ await writeFile16(join17(folder, APP_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
73801
74076
  `);
73802
74077
  print5({
73803
74078
  context,
@@ -73834,7 +74109,7 @@ var appPush = async ({ context, args }) => {
73834
74109
  paths.map(
73835
74110
  async (path) => buildFileOf({
73836
74111
  path: relative3(folder, path).split(sep2).join("/"),
73837
- bytes: await readFile15(path)
74112
+ bytes: await readFile16(path)
73838
74113
  })
73839
74114
  )
73840
74115
  );
@@ -74217,7 +74492,7 @@ var appImport = async ({ context, args }) => {
74217
74492
  const words = args.words.slice(2);
74218
74493
  const [named, collection, file3] = words.length >= 3 ? words : [void 0, ...words];
74219
74494
  if (!collection || !file3) throw new CliUsageError(USAGE5);
74220
- const csv = await readFile15(resolve6(context.cwd, file3), "utf8").catch(() => {
74495
+ const csv = await readFile16(resolve6(context.cwd, file3), "utf8").catch(() => {
74221
74496
  throw new CliUsageError(`Cannot read ${file3}`);
74222
74497
  });
74223
74498
  const scoped = named ? { ...args, flags: { ...args.flags, app: named } } : args;
@@ -74783,8 +75058,8 @@ async function billing({ context, args }) {
74783
75058
 
74784
75059
  // src/services/browser-commands.service.ts
74785
75060
  import { randomBytes } from "node:crypto";
74786
- import { mkdir as mkdir16, readFile as readFile16, writeFile as writeFile17 } from "node:fs/promises";
74787
- import { dirname as dirname15, join as join17 } from "node:path";
75061
+ import { mkdir as mkdir16, readFile as readFile17, writeFile as writeFile17 } from "node:fs/promises";
75062
+ import { dirname as dirname16, join as join18 } from "node:path";
74788
75063
 
74789
75064
  // src/services/browser-tab-commands.service.ts
74790
75065
  var BROWSER_TAB_PATHS = {
@@ -75330,7 +75605,7 @@ async function turnTokenOf2({ context }) {
75330
75605
  const pinned = env.LAZE_TURN_TOKEN?.trim();
75331
75606
  if (pinned) return pinned;
75332
75607
  if (!env.LAZE_TURN_FILE) return "";
75333
- return readFile16(env.LAZE_TURN_FILE, "utf8").then(
75608
+ return readFile17(env.LAZE_TURN_FILE, "utf8").then(
75334
75609
  (text2) => text2.trim(),
75335
75610
  () => ""
75336
75611
  );
@@ -75404,7 +75679,7 @@ async function cdp({ context, args }) {
75404
75679
  }
75405
75680
  function bridgeStatePath({ context, machine: machine2 }) {
75406
75681
  const safe = machine2.replace(/[^a-zA-Z0-9_-]/g, "_");
75407
- return join17(dirname15(context.environment.configPath), "bridges", `${safe}.json`);
75682
+ return join18(dirname16(context.environment.configPath), "bridges", `${safe}.json`);
75408
75683
  }
75409
75684
  async function bridgePort({
75410
75685
  context,
@@ -75412,7 +75687,7 @@ async function bridgePort({
75412
75687
  access
75413
75688
  }) {
75414
75689
  const path = bridgeStatePath({ context, machine: machine2 });
75415
- const live = await readFile16(path, "utf8").then(
75690
+ const live = await readFile17(path, "utf8").then(
75416
75691
  (text2) => JSON.parse(text2),
75417
75692
  () => void 0
75418
75693
  );
@@ -75425,7 +75700,7 @@ async function bridgePort({
75425
75700
  key,
75426
75701
  ...target
75427
75702
  });
75428
- await mkdir16(dirname15(path), { recursive: true, mode: 448 });
75703
+ await mkdir16(dirname16(path), { recursive: true, mode: 448 });
75429
75704
  await writeFile17(path, JSON.stringify({ port, key }), { mode: 384 });
75430
75705
  return port;
75431
75706
  }
@@ -76070,9 +76345,42 @@ async function channelSettings({ context, args }) {
76070
76345
  }
76071
76346
 
76072
76347
  // src/services/chat-actions-commands.service.ts
76073
- import { readFile as readFile17 } from "node:fs/promises";
76348
+ import { readFile as readFile18 } from "node:fs/promises";
76074
76349
  import { basename as basename3, isAbsolute as isAbsolute2, relative as relative4, resolve as resolve7 } from "node:path";
76075
76350
 
76351
+ // src/rules/file-types.rules.ts
76352
+ var TYPES = {
76353
+ png: "image/png",
76354
+ jpg: "image/jpeg",
76355
+ jpeg: "image/jpeg",
76356
+ webp: "image/webp",
76357
+ gif: "image/gif",
76358
+ svg: "image/svg+xml",
76359
+ pdf: "application/pdf",
76360
+ txt: "text/plain",
76361
+ md: "text/markdown",
76362
+ csv: "text/csv",
76363
+ json: "application/json",
76364
+ zip: "application/zip"
76365
+ };
76366
+ function contentTypeOf(fileName) {
76367
+ const extension2 = fileName.toLowerCase().split(".").pop() ?? "";
76368
+ return TYPES[extension2] ?? "application/octet-stream";
76369
+ }
76370
+ var MACHINE_NAME = /^(?:[a-z]{1,8}[_-])?[0-9a-f][0-9a-f_-]{11,}$/i;
76371
+ function readableUploadName({ name: name2, asked }) {
76372
+ const slash = name2.lastIndexOf("/");
76373
+ const base = name2.slice(slash + 1);
76374
+ const dot = base.lastIndexOf(".");
76375
+ const extension2 = dot > 0 ? base.slice(dot) : "";
76376
+ const wanted = asked?.trim();
76377
+ if (wanted) return /\.[A-Za-z0-9]{1,8}$/.test(wanted) ? wanted : `${wanted}${extension2}`;
76378
+ const stem = dot > 0 ? base.slice(0, dot) : base;
76379
+ if (!MACHINE_NAME.test(stem)) return name2;
76380
+ const image = contentTypeOf(base).startsWith("image/");
76381
+ return `${image ? "image" : "file"}${extension2}`;
76382
+ }
76383
+
76076
76384
  // src/services/file-upload.service.ts
76077
76385
  async function sendParts({
76078
76386
  context,
@@ -76171,7 +76479,7 @@ var CHAT_ACTIONS_USAGE = `Usage:
76171
76479
  laze files <channel> [--before <fileId>] [--limit <n>] its files, newest first
76172
76480
  laze file link <fileId> [--variant original|thumbnail|poster|preview] [--download]
76173
76481
  laze file rename <fileId> <name> rename a file you posted
76174
- laze file upload <channel> <path> [--type <content-type>] upload a file; post it with its id
76482
+ laze file upload <channel> <path> [--name <name>] [--type <content-type>] upload a file; post it with its id
76175
76483
  laze saved [--done] [--limit <n>] | laze saved marks your saved messages (people)
76176
76484
  laze save <messageId> [--off] save a message for later, or take it out
76177
76485
  laze saved done <messageId> [--undo] mark a saved message done, or open again
@@ -76375,19 +76683,27 @@ function uploadNameOf({ cwd, path }) {
76375
76683
  }
76376
76684
  var fileUpload = async ({ context, args, client }) => {
76377
76685
  const path = resolve7(context.cwd, wordAt(args, 3));
76378
- const bytes = new Uint8Array(await readFile17(path));
76686
+ const bytes = new Uint8Array(await readFile18(path));
76379
76687
  const answer4 = await uploadFile({
76380
76688
  context,
76381
76689
  client,
76382
76690
  file: {
76383
76691
  channel: wordAt(args, 2),
76384
- fileName: uploadNameOf({ cwd: context.cwd, path }),
76385
- contentType: flagText({ args, name: "type", fallback: "application/octet-stream" }),
76692
+ fileName: readableUploadName({
76693
+ name: uploadNameOf({ cwd: context.cwd, path }),
76694
+ ...flagText({ args, name: "name" }) && { asked: flagText({ args, name: "name" }) }
76695
+ }),
76696
+ contentType: flagText({ args, name: "type", fallback: contentTypeOf(path) }),
76386
76697
  bytes
76387
76698
  }
76388
76699
  });
76389
- print6({ context, args, answer: answer4, text: (it) => `Uploaded ${it.fileName} as ${it.id}.
76390
- ` });
76700
+ print6({
76701
+ context,
76702
+ args,
76703
+ answer: answer4,
76704
+ text: (it) => `Uploaded ${it.fileName} as ${it.id}. Put <file:${it.id}> in a message to share it.
76705
+ `
76706
+ });
76391
76707
  };
76392
76708
  var FILE_VERBS = {
76393
76709
  link: async ({ context, args, client }) => {
@@ -76540,7 +76856,7 @@ async function chatActions({
76540
76856
  }
76541
76857
 
76542
76858
  // src/services/claude-monitor.service.ts
76543
- import { readFile as readFile18, rm as rm9 } from "node:fs/promises";
76859
+ import { readFile as readFile19, rm as rm9 } from "node:fs/promises";
76544
76860
  var MONITOR_IDLE_MS = 3e4;
76545
76861
  var MONITOR_OUTRANKED_MS = 3e3;
76546
76862
  async function deliverOnce({
@@ -76558,7 +76874,7 @@ async function deliverOnce({
76558
76874
  const named = { ...args, flags: { ...args.flags, profile } };
76559
76875
  const { client } = await signedIn({ context, args: named });
76560
76876
  const due = await dueFromSpool({ context, profile, seen: async () => "", pushedToo: true });
76561
- const taken = due.length > 0 ? [] : await takeRound({ context, client, claudePid, session });
76877
+ const taken = due.length > 0 ? [] : await takeRound2({ context, client, claudePid, session });
76562
76878
  const messages = [...due, ...taken];
76563
76879
  if (messages.length === 0) {
76564
76880
  await context.sleep(1e3);
@@ -76635,7 +76951,7 @@ async function monitorSessionOf({
76635
76951
  const fromEnv = sessionOf({ context, harness: "claude-code", sessionId });
76636
76952
  if (fromEnv || !claudePid) return fromEnv;
76637
76953
  const path = statePathOf({ context, kind: "sessions", profile: String(claudePid) });
76638
- return readFile18(path, "utf8").then(
76954
+ return readFile19(path, "utf8").then(
76639
76955
  (text2) => JSON.parse(text2),
76640
76956
  () => void 0
76641
76957
  );
@@ -78310,10 +78626,10 @@ async function computer({ context, args }) {
78310
78626
  }
78311
78627
 
78312
78628
  // src/services/connect-commands.service.ts
78313
- import { readFile as readFile20 } from "node:fs/promises";
78629
+ import { readFile as readFile21 } from "node:fs/promises";
78314
78630
 
78315
78631
  // src/services/mcp-gateway.service.ts
78316
- import { readFile as readFile19 } from "node:fs/promises";
78632
+ import { readFile as readFile20 } from "node:fs/promises";
78317
78633
  import { createInterface as createInterface3 } from "node:readline";
78318
78634
  var TURN_HEADER = "x-laze-turn";
78319
78635
  function serveMcpGateway({
@@ -78356,7 +78672,7 @@ async function relayMcpLines({
78356
78672
  const github3 = env.LAZE_GITHUB_CONNECTION;
78357
78673
  const url2 = `${profile.url.replace(/\/+$/, "")}/api/connectors/mcp/${encodeURIComponent(profile.agentId)}${github3 ? `?github=${encodeURIComponent(github3)}` : ""}`;
78358
78674
  const turnFile = env.LAZE_TURN_FILE;
78359
- const readTurn = () => readFile19(turnFile, "utf8").then(
78675
+ const readTurn = () => readFile20(turnFile, "utf8").then(
78360
78676
  (text2) => text2.trim(),
78361
78677
  () => ""
78362
78678
  );
@@ -78446,7 +78762,7 @@ async function turnOf({ context }) {
78446
78762
  const pinned = env.LAZE_TURN_TOKEN?.trim();
78447
78763
  if (pinned) return pinned;
78448
78764
  const file3 = env.LAZE_TURN_FILE;
78449
- const turn = file3 ? await readFile20(file3, "utf8").then(
78765
+ const turn = file3 ? await readFile21(file3, "utf8").then(
78450
78766
  (text2) => text2.trim(),
78451
78767
  () => ""
78452
78768
  ) : "";
@@ -78504,11 +78820,11 @@ async function connect({
78504
78820
  }
78505
78821
 
78506
78822
  // src/services/connector-commands.service.ts
78507
- import { readFile as readFile22 } from "node:fs/promises";
78823
+ import { readFile as readFile23 } from "node:fs/promises";
78508
78824
  import { resolve as resolve8 } from "node:path";
78509
78825
 
78510
78826
  // src/services/vault-keychain-commands.service.ts
78511
- import { readFile as readFile21 } from "node:fs/promises";
78827
+ import { readFile as readFile22 } from "node:fs/promises";
78512
78828
 
78513
78829
  // src/rules/vault-input.rules.ts
78514
78830
  function secondsOf(text2) {
@@ -78830,7 +79146,7 @@ async function secretText({ context, args }) {
78830
79146
  );
78831
79147
  }
78832
79148
  const file3 = flagText({ args, name: "from-file" });
78833
- const text2 = file3 ? await readFile21(file3, "utf8") : await context.readStdin();
79149
+ const text2 = file3 ? await readFile22(file3, "utf8") : await context.readStdin();
78834
79150
  const trimmed = text2.replace(/\r?\n$/, "");
78835
79151
  if (!trimmed.trim()) throw new CliUsageError("No value: pipe it on stdin or use --from-file.");
78836
79152
  return trimmed;
@@ -79040,7 +79356,7 @@ async function keyText({ context, args }) {
79040
79356
  throw new CliUsageError("A key never goes in a flag: pipe it on stdin or use --from-file.");
79041
79357
  }
79042
79358
  const file3 = flagText({ args, name: "from-file" });
79043
- const text2 = file3 ? await readFile22(resolve8(context.cwd, file3), "utf8") : await context.readStdin();
79359
+ const text2 = file3 ? await readFile23(resolve8(context.cwd, file3), "utf8") : await context.readStdin();
79044
79360
  const trimmed = text2.trim();
79045
79361
  if (!trimmed) throw new CliUsageError("No key: pipe it on stdin or use --from-file.");
79046
79362
  return trimmed;
@@ -79432,8 +79748,8 @@ var DOMAINS_USAGE = `Usage:
79432
79748
  var printJson5 = (context, data) => context.out(`${JSON.stringify(data, null, 2)}
79433
79749
  `);
79434
79750
  function printDomain(context, row) {
79435
- const join22 = row.autoJoin ? "auto-join on" : "auto-join off";
79436
- context.out(`${row.domain} ${join22}${row.enforced ? " single sign-on enforced" : ""}
79751
+ const join23 = row.autoJoin ? "auto-join on" : "auto-join off";
79752
+ context.out(`${row.domain} ${join23}${row.enforced ? " single sign-on enforced" : ""}
79437
79753
  `);
79438
79754
  }
79439
79755
  async function list4({ context, args }) {
@@ -79465,7 +79781,7 @@ async function domains({ context, args }) {
79465
79781
  }
79466
79782
 
79467
79783
  // src/services/feed-commands.service.ts
79468
- import { readFile as readFile24 } from "node:fs/promises";
79784
+ import { readFile as readFile25 } from "node:fs/promises";
79469
79785
  import { resolve as resolve10 } from "node:path";
79470
79786
 
79471
79787
  // src/rules/feed-input.rules.ts
@@ -79590,7 +79906,7 @@ function feedFlagsOf({ args }) {
79590
79906
  }
79591
79907
 
79592
79908
  // src/services/feed-files.service.ts
79593
- import { readFile as readFile23 } from "node:fs/promises";
79909
+ import { readFile as readFile24 } from "node:fs/promises";
79594
79910
  import { basename as basename4, resolve as resolve9 } from "node:path";
79595
79911
 
79596
79912
  // ../../modules/feed/contract/src/feed.ts
@@ -80135,26 +80451,6 @@ var feedWakeIntentSchemaDefinition = external_exports.object({
80135
80451
  // ../../modules/feed/contract/src/feed.config.ts
80136
80452
  var feedConfig = Config.define(() => ({ publicBaseUrl }));
80137
80453
 
80138
- // src/rules/file-types.rules.ts
80139
- var TYPES = {
80140
- png: "image/png",
80141
- jpg: "image/jpeg",
80142
- jpeg: "image/jpeg",
80143
- webp: "image/webp",
80144
- gif: "image/gif",
80145
- svg: "image/svg+xml",
80146
- pdf: "application/pdf",
80147
- txt: "text/plain",
80148
- md: "text/markdown",
80149
- csv: "text/csv",
80150
- json: "application/json",
80151
- zip: "application/zip"
80152
- };
80153
- function contentTypeOf(fileName) {
80154
- const extension2 = fileName.toLowerCase().split(".").pop() ?? "";
80155
- return TYPES[extension2] ?? "application/octet-stream";
80156
- }
80157
-
80158
80454
  // src/services/feed-files.service.ts
80159
80455
  async function bytesOf2({
80160
80456
  context,
@@ -80185,7 +80481,7 @@ async function local({ context, path }) {
80185
80481
  return {
80186
80482
  fileName,
80187
80483
  contentType: contentTypeOf(fileName),
80188
- bytes: new Uint8Array(await readFile23(full))
80484
+ bytes: new Uint8Array(await readFile24(full))
80189
80485
  };
80190
80486
  }
80191
80487
  async function directWith({ client, to }) {
@@ -80263,7 +80559,7 @@ async function bodyOf2({
80263
80559
  flags: flags2
80264
80560
  }) {
80265
80561
  const body = { ...flags2.fields };
80266
- const read3 = (source) => "file" in source ? readFile24(resolve10(context.cwd, source.file), "utf8") : source.text;
80562
+ const read3 = (source) => "file" in source ? readFile25(resolve10(context.cwd, source.file), "utf8") : source.text;
80267
80563
  for (const [field, source] of Object.entries(flags2.texts)) body[field] = await read3(source);
80268
80564
  if (flags2.rich) {
80269
80565
  const text2 = await read3(flags2.rich.source);
@@ -80425,7 +80721,7 @@ async function textFlag({
80425
80721
  }) {
80426
80722
  const value = flagText({ args, name: name2 });
80427
80723
  if (!value.startsWith("@")) return value;
80428
- return readFile24(resolve10(context.cwd, value.slice(1)), "utf8");
80724
+ return readFile25(resolve10(context.cwd, value.slice(1)), "utf8");
80429
80725
  }
80430
80726
  async function feedList({ context, args }) {
80431
80727
  const { client } = await signedIn({ context, args });
@@ -80535,7 +80831,7 @@ async function feed({ context, args }) {
80535
80831
  }
80536
80832
 
80537
80833
  // src/services/github-commands.service.ts
80538
- import { readFile as readFile25 } from "node:fs/promises";
80834
+ import { readFile as readFile26 } from "node:fs/promises";
80539
80835
 
80540
80836
  // src/rules/github-signature.rules.ts
80541
80837
  var TURN_SEPARATOR = "~";
@@ -80605,7 +80901,7 @@ var REAL_GH = "/usr/bin/gh";
80605
80901
  var NOT_SET = "laze: agent_github_not_set: this agent has no GitHub connection. Its owner sets one on the agent's settings page or with `laze agent set-github <agent> <connection>`.";
80606
80902
  async function turnFileToken({ env }) {
80607
80903
  if (!env.LAZE_TURN_FILE) return "";
80608
- return readFile25(env.LAZE_TURN_FILE, "utf8").then(
80904
+ return readFile26(env.LAZE_TURN_FILE, "utf8").then(
80609
80905
  (text2) => text2.trim(),
80610
80906
  () => ""
80611
80907
  );
@@ -80639,7 +80935,7 @@ async function githubGh({
80639
80935
  args: args.rest,
80640
80936
  agentName: profile.name ?? "An agent",
80641
80937
  threadUrl: threadUrlOf({ env, workspaceId: profile.workspaceId }),
80642
- readBodyFile: (path) => path === "-" ? context.readStdin() : readFile25(path, "utf8")
80938
+ readBodyFile: (path) => path === "-" ? context.readStdin() : readFile26(path, "utf8")
80643
80939
  });
80644
80940
  return context.runCommand({
80645
80941
  command: [REAL_GH, ...ghArgs],
@@ -80738,7 +81034,7 @@ async function setAgentGithub({
80738
81034
  }
80739
81035
 
80740
81036
  // src/services/history-commands.service.ts
80741
- import { readFile as readFile26 } from "node:fs/promises";
81037
+ import { readFile as readFile27 } from "node:fs/promises";
80742
81038
 
80743
81039
  // src/rules/history-format.rules.ts
80744
81040
  function timeOf2(iso) {
@@ -80834,7 +81130,7 @@ async function turnTokenOf3({ context }) {
80834
81130
  const pinned = env.LAZE_TURN_TOKEN?.trim();
80835
81131
  if (pinned) return pinned;
80836
81132
  if (!env.LAZE_TURN_FILE) return "";
80837
- return readFile26(env.LAZE_TURN_FILE, "utf8").then(
81133
+ return readFile27(env.LAZE_TURN_FILE, "utf8").then(
80838
81134
  (text2) => text2.trim(),
80839
81135
  () => ""
80840
81136
  );
@@ -81026,19 +81322,19 @@ async function ip({ context, args }) {
81026
81322
  }
81027
81323
 
81028
81324
  // src/services/join-commands.service.ts
81029
- import { mkdir as mkdir17, readFile as readFile27, rename as rename5, rm as rm10, writeFile as writeFile18 } from "node:fs/promises";
81030
- import { dirname as dirname16, join as join18 } from "node:path";
81325
+ import { mkdir as mkdir17, readFile as readFile28, rename as rename5, rm as rm10, writeFile as writeFile18 } from "node:fs/promises";
81326
+ import { dirname as dirname17, join as join19 } from "node:path";
81031
81327
  var DEFAULT_WAIT_SECONDS2 = 100;
81032
81328
  var JOIN_USAGE = "Usage: laze join [--workspace <name|id|invite link>] [--for <email>] [--name <name>] [--note <text>] [--timeout <seconds>] [--project <folder>]";
81033
81329
  function pendingPathOf({ context }) {
81034
- return join18(dirname16(context.environment.configPath), "join", "pending.json");
81330
+ return join19(dirname17(context.environment.configPath), "join", "pending.json");
81035
81331
  }
81036
81332
  async function readPending({
81037
81333
  context,
81038
81334
  url: url2,
81039
81335
  args
81040
81336
  }) {
81041
- const pending = await readFile27(pendingPathOf({ context }), "utf8").then(
81337
+ const pending = await readFile28(pendingPathOf({ context }), "utf8").then(
81042
81338
  (text2) => JSON.parse(text2),
81043
81339
  () => void 0
81044
81340
  );
@@ -81048,7 +81344,7 @@ async function readPending({
81048
81344
  }
81049
81345
  async function keepPending({ context, pending }) {
81050
81346
  const path = pendingPathOf({ context });
81051
- await mkdir17(dirname16(path), { recursive: true, mode: 448 });
81347
+ await mkdir17(dirname17(path), { recursive: true, mode: 448 });
81052
81348
  const temporary = `${path}.${process.pid}.tmp`;
81053
81349
  await writeFile18(temporary, JSON.stringify(pending), { mode: 384 });
81054
81350
  await rename5(temporary, path);
@@ -81368,9 +81664,9 @@ function machineAccessCommand(name2) {
81368
81664
 
81369
81665
  // src/services/vault-commands.service.ts
81370
81666
  import { createHash as createHash2 } from "node:crypto";
81371
- import { mkdir as mkdir18, readFile as readFile28, rm as rm11, writeFile as writeFile19 } from "node:fs/promises";
81667
+ import { mkdir as mkdir18, readFile as readFile29, rm as rm11, writeFile as writeFile19 } from "node:fs/promises";
81372
81668
  import { tmpdir as tmpdir2 } from "node:os";
81373
- import { dirname as dirname17, join as join19 } from "node:path";
81669
+ import { dirname as dirname18, join as join20 } from "node:path";
81374
81670
  var USAGE10 = `Usage: laze vault run <connection> --reason "<one plain sentence>" [--wait <s>] -- <command> [args...]
81375
81671
  Runs the command with the connection's values in its environment, on a Laze agent's computer
81376
81672
  or on a machine it runs on.`;
@@ -81409,7 +81705,7 @@ async function turnTokenOf4({
81409
81705
  if (pinned) return pinned;
81410
81706
  if (!turnFile) throw new CliUsageError(`${command} works only during an agent's turn`);
81411
81707
  try {
81412
- return (await readFile28(turnFile, "utf8")).trim();
81708
+ return (await readFile29(turnFile, "utf8")).trim();
81413
81709
  } catch {
81414
81710
  throw new CliUsageError(`${command} works only during an agent's turn`);
81415
81711
  }
@@ -81419,11 +81715,11 @@ function runKeyPathOf({
81419
81715
  connection
81420
81716
  }) {
81421
81717
  const name2 = createHash2("sha256").update(connection).digest("hex");
81422
- const base = turnFile ? dirname17(turnFile) : join19(tmpdir2(), "laze-vault");
81423
- return join19(base, "vault-run-keys", `${name2}.json`);
81718
+ const base = turnFile ? dirname18(turnFile) : join20(tmpdir2(), "laze-vault");
81719
+ return join20(base, "vault-run-keys", `${name2}.json`);
81424
81720
  }
81425
81721
  async function runKeyAt({ path }) {
81426
- const saved3 = await readFile28(path, "utf8").then(
81722
+ const saved3 = await readFile29(path, "utf8").then(
81427
81723
  (text2) => JSON.parse(text2),
81428
81724
  () => void 0
81429
81725
  );
@@ -81433,7 +81729,7 @@ async function runKeyAt({ path }) {
81433
81729
  }
81434
81730
  const fresh = await generateEcdhKeys();
81435
81731
  const jwk = await globalThis.crypto.subtle.exportKey("jwk", fresh.privateKey);
81436
- await mkdir18(dirname17(path), { recursive: true, mode: 448 });
81732
+ await mkdir18(dirname18(path), { recursive: true, mode: 448 });
81437
81733
  await writeFile19(path, JSON.stringify({ publicKey: fresh.publicKey, privateKey: jwk }), {
81438
81734
  mode: 384
81439
81735
  });
@@ -82106,14 +82402,14 @@ async function serveMcp({
82106
82402
  }
82107
82403
 
82108
82404
  // src/services/mount-files.service.ts
82109
- import { mkdir as mkdir19, readFile as readFile29, rm as rm12, writeFile as writeFile20 } from "node:fs/promises";
82110
- import { dirname as dirname18, relative as relative5, resolve as resolve11 } from "node:path";
82405
+ import { mkdir as mkdir19, readFile as readFile30, rm as rm12, writeFile as writeFile20 } from "node:fs/promises";
82406
+ import { dirname as dirname19, relative as relative5, resolve as resolve11 } from "node:path";
82111
82407
  async function textArgument({
82112
82408
  context,
82113
82409
  value
82114
82410
  }) {
82115
82411
  if (value === "-") return context.readStdin();
82116
- if (value.startsWith("@")) return readFile29(resolve11(context.cwd, value.slice(1)), "utf8");
82412
+ if (value.startsWith("@")) return readFile30(resolve11(context.cwd, value.slice(1)), "utf8");
82117
82413
  return value;
82118
82414
  }
82119
82415
  function turnChannel({ context, args }) {
@@ -82133,7 +82429,7 @@ async function writeMount({
82133
82429
  const inside = relative5(root, target);
82134
82430
  if (!inside || inside.startsWith(".."))
82135
82431
  throw new Error(`Refusing to write outside ${root}: ${file3.path}`);
82136
- await mkdir19(dirname18(target), { recursive: true });
82432
+ await mkdir19(dirname19(target), { recursive: true });
82137
82433
  await writeFile20(target, file3.content);
82138
82434
  }
82139
82435
  return root;
@@ -82775,8 +83071,8 @@ ${OPS_USAGE}`);
82775
83071
  }
82776
83072
 
82777
83073
  // src/services/release-watch.service.ts
82778
- import { mkdir as mkdir20, readFile as readFile30, realpath, writeFile as writeFile21 } from "node:fs/promises";
82779
- import { dirname as dirname19, join as join20 } from "node:path";
83074
+ import { mkdir as mkdir20, readFile as readFile31, realpath, writeFile as writeFile21 } from "node:fs/promises";
83075
+ import { dirname as dirname20, join as join21 } from "node:path";
82780
83076
 
82781
83077
  // src/rules/cli-update.rules.ts
82782
83078
  var CLI_PACKAGE_LATEST = "@lazehq/cli@latest";
@@ -82877,16 +83173,16 @@ async function startedUpdate({
82877
83173
  if (context.environment.inherited.LAZE_AUTO_UPDATE === "0") return null;
82878
83174
  const plan2 = updatePlanOf({ script: await scriptOf(context) });
82879
83175
  if (plan2.kind !== "install") return null;
82880
- const folder = dirname19(context.environment.configPath);
82881
- const stamp = join20(folder, "auto-update.json");
82882
- const last = await readFile30(stamp, "utf8").then((text2) => JSON.parse(text2)).catch(() => null);
83176
+ const folder = dirname20(context.environment.configPath);
83177
+ const stamp = join21(folder, "auto-update.json");
83178
+ const last = await readFile31(stamp, "utf8").then((text2) => JSON.parse(text2)).catch(() => null);
82883
83179
  const now = context.nowMs();
82884
83180
  if (last?.server === server && now - last.atMs < RETRY_AFTER_MS) return null;
82885
83181
  await mkdir20(folder, { recursive: true, mode: 448 });
82886
83182
  await writeFile21(stamp, JSON.stringify({ server, atMs: now }), { mode: 384 });
82887
83183
  context.processes.spawnDetached({
82888
83184
  argv: [...context.program, "update"],
82889
- logPath: join20(folder, "auto-update.log")
83185
+ logPath: join21(folder, "auto-update.log")
82890
83186
  });
82891
83187
  return { manager: plan2.manager };
82892
83188
  }
@@ -82916,19 +83212,19 @@ function watchingRelease({
82916
83212
  }
82917
83213
 
82918
83214
  // src/services/rush-guard.service.ts
82919
- import { readFile as readFile31, rm as rm13 } from "node:fs/promises";
83215
+ import { readFile as readFile32, rm as rm13 } from "node:fs/promises";
82920
83216
  var WATCH_MS3 = 2e3;
82921
83217
  var RETRY_MS2 = 3e4;
82922
83218
  async function guardRound({ context, client, name: name2, lock, claudePid, session, rush }) {
82923
83219
  const key = session ? sessionKeyOf({ session }) : void 0;
82924
- if (key && await liveElsewhere({ context, key, claudePid })) return true;
83220
+ if (key && await liveElsewhere({ context, key, claudePid, asleepCounts: false })) return true;
82925
83221
  const holder = await holderOf({ path: lock });
82926
83222
  if (holder?.pid !== context.processes.pid) {
82927
83223
  if (!await takeLock({ context, path: lock, claudePid, ...sessionIdOf({ session }) }))
82928
83224
  return true;
82929
83225
  }
82930
83226
  const due = await dueFromSpool({ context, profile: name2, seen: async () => "", pushedToo: true });
82931
- const messages = due.length > 0 ? due : await takeRound({ context, client, claudePid: 0, session });
83227
+ const messages = due.length > 0 ? due : await takeRound2({ context, client, claudePid: 0, session });
82932
83228
  if (messages.length === 0) return false;
82933
83229
  await keepTaken({ context, profile: name2, messages });
82934
83230
  const self2 = await currentNameOf({ context, client, profile: name2 });
@@ -82952,7 +83248,7 @@ async function rushWakeHook({ context, args }) {
82952
83248
  while (context.processes.alive(claudePid)) await context.sleep(WATCH_MS3);
82953
83249
  const { client, name: name2 } = await signedIn({ context, args });
82954
83250
  const noted = statePathOf({ context, kind: "sessions", profile: String(claudePid) });
82955
- const session = await readFile31(noted, "utf8").then(
83251
+ const session = await readFile32(noted, "utf8").then(
82956
83252
  (text2) => JSON.parse(text2),
82957
83253
  () => void 0
82958
83254
  );
@@ -83118,8 +83414,8 @@ async function schedule({ context, args }) {
83118
83414
  }
83119
83415
 
83120
83416
  // src/services/skill-commands.service.ts
83121
- import { readdir as readdir6, readFile as readFile32 } from "node:fs/promises";
83122
- import { join as join21, relative as relative6, resolve as resolve12 } from "node:path";
83417
+ import { readdir as readdir7, readFile as readFile33 } from "node:fs/promises";
83418
+ import { join as join22, relative as relative6, resolve as resolve12 } from "node:path";
83123
83419
  var USAGE16 = `Usage:
83124
83420
  laze skill list [--agent <agentId>]
83125
83421
  laze skill install <catalogue-id> [--as <name>] [--agent <agentId>]
@@ -83136,12 +83432,12 @@ var USAGE16 = `Usage:
83136
83432
  --agent names the agent with a person's key; an agent's key works on its own skills.
83137
83433
  With a person's key, list without --agent shows every agent's skills.`;
83138
83434
  async function folderFiles({ root }) {
83139
- const entries = await readdir6(root, { recursive: true, withFileTypes: true });
83435
+ const entries = await readdir7(root, { recursive: true, withFileTypes: true });
83140
83436
  const files2 = [];
83141
83437
  for (const entry of entries) {
83142
83438
  if (!entry.isFile()) continue;
83143
- const full = join21(entry.parentPath, entry.name);
83144
- files2.push({ path: relative6(root, full), content: await readFile32(full, "utf8") });
83439
+ const full = join22(entry.parentPath, entry.name);
83440
+ files2.push({ path: relative6(root, full), content: await readFile33(full, "utf8") });
83145
83441
  }
83146
83442
  return files2.toSorted((a, b) => a.path.localeCompare(b.path));
83147
83443
  }
@@ -83239,7 +83535,7 @@ async function skillUpdate({ context, args }) {
83239
83535
  if (!name2 || !newName && description === void 0 && !skillMdFile) {
83240
83536
  throw new CliUsageError(USAGE16);
83241
83537
  }
83242
- const skillMd = skillMdFile ? await readFile32(resolve12(context.cwd, skillMdFile), "utf8") : void 0;
83538
+ const skillMd = skillMdFile ? await readFile33(resolve12(context.cwd, skillMdFile), "utf8") : void 0;
83243
83539
  const { client } = await signedIn({ context, args });
83244
83540
  const updated = await client.post("/api/skills/update", {
83245
83541
  name: name2,
@@ -83285,7 +83581,7 @@ async function skill({ context, args }) {
83285
83581
  }
83286
83582
 
83287
83583
  // src/services/slack-commands.service.ts
83288
- import { readFile as readFile33 } from "node:fs/promises";
83584
+ import { readFile as readFile34 } from "node:fs/promises";
83289
83585
  import { resolve as resolve13 } from "node:path";
83290
83586
  var SLACK_USAGE = `Usage (a person's key; Slack stays the source, the bot joins no channel by itself):
83291
83587
  laze slack overview connected Slack workspaces, mirrors, your link
@@ -83333,7 +83629,7 @@ async function secretLines({ context, args }) {
83333
83629
  throw new CliUsageError("A secret never goes in a flag: pipe it on stdin or use --from-file.");
83334
83630
  }
83335
83631
  const file3 = flagText({ args, name: "from-file" });
83336
- const text2 = file3 ? await readFile33(resolve13(context.cwd, file3), "utf8") : await context.readStdin();
83632
+ const text2 = file3 ? await readFile34(resolve13(context.cwd, file3), "utf8") : await context.readStdin();
83337
83633
  return text2.split("\n").map((line) => line.trim()).filter(Boolean);
83338
83634
  }
83339
83635
  async function secretsOf({
@@ -83637,7 +83933,7 @@ async function slack({
83637
83933
  }
83638
83934
 
83639
83935
  // src/services/sso-commands.service.ts
83640
- import { readFile as readFile34 } from "node:fs/promises";
83936
+ import { readFile as readFile35 } from "node:fs/promises";
83641
83937
  var SSO_USAGE = `Usage:
83642
83938
  laze sso domains claimed domains and how each signs in (admins)
83643
83939
  laze sso claim <domain> the TXT record that proves the domain
@@ -83724,7 +84020,7 @@ function refuseSecretFlags({ args }) {
83724
84020
  }
83725
84021
  async function clientSecretOf({ context, args }) {
83726
84022
  const file3 = flagText({ args, name: "from-file" });
83727
- const text2 = file3 ? await readFile34(file3, "utf8") : await context.readStdin();
84023
+ const text2 = file3 ? await readFile35(file3, "utf8") : await context.readStdin();
83728
84024
  const secret = text2.trim();
83729
84025
  if (!secret) throw new CliUsageError("No client secret: pipe it on stdin or use --from-file.");
83730
84026
  return secret;
@@ -84098,7 +84394,7 @@ async function vaultScrub({ context, args }) {
84098
84394
  }
84099
84395
 
84100
84396
  // src/services/whatsapp-business-commands.service.ts
84101
- import { readFile as readFile35 } from "node:fs/promises";
84397
+ import { readFile as readFile36 } from "node:fs/promises";
84102
84398
  import { resolve as resolve14 } from "node:path";
84103
84399
 
84104
84400
  // ../../modules/whatsapp-business/contract/src/whatsapp-business.prices.ts
@@ -84518,7 +84814,7 @@ async function secretsOf2({ context, args }) {
84518
84814
  const fromConnection = flagText({ args, name: "from-vault" });
84519
84815
  if (fromConnection) return { fromConnection };
84520
84816
  const file3 = flagText({ args, name: "from-file" });
84521
- const text2 = file3 ? await readFile35(resolve14(context.cwd, file3), "utf8") : await context.readStdin();
84817
+ const text2 = file3 ? await readFile36(resolve14(context.cwd, file3), "utf8") : await context.readStdin();
84522
84818
  const lines = text2.split("\n").map((line) => line.trim()).filter(Boolean);
84523
84819
  if (lines.length !== 2) {
84524
84820
  throw new CliUsageError(
@@ -85099,7 +85395,7 @@ async function flags({ context, args }) {
85099
85395
  }
85100
85396
 
85101
85397
  // src/services/workspace-commands.service.ts
85102
- import { readFile as readFile36 } from "node:fs/promises";
85398
+ import { readFile as readFile37 } from "node:fs/promises";
85103
85399
  import { resolve as resolve16 } from "node:path";
85104
85400
  var ROLE_NAMES2 = {
85105
85401
  OWNER: "Owner",
@@ -85282,7 +85578,7 @@ var LOGO_USAGE = "Usage: laze workspace logo set <file.png|jpg|webp> | laze work
85282
85578
  async function readLogo({ context, file: file3 }) {
85283
85579
  let bytes;
85284
85580
  try {
85285
- bytes = new Uint8Array(await readFile36(resolve16(context.cwd, file3)));
85581
+ bytes = new Uint8Array(await readFile37(resolve16(context.cwd, file3)));
85286
85582
  } catch {
85287
85583
  throw new CliUsageError(`No file to read at ${file3}.`);
85288
85584
  }
@@ -85589,7 +85885,7 @@ var HELP = `laze: work in a Laze workspace from your terminal or your agent.
85589
85885
  to your vault first; --save saves it without asking,
85590
85886
  --as-is sends it raw, --keychain workspace saves it
85591
85887
  for everyone
85592
- laze inbox [--wait] [--timeout <s>] messages addressed to your agent
85888
+ laze inbox [--wait] [--timeout <s>] [--take] messages addressed to your agent (--take: from outside its bound session)
85593
85889
  laze search <query> [--channel <c>] [--limit <n>] search messages, and Slack when yours is linked
85594
85890
  the sidebar's search: words, "phrases", from:@name in:#channel has: before: after: is:thread
85595
85891
  laze history <channel> [--before <id>] [--limit <n>] a channel's messages, oldest first
@@ -85950,8 +86246,8 @@ async function runCli({
85950
86246
  // src/services/processes.service.ts
85951
86247
  import { execFile as execFile2, spawn as spawn4 } from "node:child_process";
85952
86248
  import { mkdirSync, openSync } from "node:fs";
85953
- import { readFile as readFile37, readlink } from "node:fs/promises";
85954
- import { dirname as dirname20 } from "node:path";
86249
+ import { readFile as readFile38, readlink } from "node:fs/promises";
86250
+ import { dirname as dirname21 } from "node:path";
85955
86251
  import { promisify as promisify2 } from "node:util";
85956
86252
  var run3 = promisify2(execFile2);
85957
86253
  function alive(pid) {
@@ -85964,15 +86260,15 @@ function alive(pid) {
85964
86260
  }
85965
86261
  }
85966
86262
  async function argsOf(pid) {
85967
- const raw = await readFile37(`/proc/${pid}/cmdline`, "utf8").catch(() => void 0);
86263
+ const raw = await readFile38(`/proc/${pid}/cmdline`, "utf8").catch(() => void 0);
85968
86264
  if (raw) return raw.split("\0").filter(Boolean);
85969
86265
  const listed = await run3("ps", ["-o", "args=", "-p", String(pid)]).catch(() => void 0);
85970
86266
  const line = listed?.stdout.trim();
85971
86267
  return line ? line.split(/\s+/) : void 0;
85972
86268
  }
85973
86269
  async function parentOf(pid) {
85974
- const stat3 = await readFile37(`/proc/${pid}/stat`, "utf8").catch(() => void 0);
85975
- const fromStat = stat3 ? Number(stat3.slice(stat3.lastIndexOf(")") + 2).split(" ")[1]) : NaN;
86270
+ const stat5 = await readFile38(`/proc/${pid}/stat`, "utf8").catch(() => void 0);
86271
+ const fromStat = stat5 ? Number(stat5.slice(stat5.lastIndexOf(")") + 2).split(" ")[1]) : NaN;
85976
86272
  if (fromStat > 0) return fromStat;
85977
86273
  const listed = await run3("ps", ["-o", "ppid=", "-p", String(pid)]).catch(() => void 0);
85978
86274
  const parent = Number(listed?.stdout.trim());
@@ -85988,7 +86284,7 @@ async function cwdOf(pid) {
85988
86284
  return line ? line.slice(1) : void 0;
85989
86285
  }
85990
86286
  function spawnDetached({ argv, logPath }) {
85991
- mkdirSync(dirname20(logPath), { recursive: true, mode: 448 });
86287
+ mkdirSync(dirname21(logPath), { recursive: true, mode: 448 });
85992
86288
  const log = openSync(logPath, "a", 384);
85993
86289
  const [program = "", ...rest] = argv;
85994
86290
  const child = spawn4(program, rest, { detached: true, stdio: ["ignore", log, log] });