@alisio/core 0.1.0-alpha.8 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -7
- package/dist/agents/active.d.ts +99 -0
- package/dist/agents/active.js +218 -0
- package/dist/agents/capabilities.d.ts +26 -0
- package/dist/agents/capabilities.js +120 -0
- package/dist/agents/create-agent-skill.d.ts +11 -0
- package/dist/agents/create-agent-skill.js +60 -0
- package/dist/agents/definitions.d.ts +88 -0
- package/dist/agents/definitions.js +404 -0
- package/dist/agents/draft.d.ts +41 -0
- package/dist/agents/draft.js +133 -0
- package/dist/agents/service.d.ts +57 -0
- package/dist/agents/service.js +86 -0
- package/dist/agents/templates.d.ts +8 -0
- package/dist/agents/templates.js +102 -0
- package/dist/analysis/capabilities.d.ts +48 -0
- package/dist/analysis/capabilities.js +90 -0
- package/dist/analysis/data/csv.d.ts +46 -0
- package/dist/analysis/data/csv.js +240 -0
- package/dist/analysis/data/datasets.d.ts +132 -0
- package/dist/analysis/data/datasets.js +441 -0
- package/dist/analysis/data/describe.d.ts +27 -0
- package/dist/analysis/data/describe.js +103 -0
- package/dist/analysis/data/engine-client.d.ts +58 -0
- package/dist/analysis/data/engine-client.js +304 -0
- package/dist/analysis/data/engine-entry.d.ts +1 -0
- package/dist/analysis/data/engine-entry.js +59 -0
- package/dist/analysis/data/engine-source.d.ts +4 -0
- package/dist/analysis/data/engine-source.js +6 -0
- package/dist/analysis/data/engine-types.d.ts +86 -0
- package/dist/analysis/data/engine-types.js +7 -0
- package/dist/analysis/data/infer.d.ts +42 -0
- package/dist/analysis/data/infer.js +118 -0
- package/dist/analysis/data/ingest-worker.d.ts +17 -0
- package/dist/analysis/data/ingest-worker.js +365 -0
- package/dist/analysis/data/json.d.ts +19 -0
- package/dist/analysis/data/json.js +44 -0
- package/dist/analysis/data/query-worker.d.ts +12 -0
- package/dist/analysis/data/query-worker.js +75 -0
- package/dist/analysis/data/rows.d.ts +39 -0
- package/dist/analysis/data/rows.js +120 -0
- package/dist/analysis/data/sql-guard.d.ts +20 -0
- package/dist/analysis/data/sql-guard.js +129 -0
- package/dist/analysis/data/stats.d.ts +18 -0
- package/dist/analysis/data/stats.js +77 -0
- package/dist/analysis/install-hints.d.ts +33 -0
- package/dist/analysis/install-hints.js +144 -0
- package/dist/analysis/janitor.d.ts +60 -0
- package/dist/analysis/janitor.js +264 -0
- package/dist/analysis/jobs.d.ts +94 -0
- package/dist/analysis/jobs.js +165 -0
- package/dist/analysis/oci.d.ts +129 -0
- package/dist/analysis/oci.js +330 -0
- package/dist/analysis/python/sources.d.ts +2 -0
- package/dist/analysis/python/sources.js +10 -0
- package/dist/analysis/requirements.d.ts +32 -0
- package/dist/analysis/requirements.js +73 -0
- package/dist/analysis/rerun.d.ts +40 -0
- package/dist/analysis/rerun.js +136 -0
- package/dist/analysis/runtime-manager.d.ts +146 -0
- package/dist/analysis/runtime-manager.js +472 -0
- package/dist/analysis/status.d.ts +21 -0
- package/dist/analysis/status.js +52 -0
- package/dist/application.d.ts +118 -3
- package/dist/application.js +510 -19
- package/dist/artifacts/kinds.d.ts +35 -0
- package/dist/artifacts/kinds.js +177 -0
- package/dist/artifacts/publisher.d.ts +7 -0
- package/dist/artifacts/publisher.js +29 -0
- package/dist/artifacts/store.d.ts +119 -0
- package/dist/artifacts/store.js +581 -0
- package/dist/background/janitor.d.ts +22 -0
- package/dist/background/janitor.js +62 -0
- package/dist/background/mirror.d.ts +14 -0
- package/dist/background/mirror.js +41 -0
- package/dist/background/notify.d.ts +58 -0
- package/dist/background/notify.js +172 -0
- package/dist/background/output.d.ts +46 -0
- package/dist/background/output.js +179 -0
- package/dist/background/service.d.ts +137 -0
- package/dist/background/service.js +410 -0
- package/dist/background/store.d.ts +103 -0
- package/dist/background/store.js +195 -0
- package/dist/changelog/data.d.ts +6 -0
- package/dist/changelog/data.js +293 -0
- package/dist/changelog/index.d.ts +5 -0
- package/dist/changelog/index.js +7 -0
- package/dist/changelog/parse.d.ts +53 -0
- package/dist/changelog/parse.js +160 -0
- package/dist/commands/builtins.d.ts +10 -0
- package/dist/commands/builtins.js +161 -0
- package/dist/commands/catalog.d.ts +86 -0
- package/dist/commands/catalog.js +304 -0
- package/dist/config.d.ts +252 -5
- package/dist/config.js +514 -13
- package/dist/core/compaction.js +13 -2
- package/dist/core/contracts.d.ts +180 -3
- package/dist/core/opt-in.d.ts +12 -0
- package/dist/core/opt-in.js +12 -0
- package/dist/core/output-limit.d.ts +34 -0
- package/dist/core/output-limit.js +39 -0
- package/dist/core/run-stats.d.ts +16 -0
- package/dist/core/run-stats.js +8 -0
- package/dist/core/runner.d.ts +152 -4
- package/dist/core/runner.js +792 -138
- package/dist/core/timeout.d.ts +15 -0
- package/dist/core/timeout.js +61 -0
- package/dist/core/truncation.d.ts +30 -0
- package/dist/core/truncation.js +83 -0
- package/dist/goal/blockers.d.ts +45 -0
- package/dist/goal/blockers.js +51 -0
- package/dist/goal/budget.d.ts +24 -0
- package/dist/goal/budget.js +53 -0
- package/dist/goal/command.d.ts +36 -0
- package/dist/goal/command.js +98 -0
- package/dist/goal/format.d.ts +19 -0
- package/dist/goal/format.js +102 -0
- package/dist/goal/host.d.ts +29 -0
- package/dist/goal/host.js +42 -0
- package/dist/goal/index.d.ts +9 -0
- package/dist/goal/index.js +9 -0
- package/dist/goal/machine.d.ts +186 -0
- package/dist/goal/machine.js +344 -0
- package/dist/goal/prompts.d.ts +10 -0
- package/dist/goal/prompts.js +75 -0
- package/dist/goal/service.d.ts +113 -0
- package/dist/goal/service.js +273 -0
- package/dist/goal/store.d.ts +59 -0
- package/dist/goal/store.js +184 -0
- package/dist/index.d.ts +51 -6
- package/dist/index.js +49 -4
- package/dist/mcp/connector.js +38 -6
- package/dist/mcp/rich.d.ts +41 -0
- package/dist/mcp/rich.js +362 -0
- package/dist/permissions/modes.d.ts +72 -0
- package/dist/permissions/modes.js +98 -0
- package/dist/plan/exit-plan.d.ts +25 -0
- package/dist/plan/exit-plan.js +130 -0
- package/dist/plan/state.d.ts +102 -0
- package/dist/plan/state.js +165 -0
- package/dist/plugins/host.d.ts +39 -1
- package/dist/plugins/host.js +150 -9
- package/dist/providers/settings.d.ts +15 -0
- package/dist/providers/settings.js +38 -0
- package/dist/reload.d.ts +75 -0
- package/dist/reload.js +204 -0
- package/dist/resources/context.d.ts +5 -0
- package/dist/resources/context.js +13 -1
- package/dist/runtime/access.d.ts +62 -0
- package/dist/runtime/access.js +115 -0
- package/dist/runtime/blobs.d.ts +51 -0
- package/dist/runtime/blobs.js +177 -0
- package/dist/runtime/diff.d.ts +23 -0
- package/dist/runtime/diff.js +154 -0
- package/dist/runtime/ids.d.ts +8 -0
- package/dist/runtime/ids.js +32 -0
- package/dist/runtime/paths.d.ts +11 -0
- package/dist/runtime/paths.js +17 -1
- package/dist/runtime/process.d.ts +22 -0
- package/dist/runtime/process.js +100 -15
- package/dist/runtime/sqlite.d.ts +2 -0
- package/dist/runtime/sqlite.js +18 -0
- package/dist/runtime/store.d.ts +91 -3
- package/dist/runtime/store.js +465 -11
- package/dist/runtime/zip.d.ts +24 -0
- package/dist/runtime/zip.js +126 -0
- package/dist/sessions/children.js +17 -1
- package/dist/sessions/side-questions.d.ts +57 -0
- package/dist/sessions/side-questions.js +161 -0
- package/dist/startup/screen.js +6 -5
- package/dist/tools/analysis.d.ts +37 -0
- package/dist/tools/analysis.js +573 -0
- package/dist/tools/artifacts.d.ts +14 -0
- package/dist/tools/artifacts.js +143 -0
- package/dist/tools/background.d.ts +7 -0
- package/dist/tools/background.js +165 -0
- package/dist/tools/data.d.ts +7 -0
- package/dist/tools/data.js +160 -0
- package/dist/tools/execute.d.ts +5 -0
- package/dist/tools/execute.js +15 -3
- package/dist/tools/goal.d.ts +19 -0
- package/dist/tools/goal.js +126 -0
- package/dist/tools/search.d.ts +17 -3
- package/dist/tools/search.js +153 -0
- package/dist/tools/standard.d.ts +4 -1
- package/dist/tools/standard.js +99 -18
- package/dist/version.d.ts +5 -3
- package/dist/version.js +35 -6
- package/package.json +2 -2
package/dist/application.js
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
1
2
|
import { homedir } from "node:os";
|
|
2
3
|
import { dirname, join, resolve } from "node:path";
|
|
3
|
-
import {
|
|
4
|
+
import { AgentDefinitionService } from "./agents/service.js";
|
|
5
|
+
import { CapabilityGrants } from "./analysis/capabilities.js";
|
|
6
|
+
import { DatasetService } from "./analysis/data/datasets.js";
|
|
7
|
+
import { AnalysisJanitor } from "./analysis/janitor.js";
|
|
8
|
+
import { AnalysisJobs } from "./analysis/jobs.js";
|
|
9
|
+
import { OciRuntime } from "./analysis/oci.js";
|
|
10
|
+
import { AnalysisRerun } from "./analysis/rerun.js";
|
|
11
|
+
import { AnalysisRuntimeManager } from "./analysis/runtime-manager.js";
|
|
12
|
+
import { createArtifactPublisher } from "./artifacts/publisher.js";
|
|
13
|
+
import { ArtifactStore } from "./artifacts/store.js";
|
|
14
|
+
import { TaskJanitor } from "./background/janitor.js";
|
|
15
|
+
import { subagentTasks } from "./background/mirror.js";
|
|
16
|
+
import { BackgroundTasks } from "./background/service.js";
|
|
17
|
+
import { configFile, configHome, loadConfigWithProvenance, overridesSavedProviderProfile, setConfigValue, setGlobalMcpAllow, setMcpServerEnabled, setProjectPluginEnabled, setProjectSkillEnabled, stateHome, } from "./config.js";
|
|
4
18
|
import { completeText } from "./core/compaction.js";
|
|
19
|
+
import { DEFAULT_MAX_OUTPUT_TOKENS } from "./core/output-limit.js";
|
|
5
20
|
import { ToolRegistry } from "./core/registry.js";
|
|
6
21
|
import { AgentRunner } from "./core/runner.js";
|
|
22
|
+
import { GoalService } from "./goal/service.js";
|
|
23
|
+
import { GoalStore } from "./goal/store.js";
|
|
7
24
|
import { HerdrBridge } from "./integrations/herdr.js";
|
|
8
25
|
import { McpConnector } from "./mcp/connector.js";
|
|
9
26
|
import { discoverPlugins, PluginHost } from "./plugins/host.js";
|
|
@@ -13,10 +30,21 @@ import { ProviderSettingsStore } from "./providers/settings.js";
|
|
|
13
30
|
import { ProjectContext } from "./resources/context.js";
|
|
14
31
|
import { expandSlashPrompt, loadPromptTemplates, promptSources } from "./resources/prompts.js";
|
|
15
32
|
import { Skills, skillRoots } from "./resources/skills.js";
|
|
33
|
+
import { PathAccess } from "./runtime/access.js";
|
|
34
|
+
import { BlobStore } from "./runtime/blobs.js";
|
|
16
35
|
import { isPathSpec } from "./runtime/modules.js";
|
|
17
36
|
import { findWorkspace } from "./runtime/paths.js";
|
|
18
37
|
import { SQLiteStore } from "./runtime/store.js";
|
|
19
38
|
import { ChildSessions } from "./sessions/children.js";
|
|
39
|
+
import { SideQuestions } from "./sessions/side-questions.js";
|
|
40
|
+
import { registerGoalTools } from "./tools/goal.js";
|
|
41
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
42
|
+
/**
|
|
43
|
+
* Cap per teardown stage of `app.close()`: exit must never wait longer than this on a hanging
|
|
44
|
+
* component (MCP server, provider, plugin). Stages run in parallel where independent and
|
|
45
|
+
* failures are swallowed, so teardown errors never replace the caller's result.
|
|
46
|
+
*/
|
|
47
|
+
const TEARDOWN_STAGE_TIMEOUT_MS = 2_500;
|
|
20
48
|
/** A built-in runs unless its config sets `enabled: false` or it is disabled by id. */
|
|
21
49
|
export function enabledBuiltins(available, config, disabled = []) {
|
|
22
50
|
for (const id of [...Object.keys(config), ...disabled])
|
|
@@ -52,7 +80,28 @@ export async function createApplication(options = {}) {
|
|
|
52
80
|
// a project value (see loadConfigWithProvenance), so a project cannot grant itself MCP consent.
|
|
53
81
|
const mcpAllow = config.mcp.allow === true;
|
|
54
82
|
let persistedMcpAllow = mcpAllow;
|
|
83
|
+
// Extra tool roots: config `additionalDirectories` (already canonicalized on load) plus per-run
|
|
84
|
+
// `--add-dir` (resolved against the current directory). Ignored entirely under --read-only, so
|
|
85
|
+
// the flag and the config key can never widen a locked session.
|
|
86
|
+
const addDirs = options.readOnly
|
|
87
|
+
? []
|
|
88
|
+
: await Promise.all((options.addDirs ?? []).map((dir) => realpath(resolve(cwd, dir)).catch(() => resolve(cwd, dir))));
|
|
89
|
+
const pathAccess = new PathAccess({
|
|
90
|
+
workspace,
|
|
91
|
+
extraRoots: [...config.additionalDirectories, ...addDirs],
|
|
92
|
+
...(options.approveExternalDirectory && !options.readOnly
|
|
93
|
+
? { approve: options.approveExternalDirectory }
|
|
94
|
+
: {}),
|
|
95
|
+
readOnly: !!options.readOnly,
|
|
96
|
+
});
|
|
55
97
|
const store = new SQLiteStore(options.db ?? join(stateHome(), "sessions.sqlite"));
|
|
98
|
+
// Content-addressed attachment bytes next to the session database (no I/O until `put`).
|
|
99
|
+
const blobs = new BlobStore({
|
|
100
|
+
root: options.db && options.db !== ":memory:"
|
|
101
|
+
? join(dirname(options.db), "blobs")
|
|
102
|
+
: join(stateHome(), "blobs"),
|
|
103
|
+
db: store.db,
|
|
104
|
+
});
|
|
56
105
|
const registry = new ToolRegistry(), skills = new Skills({ overrides: config.skillOverrides }), context = new ProjectContext(workspace, {
|
|
57
106
|
globalDir: configHome(),
|
|
58
107
|
cwd,
|
|
@@ -234,7 +283,150 @@ export async function createApplication(options = {}) {
|
|
|
234
283
|
}, {
|
|
235
284
|
config: config.websearch,
|
|
236
285
|
resolveExtension: () => plugins.extensions.resolve("websearch"),
|
|
286
|
+
}, pathAccess);
|
|
287
|
+
// Python analysis and artifacts live next to the session database (like attachment blobs).
|
|
288
|
+
const stateRoot = options.db && options.db !== ":memory:" ? dirname(options.db) : stateHome();
|
|
289
|
+
const artifacts = new ArtifactStore({
|
|
290
|
+
root: stateRoot,
|
|
291
|
+
db: store.db,
|
|
292
|
+
limits: {
|
|
293
|
+
maxFiles: config.analysis.limits.maxFiles,
|
|
294
|
+
maxFileBytes: config.analysis.limits.maxFileBytes,
|
|
295
|
+
maxOutputBytes: config.analysis.limits.maxOutputBytes,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
const capabilityGrants = new CapabilityGrants({
|
|
299
|
+
db: store.db,
|
|
300
|
+
rootOf: (id) => store.rootOf(id),
|
|
301
|
+
});
|
|
302
|
+
const analysisRuntime = options.analysisRuntime ??
|
|
303
|
+
new AnalysisRuntimeManager({
|
|
304
|
+
stateDir: stateRoot,
|
|
305
|
+
...(options.python ? { python: options.python } : {}),
|
|
306
|
+
});
|
|
307
|
+
const analysisJobs = new AnalysisJobs({ root: stateRoot, db: store.db });
|
|
308
|
+
// Container mode (`analysis.runtime: "oci"`): read from the live config on every call.
|
|
309
|
+
let ociRuntime;
|
|
310
|
+
const oci = {
|
|
311
|
+
mode: () => config.analysis.runtime,
|
|
312
|
+
runtime: () => {
|
|
313
|
+
const key = JSON.stringify(config.analysis.oci);
|
|
314
|
+
if (ociRuntime?.key !== key)
|
|
315
|
+
ociRuntime = {
|
|
316
|
+
key,
|
|
317
|
+
runtime: new OciRuntime({ ...config.analysis.oci }, options.analysisOci),
|
|
318
|
+
};
|
|
319
|
+
return ociRuntime.runtime;
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
// Tabular datasets (one SQLite file each); XLSX needs the discovered Python.
|
|
323
|
+
const datasets = new DatasetService({
|
|
324
|
+
root: stateRoot,
|
|
325
|
+
db: store.db,
|
|
326
|
+
limits: config.analysis.data,
|
|
327
|
+
python: analysisRuntime,
|
|
328
|
+
});
|
|
329
|
+
const analysisRerun = new AnalysisRerun({ jobs: analysisJobs, store: artifacts, datasets });
|
|
330
|
+
// Retention: a sweep at most every 24 h, launched in the background after the start.
|
|
331
|
+
const janitor = new AnalysisJanitor({
|
|
332
|
+
root: stateRoot,
|
|
333
|
+
db: store.db,
|
|
334
|
+
artifacts,
|
|
335
|
+
datasets,
|
|
336
|
+
blobs,
|
|
337
|
+
retention: () => config.analysis.retention,
|
|
338
|
+
...(options.analysisSweepDelayMs !== undefined
|
|
339
|
+
? { initialDelayMs: options.analysisSweepDelayMs }
|
|
340
|
+
: {}),
|
|
341
|
+
});
|
|
342
|
+
// Background tasks: a service over the shared database (state change = compare-and-set), logs
|
|
343
|
+
// under `<state>/tasks/`. Tasks of a dead owner process (a previous run) become `lost` now.
|
|
344
|
+
const tasks = new BackgroundTasks({
|
|
345
|
+
db: store.db,
|
|
346
|
+
stateRoot,
|
|
347
|
+
rootOf: (id) => store.rootOf(id),
|
|
348
|
+
limits: () => config.tasks,
|
|
349
|
+
readOnly: !!options.readOnly,
|
|
350
|
+
...(options.tasks?.wake ? { wake: options.tasks.wake } : {}),
|
|
351
|
+
...(options.tasks?.onChange ? { onChange: options.tasks.onChange } : {}),
|
|
352
|
+
...(options.tasks?.timing ? { timing: options.tasks.timing } : {}),
|
|
353
|
+
...(options.tasks?.maxPerProcess ? { maxPerProcess: options.tasks.maxPerProcess } : {}),
|
|
354
|
+
...(options.tasks?.killGraceMs ? { killGraceMs: options.tasks.killGraceMs } : {}),
|
|
355
|
+
mirror: (root) => subagentTasks(plugins.panels, root),
|
|
356
|
+
onError: (error) => process.stderr.write(`Background task error: ${error instanceof Error ? error.message : String(error)}\n`),
|
|
357
|
+
});
|
|
358
|
+
tasks.recover();
|
|
359
|
+
const taskJanitor = new TaskJanitor({
|
|
360
|
+
store: tasks.store,
|
|
361
|
+
stateRoot,
|
|
362
|
+
retentionDays: () => config.tasks.retentionDays,
|
|
363
|
+
...(options.tasks?.sweepDelayMs !== undefined
|
|
364
|
+
? { initialDelayMs: options.tasks.sweepDelayMs }
|
|
365
|
+
: {}),
|
|
237
366
|
});
|
|
367
|
+
if (config.tasks.enabled) {
|
|
368
|
+
const { registerBackgroundTools } = await import("./tools/background.js");
|
|
369
|
+
registerBackgroundTools(registry, { tasks, rootOf: (id) => store.rootOf(id) });
|
|
370
|
+
}
|
|
371
|
+
// Session goals (`/goal`): one service over the shared database. A goal left `active` by a
|
|
372
|
+
// process that is gone pauses with reason `restart` now (never auto-resumed). The two goal
|
|
373
|
+
// tools are opt-in: a run only sees them while its session has an active goal.
|
|
374
|
+
const goals = new GoalService({
|
|
375
|
+
store: new GoalStore(store.db),
|
|
376
|
+
settings: () => config.goal,
|
|
377
|
+
...(options.goals?.onChange ? { onChange: options.goals.onChange } : {}),
|
|
378
|
+
...(options.goals?.onLog ? { onLog: options.goals.onLog } : {}),
|
|
379
|
+
});
|
|
380
|
+
if (options.goals?.recover !== false)
|
|
381
|
+
goals.recover();
|
|
382
|
+
registerGoalTools(registry, { goals });
|
|
383
|
+
// R4: nothing is registered with analysis disabled or under --read-only. Startup only looks
|
|
384
|
+
// for candidate interpreters with `stat`; no process is launched until the first call.
|
|
385
|
+
const analysisEnabled = config.analysis.enabled && !options.readOnly;
|
|
386
|
+
if (analysisEnabled) {
|
|
387
|
+
const [candidates, active] = await Promise.all([
|
|
388
|
+
analysisRuntime.candidates(),
|
|
389
|
+
analysisRuntime.activeRuntime(),
|
|
390
|
+
]);
|
|
391
|
+
const { registerAnalysisTools } = await import("./tools/analysis.js");
|
|
392
|
+
registerAnalysisTools(registry, {
|
|
393
|
+
store: artifacts,
|
|
394
|
+
jobs: analysisJobs,
|
|
395
|
+
runtime: analysisRuntime,
|
|
396
|
+
datasets,
|
|
397
|
+
oci,
|
|
398
|
+
rerun: analysisRerun,
|
|
399
|
+
rootOf: (id) => store.rootOf(id),
|
|
400
|
+
// Read live: a changed `analysis.limits.*` setting applies to the next call.
|
|
401
|
+
limits: {
|
|
402
|
+
get timeoutMs() {
|
|
403
|
+
return config.analysis.limits.timeoutMs;
|
|
404
|
+
},
|
|
405
|
+
get maxLogBytes() {
|
|
406
|
+
return config.analysis.limits.maxLogBytes;
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
startup: { candidates: candidates.length > 0, extras: active?.extras ?? [] },
|
|
410
|
+
});
|
|
411
|
+
const { registerArtifactTools } = await import("./tools/artifacts.js");
|
|
412
|
+
registerArtifactTools(registry, { store: artifacts, rootOf: (id) => store.rootOf(id) });
|
|
413
|
+
}
|
|
414
|
+
// `exit_plan` (opt-in: only the plan agent's run sees it): the plan review hand-over.
|
|
415
|
+
const { registerExitPlan } = await import("./plan/exit-plan.js");
|
|
416
|
+
registerExitPlan(registry, { store, ui: plugins.ui, readOnly: !!options.readOnly });
|
|
417
|
+
// Data tools only read (effect `read`): they stay available under --read-only.
|
|
418
|
+
if (config.analysis.enabled) {
|
|
419
|
+
const { registerDataTools } = await import("./tools/data.js");
|
|
420
|
+
registerDataTools(registry, { datasets, rootOf: (id) => store.rootOf(id) });
|
|
421
|
+
}
|
|
422
|
+
const sessionWorkspace = (sessionId) => {
|
|
423
|
+
try {
|
|
424
|
+
return store.get(sessionId).workspace;
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
return workspace;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
238
430
|
const { registerPluginInstallTool } = await import("./plugins/install.js");
|
|
239
431
|
registerPluginInstallTool(registry, { readOnly: !!options.readOnly });
|
|
240
432
|
if ((options.allowMcp || mcpAllow) && !options.readOnly)
|
|
@@ -475,6 +667,7 @@ export async function createApplication(options = {}) {
|
|
|
475
667
|
const runtimePolicy = {
|
|
476
668
|
write: !!options.allowWrite && !options.readOnly,
|
|
477
669
|
process: !!options.allowProcess && !options.readOnly,
|
|
670
|
+
...(options.allowAnalysis && !options.readOnly ? { analysis: true } : {}),
|
|
478
671
|
external: !options.readOnly &&
|
|
479
672
|
(!!options.allowExternal ||
|
|
480
673
|
!!options.allowMcp ||
|
|
@@ -483,6 +676,52 @@ export async function createApplication(options = {}) {
|
|
|
483
676
|
plugins.externalCount > 0 ||
|
|
484
677
|
registry.list().some((t) => t.name.startsWith("p_"))),
|
|
485
678
|
};
|
|
679
|
+
/** Model and provider of a session, for the provenance of its artifacts. */
|
|
680
|
+
const provenanceOf = (sessionId) => {
|
|
681
|
+
try {
|
|
682
|
+
const session = store.get(sessionId);
|
|
683
|
+
return {
|
|
684
|
+
...(session.model ? { model: session.model } : {}),
|
|
685
|
+
...(session.provider ? { provider: session.provider } : {}),
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
catch {
|
|
689
|
+
return {};
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
/**
|
|
693
|
+
* The maximum output a model's catalog declares (`ModelInfo.maxOutputTokens`), for the budget
|
|
694
|
+
* of each request. Looks in the active provider's catalog first (loading it once, bounded, if
|
|
695
|
+
* the first request comes before it); then in the catalogs of the configured profiles that
|
|
696
|
+
* were already listed, taking the smallest declaration when several providers list the same
|
|
697
|
+
* model id so a derived budget never exceeds any of them. Unknown stays unknown.
|
|
698
|
+
*/
|
|
699
|
+
const declaredOutputLimit = async (model) => {
|
|
700
|
+
if (!models.has(model)) {
|
|
701
|
+
const loading = ensureModels();
|
|
702
|
+
if (loading) {
|
|
703
|
+
let timer;
|
|
704
|
+
await Promise.race([
|
|
705
|
+
loading.catch(() => undefined),
|
|
706
|
+
new Promise((resolve) => {
|
|
707
|
+
timer = setTimeout(resolve, 2_000);
|
|
708
|
+
}),
|
|
709
|
+
]);
|
|
710
|
+
if (timer)
|
|
711
|
+
clearTimeout(timer);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
const own = models.get(model)?.maxOutputTokens;
|
|
715
|
+
if (own !== undefined)
|
|
716
|
+
return own;
|
|
717
|
+
const declared = catalogCache
|
|
718
|
+
? availableProviderModels(catalogCache.value)
|
|
719
|
+
.filter((entry) => entry.model.id === model)
|
|
720
|
+
.map((entry) => entry.model.maxOutputTokens)
|
|
721
|
+
.filter((value) => typeof value === "number" && value > 0)
|
|
722
|
+
: [];
|
|
723
|
+
return declared.length ? Math.min(...declared) : undefined;
|
|
724
|
+
};
|
|
486
725
|
const runner = new AgentRunner({
|
|
487
726
|
provider,
|
|
488
727
|
providerFor,
|
|
@@ -495,7 +734,43 @@ export async function createApplication(options = {}) {
|
|
|
495
734
|
compaction: config.compaction,
|
|
496
735
|
extensions: plugins,
|
|
497
736
|
contextWindow,
|
|
737
|
+
modelOutputLimit: declaredOutputLimit,
|
|
738
|
+
fallbackMaxOutputTokens: DEFAULT_MAX_OUTPUT_TOKENS,
|
|
739
|
+
effortLevels: (model) => {
|
|
740
|
+
const known = models.get(model)?.effort;
|
|
741
|
+
if (!known)
|
|
742
|
+
void ensureModels();
|
|
743
|
+
return known;
|
|
744
|
+
},
|
|
498
745
|
...(options.approve && !options.readOnly ? { approve: options.approve } : {}),
|
|
746
|
+
pathAccess,
|
|
747
|
+
...(analysisEnabled
|
|
748
|
+
? {
|
|
749
|
+
capabilities: {
|
|
750
|
+
granted: (capability, sessionId) => capabilityGrants.granted(capability, sessionId),
|
|
751
|
+
record: (input) => {
|
|
752
|
+
capabilityGrants.record({ ...input, workspace: sessionWorkspace(input.sessionId) });
|
|
753
|
+
},
|
|
754
|
+
source: options.approvalSource ?? "tui",
|
|
755
|
+
get runtime() {
|
|
756
|
+
return config.analysis.runtime;
|
|
757
|
+
},
|
|
758
|
+
// A rerun's approval shows the saved script (the input carries only its reference).
|
|
759
|
+
preview: async (input, sessionId) => typeof input.rerunOf === "string"
|
|
760
|
+
? analysisRerun.script(input.rerunOf, store.rootOf(sessionId))
|
|
761
|
+
: undefined,
|
|
762
|
+
},
|
|
763
|
+
}
|
|
764
|
+
: {}),
|
|
765
|
+
artifacts: (call, announce) => createArtifactPublisher(artifacts, {
|
|
766
|
+
sessionId: call.sessionId,
|
|
767
|
+
rootSessionId: store.rootOf(call.sessionId),
|
|
768
|
+
workspace: sessionWorkspace(call.sessionId),
|
|
769
|
+
runId: call.runId,
|
|
770
|
+
callId: call.callId,
|
|
771
|
+
// Public provenance of what produced the artifact (no paths, no keys).
|
|
772
|
+
provenance: provenanceOf(call.sessionId),
|
|
773
|
+
}, announce),
|
|
499
774
|
...(config.websearch.provider === "native"
|
|
500
775
|
? { nativeTools: [{ type: config.websearch.nativeToolType }] }
|
|
501
776
|
: {}),
|
|
@@ -508,6 +783,10 @@ export async function createApplication(options = {}) {
|
|
|
508
783
|
// Child sessions (generic delegation service for plugins). Contexts are cached per workspace
|
|
509
784
|
// so a child in a git worktree reads that worktree's AGENTS.md files.
|
|
510
785
|
const contexts = new Map([[workspace, context]]);
|
|
786
|
+
// Startup reconciliation: runs left queued/running by a dead process become `interrupted`
|
|
787
|
+
// (runs of this process, e.g. another Application in a server, are kept). Child sessions are
|
|
788
|
+
// reconciled by `interruptStale()` in the ChildSessions constructor right below.
|
|
789
|
+
store.interruptRuns();
|
|
511
790
|
plugins.setSessions(new ChildSessions({
|
|
512
791
|
store,
|
|
513
792
|
runner,
|
|
@@ -574,12 +853,43 @@ export async function createApplication(options = {}) {
|
|
|
574
853
|
}
|
|
575
854
|
}
|
|
576
855
|
}
|
|
856
|
+
// Retention runs in the background (unreferenced timer); never for in-memory test databases.
|
|
857
|
+
if (analysisEnabled && options.db !== ":memory:")
|
|
858
|
+
janitor.start();
|
|
859
|
+
// Retention is maintenance that deletes files: never under --read-only, never for `:memory:`.
|
|
860
|
+
if (options.db !== ":memory:" && !options.readOnly)
|
|
861
|
+
taskJanitor.start();
|
|
577
862
|
return {
|
|
578
863
|
workspace,
|
|
864
|
+
pathAccess,
|
|
579
865
|
config,
|
|
580
866
|
prompts,
|
|
581
867
|
expandPrompt,
|
|
582
868
|
store,
|
|
869
|
+
/** Uploaded attachment bytes; resolve a `BlobRef` with `blobs.attachment(ref)` before a run. */
|
|
870
|
+
blobs,
|
|
871
|
+
/** Published artifacts of every session (folders under `<state>/artifacts`). */
|
|
872
|
+
artifacts,
|
|
873
|
+
/** Persisted capability grants (`analysis.run`) and their audit rows. */
|
|
874
|
+
capabilityGrants,
|
|
875
|
+
/** Background tasks (`bg_*` tools, `/tasks` panels): admission, state, output, stop. */
|
|
876
|
+
tasks,
|
|
877
|
+
/** Session goals (`/goal`): state, user actions, the continuation controller. */
|
|
878
|
+
goals,
|
|
879
|
+
/** Python discovery and job folders of `python_run`; `enabled` is false under --read-only. */
|
|
880
|
+
analysis: {
|
|
881
|
+
enabled: analysisEnabled,
|
|
882
|
+
runtime: analysisRuntime,
|
|
883
|
+
jobs: analysisJobs,
|
|
884
|
+
/** Container runtime of the current configuration (status, pull); mode `managed` ignores it. */
|
|
885
|
+
oci,
|
|
886
|
+
rerun: analysisRerun,
|
|
887
|
+
janitor,
|
|
888
|
+
},
|
|
889
|
+
/** Keys a project layer set that only the user layer decides (ignored on load). */
|
|
890
|
+
configDiagnostics: configProvenance.ignored ?? [],
|
|
891
|
+
/** Tabular datasets of every session (ingestion, read-only queries, pages). */
|
|
892
|
+
datasets,
|
|
583
893
|
registry,
|
|
584
894
|
context,
|
|
585
895
|
skills,
|
|
@@ -672,12 +982,15 @@ export async function createApplication(options = {}) {
|
|
|
672
982
|
mcpStartupFailures() {
|
|
673
983
|
return [...mcpStartupFailures];
|
|
674
984
|
},
|
|
675
|
-
/**
|
|
985
|
+
/**
|
|
986
|
+
* Host-owned interactive consent boundary: the TUI and the web UI (`alisio serve`, after an
|
|
987
|
+
* explicit confirmation dialog) may grant. Headless callers remain blocked unless flagged.
|
|
988
|
+
*/
|
|
676
989
|
grantMcpRuntimePermission(request) {
|
|
677
990
|
if (!request.confirmed)
|
|
678
991
|
return mcpRuntimePermission;
|
|
679
|
-
if (request.source !== "interactive-tui")
|
|
680
|
-
throw new Error("MCP runtime permission may only be granted by
|
|
992
|
+
if (request.source !== "interactive-tui" && request.source !== "interactive-web")
|
|
993
|
+
throw new Error("MCP runtime permission may only be granted by an interactive UI");
|
|
681
994
|
if (options.readOnly)
|
|
682
995
|
throw new Error("MCP is unavailable under --read-only");
|
|
683
996
|
if (mcpRuntimePermission === "granted")
|
|
@@ -688,12 +1001,12 @@ export async function createApplication(options = {}) {
|
|
|
688
1001
|
return mcpRuntimePermission;
|
|
689
1002
|
},
|
|
690
1003
|
/** Persist global consent atomically, then grant runtime permission for this process. */
|
|
691
|
-
async rememberGlobalMcpConsent() {
|
|
1004
|
+
async rememberGlobalMcpConsent(source = "interactive-tui") {
|
|
692
1005
|
if (options.readOnly)
|
|
693
1006
|
throw new Error("MCP is unavailable under --read-only");
|
|
694
1007
|
await setGlobalMcpAllow({ allow: true });
|
|
695
1008
|
persistedMcpAllow = true;
|
|
696
|
-
this.grantMcpRuntimePermission({ source
|
|
1009
|
+
this.grantMcpRuntimePermission({ source, confirmed: true });
|
|
697
1010
|
},
|
|
698
1011
|
/**
|
|
699
1012
|
* Clear the persisted global consent atomically and drop the runtime permission (disconnecting
|
|
@@ -729,6 +1042,139 @@ export async function createApplication(options = {}) {
|
|
|
729
1042
|
: undefined);
|
|
730
1043
|
return mcp.info(id);
|
|
731
1044
|
},
|
|
1045
|
+
/**
|
|
1046
|
+
* Persist one user-facing setting to the GLOBAL user config (`<config home>/config.json`)
|
|
1047
|
+
* and apply it to this process where the value can change live. Compaction and limits land
|
|
1048
|
+
* in the runner (honored by the next run/compact), `context.*` lands in the project context
|
|
1049
|
+
* (next instructions load), `websearch.provider` mutates the shared config object the search
|
|
1050
|
+
* chain reads per call, `pluginHooks.timeoutMs` lands in the plugin host (next hook call),
|
|
1051
|
+
* and `tui.*` is persisted for the host to apply. Nothing in this set requires a restart.
|
|
1052
|
+
* `agents.*` (active agent id and reasoning effort) is persisted for the TUI to consume:
|
|
1053
|
+
* the next `/agents`/`/effort` selection and the next prompt already read the live config.
|
|
1054
|
+
* `mcp.allow` is deliberately not routed here: it flows through
|
|
1055
|
+
* `rememberGlobalMcpConsent`/`revokeGlobalMcpConsent` instead.
|
|
1056
|
+
* Throws under `--read-only`. Returns the written config file.
|
|
1057
|
+
*/
|
|
1058
|
+
async updateSetting(key, value) {
|
|
1059
|
+
if (options.readOnly)
|
|
1060
|
+
throw new Error("Settings changes are unavailable under --read-only");
|
|
1061
|
+
const file = await setConfigValue({ key, value });
|
|
1062
|
+
const compactionLeaf = (leaf) => ({ [leaf]: value });
|
|
1063
|
+
const limitLeaf = (leaf) => ({ [leaf]: value });
|
|
1064
|
+
switch (key) {
|
|
1065
|
+
case "compaction.auto":
|
|
1066
|
+
case "compaction.threshold":
|
|
1067
|
+
case "compaction.keepTurns":
|
|
1068
|
+
case "compaction.maxOutputTokens": {
|
|
1069
|
+
const patch = compactionLeaf(key.slice("compaction.".length));
|
|
1070
|
+
config.compaction = { ...config.compaction, ...patch };
|
|
1071
|
+
runner.applySettings({ compaction: patch });
|
|
1072
|
+
break;
|
|
1073
|
+
}
|
|
1074
|
+
case "context.claudeMdFallback":
|
|
1075
|
+
config.context = { ...config.context, claudeMdFallback: value === true };
|
|
1076
|
+
context.update({ claudeMdFallback: value === true });
|
|
1077
|
+
break;
|
|
1078
|
+
case "context.maxBytes":
|
|
1079
|
+
config.context = { ...config.context, maxBytes: Number(value) };
|
|
1080
|
+
context.update({ maxBytes: Number(value) });
|
|
1081
|
+
break;
|
|
1082
|
+
case "limits.maxTurns":
|
|
1083
|
+
case "limits.maxOutputTokens":
|
|
1084
|
+
case "limits.maxContextChars":
|
|
1085
|
+
case "limits.firstTokenTimeoutMs":
|
|
1086
|
+
case "limits.firstTokenRetries":
|
|
1087
|
+
case "limits.truncationRecoveries":
|
|
1088
|
+
case "limits.timeoutMs": {
|
|
1089
|
+
const patch = limitLeaf(key.slice("limits.".length));
|
|
1090
|
+
config.limits = { ...config.limits, ...patch };
|
|
1091
|
+
runner.applySettings(patch);
|
|
1092
|
+
break;
|
|
1093
|
+
}
|
|
1094
|
+
case "pluginHooks.timeoutMs":
|
|
1095
|
+
config.pluginHooks = { ...config.pluginHooks, timeoutMs: Number(value) };
|
|
1096
|
+
plugins.applyTimeoutSettings({ hookTimeoutMs: Number(value) });
|
|
1097
|
+
break;
|
|
1098
|
+
case "tui.paddingX":
|
|
1099
|
+
config.tui = { ...config.tui, paddingX: Number(value) };
|
|
1100
|
+
break;
|
|
1101
|
+
case "tui.contentPaddingX":
|
|
1102
|
+
config.tui = { ...config.tui, contentPaddingX: Number(value) };
|
|
1103
|
+
break;
|
|
1104
|
+
case "tui.skillSlashCommands":
|
|
1105
|
+
config.tui = { ...config.tui, skillSlashCommands: value === true };
|
|
1106
|
+
break;
|
|
1107
|
+
case "agents.active":
|
|
1108
|
+
config.agents = { ...config.agents, active: String(value) };
|
|
1109
|
+
break;
|
|
1110
|
+
case "agents.effort":
|
|
1111
|
+
// Clearing (undefined) drops the leaf from the live config and the JSON file.
|
|
1112
|
+
config.agents =
|
|
1113
|
+
value === undefined
|
|
1114
|
+
? { active: config.agents.active }
|
|
1115
|
+
: { ...config.agents, effort: String(value) };
|
|
1116
|
+
break;
|
|
1117
|
+
case "analysis.enabled":
|
|
1118
|
+
// Tools are registered when the application starts: the change applies to the next
|
|
1119
|
+
// application (a restart; the web recycles the workspace application).
|
|
1120
|
+
config.analysis = { ...config.analysis, enabled: value === true };
|
|
1121
|
+
break;
|
|
1122
|
+
case "analysis.limits.timeoutMs":
|
|
1123
|
+
// Read live by python_run on its next call.
|
|
1124
|
+
config.analysis = {
|
|
1125
|
+
...config.analysis,
|
|
1126
|
+
limits: { ...config.analysis.limits, timeoutMs: Number(value) },
|
|
1127
|
+
};
|
|
1128
|
+
break;
|
|
1129
|
+
case "analysis.retention.jobsDays":
|
|
1130
|
+
case "analysis.retention.intermediateDays":
|
|
1131
|
+
case "analysis.retention.artifactsDays": {
|
|
1132
|
+
// Read by the next sweep.
|
|
1133
|
+
const leaf = key.slice("analysis.retention.".length);
|
|
1134
|
+
config.analysis = {
|
|
1135
|
+
...config.analysis,
|
|
1136
|
+
retention: { ...config.analysis.retention, [leaf]: Number(value) },
|
|
1137
|
+
};
|
|
1138
|
+
break;
|
|
1139
|
+
}
|
|
1140
|
+
case "goal.enabled":
|
|
1141
|
+
case "goal.maxTurns":
|
|
1142
|
+
case "goal.maxMinutes":
|
|
1143
|
+
case "goal.repeatedReplyLimit":
|
|
1144
|
+
case "goal.noToolTurnsLimit":
|
|
1145
|
+
case "goal.blockedRepeats": {
|
|
1146
|
+
// Read live: the next continuation (or the next `/goal`) uses the new value. The caps
|
|
1147
|
+
// of a goal already running were snapshotted when it was created.
|
|
1148
|
+
const leaf = key.slice("goal.".length);
|
|
1149
|
+
config.goal = {
|
|
1150
|
+
...config.goal,
|
|
1151
|
+
[leaf]: leaf === "enabled" ? value === true : Number(value),
|
|
1152
|
+
};
|
|
1153
|
+
break;
|
|
1154
|
+
}
|
|
1155
|
+
case "tasks.enabled":
|
|
1156
|
+
// Tools are registered when the application starts: the change applies to the next
|
|
1157
|
+
// application (a restart; the web recycles the workspace application).
|
|
1158
|
+
config.tasks = { ...config.tasks, enabled: value === true };
|
|
1159
|
+
break;
|
|
1160
|
+
case "tasks.maxPerSession":
|
|
1161
|
+
case "tasks.maxRunMs":
|
|
1162
|
+
case "tasks.maxOutputBytes":
|
|
1163
|
+
case "tasks.retentionDays": {
|
|
1164
|
+
// Read live: the next task (or the next sweep) uses the new value.
|
|
1165
|
+
const leaf = key.slice("tasks.".length);
|
|
1166
|
+
config.tasks = { ...config.tasks, [leaf]: Number(value) };
|
|
1167
|
+
break;
|
|
1168
|
+
}
|
|
1169
|
+
case "websearch.provider":
|
|
1170
|
+
// Mutated in place (same object identity) so the tool chain's per-call
|
|
1171
|
+
// `websearchCtx.config` sees the new provider on the very next search call.
|
|
1172
|
+
config.websearch.provider =
|
|
1173
|
+
value === undefined ? undefined : value;
|
|
1174
|
+
break;
|
|
1175
|
+
}
|
|
1176
|
+
return file;
|
|
1177
|
+
},
|
|
732
1178
|
provider,
|
|
733
1179
|
providers,
|
|
734
1180
|
providerSettings,
|
|
@@ -739,6 +1185,40 @@ export async function createApplication(options = {}) {
|
|
|
739
1185
|
return providerInfo;
|
|
740
1186
|
},
|
|
741
1187
|
runner,
|
|
1188
|
+
/** `/btw` side questions: tool-less answers about a session outside its conversation. */
|
|
1189
|
+
sideQuestions: new SideQuestions({ runner, state: store }),
|
|
1190
|
+
/**
|
|
1191
|
+
* User agent files (`<workspace>/.agents/agents`, `~/.agents/agents`). Every write asks the
|
|
1192
|
+
* subagents plugin (the runtime agent registry) to rediscover through its `/agents reload`
|
|
1193
|
+
* verb and reports whether the saved file is loaded; without the plugin nothing reloads.
|
|
1194
|
+
*/
|
|
1195
|
+
agentDefinitions: new AgentDefinitionService({
|
|
1196
|
+
workspace,
|
|
1197
|
+
home: homedir(),
|
|
1198
|
+
registry: {
|
|
1199
|
+
async reload() {
|
|
1200
|
+
const handler = plugins.commands.get("agents");
|
|
1201
|
+
if (!handler)
|
|
1202
|
+
return false;
|
|
1203
|
+
await handler("reload");
|
|
1204
|
+
return Array.isArray(plugins.pluginState("subagents", "definitions"));
|
|
1205
|
+
},
|
|
1206
|
+
loadedPaths() {
|
|
1207
|
+
let state;
|
|
1208
|
+
try {
|
|
1209
|
+
state = plugins.pluginState("subagents", "definitions");
|
|
1210
|
+
}
|
|
1211
|
+
catch {
|
|
1212
|
+
return undefined;
|
|
1213
|
+
}
|
|
1214
|
+
if (!Array.isArray(state))
|
|
1215
|
+
return undefined;
|
|
1216
|
+
return state
|
|
1217
|
+
.map((entry) => entry?.path)
|
|
1218
|
+
.filter((path) => typeof path === "string");
|
|
1219
|
+
},
|
|
1220
|
+
},
|
|
1221
|
+
}),
|
|
742
1222
|
herdr,
|
|
743
1223
|
contextWindow,
|
|
744
1224
|
/** Effective context budget + compaction point shared by the runner and the TUI bar. */
|
|
@@ -837,24 +1317,34 @@ export async function createApplication(options = {}) {
|
|
|
837
1317
|
});
|
|
838
1318
|
},
|
|
839
1319
|
async close() {
|
|
1320
|
+
// Exit latency is user-facing: tear down herdr + MCP in parallel, then provider +
|
|
1321
|
+
// plugins (store last). Every stage is raced against a cap so a single hanging
|
|
1322
|
+
// component cannot stall /exit; teardown errors are swallowed for callers.
|
|
1323
|
+
const capped = (work) => Promise.race([work.catch(() => { }), delay(TEARDOWN_STAGE_TIMEOUT_MS)]);
|
|
840
1324
|
try {
|
|
841
|
-
|
|
842
|
-
|
|
1325
|
+
janitor.stop();
|
|
1326
|
+
taskJanitor.stop();
|
|
1327
|
+
datasets?.close();
|
|
1328
|
+
// Tasks first in the same stage: they end with Alisio (process groups killed).
|
|
1329
|
+
await capped(Promise.allSettled([herdr.close(), mcp.close(), tasks.close()]));
|
|
843
1330
|
}
|
|
844
1331
|
finally {
|
|
845
1332
|
try {
|
|
846
|
-
await
|
|
847
|
-
|
|
848
|
-
...new Set([
|
|
1333
|
+
await capped((async () => {
|
|
1334
|
+
const runtimes = new Set([
|
|
849
1335
|
...(await Promise.allSettled(targetProviders.values()))
|
|
850
1336
|
.filter((x) => x.status === "fulfilled")
|
|
851
1337
|
.map((x) => x.value),
|
|
852
1338
|
...retainedProviders,
|
|
853
|
-
])
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1339
|
+
]);
|
|
1340
|
+
await Promise.allSettled([
|
|
1341
|
+
provider.dispose(),
|
|
1342
|
+
...[...runtimes]
|
|
1343
|
+
.filter((runtime) => runtime !== provider.currentProvider)
|
|
1344
|
+
.map((runtime) => Promise.resolve(runtime.dispose?.())),
|
|
1345
|
+
plugins.close(),
|
|
1346
|
+
]);
|
|
1347
|
+
})());
|
|
858
1348
|
}
|
|
859
1349
|
finally {
|
|
860
1350
|
store.close();
|
|
@@ -864,9 +1354,10 @@ export async function createApplication(options = {}) {
|
|
|
864
1354
|
};
|
|
865
1355
|
}
|
|
866
1356
|
catch (e) {
|
|
867
|
-
await
|
|
868
|
-
|
|
869
|
-
|
|
1357
|
+
await Promise.race([
|
|
1358
|
+
Promise.allSettled([herdr.close(), mcp.close(), plugins.close()]),
|
|
1359
|
+
delay(TEARDOWN_STAGE_TIMEOUT_MS),
|
|
1360
|
+
]);
|
|
870
1361
|
store.close();
|
|
871
1362
|
throw e;
|
|
872
1363
|
}
|