@caupulican/pi-adaptative 0.93.17 → 0.93.19

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 (104) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/core/agent-session.d.ts +1 -0
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +22 -12
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/compaction-controller.d.ts +22 -0
  7. package/dist/core/compaction-controller.d.ts.map +1 -1
  8. package/dist/core/compaction-controller.js +191 -30
  9. package/dist/core/compaction-controller.js.map +1 -1
  10. package/dist/core/compaction-support.d.ts.map +1 -1
  11. package/dist/core/compaction-support.js +21 -1
  12. package/dist/core/compaction-support.js.map +1 -1
  13. package/dist/core/delegation/worker-agent-control-coordinator.d.ts.map +1 -1
  14. package/dist/core/delegation/worker-agent-control-coordinator.js +1 -0
  15. package/dist/core/delegation/worker-agent-control-coordinator.js.map +1 -1
  16. package/dist/core/delegation/worker-agent-control.d.ts +2 -0
  17. package/dist/core/delegation/worker-agent-control.d.ts.map +1 -1
  18. package/dist/core/delegation/worker-agent-control.js.map +1 -1
  19. package/dist/core/foreground-lifecycle-adapter.d.ts +27 -0
  20. package/dist/core/foreground-lifecycle-adapter.d.ts.map +1 -0
  21. package/dist/core/foreground-lifecycle-adapter.js +61 -0
  22. package/dist/core/foreground-lifecycle-adapter.js.map +1 -0
  23. package/dist/core/foreground-lifecycle-controller.d.ts +48 -0
  24. package/dist/core/foreground-lifecycle-controller.d.ts.map +1 -0
  25. package/dist/core/foreground-lifecycle-controller.js +404 -0
  26. package/dist/core/foreground-lifecycle-controller.js.map +1 -0
  27. package/dist/core/foreground-recovery-controller.d.ts +3 -0
  28. package/dist/core/foreground-recovery-controller.d.ts.map +1 -1
  29. package/dist/core/foreground-recovery-controller.js +15 -1
  30. package/dist/core/foreground-recovery-controller.js.map +1 -1
  31. package/dist/core/goals/goal-state.d.ts.map +1 -1
  32. package/dist/core/goals/goal-state.js +9 -2
  33. package/dist/core/goals/goal-state.js.map +1 -1
  34. package/dist/core/keybindings.d.ts +2 -2
  35. package/dist/core/keybindings.d.ts.map +1 -1
  36. package/dist/core/keybindings.js +2 -2
  37. package/dist/core/keybindings.js.map +1 -1
  38. package/dist/core/memory/memory-manager.d.ts +22 -0
  39. package/dist/core/memory/memory-manager.d.ts.map +1 -1
  40. package/dist/core/memory/memory-manager.js +108 -49
  41. package/dist/core/memory/memory-manager.js.map +1 -1
  42. package/dist/core/model-router/session-buffer.d.ts +10 -2
  43. package/dist/core/model-router/session-buffer.d.ts.map +1 -1
  44. package/dist/core/model-router/session-buffer.js +35 -9
  45. package/dist/core/model-router/session-buffer.js.map +1 -1
  46. package/dist/core/model-router-controller.d.ts +20 -2
  47. package/dist/core/model-router-controller.d.ts.map +1 -1
  48. package/dist/core/model-router-controller.js +70 -17
  49. package/dist/core/model-router-controller.js.map +1 -1
  50. package/dist/core/provider-request-runtime-controller.d.ts +12 -1
  51. package/dist/core/provider-request-runtime-controller.d.ts.map +1 -1
  52. package/dist/core/provider-request-runtime-controller.js +45 -2
  53. package/dist/core/provider-request-runtime-controller.js.map +1 -1
  54. package/dist/core/settings-manager.d.ts +1 -0
  55. package/dist/core/settings-manager.d.ts.map +1 -1
  56. package/dist/core/settings-manager.js +3 -0
  57. package/dist/core/settings-manager.js.map +1 -1
  58. package/dist/core/tools/delegate.d.ts.map +1 -1
  59. package/dist/core/tools/delegate.js +4 -2
  60. package/dist/core/tools/delegate.js.map +1 -1
  61. package/dist/modes/interactive/components/assistant-message.d.ts +1 -3
  62. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  63. package/dist/modes/interactive/components/assistant-message.js +10 -20
  64. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  65. package/dist/modes/interactive/components/tool-group.d.ts +3 -0
  66. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  67. package/dist/modes/interactive/components/tool-group.js +25 -0
  68. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  69. package/dist/modes/interactive/components/transcript-overlay.d.ts +13 -0
  70. package/dist/modes/interactive/components/transcript-overlay.d.ts.map +1 -0
  71. package/dist/modes/interactive/components/transcript-overlay.js +35 -0
  72. package/dist/modes/interactive/components/transcript-overlay.js.map +1 -0
  73. package/dist/modes/interactive/components/tree-selector.d.ts +1 -1
  74. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  75. package/dist/modes/interactive/components/tree-selector.js +7 -4
  76. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  77. package/dist/modes/interactive/interactive-event-controller.d.ts +1 -1
  78. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -1
  79. package/dist/modes/interactive/interactive-event-controller.js +2 -1
  80. package/dist/modes/interactive/interactive-event-controller.js.map +1 -1
  81. package/dist/modes/interactive/interactive-mode.d.ts +9 -7
  82. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  83. package/dist/modes/interactive/interactive-mode.js +70 -99
  84. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  85. package/dist/modes/interactive/runtime-status-controller.d.ts +40 -0
  86. package/dist/modes/interactive/runtime-status-controller.d.ts.map +1 -0
  87. package/dist/modes/interactive/runtime-status-controller.js +147 -0
  88. package/dist/modes/interactive/runtime-status-controller.js.map +1 -0
  89. package/dist/modes/interactive/runtime-status.d.ts +15 -0
  90. package/dist/modes/interactive/runtime-status.d.ts.map +1 -0
  91. package/dist/modes/interactive/runtime-status.js +18 -0
  92. package/dist/modes/interactive/runtime-status.js.map +1 -0
  93. package/docs/json.md +1 -1
  94. package/docs/keybindings.md +2 -1
  95. package/docs/session-format.md +59 -4
  96. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  97. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  98. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  99. package/examples/extensions/sandbox/package-lock.json +2 -2
  100. package/examples/extensions/sandbox/package.json +1 -1
  101. package/examples/extensions/with-deps/package-lock.json +2 -2
  102. package/examples/extensions/with-deps/package.json +1 -1
  103. package/npm-shrinkwrap.json +12 -12
  104. package/package.json +4 -4
@@ -0,0 +1,40 @@
1
+ import type { AssistantMessage } from "@caupulican/pi-ai";
2
+ import { type Container, Loader, type LoaderIndicatorOptions, type TUI } from "@caupulican/pi-tui";
3
+ import type { ActivityLaneComponent } from "./components/activity-lane.ts";
4
+ export interface RuntimeStatusControllerHost {
5
+ readonly ui: TUI;
6
+ readonly statusContainer: Container;
7
+ readonly activityLane: ActivityLaneComponent | undefined;
8
+ readonly hasHumanAudience: boolean;
9
+ isStreaming(): boolean;
10
+ isThinkingHidden(): boolean;
11
+ }
12
+ /** Owns the human-facing turn indicator and its loader/activity-lane lifecycle. */
13
+ export declare class RuntimeStatusController {
14
+ private readonly host;
15
+ private activeLoader;
16
+ private workingMessage;
17
+ private workingVisible;
18
+ private workingIndicatorOptions;
19
+ private readonly defaultWorkingMessage;
20
+ private readonly defaultHiddenThinkingLabel;
21
+ private hiddenThinkingLabel;
22
+ private runtimeStatusLabel;
23
+ constructor(host: RuntimeStatusControllerHost);
24
+ get loadingAnimation(): Loader | undefined;
25
+ set loadingAnimation(value: Loader | undefined);
26
+ get isWorkingVisible(): boolean;
27
+ set isWorkingVisible(value: boolean);
28
+ get indicatorOptions(): LoaderIndicatorOptions | undefined;
29
+ set indicatorOptions(value: LoaderIndicatorOptions | undefined);
30
+ getWorkingLoaderMessage(): string;
31
+ createWorkingLoader(): Loader;
32
+ stopWorkingLoader(): void;
33
+ setWorkingVisible(visible: boolean): void;
34
+ setWorkingIndicator(options?: LoaderIndicatorOptions): void;
35
+ setHiddenThinkingLabel(label?: string): void;
36
+ updateRuntimeStatus(message?: AssistantMessage): void;
37
+ setWorkingMessage(message: string | undefined, messageInFlight: AssistantMessage | undefined): void;
38
+ resetWorkingIndicators(): void;
39
+ }
40
+ //# sourceMappingURL=runtime-status-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-status-controller.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/runtime-status-controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,EAAE,KAAK,sBAAsB,EAAE,KAAK,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAK3E,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;IACjB,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC;IACpC,QAAQ,CAAC,YAAY,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,WAAW,IAAI,OAAO,CAAC;IACvB,gBAAgB,IAAI,OAAO,CAAC;CAC5B;AAED,mFAAmF;AACnF,qBAAa,uBAAuB;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA8B;IACnD,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,uBAAuB,CAAqC;IACpE,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAgB;IACtD,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAiB;IAC5D,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,OAAO,CAAC,kBAAkB,CAAqB;IAE/C,YAAY,IAAI,EAAE,2BAA2B,EAG5C;IAED,IAAI,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAEzC;IAED,IAAI,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAE7C;IAED,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IAED,IAAI,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAElC;IAED,IAAI,gBAAgB,IAAI,sBAAsB,GAAG,SAAS,CAEzD;IAED,IAAI,gBAAgB,CAAC,KAAK,EAAE,sBAAsB,GAAG,SAAS,EAE7D;IAED,uBAAuB,IAAI,MAAM,CAEhC;IAED,mBAAmB,IAAI,MAAM,CAQ5B;IAED,iBAAiB,IAAI,IAAI,CASxB;IAED,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4BxC;IAED,mBAAmB,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,IAAI,CA4B1D;IAED,sBAAsB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAE3C;IAED,mBAAmB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAoBpD;IAED,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,eAAe,EAAE,gBAAgB,GAAG,SAAS,GAAG,IAAI,CAUlG;IAED,sBAAsB,IAAI,IAAI,CAQ7B;CACD"}
@@ -0,0 +1,147 @@
1
+ import { Loader } from "@caupulican/pi-tui";
2
+ import { keyText } from "./components/keybinding-hints.js";
3
+ import { applyRuntimeStatusLabel, resolveHiddenThinkingStatus } from "./runtime-status.js";
4
+ import { theme } from "./theme/theme.js";
5
+ /** Owns the human-facing turn indicator and its loader/activity-lane lifecycle. */
6
+ export class RuntimeStatusController {
7
+ constructor(host) {
8
+ this.defaultWorkingMessage = "Working...";
9
+ this.defaultHiddenThinkingLabel = "Thinking...";
10
+ this.hiddenThinkingLabel = this.defaultHiddenThinkingLabel;
11
+ this.host = host;
12
+ this.workingVisible = host.hasHumanAudience;
13
+ }
14
+ get loadingAnimation() {
15
+ return this.activeLoader;
16
+ }
17
+ set loadingAnimation(value) {
18
+ this.activeLoader = value;
19
+ }
20
+ get isWorkingVisible() {
21
+ return this.workingVisible;
22
+ }
23
+ set isWorkingVisible(value) {
24
+ this.workingVisible = value;
25
+ }
26
+ get indicatorOptions() {
27
+ return this.workingIndicatorOptions;
28
+ }
29
+ set indicatorOptions(value) {
30
+ this.workingIndicatorOptions = value;
31
+ }
32
+ getWorkingLoaderMessage() {
33
+ return this.workingMessage ?? this.defaultWorkingMessage;
34
+ }
35
+ createWorkingLoader() {
36
+ return new Loader(this.host.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), this.runtimeStatusLabel ?? this.getWorkingLoaderMessage(), this.workingIndicatorOptions);
37
+ }
38
+ stopWorkingLoader() {
39
+ if (this.activeLoader) {
40
+ this.activeLoader.stop();
41
+ this.activeLoader = undefined;
42
+ }
43
+ this.host.statusContainer.clear();
44
+ this.runtimeStatusLabel = undefined;
45
+ this.host.activityLane?.remove("runtime:routing");
46
+ this.host.activityLane?.remove("runtime:turn");
47
+ }
48
+ setWorkingVisible(visible) {
49
+ if (!this.host.hasHumanAudience) {
50
+ this.workingVisible = false;
51
+ this.stopWorkingLoader();
52
+ return;
53
+ }
54
+ this.workingVisible = visible;
55
+ if (!visible) {
56
+ const currentRuntimeStatus = this.runtimeStatusLabel;
57
+ this.stopWorkingLoader();
58
+ if (this.host.isStreaming())
59
+ this.runtimeStatusLabel = currentRuntimeStatus;
60
+ this.host.ui.requestRender();
61
+ return;
62
+ }
63
+ if (this.host.isStreaming() && !this.activeLoader) {
64
+ if (this.workingIndicatorOptions) {
65
+ this.host.statusContainer.clear();
66
+ this.activeLoader = this.createWorkingLoader();
67
+ this.host.statusContainer.addChild(this.activeLoader);
68
+ }
69
+ else {
70
+ this.host.activityLane?.start({
71
+ id: "runtime:turn",
72
+ kind: "runtime",
73
+ label: this.runtimeStatusLabel ?? this.getWorkingLoaderMessage(),
74
+ });
75
+ }
76
+ }
77
+ this.host.ui.requestRender();
78
+ }
79
+ setWorkingIndicator(options) {
80
+ this.workingIndicatorOptions = options;
81
+ if (!this.host.hasHumanAudience) {
82
+ this.stopWorkingLoader();
83
+ return;
84
+ }
85
+ if (options) {
86
+ this.host.activityLane?.remove("runtime:turn");
87
+ if (this.host.isStreaming() && this.workingVisible) {
88
+ const currentRuntimeStatus = this.runtimeStatusLabel;
89
+ this.stopWorkingLoader();
90
+ this.runtimeStatusLabel = currentRuntimeStatus;
91
+ this.activeLoader = this.createWorkingLoader();
92
+ this.host.statusContainer.addChild(this.activeLoader);
93
+ }
94
+ }
95
+ else {
96
+ this.activeLoader?.stop();
97
+ this.activeLoader = undefined;
98
+ this.host.statusContainer.clear();
99
+ if (this.host.isStreaming() && this.workingVisible) {
100
+ this.host.activityLane?.start({
101
+ id: "runtime:turn",
102
+ kind: "runtime",
103
+ label: this.runtimeStatusLabel ?? this.getWorkingLoaderMessage(),
104
+ });
105
+ }
106
+ }
107
+ this.host.ui.requestRender();
108
+ }
109
+ setHiddenThinkingLabel(label) {
110
+ this.hiddenThinkingLabel = label ?? this.defaultHiddenThinkingLabel;
111
+ }
112
+ updateRuntimeStatus(message) {
113
+ if (!this.host.hasHumanAudience)
114
+ return;
115
+ const label = message
116
+ ? resolveHiddenThinkingStatus(message, this.host.isThinkingHidden(), this.hiddenThinkingLabel, this.getWorkingLoaderMessage())
117
+ : this.getWorkingLoaderMessage();
118
+ this.runtimeStatusLabel = applyRuntimeStatusLabel({
119
+ hasHumanAudience: this.host.hasHumanAudience,
120
+ currentLabel: this.runtimeStatusLabel,
121
+ loadingAnimation: this.activeLoader,
122
+ activityLane: this.host.activityLane,
123
+ requestRender: () => this.host.ui.requestRender(),
124
+ }, label);
125
+ }
126
+ setWorkingMessage(message, messageInFlight) {
127
+ this.workingMessage = message;
128
+ if (messageInFlight) {
129
+ this.updateRuntimeStatus(messageInFlight);
130
+ return;
131
+ }
132
+ if (this.activeLoader) {
133
+ this.activeLoader.setMessage(message ?? this.defaultWorkingMessage);
134
+ }
135
+ this.host.activityLane?.update("runtime:turn", message ?? this.defaultWorkingMessage);
136
+ }
137
+ resetWorkingIndicators() {
138
+ this.workingMessage = undefined;
139
+ this.workingVisible = this.host.hasHumanAudience;
140
+ this.setWorkingIndicator();
141
+ if (this.activeLoader) {
142
+ this.activeLoader.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
143
+ }
144
+ this.setHiddenThinkingLabel();
145
+ }
146
+ }
147
+ //# sourceMappingURL=runtime-status-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-status-controller.js","sourceRoot":"","sources":["../../../src/modes/interactive/runtime-status-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@caupulican/pi-ai\";\nimport { type Container, Loader, type LoaderIndicatorOptions, type TUI } from \"@caupulican/pi-tui\";\nimport type { ActivityLaneComponent } from \"./components/activity-lane.ts\";\nimport { keyText } from \"./components/keybinding-hints.ts\";\nimport { applyRuntimeStatusLabel, resolveHiddenThinkingStatus } from \"./runtime-status.ts\";\nimport { theme } from \"./theme/theme.ts\";\n\nexport interface RuntimeStatusControllerHost {\n\treadonly ui: TUI;\n\treadonly statusContainer: Container;\n\treadonly activityLane: ActivityLaneComponent | undefined;\n\treadonly hasHumanAudience: boolean;\n\tisStreaming(): boolean;\n\tisThinkingHidden(): boolean;\n}\n\n/** Owns the human-facing turn indicator and its loader/activity-lane lifecycle. */\nexport class RuntimeStatusController {\n\tprivate readonly host: RuntimeStatusControllerHost;\n\tprivate activeLoader: Loader | undefined;\n\tprivate workingMessage: string | undefined;\n\tprivate workingVisible: boolean;\n\tprivate workingIndicatorOptions: LoaderIndicatorOptions | undefined;\n\tprivate readonly defaultWorkingMessage = \"Working...\";\n\tprivate readonly defaultHiddenThinkingLabel = \"Thinking...\";\n\tprivate hiddenThinkingLabel = this.defaultHiddenThinkingLabel;\n\tprivate runtimeStatusLabel: string | undefined;\n\n\tconstructor(host: RuntimeStatusControllerHost) {\n\t\tthis.host = host;\n\t\tthis.workingVisible = host.hasHumanAudience;\n\t}\n\n\tget loadingAnimation(): Loader | undefined {\n\t\treturn this.activeLoader;\n\t}\n\n\tset loadingAnimation(value: Loader | undefined) {\n\t\tthis.activeLoader = value;\n\t}\n\n\tget isWorkingVisible(): boolean {\n\t\treturn this.workingVisible;\n\t}\n\n\tset isWorkingVisible(value: boolean) {\n\t\tthis.workingVisible = value;\n\t}\n\n\tget indicatorOptions(): LoaderIndicatorOptions | undefined {\n\t\treturn this.workingIndicatorOptions;\n\t}\n\n\tset indicatorOptions(value: LoaderIndicatorOptions | undefined) {\n\t\tthis.workingIndicatorOptions = value;\n\t}\n\n\tgetWorkingLoaderMessage(): string {\n\t\treturn this.workingMessage ?? this.defaultWorkingMessage;\n\t}\n\n\tcreateWorkingLoader(): Loader {\n\t\treturn new Loader(\n\t\t\tthis.host.ui,\n\t\t\t(spinner) => theme.fg(\"accent\", spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\tthis.runtimeStatusLabel ?? this.getWorkingLoaderMessage(),\n\t\t\tthis.workingIndicatorOptions,\n\t\t);\n\t}\n\n\tstopWorkingLoader(): void {\n\t\tif (this.activeLoader) {\n\t\t\tthis.activeLoader.stop();\n\t\t\tthis.activeLoader = undefined;\n\t\t}\n\t\tthis.host.statusContainer.clear();\n\t\tthis.runtimeStatusLabel = undefined;\n\t\tthis.host.activityLane?.remove(\"runtime:routing\");\n\t\tthis.host.activityLane?.remove(\"runtime:turn\");\n\t}\n\n\tsetWorkingVisible(visible: boolean): void {\n\t\tif (!this.host.hasHumanAudience) {\n\t\t\tthis.workingVisible = false;\n\t\t\tthis.stopWorkingLoader();\n\t\t\treturn;\n\t\t}\n\t\tthis.workingVisible = visible;\n\t\tif (!visible) {\n\t\t\tconst currentRuntimeStatus = this.runtimeStatusLabel;\n\t\t\tthis.stopWorkingLoader();\n\t\t\tif (this.host.isStreaming()) this.runtimeStatusLabel = currentRuntimeStatus;\n\t\t\tthis.host.ui.requestRender();\n\t\t\treturn;\n\t\t}\n\t\tif (this.host.isStreaming() && !this.activeLoader) {\n\t\t\tif (this.workingIndicatorOptions) {\n\t\t\t\tthis.host.statusContainer.clear();\n\t\t\t\tthis.activeLoader = this.createWorkingLoader();\n\t\t\t\tthis.host.statusContainer.addChild(this.activeLoader);\n\t\t\t} else {\n\t\t\t\tthis.host.activityLane?.start({\n\t\t\t\t\tid: \"runtime:turn\",\n\t\t\t\t\tkind: \"runtime\",\n\t\t\t\t\tlabel: this.runtimeStatusLabel ?? this.getWorkingLoaderMessage(),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.host.ui.requestRender();\n\t}\n\n\tsetWorkingIndicator(options?: LoaderIndicatorOptions): void {\n\t\tthis.workingIndicatorOptions = options;\n\t\tif (!this.host.hasHumanAudience) {\n\t\t\tthis.stopWorkingLoader();\n\t\t\treturn;\n\t\t}\n\t\tif (options) {\n\t\t\tthis.host.activityLane?.remove(\"runtime:turn\");\n\t\t\tif (this.host.isStreaming() && this.workingVisible) {\n\t\t\t\tconst currentRuntimeStatus = this.runtimeStatusLabel;\n\t\t\t\tthis.stopWorkingLoader();\n\t\t\t\tthis.runtimeStatusLabel = currentRuntimeStatus;\n\t\t\t\tthis.activeLoader = this.createWorkingLoader();\n\t\t\t\tthis.host.statusContainer.addChild(this.activeLoader);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.activeLoader?.stop();\n\t\t\tthis.activeLoader = undefined;\n\t\t\tthis.host.statusContainer.clear();\n\t\t\tif (this.host.isStreaming() && this.workingVisible) {\n\t\t\t\tthis.host.activityLane?.start({\n\t\t\t\t\tid: \"runtime:turn\",\n\t\t\t\t\tkind: \"runtime\",\n\t\t\t\t\tlabel: this.runtimeStatusLabel ?? this.getWorkingLoaderMessage(),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.host.ui.requestRender();\n\t}\n\n\tsetHiddenThinkingLabel(label?: string): void {\n\t\tthis.hiddenThinkingLabel = label ?? this.defaultHiddenThinkingLabel;\n\t}\n\n\tupdateRuntimeStatus(message?: AssistantMessage): void {\n\t\tif (!this.host.hasHumanAudience) return;\n\t\tconst label = message\n\t\t\t? resolveHiddenThinkingStatus(\n\t\t\t\t\tmessage,\n\t\t\t\t\tthis.host.isThinkingHidden(),\n\t\t\t\t\tthis.hiddenThinkingLabel,\n\t\t\t\t\tthis.getWorkingLoaderMessage(),\n\t\t\t\t)\n\t\t\t: this.getWorkingLoaderMessage();\n\t\tthis.runtimeStatusLabel = applyRuntimeStatusLabel(\n\t\t\t{\n\t\t\t\thasHumanAudience: this.host.hasHumanAudience,\n\t\t\t\tcurrentLabel: this.runtimeStatusLabel,\n\t\t\t\tloadingAnimation: this.activeLoader,\n\t\t\t\tactivityLane: this.host.activityLane,\n\t\t\t\trequestRender: () => this.host.ui.requestRender(),\n\t\t\t},\n\t\t\tlabel,\n\t\t);\n\t}\n\n\tsetWorkingMessage(message: string | undefined, messageInFlight: AssistantMessage | undefined): void {\n\t\tthis.workingMessage = message;\n\t\tif (messageInFlight) {\n\t\t\tthis.updateRuntimeStatus(messageInFlight);\n\t\t\treturn;\n\t\t}\n\t\tif (this.activeLoader) {\n\t\t\tthis.activeLoader.setMessage(message ?? this.defaultWorkingMessage);\n\t\t}\n\t\tthis.host.activityLane?.update(\"runtime:turn\", message ?? this.defaultWorkingMessage);\n\t}\n\n\tresetWorkingIndicators(): void {\n\t\tthis.workingMessage = undefined;\n\t\tthis.workingVisible = this.host.hasHumanAudience;\n\t\tthis.setWorkingIndicator();\n\t\tif (this.activeLoader) {\n\t\t\tthis.activeLoader.setMessage(`${this.defaultWorkingMessage} (${keyText(\"app.interrupt\")} to interrupt)`);\n\t\t}\n\t\tthis.setHiddenThinkingLabel();\n\t}\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { AssistantMessage } from "@caupulican/pi-ai";
2
+ export interface RuntimeStatusPresentation {
3
+ hasHumanAudience: boolean;
4
+ currentLabel: string | undefined;
5
+ loadingAnimation: {
6
+ setMessage(message: string): void;
7
+ } | undefined;
8
+ activityLane: {
9
+ update(id: string, label: string): void;
10
+ } | undefined;
11
+ requestRender(): void;
12
+ }
13
+ export declare function applyRuntimeStatusLabel(presentation: RuntimeStatusPresentation, label: string): string | undefined;
14
+ export declare function resolveHiddenThinkingStatus(message: AssistantMessage, hideThinkingBlock: boolean, hiddenThinkingLabel: string, workingLabel: string): string;
15
+ //# sourceMappingURL=runtime-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-status.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/runtime-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,WAAW,yBAAyB;IACzC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,gBAAgB,EAAE;QAAE,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,SAAS,CAAC;IACpE,YAAY,EAAE;QAAE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,SAAS,CAAC;IACtE,aAAa,IAAI,IAAI,CAAC;CACtB;AAED,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,yBAAyB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMlH;AAED,wBAAgB,2BAA2B,CAC1C,OAAO,EAAE,gBAAgB,EACzB,iBAAiB,EAAE,OAAO,EAC1B,mBAAmB,EAAE,MAAM,EAC3B,YAAY,EAAE,MAAM,GAClB,MAAM,CASR"}
@@ -0,0 +1,18 @@
1
+ export function applyRuntimeStatusLabel(presentation, label) {
2
+ if (!presentation.hasHumanAudience || presentation.currentLabel === label)
3
+ return presentation.currentLabel;
4
+ if (presentation.loadingAnimation)
5
+ presentation.loadingAnimation.setMessage(label);
6
+ else
7
+ presentation.activityLane?.update("runtime:turn", label);
8
+ presentation.requestRender();
9
+ return label;
10
+ }
11
+ export function resolveHiddenThinkingStatus(message, hideThinkingBlock, hiddenThinkingLabel, workingLabel) {
12
+ if (!hideThinkingBlock)
13
+ return workingLabel;
14
+ const hasThinking = message.content.some((content) => content.type === "thinking" && content.thinking.trim().length > 0);
15
+ const hasVisibleWork = message.content.some((content) => (content.type === "text" && content.text.trim().length > 0) || content.type === "toolCall");
16
+ return hasThinking && !hasVisibleWork ? hiddenThinkingLabel : workingLabel;
17
+ }
18
+ //# sourceMappingURL=runtime-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-status.js","sourceRoot":"","sources":["../../../src/modes/interactive/runtime-status.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,uBAAuB,CAAC,YAAuC,EAAE,KAAa;IAC7F,IAAI,CAAC,YAAY,CAAC,gBAAgB,IAAI,YAAY,CAAC,YAAY,KAAK,KAAK;QAAE,OAAO,YAAY,CAAC,YAAY,CAAC;IAC5G,IAAI,YAAY,CAAC,gBAAgB;QAAE,YAAY,CAAC,gBAAgB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;;QAC9E,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IAC9D,YAAY,CAAC,aAAa,EAAE,CAAC;IAC7B,OAAO,KAAK,CAAC;AACd,CAAC;AAED,MAAM,UAAU,2BAA2B,CAC1C,OAAyB,EACzB,iBAA0B,EAC1B,mBAA2B,EAC3B,YAAoB;IAEpB,IAAI,CAAC,iBAAiB;QAAE,OAAO,YAAY,CAAC;IAC5C,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CACvC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAC9E,CAAC;IACF,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAC1C,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,CACvG,CAAC;IACF,OAAO,WAAW,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,YAAY,CAAC;AAC5E,CAAC","sourcesContent":["import type { AssistantMessage } from \"@caupulican/pi-ai\";\n\nexport interface RuntimeStatusPresentation {\n\thasHumanAudience: boolean;\n\tcurrentLabel: string | undefined;\n\tloadingAnimation: { setMessage(message: string): void } | undefined;\n\tactivityLane: { update(id: string, label: string): void } | undefined;\n\trequestRender(): void;\n}\n\nexport function applyRuntimeStatusLabel(presentation: RuntimeStatusPresentation, label: string): string | undefined {\n\tif (!presentation.hasHumanAudience || presentation.currentLabel === label) return presentation.currentLabel;\n\tif (presentation.loadingAnimation) presentation.loadingAnimation.setMessage(label);\n\telse presentation.activityLane?.update(\"runtime:turn\", label);\n\tpresentation.requestRender();\n\treturn label;\n}\n\nexport function resolveHiddenThinkingStatus(\n\tmessage: AssistantMessage,\n\thideThinkingBlock: boolean,\n\thiddenThinkingLabel: string,\n\tworkingLabel: string,\n): string {\n\tif (!hideThinkingBlock) return workingLabel;\n\tconst hasThinking = message.content.some(\n\t\t(content) => content.type === \"thinking\" && content.thinking.trim().length > 0,\n\t);\n\tconst hasVisibleWork = message.content.some(\n\t\t(content) => (content.type === \"text\" && content.text.trim().length > 0) || content.type === \"toolCall\",\n\t);\n\treturn hasThinking && !hasVisibleWork ? hiddenThinkingLabel : workingLabel;\n}\n"]}
package/docs/json.md CHANGED
@@ -62,7 +62,7 @@ Extended messages from [`packages/coding-agent/src/core/messages.ts`](https://gi
62
62
  Each line is a JSON object. The first line is the session header:
63
63
 
64
64
  ```json
65
- {"type":"session","version":3,"id":"uuid","timestamp":"...","cwd":"/path"}
65
+ {"type":"session","version":4,"id":"uuid","timestamp":"...","cwd":"/path"}
66
66
  ```
67
67
 
68
68
  Followed by events as they occur:
@@ -122,13 +122,14 @@ These actions apply while the built-in `ask_question` interaction has focus. The
122
122
  | `app.model.cycleForward` | `ctrl+p` | Cycle to next model |
123
123
  | `app.model.cycleBackward` | `shift+ctrl+p` | Cycle to previous model |
124
124
  | `app.thinking.cycle` | `shift+tab` | Cycle thinking level |
125
- | `app.thinking.toggle` | `ctrl+t` | Show or hide thinking blocks (hidden by default) |
125
+ | `app.thinking.toggle` | `shift+pageUp` | Show or hide thinking blocks (hidden by default) |
126
126
 
127
127
  ### Display and Message Queue
128
128
 
129
129
  | Keybinding id | Default | Description |
130
130
  |--------|---------|-------------|
131
131
  | `app.tools.expand` | `ctrl+o` | Expand or collapse tool output (file groups stay as a count + short list until then) |
132
+ | `app.transcript.open` | `ctrl+t` | Open expanded transcript scrollback |
132
133
  | `app.history.load` | `ctrl+shift+h` | Load deferred session history into the chat |
133
134
  | `app.message.followUp` | `alt+enter` | Queue follow-up message |
134
135
  | `app.message.dequeue` | `alt+up` | Restore queued messages to editor |
@@ -23,13 +23,14 @@ Sessions have a version field in the header:
23
23
  - **Version 1**: Linear entry sequence (legacy, auto-migrated on load)
24
24
  - **Version 2**: Tree structure with `id`/`parentId` linking
25
25
  - **Version 3**: Renamed `hookMessage` role to `custom` (extensions unification)
26
+ - **Version 4**: Added bounded provider-request, foreground-tool, and compaction lifecycle records for crash recovery
26
27
 
27
- Existing sessions are automatically migrated to the current version (v3) when loaded.
28
+ Existing sessions are automatically migrated to the current version (v4) when loaded.
28
29
 
29
30
  ## Source Files
30
31
 
31
32
  Source on GitHub ([pi-mono](https://github.com/earendil-works/pi-mono)):
32
- - [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/session-manager.ts) - Session entry types and SessionManager
33
+ - [`packages/agent/src/session/session-manager.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/agent/src/session/session-manager.ts) - Session entry types and SessionManager
33
34
  - [`packages/coding-agent/src/core/messages.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/messages.ts) - Extended message types (BashExecutionMessage, CustomMessage, etc.)
34
35
  - [`packages/ai/src/types.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/ai/src/types.ts) - Base message types (UserMessage, AssistantMessage, ToolResultMessage)
35
36
  - [`packages/agent/src/types.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/agent/src/types.ts) - AgentMessage union type
@@ -188,13 +189,13 @@ interface SessionEntryBase {
188
189
  First line of the file. Metadata only, not part of the tree (no `id`/`parentId`).
189
190
 
190
191
  ```json
191
- {"type":"session","version":3,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project"}
192
+ {"type":"session","version":4,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project"}
192
193
  ```
193
194
 
194
195
  For sessions with a parent (created via `/fork`, `/clone`, or `newSession({ parentSession })`):
195
196
 
196
197
  ```json
197
- {"type":"session","version":3,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project","parentSession":"/path/to/original/session.jsonl"}
198
+ {"type":"session","version":4,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project","parentSession":"/path/to/original/session.jsonl"}
198
199
  ```
199
200
 
200
201
  ### SessionMessageEntry
@@ -290,6 +291,37 @@ Session metadata (e.g., user-defined display name). Set via `/name`, `--name` /
290
291
 
291
292
  The session name is displayed in the session selector (`/resume`) instead of the first message when set.
292
293
 
294
+ ### Lifecycle Entries (v4)
295
+
296
+ Lifecycle entries make interrupted foreground work recoverable without duplicating provider-visible data. They participate in tree ancestry but are excluded from model context and hidden from ordinary `/tree` views.
297
+
298
+ `RequestSnapshotEntry` is force-flushed before provider transport. It contains only the accepted model identity, bounded SHA-256 fingerprints, and bounded message-entry IDs; it never stores prompt text, tool arguments, results, credentials, or headers.
299
+
300
+ ```json
301
+ {"type":"request_snapshot","id":"r1","parentId":"u1","timestamp":"2026-08-21T12:00:00.000Z","requestId":"0198...","reason":"initial","api":"anthropic-messages","provider":"amazon-bedrock","modelId":"global.anthropic.claude-haiku-4-5-20251001-v1:0","effectiveConfigFingerprint":"...","systemFingerprint":"...","toolsFingerprint":"...","historyFingerprint":"...","messageEntryIds":["u1"]}
302
+ ```
303
+
304
+ `ForegroundToolStartEntry` is written after validation/policy checks and before a prepared tool body starts. Parallel waves are appended in one bounded batch.
305
+
306
+ ```json
307
+ {"type":"foreground_tool_start","id":"t1","parentId":"a1","timestamp":"2026-08-21T12:00:01.000Z","requestId":"0198...","assistantMessageEntryId":"a1","callId":"toolu_123","toolName":"bash"}
308
+ ```
309
+
310
+ `ForegroundToolTerminalEntry` is written only after the canonical `toolResult` message. Its composite identity is `(requestId, assistantMessageEntryId, callId)`.
311
+
312
+ ```json
313
+ {"type":"foreground_tool_terminal","id":"t2","parentId":"result1","timestamp":"2026-08-21T12:00:02.000Z","requestId":"0198...","assistantMessageEntryId":"a1","callId":"toolu_123","toolName":"bash","outcome":"success","resultMessageEntryId":"result1"}
314
+ ```
315
+
316
+ `CompactionStartEntry` and `CompactionEndEntry` bracket one complete compaction retry ladder. A successful end references the canonical `compaction` entry; interrupted runs are closed as `interrupted` during reopen repair.
317
+
318
+ ```json
319
+ {"type":"compaction_start","id":"c1","parentId":"m1","timestamp":"2026-08-21T12:01:00.000Z","compactionId":"...","firstKeptEntryId":"m1","tokensBefore":50000}
320
+ {"type":"compaction_end","id":"c3","parentId":"c2","timestamp":"2026-08-21T12:01:03.000Z","compactionId":"...","outcome":"success","compactionEntryId":"c2"}
321
+ ```
322
+
323
+ On reopen, deterministic repair distinguishes calls that were never started from started calls whose outcome is unknown. Duplicate, contradictory, ambiguous, or out-of-order records are refused and surfaced for manual review rather than guessed.
324
+
293
325
  ## Tree Structure
294
326
 
295
327
  Entries form a tree:
@@ -315,6 +347,7 @@ Entries form a tree:
315
347
  - Then messages from `firstKeptEntryId` to compaction
316
348
  - Then messages after compaction
317
349
  4. Converts `BranchSummaryEntry` and `CustomMessageEntry` to appropriate message formats
350
+ 5. Ignores lifecycle-only entries while preserving their ancestry for recovery
318
351
 
319
352
  ## Parsing Example
320
353
 
@@ -354,6 +387,21 @@ for (const line of lines) {
354
387
  case "thinking_level_change":
355
388
  console.log(`[${entry.id}] Thinking: ${entry.thinkingLevel}`);
356
389
  break;
390
+ case "request_snapshot":
391
+ console.log(`[${entry.id}] Request ${entry.requestId}: ${entry.provider}/${entry.modelId}`);
392
+ break;
393
+ case "foreground_tool_start":
394
+ console.log(`[${entry.id}] Tool started: ${entry.toolName}/${entry.callId}`);
395
+ break;
396
+ case "foreground_tool_terminal":
397
+ console.log(`[${entry.id}] Tool ${entry.outcome}: ${entry.toolName}/${entry.callId}`);
398
+ break;
399
+ case "compaction_start":
400
+ console.log(`[${entry.id}] Compaction started: ${entry.compactionId}`);
401
+ break;
402
+ case "compaction_end":
403
+ console.log(`[${entry.id}] Compaction ${entry.outcome}: ${entry.compactionId}`);
404
+ break;
357
405
  }
358
406
  }
359
407
  ```
@@ -380,6 +428,7 @@ Key methods for working with sessions programmatically.
380
428
 
381
429
  ### Instance Methods - Appending (all return entry ID)
382
430
  - `appendMessage(message)` - Add message
431
+ - `appendMessageBatch(entries)` - Atomically append a bounded source-order message/custom-message batch
383
432
  - `appendThinkingLevelChange(level)` - Record thinking change
384
433
  - `appendModelChange(provider, modelId)` - Record model change
385
434
  - `appendCompaction(summary, firstKeptEntryId, tokensBefore, details?, fromHook?)` - Add compaction
@@ -387,6 +436,10 @@ Key methods for working with sessions programmatically.
387
436
  - `appendSessionInfo(name)` - Set session display name
388
437
  - `appendCustomMessageEntry(customType, content, display, details?)` - Extension message (in context)
389
438
  - `appendLabelChange(targetId, label)` - Set/clear label
439
+ - `appendRequestSnapshot(snapshot)` - Force-flush a bounded accepted-request record
440
+ - `appendForegroundToolStarts(starts)` - Atomically reserve one prepared tool wave
441
+ - `appendForegroundToolTerminal(...)` - Link a started call to its canonical result
442
+ - `appendCompactionStart(...)` / `appendCompactionEnd(...)` - Bracket a compaction retry ladder
390
443
 
391
444
  ### Instance Methods - Tree Navigation
392
445
  - `getLeafId()` - Current position
@@ -402,6 +455,8 @@ Key methods for working with sessions programmatically.
402
455
 
403
456
  ### Instance Methods - Context & Info
404
457
  - `buildSessionContext()` - Get messages, thinkingLevel, and model for LLM
458
+ - `inspectSessionLifecycle()` - Validate the active branch lifecycle and classify incomplete work
459
+ - `planSessionLifecycleRepair()` - Produce a deterministic repair plan or a refusal with reasons
405
460
  - `getEntries()` - All entries (excluding header)
406
461
  - `getHeader()` - Session header metadata
407
462
  - `getSessionName()` - Get display name from latest session_info entry
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider",
3
- "version": "0.93.17",
3
+ "version": "0.93.19",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-custom-provider",
9
- "version": "0.93.17",
9
+ "version": "0.93.19",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.52.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "0.93.17",
4
+ "version": "0.93.19",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "0.93.17",
4
+ "version": "0.93.19",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
- "version": "0.93.17",
3
+ "version": "0.93.19",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-sandbox",
9
- "version": "0.93.17",
9
+ "version": "0.93.19",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sandbox-runtime": "^0.0.26"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
3
  "private": true,
4
- "version": "0.93.17",
4
+ "version": "0.93.19",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
- "version": "0.93.17",
3
+ "version": "0.93.19",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-with-deps",
9
- "version": "0.93.17",
9
+ "version": "0.93.19",
10
10
  "dependencies": {
11
11
  "ms": "^2.1.3"
12
12
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
3
  "private": true,
4
- "version": "0.93.17",
4
+ "version": "0.93.19",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@caupulican/pi-adaptative",
3
- "version": "0.93.17",
3
+ "version": "0.93.19",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@caupulican/pi-adaptative",
9
- "version": "0.93.17",
9
+ "version": "0.93.19",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@caupulican/pi-agent-core": "^0.93.17",
13
- "@caupulican/pi-ai": "^0.93.17",
14
- "@caupulican/pi-tui": "^0.93.17",
12
+ "@caupulican/pi-agent-core": "^0.93.19",
13
+ "@caupulican/pi-ai": "^0.93.19",
14
+ "@caupulican/pi-tui": "^0.93.19",
15
15
  "@silvia-odwyer/photon-node": "0.3.4",
16
16
  "chalk": "5.6.2",
17
17
  "cross-spawn": "7.0.6",
@@ -506,11 +506,11 @@
506
506
  }
507
507
  },
508
508
  "node_modules/@caupulican/pi-agent-core": {
509
- "version": "0.93.17",
510
- "resolved": "https://registry.npmjs.org/@caupulican/pi-agent-core/-/pi-agent-core-0.93.17.tgz",
509
+ "version": "0.93.19",
510
+ "resolved": "https://registry.npmjs.org/@caupulican/pi-agent-core/-/pi-agent-core-0.93.19.tgz",
511
511
  "license": "MIT",
512
512
  "dependencies": {
513
- "@caupulican/pi-ai": "^0.93.17",
513
+ "@caupulican/pi-ai": "^0.93.19",
514
514
  "ignore": "7.0.5",
515
515
  "typebox": "1.1.38",
516
516
  "yaml": "2.9.0"
@@ -520,8 +520,8 @@
520
520
  }
521
521
  },
522
522
  "node_modules/@caupulican/pi-ai": {
523
- "version": "0.93.17",
524
- "resolved": "https://registry.npmjs.org/@caupulican/pi-ai/-/pi-ai-0.93.17.tgz",
523
+ "version": "0.93.19",
524
+ "resolved": "https://registry.npmjs.org/@caupulican/pi-ai/-/pi-ai-0.93.19.tgz",
525
525
  "license": "MIT",
526
526
  "dependencies": {
527
527
  "@anthropic-ai/sdk": "0.117.1",
@@ -546,8 +546,8 @@
546
546
  }
547
547
  },
548
548
  "node_modules/@caupulican/pi-tui": {
549
- "version": "0.93.17",
550
- "resolved": "https://registry.npmjs.org/@caupulican/pi-tui/-/pi-tui-0.93.17.tgz",
549
+ "version": "0.93.19",
550
+ "resolved": "https://registry.npmjs.org/@caupulican/pi-tui/-/pi-tui-0.93.19.tgz",
551
551
  "license": "MIT",
552
552
  "dependencies": {
553
553
  "get-east-asian-width": "1.6.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caupulican/pi-adaptative",
3
- "version": "0.93.17",
3
+ "version": "0.93.19",
4
4
  "description": "Adaptive fork of Pi coding agent for self-evolving agent harness experiments",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -89,9 +89,9 @@
89
89
  "postinstall": "node scripts/postinstall-python-runtime.mjs"
90
90
  },
91
91
  "dependencies": {
92
- "@caupulican/pi-agent-core": "^0.93.17",
93
- "@caupulican/pi-ai": "^0.93.17",
94
- "@caupulican/pi-tui": "^0.93.17",
92
+ "@caupulican/pi-agent-core": "^0.93.19",
93
+ "@caupulican/pi-ai": "^0.93.19",
94
+ "@caupulican/pi-tui": "^0.93.19",
95
95
  "@silvia-odwyer/photon-node": "0.3.4",
96
96
  "chalk": "5.6.2",
97
97
  "cross-spawn": "7.0.6",