@alisio/core 0.1.1 → 0.2.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.
@@ -413,7 +413,15 @@ export async function createApplication(options = {}) {
413
413
  }
414
414
  // `exit_plan` (opt-in: only the plan agent's run sees it): the plan review hand-over.
415
415
  const { registerExitPlan } = await import("./plan/exit-plan.js");
416
- registerExitPlan(registry, { store, ui: plugins.ui, readOnly: !!options.readOnly });
416
+ registerExitPlan(registry, {
417
+ store,
418
+ ui: plugins.ui,
419
+ readOnly: !!options.readOnly,
420
+ diagrams: () => ({
421
+ enabled: config.plan.diagrams,
422
+ max: config.plan.diagrams ? config.plan.maxDiagrams : 0,
423
+ }),
424
+ });
417
425
  // Data tools only read (effect `read`): they stay available under --read-only.
418
426
  if (config.analysis.enabled) {
419
427
  const { registerDataTools } = await import("./tools/data.js");
@@ -1152,6 +1160,13 @@ export async function createApplication(options = {}) {
1152
1160
  };
1153
1161
  break;
1154
1162
  }
1163
+ case "plan.diagrams":
1164
+ // Read live: `exit_plan` offers (or hides) its `diagrams` field on the next request.
1165
+ config.plan = { ...config.plan, diagrams: value === true };
1166
+ break;
1167
+ case "plan.maxDiagrams":
1168
+ config.plan = { ...config.plan, maxDiagrams: Number(value) };
1169
+ break;
1155
1170
  case "tasks.enabled":
1156
1171
  // Tools are registered when the application starts: the change applies to the next
1157
1172
  // application (a restart; the web recycles the workspace application).
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A cheap, deterministic quality gate for HTML dashboards: it spots the chart mistakes that models
3
+ * make when they hand-write charts (SVG pie arcs, fixed-size SVGs, libraries loaded from a CDN that
4
+ * the viewer blocks) and names the helper that avoids them. It only produces warnings for the
5
+ * `python_run` / `artifact_create` result; it never rejects an artifact.
6
+ */
7
+ /** Warnings (empty when the page looks fine) for one HTML document. */
8
+ export declare function chartWarnings(html: string): string[];
@@ -0,0 +1,84 @@
1
+ /**
2
+ * A cheap, deterministic quality gate for HTML dashboards: it spots the chart mistakes that models
3
+ * make when they hand-write charts (SVG pie arcs, fixed-size SVGs, libraries loaded from a CDN that
4
+ * the viewer blocks) and names the helper that avoids them. It only produces warnings for the
5
+ * `python_run` / `artifact_create` result; it never rejects an artifact.
6
+ */
7
+ const HELPERS = "alisio_runtime.charts (Chart.js, interactive) or alisio_runtime.svg (static)";
8
+ /** Strips scripts and styles so a bundled library never triggers the markup checks. */
9
+ function markupOf(html) {
10
+ return html
11
+ .replace(/(<script\b[^>]*>)[\s\S]*?<\/script\s*>/gi, "$1</script>")
12
+ .replace(/<style\b[^>]*>[\s\S]*?<\/style\s*>/gi, "<style></style>");
13
+ }
14
+ /** `d` attributes that draw a wedge: a line to/from the centre, an arc command and a close. */
15
+ function wedgeCount(markup) {
16
+ let count = 0;
17
+ for (const match of markup.matchAll(/<path\b[^>]*?\sd\s*=\s*["']([^"']*)["']/gi)) {
18
+ const d = match[1] ?? "";
19
+ if (/[Aa]\s*[\d.]+[\s,]+[\d.]+[\s,]+-?[\d.]+[\s,]+[01][\s,]*[01]/.test(d) &&
20
+ /[Ll]/.test(d) &&
21
+ /[Zz]/.test(d))
22
+ count++;
23
+ }
24
+ return count;
25
+ }
26
+ const numeric = (value) => {
27
+ const match = /^\s*(\d+(?:\.\d+)?)(?:px)?\s*$/.exec(value ?? "");
28
+ return match ? Number(match[1]) : undefined;
29
+ };
30
+ /** Fixed-size SVG charts: numeric width and height, no `viewBox` (they do not scale with the card). */
31
+ function fixedSvgCount(markup) {
32
+ let count = 0;
33
+ for (const block of markup.split(/<svg\b/i).slice(1)) {
34
+ const tagEnd = block.indexOf(">");
35
+ if (tagEnd < 0)
36
+ continue;
37
+ const tag = block.slice(0, tagEnd);
38
+ const body = block.slice(tagEnd, Math.max(tagEnd, block.search(/<\/svg\s*>/i)));
39
+ const attr = (name) => new RegExp(`\\s${name}\\s*=\\s*["']([^"']*)["']`, "i").exec(tag)?.[1];
40
+ const width = numeric(attr("width"));
41
+ const height = numeric(attr("height"));
42
+ const drawn = (body.match(/<(?:rect|path|polyline|circle|line)\b/gi) ?? []).length;
43
+ if (width !== undefined &&
44
+ height !== undefined &&
45
+ width >= 150 &&
46
+ drawn >= 4 &&
47
+ !/\sviewBox\s*=/i.test(tag))
48
+ count++;
49
+ }
50
+ return count;
51
+ }
52
+ /** `<script src>`, `<link href>` and `@import` that point at the network. */
53
+ function remoteHosts(markup, html) {
54
+ const hosts = new Set();
55
+ const sources = [
56
+ ...markup.matchAll(/<script\b[^>]*\ssrc\s*=\s*["']((?:https?:)?\/\/[^"']+)["']/gi),
57
+ ...markup.matchAll(/<link\b[^>]*\shref\s*=\s*["']((?:https?:)?\/\/[^"']+)["']/gi),
58
+ ...html.matchAll(/@import\s+(?:url\()?["']?((?:https?:)?\/\/[^"')\s]+)/gi),
59
+ ];
60
+ for (const match of sources) {
61
+ try {
62
+ hosts.add(new URL(match[1].replace(/^\/\//, "https://")).host);
63
+ }
64
+ catch {
65
+ // Not a URL: ignore it.
66
+ }
67
+ }
68
+ return [...hosts];
69
+ }
70
+ /** Warnings (empty when the page looks fine) for one HTML document. */
71
+ export function chartWarnings(html) {
72
+ const markup = markupOf(html);
73
+ const warnings = [];
74
+ const hosts = remoteHosts(markup, html);
75
+ if (hosts.length)
76
+ warnings.push(`loads resources from the network (${hosts.slice(0, 3).join(", ")}); the viewer blocks the network, so they will not load. Charts: use ${HELPERS}, which inlines Chart.js`);
77
+ const wedges = wedgeCount(markup);
78
+ if (wedges >= 2)
79
+ warnings.push(`${wedges} hand-written SVG arc paths look like a pie or donut; hand-written arcs are often wrong (large-arc flag, 100% slice). Use charts.pie/donut or svg.pie/donut`);
80
+ const fixed = fixedSvgCount(markup);
81
+ if (fixed)
82
+ warnings.push(`${fixed} SVG chart${fixed === 1 ? "" : "s"} with a fixed width and height and no viewBox will not scale with its container (small text, empty space). Use ${HELPERS}, or give the SVG a viewBox and width:100%`);
83
+ return warnings;
84
+ }
@@ -8,6 +8,9 @@ export function createArtifactPublisher(store, owner, announce) {
8
8
  async publish(input) {
9
9
  return done(await store.publish(input, owner)).artifact;
10
10
  },
11
+ async publishDetailed(input) {
12
+ return done(await store.publish(input, owner));
13
+ },
11
14
  async publishText(input) {
12
15
  return done(await store.publishText(input, owner)).artifact;
13
16
  },
@@ -71,7 +71,9 @@ export declare class ArtifactStore {
71
71
  title?: string;
72
72
  }): Promise<PublishedArtifact[]>;
73
73
  /** Publishes one caller-owned file or directory. */
74
- publish(input: ArtifactPublishInput, owner: ArtifactOwner): Promise<PublishedArtifact>;
74
+ publish(input: ArtifactPublishInput & {
75
+ fileName?: string;
76
+ }, owner: ArtifactOwner): Promise<PublishedArtifact>;
75
77
  /** Publishes a single text file the caller holds in memory. */
76
78
  publishText(input: {
77
79
  fileName: string;
@@ -11,6 +11,7 @@ import { basename, dirname, join, relative, resolve, sep } from "node:path";
11
11
  import { newId } from "../runtime/ids.js";
12
12
  import { inside, workspaceKey } from "../runtime/paths.js";
13
13
  import { writeZip } from "../runtime/zip.js";
14
+ import { chartWarnings } from "./chart-lint.js";
14
15
  import { classifyArtifact, isPreviewable } from "./kinds.js";
15
16
  export const DEFAULT_ARTIFACT_LIMITS = {
16
17
  maxFiles: 200,
@@ -21,6 +22,8 @@ export const DEFAULT_ARTIFACT_LIMITS = {
21
22
  export class ArtifactRejected extends Error {
22
23
  }
23
24
  const MAX_DEPTH = 8;
25
+ /** HTML larger than this is not scanned for chart mistakes. */
26
+ const MAX_LINT_BYTES = 8 * 1024 * 1024;
24
27
  const HEAD_BYTES = 8192;
25
28
  /** `title` → `[a-z0-9-]`, at most 48 characters (`artifact` when nothing remains). */
26
29
  export function slugify(title) {
@@ -200,6 +203,7 @@ export class ArtifactStore {
200
203
  source: resolve(input.source),
201
204
  ...(input.title ? { title: input.title } : {}),
202
205
  ...(input.entry ? { entry: input.entry } : {}),
206
+ ...(input.fileName ? { fileName: checkName(input.fileName) } : {}),
203
207
  },
204
208
  ], owner);
205
209
  return published;
@@ -380,19 +384,25 @@ export class ArtifactStore {
380
384
  kind = type.kind;
381
385
  mimeType = type.mimeType;
382
386
  fileName = only.path;
387
+ if (kind === "dashboard" && only.bytes <= MAX_LINT_BYTES)
388
+ for (const note of chartWarnings(await readFile(join(filesDir, only.path), "utf8")))
389
+ warnings.push(`${label}: ${note}`);
383
390
  }
384
391
  else {
385
392
  entry = plan.entry;
386
393
  const type = classifyArtifact(entry, await readHead(join(filesDir, ...entry.split("/"))));
387
394
  kind = type.kind;
388
395
  mimeType = type.mimeType;
389
- fileName = files.length > 1 ? `${baseName}.zip` : basename(entry);
396
+ fileName =
397
+ plan.candidate.fileName ?? (files.length > 1 ? `${baseName}.zip` : basename(entry));
390
398
  if (type.kind === "dashboard") {
391
399
  const html = await readFile(join(filesDir, ...entry.split("/")), "utf8");
392
400
  const entryDir = entry.includes("/") ? entry.slice(0, entry.lastIndexOf("/")) : "";
393
401
  const missing = missingReferences(html, entryDir, new Set(files.map((f) => f.path)));
394
402
  if (missing.length)
395
403
  warnings.push(`${label}: ${entry} references missing files: ${missing.join(", ")}`);
404
+ for (const note of chartWarnings(html))
405
+ warnings.push(`${label}: ${entry} ${note}`);
396
406
  }
397
407
  }
398
408
  }
@@ -2,9 +2,40 @@
2
2
  export const CHANGELOG_DATA = {
3
3
  schema: 1,
4
4
  entries: [
5
+ {
6
+ version: "0.2.0",
7
+ date: "2026-10-02",
8
+ sections: [
9
+ {
10
+ title: "Added",
11
+ items: [
12
+ "Plan diagrams: the plan agent can attach small Mermaid diagrams (flows, sequences, architecture) to the plan it proposes with `exit_plan`.",
13
+ "A plan viewer in the web UI: the plan opens in the artifact panel with its diagrams drawn in your theme, next to the plan review. The terminal shows the diagram source.",
14
+ "Plan files are saved in a plan folder with a `plan.json` manifest, so the plan and its diagrams are easy to find and reuse.",
15
+ "Two new settings, `plan.diagrams` and `plan.maxDiagrams` (in the configuration file, **Settings** in the web and `/settings` in the terminal), to turn diagrams off or cap how many a plan keeps.",
16
+ "Dashboard charts for Python analysis: `alisio_runtime.charts` builds interactive pie, donut, bar, line, area and scatter charts, KPI tiles and cards with an embedded Chart.js (MIT), so dashboards work offline, in the viewer and in the downloaded file.",
17
+ ],
18
+ },
19
+ {
20
+ title: "Improved",
21
+ items: [
22
+ "Charts adapt to their card and follow the light and dark theme, with value labels, tooltips and a data table for screen readers.",
23
+ "The pure-SVG helpers (`alisio_runtime.svg`) were rewritten: they scale with their container and carry a title and description.",
24
+ "The agent receives clearer guidance for `python_run` about how to draw charts and dashboards.",
25
+ ],
26
+ },
27
+ {
28
+ title: "Fixed",
29
+ items: [
30
+ "Pie charts drew wrong or broken slices in generated dashboards (including a single 100% slice), and bar charts rendered at a fixed small size.",
31
+ "A dashboard that draws SVG pies by hand, uses fixed-size SVG charts or loads a script from the network now gets a warning in the `python_run` result that points to the chart helpers.",
32
+ ],
33
+ },
34
+ ],
35
+ },
5
36
  {
6
37
  version: "0.1.1",
7
- date: "2026-10-03",
38
+ date: "2026-10-02",
8
39
  sections: [
9
40
  {
10
41
  title: "Fixed",
package/dist/config.d.ts CHANGED
@@ -231,6 +231,10 @@ export declare const configSchema: z.ZodPipe<z.ZodObject<{
231
231
  noToolTurnsLimit: z.ZodDefault<z.ZodNumber>;
232
232
  blockedRepeats: z.ZodDefault<z.ZodNumber>;
233
233
  }, z.core.$strict>>;
234
+ plan: z.ZodDefault<z.ZodObject<{
235
+ diagrams: z.ZodDefault<z.ZodBoolean>;
236
+ maxDiagrams: z.ZodDefault<z.ZodNumber>;
237
+ }, z.core.$strict>>;
234
238
  tui: z.ZodDefault<z.ZodObject<{
235
239
  paddingX: z.ZodDefault<z.ZodNumber>;
236
240
  contentPaddingX: z.ZodDefault<z.ZodNumber>;
@@ -338,6 +342,10 @@ export declare const configSchema: z.ZodPipe<z.ZodObject<{
338
342
  noToolTurnsLimit: number;
339
343
  blockedRepeats: number;
340
344
  };
345
+ plan: {
346
+ diagrams: boolean;
347
+ maxDiagrams: number;
348
+ };
341
349
  tui: {
342
350
  paddingX: number;
343
351
  contentPaddingX: number;
@@ -528,6 +536,10 @@ export declare const configSchema: z.ZodPipe<z.ZodObject<{
528
536
  noToolTurnsLimit: number;
529
537
  blockedRepeats: number;
530
538
  };
539
+ plan: {
540
+ diagrams: boolean;
541
+ maxDiagrams: number;
542
+ };
531
543
  tui: {
532
544
  paddingX: number;
533
545
  contentPaddingX: number;
@@ -643,6 +655,8 @@ declare const SETTABLE_KEYS: {
643
655
  readonly "goal.repeatedReplyLimit": z.ZodDefault<z.ZodNumber>;
644
656
  readonly "goal.noToolTurnsLimit": z.ZodDefault<z.ZodNumber>;
645
657
  readonly "goal.blockedRepeats": z.ZodDefault<z.ZodNumber>;
658
+ readonly "plan.diagrams": z.ZodDefault<z.ZodBoolean>;
659
+ readonly "plan.maxDiagrams": z.ZodDefault<z.ZodNumber>;
646
660
  };
647
661
  export type SettableSettingKey = keyof typeof SETTABLE_KEYS;
648
662
  export declare function isSettableSettingKey(key: string): key is SettableSettingKey;
package/dist/config.js CHANGED
@@ -386,6 +386,18 @@ const configObjectSchema = z
386
386
  noToolTurnsLimit: 3,
387
387
  blockedRepeats: 2,
388
388
  })),
389
+ /**
390
+ * Plan diagrams (`exit_plan`): the plan agent may add Mermaid diagrams to a plan. `diagrams`
391
+ * off removes them from the tool and from the agent's instructions; `maxDiagrams` caps how
392
+ * many one plan keeps (0 to 8). The size and node limits of one diagram are constants.
393
+ */
394
+ plan: z
395
+ .object({
396
+ diagrams: z.boolean().default(true),
397
+ maxDiagrams: z.number().int().min(0).max(8).default(5),
398
+ })
399
+ .strict()
400
+ .default(() => ({ diagrams: true, maxDiagrams: 5 })),
389
401
  tui: z
390
402
  .object({
391
403
  /** Horizontal padding (columns) around the editor input box. Editor-only. */
@@ -767,6 +779,7 @@ const SETTABLE_SECTIONS = {
767
779
  analysis: configObjectSchema.shape.analysis.removeDefault(),
768
780
  tasks: configObjectSchema.shape.tasks.removeDefault(),
769
781
  goal: configObjectSchema.shape.goal.removeDefault(),
782
+ plan: configObjectSchema.shape.plan.removeDefault(),
770
783
  };
771
784
  const ANALYSIS_LIMITS = SETTABLE_SECTIONS.analysis.shape.limits.removeDefault();
772
785
  const ANALYSIS_RETENTION = SETTABLE_SECTIONS.analysis.shape.retention.removeDefault();
@@ -807,6 +820,8 @@ const SETTABLE_KEYS = {
807
820
  "goal.repeatedReplyLimit": SETTABLE_SECTIONS.goal.shape.repeatedReplyLimit,
808
821
  "goal.noToolTurnsLimit": SETTABLE_SECTIONS.goal.shape.noToolTurnsLimit,
809
822
  "goal.blockedRepeats": SETTABLE_SECTIONS.goal.shape.blockedRepeats,
823
+ "plan.diagrams": SETTABLE_SECTIONS.plan.shape.diagrams,
824
+ "plan.maxDiagrams": SETTABLE_SECTIONS.plan.shape.maxDiagrams,
810
825
  };
811
826
  export function isSettableSettingKey(key) {
812
827
  return Object.prototype.hasOwnProperty.call(SETTABLE_KEYS, key);
@@ -1,4 +1,4 @@
1
- import type { AnalysisCapability, ArtifactPublisher, ArtifactRef, CompactionCheckpoint, InstallPreview, Message, ToolCall, ToolResult } from "@alisio/sdk";
1
+ import type { AnalysisCapability, ArtifactPublisher, ArtifactPublishInput, ArtifactRef, CompactionCheckpoint, InstallPreview, Message, ToolCall, ToolResult } from "@alisio/sdk";
2
2
  export interface Session {
3
3
  id: string;
4
4
  workspace: string;
@@ -255,6 +255,13 @@ export interface CoreArtifactPublisher extends ArtifactPublisher {
255
255
  partial?: boolean;
256
256
  provenance?: Record<string, unknown>;
257
257
  }): Promise<PublishedArtifactInfo[]>;
258
+ /**
259
+ * Detailed variant of `publish` (path and warnings). `fileName` names a multi-file folder with
260
+ * an `entry` after its main file (`plan.md`) instead of `<folder>.zip`; downloads are still ZIPs.
261
+ */
262
+ publishDetailed(input: ArtifactPublishInput & {
263
+ fileName?: string;
264
+ }): Promise<PublishedArtifactInfo>;
258
265
  /** Detailed variant of `publishText` (path and warnings). */
259
266
  publishTextDetailed(input: {
260
267
  fileName: string;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /** @alisio/core public API: embed the Alisio agent programmatically. */
2
2
  export * from "@alisio/sdk";
3
- export { type ActiveAgent, AGENT_COMMAND_PREFIX, type AgentPickerItem, activeAgentCatalog, agentCatalogFromState, agentCommandDescriptors, agentCommandName, agentIdFromCommand, agentPickerItems, agentRunOptions, BUILTIN_AGENTS, cycleableAgents, DEFAULT_AGENT_ID, type MainCapableAgentRecord, mainAgentFromRecord, nextAgent, PLAN_AGENT_ID, resolveActiveAgent, } from "./agents/active.ts";
3
+ export { type ActiveAgent, AGENT_COMMAND_PREFIX, type AgentPickerItem, activeAgentCatalog, agentCatalogFromState, agentCommandDescriptors, agentCommandName, agentIdFromCommand, agentPickerItems, agentRunOptions, BUILTIN_AGENTS, cycleableAgents, DEFAULT_AGENT_ID, type MainCapableAgentRecord, mainAgentFromRecord, nextAgent, PLAN_AGENT_ID, type PlanInstructionSettings, planInstructions, resolveActiveAgent, } from "./agents/active.ts";
4
4
  export { agentModelCapabilities, agentModelLabels, agentModelOptions, DEFAULT_EFFORT_LEVELS, fitAgentSettings, } from "./agents/capabilities.ts";
5
5
  export { AGENT_AUTHORING_SKILL_NAMES, CREATE_AGENT_SKILL, } from "./agents/create-agent-skill.ts";
6
6
  export { AGENT_ID_PATTERN, AGENT_LIMITS, AGENT_REASONING_SUMMARIES, AGENT_TEXT_FORMATS, AGENT_VERBOSITIES, type AgentFieldError, AgentNotFoundError, AgentScopeStore, agentIdFromName, agentScopeDir, parseAgentFile, RESERVED_AGENT_IDS, slugify, validateAgentDefinitionInput, } from "./agents/definitions.ts";
@@ -43,6 +43,8 @@ export * from "./goal/index.ts";
43
43
  export { HerdrBridge } from "./integrations/herdr.ts";
44
44
  export { McpConnector, type McpServerInfo, type McpStatus, type McpToolInfo, } from "./mcp/connector.ts";
45
45
  export { describePermissionStatus, type EffectState, effectState, FULL_ACCESS_WARNING, type ModeFlags, type ModePolicy, modeFromFlags, modeToPreset, PERMISSION_MODE_TABLE, PERMISSION_MODES, PERMISSION_MODES_LOCKED, PERMISSION_USAGE, type PermissionCommand, type PermissionModeLabel, type PermissionModeSpec, parsePermissionCommand, parsePermissionMode, presetToMode, READ_ONLY_POLICY, } from "./permissions/modes.ts";
46
+ export { DIAGRAM_MAX_BYTES, DIAGRAM_MAX_NODES, DIAGRAM_SYNTAXES, DIAGRAMS_MAX_ALLOWED, mermaidProblem, type PlanDiagram, validateDiagrams, } from "./plan/diagrams.ts";
47
+ export { buildPlanManifest, parsePlanHeadings, slugifyHeading, } from "./plan/manifest.ts";
46
48
  export { claimApprovedPlan, currentPlan, discardApprovedPlan, IMPLEMENTATION_AGENT_ID, implementationPrompt, PLAN_CONTEXT_MAX_CHARS, PLAN_OPTIONS, PLAN_QUESTION_ID, PLAN_REVIEW_TITLE, PLAN_TEXT_KEY, type PlanFollowUp, type PlanState, type PlanStatus, planHash, readPlanState, settlePlanRun, withdrawPendingPlan, } from "./plan/state.ts";
47
49
  export { discoverPlugins, PluginHost, type PluginHostOptions, pluginPrefix, type ViewInfo, ViewRunError, } from "./plugins/host.ts";
48
50
  export { type CliInstallOptions, cliInstall, INSTALL_TIMEOUT_MS, type InstallPluginInput, type InstallPluginResult, type InstallRunner, installedNpmPlugins, installPlugin, npmInstallTarget, type PluginSpec, parsePluginSpec, pluginTrustRemark, printInstallResult, registerPluginInstallTool, sanitizeNpmError, } from "./plugins/install.ts";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /** @alisio/core public API: embed the Alisio agent programmatically. */
2
2
  export * from "@alisio/sdk";
3
- export { AGENT_COMMAND_PREFIX, activeAgentCatalog, agentCatalogFromState, agentCommandDescriptors, agentCommandName, agentIdFromCommand, agentPickerItems, agentRunOptions, BUILTIN_AGENTS, cycleableAgents, DEFAULT_AGENT_ID, mainAgentFromRecord, nextAgent, PLAN_AGENT_ID, resolveActiveAgent, } from "./agents/active.js";
3
+ export { AGENT_COMMAND_PREFIX, activeAgentCatalog, agentCatalogFromState, agentCommandDescriptors, agentCommandName, agentIdFromCommand, agentPickerItems, agentRunOptions, BUILTIN_AGENTS, cycleableAgents, DEFAULT_AGENT_ID, mainAgentFromRecord, nextAgent, PLAN_AGENT_ID, planInstructions, resolveActiveAgent, } from "./agents/active.js";
4
4
  export { agentModelCapabilities, agentModelLabels, agentModelOptions, DEFAULT_EFFORT_LEVELS, fitAgentSettings, } from "./agents/capabilities.js";
5
5
  export { AGENT_AUTHORING_SKILL_NAMES, CREATE_AGENT_SKILL, } from "./agents/create-agent-skill.js";
6
6
  export { AGENT_ID_PATTERN, AGENT_LIMITS, AGENT_REASONING_SUMMARIES, AGENT_TEXT_FORMATS, AGENT_VERBOSITIES, AgentNotFoundError, AgentScopeStore, agentIdFromName, agentScopeDir, parseAgentFile, RESERVED_AGENT_IDS, slugify, validateAgentDefinitionInput, } from "./agents/definitions.js";
@@ -42,6 +42,8 @@ export * from "./goal/index.js";
42
42
  export { HerdrBridge } from "./integrations/herdr.js";
43
43
  export { McpConnector, } from "./mcp/connector.js";
44
44
  export { describePermissionStatus, effectState, FULL_ACCESS_WARNING, modeFromFlags, modeToPreset, PERMISSION_MODE_TABLE, PERMISSION_MODES, PERMISSION_MODES_LOCKED, PERMISSION_USAGE, parsePermissionCommand, parsePermissionMode, presetToMode, READ_ONLY_POLICY, } from "./permissions/modes.js";
45
+ export { DIAGRAM_MAX_BYTES, DIAGRAM_MAX_NODES, DIAGRAM_SYNTAXES, DIAGRAMS_MAX_ALLOWED, mermaidProblem, validateDiagrams, } from "./plan/diagrams.js";
46
+ export { buildPlanManifest, parsePlanHeadings, slugifyHeading, } from "./plan/manifest.js";
45
47
  export { claimApprovedPlan, currentPlan, discardApprovedPlan, IMPLEMENTATION_AGENT_ID, implementationPrompt, PLAN_CONTEXT_MAX_CHARS, PLAN_OPTIONS, PLAN_QUESTION_ID, PLAN_REVIEW_TITLE, PLAN_TEXT_KEY, planHash, readPlanState, settlePlanRun, withdrawPendingPlan, } from "./plan/state.js";
46
48
  export { discoverPlugins, PluginHost, pluginPrefix, ViewRunError, } from "./plugins/host.js";
47
49
  export { cliInstall, INSTALL_TIMEOUT_MS, installedNpmPlugins, installPlugin, npmInstallTarget, parsePluginSpec, pluginTrustRemark, printInstallResult, registerPluginInstallTool, sanitizeNpmError, } from "./plugins/install.js";
@@ -0,0 +1,76 @@
1
+ import type { PlanDiagramType } from "@alisio/sdk";
2
+ /** Largest Mermaid source of one diagram (UTF-8 bytes). */
3
+ export declare const DIAGRAM_MAX_BYTES: number;
4
+ /** Most nodes (participants, entities, states, tasks...) of one diagram, estimated from the text. */
5
+ export declare const DIAGRAM_MAX_NODES = 40;
6
+ /** Hard ceiling of `plan.maxDiagrams`. */
7
+ export declare const DIAGRAMS_MAX_ALLOWED = 8;
8
+ export declare const DIAGRAM_ID_MAX = 40;
9
+ export declare const DIAGRAM_TITLE_MAX = 80;
10
+ export declare const DIAGRAM_EXPLANATION_MAX = 400;
11
+ export declare const DIAGRAM_SECTION_MAX = 120;
12
+ /** Mermaid diagram keywords a plan may use (the first statement of the source). */
13
+ export declare const DIAGRAM_SYNTAXES: readonly string[];
14
+ export declare const DIAGRAM_TYPES: readonly PlanDiagramType[];
15
+ /**
16
+ * The semantic classes of the style guide. The web applies the same names as a `classDef` block
17
+ * at render time when a diagram uses a class without defining it (colors live in the web).
18
+ */
19
+ export declare const DIAGRAM_CLASSES: readonly string[];
20
+ export interface PlanDiagram {
21
+ id: string;
22
+ title: string;
23
+ explanation: string;
24
+ /** As the model wrote it; the manifest resolves it against the plan headings. */
25
+ section?: string;
26
+ type: PlanDiagramType;
27
+ syntax: string;
28
+ mermaid: string;
29
+ nodes: number;
30
+ }
31
+ export interface DroppedDiagram {
32
+ /** The id as given (or `#<position>` when it has none). */
33
+ id: string;
34
+ reason: string;
35
+ }
36
+ export interface DiagramValidation {
37
+ accepted: PlanDiagram[];
38
+ dropped: DroppedDiagram[];
39
+ }
40
+ export interface DiagramLimits {
41
+ /** Most diagrams of one plan (0 accepts none). */
42
+ max: number;
43
+ maxBytes?: number;
44
+ maxNodes?: number;
45
+ }
46
+ /** Normalizes line endings and trims: what is stored and hashed. */
47
+ export declare const normalizeMermaid: (source: string) => string;
48
+ /** The diagram keyword of a source (its first statement), or undefined when it has none. */
49
+ export declare function diagramSyntax(source: string): string | undefined;
50
+ /** The purpose a syntax implies when the model gave none. */
51
+ export declare function defaultDiagramType(syntax: string): PlanDiagramType;
52
+ /**
53
+ * An estimate of the diagram's nodes from its text (participants, entities, states, tasks, topics
54
+ * or flowchart node ids). It errs on the high side: it is a guard against walls of boxes, not a
55
+ * parser.
56
+ */
57
+ export declare function estimateNodes(source: string, syntax: string): number;
58
+ /** The first problem that makes a Mermaid source unsafe or unsupported, or undefined when fine. */
59
+ export declare function mermaidProblem(source: string, limits?: {
60
+ maxBytes?: number;
61
+ maxNodes?: number;
62
+ }): string | undefined;
63
+ /** SHA-256 of what makes a diagram "the same" across revisions. */
64
+ export declare function diagramHash(diagram: {
65
+ title: string;
66
+ explanation: string;
67
+ section?: string;
68
+ type: string;
69
+ mermaid: string;
70
+ }): string;
71
+ /**
72
+ * Validates the `diagrams` argument of `exit_plan`. Never throws: every problem becomes a dropped
73
+ * diagram with the reason the model needs to fix it. Order is kept; the first diagram with an id
74
+ * wins; only `limits.max` are accepted.
75
+ */
76
+ export declare function validateDiagrams(input: unknown, limits: DiagramLimits): DiagramValidation;