specrails-desktop 2.43.2 → 2.44.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.
- package/README.md +1 -1
- package/client/dist/assets/{ActivityFeedPage-C7XJ5-bJ.js → ActivityFeedPage-CL1BUXoj.js} +1 -1
- package/client/dist/assets/{AgentBrowserCapture-C_WpXceT.js → AgentBrowserCapture-BQem50z4.js} +1 -1
- package/client/dist/assets/{AgentModeAnalyticsPane-PEZKjyZS.js → AgentModeAnalyticsPane-BC_xbT_l.js} +2 -2
- package/client/dist/assets/{AgentModeCodePane-D_Xcq5t5.js → AgentModeCodePane-DK-q3K6Y.js} +2 -2
- package/client/dist/assets/{AgentModeJobsPane-CDSkOuNP.js → AgentModeJobsPane-C7ELTPC1.js} +1 -1
- package/client/dist/assets/{AgentsPage-D577NzIM.js → AgentsPage-DbLezyI6.js} +1 -1
- package/client/dist/assets/{AnalyticsPage-C6ZZI_zg.js → AnalyticsPage-DTsg-N5z.js} +1 -1
- package/client/dist/assets/{CodePage-B5z5oLnP.js → CodePage-DwgbeqQ_.js} +1 -1
- package/client/dist/assets/{DesktopAnalyticsPage-D_V9RuGg.js → DesktopAnalyticsPage-Y0Z1ryQr.js} +1 -1
- package/client/dist/assets/{DocsDialog-Beg82MEe.js → DocsDialog-KeCOxvGH.js} +1 -1
- package/client/dist/assets/{DocsPage-BkE4m4wp.js → DocsPage-Bt1PgYPO.js} +1 -1
- package/client/dist/assets/{ExportDropdown-ophapHrT.js → ExportDropdown-DczgU4at.js} +1 -1
- package/client/dist/assets/InteractiveJobComposer-BcR6xlHU.js +19 -0
- package/client/dist/assets/{JobDetailModal-BCxue_Do.js → JobDetailModal-DKA_DUHe.js} +1 -1
- package/client/dist/assets/{JobDetailPage-_rIDpNfo.js → JobDetailPage-vaOcE-cI.js} +1 -1
- package/client/dist/assets/{JobsPage-C6xcijbs.js → JobsPage-Bwoe-Fb0.js} +1 -1
- package/client/dist/assets/{LoopBuilderPage-A-Mt6EjT.js → LoopBuilderPage-CqC4hbXb.js} +1 -1
- package/client/dist/assets/{LoopPreviewModal-DqHiG4Dt.js → LoopPreviewModal-T0zuFv6y.js} +1 -1
- package/client/dist/assets/{LoopsPage-B-ketPET.js → LoopsPage-DrQGcZv2.js} +1 -1
- package/client/dist/assets/{MinimizedChatsContext-Deg39peL.js → MinimizedChatsContext-C843Y13h.js} +1 -1
- package/client/dist/assets/{PluginsPage-Dn2jPvJL.js → PluginsPage-CTUHX_Lu.js} +1 -1
- package/client/dist/assets/{ProjectSettingsDialog-CVTj4VLt.js → ProjectSettingsDialog-DeL8md1s.js} +1 -1
- package/client/dist/assets/{RepositoryDeliveries-IiQCcndQ.js → RepositoryDeliveries-bgIHE8ep.js} +1 -1
- package/client/dist/assets/{RepositoryScopeSelector-D-RCaknl.js → RepositoryScopeSelector-CZ_U_R3U.js} +1 -1
- package/client/dist/assets/{ReviewPacketPage-BBd617OM.js → ReviewPacketPage-DbKO6pT8.js} +1 -1
- package/client/dist/assets/{TemplatePreviewModal-COHFkUS4.js → TemplatePreviewModal-_CgCCV7L.js} +1 -1
- package/client/dist/assets/{TicketDetailModalContext-BNa1mdXq.js → TicketDetailModalContext-BbRA6cb7.js} +1 -1
- package/client/dist/assets/{Trans-SnMX4MhW.js → Trans-mjFZpHw1.js} +1 -1
- package/client/dist/assets/{formatDistanceToNow-DSj5DprF.js → formatDistanceToNow-BIL-HxGy.js} +1 -1
- package/client/dist/assets/{getTimezoneOffsetInMilliseconds-YhD8rIEs.js → getTimezoneOffsetInMilliseconds-Cs9z2sdO.js} +1 -1
- package/client/dist/assets/{index-D5n_jg_I.css → index-Bfj8HvX1.css} +1 -1
- package/client/dist/assets/{index-m5pKr1T6.js → index-UnaJTMIy.js} +6 -6
- package/client/dist/assets/{jira-api-CSCqGr-Q.js → jira-api-B2BBZQTx.js} +1 -1
- package/client/dist/assets/{jobs-BS6RTurf.js → jobs-5PQJbdOf.js} +1 -1
- package/client/dist/assets/{jobs-CezU69AE.js → jobs-B2B08Oy9.js} +1 -1
- package/client/dist/assets/{jobs-ClFJae0s.js → jobs-BJZtBbwb.js} +1 -1
- package/client/dist/assets/{jobs-BTT0Bsks.js → jobs-BlWEsQb7.js} +1 -1
- package/client/dist/assets/{jobs-DJSFIFVy.js → jobs-ConfD8xD.js} +1 -1
- package/client/dist/assets/jobs-DMPU64ms.js +1 -0
- package/client/dist/assets/{jobs-DhgGr8vm.js → jobs-DojASiTp.js} +1 -1
- package/client/dist/assets/{jobs-B8rrzfyZ.js → jobs-kVHkNpB-.js} +1 -1
- package/client/dist/assets/{project-repositories-DYhTvwQ1.js → project-repositories-xSqimlaj.js} +1 -1
- package/client/dist/assets/settings-2Yx_9yJM.js +1 -0
- package/client/dist/assets/settings-BLOsrXEw.js +1 -0
- package/client/dist/assets/settings-C6s9PtRD.js +1 -0
- package/client/dist/assets/settings-CCNZN5Q-.js +1 -0
- package/client/dist/assets/{settings-Deupji9c.js → settings-CpKwTew1.js} +1 -1
- package/client/dist/assets/settings-DPjNiUsS.js +1 -0
- package/client/dist/assets/settings-FIqwhTup.js +1 -0
- package/client/dist/assets/{settings-CrMi3kSi.js → settings-NSWQjY5B.js} +1 -1
- package/client/dist/assets/{spending-BqbdPm_4.js → spending-DXOcv1tn.js} +1 -1
- package/client/dist/assets/{useDesktop-RSMTyy7V.js → useDesktop-gVGoWWiY.js} +1 -1
- package/client/dist/assets/{useSharedWebSocket-BOdS5_Iz.js → useSharedWebSocket-DbGL_YOt.js} +2 -2
- package/client/dist/index.html +16 -16
- package/docs/README.md +6 -1
- package/docs/agents/README.md +13 -0
- package/docs/agents/mcp.md +103 -0
- package/docs/guide/de/integrations/5-mcp-server.md +2 -0
- package/docs/guide/de/settings/3-pipeline-telemetry-and-diagnostics.md +1 -1
- package/docs/guide/en/integrations/5-mcp-server.md +3 -30
- package/docs/guide/en/pipeline/3-batch-implement-and-multi-feature.md +29 -0
- package/docs/guide/en/settings/3-pipeline-telemetry-and-diagnostics.md +10 -1
- package/docs/guide/es/integrations/5-mcp-server.md +3 -30
- package/docs/guide/es/pipeline/3-batch-implement-and-multi-feature.md +30 -0
- package/docs/guide/es/settings/3-pipeline-telemetry-and-diagnostics.md +11 -1
- package/docs/guide/fr/integrations/5-mcp-server.md +2 -0
- package/docs/guide/fr/settings/3-pipeline-telemetry-and-diagnostics.md +1 -1
- package/docs/guide/it/integrations/5-mcp-server.md +2 -0
- package/docs/guide/it/settings/3-pipeline-telemetry-and-diagnostics.md +1 -1
- package/docs/guide/ja/integrations/5-mcp-server.md +2 -0
- package/docs/guide/ja/settings/3-pipeline-telemetry-and-diagnostics.md +1 -1
- package/docs/guide/pt/integrations/5-mcp-server.md +2 -0
- package/docs/guide/pt/settings/3-pipeline-telemetry-and-diagnostics.md +1 -1
- package/docs/guide/zh/integrations/5-mcp-server.md +2 -0
- package/docs/guide/zh/settings/3-pipeline-telemetry-and-diagnostics.md +1 -1
- package/docs/mcp.md +18 -48
- package/package.json +1 -1
- package/server/dist/core-completion.js +58 -0
- package/server/dist/core-execution.js +2 -1
- package/server/dist/db.js +1 -1
- package/server/dist/loop-executors.js +15 -2
- package/server/dist/loop-graph.js +2 -1
- package/server/dist/loop-run-manager.js +18 -1
- package/client/dist/assets/InteractiveJobComposer-wBBBNaJn.js +0 -19
- package/client/dist/assets/jobs-DzMjUcaN.js +0 -1
- package/client/dist/assets/settings-BBt2xtDQ.js +0 -1
- package/client/dist/assets/settings-BJB9RKJj.js +0 -1
- package/client/dist/assets/settings-CHwQR2rB.js +0 -1
- package/client/dist/assets/settings-DKyhDGD1.js +0 -1
- package/client/dist/assets/settings-DqRMmwAM.js +0 -1
- package/client/dist/assets/settings-J4rj6vo-.js +0 -1
package/docs/mcp.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# The Specrails MCP server
|
|
2
2
|
|
|
3
3
|
Specrails Desktop can expose itself to **any MCP client** — Claude Desktop,
|
|
4
|
-
Claude Code, Cursor, or your own agent — as a local
|
|
4
|
+
Claude Code, Codex, Cursor, or your own agent — as a local
|
|
5
5
|
[Model Context Protocol](https://modelcontextprotocol.io) server. A connected
|
|
6
6
|
agent can drive the whole dashboard: list your projects, read and
|
|
7
7
|
create specs, launch the AI pipeline, watch jobs settle, inspect analytics, and
|
|
8
|
-
more — through
|
|
8
|
+
more — through a versioned tool catalog with discoverable action schemas.
|
|
9
9
|
|
|
10
10
|
> **Just want to get going?** Open **Settings ▸ MCP**, click **Copy client
|
|
11
|
-
> config**,
|
|
11
|
+
> config**, then follow the [client-specific agent runbook](agents/mcp.md).
|
|
12
|
+
> MCP and all four permission tiers
|
|
12
13
|
> are on by default. Disable **Write**, **AI-spawn**, or **Destructive** there
|
|
13
14
|
> to restrict external clients. Existing disabled settings survive upgrades.
|
|
14
15
|
|
|
15
16
|
This is the **app talking to an outside agent** — the opposite direction from
|
|
16
|
-
the [Serena plugin](running-pipelines.md#plugins)
|
|
17
|
-
`codex mcp add`, where Specrails *consumes* an MCP server. Here Specrails *is*
|
|
17
|
+
the [Serena plugin](running-pipelines.md#plugins), where Specrails *consumes* an MCP server. Here Specrails *is*
|
|
18
18
|
the server.
|
|
19
19
|
|
|
20
20
|
The MCP server is **on by default** and entirely local: it listens only on
|
|
@@ -28,7 +28,7 @@ When enabled, the server registers a compact catalog of **domain-facade tools**
|
|
|
28
28
|
plus a few **meta tools**, a set of read-only **resources**, and a self-contained
|
|
29
29
|
**guide** an LLM can read to learn the platform with no prior knowledge.
|
|
30
30
|
|
|
31
|
-
### Tools
|
|
31
|
+
### Tools
|
|
32
32
|
|
|
33
33
|
Each domain is a single tool with an `action` enum, rather than dozens of
|
|
34
34
|
narrow tools — so the catalog stays small and an agent discovers actions by
|
|
@@ -166,23 +166,16 @@ stdio from your client to the embedded HTTP server on loopback — and it reads
|
|
|
166
166
|
the scoped token from `~/.specrails/mcp.token` **locally**, so the token never
|
|
167
167
|
appears in your client's config file.
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
Use **Copy client config** as a starting point. Some versions return only
|
|
170
|
+
`specrails-mcp`, which may not be on PATH. Follow the linked agent runbook for path discovery and client-specific
|
|
171
|
+
registration; no token belongs in the stdio configuration.
|
|
170
172
|
|
|
171
|
-
|
|
172
|
-
{
|
|
173
|
-
"mcpServers": {
|
|
174
|
-
"specrails": {
|
|
175
|
-
"command": "specrails-mcp"
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
```
|
|
173
|
+
### For agents only — Claude, Codex, Kimi and Gemini
|
|
180
174
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
the Specrails Desktop app, then retry."* rather than a cryptic connection error.
|
|
175
|
+
Follow the [agent connection runbook](agents/mcp.md)
|
|
176
|
+
for executable discovery, client-specific registration, real read-only verification
|
|
177
|
+
and troubleshooting. It distinguishes saved configuration, bridge connectivity
|
|
178
|
+
and tools available in the current conversation.
|
|
186
179
|
|
|
187
180
|
### Option B — the direct HTTP URL (remote-HTTP clients)
|
|
188
181
|
|
|
@@ -207,30 +200,6 @@ HTTP-capable clients, not for exposing Specrails on a network. (`4200` is the
|
|
|
207
200
|
default app port; if you've changed it, the panel's config reflects the real
|
|
208
201
|
one.)
|
|
209
202
|
|
|
210
|
-
#### One-liners for the common CLIs
|
|
211
|
-
|
|
212
|
-
**Claude Code** (HTTP transport):
|
|
213
|
-
|
|
214
|
-
```bash
|
|
215
|
-
claude mcp add --transport http specrails http://localhost:4200/api/mcp \
|
|
216
|
-
--header "X-Desktop-Token: <your mcp token>"
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
**Gemini CLI** (HTTP transport — same shape):
|
|
220
|
-
|
|
221
|
-
```bash
|
|
222
|
-
gemini mcp add --transport http specrails http://localhost:4200/api/mcp \
|
|
223
|
-
--header "X-Desktop-Token: <your mcp token>"
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
**Codex CLI** (stdio — register the bundled bridge; copy the exact bridge
|
|
227
|
-
command from **Settings ▸ MCP ▸ Copy config**, it embeds the app's bundled
|
|
228
|
-
Node + script path):
|
|
229
|
-
|
|
230
|
-
```bash
|
|
231
|
-
codex mcp add specrails -- <bridge command from Settings ▸ MCP>
|
|
232
|
-
```
|
|
233
|
-
|
|
234
203
|
## Security model
|
|
235
204
|
|
|
236
205
|
- **A scoped token, not the master token.** The MCP surface is authenticated by
|
|
@@ -316,8 +285,8 @@ extra tiers.
|
|
|
316
285
|
|
|
317
286
|
**`401 Unauthorized: invalid MCP token`** (direct-HTTP path) — the bearer token
|
|
318
287
|
is wrong or stale. Re-copy it from **Settings ▸ MCP ▸ Copy token**, or
|
|
319
|
-
**Regenerate token** and update your client. The stdio bridge
|
|
320
|
-
|
|
288
|
+
**Regenerate token** and update your client. The stdio bridge reads the current token locally; check the OS user and
|
|
289
|
+
token-file access if it also reports an authentication failure.
|
|
321
290
|
|
|
322
291
|
**The agent assumed a rail succeeded but it didn't** — cost-incurring actions
|
|
323
292
|
return a reference, not a result. The agent must call `specrails_watch` with the
|
|
@@ -326,7 +295,8 @@ returned `jobId`/`requestId` to get the real outcome. This is documented in
|
|
|
326
295
|
|
|
327
296
|
**Connection refused on `:4200`** — that's the default app port. If you changed
|
|
328
297
|
the port in Settings, use the URL from **Copy client config**, which reflects
|
|
329
|
-
the real port.
|
|
298
|
+
the real port. Set `SPECRAILS_MCP_PORT` in the bridge environment for a custom port;
|
|
299
|
+
it defaults to `4200` and does not discover arbitrary ports automatically.
|
|
330
300
|
|
|
331
301
|
## See also
|
|
332
302
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseCoreCompletion = parseCoreCompletion;
|
|
4
|
+
exports.readCoreCompletion = readCoreCompletion;
|
|
5
|
+
const node_child_process_1 = require("node:child_process");
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const node_util_1 = require("node:util");
|
|
9
|
+
const path_resolver_1 = require("./path-resolver");
|
|
10
|
+
const obj = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) ? value : null;
|
|
11
|
+
const strings = (value) => Array.isArray(value) && value.every(item => typeof item === 'string');
|
|
12
|
+
const count = (value) => typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : null;
|
|
13
|
+
/** Parse only runtime-owned status, never the model's prose or stdout JSON. */
|
|
14
|
+
function parseCoreCompletion(value, runId) {
|
|
15
|
+
const status = obj(value), completion = obj(status?.completion);
|
|
16
|
+
if (status?.schemaVersion !== 1 || status.runId !== runId || typeof status.change !== 'string' || !completion)
|
|
17
|
+
return null;
|
|
18
|
+
const enums = { implementation: ['complete', 'incomplete'], validation: ['verified', 'with-exceptions', 'pending', 'blocked'], archive: ['pending', 'running', 'done', 'blocked', 'failed', 'skipped'], delivery: ['pending-host', 'complete', 'pending'] };
|
|
19
|
+
if (Object.entries(enums).some(([key, values]) => !values.includes(String(completion[key]))) || !strings(completion.reasons))
|
|
20
|
+
return null;
|
|
21
|
+
const acceptance = obj(status.acceptance), receipt = obj(acceptance?.receipt);
|
|
22
|
+
// Even a well-shaped summary cannot claim verified with invalid backing evidence.
|
|
23
|
+
if (['verified', 'with-exceptions'].includes(String(completion.validation)) && (acceptance?.valid !== true || obj(status.verification)?.valid !== true || obj(obj(status.phases)?.reviewer)?.status !== 'done'))
|
|
24
|
+
return null;
|
|
25
|
+
const exceptions = [];
|
|
26
|
+
for (const raw of Array.isArray(receipt?.criteria) ? receipt.criteria : []) {
|
|
27
|
+
const row = obj(raw), exception = obj(row?.exception);
|
|
28
|
+
if (row?.status === 'exception' && typeof row.requirement === 'string' && exception && ['reason', 'impact', 'acceptedBy', 'approvalEvidence'].every(key => typeof exception[key] === 'string')) {
|
|
29
|
+
exceptions.push({ requirement: row.requirement, reason: exception.reason, impact: exception.impact, acceptedBy: exception.acceptedBy, approvalEvidence: exception.approvalEvidence });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const checks = [];
|
|
33
|
+
for (const raw of Array.isArray(receipt?.checks) ? receipt.checks : []) {
|
|
34
|
+
const check = obj(raw);
|
|
35
|
+
if (check && ['name', 'status', 'scope', 'limitations'].every(key => typeof check[key] === 'string') && typeof check.required === 'boolean' && strings(check.evidence))
|
|
36
|
+
checks.push(check);
|
|
37
|
+
}
|
|
38
|
+
return { completion: completion, recordedAt: new Date().toISOString(), change: status.change,
|
|
39
|
+
exceptions, checks, findings: strings(receipt?.findings) ? receipt.findings : [],
|
|
40
|
+
phases: Object.entries(obj(status.phases) ?? {}).flatMap(([name, raw]) => {
|
|
41
|
+
const phase = obj(raw);
|
|
42
|
+
return phase && typeof phase.status === 'string' ? [{ name, status: phase.status, durationMs: count(phase.durationMs), attempts: count(phase.attempts) }] : [];
|
|
43
|
+
}), };
|
|
44
|
+
}
|
|
45
|
+
async function readCoreCompletion(input) {
|
|
46
|
+
const runtime = (0, node_path_1.join)(input.cwd, '.specrails', 'runtime', 'pipeline.mjs');
|
|
47
|
+
if (!(0, node_fs_1.existsSync)(runtime))
|
|
48
|
+
return null;
|
|
49
|
+
try {
|
|
50
|
+
const { stdout } = await (0, node_util_1.promisify)(node_child_process_1.execFile)((0, path_resolver_1.resolveBundledNodeExe)() ?? process.execPath, [runtime, 'status', '--context', input.contextPath], {
|
|
51
|
+
cwd: input.cwd, env: input.env, encoding: 'utf8', timeout: 15_000, maxBuffer: 4 * 1024 * 1024, windowsHide: true,
|
|
52
|
+
});
|
|
53
|
+
return parseCoreCompletion(JSON.parse(stdout), input.runId);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -43,10 +43,11 @@ function prepareCoreExecution(input) {
|
|
|
43
43
|
throw new Error('Core artifact repository is outside the run scope');
|
|
44
44
|
const rawTickets = run.spec?.tickets?.length ? run.spec.tickets : run.spec ? [{
|
|
45
45
|
id: run.spec.id ?? run.spec.ticketIds?.[0] ?? 'goal', title: run.spec.title,
|
|
46
|
-
description: run.spec.description, repositoryIds: run.spec.repositoryIds,
|
|
46
|
+
description: run.spec.description, acceptanceCriteria: run.spec.acceptanceCriteria, repositoryIds: run.spec.repositoryIds,
|
|
47
47
|
}] : run.goal ? [{ id: 'goal', title: 'Loop goal', description: run.goal }] : [];
|
|
48
48
|
const specs = rawTickets.map(ticket => ({
|
|
49
49
|
id: ticket.id, title: ticket.title ?? '', description: ticket.description ?? '',
|
|
50
|
+
...(ticket.acceptanceCriteria ? { acceptanceCriteria: [...ticket.acceptanceCriteria] } : {}),
|
|
50
51
|
...(ticket.repositoryIds ? { repositoryIds: [...ticket.repositoryIds] } : {}),
|
|
51
52
|
}));
|
|
52
53
|
if (specs.some(spec => spec.repositoryIds?.some(id => !repositories.some(repo => repo.id === id)))) {
|
package/server/dist/db.js
CHANGED
|
@@ -2085,7 +2085,7 @@ function getProjectSettings(db) {
|
|
|
2085
2085
|
const integrationBranchRow = db.prepare(`SELECT value FROM queue_state WHERE key = 'config.integration_branch'`).get();
|
|
2086
2086
|
const worktreeEnvPassthroughRow = db.prepare(`SELECT value FROM queue_state WHERE key = 'config.worktree_env_passthrough'`).get();
|
|
2087
2087
|
return {
|
|
2088
|
-
pipelineTelemetryEnabled: telemetryRow?.value
|
|
2088
|
+
pipelineTelemetryEnabled: telemetryRow?.value !== 'false',
|
|
2089
2089
|
orchestratorModel: modelRow?.value ?? 'sonnet',
|
|
2090
2090
|
orchestratorModelExplicit: modelRow?.value !== undefined,
|
|
2091
2091
|
prePrompt: prePromptRow?.value ?? '',
|
|
@@ -9,6 +9,7 @@ exports.createLoopExecutors = createLoopExecutors;
|
|
|
9
9
|
* from coverage; the engine's traversal/decision logic is unit-tested against
|
|
10
10
|
* fake executors in `loop-run-manager.test.ts`.
|
|
11
11
|
*/
|
|
12
|
+
const core_completion_1 = require("./core-completion");
|
|
12
13
|
const core_execution_1 = require("./core-execution");
|
|
13
14
|
const codex_spawn_1 = require("./plugins/codex-spawn");
|
|
14
15
|
const node_child_process_1 = require("node:child_process");
|
|
@@ -161,7 +162,13 @@ function createLoopExecutors(opts = {}) {
|
|
|
161
162
|
return env;
|
|
162
163
|
}
|
|
163
164
|
};
|
|
165
|
+
const completionContexts = new Map();
|
|
164
166
|
return {
|
|
167
|
+
async readCoreCompletion(runId) {
|
|
168
|
+
const context = completionContexts.get(runId);
|
|
169
|
+
completionContexts.delete(runId);
|
|
170
|
+
return context ? (0, core_completion_1.readCoreCompletion)(context) : null;
|
|
171
|
+
},
|
|
165
172
|
// Cheap working-tree fingerprint for the engine's non-convergence guard:
|
|
166
173
|
// HEAD, tracked diffs and untracked file contents, hashed. Status/path names
|
|
167
174
|
// alone stay identical while a fixer keeps improving the same files.
|
|
@@ -266,6 +273,9 @@ function createLoopExecutors(opts = {}) {
|
|
|
266
273
|
// `is_error: true` — a usage/rate-limit notice returned AS the reply).
|
|
267
274
|
let resultIsError = false;
|
|
268
275
|
let liveBackgroundTasks = [];
|
|
276
|
+
const providerEnv = (0, runtime_1.buildProviderEnv)(adapter, buildOpts, stepEnv);
|
|
277
|
+
if (core && coreRun)
|
|
278
|
+
completionContexts.set(coreRun.runId, { cwd, contextPath: core.contextPath, env: providerEnv, runId: coreRun.runId });
|
|
269
279
|
const effectiveIdleTimeoutMs = idleTimeoutMs ?? inactivityTimeoutMs();
|
|
270
280
|
const wallStartedAt = Date.now();
|
|
271
281
|
const res = await (0, spawn_lifecycle_1.runAiCliInvocation)({
|
|
@@ -273,7 +283,7 @@ function createLoopExecutors(opts = {}) {
|
|
|
273
283
|
action,
|
|
274
284
|
buildOpts,
|
|
275
285
|
cwd,
|
|
276
|
-
env:
|
|
286
|
+
env: providerEnv,
|
|
277
287
|
// 0 ⇒ watchdog disabled (factory loops run untimed; the loop's
|
|
278
288
|
// maxIterations / cost cap remain the runaway guards).
|
|
279
289
|
timeoutMs: (aiStepTimeoutMs ?? AI_STEP_TIMEOUT_MS) > 0 ? (aiStepTimeoutMs ?? AI_STEP_TIMEOUT_MS) : undefined,
|
|
@@ -463,10 +473,13 @@ function createLoopExecutors(opts = {}) {
|
|
|
463
473
|
extraArgs,
|
|
464
474
|
};
|
|
465
475
|
const args = adapter.buildArgs('chat-stream', buildOpts);
|
|
476
|
+
const providerEnv = (0, runtime_1.buildProviderEnv)(adapter, buildOpts, stepEnv);
|
|
477
|
+
if (core && coreRun)
|
|
478
|
+
completionContexts.set(coreRun.runId, { cwd, contextPath: core.contextPath, env: providerEnv, runId: coreRun.runId });
|
|
466
479
|
const effectiveIdleTimeoutMs = idleTimeoutMs ?? inactivityTimeoutMs();
|
|
467
480
|
return {
|
|
468
481
|
adapter,
|
|
469
|
-
spec: { binary: adapter.binary, args, cwd, env:
|
|
482
|
+
spec: { binary: adapter.binary, args, cwd, env: providerEnv },
|
|
470
483
|
// The loop's ai-step timeout bounds the WHOLE step, interactive
|
|
471
484
|
// included. 0 ⇒ unbounded (the engine skips arming the step timer).
|
|
472
485
|
...(core?.promptPrefix ? { promptPrefix: core.promptPrefix } : {}),
|
|
@@ -227,9 +227,10 @@ function interpolateSpec(text, spec) {
|
|
|
227
227
|
ticketIds: spec.ticketIds,
|
|
228
228
|
title: spec.title,
|
|
229
229
|
description: spec.description,
|
|
230
|
+
acceptanceCriteria: spec.acceptanceCriteria,
|
|
230
231
|
repositoryIds: spec.repositoryIds,
|
|
231
232
|
openspecChangeName: changeName || undefined,
|
|
232
|
-
tickets: spec.tickets?.map(ticket => ({ id: ticket.id, title: ticket.title, description: ticket.description, repositoryIds: ticket.repositoryIds })),
|
|
233
|
+
tickets: spec.tickets?.map(ticket => ({ id: ticket.id, title: ticket.title, description: ticket.description, acceptanceCriteria: ticket.acceptanceCriteria, repositoryIds: ticket.repositoryIds })),
|
|
233
234
|
}, null, 2);
|
|
234
235
|
if (scope === '{}')
|
|
235
236
|
return '';
|
|
@@ -1615,6 +1615,21 @@ class LoopRunManager {
|
|
|
1615
1615
|
}
|
|
1616
1616
|
console.log(`[loop] settle run=${runId} outcome=${outcome} iterations=${iteration} ` +
|
|
1617
1617
|
(usageTelemetryAvailable ? `cost=$${totalCost.toFixed(4)}` : 'usage=unavailable'));
|
|
1618
|
+
// Execution and acceptance are separate facts. Persist the runtime's own
|
|
1619
|
+
// terminal snapshot alongside counters so history does not depend on prose.
|
|
1620
|
+
let coreCompletion = null;
|
|
1621
|
+
try {
|
|
1622
|
+
coreCompletion = await this.executors.readCoreCompletion?.(runId) ?? null;
|
|
1623
|
+
}
|
|
1624
|
+
catch { /* old/unavailable runtime */ }
|
|
1625
|
+
const executionOutcome = outcome;
|
|
1626
|
+
if (outcome === 'success' && coreCompletion && (coreCompletion.completion.implementation !== 'complete' || !['verified', 'with-exceptions'].includes(coreCompletion.completion.validation)))
|
|
1627
|
+
outcome = 'blocked';
|
|
1628
|
+
emitRunEvent('loop_completion', {
|
|
1629
|
+
version: 1, execution: executionOutcome, steps: stepNum, deciderEvaluations: iteration,
|
|
1630
|
+
turns: finalJobUsage.numTurns, costUsd: usageTelemetryAvailable ? totalCost : null,
|
|
1631
|
+
costUncertain, core: coreCompletion,
|
|
1632
|
+
});
|
|
1618
1633
|
// Settle the backing job so the Jobs list + JobDetail reflect the final
|
|
1619
1634
|
// status, and emit job.finalized so an open JobDetail re-fetches + stops the
|
|
1620
1635
|
// live stream (mirrors QueueManager).
|
|
@@ -1627,10 +1642,12 @@ class LoopRunManager {
|
|
|
1627
1642
|
// `≥` when any cost-bearing step ended unpriced (timeout/crash) — the figure
|
|
1628
1643
|
// is a lower bound, not exact. Providers without usage telemetry get an
|
|
1629
1644
|
// explicit unavailable marker, never a fabricated "$0.0000".
|
|
1630
|
-
logLine(`\n■ Loop finished: ${
|
|
1645
|
+
logLine(`\n■ Loop execution finished: ${executionOutcome} — ${stepNum} step${stepNum === 1 ? '' : 's'}, ${iteration} decider evaluation${iteration === 1 ? '' : 's'}, ${finalJobUsage.numTurns ?? 'unknown'} agent turns, ` +
|
|
1631
1646
|
(usageTelemetryAvailable
|
|
1632
1647
|
? `${costUncertain ? '≥ ' : ''}$${totalCost.toFixed(4)}`
|
|
1633
1648
|
: 'usage/cost unavailable'));
|
|
1649
|
+
if (coreCompletion)
|
|
1650
|
+
logLine(`Core result: implementation=${coreCompletion.completion.implementation}; validation=${coreCompletion.completion.validation}; archive=${coreCompletion.completion.archive}; delivery=${coreCompletion.completion.delivery}`);
|
|
1634
1651
|
const finishedAt = new Date(this.now()).toISOString();
|
|
1635
1652
|
(0, loop_runs_store_1.finishLoopRunAndJob)(this.db, runId, {
|
|
1636
1653
|
outcome,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-zu2_FqZY.js";import{J as r,X as i,z as a}from"./TicketDetailModalContext-BNa1mdXq.js";import{h as o,l as s,r as c}from"./useSharedWebSocket-BOdS5_Iz.js";import{n as l,t as u}from"./createLucideIcon-Bjbbp_KS.js";import{a as d,r as f,s as p}from"./useDesktop-RSMTyy7V.js";import{d as m,u as h}from"./MinimizedChatsContext-Deg39peL.js";import{t as g}from"./brain-DI9lHkKY.js";import{n as _}from"./file-text-BcLCfcWZ.js";import{t as v}from"./circle-x-CMYsN4ZH.js";import{t as y}from"./git-branch-BRM0F5GN.js";import{t as b}from"./loader-circle-DcygOQpC.js";import{n as x,t as S}from"./square-Ci-PFcFe.js";import{t as C}from"./search-Cq_gE3Ik.js";import{t as w}from"./triangle-alert-H9T4jAmh.js";import{t as T}from"./x-CBMI9ejn.js";import{t as E}from"./utils-BC4DHlz2.js";import{n as D,t as O}from"./lib-CGdyxIWg.js";import{t as k}from"./button-Ccc9Dc-D.js";import{Et as A,F as j,G as M,J as ee,K as N,R as P,V as F,bt as te,dt as ne,f as I,jt as L,kt as R,lt as re,p as z,q as B,rt as ie,ut as ae,z as V}from"./index-m5pKr1T6.js";import{t as oe}from"./lib-C7Mhm-gT.js";var se=u(`chevrons-down-up`,[[`path`,{d:`m7 20 5-5 5 5`,key:`13a0gw`}],[`path`,{d:`m7 4 5 5 5-5`,key:`1kwcof`}]]),ce=u(`chevrons-up-down`,[[`path`,{d:`m7 15 5 5 5-5`,key:`1hf1tw`}],[`path`,{d:`m7 9 5-5 5 5`,key:`sgt6xg`}]]),le=u(`circle-dot`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}]]),ue=u(`clock`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 6v6l4 2`,key:`mmk7yg`}]]),de=u(`hourglass`,[[`path`,{d:`M5 22h14`,key:`ehvnwv`}],[`path`,{d:`M5 2h14`,key:`pdyrp9`}],[`path`,{d:`M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22`,key:`1d314k`}],[`path`,{d:`M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2`,key:`1vvvr6`}]]),H=n();function fe({phases:e,phaseDefinitions:t}){return t.length===0?null:(0,H.jsx)(`div`,{className:`flex items-center`,children:t.map((n,r)=>{let i=e[n.key]??`idle`,a=r<t.length-1?e[t[r+1].key]??`idle`:null;return(0,H.jsxs)(`div`,{className:`flex items-center`,children:[(0,H.jsxs)(P,{children:[(0,H.jsx)(F,{asChild:!0,children:(0,H.jsxs)(`div`,{className:`flex flex-col items-center gap-1.5 cursor-default px-4`,children:[(0,H.jsx)(pe,{state:i}),(0,H.jsx)(`span`,{className:E(`text-xs font-medium transition-colors`,i===`running`?`text-blue-400 aurora-light:text-accent-info`:i===`done`?`text-emerald-400 aurora-light:text-accent-success`:i===`error`?`text-red-400 aurora-light:text-destructive`:`text-muted-foreground/40`),children:n.label})]})}),(0,H.jsxs)(V,{side:`bottom`,className:`max-w-[200px]`,children:[(0,H.jsx)(`p`,{className:`font-medium`,children:n.label}),(0,H.jsx)(`p`,{className:`text-muted-foreground mt-0.5`,children:n.description})]})]}),a!==null&&(0,H.jsx)(`div`,{className:E(`h-px w-12 -mt-5 shrink-0 transition-all duration-300`,a===`done`||i===`done`?`bg-emerald-500/30 aurora-light:bg-accent-success/40`:a===`running`?`bg-blue-400/40 aurora-light:bg-accent-info/40`:`bg-border/30`)})]},n.key)})})}function pe({state:e}){return(0,H.jsxs)(`div`,{className:E(`flex items-center justify-center w-10 h-10 rounded-full transition-all duration-300`,e===`running`?`bg-blue-500/10 aurora-light:bg-accent-info/10 ring-1 ring-blue-400/30 aurora-light:ring-accent-info/30 animate-pulse`:e===`done`?`bg-emerald-500/10 aurora-light:bg-accent-success/10`:e===`error`?`bg-red-500/10 aurora-light:bg-destructive/10`:`bg-muted/20`),children:[e===`running`&&(0,H.jsx)(b,{className:`w-6 h-6 text-blue-400 aurora-light:text-accent-info animate-spin`}),e===`done`&&(0,H.jsx)(L,{className:`w-6 h-6 text-emerald-400 aurora-light:text-accent-success`}),e===`error`&&(0,H.jsx)(v,{className:`w-6 h-6 text-red-400 aurora-light:text-destructive`}),e===`idle`&&(0,H.jsx)(r,{className:`w-6 h-6 text-muted-foreground/20`})]})}var U=e(t(),1);function me(e){let t=e.trimStart();return!!(/^#{1,6}\s/.test(t)||/^[-*+]\s/.test(t)||/^\d+\.\s/.test(t)||/^\|.+\|/.test(t)||t.startsWith("```")||t.startsWith(`> `)||/\*\*[^*]+\*\*/.test(e)||/`[^`]+`/.test(e)||/\[.+\]\(.+\)/.test(e)||/^(-{3,}|_{3,}|\*{3,})$/.test(t)||/^- \[[ x]\]\s/.test(t))}var he=new Set;function ge({ticketId:e,onOpen:t,children:n}){let{t:r}=l(`agent`),i=r(`refs.openTicket`,{id:e});return(0,H.jsx)(`button`,{type:`button`,"data-testid":`log-ticket-ref`,onClick:n=>{n.stopPropagation(),t(e)},title:i,"aria-label":i,className:`inline cursor-pointer p-0 align-baseline text-accent-primary/90 underline decoration-accent-primary/50 decoration-dotted underline-offset-2 transition-colors hover:text-accent-primary hover:decoration-solid`,children:n})}function _e(e){if(!e.includes(`#`))return null;let t=B(e,he);return t.some(e=>e.kind===`ticket`)?t:null}function ve(e,t){let n=_e(e);return n?n.map((e,n)=>e.kind===`ticket`?(0,H.jsx)(ge,{ticketId:e.ticketId,onOpen:t,children:e.label},n):(0,H.jsx)(U.Fragment,{children:e.kind===`text`?e.text:e.label},n)):e}var ye=new Set([`code`,`inlineCode`,`link`,`linkReference`,`image`,`imageReference`,`definition`,`html`]);function be(e){return e.kind===`ticket`?{type:`link`,url:M({kind:`ticket`,ticketId:e.ticketId}),children:[{type:`text`,value:e.label}]}:{type:`text`,value:e.kind===`text`?e.text:e.label}}function xe(e){let t=e.children;if(t)for(let e=t.length-1;e>=0;e--){let n=t[e];if(!ye.has(n.type))if(n.type===`text`&&typeof n.value==`string`){let r=B(n.value,he);r.some(e=>e.kind===`ticket`)&&t.splice(e,1,...r.map(be))}else xe(n)}}function Se(){return e=>xe(e)}function Ce(e){let{activeProjectId:t}=f(),{openRef:n}=ee(),r=e??t??void 0;return(0,U.useMemo)(()=>r?e=>{n(r,{kind:`ticket`,ticketId:e})}:void 0,[r,n])}function we(e,t){let n=`${e.id??t}`,r=e.timestamp;if(e.event_type===`log`)try{let t=JSON.parse(e.payload).line??``;return t.trim()?t.startsWith(`▸`)||t.match(/^(architect|developer|reviewer|ship|analyst)\s*:/i)?{id:n,content:t,type:`phase`,timestamp:r}:e.source===`stderr`?{id:n,content:t,type:`stderr`,timestamp:r}:me(t)?{id:n,content:t,type:`assistant`,timestamp:r}:{id:n,content:t,type:`plain`,timestamp:r}:null}catch{return null}if(e.event_type!==`log`&&e.event_type!==`result`)return null;if(e.event_type===`result`)try{let t=JSON.parse(e.payload),i=[];return t.duration_ms&&i.push(`${(t.duration_ms/1e3).toFixed(1)}s`),t.total_cost_usd&&i.push(`$${t.total_cost_usd.toFixed(4)}`),t.num_turns&&i.push(o.t(`jobs:logViewer.turns`,{count:t.num_turns})),{id:n,content:`▸ ${o.t(`jobs:logViewer.completed`)}${i.length?` — ${i.join(` · `)}`:``}`,type:`result`,timestamp:r}}catch{return null}return null}function Te(e){let t=`none`,n=[];for(let r of e){let e=r.type;if(e!==`plain`&&e!==`log`){t=`none`,n.push(r);continue}let i=r.content;i.startsWith(`--- `)?(t=`saw_minus`,n.push({...r,type:`diff-meta`})):t===`saw_minus`&&i.startsWith(`+++ `)?(t=`active`,n.push({...r,type:`diff-meta`})):t===`active`&&i.startsWith(`@@ `)?n.push({...r,type:`diff-hunk`}):t===`active`&&i.startsWith(`+`)&&!i.startsWith(`+++`)?n.push({...r,type:`diff-add`}):t===`active`&&i.startsWith(`-`)&&!i.startsWith(`---`)?n.push({...r,type:`diff-remove`}):(t===`active`&&(i.startsWith(` `)||i===``)||(t=`none`),n.push(r))}return n}function Ee(e){let t=[];for(let n of e){let e=t.length>0?t[t.length-1]:null;n.type===`assistant`&&e?.type===`assistant`?e.content+=`
|
|
2
|
-
`+n.content:t.push({...n})}return t}function De(e){let t=[{key:`__preamble__`,header:null,lines:[]}];for(let n of e)n.type===`phase`?t.push({key:n.id,header:n,lines:[]}):t[t.length-1].lines.push(n);return t.filter(e=>e.header!==null||e.lines.length>0)}function Oe({events:e,isLoading:t,projectId:n}){let{t:r,i18n:i}=l(`jobs`),[a,o]=(0,U.useState)(``),[s,c]=(0,U.useState)(!0),[u,d]=(0,U.useState)(new Set),f=(0,U.useRef)(null),m=(0,U.useRef)(null),g=Ce(n),{processedLines:_,groups:v,totalLines:y}=(0,U.useMemo)(()=>{let t=Te(Ee(e.map((e,t)=>we(e,t)).filter(e=>e!==null)));return{processedLines:t,groups:De(t),totalLines:t.length}},[e,i.language]),b=(0,U.useMemo)(()=>{if(!a)return y;let e=a.toLowerCase();return _.filter(t=>t.content.toLowerCase().includes(e)).length},[a,_,y]),x=(0,U.useCallback)(()=>{let e=m.current;e&&(e.scrollTop=e.scrollHeight)},[]);(0,U.useEffect)(()=>{s&&x()},[e.length,s,x]);function S(){let e=m.current;if(!e)return;let t=e.scrollHeight-e.scrollTop-e.clientHeight<50;c(t)}function w(e){d(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})}return t?(0,H.jsx)(`div`,{className:`flex-1 flex items-center justify-center`,children:(0,H.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:r(`logViewer.loading`)})}):y===0?(0,H.jsx)(`div`,{className:`flex-1 flex items-center justify-center`,children:(0,H.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:r(`logViewer.empty`)})}):(0,H.jsxs)(`div`,{className:`flex flex-col h-full`,children:[(0,H.jsxs)(`div`,{className:`px-4 py-2 border-b border-border flex items-center gap-2`,children:[(0,H.jsxs)(`div`,{className:`relative flex-1 max-w-xs`,children:[(0,H.jsx)(C,{className:`absolute left-2.5 top-1/2 -translate-y-1/2 w-3 h-3 text-muted-foreground`}),(0,H.jsx)(j,{placeholder:r(`logViewer.filterPlaceholder`),value:a,onChange:e=>o(e.target.value),className:`pl-7 h-7`})]}),(0,H.jsx)(k,{variant:`ghost`,size:`sm`,className:`h-7 px-2 text-muted-foreground/50 hover:text-foreground`,onClick:()=>{let e=_.map(e=>e.content).join(`
|
|
3
|
-
`);navigator.clipboard.writeText(e).then(()=>{p.success(r(`logViewer.copySuccess`))}).catch(()=>{p.error(r(`logViewer.copyFailed`))})},children:(0,H.jsx)(R,{className:`w-3.5 h-3.5`})}),(0,H.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:r(`logViewer.lineCount`,{filtered:b,total:y})})]}),(0,H.jsxs)(`div`,{ref:m,className:`flex-1 overflow-y-auto p-2 text-xs relative`,onScroll:S,children:[v.map(e=>(0,H.jsx)(ke,{group:e,filter:a,collapsed:u.has(e.key),onToggle:()=>w(e.key),onOpenTicket:g},e.key)),(0,H.jsx)(`div`,{ref:f})]}),!s&&(0,H.jsxs)(k,{size:`sm`,variant:`secondary`,onClick:()=>{c(!0),x()},className:`absolute bottom-16 right-6 h-7 gap-1 shadow-lg`,children:[(0,H.jsx)(h,{className:`w-3 h-3`}),r(`logViewer.jumpToBottom`)]})]})}var ke=(0,U.memo)(function({group:e,filter:t,collapsed:n,onToggle:r,onOpenTicket:i}){let{t:a}=l(`jobs`),o=t?e.lines.filter(e=>e.content.toLowerCase().includes(t.toLowerCase())):e.lines;if(e.header===null)return o.length===0?null:(0,H.jsx)(`div`,{children:o.map((e,t)=>(0,H.jsx)(W,{line:e,even:t%2==0,onOpenTicket:i},e.id))});let s=e.header.content;return(0,H.jsxs)(`div`,{className:`mt-3 rounded-md overflow-hidden border border-border/20`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:r,className:E(`flex items-center gap-2 w-full text-left px-3 py-2`,`bg-primary/5 border-b border-primary/20`,`hover:bg-primary/10 transition-colors duration-150 cursor-pointer`),children:[(0,H.jsx)(_,{className:E(`w-3 h-3 text-primary/60 shrink-0 transition-transform duration-150`,!n&&`rotate-90`)}),(0,H.jsx)(`span`,{className:`flex-1 text-[12px] font-semibold text-foreground leading-none`,children:s}),e.header.timestamp&&(0,H.jsx)(`span`,{className:`text-[10px] text-muted-foreground/40 font-mono tabular-nums shrink-0`,children:new Date(e.header.timestamp).toLocaleTimeString(`en`,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1})}),(0,H.jsx)(`span`,{className:`text-[10px] text-muted-foreground/40 shrink-0`,children:a(`logViewer.phaseLines`,{count:e.lines.length})})]}),!n&&(0,H.jsx)(`div`,{className:`bg-muted/5`,children:o.length===0?(0,H.jsx)(`p`,{className:`px-4 py-2 text-[10px] text-muted-foreground/40 italic`,children:a(t?`logViewer.noMatchingLines`:`logViewer.noOutput`)}):o.map((e,t)=>(0,H.jsx)(W,{line:e,even:t%2==0,onOpenTicket:i},e.id))})]})}),Ae=[oe],je=[O],Me=[O,Se],W=(0,U.memo)(function({line:e,even:t,onOpenTicket:n}){let r=e.type===`assistant`,i=e.type===`diff-add`,a=e.type===`diff-remove`,o=e.type===`diff-meta`,s=e.type===`diff-hunk`,c=i||a||o||s,l=n!=null&&(e.type===`plain`||e.type===`log`),u=(0,U.useMemo)(()=>l&&n?ve(e.content,n):e.content,[l,n,e.content]),d=r&&n?Me:je,f=(0,U.useMemo)(()=>n?{a:({href:e,children:t})=>{let r=N(e);return r?.kind===`ticket`?(0,H.jsx)(ge,{ticketId:r.ticketId,onOpen:n,children:t}):(0,H.jsx)(`a`,{href:e,children:t})}}:void 0,[n]);return(0,H.jsxs)(`div`,{className:E(`flex items-start gap-2 group px-2 py-0.5 rounded-sm`,!c&&(t?`bg-muted/20`:`bg-transparent`),e.type===`result`&&`bg-emerald-500/5 aurora-light:bg-accent-success/10 border-l-2 border-emerald-500/40 aurora-light:border-accent-success/40 mt-2 py-2`,i&&`bg-emerald-500/8 aurora-light:bg-accent-success/10 border-l-2 border-emerald-500/50 aurora-light:border-accent-success/50`,a&&`bg-red-500/8 aurora-light:bg-destructive/10 border-l-2 border-red-500/50 aurora-light:border-destructive/50`,o&&`bg-accent-primary/5 border-l-2 border-accent-primary/30`,s&&`bg-accent-info/5 border-l-2 border-accent-info/30`),children:[e.timestamp&&(0,H.jsx)(`span`,{className:`text-[10px] text-muted-foreground/40 shrink-0 mt-0.5 w-[52px] font-mono tabular-nums`,children:new Date(e.timestamp).toLocaleTimeString(`en`,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1})}),r?(0,H.jsx)(`div`,{className:`flex-1 min-w-0 prose prose-invert prose-xs max-w-none
|
|
4
|
-
prose-p:my-1 prose-p:leading-relaxed
|
|
5
|
-
prose-headings:mt-2 prose-headings:mb-1 prose-headings:text-sm prose-headings:font-semibold
|
|
6
|
-
prose-ul:my-1 prose-ol:my-1 prose-li:my-0
|
|
7
|
-
prose-code:text-cyan-300 prose-code:text-[11px] prose-code:bg-muted/40 prose-code:px-1 prose-code:py-0.5 prose-code:rounded
|
|
8
|
-
prose-pre:my-1 prose-pre:bg-muted/30 prose-pre:rounded-md prose-pre:p-2 prose-pre:text-[11px]
|
|
9
|
-
prose-strong:text-foreground prose-em:text-foreground/70
|
|
10
|
-
prose-a:text-blue-400 prose-a:no-underline hover:prose-a:underline
|
|
11
|
-
prose-table:my-2 prose-table:text-[11px]
|
|
12
|
-
prose-thead:border-border prose-thead:bg-muted/30
|
|
13
|
-
prose-th:px-3 prose-th:py-1.5 prose-th:text-left prose-th:font-semibold prose-th:text-foreground/90
|
|
14
|
-
prose-td:px-3 prose-td:py-1.5 prose-td:border-border
|
|
15
|
-
prose-tr:border-border
|
|
16
|
-
text-foreground/80`,children:(0,H.jsx)(D,{remarkPlugins:d,rehypePlugins:Ae,components:f,children:e.content})}):(0,H.jsx)(`span`,{className:E(`flex-1 break-all leading-relaxed whitespace-pre-wrap font-mono`,e.type===`tool-use`&&`text-cyan-400/80 aurora-light:text-accent-info text-[11px]`,e.type===`stderr`&&`text-orange-400 aurora-light:text-accent-warning`,e.type===`result`&&`text-emerald-400 aurora-light:text-accent-success font-medium`,e.type===`log`&&`text-foreground/60`,e.type===`plain`&&`text-foreground/70`,e.type===`tool-result`&&`text-muted-foreground/50`,i&&`text-emerald-400 aurora-light:text-accent-success`,a&&`text-red-400 aurora-light:text-destructive`,o&&`text-accent-primary/80`,s&&`text-accent-info/80`),children:u})]})});function G(e){try{let t=JSON.parse(e);if(t&&typeof t==`object`&&!Array.isArray(t))return t}catch{}return null}var Ne=/^\s*━+\s*Step\s+\d+\s*·/,Pe=/\s*\(iteration\s+\d+\)\s*$/i;function K(e){return e.replace(/^[\s\uFE0F\p{Extended_Pictographic}]+/u,``).trim()||e.trim()}function q(e){let t=K(e.title);return e.iteration==null?t:t.replace(Pe,``)}function Fe(e){return e.meta.nodeId??`${e.meta.kind}::${K(e.meta.title).replace(Pe,``)}`}function Ie(e){let t=null,n=0,r=[[]],i=[];for(let a=0;a<e.length;a++){let o=e[a];if(o.event_type===`loop_graph`){let e=G(o.payload);e&&e.graph&&typeof e.graph==`object`&&!Array.isArray(e.graph)&&(t={graph:e.graph,loopId:typeof e.loopId==`string`?e.loopId:void 0,loopName:typeof e.loopName==`string`?e.loopName:void 0,provider:typeof e.provider==`string`?e.provider:void 0,model:typeof e.model==`string`?e.model:void 0,iterationLimit:typeof e.iterationLimit==`number`?e.iterationLimit:void 0});continue}if(o.event_type===`loop_step`){let e=G(o.payload);if(!e||typeof e.index!=`number`)continue;let t=typeof e.iteration==`number`?e.iteration:null;t!=null&&t>n&&(n=t),i.push({meta:{index:e.index,kind:typeof e.kind==`string`?e.kind:`ai-step`,title:typeof e.title==`string`?e.title:``,nodeId:typeof e.nodeId==`string`?e.nodeId:null,iteration:t,template:typeof e.template==`string`&&e.template?e.template:void 0,command:typeof e.command==`string`&&e.command?e.command:void 0},end:null,lastActivity:null}),r.push([]);continue}if(o.event_type===`loop_step_end`){let e=G(o.payload);if(!e||typeof e.index!=`number`)continue;for(let t=i.length-1;t>=0;t--)if(i[t].meta.index===e.index){i[t].end={index:e.index,nodeId:typeof e.nodeId==`string`?e.nodeId:null,status:e.status===`stalled`?`stalled`:e.status===`failed`?`failed`:`ok`,exitCode:typeof e.exitCode==`number`?e.exitCode:null,durationMs:typeof e.durationMs==`number`?e.durationMs:null,decision:e.decision===`continue`||e.decision===`stop`?e.decision:void 0,...e.reason===`idle_timeout`||e.reason===`provider_limit`?{reason:e.reason}:{},...typeof e.idleMs==`number`?{idleMs:e.idleMs}:{}};break}continue}let s=i.length>0,c=we(o,a);if(c&&!(s&&Ne.test(c.content))&&r[r.length-1].push(c),s){let e=z(o);e.step&&e.actionKey&&(i[i.length-1].lastActivity={actionKey:e.actionKey,actionArg:e.actionArg})}}let a=e=>Te(Ee(e)),o=a(r[0]),s=i.map((e,t)=>({key:`step-${t}-${e.meta.index}`,meta:e.meta,lines:a(r[t+1]),end:e.end,lastActivity:e.lastActivity})),c=o.length+s.reduce((e,t)=>e+t.lines.length,0);return{graphMeta:t,setup:o,segments:s,maxIteration:n,totalLines:c}}function Le(e,t){return e.end?e.end.status:t.isLast?t.jobSettled?`interrupted`:`running`:`unknown`}function Re(e){return e===`continue`?0:e===`stop`?2:1}function ze(e){let t=new Map(e.nodes.map(e=>[e.id,e])),n=new Set,r=[],i=a=>{if(n.has(a))return;let o=t.get(a);if(!o)return;n.add(a),r.push(o);let s=e.edges.filter(e=>e.source===a).slice().sort((e,t)=>Re(e.branch)-Re(t.branch));for(let e of s)i(e.target)},a=e.nodes.find(e=>e.type===`start`);a&&i(a.id);for(let t of e.nodes)i(t.id);return r}function J(e){let t=e.data?.label;return typeof t==`string`&&t.trim()?t.trim():null}function Be(e,t){let n=e.segments.length-1,r=new Map,i=new Map;e.segments.forEach((e,t)=>{let n=Fe(e);r.set(n,{seg:e,idx:t}),e.meta.kind===`decider`&&e.end?.decision&&i.set(n,e.end.decision)});let a=e=>{let r=Le(e.seg,{isLast:e.idx===n,jobSettled:t.jobSettled});return r===`unknown`?`ok`:r===`stalled`?`failed`:r};if(e.graphMeta)return ze(e.graphMeta.graph).map(e=>{if(e.type===`start`)return{key:e.id,kind:`start`,label:J(e),state:`ok`,latestSegmentKey:null};if(e.type===`end`)return{key:e.id,kind:`end`,label:J(e),state:t.jobSettled?t.jobFailed?`failed`:`ok`:`pending`,latestSegmentKey:null};let n=r.get(e.id);return n?{key:e.id,kind:e.type,label:J(e)??q(n.seg.meta),state:a(n),decision:e.type===`decider`?i.get(e.id):void 0,latestSegmentKey:n.seg.key}:{key:e.id,kind:e.type,label:J(e),state:`pending`,latestSegmentKey:null}});let o=[],s=new Map;return e.segments.forEach((e,t)=>{let n=Fe(e),r={seg:e,idx:t},c=s.get(n),l=e.meta.kind===`decider`?i.get(n):void 0;if(c!=null){let t=o[c];t.state=a(r),t.decision=l,t.latestSegmentKey=e.key}else s.set(n,o.length),o.push({key:n,kind:e.meta.kind,label:q(e.meta)||null,state:a(r),decision:l,latestSegmentKey:e.key})}),o}function Ve(e){if(!Number.isFinite(e)||e<0)return`—`;if(e<1e3)return`${Math.round(e)}ms`;let t=e/1e3;if(t<60)return`${t.toFixed(1)}s`;let n=Math.floor(t/60),r=Math.round(t%60);return n<60?`${n}m ${r}s`:`${Math.floor(n/60)}h ${n%60}m`}var He={start:x,"ai-step":g,shell:ie,decider:y,condition:y,end:A},Ue=S,We={start:`text-accent-success`,"ai-step":`text-accent-primary`,shell:`text-accent-warning`,decider:`text-accent-highlight`,condition:`text-accent-info`,end:`text-accent-secondary`},Ge={start:`border-accent-success/60`,"ai-step":`border-accent-primary/60`,shell:`border-accent-warning/60`,decider:`border-accent-highlight/60`,condition:`border-accent-info/60`,end:`border-accent-secondary/60`};function Ke(e){return He[e]??Ue}function qe({chips:e,iteration:t,onChipClick:n,variant:r}){let{t:o}=l(`jobs`);return e.length===0&&!t?null:(0,H.jsxs)(`div`,{"data-testid":`loop-overview-strip`,role:`list`,"aria-label":o(`loopExplorer.stepMapAria`),className:E(`flex items-center gap-1 overflow-x-auto border-b border-border/30 bg-surface/20`,r===`glass`?`px-3 py-1.5`:`px-4 py-2`),children:[e.map((e,t)=>{let r=Ke(e.kind),s=We[e.kind]??`text-foreground`,c=Ge[e.kind]??`border-border/40`,l=e.label??o(`loops:builder.nodes.${e.kind}`,{defaultValue:e.kind}),u=e.latestSegmentKey!=null;return(0,H.jsxs)(U.Fragment,{children:[t>0&&(0,H.jsx)(_,{className:`w-3 h-3 text-muted-foreground/30 shrink-0`}),(0,H.jsxs)(`button`,{type:`button`,role:`listitem`,"data-testid":`loop-node-chip`,"data-state":e.state,"data-kind":e.kind,"data-decision":e.decision,"aria-label":`${l} — ${e.state}`,disabled:!u,onClick:()=>e.latestSegmentKey&&n(e.latestSegmentKey),className:E(`relative flex items-center gap-1.5 shrink-0 rounded-full border bg-surface/40 px-2.5 py-1 text-[11px] transition-colors`,c,e.state===`pending`&&`opacity-45 border-border/40`,e.state===`interrupted`&&`border-dashed border-accent-warning/50`,u?`cursor-pointer hover:bg-surface/70`:`cursor-default`),children:[e.state===`running`&&(0,H.jsx)(`span`,{"aria-hidden":!0,className:`absolute -inset-px rounded-full ring-2 ring-accent-primary/50 motion-safe:animate-pulse pointer-events-none`}),(0,H.jsx)(r,{className:E(`w-3 h-3 shrink-0`,s)}),(0,H.jsx)(`span`,{className:E(`max-w-[120px] truncate font-medium text-foreground/90`,e.state===`running`&&`title-shimmer`),children:l}),e.state===`ok`&&(0,H.jsx)(m,{className:`w-3 h-3 text-accent-success shrink-0`}),e.state===`failed`&&(0,H.jsx)(T,{className:`w-3 h-3 text-destructive shrink-0`}),e.decision===`continue`&&(0,H.jsx)(a,{className:`w-3 h-3 text-accent-highlight shrink-0`}),e.decision===`stop`&&(0,H.jsx)(i,{className:`w-3 h-3 text-accent-success shrink-0`})]})]},e.key)}),t&&(0,H.jsxs)(`span`,{"data-testid":`loop-iteration-chip`,className:`ml-auto flex items-center gap-1.5 shrink-0 rounded-full border border-accent-highlight/40 bg-accent-highlight/10 px-2.5 py-1 text-[10px] font-medium text-accent-highlight tabular-nums`,children:[(0,H.jsx)(ne,{className:`w-3 h-3`}),t.limit==null?o(`loopExplorer.iterationBadge`,{count:t.current}):o(`loopExplorer.iteration`,{current:t.current,limit:t.limit})]})]})}var Je=(0,U.memo)(qe);function Ye({className:e}){return(0,H.jsxs)(`span`,{className:E(`relative flex h-2 w-2 shrink-0`,e),children:[(0,H.jsx)(`span`,{className:`motion-safe:animate-ping absolute inline-flex h-full w-full rounded-full bg-accent-primary opacity-60`}),(0,H.jsx)(`span`,{className:`relative inline-flex rounded-full h-2 w-2 bg-accent-primary`})]})}function Xe(e,t){if(!t)return e;let n=t.toLowerCase();return e.filter(e=>e.content.toLowerCase().includes(n))}function Ze(e,t,n,r){return e.length===0?(0,H.jsx)(`p`,{className:`px-4 py-2 text-[10px] text-muted-foreground/40 italic`,children:n(t?`logViewer.noMatchingLines`:`logViewer.noOutput`)}):e.map((e,t)=>(0,H.jsx)(W,{line:e,even:t%2==0,onOpenTicket:r},e.id))}function Qe({label:e,value:t,copyLabel:n}){let[r,i]=(0,U.useState)(!1),a=async()=>{try{await navigator.clipboard.writeText(t),i(!0),window.setTimeout(()=>i(!1),1500)}catch{}};return(0,H.jsxs)(`div`,{className:`min-w-0`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,H.jsx)(`span`,{className:`text-[9px] font-semibold uppercase tracking-wider text-muted-foreground/50`,children:e}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void a(),"aria-label":`${n} — ${e}`,title:n,className:`p-0.5 text-muted-foreground/40 hover:text-foreground transition-colors cursor-pointer`,children:r?(0,H.jsx)(m,{className:`w-2.5 h-2.5 text-accent-success`}):(0,H.jsx)(R,{className:`w-2.5 h-2.5`})})]}),(0,H.jsx)(`pre`,{className:`mt-0.5 text-[10px] font-mono leading-relaxed text-foreground/75 whitespace-pre-wrap break-words`,children:t})]})}function $e({segment:e,status:t,collapsed:n,filter:r,onToggle:i,onCopy:a,setRef:o,onOpenTicket:s}){let{t:c}=l(`jobs`),{meta:u,lines:d,end:f,lastActivity:p}=e,h=Ke(u.kind),g=We[u.kind]??`text-foreground`,v=Xe(d,r),y=t===`running`,b=!!(u.template||u.command),[x,S]=(0,U.useState)(!1);return(0,H.jsxs)(`div`,{ref:t=>o(e.key,t),"data-testid":`loop-step-section`,"data-status":t,"data-step-index":u.index,className:E(`mt-3 rounded-md overflow-hidden border animate-in fade-in duration-200`,t===`running`&&`border-accent-primary/40`,t===`failed`&&`border-destructive/30`,t===`stalled`&&`border-dashed border-destructive/40`,t===`interrupted`&&`border-dashed border-accent-warning/40`,(t===`ok`||t===`unknown`)&&`border-border/20`),children:[(0,H.jsxs)(`div`,{className:E(`flex items-stretch bg-primary/5 border-b`,t===`failed`||t===`stalled`?`border-destructive/20`:`border-primary/20`),children:[(0,H.jsxs)(`button`,{type:`button`,onClick:()=>i(e.key),className:`flex items-center gap-2 flex-1 min-w-0 text-left px-3 py-2 hover:bg-primary/10 transition-colors duration-150 cursor-pointer`,children:[(0,H.jsx)(_,{className:E(`w-3 h-3 text-primary/60 shrink-0 transition-transform duration-150`,!n&&`rotate-90`)}),(0,H.jsx)(`span`,{className:`text-[10px] font-mono tabular-nums text-muted-foreground/60 shrink-0 w-5 text-right`,children:u.index}),(0,H.jsx)(h,{className:E(`w-3.5 h-3.5 shrink-0`,g)}),(0,H.jsx)(`span`,{className:`text-[12px] font-semibold text-foreground leading-none truncate`,children:q(u)}),u.iteration!=null&&u.iteration>=1&&(0,H.jsx)(`span`,{className:`shrink-0 rounded-full bg-muted/60 px-1.5 py-0.5 text-[9px] font-medium text-muted-foreground tabular-nums`,children:c(`loopExplorer.iterationBadge`,{count:u.iteration})}),y&&(0,H.jsxs)(`span`,{className:`flex items-center gap-1.5 min-w-0 shrink-0 max-w-[40%]`,children:[(0,H.jsx)(Ye,{}),p&&(0,H.jsx)(`span`,{className:`title-shimmer text-[10px] truncate`,children:c(`statusPanel.activity.${p.actionKey}`,{arg:p.actionArg??``})})]}),t===`ok`&&(0,H.jsx)(m,{className:`w-3.5 h-3.5 text-accent-success shrink-0`}),t===`failed`&&f?.reason===`provider_limit`&&(0,H.jsx)(`span`,{className:`shrink-0 rounded border border-dashed border-destructive/50 px-1.5 py-0.5 text-[9px] font-medium uppercase tracking-wide text-destructive`,title:c(`loopExplorer.providerLimitHint`),"data-testid":`loop-step-provider-limit`,children:c(`loopExplorer.providerLimit`)}),t===`failed`&&(0,H.jsx)(T,{className:`w-3.5 h-3.5 text-destructive shrink-0`}),t===`stalled`&&(0,H.jsx)(`span`,{className:`shrink-0 rounded border border-dashed border-destructive/50 px-1.5 py-0.5 text-[9px] font-medium uppercase tracking-wide text-destructive`,title:f?.idleMs==null?void 0:c(`loopExplorer.stalledIdle`,{count:Math.max(1,Math.round(f.idleMs/6e4))}),children:c(`loopExplorer.stalled`)}),t===`interrupted`&&(0,H.jsx)(`span`,{className:`shrink-0 rounded border border-dashed border-accent-warning/50 px-1.5 py-0.5 text-[9px] font-medium uppercase tracking-wide text-accent-warning`,children:c(`loopExplorer.interrupted`)}),(0,H.jsx)(`span`,{className:`flex-1`}),f?.durationMs!=null&&(0,H.jsx)(`span`,{className:`text-[10px] text-muted-foreground/50 font-mono tabular-nums shrink-0`,children:Ve(f.durationMs)}),t===`failed`&&f?.exitCode!=null&&f.exitCode!==0&&(0,H.jsx)(`span`,{className:`text-[10px] text-destructive/70 font-mono shrink-0`,children:c(`activeJob.exitCode`,{code:f.exitCode})}),(0,H.jsx)(`span`,{className:`text-[10px] text-muted-foreground/40 shrink-0`,children:c(`logViewer.phaseLines`,{count:d.length})})]}),b&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>S(e=>!e),"aria-label":c(`loopExplorer.stepDetail`),"aria-expanded":x,title:c(`loopExplorer.stepDetail`),className:E(`px-2 flex items-center transition-colors cursor-pointer`,x?`text-foreground bg-primary/10`:`text-muted-foreground/40 hover:text-foreground hover:bg-primary/10`),children:(0,H.jsx)(te,{className:`w-3 h-3`})}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>a(e.key),"aria-label":c(`loopExplorer.copyStep`),title:c(`loopExplorer.copyStep`),className:`px-2.5 flex items-center text-muted-foreground/40 hover:text-foreground hover:bg-primary/10 transition-colors cursor-pointer`,children:(0,H.jsx)(R,{className:`w-3 h-3`})})]}),x&&b&&(0,H.jsxs)(`div`,{"data-testid":`loop-step-detail`,className:E(`px-4 py-2.5 space-y-2.5 bg-muted/10 border-b animate-in fade-in duration-150`,t===`failed`?`border-destructive/20`:`border-primary/10`),children:[u.template&&(0,H.jsx)(Qe,{label:c(`loopExplorer.stepDetailTemplate`),value:u.template,copyLabel:c(`loopExplorer.copyCommand`)}),u.command&&(0,H.jsx)(Qe,{label:c(`loopExplorer.stepDetailCommand`),value:u.command,copyLabel:c(`loopExplorer.copyCommand`)})]}),!n&&(0,H.jsx)(`div`,{className:`bg-muted/5`,children:Ze(v,r,c,s)})]})}var et=(0,U.memo)($e,(e,t)=>e.segment.key===t.segment.key&&e.segment.lines.length===t.segment.lines.length&&e.segment.lines[e.segment.lines.length-1]?.content===t.segment.lines[t.segment.lines.length-1]?.content&&e.segment.meta.template===t.segment.meta.template&&e.segment.meta.command===t.segment.meta.command&&e.segment.end?.status===t.segment.end?.status&&e.segment.end?.durationMs===t.segment.end?.durationMs&&e.segment.end?.decision===t.segment.end?.decision&&e.segment.end?.exitCode===t.segment.end?.exitCode&&e.segment.lastActivity?.actionKey===t.segment.lastActivity?.actionKey&&e.segment.lastActivity?.actionArg===t.segment.lastActivity?.actionArg&&e.status===t.status&&e.collapsed===t.collapsed&&e.filter===t.filter&&e.onOpenTicket===t.onOpenTicket),Y=`__setup__`;function tt({lines:e,collapsed:t,filter:n,onToggle:r,setRef:i,onOpenTicket:a}){let{t:o}=l(`jobs`),s=Xe(e,n);return(0,H.jsxs)(`div`,{ref:e=>i(Y,e),"data-testid":`loop-setup-section`,className:`rounded-md overflow-hidden border border-border/20`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:()=>r(Y),className:`flex items-center gap-2 w-full text-left px-3 py-2 bg-muted/10 border-b border-border/20 hover:bg-muted/20 transition-colors duration-150 cursor-pointer`,children:[(0,H.jsx)(_,{className:E(`w-3 h-3 text-muted-foreground/60 shrink-0 transition-transform duration-150`,!t&&`rotate-90`)}),(0,H.jsx)(x,{className:`w-3.5 h-3.5 text-accent-success/70 shrink-0`}),(0,H.jsx)(`span`,{className:`text-[11px] font-semibold text-muted-foreground leading-none uppercase tracking-wide`,children:o(`loopExplorer.setup`)}),(0,H.jsx)(`span`,{className:`flex-1`}),(0,H.jsx)(`span`,{className:`text-[10px] text-muted-foreground/40 shrink-0`,children:o(`logViewer.phaseLines`,{count:e.length})})]}),!t&&(0,H.jsx)(`div`,{className:`bg-muted/5`,children:Ze(s,n,o,a)})]})}var nt=(0,U.memo)(tt,(e,t)=>e.lines.length===t.lines.length&&e.lines[e.lines.length-1]?.content===t.lines[t.lines.length-1]?.content&&e.collapsed===t.collapsed&&e.filter===t.filter&&e.onOpenTicket===t.onOpenTicket);function X(){return(0,H.jsxs)(`span`,{className:`relative flex h-1.5 w-1.5 shrink-0`,children:[(0,H.jsx)(`span`,{className:`motion-safe:animate-ping absolute inline-flex h-full w-full rounded-full bg-accent-primary opacity-60`}),(0,H.jsx)(`span`,{className:`relative inline-flex rounded-full h-1.5 w-1.5 bg-accent-primary`})]})}function rt({events:e,jobStatus:t,isLoading:n,variant:r=`page`,projectId:i}){let{t:a,i18n:o}=l(`jobs`),[s,c]=(0,U.useState)(``),[u,d]=(0,U.useState)(`follow`),[f,m]=(0,U.useState)(new Set),h=(0,U.useRef)(null),g=(0,U.useRef)(new Map),_=Ce(i),v=(0,U.useMemo)(()=>Ie(e),[e,o.language]),y=t!=null&&t!==`running`&&t!==`queued`,b=t===`running`,x=(0,U.useMemo)(()=>v.segments.map((e,t)=>Le(e,{isLast:t===v.segments.length-1,jobSettled:y})),[v,y]),S=(0,U.useMemo)(()=>{let e=v.segments.map(e=>e.key);return v.setup.length>0&&e.push(Y),e},[v]),w=v.segments.length>0?v.segments[v.segments.length-1].key:Y,T=(0,U.useMemo)(()=>s?new Set(S):u===`follow`?new Set([w]):f,[s,u,w,f,S]),D=(0,U.useRef)(T);D.current=T;let O=(0,U.useRef)(v);O.current=v;let A=(0,U.useCallback)(e=>{let t=new Set(D.current);e?.(t),m(t),d(`manual`)},[]),M=(0,U.useCallback)(e=>{A(t=>{t.has(e)?t.delete(e):t.add(e)})},[A]),ee=(0,U.useCallback)(e=>{A(t=>t.add(e)),requestAnimationFrame(()=>{g.current.get(e)?.scrollIntoView?.({behavior:`smooth`,block:`start`})})},[A]),N=(0,U.useCallback)(()=>{let e=h.current;e&&(e.scrollTop=e.scrollHeight)},[]),P=(0,U.useCallback)(()=>{d(`follow`),requestAnimationFrame(N)},[N]),F=(0,U.useCallback)(()=>{m(new Set(S)),d(`manual`)},[S]),te=(0,U.useCallback)(()=>{m(new Set),d(`manual`)},[]);(0,U.useEffect)(()=>{u===`follow`&&!s&&N()},[v.totalLines,v.segments.length,u,s,N]);let ne=(0,U.useCallback)(()=>{let e=h.current;!e||u!==`follow`||e.scrollHeight-e.scrollTop-e.clientHeight>80&&A()},[u,A]),I=(0,U.useCallback)((e,t)=>{t?g.current.set(e,t):g.current.delete(e)},[]),L=(0,U.useCallback)(e=>{let t=O.current.segments.find(t=>t.key===e),n=e===`__setup__`?O.current.setup.map(e=>e.content).join(`
|
|
17
|
-
`):(t?.lines??[]).map(e=>e.content).join(`
|
|
18
|
-
`);navigator.clipboard.writeText(n).then(()=>p.success(a(`loopExplorer.copied`))).catch(()=>p.error(a(`logViewer.copyFailed`)))},[a]),re=(0,U.useCallback)(()=>{let e=O.current,t=e.setup.map(e=>e.content);for(let n of e.segments){t.push(`── Step ${n.meta.index} · ${K(n.meta.title)} ──`);for(let e of n.lines)t.push(e.content)}navigator.clipboard.writeText(t.join(`
|
|
19
|
-
`)).then(()=>p.success(a(`logViewer.copySuccess`))).catch(()=>p.error(a(`logViewer.copyFailed`)))},[a]),z=(0,U.useMemo)(()=>Be(v,{jobSettled:y,jobFailed:t===`failed`}),[v,y,t]),B=v.graphMeta?.iterationLimit??v.graphMeta?.graph.config.maxIterations??null,ie=v.maxIteration>0?{current:v.maxIteration,limit:B}:null,ae=(0,U.useMemo)(()=>{if(!s)return v.totalLines;let e=s.toLowerCase(),t=v.setup.filter(t=>t.content.toLowerCase().includes(e)).length;for(let n of v.segments)t+=n.lines.filter(t=>t.content.toLowerCase().includes(e)).length;return t},[s,v]),V=v.segments[v.segments.length-1],oe=b&&(v.segments.length===0||V?.end!=null);return n?(0,H.jsx)(`div`,{className:`flex-1 flex items-center justify-center h-full`,children:(0,H.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:a(`logViewer.loading`)})}):v.totalLines===0&&v.segments.length===0?(0,H.jsx)(`div`,{"data-testid":`loop-step-explorer`,className:`flex-1 flex items-center justify-center h-full`,children:(0,H.jsxs)(`p`,{className:`text-xs text-muted-foreground flex items-center gap-2`,children:[b&&(0,H.jsx)(X,{}),a(b?`loopExplorer.waiting`:`logViewer.empty`)]})}):(0,H.jsxs)(`div`,{"data-testid":`loop-step-explorer`,className:`relative flex flex-col h-full`,children:[(0,H.jsxs)(`div`,{className:E(`border-b border-border flex items-center gap-2`,r===`glass`?`px-3 py-1.5`:`px-4 py-2`),children:[(0,H.jsxs)(`div`,{className:`relative flex-1 max-w-xs`,children:[(0,H.jsx)(C,{className:`absolute left-2.5 top-1/2 -translate-y-1/2 w-3 h-3 text-muted-foreground`}),(0,H.jsx)(j,{placeholder:a(`logViewer.filterPlaceholder`),value:s,onChange:e=>c(e.target.value),className:`pl-7 h-7`})]}),(0,H.jsx)(k,{variant:`ghost`,size:`sm`,className:`h-7 px-2 text-muted-foreground/50 hover:text-foreground`,onClick:F,"aria-label":a(`loopExplorer.expandAll`),title:a(`loopExplorer.expandAll`),children:(0,H.jsx)(ce,{className:`w-3.5 h-3.5`})}),(0,H.jsx)(k,{variant:`ghost`,size:`sm`,className:`h-7 px-2 text-muted-foreground/50 hover:text-foreground`,onClick:te,"aria-label":a(`loopExplorer.collapseAll`),title:a(`loopExplorer.collapseAll`),children:(0,H.jsx)(se,{className:`w-3.5 h-3.5`})}),u===`follow`&&b&&(0,H.jsxs)(`span`,{className:`flex items-center gap-1.5 text-[10px] text-accent-primary shrink-0`,children:[(0,H.jsx)(X,{}),a(`loopExplorer.follow`)]}),(0,H.jsx)(`span`,{className:`flex-1`}),(0,H.jsx)(k,{variant:`ghost`,size:`sm`,className:`h-7 px-2 text-muted-foreground/50 hover:text-foreground`,onClick:re,"aria-label":a(`logViewer.copySuccess`),children:(0,H.jsx)(R,{className:`w-3.5 h-3.5`})}),(0,H.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:a(`logViewer.lineCount`,{filtered:ae,total:v.totalLines})})]}),(0,H.jsx)(Je,{chips:z,iteration:ie,onChipClick:ee,variant:r}),(0,H.jsxs)(`div`,{ref:h,onScroll:ne,className:`flex-1 overflow-y-auto p-2 text-xs`,children:[v.setup.length>0&&(0,H.jsx)(nt,{lines:v.setup,collapsed:!T.has(`__setup__`),filter:s,onToggle:M,setRef:I,onOpenTicket:_}),v.segments.map((e,t)=>(0,H.jsx)(et,{segment:e,status:x[t],collapsed:!T.has(e.key),filter:s,onToggle:M,onCopy:L,setRef:I,onOpenTicket:_},e.key)),oe&&(0,H.jsxs)(`div`,{"data-testid":`loop-waiting-row`,className:`mt-3 flex items-center gap-2 px-3 py-2 text-[11px] text-muted-foreground/70 italic`,children:[(0,H.jsx)(X,{}),a(`loopExplorer.waiting`)]})]}),u===`manual`&&b&&!s&&(0,H.jsxs)(`button`,{type:`button`,"data-testid":`resume-follow-pill`,onClick:P,className:`absolute bottom-4 left-1/2 -translate-x-1/2 z-10 flex items-center gap-1.5 rounded-full glass-card border border-accent-primary/30 px-3 py-1.5 text-[11px] font-medium text-foreground shadow-lg hover:border-accent-primary/60 transition-colors cursor-pointer animate-in fade-in slide-in-from-bottom-2 duration-200`,children:[(0,H.jsx)(X,{}),a(`loopExplorer.resumeFollow`)]})]})}var it=new Set(`grep.rg.ag.ack.find.fd.ls.cat.head.tail.sed.awk.cut.sort.uniq.wc.jq.yq.tr.xargs.tee.column.less.more.cd.pwd.echo.printf.which.type.test.true.false.env.export.set.source.date.basename.dirname.realpath.readlink.stat.file.tree.diff.sleep.seq.hostname.whoami.uname.mkdir.rmdir.cp.mv.rm.touch.ln.chmod.chown.install.[[.[.]].].for.while.until.if.then.else.elif.fi.do.done.case.esac.exec.eval.trap.read.shift.wait`.split(`.`)),at=new Set([`status`,`diff`,`log`,`show`,`branch`,`rev-parse`,`ls-files`,`blame`,`describe`]),ot=new Set([...at,`commit`,`add`,`stage`,`push`,`pull`,`fetch`,`checkout`,`switch`,`merge`,`rebase`,`reset`,`stash`,`tag`,`clone`,`worktree`,`cherry-pick`,`restore`,`apply`,`init`,`remote`,`config`,`update-ref`,`for-each-ref`]),st=new Set([`run`,`run-script`,`test`,`install`,`ci`,`i`,`add`,`exec`,`start`,`dlx`]),ct=[[/^(test|tests|test:.*|vitest|jest|spec)$/,`activity.testing`],[/^(build|compile|bundle|dist)$/,`activity.building`],[/^(typecheck|tsc|types?)$/,`activity.typechecking`],[/^(lint|lint:.*|eslint|format|fmt|prettier)$/,`activity.linting`]],lt=new Set([`vitest`,`jest`,`pytest`,`mocha`,`ava`,`rspec`,`phpunit`]);function ut(e){for(let[t,n]of ct)if(t.test(e))return n;return null}function dt(e){return e.split(/\s+/).map(e=>e.replace(/^['"`]+/,``).replace(/['"`]+$/,``)).filter(e=>e.length>0&&!e.startsWith(`-`))}function ft(e){let t=dt(e);if(t.length===0)return{kind:`plumbing`};let n=t[0].split(`/`).pop()??t[0],r=t.slice(1);if(it.has(n))return{kind:`plumbing`};if(lt.has(n))return{kind:`intent`,code:`activity.testing`};if((n===`npx`||n===`pnpm`||n===`yarn`||n===`bunx`)&&r.length>0){let e=r[0]===`dlx`||r[0]===`exec`?r[1]??``:r[0];if(lt.has(e))return{kind:`intent`,code:`activity.testing`};let t=ut(e===`run`?r[r.indexOf(`run`)+1]??``:e);if(t)return{kind:`intent`,code:t};if(e===`tsc`)return{kind:`intent`,code:`activity.typechecking`}}if(n===`npm`||n===`yarn`||n===`pnpm`||n===`bun`){let e=r.findIndex(e=>st.has(e)),t=e===-1?``:r[e];if(t===`install`||t===`ci`||t===`i`||t===`add`)return{kind:`intent`,code:`activity.installing`};let i=ut(t===`run`||t===`run-script`?r[e+1]??``:t);return i?{kind:`intent`,code:i}:{kind:`named`,tool:n}}if(n===`git`){let e=r.find(e=>ot.has(e))??``;return at.has(e)?{kind:`plumbing`}:e===`commit`||e===`add`||e===`stage`?{kind:`intent`,code:`activity.savingWork`}:{kind:`named`,tool:n}}if(n===`cargo`||n===`go`||n===`dotnet`||n===`mvn`||n===`gradle`){let e=r.find(e=>e===`test`||e===`build`||e===`compile`)??``;return e===`test`?{kind:`intent`,code:`activity.testing`}:e===`build`||e===`compile`?{kind:`intent`,code:`activity.building`}:{kind:`named`,tool:n}}return n===`tsc`?{kind:`intent`,code:`activity.typechecking`}:n===`openspec`?{kind:`intent`,code:`activity.checkingSpec`}:{kind:`named`,tool:n}}function pt(e){try{let t=JSON.parse(e);return t&&typeof t==`object`&&!Array.isArray(t)?t:{}}catch{return{}}}function mt(e,t){return e&&/^main-\d+$/.test(e)?`step.role.work`:e===`verify`?`step.role.verify`:e===`decide`||t===`decider`?`step.role.decide`:e===`fix`?`step.role.fix`:null}function ht(e){return e.replace(/^[^\p{L}\p{N}(]+/u,``).trim()}var Z=e=>typeof e==`number`&&Number.isFinite(e)?e:null,Q=e=>typeof e==`string`&&e.length>0?e:null,gt=new Set([`thinking`,`reasoning`]),_t=/^(MEMORY\.md|confidence-score\.json|design-confidence\.json|\d{4}-\d{2}-\d{2}-.+|feedback_.+)$/,vt=/^(proposal|design|tasks|spec|context-bundle)\.md$/,yt=new Set([`reading`,`writing`,`editing`]);function $(e,t,n,r,i){for(let t=e.length-1;t>=0;t--){let a=e[t];if(a.kind!==`activity`){if(a.stepIndex!==n)break;continue}if(a.stepIndex!==n)break;if(a.values.action===r&&a.values.target===i){a.values.repeats=Number(a.values.repeats??1)+1;return}}e.push({seq:t,kind:`activity`,code:r===`intent`?i:i?`activity.${r}`:`activity.${r}Bare`,values:{action:r,target:i,repeats:1},stepIndex:n,tone:`neutral`})}var bt=3;function xt(e,t,n,r,i){for(let t=e.length-1;t>=0;t--){let a=e[t];if(a.stepIndex!==n)break;if(a.kind!==`activity`||a.values.action!==r||a.values.fileGroup!==1)continue;let o=String(a.values.allNames??``).split(`\0`).filter(Boolean),s=!!i&&!o.includes(i);s&&o.push(i),a.values.allNames=o.join(`\0`),a.values.files=o.length;let c=String(a.values.names??``).split(`, `).filter(Boolean);s&&c.length<bt&&(c.push(i),a.values.names=c.join(`, `)),a.code=o.length>1?`activity.${r}Files`:i?`activity.${r}`:`activity.${r}Bare`,a.values.repeats=o.length>1?1:Number(a.values.repeats??1)+1;return}e.push({seq:t,kind:`activity`,code:i?`activity.${r}`:`activity.${r}Bare`,values:{action:r,target:i,names:i,allNames:i,files:+!!i,fileGroup:1,repeats:1},stepIndex:n,tone:`neutral`})}function St({events:e,settled:t}){let n=[],r=new Map,i=null,a=!1;for(let t of e){if(t.event_type===`loop_graph`){a=!0;continue}if(t.event_type===`loop_step`){let e=pt(t.payload),o=Z(e.index);if(o===null)continue;a=!0;let s=Q(e.kind)??`ai-step`,c={index:o,title:ht(Q(e.title)??``),roleCode:mt(Q(e.nodeId),s),kind:s,iteration:Z(e.iteration),ended:!1};r.set(o,c),i=o;let l=Z(e.attempt);n.push({seq:t.seq,kind:`step-start`,code:l!==null&&l>1?`step.startResume`:c.iteration&&c.iteration>1?`step.startRetry`:`step.start`,values:{step:o,title:c.title,iteration:c.iteration??1,...l!==null&&l>1?{attempt:l}:{},...c.roleCode?{roleCode:c.roleCode}:{}},stepIndex:o,tone:`neutral`});continue}if(t.event_type===`loop_step_end`){let e=pt(t.payload),i=Z(e.index);if(i===null)continue;let a=i===null?void 0:r.get(i);a&&(a.ended=!0);let o=Q(e.status),s=Z(e.durationMs),c=Z(e.exitCode),l=Z(e.idleMs),u=o===`stalled`,d=o===`failed`||u,f=o===`failed`&&Q(e.reason)===`provider_limit`;n.push({seq:t.seq,kind:`step-end`,code:u?`step.stalled`:f?`step.providerLimit`:d?`step.failed`:s===null?`step.done`:s>=9e4?`step.doneTimedMin`:`step.doneTimed`,values:{step:i,title:a?.title??``,seconds:s===null?0:Math.max(1,Math.round(s/1e3)),minutes:s===null?0:Math.max(1,Math.round(s/6e4)),...u?{idleMinutes:l===null?0:Math.max(1,Math.round(l/6e4))}:{},...a?.roleCode?{roleCode:a.roleCode}:{},...c===null?{}:{exitCode:c}},stepIndex:i,tone:d?`bad`:`good`});let p=Q(e.decision);(p===`continue`||p===`stop`)&&n.push({seq:t.seq,kind:`decision`,code:p===`continue`?`decision.another`:`decision.satisfied`,values:{step:i},stepIndex:i,tone:p===`continue`?`neutral`:`good`});continue}let e=z(t);if(!(!e.step||!e.actionKey)&&!gt.has(e.actionKey)){if(e.actionKey===`running`){let r=I(t),a=r?ft(r):{kind:`named`,tool:e.actionArg??``};if(a.kind===`plumbing`){$(n,t.seq,i,`exploring`,``);continue}if(a.kind===`intent`){$(n,t.seq,i,`intent`,a.code);continue}$(n,t.seq,i,`running`,a.tool);continue}if(yt.has(e.actionKey)){let r=e.actionArg??``;if(_t.test(r)){$(n,t.seq,i,`intent`,`activity.bookkeeping`);continue}if(vt.test(r)){$(n,t.seq,i,`intent`,`activity.writingSpec`);continue}xt(n,t.seq,i,e.actionKey,r);continue}$(n,t.seq,i,e.actionKey,e.actionArg??``)}}if(t)for(let e of r.values())e.ended||n.push({seq:2**53-1-(1e3-e.index),kind:`step-interrupted`,code:`step.interrupted`,values:{step:e.index,title:e.title},stepIndex:e.index,tone:`bad`});return{milestones:n,stepCount:r.size,plainJob:!a}}var Ct={"step-start":le,"step-end":m,"step-interrupted":w,decision:ae,activity:le},wt={neutral:`text-muted-foreground`,good:`text-accent-success`,bad:`text-accent-warning`};function Tt({events:e,settled:t,durationRange:n,elapsedMs:r,variant:i=`page`}){let{t:a}=l(`narration`),o=(0,U.useMemo)(()=>St({events:e,settled:t}),[e,t]),s=(0,U.useMemo)(()=>[...o.milestones].sort((e,t)=>e.seq-t.seq),[o.milestones]);return(0,H.jsxs)(`div`,{className:i===`glass`?`flex h-full flex-col overflow-hidden`:`flex flex-col`,children:[(0,H.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 border-b border-border/50 px-3 py-2 text-[11px] text-muted-foreground`,children:[typeof r==`number`&&r>0?(0,H.jsxs)(`span`,{className:`inline-flex items-center gap-1`,children:[(0,H.jsx)(ue,{className:`size-3`,"aria-hidden":!0}),a(`waiting.elapsed`,{minutes:Math.max(1,Math.round(r/6e4))})]}):null,n?(0,H.jsx)(`span`,{"data-testid":`narration-range`,children:a(`waiting.range`,{low:Math.max(1,Math.round(n.p25Ms/6e4)),high:Math.max(1,Math.round(n.p75Ms/6e4)),count:n.sampleCount})}):null,(0,H.jsx)(`span`,{className:`ml-auto italic opacity-70`,children:a(`aiNote`)})]}),(0,H.jsx)(`ol`,{className:`flex-1 space-y-1 px-3 py-2 ${i===`glass`?`overflow-y-auto`:``}`,"data-testid":`narration-list`,children:s.length===0?(0,H.jsx)(`li`,{className:`py-6 text-center text-xs text-muted-foreground`,children:a(t?`emptySettled`:`emptyLive`)}):s.map((e,t)=>{let n=Ct[e.kind],r=e.kind===`step-start`||e.kind===`step-end`||e.kind===`step-interrupted`,i=Number(e.values.files??0)>1?1:Number(e.values.repeats??1);return(0,H.jsxs)(`li`,{className:`flex items-start gap-2 text-sm ${r?`font-medium text-foreground`:`text-muted-foreground`} ${e.kind===`step-start`&&t>0?`pt-2`:``}`,children:[(0,H.jsx)(n,{className:`mt-0.5 size-3.5 shrink-0 ${wt[e.tone]}`,"aria-hidden":!0}),(0,H.jsxs)(`span`,{children:[e.kind===`step-start`&&typeof e.values.roleCode==`string`?a(e.code,{...e.values,title:a(e.values.roleCode),defaultValue:e.code}):a(e.code,{...e.values,defaultValue:e.code}),i>1?(0,H.jsx)(`span`,{className:`ml-1.5 text-[11px] opacity-70`,children:a(`repeats`,{count:i})}):null]})]},`${e.seq}-${e.code}-${t}`)})})]})}var Et=`specrails-desktop:job-log-mode`;function Dt(){try{let e=localStorage.getItem(Et);return e===`log`||e===`narrated`?e:`narrated`}catch{return`narrated`}}function Ot(e){try{localStorage.setItem(Et,e)}catch{}}function kt(e,t){switch(t.type){case`turn-user`:return{...e,streaming:!0,accepting:!0,queued:t.queued?e.queued+1:e.queued};case`turn-done`:{let n=Math.max(0,e.queued-1);return{...e,totals:t.totals,queued:n,streaming:e.queued>0}}case`finalized`:return{...e,streaming:!1,finalizing:!1,accepting:!1,queued:0,totals:t.totals??e.totals};case`accepting`:return t.accepting?{...e,accepting:!0}:{...e,accepting:!1,streaming:!1,queued:0};case`finalize-request`:return{...e,finalizing:!0};case`finalize-reject`:return{...e,finalizing:!1};case`blocked`:return{...e,accepting:!1,streaming:!1};default:return e}}function At(){try{return c()}catch{return null}}function jt({jobId:e,projectId:t,settleMode:n,initialAcceptingTurns:r,kind:i=`job`,variant:a=`page`,onFinalized:o}){let{t:c}=l(`jobs`),u=n??`finalize`,f=()=>t?`${s}/api/projects/${t}`:d(),[m,h]=(0,U.useReducer)(kt,{streaming:!1,queued:0,totals:null,accepting:r??!0,finalizing:!1}),[g,_]=(0,U.useState)(``),[v,y]=(0,U.useState)(!1),x=(0,U.useRef)(null);(0,U.useEffect)(()=>{r!==void 0&&h({type:`accepting`,accepting:r})},[r]);let S=(0,U.useRef)(o);S.current=o;let C=At(),w=(0,U.useId)();(0,U.useEffect)(()=>{if(!C)return;let t=`interactive-composer-${e}-${w}`;return C.registerHandler(t,t=>{let n=t;n.jobId===e&&(n.type===`job.turn_user`?h({type:`turn-user`,queued:!!n.queued}):n.type===`job.turn_done`?h({type:`turn-done`,totals:n.totals}):n.type===`job.finalized`?(h({type:`finalized`,totals:n.totals??null}),S.current?.()):n.type===`job.interactive`&&h({type:`accepting`,accepting:!!n.acceptingTurns}))}),()=>C.unregisterHandler(t)},[C,e,w]);let T=i===`loop-step`&&!m.accepting;async function D(){let t=g.trim();if(!(!t||v||T)){y(!0);try{let n=await fetch(`${f()}/jobs/${e}/messages`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({text:t})});if(n.ok)_(``),requestAnimationFrame(()=>x.current?.focus());else if(n.status===409&&i===`loop-step`)h({type:`blocked`});else{let e=await n.json().catch(()=>({}));p.error(c(`detail.toast.sendFailed`),{description:e.error})}}catch{p.error(c(`detail.toast.networkError`))}finally{y(!1)}}}async function O(){if(!m.finalizing){h({type:`finalize-request`});try{let t=await fetch(`${f()}/jobs/${e}/finalize`,{method:`POST`});if(t.ok)p.success(c(u===`finalize`?`detail.toast.finalizeScheduled`:i===`loop-step`?`detail.toast.wrapUpStepScheduled`:`detail.toast.wrapUpScheduled`));else if(t.status===409&&i===`loop-step`)h({type:`blocked`}),h({type:`finalize-reject`});else{let e=await t.json().catch(()=>({}));p.error(c(`detail.toast.finalizeFailed`),{description:e.error}),h({type:`finalize-reject`})}}catch{p.error(c(`detail.toast.networkError`)),h({type:`finalize-reject`})}}}let A=v||T||!g.trim(),j=c(`detail.interactive.working`);return(0,H.jsxs)(`div`,{"data-testid":`interactive-job-composer`,className:E(`shrink-0 border-t px-3 py-2 space-y-1.5`,`motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-2 motion-safe:duration-300`,a===`glass`?`border-border/30 bg-surface/30`:`border-border/40 bg-surface/40`),children:[(0,H.jsxs)(`div`,{className:`flex items-center justify-between gap-3 text-[11px] text-muted-foreground`,children:[(0,H.jsxs)(`span`,{className:`flex min-w-0 items-center gap-2`,children:[T?(0,H.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[(0,H.jsx)(de,{className:`h-3 w-3 motion-safe:animate-pulse`}),c(`detail.interactive.waitingForStepShort`)]}):m.streaming?(0,H.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[(0,H.jsx)(b,{className:`h-3 w-3 animate-spin text-accent-primary`}),(0,H.jsxs)(`span`,{className:`relative`,children:[j,(0,H.jsx)(`span`,{"aria-hidden":!0,className:`title-shimmer pointer-events-none absolute inset-0`,children:j})]})]}):(0,H.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[(0,H.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-accent-success motion-safe:animate-pulse`}),c(`detail.interactive.ready`)]}),m.queued>0&&(0,H.jsx)(`span`,{className:`rounded-full border border-accent-info/30 bg-accent-info/10 px-1.5 py-px text-[10px] tabular-nums text-accent-info motion-safe:animate-in motion-safe:fade-in`,children:c(`detail.interactive.queued`,{count:m.queued})})]}),(0,H.jsxs)(`span`,{className:`flex shrink-0 items-center gap-3`,children:[m.totals&&(0,H.jsx)(`span`,{className:`tabular-nums`,children:c(`detail.interactive.liveTotals`,{turns:m.totals.num_turns,cost:m.totals.total_cost_usd.toFixed(4)})}),u===`finalize`?(0,H.jsxs)(P,{children:[(0,H.jsx)(F,{asChild:!0,children:(0,H.jsxs)(k,{variant:`outline`,size:`sm`,onClick:()=>void O(),disabled:m.finalizing,className:`h-7 border-accent-success/40 text-accent-success hover:bg-accent-success/10`,children:[(0,H.jsx)(L,{className:`mr-1.5 h-3.5 w-3.5`}),m.finalizing?c(`detail.finalizing`):c(`detail.finalizeJob`)]})}),(0,H.jsx)(V,{children:c(`detail.finalizeJobTooltip`)})]}):(0,H.jsxs)(P,{children:[(0,H.jsx)(F,{asChild:!0,children:(0,H.jsx)(`button`,{type:`button`,onClick:()=>void O(),disabled:m.finalizing||T,className:E(`text-[11px] underline-offset-2 transition-colors`,T?`cursor-not-allowed text-muted-foreground/40`:`text-muted-foreground hover:text-accent-success hover:underline`),children:m.finalizing?c(`detail.interactive.wrappingUp`):c(i===`loop-step`?`detail.interactive.wrapUpStep`:`detail.interactive.wrapUp`)})}),(0,H.jsx)(V,{children:c(i===`loop-step`?`detail.interactive.wrapUpStepTooltip`:`detail.interactive.wrapUpTooltip`)})]})]})]}),u===`auto`&&(0,H.jsx)(`p`,{className:`text-[11px] leading-snug text-muted-foreground/60`,children:c(T?`detail.interactive.waitingForStep`:`detail.interactive.autoHint`)}),(0,H.jsxs)(`div`,{className:`flex items-end gap-2`,children:[(0,H.jsx)(`textarea`,{ref:x,value:g,onChange:e=>_(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(!e.shiftKey||e.metaKey||e.ctrlKey)&&(e.preventDefault(),D())},rows:2,placeholder:c(T?`detail.interactive.waitingForStepShort`:`detail.interactive.placeholder`),"aria-label":c(`detail.interactive.placeholder`),disabled:T,className:E(`flex-1 resize-none rounded-md border border-border/50 bg-background px-2.5 py-1.5 text-sm transition-opacity focus:outline-none focus:ring-2 focus:ring-ring`,T&&`opacity-60`)}),(0,H.jsxs)(P,{children:[(0,H.jsx)(F,{asChild:!0,children:(0,H.jsx)(`span`,{className:`shrink-0`,children:(0,H.jsxs)(k,{size:`sm`,onClick:()=>void D(),disabled:A,className:`h-9`,children:[(0,H.jsx)(re,{className:`mr-1.5 h-3.5 w-3.5`}),c(`detail.interactive.send`)]})})}),A&&!v&&(0,H.jsx)(V,{children:c(T?`detail.interactive.sendDisabledWaiting`:`detail.interactive.sendDisabledEmpty`)})]})]})]})}export{rt as a,ue as c,Tt as i,Dt as n,Oe as o,Ot as r,fe as s,jt as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-CNC7AqOf.js";var t=e({activeJob:()=>f,comparison:()=>u,default:()=>h,detail:()=>o,logViewer:()=>m,loopExplorer:()=>p,modal:()=>l,page:()=>a,recent:()=>d,statusLabel:()=>n,statusName:()=>i,statusPanel:()=>s,statusTooltip:()=>r,ticketHeader:()=>c}),n={running:`running`,completed:`completed`,done:`done`,failed:`failed`,canceled:`canceled`,queued:`queued`,zombie:`zombie`,skipped:`skipped`},r={running:`Job is actively executing`,completed:`Job completed successfully`,failed:`Job exited with a non-zero exit code`,canceled:`Job was manually canceled`,queued:`Job is waiting in the queue`,queuedToRun:`Job is waiting to run`,zombie:`Job was auto-terminated after prolonged inactivity`,skipped:`Job was skipped because a parent job in the pipeline failed`},i={running:`running`,completed:`completed`,failed:`failed`,canceled:`canceled`,zombie_terminated:`zombie`,queued:`queued`,skipped:`skipped`},a={title:`Jobs`,exportJobs:`Export Jobs`,proposalDeleted:`Proposal deleted`,proposal:{title:`Proposal`,noContent:`No proposal content yet.`,githubIssue:`GitHub Issue:`,status:{input:`Awaiting input`,exploring:`Exploring`,review:`Ready for review`,refining:`Refining`,creatingIssue:`Creating issue`,created:`Created`,cancelled:`Cancelled`,unknown:`Unknown status: {{status}}`}}},o={breadcrumbDashboard:`Dashboard`,breadcrumbJob:`Job #{{id}}`,notFound:`Job not found`,notFoundDescription:`The job ID "{{id}}" doesn't exist`,backToDashboard:`Back to Dashboard`,startedAgo:`Started {{timeAgo}}`,queuedWaiting:`Queued — waiting to start`,exportDiagnostic:`Export diagnostic`,exportDiagnosticAria:`Export diagnostic bundle`,exportDiagnosticTooltip:`Download ZIP with telemetry, logs, and summary for this job`,reExecute:`Re-execute`,reExecuteTooltip:`Spawn a new job with the same command`,cancelJob:`Cancel Job`,cancelJobTooltip:`Send SIGTERM to the running process. The job will be marked as canceled.`,cancelInteractive:`Discard`,finalizeJob:`Finalize Job`,finalizing:`Finalizing…`,finalizeJobTooltip:`End this interactive session and roll every turn's tokens and cost into the job total.`,interactive:{ready:`Ready — send a prompt`,working:`Agent working…`,placeholder:`Send a message to the running job…`,send:`Send`,liveTotals:"{{turns}} turns · ${{cost}}",autoHint:`This job follows its plan and finishes on its own — messages are optional steering.`,wrapUp:`Wrap up now`,wrapUpTooltip:`End the session now — the job completes with the work produced so far, every turn's tokens and cost rolled into the total.`,wrapUpStep:`Settle this step`,wrapUpStepTooltip:`End the current step now — the loop advances with what the step has produced so far.`,wrappingUp:`Wrapping up…`,queued_one:`{{count}} queued message`,queued_other:`{{count}} queued messages`,waitingForStep:`Between steps — the loop is deciding what runs next. You can send a message when the next AI step starts.`,waitingForStepShort:`Waiting for the next step…`,sendDisabledEmpty:`Type a message first`,sendDisabledWaiting:`No active step session right now`},toast:{jobDeleted:`Job deleted`,cancelSignalSent:`Cancel signal sent`,cancelSignalSentDescription:`Job will stop at the next safe point`,failed:`Failed`,networkError:`Network error`,exportFailed:`Export failed`,exportFailedHttp:`Export failed (HTTP {{status}})`,jobRequeued:`Job re-queued`,spawnFailed:`Failed to spawn job`,finalizeScheduled:`Finalizing interactive job…`,finalizeFailed:`Failed to finalize job`,sendFailed:`Failed to send message`,wrapUpScheduled:`Wrapping up the job…`,wrapUpStepScheduled:`Settling the step — the loop advances with what it produced`}},s={inProgress:`Job in progress`,completed:`Job completed`,failed:`Job failed`,duration:`Duration`,cost:`Cost`,turns:`Turns`,tokens:`Tokens`,filesCount_one:`{{count}} file`,filesCount_other:`{{count}} files`,pipelineTotal:`Pipeline total ({{count}} phases)`,totalCost:`Total cost`,totalTokens:`Total tokens`,filesModified:`Files modified`,zoneInProgress:`In progress`,zoneFinal:`Final summary`,zoneFinalPending:`Final summary — calculated when finished`,pendingCaption:`Calculated when finished`,pendingTooltip:`This is the provider's real figure; it appears when the job finishes.`,costTooltip:`The real cost is billed by the provider when the job closes.`,liveTooltip:`Live`,explainer:`Cost, turns and tokens are the provider's real figures and appear when the job finishes.`,notAvailable:`Not available`,steps_one:`{{count}} step`,steps_other:`{{count}} steps`,activity:{editing:`Editing {{arg}}`,writing:`Writing {{arg}}`,reading:`Reading {{arg}}`,searching:`Searching “{{arg}}”`,running:`Running: {{arg}}`,thinking:`Thinking…`,reasoning:`Reasoning…`,working:`Working…`,connecting:`Connecting to the agent…`,starting:`Starting…`},pipelinePartial:`≥ shown — {{count}} phase(s) have no recorded cost yet`,pipelinePartialTooltip:`Some phases did not report cost, so this total is a lower bound.`,pipelineCostUnavailable:`Cost telemetry is unavailable for every phase.`,pipelineUsageUnavailable:`Token telemetry is unavailable for every phase.`,pipelineUsagePartial:`≥ shown — {{count}} phase(s) have no token telemetry`,pipelineUsageTooltip:`Providers may complete phases without exposing token telemetry; only known usage is included.`},c={showMore:`+ {{count}} more`,showLess:`Show less`,deletedTicket:`#{{id}} (deleted)`,deletedTooltip:`Ticket no longer exists`},l={notFound:`Job not found`,cancelConfirmTitle:`Cancel job?`,cancelConfirmDescription:`The job will stop at the next safe point. This action cannot be undone.`,keepRunning:`Keep running`,cancelJob:`Cancel job`,stopRun:`Stop run`,stopRunConfirmTitle:`Stop this run?`,stopRunConfirmDescription:`The loop run will stop at the next step boundary. This action cannot be undone.`,toast:{cancelSignalSent:`Cancel signal sent`,cancelSignalSentDescription:`Job will stop at the next safe point`,stopSignalSent:`Stop signal sent`,stopSignalSentDescription:`The run will stop at the next step boundary`,cancelFailed:`Failed to cancel`,networkError:`Network error`}},u={title:`Job Comparison`,jobN:`Job {{n}}`,loadFailed:`Failed to load comparison: {{error}}`,duration:`Duration`,cost:`Cost`,tokensOut:`Tokens out`,tokensIn:`Tokens in`,cacheRead:`Cache read`,model:`Model`,phasesDone:`Phases done`,betterValueHint:`Green highlights indicate better value`},d={emptyTitle:`No jobs yet`,emptyDescription:`Run a command above to see your job history here`,loadFailed:`Failed to load jobs`,filterAll:`All ({{count}})`,filterStatus:`{{status}} ({{count}})`,fromDate:`From date`,toDate:`To date`,clear:`Clear`,exitCompareMode:`Exit compare mode`,compareTwoJobs:`Compare 2 jobs`,clearJobs:`Clear jobs`,selectTwoToCompare:`Select 2 jobs to compare`,selectOneMore:`Select 1 more job`,readyToCompare:`Ready — click compare`,compareAction:`Compare →`,colStatus:`Status`,colCommand:`Command`,colDuration:`Duration`,colTokens:`Tokens`,colCost:`Cost`,colStarted:`Started`,profileTooltip:`Profile: {{name}}`,pipelinePart:`Part of a pipeline`,pipelineDependsOn:`(depends on previous step)`,deleteProposal:`Delete proposal`,loadMore:`Load more ({{count}} remaining)`,priority:{critical:`critical`,high:`high`,normal:`normal`,low:`low`},clearModal:{title:`Clear Jobs`,jobsInHistory_one:`{{count}} job in history`,jobsInHistory_other:`{{count}} jobs in history`,clearAll_one:`Clear all {{count}} job`,clearAll_other:`Clear all {{count}} jobs`,orByRange:`Or clear by date range:`,fromPlaceholder:`From`,toPlaceholder:`To`,clearInRange_one:`Clear {{count}} job in range`,clearInRange_other:`Clear {{count}} jobs in range`,clearRange:`Clear range`},deleteProposalConfirm:{title:`Delete proposal?`,description:`This will permanently delete 1 proposal. This action cannot be undone.`},toast:{cleared_one:`Cleared {{count}} job`,cleared_other:`Cleared {{count}} jobs`,clearFailed:`Failed to clear jobs`,networkError:`Network error`}},f={none:`No active job`,noneHint:`Select a command below to start a job`,exitCode:`exit {{code}}`,cancelTooltip:`Send SIGTERM to the running claude process`,viewLogs:`View Logs`,toast:{cancelRequested:`Job cancellation requested`,cancelRequestedDescription:`Sending SIGTERM to the process`,cancelFailed:`Failed to cancel job`,networkError:`Network error canceling job`}},p={setup:`Setup`,iteration:`Iteration {{current}}/{{limit}}`,iterationBadge:`iter {{count}}`,follow:`Following live`,resumeFollow:`Resume follow`,expandAll:`Expand all`,collapseAll:`Collapse all`,copyStep:`Copy step`,copied:`Step copied to clipboard`,stepDetail:`Step details`,stepDetailTemplate:`Template`,stepDetailCommand:`Command`,copyCommand:`Copy`,interrupted:`Interrupted`,waiting:`Waiting for the next step…`,stepMapAria:`Loop step map`,stalled:`Stalled`,stalledIdle_one:`No provider output for {{count}} minute — the app stopped this attempt`,stalledIdle_other:`No provider output for {{count}} minutes — the app stopped this attempt`,providerLimit:`Provider limit`,providerLimitHint:`The provider answered with a usage or rate-limit notice, so the app stopped the run instead of cycling.`},m={loading:`Loading logs...`,empty:`No log output yet`,filterPlaceholder:`Filter logs...`,copySuccess:`Log copied to clipboard`,copyFailed:`Failed to copy log`,lineCount:`{{filtered}} / {{total}} lines`,jumpToBottom:`Jump to bottom`,phaseLines_one:`{{count}} line`,phaseLines_other:`{{count}} lines`,noMatchingLines:`No matching lines`,noOutput:`No output`,completed:`Completed`,turns_one:`{{count}} turn`,turns_other:`{{count}} turns`},h={statusLabel:n,statusTooltip:r,statusName:i,page:a,detail:o,statusPanel:s,ticketHeader:c,modal:l,comparison:u,recent:d,activeJob:f,loopExplorer:p,logViewer:m};export{t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e={title:`Idioma`,description:`Idioma de la UI para todo Desktop. Se aplica al instante — no hace falta reiniciar.`,selectLabel:`Idioma de la interfaz`,updateFailed:`No se pudo guardar la preferencia de idioma`},t={title:`Ajustes del proyecto`},n={saveFailed:`Error al guardar: {{message}}`},r={title:`Telemetría del pipeline`,description:`Captura el uso de tokens, la duración de las fases y la actividad de los subagentes para exportar diagnósticos. Desactivada por defecto.`,toggleLabel:`Activar telemetría del pipeline`,toggleDescription:`Cuando está activa, los datos OTEL de los jobs del pipeline se capturan en local. Usa el botón <mono>Exportar diagnóstico</mono> en cualquier tarjeta de job para descargarlos.`,enabled:`Telemetría del pipeline activada`,disabled:`Telemetría del pipeline desactivada`,saveFailed:`No se pudo guardar el ajuste de telemetría`},i={title:`Pre-prompt de rail`,description:`Instrucciones extra específicas del proyecto que se añaden a los jobs de rail implement y batch-implement, después del contexto del ticket y antes de la ejecución.`,label:`Pre-prompt`,placeholder:`Ejemplo: Prefiere cambios incrementales, mantén las migraciones retrocompatibles y añade tests para cada cambio de rail.`,helper:`Úsalo para directrices estables del proyecto que deban acompañar cada ejecución de implementación en rail.`,saveButton:`Guardar pre-prompt`,cleared:`Pre-prompt borrado`,saved:`Pre-prompt guardado`,saveFailed:`No se pudo guardar el pre-prompt`},a={title:`Pre-prompt de Freestyle`,description:`Instrucción enviada al proveedor seleccionado en Freestyle. Freestyle se salta el pipeline de OpenSpec — le entrega al proveedor este pre-prompt más el texto de la spec y le deja implementar de forma autónoma. Déjalo en blanco para usar el valor por defecto integrado.`,label:`Pre-prompt Freestyle`,placeholder:`Déjalo en blanco para usar la instrucción por defecto de Freestyle.`,helper:`El texto de la spec se añade automáticamente después de este pre-prompt. Vacío = por defecto.`,saveButton:`Guardar pre-prompt Freestyle`,resetToDefault:`Pre-prompt Freestyle restablecido al valor por defecto`,saved:`Pre-prompt Freestyle guardado`,saveFailed:`No se pudo guardar el pre-prompt Freestyle`},o={title:`Presupuesto`,description:`Define un límite de gasto diario para este proyecto. La cola se pausa automáticamente al alcanzar el límite.`,dailyLabel:`Presupuesto diario (USD)`,dailyHelper:`Déjalo en blanco para desactivarlo. El gasto se calcula sobre las últimas 24 horas.`,dailyPlaceholder:`p. ej. 5.00`,perJobLabel:`Alerta de coste por job (USD)`,perJobHelper:`Avisa cuando un único job de este proyecto supere este importe.`,perJobPlaceholder:`p. ej. 0.50`,invalidNumber:`Introduce un número positivo o déjalo en blanco para desactivar`,dailyRemoved:`Presupuesto diario eliminado`,dailySet:"Presupuesto diario fijado en ${{amount}}",perJobAlertDisabled:`Alerta de coste por job desactivada`,alertSet:"Alerta configurada para jobs de más de ${{amount}}",saveBudgetFailed:`No se pudo guardar el presupuesto`,saveThresholdFailed:`No se pudo guardar el umbral`},s={nav:{appearance:`Apariencia`,specrailsAgents:`Specrails Agents`,code:`Código`,terminal:`Terminal`,updates:`Actualizaciones`,mobile:`Móvil`,mcp:`MCP`,projects:`Proyectos`,advanced:`Avanzado`,webhooks:`Webhooks`,about:`Acerca de`,effects:`Efectos`},title:`Ajustes de Desktop`,description:`Gestiona los proyectos registrados y consulta la información de Desktop.`,registeredProjects:`Proyectos registrados`,noProjects:`Aún no hay proyectos registrados`,techUrlDescription:`URL base de la API de specrails-tech (por defecto: http://localhost:3000)`,techUrlSaved:`URL de specrails-tech guardada`,techUrlSaveFailed:`No se pudo guardar la URL`,budgetAlertsHeading:`Presupuesto y alertas`,dailyBudgetLabel:`Presupuesto diario de Desktop (USD)`,dailyBudgetHelper:`Límite global de gasto diario en todos los proyectos. Las colas se pausan automáticamente al superarlo.`,dailyBudgetPlaceholder:`p. ej. 10.00`,perJobHelper:`Avisa cuando un único job supere este importe. Déjalo en blanco para desactivarlo.`,costAlertsDisabled:`Alertas de coste desactivadas`,dailyBudgetRemoved:`Presupuesto diario de Desktop eliminado`,dailyBudgetSet:"Presupuesto diario de Desktop fijado en ${{amount}}",dailyBudgetSaveFailed:`No se pudo guardar el presupuesto diario de Desktop`,projectRemoved:`Proyecto eliminado`,projectRemoveFailed:`No se pudo eliminar el proyecto`,onboardingHeading:`Onboarding`,platformTour:`Tour de la plataforma`,platformTourDescription:`Vuelve a ver el asistente de bienvenida para repasar las funciones clave.`,replayTour:`Repetir tour`,terminalPanelHeading:`Panel de terminal`,infoHeading:`Información de Desktop`,infoPort:`Puerto`,infoProjects:`Proyectos`,infoDb:`BD de Desktop`},c={heading:`Notificaciones del sistema`,description:`Muestra notificaciones nativas de escritorio cuando los jobs se completan o fallan. Las notificaciones solo aparecen cuando la pestaña no tiene el foco.`,enableLabel:`Activar notificaciones del sistema`,notifyOn:`Notificar en:`,filterAll:`Todos (completados y fallidos)`,filterCompleted:`Solo completados`,filterFailed:`Solo fallidos`,enabledToast:`Notificaciones del sistema activadas`,disabledToast:`Notificaciones del sistema desactivadas`},l={heading:`Webhooks salientes`,description:`Notifica a herramientas externas (Slack, Zapier, CI/CD) los eventos de Desktop. Las peticiones se firman con <code>X-Specrails-Signature</code> cuando hay un secreto configurado.`,eventJobCompleted:`Job completado`,eventJobFailed:`Job fallido`,eventDailyBudgetExceeded:`Presupuesto diario superado`,statusOn:`on`,statusOff:`off`,disable:`Desactivar`,enable:`Activar`,sendTestPing:`Enviar ping de prueba`,addHeading:`Añadir webhook`,secretPlaceholder:`Secreto de firma (opcional)`,addButton:`Añadir webhook`,urlRequired:`La URL es obligatoria`,selectEvent:`Selecciona al menos un evento`,added:`Webhook añadido`,addFailed:`No se pudo añadir el webhook`,updateFailed:`No se pudo actualizar el webhook`,removed:`Webhook eliminado`,removeFailed:`No se pudo eliminar el webhook`,testPingSent:`Ping de prueba enviado`,testPingFailed:`No se pudo enviar el ping de prueba`},u={title:`Panel de terminal`,desktopDescription:`Valores por defecto de Desktop aplicados a todos los proyectos salvo que exista un override por proyecto.`,projectDescription:`Overrides por proyecto para el panel de terminal. Deja un campo sin cambios para heredar el valor por defecto de Desktop.`,fontFamily:`Familia tipográfica`,fontSize:`Tamaño de fuente ({{min}}–{{max}})`,renderMode:`Modo de renderizado`,copyOnSelect:`Copiar al seleccionar`,shellIntegration:`Integración con el shell (marcas OSC 133)`,notifyLongRunning:`Notificar comandos de larga duración`,longCommandThreshold:`Umbral de comando largo (ms)`,imageRendering:`Renderizado de imágenes inline (Sixel + iTerm2)`,browserShortcutUrl:`URL del atajo de navegador`,quickScript:`Script rápido (se pega en el terminal activo — pulsa Enter manualmente)`,reset:`Restablecer`,unsavedChanges:`Cambios sin guardar`,clearOverride:`Quitar override`,clear:`Quitar`,inheritingDefault:`Heredando el valor por defecto de Desktop`,nothingToSave:`Nada que guardar`,saved:`Ajustes del terminal guardados`},d={heading:`Sección de código`,summaryLanguage:`Idioma de los resúmenes`,monthlyBudget:`Presupuesto mensual (USD)`,budgetHelper:"Tope de gasto de `surface=file-summary` por mes natural. Las regeneraciones iniciadas por el usuario pueden sobrepasarlo."},f={taglines:{dracula:`El original — oscuro con tinte púrpura y acentos neón vivos`,"aurora-light":`Claro premium — índigo inspirado en Linear sobre blanco cálido`,"obsidian-dark":`Oscuro premium — casi negro con tinte azul y acentos eléctricos`,specrails:`Tema de marca — azul marino-índigo profundo con acentos cian saturados`,"code-rain":`Terminal de fósforo — menta suave sobre casi negro verdoso`,galaxy:`Azul de espacio profundo con una estela de hoja brillante`},heading:`Apariencia`,themeGroupLabel:`Tema`,currentlyActive:`Activo actualmente`,updateFailed:`No se pudo actualizar el tema`},p={heading:`App móvil`,description:`Controla Specrails desde la app SpecRails Companion de tu teléfono, 100 % a través de tu red local. Desactivado por defecto.`,accessOn:`Acceso móvil activado`,accessOff:`Acceso móvil desactivado`,listeningOnPort:`A la escucha en el puerto {{port}}`,notListening:`No está a la escucha`,turnOn:`Activar`,turnOff:`Desactivar`,pairWebDevice:`Emparejar companion web`,reset:`Restablecer`,resetConfirm:`¿Restablecer la identidad móvil? Todos los dispositivos emparejados se revocarán y tendrán que emparejarse de nuevo.`,identityReset:`Identidad móvil restablecida`,enableFailed:`No se pudo activar el acceso móvil: {{message}}`,disableFailed:`No se pudo desactivar el acceso móvil: {{message}}`,windowsFirewall:`El Firewall de Windows pedirá permiso para el servidor de SpecRails la primera vez que lo actives — elige «Permitir en redes privadas».`,pairedDevices:`Dispositivos emparejados`,noDevices:`Aún no hay dispositivos emparejados.`,revokeDevice:`Revocar {{name}}`},m={title:`Emparejar companion web`,description:`Abre specrails.dev/companion-app en tu teléfono y escanea este código con él.`,startFailed:`No se pudo iniciar el emparejamiento: {{error}}`,showThenScan:`Cuando tu teléfono haya escaneado esto, toca «Escanear código del teléfono» y apunta la cámara hacia tu teléfono.`,scanAnswer:`Escanear código del teléfono`,scanning:`Apunta la cámara al código de tu teléfono…`,cameraFailed:`Cámara no disponible: {{message}}`,notAnswer:`Ese QR no es una respuesta de emparejamiento.`,connecting:`Conectando…`,paired:`✓ Emparejado`,pairedToast:`Companion web emparejado`,answerRejected:`El equipo de escritorio rechazó ese código. Genera uno nuevo e inténtalo de nuevo.`,copyCode:`Copiar código`,codeCopied:`Código copiado`,cancel:`Cancelar`},h={heading:`Specrails Core`,installed:`Instalado:`,updateAvailable:`Actualización disponible: {{version}}`,upToDate:`Actualizado`,neverChecked:`Sin comprobar`,check:`Buscar actualizaciones`,checking:`Comprobando…`,update:`Actualizar a {{version}}`,downloading:`Descargando…`,materializing:`Instalando…`,affectsAll:`Afecta a todos los proyectos — sin reiniciar.`,unavailable:`Las actualizaciones del core no están disponibles en esta versión.`,toastDone:`Specrails Core actualizado a {{version}}`,toastError:`Error al actualizar el core: {{message}}`,toastUpToDate:`Specrails Core está actualizado`,toastCheckFailed:`Error al comprobar actualizaciones: {{message}}`,loadFailed:`No se pudo actualizar el estado de Core. Reintentar`,runtime:`Motor: {{version}}`,bundled:`Incluido en Desktop: {{version}}`,sources:{override:`Selección explícita`,managed:`Gestionado por Desktop`,bundled:`Incluido en Desktop`,local:`Paquete local`,global:`CLI externo`},repair:`Completar actualización {{version}}`},g={heading:`Specrails Desktop`,installed:`Instalada:`,check:`Buscar actualizaciones`,checking:`Comprobando…`,upToDate:`Tienes la última versión`,updateAvailable:`Actualización disponible: {{version}}`,autoHint:`Se comprueba automáticamente al arrancar y cada 6 horas.`,unavailable:`Las actualizaciones solo están disponibles en la app de escritorio.`,toastUpToDate:`Specrails Desktop está actualizado`,toastCheckFailed:`Error al buscar actualizaciones: {{message}}`},_={title:`{{name}} — Ajustes`,description:`Configuración del proyecto: prompts, rama base, entorno, presupuesto, telemetría y terminal.`,nav:{general:`General`,branch:`Rama base`,environment:`Entorno`,budget:`Presupuesto`,telemetry:`Telemetría`,terminal:`Terminal`}},v={title:`Rama de integración`,description:`La rama desde la que parten los rails paralelos y a la que apuntan sus PRs en borrador. Déjalo vacío para resolver automáticamente a la rama por defecto del repositorio.`,placeholder:`automático (rama por defecto)`,resolved:`Los rails parten de <mono>{{branch}}</mono>`,save:`Guardar rama`,saved:`Rama de integración guardada`,saveFailed:`No se pudo guardar la rama de integración`},y={title:`Entorno de worktrees`,description:`Elige los nombres de variables de entorno que este proyecto pasa a jobs de rail y worktrees aislados de loops. Solo se guardan nombres; los valores se leen al iniciar la ejecución, recuperándolos del login shell si faltan en el proceso de escritorio.`,label:`Variable de entorno`,placeholder:`NODE_AUTH_TOKEN`,helper:`Pulsa Enter o Añadir. Puedes pegar varios nombres separados por comas o espacios.`,add:`Añadir`,empty:`Aún no hay variables específicas para este proyecto.`,remove:`Quitar {{name}}`,save:`Guardar entorno`,saved:`Entorno de worktrees guardado`,saveFailed:`No se pudo guardar el entorno de worktrees`,invalidName:`{{name}} no es un nombre válido de variable de entorno`,noValues:`Añade solo nombres de variables, no secretos KEY=value.`},b={heading:`Specrails Agents`,description:`Personaliza los agentes del pipeline de specrails-core por proveedor de IA — modelo y esfuerzo de razonamiento. Los cambios aplican a la siguiente ejecución, sin reiniciar.`,loadFailed:`No se pudieron cargar los ajustes de agentes.`,modeDefault:`Por defecto`,modeCustom:`Personalizado`,notDetected:`No detectado`,notSignedIn:`Sin iniciar sesión`,pipeline:`Pipeline`,pipelineHint:`Modelo y esfuerzo de toda la ejecución — los subagentes los heredan salvo que los cambies abajo.`,model:`Modelo`,effort:`Esfuerzo`,defaultModel:`Por defecto ({{model}})`,defaultEffort:`Esfuerzo por defecto`,agentsTitle:`Agentes del pipeline`,agentsHint:`Modelo por agente para este proveedor.`,inheritNote:`Los subagentes de Codex heredan el modelo y esfuerzo del pipeline por diseño.`,noPerAgentNote:`Este proveedor no admite modelos por agente.`,reset:`Restaurar valores por defecto`,agentNames:{"sr-architect":`Arquitecto`,"sr-developer":`Desarrollador`,"sr-reviewer":`Revisor`}},x={heading:`Efectos`,description:`Detalles visuales de la app. Cada uno se puede desactivar aquí.`,thinkingHalo:{label:`Halo de pensamiento en el composer del agente`,description:`Mientras el agente piensa o escribe, el anillo orbitante del Constructor brilla alrededor del composer: aparece con un fundido al empezar el turno y se desvanece al terminar la respuesta.`},reducedMotion:`Respeta el ajuste de movimiento reducido del sistema: el anillo queda como un brillo estático.`,preview:`Vista previa`,previewThinking:`Pensando…`},S={language:e,page:t,errors:n,telemetry:r,prePrompt:i,freestylePrePrompt:a,budget:o,desktop:s,notifications:c,webhooks:l,terminal:u,codeSection:d,appearance:f,mobile:p,pairWeb:m,coreUpdate:h,appUpdate:g,projectDialog:_,integrationBranch:v,worktreeEnv:y,specrailsAgents:b,effects:x};export{g as appUpdate,f as appearance,o as budget,d as codeSection,h as coreUpdate,S as default,s as desktop,x as effects,n as errors,a as freestylePrePrompt,v as integrationBranch,e as language,p as mobile,c as notifications,t as page,m as pairWeb,i as prePrompt,_ as projectDialog,b as specrailsAgents,r as telemetry,u as terminal,l as webhooks,y as worktreeEnv};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-CNC7AqOf.js";var t=e({appUpdate:()=>v,appearance:()=>m,budget:()=>c,codeSection:()=>p,coreUpdate:()=>_,default:()=>w,desktop:()=>l,effects:()=>C,errors:()=>i,freestylePrePrompt:()=>s,integrationBranch:()=>b,language:()=>n,mobile:()=>h,notifications:()=>u,page:()=>r,pairWeb:()=>g,prePrompt:()=>o,projectDialog:()=>y,specrailsAgents:()=>S,telemetry:()=>a,terminal:()=>f,webhooks:()=>d,worktreeEnv:()=>x}),n={title:`Language`,description:`Desktop-wide UI language. Applies instantly — no restart needed.`,selectLabel:`Interface language`,updateFailed:`Could not save the language preference`},r={title:`Project Settings`},i={saveFailed:`Failed to save: {{message}}`},a={title:`Pipeline Telemetry`,description:`Capture token usage, phase durations, and subagent activity for diagnostic export. Off by default.`,toggleLabel:`Enable pipeline telemetry`,toggleDescription:`When on, OTEL data from pipeline jobs is captured locally. Use the <mono>Export diagnostic</mono> button on any job card to download.`,enabled:`Pipeline telemetry enabled`,disabled:`Pipeline telemetry disabled`,saveFailed:`Failed to save telemetry setting`},o={title:`Rail Pre-prompt`,description:`Extra project-specific instructions appended to implement and batch-implement rail jobs after the ticket context and before execution.`,label:`Pre-prompt`,placeholder:`Example: Prefer incremental changes, keep migrations backward compatible, and add tests for every rail change.`,helper:`Use this for stable project guidance that should accompany every rail implementation run.`,saveButton:`Save pre-prompt`,cleared:`Pre-prompt cleared`,saved:`Pre-prompt saved`,saveFailed:`Failed to save pre-prompt`},s={title:`Freestyle pre-prompt`,description:`Instruction sent to the selected provider in Freestyle. Freestyle skips the OpenSpec pipeline — it hands the provider this pre-prompt plus the spec text and lets it implement autonomously. Leave blank to use the built-in default.`,label:`Freestyle pre-prompt`,placeholder:`Leave blank to use the default Freestyle instruction.`,helper:`The spec text is appended automatically after this pre-prompt. Empty = default.`,saveButton:`Save Freestyle pre-prompt`,resetToDefault:`Freestyle pre-prompt reset to default`,saved:`Freestyle pre-prompt saved`,saveFailed:`Failed to save Freestyle pre-prompt`},c={title:`Budget`,description:`Set a daily spend cap for this project. The queue auto-pauses when the limit is hit.`,dailyLabel:`Daily budget (USD)`,dailyHelper:`Leave blank to disable. Spend is calculated over the last 24 hours.`,dailyPlaceholder:`e.g. 5.00`,perJobLabel:`Per-job cost alert (USD)`,perJobHelper:`Alert when a single job in this project exceeds this amount.`,perJobPlaceholder:`e.g. 0.50`,invalidNumber:`Enter a positive number or leave blank to disable`,dailyRemoved:`Daily budget removed`,dailySet:"Daily budget set to ${{amount}}",perJobAlertDisabled:`Per-job cost alert disabled`,alertSet:"Alert set for jobs over ${{amount}}",saveBudgetFailed:`Failed to save budget`,saveThresholdFailed:`Failed to save threshold`},l={nav:{appearance:`Appearance`,specrailsAgents:`Specrails Agents`,code:`Code`,terminal:`Terminal`,updates:`Updates`,mobile:`Mobile`,mcp:`MCP`,projects:`Projects`,advanced:`Advanced`,webhooks:`Webhooks`,about:`About`,effects:`Effects`},title:`Desktop Settings`,description:`Manage registered projects and view Desktop information.`,registeredProjects:`Registered Projects`,noProjects:`No projects registered yet`,techUrlDescription:`Base URL for the specrails-tech API (default: http://localhost:3000)`,techUrlSaved:`specrails-tech URL saved`,techUrlSaveFailed:`Failed to save URL`,budgetAlertsHeading:`Budget & Alerts`,dailyBudgetLabel:`Desktop daily budget (USD)`,dailyBudgetHelper:`Global daily spend limit across all projects. Queues auto-pause when exceeded.`,dailyBudgetPlaceholder:`e.g. 10.00`,perJobHelper:`Alert when a single job exceeds this amount. Leave blank to disable.`,costAlertsDisabled:`Cost alerts disabled`,dailyBudgetRemoved:`Desktop daily budget removed`,dailyBudgetSet:"Desktop daily budget set to ${{amount}}",dailyBudgetSaveFailed:`Failed to save Desktop daily budget`,projectRemoved:`Project removed`,projectRemoveFailed:`Failed to remove project`,onboardingHeading:`Onboarding`,platformTour:`Platform Tour`,platformTourDescription:`Replay the welcome wizard to review key features.`,replayTour:`Replay Tour`,terminalPanelHeading:`Terminal Panel`,infoHeading:`Desktop Information`,infoPort:`Port`,infoProjects:`Projects`,infoDb:`Desktop DB`},u={heading:`OS Notifications`,description:`Show native desktop notifications when jobs complete or fail. Notifications only appear when the tab is not focused.`,enableLabel:`Enable OS Notifications`,notifyOn:`Notify on:`,filterAll:`All (completed & failed)`,filterCompleted:`Completed only`,filterFailed:`Failed only`,enabledToast:`OS notifications enabled`,disabledToast:`OS notifications disabled`},d={heading:`Outbound Webhooks`,description:`Notify external tools (Slack, Zapier, CI/CD) on Desktop events. Requests are signed via <code>X-Specrails-Signature</code> when a secret is set.`,eventJobCompleted:`Job completed`,eventJobFailed:`Job failed`,eventDailyBudgetExceeded:`Daily budget exceeded`,statusOn:`on`,statusOff:`off`,disable:`Disable`,enable:`Enable`,sendTestPing:`Send test ping`,addHeading:`Add webhook`,secretPlaceholder:`Signing secret (optional)`,addButton:`Add Webhook`,urlRequired:`URL is required`,selectEvent:`Select at least one event`,added:`Webhook added`,addFailed:`Failed to add webhook`,updateFailed:`Failed to update webhook`,removed:`Webhook removed`,removeFailed:`Failed to remove webhook`,testPingSent:`Test ping sent`,testPingFailed:`Failed to send test ping`},f={title:`Terminal panel`,desktopDescription:`Desktop-wide defaults applied to every project unless a per-project override is set.`,projectDescription:`Per-project overrides for the terminal panel. Leave a field unchanged to inherit the Desktop default.`,fontFamily:`Font family`,fontSize:`Font size ({{min}}–{{max}})`,renderMode:`Render mode`,copyOnSelect:`Copy on select`,shellIntegration:`Shell integration (OSC 133 marks)`,notifyLongRunning:`Notify on long-running commands`,longCommandThreshold:`Long-command threshold (ms)`,imageRendering:`Inline image rendering (Sixel + iTerm2)`,browserShortcutUrl:`Browser shortcut URL`,quickScript:`Quick script (pasted into active terminal — Enter manually)`,reset:`Reset`,unsavedChanges:`Unsaved changes`,clearOverride:`Clear override`,clear:`Clear`,inheritingDefault:`Inheriting Desktop default`,nothingToSave:`Nothing to save`,saved:`Terminal settings saved`},p={heading:`Code section`,summaryLanguage:`Summary language`,monthlyBudget:`Monthly budget (USD)`,budgetHelper:"Cap on `surface=file-summary` spend per calendar month. User-initiated regenerations can override."},m={taglines:{dracula:`The original — dark purple-tinted with vivid neon accents`,"aurora-light":`Premium light — Linear-inspired indigo on warm off-white`,"obsidian-dark":`Premium dark — near-black blue-tinted with electric accents`,specrails:`Brand theme — deep navy-indigo with saturated cyan accents`,"code-rain":`Phosphor terminal — soft mint on green-tinted near-black`,galaxy:`Deep-space blue with a glowing blade trail`},heading:`Appearance`,themeGroupLabel:`Theme`,currentlyActive:`Currently active`,updateFailed:`Failed to update theme`},h={heading:`Mobile companion`,description:`Control Specrails from the SpecRails Companion app on your phone, 100% over your local network. Off by default.`,accessOn:`Mobile access on`,accessOff:`Mobile access off`,listeningOnPort:`Listening on port {{port}}`,notListening:`Not listening`,turnOn:`Turn on`,turnOff:`Turn off`,pairWebDevice:`Pair web companion`,reset:`Reset`,resetConfirm:`Reset the mobile identity? Every paired device will be revoked and must pair again.`,identityReset:`Mobile identity reset`,enableFailed:`Could not enable mobile access: {{message}}`,disableFailed:`Could not disable mobile access: {{message}}`,windowsFirewall:`Windows Firewall will ask to allow the SpecRails server on first enable — choose “Allow on private networks”.`,pairedDevices:`Paired devices`,noDevices:`No devices paired yet.`,revokeDevice:`Revoke {{name}}`},g={title:`Pair web companion`,description:`Open specrails.dev/companion-app on your phone, then scan this code with it.`,startFailed:`Could not start pairing: {{error}}`,showThenScan:`After your phone scans this, tap “Scan phone's code” and point the camera at your phone.`,scanAnswer:`Scan phone's code`,scanning:`Point the camera at the code on your phone…`,cameraFailed:`Camera unavailable: {{message}}`,notAnswer:`That QR isn't a pairing answer.`,connecting:`Connecting…`,paired:`✓ Paired`,pairedToast:`Web companion paired`,answerRejected:`The desktop rejected that code. Generate a fresh one and retry.`,copyCode:`Copy code`,codeCopied:`Code copied`,cancel:`Cancel`},_={heading:`Specrails Core`,installed:`Installed:`,updateAvailable:`Update available: {{version}}`,upToDate:`Up to date`,neverChecked:`Not checked yet`,check:`Check for updates`,checking:`Checking…`,update:`Update to {{version}}`,downloading:`Downloading…`,materializing:`Installing…`,affectsAll:`Applies to all projects — no restart needed.`,unavailable:`Core updates aren't available in this build.`,toastDone:`Specrails Core updated to {{version}}`,toastError:`Core update failed: {{message}}`,toastUpToDate:`Specrails Core is up to date`,toastCheckFailed:`Update check failed: {{message}}`,loadFailed:`Could not refresh Core status. Retry`,runtime:`Runtime: {{version}}`,bundled:`Included in Desktop: {{version}}`,sources:{override:`Explicit override`,managed:`Managed by Desktop`,bundled:`Included in Desktop`,local:`Local package`,global:`External CLI`},repair:`Finish updating {{version}}`},v={heading:`Specrails Desktop`,installed:`Installed:`,check:`Check for updates`,checking:`Checking…`,upToDate:`You're on the latest version`,updateAvailable:`Update available: {{version}}`,autoHint:`Checks automatically at launch and every 6 hours.`,unavailable:`App updates are only available in the desktop app.`,toastUpToDate:`Specrails Desktop is up to date`,toastCheckFailed:`Update check failed: {{message}}`},y={title:`{{name}} — Settings`,description:`Project-level configuration: prompts, branch, environment, budget, telemetry and terminal.`,nav:{general:`General`,branch:`Branch`,environment:`Environment`,budget:`Budget`,telemetry:`Telemetry`,terminal:`Terminal`}},b={title:`Integration branch`,description:`The branch parallel rails branch from and target their draft PRs at. Leave empty to auto-resolve to the repository's default branch.`,placeholder:`auto (repository default)`,resolved:`Rails branch off <mono>{{branch}}</mono>`,save:`Save branch`,saved:`Integration branch saved`,saveFailed:`Could not save the integration branch`},x={title:`Worktree environment`,description:`Choose environment variable names this project passes to rail jobs and isolated loop worktrees. Only names are saved; values are read when a run starts, with login-shell recovery when the desktop process is missing them.`,label:`Environment variable`,placeholder:`NODE_AUTH_TOKEN`,helper:`Press Enter or Add. You can paste several names separated by commas or spaces.`,add:`Add`,empty:`No project-specific variables configured yet.`,remove:`Remove {{name}}`,save:`Save environment`,saved:`Worktree environment saved`,saveFailed:`Could not save the worktree environment`,invalidName:`{{name}} is not a valid environment variable name`,noValues:`Add only variable names here, not KEY=value secrets.`},S={heading:`Specrails Agents`,description:`Customize the specrails-core pipeline agents per AI provider — model and reasoning effort. Changes apply to the next run, no restart needed.`,loadFailed:`Could not load the agent defaults.`,modeDefault:`Default`,modeCustom:`Custom`,notDetected:`Not detected`,notSignedIn:`Not signed in`,pipeline:`Pipeline`,pipelineHint:`Model and effort for the whole run — sub-agents inherit them unless overridden below.`,model:`Model`,effort:`Effort`,defaultModel:`Default ({{model}})`,defaultEffort:`Default effort`,agentsTitle:`Pipeline agents`,agentsHint:`Per-agent model override for this provider.`,inheritNote:`Codex sub-agents inherit the pipeline model and effort by design.`,noPerAgentNote:`This provider does not support per-agent model overrides.`,reset:`Restore defaults`,agentNames:{"sr-architect":`Architect`,"sr-developer":`Developer`,"sr-reviewer":`Reviewer`}},C={heading:`Effects`,description:`Visual flourishes across the app. Each one can be switched off here.`,thinkingHalo:{label:`Thinking halo on the agent composer`,description:`While the agent is thinking or writing, the Builder's orbiting ring glows around the composer — it fades in when a turn starts and fades out when the reply settles.`},reducedMotion:`Follows your system's reduced-motion setting: the ring stays as a static glow.`,preview:`Preview`,previewThinking:`Thinking…`},w={language:n,page:r,errors:i,telemetry:a,prePrompt:o,freestylePrePrompt:s,budget:c,desktop:l,notifications:u,webhooks:d,terminal:f,codeSection:p,appearance:m,mobile:h,pairWeb:g,coreUpdate:_,appUpdate:v,projectDialog:y,integrationBranch:b,worktreeEnv:x,specrailsAgents:S,effects:C};export{t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e={title:`Sprache`,description:`Desktop-weite UI-Sprache. Wird sofort angewendet – kein Neustart nötig.`,selectLabel:`Oberflächensprache`,updateFailed:`Spracheinstellung konnte nicht gespeichert werden`},t={title:`Projekteinstellungen`},n={saveFailed:`Speichern fehlgeschlagen: {{message}}`},r={title:`Pipeline-Telemetrie`,description:`Erfasst Token-Verbrauch, Phasendauern und Subagent-Aktivität für den Diagnose-Export. Standardmäßig aus.`,toggleLabel:`Pipeline-Telemetrie aktivieren`,toggleDescription:`Wenn aktiviert, werden OTEL-Daten aus Pipeline-Jobs lokal erfasst. Verwenden Sie zum Herunterladen die Schaltfläche <mono>Diagnose exportieren</mono> auf einer beliebigen Job-Karte.`,enabled:`Pipeline-Telemetrie aktiviert`,disabled:`Pipeline-Telemetrie deaktiviert`,saveFailed:`Telemetrie-Einstellung konnte nicht gespeichert werden`},i={title:`Rail-Pre-Prompt`,description:`Zusätzliche projektspezifische Anweisungen, die an implement- und batch-implement-Rail-Jobs angehängt werden – nach dem Ticket-Kontext und vor der Ausführung.`,label:`Pre-Prompt`,placeholder:`Beispiel: Bevorzuge inkrementelle Änderungen, halte Migrationen abwärtskompatibel und füge Tests für jede Rail-Änderung hinzu.`,helper:`Für stabile Projektleitlinien, die jeden Rail-Implementierungslauf begleiten sollen.`,saveButton:`Pre-Prompt speichern`,cleared:`Pre-Prompt gelöscht`,saved:`Pre-Prompt gespeichert`,saveFailed:`Pre-Prompt konnte nicht gespeichert werden`},a={title:`Freestyle-Pre-Prompt`,description:`Anweisung, die in Freestyle an den ausgewählten Anbieter gesendet wird. Freestyle überspringt die OpenSpec-Pipeline – der Anbieter erhält diesen Pre-Prompt plus den Spec-Text und implementiert autonom. Leer lassen, um den eingebauten Standard zu verwenden.`,label:`Freestyle-Pre-Prompt`,placeholder:`Leer lassen, um die Standard-Freestyle-Anweisung zu verwenden.`,helper:`Der Spec-Text wird automatisch nach diesem Pre-Prompt angehängt. Leer = Standard.`,saveButton:`Freestyle-Pre-Prompt speichern`,resetToDefault:`Freestyle-Pre-Prompt auf Standard zurückgesetzt`,saved:`Freestyle-Pre-Prompt gespeichert`,saveFailed:`Freestyle-Pre-Prompt konnte nicht gespeichert werden`},o={title:`Budget`,description:`Tagesausgabenlimit für dieses Projekt festlegen. Die Queue pausiert automatisch, wenn das Limit erreicht ist.`,dailyLabel:`Tagesbudget (USD)`,dailyHelper:`Leer lassen zum Deaktivieren. Ausgaben werden über die letzten 24 Stunden berechnet.`,dailyPlaceholder:`z. B. 5.00`,perJobLabel:`Kostenalarm pro Job (USD)`,perJobHelper:`Alarm, wenn ein einzelner Job in diesem Projekt diesen Betrag überschreitet.`,perJobPlaceholder:`z. B. 0.50`,invalidNumber:`Positive Zahl eingeben oder leer lassen zum Deaktivieren`,dailyRemoved:`Tagesbudget entfernt`,dailySet:"Tagesbudget auf ${{amount}} gesetzt",perJobAlertDisabled:`Kostenalarm pro Job deaktiviert`,alertSet:"Alarm für Jobs über ${{amount}} gesetzt",saveBudgetFailed:`Budget konnte nicht gespeichert werden`,saveThresholdFailed:`Schwellenwert konnte nicht gespeichert werden`},s={nav:{appearance:`Darstellung`,specrailsAgents:`Specrails Agents`,code:`Code`,terminal:`Terminal`,updates:`Updates`,mobile:`Mobil`,mcp:`MCP`,projects:`Projekte`,advanced:`Erweitert`,webhooks:`Webhooks`,about:`Info`,effects:`Effekte`},title:`Desktop-Einstellungen`,description:`Registrierte Projekte verwalten und Desktop-Informationen einsehen.`,registeredProjects:`Registrierte Projekte`,noProjects:`Noch keine Projekte registriert`,techUrlDescription:`Basis-URL für die specrails-tech-API (Standard: http://localhost:3000)`,techUrlSaved:`specrails-tech-URL gespeichert`,techUrlSaveFailed:`URL konnte nicht gespeichert werden`,budgetAlertsHeading:`Budget & Alarme`,dailyBudgetLabel:`Desktop-Tagesbudget (USD)`,dailyBudgetHelper:`Globales Tagesausgabenlimit über alle Projekte. Queues pausieren automatisch bei Überschreitung.`,dailyBudgetPlaceholder:`z. B. 10.00`,perJobHelper:`Alarm, wenn ein einzelner Job diesen Betrag überschreitet. Leer lassen zum Deaktivieren.`,costAlertsDisabled:`Kostenalarme deaktiviert`,dailyBudgetRemoved:`Desktop-Tagesbudget entfernt`,dailyBudgetSet:"Desktop-Tagesbudget auf ${{amount}} gesetzt",dailyBudgetSaveFailed:`Desktop-Tagesbudget konnte nicht gespeichert werden`,projectRemoved:`Projekt entfernt`,projectRemoveFailed:`Projekt konnte nicht entfernt werden`,onboardingHeading:`Onboarding`,platformTour:`Plattform-Tour`,platformTourDescription:`Den Willkommensassistenten erneut abspielen, um die wichtigsten Funktionen zu sehen.`,replayTour:`Tour erneut abspielen`,terminalPanelHeading:`Terminal-Panel`,infoHeading:`Desktop-Informationen`,infoPort:`Port`,infoProjects:`Projekte`,infoDb:`Desktop-DB`},c={heading:`OS-Benachrichtigungen`,description:`Native Desktop-Benachrichtigungen anzeigen, wenn Jobs abgeschlossen werden oder fehlschlagen. Benachrichtigungen erscheinen nur, wenn der Tab nicht fokussiert ist.`,enableLabel:`OS-Benachrichtigungen aktivieren`,notifyOn:`Benachrichtigen bei:`,filterAll:`Alle (abgeschlossen & fehlgeschlagen)`,filterCompleted:`Nur abgeschlossen`,filterFailed:`Nur fehlgeschlagen`,enabledToast:`OS-Benachrichtigungen aktiviert`,disabledToast:`OS-Benachrichtigungen deaktiviert`},l={heading:`Ausgehende Webhooks`,description:`Externe Tools (Slack, Zapier, CI/CD) bei Desktop-Ereignissen benachrichtigen. Anfragen werden über <code>X-Specrails-Signature</code> signiert, wenn ein Secret gesetzt ist.`,eventJobCompleted:`Job abgeschlossen`,eventJobFailed:`Job fehlgeschlagen`,eventDailyBudgetExceeded:`Tagesbudget überschritten`,statusOn:`an`,statusOff:`aus`,disable:`Deaktivieren`,enable:`Aktivieren`,sendTestPing:`Test-Ping senden`,addHeading:`Webhook hinzufügen`,secretPlaceholder:`Signatur-Secret (optional)`,addButton:`Webhook hinzufügen`,urlRequired:`URL ist erforderlich`,selectEvent:`Mindestens ein Ereignis auswählen`,added:`Webhook hinzugefügt`,addFailed:`Webhook konnte nicht hinzugefügt werden`,updateFailed:`Webhook konnte nicht aktualisiert werden`,removed:`Webhook entfernt`,removeFailed:`Webhook konnte nicht entfernt werden`,testPingSent:`Test-Ping gesendet`,testPingFailed:`Test-Ping konnte nicht gesendet werden`},u={title:`Terminal-Panel`,desktopDescription:`Desktop-weite Standardwerte für alle Projekte, sofern kein projektspezifischer Override gesetzt ist.`,projectDescription:`Projektspezifische Overrides für das Terminal-Panel. Lassen Sie ein Feld unverändert, um den Desktop-Standard zu erben.`,fontFamily:`Schriftfamilie`,fontSize:`Schriftgröße ({{min}}–{{max}})`,renderMode:`Render-Modus`,copyOnSelect:`Beim Auswählen kopieren`,shellIntegration:`Shell-Integration (OSC-133-Marken)`,notifyLongRunning:`Bei lang laufenden Befehlen benachrichtigen`,longCommandThreshold:`Schwellenwert für lange Befehle (ms)`,imageRendering:`Inline-Bilddarstellung (Sixel + iTerm2)`,browserShortcutUrl:`Browser-Shortcut-URL`,quickScript:`Quick-Skript (wird ins aktive Terminal eingefügt – Enter manuell drücken)`,reset:`Zurücksetzen`,unsavedChanges:`Ungespeicherte Änderungen`,clearOverride:`Override entfernen`,clear:`Entfernen`,inheritingDefault:`Erbt Desktop-Standard`,nothingToSave:`Nichts zu speichern`,saved:`Terminal-Einstellungen gespeichert`},d={heading:`Code-Bereich`,summaryLanguage:`Sprache der Zusammenfassungen`,monthlyBudget:`Monatsbudget (USD)`,budgetHelper:"Obergrenze für `surface=file-summary`-Ausgaben pro Kalendermonat. Von Nutzern angestoßene Neugenerierungen können sie überschreiten."},f={taglines:{dracula:`Das Original — dunkel mit Violettstich und lebhaften Neon-Akzenten`,"aurora-light":`Premium hell — Linear-inspiriertes Indigo auf warmem Cremeweiß`,"obsidian-dark":`Premium dunkel — fast schwarz mit Blaustich und elektrischen Akzenten`,specrails:`Marken-Theme — tiefes Marine-Indigo mit satten Cyan-Akzenten`,"code-rain":`Phosphor-Terminal — sanftes Mint auf grünlichem Fast-Schwarz`,galaxy:`Tiefraum-Blau mit einer leuchtenden Klingenspur`},heading:`Erscheinungsbild`,themeGroupLabel:`Theme`,currentlyActive:`Derzeit aktiv`,updateFailed:`Theme konnte nicht aktualisiert werden`},p={heading:`Mobile Companion`,description:`Steuern Sie Specrails über die SpecRails Companion-App auf Ihrem Smartphone – zu 100 % über Ihr lokales Netzwerk. Standardmäßig aus.`,accessOn:`Mobilzugriff an`,accessOff:`Mobilzugriff aus`,listeningOnPort:`Lauscht auf Port {{port}}`,notListening:`Lauscht nicht`,turnOn:`Einschalten`,turnOff:`Ausschalten`,pairWebDevice:`Web-Companion koppeln`,reset:`Zurücksetzen`,resetConfirm:`Mobile Identität zurücksetzen? Alle gekoppelten Geräte werden widerrufen und müssen neu gekoppelt werden.`,identityReset:`Mobile Identität zurückgesetzt`,enableFailed:`Mobilzugriff konnte nicht aktiviert werden: {{message}}`,disableFailed:`Mobilzugriff konnte nicht deaktiviert werden: {{message}}`,windowsFirewall:`Die Windows-Firewall fragt beim ersten Aktivieren, ob der SpecRails-Server zugelassen werden soll – wählen Sie „In privaten Netzwerken zulassen“.`,pairedDevices:`Gekoppelte Geräte`,noDevices:`Noch keine Geräte gekoppelt.`,revokeDevice:`{{name}} widerrufen`},m={title:`Web-Companion koppeln`,description:`Öffnen Sie specrails.dev/companion-app auf Ihrem Smartphone und scannen Sie damit diesen Code.`,startFailed:`Koppeln konnte nicht gestartet werden: {{error}}`,showThenScan:`Nachdem Ihr Smartphone dies gescannt hat, tippen Sie auf „Code des Smartphones scannen“ und richten Sie die Kamera auf Ihr Smartphone.`,scanAnswer:`Code des Smartphones scannen`,scanning:`Richten Sie die Kamera auf den Code auf Ihrem Smartphone…`,cameraFailed:`Kamera nicht verfügbar: {{message}}`,notAnswer:`Dieser QR-Code ist keine Kopplungsantwort.`,connecting:`Verbinden…`,paired:`✓ Gekoppelt`,pairedToast:`Web-Companion gekoppelt`,answerRejected:`Der Desktop hat diesen Code abgelehnt. Erzeugen Sie einen neuen und versuchen Sie es erneut.`,copyCode:`Code kopieren`,codeCopied:`Code kopiert`,cancel:`Abbrechen`},h={heading:`Specrails Core`,installed:`Installiert:`,updateAvailable:`Update verfügbar: {{version}}`,upToDate:`Aktuell`,neverChecked:`Nicht geprüft`,check:`Nach Updates suchen`,checking:`Wird geprüft…`,update:`Auf {{version}} aktualisieren`,downloading:`Wird heruntergeladen…`,materializing:`Wird installiert…`,affectsAll:`Gilt für alle Projekte — kein Neustart nötig.`,unavailable:`Core-Updates sind in diesem Build nicht verfügbar.`,toastDone:`Specrails Core auf {{version}} aktualisiert`,toastError:`Core-Update fehlgeschlagen: {{message}}`,toastUpToDate:`Specrails Core ist aktuell`,toastCheckFailed:`Update-Prüfung fehlgeschlagen: {{message}}`,loadFailed:`Core-Status konnte nicht geladen werden. Erneut versuchen`,runtime:`Laufzeit: {{version}}`,bundled:`In Desktop enthalten: {{version}}`,sources:{override:`Explizite Auswahl`,managed:`Von Desktop verwaltet`,bundled:`In Desktop enthalten`,local:`Lokales Paket`,global:`Externe CLI`},repair:`Update auf {{version}} abschließen`},g={heading:`Specrails Desktop`,installed:`Installiert:`,check:`Nach Updates suchen`,checking:`Wird geprüft…`,upToDate:`Du hast die neueste Version`,updateAvailable:`Update verfügbar: {{version}}`,autoHint:`Wird beim Start und alle 6 Stunden automatisch geprüft.`,unavailable:`App-Updates sind nur in der Desktop-App verfügbar.`,toastUpToDate:`Specrails Desktop ist aktuell`,toastCheckFailed:`Update-Prüfung fehlgeschlagen: {{message}}`},_={title:`{{name}} — Einstellungen`,description:`Projektkonfiguration: Prompts, Branch, Umgebung, Budget, Telemetrie und Terminal.`,nav:{general:`Allgemein`,branch:`Branch`,environment:`Umgebung`,budget:`Budget`,telemetry:`Telemetrie`,terminal:`Terminal`}},v={title:`Integrationszweig`,description:`Der Branch, von dem parallele Rails abzweigen und auf den ihre Entwurfs-PRs zielen. Leer lassen, um automatisch den Standard-Branch des Repositorys zu verwenden.`,placeholder:`automatisch (Standard-Branch)`,resolved:`Rails zweigen von <mono>{{branch}}</mono> ab`,save:`Branch speichern`,saved:`Integrationszweig gespeichert`,saveFailed:`Integrationszweig konnte nicht gespeichert werden`},y={title:`Worktree-Umgebung`,description:`Wählen Sie die Namen der Umgebungsvariablen, die dieses Projekt an Rail-Jobs und isolierte Loop-Worktrees weitergibt. Gespeichert werden nur Namen; Werte werden beim Start gelesen und bei Bedarf aus der Login-Shell nachgeladen.`,label:`Umgebungsvariable`,placeholder:`NODE_AUTH_TOKEN`,helper:`Drücken Sie Enter oder Hinzufügen. Mehrere Namen können durch Kommas oder Leerzeichen getrennt eingefügt werden.`,add:`Hinzufügen`,empty:`Für dieses Projekt sind noch keine eigenen Variablen konfiguriert.`,remove:`{{name}} entfernen`,save:`Umgebung speichern`,saved:`Worktree-Umgebung gespeichert`,saveFailed:`Worktree-Umgebung konnte nicht gespeichert werden`,invalidName:`{{name}} ist kein gültiger Name für eine Umgebungsvariable`,noValues:`Fügen Sie hier nur Variablennamen hinzu, keine KEY=value-Geheimnisse.`},b={heading:`Specrails Agents`,description:`Passe die specrails-core-Pipeline-Agenten pro KI-Anbieter an — Modell und Reasoning-Aufwand. Änderungen gelten ab dem nächsten Lauf, ohne Neustart.`,loadFailed:`Agent-Einstellungen konnten nicht geladen werden.`,modeDefault:`Standard`,modeCustom:`Angepasst`,notDetected:`Nicht erkannt`,notSignedIn:`Nicht angemeldet`,pipeline:`Pipeline`,pipelineHint:`Modell und Aufwand für den gesamten Lauf — Subagenten erben sie, sofern unten nichts anderes gesetzt ist.`,model:`Modell`,effort:`Aufwand`,defaultModel:`Standard ({{model}})`,defaultEffort:`Standard-Aufwand`,agentsTitle:`Pipeline-Agenten`,agentsHint:`Modell-Override pro Agent für diesen Anbieter.`,inheritNote:`Codex-Subagenten erben Modell und Aufwand der Pipeline — by design.`,noPerAgentNote:`Dieser Anbieter unterstützt keine Modelle pro Agent.`,reset:`Standardwerte wiederherstellen`,agentNames:{"sr-architect":`Architekt`,"sr-developer":`Entwickler`,"sr-reviewer":`Reviewer`}},x={heading:`Effekte`,description:`Visuelle Akzente in der App. Jeder lässt sich hier abschalten.`,thinkingHalo:{label:`Denk-Halo am Agent-Composer`,description:`Während der Agent nachdenkt oder schreibt, leuchtet der kreisende Ring des Builders um den Composer: er blendet beim Start eines Turns ein und beim Abschluss der Antwort aus.`},reducedMotion:`Folgt der Systemeinstellung für reduzierte Bewegung: der Ring bleibt ein statisches Leuchten.`,preview:`Vorschau`,previewThinking:`Denkt nach…`},S={language:e,page:t,errors:n,telemetry:r,prePrompt:i,freestylePrePrompt:a,budget:o,desktop:s,notifications:c,webhooks:l,terminal:u,codeSection:d,appearance:f,mobile:p,pairWeb:m,coreUpdate:h,appUpdate:g,projectDialog:_,integrationBranch:v,worktreeEnv:y,specrailsAgents:b,effects:x};export{g as appUpdate,f as appearance,o as budget,d as codeSection,h as coreUpdate,S as default,s as desktop,x as effects,n as errors,a as freestylePrePrompt,v as integrationBranch,e as language,p as mobile,c as notifications,t as page,m as pairWeb,i as prePrompt,_ as projectDialog,b as specrailsAgents,r as telemetry,u as terminal,l as webhooks,y as worktreeEnv};
|