@llblab/pi-kit 0.24.0 → 0.25.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.
Files changed (112) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +10 -0
  3. package/README.md +6 -5
  4. package/node_modules/@llblab/pi-claude-usage/AGENTS.md +20 -0
  5. package/node_modules/@llblab/pi-claude-usage/BACKLOG.md +3 -0
  6. package/node_modules/@llblab/pi-claude-usage/CHANGELOG.md +13 -0
  7. package/node_modules/@llblab/pi-claude-usage/LICENSE +22 -0
  8. package/node_modules/@llblab/pi-claude-usage/README.md +110 -0
  9. package/node_modules/@llblab/pi-claude-usage/banner.jpg +0 -0
  10. package/node_modules/@llblab/pi-claude-usage/index.ts +1159 -0
  11. package/node_modules/@llblab/pi-claude-usage/package.json +60 -0
  12. package/node_modules/@llblab/pi-state-flow/AGENTS.md +42 -56
  13. package/node_modules/@llblab/pi-state-flow/BACKLOG.md +16 -3
  14. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +19 -0
  15. package/node_modules/@llblab/pi-state-flow/README.md +15 -12
  16. package/node_modules/@llblab/pi-state-flow/dist/index.d.ts +2 -2
  17. package/node_modules/@llblab/pi-state-flow/dist/index.js +2 -2
  18. package/node_modules/@llblab/pi-state-flow/dist/lib/config.d.ts +7 -3
  19. package/node_modules/@llblab/pi-state-flow/dist/lib/config.js +16 -7
  20. package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +9 -9
  21. package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +5 -4
  22. package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.js +2 -2
  23. package/node_modules/@llblab/pi-state-flow/dist/lib/durable.d.ts +1 -1
  24. package/node_modules/@llblab/pi-state-flow/dist/lib/durable.js +7 -4
  25. package/node_modules/@llblab/pi-state-flow/dist/lib/episode.d.ts +3 -3
  26. package/node_modules/@llblab/pi-state-flow/dist/lib/episode.js +5 -5
  27. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.d.ts +3 -5
  28. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +275 -199
  29. package/node_modules/@llblab/pi-state-flow/dist/lib/history.d.ts +11 -4
  30. package/node_modules/@llblab/pi-state-flow/dist/lib/history.js +6 -7
  31. package/node_modules/@llblab/pi-state-flow/dist/lib/logging.d.ts +4 -1
  32. package/node_modules/@llblab/pi-state-flow/dist/lib/logging.js +1 -0
  33. package/node_modules/@llblab/pi-state-flow/dist/lib/query.d.ts +4 -5
  34. package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +13 -13
  35. package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.d.ts +7 -6
  36. package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.js +9 -9
  37. package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.d.ts +3 -2
  38. package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.js +17 -12
  39. package/node_modules/@llblab/pi-state-flow/dist/lib/session.d.ts +4 -1
  40. package/node_modules/@llblab/pi-state-flow/dist/lib/session.js +2 -1
  41. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +17 -8
  42. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +49 -20
  43. package/node_modules/@llblab/pi-state-flow/dist/lib/state.d.ts +22 -3
  44. package/node_modules/@llblab/pi-state-flow/dist/lib/state.js +30 -10
  45. package/node_modules/@llblab/pi-state-flow/dist/lib/status.d.ts +5 -3
  46. package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +19 -28
  47. package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.d.ts +17 -15
  48. package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.js +52 -52
  49. package/node_modules/@llblab/pi-state-flow/dist/lib/temporal.d.ts +8 -4
  50. package/node_modules/@llblab/pi-state-flow/dist/lib/temporal.js +34 -18
  51. package/node_modules/@llblab/pi-state-flow/dist/lib/transition.d.ts +5 -5
  52. package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +13 -19
  53. package/node_modules/@llblab/pi-state-flow/dist/package.json +3 -3
  54. package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-guide/SKILL.md +2 -2
  55. package/node_modules/@llblab/pi-state-flow/docs/README.md +2 -1
  56. package/node_modules/@llblab/pi-state-flow/docs/agent-contract-relocation.md +72 -0
  57. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +36 -32
  58. package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +12 -4
  59. package/node_modules/@llblab/pi-state-flow/docs/fork-contract.md +5 -5
  60. package/node_modules/@llblab/pi-state-flow/docs/lazy-state.md +6 -6
  61. package/node_modules/@llblab/pi-state-flow/docs/performance.md +1 -1
  62. package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +13 -12
  63. package/node_modules/@llblab/pi-state-flow/docs/usage.md +32 -29
  64. package/node_modules/@llblab/pi-state-flow/index.ts +3 -2
  65. package/node_modules/@llblab/pi-state-flow/lib/config.ts +20 -10
  66. package/node_modules/@llblab/pi-state-flow/lib/context.ts +15 -14
  67. package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +1 -1
  68. package/node_modules/@llblab/pi-state-flow/lib/durable.ts +8 -6
  69. package/node_modules/@llblab/pi-state-flow/lib/episode.ts +6 -6
  70. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +274 -197
  71. package/node_modules/@llblab/pi-state-flow/lib/history.ts +16 -11
  72. package/node_modules/@llblab/pi-state-flow/lib/logging.ts +5 -1
  73. package/node_modules/@llblab/pi-state-flow/lib/query.ts +16 -16
  74. package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +11 -11
  75. package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +19 -13
  76. package/node_modules/@llblab/pi-state-flow/lib/session.ts +6 -3
  77. package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +55 -22
  78. package/node_modules/@llblab/pi-state-flow/lib/state.ts +46 -13
  79. package/node_modules/@llblab/pi-state-flow/lib/status.ts +23 -32
  80. package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +66 -65
  81. package/node_modules/@llblab/pi-state-flow/lib/temporal.ts +39 -19
  82. package/node_modules/@llblab/pi-state-flow/lib/transition.ts +19 -27
  83. package/node_modules/@llblab/pi-state-flow/package.json +3 -3
  84. package/node_modules/@llblab/pi-state-flow/skills/state-flow-guide/SKILL.md +2 -2
  85. package/node_modules/@llblab/pi-telegram/AGENTS.md +1 -1
  86. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +5 -0
  87. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +2 -0
  88. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +55 -2
  89. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +21 -0
  90. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +144 -1
  91. package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +9 -0
  92. package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +19 -0
  93. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +13 -0
  94. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +29 -6
  95. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +16 -0
  96. package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +5 -1
  97. package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +6 -2
  98. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +7 -0
  99. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +13 -5
  100. package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
  101. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +2 -2
  102. package/node_modules/@llblab/pi-telegram/docs/public-api.md +1 -1
  103. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +79 -1
  104. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +197 -0
  105. package/node_modules/@llblab/pi-telegram/lib/bus.ts +33 -0
  106. package/node_modules/@llblab/pi-telegram/lib/commands.ts +38 -6
  107. package/node_modules/@llblab/pi-telegram/lib/extension.ts +15 -0
  108. package/node_modules/@llblab/pi-telegram/lib/locks.ts +6 -1
  109. package/node_modules/@llblab/pi-telegram/lib/polling.ts +10 -2
  110. package/node_modules/@llblab/pi-telegram/lib/threads.ts +19 -5
  111. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  112. package/package.json +7 -3
@@ -5,15 +5,15 @@ import { getAgentDir } from "@earendil-works/pi-coding-agent";
5
5
  import { getDurableRepositoryRoot } from "./durable.js";
6
6
  import { DEFAULT_HISTORY_LIMIT, MAX_HISTORY_LIMIT } from "./history.js";
7
7
  import { isObject } from "./json.js";
8
+ import { isStateFlowMode } from "./snapshot.js";
8
9
  /** Read the repository-global config once at extension load/reload. Missing config uses defaults; invalid config never falls back. */
9
10
  export function loadStateFlowConfig(agentDir = getAgentDir(), repositoryRoot = getDurableRepositoryRoot(agentDir)) {
10
11
  const directory = repositoryRoot;
11
12
  const path = join(directory, "config.json");
12
13
  const defaults = {
13
14
  directory,
14
- autoStart: false,
15
- passiveBootstrap: true,
16
- passiveTools: true,
15
+ mode: "off",
16
+ inactiveMode: "off",
17
17
  logging: false,
18
18
  showSuccessfulPatches: true,
19
19
  historyLimit: DEFAULT_HISTORY_LIMIT,
@@ -27,10 +27,13 @@ export function loadStateFlowConfig(agentDir = getAgentDir(), repositoryRoot = g
27
27
  catch (error) {
28
28
  throw new Error(`Cannot read State Flow configuration: ${path}`, { cause: error });
29
29
  }
30
- const allowed = new Set(["autoStart", "passiveBootstrap", "passiveTools", "logging", "showSuccessfulPatches", "historyLimit"]);
30
+ // autoStart/passiveBootstrap/passiveTools are read-only compatibility inputs; explicit mode is authoritative.
31
+ const allowed = new Set(["mode", "autoStart", "passiveBootstrap", "passiveTools", "logging", "showSuccessfulPatches", "historyLimit"]);
31
32
  if (!isObject(value) || Object.keys(value).some((key) => !allowed.has(key))) {
32
33
  throw new Error(`State Flow configuration contains unknown settings: ${path}`);
33
34
  }
35
+ if (Object.hasOwn(value, "mode") && !isStateFlowMode(value.mode))
36
+ throw new Error(`State Flow mode must be "active", "passive" or "off": ${path}`);
34
37
  if (Object.hasOwn(value, "autoStart") && typeof value.autoStart !== "boolean")
35
38
  throw new Error(`State Flow autoStart must be a boolean: ${path}`);
36
39
  if (Object.hasOwn(value, "passiveBootstrap") && typeof value.passiveBootstrap !== "boolean")
@@ -43,13 +46,19 @@ export function loadStateFlowConfig(agentDir = getAgentDir(), repositoryRoot = g
43
46
  throw new Error(`State Flow showSuccessfulPatches must be a boolean: ${path}`);
44
47
  if (Object.hasOwn(value, "historyLimit") && (!Number.isSafeInteger(value.historyLimit) || value.historyLimit < 0 || value.historyLimit > MAX_HISTORY_LIMIT))
45
48
  throw new Error(`State Flow historyLimit must be an integer from 0 to ${MAX_HISTORY_LIMIT}: ${path}`);
49
+ const legacyInactive = value.passiveBootstrap !== false || value.passiveTools !== false ? "passive" : "off";
50
+ const hasLegacyMode = Object.hasOwn(value, "autoStart") || Object.hasOwn(value, "passiveBootstrap") || Object.hasOwn(value, "passiveTools");
51
+ const mode = isStateFlowMode(value.mode) ? value.mode : value.autoStart === true ? "active" : hasLegacyMode ? legacyInactive : "off";
46
52
  return {
47
53
  directory,
48
- autoStart: value.autoStart === true,
49
- passiveBootstrap: value.passiveBootstrap !== false,
50
- passiveTools: value.passiveTools !== false,
54
+ mode,
55
+ inactiveMode: isStateFlowMode(value.mode) ? inactiveModeFor(value.mode) : hasLegacyMode ? legacyInactive : "off",
51
56
  logging: value.logging === true,
52
57
  showSuccessfulPatches: value.showSuccessfulPatches !== false,
53
58
  historyLimit: typeof value.historyLimit === "number" ? value.historyLimit : DEFAULT_HISTORY_LIMIT,
54
59
  };
55
60
  }
61
+ /** Explicit modes never carry a separate passive policy: only Off stays off when inactive. */
62
+ export function inactiveModeFor(mode) {
63
+ return mode === "off" ? "off" : "passive";
64
+ }
@@ -4,12 +4,12 @@ import type { RecentTransitionWindow } from "./history.ts";
4
4
  import { type JsonValue } from "./json.ts";
5
5
  import type { Snapshot } from "./snapshot.ts";
6
6
  import type { RehydrationPhase } from "./rehydration.ts";
7
- import { type AtomicScopePatches, type MaterializedState, type ModelState } from "./state.ts";
7
+ import { type AtomicScopePatches, type SemanticState } from "./state.ts";
8
8
  /** Refresh only our section; Pi owns system frames, tools and forced-prompt precedence. */
9
9
  export declare function projectSystemProtocol(messages: AgentMessage[], protocol: string | undefined): AgentMessage[];
10
10
  type LazyValueKind = "array" | "boolean" | "null" | "number" | "object" | "string";
11
11
  /** Fixed-budget navigation only: never place lazy bodies or partial key catalogs in baseline context. */
12
- export declare function lazyNavigationHint(state: MaterializedState): {
12
+ export declare function lazyNavigationHint(state: SemanticState): {
13
13
  available: boolean;
14
14
  path: string;
15
15
  keys?: Record<string, LazyValueKind>;
@@ -22,7 +22,7 @@ export type ModelStateUpdate = {
22
22
  deleted: true;
23
23
  });
24
24
  /** Exact projected replacements, not authored merge patches; paths are unambiguous key/index segments. */
25
- export declare function acceptedStateUpdates(before: MaterializedState, after: MaterializedState, patches: AtomicScopePatches): {
25
+ export declare function acceptedStateUpdates(before: SemanticState, after: SemanticState, patches: AtomicScopePatches): {
26
26
  effective: ModelStateUpdate[];
27
27
  lazy_navigation?: {
28
28
  available: boolean;
@@ -31,14 +31,14 @@ export declare function acceptedStateUpdates(before: MaterializedState, after: M
31
31
  } | undefined;
32
32
  };
33
33
  export interface ContextView {
34
- state: ModelState;
34
+ state: SemanticState;
35
35
  lazy_navigation?: ReturnType<typeof lazyNavigationHint>;
36
36
  artifact_invalidations: readonly ArtifactInvalidationNotice[];
37
37
  knowledge_rehydration: {
38
38
  phase: RehydrationPhase;
39
39
  } | null;
40
40
  }
41
- export declare function contextView(state: MaterializedState, hints: ArtifactModelHints, invalidations: readonly ArtifactInvalidationNotice[], phase?: RehydrationPhase): ContextView;
41
+ export declare function contextView(state: SemanticState, hints: ArtifactModelHints, invalidations: readonly ArtifactInvalidationNotice[], phase?: RehydrationPhase): ContextView;
42
42
  /** Volatile model projection only. Native messages own trajectory; this cache owns no persistence or lifecycle. */
43
43
  export declare class ContextProjection {
44
44
  private identity;
@@ -48,7 +48,7 @@ export declare class ContextProjection {
48
48
  private notices;
49
49
  reset(): void;
50
50
  /** Called only after successful publication and ancillary acceptance, immediately before returning the native result. */
51
- acceptPatch(before: MaterializedState, after: MaterializedState, patches: AtomicScopePatches, hints: ArtifactModelHints): {
51
+ acceptPatch(before: SemanticState, after: SemanticState, patches: AtomicScopePatches, hints: ArtifactModelHints): {
52
52
  effective: ModelStateUpdate[];
53
53
  lazy_navigation?: {
54
54
  available: boolean;
@@ -65,13 +65,13 @@ export interface PassiveContinuation {
65
65
  activeRunStartedAt?: number;
66
66
  preserveContext?: true;
67
67
  handoff: AgentMessage;
68
- state: ModelState;
68
+ state: SemanticState;
69
69
  }
70
70
  export declare function syntheticUser(text: string): AgentMessage;
71
- export declare function createPassiveContinuation(state: ModelState, startedAt?: number, activeRunStartedAt?: number, preserveContext?: boolean): PassiveContinuation;
71
+ export declare function createPassiveContinuation(state: SemanticState, startedAt?: number, activeRunStartedAt?: number, preserveContext?: boolean): PassiveContinuation;
72
72
  /** Keep the interrupted run through later results; an idle stop retains only later conversation. */
73
73
  export declare function passiveContinuationMessages(messages: AgentMessage[], continuation: PassiveContinuation): AgentMessage[];
74
- export declare function runtimeContextMessage(snapshot: Snapshot, state: MaterializedState, recentTransitions?: RecentTransitionWindow, artifactInvalidations?: readonly ArtifactInvalidationNotice[], rehydrationPhase?: RehydrationPhase, artifactHints?: ArtifactModelHints): AgentMessage;
74
+ export declare function runtimeContextMessage(snapshot: Snapshot, state: SemanticState, recentTransitions?: RecentTransitionWindow, artifactInvalidations?: readonly ArtifactInvalidationNotice[], rehydrationPhase?: RehydrationPhase, artifactHints?: ArtifactModelHints): AgentMessage;
75
75
  /** Render a view already projected by this domain without cloning the full semantic overlay twice. */
76
76
  export declare function runtimeContextHead(snapshot: Snapshot, view: ContextView, recentTransitions?: RecentTransitionWindow): AgentMessage;
77
77
  /** Captured identity survives text decoration; an uncertain boundary retains available context. */
@@ -1,7 +1,7 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { projectArtifactForModel } from "./artifact.js";
3
3
  import { applyPatch, isObject, presentationJson, sameJson } from "./json.js";
4
- import { projectStateForModel } from "./state.js";
4
+ import { projectSemanticPatch, projectStateForModel } from "./state.js";
5
5
  /** Refresh only our section; Pi owns system frames, tools and forced-prompt precedence. */
6
6
  export function projectSystemProtocol(messages, protocol) {
7
7
  let lastSystem = -1;
@@ -74,8 +74,8 @@ function projectedStateUpdates(previous, current, patches, beforeNavigation, nav
74
74
  const diff = (left, right, path) => {
75
75
  if (left === undefined && right === undefined || left !== undefined && right !== undefined && sameJson(left, right))
76
76
  return;
77
- if (isObject(left) && isObject(right)) {
78
- for (const key of new Set([...Object.keys(left), ...Object.keys(right)]))
77
+ if (isObject(right) && (isObject(left) || left === undefined && path.length === 1 && Object.keys(right).length > 0)) {
78
+ for (const key of new Set([...Object.keys(left ?? {}), ...Object.keys(right)]))
79
79
  diff(child(left, key), child(right, key), [...path, key]);
80
80
  }
81
81
  else if (Array.isArray(left) && Array.isArray(right) && left.length === right.length) {
@@ -336,8 +336,9 @@ function projectRecentForModel(recent) {
336
336
  const projected = structuredClone(recent);
337
337
  for (const record of projected)
338
338
  for (const transition of record.transitions) {
339
+ transition.patch = projectSemanticPatch(transition.patch);
339
340
  delete transition.patch.lazy;
340
- if (transition.patch.artifacts === undefined)
341
+ if (!isObject(transition.patch.artifacts))
341
342
  continue;
342
343
  for (const [path, entry] of Object.entries(transition.patch.artifacts)) {
343
344
  Object.defineProperty(transition.patch.artifacts, path, {
@@ -149,8 +149,8 @@ export async function inspectStateFlowContinuationProvenance(header, repositoryR
149
149
  const runtime = parseSessionRuntime(files.get(paths.config), files.get(paths.runtime), selected.cwd, selected.id);
150
150
  if (!runtime)
151
151
  throw new Error("incomplete canonical session runtime");
152
- if (!runtime.config.enabled)
153
- return { stateFlow: { enabled: false, restorable: true }, reason: "State Flow stopped on selected runtime" };
152
+ if (runtime.config.mode !== "active")
153
+ return { stateFlow: { enabled: false, restorable: true }, reason: "State Flow is not active on selected runtime" };
154
154
  const streams = ["global", "cwd", "session"].map((scope) => {
155
155
  const owned = temporalScopePaths(selected.cwd, selected.id, scope, root, sessionKey);
156
156
  return parseScopeStream(files.get(owned.checkpoint), files.get(owned.patches), scope, scope === "cwd" ? selected.cwd : undefined, files.get(owned.meta));
@@ -1,6 +1,6 @@
1
1
  import { type ArtifactProvenanceRegistry } from "./artifact.ts";
2
2
  import { type ScopeStream, type TemporalState } from "./temporal.ts";
3
- import type { StateScope } from "./state.ts";
3
+ import { type StateScope } from "./state.ts";
4
4
  /** Canonical semantic sources plus runtime-owned temporal metadata. */
5
5
  export interface ScopeStreamSources {
6
6
  checkpoint: string;
@@ -6,6 +6,7 @@ import { parseArtifactProvenanceRegistry, serializeArtifactProvenanceRegistry, }
6
6
  import { MAX_HISTORY_LIMIT } from "./history.js";
7
7
  import { canonicalJson, isJsonValue, isObject } from "./json.js";
8
8
  import { validateScopeStream, validateTemporalState } from "./temporal.js";
9
+ import { selectSemanticFields } from "./state.js";
9
10
  const SESSION_KEY_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
10
11
  const STATE_FILE = "state.json";
11
12
  const CHECKPOINT_FILE = "checkpoint.json";
@@ -33,8 +34,8 @@ export function serializeScopeStream(stream, scope, cwdIdentity) {
33
34
  if (scope !== "cwd" && cwdIdentity !== undefined)
34
35
  throw new Error("Only State Flow CWD scope serialization accepts a CWD identity");
35
36
  return {
36
- checkpoint: `${canonicalJson(stream.checkpoint.state)}\n`,
37
- patches: stream.patches.map((record) => `${canonicalJson(record.patch)}\n`).join(""),
37
+ checkpoint: `${canonicalJson(selectSemanticFields(stream.checkpoint.state))}\n`,
38
+ patches: stream.patches.map((record) => `${canonicalJson(selectSemanticFields(record.patch))}\n`).join(""),
38
39
  temporal: {
39
40
  revision: stream.revision,
40
41
  checkpoint: structuredClone(stream.checkpoint.through),
@@ -96,8 +97,10 @@ export function classifyScopeStream(checkpointSource, patchesSource, scope, expe
96
97
  // 0.17.4 and earlier did not persist scope revisions. Credit only their still-retained
97
98
  // semantic tail; discarded ancestry cannot be reconstructed without inventing history.
98
99
  revision: temporal.revision === undefined ? patches.length : temporal.revision,
99
- checkpoint: { through: temporal.checkpoint, state: checkpoint },
100
- patches: patches.map((patch, index) => ({ transition: boundaries[index], patch })),
100
+ checkpoint: { through: temporal.checkpoint, state: isObject(checkpoint) ? selectSemanticFields(checkpoint) : checkpoint },
101
+ patches: patches.map((patch, index) => ({
102
+ transition: boundaries[index], patch: isObject(patch) ? selectSemanticFields(patch) : patch,
103
+ })),
101
104
  };
102
105
  validateScopeStream(stream, scope, MAX_HISTORY_LIMIT);
103
106
  return { kind: "present", stream };
@@ -1,9 +1,9 @@
1
- import { type Snapshot } from "./snapshot.ts";
1
+ import { type InactiveMode, type Snapshot } from "./snapshot.ts";
2
2
  export declare function startEpisode(bootstrap: boolean): Snapshot;
3
3
  /** Re-enable a branch checkpoint without discarding its runtime config or provenance. */
4
4
  export declare function resumeEpisode(snapshot: Snapshot, bootstrap: boolean): Snapshot;
5
- /** Disable only this branch; durable defaults and session history remain intact. */
6
- export declare function stopEpisode(snapshot: Snapshot): Snapshot;
5
+ /** Select an inactive mode for only this branch; durable defaults and session history remain intact. */
6
+ export declare function deactivateEpisode(snapshot: Snapshot, mode: InactiveMode): Snapshot;
7
7
  /** Apply one user-run boundary while preserving checkpoint-owned runtime state. */
8
8
  export declare function prepareRun(snapshot: Snapshot, prompt: string): boolean;
9
9
  /** Retain the full prompt only while its run remains recoverable and unfinished. */
@@ -1,6 +1,6 @@
1
1
  import { emptySnapshot } from "./snapshot.js";
2
2
  export function startEpisode(bootstrap) {
3
- const snapshot = emptySnapshot(true);
3
+ const snapshot = emptySnapshot("active");
4
4
  if (bootstrap)
5
5
  snapshot.meta.bootstrap = true;
6
6
  return snapshot;
@@ -8,15 +8,15 @@ export function startEpisode(bootstrap) {
8
8
  /** Re-enable a branch checkpoint without discarding its runtime config or provenance. */
9
9
  export function resumeEpisode(snapshot, bootstrap) {
10
10
  const next = structuredClone(snapshot);
11
- next.config.enabled = true;
11
+ next.config.mode = "active";
12
12
  if (bootstrap)
13
13
  next.meta.bootstrap = true;
14
14
  return next;
15
15
  }
16
- /** Disable only this branch; durable defaults and session history remain intact. */
17
- export function stopEpisode(snapshot) {
16
+ /** Select an inactive mode for only this branch; durable defaults and session history remain intact. */
17
+ export function deactivateEpisode(snapshot, mode) {
18
18
  const next = structuredClone(snapshot);
19
- next.config.enabled = false;
19
+ next.config.mode = mode;
20
20
  return next;
21
21
  }
22
22
  /** Apply one user-run boundary while preserving checkpoint-owned runtime state. */
@@ -1,5 +1,6 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { formatPatchStateArguments } from "./protocol.ts";
3
+ import { type StateFlowMode } from "./snapshot.ts";
3
4
  import { type ModelState, type StateScope } from "./state.ts";
4
5
  import { type StateFlowTelegramLoader } from "./telegram.ts";
5
6
  export interface StateFlowExtensionOptions {
@@ -11,11 +12,8 @@ export interface StateFlowExtensionOptions {
11
12
  telegram?: {
12
13
  load?: StateFlowTelegramLoader;
13
14
  };
14
- /** Test/SDK capability override; repository config remains the Pi default. */
15
- passive?: {
16
- bootstrap?: boolean;
17
- tools?: boolean;
18
- };
15
+ /** Test/SDK override of the default mode for new sessions; repository config remains the Pi default. */
16
+ mode?: StateFlowMode;
19
17
  }
20
18
  export { formatPatchStateArguments };
21
19
  export declare const PATCH_STATE_TOOL_NAME = "patch_state";