@wjarka/cezarion 0.14.8 → 0.14.9-dev.829
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 +76 -2
- package/dist/application-update/bin-recovery.d.ts +5 -0
- package/dist/application-update/bin-recovery.js +96 -0
- package/dist/application-update/bin-recovery.js.map +1 -0
- package/dist/application-update/discovery.d.ts +22 -0
- package/dist/application-update/discovery.js +91 -0
- package/dist/application-update/discovery.js.map +1 -0
- package/dist/application-update/helper.d.ts +57 -0
- package/dist/application-update/helper.js +374 -0
- package/dist/application-update/helper.js.map +1 -0
- package/dist/application-update/launcher.d.ts +8 -0
- package/dist/application-update/launcher.js +53 -0
- package/dist/application-update/launcher.js.map +1 -0
- package/dist/application-update/lock.d.ts +4 -0
- package/dist/application-update/lock.js +70 -0
- package/dist/application-update/lock.js.map +1 -0
- package/dist/application-update/npm-process.d.ts +17 -0
- package/dist/application-update/npm-process.js +133 -0
- package/dist/application-update/npm-process.js.map +1 -0
- package/dist/application-update/service.d.ts +69 -0
- package/dist/application-update/service.js +456 -0
- package/dist/application-update/service.js.map +1 -0
- package/dist/artifacts/cli.d.ts +1 -0
- package/dist/artifacts/cli.js +32 -0
- package/dist/artifacts/cli.js.map +1 -0
- package/dist/artifacts/lifecycle.d.ts +4 -0
- package/dist/artifacts/lifecycle.js +42 -0
- package/dist/artifacts/lifecycle.js.map +1 -0
- package/dist/artifacts/resolve.d.ts +18 -0
- package/dist/artifacts/resolve.js +102 -0
- package/dist/artifacts/resolve.js.map +1 -0
- package/dist/artifacts/store.d.ts +8 -0
- package/dist/artifacts/store.js +323 -0
- package/dist/artifacts/store.js.map +1 -0
- package/dist/ci-wait/mcp.d.ts +3 -0
- package/dist/ci-wait/mcp.js +14 -3
- package/dist/ci-wait/mcp.js.map +1 -1
- package/dist/contract/application-update.d.ts +32 -0
- package/dist/contract/artifacts.d.ts +83 -0
- package/dist/contract/ask-schema.d.ts +32 -0
- package/dist/contract/ask.d.ts +2 -32
- package/dist/contract/conversations.d.ts +165 -0
- package/dist/contract/delegation.d.ts +39 -0
- package/dist/contract/events.d.ts +49 -0
- package/dist/contract/health.d.ts +12 -0
- package/dist/contract/index.d.ts +2 -0
- package/dist/contract/index.js +1374 -1247
- package/dist/contract/runs.d.ts +143 -0
- package/dist/contract/skills.d.ts +28 -0
- package/dist/core/agent-runner.d.ts +33 -4
- package/dist/core/agent-runner.js +5 -0
- package/dist/core/agent-runner.js.map +1 -1
- package/dist/core/claude-cli-runner.d.ts +6 -12
- package/dist/core/claude-cli-runner.js +89 -19
- package/dist/core/claude-cli-runner.js.map +1 -1
- package/dist/core/codex-app-server-runner.d.ts +2 -1
- package/dist/core/codex-app-server-runner.js +327 -92
- package/dist/core/codex-app-server-runner.js.map +1 -1
- package/dist/core/codex-app-server-transport.d.ts +13 -1
- package/dist/core/codex-app-server-transport.js +58 -17
- package/dist/core/codex-app-server-transport.js.map +1 -1
- package/dist/core/cursor-acp-runner.d.ts +4 -1
- package/dist/core/cursor-acp-runner.js +3 -0
- package/dist/core/cursor-acp-runner.js.map +1 -1
- package/dist/core/cursor-provider-error.js +3 -1
- package/dist/core/cursor-provider-error.js.map +1 -1
- package/dist/core/input-submissions.d.ts +14 -0
- package/dist/core/input-submissions.js +26 -0
- package/dist/core/input-submissions.js.map +1 -0
- package/dist/core/opencode-server-runner.d.ts +4 -1
- package/dist/core/opencode-server-runner.js +144 -21
- package/dist/core/opencode-server-runner.js.map +1 -1
- package/dist/core/pi-runner.d.ts +2 -1
- package/dist/core/pi-runner.js +72 -7
- package/dist/core/pi-runner.js.map +1 -1
- package/dist/delegation/cli.js +102 -6
- package/dist/delegation/cli.js.map +1 -1
- package/dist/delegation/conversations.js +13 -5
- package/dist/delegation/conversations.js.map +1 -1
- package/dist/delegation/input.d.ts +2 -1
- package/dist/delegation/input.js +6 -1
- package/dist/delegation/input.js.map +1 -1
- package/dist/delegation/provision.js +5 -3
- package/dist/delegation/provision.js.map +1 -1
- package/dist/delegation/questions.d.ts +19 -0
- package/dist/delegation/questions.js +45 -0
- package/dist/delegation/questions.js.map +1 -0
- package/dist/delegation/results.d.ts +1 -1
- package/dist/delegation/results.js +23 -13
- package/dist/delegation/results.js.map +1 -1
- package/dist/delegation/routes.d.ts +142 -15
- package/dist/delegation/routes.js +4 -1
- package/dist/delegation/routes.js.map +1 -1
- package/dist/delegation/service.d.ts +9 -5
- package/dist/delegation/service.js +106 -7
- package/dist/delegation/service.js.map +1 -1
- package/dist/delegation/transport.d.ts +138 -11
- package/dist/index.js +72 -26
- package/dist/index.js.map +1 -1
- package/dist/open-url.d.ts +2 -0
- package/dist/open-url.js +20 -0
- package/dist/open-url.js.map +1 -0
- package/dist/release/snapshot.d.ts +3 -3
- package/dist/release/snapshot.js +6 -6
- package/dist/release/snapshot.js.map +1 -1
- package/dist/runs/client-request.d.ts +11 -0
- package/dist/runs/client-request.js +26 -0
- package/dist/runs/client-request.js.map +1 -0
- package/dist/runs/delegation-state.d.ts +17 -0
- package/dist/runs/event-history.js +6 -0
- package/dist/runs/event-history.js.map +1 -1
- package/dist/runs/store.d.ts +78 -6
- package/dist/runs/store.js +163 -1
- package/dist/runs/store.js.map +1 -1
- package/dist/server/server.d.ts +3761 -1648
- package/dist/server/server.js +170 -4
- package/dist/server/server.js.map +1 -1
- package/dist/task-cli/cli.d.ts +38 -0
- package/dist/task-cli/cli.js +463 -0
- package/dist/task-cli/cli.js.map +1 -0
- package/dist/task-cli/discovery.d.ts +22 -0
- package/dist/task-cli/discovery.js +95 -0
- package/dist/task-cli/discovery.js.map +1 -0
- package/dist/task-cli/http.d.ts +43 -0
- package/dist/task-cli/http.js +101 -0
- package/dist/task-cli/http.js.map +1 -0
- package/dist/task-cli/projections.d.ts +40 -0
- package/dist/task-cli/projections.js +45 -0
- package/dist/task-cli/projections.js.map +1 -0
- package/dist/task-cli/watch.d.ts +78 -0
- package/dist/task-cli/watch.js +336 -0
- package/dist/task-cli/watch.js.map +1 -0
- package/dist/workflows/run.d.ts +93 -0
- package/dist/workflows/run.js +816 -81
- package/dist/workflows/run.js.map +1 -1
- package/dist/workspace/projects-cli.js +1 -1
- package/package.json +3 -3
- package/scripts/mock-claude.mjs +38 -2
- package/scripts/mock-codex-app-server.mjs +98 -1
- package/scripts/mock-cursor-acp.mjs +3 -0
- package/scripts/mock-opencode-serve.mjs +69 -2
- package/scripts/mock-pi-rpc.mjs +63 -2
- package/web/dist/assets/agent-accounts-JPfZPgKn.js +1 -0
- package/web/dist/assets/centered-state-HwCqQkH3.js +43 -0
- package/web/dist/assets/collapsible-CTymFdL7.js +1 -0
- package/web/dist/assets/commit-list-BZpYGQl2.js +1 -0
- package/web/dist/assets/compare-variants-9VkybaQ7.js +1 -0
- package/web/dist/assets/{diff-tRE59UNb2.js → diff-CZcD4D1r2.js} +2 -2
- package/web/dist/assets/diff-controls-CpcHG3Mm.js +1 -0
- package/web/dist/assets/{diff-stat-Cgnl_hYF.js → diff-stat-Cn7rzy1H.js} +1 -1
- package/web/dist/assets/{diff-view-DN1ort7Q.js → diff-view-C46nHiP2.js} +2 -2
- package/web/dist/assets/dropdown-menu-_YAzCaoQ.js +1 -0
- package/web/dist/assets/git-toolbar-BvKDz6uS.js +1 -0
- package/web/dist/assets/github-CgjJCGrD.js +1 -0
- package/web/dist/assets/{image-preview-C2JGcBlC.js → image-preview-B618kDBH.js} +1 -1
- package/web/dist/assets/index-BJtve0Pm.js +7 -0
- package/web/dist/assets/index-D0WAgmTQ.css +1 -0
- package/web/dist/assets/markdown-CFWZnvMh.js +2 -0
- package/web/dist/assets/pill-QfwkuR50.js +1 -0
- package/web/dist/assets/project-router-CkAA39N5.js +1 -0
- package/web/dist/assets/prompt-templates-Cfna_S0T.js +15 -0
- package/web/dist/assets/repo-git-DgzgJ0cP.js +1 -0
- package/web/dist/assets/{run-diff-CyG0Nciv.js → run-diff-YbCEQn5I.js} +2 -2
- package/web/dist/assets/run-header-DMgIbr1d.js +1 -0
- package/web/dist/assets/skills-BW79kUTd.js +1 -0
- package/web/dist/assets/{tab-link-BWNp3mLY.js → tab-link-MIHvczEm.js} +1 -1
- package/web/dist/assets/task-changes-C96ekt94.js +1 -0
- package/web/dist/assets/task-commits-DBfcMZyG.js +1 -0
- package/web/dist/assets/task-files-BKpH8dKQ.js +2 -0
- package/web/dist/assets/task-thread-Bw_nQuTx.css +1 -0
- package/web/dist/assets/task-thread-Dnq7Ek6W.js +9 -0
- package/web/dist/assets/textarea-D2vAVgYW.js +1 -0
- package/web/dist/assets/thread-loading-NW8Mthco.js +1 -0
- package/web/dist/assets/token-metrics-D188e6_0.js +1 -0
- package/web/dist/assets/utils-DKheTxGD.js +64 -0
- package/web/dist/assets/workflows-BFY1hgp3.js +11 -0
- package/web/dist/assets/{zoomable-image-Z3JDnm0b.js → zoomable-image-YW3Qdrr_.js} +1 -1
- package/web/dist/index.html +14 -14
- package/web/dist/assets/agent-accounts-BZm_2WAv.js +0 -1
- package/web/dist/assets/alert-dialog-B422RI-k.js +0 -43
- package/web/dist/assets/collapsible-Cy_Fmkrd.js +0 -1
- package/web/dist/assets/commit-list-Dcnk7TnI.js +0 -1
- package/web/dist/assets/compare-variants-Ciqwvd_f.js +0 -1
- package/web/dist/assets/diff-controls-BGrXGi7O.js +0 -1
- package/web/dist/assets/dropdown-menu-dwDGT8MM.js +0 -1
- package/web/dist/assets/git-toolbar-UiHnGvE0.js +0 -1
- package/web/dist/assets/github-D-MrkbJ7.js +0 -1
- package/web/dist/assets/ibm-plex-mono-regular-BF3vfe7_.ttf +0 -0
- package/web/dist/assets/index-BszfYvBq.js +0 -7
- package/web/dist/assets/index-CWh4pKP3.css +0 -1
- package/web/dist/assets/markdown-C_IcKVQd.js +0 -2
- package/web/dist/assets/pill-BsbO6G7y.js +0 -1
- package/web/dist/assets/project-router-DbLkll25.js +0 -1
- package/web/dist/assets/prompt-templates-BlTGJB5W.js +0 -15
- package/web/dist/assets/repo-git-Bm3s6Why.js +0 -1
- package/web/dist/assets/run-header-IFyIGCey.js +0 -1
- package/web/dist/assets/skills-C-C4DVFY.js +0 -1
- package/web/dist/assets/task-changes-D2PHtWUW.js +0 -1
- package/web/dist/assets/task-commits-N5u9U0_R.js +0 -1
- package/web/dist/assets/task-files-BS7c7CFm.js +0 -2
- package/web/dist/assets/task-thread-BQFdz1dJ.css +0 -1
- package/web/dist/assets/task-thread-DGM2dZV-.js +0 -9
- package/web/dist/assets/textarea-FjaU370i.js +0 -1
- package/web/dist/assets/thread-loading-77sJ8Yu_.js +0 -1
- package/web/dist/assets/token-metrics-Clxh03bE.js +0 -1
- package/web/dist/assets/utils-PYYcpCFZ.js +0 -64
- package/web/dist/assets/workflows-Czl0ZfXH.js +0 -11
package/dist/server/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DelegationService } from '../delegation/service.js';
|
|
2
2
|
import { delegationFailure } from '../delegation/routes.js';
|
|
3
|
-
import { workerEmptyRequestSchema, runRelationshipsSchema, runDelegationSummarySchema } from '../contract/index.js';
|
|
3
|
+
import { CLIENT_REQUEST_VARIANTS_ERROR, workerEmptyRequestSchema, runRelationshipsSchema, runDelegationSummarySchema } from '../contract/index.js';
|
|
4
4
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
5
5
|
import { randomUUID } from 'node:crypto';
|
|
6
6
|
import { AutomationStore } from '../automations/store.js';
|
|
@@ -41,10 +41,14 @@ import { appendHandoffHeartbeat, handoffProgressExcerpt, readHandoff } from '../
|
|
|
41
41
|
import { markStarted, onTodosChanged, readTodos, removeTodo, todoTaskText } from '../todos.js';
|
|
42
42
|
import { HistoryCursorError, deriveRunContextEvents, readEventsAfterLiveCursor, readRunHistoryPage, validateLiveCursor, } from '../runs/event-history.js';
|
|
43
43
|
import { readRunIndexFromDisk } from '../runs/run-index.js';
|
|
44
|
+
import { clientRequestHash } from '../runs/client-request.js';
|
|
44
45
|
import { ColdRepoHandles } from './cold-repo-handles.js';
|
|
45
46
|
import { isV2WireEventType } from '../runs/ui-event-sink.js';
|
|
46
47
|
import { runEventsQuerySchema, runHistoryQuerySchema, runIdParamSchema, } from '../contract/index.js';
|
|
47
48
|
import { resolveAttachmentPath } from '../workflows/attachment-path.js';
|
|
49
|
+
import { artifactParamsSchema, fileLinkQuerySchema } from '../contract/index.js';
|
|
50
|
+
import { artifactDirectory, listArtifacts, readArtifact } from '../artifacts/store.js';
|
|
51
|
+
import { artifactPreview, loadFileLink, rasterMime } from '../artifacts/resolve.js';
|
|
48
52
|
import { isUntouchedCancelledRun, toPastedContent } from '../workflows/run.js';
|
|
49
53
|
import { removeWorktree, worktreeDiff, worktreeDiffStat, worktreeSizeBytes } from '../git-worktree.js';
|
|
50
54
|
import { isReclaimable, reclaimWorktrees } from '../runs/retention.js';
|
|
@@ -72,6 +76,8 @@ import { reviewGateEnabled } from '../runs/review-gate.js';
|
|
|
72
76
|
import { readUiState, uiStatePath } from '../ui-state.js';
|
|
73
77
|
import { agentHomePaths, expandTilde } from '../paths.js';
|
|
74
78
|
import { isLoopbackHostHeader, normalizeHostname, resolveCapabilities } from './capabilities.js';
|
|
79
|
+
import { applicationUpdateInputSchema } from '../contract/index.js';
|
|
80
|
+
import { ApplicationUpdateConflictError, ApplicationUpdateFailureError } from '../application-update/service.js';
|
|
75
81
|
import { createSocketHub } from './ws.js';
|
|
76
82
|
import { browseDirectory, isInsideBrowseRoot, isLexicallyInsideBrowseRoot, resolveBrowseRoot } from './fs-browse.js';
|
|
77
83
|
import { parseRemote, resolveForge } from './forge/index.js';
|
|
@@ -304,9 +310,14 @@ const startRunSchema = z
|
|
|
304
310
|
// audit trail survives the composer detour. Bounded like every other
|
|
305
311
|
// string here; a todo id is a short generated key.
|
|
306
312
|
todoId: z.string().min(1).max(200, 'must be at most 200 characters').optional(),
|
|
313
|
+
// Idempotent start (#504): the same id and payload answer 200 with the existing run.
|
|
314
|
+
clientRequestId: z.string().uuid().optional(),
|
|
307
315
|
})
|
|
308
316
|
.refine((b) => Boolean(b.workflow) !== Boolean(b.steps), {
|
|
309
317
|
message: 'provide either "workflow" or "steps", not both',
|
|
318
|
+
})
|
|
319
|
+
.refine((b) => !(b.clientRequestId && (b.variants ?? 1) > 1), {
|
|
320
|
+
message: CLIENT_REQUEST_VARIANTS_ERROR,
|
|
310
321
|
});
|
|
311
322
|
const pickSchema = z.object({
|
|
312
323
|
runId: z.string().min(1),
|
|
@@ -1088,6 +1099,9 @@ export function createApp(deps) {
|
|
|
1088
1099
|
// the key as always-present, which is a shape no client ever receives. The contract schema
|
|
1089
1100
|
// says `.optional()`, and contract-parity.test.ts holds the two together.
|
|
1090
1101
|
...(update?.latest !== undefined ? { latestVersion: update.latest } : {}),
|
|
1102
|
+
...(deps.applicationUpdate ? { applicationUpdate: caps.localHandoff
|
|
1103
|
+
? deps.applicationUpdate.snapshot()
|
|
1104
|
+
: { status: 'idle', supported: false, message: 'Update this installation manually.' } } : {}),
|
|
1091
1105
|
// Health is CORS-open and, in hosted mode, reachable off the loopback —
|
|
1092
1106
|
// so any site/host that reads it would learn the developer's absolute
|
|
1093
1107
|
// checkout path and username (#431). Local mode keeps the full path (the
|
|
@@ -1163,6 +1177,10 @@ export function createApp(deps) {
|
|
|
1163
1177
|
})();
|
|
1164
1178
|
return healthInFlight;
|
|
1165
1179
|
};
|
|
1180
|
+
deps.applicationUpdate?.onStateChange?.(() => {
|
|
1181
|
+
healthCache = undefined;
|
|
1182
|
+
void refreshHealth();
|
|
1183
|
+
});
|
|
1166
1184
|
// The read the GET and the topic snapshot share. On the live server (a hub is
|
|
1167
1185
|
// injected) it answers from cache instantly and revalidates behind the
|
|
1168
1186
|
// response; without a hub — a bare app in tests — there is no refresher
|
|
@@ -2342,6 +2360,32 @@ export function createApp(deps) {
|
|
|
2342
2360
|
throw error;
|
|
2343
2361
|
}
|
|
2344
2362
|
});
|
|
2363
|
+
// Workspace-level, server-selected target and executable. The empty JSON body is strict.
|
|
2364
|
+
const applicationUpdateRoutes = new Hono()
|
|
2365
|
+
.post('/workspace/application-update/apply', jsonZodValidator(applicationUpdateInputSchema), async (c) => {
|
|
2366
|
+
if (!capabilities().localHandoff)
|
|
2367
|
+
return c.json({ error: 'Application updates require a local cockpit.' }, 409);
|
|
2368
|
+
if (!deps.applicationUpdate)
|
|
2369
|
+
return c.json({ error: 'Application update is unavailable.' }, 409);
|
|
2370
|
+
try {
|
|
2371
|
+
return c.json({ state: await deps.applicationUpdate.apply() });
|
|
2372
|
+
}
|
|
2373
|
+
catch (error) {
|
|
2374
|
+
return c.json({ error: error instanceof ApplicationUpdateConflictError || error instanceof ApplicationUpdateFailureError ? error.message : 'Application update preparation failed.' }, error instanceof ApplicationUpdateConflictError ? 409 : error instanceof ApplicationUpdateFailureError ? error.status : 500);
|
|
2375
|
+
}
|
|
2376
|
+
})
|
|
2377
|
+
.post('/workspace/application-update/restart', jsonZodValidator(applicationUpdateInputSchema), async (c) => {
|
|
2378
|
+
if (!capabilities().localHandoff)
|
|
2379
|
+
return c.json({ error: 'Application updates require a local cockpit.' }, 409);
|
|
2380
|
+
if (!deps.applicationUpdate)
|
|
2381
|
+
return c.json({ error: 'Application update is unavailable.' }, 409);
|
|
2382
|
+
try {
|
|
2383
|
+
return c.json({ state: await deps.applicationUpdate.restart() });
|
|
2384
|
+
}
|
|
2385
|
+
catch (error) {
|
|
2386
|
+
return c.json({ error: error instanceof ApplicationUpdateConflictError ? error.message : 'Application restart is unavailable.' }, error instanceof ApplicationUpdateConflictError ? 409 : 500);
|
|
2387
|
+
}
|
|
2388
|
+
});
|
|
2345
2389
|
// ---- GUI clone (multi-project spec, step 4.3) ----------------------------
|
|
2346
2390
|
// "Add project → Clone from GitHub": clone into the checkout root, then
|
|
2347
2391
|
// register the result through `registerFolder` above (same guards, same
|
|
@@ -3131,8 +3175,21 @@ export function createApp(deps) {
|
|
|
3131
3175
|
return run ? c.json(run) : c.json({ error: 'not found' }, 404);
|
|
3132
3176
|
})
|
|
3133
3177
|
.post('/runs', jsonZodValidator(startRunSchema), async (c) => {
|
|
3134
|
-
const { root: repoRoot, dataDir, manager } = c.get('project');
|
|
3178
|
+
const { root: repoRoot, dataDir, manager, store } = c.get('project');
|
|
3135
3179
|
const parsed = { data: c.req.valid('json') };
|
|
3180
|
+
const clientRequest = parsed.data.clientRequestId
|
|
3181
|
+
? { id: parsed.data.clientRequestId, hash: clientRequestHash(parsed.data) }
|
|
3182
|
+
: undefined;
|
|
3183
|
+
// A retry only retrieves a persisted result: mutable start prerequisites (workflow,
|
|
3184
|
+
// provider, account and model policy) must not invalidate an already accepted request.
|
|
3185
|
+
if (clientRequest) {
|
|
3186
|
+
const existing = store.findRunByClientRequestId(clientRequest.id);
|
|
3187
|
+
if (existing) {
|
|
3188
|
+
if (existing.clientRequestHash !== clientRequest.hash)
|
|
3189
|
+
return c.json({ error: 'request id payload conflict' }, 409);
|
|
3190
|
+
return c.json(existing, 200);
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3136
3193
|
if (agentModelsLocked(repoRoot) &&
|
|
3137
3194
|
(parsed.data.model?.trim() || parsed.data.effort?.trim())) {
|
|
3138
3195
|
return c.json({ error: AGENT_MODELS_LOCKED_ERROR }, 409);
|
|
@@ -3186,6 +3243,18 @@ export function createApp(deps) {
|
|
|
3186
3243
|
// CEZ_TODOS_FILE alike (RunManager.agentEnv).
|
|
3187
3244
|
generateFollowups: capabilities().followups ? parsed.data.generateFollowups : false,
|
|
3188
3245
|
};
|
|
3246
|
+
if (clientRequest) {
|
|
3247
|
+
// Recheck after every await: concurrent first requests may both miss the early lookup.
|
|
3248
|
+
// The manager's lookup and create are synchronous, so exactly one can create (#504).
|
|
3249
|
+
const result = manager.startRunIdempotent(workflow, input, clientRequest);
|
|
3250
|
+
if ('conflict' in result)
|
|
3251
|
+
return c.json({ error: 'request id payload conflict' }, 409);
|
|
3252
|
+
if (!result.created)
|
|
3253
|
+
return c.json(result.run, 200);
|
|
3254
|
+
if (parsed.data.todoId)
|
|
3255
|
+
await noteTodoStarted(dataDir, parsed.data.todoId, result.run.id);
|
|
3256
|
+
return c.json(result.run, 201);
|
|
3257
|
+
}
|
|
3189
3258
|
const variants = parsed.data.variants ?? 1;
|
|
3190
3259
|
if (variants > 1) {
|
|
3191
3260
|
// Variants live in worktrees — without git there's nothing to isolate
|
|
@@ -3703,6 +3772,70 @@ export function createApp(deps) {
|
|
|
3703
3772
|
if (!result.ok)
|
|
3704
3773
|
return c.json({ error: result.error }, 409);
|
|
3705
3774
|
return c.json(result.commit);
|
|
3775
|
+
})
|
|
3776
|
+
.get('/runs/:id/file-link', paramZodValidator(artifactParamsSchema.omit({ artifactId: true })), queryZodValidator(fileLinkQuerySchema), async (c) => {
|
|
3777
|
+
const { root, dataDir, store } = c.get('project');
|
|
3778
|
+
const run = store.getRun(c.req.valid('param').id);
|
|
3779
|
+
if (!run)
|
|
3780
|
+
return c.json({ error: 'not found' }, 404);
|
|
3781
|
+
const query = c.req.valid('query');
|
|
3782
|
+
const loaded = await loadFileLink({ dataDir, runId: run.id, projectRoot: root, workingDirectory: run.worktreePath ?? root, path: query.path });
|
|
3783
|
+
if (query.raw === '1') {
|
|
3784
|
+
if (!loaded.imageBytes || loaded.preview.type !== 'file')
|
|
3785
|
+
return c.json({ error: 'Only bounded raster images can be served inline.' }, 409);
|
|
3786
|
+
return c.body(new Uint8Array(loaded.imageBytes).buffer, 200, {
|
|
3787
|
+
'content-type': rasterMime(loaded.preview.path), 'x-content-type-options': 'nosniff',
|
|
3788
|
+
'content-security-policy': "default-src 'none'; sandbox", 'cache-control': 'private, no-store',
|
|
3789
|
+
});
|
|
3790
|
+
}
|
|
3791
|
+
return c.json(loaded.preview);
|
|
3792
|
+
})
|
|
3793
|
+
.get('/runs/:id/artifacts', paramZodValidator(artifactParamsSchema.omit({ artifactId: true })), async (c) => {
|
|
3794
|
+
const { dataDir, store } = c.get('project');
|
|
3795
|
+
const id = c.req.valid('param').id;
|
|
3796
|
+
if (!store.getRun(id))
|
|
3797
|
+
return c.json({ error: 'not found' }, 404);
|
|
3798
|
+
return c.json({ artifacts: await listArtifacts(artifactDirectory(dataDir, id), id) });
|
|
3799
|
+
})
|
|
3800
|
+
.get('/runs/:id/artifacts/:artifactId', paramZodValidator(artifactParamsSchema), async (c) => {
|
|
3801
|
+
const { dataDir, store } = c.get('project');
|
|
3802
|
+
const { id, artifactId } = c.req.valid('param');
|
|
3803
|
+
if (!store.getRun(id))
|
|
3804
|
+
return c.json({ error: 'not found' }, 404);
|
|
3805
|
+
const entry = await readArtifact(artifactDirectory(dataDir, id), id, artifactId);
|
|
3806
|
+
if (!entry)
|
|
3807
|
+
return c.json({ error: 'Published file is missing or unavailable.' }, 404);
|
|
3808
|
+
return c.json(artifactPreview(entry.metadata, entry.bytes));
|
|
3809
|
+
})
|
|
3810
|
+
.get('/runs/:id/artifacts/:artifactId/download', paramZodValidator(artifactParamsSchema), async (c) => {
|
|
3811
|
+
const { dataDir, store } = c.get('project');
|
|
3812
|
+
const { id, artifactId } = c.req.valid('param');
|
|
3813
|
+
if (!store.getRun(id))
|
|
3814
|
+
return c.json({ error: 'not found' }, 404);
|
|
3815
|
+
const entry = await readArtifact(artifactDirectory(dataDir, id), id, artifactId);
|
|
3816
|
+
if (!entry)
|
|
3817
|
+
return c.json({ error: 'Published file is missing or unavailable.' }, 404);
|
|
3818
|
+
return c.body(new Uint8Array(entry.bytes).buffer, 200, {
|
|
3819
|
+
'content-type': 'application/octet-stream', 'x-content-type-options': 'nosniff',
|
|
3820
|
+
'content-disposition': `attachment; filename="${entry.metadata.name.replace(/[^A-Za-z0-9._-]/g, '_')}"`,
|
|
3821
|
+
'content-security-policy': "default-src 'none'; sandbox", 'cache-control': 'private, no-store',
|
|
3822
|
+
});
|
|
3823
|
+
})
|
|
3824
|
+
.get('/runs/:id/artifacts/:artifactId/image', paramZodValidator(artifactParamsSchema), async (c) => {
|
|
3825
|
+
const { dataDir, store } = c.get('project');
|
|
3826
|
+
const { id, artifactId } = c.req.valid('param');
|
|
3827
|
+
if (!store.getRun(id))
|
|
3828
|
+
return c.json({ error: 'not found' }, 404);
|
|
3829
|
+
const entry = await readArtifact(artifactDirectory(dataDir, id), id, artifactId);
|
|
3830
|
+
if (!entry)
|
|
3831
|
+
return c.json({ error: 'Published file is missing or unavailable.' }, 404);
|
|
3832
|
+
const mime = rasterMime(entry.metadata.name);
|
|
3833
|
+
if (!mime)
|
|
3834
|
+
return c.json({ error: 'Only raster images can be served inline.' }, 409);
|
|
3835
|
+
return c.body(new Uint8Array(entry.bytes).buffer, 200, {
|
|
3836
|
+
'content-type': mime, 'x-content-type-options': 'nosniff',
|
|
3837
|
+
'content-security-policy': "default-src 'none'; sandbox", 'cache-control': 'private, no-store',
|
|
3838
|
+
});
|
|
3706
3839
|
})
|
|
3707
3840
|
// Files tab: directory listing (path omitted or a dir) or file content
|
|
3708
3841
|
// (size-capped, binary flagged). Traversal-safe — readWorktreePath rejects
|
|
@@ -5080,6 +5213,7 @@ export function createApp(deps) {
|
|
|
5080
5213
|
.route('/', projectsRoutes)
|
|
5081
5214
|
.route('/', agentProfilesRoutes)
|
|
5082
5215
|
.route('/', skillsUpdateRoutes)
|
|
5216
|
+
.route('/', applicationUpdateRoutes)
|
|
5083
5217
|
.route('/', workspaceConfigRoutes)
|
|
5084
5218
|
.route('/', fsBrowseRoutes)
|
|
5085
5219
|
.route('/', automationChecksRoutes)
|
|
@@ -5146,7 +5280,28 @@ export function startServer(deps, port) {
|
|
|
5146
5280
|
// hosted/VPS deployment (which also flips CEZ_REMOTE to gate the local-handoff endpoints) —
|
|
5147
5281
|
// src/index.ts never passes it, so the loopback guarantee holds for the normal CLI.
|
|
5148
5282
|
const server = serve({
|
|
5149
|
-
fetch:
|
|
5283
|
+
fetch: async (request, env) => {
|
|
5284
|
+
const result = await app.fetch(request, env);
|
|
5285
|
+
if (request.method === 'POST' && new URL(request.url).pathname === '/api/v1/workspace/application-update/restart'
|
|
5286
|
+
&& result.status === 200) {
|
|
5287
|
+
// Arming is server-owned. A connected caller must receive the complete
|
|
5288
|
+
// acknowledgement before shutdown; a caller that already disconnected
|
|
5289
|
+
// cannot leave its explicitly requested, armed restart stranded.
|
|
5290
|
+
const response = env.outgoing;
|
|
5291
|
+
const handoff = () => {
|
|
5292
|
+
response.off('finish', handoff);
|
|
5293
|
+
response.off('close', handoff);
|
|
5294
|
+
deps.applicationUpdate?.afterResponse?.();
|
|
5295
|
+
};
|
|
5296
|
+
if (response.destroyed)
|
|
5297
|
+
handoff();
|
|
5298
|
+
else {
|
|
5299
|
+
response.once('finish', handoff);
|
|
5300
|
+
response.once('close', handoff);
|
|
5301
|
+
}
|
|
5302
|
+
}
|
|
5303
|
+
return result;
|
|
5304
|
+
},
|
|
5150
5305
|
port,
|
|
5151
5306
|
hostname: deps.bindHost ?? '127.0.0.1',
|
|
5152
5307
|
});
|
|
@@ -5239,7 +5394,18 @@ export function startServer(deps, port) {
|
|
|
5239
5394
|
});
|
|
5240
5395
|
server.once('close', () => { unsubscribe(); coordinator.stop(); automationScheduler.stop(); sharedContexts.disposeAll(); void deps.delegation?.close(); });
|
|
5241
5396
|
socketHub.attach(server, (req) => verifyWsUpgrade(req, deps.bindHost));
|
|
5242
|
-
|
|
5397
|
+
const shutdownForRestart = async () => {
|
|
5398
|
+
sharedContexts.disposeAll(); // flush every built secondary project before old process exits
|
|
5399
|
+
deps.store.flush();
|
|
5400
|
+
socketHub.close();
|
|
5401
|
+
await deps.delegation?.close();
|
|
5402
|
+
await new Promise((resolve) => {
|
|
5403
|
+
server.close(() => resolve());
|
|
5404
|
+
if ('closeAllConnections' in server)
|
|
5405
|
+
server.closeAllConnections();
|
|
5406
|
+
});
|
|
5407
|
+
};
|
|
5408
|
+
return Object.assign(server, { shutdownForRestart });
|
|
5243
5409
|
}
|
|
5244
5410
|
/**
|
|
5245
5411
|
* The WebSocket twin of the `/api/*` request-origin guard (#426), applied
|