@capybara-hq/kernel 0.1.0-rc.23 → 0.1.0-rc.24
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/bootstrap.json +25 -25
- package/dist/admin/admin.module.d.ts +2 -1
- package/dist/admin/admin.module.js +7 -3
- package/dist/admin/outbox-dead.controller.d.ts +23 -0
- package/dist/admin/outbox-dead.controller.js +62 -0
- package/dist/admin/outbox-dead.schemas.d.ts +8 -0
- package/dist/admin/outbox-dead.schemas.js +18 -0
- package/dist/admin/outbox-dead.service.d.ts +66 -0
- package/dist/admin/outbox-dead.service.js +179 -0
- package/dist/admin/overview.service.d.ts +40 -5
- package/dist/admin/overview.service.js +41 -7
- package/dist/agents/from-template.js +1 -1
- package/dist/background/finish.d.ts +5 -2
- package/dist/background/finish.js +14 -3
- package/dist/background/launch.d.ts +2 -1
- package/dist/background/launch.js +5 -2
- package/dist/background/store.d.ts +8 -0
- package/dist/background/store.js +24 -0
- package/dist/catalog/admin-catalog.controller.d.ts +21 -2
- package/dist/catalog/admin-catalog.controller.js +45 -6
- package/dist/catalog/admin-catalog.schemas.d.ts +5 -0
- package/dist/catalog/admin-catalog.schemas.js +8 -0
- package/dist/catalog/catalog.module.d.ts +2 -1
- package/dist/catalog/catalog.module.js +5 -1
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/platform-import-update.d.ts +50 -0
- package/dist/catalog/platform-import-update.js +116 -0
- package/dist/catalog/plugin-import.d.ts +36 -1
- package/dist/catalog/plugin-import.js +23 -1
- package/dist/catalog/plugin-upgrade.d.ts +18 -0
- package/dist/catalog/plugin-upgrade.js +19 -0
- package/dist/channels/channels.module.d.ts +5 -2
- package/dist/channels/channels.module.js +9 -2
- package/dist/channels/deliver-job.d.ts +25 -0
- package/dist/channels/deliver-job.js +25 -0
- package/dist/channels/inbound.d.ts +1 -1
- package/dist/channels/inbound.js +2 -15
- package/dist/channels/jobs.d.ts +28 -18
- package/dist/channels/jobs.js +63 -26
- package/dist/config/schema.d.ts +0 -3
- package/dist/config/schema.js +11 -20
- package/dist/conversations/agent-tree.d.ts +16 -0
- package/dist/conversations/agent-tree.js +36 -0
- package/dist/conversations/conversations.service.d.ts +44 -14
- package/dist/conversations/conversations.service.js +52 -38
- package/dist/conversations/event-log.d.ts +7 -10
- package/dist/conversations/event-log.js +24 -15
- package/dist/conversations/events.js +2 -1
- package/dist/conversations/queue.service.d.ts +8 -3
- package/dist/conversations/queue.service.js +37 -13
- package/dist/conversations/titles.d.ts +21 -8
- package/dist/conversations/titles.js +42 -15
- package/dist/db/kernel-schema.d.ts +26 -8
- package/dist/devices/devices.service.d.ts +12 -3
- package/dist/devices/devices.service.js +18 -3
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +11 -0
- package/dist/evals/run-replay.js +14 -8
- package/dist/extensions/extensions.module.js +3 -0
- package/dist/extensions/lifecycle.d.ts +6 -1
- package/dist/extensions/lifecycle.js +9 -2
- package/dist/extensions/usage-subscribers.d.ts +43 -0
- package/dist/extensions/usage-subscribers.js +108 -0
- package/dist/http/api.module.js +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/infra/cli/kernel-cli.module.js +5 -0
- package/dist/infra/events/kernel-events.d.ts +9 -35
- package/dist/infra/outbox/outbox-relay.module.d.ts +6 -0
- package/dist/infra/outbox/outbox-relay.module.js +18 -0
- package/dist/infra/outbox/outbox.dispatcher.d.ts +103 -0
- package/dist/infra/outbox/outbox.dispatcher.js +310 -0
- package/dist/infra/outbox/outbox.module.d.ts +24 -0
- package/dist/infra/outbox/outbox.module.js +50 -0
- package/dist/infra/outbox/outbox.relay.d.ts +31 -0
- package/dist/infra/outbox/outbox.relay.js +76 -0
- package/dist/infra/outbox/outbox.service.d.ts +51 -0
- package/dist/infra/outbox/outbox.service.js +131 -0
- package/dist/infra/outbox/registry.d.ts +120 -0
- package/dist/infra/outbox/registry.js +108 -0
- package/dist/infra/queue/queue-names.d.ts +8 -0
- package/dist/infra/queue/queue-names.js +16 -0
- package/dist/kernel.module.js +3 -0
- package/dist/local-devices/device-policy.service.d.ts +4 -0
- package/dist/local-devices/device-policy.service.js +61 -3
- package/dist/local-devices/machines.d.ts +13 -5
- package/dist/local-devices/machines.js +45 -7
- package/dist/local-devices/policy-summary.d.ts +44 -1
- package/dist/local-devices/policy-summary.js +69 -0
- package/dist/models/embeddings.d.ts +9 -9
- package/dist/models/embeddings.js +11 -18
- package/dist/models/models.module.js +3 -0
- package/dist/orgs/orgs.service.js +7 -0
- package/dist/overrides.d.ts +20 -3
- package/dist/overrides.js +10 -2
- package/dist/platform/exclusions.js +5 -0
- package/dist/platform/ops/admin.ops.js +18 -2
- package/dist/platform/ops/catalog-admin.ops.d.ts +3 -1
- package/dist/platform/ops/catalog-admin.ops.js +32 -4
- package/dist/platform/ops/outbox.ops.d.ts +21 -0
- package/dist/platform/ops/outbox.ops.js +125 -0
- package/dist/platform/ops/schedules.ops.js +40 -1
- package/dist/platform/platform-ops.module.d.ts +2 -1
- package/dist/platform/platform-ops.module.js +3 -0
- package/dist/platform/route-schemas.js +3 -0
- package/dist/roles/worker.module.js +9 -4
- package/dist/runtime/langgraph-loop.js +13 -5
- package/dist/runtime/limits.d.ts +15 -0
- package/dist/runtime/limits.js +25 -0
- package/dist/runtime/loop.d.ts +8 -3
- package/dist/runtime/loop.js +2 -1
- package/dist/runtime/maintenance.d.ts +4 -2
- package/dist/runtime/maintenance.js +17 -2
- package/dist/runtime/model-call.d.ts +14 -16
- package/dist/runtime/model-call.js +14 -24
- package/dist/runtime/queue-lost-jobs.d.ts +24 -0
- package/dist/runtime/queue-lost-jobs.js +51 -0
- package/dist/runtime/run-control.d.ts +42 -5
- package/dist/runtime/run-control.js +66 -12
- package/dist/runtime/run-finish.d.ts +39 -12
- package/dist/runtime/run-finish.js +97 -14
- package/dist/runtime/run-jobs.d.ts +95 -13
- package/dist/runtime/run-jobs.js +199 -28
- package/dist/runtime/run-orphan-check.job.d.ts +142 -0
- package/dist/runtime/run-orphan-check.job.js +339 -0
- package/dist/runtime/run-processors.d.ts +16 -9
- package/dist/runtime/run-processors.js +1 -1
- package/dist/runtime/run-queue.d.ts +64 -55
- package/dist/runtime/run-queue.js +147 -284
- package/dist/runtime/run-steps.d.ts +1 -2
- package/dist/runtime/run-steps.js +8 -11
- package/dist/runtime/run-worker.d.ts +6 -17
- package/dist/runtime/run-worker.js +32 -34
- package/dist/runtime/runtime.module.d.ts +2 -3
- package/dist/runtime/runtime.module.js +5 -6
- package/dist/runtime/step-log.d.ts +16 -4
- package/dist/runtime/step-log.js +26 -6
- package/dist/runtime/stream.controller.d.ts +2 -4
- package/dist/runtime/stream.controller.js +5 -11
- package/dist/runtime/subagents/child.js +1 -1
- package/dist/runtime/subagents/definition.d.ts +2 -1
- package/dist/runtime/subagents/definition.js +4 -2
- package/dist/runtime/subagents/deliveries.d.ts +6 -3
- package/dist/runtime/subagents/deliveries.js +16 -7
- package/dist/runtime/subagents/dispatch.d.ts +12 -12
- package/dist/runtime/subagents/dispatch.js +13 -38
- package/dist/runtime/subagents/messages.d.ts +5 -1
- package/dist/runtime/subagents/messages.js +11 -3
- package/dist/runtime/subagents/skill-fork.d.ts +3 -3
- package/dist/runtime/subagents/skill-fork.js +5 -5
- package/dist/runtime/subagents/subagents.service.js +1 -1
- package/dist/runtime/subagents/tree-jobs.d.ts +61 -0
- package/dist/runtime/subagents/tree-jobs.js +86 -0
- package/dist/runtime/usage-report-jobs.d.ts +23 -48
- package/dist/runtime/usage-report-jobs.js +67 -119
- package/dist/runtime/usage-report.d.ts +28 -77
- package/dist/runtime/usage-report.js +35 -213
- package/dist/runtime/waits.d.ts +48 -198
- package/dist/runtime/waits.js +103 -805
- package/dist/sandbox/sandbox.service.d.ts +17 -4
- package/dist/sandbox/sandbox.service.js +55 -14
- package/dist/schedules/calendar.d.ts +134 -0
- package/dist/schedules/calendar.js +410 -0
- package/dist/schedules/fire.d.ts +1 -3
- package/dist/schedules/fire.js +5 -10
- package/dist/schedules/run-tracker.d.ts +0 -5
- package/dist/schedules/run-tracker.js +0 -13
- package/dist/schedules/scan.job.js +15 -20
- package/dist/schedules/schedule-math.d.ts +42 -0
- package/dist/schedules/schedule-math.js +52 -0
- package/dist/schedules/scheduled-tasks.service.d.ts +16 -0
- package/dist/schedules/scheduled-tasks.service.js +53 -0
- package/dist/schedules/schedules.controller.d.ts +5 -1
- package/dist/schedules/schedules.controller.js +15 -1
- package/dist/schedules/schedules.schemas.d.ts +35 -0
- package/dist/schedules/schedules.schemas.js +27 -0
- package/dist/schedules/store.d.ts +5 -0
- package/dist/schedules/store.js +20 -0
- package/dist/tools/approvals.service.d.ts +26 -7
- package/dist/tools/approvals.service.js +88 -10
- package/dist/tools/builtin-names.d.ts +5 -3
- package/dist/tools/builtin-names.js +12 -4
- package/dist/tools/builtins/builtin-tools.d.ts +1 -2
- package/dist/tools/builtins/builtin-tools.js +21 -17
- package/dist/tools/builtins/sandbox/bash.js +9 -3
- package/dist/tools/builtins/sandbox/common.d.ts +18 -1
- package/dist/tools/builtins/sandbox/common.js +14 -1
- package/dist/tools/builtins/sandbox/index.d.ts +2 -1
- package/dist/tools/builtins/sandbox/index.js +4 -1
- package/dist/tools/builtins/sandbox/task-list.d.ts +12 -0
- package/dist/tools/builtins/sandbox/task-list.js +130 -0
- package/dist/tools/builtins/sandbox/task-output.d.ts +8 -1
- package/dist/tools/builtins/sandbox/task-output.js +21 -3
- package/dist/tools/builtins/web/extract.d.ts +2 -4
- package/dist/tools/builtins/web/extract.js +2 -5
- package/dist/tools/pipeline.d.ts +1 -1
- package/dist/tools/pipeline.js +1 -1
- package/dist/tools/questions.service.d.ts +15 -6
- package/dist/tools/questions.service.js +20 -8
- package/dist/tools/registry.d.ts +4 -2
- package/dist/tools/registry.js +4 -3
- package/dist/tools/tools.module.js +4 -3
- package/package.json +3 -3
- package/src/migrations/0118_device_policy_ops.sql +6 -0
- package/src/migrations/0119_outbox.sql +22 -0
- package/src/migrations/0120_drop_usage_report_sweep.sql +7 -0
|
@@ -18,6 +18,8 @@ import { PlatformInboxService } from "../inbox/platform-inbox.service.js";
|
|
|
18
18
|
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
19
19
|
import { OrgsService } from "../orgs/orgs.service.js";
|
|
20
20
|
import { ProviderRegistry } from "../runtime/providers.js";
|
|
21
|
+
import { QueueLostJobs } from "../runtime/queue-lost-jobs.js";
|
|
22
|
+
import { OutboxDeadService } from "./outbox-dead.service.js";
|
|
21
23
|
/** The most rows each attention list returns; the rest are counted in `more`. */
|
|
22
24
|
export const ATTENTION_LIST_MAX = 20;
|
|
23
25
|
/** The reason an extension is listed, or null when it needs nothing. */
|
|
@@ -53,8 +55,9 @@ export function providerProblem(p) {
|
|
|
53
55
|
/**
|
|
54
56
|
* The admin overview (spec §4.1, §5.2): its numbers and the 待处理 lists, read live from the
|
|
55
57
|
* sources the admin pages read (`ExtensionAdmin`, the catalog, the provider registry's cached
|
|
56
|
-
* lists). Each source is read on its own: a failing one is reported in
|
|
57
|
-
* audited (decision D5) and not cached further (every source is PG
|
|
58
|
+
* lists, the dead outbox rows, the run queue's lost-jobs canary). Each source is read on its own: a failing one is reported in
|
|
59
|
+
* `unavailable`. Reads are not audited (decision D5) and not cached further (every source is PG
|
|
60
|
+
* or already Redis-cached).
|
|
58
61
|
*/
|
|
59
62
|
let AdminOverviewService = class AdminOverviewService {
|
|
60
63
|
extensions;
|
|
@@ -66,8 +69,10 @@ let AdminOverviewService = class AdminOverviewService {
|
|
|
66
69
|
orgs;
|
|
67
70
|
accounts;
|
|
68
71
|
marketplaces;
|
|
72
|
+
outboxDead;
|
|
73
|
+
lostJobs;
|
|
69
74
|
log;
|
|
70
|
-
constructor(extensions, catalog, registry, displayNames, icons, inbox, orgs, accounts, marketplaces, log) {
|
|
75
|
+
constructor(extensions, catalog, registry, displayNames, icons, inbox, orgs, accounts, marketplaces, outboxDead, lostJobs, log) {
|
|
71
76
|
this.extensions = extensions;
|
|
72
77
|
this.catalog = catalog;
|
|
73
78
|
this.registry = registry;
|
|
@@ -77,6 +82,8 @@ let AdminOverviewService = class AdminOverviewService {
|
|
|
77
82
|
this.orgs = orgs;
|
|
78
83
|
this.accounts = accounts;
|
|
79
84
|
this.marketplaces = marketplaces;
|
|
85
|
+
this.outboxDead = outboxDead;
|
|
86
|
+
this.lostJobs = lostJobs;
|
|
80
87
|
this.log = log;
|
|
81
88
|
}
|
|
82
89
|
async stats() {
|
|
@@ -87,10 +94,17 @@ let AdminOverviewService = class AdminOverviewService {
|
|
|
87
94
|
this.attention(),
|
|
88
95
|
]);
|
|
89
96
|
const listed = (s) => attention[s].length + attention.more[s];
|
|
97
|
+
// each dead row waits for a super admin, not the one item that counts them
|
|
98
|
+
const dead = attention.outbox.reduce((n, o) => n + o.count, 0);
|
|
90
99
|
return {
|
|
91
100
|
orgs: orgs.length,
|
|
92
101
|
accounts,
|
|
93
|
-
attentionTotal: inbox +
|
|
102
|
+
attentionTotal: inbox +
|
|
103
|
+
listed("extensions") +
|
|
104
|
+
listed("updates") +
|
|
105
|
+
listed("providers") +
|
|
106
|
+
dead +
|
|
107
|
+
attention.queue.length,
|
|
94
108
|
partial: attention.unavailable.length > 0,
|
|
95
109
|
};
|
|
96
110
|
}
|
|
@@ -98,16 +112,20 @@ let AdminOverviewService = class AdminOverviewService {
|
|
|
98
112
|
// the catalog is read once: the update rows, and the plugins the inbox already lists
|
|
99
113
|
const items = this.catalogItems();
|
|
100
114
|
items.catch(() => { }); // awaited (and reported) by updateRows
|
|
101
|
-
const [extensions, updates, providers] = await Promise.allSettled([
|
|
115
|
+
const [extensions, updates, providers, outbox, queue] = await Promise.allSettled([
|
|
102
116
|
this.extensionRows(items),
|
|
103
117
|
this.updateRows(items),
|
|
104
118
|
this.providerRows(),
|
|
119
|
+
this.outboxRows(),
|
|
120
|
+
this.queueRows(),
|
|
105
121
|
]);
|
|
106
122
|
const out = {
|
|
107
123
|
extensions: [],
|
|
108
124
|
updates: [],
|
|
109
125
|
providers: [],
|
|
110
|
-
|
|
126
|
+
outbox: [],
|
|
127
|
+
queue: [],
|
|
128
|
+
more: { extensions: 0, updates: 0, providers: 0, outbox: 0, queue: 0 },
|
|
111
129
|
unavailable: [],
|
|
112
130
|
};
|
|
113
131
|
/** The rows of a source that answered (capped), or none and its name in `unavailable`. */
|
|
@@ -127,8 +145,22 @@ let AdminOverviewService = class AdminOverviewService {
|
|
|
127
145
|
out.extensions = take("extensions", extensions);
|
|
128
146
|
out.updates = take("updates", updates);
|
|
129
147
|
out.providers = take("providers", providers);
|
|
148
|
+
out.outbox = take("outbox", outbox);
|
|
149
|
+
out.queue = take("queue", queue);
|
|
130
150
|
return out;
|
|
131
151
|
}
|
|
152
|
+
/** The `queue_lost_jobs` item when the run queue lost jobs this week, else none. */
|
|
153
|
+
async queueRows() {
|
|
154
|
+
const lost = await this.lostJobs.summary();
|
|
155
|
+
return lost === null ? [] : [{ kind: "queue_lost_jobs", ...lost }];
|
|
156
|
+
}
|
|
157
|
+
/** The `outbox_dead` item when some outbox rows are dead, else none. */
|
|
158
|
+
async outboxRows() {
|
|
159
|
+
const { count, oldestAt } = await this.outboxDead.summary();
|
|
160
|
+
if (count === 0 || oldestAt === null)
|
|
161
|
+
return [];
|
|
162
|
+
return [{ kind: "outbox_dead", count, oldestAt: oldestAt.toISOString() }];
|
|
163
|
+
}
|
|
132
164
|
/**
|
|
133
165
|
* The extensions needing a look, but not one pending approval whose plugin waits in the platform
|
|
134
166
|
* inbox (a permission confirmation or an org upload: the inbox already lists and counts it). A
|
|
@@ -218,6 +250,8 @@ AdminOverviewService = __decorate([
|
|
|
218
250
|
__param(6, Inject(OrgsService)),
|
|
219
251
|
__param(7, Inject(AccountsService)),
|
|
220
252
|
__param(8, Inject(MarketplacesService)),
|
|
221
|
-
__param(9, Inject(
|
|
253
|
+
__param(9, Inject(OutboxDeadService)),
|
|
254
|
+
__param(10, Inject(QueueLostJobs)),
|
|
255
|
+
__param(11, Inject(KERNEL_LOGGER))
|
|
222
256
|
], AdminOverviewService);
|
|
223
257
|
export { AdminOverviewService };
|
|
@@ -329,7 +329,7 @@ export async function planFromTemplate(db, orgId, row, opts) {
|
|
|
329
329
|
}
|
|
330
330
|
if (describesSubagents)
|
|
331
331
|
listed.add(AGENT_TOOL);
|
|
332
|
-
// `TaskOutput` / `TaskStop` follow `Bash`
|
|
332
|
+
// `TaskOutput` / `TaskStop` / `TaskList` follow `Bash`
|
|
333
333
|
for (const name of AGENT_BUILTIN_NAMES)
|
|
334
334
|
if (!listed.has(name))
|
|
335
335
|
offBuiltin(name);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventLog } from "../conversations/event-log.js";
|
|
2
2
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
3
3
|
import { KernelEvents } from "../infra/events/kernel-events.js";
|
|
4
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
4
5
|
import { type BackgroundTaskRow, BackgroundTaskStore } from "./store.js";
|
|
5
6
|
/** Where a task ends (as {@link BackgroundTaskStore.finish} takes it). */
|
|
6
7
|
export type BackgroundFinish = Parameters<BackgroundTaskStore["finish"]>[1];
|
|
@@ -19,7 +20,8 @@ export declare const finishedEventKey: (taskId: string) => string;
|
|
|
19
20
|
* task (two pollers, a poll and a stop) exactly one writes it. After the commit: the log's notify,
|
|
20
21
|
* the `changed: "background"` frame (to the owner and, for a sub-agent's task, the conversation
|
|
21
22
|
* that owns the sandbox, whose panel lists it too) and the `background_task.finished` domain event
|
|
22
|
-
* (`BackgroundWake` wakes an idle conversation; it lives in the runtime, above this module).
|
|
23
|
+
* (`BackgroundWake` wakes an idle conversation; it lives in the runtime, above this module). A
|
|
24
|
+
* finish that may wake the conversation also owes the ensure-run backstop in the transaction.
|
|
23
25
|
*
|
|
24
26
|
* Holds no lock and runs no sandbox command: the caller reads `lastLines` before.
|
|
25
27
|
*/
|
|
@@ -28,7 +30,8 @@ export declare class BackgroundTaskFinisher {
|
|
|
28
30
|
private readonly eventLog;
|
|
29
31
|
private readonly events;
|
|
30
32
|
readonly txHost: TransactionHost;
|
|
31
|
-
|
|
33
|
+
private readonly outbox;
|
|
34
|
+
constructor(store: Pick<BackgroundTaskStore, "finish">, eventLog: EventLog, events: KernelEvents, txHost: TransactionHost, outbox: Pick<OutboxService, "add">);
|
|
32
35
|
/**
|
|
33
36
|
* Finishes `task` as `to` with its last output lines (cut to their last 4 000 characters);
|
|
34
37
|
* `reported` when a tool call already told the model in its run. False (nothing written) when the
|
|
@@ -13,6 +13,8 @@ import { afterCommit } from "../infra/database/after-commit.js";
|
|
|
13
13
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
14
14
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
15
15
|
import { KernelEvents } from "../infra/events/kernel-events.js";
|
|
16
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
17
|
+
import { oweEnsureRun } from "../runtime/run-jobs.js";
|
|
16
18
|
import { taskOutputFile } from "./launch.js";
|
|
17
19
|
import { LAST_LINES_MAX_CHARS } from "./session.js";
|
|
18
20
|
import { BackgroundTaskStore } from "./store.js";
|
|
@@ -25,7 +27,8 @@ export const finishedEventKey = (taskId) => `background_task_finished:${taskId}`
|
|
|
25
27
|
* task (two pollers, a poll and a stop) exactly one writes it. After the commit: the log's notify,
|
|
26
28
|
* the `changed: "background"` frame (to the owner and, for a sub-agent's task, the conversation
|
|
27
29
|
* that owns the sandbox, whose panel lists it too) and the `background_task.finished` domain event
|
|
28
|
-
* (`BackgroundWake` wakes an idle conversation; it lives in the runtime, above this module).
|
|
30
|
+
* (`BackgroundWake` wakes an idle conversation; it lives in the runtime, above this module). A
|
|
31
|
+
* finish that may wake the conversation also owes the ensure-run backstop in the transaction.
|
|
29
32
|
*
|
|
30
33
|
* Holds no lock and runs no sandbox command: the caller reads `lastLines` before.
|
|
31
34
|
*/
|
|
@@ -34,11 +37,13 @@ let BackgroundTaskFinisher = class BackgroundTaskFinisher {
|
|
|
34
37
|
eventLog;
|
|
35
38
|
events;
|
|
36
39
|
txHost;
|
|
37
|
-
|
|
40
|
+
outbox;
|
|
41
|
+
constructor(store, eventLog, events, txHost, outbox) {
|
|
38
42
|
this.store = store;
|
|
39
43
|
this.eventLog = eventLog;
|
|
40
44
|
this.events = events;
|
|
41
45
|
this.txHost = txHost;
|
|
46
|
+
this.outbox = outbox;
|
|
42
47
|
}
|
|
43
48
|
/**
|
|
44
49
|
* Finishes `task` as `to` with its last output lines (cut to their last 4 000 characters);
|
|
@@ -71,6 +76,11 @@ let BackgroundTaskFinisher = class BackgroundTaskFinisher {
|
|
|
71
76
|
},
|
|
72
77
|
},
|
|
73
78
|
]);
|
|
79
|
+
// a finish that may wake the conversation owes the ensure-run backstop with its event: the
|
|
80
|
+
// wake after the commit (`BackgroundWake`) may never happen (transactional outbox spec §6)
|
|
81
|
+
if (event && !reported && opts.stoppedBy === undefined) {
|
|
82
|
+
await oweEnsureRun(this.outbox, task.conversationId, event.seq, task.orgId);
|
|
83
|
+
}
|
|
74
84
|
const conversations = [...new Set([task.conversationId, task.sandboxConversationId])];
|
|
75
85
|
afterCommit(async () => {
|
|
76
86
|
if (event)
|
|
@@ -90,6 +100,7 @@ BackgroundTaskFinisher = __decorate([
|
|
|
90
100
|
__param(0, Inject(BackgroundTaskStore)),
|
|
91
101
|
__param(1, Inject(EventLog)),
|
|
92
102
|
__param(2, Inject(KernelEvents)),
|
|
93
|
-
__param(3, Inject(TransactionHost))
|
|
103
|
+
__param(3, Inject(TransactionHost)),
|
|
104
|
+
__param(4, Inject(OutboxService))
|
|
94
105
|
], BackgroundTaskFinisher);
|
|
95
106
|
export { BackgroundTaskFinisher };
|
|
@@ -70,7 +70,8 @@ export declare const GROUP_LAUNCHER: string;
|
|
|
70
70
|
* `setsid nohup sh -c 'timeout -s KILL <seconds> …'` and the sid is `$!`, the pid `setsid` started;
|
|
71
71
|
* elsewhere (macOS: no `setsid`, no `timeout`, no `pgrep -s`) {@link GROUP_LAUNCHER} runs it in a
|
|
72
72
|
* process group of its own, watched by the launcher, and writes the sid (the group id) itself,
|
|
73
|
-
* which the launch waits for (up to 10 s).
|
|
73
|
+
* which the launch waits for (up to 10 s). The script starts with `BACKGROUND_LAUNCH_LINE`, so a
|
|
74
|
+
* local device, which kills what any other exec leaves running, leaves the task alone. An
|
|
74
75
|
* environment without one of the needed programs fails with a readable error on stderr and exit
|
|
75
76
|
* code 127, before anything starts. `id` must be a task id and `seconds` a positive integer (both
|
|
76
77
|
* go into the script unquoted).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import { DEFAULT_SANDBOX_ROOTS } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import { BACKGROUND_LAUNCH_LINE, DEFAULT_SANDBOX_ROOTS } from "@capybara-hq/plugin-sdk";
|
|
3
3
|
/**
|
|
4
4
|
* Launching a background Bash task (spec 2026-11-05-background-bash-design §4.2): the task id, the
|
|
5
5
|
* one short exec that starts the command detached from the exec, and the model-visible result.
|
|
@@ -112,7 +112,8 @@ export const GROUP_LAUNCHER = [
|
|
|
112
112
|
* `setsid nohup sh -c 'timeout -s KILL <seconds> …'` and the sid is `$!`, the pid `setsid` started;
|
|
113
113
|
* elsewhere (macOS: no `setsid`, no `timeout`, no `pgrep -s`) {@link GROUP_LAUNCHER} runs it in a
|
|
114
114
|
* process group of its own, watched by the launcher, and writes the sid (the group id) itself,
|
|
115
|
-
* which the launch waits for (up to 10 s).
|
|
115
|
+
* which the launch waits for (up to 10 s). The script starts with `BACKGROUND_LAUNCH_LINE`, so a
|
|
116
|
+
* local device, which kills what any other exec leaves running, leaves the task alone. An
|
|
116
117
|
* environment without one of the needed programs fails with a readable error on stderr and exit
|
|
117
118
|
* code 127, before anything starts. `id` must be a task id and `seconds` a positive integer (both
|
|
118
119
|
* go into the script unquoted).
|
|
@@ -127,6 +128,8 @@ export function launchScript(id, command, seconds) {
|
|
|
127
128
|
const t = `${TASKS_DIR}/${id}`;
|
|
128
129
|
const need = (list) => `for c in ${list.join(" ")}; do command -v "$c" >/dev/null 2>&1 || { echo "Background tasks need ${list.join(", ")} in this environment; $c is missing." >&2; exit 127; }; done`;
|
|
129
130
|
return [
|
|
131
|
+
// first: a local device kills what an exec leaves running, except a launch's detached task
|
|
132
|
+
BACKGROUND_LAUNCH_LINE,
|
|
130
133
|
"set -e",
|
|
131
134
|
SESSION_MODE_SCRIPT,
|
|
132
135
|
`if [ "$pg" = -s ]; then ${need(REQUIRED_SESSION)}; else ${need(REQUIRED_GROUP)}; fi`,
|
|
@@ -137,6 +137,14 @@ export declare class BackgroundTaskStore {
|
|
|
137
137
|
runningStarted(): Promise<BackgroundTaskRow[]>;
|
|
138
138
|
/** The running tasks one conversation owns (not those of its sub-agents), oldest first. */
|
|
139
139
|
runningOwnedBy(conversationId: string): Promise<BackgroundTaskRow[]>;
|
|
140
|
+
/**
|
|
141
|
+
* The finished tasks one conversation owns (not those of its sub-agents), the most recently
|
|
142
|
+
* finished first, at most `limit` of them, with how many it owns in all (`TaskList`).
|
|
143
|
+
*/
|
|
144
|
+
finishedOwnedBy(conversationId: string, limit: number): Promise<{
|
|
145
|
+
rows: BackgroundTaskRow[];
|
|
146
|
+
total: number;
|
|
147
|
+
}>;
|
|
140
148
|
/** The running tasks of one root conversation's tree (what `maxTasks` limits). */
|
|
141
149
|
countRunning(sandboxConversationId: string): Promise<number>;
|
|
142
150
|
/** The tasks owned by any of the conversations, newest first. */
|
package/dist/background/store.js
CHANGED
|
@@ -258,6 +258,30 @@ let BackgroundTaskStore = class BackgroundTaskStore {
|
|
|
258
258
|
.execute();
|
|
259
259
|
return rows.map(toRow);
|
|
260
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* The finished tasks one conversation owns (not those of its sub-agents), the most recently
|
|
263
|
+
* finished first, at most `limit` of them, with how many it owns in all (`TaskList`).
|
|
264
|
+
*/
|
|
265
|
+
async finishedOwnedBy(conversationId, limit) {
|
|
266
|
+
const [rows, count] = await Promise.all([
|
|
267
|
+
this.db
|
|
268
|
+
.selectFrom("background_tasks")
|
|
269
|
+
.selectAll()
|
|
270
|
+
.where("conversation_id", "=", conversationId)
|
|
271
|
+
.where("status", "<>", "running")
|
|
272
|
+
.orderBy("finished_at", "desc")
|
|
273
|
+
.orderBy("id", "desc")
|
|
274
|
+
.limit(limit)
|
|
275
|
+
.execute(),
|
|
276
|
+
this.db
|
|
277
|
+
.selectFrom("background_tasks")
|
|
278
|
+
.select((eb) => eb.fn.countAll().as("n"))
|
|
279
|
+
.where("conversation_id", "=", conversationId)
|
|
280
|
+
.where("status", "<>", "running")
|
|
281
|
+
.executeTakeFirstOrThrow(),
|
|
282
|
+
]);
|
|
283
|
+
return { rows: rows.map(toRow), total: Number(count.n) };
|
|
284
|
+
}
|
|
261
285
|
/** The running tasks of one root conversation's tree (what `maxTasks` limits). */
|
|
262
286
|
async countRunning(sandboxConversationId) {
|
|
263
287
|
const r = await this.db
|
|
@@ -5,12 +5,13 @@ import { type ClientBuildSummary, ClientBuilds } from "../client/client-builds.s
|
|
|
5
5
|
import { PluginGuides, type RenderedSetupGuide } from "../extensions/plugin-guides.js";
|
|
6
6
|
import { PluginIcons } from "../extensions/plugin-icons.js";
|
|
7
7
|
import { type Principal } from "../identity/principal.js";
|
|
8
|
-
import { AdminCatalogGuideQuery, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogNpmImportBody as NpmBody, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody } from "./admin-catalog.schemas.js";
|
|
8
|
+
import { AdminCatalogGuideQuery, CatalogImportUpdateBody, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogNpmImportBody as NpmBody, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody } from "./admin-catalog.schemas.js";
|
|
9
9
|
import { AppearanceApplyBody } from "./appearance.schemas.js";
|
|
10
10
|
import { type AppearanceResult, AppearanceService } from "./appearance.service.js";
|
|
11
11
|
import { type CatalogItemDetail, type CatalogItemView, CatalogService, type PermissionsMismatch } from "./catalog.service.js";
|
|
12
12
|
import { CatalogScopeService, type ScopePreview } from "./catalog-scope.service.js";
|
|
13
13
|
import { OrgCatalogService } from "./org-catalog.service.js";
|
|
14
|
+
import { PlatformImportUpdate, type PlatformImportUpdateResult } from "./platform-import-update.js";
|
|
14
15
|
import { type PluginConfirmResult, PluginImport, type PluginReview } from "./plugin-import.js";
|
|
15
16
|
import { PlatformPluginUpdater, type PlatformUpdatePreview, type PlatformUpdateResult } from "./plugin-upgrade.js";
|
|
16
17
|
declare const ConfirmBody: z.ZodObject<{
|
|
@@ -41,11 +42,12 @@ export declare class AdminCatalogController {
|
|
|
41
42
|
private readonly orgCatalog;
|
|
42
43
|
private readonly scope;
|
|
43
44
|
private readonly updater;
|
|
45
|
+
private readonly importUpdate;
|
|
44
46
|
private readonly icons;
|
|
45
47
|
private readonly appearance;
|
|
46
48
|
private readonly clientBuilds;
|
|
47
49
|
private readonly guides;
|
|
48
|
-
constructor(catalog: CatalogService, pluginImport: PluginImport, orgCatalog: OrgCatalogService, scope: CatalogScopeService, updater: PlatformPluginUpdater, icons: PluginIcons, appearance: AppearanceService, clientBuilds: ClientBuilds, guides: PluginGuides);
|
|
50
|
+
constructor(catalog: CatalogService, pluginImport: PluginImport, orgCatalog: OrgCatalogService, scope: CatalogScopeService, updater: PlatformPluginUpdater, importUpdate: PlatformImportUpdate, icons: PluginIcons, appearance: AppearanceService, clientBuilds: ClientBuilds, guides: PluginGuides);
|
|
49
51
|
/**
|
|
50
52
|
* Prepares the import of an uploaded plugin (an npm-pack tgz as the raw body,
|
|
51
53
|
* `application/octet-stream`, at most `packages.maxBytes`): reads and checks the whole plugin
|
|
@@ -108,6 +110,23 @@ export declare class AdminCatalogController {
|
|
|
108
110
|
* is an unknown field (400 `validation_failed`).
|
|
109
111
|
*/
|
|
110
112
|
confirm(principal: Principal, stagingId: string, body: z.infer<typeof ConfirmBody>): Promise<PluginConfirmResult>;
|
|
113
|
+
/**
|
|
114
|
+
* What confirming a staged new version of an installed platform plugin would do as the platform
|
|
115
|
+
* update (`PlatformImportUpdate`, the one 更新到 wizard): the update preview of the staged
|
|
116
|
+
* version, nothing written (cancelling the wizard leaves only the staging row). Not a platform
|
|
117
|
+
* plugin yet -> 409 `plugin.upgrade_target_invalid` (reason `not_installed`); staging missing ->
|
|
118
|
+
* 404 `plugin.staging_not_found`; otherwise as `items/:id/update/preview`.
|
|
119
|
+
*/
|
|
120
|
+
importUpdatePreview(stagingId: string): Promise<PlatformUpdatePreview>;
|
|
121
|
+
/**
|
|
122
|
+
* Imports the staged version and updates the platform plugin to it, confirmed with the import
|
|
123
|
+
* review's `reviewHash` and the update preview's `diffHash` (201 `{ item, update }`). Stale review
|
|
124
|
+
* -> 409 `plugin.review_stale`, stale preview -> 409 `plugin.upgrade_stale`, another update
|
|
125
|
+
* running -> 409 `plugin.install_in_progress`: nothing written. The update failing after the
|
|
126
|
+
* import -> 409 `plugin.imported_not_updated` (the version stays in the catalog, the platform on
|
|
127
|
+
* its version, the extension's approval put back; details name the cause).
|
|
128
|
+
*/
|
|
129
|
+
importAndUpdate(principal: Principal, stagingId: string, body: z.infer<typeof CatalogImportUpdateBody>): Promise<PlatformImportUpdateResult>;
|
|
111
130
|
/**
|
|
112
131
|
* The item list (`includeDeleted=true` includes deleted items). Paging: `limit` (default 200, at
|
|
113
132
|
* most 1000) and `offset`; `nextOffset` is the next page's offset, null when there is none.
|
|
@@ -16,13 +16,14 @@ import { PluginIcons } from "../extensions/plugin-icons.js";
|
|
|
16
16
|
import { CurrentPrincipal, patTokenId, requireUser, SuperAdmin, } from "../identity/principal.js";
|
|
17
17
|
import { createZodDto } from "../infra/validation/create-zod-dto.js";
|
|
18
18
|
import { ZBody, ZQuery } from "../infra/validation/zod-params.js";
|
|
19
|
-
import { AdminCatalogGuideQuery, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogHash as Hash, CatalogNpmImportBody as NpmBody, CatalogScopeOrgs as Orgs, CatalogScope as Scope, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody, } from "./admin-catalog.schemas.js";
|
|
19
|
+
import { AdminCatalogGuideQuery, CatalogImportUpdateBody, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogHash as Hash, CatalogNpmImportBody as NpmBody, CatalogScopeOrgs as Orgs, CatalogScope as Scope, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody, } from "./admin-catalog.schemas.js";
|
|
20
20
|
import { AppearanceApplyBody } from "./appearance.schemas.js";
|
|
21
21
|
import { AppearanceService, suggestedAppearanceOf, } from "./appearance.service.js";
|
|
22
22
|
import { CatalogService, } from "./catalog.service.js";
|
|
23
23
|
import { CatalogScopeService } from "./catalog-scope.service.js";
|
|
24
24
|
import { sendCatalogIcon } from "./org-catalog.controller.js";
|
|
25
25
|
import { OrgCatalogService } from "./org-catalog.service.js";
|
|
26
|
+
import { PlatformImportUpdate } from "./platform-import-update.js";
|
|
26
27
|
import { PluginImport } from "./plugin-import.js";
|
|
27
28
|
import { PlatformPluginUpdater, } from "./plugin-upgrade.js";
|
|
28
29
|
const ConfirmBody = z
|
|
@@ -66,6 +67,8 @@ class CatalogUpdatePreviewBodyDto extends createZodDto(CatalogUpdatePreviewBody,
|
|
|
66
67
|
}
|
|
67
68
|
class CatalogUpdateBodyDto extends createZodDto(CatalogUpdateBody, "CatalogUpdateBody") {
|
|
68
69
|
}
|
|
70
|
+
class CatalogImportUpdateBodyDto extends createZodDto(CatalogImportUpdateBody, "CatalogImportUpdateBody") {
|
|
71
|
+
}
|
|
69
72
|
class AppearanceApplyBodyDto extends createZodDto(AppearanceApplyBody, "AppearanceApplyBody") {
|
|
70
73
|
}
|
|
71
74
|
/**
|
|
@@ -80,16 +83,18 @@ let AdminCatalogController = class AdminCatalogController {
|
|
|
80
83
|
orgCatalog;
|
|
81
84
|
scope;
|
|
82
85
|
updater;
|
|
86
|
+
importUpdate;
|
|
83
87
|
icons;
|
|
84
88
|
appearance;
|
|
85
89
|
clientBuilds;
|
|
86
90
|
guides;
|
|
87
|
-
constructor(catalog, pluginImport, orgCatalog, scope, updater, icons, appearance, clientBuilds, guides) {
|
|
91
|
+
constructor(catalog, pluginImport, orgCatalog, scope, updater, importUpdate, icons, appearance, clientBuilds, guides) {
|
|
88
92
|
this.catalog = catalog;
|
|
89
93
|
this.pluginImport = pluginImport;
|
|
90
94
|
this.orgCatalog = orgCatalog;
|
|
91
95
|
this.scope = scope;
|
|
92
96
|
this.updater = updater;
|
|
97
|
+
this.importUpdate = importUpdate;
|
|
93
98
|
this.icons = icons;
|
|
94
99
|
this.appearance = appearance;
|
|
95
100
|
this.clientBuilds = clientBuilds;
|
|
@@ -169,6 +174,28 @@ let AdminCatalogController = class AdminCatalogController {
|
|
|
169
174
|
...(body.orgs !== undefined && { orgs: body.orgs }),
|
|
170
175
|
}, actorOpts(actor));
|
|
171
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* What confirming a staged new version of an installed platform plugin would do as the platform
|
|
179
|
+
* update (`PlatformImportUpdate`, the one 更新到 wizard): the update preview of the staged
|
|
180
|
+
* version, nothing written (cancelling the wizard leaves only the staging row). Not a platform
|
|
181
|
+
* plugin yet -> 409 `plugin.upgrade_target_invalid` (reason `not_installed`); staging missing ->
|
|
182
|
+
* 404 `plugin.staging_not_found`; otherwise as `items/:id/update/preview`.
|
|
183
|
+
*/
|
|
184
|
+
importUpdatePreview(stagingId) {
|
|
185
|
+
return this.importUpdate.preview(stagingId);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Imports the staged version and updates the platform plugin to it, confirmed with the import
|
|
189
|
+
* review's `reviewHash` and the update preview's `diffHash` (201 `{ item, update }`). Stale review
|
|
190
|
+
* -> 409 `plugin.review_stale`, stale preview -> 409 `plugin.upgrade_stale`, another update
|
|
191
|
+
* running -> 409 `plugin.install_in_progress`: nothing written. The update failing after the
|
|
192
|
+
* import -> 409 `plugin.imported_not_updated` (the version stays in the catalog, the platform on
|
|
193
|
+
* its version, the extension's approval put back; details name the cause).
|
|
194
|
+
*/
|
|
195
|
+
importAndUpdate(principal, stagingId, body) {
|
|
196
|
+
const actor = requireUser(principal);
|
|
197
|
+
return this.importUpdate.confirm(actor.account.id, stagingId, body, actorOpts(actor));
|
|
198
|
+
}
|
|
172
199
|
/**
|
|
173
200
|
* The item list (`includeDeleted=true` includes deleted items). Paging: `limit` (default 200, at
|
|
174
201
|
* most 1000) and `offset`; `nextOffset` is the next page's offset, null when there is none.
|
|
@@ -367,6 +394,17 @@ __decorate([
|
|
|
367
394
|
__param(1, Param("stagingId")),
|
|
368
395
|
__param(2, ZBody(CatalogImportConfirmBody))
|
|
369
396
|
], AdminCatalogController.prototype, "confirm", null);
|
|
397
|
+
__decorate([
|
|
398
|
+
Get("imports/:stagingId/update-preview"),
|
|
399
|
+
__param(0, Param("stagingId"))
|
|
400
|
+
], AdminCatalogController.prototype, "importUpdatePreview", null);
|
|
401
|
+
__decorate([
|
|
402
|
+
Post("imports/:stagingId/update"),
|
|
403
|
+
HttpCode(201),
|
|
404
|
+
__param(0, CurrentPrincipal()),
|
|
405
|
+
__param(1, Param("stagingId")),
|
|
406
|
+
__param(2, ZBody(CatalogImportUpdateBodyDto))
|
|
407
|
+
], AdminCatalogController.prototype, "importAndUpdate", null);
|
|
370
408
|
__decorate([
|
|
371
409
|
Get("items"),
|
|
372
410
|
__param(0, ZQuery(CatalogItemsQueryDto))
|
|
@@ -457,9 +495,10 @@ AdminCatalogController = __decorate([
|
|
|
457
495
|
__param(2, Inject(OrgCatalogService)),
|
|
458
496
|
__param(3, Inject(CatalogScopeService)),
|
|
459
497
|
__param(4, Inject(PlatformPluginUpdater)),
|
|
460
|
-
__param(5, Inject(
|
|
461
|
-
__param(6, Inject(
|
|
462
|
-
__param(7, Inject(
|
|
463
|
-
__param(8, Inject(
|
|
498
|
+
__param(5, Inject(PlatformImportUpdate)),
|
|
499
|
+
__param(6, Inject(PluginIcons)),
|
|
500
|
+
__param(7, Inject(AppearanceService)),
|
|
501
|
+
__param(8, Inject(ClientBuilds)),
|
|
502
|
+
__param(9, Inject(PluginGuides))
|
|
464
503
|
], AdminCatalogController);
|
|
465
504
|
export { AdminCatalogController };
|
|
@@ -20,6 +20,11 @@ export declare const CatalogUpdateBody: z.ZodObject<{
|
|
|
20
20
|
version: z.ZodString;
|
|
21
21
|
diffHash: z.ZodString;
|
|
22
22
|
}, z.core.$strict>;
|
|
23
|
+
/** `POST imports/:stagingId/update`: the import review's hash and the update preview's. */
|
|
24
|
+
export declare const CatalogImportUpdateBody: z.ZodObject<{
|
|
25
|
+
reviewHash: z.ZodString;
|
|
26
|
+
diffHash: z.ZodString;
|
|
27
|
+
}, z.core.$strict>;
|
|
23
28
|
/** `:id` as the routes take it (`@Param`). */
|
|
24
29
|
export declare const CatalogIdPathParams: z.ZodObject<{
|
|
25
30
|
id: z.ZodString;
|
|
@@ -13,6 +13,10 @@ export const CatalogUpdatePreviewBody = z.object({ version: CatalogVersion }).st
|
|
|
13
13
|
export const CatalogUpdateBody = z
|
|
14
14
|
.object({ version: CatalogVersion, diffHash: CatalogHash })
|
|
15
15
|
.strict();
|
|
16
|
+
/** `POST imports/:stagingId/update`: the import review's hash and the update preview's. */
|
|
17
|
+
export const CatalogImportUpdateBody = z
|
|
18
|
+
.object({ reviewHash: CatalogHash, diffHash: CatalogHash })
|
|
19
|
+
.strict();
|
|
16
20
|
/** `:id` as the routes take it (`@Param`). */
|
|
17
21
|
export const CatalogIdPathParams = z.object({ id: z.string().min(1) });
|
|
18
22
|
/** `:stagingId` of a staged import as the route takes it (`@Param`). */
|
|
@@ -75,6 +79,10 @@ export const ADMIN_CATALOG_ROUTES = [
|
|
|
75
79
|
{ route: "POST /api/v1/admin/catalog/import/npm", body: CatalogNpmImportBody },
|
|
76
80
|
{ route: "POST /api/v1/admin/catalog/import/git", body: CatalogGitImportBody },
|
|
77
81
|
{ route: "GET /api/v1/admin/catalog/imports/:stagingId", params: CatalogStagingPathParams },
|
|
82
|
+
{
|
|
83
|
+
route: "GET /api/v1/admin/catalog/imports/:stagingId/update-preview",
|
|
84
|
+
params: CatalogStagingPathParams,
|
|
85
|
+
},
|
|
78
86
|
{
|
|
79
87
|
route: "POST /api/v1/admin/catalog/items/:id/scope/preview",
|
|
80
88
|
params: CatalogIdPathParams,
|
|
@@ -2,7 +2,8 @@ import { CatalogImportModule } from "./catalog-import.module.js";
|
|
|
2
2
|
export { CatalogImportModule };
|
|
3
3
|
/**
|
|
4
4
|
* The plugin catalog (spec §4, §10): {@link CatalogImportModule}, catalog requests, org installs
|
|
5
|
-
* with their dependencies, the platform plugin update (`PlatformPluginUpdater`)
|
|
5
|
+
* with their dependencies, the platform plugin update (`PlatformPluginUpdater`) and the update to a
|
|
6
|
+
* staged version (`PlatformImportUpdate`), the admin's scope
|
|
6
7
|
* and disable
|
|
7
8
|
* (`CatalogScopeService`), org admins' plugin uploads (`OrgPluginUploads`) and their own plugins (`OwnedItems`), and the producer of the plugin scope sync
|
|
8
9
|
* (`PluginScopeSync`; its consumer is the worker role's `PluginScopeWorkersModule`). The catalog's periodic jobs (`CatalogJobs`) are
|
|
@@ -21,6 +21,7 @@ import { OrgCatalogService } from "./org-catalog.service.js";
|
|
|
21
21
|
import { OrgExtensionSwitch } from "./org-extension-switch.js";
|
|
22
22
|
import { OrgPluginUploads } from "./org-plugin-uploads.js";
|
|
23
23
|
import { OwnedItems } from "./owned-items.js";
|
|
24
|
+
import { PlatformImportUpdate } from "./platform-import-update.js";
|
|
24
25
|
import { PluginInstaller } from "./plugin-install.js";
|
|
25
26
|
import { PlatformPluginUpdater } from "./plugin-upgrade.js";
|
|
26
27
|
import { CatalogRequestsService } from "./requests.service.js";
|
|
@@ -32,7 +33,8 @@ const PLUGIN_SCOPE_QUEUE_MODULE = QueueModule.registerQueue(PLUGIN_SCOPE_QUEUE);
|
|
|
32
33
|
const MAINTENANCE_QUEUE_MODULE = QueueModule.registerQueue(MAINTENANCE_QUEUE_NAME);
|
|
33
34
|
/**
|
|
34
35
|
* The plugin catalog (spec §4, §10): {@link CatalogImportModule}, catalog requests, org installs
|
|
35
|
-
* with their dependencies, the platform plugin update (`PlatformPluginUpdater`)
|
|
36
|
+
* with their dependencies, the platform plugin update (`PlatformPluginUpdater`) and the update to a
|
|
37
|
+
* staged version (`PlatformImportUpdate`), the admin's scope
|
|
36
38
|
* and disable
|
|
37
39
|
* (`CatalogScopeService`), org admins' plugin uploads (`OrgPluginUploads`) and their own plugins (`OwnedItems`), and the producer of the plugin scope sync
|
|
38
40
|
* (`PluginScopeSync`; its consumer is the worker role's `PluginScopeWorkersModule`). The catalog's periodic jobs (`CatalogJobs`) are
|
|
@@ -69,6 +71,7 @@ CatalogModule = __decorate([
|
|
|
69
71
|
ComponentScopeService,
|
|
70
72
|
OrgPluginUploads,
|
|
71
73
|
OwnedItems,
|
|
74
|
+
PlatformImportUpdate,
|
|
72
75
|
],
|
|
73
76
|
exports: [
|
|
74
77
|
PLUGIN_SCOPE_QUEUE_MODULE,
|
|
@@ -84,6 +87,7 @@ CatalogModule = __decorate([
|
|
|
84
87
|
ComponentScopeService,
|
|
85
88
|
OrgPluginUploads,
|
|
86
89
|
OwnedItems,
|
|
90
|
+
PlatformImportUpdate,
|
|
87
91
|
],
|
|
88
92
|
})
|
|
89
93
|
], CatalogModule);
|
|
@@ -188,7 +188,7 @@ export declare function headsToResolve(entries: readonly MarketplaceEntry[], imp
|
|
|
188
188
|
/** The host versions (an entry's `minKernel` is judged against them). */
|
|
189
189
|
export declare const HOST_VERSIONS: {
|
|
190
190
|
readonly kernel: string;
|
|
191
|
-
readonly sdk: "0.1.0-rc.
|
|
191
|
+
readonly sdk: "0.1.0-rc.18";
|
|
192
192
|
};
|
|
193
193
|
/** Whether this deployment satisfies the entry's `minKernel`. */
|
|
194
194
|
export declare const entryCompatible: (e: Pick<MarketplaceEntry, "minKernel">) => boolean;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { KernelLogger } from "../log.js";
|
|
2
|
+
import type { ActorOpts, CatalogItemView } from "./catalog.service.js";
|
|
3
|
+
import { PluginImport } from "./plugin-import.js";
|
|
4
|
+
import { PlatformPluginUpdater, type PlatformUpdatePreview, type PlatformUpdateResult } from "./plugin-upgrade.js";
|
|
5
|
+
/** `POST /api/v1/admin/catalog/imports/:stagingId/update`: the import and the update it applied. */
|
|
6
|
+
export interface PlatformImportUpdateResult {
|
|
7
|
+
item: CatalogItemView;
|
|
8
|
+
update: PlatformUpdateResult;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The platform's update of an installed plugin to a version staged for import (the one wizard of
|
|
12
|
+
* the admin plugin pages, maintainer decision 2026-11-13): the import review (prepared as any
|
|
13
|
+
* import, `PluginImport.prepare`) and the platform update preview of the staged version
|
|
14
|
+
* ({@link preview}: `PlatformPluginUpdater.previewStaged`, the target read from the staging) are
|
|
15
|
+
* confirmed together ({@link confirm} with the review's `reviewHash` and the preview's `diffHash`).
|
|
16
|
+
* Nothing is written before that confirm: cancelling the wizard leaves only the staging row, which
|
|
17
|
+
* expires like any staged import.
|
|
18
|
+
*
|
|
19
|
+
* The confirm holds the item's update lock (`PlatformPluginUpdater.withItemLock`, one per item
|
|
20
|
+
* across replicas: another update -> 409 `plugin.install_in_progress`), recomputes the preview
|
|
21
|
+
* (another `diffHash` -> 409 `plugin.upgrade_stale`, nothing written), commits the import without
|
|
22
|
+
* deploying its extension (the permission snapshot is written as the review approved it), then
|
|
23
|
+
* runs the platform update, which moves the extension with its own rollback and writes the
|
|
24
|
+
* components in one transaction. When that update fails, the platform stays on its version, the
|
|
25
|
+
* extension where it was and its previous approval is put back; the imported version stays in the
|
|
26
|
+
* catalog (its 版本 tab, and 更新到 retries the update with the plain update preview): 409
|
|
27
|
+
* `plugin.imported_not_updated` says so, with the cause in the details. No in-process state.
|
|
28
|
+
*/
|
|
29
|
+
export declare class PlatformImportUpdate {
|
|
30
|
+
private readonly pluginImport;
|
|
31
|
+
private readonly updater;
|
|
32
|
+
private readonly log;
|
|
33
|
+
constructor(pluginImport: PluginImport, updater: PlatformPluginUpdater, log: KernelLogger);
|
|
34
|
+
/**
|
|
35
|
+
* The platform update the staged version would apply (writes nothing). The staging must be a
|
|
36
|
+
* platform staging (else 404 `plugin.staging_not_found`) of a new version of a live
|
|
37
|
+
* platform-owned plugin (else 409 `plugin.upgrade_target_invalid`, reason `not_installed`); the
|
|
38
|
+
* updater's refusals apply as for any update preview. `needsApproval` is false: the confirm
|
|
39
|
+
* approves the permissions the review shows.
|
|
40
|
+
*/
|
|
41
|
+
preview(stagingId: string): Promise<PlatformUpdatePreview>;
|
|
42
|
+
/** Confirms the import and the update together (see the class comment). */
|
|
43
|
+
confirm(actor: string, stagingId: string, input: {
|
|
44
|
+
reviewHash: string;
|
|
45
|
+
diffHash: string;
|
|
46
|
+
}, opts?: ActorOpts): Promise<PlatformImportUpdateResult>;
|
|
47
|
+
/** The staged target, which must be a new version of a live platform-owned plugin. */
|
|
48
|
+
private target;
|
|
49
|
+
private previewOf;
|
|
50
|
+
}
|