@lazehq/cli 0.1.30 → 0.1.31

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 +1108 -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.31";
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) {
@@ -68045,396 +67964,21 @@ function rolloutEventOf({
68045
67964
  return held.length > 0 ? { kind: "holds", messageIds: held } : void 0;
68046
67965
  }
68047
67966
 
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
67967
  // 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";
67968
+ import { mkdir as mkdir7, readFile as readFile9, rename as rename3, rm as rm2, stat as stat2, writeFile as writeFile7 } from "node:fs/promises";
68425
67969
  import { homedir as homedir2, hostname as hostname4 } from "node:os";
68426
- import { dirname as dirname9, join as join10 } from "node:path";
67970
+ import { dirname as dirname8, join as join10 } from "node:path";
68427
67971
 
68428
67972
  // 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";
67973
+ import { open as open2, readdir as readdir2 } from "node:fs/promises";
67974
+ import { join as join6 } from "node:path";
68431
67975
  var READ_MS = 1500;
68432
67976
  var KEEP_WORKING_MS = 3e4;
68433
67977
  async function rolloutPathOf({ delivery }) {
68434
- const root = join8(delivery.codexHome, "sessions");
68435
- const files2 = await readdir3(root, { recursive: true }).catch(() => []);
67978
+ const root = join6(delivery.codexHome, "sessions");
67979
+ const files2 = await readdir2(root, { recursive: true }).catch(() => []);
68436
67980
  const file3 = files2.find((name2) => name2.endsWith(`-${delivery.threadId}.jsonl`));
68437
- return file3 ? join8(root, file3) : void 0;
67981
+ return file3 ? join6(root, file3) : void 0;
68438
67982
  }
68439
67983
  async function readFrom({ path, offset }) {
68440
67984
  const handle = await open2(path, "r");
@@ -68520,8 +68064,8 @@ var CodexTurnWatch = class _CodexTurnWatch {
68520
68064
  };
68521
68065
 
68522
68066
  // 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";
68067
+ import { chmod as chmod2, mkdir as mkdir5, readFile as readFile6, writeFile as writeFile5 } from "node:fs/promises";
68068
+ import { dirname as dirname5, join as join7 } from "node:path";
68525
68069
 
68526
68070
  // ../../modules/openclaw/contract/src/openclaw.ts
68527
68071
  var workspaceIdSchema14 = external_exports.string().min(1);
@@ -68749,11 +68293,11 @@ var STOPS = /* @__PURE__ */ new Map([
68749
68293
  [OPENCLAW_RELAY_CLOSE.replaced.code, "another relay for this gateway took over"]
68750
68294
  ]);
68751
68295
  function relaysPathOf({ context }) {
68752
- return join9(dirname8(context.environment.configPath), "connect", "openclaw-relays.json");
68296
+ return join7(dirname5(context.environment.configPath), "connect", "openclaw-relays.json");
68753
68297
  }
68754
68298
  async function readRelays({ context }) {
68755
68299
  try {
68756
- return JSON.parse(await readFile9(relaysPathOf({ context }), "utf8"));
68300
+ return JSON.parse(await readFile6(relaysPathOf({ context }), "utf8"));
68757
68301
  } catch {
68758
68302
  return {};
68759
68303
  }
@@ -68763,8 +68307,8 @@ async function saveRelays({
68763
68307
  relays
68764
68308
  }) {
68765
68309
  const path = relaysPathOf({ context });
68766
- await mkdir8(dirname8(path), { recursive: true, mode: 448 });
68767
- await writeFile8(path, `${JSON.stringify(relays, null, 2)}
68310
+ await mkdir5(dirname5(path), { recursive: true, mode: 448 });
68311
+ await writeFile5(path, `${JSON.stringify(relays, null, 2)}
68768
68312
  `, { mode: 384 });
68769
68313
  await chmod2(path, 384);
68770
68314
  }
@@ -68948,16 +68492,148 @@ var RelayLoops = class _RelayLoops {
68948
68492
  }
68949
68493
  };
68950
68494
 
68495
+ // src/services/rush-listeners.service.ts
68496
+ import { readFile as readFile8, readdir as readdir3, stat } from "node:fs/promises";
68497
+ import { dirname as dirname7, join as join9 } from "node:path";
68498
+
68499
+ // src/services/rush-host.service.ts
68500
+ import { mkdir as mkdir6, readFile as readFile7, writeFile as writeFile6 } from "node:fs/promises";
68501
+ import { dirname as dirname6, join as join8 } from "node:path";
68502
+ async function rushAboveOf({
68503
+ context,
68504
+ from = context.processes.pid
68505
+ }) {
68506
+ let pid = await context.processes.parentOf(from);
68507
+ for (let depth = 0; pid !== void 0 && pid > 1 && depth < 16; depth += 1) {
68508
+ const rush = rushSessionOf({ parentArgs: await context.processes.argsOf(pid) });
68509
+ if (rush) return rush;
68510
+ pid = await context.processes.parentOf(pid);
68511
+ }
68512
+ return void 0;
68513
+ }
68514
+ function guardPathOf({ context, claudePid }) {
68515
+ return join8(dirname6(context.environment.configPath), "rush-guards", `${claudePid}.json`);
68516
+ }
68517
+ async function startRushGuard({
68518
+ context,
68519
+ profile,
68520
+ claudePid,
68521
+ rush
68522
+ }) {
68523
+ const path = guardPathOf({ context, claudePid });
68524
+ const holder = await guardHolderOf({ path });
68525
+ if (holder && context.processes.alive(holder.pid)) return;
68526
+ const flags2 = ["--profile", profile, "--claude-pid", String(claudePid), "--rush-id", rush.id];
68527
+ const argv = [...context.program, "hook", "rush-wake", ...flags2, "--rush-program", rush.program];
68528
+ const logPath = join8(dirname6(context.environment.configPath), "rush-guards", "guard.log");
68529
+ context.processes.spawnDetached({ argv: ["sh", "-c", '"$@" &', "sh", ...argv], logPath });
68530
+ }
68531
+ async function claimRushGuard({
68532
+ context,
68533
+ claudePid
68534
+ }) {
68535
+ const path = guardPathOf({ context, claudePid });
68536
+ const holder = await guardHolderOf({ path });
68537
+ const self2 = context.processes.pid;
68538
+ if (holder && holder.pid !== self2 && context.processes.alive(holder.pid)) return false;
68539
+ await mkdir6(dirname6(path), { recursive: true, mode: 448 });
68540
+ await writeFile6(path, JSON.stringify({ pid: self2, claudePid }), { mode: 384 });
68541
+ return true;
68542
+ }
68543
+ function guardHolderOf({ path }) {
68544
+ return readFile7(path, "utf8").then(
68545
+ (text2) => JSON.parse(text2),
68546
+ () => void 0
68547
+ );
68548
+ }
68549
+
68550
+ // src/services/rush-listeners.service.ts
68551
+ async function jsonOf(path) {
68552
+ return readFile8(path, "utf8").then(
68553
+ (text2) => JSON.parse(text2),
68554
+ () => void 0
68555
+ );
68556
+ }
68557
+ async function notesOf({ context }) {
68558
+ const folder = dirname7(statePathOf({ context, kind: "sessions", profile: "x" }));
68559
+ const files2 = await readdir3(folder).catch(() => []);
68560
+ const notes = await Promise.all(
68561
+ files2.map(async (file3) => {
68562
+ const pid = Number(file3.replace(/\.json$/, ""));
68563
+ const session = await jsonOf(join9(folder, file3));
68564
+ const at = await stat(join9(folder, file3)).then(
68565
+ (info) => info.mtimeMs,
68566
+ () => 0
68567
+ );
68568
+ return pid && session ? [{ pid, key: sessionKeyOf({ session }), at }] : [];
68569
+ })
68570
+ );
68571
+ return notes.flat().toSorted((a, b) => b.at - a.at);
68572
+ }
68573
+ async function rushListenersOf({
68574
+ context
68575
+ }) {
68576
+ const bound = Object.entries((await context.store.read()).sessions ?? {}).filter(
68577
+ ([key]) => key.startsWith("claude-code:")
68578
+ );
68579
+ if (bound.length === 0) return [];
68580
+ const listed = await rushListingOf({ context });
68581
+ if (listed === void 0) return [];
68582
+ const sessions = rushListedOf({ listed });
68583
+ const notes = await notesOf({ context });
68584
+ const rows = [];
68585
+ for (const [key, profile] of bound) {
68586
+ const one = sessions.find((each) => `claude-code:${each.sessionId}` === key);
68587
+ if (!one?.id) continue;
68588
+ const pids = notes.filter((note) => note.key === key).map((note) => note.pid);
68589
+ const listenerPid = await listenerOf({ context, key, profile, pids });
68590
+ const lastClaudePid = pids.find((pid) => !context.processes.alive(pid));
68591
+ rows.push({
68592
+ profile,
68593
+ rushId: one.id,
68594
+ standing: rushStandingOf({ one }),
68595
+ ...listenerPid ? { listenerPid } : {},
68596
+ ...lastClaudePid ? { lastClaudePid } : {}
68597
+ });
68598
+ }
68599
+ return rows;
68600
+ }
68601
+ async function listenerOf({
68602
+ context,
68603
+ key,
68604
+ profile,
68605
+ pids
68606
+ }) {
68607
+ for (const claudePid of pids) {
68608
+ const guard = await jsonOf(guardPathOf({ context, claudePid }));
68609
+ if (guard && context.processes.alive(guard.pid)) return guard.pid;
68610
+ }
68611
+ const lock = statePathOf({ context, kind: "waiters", profile });
68612
+ const waiter = await jsonOf(lock);
68613
+ const mine4 = waiter?.sessionId === key.slice(key.indexOf(":") + 1);
68614
+ return waiter && mine4 && context.processes.alive(waiter.pid) ? waiter.pid : void 0;
68615
+ }
68616
+ async function rearmRushGuards({ context }) {
68617
+ let started = 0;
68618
+ for (const row of await rushListenersOf({ context })) {
68619
+ if (row.standing !== "asleep" || row.listenerPid || !row.lastClaudePid) continue;
68620
+ const rush = { id: row.rushId, program: "rush" };
68621
+ await startRushGuard({ context, profile: row.profile, claudePid: row.lastClaudePid, rush });
68622
+ started += 1;
68623
+ }
68624
+ return started;
68625
+ }
68626
+
68951
68627
  // src/services/connect-delivery.service.ts
68952
68628
  function connectFolderOf({ context }) {
68953
- return join10(dirname9(context.environment.configPath), "connect");
68629
+ return join10(dirname8(context.environment.configPath), "connect");
68954
68630
  }
68955
68631
  function runStatePathOf({ context }) {
68956
68632
  return join10(connectFolderOf({ context }), "run.json");
68957
68633
  }
68958
68634
  async function readJson({ path }) {
68959
68635
  try {
68960
- return JSON.parse(await readFile10(path, "utf8"));
68636
+ return JSON.parse(await readFile9(path, "utf8"));
68961
68637
  } catch {
68962
68638
  return void 0;
68963
68639
  }
@@ -68965,9 +68641,18 @@ async function readJson({ path }) {
68965
68641
  async function runStateOf({ context }) {
68966
68642
  return readJson({ path: runStatePathOf({ context }) });
68967
68643
  }
68968
- var ROUND_SECONDS2 = 50;
68644
+ var ROUND_SECONDS = 50;
68969
68645
  var REFRESH_MS = 3e4;
68970
68646
  var MAX_RETRY_SECONDS2 = 60;
68647
+ var CLI_CHANGED_EXIT = 75;
68648
+ async function cliStampOf({ context }) {
68649
+ const file3 = context.program.at(-1);
68650
+ if (!file3) return "";
68651
+ return stat2(file3).then(
68652
+ (info) => `${info.mtimeMs}:${info.size}`,
68653
+ () => ""
68654
+ );
68655
+ }
68971
68656
  var CodexQueueError = class extends Error {
68972
68657
  constructor(reason, detail) {
68973
68658
  super(detail);
@@ -68998,7 +68683,7 @@ async function queueInCodex({
68998
68683
  throw new CodexQueueError(codexQueueFailureOf({ stderr: stderr2 }), stderr2.trim() || `exit ${code}`);
68999
68684
  }
69000
68685
  }
69001
- async function takeRound2({
68686
+ async function takeRound({
69002
68687
  client,
69003
68688
  signal,
69004
68689
  delivery
@@ -69010,7 +68695,7 @@ async function takeRound2({
69010
68695
  host: hostname4()
69011
68696
  };
69012
68697
  try {
69013
- return await client.withHeaders(sessionHeadersOf({ session })).post("/api/agents/me/inbox", { waitSeconds: ROUND_SECONDS2 }, { signal });
68698
+ return await client.withHeaders(sessionHeadersOf({ session })).post("/api/agents/me/inbox", { waitSeconds: ROUND_SECONDS }, { signal });
69014
68699
  } catch (error62) {
69015
68700
  if (signal.aborted) return [];
69016
68701
  throw error62;
@@ -69025,7 +68710,7 @@ async function deliverRound({
69025
68710
  watch
69026
68711
  }) {
69027
68712
  const kept = await dueFromSpool({ context, profile, seen: async () => "", pushedToo: true });
69028
- const messages = kept.length > 0 ? kept : await takeRound2({ client, signal, delivery });
68713
+ const messages = kept.length > 0 ? kept : await takeRound({ client, signal, delivery });
69029
68714
  if (messages.length === 0) return 0;
69030
68715
  if (kept.length === 0) await keepTaken({ context, profile, messages });
69031
68716
  const self2 = await currentNameOf({ context, client, profile });
@@ -69108,9 +68793,9 @@ async function serveRounds({
69108
68793
  }
69109
68794
  var saves = 0;
69110
68795
  async function save(run4) {
69111
- await mkdir9(dirname9(run4.path), { recursive: true, mode: 448 });
68796
+ await mkdir7(dirname8(run4.path), { recursive: true, mode: 448 });
69112
68797
  const temporary = `${run4.path}.${run4.self}.${saves += 1}.tmp`;
69113
- await writeFile9(temporary, JSON.stringify(run4.state));
68798
+ await writeFile7(temporary, JSON.stringify(run4.state));
69114
68799
  await rename3(temporary, run4.path);
69115
68800
  }
69116
68801
  async function holdsLock(run4) {
@@ -69165,6 +68850,7 @@ async function runConnectLoop({ context }) {
69165
68850
  await save(run4);
69166
68851
  context.out(`laze connect run: pid ${self2}
69167
68852
  `);
68853
+ const startedFrom = await cliStampOf({ context });
69168
68854
  const relays = RelayLoops.create({
69169
68855
  context,
69170
68856
  report: async (connectionId, relay2) => {
@@ -69177,26 +68863,31 @@ async function runConnectLoop({ context }) {
69177
68863
  while (await holdsLock(run4)) {
69178
68864
  await syncLoops(run4);
69179
68865
  await relays.sync();
68866
+ await rearmRushGuards({ context }).catch((error62) => {
68867
+ context.err(`laze connect: no rush guard check this round: ${String(error62)}
68868
+ `);
68869
+ });
69180
68870
  await save(run4);
69181
68871
  await context.sleep(REFRESH_MS);
68872
+ if (await cliStampOf({ context }) !== startedFrom) {
68873
+ context.out("laze connect run: the CLI changed on disk, exiting so the new one starts\n");
68874
+ return CLI_CHANGED_EXIT;
68875
+ }
69182
68876
  }
69183
68877
  } finally {
69184
68878
  await relays.stopAll();
69185
68879
  for (const current2 of run4.served.values()) current2.stop.abort();
69186
68880
  await Promise.all([...run4.served.values()].map((current2) => current2.done));
69187
- if (await holdsLock(run4)) await rm4(run4.path, { force: true });
68881
+ if (await holdsLock(run4)) await rm2(run4.path, { force: true });
69188
68882
  }
69189
68883
  return 0;
69190
68884
  }
69191
68885
 
69192
68886
  // 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.
68887
+ 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
68888
 
69198
68889
  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
68890
+ laze connect status whether it runs, which agents it serves, who listens per rush session
69200
68891
  laze connect stop stop it until the next login or install
69201
68892
  laze connect uninstall stop it and remove it
69202
68893
  laze connect run the service itself, in the foreground
@@ -69211,7 +68902,7 @@ function logPathOf({ context }) {
69211
68902
  return join11(connectFolderOf({ context }), "connect.log");
69212
68903
  }
69213
68904
  function homeOf({ context }) {
69214
- return context.environment.inherited.HOME ?? dirname10(dirname10(context.environment.configPath));
68905
+ return context.environment.inherited.HOME ?? dirname9(dirname9(context.environment.configPath));
69215
68906
  }
69216
68907
  function serviceNameOf({ context }) {
69217
68908
  const { configPath } = context.environment;
@@ -69240,8 +68931,8 @@ async function installSystemd({ context }) {
69240
68931
  const env = context.environment.inherited;
69241
68932
  const base = env.XDG_CONFIG_HOME || join11(homeOf({ context }), ".config");
69242
68933
  const file3 = join11(base, "systemd", "user", `${name2}.service`);
69243
- await mkdir10(dirname10(file3), { recursive: true });
69244
- await writeFile10(
68934
+ await mkdir8(dirname9(file3), { recursive: true });
68935
+ await writeFile8(
69245
68936
  file3,
69246
68937
  systemdUnitOf({ argv: runArgvOf({ context }), env: serviceEnvOf({ context }) })
69247
68938
  );
@@ -69256,8 +68947,8 @@ async function installLaunchd({ context }) {
69256
68947
  const label2 = `ai.laze.${name2}`;
69257
68948
  const file3 = join11(homeOf({ context }), "Library", "LaunchAgents", `${label2}.plist`);
69258
68949
  const log = logPathOf({ context });
69259
- await mkdir10(dirname10(file3), { recursive: true });
69260
- await writeFile10(
68950
+ await mkdir8(dirname9(file3), { recursive: true });
68951
+ await writeFile8(
69261
68952
  file3,
69262
68953
  launchAgentOf({
69263
68954
  label: label2,
@@ -69309,10 +69000,16 @@ async function installConnectService({ context }) {
69309
69000
  const manager = await managerOf({ context });
69310
69001
  const install = { systemd: installSystemd, launchd: installLaunchd, detached: installDetached };
69311
69002
  const installed = await install[manager]({ context });
69312
- await mkdir10(dirname10(path), { recursive: true, mode: 448 });
69313
- await writeFile10(path, JSON.stringify(installed));
69003
+ await mkdir8(dirname9(path), { recursive: true, mode: 448 });
69004
+ await writeFile8(path, JSON.stringify(installed));
69314
69005
  return describeInstalled({ installed });
69315
69006
  }
69007
+ async function ensureConnectService({ context }) {
69008
+ const running = await runStateOf({ context });
69009
+ if (running && context.processes.alive(running.pid)) return false;
69010
+ await installConnectService({ context });
69011
+ return true;
69012
+ }
69316
69013
  function describeInstalled({ installed }) {
69317
69014
  switch (installed.manager) {
69318
69015
  case "systemd":
@@ -69340,6 +69037,8 @@ async function status({ context }) {
69340
69037
  `
69341
69038
  );
69342
69039
  }
69040
+ for (const row of await rushListenersOf({ context })) context.out(`${rushLineOf({ row })}
69041
+ `);
69343
69042
  const config2 = await context.store.read();
69344
69043
  const linked = Object.entries(config2.profiles).filter(([, profile]) => profile.delivery);
69345
69044
  if (linked.length === 0) {
@@ -69352,6 +69051,13 @@ async function status({ context }) {
69352
69051
  `);
69353
69052
  }
69354
69053
  }
69054
+ function rushLineOf({ row }) {
69055
+ const head = `${row.profile} Claude Code in rush ${row.rushId} ${row.standing}`;
69056
+ if (row.standing === "awake") return `${head}, its Claude Code delivers`;
69057
+ if (row.standing === "stopped") return `${head}, gets messages when rush starts it again`;
69058
+ if (row.listenerPid) return `${head}, guard pid ${row.listenerPid}`;
69059
+ return `${head}, NO LISTENER: messages wait in Laze; \`laze connect install\` brings a guard back`;
69060
+ }
69355
69061
  async function stop({ context }) {
69356
69062
  const installed = await readJson({ path: installedPathOf({ context }) });
69357
69063
  if (!installed) {
@@ -69376,11 +69082,11 @@ async function uninstall({ context }) {
69376
69082
  command: ["systemctl", "--user", "disable", `${installed.name}.service`]
69377
69083
  });
69378
69084
  }
69379
- if (installed.file) await rm5(installed.file, { force: true });
69085
+ if (installed.file) await rm3(installed.file, { force: true });
69380
69086
  if (installed.manager === "systemd") {
69381
69087
  await run({ context, command: ["systemctl", "--user", "daemon-reload"] });
69382
69088
  }
69383
- await rm5(path, { force: true });
69089
+ await rm3(path, { force: true });
69384
69090
  context.out(
69385
69091
  `Removed the connect service (${installed.manager}, ${installed.name}). Linked Codex agents get no messages until \`laze connect install\`.
69386
69092
  `
@@ -69405,6 +69111,571 @@ async function connectService({ context, args }) {
69405
69111
  }
69406
69112
  }
69407
69113
 
69114
+ // src/services/claude-wait.service.ts
69115
+ var ROUND_SECONDS2 = 50;
69116
+ var WATCH_MS = 2e3;
69117
+ var CHANNEL_CHECK_MS = 5e3;
69118
+ async function holderOf({ path }) {
69119
+ return readFile10(path, "utf8").then(
69120
+ (text2) => JSON.parse(text2),
69121
+ () => void 0
69122
+ );
69123
+ }
69124
+ async function holderClaudeOf({ context, holder }) {
69125
+ if (holder.claudePid) return holder.claudePid;
69126
+ return (await nearestHarnessOf({ context, from: holder.pid }))?.pid;
69127
+ }
69128
+ async function takeLock({
69129
+ context,
69130
+ path,
69131
+ sessionId,
69132
+ claudePid,
69133
+ preempt = false
69134
+ }) {
69135
+ const holder = await holderOf({ path });
69136
+ const self2 = context.processes.pid;
69137
+ if (holder && holder.pid !== self2 && context.processes.alive(holder.pid)) {
69138
+ const served = await holderClaudeOf({ context, holder });
69139
+ const mine4 = preempt && served === claudePid && !holder.monitor;
69140
+ if (served && context.processes.alive(served) && !mine4) return false;
69141
+ context.processes.stop(holder.pid);
69142
+ }
69143
+ await mkdir9(dirname10(path), { recursive: true, mode: 448 });
69144
+ await writeFile9(
69145
+ path,
69146
+ JSON.stringify({
69147
+ pid: self2,
69148
+ claudePid,
69149
+ ...sessionId ? { sessionId } : {},
69150
+ ...preempt ? { monitor: true } : {}
69151
+ })
69152
+ );
69153
+ return true;
69154
+ }
69155
+ async function channelLive({ context, profile }) {
69156
+ const holder = await holderOf({ path: statePathOf({ context, kind: "channels", profile }) });
69157
+ return holder !== void 0 && context.processes.alive(holder.pid);
69158
+ }
69159
+ async function takeRound2({
69160
+ context,
69161
+ client,
69162
+ claudePid,
69163
+ session
69164
+ }) {
69165
+ const controller = new AbortController();
69166
+ const { signal } = controller;
69167
+ const watch = (async () => {
69168
+ while (!signal.aborted) {
69169
+ await context.sleep(WATCH_MS, signal);
69170
+ if (claudePid && !context.processes.alive(claudePid)) controller.abort();
69171
+ }
69172
+ })();
69173
+ try {
69174
+ return await forSession({ client, session }).post(
69175
+ "/api/agents/me/inbox",
69176
+ { waitSeconds: ROUND_SECONDS2 },
69177
+ { signal }
69178
+ );
69179
+ } catch (error62) {
69180
+ if (signal.aborted) return [];
69181
+ throw error62;
69182
+ } finally {
69183
+ controller.abort();
69184
+ await watch;
69185
+ }
69186
+ }
69187
+ async function roundOf({ context, client, name: name2, lock, claudePid, session, seen }) {
69188
+ if ((await holderOf({ path: lock }))?.pid !== context.processes.pid) return void 0;
69189
+ if (claudePid && !context.processes.alive(claudePid)) return void 0;
69190
+ const due = await dueFromSpool({ context, profile: name2, seen, pushedToo: true });
69191
+ if (due.length > 0) return due;
69192
+ if (await channelLive({ context, profile: name2 })) {
69193
+ await context.sleep(CHANNEL_CHECK_MS);
69194
+ return [];
69195
+ }
69196
+ const taken = await takeRound2({ context, client, claudePid, session });
69197
+ if (taken.length === 0) {
69198
+ await context.sleep(1e3);
69199
+ return [];
69200
+ }
69201
+ await keepTaken({ context, profile: name2, messages: taken });
69202
+ return taken;
69203
+ }
69204
+ async function claudePidOf({ context }) {
69205
+ const harness = await nearestHarnessOf({ context });
69206
+ if (harness?.harness === "claude-code") return harness.pid;
69207
+ return await context.processes.parentOf(context.processes.pid) ?? 0;
69208
+ }
69209
+ async function settleRound(round) {
69210
+ const { context, client, name: name2, session } = round;
69211
+ const messages = await roundOf(round).catch(async (error62) => {
69212
+ const refused = await notBoundNotice({
69213
+ context,
69214
+ client: forSession({ client, session }),
69215
+ session,
69216
+ error: error62,
69217
+ profile: name2
69218
+ });
69219
+ if (!refused) throw error62;
69220
+ return refused;
69221
+ });
69222
+ if (messages === void 0) return 0;
69223
+ if (!Array.isArray(messages)) {
69224
+ if (messages.rebound) return "again";
69225
+ if (!messages.notice) return 0;
69226
+ context.err(`${messages.notice}
69227
+ `);
69228
+ return 2;
69229
+ }
69230
+ if (messages.length === 0) return "again";
69231
+ await turnStarted({ context, client, agent: name2, messages }).catch(() => void 0);
69232
+ const self2 = await currentNameOf({ context, client, profile: name2 });
69233
+ context.err(`${hookContextOf({ messages, self: self2 })}
69234
+ `);
69235
+ const messageIds = messages.map((message2) => message2.messageId);
69236
+ await dropFromSpool({ context, profile: name2, messageIds });
69237
+ return 2;
69238
+ }
69239
+ async function waitForMessages({ context, args }) {
69240
+ const raw = await context.readStdin();
69241
+ const input2 = raw.trim() ? JSON.parse(raw) : {};
69242
+ const session = sessionOf({ context, harness: "claude-code", sessionId: input2.session_id });
69243
+ const claudePid = await claudePidOf({ context });
69244
+ const asked = await pluginHookArgs({ context, args, session, claudePid });
69245
+ if (!asked) return 0;
69246
+ const named = await sessionProfileArgs({ context, args: asked, session });
69247
+ const { client, name: name2 } = await signedIn({ context, args: named });
69248
+ await rememberSession({ context, claudePid, session });
69249
+ const rush = rushSessionOf({
69250
+ parentArgs: await context.processes.argsOf(await context.processes.parentOf(claudePid) ?? 0)
69251
+ });
69252
+ if (rush) await startRushGuard({ context, profile: name2, claudePid, rush });
69253
+ if (rush) await healRushDelivery({ context });
69254
+ const lock = statePathOf({ context, kind: "waiters", profile: name2 });
69255
+ if (!await takeLock({ context, path: lock, sessionId: input2.session_id, claudePid })) return 0;
69256
+ const seen = () => input2.transcript_path ? readFile10(input2.transcript_path, "utf8") : Promise.resolve("");
69257
+ const deadline = context.nowMs() + (WAIT_HOOK_TIMEOUT_SECONDS - 60) * 1e3;
69258
+ try {
69259
+ while (context.nowMs() < deadline) {
69260
+ const code = await settleRound({ context, client, name: name2, lock, claudePid, session, seen });
69261
+ if (code !== "again") return code;
69262
+ }
69263
+ return 0;
69264
+ } finally {
69265
+ if ((await holderOf({ path: lock }))?.pid === context.processes.pid)
69266
+ await rm4(lock, { force: true });
69267
+ }
69268
+ }
69269
+ async function healRushDelivery({ context }) {
69270
+ await rearmRushGuards({ context }).catch((error62) => {
69271
+ context.err(`laze: could not check the other rush sessions: ${String(error62)}
69272
+ `);
69273
+ });
69274
+ await ensureConnectService({ context }).catch((error62) => {
69275
+ context.err(`laze: could not start the connect service: ${String(error62)}
69276
+ `);
69277
+ });
69278
+ }
69279
+ async function waitHook({ context, args }) {
69280
+ try {
69281
+ return await waitForMessages({ context, args });
69282
+ } catch (error62) {
69283
+ context.err(`laze: the background waiter stopped: ${String(error62)}
69284
+ `);
69285
+ return 0;
69286
+ }
69287
+ }
69288
+ async function monitorServes({
69289
+ context,
69290
+ profile,
69291
+ claudePid
69292
+ }) {
69293
+ const holder = await holderOf({ path: statePathOf({ context, kind: "waiters", profile }) });
69294
+ if (!holder?.monitor || !context.processes.alive(holder.pid)) return false;
69295
+ return await holderClaudeOf({ context, holder }) === claudePid;
69296
+ }
69297
+
69298
+ // src/services/codex-link.service.ts
69299
+ import { createReadStream } from "node:fs";
69300
+ import { readdir as readdir5, rm as rm6, stat as stat4 } from "node:fs/promises";
69301
+ import { join as join13, resolve as resolve3 } from "node:path";
69302
+ import { createInterface as createInterface2 } from "node:readline";
69303
+
69304
+ // src/services/codex-adopt.service.ts
69305
+ import { spawn as spawn2 } from "node:child_process";
69306
+ import { mkdir as mkdir10, readdir as readdir4, readFile as readFile11, rm as rm5, stat as stat3, writeFile as writeFile10 } from "node:fs/promises";
69307
+ import { dirname as dirname11, join as join12 } from "node:path";
69308
+ import { createInterface } from "node:readline";
69309
+
69310
+ // src/rules/codex-requests.rules.ts
69311
+ var DECLINED_DECISION = {
69312
+ "item/commandExecution/requestApproval": "decline",
69313
+ "item/fileChange/requestApproval": "decline",
69314
+ execCommandApproval: "denied",
69315
+ applyPatchApproval: "denied"
69316
+ };
69317
+ function codexRequestReplyOf({ method }) {
69318
+ const decision = DECLINED_DECISION[method];
69319
+ if (decision) return { result: { decision } };
69320
+ if (method === "item/permissions/requestApproval") {
69321
+ return { result: { permissions: {}, scope: "turn" } };
69322
+ }
69323
+ if (method === "mcpServer/elicitation/request") {
69324
+ return { result: { action: "decline", content: null } };
69325
+ }
69326
+ return { error: { code: -32601, message: `${method} is not supported here` } };
69327
+ }
69328
+
69329
+ // src/services/codex-adopt.service.ts
69330
+ function record3(value) {
69331
+ return typeof value === "object" && value !== null ? value : {};
69332
+ }
69333
+ function absorbTurnEvent({ result, message: message2 }) {
69334
+ const params = record3(message2.params);
69335
+ if (message2.method === "item/completed") {
69336
+ const item = record3(params.item);
69337
+ if (item.type === "agentMessage" && typeof item.text === "string") result.answer = item.text;
69338
+ return;
69339
+ }
69340
+ if (message2.method !== "thread/tokenUsage/updated") return;
69341
+ const usage = record3(params.tokenUsage);
69342
+ const total = record3(usage.last).totalTokens;
69343
+ if (typeof total === "number") result.contextTokens = total;
69344
+ const window2 = usage.modelContextWindow;
69345
+ if (typeof window2 === "number" && window2 > 0) result.contextWindow = window2;
69346
+ }
69347
+ var TURN_HEARTBEAT_MS = 1e4;
69348
+ var CodexAppServer = class _CodexAppServer {
69349
+ constructor(child) {
69350
+ this.child = child;
69351
+ createInterface({ input: child.stdout }).on("line", (line) => this.receive(line));
69352
+ }
69353
+ child;
69354
+ #nextId = 0;
69355
+ #pending = /* @__PURE__ */ new Map();
69356
+ #listeners = /* @__PURE__ */ new Set();
69357
+ static start({
69358
+ codexHome,
69359
+ inherited
69360
+ }) {
69361
+ const env = { ...inherited, CODEX_HOME: codexHome };
69362
+ return new _CodexAppServer(spawn2("codex", ["app-server"], { env, stdio: "pipe" }));
69363
+ }
69364
+ async call(method, params) {
69365
+ const id = ++this.#nextId;
69366
+ const reply2 = await new Promise((resolve17) => {
69367
+ this.#pending.set(id, resolve17);
69368
+ this.write({ id, method, params });
69369
+ });
69370
+ if (reply2.error !== void 0) throw new Error(`${method}: ${JSON.stringify(reply2.error)}`);
69371
+ return record3(reply2.result);
69372
+ }
69373
+ notify(method) {
69374
+ this.write({ method });
69375
+ }
69376
+ /** Starts one turn; `done` settles when it completes, keeping its last agent message. */
69377
+ async startTurn({ threadId, text: text2 }) {
69378
+ const result = { answer: "" };
69379
+ const done = new Promise((resolve17) => {
69380
+ const listen = (message2) => {
69381
+ absorbTurnEvent({ result, message: message2 });
69382
+ if (message2.method !== "turn/completed") return;
69383
+ this.#listeners.delete(listen);
69384
+ resolve17(result);
69385
+ };
69386
+ this.#listeners.add(listen);
69387
+ });
69388
+ const started = await this.call("turn/start", {
69389
+ threadId,
69390
+ input: [{ type: "text", text: text2, text_elements: [] }]
69391
+ });
69392
+ const turnId = record3(started.turn).id;
69393
+ return { turnId: typeof turnId === "string" ? turnId : null, done };
69394
+ }
69395
+ stop() {
69396
+ this.child.kill("SIGTERM");
69397
+ }
69398
+ write(message2) {
69399
+ this.child.stdin.write(`${JSON.stringify(message2)}
69400
+ `);
69401
+ }
69402
+ receive(line) {
69403
+ let message2;
69404
+ try {
69405
+ message2 = record3(JSON.parse(line));
69406
+ } catch {
69407
+ return;
69408
+ }
69409
+ if (typeof message2.id === "number" && message2.method === void 0) {
69410
+ this.#pending.get(message2.id)?.(message2);
69411
+ this.#pending.delete(message2.id);
69412
+ return;
69413
+ }
69414
+ if (message2.method !== void 0 && message2.id !== void 0) {
69415
+ this.write({
69416
+ id: message2.id,
69417
+ ...codexRequestReplyOf({
69418
+ method: typeof message2.method === "string" ? message2.method : ""
69419
+ })
69420
+ });
69421
+ return;
69422
+ }
69423
+ for (const listen of this.#listeners) listen(message2);
69424
+ }
69425
+ };
69426
+ async function newestThreadId({ codexHome }) {
69427
+ const root = join12(codexHome, "sessions");
69428
+ const files2 = await readdir4(root, { recursive: true }).catch(() => []);
69429
+ const rollouts = files2.filter((file3) => /rollout-.*\.jsonl$/.test(file3));
69430
+ const dated = await Promise.all(
69431
+ rollouts.map(async (file3) => ({ file: file3, at: (await stat3(join12(root, file3))).mtimeMs }))
69432
+ );
69433
+ const newest = dated.toSorted((a, b) => b.at - a.at)[0]?.file ?? "";
69434
+ 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);
69435
+ if (!id?.[1]) throw new CliUsageError("No Codex session found: pass --thread <id>.");
69436
+ return id[1];
69437
+ }
69438
+ function promptOf({ message: message2, self: self2 }) {
69439
+ return [
69440
+ `A message reached you in the Laze workspace${selfClauseOf({ self: self2 })}. Answer it; your final`,
69441
+ "message is posted as your reply in its thread.",
69442
+ "",
69443
+ formatInboxMessage({ message: message2 }).split("\n").slice(0, -1).join("\n")
69444
+ ].join("\n");
69445
+ }
69446
+ async function heartbeat({
69447
+ client,
69448
+ message: message2,
69449
+ state
69450
+ }) {
69451
+ return client.post("/api/agents/me/turn", {
69452
+ channelId: message2.channelId,
69453
+ threadRootId: message2.threadRootId,
69454
+ state,
69455
+ ...state === "working" ? { messageId: message2.messageId } : {}
69456
+ }).catch(() => void 0);
69457
+ }
69458
+ async function watchTurn({
69459
+ context,
69460
+ client,
69461
+ codex,
69462
+ threadId,
69463
+ turn,
69464
+ message: message2
69465
+ }) {
69466
+ const finished = new AbortController();
69467
+ void turn.done.then(() => finished.abort());
69468
+ while (!finished.signal.aborted) {
69469
+ const beat2 = await heartbeat({ client, message: message2, state: "working" });
69470
+ if (beat2?.stop && turn.turnId) {
69471
+ await codex.call("turn/interrupt", { threadId, turnId: turn.turnId }).catch(() => void 0);
69472
+ return beat2.stoppedBy ?? "someone";
69473
+ }
69474
+ await context.sleep(TURN_HEARTBEAT_MS, finished.signal);
69475
+ }
69476
+ return void 0;
69477
+ }
69478
+ async function answer({
69479
+ context,
69480
+ codex,
69481
+ client,
69482
+ threadId,
69483
+ message: message2,
69484
+ profile
69485
+ }) {
69486
+ const self2 = await currentNameOf({ context, client, profile });
69487
+ const running = await codex.startTurn({ threadId, text: promptOf({ message: message2, self: self2 }) });
69488
+ const stoppedBy = await watchTurn({ context, client, codex, threadId, turn: running, message: message2 });
69489
+ const turn = await running.done;
69490
+ await heartbeat({ client, message: message2, state: "idle" });
69491
+ if (stoppedBy !== void 0) return `(stopped by ${stoppedBy})`;
69492
+ const body = turn.answer.trim() || "(no answer)";
69493
+ await client.post("/api/agents/me/replies", { messageId: message2.messageId, body });
69494
+ if (turn.contextTokens !== void 0) {
69495
+ await client.post("/api/agents/me/activity", {
69496
+ sessionId: threadId,
69497
+ contextTokens: turn.contextTokens,
69498
+ ...turn.contextWindow ? { contextWindow: turn.contextWindow } : {}
69499
+ });
69500
+ }
69501
+ return body;
69502
+ }
69503
+ var MAX_RESTART_WAIT_SECONDS = 60;
69504
+ var HEALTHY_RUN_MS = 6e4;
69505
+ async function recordOf({ path }) {
69506
+ return readFile11(path, "utf8").then(
69507
+ (text2) => JSON.parse(text2),
69508
+ () => void 0
69509
+ );
69510
+ }
69511
+ function threadFlag({ thread: thread2 }) {
69512
+ return thread2 ? ["--thread", thread2] : [];
69513
+ }
69514
+ async function startAdoptInBackground({
69515
+ context,
69516
+ args,
69517
+ profile,
69518
+ laze
69519
+ }) {
69520
+ const thread2 = flagText({ args, name: "thread" }) || context.environment.inherited.CODEX_THREAD_ID || null;
69521
+ const path = statePathOf({ context, kind: "adopt", profile });
69522
+ const log = statePathOf({ context, kind: "adopt", profile, extension: "log" });
69523
+ const running = await recordOf({ path });
69524
+ if (running) context.processes.stop(running.pid);
69525
+ const adopt = ["adopt", "codex", "--profile", profile, ...threadFlag({ thread: thread2 })];
69526
+ const argv = [...context.program, ...adopt, "--supervise"];
69527
+ const pid = context.processes.spawnDetached({ argv, logPath: log });
69528
+ await mkdir10(dirname11(path), { recursive: true, mode: 448 });
69529
+ await writeFile10(path, JSON.stringify({ pid, thread: thread2, log, startedAt: context.nowMs() }));
69530
+ return [
69531
+ `Started \`${laze} adopt codex\` in the background (pid ${pid}). It answers each Laze message`,
69532
+ `as a turn in ${thread2 ? `this Codex thread (${thread2})` : "the newest Codex thread"}, and starts again if it stops.`,
69533
+ `Log: ${log}`,
69534
+ ` ${laze} adopt codex --status --profile ${profile} shows whether it runs`,
69535
+ ` ${laze} adopt codex --stop --profile ${profile} stops it`,
69536
+ "Nothing else needs to run. While this Codex window stays open, Codex lets only it write the",
69537
+ "thread, so adopt answers in a fork of it (the same history so far; `codex resume <fork id>`",
69538
+ "from the log opens it). Started again with this window closed, it answers in the thread itself."
69539
+ ].join("\n");
69540
+ }
69541
+ async function supervise({
69542
+ context,
69543
+ args,
69544
+ profile
69545
+ }) {
69546
+ const path = statePathOf({ context, kind: "adopt", profile });
69547
+ const thread2 = flagText({ args, name: "thread" });
69548
+ const adopt = ["adopt", "codex", "--profile", profile, ...threadFlag({ thread: thread2 })];
69549
+ const command = [...context.program, ...adopt];
69550
+ let wait = 1;
69551
+ while ((await recordOf({ path }))?.pid === context.processes.pid) {
69552
+ const started = context.nowMs();
69553
+ context.out(
69554
+ `${Temporal3.Instant.fromEpochMilliseconds(started).toString()} starting laze adopt codex
69555
+ `
69556
+ );
69557
+ const code = await context.runCommand({ command, env: {} }).catch(() => 1);
69558
+ if (context.nowMs() - started > HEALTHY_RUN_MS) wait = 1;
69559
+ if ((await recordOf({ path }))?.pid !== context.processes.pid) break;
69560
+ context.out(`laze adopt codex exited ${code}; starting it again in ${wait}s
69561
+ `);
69562
+ await context.sleep(wait * 1e3);
69563
+ wait = Math.min(MAX_RESTART_WAIT_SECONDS, wait * 2);
69564
+ }
69565
+ return 0;
69566
+ }
69567
+ async function adoptStatus({ context, profile }) {
69568
+ const record4 = await recordOf({ path: statePathOf({ context, kind: "adopt", profile }) });
69569
+ if (!record4 || !context.processes.alive(record4.pid)) {
69570
+ context.out(`laze adopt codex does not run in the background for profile "${profile}".
69571
+ `);
69572
+ return;
69573
+ }
69574
+ const thread2 = record4.thread ?? "the newest thread";
69575
+ context.out(
69576
+ `laze adopt codex runs in the background for profile "${profile}" (pid ${record4.pid}), thread ${thread2}.
69577
+ Log: ${record4.log}
69578
+ `
69579
+ );
69580
+ }
69581
+ async function adoptStop({ context, profile }) {
69582
+ const path = statePathOf({ context, kind: "adopt", profile });
69583
+ const record4 = await recordOf({ path });
69584
+ await rm5(path, { force: true });
69585
+ if (!record4 || !context.processes.stop(record4.pid)) {
69586
+ context.out(`laze adopt codex was not running in the background for profile "${profile}".
69587
+ `);
69588
+ return;
69589
+ }
69590
+ context.out(`Stopped laze adopt codex (pid ${record4.pid}) for profile "${profile}".
69591
+ `);
69592
+ }
69593
+ var HELD_THREAD = /active writer/;
69594
+ async function adoptedThreadOf({
69595
+ context,
69596
+ codex,
69597
+ threadId,
69598
+ profile
69599
+ }) {
69600
+ const held = await codex.call("thread/resume", { threadId }).then(
69601
+ () => false,
69602
+ (error62) => {
69603
+ if (HELD_THREAD.test(String(error62))) return true;
69604
+ throw error62;
69605
+ }
69606
+ );
69607
+ if (!held) return threadId;
69608
+ const path = statePathOf({ context, kind: "adopt", profile, extension: "forks.json" });
69609
+ const forks = await readFile11(path, "utf8").then(
69610
+ (text2) => JSON.parse(text2),
69611
+ () => ({})
69612
+ );
69613
+ const known = forks[threadId];
69614
+ if (known && await codex.call("thread/resume", { threadId: known }).then(
69615
+ () => true,
69616
+ () => false
69617
+ )) {
69618
+ context.out(`Codex holds thread ${threadId} open elsewhere; answering in its fork ${known}.
69619
+ `);
69620
+ return known;
69621
+ }
69622
+ const forked = record3((await codex.call("thread/fork", { threadId })).thread).id;
69623
+ if (typeof forked !== "string") throw new Error("thread/fork answered no thread id");
69624
+ await mkdir10(dirname11(path), { recursive: true, mode: 448 });
69625
+ await writeFile10(path, JSON.stringify({ ...forks, [threadId]: forked }));
69626
+ context.out(
69627
+ `Codex holds thread ${threadId} open elsewhere; answering in its new fork ${forked}.
69628
+ `
69629
+ );
69630
+ return forked;
69631
+ }
69632
+ async function adoptCodex({ context, args }) {
69633
+ if (args.words[1] !== "codex") {
69634
+ throw new CliUsageError("Usage: laze adopt codex [--thread <id>] | --status | --stop");
69635
+ }
69636
+ const { client, name: name2 } = await signedIn({ context, args });
69637
+ if (args.flags.status) return adoptStatus({ context, profile: name2 });
69638
+ if (args.flags.stop) return adoptStop({ context, profile: name2 });
69639
+ if (args.flags.supervise) return supervise({ context, args, profile: name2 });
69640
+ const { codexHome } = context.environment;
69641
+ const threadId = flagText({ args, name: "thread" }) || context.environment.inherited.CODEX_THREAD_ID || await newestThreadId({ codexHome });
69642
+ const once = Boolean(args.flags.once);
69643
+ const codex = CodexAppServer.start({ codexHome, inherited: context.environment.inherited });
69644
+ try {
69645
+ await codex.call("initialize", {
69646
+ clientInfo: { name: "laze", title: "Laze", version: "1" },
69647
+ capabilities: null
69648
+ });
69649
+ codex.notify("initialized");
69650
+ const adopted = await adoptedThreadOf({ context, codex, threadId, profile: name2 });
69651
+ context.out(`Adopted Codex thread ${adopted}; answering Laze messages.
69652
+ `);
69653
+ const timeout = Number(flagText({ args, name: "timeout", fallback: "0" }));
69654
+ do {
69655
+ const messages = await receiveMessages({
69656
+ context,
69657
+ client,
69658
+ waitSeconds: timeout > 0 ? timeout : Infinity
69659
+ });
69660
+ for (const message2 of messages) {
69661
+ const body = await answer({
69662
+ context,
69663
+ codex,
69664
+ client,
69665
+ threadId: adopted,
69666
+ message: message2,
69667
+ profile: name2
69668
+ });
69669
+ context.out(`Answered ${message2.messageId}: ${body.slice(0, 120)}
69670
+ `);
69671
+ }
69672
+ if (messages.length === 0 && timeout > 0) break;
69673
+ } while (!once);
69674
+ } finally {
69675
+ codex.stop();
69676
+ }
69677
+ }
69678
+
69408
69679
  // src/services/codex-link.service.ts
69409
69680
  var ROLLOUTS_READ = 200;
69410
69681
  async function firstLineOf({ path }) {
@@ -69422,13 +69693,13 @@ async function newestThreadIn({
69422
69693
  codexHome,
69423
69694
  directory
69424
69695
  }) {
69425
- const root = join12(codexHome, "sessions");
69426
- const files2 = await readdir4(root, { recursive: true }).catch(() => []);
69696
+ const root = join13(codexHome, "sessions");
69697
+ const files2 = await readdir5(root, { recursive: true }).catch(() => []);
69427
69698
  const rollouts = files2.filter((file3) => /rollout-.*\.jsonl$/.test(file3));
69428
69699
  const dated = await Promise.all(
69429
69700
  rollouts.map(async (file3) => ({
69430
- path: join12(root, file3),
69431
- at: await stat2(join12(root, file3)).then(
69701
+ path: join13(root, file3),
69702
+ at: await stat4(join13(root, file3)).then(
69432
69703
  (info) => info.mtimeMs,
69433
69704
  () => 0
69434
69705
  )
@@ -69498,9 +69769,9 @@ async function linkCodexSession({
69498
69769
  }
69499
69770
 
69500
69771
  // src/services/laze-plugin.service.ts
69501
- import { mkdir as mkdir11, readFile as readFile11, writeFile as writeFile11 } from "node:fs/promises";
69772
+ import { mkdir as mkdir11, readFile as readFile12, writeFile as writeFile11 } from "node:fs/promises";
69502
69773
  import { homedir as homedir3 } from "node:os";
69503
- import { dirname as dirname11, join as join13 } from "node:path";
69774
+ import { dirname as dirname12, join as join14 } from "node:path";
69504
69775
 
69505
69776
  // src/rules/laze-plugin.rules.ts
69506
69777
  var LAZE_PLUGIN = "laze";
@@ -69616,11 +69887,11 @@ function lazePluginFiles({
69616
69887
  var REGISTER_LIMIT_MS = 6e4;
69617
69888
  var quote2 = (value) => `'${value.replaceAll("'", "'\\''")}'`;
69618
69889
  function pluginFolderOf({ context }) {
69619
- return join13(dirname11(context.environment.configPath), "plugins");
69890
+ return join14(dirname12(context.environment.configPath), "plugins");
69620
69891
  }
69621
69892
  async function pluginIsCurrent({ context }) {
69622
- const manifest = join13(pluginFolderOf({ context }), LAZE_PLUGIN, ".claude-plugin", "plugin.json");
69623
- const written = await readFile11(manifest, "utf8").then(
69893
+ const manifest = join14(pluginFolderOf({ context }), LAZE_PLUGIN, ".claude-plugin", "plugin.json");
69894
+ const written = await readFile12(manifest, "utf8").then(
69624
69895
  (text2) => JSON.parse(text2).version,
69625
69896
  () => void 0
69626
69897
  );
@@ -69634,8 +69905,8 @@ async function writeLazePlugin({ context }) {
69634
69905
  configPath: context.environment.configPath
69635
69906
  });
69636
69907
  for (const [path, text2] of Object.entries(files2)) {
69637
- const target = join13(folder, path);
69638
- await mkdir11(dirname11(target), { recursive: true });
69908
+ const target = join14(folder, path);
69909
+ await mkdir11(dirname12(target), { recursive: true });
69639
69910
  await writeFile11(target, text2);
69640
69911
  }
69641
69912
  return folder;
@@ -69666,8 +69937,8 @@ var RUN_FILES = ["hooks/hooks.json", "monitors/monitors.json"];
69666
69937
  async function cachedPluginOf({ context }) {
69667
69938
  const inherited = context.environment.inherited;
69668
69939
  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(
69940
+ const claude = inherited.CLAUDE_CONFIG_DIR || join14(home, ".claude");
69941
+ const listed = await readFile12(join14(claude, "plugins", "installed_plugins.json"), "utf8").then(
69671
69942
  (text2) => JSON.parse(text2),
69672
69943
  () => void 0
69673
69944
  );
@@ -69676,10 +69947,10 @@ async function cachedPluginOf({ context }) {
69676
69947
  async function refreshStaleCache({ context, folder }) {
69677
69948
  const cached2 = await cachedPluginOf({ context });
69678
69949
  if (!cached2) return true;
69679
- const read3 = (path) => readFile11(path, "utf8").catch(() => "");
69950
+ const read3 = (path) => readFile12(path, "utf8").catch(() => "");
69680
69951
  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;
69952
+ const ours = await read3(join14(folder, LAZE_PLUGIN, file3));
69953
+ if (ours === await read3(join14(cached2, file3))) continue;
69683
69954
  const plugin2 = `${LAZE_PLUGIN}@${LAZE_PLUGIN}`;
69684
69955
  const script = [
69685
69956
  `claude plugin uninstall ${plugin2} --scope user ${QUIET}`,
@@ -69690,10 +69961,10 @@ async function refreshStaleCache({ context, folder }) {
69690
69961
  return true;
69691
69962
  }
69692
69963
  function registeredMarkOf({ context }) {
69693
- return join13(pluginFolderOf({ context }), "registered");
69964
+ return join14(pluginFolderOf({ context }), "registered");
69694
69965
  }
69695
69966
  async function pluginRegistered({ context }) {
69696
- return readFile11(registeredMarkOf({ context }), "utf8").then(
69967
+ return readFile12(registeredMarkOf({ context }), "utf8").then(
69697
69968
  () => true,
69698
69969
  () => false
69699
69970
  );
@@ -69707,7 +69978,7 @@ async function installLazePlugin({ context }) {
69707
69978
  async function plugin({ context, args }) {
69708
69979
  const action = args.words[1] ?? "install";
69709
69980
  if (action === "path") {
69710
- context.out(`${join13(pluginFolderOf({ context }), LAZE_PLUGIN)}
69981
+ context.out(`${join14(pluginFolderOf({ context }), LAZE_PLUGIN)}
69711
69982
  `);
69712
69983
  return 0;
69713
69984
  }
@@ -69726,7 +69997,7 @@ async function plugin({ context, args }) {
69726
69997
 
69727
69998
  // src/services/mcp-channel.service.ts
69728
69999
  import { mkdir as mkdir12, rm as rm7, writeFile as writeFile12 } from "node:fs/promises";
69729
- import { dirname as dirname12 } from "node:path";
70000
+ import { dirname as dirname13 } from "node:path";
69730
70001
  var LAZE_MCP_SERVER = "laze";
69731
70002
  var DEV_CHANNELS_FLAG = "--dangerously-load-development-channels";
69732
70003
  var ROUND_SECONDS3 = 50;
@@ -69816,7 +70087,7 @@ async function pushInbox({
69816
70087
  signal
69817
70088
  }) {
69818
70089
  const marker = statePathOf({ context, kind: "channels", profile });
69819
- await mkdir12(dirname12(marker), { recursive: true, mode: 448 });
70090
+ await mkdir12(dirname13(marker), { recursive: true, mode: 448 });
69820
70091
  await writeFile12(marker, JSON.stringify({ pid: context.processes.pid }));
69821
70092
  try {
69822
70093
  while (!signal.aborted) {
@@ -69844,8 +70115,8 @@ async function pushInbox({
69844
70115
  }
69845
70116
 
69846
70117
  // 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";
70118
+ import { mkdir as mkdir13, readFile as readFile13, writeFile as writeFile13 } from "node:fs/promises";
70119
+ import { dirname as dirname14 } from "node:path";
69849
70120
  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
70121
  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
70122
  function monitorsRunHere({ context }) {
@@ -69879,7 +70150,7 @@ async function markReloadTipTold({
69879
70150
  }) {
69880
70151
  if (!session) return;
69881
70152
  const path = toldPathOf({ context, session });
69882
- await mkdir13(dirname13(path), { recursive: true, mode: 448 });
70153
+ await mkdir13(dirname14(path), { recursive: true, mode: 448 });
69883
70154
  await writeFile13(path, String(context.nowMs()), { mode: 384 });
69884
70155
  }
69885
70156
  async function reloadTipOnce({
@@ -69888,7 +70159,7 @@ async function reloadTipOnce({
69888
70159
  }) {
69889
70160
  if (!session || !monitorsRunHere({ context })) return void 0;
69890
70161
  if (!await pluginRegistered({ context })) return void 0;
69891
- const told = await readFile12(toldPathOf({ context, session }), "utf8").then(
70162
+ const told = await readFile13(toldPathOf({ context, session }), "utf8").then(
69892
70163
  () => true,
69893
70164
  () => false
69894
70165
  );
@@ -69954,9 +70225,9 @@ async function installHooks({
69954
70225
  directory,
69955
70226
  profile
69956
70227
  }) {
69957
- const folder = join14(directory, ".claude");
69958
- const path = join14(folder, "settings.local.json");
69959
- const current2 = await readFile13(path, "utf8").then(
70228
+ const folder = join15(directory, ".claude");
70229
+ const path = join15(folder, "settings.local.json");
70230
+ const current2 = await readFile14(path, "utf8").then(
69960
70231
  (text2) => JSON.parse(text2),
69961
70232
  () => ({})
69962
70233
  );
@@ -70158,7 +70429,7 @@ async function reportTranscript({
70158
70429
  input: input2
70159
70430
  }) {
70160
70431
  if (!input2.transcript_path || !input2.session_id) return;
70161
- const lines = (await readFile13(input2.transcript_path, "utf8")).split("\n");
70432
+ const lines = (await readFile14(input2.transcript_path, "utf8")).split("\n");
70162
70433
  const context = readTranscript({ lines });
70163
70434
  await client.post("/api/agents/me/activity", {
70164
70435
  sessionId: input2.session_id,
@@ -70191,7 +70462,7 @@ async function handOver({ context, args }) {
70191
70462
  const kept = await dueFromSpool({
70192
70463
  context,
70193
70464
  profile: agent2,
70194
- seen: () => input2.transcript_path ? readFile13(input2.transcript_path, "utf8") : Promise.resolve(""),
70465
+ seen: () => input2.transcript_path ? readFile14(input2.transcript_path, "utf8") : Promise.resolve(""),
70195
70466
  pushedToo: false
70196
70467
  });
70197
70468
  const claim3 = forSession({ client, session });
@@ -70231,8 +70502,8 @@ async function addSessionStartWaiter({ context, args }) {
70231
70502
  const directory = context.environment.inherited.CLAUDE_PROJECT_DIR;
70232
70503
  const profile = flagText({ args, name: "profile" });
70233
70504
  if (!directory || !profile) return;
70234
- const path = join14(directory, ".claude", "settings.local.json");
70235
- const settings2 = await readFile13(path, "utf8").then(
70505
+ const path = join15(directory, ".claude", "settings.local.json");
70506
+ const settings2 = await readFile14(path, "utf8").then(
70236
70507
  (text2) => JSON.parse(text2),
70237
70508
  () => void 0
70238
70509
  );
@@ -70241,7 +70512,7 @@ async function addSessionStartWaiter({ context, args }) {
70241
70512
  }
70242
70513
  async function refreshPlugin({ context }) {
70243
70514
  if (await pluginIsCurrent({ context })) return;
70244
- const logPath = join14(pluginFolderOf({ context }), "install.log");
70515
+ const logPath = join15(pluginFolderOf({ context }), "install.log");
70245
70516
  context.processes.spawnDetached({ argv: [...context.program, "plugin", "install"], logPath });
70246
70517
  }
70247
70518
  async function stopHook({ context, args }) {
@@ -70259,7 +70530,7 @@ async function stopHook({ context, args }) {
70259
70530
  }
70260
70531
 
70261
70532
  // src/services/agent-manage-commands.service.ts
70262
- import { readFile as readFile14 } from "node:fs/promises";
70533
+ import { readFile as readFile15 } from "node:fs/promises";
70263
70534
  import { extname, resolve as resolve5 } from "node:path";
70264
70535
 
70265
70536
  // src/rules/login-format.rules.ts
@@ -70388,7 +70659,7 @@ async function avatarOf({
70388
70659
  }) {
70389
70660
  const path = flagText({ args, name: "avatar" });
70390
70661
  if (!path) return void 0;
70391
- const bytes = await readFile14(resolve5(context.cwd, path)).catch(() => {
70662
+ const bytes = await readFile15(resolve5(context.cwd, path)).catch(() => {
70392
70663
  throw new CliUsageError(`laze: cannot read the avatar file ${path}.`);
70393
70664
  });
70394
70665
  const uploaded = await client.post("/api/agents/avatars", {
@@ -71091,8 +71362,8 @@ async function requestAgent({ context, args }) {
71091
71362
  }
71092
71363
 
71093
71364
  // 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";
71365
+ import { mkdir as mkdir15, readdir as readdir6, readFile as readFile16, writeFile as writeFile16 } from "node:fs/promises";
71366
+ import { dirname as dirname15, join as join17, relative as relative3, resolve as resolve6, sep as sep2 } from "node:path";
71096
71367
 
71097
71368
  // ../../modules/app/contract/src/app.connections.ts
71098
71369
  var appFunctionNameSchema = external_exports.string().regex(/^[a-z0-9][a-z0-9_-]{0,63}$/);
@@ -73487,7 +73758,7 @@ async function appPinsCommand({
73487
73758
  import { execFile } from "node:child_process";
73488
73759
  import { mkdtemp, rm as rm8, writeFile as writeFile15 } from "node:fs/promises";
73489
73760
  import { tmpdir } from "node:os";
73490
- import { join as join15 } from "node:path";
73761
+ import { join as join16 } from "node:path";
73491
73762
  import { promisify } from "node:util";
73492
73763
  var run2 = promisify(execFile);
73493
73764
  var MODULE_SYNTAX = /^\s*(import|export)\s/m;
@@ -73516,11 +73787,11 @@ async function scriptErrorsOf({
73516
73787
  const unknown2 = unknownCollectionsOf({ files: files2, collections });
73517
73788
  const scripts = files2.flatMap(scriptsOf);
73518
73789
  if (scripts.length === 0) return unknown2;
73519
- const dir = await mkdtemp(join15(tmpdir(), "laze-app-check-"));
73790
+ const dir = await mkdtemp(join16(tmpdir(), "laze-app-check-"));
73520
73791
  try {
73521
73792
  const errors = await Promise.all(
73522
73793
  scripts.map(async (script, index) => {
73523
- const file3 = join15(dir, `${index}.${script.module ? "mjs" : "cjs"}`);
73794
+ const file3 = join16(dir, `${index}.${script.module ? "mjs" : "cjs"}`);
73524
73795
  await writeFile15(file3, script.code);
73525
73796
  try {
73526
73797
  await run2(process.execPath, ["--check", file3]);
@@ -73670,7 +73941,7 @@ async function turnTokenOf({
73670
73941
  const pinned = env.LAZE_TURN_TOKEN?.trim();
73671
73942
  if (pinned) return pinned;
73672
73943
  if (env.LAZE_TURN_FILE) {
73673
- return readFile15(env.LAZE_TURN_FILE, "utf8").then(
73944
+ return readFile16(env.LAZE_TURN_FILE, "utf8").then(
73674
73945
  (text2) => text2.trim(),
73675
73946
  () => ""
73676
73947
  );
@@ -73696,7 +73967,7 @@ function folderOf({ context, word: word3 }) {
73696
73967
  return resolve6(context.cwd, word3 ?? ".");
73697
73968
  }
73698
73969
  async function readManifest(folder) {
73699
- const text2 = await readFile15(join16(folder, APP_MANIFEST_FILE), "utf8").catch(() => void 0);
73970
+ const text2 = await readFile16(join17(folder, APP_MANIFEST_FILE), "utf8").catch(() => void 0);
73700
73971
  if (text2 === void 0) return void 0;
73701
73972
  const parsed = appManifestSchema.safeParse(JSON.parse(text2));
73702
73973
  if (!parsed.success) {
@@ -73731,7 +74002,7 @@ async function jsonFlag({
73731
74002
  }) {
73732
74003
  const raw = flagText({ args, name: name2 });
73733
74004
  if (!raw) return void 0;
73734
- const text2 = raw.startsWith("@") ? await readFile15(resolve6(context.cwd, raw.slice(1)), "utf8") : raw;
74005
+ const text2 = raw.startsWith("@") ? await readFile16(resolve6(context.cwd, raw.slice(1)), "utf8") : raw;
73735
74006
  try {
73736
74007
  return JSON.parse(text2);
73737
74008
  } catch {
@@ -73743,8 +74014,8 @@ async function listFiles(folder) {
73743
74014
  const pending = [folder];
73744
74015
  while (pending.length > 0 && found.length <= MAX_FILES) {
73745
74016
  const current2 = pending.pop() ?? folder;
73746
- for (const entry of await readdir5(current2, { withFileTypes: true })) {
73747
- const path = join16(current2, entry.name);
74017
+ for (const entry of await readdir6(current2, { withFileTypes: true })) {
74018
+ const path = join17(current2, entry.name);
73748
74019
  const rel = relative3(folder, path).split(sep2).join("/");
73749
74020
  if (isSkippedPath({ path: rel })) continue;
73750
74021
  if (entry.isDirectory()) pending.push(path);
@@ -73788,8 +74059,8 @@ var appCreate = async ({ context, args }) => {
73788
74059
  await mkdir15(folder, { recursive: true });
73789
74060
  const files2 = template ? templateFiles({ template, name: name2 }) : {};
73790
74061
  for (const [path, content] of Object.entries(files2)) {
73791
- await mkdir15(dirname14(join16(folder, path)), { recursive: true });
73792
- await writeFile16(join16(folder, path), content);
74062
+ await mkdir15(dirname15(join17(folder, path)), { recursive: true });
74063
+ await writeFile16(join17(folder, path), content);
73793
74064
  }
73794
74065
  const manifest = {
73795
74066
  app: { id: app2.id, name: app2.name, slug: app2.slug },
@@ -73797,7 +74068,7 @@ var appCreate = async ({ context, args }) => {
73797
74068
  views: template?.views ? [...template.views] : [],
73798
74069
  seed: template ? { ...template.seed } : {}
73799
74070
  };
73800
- await writeFile16(join16(folder, APP_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
74071
+ await writeFile16(join17(folder, APP_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
73801
74072
  `);
73802
74073
  print5({
73803
74074
  context,
@@ -73834,7 +74105,7 @@ var appPush = async ({ context, args }) => {
73834
74105
  paths.map(
73835
74106
  async (path) => buildFileOf({
73836
74107
  path: relative3(folder, path).split(sep2).join("/"),
73837
- bytes: await readFile15(path)
74108
+ bytes: await readFile16(path)
73838
74109
  })
73839
74110
  )
73840
74111
  );
@@ -74217,7 +74488,7 @@ var appImport = async ({ context, args }) => {
74217
74488
  const words = args.words.slice(2);
74218
74489
  const [named, collection, file3] = words.length >= 3 ? words : [void 0, ...words];
74219
74490
  if (!collection || !file3) throw new CliUsageError(USAGE5);
74220
- const csv = await readFile15(resolve6(context.cwd, file3), "utf8").catch(() => {
74491
+ const csv = await readFile16(resolve6(context.cwd, file3), "utf8").catch(() => {
74221
74492
  throw new CliUsageError(`Cannot read ${file3}`);
74222
74493
  });
74223
74494
  const scoped = named ? { ...args, flags: { ...args.flags, app: named } } : args;
@@ -74783,8 +75054,8 @@ async function billing({ context, args }) {
74783
75054
 
74784
75055
  // src/services/browser-commands.service.ts
74785
75056
  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";
75057
+ import { mkdir as mkdir16, readFile as readFile17, writeFile as writeFile17 } from "node:fs/promises";
75058
+ import { dirname as dirname16, join as join18 } from "node:path";
74788
75059
 
74789
75060
  // src/services/browser-tab-commands.service.ts
74790
75061
  var BROWSER_TAB_PATHS = {
@@ -75330,7 +75601,7 @@ async function turnTokenOf2({ context }) {
75330
75601
  const pinned = env.LAZE_TURN_TOKEN?.trim();
75331
75602
  if (pinned) return pinned;
75332
75603
  if (!env.LAZE_TURN_FILE) return "";
75333
- return readFile16(env.LAZE_TURN_FILE, "utf8").then(
75604
+ return readFile17(env.LAZE_TURN_FILE, "utf8").then(
75334
75605
  (text2) => text2.trim(),
75335
75606
  () => ""
75336
75607
  );
@@ -75404,7 +75675,7 @@ async function cdp({ context, args }) {
75404
75675
  }
75405
75676
  function bridgeStatePath({ context, machine: machine2 }) {
75406
75677
  const safe = machine2.replace(/[^a-zA-Z0-9_-]/g, "_");
75407
- return join17(dirname15(context.environment.configPath), "bridges", `${safe}.json`);
75678
+ return join18(dirname16(context.environment.configPath), "bridges", `${safe}.json`);
75408
75679
  }
75409
75680
  async function bridgePort({
75410
75681
  context,
@@ -75412,7 +75683,7 @@ async function bridgePort({
75412
75683
  access
75413
75684
  }) {
75414
75685
  const path = bridgeStatePath({ context, machine: machine2 });
75415
- const live = await readFile16(path, "utf8").then(
75686
+ const live = await readFile17(path, "utf8").then(
75416
75687
  (text2) => JSON.parse(text2),
75417
75688
  () => void 0
75418
75689
  );
@@ -75425,7 +75696,7 @@ async function bridgePort({
75425
75696
  key,
75426
75697
  ...target
75427
75698
  });
75428
- await mkdir16(dirname15(path), { recursive: true, mode: 448 });
75699
+ await mkdir16(dirname16(path), { recursive: true, mode: 448 });
75429
75700
  await writeFile17(path, JSON.stringify({ port, key }), { mode: 384 });
75430
75701
  return port;
75431
75702
  }
@@ -76070,9 +76341,42 @@ async function channelSettings({ context, args }) {
76070
76341
  }
76071
76342
 
76072
76343
  // src/services/chat-actions-commands.service.ts
76073
- import { readFile as readFile17 } from "node:fs/promises";
76344
+ import { readFile as readFile18 } from "node:fs/promises";
76074
76345
  import { basename as basename3, isAbsolute as isAbsolute2, relative as relative4, resolve as resolve7 } from "node:path";
76075
76346
 
76347
+ // src/rules/file-types.rules.ts
76348
+ var TYPES = {
76349
+ png: "image/png",
76350
+ jpg: "image/jpeg",
76351
+ jpeg: "image/jpeg",
76352
+ webp: "image/webp",
76353
+ gif: "image/gif",
76354
+ svg: "image/svg+xml",
76355
+ pdf: "application/pdf",
76356
+ txt: "text/plain",
76357
+ md: "text/markdown",
76358
+ csv: "text/csv",
76359
+ json: "application/json",
76360
+ zip: "application/zip"
76361
+ };
76362
+ function contentTypeOf(fileName) {
76363
+ const extension2 = fileName.toLowerCase().split(".").pop() ?? "";
76364
+ return TYPES[extension2] ?? "application/octet-stream";
76365
+ }
76366
+ var MACHINE_NAME = /^(?:[a-z]{1,8}[_-])?[0-9a-f][0-9a-f_-]{11,}$/i;
76367
+ function readableUploadName({ name: name2, asked }) {
76368
+ const slash = name2.lastIndexOf("/");
76369
+ const base = name2.slice(slash + 1);
76370
+ const dot = base.lastIndexOf(".");
76371
+ const extension2 = dot > 0 ? base.slice(dot) : "";
76372
+ const wanted = asked?.trim();
76373
+ if (wanted) return /\.[A-Za-z0-9]{1,8}$/.test(wanted) ? wanted : `${wanted}${extension2}`;
76374
+ const stem = dot > 0 ? base.slice(0, dot) : base;
76375
+ if (!MACHINE_NAME.test(stem)) return name2;
76376
+ const image = contentTypeOf(base).startsWith("image/");
76377
+ return `${image ? "image" : "file"}${extension2}`;
76378
+ }
76379
+
76076
76380
  // src/services/file-upload.service.ts
76077
76381
  async function sendParts({
76078
76382
  context,
@@ -76171,7 +76475,7 @@ var CHAT_ACTIONS_USAGE = `Usage:
76171
76475
  laze files <channel> [--before <fileId>] [--limit <n>] its files, newest first
76172
76476
  laze file link <fileId> [--variant original|thumbnail|poster|preview] [--download]
76173
76477
  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
76478
+ laze file upload <channel> <path> [--name <name>] [--type <content-type>] upload a file; post it with its id
76175
76479
  laze saved [--done] [--limit <n>] | laze saved marks your saved messages (people)
76176
76480
  laze save <messageId> [--off] save a message for later, or take it out
76177
76481
  laze saved done <messageId> [--undo] mark a saved message done, or open again
@@ -76375,19 +76679,27 @@ function uploadNameOf({ cwd, path }) {
76375
76679
  }
76376
76680
  var fileUpload = async ({ context, args, client }) => {
76377
76681
  const path = resolve7(context.cwd, wordAt(args, 3));
76378
- const bytes = new Uint8Array(await readFile17(path));
76682
+ const bytes = new Uint8Array(await readFile18(path));
76379
76683
  const answer4 = await uploadFile({
76380
76684
  context,
76381
76685
  client,
76382
76686
  file: {
76383
76687
  channel: wordAt(args, 2),
76384
- fileName: uploadNameOf({ cwd: context.cwd, path }),
76385
- contentType: flagText({ args, name: "type", fallback: "application/octet-stream" }),
76688
+ fileName: readableUploadName({
76689
+ name: uploadNameOf({ cwd: context.cwd, path }),
76690
+ ...flagText({ args, name: "name" }) && { asked: flagText({ args, name: "name" }) }
76691
+ }),
76692
+ contentType: flagText({ args, name: "type", fallback: contentTypeOf(path) }),
76386
76693
  bytes
76387
76694
  }
76388
76695
  });
76389
- print6({ context, args, answer: answer4, text: (it) => `Uploaded ${it.fileName} as ${it.id}.
76390
- ` });
76696
+ print6({
76697
+ context,
76698
+ args,
76699
+ answer: answer4,
76700
+ text: (it) => `Uploaded ${it.fileName} as ${it.id}. Put <file:${it.id}> in a message to share it.
76701
+ `
76702
+ });
76391
76703
  };
76392
76704
  var FILE_VERBS = {
76393
76705
  link: async ({ context, args, client }) => {
@@ -76540,7 +76852,7 @@ async function chatActions({
76540
76852
  }
76541
76853
 
76542
76854
  // src/services/claude-monitor.service.ts
76543
- import { readFile as readFile18, rm as rm9 } from "node:fs/promises";
76855
+ import { readFile as readFile19, rm as rm9 } from "node:fs/promises";
76544
76856
  var MONITOR_IDLE_MS = 3e4;
76545
76857
  var MONITOR_OUTRANKED_MS = 3e3;
76546
76858
  async function deliverOnce({
@@ -76558,7 +76870,7 @@ async function deliverOnce({
76558
76870
  const named = { ...args, flags: { ...args.flags, profile } };
76559
76871
  const { client } = await signedIn({ context, args: named });
76560
76872
  const due = await dueFromSpool({ context, profile, seen: async () => "", pushedToo: true });
76561
- const taken = due.length > 0 ? [] : await takeRound({ context, client, claudePid, session });
76873
+ const taken = due.length > 0 ? [] : await takeRound2({ context, client, claudePid, session });
76562
76874
  const messages = [...due, ...taken];
76563
76875
  if (messages.length === 0) {
76564
76876
  await context.sleep(1e3);
@@ -76635,7 +76947,7 @@ async function monitorSessionOf({
76635
76947
  const fromEnv = sessionOf({ context, harness: "claude-code", sessionId });
76636
76948
  if (fromEnv || !claudePid) return fromEnv;
76637
76949
  const path = statePathOf({ context, kind: "sessions", profile: String(claudePid) });
76638
- return readFile18(path, "utf8").then(
76950
+ return readFile19(path, "utf8").then(
76639
76951
  (text2) => JSON.parse(text2),
76640
76952
  () => void 0
76641
76953
  );
@@ -78310,10 +78622,10 @@ async function computer({ context, args }) {
78310
78622
  }
78311
78623
 
78312
78624
  // src/services/connect-commands.service.ts
78313
- import { readFile as readFile20 } from "node:fs/promises";
78625
+ import { readFile as readFile21 } from "node:fs/promises";
78314
78626
 
78315
78627
  // src/services/mcp-gateway.service.ts
78316
- import { readFile as readFile19 } from "node:fs/promises";
78628
+ import { readFile as readFile20 } from "node:fs/promises";
78317
78629
  import { createInterface as createInterface3 } from "node:readline";
78318
78630
  var TURN_HEADER = "x-laze-turn";
78319
78631
  function serveMcpGateway({
@@ -78356,7 +78668,7 @@ async function relayMcpLines({
78356
78668
  const github3 = env.LAZE_GITHUB_CONNECTION;
78357
78669
  const url2 = `${profile.url.replace(/\/+$/, "")}/api/connectors/mcp/${encodeURIComponent(profile.agentId)}${github3 ? `?github=${encodeURIComponent(github3)}` : ""}`;
78358
78670
  const turnFile = env.LAZE_TURN_FILE;
78359
- const readTurn = () => readFile19(turnFile, "utf8").then(
78671
+ const readTurn = () => readFile20(turnFile, "utf8").then(
78360
78672
  (text2) => text2.trim(),
78361
78673
  () => ""
78362
78674
  );
@@ -78446,7 +78758,7 @@ async function turnOf({ context }) {
78446
78758
  const pinned = env.LAZE_TURN_TOKEN?.trim();
78447
78759
  if (pinned) return pinned;
78448
78760
  const file3 = env.LAZE_TURN_FILE;
78449
- const turn = file3 ? await readFile20(file3, "utf8").then(
78761
+ const turn = file3 ? await readFile21(file3, "utf8").then(
78450
78762
  (text2) => text2.trim(),
78451
78763
  () => ""
78452
78764
  ) : "";
@@ -78504,11 +78816,11 @@ async function connect({
78504
78816
  }
78505
78817
 
78506
78818
  // src/services/connector-commands.service.ts
78507
- import { readFile as readFile22 } from "node:fs/promises";
78819
+ import { readFile as readFile23 } from "node:fs/promises";
78508
78820
  import { resolve as resolve8 } from "node:path";
78509
78821
 
78510
78822
  // src/services/vault-keychain-commands.service.ts
78511
- import { readFile as readFile21 } from "node:fs/promises";
78823
+ import { readFile as readFile22 } from "node:fs/promises";
78512
78824
 
78513
78825
  // src/rules/vault-input.rules.ts
78514
78826
  function secondsOf(text2) {
@@ -78830,7 +79142,7 @@ async function secretText({ context, args }) {
78830
79142
  );
78831
79143
  }
78832
79144
  const file3 = flagText({ args, name: "from-file" });
78833
- const text2 = file3 ? await readFile21(file3, "utf8") : await context.readStdin();
79145
+ const text2 = file3 ? await readFile22(file3, "utf8") : await context.readStdin();
78834
79146
  const trimmed = text2.replace(/\r?\n$/, "");
78835
79147
  if (!trimmed.trim()) throw new CliUsageError("No value: pipe it on stdin or use --from-file.");
78836
79148
  return trimmed;
@@ -79040,7 +79352,7 @@ async function keyText({ context, args }) {
79040
79352
  throw new CliUsageError("A key never goes in a flag: pipe it on stdin or use --from-file.");
79041
79353
  }
79042
79354
  const file3 = flagText({ args, name: "from-file" });
79043
- const text2 = file3 ? await readFile22(resolve8(context.cwd, file3), "utf8") : await context.readStdin();
79355
+ const text2 = file3 ? await readFile23(resolve8(context.cwd, file3), "utf8") : await context.readStdin();
79044
79356
  const trimmed = text2.trim();
79045
79357
  if (!trimmed) throw new CliUsageError("No key: pipe it on stdin or use --from-file.");
79046
79358
  return trimmed;
@@ -79432,8 +79744,8 @@ var DOMAINS_USAGE = `Usage:
79432
79744
  var printJson5 = (context, data) => context.out(`${JSON.stringify(data, null, 2)}
79433
79745
  `);
79434
79746
  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" : ""}
79747
+ const join23 = row.autoJoin ? "auto-join on" : "auto-join off";
79748
+ context.out(`${row.domain} ${join23}${row.enforced ? " single sign-on enforced" : ""}
79437
79749
  `);
79438
79750
  }
79439
79751
  async function list4({ context, args }) {
@@ -79465,7 +79777,7 @@ async function domains({ context, args }) {
79465
79777
  }
79466
79778
 
79467
79779
  // src/services/feed-commands.service.ts
79468
- import { readFile as readFile24 } from "node:fs/promises";
79780
+ import { readFile as readFile25 } from "node:fs/promises";
79469
79781
  import { resolve as resolve10 } from "node:path";
79470
79782
 
79471
79783
  // src/rules/feed-input.rules.ts
@@ -79590,7 +79902,7 @@ function feedFlagsOf({ args }) {
79590
79902
  }
79591
79903
 
79592
79904
  // src/services/feed-files.service.ts
79593
- import { readFile as readFile23 } from "node:fs/promises";
79905
+ import { readFile as readFile24 } from "node:fs/promises";
79594
79906
  import { basename as basename4, resolve as resolve9 } from "node:path";
79595
79907
 
79596
79908
  // ../../modules/feed/contract/src/feed.ts
@@ -80135,26 +80447,6 @@ var feedWakeIntentSchemaDefinition = external_exports.object({
80135
80447
  // ../../modules/feed/contract/src/feed.config.ts
80136
80448
  var feedConfig = Config.define(() => ({ publicBaseUrl }));
80137
80449
 
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
80450
  // src/services/feed-files.service.ts
80159
80451
  async function bytesOf2({
80160
80452
  context,
@@ -80185,7 +80477,7 @@ async function local({ context, path }) {
80185
80477
  return {
80186
80478
  fileName,
80187
80479
  contentType: contentTypeOf(fileName),
80188
- bytes: new Uint8Array(await readFile23(full))
80480
+ bytes: new Uint8Array(await readFile24(full))
80189
80481
  };
80190
80482
  }
80191
80483
  async function directWith({ client, to }) {
@@ -80263,7 +80555,7 @@ async function bodyOf2({
80263
80555
  flags: flags2
80264
80556
  }) {
80265
80557
  const body = { ...flags2.fields };
80266
- const read3 = (source) => "file" in source ? readFile24(resolve10(context.cwd, source.file), "utf8") : source.text;
80558
+ const read3 = (source) => "file" in source ? readFile25(resolve10(context.cwd, source.file), "utf8") : source.text;
80267
80559
  for (const [field, source] of Object.entries(flags2.texts)) body[field] = await read3(source);
80268
80560
  if (flags2.rich) {
80269
80561
  const text2 = await read3(flags2.rich.source);
@@ -80425,7 +80717,7 @@ async function textFlag({
80425
80717
  }) {
80426
80718
  const value = flagText({ args, name: name2 });
80427
80719
  if (!value.startsWith("@")) return value;
80428
- return readFile24(resolve10(context.cwd, value.slice(1)), "utf8");
80720
+ return readFile25(resolve10(context.cwd, value.slice(1)), "utf8");
80429
80721
  }
80430
80722
  async function feedList({ context, args }) {
80431
80723
  const { client } = await signedIn({ context, args });
@@ -80535,7 +80827,7 @@ async function feed({ context, args }) {
80535
80827
  }
80536
80828
 
80537
80829
  // src/services/github-commands.service.ts
80538
- import { readFile as readFile25 } from "node:fs/promises";
80830
+ import { readFile as readFile26 } from "node:fs/promises";
80539
80831
 
80540
80832
  // src/rules/github-signature.rules.ts
80541
80833
  var TURN_SEPARATOR = "~";
@@ -80605,7 +80897,7 @@ var REAL_GH = "/usr/bin/gh";
80605
80897
  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
80898
  async function turnFileToken({ env }) {
80607
80899
  if (!env.LAZE_TURN_FILE) return "";
80608
- return readFile25(env.LAZE_TURN_FILE, "utf8").then(
80900
+ return readFile26(env.LAZE_TURN_FILE, "utf8").then(
80609
80901
  (text2) => text2.trim(),
80610
80902
  () => ""
80611
80903
  );
@@ -80639,7 +80931,7 @@ async function githubGh({
80639
80931
  args: args.rest,
80640
80932
  agentName: profile.name ?? "An agent",
80641
80933
  threadUrl: threadUrlOf({ env, workspaceId: profile.workspaceId }),
80642
- readBodyFile: (path) => path === "-" ? context.readStdin() : readFile25(path, "utf8")
80934
+ readBodyFile: (path) => path === "-" ? context.readStdin() : readFile26(path, "utf8")
80643
80935
  });
80644
80936
  return context.runCommand({
80645
80937
  command: [REAL_GH, ...ghArgs],
@@ -80738,7 +81030,7 @@ async function setAgentGithub({
80738
81030
  }
80739
81031
 
80740
81032
  // src/services/history-commands.service.ts
80741
- import { readFile as readFile26 } from "node:fs/promises";
81033
+ import { readFile as readFile27 } from "node:fs/promises";
80742
81034
 
80743
81035
  // src/rules/history-format.rules.ts
80744
81036
  function timeOf2(iso) {
@@ -80834,7 +81126,7 @@ async function turnTokenOf3({ context }) {
80834
81126
  const pinned = env.LAZE_TURN_TOKEN?.trim();
80835
81127
  if (pinned) return pinned;
80836
81128
  if (!env.LAZE_TURN_FILE) return "";
80837
- return readFile26(env.LAZE_TURN_FILE, "utf8").then(
81129
+ return readFile27(env.LAZE_TURN_FILE, "utf8").then(
80838
81130
  (text2) => text2.trim(),
80839
81131
  () => ""
80840
81132
  );
@@ -81026,19 +81318,19 @@ async function ip({ context, args }) {
81026
81318
  }
81027
81319
 
81028
81320
  // 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";
81321
+ import { mkdir as mkdir17, readFile as readFile28, rename as rename5, rm as rm10, writeFile as writeFile18 } from "node:fs/promises";
81322
+ import { dirname as dirname17, join as join19 } from "node:path";
81031
81323
  var DEFAULT_WAIT_SECONDS2 = 100;
81032
81324
  var JOIN_USAGE = "Usage: laze join [--workspace <name|id|invite link>] [--for <email>] [--name <name>] [--note <text>] [--timeout <seconds>] [--project <folder>]";
81033
81325
  function pendingPathOf({ context }) {
81034
- return join18(dirname16(context.environment.configPath), "join", "pending.json");
81326
+ return join19(dirname17(context.environment.configPath), "join", "pending.json");
81035
81327
  }
81036
81328
  async function readPending({
81037
81329
  context,
81038
81330
  url: url2,
81039
81331
  args
81040
81332
  }) {
81041
- const pending = await readFile27(pendingPathOf({ context }), "utf8").then(
81333
+ const pending = await readFile28(pendingPathOf({ context }), "utf8").then(
81042
81334
  (text2) => JSON.parse(text2),
81043
81335
  () => void 0
81044
81336
  );
@@ -81048,7 +81340,7 @@ async function readPending({
81048
81340
  }
81049
81341
  async function keepPending({ context, pending }) {
81050
81342
  const path = pendingPathOf({ context });
81051
- await mkdir17(dirname16(path), { recursive: true, mode: 448 });
81343
+ await mkdir17(dirname17(path), { recursive: true, mode: 448 });
81052
81344
  const temporary = `${path}.${process.pid}.tmp`;
81053
81345
  await writeFile18(temporary, JSON.stringify(pending), { mode: 384 });
81054
81346
  await rename5(temporary, path);
@@ -81368,9 +81660,9 @@ function machineAccessCommand(name2) {
81368
81660
 
81369
81661
  // src/services/vault-commands.service.ts
81370
81662
  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";
81663
+ import { mkdir as mkdir18, readFile as readFile29, rm as rm11, writeFile as writeFile19 } from "node:fs/promises";
81372
81664
  import { tmpdir as tmpdir2 } from "node:os";
81373
- import { dirname as dirname17, join as join19 } from "node:path";
81665
+ import { dirname as dirname18, join as join20 } from "node:path";
81374
81666
  var USAGE10 = `Usage: laze vault run <connection> --reason "<one plain sentence>" [--wait <s>] -- <command> [args...]
81375
81667
  Runs the command with the connection's values in its environment, on a Laze agent's computer
81376
81668
  or on a machine it runs on.`;
@@ -81409,7 +81701,7 @@ async function turnTokenOf4({
81409
81701
  if (pinned) return pinned;
81410
81702
  if (!turnFile) throw new CliUsageError(`${command} works only during an agent's turn`);
81411
81703
  try {
81412
- return (await readFile28(turnFile, "utf8")).trim();
81704
+ return (await readFile29(turnFile, "utf8")).trim();
81413
81705
  } catch {
81414
81706
  throw new CliUsageError(`${command} works only during an agent's turn`);
81415
81707
  }
@@ -81419,11 +81711,11 @@ function runKeyPathOf({
81419
81711
  connection
81420
81712
  }) {
81421
81713
  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`);
81714
+ const base = turnFile ? dirname18(turnFile) : join20(tmpdir2(), "laze-vault");
81715
+ return join20(base, "vault-run-keys", `${name2}.json`);
81424
81716
  }
81425
81717
  async function runKeyAt({ path }) {
81426
- const saved3 = await readFile28(path, "utf8").then(
81718
+ const saved3 = await readFile29(path, "utf8").then(
81427
81719
  (text2) => JSON.parse(text2),
81428
81720
  () => void 0
81429
81721
  );
@@ -81433,7 +81725,7 @@ async function runKeyAt({ path }) {
81433
81725
  }
81434
81726
  const fresh = await generateEcdhKeys();
81435
81727
  const jwk = await globalThis.crypto.subtle.exportKey("jwk", fresh.privateKey);
81436
- await mkdir18(dirname17(path), { recursive: true, mode: 448 });
81728
+ await mkdir18(dirname18(path), { recursive: true, mode: 448 });
81437
81729
  await writeFile19(path, JSON.stringify({ publicKey: fresh.publicKey, privateKey: jwk }), {
81438
81730
  mode: 384
81439
81731
  });
@@ -82106,14 +82398,14 @@ async function serveMcp({
82106
82398
  }
82107
82399
 
82108
82400
  // 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";
82401
+ import { mkdir as mkdir19, readFile as readFile30, rm as rm12, writeFile as writeFile20 } from "node:fs/promises";
82402
+ import { dirname as dirname19, relative as relative5, resolve as resolve11 } from "node:path";
82111
82403
  async function textArgument({
82112
82404
  context,
82113
82405
  value
82114
82406
  }) {
82115
82407
  if (value === "-") return context.readStdin();
82116
- if (value.startsWith("@")) return readFile29(resolve11(context.cwd, value.slice(1)), "utf8");
82408
+ if (value.startsWith("@")) return readFile30(resolve11(context.cwd, value.slice(1)), "utf8");
82117
82409
  return value;
82118
82410
  }
82119
82411
  function turnChannel({ context, args }) {
@@ -82133,7 +82425,7 @@ async function writeMount({
82133
82425
  const inside = relative5(root, target);
82134
82426
  if (!inside || inside.startsWith(".."))
82135
82427
  throw new Error(`Refusing to write outside ${root}: ${file3.path}`);
82136
- await mkdir19(dirname18(target), { recursive: true });
82428
+ await mkdir19(dirname19(target), { recursive: true });
82137
82429
  await writeFile20(target, file3.content);
82138
82430
  }
82139
82431
  return root;
@@ -82775,8 +83067,8 @@ ${OPS_USAGE}`);
82775
83067
  }
82776
83068
 
82777
83069
  // 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";
83070
+ import { mkdir as mkdir20, readFile as readFile31, realpath, writeFile as writeFile21 } from "node:fs/promises";
83071
+ import { dirname as dirname20, join as join21 } from "node:path";
82780
83072
 
82781
83073
  // src/rules/cli-update.rules.ts
82782
83074
  var CLI_PACKAGE_LATEST = "@lazehq/cli@latest";
@@ -82877,16 +83169,16 @@ async function startedUpdate({
82877
83169
  if (context.environment.inherited.LAZE_AUTO_UPDATE === "0") return null;
82878
83170
  const plan2 = updatePlanOf({ script: await scriptOf(context) });
82879
83171
  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);
83172
+ const folder = dirname20(context.environment.configPath);
83173
+ const stamp = join21(folder, "auto-update.json");
83174
+ const last = await readFile31(stamp, "utf8").then((text2) => JSON.parse(text2)).catch(() => null);
82883
83175
  const now = context.nowMs();
82884
83176
  if (last?.server === server && now - last.atMs < RETRY_AFTER_MS) return null;
82885
83177
  await mkdir20(folder, { recursive: true, mode: 448 });
82886
83178
  await writeFile21(stamp, JSON.stringify({ server, atMs: now }), { mode: 384 });
82887
83179
  context.processes.spawnDetached({
82888
83180
  argv: [...context.program, "update"],
82889
- logPath: join20(folder, "auto-update.log")
83181
+ logPath: join21(folder, "auto-update.log")
82890
83182
  });
82891
83183
  return { manager: plan2.manager };
82892
83184
  }
@@ -82916,19 +83208,19 @@ function watchingRelease({
82916
83208
  }
82917
83209
 
82918
83210
  // src/services/rush-guard.service.ts
82919
- import { readFile as readFile31, rm as rm13 } from "node:fs/promises";
83211
+ import { readFile as readFile32, rm as rm13 } from "node:fs/promises";
82920
83212
  var WATCH_MS3 = 2e3;
82921
83213
  var RETRY_MS2 = 3e4;
82922
83214
  async function guardRound({ context, client, name: name2, lock, claudePid, session, rush }) {
82923
83215
  const key = session ? sessionKeyOf({ session }) : void 0;
82924
- if (key && await liveElsewhere({ context, key, claudePid })) return true;
83216
+ if (key && await liveElsewhere({ context, key, claudePid, asleepCounts: false })) return true;
82925
83217
  const holder = await holderOf({ path: lock });
82926
83218
  if (holder?.pid !== context.processes.pid) {
82927
83219
  if (!await takeLock({ context, path: lock, claudePid, ...sessionIdOf({ session }) }))
82928
83220
  return true;
82929
83221
  }
82930
83222
  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 });
83223
+ const messages = due.length > 0 ? due : await takeRound2({ context, client, claudePid: 0, session });
82932
83224
  if (messages.length === 0) return false;
82933
83225
  await keepTaken({ context, profile: name2, messages });
82934
83226
  const self2 = await currentNameOf({ context, client, profile: name2 });
@@ -82952,7 +83244,7 @@ async function rushWakeHook({ context, args }) {
82952
83244
  while (context.processes.alive(claudePid)) await context.sleep(WATCH_MS3);
82953
83245
  const { client, name: name2 } = await signedIn({ context, args });
82954
83246
  const noted = statePathOf({ context, kind: "sessions", profile: String(claudePid) });
82955
- const session = await readFile31(noted, "utf8").then(
83247
+ const session = await readFile32(noted, "utf8").then(
82956
83248
  (text2) => JSON.parse(text2),
82957
83249
  () => void 0
82958
83250
  );
@@ -83118,8 +83410,8 @@ async function schedule({ context, args }) {
83118
83410
  }
83119
83411
 
83120
83412
  // 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";
83413
+ import { readdir as readdir7, readFile as readFile33 } from "node:fs/promises";
83414
+ import { join as join22, relative as relative6, resolve as resolve12 } from "node:path";
83123
83415
  var USAGE16 = `Usage:
83124
83416
  laze skill list [--agent <agentId>]
83125
83417
  laze skill install <catalogue-id> [--as <name>] [--agent <agentId>]
@@ -83136,12 +83428,12 @@ var USAGE16 = `Usage:
83136
83428
  --agent names the agent with a person's key; an agent's key works on its own skills.
83137
83429
  With a person's key, list without --agent shows every agent's skills.`;
83138
83430
  async function folderFiles({ root }) {
83139
- const entries = await readdir6(root, { recursive: true, withFileTypes: true });
83431
+ const entries = await readdir7(root, { recursive: true, withFileTypes: true });
83140
83432
  const files2 = [];
83141
83433
  for (const entry of entries) {
83142
83434
  if (!entry.isFile()) continue;
83143
- const full = join21(entry.parentPath, entry.name);
83144
- files2.push({ path: relative6(root, full), content: await readFile32(full, "utf8") });
83435
+ const full = join22(entry.parentPath, entry.name);
83436
+ files2.push({ path: relative6(root, full), content: await readFile33(full, "utf8") });
83145
83437
  }
83146
83438
  return files2.toSorted((a, b) => a.path.localeCompare(b.path));
83147
83439
  }
@@ -83239,7 +83531,7 @@ async function skillUpdate({ context, args }) {
83239
83531
  if (!name2 || !newName && description === void 0 && !skillMdFile) {
83240
83532
  throw new CliUsageError(USAGE16);
83241
83533
  }
83242
- const skillMd = skillMdFile ? await readFile32(resolve12(context.cwd, skillMdFile), "utf8") : void 0;
83534
+ const skillMd = skillMdFile ? await readFile33(resolve12(context.cwd, skillMdFile), "utf8") : void 0;
83243
83535
  const { client } = await signedIn({ context, args });
83244
83536
  const updated = await client.post("/api/skills/update", {
83245
83537
  name: name2,
@@ -83285,7 +83577,7 @@ async function skill({ context, args }) {
83285
83577
  }
83286
83578
 
83287
83579
  // src/services/slack-commands.service.ts
83288
- import { readFile as readFile33 } from "node:fs/promises";
83580
+ import { readFile as readFile34 } from "node:fs/promises";
83289
83581
  import { resolve as resolve13 } from "node:path";
83290
83582
  var SLACK_USAGE = `Usage (a person's key; Slack stays the source, the bot joins no channel by itself):
83291
83583
  laze slack overview connected Slack workspaces, mirrors, your link
@@ -83333,7 +83625,7 @@ async function secretLines({ context, args }) {
83333
83625
  throw new CliUsageError("A secret never goes in a flag: pipe it on stdin or use --from-file.");
83334
83626
  }
83335
83627
  const file3 = flagText({ args, name: "from-file" });
83336
- const text2 = file3 ? await readFile33(resolve13(context.cwd, file3), "utf8") : await context.readStdin();
83628
+ const text2 = file3 ? await readFile34(resolve13(context.cwd, file3), "utf8") : await context.readStdin();
83337
83629
  return text2.split("\n").map((line) => line.trim()).filter(Boolean);
83338
83630
  }
83339
83631
  async function secretsOf({
@@ -83637,7 +83929,7 @@ async function slack({
83637
83929
  }
83638
83930
 
83639
83931
  // src/services/sso-commands.service.ts
83640
- import { readFile as readFile34 } from "node:fs/promises";
83932
+ import { readFile as readFile35 } from "node:fs/promises";
83641
83933
  var SSO_USAGE = `Usage:
83642
83934
  laze sso domains claimed domains and how each signs in (admins)
83643
83935
  laze sso claim <domain> the TXT record that proves the domain
@@ -83724,7 +84016,7 @@ function refuseSecretFlags({ args }) {
83724
84016
  }
83725
84017
  async function clientSecretOf({ context, args }) {
83726
84018
  const file3 = flagText({ args, name: "from-file" });
83727
- const text2 = file3 ? await readFile34(file3, "utf8") : await context.readStdin();
84019
+ const text2 = file3 ? await readFile35(file3, "utf8") : await context.readStdin();
83728
84020
  const secret = text2.trim();
83729
84021
  if (!secret) throw new CliUsageError("No client secret: pipe it on stdin or use --from-file.");
83730
84022
  return secret;
@@ -84098,7 +84390,7 @@ async function vaultScrub({ context, args }) {
84098
84390
  }
84099
84391
 
84100
84392
  // src/services/whatsapp-business-commands.service.ts
84101
- import { readFile as readFile35 } from "node:fs/promises";
84393
+ import { readFile as readFile36 } from "node:fs/promises";
84102
84394
  import { resolve as resolve14 } from "node:path";
84103
84395
 
84104
84396
  // ../../modules/whatsapp-business/contract/src/whatsapp-business.prices.ts
@@ -84518,7 +84810,7 @@ async function secretsOf2({ context, args }) {
84518
84810
  const fromConnection = flagText({ args, name: "from-vault" });
84519
84811
  if (fromConnection) return { fromConnection };
84520
84812
  const file3 = flagText({ args, name: "from-file" });
84521
- const text2 = file3 ? await readFile35(resolve14(context.cwd, file3), "utf8") : await context.readStdin();
84813
+ const text2 = file3 ? await readFile36(resolve14(context.cwd, file3), "utf8") : await context.readStdin();
84522
84814
  const lines = text2.split("\n").map((line) => line.trim()).filter(Boolean);
84523
84815
  if (lines.length !== 2) {
84524
84816
  throw new CliUsageError(
@@ -85099,7 +85391,7 @@ async function flags({ context, args }) {
85099
85391
  }
85100
85392
 
85101
85393
  // src/services/workspace-commands.service.ts
85102
- import { readFile as readFile36 } from "node:fs/promises";
85394
+ import { readFile as readFile37 } from "node:fs/promises";
85103
85395
  import { resolve as resolve16 } from "node:path";
85104
85396
  var ROLE_NAMES2 = {
85105
85397
  OWNER: "Owner",
@@ -85282,7 +85574,7 @@ var LOGO_USAGE = "Usage: laze workspace logo set <file.png|jpg|webp> | laze work
85282
85574
  async function readLogo({ context, file: file3 }) {
85283
85575
  let bytes;
85284
85576
  try {
85285
- bytes = new Uint8Array(await readFile36(resolve16(context.cwd, file3)));
85577
+ bytes = new Uint8Array(await readFile37(resolve16(context.cwd, file3)));
85286
85578
  } catch {
85287
85579
  throw new CliUsageError(`No file to read at ${file3}.`);
85288
85580
  }
@@ -85589,7 +85881,7 @@ var HELP = `laze: work in a Laze workspace from your terminal or your agent.
85589
85881
  to your vault first; --save saves it without asking,
85590
85882
  --as-is sends it raw, --keychain workspace saves it
85591
85883
  for everyone
85592
- laze inbox [--wait] [--timeout <s>] messages addressed to your agent
85884
+ laze inbox [--wait] [--timeout <s>] [--take] messages addressed to your agent (--take: from outside its bound session)
85593
85885
  laze search <query> [--channel <c>] [--limit <n>] search messages, and Slack when yours is linked
85594
85886
  the sidebar's search: words, "phrases", from:@name in:#channel has: before: after: is:thread
85595
85887
  laze history <channel> [--before <id>] [--limit <n>] a channel's messages, oldest first
@@ -85950,8 +86242,8 @@ async function runCli({
85950
86242
  // src/services/processes.service.ts
85951
86243
  import { execFile as execFile2, spawn as spawn4 } from "node:child_process";
85952
86244
  import { mkdirSync, openSync } from "node:fs";
85953
- import { readFile as readFile37, readlink } from "node:fs/promises";
85954
- import { dirname as dirname20 } from "node:path";
86245
+ import { readFile as readFile38, readlink } from "node:fs/promises";
86246
+ import { dirname as dirname21 } from "node:path";
85955
86247
  import { promisify as promisify2 } from "node:util";
85956
86248
  var run3 = promisify2(execFile2);
85957
86249
  function alive(pid) {
@@ -85964,15 +86256,15 @@ function alive(pid) {
85964
86256
  }
85965
86257
  }
85966
86258
  async function argsOf(pid) {
85967
- const raw = await readFile37(`/proc/${pid}/cmdline`, "utf8").catch(() => void 0);
86259
+ const raw = await readFile38(`/proc/${pid}/cmdline`, "utf8").catch(() => void 0);
85968
86260
  if (raw) return raw.split("\0").filter(Boolean);
85969
86261
  const listed = await run3("ps", ["-o", "args=", "-p", String(pid)]).catch(() => void 0);
85970
86262
  const line = listed?.stdout.trim();
85971
86263
  return line ? line.split(/\s+/) : void 0;
85972
86264
  }
85973
86265
  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;
86266
+ const stat5 = await readFile38(`/proc/${pid}/stat`, "utf8").catch(() => void 0);
86267
+ const fromStat = stat5 ? Number(stat5.slice(stat5.lastIndexOf(")") + 2).split(" ")[1]) : NaN;
85976
86268
  if (fromStat > 0) return fromStat;
85977
86269
  const listed = await run3("ps", ["-o", "ppid=", "-p", String(pid)]).catch(() => void 0);
85978
86270
  const parent = Number(listed?.stdout.trim());
@@ -85988,7 +86280,7 @@ async function cwdOf(pid) {
85988
86280
  return line ? line.slice(1) : void 0;
85989
86281
  }
85990
86282
  function spawnDetached({ argv, logPath }) {
85991
- mkdirSync(dirname20(logPath), { recursive: true, mode: 448 });
86283
+ mkdirSync(dirname21(logPath), { recursive: true, mode: 448 });
85992
86284
  const log = openSync(logPath, "a", 384);
85993
86285
  const [program = "", ...rest] = argv;
85994
86286
  const child = spawn4(program, rest, { detached: true, stdio: ["ignore", log, log] });