@alisio/core 0.1.1 → 0.2.1

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.
@@ -1,6 +1,7 @@
1
1
  import { type Attachment, type DatasetRef, type Message, type ModelProvider, type RunEvent, type ToolDefinition, type ToolResult } from "@alisio/sdk";
2
2
  import type { PathAccess } from "../runtime/access.ts";
3
3
  import type { ApprovalHandler, ArtifactPublisherFactory, CapabilityGate, ContextSource, Policy, RunnerExtensions, SessionStore } from "./contracts.ts";
4
+ import { HumanWaits } from "./human-wait.ts";
4
5
  import type { ToolRegistry } from "./registry.ts";
5
6
  export interface CompactionSettings {
6
7
  /** Compact automatically when context usage crosses `threshold` of a known window. */
@@ -62,6 +63,13 @@ export interface RunnerOptions {
62
63
  compaction?: CompactionSettings;
63
64
  /** When set, write/process tools not allowed by the policy are offered and ask first. */
64
65
  approve?: ApprovalHandler;
66
+ /**
67
+ * Registry of the waits for a person (approvals, questions, the plan review): the run's time
68
+ * limit does not count them. Share one with the plugin host and every other asking surface so a
69
+ * wait outside the runner (for example `ask_user_question`) pauses the same clocks. Without it
70
+ * the runner uses a private one, which still covers every approval it asks itself.
71
+ */
72
+ humanWaits?: HumanWaits;
65
73
  /**
66
74
  * Mediated path policy (workspace plus declared extra directories and external approval).
67
75
  * When set, declared tool paths outside the allowed roots ask before the effect gate runs.
@@ -179,6 +187,8 @@ export declare class AgentRunner {
179
187
  private inbox;
180
188
  /** Last provider-reported context size per session and the history length it covered. */
181
189
  private reported;
190
+ /** Where human waits are opened; the clocks of the active runs listen to it. */
191
+ readonly humanWaits: HumanWaits;
182
192
  constructor(options: RunnerOptions);
183
193
  /** Current capability policy (may widen when the user approves an effect for the session). */
184
194
  get policy(): Readonly<Policy>;
@@ -284,5 +294,7 @@ export declare class AgentRunner {
284
294
  };
285
295
  /** Tool calls the model made during the run (the goal controller's no-progress breaker). */
286
296
  toolCalls: number;
297
+ /** Time the run was really working: wall time minus the waits for a person. */
298
+ activeMs: number;
287
299
  }>;
288
300
  }
@@ -1,7 +1,9 @@
1
1
  import { isEphemeralRunEventType, textProjection, textResult, } from "@alisio/sdk";
2
2
  import { checkpointInstructions, estimateTokens, MAX_TRUSTED_WINDOW, parseCheckpointOutput, planCompaction, reduceMessagesToBudget, shouldCompactContext, summarize, summaryMessage, } from "./compaction.js";
3
+ import { HumanWaits } from "./human-wait.js";
3
4
  import { EXIT_PLAN_TOOL, optInAllows } from "./opt-in.js";
4
5
  import { resolveMaxOutputTokens } from "./output-limit.js";
6
+ import { RunClock } from "./run-clock.js";
5
7
  import { attachRunStats } from "./run-stats.js";
6
8
  import { isTimeoutReason, providerLabel, RunTimeoutError } from "./timeout.js";
7
9
  import { incompleteCalls, isOutputTruncationError, lowerEffort, RunTruncationError, TRUNCATION_NOTICE, } from "./truncation.js";
@@ -60,8 +62,20 @@ export class AgentRunner {
60
62
  inbox = new Map();
61
63
  /** Last provider-reported context size per session and the history length it covered. */
62
64
  reported = new Map();
65
+ /** Where human waits are opened; the clocks of the active runs listen to it. */
66
+ humanWaits;
63
67
  constructor(options) {
64
68
  this.options = options;
69
+ this.humanWaits =
70
+ options.humanWaits ??
71
+ new HumanWaits((session) => {
72
+ try {
73
+ return options.store.get(session).parentId ?? undefined;
74
+ }
75
+ catch {
76
+ return undefined;
77
+ }
78
+ });
65
79
  }
66
80
  /** Current capability policy (may widen when the user approves an effect for the session). */
67
81
  get policy() {
@@ -465,17 +479,20 @@ export class AgentRunner {
465
479
  ...(options.label ? { label: options.label } : {}),
466
480
  ...(capability ? { capability } : {}),
467
481
  });
468
- const decision = await o.approve({
482
+ const approve = o.approve;
483
+ const callInput = p.input;
484
+ // Waiting for the person is not work: the run's time limit does not count it.
485
+ const decision = await this.humanWaits.track(sessionId, () => approve({
469
486
  call,
470
487
  effect,
471
- input: p.input,
488
+ input: callInput,
472
489
  signal: combined,
473
490
  session: sessionId,
474
491
  ...(options.label ? { label: options.label } : {}),
475
492
  ...(capability ? { capability } : {}),
476
493
  ...(preview !== undefined ? { preview } : {}),
477
494
  ...(capability && gate?.runtime ? { runtime: gate.runtime } : {}),
478
- });
495
+ }));
479
496
  combined.throwIfAborted();
480
497
  const persisted = !!capability && !!gate && decision === "session";
481
498
  if (capability && gate)
@@ -530,7 +547,8 @@ export class AgentRunner {
530
547
  });
531
548
  let decision = "deny";
532
549
  try {
533
- decision = await o.approve({
550
+ const approve = o.approve;
551
+ decision = await this.humanWaits.track(sessionId, () => approve({
534
552
  call: installCall,
535
553
  effect: "process",
536
554
  input: { extras: install.extras },
@@ -539,7 +557,7 @@ export class AgentRunner {
539
557
  ...(options.label ? { label: options.label } : {}),
540
558
  capability: "analysis.install",
541
559
  install,
542
- });
560
+ }));
543
561
  }
544
562
  finally {
545
563
  combined.throwIfAborted();
@@ -607,8 +625,12 @@ export class AgentRunner {
607
625
  }
608
626
  catch (error) {
609
627
  result = textResult(error instanceof Error ? error.message : String(error), true);
610
- // A cancellation after execution may have left effects; journal remains pending.
611
- if (!combined.aborted)
628
+ // A cancellation after execution may have left effects, so the journal stays pending for
629
+ // the user to inspect. A `read` call cannot have left any (and `exit_plan`, which is one,
630
+ // is exactly what a stop or the run limit interrupts while a person decides): it is closed
631
+ // with the cancellation, so the next message continues normally instead of asking to
632
+ // "recover" a call nobody needs to inspect.
633
+ if (!combined.aborted || p.tool?.effect === "read")
612
634
  o.store.endCall(sessionId, call, result);
613
635
  }
614
636
  emit("tool_completed", {
@@ -649,10 +671,11 @@ export class AgentRunner {
649
671
  }
650
672
  };
651
673
  const runTimeoutMs = options.timeoutMs ?? o.timeoutMs ?? 300_000;
652
- const timeout = AbortSignal.timeout(runTimeoutMs);
674
+ const clock = new RunClock(runTimeoutMs);
675
+ const unregisterClock = this.humanWaits.register(sessionId, clock);
653
676
  const combined = AbortSignal.any([
654
677
  controller.signal,
655
- timeout,
678
+ clock.signal,
656
679
  ...(options.signal ? [options.signal] : []),
657
680
  ]);
658
681
  const workspace = options.workspace ?? o.workspace;
@@ -730,6 +753,8 @@ export class AgentRunner {
730
753
  throw error;
731
754
  }
732
755
  finally {
756
+ unregisterClock();
757
+ clock.dispose();
733
758
  if (acquired)
734
759
  o.store.release(sessionId);
735
760
  this.active.delete(sessionId);
@@ -760,9 +785,14 @@ export class AgentRunner {
760
785
  /** Continuation notice and lowered effort for the request that follows a cut-off response. */
761
786
  let recoveryNotice;
762
787
  let recoveryEffort;
763
- const runStartedAt = Date.now();
764
- const timeout = AbortSignal.timeout(runTimeoutMs);
765
- const combined = AbortSignal.any([controller.signal, timeout, ...(signal ? [signal] : [])]);
788
+ // Active time only: waits for a person pause it (see `RunClock`).
789
+ const clock = new RunClock(runTimeoutMs);
790
+ const unregisterClock = this.humanWaits.register(sessionId, clock);
791
+ const combined = AbortSignal.any([
792
+ controller.signal,
793
+ clock.signal,
794
+ ...(signal ? [signal] : []),
795
+ ]);
766
796
  // What the run was doing, so a timeout can say where it was stuck (see `RunTimeoutError`).
767
797
  let stage = "other";
768
798
  let stageTool;
@@ -1006,7 +1036,7 @@ export class AgentRunner {
1006
1036
  }
1007
1037
  // Do not start an attempt the whole-run limit could not let finish.
1008
1038
  const retryPauseMs = FIRST_TOKEN_RETRY_PAUSE_MS;
1009
- if (runTimeoutMs - (Date.now() - runStartedAt) < retryPauseMs + firstTokenMs) {
1039
+ if (clock.remainingMs() < retryPauseMs + firstTokenMs) {
1010
1040
  if (failure !== undefined)
1011
1041
  throw failure;
1012
1042
  break;
@@ -1118,7 +1148,14 @@ export class AgentRunner {
1118
1148
  }
1119
1149
  emit("run_completed", final);
1120
1150
  finish("completed");
1121
- return { sessionId, text: lastText, status: "completed", usage: usageTotal, toolCalls };
1151
+ return {
1152
+ sessionId,
1153
+ text: lastText,
1154
+ status: "completed",
1155
+ usage: usageTotal,
1156
+ toolCalls,
1157
+ activeMs: clock.activeMs(),
1158
+ };
1122
1159
  }
1123
1160
  toolCalls += completion.calls.length;
1124
1161
  const prepared = completion.calls.map((call) => {
@@ -1209,7 +1246,14 @@ export class AgentRunner {
1209
1246
  // token budget (`maxTokens`) and the timeout; the turn count is a safety rail.
1210
1247
  emit("run_turns_exceeded", { turns: maxTurns, maxTurns });
1211
1248
  finish("turns_exceeded");
1212
- return { sessionId, text: lastText, status: "turns-exceeded", usage: usageTotal, toolCalls };
1249
+ return {
1250
+ sessionId,
1251
+ text: lastText,
1252
+ status: "turns-exceeded",
1253
+ usage: usageTotal,
1254
+ toolCalls,
1255
+ activeMs: clock.activeMs(),
1256
+ };
1213
1257
  }
1214
1258
  catch (error) {
1215
1259
  const timedOut = silentTimedOut
@@ -1228,7 +1272,11 @@ export class AgentRunner {
1228
1272
  });
1229
1273
  emit("run_failed", { error: failure.message, code: "timeout", timeout: failure.info });
1230
1274
  finish("failed", failure.message);
1231
- attachRunStats(failure, { usage: { ...usageTotal }, toolCalls });
1275
+ attachRunStats(failure, {
1276
+ usage: { ...usageTotal },
1277
+ toolCalls,
1278
+ activeMs: clock.activeMs(),
1279
+ });
1232
1280
  throw failure;
1233
1281
  }
1234
1282
  if (error instanceof RunTruncationError) {
@@ -1238,7 +1286,7 @@ export class AgentRunner {
1238
1286
  truncation: error.info,
1239
1287
  });
1240
1288
  finish("failed", error.message);
1241
- attachRunStats(error, { usage: { ...usageTotal }, toolCalls });
1289
+ attachRunStats(error, { usage: { ...usageTotal }, toolCalls, activeMs: clock.activeMs() });
1242
1290
  throw error;
1243
1291
  }
1244
1292
  // On cancellation report the abort reason, not the transport's secondary error.
@@ -1246,10 +1294,12 @@ export class AgentRunner {
1246
1294
  const message = cause instanceof Error ? cause.message : String(cause);
1247
1295
  emit(combined.aborted ? "run_cancelled" : "run_failed", { error: message });
1248
1296
  finish(combined.aborted ? "cancelled" : "failed", message);
1249
- attachRunStats(error, { usage: { ...usageTotal }, toolCalls });
1297
+ attachRunStats(error, { usage: { ...usageTotal }, toolCalls, activeMs: clock.activeMs() });
1250
1298
  throw error;
1251
1299
  }
1252
1300
  finally {
1301
+ unregisterClock();
1302
+ clock.dispose();
1253
1303
  if (acquired)
1254
1304
  o.store.release(sessionId);
1255
1305
  this.active.delete(sessionId);
@@ -48,7 +48,7 @@ export function describeTimeout(info) {
48
48
  return info.firstRequest
49
49
  ? `${who} did not respond within ${limit}: no tokens were received. ` +
50
50
  "Retry, switch to another model, or raise limits.timeoutMs."
51
- : `The run reached its ${limit} limit while waiting for ${info.model ? `the model ${info.model}` : "the model"}` +
51
+ : `The run reached its limit of ${limit} of active time (time spent waiting for you is not counted) while waiting for ${info.model ? `the model ${info.model}` : "the model"}` +
52
52
  `${info.provider ? ` (${info.provider})` : ""}. ` +
53
53
  "Everything produced so far is kept: prompt again to continue, switch model, or raise limits.timeoutMs.";
54
54
  const doing = info.stage === "tool" && info.tool
@@ -56,6 +56,6 @@ export function describeTimeout(info) {
56
56
  : info.stage === "streaming"
57
57
  ? "while the model was answering"
58
58
  : "";
59
- return (`The run reached its ${limit} limit${doing ? ` ${doing}` : ""}. ` +
59
+ return (`The run reached its limit of ${limit} of active time (time spent waiting for you is not counted)${doing ? ` ${doing}` : ""}. ` +
60
60
  "Everything produced so far is kept: prompt again to continue, or raise limits.timeoutMs.");
61
61
  }
@@ -8,6 +8,8 @@ export interface RunSummary {
8
8
  output: number;
9
9
  };
10
10
  toolCalls?: number;
11
+ /** Active time of the run: waits for a person are not counted. */
12
+ activeMs?: number;
11
13
  }
12
14
  /**
13
15
  * The outcome of one run. `cancelled` is whether the run's abort signal fired (the user stopped
package/dist/goal/host.js CHANGED
@@ -30,7 +30,8 @@ export function goalOutcome(input) {
30
30
  text: result?.text ?? "",
31
31
  toolCalls: result?.toolCalls ?? stats?.toolCalls ?? 0,
32
32
  startedAt: input.startedAt,
33
- durationMs: Math.max(0, input.endedAt - input.startedAt),
33
+ // `goal.maxMinutes` counts the time a run was working, never the time it waited for you.
34
+ durationMs: Math.max(0, Math.min(input.endedAt - input.startedAt, result?.activeMs ?? stats?.activeMs ?? Number.POSITIVE_INFINITY)),
34
35
  };
35
36
  }
36
37
  /**
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";
@@ -34,15 +34,19 @@ export { BUILTIN_COMMANDS, type BuiltinCommand, CommandCatalog, type CommandExec
34
34
  export { type Config, type ConfigLoadResult, type ConfigProvenance, configFile, configHome, configSchema, isSettableSettingKey, type LoadedConfig, loadConfig, loadConfigWithProvenance, type McpServerSource, OCI_IMAGE_PATTERN, overridesSavedProviderProfile, type SettableSettingInfo, type SettableSettingKey, setConfigValue, setGlobalMcpAllow, setMcpServerEnabled, setProjectPluginEnabled, setProjectSkillEnabled, settableSettings, stateHome, } from "./config.ts";
35
35
  export { type ContextBudget, checkpointInstructions, completeText, effectiveContextBudget, estimateTokens, MAX_TRUSTED_WINDOW, parseCheckpointOutput, planCompaction, renderCheckpoint, serializeForSummary, shouldCompact, shouldCompactContext, summarize, } from "./core/compaction.ts";
36
36
  export type { ApprovalDecision, ApprovalHandler, ApprovalRequest, ArtifactPublisherFactory, BeginRunInput, CapabilityGate, ContextSource, CoreArtifactPublisher, EndRunInput, EventPage, HookFailure, MessagePage, PageOptions, Policy, PublishedArtifactInfo, RunnerExtensions, RunRecord, RunStatus, Session, SessionStore, StoredEvent, TerminalRunStatus, ToolCallMeta, } from "./core/contracts.ts";
37
+ export { HumanWaits } from "./core/human-wait.ts";
37
38
  export { EXIT_PLAN_TOOL, GOAL_TOOLS, OPT_IN_TOOLS } from "./core/opt-in.ts";
38
39
  export { DEFAULT_MAX_OUTPUT_TOKENS, describeOutputLimitSource, MAX_AUTO_OUTPUT_TOKENS, type OutputLimit, type OutputLimitSource, resolveMaxOutputTokens, } from "./core/output-limit.ts";
39
40
  export { ToolRegistry } from "./core/registry.ts";
41
+ export { RunClock } from "./core/run-clock.ts";
40
42
  export { AgentRunner, type CompactionResult, defaultTokenBudget, type RunnerOptions, type RunnerSettingsPatch, type RunOptions, } from "./core/runner.ts";
41
43
  export { type ExtensionConflict, ExtensionRegistry } from "./extensions/registry.ts";
42
44
  export * from "./goal/index.ts";
43
45
  export { HerdrBridge } from "./integrations/herdr.ts";
44
46
  export { McpConnector, type McpServerInfo, type McpStatus, type McpToolInfo, } from "./mcp/connector.ts";
45
47
  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";
48
+ export { DIAGRAM_MAX_BYTES, DIAGRAM_MAX_NODES, DIAGRAM_SYNTAXES, DIAGRAMS_MAX_ALLOWED, mermaidProblem, type PlanDiagram, validateDiagrams, } from "./plan/diagrams.ts";
49
+ export { buildPlanManifest, parsePlanHeadings, slugifyHeading, } from "./plan/manifest.ts";
46
50
  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
51
  export { discoverPlugins, PluginHost, type PluginHostOptions, pluginPrefix, type ViewInfo, ViewRunError, } from "./plugins/host.ts";
48
52
  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";
@@ -33,15 +33,19 @@ export { changelogNews, compareVersions, formatChangelogMarkdown, isVersion, loa
33
33
  export { BUILTIN_COMMANDS, CommandCatalog, } from "./commands/catalog.js";
34
34
  export { configFile, configHome, configSchema, isSettableSettingKey, loadConfig, loadConfigWithProvenance, OCI_IMAGE_PATTERN, overridesSavedProviderProfile, setConfigValue, setGlobalMcpAllow, setMcpServerEnabled, setProjectPluginEnabled, setProjectSkillEnabled, settableSettings, stateHome, } from "./config.js";
35
35
  export { checkpointInstructions, completeText, effectiveContextBudget, estimateTokens, MAX_TRUSTED_WINDOW, parseCheckpointOutput, planCompaction, renderCheckpoint, serializeForSummary, shouldCompact, shouldCompactContext, summarize, } from "./core/compaction.js";
36
+ export { HumanWaits } from "./core/human-wait.js";
36
37
  export { EXIT_PLAN_TOOL, GOAL_TOOLS, OPT_IN_TOOLS } from "./core/opt-in.js";
37
38
  export { DEFAULT_MAX_OUTPUT_TOKENS, describeOutputLimitSource, MAX_AUTO_OUTPUT_TOKENS, resolveMaxOutputTokens, } from "./core/output-limit.js";
38
39
  export { ToolRegistry } from "./core/registry.js";
40
+ export { RunClock } from "./core/run-clock.js";
39
41
  export { AgentRunner, defaultTokenBudget, } from "./core/runner.js";
40
42
  export { ExtensionRegistry } from "./extensions/registry.js";
41
43
  export * from "./goal/index.js";
42
44
  export { HerdrBridge } from "./integrations/herdr.js";
43
45
  export { McpConnector, } from "./mcp/connector.js";
44
46
  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";
47
+ export { DIAGRAM_MAX_BYTES, DIAGRAM_MAX_NODES, DIAGRAM_SYNTAXES, DIAGRAMS_MAX_ALLOWED, mermaidProblem, validateDiagrams, } from "./plan/diagrams.js";
48
+ export { buildPlanManifest, parsePlanHeadings, slugifyHeading, } from "./plan/manifest.js";
45
49
  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
50
  export { discoverPlugins, PluginHost, pluginPrefix, ViewRunError, } from "./plugins/host.js";
47
51
  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;