antechamber 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.
Files changed (59) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +24 -14
  3. package/bin/opencode-antechamber +14 -1
  4. package/bin/opencode-pi +11 -1
  5. package/dist/approvals.d.ts +4 -1
  6. package/dist/approvals.js +51 -33
  7. package/dist/catalog.d.ts +1 -1
  8. package/dist/catalog.js +1 -1
  9. package/dist/commands/context.d.ts +0 -1
  10. package/dist/commands/context.js +1 -1
  11. package/dist/commands/doctor.d.ts +3 -2
  12. package/dist/commands/serve.d.ts +2 -1
  13. package/dist/commands/setup.d.ts +2 -3
  14. package/dist/commands/setup.js +16 -4
  15. package/dist/http.d.ts +8 -1
  16. package/dist/http.js +42 -19
  17. package/dist/pi-event-translation.d.ts +10 -6
  18. package/dist/pi-event-translation.js +237 -80
  19. package/dist/pi-rpc.d.ts +20 -2
  20. package/dist/pi-rpc.js +96 -29
  21. package/dist/prompt-parts.d.ts +40 -0
  22. package/dist/prompt-parts.js +157 -0
  23. package/dist/route-services.d.ts +45 -2
  24. package/dist/route-services.js +70 -3
  25. package/dist/routes-v1.js +113 -65
  26. package/dist/routes-v2.js +407 -95
  27. package/dist/server.d.ts +9 -1
  28. package/dist/server.js +109 -9
  29. package/dist/session-commands.d.ts +12 -15
  30. package/dist/session-commands.js +54 -13
  31. package/dist/session-diff.d.ts +1 -1
  32. package/dist/session-diff.js +10 -2
  33. package/dist/session-history.d.ts +1 -1
  34. package/dist/session-history.js +110 -44
  35. package/dist/session-hosts.js +2 -2
  36. package/dist/session-store.d.ts +8 -4
  37. package/dist/session-store.js +191 -38
  38. package/dist/session-tree.d.ts +10 -2
  39. package/dist/session-tree.js +55 -26
  40. package/dist/sessions.d.ts +32 -5
  41. package/dist/sessions.js +331 -120
  42. package/dist/sse.d.ts +16 -6
  43. package/dist/sse.js +77 -21
  44. package/dist/subagents.d.ts +5 -0
  45. package/dist/subagents.js +84 -71
  46. package/dist/tool-map.d.ts +3 -2
  47. package/dist/types.d.ts +152 -1
  48. package/dist/v2.d.ts +18 -4
  49. package/dist/v2.js +128 -44
  50. package/dist/vcs.d.ts +5 -0
  51. package/dist/vcs.js +199 -0
  52. package/dist/version.d.ts +1 -1
  53. package/dist/version.js +1 -1
  54. package/extensions/omo-dag/README.md +2 -0
  55. package/extensions/omo-dag/docs/DESIGN.md +10 -1
  56. package/extensions/omo-dag/panel/index.html +1 -1
  57. package/extensions/omo-dag/panel/main.js +60 -60
  58. package/extensions/omo-dag/service/main.js +72 -8
  59. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { RPC_COMMAND_TIMEOUT_MS } from "./pi-rpc.js";
2
2
  import { readFileSync } from "node:fs";
3
+ import { contextMessageID, nativePromptInput } from "./prompt-parts.js";
3
4
  export class SessionTreeError extends Error {
4
5
  }
5
6
  export function durableShellTree(tree) {
@@ -59,19 +60,19 @@ export function branchEntries(tree, leafId = tree.leafId) {
59
60
  }
60
61
  return branch.reverse();
61
62
  }
62
- /** Live ids belong to the UI; restored ids belong to JSONL offsets. Save both. */
63
- export function bindMessageEntries(s, tree) {
63
+ function selectedLeafId(s, tree) {
64
64
  let leafId = tree.leafId;
65
65
  if (!s.tree.revert && s.tree.leafId !== undefined && s.tree.leafId !== null) {
66
66
  const selected = branchEntries(tree, s.tree.leafId);
67
67
  // A stale snapshot cannot discard a selection or its identity candidates.
68
68
  if (selected.length === 0)
69
- return;
69
+ return undefined;
70
70
  if (tree.leafId === null || selected.some((entry) => entry.id === tree.leafId))
71
71
  leafId = s.tree.leafId;
72
72
  }
73
- const branch = branchEntries(tree, s.tree.revert ? s.tree.revert.previousLeafId : leafId);
74
- const positions = new Map(branch.map((entry, index) => [entry.id, index]));
73
+ return leafId;
74
+ }
75
+ function pruneStaleShellTurns(s, positions) {
75
76
  s.tree.localShellTurns = (s.tree.localShellTurns ?? []).filter((turn) => {
76
77
  if (turn.afterEntryId === null || positions.has(turn.afterEntryId))
77
78
  return true;
@@ -83,13 +84,58 @@ export function bindMessageEntries(s, tree) {
83
84
  delete s.tree.shellDispatch[turn.messages[1].info.id];
84
85
  return false;
85
86
  });
87
+ }
88
+ function bindOrdinaryEntry(s, entry, messages, cursor) {
89
+ const content = entry.message?.content;
90
+ // pi allows plain-string message content (extensions, append_user_message).
91
+ const text = typeof content === "string"
92
+ ? content
93
+ : content
94
+ ?.filter((part) => part.type === "text")
95
+ .map((part) => part.text ?? "")
96
+ .join("");
97
+ const index = messages.findIndex((message, position) => position >= cursor &&
98
+ !s.localMessageIds?.has(message.info.id) &&
99
+ s.tree.messageEntries[message.info.id] === undefined &&
100
+ message.info.role === entry.message?.role &&
101
+ (message.info.role !== "user" ||
102
+ (s.tree.promptParts?.[message.info.id]
103
+ ? nativePromptInput(message.parts
104
+ .filter((part) => part.type === "text")
105
+ .map((part) => part.text)
106
+ .join("\n"), s.tree.promptParts[message.info.id] ?? []).message
107
+ : message.parts
108
+ .filter((part) => part.type === "text")
109
+ .map((part) => part.text)
110
+ .join("")) === text));
111
+ const message = messages[index];
112
+ if (message === undefined)
113
+ return cursor;
114
+ s.tree.messageEntries[message.info.id] = entry.id;
115
+ return index + 1;
116
+ }
117
+ /** Live ids belong to the UI; restored ids belong to JSONL offsets. Save both. */
118
+ export function bindMessageEntries(s, tree) {
119
+ const leafId = selectedLeafId(s, tree);
120
+ if (leafId === undefined)
121
+ return;
122
+ const branch = branchEntries(tree, s.tree.revert ? s.tree.revert.previousLeafId : leafId);
123
+ const positions = new Map(branch.map((entry, index) => [entry.id, index]));
124
+ pruneStaleShellTurns(s, positions);
125
+ // Admitted context carries its OpenChamber id in the native custom message.
126
+ for (const entry of branch) {
127
+ const messageID = contextMessageID(entry);
128
+ if (messageID !== undefined && s.messages?.some((message) => message.info.id === messageID))
129
+ s.tree.messageEntries[messageID] = entry.id;
130
+ }
86
131
  const entries = branch.filter((entry) => entry.type === "message" &&
87
132
  (entry.message?.role === "user" ||
88
133
  entry.message?.role === "assistant" ||
89
134
  entry.message?.role === "bashExecution"));
135
+ const localShellTurns = s.tree.localShellTurns ?? [];
90
136
  const visible = s.messages ?? [];
91
137
  const visibleIds = new Set(visible.map((message) => message.info.id));
92
- const candidates = s.tree.localShellTurns
138
+ const candidates = localShellTurns
93
139
  .flatMap((turn) => turn.messages)
94
140
  .filter((message) => !visibleIds.has(message.info.id));
95
141
  for (const message of candidates)
@@ -167,32 +213,15 @@ export function bindMessageEntries(s, tree) {
167
213
  }
168
214
  continue;
169
215
  }
170
- const text = entry.message?.content
171
- ?.filter((part) => part.type === "text")
172
- .map((part) => part.text ?? "")
173
- .join("");
174
- const index = messages.findIndex((message, i) => i >= cursor &&
175
- !s.localMessageIds?.has(message.info.id) &&
176
- s.tree.messageEntries[message.info.id] === undefined &&
177
- message.info.role === entry.message?.role &&
178
- (message.info.role !== "user" ||
179
- message.parts
180
- .filter((part) => part.type === "text")
181
- .map((part) => part.text)
182
- .join("") === text));
183
- const message = messages[index];
184
- if (message) {
185
- s.tree.messageEntries[message.info.id] = entry.id;
186
- cursor = index + 1;
187
- }
216
+ cursor = bindOrdinaryEntry(s, entry, messages, cursor);
188
217
  }
189
218
  // Syncs/agent events preserve an active revert's navigation pin. Only
190
219
  // revert/unrevert select it explicitly; prompt clears the pin before branching.
191
220
  if (!s.tree.revert)
192
221
  s.tree.leafId = leafId;
193
- s.tree.localShellTurns = s.tree.localShellTurns.filter((turn) => s.tree.messageEntries[turn.messages[1].info.id] === undefined);
222
+ s.tree.localShellTurns = localShellTurns.filter((turn) => s.tree.messageEntries[turn.messages[1].info.id] === undefined);
194
223
  }
195
- export function entryForMessage(s, tree, messageID) {
224
+ function entryForMessage(s, tree, messageID) {
196
225
  const entryId = s.tree.messageEntries[messageID];
197
226
  const entry = tree.entries.find((candidate) => candidate.id === entryId);
198
227
  if (!entry || !s.messages?.some((message) => message.info.id === messageID)) {
@@ -10,7 +10,7 @@ import type { TodoBridge, Todo, TodoUpdated } from "./todo-bridge.js";
10
10
  import { type SessionTreeState } from "./session-tree.js";
11
11
  import { SubagentBridge } from "./subagents.js";
12
12
  import { SessionStore, type TitleSource } from "./session-store.js";
13
- import type { OCAssistantMessage, OCEvent, OCMessageWithParts, OCModelRef, OCPart, OCSession, OCSessionStatus, OCToolPart } from "./types.js";
13
+ import type { OCAssistantMessage, OCEvent, OCMessageWithParts, OCModelRef, OCPart, OCPromptPart, OCSession, OCSessionStatus, OCToolPart } from "./types.js";
14
14
  export { ADAPTER_VERSION } from "./version.js";
15
15
  interface StreamingState {
16
16
  message: OCAssistantMessage;
@@ -18,6 +18,7 @@ interface StreamingState {
18
18
  parts: Map<number, OCPart>;
19
19
  }
20
20
  export interface ManagedSession extends ThinkingState {
21
+ interruptRequested?: boolean;
21
22
  titleSource?: TitleSource;
22
23
  activeUserMessageID?: string;
23
24
  inputs?: Map<string, {
@@ -42,6 +43,7 @@ export interface ManagedSession extends ThinkingState {
42
43
  streaming: StreamingState | undefined;
43
44
  /** A manual compaction started while idle; its end returns the session to idle. */
44
45
  compactingFromIdle?: boolean;
46
+ compactionID?: string;
45
47
  /** Cancels the adapter-owned user bash waiter and its OmO execution. */
46
48
  cancelShell?: (interrupted?: boolean) => void;
47
49
  /**
@@ -85,8 +87,14 @@ export declare class SessionManager {
85
87
  /** freshness of the all-directories scan (see listAll). */
86
88
  private scanAllCache;
87
89
  constructor(emit: EventSink, store?: SessionStore, defaultDirectory?: string | undefined, lifecycleOptions?: LifecycleOptions);
88
- create(directory: string, title?: string, parentID?: string): Promise<OCSession>;
90
+ create(directory: string, title?: string, parentID?: string, options?: {
91
+ id?: string;
92
+ agent?: string;
93
+ model?: ModelSelection;
94
+ metadata?: Record<string, unknown>;
95
+ }): Promise<OCSession>;
89
96
  private createLive;
97
+ private rollbackCreate;
90
98
  private applyNativeTitle;
91
99
  private refreshNativeTitles;
92
100
  private wirePi;
@@ -111,11 +119,15 @@ export declare class SessionManager {
111
119
  update(sessionId: string, patch: {
112
120
  title?: string | undefined;
113
121
  archived?: number | undefined;
114
- }): OCSession | undefined;
122
+ metadata?: Record<string, unknown> | undefined;
123
+ agent?: string | undefined;
124
+ }): Promise<OCSession | undefined>;
115
125
  messages(sessionId: string): OCMessageWithParts[] | undefined;
116
126
  /** Append to canonical history, before the hidden redo branch while reverted. */
117
127
  appendMessage(sessionId: string, message: OCMessageWithParts): void;
118
128
  private operation;
129
+ /** Cancellation releases only the caller; the native action keeps its queue lease. */
130
+ private waitForOperation;
119
131
  private syncTree;
120
132
  private treeSession;
121
133
  fork(sessionId: string, messageID?: string): Promise<OCSession>;
@@ -126,7 +138,13 @@ export declare class SessionManager {
126
138
  private reloadMessagesLive;
127
139
  statuses(): Record<string, OCSessionStatus>;
128
140
  todos(sessionId: string): Todo[] | undefined;
129
- diff(sessionId: string): Promise<import("./session-diff.js").SessionFileDiff[]>;
141
+ commitRevert(sessionId: string): Promise<void>;
142
+ private commitRevertLive;
143
+ diff(sessionId: string, options?: {
144
+ from?: string | undefined;
145
+ to?: string | undefined;
146
+ context?: number | undefined;
147
+ }): Promise<import("./session-diff.js").SessionFileDiff[]>;
130
148
  private emitDiff;
131
149
  abort(sessionId: string): Promise<boolean>;
132
150
  permissions(sessionId?: string): PendingPermission[];
@@ -149,8 +167,17 @@ export declare class SessionManager {
149
167
  * the next cold start, and tell the UI. Returns whether anything changed.
150
168
  */
151
169
  private applyPiModel;
152
- prompt(sessionId: string, text: string, model?: ModelSelection, noReply?: boolean, messageID?: string, delivery?: "steer" | "queue"): Promise<void>;
170
+ prompt(sessionId: string, text: string, model?: ModelSelection, noReply?: boolean, messageID?: string, delivery?: "steer" | "queue", parts?: readonly OCPromptPart[], metadata?: Record<string, unknown>): Promise<void>;
171
+ private preparePrompt;
172
+ private publishPrompt;
153
173
  private promptLive;
174
+ /**
175
+ * No-reply context (v2 synthetic, v1 noReply) joins the native conversation without a turn:
176
+ * OmO appends it now when idle, or after the running turn, so the next prompt carries it.
177
+ */
178
+ private admitContext;
179
+ private dispatchPrompt;
180
+ private bindPromptState;
154
181
  disposeAll(): Promise<void>;
155
182
  /** Spawn pi against the session's JSONL file and adopt it as live. */
156
183
  private revive;