arcane-agents 1.0.2 → 1.1.0

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.
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Arcane Agents</title>
7
- <script type="module" crossorigin src="/assets/index-CyA5FKrE.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-TxsheMVB.css">
7
+ <script type="module" crossorigin src="/assets/index-HfXsReQG.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-CWU29xaz.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
@@ -9,12 +9,14 @@ function parseSpawnInput(body) {
9
9
  }
10
10
  const record = body;
11
11
  const spawnNearWorkerIds = parseSpawnNearWorkerIds(record);
12
+ const displayName = parseDisplayName(record);
12
13
  if (typeof record.shortcutIndex !== "undefined") {
13
14
  if (typeof record.shortcutIndex !== "number" || !Number.isInteger(record.shortcutIndex) || record.shortcutIndex < 0) {
14
15
  throw (0, appError_1.validationError)("shortcutIndex must be a non-negative integer.", "spawn_invalid_shortcut_index");
15
16
  }
16
17
  return {
17
18
  shortcutIndex: record.shortcutIndex,
19
+ displayName,
18
20
  spawnNearWorkerIds
19
21
  };
20
22
  }
@@ -24,11 +26,22 @@ function parseSpawnInput(body) {
24
26
  projectId: record.projectId,
25
27
  runtimeId: record.runtimeId,
26
28
  command,
29
+ displayName,
27
30
  spawnNearWorkerIds
28
31
  };
29
32
  }
30
33
  throw (0, appError_1.validationError)("Invalid spawn request: expected shortcutIndex or projectId+runtimeId.", "spawn_invalid_payload");
31
34
  }
35
+ function parseDisplayName(record) {
36
+ if (typeof record.displayName === "undefined") {
37
+ return undefined;
38
+ }
39
+ if (typeof record.displayName !== "string") {
40
+ throw (0, appError_1.validationError)("displayName must be a string when provided.", "spawn_invalid_display_name");
41
+ }
42
+ const trimmed = record.displayName.trim();
43
+ return trimmed.length > 0 ? trimmed : undefined;
44
+ }
32
45
  function parseSpawnNearWorkerIds(record) {
33
46
  if (typeof record.spawnNearWorkerIds === "undefined") {
34
47
  return undefined;
@@ -22,7 +22,7 @@ function resolveSpawnPlan(config, input) {
22
22
  runtimeId: shortcut.runtime,
23
23
  runtime,
24
24
  command: shortcut.command ?? runtime.command,
25
- displayName: shortcut.label,
25
+ displayName: input.displayName ?? shortcut.label,
26
26
  avatar: shortcut.avatar
27
27
  };
28
28
  }
@@ -39,6 +39,7 @@ function resolveSpawnPlan(config, input) {
39
39
  project,
40
40
  runtimeId: input.runtimeId,
41
41
  runtime,
42
- command: input.command && input.command.length > 0 ? input.command : runtime.command
42
+ command: input.command && input.command.length > 0 ? input.command : runtime.command,
43
+ displayName: input.displayName
43
44
  };
44
45
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.recoverableToolErrorMatchers = exports.fatalRuntimeErrorMatchers = exports.openCodeWorkingFreshWindowMs = exports.claudeWorkingFreshWindowMs = exports.genericWorkingFreshWindowMs = exports.claudeSpawnGraceMs = exports.cachedActivityWindowMs = exports.stickyWorkingWindowMs = exports.commandWarmupWindowMs = exports.recentErrorSignalWindowMs = exports.parsedStrongEvidenceWindowMs = void 0;
3
+ exports.recoverableToolErrorMatchers = exports.fatalRuntimeErrorMatchers = exports.openCodeWorkingFreshWindowMs = exports.claudeWorkingFreshWindowMs = exports.genericWorkingFreshWindowMs = exports.openCodeSpawnGraceMs = exports.claudeSpawnGraceMs = exports.cachedActivityWindowMs = exports.stickyWorkingWindowMs = exports.commandWarmupWindowMs = exports.recentErrorSignalWindowMs = exports.parsedStrongEvidenceWindowMs = void 0;
4
4
  const parsedStrongEvidenceWindowMs = 8_000;
5
5
  exports.parsedStrongEvidenceWindowMs = parsedStrongEvidenceWindowMs;
6
6
  const recentErrorSignalWindowMs = 15_000;
@@ -13,6 +13,8 @@ const cachedActivityWindowMs = 12_000;
13
13
  exports.cachedActivityWindowMs = cachedActivityWindowMs;
14
14
  const claudeSpawnGraceMs = 5_000;
15
15
  exports.claudeSpawnGraceMs = claudeSpawnGraceMs;
16
+ const openCodeSpawnGraceMs = 5_000;
17
+ exports.openCodeSpawnGraceMs = openCodeSpawnGraceMs;
16
18
  const genericWorkingFreshWindowMs = 12_000;
17
19
  exports.genericWorkingFreshWindowMs = genericWorkingFreshWindowMs;
18
20
  const claudeWorkingFreshWindowMs = 10_000;
@@ -137,4 +137,17 @@ function createContext(overrides = {}) {
137
137
  (0, vitest_1.expect)(decision.activityTool).toBeUndefined();
138
138
  (0, vitest_1.expect)(decision.reasons[0]?.code).toBe("opencode-prompt-idle");
139
139
  });
140
+ (0, vitest_1.it)("returns idle for freshly spawned OpenCode sessions within grace window", () => {
141
+ const decision = (0, decision_1.deriveWorkerStatusDecision)(createContext({
142
+ isOpenCodeSession: true,
143
+ currentCommand: "opencode",
144
+ commandLower: "opencode",
145
+ hasOpenCodePromptSignal: false,
146
+ hasOpenCodeActiveSignal: false,
147
+ commandQuietForMs: 500,
148
+ workerAgeMs: 2_000
149
+ }));
150
+ (0, vitest_1.expect)(decision.status).toBe("idle");
151
+ (0, vitest_1.expect)(decision.reasons.some((r) => r.code === "opencode-spawn-grace-idle")).toBe(true);
152
+ });
140
153
  });
@@ -41,6 +41,19 @@ function detectIdleBlocker(context, evidence) {
41
41
  }
42
42
  };
43
43
  }
44
+ if (context.isOpenCodeSession &&
45
+ context.workerAgeMs <= constants_1.openCodeSpawnGraceMs &&
46
+ context.transcriptSnapshot?.status !== "working" &&
47
+ !context.hasOpenCodeActiveSignal &&
48
+ !evidence.parsedStrongSignal) {
49
+ return {
50
+ reason: {
51
+ code: "opencode-spawn-grace-idle",
52
+ message: "During early OpenCode spawn grace window without active signals.",
53
+ detail: `${Math.round(context.workerAgeMs)}ms since worker creation`
54
+ }
55
+ };
56
+ }
44
57
  const activeWindowMs = (0, helpers_1.statusFreshnessWindowMs)(context);
45
58
  if (context.outputQuietForMs > activeWindowMs && context.transcriptSnapshot?.status !== "working") {
46
59
  return {
@@ -183,15 +183,14 @@ class TmuxAdapter {
183
183
  }
184
184
  const normalizedText = text.replace(/\r\n?/g, "\n");
185
185
  if (normalizedText.length > 0) {
186
- const lines = normalizedText.split("\n");
187
- for (let index = 0; index < lines.length; index += 1) {
188
- const line = lines[index] ?? "";
189
- if (line.length > 0) {
190
- await this.runTmux(["send-keys", "-t", target, "-l", line]);
191
- }
192
- if (index < lines.length - 1) {
193
- await this.runTmux(["send-keys", "-t", target, "Enter"]);
194
- }
186
+ const isMultiline = normalizedText.includes("\n");
187
+ if (isMultiline) {
188
+ await this.runTmux(["send-keys", "-t", target, "-l", "\x1b[200~"]);
189
+ await this.runTmux(["send-keys", "-t", target, "-l", normalizedText]);
190
+ await this.runTmux(["send-keys", "-t", target, "-l", "\x1b[201~"]);
191
+ }
192
+ else {
193
+ await this.runTmux(["send-keys", "-t", target, "-l", normalizedText]);
195
194
  }
196
195
  }
197
196
  if (options?.submit ?? true) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-agents",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Local-first visual control room for tmux-backed coding agents",
5
5
  "bin": {
6
6
  "arcane-agents": "dist/server/server/cli.js"