specrails-desktop 2.44.2 → 2.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/client/dist/assets/{ActivityFeedPage-CL1BUXoj.js → ActivityFeedPage-CsHQPpvl.js} +1 -1
- package/client/dist/assets/AgentBrowserCapture-BVcCK7x0.js +1 -0
- package/client/dist/assets/AgentModeAnalyticsPane-C5F3m29G.js +2 -0
- package/client/dist/assets/AgentModeCodePane-C5QuKsu0.js +2 -0
- package/client/dist/assets/AgentModeJobsPane-rnD-EPMd.js +1 -0
- package/client/dist/assets/{AgentsPage-DbLezyI6.js → AgentsPage-DiyJWZcU.js} +3 -3
- package/client/dist/assets/{AnalyticsPage-DTsg-N5z.js → AnalyticsPage-Dkmb0dnd.js} +1 -1
- package/client/dist/assets/CodePage-C0dH99-t.js +3 -0
- package/client/dist/assets/{DesktopAnalyticsPage-Y0Z1ryQr.js → DesktopAnalyticsPage-DuTjr2n8.js} +1 -1
- package/client/dist/assets/{DocsDialog-KeCOxvGH.js → DocsDialog-BVZJZHVR.js} +1 -1
- package/client/dist/assets/{DocsPage-Bt1PgYPO.js → DocsPage-D6KHTv8V.js} +1 -1
- package/client/dist/assets/{ExportDropdown-DczgU4at.js → ExportDropdown-pWZGYCv3.js} +1 -1
- package/client/dist/assets/InteractiveJobComposer-Ck3PQxjN.js +19 -0
- package/client/dist/assets/JobDetailModal-DkoMH3ie.js +1 -0
- package/client/dist/assets/JobDetailPage-CBVivcl2.js +1 -0
- package/client/dist/assets/JobsPage-CzxEeca9.js +1 -0
- package/client/dist/assets/{LoopBuilderPage-CqC4hbXb.js → LoopBuilderPage-CtmOE4-b.js} +2 -2
- package/client/dist/assets/{LoopPreviewModal-T0zuFv6y.js → LoopPreviewModal-BYeLjQbr.js} +1 -1
- package/client/dist/assets/{LoopsPage-DrQGcZv2.js → LoopsPage-6iW7g25k.js} +1 -1
- package/client/dist/assets/{MinimizedChatsContext-C843Y13h.js → MinimizedChatsContext-B6wVevPq.js} +1 -1
- package/client/dist/assets/PluginsPage-Bf1z3WPF.js +2 -0
- package/client/dist/assets/ProjectSettingsDialog-DsCRIc4v.js +1 -0
- package/client/dist/assets/{RepositoryDeliveries-bgIHE8ep.js → RepositoryDeliveries-BQm_3TO8.js} +1 -1
- package/client/dist/assets/{RepositoryScopeSelector-CZ_U_R3U.js → RepositoryScopeSelector-DnAFtjTz.js} +1 -1
- package/client/dist/assets/{ReviewPacketPage-DbKO6pT8.js → ReviewPacketPage-CaXAwtR7.js} +1 -1
- package/client/dist/assets/TemplatePreviewModal-9aRFpJ_J.js +1 -0
- package/client/dist/assets/{TicketDetailModalContext-BbRA6cb7.js → TicketDetailModalContext-B1X5glzV.js} +1 -1
- package/client/dist/assets/{Trans-mjFZpHw1.js → Trans-BwLgX6n7.js} +1 -1
- package/client/dist/assets/agentRuntime-BUagD2I_.js +1 -0
- package/client/dist/assets/agentRuntime-BkL70WtX.js +1 -0
- package/client/dist/assets/agentRuntime-CWXVqgqE.js +1 -0
- package/client/dist/assets/agentRuntime-CvNBdUAe.js +1 -0
- package/client/dist/assets/agentRuntime-D4RmeuNY.js +1 -0
- package/client/dist/assets/agentRuntime-DTidBWKg.js +1 -0
- package/client/dist/assets/agentRuntime-DhKYfyaU.js +1 -0
- package/client/dist/assets/agentRuntime-LL8_GLx9.js +1 -0
- package/client/dist/assets/format-duration-NJVPOPBG.js +1 -0
- package/client/dist/assets/{formatDistanceToNow-BIL-HxGy.js → formatDistanceToNow-CeZv93iR.js} +1 -1
- package/client/dist/assets/{getTimezoneOffsetInMilliseconds-Cs9z2sdO.js → getTimezoneOffsetInMilliseconds-DxAkjvJb.js} +1 -1
- package/client/dist/assets/index-Cfh9aaep.css +2 -0
- package/client/dist/assets/index-DYoyDWim.js +76 -0
- package/client/dist/assets/{jira-api-B2BBZQTx.js → jira-api-ChjVGJx_.js} +1 -1
- package/client/dist/assets/narration-4OSg0b5-.js +1 -0
- package/client/dist/assets/narration-BPMOQPFe.js +1 -0
- package/client/dist/assets/narration-BSldQfjd.js +1 -0
- package/client/dist/assets/narration-CvQdWdR5.js +1 -0
- package/client/dist/assets/narration-D-e9ssxA.js +1 -0
- package/client/dist/assets/narration-DKLjXIFI.js +1 -0
- package/client/dist/assets/narration-DnrKC3mF.js +1 -0
- package/client/dist/assets/narration-Dypjxeel.js +1 -0
- package/client/dist/assets/{project-repositories-xSqimlaj.js → project-repositories-BvBj9XH9.js} +1 -1
- package/client/dist/assets/{provider-capabilities-B-wOHfLP.js → provider-capabilities-CXipwrXJ.js} +1 -1
- package/client/dist/assets/{settings-2Yx_9yJM.js → settings-B3rWEwOx.js} +1 -1
- package/client/dist/assets/{settings-BLOsrXEw.js → settings-BcVoiMyw.js} +1 -1
- package/client/dist/assets/settings-BlYvaQ7w.js +1 -0
- package/client/dist/assets/{settings-DPjNiUsS.js → settings-CD5uEBiL.js} +1 -1
- package/client/dist/assets/{settings-CpKwTew1.js → settings-CyhS0DLJ.js} +1 -1
- package/client/dist/assets/{settings-FIqwhTup.js → settings-DCMFUGDs.js} +1 -1
- package/client/dist/assets/{settings-C6s9PtRD.js → settings-DEgcA0jd.js} +1 -1
- package/client/dist/assets/{settings-NSWQjY5B.js → settings-DmbYKyMJ.js} +1 -1
- package/client/dist/assets/{spending-DXOcv1tn.js → spending-DNM6NAoA.js} +1 -1
- package/client/dist/assets/{useDesktop-gVGoWWiY.js → useDesktop-mxHVQOdx.js} +1 -1
- package/client/dist/assets/useSharedWebSocket-DnxHj8jP.js +2 -0
- package/client/dist/index.html +19 -17
- package/docs/README.md +1 -0
- package/docs/internals/README.md +2 -0
- package/docs/internals/agent-runtime-framework-evaluation.md +208 -0
- package/docs/internals/programmatic-agent-runtime-validation.md +72 -0
- package/docs/internals/programmatic-agent-runtime.md +140 -0
- package/package.json +1 -1
- package/server/dist/agent-mcp-config.js +5 -0
- package/server/dist/agent-operator-prompt.js +2 -2
- package/server/dist/agent-runtime-accounting.js +73 -0
- package/server/dist/agent-runtime-bridge.js +231 -0
- package/server/dist/agent-runtime-controls-router.js +86 -0
- package/server/dist/agent-runtime-controls.js +341 -0
- package/server/dist/agent-runtime-loader.js +91 -0
- package/server/dist/agent-runtime-metrics.js +46 -0
- package/server/dist/agent-runtime-paths.js +12 -0
- package/server/dist/agent-runtime-repositories.js +37 -0
- package/server/dist/agent-runtime-settings-router.js +61 -0
- package/server/dist/agent-runtime-settings.js +239 -0
- package/server/dist/agent-runtime-settlement.js +133 -0
- package/server/dist/agent-runtime-verification-suggestions.js +119 -0
- package/server/dist/contract-refine-runner.js +7 -7
- package/server/dist/core-completion.js +8 -5
- package/server/dist/core-execution.js +17 -8
- package/server/dist/core-node-runtime.js +12 -0
- package/server/dist/desktop-router.js +26 -0
- package/server/dist/job-listing.js +7 -3
- package/server/dist/loop-command-catalog.js +2 -2
- package/server/dist/loop-executors.js +44 -2
- package/server/dist/loop-factory.js +1 -1
- package/server/dist/loop-run-manager.js +62 -28
- package/server/dist/mcp/tools/specs.js +7 -4
- package/server/dist/multi-repo-execution.js +1 -0
- package/server/dist/project-registry.js +9 -0
- package/server/dist/project-router-jobs.js +8 -2
- package/server/dist/project-router-settings.js +4 -0
- package/server/dist/project-router-tickets.js +4 -4
- package/server/dist/providers/runtime.js +6 -0
- package/server/dist/rail-isolated-launch.js +18 -0
- package/server/dist/rails-router.js +4 -1
- package/server/dist/runtime-role-prompts-router.js +25 -0
- package/server/dist/schemas/agent-runtime.schema.json +60 -0
- package/server/dist/worktree-overlay.js +32 -1
- package/client/dist/assets/AgentBrowserCapture-BQem50z4.js +0 -1
- package/client/dist/assets/AgentModeAnalyticsPane-BC_xbT_l.js +0 -2
- package/client/dist/assets/AgentModeCodePane-DK-q3K6Y.js +0 -2
- package/client/dist/assets/AgentModeJobsPane-C7ELTPC1.js +0 -1
- package/client/dist/assets/CodePage-DwgbeqQ_.js +0 -3
- package/client/dist/assets/InteractiveJobComposer-BcR6xlHU.js +0 -19
- package/client/dist/assets/JobDetailModal-DKA_DUHe.js +0 -1
- package/client/dist/assets/JobDetailPage-vaOcE-cI.js +0 -1
- package/client/dist/assets/JobsPage-Bwoe-Fb0.js +0 -1
- package/client/dist/assets/PluginsPage-CTUHX_Lu.js +0 -2
- package/client/dist/assets/ProjectSettingsDialog-DeL8md1s.js +0 -1
- package/client/dist/assets/TemplatePreviewModal-_CgCCV7L.js +0 -1
- package/client/dist/assets/index-Bfj8HvX1.css +0 -2
- package/client/dist/assets/index-UnaJTMIy.js +0 -76
- package/client/dist/assets/narration-B-ynWTpn.js +0 -1
- package/client/dist/assets/narration-Bj_laZwg.js +0 -1
- package/client/dist/assets/narration-BxHpmMv_.js +0 -1
- package/client/dist/assets/narration-C1Px0-0j.js +0 -1
- package/client/dist/assets/narration-CAXhGbzM.js +0 -1
- package/client/dist/assets/narration-DQ1l_Kq6.js +0 -1
- package/client/dist/assets/narration-XISXwqZd.js +0 -1
- package/client/dist/assets/narration-kwzfglQo.js +0 -1
- package/client/dist/assets/settings-CCNZN5Q-.js +0 -1
- package/client/dist/assets/useSharedWebSocket-DbGL_YOt.js +0 -2
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RUNTIME_HOST_ENV_KEYS = void 0;
|
|
4
|
+
exports.runtimeChangeName = runtimeChangeName;
|
|
5
|
+
exports.runAgentRuntimeInvocation = runAgentRuntimeInvocation;
|
|
6
|
+
const agent_runtime_repositories_1 = require("./agent-runtime-repositories");
|
|
7
|
+
const node_util_1 = require("node:util");
|
|
8
|
+
const providers_1 = require("./providers");
|
|
9
|
+
const node_child_process_1 = require("node:child_process");
|
|
10
|
+
const node_crypto_1 = require("node:crypto");
|
|
11
|
+
const node_fs_1 = require("node:fs");
|
|
12
|
+
const node_path_1 = require("node:path");
|
|
13
|
+
const node_readline_1 = require("node:readline");
|
|
14
|
+
const agent_runtime_loader_1 = require("./agent-runtime-loader");
|
|
15
|
+
const agent_runtime_settings_1 = require("./agent-runtime-settings");
|
|
16
|
+
const core_node_runtime_1 = require("./core-node-runtime");
|
|
17
|
+
const win_spawn_1 = require("./util/win-spawn");
|
|
18
|
+
function runtimeChangeName(runId) {
|
|
19
|
+
return 'runtime-' + (0, node_crypto_1.createHash)('sha256').update(runId).digest('hex').slice(0, 20);
|
|
20
|
+
}
|
|
21
|
+
exports.RUNTIME_HOST_ENV_KEYS = [
|
|
22
|
+
'SPECRAILS_REPO_DIR', 'SPECRAILS_GIT_AUTO', 'SPECRAILS_REPO_MAP_PATH',
|
|
23
|
+
'SPECRAILS_EXECUTION_CONTEXT', 'SPECRAILS_EXECUTION_MANIFEST', 'SPECRAILS_REPOSITORIES',
|
|
24
|
+
'SPECRAILS_WORKSPACE_DIR', 'SPECRAILS_TICKETS_PATH', 'SPECRAILS_STATE_DIR',
|
|
25
|
+
'SPECRAILS_BACKLOG_CONFIG_PATH', 'SPECRAILS_PROFILES_DIR',
|
|
26
|
+
'SPECRAILS_PROFILE_PATH',
|
|
27
|
+
];
|
|
28
|
+
function saveHostContext(options) {
|
|
29
|
+
const file = (0, node_path_1.join)((0, node_path_1.dirname)(options.contextPath), 'desktop-runtime-host.json');
|
|
30
|
+
const serialized = JSON.stringify({ schemaVersion: 1, cwd: (0, node_fs_1.realpathSync)(options.cwd), env: Object.fromEntries(exports.RUNTIME_HOST_ENV_KEYS.filter(key => options.env[key] !== undefined).map(key => [key, options.env[key]])) }, null, 2) + '\n';
|
|
31
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(file), { recursive: true, mode: 0o700 });
|
|
32
|
+
try {
|
|
33
|
+
(0, node_fs_1.writeFileSync)(file, serialized, { flag: 'wx', mode: 0o600 });
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error.code !== 'EEXIST')
|
|
37
|
+
throw error;
|
|
38
|
+
if ((0, node_fs_1.readFileSync)(file, 'utf8') !== serialized)
|
|
39
|
+
throw new Error('Desktop runtime scope changed; resume using its frozen host context');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Core owns the complete agent workflow in one managed process. The existing
|
|
43
|
+
* rail's cancellation and worktree ownership remain in Desktop. */
|
|
44
|
+
async function runAgentRuntimeInvocation(options) {
|
|
45
|
+
const cli = (0, agent_runtime_loader_1.findCoreAgentRuntimeCli)();
|
|
46
|
+
if (!cli)
|
|
47
|
+
throw new Error('Programmatic agent runtime is enabled but its Core CLI is unavailable. Build or bundle the compatible Core runtime.');
|
|
48
|
+
if (!options.resume && (!options.configPath || !options.change))
|
|
49
|
+
throw new Error('New programmatic runs require configuration and a change name');
|
|
50
|
+
const admittedContext = JSON.parse((0, node_fs_1.readFileSync)(options.contextPath, 'utf8'));
|
|
51
|
+
if (typeof admittedContext.runId !== 'string')
|
|
52
|
+
throw new Error('Core context is missing its run identity');
|
|
53
|
+
if (!options.resume)
|
|
54
|
+
saveHostContext(options);
|
|
55
|
+
const args = [cli, options.resume ? 'resume' : 'run', '--context', options.contextPath];
|
|
56
|
+
if (!options.resume) {
|
|
57
|
+
if (!Array.isArray(admittedContext.repositories) || !admittedContext.repositories.length || admittedContext.repositories.some(repo => !repo || typeof repo.id !== 'string' || !repo.id))
|
|
58
|
+
throw new Error('Core context is missing its repository scope');
|
|
59
|
+
const config = (0, agent_runtime_settings_1.loadRuntimeConfigFile)(options.configPath, options.defaultProvider);
|
|
60
|
+
config.rolePrompts = { ...(await (0, agent_runtime_loader_1.loadCoreAgentRuntime)()).rolePromptDefaults(), ...(0, agent_runtime_settings_1.loadRuntimeRolePrompts)() };
|
|
61
|
+
if (options.defaultProvider) {
|
|
62
|
+
const provider = config.providers.find(entry => entry.id === options.defaultProvider);
|
|
63
|
+
if (!provider)
|
|
64
|
+
throw new Error(`Selected runtime provider is not configured: ${options.defaultProvider}`);
|
|
65
|
+
for (const role of Object.values(config.agents)) {
|
|
66
|
+
if (role.provider !== provider.id) {
|
|
67
|
+
role.provider = provider.id;
|
|
68
|
+
role.model = options.selectedModel ?? (provider.kind === 'cli' ? (0, providers_1.getAdapter)(provider.cli).defaultModel() : undefined);
|
|
69
|
+
if (!role.model)
|
|
70
|
+
throw new Error(`Selected runtime provider requires a model: ${provider.id}`);
|
|
71
|
+
}
|
|
72
|
+
if (!role.model && provider.kind === 'cli')
|
|
73
|
+
role.model = (0, providers_1.getAdapter)(provider.cli).defaultModel();
|
|
74
|
+
}
|
|
75
|
+
if (options.selectedModel)
|
|
76
|
+
config.agents.developer.model = options.selectedModel;
|
|
77
|
+
}
|
|
78
|
+
const selected = new Set(admittedContext.repositories.map(repo => repo.id));
|
|
79
|
+
// Project settings cover every repository; a ticket may select only a subset.
|
|
80
|
+
// Freeze that subset for admission without changing the project settings.
|
|
81
|
+
config.verification = config.verification.filter(command => selected.has(command.repositoryId));
|
|
82
|
+
const scopedPath = (0, node_path_1.join)((0, node_path_1.dirname)(options.contextPath), 'desktop-runtime-config.json');
|
|
83
|
+
const serialized = JSON.stringify(config, null, 2) + '\n';
|
|
84
|
+
try {
|
|
85
|
+
(0, node_fs_1.writeFileSync)(scopedPath, serialized, { flag: 'wx', mode: 0o600 });
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error.code !== 'EEXIST')
|
|
89
|
+
throw error;
|
|
90
|
+
if ((0, node_fs_1.readFileSync)(scopedPath, 'utf8') !== serialized)
|
|
91
|
+
throw new Error('Desktop runtime configuration changed; start a new run');
|
|
92
|
+
}
|
|
93
|
+
args.push('--config', scopedPath, '--change', options.change);
|
|
94
|
+
}
|
|
95
|
+
const frozenPath = (0, node_path_1.join)((0, node_path_1.dirname)(options.contextPath), 'desktop-runtime-config.json');
|
|
96
|
+
if ((0, node_fs_1.existsSync)(frozenPath)) {
|
|
97
|
+
const frozen = JSON.parse((0, node_fs_1.readFileSync)(frozenPath, 'utf8'));
|
|
98
|
+
for (const [role, assignment] of Object.entries(frozen.agents)) {
|
|
99
|
+
try {
|
|
100
|
+
options.onLine?.(`[runtime] ${role}: ${assignment.provider}/${assignment.model ?? 'provider default'}\n`);
|
|
101
|
+
}
|
|
102
|
+
catch { /* Log observers cannot prevent execution. */ }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
for (const [flag, values] of [['approve', options.approve], ['recover', options.recover], ['invalidate', options.invalidate]]) {
|
|
106
|
+
if (values?.length)
|
|
107
|
+
args.push('--' + flag, values.join(','));
|
|
108
|
+
}
|
|
109
|
+
if (options.answer !== undefined) {
|
|
110
|
+
if (!options.resume)
|
|
111
|
+
throw new Error('Answers apply to runtime resume');
|
|
112
|
+
args.push('--answer', options.answer);
|
|
113
|
+
}
|
|
114
|
+
const started = Date.now();
|
|
115
|
+
return new Promise((resolve) => {
|
|
116
|
+
let result;
|
|
117
|
+
let stderr = '', summary = '', invalidProtocol = false, timedOut = false;
|
|
118
|
+
let timer;
|
|
119
|
+
const child = (0, node_child_process_1.spawn)((0, core_node_runtime_1.resolveCoreNodeRuntime)(), args, {
|
|
120
|
+
cwd: options.cwd, env: (0, win_spawn_1.windowsSpawnEnv)(options.env), shell: false, windowsHide: true,
|
|
121
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
122
|
+
});
|
|
123
|
+
// Always leave a terminal result, including synchronous observer failures.
|
|
124
|
+
let observerError;
|
|
125
|
+
try {
|
|
126
|
+
options.onSpawn?.(child);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
observerError = error instanceof Error ? error.message : String(error);
|
|
130
|
+
if (child.pid)
|
|
131
|
+
(0, win_spawn_1.treeKillSafe)(child.pid, 'SIGKILL');
|
|
132
|
+
}
|
|
133
|
+
const observe = (callback) => { try {
|
|
134
|
+
callback?.();
|
|
135
|
+
}
|
|
136
|
+
catch { /* Logging cannot replay a workflow. */ } };
|
|
137
|
+
const lines = (0, node_readline_1.createInterface)({ input: child.stdout });
|
|
138
|
+
lines.on('line', line => {
|
|
139
|
+
if (line.length > 2_000_000) {
|
|
140
|
+
invalidProtocol = true;
|
|
141
|
+
if (child.pid)
|
|
142
|
+
(0, win_spawn_1.treeKillSafe)(child.pid, 'SIGKILL');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
let event;
|
|
146
|
+
try {
|
|
147
|
+
event = JSON.parse(line);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
invalidProtocol = true;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (!event || typeof event !== 'object') {
|
|
154
|
+
invalidProtocol = true;
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (event.type === 'agent-event' && event.event && typeof event.event === 'object' && event.event.kind === 'tool-start' && (admittedContext.repositories?.length ?? 0) > 1) {
|
|
158
|
+
const repositories = (0, agent_runtime_repositories_1.toolRepositories)(event.event, admittedContext.repositories, admittedContext.artifactRoot ?? options.cwd);
|
|
159
|
+
if (repositories.length)
|
|
160
|
+
event.repositories = repositories.map(repo => ({ id: repo.id, name: repo.name || repo.id }));
|
|
161
|
+
}
|
|
162
|
+
observe(() => options.onRawLine?.(event.repositories ? JSON.stringify(event) : line));
|
|
163
|
+
if (event.type === 'runtime-result') {
|
|
164
|
+
if (result)
|
|
165
|
+
invalidProtocol = true;
|
|
166
|
+
result = event;
|
|
167
|
+
}
|
|
168
|
+
else if (event.type === 'workflow-event') {
|
|
169
|
+
const payload = event.event;
|
|
170
|
+
if (payload?.type)
|
|
171
|
+
observe(() => options.onLine?.(`[runtime] ${payload.type}${payload.stepId ? ': ' + payload.stepId : ''}${payload.message ? ' — ' + payload.message : ''}\n`));
|
|
172
|
+
}
|
|
173
|
+
else if (event.type === 'agent-event') {
|
|
174
|
+
const payload = event.event;
|
|
175
|
+
const role = typeof event.role === 'string' ? event.role : 'agent';
|
|
176
|
+
if (payload?.kind === 'text' && typeof payload.text === 'string') {
|
|
177
|
+
summary = (summary + payload.text).slice(-32_000);
|
|
178
|
+
observe(() => options.onLine?.(payload.text + '\n'));
|
|
179
|
+
}
|
|
180
|
+
else if (payload?.kind === 'tool-start' && typeof payload.tool === 'string') {
|
|
181
|
+
// Live tool activity keeps a long developer turn from looking hung.
|
|
182
|
+
const repositories = event.repositories;
|
|
183
|
+
const scope = repositories?.length ? ` [${repositories.map(repo => repo.name).join(' + ')}]` : '';
|
|
184
|
+
observe(() => options.onLine?.(`[${role}]${scope} ${payload.tool}${payload.detail ? ' ' + payload.detail : ''}\n`));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else if (event.type === 'verification-output' && typeof event.text === 'string') {
|
|
188
|
+
observe(() => options.onLine?.((0, node_util_1.stripVTControlCharacters)(String(event.text))));
|
|
189
|
+
}
|
|
190
|
+
else if (event.type === 'span') {
|
|
191
|
+
// Trace spans are telemetry; the raw line is already recorded for diagnostics.
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
child.stderr?.on('data', (chunk) => {
|
|
195
|
+
stderr = (stderr + chunk.toString('utf8')).slice(-32_000);
|
|
196
|
+
observe(() => options.onLine?.(chunk.toString('utf8'), 'stderr'));
|
|
197
|
+
});
|
|
198
|
+
child.on('error', error => { stderr = error.message; });
|
|
199
|
+
if (options.timeoutMs && options.timeoutMs > 0) {
|
|
200
|
+
timer = setTimeout(() => {
|
|
201
|
+
timedOut = true;
|
|
202
|
+
if (child.pid)
|
|
203
|
+
(0, win_spawn_1.treeKillSafe)(child.pid, 'SIGKILL');
|
|
204
|
+
}, options.timeoutMs);
|
|
205
|
+
timer.unref?.();
|
|
206
|
+
}
|
|
207
|
+
child.on('close', code => {
|
|
208
|
+
if (timer)
|
|
209
|
+
clearTimeout(timer);
|
|
210
|
+
lines.close();
|
|
211
|
+
const usage = result?.invocationUsage;
|
|
212
|
+
const known = (value) => typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
213
|
+
const cost = known(usage?.costUsd), tokensIn = known(usage?.inputTokens), tokensOut = known(usage?.outputTokens);
|
|
214
|
+
if (result?.status === 'succeeded' && result.runId !== admittedContext.runId)
|
|
215
|
+
invalidProtocol = true;
|
|
216
|
+
const failed = code !== 0 || result?.status !== 'succeeded' || invalidProtocol || timedOut || Boolean(observerError);
|
|
217
|
+
const errorText = observerError ?? (timedOut ? 'Programmatic workflow timed out; inspect its checkpoint before recovery'
|
|
218
|
+
: invalidProtocol ? 'Core returned an invalid runtime event stream'
|
|
219
|
+
: result?.error ?? (result?.status === 'paused' ? (typeof result.pendingQuestion?.question === 'string' && result.pendingQuestion.question.trim()
|
|
220
|
+
? `Workflow awaits an answer in Agent Runtime settings: ${result.pendingQuestion.question.trim().slice(0, 500)}`
|
|
221
|
+
: 'Workflow awaits approval in Agent Runtime settings')
|
|
222
|
+
: failed ? stderr || 'Core exited without a successful programmatic workflow result' : undefined));
|
|
223
|
+
resolve({
|
|
224
|
+
text: summary || (failed ? errorText ?? '' : 'Programmatic implementation verified and archived.'),
|
|
225
|
+
provider: 'agent-runtime', model: 'per-role', failed, errorText,
|
|
226
|
+
cost, tokensIn, tokensOut, tokens: tokensIn === undefined || tokensOut === undefined ? undefined : tokensIn + tokensOut,
|
|
227
|
+
estimated: cost === undefined, durationMs: Date.now() - started,
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isRuntimeContinuationActive = isRuntimeContinuationActive;
|
|
4
|
+
exports.activeRuntimeContinuationIds = activeRuntimeContinuationIds;
|
|
5
|
+
exports.cancelRuntimeContinuation = cancelRuntimeContinuation;
|
|
6
|
+
exports.shutdownAgentRuntimeControls = shutdownAgentRuntimeControls;
|
|
7
|
+
exports.registerAgentRuntimeControlRoutes = registerAgentRuntimeControlRoutes;
|
|
8
|
+
const agent_runtime_paths_1 = require("./agent-runtime-paths");
|
|
9
|
+
const agent_runtime_controls_1 = require("./agent-runtime-controls");
|
|
10
|
+
const controllers = new WeakMap();
|
|
11
|
+
function isRuntimeContinuationActive(context, runId) { return controllers.get(context)?.isActive(runId) ?? false; }
|
|
12
|
+
function activeRuntimeContinuationIds(context) { return controllers.get(context)?.activeRunIds() ?? []; }
|
|
13
|
+
function cancelRuntimeContinuation(context, runId) {
|
|
14
|
+
const controller = controllers.get(context);
|
|
15
|
+
if (!controller?.isActive(runId))
|
|
16
|
+
return false;
|
|
17
|
+
controller.cancel(runId);
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
function shutdownAgentRuntimeControls(context) { controllers.get(context)?.shutdown(); }
|
|
21
|
+
function registerAgentRuntimeControlRoutes({ router, ctx }) {
|
|
22
|
+
function controls(request) {
|
|
23
|
+
const context = ctx(request);
|
|
24
|
+
let controller = controllers.get(context);
|
|
25
|
+
if (!controller) {
|
|
26
|
+
controller = new agent_runtime_controls_1.AgentRuntimeControls(context);
|
|
27
|
+
controllers.set(context, controller);
|
|
28
|
+
}
|
|
29
|
+
return controller;
|
|
30
|
+
}
|
|
31
|
+
router.get('/:projectId/agent-runtime/runs', async (req, res) => {
|
|
32
|
+
try {
|
|
33
|
+
if (req.query.railIndex !== undefined) {
|
|
34
|
+
const railIndex = Number(req.query.railIndex);
|
|
35
|
+
if (!Number.isSafeInteger(railIndex) || railIndex < 0) {
|
|
36
|
+
res.status(400).json({ error: 'invalid_rail_index' });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const context = ctx(req);
|
|
40
|
+
const latest = context.db.prepare('SELECT id FROM loop_runs WHERE rail_index = ? ORDER BY started_at DESC, rowid DESC LIMIT 1').get(railIndex);
|
|
41
|
+
res.json({ runs: latest && (0, agent_runtime_paths_1.hasAgentRuntimeRequest)(context.project, latest.id) ? [await controls(req).summary(latest.id)] : [] });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
res.json({ runs: await controls(req).list() });
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
res.status(500).json({ error: 'runtime_status_failed', message: 'Could not read runtime executions' });
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
router.get('/:projectId/agent-runtime/runs/:runId', async (req, res) => {
|
|
51
|
+
try {
|
|
52
|
+
const context = ctx(req), runId = String(req.params.runId);
|
|
53
|
+
res.json({ runs: (0, agent_runtime_paths_1.hasAgentRuntimeRequest)(context.project, runId) ? [await controls(req).summary(runId)] : [] });
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
res.status(500).json({ error: 'runtime_status_failed' });
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
router.post('/:projectId/agent-runtime/runs/:runId/resume', async (req, res) => {
|
|
60
|
+
try {
|
|
61
|
+
await controls(req).resume(String(req.params.runId), (0, agent_runtime_controls_1.validateRuntimeResumeInput)(req.body));
|
|
62
|
+
res.status(202).json({ accepted: true });
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
res.status(error instanceof agent_runtime_controls_1.RuntimeControlError ? error.statusCode : 500).json({ error: error instanceof agent_runtime_controls_1.RuntimeControlError ? error.code : 'runtime_resume_failed', message: error instanceof agent_runtime_controls_1.RuntimeControlError ? error.message : 'Could not resume runtime execution' });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
router.post('/:projectId/agent-runtime/runs/:runId/settle', async (req, res) => {
|
|
69
|
+
try {
|
|
70
|
+
await controls(req).settle(String(req.params.runId));
|
|
71
|
+
res.json({ settled: true });
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
res.status(error instanceof agent_runtime_controls_1.RuntimeControlError ? error.statusCode : 500).json({ message: error instanceof agent_runtime_controls_1.RuntimeControlError ? error.message : 'Could not prepare delivery' });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
router.post('/:projectId/agent-runtime/runs/:runId/cancel', (req, res) => {
|
|
78
|
+
try {
|
|
79
|
+
controls(req).cancel(String(req.params.runId));
|
|
80
|
+
res.status(202).json({ accepted: true });
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
res.status(error instanceof agent_runtime_controls_1.RuntimeControlError ? error.statusCode : 500).json({ error: error instanceof agent_runtime_controls_1.RuntimeControlError ? error.code : 'runtime_cancel_failed', message: error instanceof agent_runtime_controls_1.RuntimeControlError ? error.message : 'Could not cancel runtime execution' });
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|