@factory/droid-sdk 0.9.0 → 0.9.1

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.
@@ -1465,6 +1465,7 @@ var ToolConfirmationOutcome = /* @__PURE__ */ ((ToolConfirmationOutcome2) => {
1465
1465
  ToolConfirmationOutcome2["ProceedEdit"] = "proceed_edit";
1466
1466
  ToolConfirmationOutcome2["ProceedAlwaysTools"] = "proceed_always_tools";
1467
1467
  ToolConfirmationOutcome2["ProceedAlwaysServer"] = "proceed_always_server";
1468
+ ToolConfirmationOutcome2["ProceedReportFalsePositive"] = "proceed_report_false_positive";
1468
1469
  ToolConfirmationOutcome2["Cancel"] = "cancel";
1469
1470
  return ToolConfirmationOutcome2;
1470
1471
  })(ToolConfirmationOutcome || {});
@@ -1573,6 +1574,7 @@ var SessionNotificationType = /* @__PURE__ */ ((SessionNotificationType2) => {
1573
1574
  SessionNotificationType2["MCP_STATUS_CHANGED"] = "mcp_status_changed";
1574
1575
  SessionNotificationType2["ASSISTANT_TEXT_DELTA"] = "assistant_text_delta";
1575
1576
  SessionNotificationType2["ASSISTANT_TEXT_COMPLETE"] = "assistant_text_complete";
1577
+ SessionNotificationType2["ASSISTANT_MESSAGE_RETRACTED"] = "assistant_message_retracted";
1576
1578
  SessionNotificationType2["STRUCTURED_OUTPUT"] = "structured_output";
1577
1579
  SessionNotificationType2["THINKING_TEXT_DELTA"] = "thinking_text_delta";
1578
1580
  SessionNotificationType2["THINKING_TEXT_COMPLETE"] = "thinking_text_complete";
@@ -1627,6 +1629,7 @@ var AgentTurnCompletionReason = /* @__PURE__ */ ((AgentTurnCompletionReason3) =>
1627
1629
  AgentTurnCompletionReason3["ModelRequestRejected"] = "model_request_rejected";
1628
1630
  AgentTurnCompletionReason3["ModelProviderUnreachable"] = "model_provider_unreachable";
1629
1631
  AgentTurnCompletionReason3["ModelProviderUnavailable"] = "model_provider_unavailable";
1632
+ AgentTurnCompletionReason3["ModelRateLimited"] = "model_rate_limited";
1630
1633
  AgentTurnCompletionReason3["PromptRejected"] = "prompt_rejected";
1631
1634
  AgentTurnCompletionReason3["CompletionPersistenceFailed"] = "completion_persistence_failed";
1632
1635
  AgentTurnCompletionReason3["NoApproverAvailable"] = "no_approver_available";
@@ -1872,6 +1875,7 @@ var ModelID = /* @__PURE__ */ ((ModelID2) => {
1872
1875
  ModelID2["CLAUDE_OPUS_5_FAST"] = "claude-opus-5-fast";
1873
1876
  ModelID2["CLAUDE_SONNET_5"] = "claude-sonnet-5";
1874
1877
  ModelID2["CLAUDE_FABLE_5"] = "claude-fable-5";
1878
+ ModelID2["CLAUDE_FABLE_5_1"] = "claude-fable-5.1";
1875
1879
  ModelID2["ATLAS_0721"] = "atlas-07-21";
1876
1880
  ModelID2["ASTER_0715"] = "aster-07-15";
1877
1881
  ModelID2["GPT_5"] = "gpt-5-2025-08-07";
@@ -1896,6 +1900,7 @@ var ModelID = /* @__PURE__ */ ((ModelID2) => {
1896
1900
  ModelID2["GPT_5_6_SOL_FAST"] = "gpt-5.6-sol-fast";
1897
1901
  ModelID2["GPT_5_6_TERRA"] = "gpt-5.6-terra";
1898
1902
  ModelID2["GPT_5_6_LUNA"] = "gpt-5.6-luna";
1903
+ ModelID2["GPT_6_ASTRA"] = "gpt-6-astra";
1899
1904
  ModelID2["GPT_IMAGE_2"] = "gpt-image-2";
1900
1905
  ModelID2["GPT_TRANSCRIBE"] = "gpt-transcribe";
1901
1906
  ModelID2["GPT_4O_MINI_TRANSCRIBE"] = "gpt-4o-mini-transcribe";
@@ -1907,6 +1912,7 @@ var ModelID = /* @__PURE__ */ ((ModelID2) => {
1907
1912
  ModelID2["GEMINI_3_5_FLASH"] = "gemini-3.5-flash";
1908
1913
  ModelID2["GEMINI_3_6_FLASH"] = "gemini-3.6-flash";
1909
1914
  ModelID2["GEMINI_3_7_FLASH"] = "gemini-3.7-flash";
1915
+ ModelID2["GEMINI_3_8_FLASH"] = "gemini-3.8-flash";
1910
1916
  ModelID2["GEMINI_3_PRO_IMAGE"] = "gemini-3-pro-image-preview";
1911
1917
  ModelID2["GARNET_0715"] = "garnet-07-15";
1912
1918
  ModelID2["GROK_4_5"] = "grok-4.5";
@@ -2288,6 +2294,9 @@ var ToolUseSchema = z2.object({
2288
2294
  name: z2.string(),
2289
2295
  thoughtSignature: z2.string().optional(),
2290
2296
  // Gemini thought signature
2297
+ // OpenAI Responses function_call.namespace (native client tool search).
2298
+ // Provider-emitted and replayed verbatim; never synthesized.
2299
+ namespace: z2.string().optional(),
2291
2300
  scriptExecution: z2.object({
2292
2301
  runId: z2.string(),
2293
2302
  outerToolUseId: z2.string()
@@ -3135,6 +3144,10 @@ var AssistantTextCompleteNotificationSchema = z11.object({
3135
3144
  messageId: z11.string(),
3136
3145
  blockIndex: z11.number()
3137
3146
  });
3147
+ var AssistantMessageRetractedNotificationSchema = z11.object({
3148
+ type: z11.literal("assistant_message_retracted" /* ASSISTANT_MESSAGE_RETRACTED */),
3149
+ messageId: z11.string()
3150
+ });
3138
3151
  var StructuredOutputNotificationSchema = z11.object({
3139
3152
  type: z11.literal("structured_output" /* STRUCTURED_OUTPUT */),
3140
3153
  messageId: z11.string(),
@@ -3342,7 +3355,8 @@ var SessionNotificationSchemaList = [
3342
3355
  // N[] aliases in schemas/sdk-local.ts keep their canonical indices.
3343
3356
  SessionWorkingDirectoryChangedNotificationSchema,
3344
3357
  LlmRetryNotificationSchema,
3345
- ToolExecutionPhaseChangedNotificationSchema
3358
+ ToolExecutionPhaseChangedNotificationSchema,
3359
+ AssistantMessageRetractedNotificationSchema
3346
3360
  ];
3347
3361
  var SessionNotificationParamsSchema = z11.object({
3348
3362
  sessionId: z11.string().optional(),
@@ -3891,9 +3905,10 @@ var InitializeSessionRequestParamsSchema = z14.object({
3891
3905
  */
3892
3906
  worktree: z14.boolean().optional(),
3893
3907
  /**
3894
- * Optional override for the worktrees root this session's checkout is
3895
- * created under. Falls back to the user's `worktreeDirectory` setting
3896
- * (or that setting's default root) when omitted.
3908
+ * @deprecated Ignored once Desktop worktrees are on: the checkout is
3909
+ * created under the single root the user's `worktreeDirectory` setting
3910
+ * names, so that only one root's worktrees have their lifecycle managed.
3911
+ * Kept for wire compatibility with clients that still send it.
3897
3912
  */
3898
3913
  worktreeDir: z14.string().optional(),
3899
3914
  /**
@@ -5428,291 +5443,8 @@ var DaemonCronStateChangedNotificationSchema = JsonRpcBaseNotificationSchema.ext
5428
5443
  // ../droid-sdk-core/src/protocol/daemon/schemas/droid.ts
5429
5444
  import z31 from "zod";
5430
5445
 
5431
- // ../droid-sdk-core/src/protocol/droid/constants.ts
5432
- var seconds = (value) => value * 1e3;
5433
- var minutes = (value) => seconds(value * 60);
5434
- var hours = (value) => minutes(value * 60);
5435
- var LOOP_INTERVAL_POLICY = {
5436
- minMs: minutes(1),
5437
- maxMs: hours(24),
5438
- displayRange: "1m\u201324h",
5439
- examples: "5m, 30m, 2h"
5440
- };
5441
- var SYSTEM_REMINDER_START = "<system-reminder>";
5442
- var SYSTEM_REMINDER_END = "</system-reminder>";
5443
- var SYSTEM_NOTIFICATION_START = "<system-notification>";
5444
- var SYSTEM_NOTIFICATION_END = "</system-notification>";
5445
- var DROID_RUNNING_STATES = [
5446
- "thinking" /* Thinking */,
5447
- "streaming_assistant_message" /* StreamingAssistantMessage */,
5448
- "executing_tool" /* ExecutingTool */,
5449
- "compacting_conversation" /* CompactingConversation */
5450
- ];
5451
- var DROID_IN_PROGRESS_STATES = [
5452
- ...DROID_RUNNING_STATES,
5453
- "waiting_for_tool_confirmation" /* WaitingForToolConfirmation */
5454
- ];
5455
-
5456
- // ../droid-sdk-core/src/protocol/droid/tool-execution-lifecycle.ts
5457
- function getToolExecutionLifecyclePhaseRank(phase) {
5458
- switch (phase) {
5459
- case "streaming_input" /* StreamingInput */:
5460
- return 0;
5461
- case "queued" /* Queued */:
5462
- return 1;
5463
- case "executing" /* Executing */:
5464
- return 2;
5465
- case "settled_after_execution" /* SettledAfterExecution */:
5466
- case "settled_without_execution" /* SettledWithoutExecution */:
5467
- case "settled_unknown" /* SettledUnknown */:
5468
- return 3;
5469
- }
5470
- }
5471
- function mergeToolExecutionLifecyclePhase(current, next) {
5472
- if (!current) return next;
5473
- if (!next) return current;
5474
- return getToolExecutionLifecyclePhaseRank(next) > getToolExecutionLifecyclePhaseRank(current) ? next : current;
5475
- }
5476
- function settleToolExecutionLifecyclePhase(phase) {
5477
- if (phase === "settled_after_execution" /* SettledAfterExecution */ || phase === "settled_without_execution" /* SettledWithoutExecution */ || phase === "settled_unknown" /* SettledUnknown */) {
5478
- return phase;
5479
- }
5480
- if (phase === "executing" /* Executing */) {
5481
- return "settled_after_execution" /* SettledAfterExecution */;
5482
- }
5483
- if (phase === "streaming_input" /* StreamingInput */ || phase === "queued" /* Queued */) {
5484
- return "settled_without_execution" /* SettledWithoutExecution */;
5485
- }
5486
- return "settled_unknown" /* SettledUnknown */;
5487
- }
5488
-
5489
- // ../droid-sdk-core/src/protocol/droid/schemas/constants.ts
5490
- var FACTORY_PROTOCOL_VERSION = "1.193.0";
5491
- var FACTORY_CLIENT_HEADER = "X-Factory-Client";
5492
- var FACTORY_SDK_HEADER = "X-Factory-Sdk";
5493
- var FACTORY_CLIENT_VERSION = "X-Client-Version";
5494
- var LEGACY_FACTORY_API_VERSION2 = LEGACY_FACTORY_API_VERSION;
5495
- var JSONRPC_VERSION2 = JSONRPC_VERSION;
5496
-
5497
- // ../droid-sdk-core/src/protocol/droid/schemas/automations.ts
5498
- import z18 from "zod";
5499
- var ExecutionLocationSchema = z18.enum(["local", "remote"]);
5500
- var AutomationStatusSchema = z18.enum(["active", "paused"]);
5501
- var AutomationIdSchema = z18.string().trim().min(1);
5502
- var PromptSchema = z18.string().trim().min(1);
5503
- function requireField(ctx, field, message) {
5504
- ctx.addIssue({ code: z18.ZodIssueCode.custom, path: [field], message });
5505
- }
5506
- var AutomationCreateToolInputSchema = z18.object({
5507
- executionLocation: ExecutionLocationSchema.describe(
5508
- 'Where the automation runs: "local" creates a local filesystem automation on this machine; "remote" creates a cloud automation that runs on a droid computer.'
5509
- ),
5510
- name: z18.string().trim().min(1).max(128).describe("Display name for the automation."),
5511
- schedule: z18.string().trim().min(1).describe(
5512
- "A 5-field cron expression for local automations, or a 5-field cron expression/natural-language cadence for remote automations."
5513
- ),
5514
- prompt: PromptSchema.describe(
5515
- "Agent instructions to run on each scheduled tick."
5516
- ),
5517
- status: AutomationStatusSchema.optional().default("active").describe(
5518
- 'Initial status. Use "paused" when creating an automation for a draft Software Factory workstream.'
5519
- ),
5520
- description: z18.string().trim().max(1024).optional().describe("Optional description."),
5521
- visualization_instruction: z18.string().trim().min(1).optional().describe(
5522
- 'Optional visualization guidance, folded into the run prompt as a "## Visualization" section.'
5523
- ),
5524
- memory_instruction: z18.string().trim().min(1).optional().describe(
5525
- 'Optional memory guidance, folded into the run prompt as a "## Memory & Evolution" section.'
5526
- ),
5527
- computerId: z18.string().trim().min(1).optional().describe(
5528
- "ID of the droid computer the automation runs on. Remote automations require computerId or computerName."
5529
- ),
5530
- computerName: z18.string().trim().min(1).optional().describe(
5531
- "Name of the droid computer the automation runs on, resolved to its ID at creation time (use ListComputers to see available names). Remote automations require computerId or computerName; if the name matches multiple computers, ask the user which one to use and retry with its computerId."
5532
- ),
5533
- executionTemplateId: z18.string().trim().min(1).optional().describe(
5534
- "ID of the Execution Template used to provision a fresh Computer for every remote automation run."
5535
- ),
5536
- workstreamId: z18.string().trim().min(1).max(128).optional().describe(
5537
- "Optional Software Factory workstream id. Set this when the automation is created as part of a workstream so it stays linked to that workstream."
5538
- ),
5539
- tags: z18.array(z18.string().trim().min(1).max(128)).max(16).optional().describe(
5540
- 'Optional tags stored on the remote automation, used for grouping and lifecycle linkage (e.g. "sf-workstream:<id>" ties the automation to a Software Factory workstream so workstream deletion removes it). Remote automations only.'
5541
- )
5542
- }).superRefine((data, ctx) => {
5543
- const remoteTargets = [
5544
- data.computerId,
5545
- data.computerName,
5546
- data.executionTemplateId
5547
- ].filter((target) => target !== void 0);
5548
- if (data.executionLocation === "remote" && remoteTargets.length === 0) {
5549
- requireField(
5550
- ctx,
5551
- "computerId",
5552
- 'computerId, computerName, or executionTemplateId is required when executionLocation is "remote".'
5553
- );
5554
- }
5555
- if (remoteTargets.length > 1) {
5556
- requireField(
5557
- ctx,
5558
- data.executionTemplateId ? "executionTemplateId" : "computerName",
5559
- "Provide exactly one of computerId, computerName, or executionTemplateId."
5560
- );
5561
- }
5562
- if (data.executionLocation === "local" && data.computerId) {
5563
- requireField(
5564
- ctx,
5565
- "computerId",
5566
- 'computerId is only supported when executionLocation is "remote".'
5567
- );
5568
- }
5569
- if (data.executionLocation === "local" && data.computerName) {
5570
- requireField(
5571
- ctx,
5572
- "computerName",
5573
- 'computerName is only supported when executionLocation is "remote".'
5574
- );
5575
- }
5576
- if (data.executionLocation === "local" && data.executionTemplateId) {
5577
- requireField(
5578
- ctx,
5579
- "executionTemplateId",
5580
- 'executionTemplateId is only supported when executionLocation is "remote".'
5581
- );
5582
- }
5583
- if (data.executionLocation === "local" && data.tags) {
5584
- requireField(
5585
- ctx,
5586
- "tags",
5587
- 'tags are only supported when executionLocation is "remote".'
5588
- );
5589
- }
5590
- });
5591
- var AutomationListToolInputSchema = z18.object({
5592
- executionLocation: ExecutionLocationSchema.describe(
5593
- 'Where to list automations from: "local" for this machine or "remote" for cloud automations.'
5594
- )
5595
- });
5596
- var AutomationReadToolInputSchema = z18.object({
5597
- executionLocation: ExecutionLocationSchema.describe(
5598
- 'Where to read the automation from: "local" for this machine or "remote" for cloud automations.'
5599
- ),
5600
- automationId: AutomationIdSchema.describe("Automation id.")
5601
- });
5602
- var AutomationDeleteToolInputSchema = z18.object({
5603
- executionLocation: ExecutionLocationSchema.describe(
5604
- 'Where to delete the automation from: "local" for this machine or "remote" for cloud automations.'
5605
- ),
5606
- automationId: AutomationIdSchema.describe("Automation id.")
5607
- });
5608
- var AutomationEditToolInputSchema = z18.object({
5609
- executionLocation: ExecutionLocationSchema.describe(
5610
- 'Where to edit the automation: "local" for this machine or "remote" for cloud automations.'
5611
- ),
5612
- automationId: AutomationIdSchema.describe("Automation id."),
5613
- name: z18.string().trim().min(1).max(128).optional().describe("New display name."),
5614
- description: z18.string().trim().max(1024).optional().describe("New description."),
5615
- schedule: z18.string().trim().min(1).optional().describe("New cron expression or natural-language cadence."),
5616
- prompt: PromptSchema.optional().describe("New agent instructions."),
5617
- status: AutomationStatusSchema.optional().describe(
5618
- 'New status: "active" or "paused".'
5619
- ),
5620
- computerId: z18.string().trim().min(1).optional().describe("Move a remote automation to a different computer.")
5621
- }).superRefine((data, ctx) => {
5622
- const hasAnyUpdate = data.name !== void 0 || data.description !== void 0 || data.schedule !== void 0 || data.prompt !== void 0 || data.status !== void 0 || data.computerId !== void 0;
5623
- if (!hasAnyUpdate) {
5624
- ctx.addIssue({
5625
- code: z18.ZodIssueCode.custom,
5626
- message: "Provide at least one field to update."
5627
- });
5628
- }
5629
- if (data.executionLocation === "local") {
5630
- if (data.description !== void 0) {
5631
- requireField(
5632
- ctx,
5633
- "description",
5634
- 'description is only supported when executionLocation is "remote".'
5635
- );
5636
- }
5637
- if (data.schedule !== void 0) {
5638
- requireField(
5639
- ctx,
5640
- "schedule",
5641
- 'schedule edits are only supported when executionLocation is "remote".'
5642
- );
5643
- }
5644
- if (data.computerId !== void 0) {
5645
- requireField(
5646
- ctx,
5647
- "computerId",
5648
- 'computerId is only supported when executionLocation is "remote".'
5649
- );
5650
- }
5651
- }
5652
- });
5653
-
5654
- // ../droid-sdk-core/src/protocol/droid/schemas/loop-tool.ts
5655
- import z19 from "zod";
5656
- var CronExpressionSchema = z19.string().trim().regex(/^(\S+\s+){4}\S+$/, "Expected a standard 5-field cron expression");
5657
- var LoopToolInputSchema = z19.object({
5658
- action: z19.enum(["create", "list", "cancel"]).describe("Operation to perform: create, list, or cancel."),
5659
- prompt: z19.string().trim().min(1).optional().describe('Recurring prompt. Required when action is "create".'),
5660
- cron: CronExpressionSchema.optional().describe(
5661
- "5-field cron expression in UTC. Pure step cadences are anchored to loop creation."
5662
- ),
5663
- loopId: z19.string().trim().min(1).optional().describe(
5664
- 'Loop ID returned by the "list" action. Required when action is "cancel".'
5665
- ),
5666
- runImmediately: z19.boolean().optional().describe(
5667
- 'Also fire once on creation. Defaults to true; only valid for action "create".'
5668
- )
5669
- }).superRefine((data, ctx) => {
5670
- const addRequiredIssue = (field) => {
5671
- ctx.addIssue({
5672
- code: z19.ZodIssueCode.custom,
5673
- path: [field],
5674
- message: `"${field}" is required when action is "${data.action}".`
5675
- });
5676
- };
5677
- const rejectField = (field) => {
5678
- if (data[field] === void 0) return;
5679
- ctx.addIssue({
5680
- code: z19.ZodIssueCode.custom,
5681
- path: [field],
5682
- message: `"${field}" is not valid when action is "${data.action}".`
5683
- });
5684
- };
5685
- switch (data.action) {
5686
- case "create":
5687
- if (data.prompt === void 0) addRequiredIssue("prompt");
5688
- if (data.cron === void 0) addRequiredIssue("cron");
5689
- rejectField("loopId");
5690
- break;
5691
- case "list":
5692
- rejectField("prompt");
5693
- rejectField("cron");
5694
- rejectField("loopId");
5695
- rejectField("runImmediately");
5696
- break;
5697
- case "cancel":
5698
- if (data.loopId === void 0) addRequiredIssue("loopId");
5699
- rejectField("prompt");
5700
- rejectField("cron");
5701
- rejectField("runImmediately");
5702
- break;
5703
- default:
5704
- break;
5705
- }
5706
- });
5707
-
5708
- // ../droid-sdk-core/src/protocol/session/tags/constants.ts
5709
- var SESSION_TAG_SUBAGENT = "subagent";
5710
-
5711
- // ../droid-sdk-core/src/protocol/sessionV2/constants.ts
5712
- var TOOL_RESULT_PENDING_MARKER = "__TOOL_RESULT_PENDING__";
5713
-
5714
5446
  // ../droid-sdk-core/src/protocol/daemon/schemas/automations.ts
5715
- import z20 from "zod";
5447
+ import z18 from "zod";
5716
5448
  var AutomationTemplateId = /* @__PURE__ */ ((AutomationTemplateId2) => {
5717
5449
  AutomationTemplateId2["CodeReview"] = "code-review";
5718
5450
  AutomationTemplateId2["Qa"] = "qa";
@@ -5733,48 +5465,48 @@ var AutomationRunType = /* @__PURE__ */ ((AutomationRunType2) => {
5733
5465
  AutomationRunType2["Run"] = "run";
5734
5466
  return AutomationRunType2;
5735
5467
  })(AutomationRunType || {});
5736
- var DaemonListAutomationsRequestParamsSchema = z20.object({
5737
- basePath: z20.string().optional()
5468
+ var DaemonListAutomationsRequestParamsSchema = z18.object({
5469
+ basePath: z18.string().optional()
5738
5470
  });
5739
5471
  var DaemonListAutomationsRequestSchema = JsonRpcBaseRequestSchema.extend({
5740
- method: z20.literal("daemon.list_automations" /* LIST_AUTOMATIONS */),
5472
+ method: z18.literal("daemon.list_automations" /* LIST_AUTOMATIONS */),
5741
5473
  params: DaemonListAutomationsRequestParamsSchema
5742
5474
  });
5743
- var AutomationEntrySchema = z20.object({
5475
+ var AutomationEntrySchema = z18.object({
5744
5476
  /** Directory name slug (e.g. "health-check"). Kept as `id` because protocol rules forbid renaming required fields. */
5745
- id: z20.string(),
5477
+ id: z18.string(),
5746
5478
  /** Stable UUID from HEARTBEAT.md frontmatter, used for backend/Firestore sync. */
5747
- uuid: z20.string().optional(),
5748
- name: z20.string(),
5749
- description: z20.string().optional(),
5750
- prompt: z20.string().optional(),
5751
- status: z20.string(),
5752
- schedule: z20.string().optional(),
5753
- model: z20.string().optional(),
5479
+ uuid: z18.string().optional(),
5480
+ name: z18.string(),
5481
+ description: z18.string().optional(),
5482
+ prompt: z18.string().optional(),
5483
+ status: z18.string(),
5484
+ schedule: z18.string().optional(),
5485
+ model: z18.string().optional(),
5754
5486
  /** Optional reasoning effort for run sessions (loose string; clamped to the model's supported efforts at run time). */
5755
- reasoningEffort: z20.string().optional(),
5756
- tags: z20.array(z20.string()).optional(),
5757
- nextRunAt: z20.string().optional(),
5758
- lastRunAt: z20.string().optional(),
5487
+ reasoningEffort: z18.string().optional(),
5488
+ tags: z18.array(z18.string()).optional(),
5489
+ nextRunAt: z18.string().optional(),
5490
+ lastRunAt: z18.string().optional(),
5759
5491
  /** Terminal status of the last run (daemon-written to memory/state.json). Drives Software Factory health (`lastRunStatus === Success`). */
5760
- lastRunStatus: z20.string().optional(),
5761
- isValid: z20.boolean(),
5762
- path: z20.string(),
5492
+ lastRunStatus: z18.string().optional(),
5493
+ isValid: z18.boolean(),
5494
+ path: z18.string(),
5763
5495
  /** Template this automation was created from (e.g. `triage`), parsed from HEARTBEAT.md frontmatter. Drives Software Factory SDLC-stage categorization. */
5764
- templateId: z20.nativeEnum(AutomationTemplateId).optional(),
5765
- privacyLevel: z20.string().optional(),
5496
+ templateId: z18.nativeEnum(AutomationTemplateId).optional(),
5497
+ privacyLevel: z18.string().optional(),
5766
5498
  /** Run-session privacy from HEARTBEAT.md frontmatter (loose string; absent = private). */
5767
- sessionPrivacy: z20.string().optional(),
5768
- createdBy: z20.object({
5769
- name: z20.string(),
5770
- email: z20.string().optional(),
5771
- avatarUrl: z20.string().optional()
5499
+ sessionPrivacy: z18.string().optional(),
5500
+ createdBy: z18.object({
5501
+ name: z18.string(),
5502
+ email: z18.string().optional(),
5503
+ avatarUrl: z18.string().optional()
5772
5504
  }).optional(),
5773
- forkedFrom: z20.string().optional(),
5505
+ forkedFrom: z18.string().optional(),
5774
5506
  /** Optional project directory the automation runs from (HEARTBEAT.md frontmatter). */
5775
- workingDirectory: z20.string().optional(),
5507
+ workingDirectory: z18.string().optional(),
5776
5508
  /** Present when the automation targets a remote computer. */
5777
- computerId: z20.string().optional(),
5509
+ computerId: z18.string().optional(),
5778
5510
  /**
5779
5511
  * Owning machine of the automation: `LOCAL_MACHINE_ID` for the local
5780
5512
  * daemon's own automations, or the computer's id for a computer daemon.
@@ -5782,15 +5514,15 @@ var AutomationEntrySchema = z20.object({
5782
5514
  * (`computerId` cannot distinguish them because BYOM-registered local
5783
5515
  * machines stamp a `computerId` on local automations too).
5784
5516
  */
5785
- machineId: z20.string().optional(),
5517
+ machineId: z18.string().optional(),
5786
5518
  /**
5787
5519
  * `hostId` of the machine whose daemon last synced this automation's files
5788
5520
  * (backend-merged entries only; see the v0 Automation schema). Lets clients
5789
5521
  * detect that the current machine owns an orphaned doc's files.
5790
5522
  */
5791
- hostId: z20.string().optional(),
5523
+ hostId: z18.string().optional(),
5792
5524
  /** Software Factory workstream id (memory/state.json), when the automation was created by a workstream. */
5793
- workstreamId: z20.string().optional(),
5525
+ workstreamId: z18.string().optional(),
5794
5526
  /**
5795
5527
  * Backend-persisted setup lifecycle for computer automations (mirrors
5796
5528
  * `AutomationSetupState`). Carried through the daemon wire so desktop
@@ -5801,13 +5533,13 @@ var AutomationEntrySchema = z20.object({
5801
5533
  * from the discarded backend copy as a fallback. String-typed so a
5802
5534
  * future state does not break older clients.
5803
5535
  */
5804
- setupState: z20.string().optional()
5536
+ setupState: z18.string().optional()
5805
5537
  });
5806
- var AutomationPendingSetupSchema = z20.object({
5538
+ var AutomationPendingSetupSchema = z18.object({
5807
5539
  /** Backend automation UUID (Firestore doc id) the setup session owns. */
5808
- automationUuid: z20.string(),
5540
+ automationUuid: z18.string(),
5809
5541
  /** Droid session performing the setup, when known. */
5810
- sessionId: z20.string().optional(),
5542
+ sessionId: z18.string().optional(),
5811
5543
  /**
5812
5544
  * Daemon-evaluated setup state. Level-based, computed at read time from
5813
5545
  * files on disk, session liveness, and the session's working state:
@@ -5816,78 +5548,78 @@ var AutomationPendingSetupSchema = z20.object({
5816
5548
  * String-typed so a future state does not break older clients; values
5817
5549
  * mirror `AutomationSetupState`.
5818
5550
  */
5819
- state: z20.string(),
5551
+ state: z18.string(),
5820
5552
  /** ISO timestamp the setup session was registered. */
5821
- startedAt: z20.string().optional()
5553
+ startedAt: z18.string().optional()
5822
5554
  });
5823
- var DaemonListAutomationsResultSchema = z20.object({
5824
- automations: z20.array(AutomationEntrySchema),
5555
+ var DaemonListAutomationsResultSchema = z18.object({
5556
+ automations: z18.array(AutomationEntrySchema),
5825
5557
  /**
5826
5558
  * In-flight deferScaffold setups on this daemon (see
5827
5559
  * `AutomationPendingSetupSchema`). Absent from pre-fix daemons and when no
5828
5560
  * setup is pending.
5829
5561
  */
5830
- pendingSetups: z20.array(AutomationPendingSetupSchema).optional()
5562
+ pendingSetups: z18.array(AutomationPendingSetupSchema).optional()
5831
5563
  });
5832
- var AutomationScaffoldSkillFileSchema = z20.object({
5564
+ var AutomationScaffoldSkillFileSchema = z18.object({
5833
5565
  /** URL-safe encoding (encodeURIComponent) of the path relative to the skill directory. */
5834
- fileId: z20.string(),
5566
+ fileId: z18.string(),
5835
5567
  /** Raw file content; absent when the mirror holds metadata only. */
5836
- content: z20.string().optional(),
5568
+ content: z18.string().optional(),
5837
5569
  /** sha256 hex of the raw file bytes; verified before the daemon writes. */
5838
- fingerprint: z20.string()
5570
+ fingerprint: z18.string()
5839
5571
  });
5840
- var AutomationScaffoldSkillSchema = z20.object({
5572
+ var AutomationScaffoldSkillSchema = z18.object({
5841
5573
  /** Skill directory name under `skills/`. */
5842
- name: z20.string(),
5574
+ name: z18.string(),
5843
5575
  /** SKILL.md content; when absent the whole skill is skipped. */
5844
- content: z20.string().optional(),
5576
+ content: z18.string().optional(),
5845
5577
  /** sha256 hex of the raw SKILL.md bytes; verified before the daemon writes. */
5846
- fingerprint: z20.string(),
5578
+ fingerprint: z18.string(),
5847
5579
  /** The skill's files other than SKILL.md. */
5848
- supportingFiles: z20.array(AutomationScaffoldSkillFileSchema).optional()
5580
+ supportingFiles: z18.array(AutomationScaffoldSkillFileSchema).optional()
5849
5581
  });
5850
- var DaemonRunAutomationRequestParamsSchema = z20.object({
5851
- automationId: z20.string(),
5582
+ var DaemonRunAutomationRequestParamsSchema = z18.object({
5583
+ automationId: z18.string(),
5852
5584
  /** Directory name of the automation (e.g. "health-check"). Preferred over automationId. */
5853
- automationDirName: z20.string().optional(),
5854
- basePath: z20.string().optional(),
5585
+ automationDirName: z18.string().optional(),
5586
+ basePath: z18.string().optional(),
5855
5587
  /** When set, fetches the automation from the backend API instead of local filesystem. */
5856
- computerId: z20.string().optional(),
5588
+ computerId: z18.string().optional(),
5857
5589
  /**
5858
5590
  * Skills to write when the run-time ensure rebuilds a missing scaffold from
5859
5591
  * the Firestore backup. Ignored when the automation directory already
5860
5592
  * exists on disk.
5861
5593
  */
5862
- skills: z20.array(AutomationScaffoldSkillSchema).optional(),
5594
+ skills: z18.array(AutomationScaffoldSkillSchema).optional(),
5863
5595
  /**
5864
5596
  * Memory files to write when the run-time ensure rebuilds a missing
5865
5597
  * scaffold from the Firestore mirror. Ignored when the automation directory
5866
5598
  * already exists on disk.
5867
5599
  */
5868
- memoryFiles: z20.array(AutomationScaffoldSkillFileSchema).optional()
5600
+ memoryFiles: z18.array(AutomationScaffoldSkillFileSchema).optional()
5869
5601
  });
5870
5602
  var DaemonRunAutomationRequestSchema = JsonRpcBaseRequestSchema.extend(
5871
5603
  {
5872
- method: z20.literal("daemon.run_automation" /* RUN_AUTOMATION */),
5604
+ method: z18.literal("daemon.run_automation" /* RUN_AUTOMATION */),
5873
5605
  params: DaemonRunAutomationRequestParamsSchema
5874
5606
  }
5875
5607
  );
5876
- var DaemonRunAutomationResultSchema = z20.object({
5877
- prompt: z20.string(),
5878
- automationName: z20.string(),
5608
+ var DaemonRunAutomationResultSchema = z18.object({
5609
+ prompt: z18.string(),
5610
+ automationName: z18.string(),
5879
5611
  /** UUID from HEARTBEAT.md frontmatter (falls back to directory name if no UUID) */
5880
- automationId: z20.string(),
5612
+ automationId: z18.string(),
5881
5613
  /** Template this automation was created from, when known. */
5882
- templateId: z20.nativeEnum(AutomationTemplateId).optional(),
5883
- cwd: z20.string(),
5614
+ templateId: z18.nativeEnum(AutomationTemplateId).optional(),
5615
+ cwd: z18.string(),
5884
5616
  /**
5885
5617
  * The model to run on. Omitted when the automation pins no model, and also
5886
5618
  * when its configured model could not be resolved on this machine, in which
5887
5619
  * case `modelFallback` explains the omission and the run uses the daemon
5888
5620
  * default.
5889
5621
  */
5890
- model: z20.string().optional(),
5622
+ model: z18.string().optional(),
5891
5623
  /**
5892
5624
  * Set when the automation's configured model was dropped because it does not
5893
5625
  * resolve on this machine. The run still proceeds on the daemon default;
@@ -5895,15 +5627,15 @@ var DaemonRunAutomationResultSchema = z20.object({
5895
5627
  */
5896
5628
  modelFallback: ModelFallbackSchema.optional(),
5897
5629
  /** Optional reasoning effort for the run session. */
5898
- reasoningEffort: z20.string().optional(),
5630
+ reasoningEffort: z18.string().optional(),
5899
5631
  /**
5900
5632
  * Run-session privacy resolved from the automation's config (loose string;
5901
5633
  * absent = private). Lets run dispatchers map `team` to an org-visible
5902
5634
  * session doc without a separate backend read.
5903
5635
  */
5904
- sessionPrivacy: z20.string().optional(),
5636
+ sessionPrivacy: z18.string().optional(),
5905
5637
  /** Present when the automation targets a remote computer. */
5906
- computerId: z20.string().optional(),
5638
+ computerId: z18.string().optional(),
5907
5639
  /**
5908
5640
  * System-reminder block mapping scaffold-relative paths (VISUAL.html,
5909
5641
  * memory/, reports/) to the automation directory. Present only when the
@@ -5912,62 +5644,62 @@ var DaemonRunAutomationResultSchema = z20.object({
5912
5644
  * separately for consumers that build their own run prompt instead of
5913
5645
  * using `prompt` (e.g. the backend computer-run workflow).
5914
5646
  */
5915
- scaffoldReminder: z20.string().optional()
5647
+ scaffoldReminder: z18.string().optional()
5916
5648
  });
5917
- var DaemonPauseAutomationRequestParamsSchema = z20.object({
5918
- automationId: z20.string(),
5919
- automationDirName: z20.string().optional(),
5920
- basePath: z20.string().optional()
5649
+ var DaemonPauseAutomationRequestParamsSchema = z18.object({
5650
+ automationId: z18.string(),
5651
+ automationDirName: z18.string().optional(),
5652
+ basePath: z18.string().optional()
5921
5653
  });
5922
5654
  var DaemonPauseAutomationRequestSchema = JsonRpcBaseRequestSchema.extend({
5923
- method: z20.literal("daemon.pause_automation" /* PAUSE_AUTOMATION */),
5655
+ method: z18.literal("daemon.pause_automation" /* PAUSE_AUTOMATION */),
5924
5656
  params: DaemonPauseAutomationRequestParamsSchema
5925
5657
  });
5926
- var DaemonPauseAutomationResultSchema = z20.object({
5927
- success: z20.boolean(),
5928
- automationId: z20.string(),
5929
- status: z20.string(),
5930
- error: z20.string().optional()
5658
+ var DaemonPauseAutomationResultSchema = z18.object({
5659
+ success: z18.boolean(),
5660
+ automationId: z18.string(),
5661
+ status: z18.string(),
5662
+ error: z18.string().optional()
5931
5663
  });
5932
- var DaemonResumeAutomationRequestParamsSchema = z20.object({
5933
- automationId: z20.string(),
5934
- automationDirName: z20.string().optional(),
5935
- basePath: z20.string().optional()
5664
+ var DaemonResumeAutomationRequestParamsSchema = z18.object({
5665
+ automationId: z18.string(),
5666
+ automationDirName: z18.string().optional(),
5667
+ basePath: z18.string().optional()
5936
5668
  });
5937
5669
  var DaemonResumeAutomationRequestSchema = JsonRpcBaseRequestSchema.extend({
5938
- method: z20.literal("daemon.resume_automation" /* RESUME_AUTOMATION */),
5670
+ method: z18.literal("daemon.resume_automation" /* RESUME_AUTOMATION */),
5939
5671
  params: DaemonResumeAutomationRequestParamsSchema
5940
5672
  });
5941
- var DaemonResumeAutomationResultSchema = z20.object({
5942
- success: z20.boolean(),
5943
- automationId: z20.string(),
5944
- status: z20.string(),
5945
- error: z20.string().optional()
5673
+ var DaemonResumeAutomationResultSchema = z18.object({
5674
+ success: z18.boolean(),
5675
+ automationId: z18.string(),
5676
+ status: z18.string(),
5677
+ error: z18.string().optional()
5946
5678
  });
5947
- var DaemonGetAutomationHistoryRequestParamsSchema = z20.object({
5948
- automationId: z20.string(),
5949
- automationDirName: z20.string().optional(),
5950
- limit: z20.number().optional(),
5951
- offset: z20.number().optional(),
5952
- basePath: z20.string().optional()
5679
+ var DaemonGetAutomationHistoryRequestParamsSchema = z18.object({
5680
+ automationId: z18.string(),
5681
+ automationDirName: z18.string().optional(),
5682
+ limit: z18.number().optional(),
5683
+ offset: z18.number().optional(),
5684
+ basePath: z18.string().optional()
5953
5685
  });
5954
5686
  var DaemonGetAutomationHistoryRequestSchema = JsonRpcBaseRequestSchema.extend({
5955
- method: z20.literal("daemon.get_automation_history" /* GET_AUTOMATION_HISTORY */),
5687
+ method: z18.literal("daemon.get_automation_history" /* GET_AUTOMATION_HISTORY */),
5956
5688
  params: DaemonGetAutomationHistoryRequestParamsSchema
5957
5689
  });
5958
- var AutomationRunRecordSchema = z20.object({
5959
- runId: z20.string(),
5960
- automationId: z20.string(),
5961
- type: z20.nativeEnum(AutomationRunType).optional(),
5962
- status: z20.string(),
5963
- startedAt: z20.string(),
5964
- completedAt: z20.string().optional(),
5965
- durationMs: z20.number().optional(),
5966
- errorMessage: z20.string().optional(),
5967
- isRetry: z20.boolean().optional(),
5968
- originalRunId: z20.string().optional(),
5690
+ var AutomationRunRecordSchema = z18.object({
5691
+ runId: z18.string(),
5692
+ automationId: z18.string(),
5693
+ type: z18.nativeEnum(AutomationRunType).optional(),
5694
+ status: z18.string(),
5695
+ startedAt: z18.string(),
5696
+ completedAt: z18.string().optional(),
5697
+ durationMs: z18.number().optional(),
5698
+ errorMessage: z18.string().optional(),
5699
+ isRetry: z18.boolean().optional(),
5700
+ originalRunId: z18.string().optional(),
5969
5701
  /** Droid session that executed this run, when dispatched as a real session. */
5970
- sessionId: z20.string().optional(),
5702
+ sessionId: z18.string().optional(),
5971
5703
  /**
5972
5704
  * Set when this run's configured model was dropped at spawn time. Scheduled
5973
5705
  * runs fire without a caller to receive the run-time result, so the history
@@ -5975,277 +5707,575 @@ var AutomationRunRecordSchema = z20.object({
5975
5707
  */
5976
5708
  modelFallback: ModelFallbackSchema.optional()
5977
5709
  });
5978
- var DaemonGetAutomationHistoryResultSchema = z20.object({
5979
- automationId: z20.string(),
5980
- runs: z20.array(AutomationRunRecordSchema),
5981
- totalCount: z20.number()
5710
+ var DaemonGetAutomationHistoryResultSchema = z18.object({
5711
+ automationId: z18.string(),
5712
+ runs: z18.array(AutomationRunRecordSchema),
5713
+ totalCount: z18.number()
5982
5714
  });
5983
- var DaemonGetAutomationVisualRequestParamsSchema = z20.object({
5984
- automationId: z20.string(),
5985
- automationDirName: z20.string().optional(),
5986
- basePath: z20.string().optional(),
5987
- sessionId: z20.string().optional()
5715
+ var DaemonGetAutomationVisualRequestParamsSchema = z18.object({
5716
+ automationId: z18.string(),
5717
+ automationDirName: z18.string().optional(),
5718
+ basePath: z18.string().optional(),
5719
+ sessionId: z18.string().optional()
5988
5720
  });
5989
5721
  var DaemonGetAutomationVisualRequestSchema = JsonRpcBaseRequestSchema.extend({
5990
- method: z20.literal("daemon.get_automation_visual" /* GET_AUTOMATION_VISUAL */),
5722
+ method: z18.literal("daemon.get_automation_visual" /* GET_AUTOMATION_VISUAL */),
5991
5723
  params: DaemonGetAutomationVisualRequestParamsSchema
5992
5724
  });
5993
- var DaemonGetAutomationVisualResultSchema = z20.object({
5994
- automationId: z20.string(),
5995
- exists: z20.boolean(),
5996
- content: z20.string().optional(),
5997
- isStale: z20.boolean().optional(),
5998
- s3Url: z20.string().optional()
5725
+ var DaemonGetAutomationVisualResultSchema = z18.object({
5726
+ automationId: z18.string(),
5727
+ exists: z18.boolean(),
5728
+ content: z18.string().optional(),
5729
+ isStale: z18.boolean().optional(),
5730
+ s3Url: z18.string().optional()
5999
5731
  });
6000
- var DaemonCreateAutomationRequestParamsSchema = z20.object({
6001
- id: z20.string(),
5732
+ var DaemonCreateAutomationRequestParamsSchema = z18.object({
5733
+ id: z18.string(),
6002
5734
  /** Stable backend UUID to persist into memory/state.json (remote scaffolds). */
6003
- uuid: z20.string().optional(),
6004
- name: z20.string(),
6005
- description: z20.string().optional(),
5735
+ uuid: z18.string().optional(),
5736
+ name: z18.string(),
5737
+ description: z18.string().optional(),
6006
5738
  /** Instructions for the agent to follow on every run. */
6007
- instructions: z20.string().optional(),
6008
- schedule: z20.string(),
5739
+ instructions: z18.string().optional(),
5740
+ schedule: z18.string(),
6009
5741
  /** Optional model ID to use when running this automation. */
6010
- model: z20.string().optional(),
5742
+ model: z18.string().optional(),
6011
5743
  /** Optional reasoning effort to use when running this automation. */
6012
- reasoningEffort: z20.string().optional(),
6013
- basePath: z20.string().optional(),
5744
+ reasoningEffort: z18.string().optional(),
5745
+ basePath: z18.string().optional(),
6014
5746
  /** Guidance for what the VISUAL.html dashboard should display. */
6015
- visualDescription: z20.string().optional(),
5747
+ visualDescription: z18.string().optional(),
6016
5748
  /** Guidance for what the automation should remember across runs. */
6017
- memoryStrategy: z20.string().optional(),
5749
+ memoryStrategy: z18.string().optional(),
6018
5750
  /**
6019
5751
  * Scaffold only: skip the local first-heartbeat run. Used for remote
6020
5752
  * (computer) scaffolds where the run is dispatched by the backend workflow.
6021
5753
  */
6022
- skipFirstRun: z20.boolean().optional(),
5754
+ skipFirstRun: z18.boolean().optional(),
6023
5755
  /** Create the scaffold with its schedule paused. */
6024
- paused: z20.boolean().optional(),
5756
+ paused: z18.boolean().optional(),
6025
5757
  /** Software Factory workstream id to persist into memory/state.json. */
6026
- workstreamId: z20.string().optional(),
5758
+ workstreamId: z18.string().optional(),
6027
5759
  /**
6028
5760
  * Surface the creation originated from (e.g. `cli`, `cli-menu`). Persisted
6029
5761
  * into HEARTBEAT.md frontmatter so the daemon sync can stamp it on the
6030
5762
  * Firestore doc.
6031
5763
  */
6032
- creationSource: z20.nativeEnum(AutomationCreationSource).optional(),
5764
+ creationSource: z18.nativeEnum(AutomationCreationSource).optional(),
6033
5765
  /** Skills to write under `skills/` after the scaffold (fork-time push). */
6034
- skills: z20.array(AutomationScaffoldSkillSchema).optional(),
5766
+ skills: z18.array(AutomationScaffoldSkillSchema).optional(),
6035
5767
  /** Run-session privacy persisted into HEARTBEAT.md frontmatter (absent = private). */
6036
- sessionPrivacy: z20.nativeEnum(SlackAutomationSessionPrivacy).optional()
5768
+ sessionPrivacy: z18.nativeEnum(SlackAutomationSessionPrivacy).optional()
6037
5769
  });
6038
5770
  var DaemonCreateAutomationRequestSchema = JsonRpcBaseRequestSchema.extend({
6039
- method: z20.literal("daemon.create_automation" /* CREATE_AUTOMATION */),
5771
+ method: z18.literal("daemon.create_automation" /* CREATE_AUTOMATION */),
6040
5772
  params: DaemonCreateAutomationRequestParamsSchema
6041
5773
  });
6042
- var DaemonCreateAutomationResultSchema = z20.object({
6043
- success: z20.boolean(),
6044
- automationId: z20.string().optional(),
6045
- error: z20.string().optional()
5774
+ var DaemonCreateAutomationResultSchema = z18.object({
5775
+ success: z18.boolean(),
5776
+ automationId: z18.string().optional(),
5777
+ error: z18.string().optional()
6046
5778
  });
6047
- var DaemonUpdateAutomationModelRequestParamsSchema = z20.object({
6048
- automationId: z20.string(),
6049
- automationDirName: z20.string().optional(),
6050
- model: z20.string().nullable(),
6051
- basePath: z20.string().optional()
5779
+ var DaemonUpdateAutomationModelRequestParamsSchema = z18.object({
5780
+ automationId: z18.string(),
5781
+ automationDirName: z18.string().optional(),
5782
+ model: z18.string().nullable(),
5783
+ basePath: z18.string().optional()
6052
5784
  });
6053
5785
  var DaemonUpdateAutomationModelRequestSchema = JsonRpcBaseRequestSchema.extend({
6054
- method: z20.literal("daemon.update_automation_model" /* UPDATE_AUTOMATION_MODEL */),
5786
+ method: z18.literal("daemon.update_automation_model" /* UPDATE_AUTOMATION_MODEL */),
6055
5787
  params: DaemonUpdateAutomationModelRequestParamsSchema
6056
5788
  });
6057
- var DaemonUpdateAutomationModelResultSchema = z20.object({
6058
- success: z20.boolean(),
6059
- error: z20.string().optional()
5789
+ var DaemonUpdateAutomationModelResultSchema = z18.object({
5790
+ success: z18.boolean(),
5791
+ error: z18.string().optional()
6060
5792
  });
6061
- var DaemonUpdateAutomationPrivacyRequestParamsSchema = z20.object({
6062
- automationId: z20.string(),
6063
- automationDirName: z20.string().optional(),
6064
- privacyLevel: z20.nativeEnum(AutomationPrivacyLevel),
5793
+ var DaemonUpdateAutomationPrivacyRequestParamsSchema = z18.object({
5794
+ automationId: z18.string(),
5795
+ automationDirName: z18.string().optional(),
5796
+ privacyLevel: z18.nativeEnum(AutomationPrivacyLevel),
6065
5797
  /**
6066
5798
  * Run-session privacy to stamp alongside `privacyLevel`. Optional so older
6067
5799
  * daemons stay compatible; when omitted the frontmatter key is left as-is
6068
5800
  * rather than cleared, since only the create-time stamp sets it here.
6069
5801
  */
6070
- sessionPrivacy: z20.nativeEnum(SlackAutomationSessionPrivacy).optional(),
6071
- createdBy: z20.object({
6072
- name: z20.string(),
6073
- email: z20.string().optional(),
6074
- avatarUrl: z20.string().optional()
5802
+ sessionPrivacy: z18.nativeEnum(SlackAutomationSessionPrivacy).optional(),
5803
+ createdBy: z18.object({
5804
+ name: z18.string(),
5805
+ email: z18.string().optional(),
5806
+ avatarUrl: z18.string().optional()
6075
5807
  }).optional(),
6076
- basePath: z20.string().optional()
5808
+ basePath: z18.string().optional()
6077
5809
  });
6078
5810
  var DaemonUpdateAutomationPrivacyRequestSchema = JsonRpcBaseRequestSchema.extend({
6079
- method: z20.literal("daemon.update_automation_privacy" /* UPDATE_AUTOMATION_PRIVACY */),
5811
+ method: z18.literal("daemon.update_automation_privacy" /* UPDATE_AUTOMATION_PRIVACY */),
6080
5812
  params: DaemonUpdateAutomationPrivacyRequestParamsSchema
6081
5813
  });
6082
- var DaemonUpdateAutomationPrivacyResultSchema = z20.object({
6083
- success: z20.boolean(),
6084
- error: z20.string().optional()
5814
+ var DaemonUpdateAutomationPrivacyResultSchema = z18.object({
5815
+ success: z18.boolean(),
5816
+ error: z18.string().optional()
6085
5817
  });
6086
- var DaemonUpdateAutomationPromptRequestParamsSchema = z20.object({
6087
- automationId: z20.string(),
6088
- automationDirName: z20.string().optional(),
6089
- prompt: z20.string(),
6090
- basePath: z20.string().optional()
5818
+ var DaemonUpdateAutomationPromptRequestParamsSchema = z18.object({
5819
+ automationId: z18.string(),
5820
+ automationDirName: z18.string().optional(),
5821
+ prompt: z18.string(),
5822
+ basePath: z18.string().optional()
6091
5823
  });
6092
5824
  var DaemonUpdateAutomationPromptRequestSchema = JsonRpcBaseRequestSchema.extend({
6093
- method: z20.literal("daemon.update_automation_prompt" /* UPDATE_AUTOMATION_PROMPT */),
5825
+ method: z18.literal("daemon.update_automation_prompt" /* UPDATE_AUTOMATION_PROMPT */),
6094
5826
  params: DaemonUpdateAutomationPromptRequestParamsSchema
6095
5827
  });
6096
- var DaemonUpdateAutomationPromptResultSchema = z20.object({
6097
- success: z20.boolean(),
6098
- error: z20.string().optional()
5828
+ var DaemonUpdateAutomationPromptResultSchema = z18.object({
5829
+ success: z18.boolean(),
5830
+ error: z18.string().optional()
6099
5831
  });
6100
- var DaemonUpdateAutomationScheduleRequestParamsSchema = z20.object({
6101
- automationId: z20.string(),
6102
- automationDirName: z20.string().optional(),
6103
- schedule: z20.string(),
6104
- basePath: z20.string().optional()
5832
+ var DaemonUpdateAutomationScheduleRequestParamsSchema = z18.object({
5833
+ automationId: z18.string(),
5834
+ automationDirName: z18.string().optional(),
5835
+ schedule: z18.string(),
5836
+ basePath: z18.string().optional()
6105
5837
  });
6106
5838
  var DaemonUpdateAutomationScheduleRequestSchema = JsonRpcBaseRequestSchema.extend({
6107
- method: z20.literal("daemon.update_automation_schedule" /* UPDATE_AUTOMATION_SCHEDULE */),
5839
+ method: z18.literal("daemon.update_automation_schedule" /* UPDATE_AUTOMATION_SCHEDULE */),
6108
5840
  params: DaemonUpdateAutomationScheduleRequestParamsSchema
6109
5841
  });
6110
- var DaemonUpdateAutomationScheduleResultSchema = z20.object({
6111
- success: z20.boolean(),
6112
- error: z20.string().optional()
5842
+ var DaemonUpdateAutomationScheduleResultSchema = z18.object({
5843
+ success: z18.boolean(),
5844
+ error: z18.string().optional()
6113
5845
  });
6114
- var DaemonRenameAutomationRequestParamsSchema = z20.object({
6115
- automationId: z20.string(),
6116
- automationDirName: z20.string().optional(),
6117
- newName: z20.string(),
6118
- basePath: z20.string().optional()
5846
+ var DaemonRenameAutomationRequestParamsSchema = z18.object({
5847
+ automationId: z18.string(),
5848
+ automationDirName: z18.string().optional(),
5849
+ newName: z18.string(),
5850
+ basePath: z18.string().optional()
6119
5851
  });
6120
5852
  var DaemonRenameAutomationRequestSchema = JsonRpcBaseRequestSchema.extend({
6121
- method: z20.literal("daemon.rename_automation" /* RENAME_AUTOMATION */),
5853
+ method: z18.literal("daemon.rename_automation" /* RENAME_AUTOMATION */),
6122
5854
  params: DaemonRenameAutomationRequestParamsSchema
6123
5855
  });
6124
- var DaemonRenameAutomationResultSchema = z20.object({
6125
- success: z20.boolean(),
6126
- error: z20.string().optional()
5856
+ var DaemonRenameAutomationResultSchema = z18.object({
5857
+ success: z18.boolean(),
5858
+ error: z18.string().optional()
6127
5859
  });
6128
- var DaemonDeleteAutomationRequestParamsSchema = z20.object({
6129
- automationId: z20.string(),
6130
- automationDirName: z20.string().optional(),
6131
- basePath: z20.string().optional()
5860
+ var DaemonDeleteAutomationRequestParamsSchema = z18.object({
5861
+ automationId: z18.string(),
5862
+ automationDirName: z18.string().optional(),
5863
+ basePath: z18.string().optional()
6132
5864
  });
6133
5865
  var DaemonDeleteAutomationRequestSchema = JsonRpcBaseRequestSchema.extend({
6134
- method: z20.literal("daemon.delete_automation" /* DELETE_AUTOMATION */),
5866
+ method: z18.literal("daemon.delete_automation" /* DELETE_AUTOMATION */),
6135
5867
  params: DaemonDeleteAutomationRequestParamsSchema
6136
5868
  });
6137
- var DaemonDeleteAutomationResultSchema = z20.object({
6138
- success: z20.boolean(),
6139
- error: z20.string().optional()
6140
- });
6141
- var DaemonForkAutomationRequestParamsSchema = z20.object({
6142
- automationId: z20.string(),
6143
- name: z20.string(),
6144
- description: z20.string().optional(),
6145
- schedule: z20.string(),
6146
- tags: z20.array(z20.string()).optional(),
6147
- model: z20.string().optional(),
6148
- reasoningEffort: z20.string().optional(),
6149
- prompt: z20.string(),
6150
- forkedFrom: z20.string(),
6151
- localDirName: z20.string(),
5869
+ var DaemonDeleteAutomationResultSchema = z18.object({
5870
+ success: z18.boolean(),
5871
+ error: z18.string().optional()
5872
+ });
5873
+ var DaemonForkAutomationRequestParamsSchema = z18.object({
5874
+ automationId: z18.string(),
5875
+ name: z18.string(),
5876
+ description: z18.string().optional(),
5877
+ schedule: z18.string(),
5878
+ tags: z18.array(z18.string()).optional(),
5879
+ model: z18.string().optional(),
5880
+ reasoningEffort: z18.string().optional(),
5881
+ prompt: z18.string(),
5882
+ forkedFrom: z18.string(),
5883
+ localDirName: z18.string(),
6152
5884
  /** Source automation's skills to write under the fork's `skills/`. */
6153
- skills: z20.array(AutomationScaffoldSkillSchema).optional()
5885
+ skills: z18.array(AutomationScaffoldSkillSchema).optional()
6154
5886
  });
6155
5887
  var DaemonForkAutomationRequestSchema = JsonRpcBaseRequestSchema.extend({
6156
- method: z20.literal("daemon.fork_automation" /* FORK_AUTOMATION */),
5888
+ method: z18.literal("daemon.fork_automation" /* FORK_AUTOMATION */),
6157
5889
  params: DaemonForkAutomationRequestParamsSchema
6158
5890
  });
6159
- var DaemonForkAutomationResultSchema = z20.object({
6160
- success: z20.boolean(),
6161
- automationId: z20.string().optional(),
6162
- error: z20.string().optional()
5891
+ var DaemonForkAutomationResultSchema = z18.object({
5892
+ success: z18.boolean(),
5893
+ automationId: z18.string().optional(),
5894
+ error: z18.string().optional()
6163
5895
  });
6164
- var DaemonApplyAutomationConfigRequestParamsSchema = z20.object({
5896
+ var DaemonApplyAutomationConfigRequestParamsSchema = z18.object({
6165
5897
  /** Stable UUID of the automation (matches HEARTBEAT.md frontmatter `id`). */
6166
- automationId: z20.string(),
6167
- basePath: z20.string().optional(),
6168
- name: z20.string(),
6169
- description: z20.string().optional(),
6170
- schedule: z20.string(),
6171
- model: z20.string().optional(),
5898
+ automationId: z18.string(),
5899
+ basePath: z18.string().optional(),
5900
+ name: z18.string(),
5901
+ description: z18.string().optional(),
5902
+ schedule: z18.string(),
5903
+ model: z18.string().optional(),
6172
5904
  /** Optional reasoning effort. Empty string clears it. */
6173
- reasoningEffort: z20.string().optional(),
6174
- prompt: z20.string(),
6175
- tags: z20.array(z20.string()).optional(),
6176
- privacyLevel: z20.nativeEnum(AutomationPrivacyLevel).optional(),
5905
+ reasoningEffort: z18.string().optional(),
5906
+ prompt: z18.string(),
5907
+ tags: z18.array(z18.string()).optional(),
5908
+ privacyLevel: z18.nativeEnum(AutomationPrivacyLevel).optional(),
6177
5909
  /** Run-session privacy. Always written explicitly when provided; absent leaves the frontmatter key untouched. */
6178
- sessionPrivacy: z20.nativeEnum(SlackAutomationSessionPrivacy).optional(),
6179
- paused: z20.boolean().optional(),
5910
+ sessionPrivacy: z18.nativeEnum(SlackAutomationSessionPrivacy).optional(),
5911
+ paused: z18.boolean().optional(),
6180
5912
  /** Project directory to run from. Empty string clears it. */
6181
- workingDirectory: z20.string().optional(),
5913
+ workingDirectory: z18.string().optional(),
6182
5914
  /** Software Factory workstream id. Persisted to memory/state.json when present. */
6183
- workstreamId: z20.string().optional()
5915
+ workstreamId: z18.string().optional()
6184
5916
  });
6185
5917
  var DaemonApplyAutomationConfigRequestSchema = JsonRpcBaseRequestSchema.extend({
6186
- method: z20.literal("daemon.apply_automation_config" /* APPLY_AUTOMATION_CONFIG */),
5918
+ method: z18.literal("daemon.apply_automation_config" /* APPLY_AUTOMATION_CONFIG */),
6187
5919
  params: DaemonApplyAutomationConfigRequestParamsSchema
6188
5920
  });
6189
- var DaemonApplyAutomationConfigReasonSchema = z20.enum([
6190
- "local-file-unavailable",
6191
- "discovery-failed",
6192
- "apply-failed"
6193
- ]);
6194
- var DaemonApplyAutomationConfigResultSchema = z20.object({
6195
- success: z20.boolean(),
6196
- error: z20.string().optional(),
6197
- /** Set only when `success` is false. Absent from pre-fix daemons. */
6198
- reason: DaemonApplyAutomationConfigReasonSchema.optional()
5921
+ var DaemonApplyAutomationConfigReasonSchema = z18.enum([
5922
+ "local-file-unavailable",
5923
+ "discovery-failed",
5924
+ "apply-failed"
5925
+ ]);
5926
+ var DaemonApplyAutomationConfigResultSchema = z18.object({
5927
+ success: z18.boolean(),
5928
+ error: z18.string().optional(),
5929
+ /** Set only when `success` is false. Absent from pre-fix daemons. */
5930
+ reason: DaemonApplyAutomationConfigReasonSchema.optional()
5931
+ });
5932
+ var DaemonUpdateAutomationRequestParamsSchema = z18.object({
5933
+ /** Stable UUID of the automation (matches HEARTBEAT.md frontmatter `id`). */
5934
+ automationId: z18.string(),
5935
+ /** Directory name slug (e.g. "health-check"). Preferred over automationId for path resolution. */
5936
+ automationDirName: z18.string().optional(),
5937
+ basePath: z18.string().optional(),
5938
+ name: z18.string(),
5939
+ description: z18.string().optional(),
5940
+ schedule: z18.string(),
5941
+ model: z18.string().optional(),
5942
+ /** Optional reasoning effort. Empty string clears the frontmatter key. */
5943
+ reasoningEffort: z18.string().optional(),
5944
+ prompt: z18.string(),
5945
+ tags: z18.array(z18.string()).optional(),
5946
+ privacyLevel: z18.nativeEnum(AutomationPrivacyLevel).optional(),
5947
+ /** Run-session privacy. Always written explicitly when provided; absent leaves the frontmatter key untouched. */
5948
+ sessionPrivacy: z18.nativeEnum(SlackAutomationSessionPrivacy).optional(),
5949
+ paused: z18.boolean().optional(),
5950
+ workingDirectory: z18.string().optional(),
5951
+ /** Software Factory workstream id. Persisted to memory/state.json when present. */
5952
+ workstreamId: z18.string().optional()
5953
+ });
5954
+ var DaemonUpdateAutomationRequestSchema = JsonRpcBaseRequestSchema.extend({
5955
+ method: z18.literal("daemon.update_automation" /* UPDATE_AUTOMATION */),
5956
+ params: DaemonUpdateAutomationRequestParamsSchema
5957
+ });
5958
+ var DaemonUpdateAutomationResultSchema = z18.object({
5959
+ success: z18.boolean(),
5960
+ error: z18.string().optional()
5961
+ });
5962
+
5963
+ // ../droid-sdk-core/src/protocol/daemon/schemas/bug-report.ts
5964
+ import z19 from "zod";
5965
+ var DaemonSubmitBugReportRequestParamsSchema = z19.object({
5966
+ sessionId: z19.string(),
5967
+ userComment: z19.string(),
5968
+ clientLogs: z19.string().optional(),
5969
+ source: BugReportSourceSchema.optional()
5970
+ });
5971
+ var DaemonSubmitBugReportRequestSchema = JsonRpcBaseRequestSchema.extend({
5972
+ method: z19.literal("daemon.submit_bug_report" /* SUBMIT_BUG_REPORT */),
5973
+ params: DaemonSubmitBugReportRequestParamsSchema
5974
+ });
5975
+ var DaemonSubmitBugReportResultSchema = z19.object({
5976
+ bugReportId: z19.string()
5977
+ });
5978
+
5979
+ // ../droid-sdk-core/src/protocol/daemon/schemas/commands.ts
5980
+ import z22 from "zod";
5981
+
5982
+ // ../droid-sdk-core/src/protocol/droid/constants.ts
5983
+ var seconds = (value) => value * 1e3;
5984
+ var minutes = (value) => seconds(value * 60);
5985
+ var hours = (value) => minutes(value * 60);
5986
+ var LOOP_INTERVAL_POLICY = {
5987
+ minMs: minutes(1),
5988
+ maxMs: hours(24),
5989
+ displayRange: "1m\u201324h",
5990
+ examples: "5m, 30m, 2h"
5991
+ };
5992
+ var SYSTEM_REMINDER_START = "<system-reminder>";
5993
+ var SYSTEM_REMINDER_END = "</system-reminder>";
5994
+ var SYSTEM_NOTIFICATION_START = "<system-notification>";
5995
+ var SYSTEM_NOTIFICATION_END = "</system-notification>";
5996
+ var DROID_RUNNING_STATES = [
5997
+ "thinking" /* Thinking */,
5998
+ "streaming_assistant_message" /* StreamingAssistantMessage */,
5999
+ "executing_tool" /* ExecutingTool */,
6000
+ "compacting_conversation" /* CompactingConversation */
6001
+ ];
6002
+ var DROID_IN_PROGRESS_STATES = [
6003
+ ...DROID_RUNNING_STATES,
6004
+ "waiting_for_tool_confirmation" /* WaitingForToolConfirmation */
6005
+ ];
6006
+
6007
+ // ../droid-sdk-core/src/protocol/droid/tool-execution-lifecycle.ts
6008
+ function getToolExecutionLifecyclePhaseRank(phase) {
6009
+ switch (phase) {
6010
+ case "streaming_input" /* StreamingInput */:
6011
+ return 0;
6012
+ case "queued" /* Queued */:
6013
+ return 1;
6014
+ case "executing" /* Executing */:
6015
+ return 2;
6016
+ case "settled_after_execution" /* SettledAfterExecution */:
6017
+ case "settled_without_execution" /* SettledWithoutExecution */:
6018
+ case "settled_unknown" /* SettledUnknown */:
6019
+ return 3;
6020
+ }
6021
+ }
6022
+ function mergeToolExecutionLifecyclePhase(current, next) {
6023
+ if (!current) return next;
6024
+ if (!next) return current;
6025
+ return getToolExecutionLifecyclePhaseRank(next) > getToolExecutionLifecyclePhaseRank(current) ? next : current;
6026
+ }
6027
+ function settleToolExecutionLifecyclePhase(phase) {
6028
+ if (phase === "settled_after_execution" /* SettledAfterExecution */ || phase === "settled_without_execution" /* SettledWithoutExecution */ || phase === "settled_unknown" /* SettledUnknown */) {
6029
+ return phase;
6030
+ }
6031
+ if (phase === "executing" /* Executing */) {
6032
+ return "settled_after_execution" /* SettledAfterExecution */;
6033
+ }
6034
+ if (phase === "streaming_input" /* StreamingInput */ || phase === "queued" /* Queued */) {
6035
+ return "settled_without_execution" /* SettledWithoutExecution */;
6036
+ }
6037
+ return "settled_unknown" /* SettledUnknown */;
6038
+ }
6039
+
6040
+ // ../droid-sdk-core/src/protocol/droid/schemas/constants.ts
6041
+ var FACTORY_PROTOCOL_VERSION = "1.201.1";
6042
+ var FACTORY_CLIENT_HEADER = "X-Factory-Client";
6043
+ var FACTORY_SDK_HEADER = "X-Factory-Sdk";
6044
+ var FACTORY_CLIENT_VERSION = "X-Client-Version";
6045
+ var LEGACY_FACTORY_API_VERSION2 = LEGACY_FACTORY_API_VERSION;
6046
+ var JSONRPC_VERSION2 = JSONRPC_VERSION;
6047
+
6048
+ // ../droid-sdk-core/src/protocol/droid/schemas/automations.ts
6049
+ import z20 from "zod";
6050
+ var ExecutionLocationSchema = z20.enum(["local", "remote"]);
6051
+ var AutomationStatusSchema = z20.enum(["active", "paused"]);
6052
+ var AutomationIdSchema = z20.string().trim().min(1);
6053
+ var PromptSchema = z20.string().trim().min(1);
6054
+ function requireField(ctx, field, message) {
6055
+ ctx.addIssue({ code: z20.ZodIssueCode.custom, path: [field], message });
6056
+ }
6057
+ var AutomationCreateToolInputSchema = z20.object({
6058
+ executionLocation: ExecutionLocationSchema.describe(
6059
+ 'Where the automation runs: "local" creates a local filesystem automation on this machine; "remote" creates a cloud automation that runs on a droid computer.'
6060
+ ),
6061
+ name: z20.string().trim().min(1).max(128).describe("Display name for the automation."),
6062
+ schedule: z20.string().trim().min(1).describe(
6063
+ "A 5-field cron expression for local automations, or a 5-field cron expression/natural-language cadence for remote automations."
6064
+ ),
6065
+ prompt: PromptSchema.describe(
6066
+ "Agent instructions to run on each scheduled tick."
6067
+ ),
6068
+ model: z20.string().trim().min(1).optional().describe(
6069
+ 'Optional model for run sessions. Accepts a model id, a model display name, or "cheapest" to pin the lowest-cost available model (good for mechanical scheduled work). Names are resolved against the live model catalog; an unrecognized name fails with the available models listed. Omit to use the default model. A pin the run target cannot resolve falls back to the default at run time.'
6070
+ ),
6071
+ reasoningEffort: z20.string().trim().min(1).optional().describe(
6072
+ 'Optional reasoning effort for run sessions (e.g. "low", "medium", "high"). Unsupported values are clamped to the model default at run time. Omit to use the model default.'
6073
+ ),
6074
+ status: AutomationStatusSchema.optional().default("active").describe(
6075
+ 'Initial status. Use "paused" when creating an automation for a draft Software Factory workstream.'
6076
+ ),
6077
+ description: z20.string().trim().max(1024).optional().describe("Optional description."),
6078
+ visualization_instruction: z20.string().trim().min(1).optional().describe(
6079
+ 'Optional visualization guidance, folded into the run prompt as a "## Visualization" section.'
6080
+ ),
6081
+ memory_instruction: z20.string().trim().min(1).optional().describe(
6082
+ 'Optional memory guidance, folded into the run prompt as a "## Memory & Evolution" section.'
6083
+ ),
6084
+ computerId: z20.string().trim().min(1).optional().describe(
6085
+ "ID of the droid computer the automation runs on. Remote automations require computerId or computerName."
6086
+ ),
6087
+ computerName: z20.string().trim().min(1).optional().describe(
6088
+ "Name of the droid computer the automation runs on, resolved to its ID at creation time (use ListComputers to see available names). Remote automations require computerId or computerName; if the name matches multiple computers, ask the user which one to use and retry with its computerId."
6089
+ ),
6090
+ executionTemplateId: z20.string().trim().min(1).optional().describe(
6091
+ "ID of the Execution Template used to provision a fresh Computer for every remote automation run."
6092
+ ),
6093
+ workstreamId: z20.string().trim().min(1).max(128).optional().describe(
6094
+ "Optional Software Factory workstream id. Set this when the automation is created as part of a workstream so it stays linked to that workstream."
6095
+ ),
6096
+ tags: z20.array(z20.string().trim().min(1).max(128)).max(16).optional().describe(
6097
+ 'Optional tags stored on the remote automation, used for grouping and lifecycle linkage (e.g. "sf-workstream:<id>" ties the automation to a Software Factory workstream so workstream deletion removes it). Remote automations only.'
6098
+ )
6099
+ }).superRefine((data, ctx) => {
6100
+ const remoteTargets = [
6101
+ data.computerId,
6102
+ data.computerName,
6103
+ data.executionTemplateId
6104
+ ].filter((target) => target !== void 0);
6105
+ if (data.executionLocation === "remote" && remoteTargets.length === 0) {
6106
+ requireField(
6107
+ ctx,
6108
+ "computerId",
6109
+ 'computerId, computerName, or executionTemplateId is required when executionLocation is "remote".'
6110
+ );
6111
+ }
6112
+ if (remoteTargets.length > 1) {
6113
+ requireField(
6114
+ ctx,
6115
+ data.executionTemplateId ? "executionTemplateId" : "computerName",
6116
+ "Provide exactly one of computerId, computerName, or executionTemplateId."
6117
+ );
6118
+ }
6119
+ if (data.executionLocation === "local" && data.computerId) {
6120
+ requireField(
6121
+ ctx,
6122
+ "computerId",
6123
+ 'computerId is only supported when executionLocation is "remote".'
6124
+ );
6125
+ }
6126
+ if (data.executionLocation === "local" && data.computerName) {
6127
+ requireField(
6128
+ ctx,
6129
+ "computerName",
6130
+ 'computerName is only supported when executionLocation is "remote".'
6131
+ );
6132
+ }
6133
+ if (data.executionLocation === "local" && data.executionTemplateId) {
6134
+ requireField(
6135
+ ctx,
6136
+ "executionTemplateId",
6137
+ 'executionTemplateId is only supported when executionLocation is "remote".'
6138
+ );
6139
+ }
6140
+ if (data.executionLocation === "local" && data.tags) {
6141
+ requireField(
6142
+ ctx,
6143
+ "tags",
6144
+ 'tags are only supported when executionLocation is "remote".'
6145
+ );
6146
+ }
6147
+ });
6148
+ var AutomationListToolInputSchema = z20.object({
6149
+ executionLocation: ExecutionLocationSchema.describe(
6150
+ 'Where to list automations from: "local" for this machine or "remote" for cloud automations.'
6151
+ )
6199
6152
  });
6200
- var DaemonUpdateAutomationRequestParamsSchema = z20.object({
6201
- /** Stable UUID of the automation (matches HEARTBEAT.md frontmatter `id`). */
6202
- automationId: z20.string(),
6203
- /** Directory name slug (e.g. "health-check"). Preferred over automationId for path resolution. */
6204
- automationDirName: z20.string().optional(),
6205
- basePath: z20.string().optional(),
6206
- name: z20.string(),
6207
- description: z20.string().optional(),
6208
- schedule: z20.string(),
6209
- model: z20.string().optional(),
6210
- /** Optional reasoning effort. Empty string clears the frontmatter key. */
6211
- reasoningEffort: z20.string().optional(),
6212
- prompt: z20.string(),
6213
- tags: z20.array(z20.string()).optional(),
6214
- privacyLevel: z20.nativeEnum(AutomationPrivacyLevel).optional(),
6215
- /** Run-session privacy. Always written explicitly when provided; absent leaves the frontmatter key untouched. */
6216
- sessionPrivacy: z20.nativeEnum(SlackAutomationSessionPrivacy).optional(),
6217
- paused: z20.boolean().optional(),
6218
- workingDirectory: z20.string().optional(),
6219
- /** Software Factory workstream id. Persisted to memory/state.json when present. */
6220
- workstreamId: z20.string().optional()
6153
+ var AutomationReadToolInputSchema = z20.object({
6154
+ executionLocation: ExecutionLocationSchema.describe(
6155
+ 'Where to read the automation from: "local" for this machine or "remote" for cloud automations.'
6156
+ ),
6157
+ automationId: AutomationIdSchema.describe("Automation id.")
6221
6158
  });
6222
- var DaemonUpdateAutomationRequestSchema = JsonRpcBaseRequestSchema.extend({
6223
- method: z20.literal("daemon.update_automation" /* UPDATE_AUTOMATION */),
6224
- params: DaemonUpdateAutomationRequestParamsSchema
6159
+ var AutomationDeleteToolInputSchema = z20.object({
6160
+ executionLocation: ExecutionLocationSchema.describe(
6161
+ 'Where to delete the automation from: "local" for this machine or "remote" for cloud automations.'
6162
+ ),
6163
+ automationId: AutomationIdSchema.describe("Automation id.")
6225
6164
  });
6226
- var DaemonUpdateAutomationResultSchema = z20.object({
6227
- success: z20.boolean(),
6228
- error: z20.string().optional()
6165
+ var AutomationEditToolInputSchema = z20.object({
6166
+ executionLocation: ExecutionLocationSchema.describe(
6167
+ 'Where to edit the automation: "local" for this machine or "remote" for cloud automations.'
6168
+ ),
6169
+ automationId: AutomationIdSchema.describe("Automation id."),
6170
+ name: z20.string().trim().min(1).max(128).optional().describe("New display name."),
6171
+ description: z20.string().trim().max(1024).optional().describe("New description."),
6172
+ schedule: z20.string().trim().min(1).optional().describe("New cron expression or natural-language cadence."),
6173
+ prompt: PromptSchema.optional().describe("New agent instructions."),
6174
+ model: z20.string().trim().optional().describe(
6175
+ 'New model for run sessions. Accepts a model id, a model display name, or "cheapest" to pin the lowest-cost available model. Pass an empty string to clear the pin and use the default model.'
6176
+ ),
6177
+ reasoningEffort: z20.string().trim().optional().describe(
6178
+ 'New reasoning effort for run sessions (e.g. "low", "medium", "high"). Pass an empty string to clear it. Remote automations only.'
6179
+ ),
6180
+ status: AutomationStatusSchema.optional().describe(
6181
+ 'New status: "active" or "paused".'
6182
+ ),
6183
+ computerId: z20.string().trim().min(1).optional().describe("Move a remote automation to a different computer.")
6184
+ }).superRefine((data, ctx) => {
6185
+ const hasAnyUpdate = data.name !== void 0 || data.description !== void 0 || data.schedule !== void 0 || data.prompt !== void 0 || data.model !== void 0 || data.reasoningEffort !== void 0 || data.status !== void 0 || data.computerId !== void 0;
6186
+ if (!hasAnyUpdate) {
6187
+ ctx.addIssue({
6188
+ code: z20.ZodIssueCode.custom,
6189
+ message: "Provide at least one field to update."
6190
+ });
6191
+ }
6192
+ if (data.executionLocation === "local") {
6193
+ if (data.description !== void 0) {
6194
+ requireField(
6195
+ ctx,
6196
+ "description",
6197
+ 'description is only supported when executionLocation is "remote".'
6198
+ );
6199
+ }
6200
+ if (data.schedule !== void 0) {
6201
+ requireField(
6202
+ ctx,
6203
+ "schedule",
6204
+ 'schedule edits are only supported when executionLocation is "remote".'
6205
+ );
6206
+ }
6207
+ if (data.reasoningEffort !== void 0) {
6208
+ requireField(
6209
+ ctx,
6210
+ "reasoningEffort",
6211
+ 'reasoningEffort edits are only supported when executionLocation is "remote".'
6212
+ );
6213
+ }
6214
+ if (data.computerId !== void 0) {
6215
+ requireField(
6216
+ ctx,
6217
+ "computerId",
6218
+ 'computerId is only supported when executionLocation is "remote".'
6219
+ );
6220
+ }
6221
+ }
6229
6222
  });
6230
6223
 
6231
- // ../droid-sdk-core/src/protocol/daemon/schemas/bug-report.ts
6224
+ // ../droid-sdk-core/src/protocol/droid/schemas/loop-tool.ts
6232
6225
  import z21 from "zod";
6233
- var DaemonSubmitBugReportRequestParamsSchema = z21.object({
6234
- sessionId: z21.string(),
6235
- userComment: z21.string(),
6236
- clientLogs: z21.string().optional(),
6237
- source: BugReportSourceSchema.optional()
6238
- });
6239
- var DaemonSubmitBugReportRequestSchema = JsonRpcBaseRequestSchema.extend({
6240
- method: z21.literal("daemon.submit_bug_report" /* SUBMIT_BUG_REPORT */),
6241
- params: DaemonSubmitBugReportRequestParamsSchema
6242
- });
6243
- var DaemonSubmitBugReportResultSchema = z21.object({
6244
- bugReportId: z21.string()
6226
+ var CronExpressionSchema = z21.string().trim().regex(/^(\S+\s+){4}\S+$/, "Expected a standard 5-field cron expression");
6227
+ var LoopToolInputSchema = z21.object({
6228
+ action: z21.enum(["create", "list", "cancel"]).describe("Operation to perform: create, list, or cancel."),
6229
+ prompt: z21.string().trim().min(1).optional().describe('Recurring prompt. Required when action is "create".'),
6230
+ cron: CronExpressionSchema.optional().describe(
6231
+ "5-field cron expression in UTC. Pure step cadences are anchored to loop creation."
6232
+ ),
6233
+ loopId: z21.string().trim().min(1).optional().describe(
6234
+ 'Loop ID returned by the "list" action. Required when action is "cancel".'
6235
+ ),
6236
+ runImmediately: z21.boolean().optional().describe(
6237
+ 'Also fire once on creation. Defaults to true; only valid for action "create".'
6238
+ )
6239
+ }).superRefine((data, ctx) => {
6240
+ const addRequiredIssue = (field) => {
6241
+ ctx.addIssue({
6242
+ code: z21.ZodIssueCode.custom,
6243
+ path: [field],
6244
+ message: `"${field}" is required when action is "${data.action}".`
6245
+ });
6246
+ };
6247
+ const rejectField = (field) => {
6248
+ if (data[field] === void 0) return;
6249
+ ctx.addIssue({
6250
+ code: z21.ZodIssueCode.custom,
6251
+ path: [field],
6252
+ message: `"${field}" is not valid when action is "${data.action}".`
6253
+ });
6254
+ };
6255
+ switch (data.action) {
6256
+ case "create":
6257
+ if (data.prompt === void 0) addRequiredIssue("prompt");
6258
+ if (data.cron === void 0) addRequiredIssue("cron");
6259
+ rejectField("loopId");
6260
+ break;
6261
+ case "list":
6262
+ rejectField("prompt");
6263
+ rejectField("cron");
6264
+ rejectField("loopId");
6265
+ rejectField("runImmediately");
6266
+ break;
6267
+ case "cancel":
6268
+ if (data.loopId === void 0) addRequiredIssue("loopId");
6269
+ rejectField("prompt");
6270
+ rejectField("cron");
6271
+ rejectField("runImmediately");
6272
+ break;
6273
+ default:
6274
+ break;
6275
+ }
6245
6276
  });
6246
6277
 
6247
6278
  // ../droid-sdk-core/src/protocol/daemon/schemas/commands.ts
6248
- import z22 from "zod";
6249
6279
  var DaemonListCommandsRequestParamsSchema = z22.object({
6250
6280
  sessionId: z22.string()
6251
6281
  });
@@ -7047,6 +7077,11 @@ var SoftwareFactoryWorkstreamSchema = z28.object({
7047
7077
  dashboardPort: z28.number().int().optional(),
7048
7078
  /** Public URL of the workstream's published Conjure dashboard site. */
7049
7079
  dashboardUrl: z28.string().optional(),
7080
+ /**
7081
+ * Self-contained dashboard HTML, present when the workstream has no
7082
+ * published site. `dashboardUrl` takes precedence when both exist.
7083
+ */
7084
+ dashboardHtml: z28.string().optional(),
7050
7085
  /** Pause proposed changes for human approval before investigation. */
7051
7086
  requireChangeApproval: z28.boolean().optional(),
7052
7087
  /** Pause completed investigation specifications for human approval. */
@@ -7225,6 +7260,7 @@ var DaemonSfUpdateWorkstreamRequestParamsSchema = z28.object({
7225
7260
  stewardConcurrency: z28.number().optional(),
7226
7261
  dashboardPort: z28.number().optional(),
7227
7262
  dashboardUrl: z28.string().optional(),
7263
+ dashboardHtml: z28.string().optional(),
7228
7264
  requireChangeApproval: z28.boolean().optional(),
7229
7265
  requireApproval: z28.boolean().optional(),
7230
7266
  reviewers: z28.array(z28.string()).optional()
@@ -7659,6 +7695,12 @@ var DaemonCleanupWorktreeResponseSchema = z30.union([
7659
7695
  JsonRpcBaseResponseFailureSchema
7660
7696
  ]);
7661
7697
 
7698
+ // ../droid-sdk-core/src/protocol/session/tags/constants.ts
7699
+ var SESSION_TAG_SUBAGENT = "subagent";
7700
+
7701
+ // ../droid-sdk-core/src/protocol/sessionV2/constants.ts
7702
+ var TOOL_RESULT_PENDING_MARKER = "__TOOL_RESULT_PENDING__";
7703
+
7662
7704
  // ../droid-sdk-core/src/protocol/daemon/schemas/droid.ts
7663
7705
  var DaemonCommandAckResultSchema = CommandAckSchema;
7664
7706
  var createResponseSchema = (resultSchema) => z31.union([
@@ -7694,7 +7736,13 @@ var DaemonLoadSessionSpawnOptionsSchema = z31.object({
7694
7736
  disableBuiltinSkills: z31.boolean().optional(),
7695
7737
  skipPermissionsUnsafe: z31.boolean().optional(),
7696
7738
  runtimeSettingsPath: z31.string().optional(),
7697
- structuredOutputFormat: OutputFormatSchema.nullable().optional()
7739
+ structuredOutputFormat: OutputFormatSchema.nullable().optional(),
7740
+ /**
7741
+ * Trusted hint from the Task executor that this load owns a Task-spawned
7742
+ * process. Used to account for legacy remote Task sessions created before
7743
+ * their persisted settings carried the process tag.
7744
+ */
7745
+ taskSubagentProcess: z31.literal(true).optional()
7698
7746
  });
7699
7747
  var DaemonLoadSessionRequestParamsSchema = LoadSessionRequestParamsSchema.merge(
7700
7748
  DaemonLoadSessionSpawnOptionsSchema
@@ -7722,7 +7770,14 @@ var DaemonInterruptSessionRequestParamsSchema = InterruptSessionRequestParamsSch
7722
7770
  sessionId: z31.string()
7723
7771
  });
7724
7772
  var DaemonCloseSessionRequestParamsSchema = z31.object({
7725
- sessionId: z31.string()
7773
+ sessionId: z31.string(),
7774
+ /**
7775
+ * Keep the session's on-disk files even when it is still an empty draft.
7776
+ * Set by close-for-respawn flows (e.g. the TUI's cwd-change reload) that
7777
+ * immediately re-load the same session: reaping the draft there would make
7778
+ * the follow-up load fail with SessionNotFoundError and strand the client.
7779
+ */
7780
+ preserveEmptyDraft: z31.boolean().optional()
7726
7781
  });
7727
7782
  var DaemonSessionListFilterSchema = z31.object({
7728
7783
  missionSessions: z31.boolean().optional(),
@@ -9244,6 +9299,7 @@ var McpAuthCompletedNotificationSchema2 = N[26];
9244
9299
  var HookExecutionStartedNotificationSchema2 = N[27];
9245
9300
  var HookExecutionCompletedNotificationSchema2 = N[28];
9246
9301
  var ToolCallNotificationSchema2 = N[29];
9302
+ var AssistantMessageRetractedNotificationSchema2 = N[35];
9247
9303
  var D = ToolConfirmationDetailsSchema.options;
9248
9304
  var EditToolConfirmationDetailsSchema2 = D[0];
9249
9305
  var ExecuteToolConfirmationDetailsSchema2 = D[1];
@@ -9299,19 +9355,20 @@ var SESSION_INIT_TIMEOUT = 6e4;
9299
9355
  var MCP_AUTH_TIMEOUT = 3e5;
9300
9356
  var COMPACTION_TIMEOUT = 24e4;
9301
9357
  var REWIND_TIMEOUT = 6e4;
9302
- var SDK_VERSION = "0.9.0";
9303
- var SDK_CLIENT_METADATA = {
9358
+ var SDK_VERSION = "0.9.1";
9359
+ var SDK_CLIENT_METADATA = Object.freeze({
9304
9360
  language: "typescript",
9305
9361
  version: SDK_VERSION
9306
- };
9307
- var SDK_REQUEST_ATTRIBUTION = {
9362
+ });
9363
+ var SDK_IDENTITY = formatSdkClientMetadata(SDK_CLIENT_METADATA);
9364
+ var SDK_REQUEST_ATTRIBUTION = Object.freeze({
9308
9365
  client: "sdk" /* SDK */,
9309
9366
  sdk: SDK_CLIENT_METADATA
9310
- };
9311
- var SDK_TAG = {
9367
+ });
9368
+ var SDK_TAG = Object.freeze({
9312
9369
  name: "sdk",
9313
9370
  metadata: SDK_CLIENT_METADATA
9314
- };
9371
+ });
9315
9372
 
9316
9373
  // src/schemas/constants.ts
9317
9374
  var JSONRPC_VERSION3 = JSONRPC_VERSION;
@@ -9570,6 +9627,7 @@ var DroidMessageType = {
9570
9627
  ToolCall: "tool_call",
9571
9628
  AssistantTextDelta: "assistant_text_delta",
9572
9629
  AssistantTextComplete: "assistant_text_complete",
9630
+ AssistantMessageRetracted: "assistant_message_retracted",
9573
9631
  ThinkingTextDelta: "thinking_text_delta",
9574
9632
  ThinkingTextComplete: "thinking_text_complete",
9575
9633
  ToolCallDelta: "tool_call_delta",
@@ -9614,6 +9672,11 @@ function convertNotificationToStreamMessage(raw) {
9614
9672
  messageId: notification.messageId,
9615
9673
  blockIndex: notification.blockIndex
9616
9674
  };
9675
+ case "assistant_message_retracted" /* ASSISTANT_MESSAGE_RETRACTED */:
9676
+ return {
9677
+ type: DroidMessageType.AssistantMessageRetracted,
9678
+ messageId: notification.messageId
9679
+ };
9617
9680
  case "thinking_text_delta" /* THINKING_TEXT_DELTA */:
9618
9681
  return {
9619
9682
  type: DroidMessageType.ThinkingTextDelta,
@@ -9835,7 +9898,9 @@ var StreamStateTracker = class {
9835
9898
  options;
9836
9899
  lastTokenUsage = null;
9837
9900
  fullText = "";
9901
+ streamedTextByMessageId = /* @__PURE__ */ new Map();
9838
9902
  finalAssistantText = "";
9903
+ finalAssistantMessageId = null;
9839
9904
  structuredOutput = null;
9840
9905
  structuredOutputError = null;
9841
9906
  errors = [];
@@ -9860,8 +9925,21 @@ var StreamStateTracker = class {
9860
9925
  }
9861
9926
  if (message.type === DroidMessageType.AssistantTextDelta) {
9862
9927
  this.fullText += message.text;
9928
+ this.streamedTextByMessageId.set(
9929
+ message.messageId,
9930
+ (this.streamedTextByMessageId.get(message.messageId) ?? "") + message.text
9931
+ );
9932
+ }
9933
+ if (message.type === DroidMessageType.AssistantMessageRetracted) {
9934
+ this.streamedTextByMessageId.delete(message.messageId);
9935
+ this.fullText = [...this.streamedTextByMessageId.values()].join("");
9936
+ if (this.finalAssistantMessageId === message.messageId) {
9937
+ this.finalAssistantMessageId = null;
9938
+ this.finalAssistantText = "";
9939
+ }
9863
9940
  }
9864
9941
  if (message.type === DroidMessageType.Assistant) {
9942
+ this.finalAssistantMessageId = message.message.id;
9865
9943
  this.finalAssistantText = message.text;
9866
9944
  if (this.fullText.length === 0) {
9867
9945
  this.fullText = message.text;
@@ -10317,6 +10395,10 @@ function buildUserMessageContentBlocks({
10317
10395
  }
10318
10396
  return blocks;
10319
10397
  }
10398
+ function compareMessagesByCreatedAtAndId(left, right) {
10399
+ const timestampDifference = left.createdAt - right.createdAt;
10400
+ return timestampDifference !== 0 ? timestampDifference : left.id.localeCompare(right.id);
10401
+ }
10320
10402
  function orderMessagesByParentChain(messages) {
10321
10403
  if (messages.length === 0) {
10322
10404
  return [];
@@ -10326,7 +10408,7 @@ function orderMessagesByParentChain(messages) {
10326
10408
  (message) => message.parentId !== void 0 && message.parentId !== message.id && messageById.has(message.parentId)
10327
10409
  );
10328
10410
  if (!hasParentLinks) {
10329
- return messages.slice().sort((left, right) => left.createdAt - right.createdAt);
10411
+ return messages.slice().sort(compareMessagesByCreatedAtAndId);
10330
10412
  }
10331
10413
  const referencedParentIds = new Set(
10332
10414
  messages.flatMap(
@@ -10352,7 +10434,7 @@ function orderMessagesByParentChain(messages) {
10352
10434
  if (ordered.length < messages.length) {
10353
10435
  const included = new Set(ordered.map((message) => message.id));
10354
10436
  ordered.push(
10355
- ...messages.filter((message) => !included.has(message.id)).sort((left, right) => left.createdAt - right.createdAt)
10437
+ ...messages.filter((message) => !included.has(message.id)).sort(compareMessagesByCreatedAtAndId)
10356
10438
  );
10357
10439
  }
10358
10440
  return ordered;
@@ -10368,30 +10450,38 @@ function repairParentChainCorruption(messages) {
10368
10450
  return parentId === message.parentId ? message : { ...message, parentId };
10369
10451
  });
10370
10452
  const byId = new Map(repaired.map((message) => [message.id, message]));
10371
- const cycleClosingIds = /* @__PURE__ */ new Set();
10453
+ const cycleRootIds = /* @__PURE__ */ new Set();
10372
10454
  const safeIds = /* @__PURE__ */ new Set();
10373
10455
  for (const start of byId.values()) {
10374
- const pathIds = /* @__PURE__ */ new Set();
10456
+ const pathIndexById = /* @__PURE__ */ new Map();
10375
10457
  const path = [];
10376
10458
  let current = start;
10377
10459
  while (current && !safeIds.has(current.id)) {
10378
- if (pathIds.has(current.id)) {
10379
- cycleClosingIds.add(path[path.length - 1].id);
10460
+ const cycleStart = pathIndexById.get(current.id);
10461
+ if (cycleStart !== void 0) {
10462
+ let cycleRoot = path[cycleStart];
10463
+ for (let index = cycleStart + 1; index < path.length; index++) {
10464
+ const candidate = path[index];
10465
+ if (compareMessagesByCreatedAtAndId(candidate, cycleRoot) < 0) {
10466
+ cycleRoot = candidate;
10467
+ }
10468
+ }
10469
+ cycleRootIds.add(cycleRoot.id);
10380
10470
  break;
10381
10471
  }
10382
- pathIds.add(current.id);
10472
+ pathIndexById.set(current.id, path.length);
10383
10473
  path.push(current);
10384
10474
  current = current.parentId ? byId.get(current.parentId) : void 0;
10385
10475
  }
10386
- for (const id of pathIds) {
10476
+ for (const id of pathIndexById.keys()) {
10387
10477
  safeIds.add(id);
10388
10478
  }
10389
10479
  }
10390
- if (cycleClosingIds.size === 0) {
10480
+ if (cycleRootIds.size === 0) {
10391
10481
  return repaired;
10392
10482
  }
10393
10483
  return repaired.map(
10394
- (message) => cycleClosingIds.has(message.id) ? { ...message, parentId: void 0 } : message
10484
+ (message) => cycleRootIds.has(message.id) ? { ...message, parentId: void 0 } : message
10395
10485
  );
10396
10486
  }
10397
10487
  function stripTaggedBlocks(text, startTag, endTag) {
@@ -10774,7 +10864,7 @@ function retryWithLogger(func, {
10774
10864
  return async function retryWrapper(...args) {
10775
10865
  let attempts = 0;
10776
10866
  let funcError = new Error("No error captured");
10777
- while (attempts < retries) {
10867
+ while (typeof retries === "function" || attempts < retries) {
10778
10868
  try {
10779
10869
  const result = await func(...args);
10780
10870
  if (onSuccess) {
@@ -10794,7 +10884,8 @@ function retryWithLogger(func, {
10794
10884
  logWarn2("Retry attempt failed", { cause: error });
10795
10885
  }
10796
10886
  }
10797
- if (attempts >= retries) {
10887
+ const retryLimit = typeof retries === "function" ? retries(funcError) : retries;
10888
+ if (attempts >= retryLimit) {
10798
10889
  break;
10799
10890
  }
10800
10891
  const baseDelayTime = exponentialBackoff ? delay * backoffFactor ** attempts : delay;
@@ -11660,14 +11751,18 @@ var DaemonClient = class _DaemonClient {
11660
11751
  const validated = DaemonKillWorkerSessionRequestSchema.parse(request);
11661
11752
  return this.sendRequest(validated, DaemonKillWorkerSessionResultSchema);
11662
11753
  }
11663
- listOpenedSessions(params = {}) {
11754
+ listOpenedSessions(params, options) {
11664
11755
  const request = _DaemonClient.buildDaemonRequest({
11665
11756
  method: "daemon.list_opened_sessions" /* LIST_OPENED_SESSIONS */,
11666
11757
  id: _DaemonClient.generateRequestId(),
11667
- params
11758
+ params: params ?? {}
11668
11759
  });
11669
11760
  const validated = DaemonListOpenedSessionsRequestSchema.parse(request);
11670
- return this.sendRequest(validated, DaemonListOpenedSessionsResultSchema);
11761
+ return this.sendRequest(
11762
+ validated,
11763
+ DaemonListOpenedSessionsResultSchema,
11764
+ options?.timeout
11765
+ );
11671
11766
  }
11672
11767
  listAvailableSessions(params) {
11673
11768
  const request = _DaemonClient.buildDaemonRequest({
@@ -11839,14 +11934,18 @@ var DaemonClient = class _DaemonClient {
11839
11934
  const validated = DaemonRelayStopRequestSchema.parse(request);
11840
11935
  return this.sendRequest(validated, DaemonRelayStopResultSchema);
11841
11936
  }
11842
- getRelayStatus() {
11937
+ getRelayStatus(options) {
11843
11938
  const request = _DaemonClient.buildDaemonRequest({
11844
11939
  method: "daemon.relay.get_status" /* GET_STATUS */,
11845
11940
  id: _DaemonClient.generateRequestId(),
11846
11941
  params: {}
11847
11942
  });
11848
11943
  const validated = DaemonRelayGetStatusRequestSchema.parse(request);
11849
- return this.sendRequest(validated, DaemonRelayGetStatusResultSchema);
11944
+ return this.sendRequest(
11945
+ validated,
11946
+ DaemonRelayGetStatusResultSchema,
11947
+ options?.timeout
11948
+ );
11850
11949
  }
11851
11950
  // Terminal methods
11852
11951
  createTerminal(params) {
@@ -12971,6 +13070,7 @@ var DaemonClient = class _DaemonClient {
12971
13070
  // ../daemon-sdk/src/connectWithRetry.ts
12972
13071
  var DEFAULT_MAX_RETRIES = 10;
12973
13072
  var RETRY_POLL_INTERVAL_MS = 2e3;
13073
+ var RETRY_POLL_JITTER_MS = 500;
12974
13074
  async function connectAndAuthenticate({
12975
13075
  client,
12976
13076
  url,
@@ -13041,7 +13141,8 @@ async function connectWithRetry({
13041
13141
  },
13042
13142
  {
13043
13143
  retries: maxRetries + 1,
13044
- delay: RETRY_POLL_INTERVAL_MS
13144
+ delay: RETRY_POLL_INTERVAL_MS,
13145
+ getDelay: () => RETRY_POLL_INTERVAL_MS + Math.random() * RETRY_POLL_JITTER_MS
13045
13146
  }
13046
13147
  );
13047
13148
  try {
@@ -13069,6 +13170,7 @@ var ConnectionFailureReason = /* @__PURE__ */ ((ConnectionFailureReason2) => {
13069
13170
  ConnectionFailureReason2["IdentityMismatch"] = "identity_mismatch";
13070
13171
  ConnectionFailureReason2["ProtocolMismatch"] = "protocol_mismatch";
13071
13172
  ConnectionFailureReason2["ComputeLimitExceeded"] = "compute_limit_exceeded";
13173
+ ConnectionFailureReason2["ComputerSessionLimitExceeded"] = "computer_session_limit_exceeded";
13072
13174
  ConnectionFailureReason2["RelayUnauthorized"] = "relay_unauthorized";
13073
13175
  ConnectionFailureReason2["DaemonConflict"] = "daemon_conflict";
13074
13176
  ConnectionFailureReason2["RelayUnreachable"] = "relay_unreachable";
@@ -13192,6 +13294,7 @@ function getMetricLabels({
13192
13294
  return {
13193
13295
  surface: options.surface,
13194
13296
  ...options.provider && { providerType: options.provider },
13297
+ ...options.audience && { audience: options.audience },
13195
13298
  attemptTrigger,
13196
13299
  outcome,
13197
13300
  ...failureReason && { failureReason },
@@ -13578,6 +13681,10 @@ var REASON_BEHAVIOR = {
13578
13681
  retryable: false,
13579
13682
  message: COMPUTE_LIMIT_EXCEEDED_MESSAGE
13580
13683
  },
13684
+ ["computer_session_limit_exceeded" /* ComputerSessionLimitExceeded */]: {
13685
+ retryable: false,
13686
+ message: "This organization has reached its active Cloud session limit."
13687
+ },
13581
13688
  ["relay_unauthorized" /* RelayUnauthorized */]: {
13582
13689
  retryable: false,
13583
13690
  message: "Relay authentication failed. Please sign in again."
@@ -14391,6 +14498,34 @@ function getWebSocketConfigForMachine(type) {
14391
14498
  }
14392
14499
 
14393
14500
  // ../daemon-sdk/src/createWebSocketDaemonClient.ts
14501
+ async function getLegacyDaemonAuthenticationCredential(getAccessToken) {
14502
+ const token = await getAccessToken();
14503
+ return token ? { token } : null;
14504
+ }
14505
+ function getDaemonAuthenticationCredential(config) {
14506
+ if (config.getCredential) {
14507
+ return config.getCredential();
14508
+ }
14509
+ return getLegacyDaemonAuthenticationCredential(config.getAccessToken);
14510
+ }
14511
+ function getDaemonClientSurface(clientType) {
14512
+ switch (clientType) {
14513
+ case "cli":
14514
+ return ClientUiSurface.CliTui;
14515
+ case "desktop":
14516
+ return ClientUiSurface.Desktop;
14517
+ case "web":
14518
+ return ClientUiSurface.Web;
14519
+ case "sdk":
14520
+ return ClientUiSurface.Sdk;
14521
+ default: {
14522
+ const exhaustiveCheck = clientType;
14523
+ throw new MetaError("Unhandled daemon client type", {
14524
+ clientType: exhaustiveCheck
14525
+ });
14526
+ }
14527
+ }
14528
+ }
14394
14529
  function createWebSocketDaemonClient(config) {
14395
14530
  const transport = new WebSocketDaemonTransport({
14396
14531
  ...getWebSocketConfigForMachine(config.machineType),
@@ -14435,6 +14570,31 @@ function createWebSocketDaemonClient(config) {
14435
14570
  }
14436
14571
  }
14437
14572
  }
14573
+ function createWebSocketDaemonClientFromConfig(config) {
14574
+ return createWebSocketDaemonClient({
14575
+ machineType: config.machineType,
14576
+ ...config.machineType === "computer" /* Computer */ ? { providerType: config.providerType } : {},
14577
+ getAccessToken: async () => {
14578
+ const credential = await getDaemonAuthenticationCredential(config);
14579
+ if (!credential) return null;
14580
+ if ("apiKey" in credential) {
14581
+ throw new MetaError(
14582
+ "API-key credentials cannot authenticate relay connections"
14583
+ );
14584
+ }
14585
+ return credential.token;
14586
+ },
14587
+ getActiveOrganizationId: config.getActiveOrganizationId,
14588
+ requestTimeout: config.requestTimeout,
14589
+ clientSurface: getDaemonClientSurface(config.clientType ?? "web"),
14590
+ transportConfig: {
14591
+ maxConnectRetries: 0,
14592
+ initialRetryDelayMs: 0,
14593
+ maxRetryDelayMs: 0,
14594
+ connectionTimeoutMs: config.connectionTimeoutMs
14595
+ }
14596
+ });
14597
+ }
14438
14598
 
14439
14599
  // ../daemon-sdk/src/session/DaemonSessionController.ts
14440
14600
  import { EventEmitter as EventEmitter4 } from "eventemitter3";
@@ -14895,12 +15055,10 @@ function orderedContentBlocksMatch(left, right) {
14895
15055
  }
14896
15056
  function hasCanonicalFallbackOrder(content) {
14897
15057
  const fallbackContent = [
14898
- ...content.images.map(
14899
- (source) => ({
14900
- type: "image" /* Image */,
14901
- source
14902
- })
14903
- )
15058
+ ...content.images.map((source) => ({
15059
+ type: "image" /* Image */,
15060
+ source
15061
+ }))
14904
15062
  ];
14905
15063
  if (content.text) {
14906
15064
  fallbackContent.push({
@@ -15131,6 +15289,15 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
15131
15289
  // exactly this controller's listeners (removeAllListeners would detach
15132
15290
  // other controllers' too).
15133
15291
  promptStoreUnsubscribes = [];
15292
+ // Prompt-owning sessions interrupted specifically by transport loss. Unlike
15293
+ // daemon inactivity, their first reconnect snapshot can transiently omit a
15294
+ // still-pending prompt while the worker is being restored.
15295
+ transportInterruptedPromptSessions = /* @__PURE__ */ new Set();
15296
+ // A reconnect may preserve an omitted prompt for one snapshot. If the user
15297
+ // answers during that grace window, the session remains in the inactive
15298
+ // response path so the answer is buffered and replayed against the worker's
15299
+ // restored request id instead of being sent to a stale pre-disconnect id.
15300
+ reconnectPromptSnapshotGraceConsumedSessions = /* @__PURE__ */ new Set();
15134
15301
  // Whether a session's worker is paused (buffer responses), whether a session
15135
15302
  // is draining a concurrent prompt batch (suppress resume-driven auto-clear),
15136
15303
  // and the spawn options replayed on self-resume all describe the *session*,
@@ -15176,24 +15343,7 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
15176
15343
  super();
15177
15344
  const { sessionStateManager, config, daemonClient, missionStateManager } = params;
15178
15345
  this.config = config;
15179
- this.daemonClient = daemonClient ?? createWebSocketDaemonClient({
15180
- machineType: config.machineType,
15181
- ...config.machineType === "computer" /* Computer */ && {
15182
- providerType: config.providerType
15183
- },
15184
- getAccessToken: config.getAccessToken,
15185
- getActiveOrganizationId: config.getActiveOrganizationId,
15186
- requestTimeout: config.requestTimeout,
15187
- clientSurface: _DaemonSessionController.getClientSurfaceForType(
15188
- config.clientType
15189
- ),
15190
- transportConfig: {
15191
- maxConnectRetries: 0,
15192
- initialRetryDelayMs: 0,
15193
- maxRetryDelayMs: 0,
15194
- connectionTimeoutMs: config.connectionTimeoutMs
15195
- }
15196
- });
15346
+ this.daemonClient = daemonClient ?? createWebSocketDaemonClientFromConfig(config);
15197
15347
  this.messageRouter = new MessageRouter({
15198
15348
  emitReceiveSpans: config.clientType !== "cli"
15199
15349
  });
@@ -15219,24 +15369,12 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
15219
15369
  getClientType() {
15220
15370
  return this.config.clientType ?? "web";
15221
15371
  }
15222
- static getClientSurfaceForType(clientType) {
15223
- if (clientType === "desktop") {
15224
- return ClientUiSurface.Desktop;
15225
- }
15226
- if (clientType === "web") {
15227
- return ClientUiSurface.Web;
15228
- }
15229
- if (clientType === "sdk") {
15230
- return ClientUiSurface.Sdk;
15231
- }
15232
- return void 0;
15233
- }
15234
15372
  /**
15235
15373
  * Get the current client interaction surface for RPC requests.
15236
15374
  * Uses injectable clientType from config instead of checking window.electronAPI.
15237
15375
  */
15238
15376
  getClientSurface() {
15239
- return _DaemonSessionController.getClientSurfaceForType(this.getClientType()) ?? ClientUiSurface.Web;
15377
+ return getDaemonClientSurface(this.getClientType());
15240
15378
  }
15241
15379
  async withConnectAttemptContext(context, fn) {
15242
15380
  const previous = this.connectAttemptContext;
@@ -15756,6 +15894,7 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
15756
15894
  case "hook_execution_completed" /* HOOK_EXECUTION_COMPLETED */:
15757
15895
  case "structured_output" /* STRUCTURED_OUTPUT */:
15758
15896
  case "session_compacted" /* SESSION_COMPACTED */:
15897
+ case "assistant_message_retracted" /* ASSISTANT_MESSAGE_RETRACTED */:
15759
15898
  break;
15760
15899
  case "tool_call" /* TOOL_CALL */: {
15761
15900
  const sessionManager = this.sessionStateManager.getSessionManager(sessionId);
@@ -15992,6 +16131,8 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
15992
16131
  break;
15993
16132
  }
15994
16133
  case "session_closed" /* SESSION_CLOSED */: {
16134
+ this.transportInterruptedPromptSessions.delete(sessionId);
16135
+ this.reconnectPromptSnapshotGraceConsumedSessions.delete(sessionId);
15995
16136
  this.trackedChildSessionIds.delete(sessionId);
15996
16137
  this.childSessionAttachmentGeneration.delete(sessionId);
15997
16138
  this.clearPendingUserActionsForSession(sessionId);
@@ -16001,6 +16142,11 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
16001
16142
  }
16002
16143
  case "droid_working_state_changed" /* DROID_WORKING_STATE_CHANGED */: {
16003
16144
  if (notification.newState !== "waiting_for_tool_confirmation" /* WaitingForToolConfirmation */) {
16145
+ if (this.transportInterruptedPromptSessions.has(sessionId)) {
16146
+ this.sessionStateManager.markSessionActive(sessionId);
16147
+ this.transportInterruptedPromptSessions.delete(sessionId);
16148
+ this.reconnectPromptSnapshotGraceConsumedSessions.delete(sessionId);
16149
+ }
16004
16150
  this.clearStalePromptsOnResume(sessionId);
16005
16151
  }
16006
16152
  break;
@@ -16043,6 +16189,7 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
16043
16189
  case "structured_output" /* STRUCTURED_OUTPUT */:
16044
16190
  case "thinking_text_delta" /* THINKING_TEXT_DELTA */:
16045
16191
  case "assistant_text_complete" /* ASSISTANT_TEXT_COMPLETE */:
16192
+ case "assistant_message_retracted" /* ASSISTANT_MESSAGE_RETRACTED */:
16046
16193
  case "thinking_text_complete" /* THINKING_TEXT_COMPLETE */:
16047
16194
  case "mcp_auth_required" /* MCP_AUTH_REQUIRED */:
16048
16195
  case "mcp_auth_completed" /* MCP_AUTH_COMPLETED */:
@@ -16596,14 +16743,14 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
16596
16743
  }
16597
16744
  );
16598
16745
  try {
16599
- const token = await this.config.getAccessToken();
16600
- if (!token) {
16746
+ const credential = await getDaemonAuthenticationCredential(this.config);
16747
+ if (!credential) {
16601
16748
  throw createConnectionFailure("no_token" /* NoToken */, {
16602
16749
  retryable: this.config.machineType === "local" /* Local */
16603
16750
  });
16604
16751
  }
16605
16752
  const actAsGrant = await this.config.getActAsGrant?.();
16606
- await this.authenticateDaemon(token, actAsGrant);
16753
+ await this.authenticateDaemon(credential, actAsGrant);
16607
16754
  this.lastConnectionFailure = null;
16608
16755
  Metrics.addToCounter(
16609
16756
  "factory_app_jsonrpc_authentication_success_count" /* FACTORY_APP_JSONRPC_AUTHENTICATION_SUCCESS_COUNT */,
@@ -16646,9 +16793,9 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
16646
16793
  * Authenticate with the daemon. Translates daemon auth errors into
16647
16794
  * ConnectionFailureError.
16648
16795
  */
16649
- async authenticateDaemon(token, actAsGrant) {
16796
+ async authenticateDaemon(credential, actAsGrant) {
16650
16797
  try {
16651
- await this.authenticate(token, { actAsGrant });
16798
+ await this.authenticate(credential, { actAsGrant });
16652
16799
  } catch (error) {
16653
16800
  if (error instanceof JsonRpcRequestError) {
16654
16801
  throw createConnectionFailure(
@@ -16675,6 +16822,20 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
16675
16822
  this._isAuthenticated = false;
16676
16823
  this.authenticationPromise = null;
16677
16824
  this.connectionGeneration += 1;
16825
+ for (const permission of this.permissionHandler.getPendingPermissions()) {
16826
+ this.sessionStateManager.markSessionInactive(permission.sessionId);
16827
+ this.transportInterruptedPromptSessions.add(permission.sessionId);
16828
+ this.reconnectPromptSnapshotGraceConsumedSessions.delete(
16829
+ permission.sessionId
16830
+ );
16831
+ }
16832
+ for (const request of this.askUserHandler.getPendingAskUserRequests()) {
16833
+ this.sessionStateManager.markSessionInactive(request.sessionId);
16834
+ this.transportInterruptedPromptSessions.add(request.sessionId);
16835
+ this.reconnectPromptSnapshotGraceConsumedSessions.delete(
16836
+ request.sessionId
16837
+ );
16838
+ }
16678
16839
  if (!this.lastConnectionFailure && !this.manuallyDisconnected) {
16679
16840
  this.lastConnectionFailure = createConnectionFailure(
16680
16841
  failureReasonFromCloseCode(code) ?? "connection_lost" /* ConnectionLost */
@@ -16800,12 +16961,12 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
16800
16961
  * Authenticate the WebSocket connection with the daemon.
16801
16962
  * Requires an open transport and must complete before session operations.
16802
16963
  * Prevents concurrent authentication attempts.
16803
- * @param token - WorkOS JWT access token
16964
+ * @param credential - WorkOS JWT access token or Factory API key.
16804
16965
  * @param options.actAsGrant - act-as delegation grant (`fdg-...`). When
16805
16966
  * provided, the operator's `token` plus this grant authenticate the
16806
16967
  * connection as the target service account on an SA-owned daemon.
16807
16968
  */
16808
- async authenticate(token, options) {
16969
+ async authenticate(credential, options) {
16809
16970
  if (this._isAuthenticated) {
16810
16971
  logInfo("Already authenticated, skipping duplicate authenticate call");
16811
16972
  return;
@@ -16817,7 +16978,7 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
16817
16978
  }
16818
16979
  const connectionId = this.daemonClient.getConnectionId();
16819
16980
  this.authenticationPromise = this.daemonClient.authenticate({
16820
- token,
16981
+ ...credential,
16821
16982
  ...options?.actAsGrant && { actAsGrant: options.actAsGrant },
16822
16983
  ...connectionId && { connectionId },
16823
16984
  caller: this.getFactoryClientType(),
@@ -17089,6 +17250,14 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
17089
17250
  sessionSource: void 0
17090
17251
  });
17091
17252
  }
17253
+ /**
17254
+ * Whether this controller currently owns an initialize or load operation for
17255
+ * the session. A false result after a failed operation means shared Loading
17256
+ * or Loaded state has no newer operation responsible for completing it.
17257
+ */
17258
+ isSessionLoadInFlight(sessionId) {
17259
+ return this.sessionLoadInFlight.has(sessionId);
17260
+ }
17092
17261
  /**
17093
17262
  * Ensures the current daemon connection is subscribed to a child session.
17094
17263
  * Loaded state only describes the local snapshot; listener attachment is
@@ -17175,9 +17344,10 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
17175
17344
  this.config.machineId
17176
17345
  );
17177
17346
  const workingStateRevisionBeforeLoad = this.sessionStateManager.getSessionManager(params.sessionId)?.getWorkingStateRevision() ?? 0;
17178
- const fetched = await this.config.getAccessToken();
17179
- if (fetched === null) {
17180
- throw new MetaError("No access token available for loadSession", {
17347
+ const subagentSummaryRevisionBeforeLoad = this.sessionStateManager.captureSubagentInvocationSummaryRevision();
17348
+ const credential = await getDaemonAuthenticationCredential(this.config);
17349
+ if (credential === null) {
17350
+ throw new MetaError("No credential available for loadSession", {
17181
17351
  sessionId: params.sessionId
17182
17352
  });
17183
17353
  }
@@ -17186,10 +17356,13 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
17186
17356
  stashedOptions,
17187
17357
  params
17188
17358
  );
17359
+ const spawnCredential = credential.token !== void 0 ? credential.token : credential.apiKey;
17189
17360
  const resolvedParams = {
17190
17361
  ...params,
17191
17362
  structuredOutputFormat,
17192
- token: fetched,
17363
+ // The daemon currently discards this legacy spawn-auth field on load.
17364
+ // Connection authentication above preserves the credential kind.
17365
+ token: spawnCredential,
17193
17366
  loadAllMessages: this.getClientType() === "cli" ? params.loadAllMessages : true,
17194
17367
  messageLimit: params.messageLimit ?? this.config.defaultMessageLimit,
17195
17368
  disableInactivityTimeout: params.disableInactivityTimeout ?? stashedOptions.disableInactivityTimeout ?? this.config.disableInactivityTimeout,
@@ -17204,7 +17377,8 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
17204
17377
  disableBuiltinSkills: resolvedParams.disableBuiltinSkills,
17205
17378
  skipPermissionsUnsafe: resolvedParams.skipPermissionsUnsafe,
17206
17379
  runtimeSettingsPath: resolvedParams.runtimeSettingsPath,
17207
- structuredOutputFormat
17380
+ structuredOutputFormat,
17381
+ taskSubagentProcess: resolvedParams.taskSubagentProcess
17208
17382
  })
17209
17383
  );
17210
17384
  let result;
@@ -17233,7 +17407,8 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
17233
17407
  );
17234
17408
  if (result.subagentInvocations && result.subagentInvocations.length > 0) {
17235
17409
  this.sessionStateManager.hydrateSubagentInvocationSummaries(
17236
- result.subagentInvocations
17410
+ result.subagentInvocations,
17411
+ subagentSummaryRevisionBeforeLoad
17237
17412
  );
17238
17413
  }
17239
17414
  } catch (error) {
@@ -17289,11 +17464,37 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
17289
17464
  settings: result.settings
17290
17465
  });
17291
17466
  let hasPendingAskUserRequests = false;
17467
+ let shouldKeepPromptSessionInactive = false;
17292
17468
  try {
17293
- this.permissionHandler.clearSessionPermissions(params.sessionId, {
17294
- preserveRelayed: true
17295
- });
17469
+ const isReconnectingPromptSession = this.transportInterruptedPromptSessions.has(params.sessionId);
17470
+ const reconnectGraceAlreadyConsumed = this.reconnectPromptSnapshotGraceConsumedSessions.has(params.sessionId);
17471
+ const localPermissions = this.permissionHandler.getPendingPermissions().filter((permission) => permission.sessionId === params.sessionId);
17472
+ const localAskUserRequests = this.askUserHandler.getPendingAskUserRequests().filter((request) => request.sessionId === params.sessionId);
17296
17473
  const reloadedPermissions = result.pendingPermissions ?? [];
17474
+ const reloadedPermissionToolUseIds = new Set(
17475
+ reloadedPermissions.flatMap(
17476
+ (permission) => (permission.toolUses ?? []).map((toolUse) => toolUse.toolUse.id)
17477
+ )
17478
+ );
17479
+ const reloadedAskUserToolCallIds = new Set(
17480
+ (result.pendingAskUserRequests ?? []).map(
17481
+ (request) => request.toolCallId
17482
+ )
17483
+ );
17484
+ const reconnectSnapshotConfirmsLocalPrompts = localPermissions.every(
17485
+ (permission) => permission.toolUses.some(
17486
+ (toolUse) => reloadedPermissionToolUseIds.has(toolUse.toolUse.id)
17487
+ )
17488
+ ) && localAskUserRequests.every(
17489
+ (request) => reloadedAskUserToolCallIds.has(request.toolCallId)
17490
+ );
17491
+ const shouldPreserveLocalPrompts = isReconnectingPromptSession && !reconnectGraceAlreadyConsumed;
17492
+ shouldKeepPromptSessionInactive = shouldPreserveLocalPrompts && !reconnectSnapshotConfirmsLocalPrompts;
17493
+ if (!shouldPreserveLocalPrompts) {
17494
+ this.permissionHandler.clearSessionPermissions(params.sessionId, {
17495
+ preserveRelayed: true
17496
+ });
17497
+ }
17297
17498
  let surfacedPermissionCount = 0;
17298
17499
  if (reloadedPermissions.length > 0) {
17299
17500
  const invalidPermissions = [];
@@ -17394,9 +17595,11 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
17394
17595
  reloadedPermissions
17395
17596
  );
17396
17597
  }
17397
- this.askUserHandler.clearSessionAskUserRequests(params.sessionId);
17398
- hasPendingAskUserRequests = !!(result.pendingAskUserRequests && result.pendingAskUserRequests.length > 0);
17399
- if (hasPendingAskUserRequests) {
17598
+ if (!shouldPreserveLocalPrompts) {
17599
+ this.askUserHandler.clearSessionAskUserRequests(params.sessionId);
17600
+ }
17601
+ const hasReloadedAskUserRequests = !!(result.pendingAskUserRequests && result.pendingAskUserRequests.length > 0);
17602
+ if (hasReloadedAskUserRequests) {
17400
17603
  for (const askUserRequest of result.pendingAskUserRequests) {
17401
17604
  const request = DaemonAskUserSchema.safeParse({
17402
17605
  type: "request",
@@ -17441,8 +17644,17 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
17441
17644
  result.pendingAskUserRequests
17442
17645
  );
17443
17646
  }
17647
+ hasPendingAskUserRequests = this.askUserHandler.getPendingAskUserRequests().some((request) => request.sessionId === params.sessionId);
17444
17648
  } finally {
17445
- this.sessionStateManager.markSessionActive(params.sessionId);
17649
+ if (shouldKeepPromptSessionInactive) {
17650
+ this.reconnectPromptSnapshotGraceConsumedSessions.add(params.sessionId);
17651
+ } else {
17652
+ this.sessionStateManager.markSessionActive(params.sessionId);
17653
+ this.transportInterruptedPromptSessions.delete(params.sessionId);
17654
+ this.reconnectPromptSnapshotGraceConsumedSessions.delete(
17655
+ params.sessionId
17656
+ );
17657
+ }
17446
17658
  }
17447
17659
  if (sessionManager) {
17448
17660
  await reconcileQueuedMessagesAfterLoad({
@@ -17728,8 +17940,13 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
17728
17940
  /**
17729
17941
  * Close a session. Used to terminate a worker session cleanly.
17730
17942
  */
17731
- async closeSession(sessionId) {
17732
- await this.daemonClient.closeSession({ sessionId });
17943
+ async closeSession(sessionId, options) {
17944
+ await this.daemonClient.closeSession({
17945
+ sessionId,
17946
+ ...options?.preserveEmptyDraft !== void 0 && {
17947
+ preserveEmptyDraft: options.preserveEmptyDraft
17948
+ }
17949
+ });
17733
17950
  this.sessionStateManager.deleteSessionLoadOptions(sessionId);
17734
17951
  this.sessionLoadInFlight.delete(sessionId);
17735
17952
  this.trackedChildSessionIds.delete(sessionId);
@@ -18691,6 +18908,19 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
18691
18908
  getMachineType() {
18692
18909
  return this.config.machineType;
18693
18910
  }
18911
+ /**
18912
+ * Refresh connection lifecycle data that may change while a Computer
18913
+ * controller remains registered under the same machine id.
18914
+ */
18915
+ updateComputerEnsureRunning(ensureRunning) {
18916
+ if (this.config.machineType !== "computer" /* Computer */) {
18917
+ return;
18918
+ }
18919
+ this.config = {
18920
+ ...this.config,
18921
+ ensureRunning
18922
+ };
18923
+ }
18694
18924
  /**
18695
18925
  * Get the machine connection type for this daemon client.
18696
18926
  *
@@ -18797,6 +19027,8 @@ var DaemonSessionController = class _DaemonSessionController extends EventEmitte
18797
19027
  this.sessionLoadInFlight.clear();
18798
19028
  this.trackedChildSessionIds.clear();
18799
19029
  this.childSessionAttachmentGeneration.clear();
19030
+ this.transportInterruptedPromptSessions.clear();
19031
+ this.reconnectPromptSnapshotGraceConsumedSessions.clear();
18800
19032
  }
18801
19033
  };
18802
19034
 
@@ -21854,7 +22086,8 @@ var SessionStateManager = class _SessionStateManager {
21854
22086
  const { notification } = params;
21855
22087
  const isStreamingDelta = notification.type === "assistant_text_delta" /* ASSISTANT_TEXT_DELTA */ || notification.type === "thinking_text_delta" /* THINKING_TEXT_DELTA */;
21856
22088
  const isBlockComplete = notification.type === "assistant_text_complete" /* ASSISTANT_TEXT_COMPLETE */ || notification.type === "thinking_text_complete" /* THINKING_TEXT_COMPLETE */;
21857
- if (this.lastNotificationWasStreamingDelta && !isStreamingDelta && !isBlockComplete) {
22089
+ const isMessageRetraction = notification.type === "assistant_message_retracted" /* ASSISTANT_MESSAGE_RETRACTED */;
22090
+ if (this.lastNotificationWasStreamingDelta && !isStreamingDelta && !isBlockComplete && !isMessageRetraction) {
21858
22091
  logInfo(
21859
22092
  "[SessionStateManager] Heuristic flush: streaming delta \u2192 discrete event",
21860
22093
  {
@@ -22121,6 +22354,24 @@ var SessionStateManager = class _SessionStateManager {
22121
22354
  this.store.notifyStreamingChange();
22122
22355
  break;
22123
22356
  }
22357
+ case "assistant_message_retracted" /* ASSISTANT_MESSAGE_RETRACTED */: {
22358
+ const pendingMessageId = this.pendingAssistantMessageId;
22359
+ const messageIds = /* @__PURE__ */ new Set([notification.messageId]);
22360
+ if (pendingMessageId) {
22361
+ messageIds.add(pendingMessageId);
22362
+ this.pendingAssistantMessageId = null;
22363
+ }
22364
+ const hadRetractedMessage = [...messageIds].some(
22365
+ (messageId) => this.store.getMessage(messageId) !== void 0
22366
+ );
22367
+ for (const messageId of messageIds) {
22368
+ this.store.removeMessage(messageId);
22369
+ }
22370
+ if (!hadRetractedMessage) break;
22371
+ this.store.flushStreamingChanges();
22372
+ this.store.flushNotify("message_thread_updated" /* MessageThreadUpdated */);
22373
+ break;
22374
+ }
22124
22375
  case "assistant_text_complete" /* ASSISTANT_TEXT_COMPLETE */: {
22125
22376
  logInfo("[SessionStateManager] Text block complete", {
22126
22377
  sessionId: params.sessionId,
@@ -23005,6 +23256,11 @@ var AskUserRequestHandler = class _AskUserRequestHandler extends EventEmitter6 {
23005
23256
  });
23006
23257
  return;
23007
23258
  }
23259
+ for (const [pendingId, existing] of this.pendingRequests) {
23260
+ if (existing.sessionId === sessionId && existing.toolCallId === pending.toolCallId) {
23261
+ this.clearAskUser(pendingId);
23262
+ }
23263
+ }
23008
23264
  this.pendingRequests.set(id, pending);
23009
23265
  this.emit("askUserRequested", pending);
23010
23266
  }
@@ -23426,6 +23682,9 @@ var MultiSessionStateManager = class _MultiSessionStateManager {
23426
23682
  // real tool-use count after the child closes or the parent session reloads.
23427
23683
  // Hydrated from loadSession (disk-backed) and updated live on completion.
23428
23684
  subagentInvocationSummaries = /* @__PURE__ */ new Map();
23685
+ subagentInvocationSummaryRevision = 0;
23686
+ subagentInvocationSummaryLastModifiedRevision = /* @__PURE__ */ new Map();
23687
+ subagentInvocationSummaryEpoch = 0;
23429
23688
  // Track sessions that have already had their initial prompt sent (persists across remounts)
23430
23689
  sentInitialPromptSessions = /* @__PURE__ */ new Set();
23431
23690
  // Session-scoped prompt state, owned here (app lifetime) rather than by the
@@ -24147,6 +24406,11 @@ var MultiSessionStateManager = class _MultiSessionStateManager {
24147
24406
  setSubagentInvocationSummary(childSessionId, summary) {
24148
24407
  _MultiSessionStateManager.validateSessionId(childSessionId);
24149
24408
  this.subagentInvocationSummaries.set(childSessionId, summary);
24409
+ this.subagentInvocationSummaryRevision += 1;
24410
+ this.subagentInvocationSummaryLastModifiedRevision.set(
24411
+ childSessionId,
24412
+ this.subagentInvocationSummaryRevision
24413
+ );
24150
24414
  this.emitSessionStateEvent(
24151
24415
  "subagent_invocation_summary_updated" /* SubagentInvocationSummaryUpdated */,
24152
24416
  { sessionId: childSessionId }
@@ -24159,20 +24423,35 @@ var MultiSessionStateManager = class _MultiSessionStateManager {
24159
24423
  getSubagentInvocationSummary(childSessionId) {
24160
24424
  return this.subagentInvocationSummaries.get(childSessionId);
24161
24425
  }
24426
+ /**
24427
+ * Capture the epoch/revision pair immediately before loadSession. Pass the
24428
+ * same pair to hydrateSubagentInvocationSummaries so reset and per-child live
24429
+ * updates win over stale load responses without blocking unrelated children.
24430
+ */
24431
+ captureSubagentInvocationSummaryRevision() {
24432
+ return {
24433
+ epoch: this.subagentInvocationSummaryEpoch,
24434
+ revision: this.subagentInvocationSummaryRevision
24435
+ };
24436
+ }
24162
24437
  /**
24163
24438
  * Bulk-hydrate subagent summaries (e.g. from a loadSession response). Existing
24164
24439
  * entries are preserved unless overwritten by a matching child session id.
24165
24440
  */
24166
- hydrateSubagentInvocationSummaries(summaries) {
24441
+ hydrateSubagentInvocationSummaries(summaries, expectedRevision) {
24442
+ if (expectedRevision !== void 0 && expectedRevision.epoch !== this.subagentInvocationSummaryEpoch) {
24443
+ return;
24444
+ }
24167
24445
  for (const summary of summaries) {
24168
24446
  if (!_MultiSessionStateManager.isValidSessionId(summary.childSessionId)) {
24169
24447
  continue;
24170
24448
  }
24171
- this.subagentInvocationSummaries.set(summary.childSessionId, summary);
24172
- this.emitSessionStateEvent(
24173
- "subagent_invocation_summary_updated" /* SubagentInvocationSummaryUpdated */,
24174
- { sessionId: summary.childSessionId }
24175
- );
24449
+ if (expectedRevision !== void 0 && (this.subagentInvocationSummaryLastModifiedRevision.get(
24450
+ summary.childSessionId
24451
+ ) ?? 0) > expectedRevision.revision) {
24452
+ continue;
24453
+ }
24454
+ this.setSubagentInvocationSummary(summary.childSessionId, summary);
24176
24455
  }
24177
24456
  }
24178
24457
  /**
@@ -24242,11 +24521,10 @@ var MultiSessionStateManager = class _MultiSessionStateManager {
24242
24521
  }
24243
24522
  /**
24244
24523
  * Roll every session bound to the given machine back to NotLoaded, emitting a
24245
- * state change for each so subscribers re-render. Called just before a forced
24246
- * teardown of the machine's controller: without this, sessions keep MSSM's
24247
- * stale Loaded state and the reconnect/remount path skips the loadSession that
24248
- * would rebind them, leaving them hung "as if disconnected" while the machine
24249
- * is actually still connected.
24524
+ * state change for each so subscribers re-render. Called when a controller
24525
+ * disconnects or is forcibly torn down. Without this, sessions keep MSSM's
24526
+ * stale Loaded state and the reconnect/remount path skips the loadSession
24527
+ * that would rebind them.
24250
24528
  */
24251
24529
  markSessionsNotLoadedForMachine(machineId) {
24252
24530
  for (const [sessionId, manager] of this.sessions.entries()) {
@@ -24343,6 +24621,9 @@ var MultiSessionStateManager = class _MultiSessionStateManager {
24343
24621
  this.sessions.clear();
24344
24622
  this.lastAccessTime.clear();
24345
24623
  this.subagentInvocationSummaries.clear();
24624
+ this.subagentInvocationSummaryLastModifiedRevision.clear();
24625
+ this.subagentInvocationSummaryRevision += 1;
24626
+ this.subagentInvocationSummaryEpoch += 1;
24346
24627
  this.preInitSessions.clear();
24347
24628
  this._askUserRequests.clearAll();
24348
24629
  this._permissionRequests.clearAllPermissions();
@@ -25638,7 +25919,7 @@ function createConnectedDroid(controller, apiKey, handlers = {}) {
25638
25919
  return new ConnectedDroidImpl(controller, apiKey, handlers);
25639
25920
  }
25640
25921
  async function connectToDaemon(options) {
25641
- const getAccessToken = () => Promise.resolve(options.auth.apiKey);
25922
+ const getCredential = () => Promise.resolve({ apiKey: options.auth.apiKey });
25642
25923
  const connectionConfig = {
25643
25924
  ...DEFAULT_CONNECTION_CONFIG,
25644
25925
  ...MACHINE_TYPE_CONFIG["local" /* Local */]
@@ -25649,9 +25930,9 @@ async function connectToDaemon(options) {
25649
25930
  machineId: LOCAL_MACHINE_ID,
25650
25931
  machineType: "local" /* Local */,
25651
25932
  url: options.url,
25652
- clientType: "sdk",
25933
+ clientType: "sdk" /* SDK */,
25653
25934
  sdk: SDK_CLIENT_METADATA,
25654
- getAccessToken,
25935
+ getCredential,
25655
25936
  onAuthenticationError: options.onAuthenticationError,
25656
25937
  connectionTimeoutMs: connectionConfig.connectionTimeoutMs,
25657
25938
  requestTimeout: connectionConfig.requestTimeoutMs,
@@ -25764,7 +26045,7 @@ async function factoryFetch(path, apiKey, baseUrl, options) {
25764
26045
  Authorization: `Bearer ${apiKey}`,
25765
26046
  Accept: "application/json",
25766
26047
  [FACTORY_CLIENT_HEADER]: "sdk" /* SDK */,
25767
- [FACTORY_SDK_HEADER]: formatSdkClientMetadata(SDK_CLIENT_METADATA)
26048
+ [FACTORY_SDK_HEADER]: SDK_IDENTITY
25768
26049
  };
25769
26050
  if (options?.body) {
25770
26051
  headers["Content-Type"] = "application/json";
@@ -25958,7 +26239,6 @@ export {
25958
26239
  SettingsLevel,
25959
26240
  SkillLocation,
25960
26241
  JSONRPC_VERSION,
25961
- formatSdkClientMetadata,
25962
26242
  TraceContextMetaSchema,
25963
26243
  JsonRpcEnvelopeSchema,
25964
26244
  JsonRpcErrorSchema,
@@ -26229,6 +26509,7 @@ export {
26229
26509
  HookExecutionStartedNotificationSchema2 as HookExecutionStartedNotificationSchema,
26230
26510
  HookExecutionCompletedNotificationSchema2 as HookExecutionCompletedNotificationSchema,
26231
26511
  ToolCallNotificationSchema2 as ToolCallNotificationSchema,
26512
+ AssistantMessageRetractedNotificationSchema2 as AssistantMessageRetractedNotificationSchema,
26232
26513
  EditToolConfirmationDetailsSchema2 as EditToolConfirmationDetailsSchema,
26233
26514
  ExecuteToolConfirmationDetailsSchema2 as ExecuteToolConfirmationDetailsSchema,
26234
26515
  CreateToolConfirmationDetailsSchema2 as CreateToolConfirmationDetailsSchema,
@@ -26249,7 +26530,7 @@ export {
26249
26530
  FactoryDroidMessageRole,
26250
26531
  ServerRequestHandlerType,
26251
26532
  SDK_VERSION,
26252
- SDK_CLIENT_METADATA,
26533
+ SDK_IDENTITY,
26253
26534
  SDK_REQUEST_ATTRIBUTION,
26254
26535
  SDK_TAG,
26255
26536
  JSONRPC_VERSION3,
@@ -26401,4 +26682,4 @@ react/cjs/react.development.js:
26401
26682
  * LICENSE file in the root directory of this source tree.
26402
26683
  *)
26403
26684
  */
26404
- //# sourceMappingURL=chunk-KXDG5ZWS.mjs.map
26685
+ //# sourceMappingURL=chunk-TWSTJMV7.mjs.map