replicas-engine 0.1.408 → 0.1.410

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/src/index.js +309 -85
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -479,7 +479,7 @@ var WORKSPACE_SIZES = ["small", "large"];
479
479
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
480
480
 
481
481
  // ../shared/src/e2b.ts
482
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-08-v3";
482
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-08-v5";
483
483
 
484
484
  // ../shared/src/runtime-env.ts
485
485
  function parsePosixEnvFile(content) {
@@ -5533,27 +5533,81 @@ function linearThoughtToResponse(thought) {
5533
5533
  function summarizeInput(input) {
5534
5534
  if (!input) return "";
5535
5535
  if (typeof input === "string") return input;
5536
- if (typeof input === "object") {
5537
- const obj = input;
5538
- if (obj.file_path) return String(obj.file_path);
5539
- if (obj.command) return String(obj.command);
5540
- if (obj.pattern) return `pattern: ${String(obj.pattern)}`;
5541
- if (obj.query) return String(obj.query);
5542
- if (obj.url) return String(obj.url);
5543
- if (typeof obj.activeForm === "string" && obj.activeForm) return String(obj.activeForm);
5544
- if (typeof obj.subject === "string" && obj.subject) return String(obj.subject);
5545
- const keys = Object.keys(obj);
5546
- if (keys.length > 0) {
5547
- const firstKey = keys[0];
5548
- return `${firstKey}: ${String(obj[firstKey])}`;
5536
+ if (isRecord(input)) {
5537
+ if (input.file_path) return String(input.file_path);
5538
+ if (input.command) return String(input.command);
5539
+ if (input.pattern) return `pattern: ${String(input.pattern)}`;
5540
+ if (input.query) return String(input.query);
5541
+ if (input.url) return String(input.url);
5542
+ if (typeof input.activeForm === "string" && input.activeForm) return String(input.activeForm);
5543
+ if (typeof input.subject === "string" && input.subject) return String(input.subject);
5544
+ for (const [key, value] of Object.entries(input)) {
5545
+ return `${key}: ${String(value)}`;
5549
5546
  }
5550
5547
  }
5551
5548
  return "";
5552
5549
  }
5550
+ function summarizeResult(result) {
5551
+ if (!result) return "";
5552
+ if (typeof result === "string") return result;
5553
+ if (isRecord(result)) {
5554
+ if (typeof result.message === "string") return result.message;
5555
+ if (typeof result.error === "string") return result.error;
5556
+ if (typeof result.stdout === "string") return result.stdout;
5557
+ if (typeof result.stderr === "string") return result.stderr;
5558
+ if (typeof result.path === "string") return result.path;
5559
+ }
5560
+ try {
5561
+ return JSON.stringify(result);
5562
+ } catch {
5563
+ return String(result);
5564
+ }
5565
+ }
5566
+ function toolAction(toolName) {
5567
+ switch (toolName) {
5568
+ case "Bash":
5569
+ case "bash":
5570
+ case "shell":
5571
+ return "Running command";
5572
+ case "Edit":
5573
+ case "edit":
5574
+ return "Editing file";
5575
+ case "Write":
5576
+ case "write":
5577
+ return "Writing file";
5578
+ case "Read":
5579
+ case "read":
5580
+ return "Reading file";
5581
+ case "Glob":
5582
+ case "glob":
5583
+ return "Searching files";
5584
+ case "Grep":
5585
+ case "grep":
5586
+ case "semsearch":
5587
+ return "Searching code";
5588
+ case "WebSearch":
5589
+ return "Web search";
5590
+ case "WebFetch":
5591
+ return "Fetching URL";
5592
+ case "delete":
5593
+ return "Deleting file";
5594
+ case "Task":
5595
+ case "task":
5596
+ return "Spawning subagent";
5597
+ case "TaskCreate":
5598
+ case "TaskUpdate":
5599
+ case "TaskList":
5600
+ case "TaskGet":
5601
+ case "update_todos":
5602
+ case "create_plan":
5603
+ return "Updating plan";
5604
+ default:
5605
+ return toolName;
5606
+ }
5607
+ }
5553
5608
  function convertClaudeEvent(event, linearSessionId) {
5554
5609
  if (event.type === "assistant") {
5555
- const message = event;
5556
- const contentBlocks = normalizeContentBlocks(message.message?.content);
5610
+ const contentBlocks = normalizeContentBlocks(event.message.content);
5557
5611
  for (const block of contentBlocks) {
5558
5612
  if (block.type === "text" && block.text) {
5559
5613
  return {
@@ -5576,47 +5630,11 @@ function convertClaudeEvent(event, linearSessionId) {
5576
5630
  if (block.type === "tool_use" && block.name) {
5577
5631
  const toolName = block.name;
5578
5632
  const parameter = summarizeInput(block.input);
5579
- let action = toolName;
5580
- switch (toolName) {
5581
- case "Bash":
5582
- action = "Running command";
5583
- break;
5584
- case "Edit":
5585
- action = "Editing file";
5586
- break;
5587
- case "Write":
5588
- action = "Writing file";
5589
- break;
5590
- case "Read":
5591
- action = "Reading file";
5592
- break;
5593
- case "Glob":
5594
- action = "Searching files";
5595
- break;
5596
- case "Grep":
5597
- action = "Searching code";
5598
- break;
5599
- case "WebSearch":
5600
- action = "Web search";
5601
- break;
5602
- case "WebFetch":
5603
- action = "Fetching URL";
5604
- break;
5605
- case "Task":
5606
- action = "Spawning subagent";
5607
- break;
5608
- case "TaskCreate":
5609
- case "TaskUpdate":
5610
- case "TaskList":
5611
- case "TaskGet":
5612
- action = "Updating plan";
5613
- break;
5614
- }
5615
5633
  return {
5616
5634
  linearSessionId,
5617
5635
  content: {
5618
5636
  type: "action",
5619
- action,
5637
+ action: toolAction(toolName),
5620
5638
  parameter
5621
5639
  }
5622
5640
  };
@@ -5624,8 +5642,7 @@ function convertClaudeEvent(event, linearSessionId) {
5624
5642
  }
5625
5643
  }
5626
5644
  if (event.type === "user") {
5627
- const message = event;
5628
- const contentBlocks = normalizeContentBlocks(message.message?.content);
5645
+ const contentBlocks = normalizeContentBlocks(event.message.content);
5629
5646
  for (const block of contentBlocks) {
5630
5647
  if (block.type === "tool_result") {
5631
5648
  const resultText = extractToolResultText(block.content);
@@ -5645,6 +5662,106 @@ function convertClaudeEvent(event, linearSessionId) {
5645
5662
  }
5646
5663
  return null;
5647
5664
  }
5665
+ function convertCursorEvent(event, linearSessionId) {
5666
+ if (event.type === "assistant") {
5667
+ for (const block of event.message.content) {
5668
+ if (block.type === "text" && block.text) {
5669
+ return {
5670
+ linearSessionId,
5671
+ content: {
5672
+ type: "thought",
5673
+ body: block.text
5674
+ }
5675
+ };
5676
+ }
5677
+ if (block.type === "tool_use" && block.name) {
5678
+ return {
5679
+ linearSessionId,
5680
+ content: {
5681
+ type: "action",
5682
+ action: toolAction(block.name),
5683
+ parameter: summarizeInput(block.input)
5684
+ }
5685
+ };
5686
+ }
5687
+ }
5688
+ }
5689
+ if (event.type === "thinking" && event.text) {
5690
+ return {
5691
+ linearSessionId,
5692
+ content: {
5693
+ type: "thought",
5694
+ body: event.text
5695
+ }
5696
+ };
5697
+ }
5698
+ if (event.type === "tool_call") {
5699
+ const result = event.status === "running" ? void 0 : event.status === "error" ? `Error: ${summarizeResult(event.result) || "Tool failed"}` : summarizeResult(event.result) || "Done";
5700
+ return {
5701
+ linearSessionId,
5702
+ content: {
5703
+ type: "action",
5704
+ action: toolAction(event.name),
5705
+ parameter: summarizeInput(event.args),
5706
+ ...result ? { result } : {}
5707
+ }
5708
+ };
5709
+ }
5710
+ if (event.type === "task" && event.text) {
5711
+ return {
5712
+ linearSessionId,
5713
+ content: {
5714
+ type: "thought",
5715
+ body: event.text
5716
+ }
5717
+ };
5718
+ }
5719
+ return null;
5720
+ }
5721
+ function isOpencodePartEnded(part) {
5722
+ return "time" in part && isRecord(part.time) && part.time.end !== void 0;
5723
+ }
5724
+ function convertOpencodePart(part, linearSessionId) {
5725
+ if ((part.type === "text" || part.type === "reasoning") && isOpencodePartEnded(part)) {
5726
+ const body = typeof part.text === "string" ? part.text.trim() : "";
5727
+ if (!body) return null;
5728
+ return {
5729
+ linearSessionId,
5730
+ content: {
5731
+ type: "thought",
5732
+ body
5733
+ }
5734
+ };
5735
+ }
5736
+ if (part.type === "tool" && isRecord(part.state)) {
5737
+ const state = part.state;
5738
+ const status = typeof state.status === "string" ? state.status : void 0;
5739
+ const result = status === "completed" ? summarizeResult(state.output) || "Done" : status === "error" ? `Error: ${summarizeResult(state.error) || "Tool failed"}` : void 0;
5740
+ return {
5741
+ linearSessionId,
5742
+ content: {
5743
+ type: "action",
5744
+ action: toolAction(typeof part.tool === "string" ? part.tool : "Tool"),
5745
+ parameter: summarizeInput(state.input),
5746
+ ...result ? { result } : {}
5747
+ }
5748
+ };
5749
+ }
5750
+ if (part.type === "patch") {
5751
+ const files = "files" in part && Array.isArray(part.files) ? part.files.filter((file) => typeof file === "string") : [];
5752
+ if (files.length === 0) return null;
5753
+ return {
5754
+ linearSessionId,
5755
+ content: {
5756
+ type: "action",
5757
+ action: "File change",
5758
+ parameter: files.join(", "),
5759
+ result: "Done"
5760
+ }
5761
+ };
5762
+ }
5763
+ return null;
5764
+ }
5648
5765
  function mapTodoStatus(status) {
5649
5766
  if (status === "in_progress") {
5650
5767
  return "inProgress";
@@ -6802,6 +6919,8 @@ var COMMAND_PROTECTION_SAFE_TOOLS = /* @__PURE__ */ new Set([
6802
6919
  "LS"
6803
6920
  ]);
6804
6921
  var CLAUDE_PARTIAL_MESSAGE_FLUSH_MS = 80;
6922
+ var CLAUDE_SLASH_COMMANDS_CACHE_MS = 6e4;
6923
+ var CLAUDE_SLASH_COMMANDS_DISCOVERY_TIMEOUT_MS = 3e4;
6805
6924
  function supportsClaudeThinkingDisplay(model) {
6806
6925
  const normalized = (normalizeClaudeModel(model) ?? model).toLowerCase();
6807
6926
  return AGENT_MODELS.claude.includes(normalized) || /^claude-(?:opus|sonnet|haiku)-[4-9]/.test(normalized);
@@ -6952,6 +7071,8 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
6952
7071
  /** Active tool-input requests keyed by requestId; resolved when the user selects an option. */
6953
7072
  pendingToolInputs = /* @__PURE__ */ new Map();
6954
7073
  supportedSlashCommands = [];
7074
+ slashCommandsDiscoveredAt = 0;
7075
+ slashCommandsDiscovery = null;
6955
7076
  authRetrying = false;
6956
7077
  constructor(options) {
6957
7078
  super(options);
@@ -6995,16 +7116,70 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
6995
7116
  }
6996
7117
  async listSlashCommands() {
6997
7118
  await this.initialized;
6998
- if (!this.activeQuery || this.isProcessing()) {
7119
+ if (this.activeQuery) {
7120
+ if (this.isProcessing()) {
7121
+ return this.supportedSlashCommands;
7122
+ }
7123
+ try {
7124
+ const commands = await this.activeQuery.supportedCommands();
7125
+ if (commands) {
7126
+ this.supportedSlashCommands = normalizeClaudeSlashCommands(commands);
7127
+ this.slashCommandsDiscoveredAt = Date.now();
7128
+ }
7129
+ } catch (error) {
7130
+ console.warn("[ClaudeManager] Failed to load slash commands:", error);
7131
+ }
7132
+ return this.supportedSlashCommands;
7133
+ }
7134
+ if (this.slashCommandsDiscoveredAt > 0 && Date.now() - this.slashCommandsDiscoveredAt < CLAUDE_SLASH_COMMANDS_CACHE_MS) {
6999
7135
  return this.supportedSlashCommands;
7000
7136
  }
7137
+ this.slashCommandsDiscovery ??= this.discoverSlashCommands().finally(() => {
7138
+ this.slashCommandsDiscovery = null;
7139
+ });
7140
+ return this.slashCommandsDiscovery;
7141
+ }
7142
+ /**
7143
+ * Sessions are created lazily on the first message, but the dashboard needs
7144
+ * the command list as soon as a chat opens — so with no session alive we
7145
+ * spawn a throwaway query (no prompt is ever pushed, so no model call is
7146
+ * made), read supportedCommands(), and terminate it.
7147
+ */
7148
+ async discoverSlashCommands() {
7149
+ const promptStream = new PromptStream();
7150
+ let discovery = null;
7151
+ let timeoutHandle;
7001
7152
  try {
7002
- const commands = await this.activeQuery?.supportedCommands();
7153
+ const shared = await this.buildSharedQueryOptions();
7154
+ discovery = query({
7155
+ prompt: promptStream,
7156
+ options: {
7157
+ cwd: this.workingDirectory,
7158
+ additionalDirectories: shared.additionalDirectories,
7159
+ settingSources: ["user", "project", "local"],
7160
+ ...this.mcpServersConfig ? { mcpServers: this.mcpServersConfig } : {},
7161
+ ...shared.plugins.length > 0 ? { plugins: shared.plugins } : {},
7162
+ ...shared.enableAllSkills ? { skills: "all" } : {},
7163
+ env: shared.env
7164
+ }
7165
+ });
7166
+ const timeout = new Promise((_, reject) => {
7167
+ timeoutHandle = setTimeout(
7168
+ () => reject(new Error("Slash command discovery timed out")),
7169
+ CLAUDE_SLASH_COMMANDS_DISCOVERY_TIMEOUT_MS
7170
+ );
7171
+ });
7172
+ const commands = await Promise.race([discovery.supportedCommands(), timeout]);
7003
7173
  if (commands) {
7004
7174
  this.supportedSlashCommands = normalizeClaudeSlashCommands(commands);
7005
7175
  }
7006
7176
  } catch (error) {
7007
- console.warn("[ClaudeManager] Failed to load slash commands:", error);
7177
+ console.warn("[ClaudeManager] Failed to discover slash commands:", error);
7178
+ } finally {
7179
+ this.slashCommandsDiscoveredAt = Date.now();
7180
+ clearTimeout(timeoutHandle);
7181
+ promptStream.close();
7182
+ discovery?.close();
7008
7183
  }
7009
7184
  return this.supportedSlashCommands;
7010
7185
  }
@@ -7376,6 +7551,21 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
7376
7551
  sessionSignaturesMatch(a, b) {
7377
7552
  return a.combinedInstructions === b.combinedInstructions && a.thinkingLevel === b.thinkingLevel && a.enableInteractiveTools === b.enableInteractiveTools && a.fastMode === b.fastMode;
7378
7553
  }
7554
+ /** Query inputs shared by real sessions and slash-command discovery. */
7555
+ async buildSharedQueryOptions() {
7556
+ const env = buildClaudeAgentEnv(this.envOverrides);
7557
+ const additionalDirectories = await getAgentAdditionalDirectories();
7558
+ let plugins = [];
7559
+ let enableAllSkills = false;
7560
+ try {
7561
+ const registryConfig = await buildClaudeRegistryConfig(ENGINE_ENV.HOME_DIR);
7562
+ plugins = registryConfig.plugins;
7563
+ enableAllSkills = registryConfig.enableAllSkills;
7564
+ } catch (error) {
7565
+ console.warn("[ClaudeManager] Failed to load skill registry config:", error);
7566
+ }
7567
+ return { env, additionalDirectories, plugins, enableAllSkills };
7568
+ }
7379
7569
  async startSession(args) {
7380
7570
  const {
7381
7571
  combinedInstructions,
@@ -7391,8 +7581,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
7391
7581
  preset: "claude_code",
7392
7582
  append: combinedInstructions
7393
7583
  };
7394
- const queryEnv = buildClaudeAgentEnv(this.envOverrides);
7395
- const additionalDirectories = await getAgentAdditionalDirectories();
7584
+ const shared = await this.buildSharedQueryOptions();
7396
7585
  const interactiveAllowed = enableInteractiveTools && resolvedPermissionMode === "plan";
7397
7586
  const useDefaultToolPolicy = !this.toolsOverride;
7398
7587
  const allowedTools = useDefaultToolPolicy ? [
@@ -7404,22 +7593,13 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
7404
7593
  ...useDefaultToolPolicy ? ALWAYS_DISALLOWED_TOOLS : [],
7405
7594
  ...interactiveAllowed ? [] : INTERACTIVE_TOOL_NAMES
7406
7595
  ];
7407
- let registryPlugins = [];
7408
- let enableRegistrySkills = false;
7409
- try {
7410
- const registryConfig = await buildClaudeRegistryConfig(ENGINE_ENV.HOME_DIR);
7411
- registryPlugins = registryConfig.plugins;
7412
- enableRegistrySkills = registryConfig.enableAllSkills;
7413
- } catch (error) {
7414
- console.warn("[ClaudeManager] Failed to load skill registry config:", error);
7415
- }
7416
7596
  const promptStream = new PromptStream();
7417
7597
  const response = query({
7418
7598
  prompt: promptStream,
7419
7599
  options: {
7420
7600
  resume: this.sessionId || void 0,
7421
7601
  cwd: this.workingDirectory,
7422
- additionalDirectories,
7602
+ additionalDirectories: shared.additionalDirectories,
7423
7603
  permissionMode: resolvedPermissionMode,
7424
7604
  allowDangerouslySkipPermissions: resolvedPermissionMode === "bypassPermissions",
7425
7605
  ...this.toolsOverride ? { tools: this.toolsOverride } : {},
@@ -7428,9 +7608,9 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
7428
7608
  settingSources: ["user", "project", "local"],
7429
7609
  systemPrompt,
7430
7610
  ...this.mcpServersConfig ? { mcpServers: this.mcpServersConfig } : {},
7431
- ...registryPlugins.length > 0 ? { plugins: registryPlugins } : {},
7432
- ...enableRegistrySkills ? { skills: "all" } : {},
7433
- env: queryEnv,
7611
+ ...shared.plugins.length > 0 ? { plugins: shared.plugins } : {},
7612
+ ...shared.enableAllSkills ? { skills: "all" } : {},
7613
+ env: shared.env,
7434
7614
  model: claudeCodeModel,
7435
7615
  settings: { fastMode: signature.fastMode },
7436
7616
  includePartialMessages: true,
@@ -7458,6 +7638,11 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
7458
7638
  this.sessionLoop = this.runSessionLoop(response).catch((err) => {
7459
7639
  console.error("[ClaudeManager] Session loop crashed:", err);
7460
7640
  });
7641
+ void response.supportedCommands().then((commands) => {
7642
+ this.supportedSlashCommands = normalizeClaudeSlashCommands(commands);
7643
+ this.slashCommandsDiscoveredAt = Date.now();
7644
+ }).catch(() => {
7645
+ });
7461
7646
  }
7462
7647
  async runSessionLoop(response) {
7463
7648
  const linearSessionId = ENGINE_ENV.LINEAR_SESSION_ID;
@@ -7791,6 +7976,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
7791
7976
  }
7792
7977
  if (message.type === "system" && message.subtype === "commands_changed") {
7793
7978
  this.supportedSlashCommands = normalizeClaudeSlashCommands(message.commands);
7979
+ this.slashCommandsDiscoveredAt = Date.now();
7794
7980
  }
7795
7981
  this.trackNativeCompaction(message);
7796
7982
  await this.recordEvent(message);
@@ -8018,7 +8204,7 @@ var AspClient = class {
8018
8204
  // src/managers/codex-asp/app-server-process.ts
8019
8205
  var DEFAULT_CODEX_BINARY = "codex";
8020
8206
  var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
8021
- var ENGINE_PACKAGE_VERSION = "0.1.408";
8207
+ var ENGINE_PACKAGE_VERSION = "0.1.410";
8022
8208
  var INITIALIZE_METHOD = "initialize";
8023
8209
  var INITIALIZED_NOTIFICATION = "initialized";
8024
8210
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -10192,9 +10378,10 @@ var CursorManager = class extends CodingAgentManager {
10192
10378
  }
10193
10379
  this.slashCommandsRequest ??= (async () => {
10194
10380
  try {
10381
+ const repoDirectories = await getAgentAdditionalDirectories();
10382
+ const commandDirectories = [this.workingDirectory, ...repoDirectories, ENGINE_ENV.HOME_DIR].map((directory) => join17(directory, ".cursor", "commands"));
10195
10383
  const commands = mergeSlashCommands(
10196
- await listCursorCommandsInDirectory(join17(this.workingDirectory, ".cursor", "commands")),
10197
- await listCursorCommandsInDirectory(join17(ENGINE_ENV.HOME_DIR, ".cursor", "commands"))
10384
+ ...await Promise.all(commandDirectories.map(listCursorCommandsInDirectory))
10198
10385
  );
10199
10386
  this.slashCommandsCache = { commands, expiresAt: Date.now() + CURSOR_SLASH_COMMANDS_CACHE_MS };
10200
10387
  return commands;
@@ -10224,6 +10411,8 @@ var CursorManager = class extends CodingAgentManager {
10224
10411
  return this.agent;
10225
10412
  }
10226
10413
  async processMessageInternal(request) {
10414
+ const linearSessionId = ENGINE_ENV.LINEAR_SESSION_ID;
10415
+ const linearForwarder = new LinearEventForwarder(linearSessionId);
10227
10416
  try {
10228
10417
  const agent = await this.ensureAgent(request);
10229
10418
  const message = await this.toCursorMessage(request);
@@ -10240,6 +10429,9 @@ var CursorManager = class extends CodingAgentManager {
10240
10429
  this.activeModel = model;
10241
10430
  for await (const event of run.stream()) {
10242
10431
  this.recordCursorEvent(event);
10432
+ if (linearSessionId) {
10433
+ linearForwarder.sendEvent(convertCursorEvent(event, linearSessionId));
10434
+ }
10243
10435
  }
10244
10436
  const result = await run.wait();
10245
10437
  if (result.status === "error") {
@@ -10248,6 +10440,8 @@ var CursorManager = class extends CodingAgentManager {
10248
10440
  message: result.result || "Cursor run failed",
10249
10441
  runId: result.id
10250
10442
  }, this.historyFile);
10443
+ } else {
10444
+ linearForwarder.flushThoughtAsResponse();
10251
10445
  }
10252
10446
  } catch (error) {
10253
10447
  this.recordHistoryEvent("cursor-error", {
@@ -10502,6 +10696,8 @@ var OpencodeManager = class extends CodingAgentManager {
10502
10696
  textParts = /* @__PURE__ */ new Map();
10503
10697
  reasoningParts = /* @__PURE__ */ new Map();
10504
10698
  nonAssistantMessageIds = /* @__PURE__ */ new Set();
10699
+ activeLinearForwarder = null;
10700
+ forwardedLinearPartKeys = /* @__PURE__ */ new Set();
10505
10701
  modelVariants = /* @__PURE__ */ new Map();
10506
10702
  slashCommandsCache = null;
10507
10703
  slashCommandsRequest = null;
@@ -10546,15 +10742,24 @@ var OpencodeManager = class extends CodingAgentManager {
10546
10742
  this.slashCommandsRequest ??= (async () => {
10547
10743
  try {
10548
10744
  const client = await this.ensureClient(DEFAULT_OPENCODE_MODEL);
10549
- const location = { directory: this.workingDirectory };
10550
- const [commandResponse, skillResponse] = await Promise.all([
10551
- client.v2.command.list({ location }, { throwOnError: true }),
10552
- client.v2.skill.list({ location }, { throwOnError: true })
10553
- ]);
10554
- const commands = mergeSlashCommands(
10555
- opencodeCommandListToSlashCommands(commandResponse.data),
10556
- opencodeSkillListToSlashCommands(skillResponse.data)
10557
- );
10745
+ const directories = [this.workingDirectory, ...await getAgentAdditionalDirectories()];
10746
+ const perDirectory = await Promise.all(directories.map(async (directory) => {
10747
+ try {
10748
+ const location = { directory };
10749
+ const [commandResponse, skillResponse] = await Promise.all([
10750
+ client.v2.command.list({ location }, { throwOnError: true }),
10751
+ client.v2.skill.list({ location }, { throwOnError: true })
10752
+ ]);
10753
+ return mergeSlashCommands(
10754
+ opencodeCommandListToSlashCommands(commandResponse.data),
10755
+ opencodeSkillListToSlashCommands(skillResponse.data)
10756
+ );
10757
+ } catch (error) {
10758
+ console.warn("[OpencodeManager] Failed to load slash commands for directory:", directory, error);
10759
+ return [];
10760
+ }
10761
+ }));
10762
+ const commands = mergeSlashCommands(...perDirectory);
10558
10763
  this.slashCommandsCache = { commands, expiresAt: Date.now() + OPENCODE_SLASH_COMMANDS_CACHE_MS };
10559
10764
  return commands;
10560
10765
  } catch (error) {
@@ -10659,7 +10864,11 @@ var OpencodeManager = class extends CodingAgentManager {
10659
10864
  async processMessageInternal(request) {
10660
10865
  const model = request.model ?? DEFAULT_OPENCODE_MODEL;
10661
10866
  const controller = new AbortController();
10867
+ const linearSessionId = ENGINE_ENV.LINEAR_SESSION_ID;
10868
+ const linearForwarder = new LinearEventForwarder(linearSessionId);
10662
10869
  this.activeAbortController = controller;
10870
+ this.activeLinearForwarder = linearForwarder;
10871
+ this.forwardedLinearPartKeys.clear();
10663
10872
  try {
10664
10873
  const client = await this.ensureClient(model);
10665
10874
  const agent = request.planMode ? "plan" : "build";
@@ -10681,6 +10890,7 @@ var OpencodeManager = class extends CodingAgentManager {
10681
10890
  }, { signal: controller.signal, throwOnError: true });
10682
10891
  this.recordHistoryEvent("opencode-message.updated", { info: result.data.info }, this.historyFile);
10683
10892
  for (const part of result.data.parts) this.recordOpencodePart(part);
10893
+ linearForwarder.flushThoughtAsResponse();
10684
10894
  this.recordHistoryEvent("opencode-session.idle", { sessionID: sessionId }, this.historyFile);
10685
10895
  } catch (error) {
10686
10896
  if (controller.signal.aborted) {
@@ -10691,6 +10901,8 @@ var OpencodeManager = class extends CodingAgentManager {
10691
10901
  }
10692
10902
  } finally {
10693
10903
  this.activeAbortController = null;
10904
+ this.activeLinearForwarder = null;
10905
+ this.forwardedLinearPartKeys.clear();
10694
10906
  await this.historyFile.flush();
10695
10907
  await this.onTurnComplete();
10696
10908
  }
@@ -10814,8 +11026,20 @@ var OpencodeManager = class extends CodingAgentManager {
10814
11026
  }
10815
11027
  return false;
10816
11028
  }
11029
+ forwardOpencodePartToLinear(part) {
11030
+ const linearSessionId = ENGINE_ENV.LINEAR_SESSION_ID;
11031
+ if (!linearSessionId || !this.activeLinearForwarder) return;
11032
+ const event = convertOpencodePart(part, linearSessionId);
11033
+ if (!event) return;
11034
+ if (typeof part.id !== "string") return;
11035
+ const key = `${part.type}:${part.id}:${JSON.stringify(event.content)}`;
11036
+ if (this.forwardedLinearPartKeys.has(key)) return;
11037
+ this.forwardedLinearPartKeys.add(key);
11038
+ this.activeLinearForwarder.sendEvent(event);
11039
+ }
10817
11040
  recordOpencodePart(part) {
10818
11041
  this.recordHistoryEvent(`opencode-part-${part.type}`, { part }, this.historyFile);
11042
+ this.forwardOpencodePartToLinear(part);
10819
11043
  }
10820
11044
  };
10821
11045
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.408",
3
+ "version": "0.1.410",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",