@alisio/core 0.4.4 → 0.5.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/dist/application.js +20 -0
- package/dist/changelog/data.js +13 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +24 -0
- package/dist/extensions/registry.d.ts +8 -5
- package/dist/extensions/registry.js +24 -0
- package/package.json +2 -2
package/dist/application.js
CHANGED
|
@@ -321,6 +321,22 @@ export async function createApplication(options = {}) {
|
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Plugin resources (`api.resources.agents`) register during activation, but the built-in
|
|
326
|
+
* subagents plugin discovers agent files in its own setup, which runs BEFORE external plugins
|
|
327
|
+
* (config, command line, plugin directories) are activated. Re-run its discovery once every
|
|
328
|
+
* plugin has registered, so the first `/api/agents` (web selector and Agents page, TUI cycle)
|
|
329
|
+
* already lists the plugin primary agents instead of waiting for a manual `/agents reload`.
|
|
330
|
+
*/
|
|
331
|
+
const rediscoverAgents = plugins.commands.get("agents");
|
|
332
|
+
if (rediscoverAgents) {
|
|
333
|
+
try {
|
|
334
|
+
await rediscoverAgents("reload");
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
/* keeps the built-ins: agent discovery is best-effort */
|
|
338
|
+
}
|
|
339
|
+
}
|
|
324
340
|
// Every plugin has registered its providers: start the configured one in the background
|
|
325
341
|
// (`activate` is bounded, never fatal and never awaited here).
|
|
326
342
|
decisionService.syncActive();
|
|
@@ -1290,6 +1306,10 @@ export async function createApplication(options = {}) {
|
|
|
1290
1306
|
config.tasks = { ...config.tasks, [leaf]: Number(value) };
|
|
1291
1307
|
break;
|
|
1292
1308
|
}
|
|
1309
|
+
case "web.iconTheme":
|
|
1310
|
+
// Read live by the icon-theme routes on the next request; `"none"` clears the theme.
|
|
1311
|
+
config.web = { ...config.web, iconTheme: String(value) };
|
|
1312
|
+
break;
|
|
1293
1313
|
case "websearch.provider":
|
|
1294
1314
|
// Mutated in place (same object identity) so the tool chain's per-call
|
|
1295
1315
|
// `websearchCtx.config` sees the new provider on the very next search call.
|
package/dist/changelog/data.js
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
export const CHANGELOG_DATA = {
|
|
3
3
|
schema: 1,
|
|
4
4
|
entries: [
|
|
5
|
+
{
|
|
6
|
+
version: "0.4.5",
|
|
7
|
+
date: "2026-10-07",
|
|
8
|
+
sections: [
|
|
9
|
+
{
|
|
10
|
+
title: "Fixed",
|
|
11
|
+
items: [
|
|
12
|
+
"The chat agent selector, the Agents page and Shift+Tab list a plugin's `primary` agents on the first open, instead of only the built-ins until you visited the Agents window and came back.",
|
|
13
|
+
'Choosing "Full access" applies to the session that is already running: it stops asking for approvals from the next tool call, not only on the following turn.',
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
},
|
|
5
18
|
{
|
|
6
19
|
version: "0.4.4",
|
|
7
20
|
date: "2026-10-04",
|
package/dist/config.d.ts
CHANGED
|
@@ -255,6 +255,9 @@ export declare const configSchema: z.ZodPipe<z.ZodObject<{
|
|
|
255
255
|
active: z.ZodDefault<z.ZodString>;
|
|
256
256
|
effort: z.ZodOptional<z.ZodString>;
|
|
257
257
|
}, z.core.$strict>>;
|
|
258
|
+
web: z.ZodDefault<z.ZodObject<{
|
|
259
|
+
iconTheme: z.ZodDefault<z.ZodString>;
|
|
260
|
+
}, z.core.$strict>>;
|
|
258
261
|
}, z.core.$strict>, z.ZodTransform<{
|
|
259
262
|
schemaVersion: 1;
|
|
260
263
|
provider: {
|
|
@@ -376,6 +379,9 @@ export declare const configSchema: z.ZodPipe<z.ZodObject<{
|
|
|
376
379
|
active: string;
|
|
377
380
|
effort?: string | undefined;
|
|
378
381
|
};
|
|
382
|
+
web: {
|
|
383
|
+
iconTheme: string;
|
|
384
|
+
};
|
|
379
385
|
mcp: {
|
|
380
386
|
allow?: boolean | undefined;
|
|
381
387
|
servers: {
|
|
@@ -580,6 +586,9 @@ export declare const configSchema: z.ZodPipe<z.ZodObject<{
|
|
|
580
586
|
active: string;
|
|
581
587
|
effort?: string | undefined;
|
|
582
588
|
};
|
|
589
|
+
web: {
|
|
590
|
+
iconTheme: string;
|
|
591
|
+
};
|
|
583
592
|
}>>;
|
|
584
593
|
export type Config = z.infer<typeof configSchema>;
|
|
585
594
|
export type ServerConfig = z.infer<typeof serverSchema>;
|
|
@@ -695,6 +704,7 @@ declare const SETTABLE_KEYS: {
|
|
|
695
704
|
readonly "goal.blockedRepeats": z.ZodDefault<z.ZodNumber>;
|
|
696
705
|
readonly "plan.diagrams": z.ZodDefault<z.ZodBoolean>;
|
|
697
706
|
readonly "plan.maxDiagrams": z.ZodDefault<z.ZodNumber>;
|
|
707
|
+
readonly "web.iconTheme": z.ZodDefault<z.ZodString>;
|
|
698
708
|
};
|
|
699
709
|
export type SettableSettingKey = keyof typeof SETTABLE_KEYS;
|
|
700
710
|
export declare function isSettableSettingKey(key: string): key is SettableSettingKey;
|
package/dist/config.js
CHANGED
|
@@ -85,6 +85,8 @@ export const OCI_IMAGE_PATTERN = /^[a-zA-Z0-9][^\s@]*@sha256:[a-f0-9]{64}$/;
|
|
|
85
85
|
const GLOBAL_ONLY_ANALYSIS = ["runtime", "oci", "retention"];
|
|
86
86
|
/** Decision Intelligence keys only the user (global) layer decides: the provider and telemetry. */
|
|
87
87
|
const GLOBAL_ONLY_DECISIONS = ["provider", "telemetry"];
|
|
88
|
+
/** Web UI keys only the user (global) layer decides: the server picks which theme it serves. */
|
|
89
|
+
const GLOBAL_ONLY_WEB = ["iconTheme"];
|
|
88
90
|
/** JSON values a plugin may receive as options (`pluginOverrides[id].options`). */
|
|
89
91
|
const jsonValueSchema = z.lazy(() => z.union([
|
|
90
92
|
z.string(),
|
|
@@ -503,6 +505,17 @@ const configObjectSchema = z
|
|
|
503
505
|
})
|
|
504
506
|
.strict()
|
|
505
507
|
.default(() => ({ active: "build" })),
|
|
508
|
+
/**
|
|
509
|
+
* Web UI preferences. `iconTheme` names the active `icon-theme` extension point provider
|
|
510
|
+
* (`"none"` keeps the built-in inline icons). GLOBAL ONLY: the server decides which theme its
|
|
511
|
+
* files serve, so a repository cannot pick one.
|
|
512
|
+
*/
|
|
513
|
+
web: z
|
|
514
|
+
.object({
|
|
515
|
+
iconTheme: z.string().trim().min(1).max(100).default("none"),
|
|
516
|
+
})
|
|
517
|
+
.strict()
|
|
518
|
+
.default(() => ({ iconTheme: "none" })),
|
|
506
519
|
})
|
|
507
520
|
.strict()
|
|
508
521
|
.superRefine((config, context) => {
|
|
@@ -618,6 +631,9 @@ export async function loadConfigWithProvenance(workspace, options = {}) {
|
|
|
618
631
|
const decisionsRaw = object.decisions && typeof object.decisions === "object" && !Array.isArray(object.decisions)
|
|
619
632
|
? object.decisions
|
|
620
633
|
: {};
|
|
634
|
+
const webRaw = object.web && typeof object.web === "object" && !Array.isArray(object.web)
|
|
635
|
+
? object.web
|
|
636
|
+
: {};
|
|
621
637
|
const overridesRaw = object.pluginOverrides &&
|
|
622
638
|
typeof object.pluginOverrides === "object" &&
|
|
623
639
|
!Array.isArray(object.pluginOverrides)
|
|
@@ -626,6 +642,7 @@ export async function loadConfigWithProvenance(workspace, options = {}) {
|
|
|
626
642
|
const ignored = [
|
|
627
643
|
...GLOBAL_ONLY_ANALYSIS.filter((key) => key in analysisRaw).map((key) => `analysis.${key}`),
|
|
628
644
|
...GLOBAL_ONLY_DECISIONS.filter((key) => key in decisionsRaw).map((key) => `decisions.${key}`),
|
|
645
|
+
...GLOBAL_ONLY_WEB.filter((key) => key in webRaw).map((key) => `web.${key}`),
|
|
629
646
|
...Object.entries(overridesRaw)
|
|
630
647
|
.filter(([, entry]) => !!entry && typeof entry === "object" && !Array.isArray(entry) && "options" in entry)
|
|
631
648
|
.map(([id]) => `pluginOverrides.${id}.options`),
|
|
@@ -738,6 +755,11 @@ export async function loadConfigWithProvenance(workspace, options = {}) {
|
|
|
738
755
|
};
|
|
739
756
|
continue;
|
|
740
757
|
}
|
|
758
|
+
if (key === "web") {
|
|
759
|
+
// `iconTheme` is global-only (the server decides which theme its files serve).
|
|
760
|
+
overlaid.web = { ...selected.config.web, iconTheme: global.config.web.iconTheme };
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
741
763
|
overlaid[key] = selected.config[key];
|
|
742
764
|
}
|
|
743
765
|
if (selected.keys.has("mcp") || selected.keys.has("mcpServers"))
|
|
@@ -889,6 +911,7 @@ const SETTABLE_SECTIONS = {
|
|
|
889
911
|
tasks: configObjectSchema.shape.tasks.removeDefault(),
|
|
890
912
|
goal: configObjectSchema.shape.goal.removeDefault(),
|
|
891
913
|
plan: configObjectSchema.shape.plan.removeDefault(),
|
|
914
|
+
web: configObjectSchema.shape.web.removeDefault(),
|
|
892
915
|
};
|
|
893
916
|
const ANALYSIS_LIMITS = SETTABLE_SECTIONS.analysis.shape.limits.removeDefault();
|
|
894
917
|
const ANALYSIS_RETENTION = SETTABLE_SECTIONS.analysis.shape.retention.removeDefault();
|
|
@@ -938,6 +961,7 @@ const SETTABLE_KEYS = {
|
|
|
938
961
|
"goal.blockedRepeats": SETTABLE_SECTIONS.goal.shape.blockedRepeats,
|
|
939
962
|
"plan.diagrams": SETTABLE_SECTIONS.plan.shape.diagrams,
|
|
940
963
|
"plan.maxDiagrams": SETTABLE_SECTIONS.plan.shape.maxDiagrams,
|
|
964
|
+
"web.iconTheme": SETTABLE_SECTIONS.web.shape.iconTheme,
|
|
941
965
|
};
|
|
942
966
|
export function isSettableSettingKey(key) {
|
|
943
967
|
return Object.prototype.hasOwnProperty.call(SETTABLE_KEYS, key);
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generic, typed extension registry. Resolution is deterministic and independent of plugin
|
|
3
|
-
* load order: highest priority, then plugin id (lexicographic), then registration order
|
|
4
|
-
* within the plugin. Fallbacks (built-in defaults) only win when nothing else is registered.
|
|
5
|
-
*/
|
|
6
1
|
import type { ExtensionPoints } from "@alisio/sdk";
|
|
7
2
|
export interface ExtensionConflict {
|
|
8
3
|
point: string;
|
|
@@ -23,6 +18,14 @@ export declare class ExtensionRegistry {
|
|
|
23
18
|
provider: ExtensionPoints[K];
|
|
24
19
|
plugin: string;
|
|
25
20
|
} | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Every provider of a point in resolution order (the same ranking `resolve` uses): highest
|
|
23
|
+
* priority first, plugin id and registration order as tie-breaks, fallbacks last.
|
|
24
|
+
*/
|
|
25
|
+
list<K extends keyof ExtensionPoints>(point: K): Array<{
|
|
26
|
+
provider: ExtensionPoints[K];
|
|
27
|
+
plugin: string;
|
|
28
|
+
}>;
|
|
26
29
|
/** Equal-priority, non-fallback competitors for each point's winning slot. */
|
|
27
30
|
conflicts(point?: keyof ExtensionPoints): ExtensionConflict[];
|
|
28
31
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, typed extension registry. Resolution is deterministic and independent of plugin
|
|
3
|
+
* load order: highest priority, then plugin id (lexicographic), then registration order
|
|
4
|
+
* within the plugin. Fallbacks (built-in defaults) only win when nothing else is registered.
|
|
5
|
+
*/
|
|
6
|
+
import { isAbsolute } from "node:path";
|
|
1
7
|
const key = (e) => `${e.plugin}/${e.provider.id}`;
|
|
2
8
|
function compare(a, b) {
|
|
3
9
|
if (a.fallback !== b.fallback)
|
|
@@ -17,6 +23,14 @@ export class ExtensionRegistry {
|
|
|
17
23
|
// a throwing or malformed provider already falls back there (see `startup/index.ts`).
|
|
18
24
|
if (!provider || typeof provider.id !== "string")
|
|
19
25
|
throw new Error(`Invalid ${point} provider: it needs an id`);
|
|
26
|
+
if (point === "icon-theme") {
|
|
27
|
+
// The server reads these absolute paths: an empty id or a relative path can never resolve.
|
|
28
|
+
const theme = provider;
|
|
29
|
+
if (!theme.id.trim())
|
|
30
|
+
throw new Error("Invalid icon-theme provider: it needs a non-empty id");
|
|
31
|
+
if (!isAbsolute(theme.manifestPath) || !isAbsolute(theme.iconsDir))
|
|
32
|
+
throw new Error("Invalid icon-theme provider: manifestPath and iconsDir must be absolute paths");
|
|
33
|
+
}
|
|
20
34
|
const priority = options.priority ?? 0;
|
|
21
35
|
if (!Number.isFinite(priority))
|
|
22
36
|
throw new Error("Extension priority must be a finite number");
|
|
@@ -40,6 +54,16 @@ export class ExtensionRegistry {
|
|
|
40
54
|
const top = this.ranked(point)[0];
|
|
41
55
|
return top ? { provider: top.provider, plugin: top.plugin } : undefined;
|
|
42
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Every provider of a point in resolution order (the same ranking `resolve` uses): highest
|
|
59
|
+
* priority first, plugin id and registration order as tie-breaks, fallbacks last.
|
|
60
|
+
*/
|
|
61
|
+
list(point) {
|
|
62
|
+
return this.ranked(point).map((entry) => ({
|
|
63
|
+
provider: entry.provider,
|
|
64
|
+
plugin: entry.plugin,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
43
67
|
/** Equal-priority, non-fallback competitors for each point's winning slot. */
|
|
44
68
|
conflicts(point) {
|
|
45
69
|
const points = point ? [point] : [...new Set(this.entries.map((e) => e.point))];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alisio/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Embeddable provider-agnostic Alisio agent core: tool loop, context compaction, local tools, MCP, plugin host and SQLite session store. Runs on Node >=22.16 and Bun.",
|
|
5
5
|
"author": "Gustavo Gutiérrez",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"node": ">=22.16"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@alisio/sdk": "0.
|
|
44
|
+
"@alisio/sdk": "0.5.0",
|
|
45
45
|
"@mixmark-io/domino": "2.2.0",
|
|
46
46
|
"@modelcontextprotocol/client": "2.1.0",
|
|
47
47
|
"ajv": "8.20.0",
|