@nexrall/code-core 1.4.76 → 1.4.78

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 (143) hide show
  1. package/dist/agent/effortCap.d.ts +24 -0
  2. package/dist/agent/effortCap.d.ts.map +1 -0
  3. package/dist/agent/effortCap.js +66 -0
  4. package/dist/agent/goal.d.ts +55 -0
  5. package/dist/agent/goal.d.ts.map +1 -0
  6. package/dist/agent/goal.js +120 -0
  7. package/dist/agent/handoffBrief.d.ts +82 -0
  8. package/dist/agent/handoffBrief.d.ts.map +1 -0
  9. package/dist/agent/handoffBrief.js +121 -0
  10. package/dist/agent/hooks.d.ts +10 -2
  11. package/dist/agent/hooks.d.ts.map +1 -1
  12. package/dist/agent/hooks.js +9 -3
  13. package/dist/agent/modelCatalogue.d.ts +23 -0
  14. package/dist/agent/modelCatalogue.d.ts.map +1 -1
  15. package/dist/agent/modelCatalogue.js +28 -0
  16. package/dist/agent/outputStyles.d.ts +27 -0
  17. package/dist/agent/outputStyles.d.ts.map +1 -0
  18. package/dist/agent/outputStyles.js +174 -0
  19. package/dist/agent/skills.d.ts.map +1 -1
  20. package/dist/agent/skills.js +21 -1
  21. package/dist/api/billingLines.d.ts +11 -0
  22. package/dist/api/billingLines.d.ts.map +1 -0
  23. package/dist/api/billingLines.js +56 -0
  24. package/dist/api/client.d.ts +2 -0
  25. package/dist/api/client.d.ts.map +1 -1
  26. package/dist/api/scheduleLines.d.ts +53 -0
  27. package/dist/api/scheduleLines.d.ts.map +1 -0
  28. package/dist/api/scheduleLines.js +150 -0
  29. package/dist/context/contextFiles.d.ts +81 -0
  30. package/dist/context/contextFiles.d.ts.map +1 -0
  31. package/dist/context/contextFiles.js +310 -0
  32. package/dist/diff/collect.d.ts +25 -0
  33. package/dist/diff/collect.d.ts.map +1 -0
  34. package/dist/diff/collect.js +169 -0
  35. package/dist/diff/diffView.d.ts +57 -0
  36. package/dist/diff/diffView.d.ts.map +1 -0
  37. package/dist/diff/diffView.js +231 -0
  38. package/dist/diff/reviewQueue.d.ts +53 -0
  39. package/dist/diff/reviewQueue.d.ts.map +1 -0
  40. package/dist/diff/reviewQueue.js +349 -0
  41. package/dist/events/recap.d.ts +54 -0
  42. package/dist/events/recap.d.ts.map +1 -0
  43. package/dist/events/recap.js +161 -0
  44. package/dist/events/sessionEvents.d.ts +54 -0
  45. package/dist/events/sessionEvents.d.ts.map +1 -0
  46. package/dist/events/sessionEvents.js +324 -0
  47. package/dist/events/sessionStats.d.ts +89 -0
  48. package/dist/events/sessionStats.d.ts.map +1 -0
  49. package/dist/events/sessionStats.js +264 -0
  50. package/dist/import/claudeImport.d.ts +44 -0
  51. package/dist/import/claudeImport.d.ts.map +1 -0
  52. package/dist/import/claudeImport.js +337 -0
  53. package/dist/index.d.ts +38 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +38 -0
  56. package/dist/mcp/manager.d.ts +8 -0
  57. package/dist/mcp/manager.d.ts.map +1 -1
  58. package/dist/mcp/manager.js +64 -57
  59. package/dist/permissions/destructiveTokens.d.ts +1 -0
  60. package/dist/permissions/destructiveTokens.d.ts.map +1 -1
  61. package/dist/permissions/destructiveTokens.js +93 -0
  62. package/dist/permissions/rules.d.ts +12 -0
  63. package/dist/permissions/rules.d.ts.map +1 -1
  64. package/dist/permissions/rules.js +89 -7
  65. package/dist/plugins/configStore.d.ts +43 -0
  66. package/dist/plugins/configStore.d.ts.map +1 -0
  67. package/dist/plugins/configStore.js +253 -0
  68. package/dist/plugins/files.d.ts +10 -0
  69. package/dist/plugins/files.d.ts.map +1 -0
  70. package/dist/plugins/files.js +85 -0
  71. package/dist/plugins/index.d.ts +3 -22
  72. package/dist/plugins/index.d.ts.map +1 -1
  73. package/dist/plugins/index.js +30 -40
  74. package/dist/plugins/resolve.d.ts +18 -0
  75. package/dist/plugins/resolve.d.ts.map +1 -0
  76. package/dist/plugins/resolve.js +152 -0
  77. package/dist/plugins/userConfig.d.ts +90 -0
  78. package/dist/plugins/userConfig.d.ts.map +1 -0
  79. package/dist/plugins/userConfig.js +332 -0
  80. package/dist/plugins/validate.d.ts +14 -0
  81. package/dist/plugins/validate.d.ts.map +1 -0
  82. package/dist/plugins/validate.js +222 -0
  83. package/dist/project/projectCommands.d.ts +33 -0
  84. package/dist/project/projectCommands.d.ts.map +1 -0
  85. package/dist/project/projectCommands.js +246 -0
  86. package/dist/search/conversationTurns.d.ts +53 -0
  87. package/dist/search/conversationTurns.d.ts.map +1 -0
  88. package/dist/search/conversationTurns.js +170 -0
  89. package/dist/search/globalSearch.d.ts +144 -0
  90. package/dist/search/globalSearch.d.ts.map +1 -0
  91. package/dist/search/globalSearch.js +350 -0
  92. package/dist/share/sessionChannel.d.ts +136 -0
  93. package/dist/share/sessionChannel.d.ts.map +1 -0
  94. package/dist/share/sessionChannel.js +373 -0
  95. package/dist/share/sessionShare.d.ts +104 -0
  96. package/dist/share/sessionShare.d.ts.map +1 -0
  97. package/dist/share/sessionShare.js +336 -0
  98. package/dist/ui/configCmd.d.ts +48 -0
  99. package/dist/ui/configCmd.d.ts.map +1 -0
  100. package/dist/ui/configCmd.js +146 -0
  101. package/dist/ui/deployPanel.d.ts +91 -0
  102. package/dist/ui/deployPanel.d.ts.map +1 -0
  103. package/dist/ui/deployPanel.js +442 -0
  104. package/dist/ui/mergeAssistant.d.ts +120 -0
  105. package/dist/ui/mergeAssistant.d.ts.map +1 -0
  106. package/dist/ui/mergeAssistant.js +391 -0
  107. package/dist/ui/notify.d.ts +114 -0
  108. package/dist/ui/notify.d.ts.map +1 -0
  109. package/dist/ui/notify.js +235 -0
  110. package/dist/ui/promptSuggest.d.ts +56 -0
  111. package/dist/ui/promptSuggest.d.ts.map +1 -0
  112. package/dist/ui/promptSuggest.js +160 -0
  113. package/dist/ui/taskGraph.d.ts +44 -0
  114. package/dist/ui/taskGraph.d.ts.map +1 -0
  115. package/dist/ui/taskGraph.js +289 -0
  116. package/dist/util/addDir.d.ts +31 -0
  117. package/dist/util/addDir.d.ts.map +1 -0
  118. package/dist/util/addDir.js +124 -0
  119. package/dist/util/batch.d.ts +16 -0
  120. package/dist/util/batch.d.ts.map +1 -0
  121. package/dist/util/batch.js +92 -0
  122. package/dist/util/cellWidth.d.ts +12 -0
  123. package/dist/util/cellWidth.d.ts.map +1 -0
  124. package/dist/util/cellWidth.js +161 -0
  125. package/dist/util/duration.d.ts +8 -0
  126. package/dist/util/duration.d.ts.map +1 -0
  127. package/dist/util/duration.js +50 -0
  128. package/dist/util/loopJobs.d.ts +67 -0
  129. package/dist/util/loopJobs.d.ts.map +1 -0
  130. package/dist/util/loopJobs.js +169 -0
  131. package/dist/util/settingsFile.d.ts +14 -0
  132. package/dist/util/settingsFile.d.ts.map +1 -0
  133. package/dist/util/settingsFile.js +99 -0
  134. package/dist/util/toolLabel.d.ts +2 -0
  135. package/dist/util/toolLabel.d.ts.map +1 -0
  136. package/dist/util/toolLabel.js +17 -0
  137. package/dist/verify/failureTimeline.d.ts +100 -0
  138. package/dist/verify/failureTimeline.d.ts.map +1 -0
  139. package/dist/verify/failureTimeline.js +253 -0
  140. package/dist/verify/verification.d.ts +75 -0
  141. package/dist/verify/verification.d.ts.map +1 -0
  142. package/dist/verify/verification.js +315 -0
  143. package/package.json +5 -4
@@ -0,0 +1,136 @@
1
+ import type { ShareIoFactory, ShareStatus } from './sessionShare';
2
+ /** One pushed message, as it came off the wire (already shape-checked). */
3
+ export interface ChannelMessage {
4
+ nonce: string;
5
+ source: string;
6
+ text: string;
7
+ ts: number;
8
+ }
9
+ /** `ask` holds pushes for a human verdict; `auto` delivers them on arrival. */
10
+ export type ChannelPolicy = 'ask' | 'auto';
11
+ /** What the module reports for the terminal to render — data, not prose. */
12
+ export type ChannelNotice = {
13
+ kind: 'queued';
14
+ msg: ChannelMessage;
15
+ position: number;
16
+ } | {
17
+ kind: 'delivered';
18
+ msg: ChannelMessage;
19
+ auto: boolean;
20
+ folded: boolean;
21
+ } | {
22
+ kind: 'discarded';
23
+ msg: ChannelMessage;
24
+ } | {
25
+ kind: 'dropped';
26
+ msg: ChannelMessage;
27
+ reason: 'queue_full';
28
+ };
29
+ export interface SessionChannelDeps {
30
+ /** Origin of the platform API — the Socket.IO server shares the host. */
31
+ url: string;
32
+ sessionId: string;
33
+ /** Called before EVERY (re)connect attempt, so a rotated token is picked up. */
34
+ tokenProvider: () => string | null;
35
+ /** Called once after an auth-shaped connect error, like the share half. */
36
+ refreshToken?: () => Promise<boolean>;
37
+ ioFactory?: ShareIoFactory;
38
+ onStatus?: (s: ShareStatus) => void;
39
+ onNotice?: (n: ChannelNotice) => void;
40
+ /**
41
+ * Deliver an accepted (or auto) message: `formatted` is what the model sees.
42
+ * Returns `queued` when the message was folded into a running turn instead
43
+ * of starting one (the REPL's busy path) — reported to watchers verbatim.
44
+ */
45
+ onDeliver?: (formatted: string, msg: ChannelMessage) => 'accepted' | 'queued' | void;
46
+ /** Test seam — the only reason a token is not always crypto-random. */
47
+ mintToken?: () => string;
48
+ }
49
+ /** Token shape the CLI mints and the relay/route only ever hash. */
50
+ export declare const CHANNEL_TOKEN_PREFIX = "nxch_";
51
+ /** More undecided pushes than this and new ones are refused, not queued — an
52
+ * external source must not be able to bury the one message a human needs. */
53
+ export declare const CHANNEL_QUEUE_CAP = 10;
54
+ /** Matches the relay's and the route's own cap (defense in depth). */
55
+ export declare const CHANNEL_TEXT_MAX_CHARS = 8192;
56
+ /** S13c: what a source may read back — one turn's closing text, same bound. */
57
+ export declare const CHANNEL_REPLY_MAX_CHARS = 8192;
58
+ export declare function hashChannelToken(token: string): string;
59
+ /**
60
+ * The push endpoint for a session. Built here so the CLI prints exactly the
61
+ * URL the route serves — one string, one place.
62
+ */
63
+ export declare function channelPushUrl(id: string, url: string): string;
64
+ /**
65
+ * Escape `<` so a hostile push cannot close the wrapper tag early; `&` and
66
+ * `>` stay readable because CI URLs are the common case and the model reads
67
+ * this text, not an XML parser.
68
+ */
69
+ export declare function escapeChannelText(text: string): string;
70
+ /**
71
+ * What the conversation receives. Same `<channel source=…>` shape Claude Code
72
+ * documents for its own channels, so prompts and habits built for one read
73
+ * the same here — and it can never parse as a slash command.
74
+ */
75
+ export declare function formatChannelEvent(msg: ChannelMessage): string;
76
+ export declare class SessionChannel {
77
+ private readonly deps;
78
+ private socket;
79
+ private id;
80
+ private status;
81
+ private stopped;
82
+ private refreshing;
83
+ private policy;
84
+ private queue;
85
+ private seenNonces;
86
+ /** S13c: nonces delivered but not yet answered by a finished turn. */
87
+ private awaitingReply;
88
+ /** Minted once per open; rotated by a re-open after /channel close. */
89
+ private token;
90
+ private tokenHash;
91
+ constructor(deps: SessionChannelDeps);
92
+ get sessionId(): string;
93
+ get state(): ShareStatus;
94
+ get activePolicy(): ChannelPolicy;
95
+ /** The push URL a human pastes into CI; the token is NOT part of it. */
96
+ get pushUrl(): string;
97
+ /** Shown once by `/channel open` — memory only, never persisted anywhere. */
98
+ get rawToken(): string | null;
99
+ /** Pending pushes, oldest first. A copy: callers cannot mutate the queue. */
100
+ pending(): ChannelMessage[];
101
+ start(policy?: ChannelPolicy): this;
102
+ /** Switch policy — `auto` drains whatever is already queued, oldest first. */
103
+ setPolicy(policy: ChannelPolicy): ChannelPolicy;
104
+ /** Accept (deliver) one pending push — 1-based `index`, default the oldest. */
105
+ accept(index?: number): ChannelMessage | null;
106
+ /** Refuse one pending push — same indexing as accept. */
107
+ discard(index?: number): ChannelMessage | null;
108
+ /** /clear and /fork: a rebind reuses the token for the new session id. */
109
+ rebind(id: string): void;
110
+ stop(reason?: string): void;
111
+ private take;
112
+ private deliver;
113
+ /**
114
+ * S13c — close the loop: hand every delivered-but-unanswered push the
115
+ * closing text of the turn that consumed it (chat.ts calls this when a turn
116
+ * ends; `null`/blank means the turn said nothing useful, which is reported
117
+ * as an EXPLICIT no-text marker rather than silence). Frames are keyed by
118
+ * nonce and stored by the relay, readable only with the channel token.
119
+ * Returns how many nonces were answered.
120
+ */
121
+ publishReplies(reply: string | null, opts?: {
122
+ interrupted?: boolean;
123
+ }): number;
124
+ /** Shape-check a pushed frame — the relay is a pipe, delivery trusts nothing. */
125
+ private validateMessage;
126
+ private ack;
127
+ private notice;
128
+ private emitOpen;
129
+ private emitTo;
130
+ private setStatus;
131
+ }
132
+ export declare function startSessionChannel(deps: SessionChannelDeps, policy?: ChannelPolicy): SessionChannel;
133
+ export declare function activeSessionChannel(): SessionChannel | null;
134
+ export declare function rebindSessionChannel(id: string): void;
135
+ export declare function stopSessionChannel(reason?: string): void;
136
+ //# sourceMappingURL=sessionChannel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionChannel.d.ts","sourceRoot":"","sources":["../../src/share/sessionChannel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,373 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionChannel = exports.CHANNEL_REPLY_MAX_CHARS = exports.CHANNEL_TEXT_MAX_CHARS = exports.CHANNEL_QUEUE_CAP = exports.CHANNEL_TOKEN_PREFIX = void 0;
4
+ exports.hashChannelToken = hashChannelToken;
5
+ exports.channelPushUrl = channelPushUrl;
6
+ exports.escapeChannelText = escapeChannelText;
7
+ exports.formatChannelEvent = formatChannelEvent;
8
+ exports.startSessionChannel = startSessionChannel;
9
+ exports.activeSessionChannel = activeSessionChannel;
10
+ exports.rebindSessionChannel = rebindSessionChannel;
11
+ exports.stopSessionChannel = stopSessionChannel;
12
+ // Lives in core (moved from the CLI's ui/sessionChannel.ts, 2026-10-05) so the
13
+ // VS Code panel opens the same inbound door with the same policy rules; the CLI
14
+ // module is a re-export shim. The singleton helpers are for the one-REPL CLI;
15
+ // the panel instantiates SessionChannel directly, one per chat tab.
16
+ // S13 — channels: the INBOUND door into a live session. An external source
17
+ // (CI, a webhook, a script, a chat bridge) pushes a message through the
18
+ // platform relay (POST /api/cli-sessions/<id>/push on the api-server) and this
19
+ // module is the terminal half: it opens the door when asked, receives pushed
20
+ // frames, and LEAVES THE POLICY TO THE TERMINAL — default `ask`, where a push
21
+ // waits for the person at the keyboard to accept it; `auto` for hands-off
22
+ // monitoring, an explicit per-session choice.
23
+ //
24
+ // Invariants, mirroring sessionShare.ts:
25
+ // · never throws and never breaks the REPL — a malformed frame is dropped.
26
+ // · default OFF: nothing is reachable until `/channel open` mints a token.
27
+ // · the raw token NEVER leaves the process — only its sha256 goes to the
28
+ // relay (relay: cli:channel-open), and the push route re-hashes the header
29
+ // it receives; a leaked relay store therefore leaks nothing usable.
30
+ // · a received message can never run a command or answer a prompt BY ITSELF:
31
+ // delivery is the caller's job (chat.ts injects a wrapped <channel> line),
32
+ // and the relay/route never inject anything.
33
+ // · the door dies with the process: stop() and disconnect both make the
34
+ // server-side mapping vanish, and the push route 404s from that moment.
35
+ const node_crypto_1 = require("node:crypto");
36
+ const socket_io_client_1 = require("socket.io-client");
37
+ /** Token shape the CLI mints and the relay/route only ever hash. */
38
+ exports.CHANNEL_TOKEN_PREFIX = 'nxch_';
39
+ /** More undecided pushes than this and new ones are refused, not queued — an
40
+ * external source must not be able to bury the one message a human needs. */
41
+ exports.CHANNEL_QUEUE_CAP = 10;
42
+ /** Matches the relay's and the route's own cap (defense in depth). */
43
+ exports.CHANNEL_TEXT_MAX_CHARS = 8192;
44
+ /** S13c: what a source may read back — one turn's closing text, same bound. */
45
+ exports.CHANNEL_REPLY_MAX_CHARS = 8192;
46
+ /** Bounded nonce memory for duplicate suppression across reconnects. */
47
+ const SEEN_NONCE_CAP = 512;
48
+ /** Delivered pushes awaiting a reply; past this the oldest stop being tracked
49
+ * (they are not owed an answer forever — the door answers what it can). */
50
+ const AWAITING_REPLY_CAP = 64;
51
+ const NONCE_RE = /^[a-f0-9]{16}$/;
52
+ const SOURCE_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$/;
53
+ function defaultMintToken() {
54
+ return exports.CHANNEL_TOKEN_PREFIX + (0, node_crypto_1.randomBytes)(24).toString('base64url');
55
+ }
56
+ function hashChannelToken(token) {
57
+ return (0, node_crypto_1.createHash)('sha256').update(token).digest('hex');
58
+ }
59
+ /**
60
+ * The push endpoint for a session. Built here so the CLI prints exactly the
61
+ * URL the route serves — one string, one place.
62
+ */
63
+ function channelPushUrl(id, url) {
64
+ return `${url.replace(/\/+$/, '')}/api/cli-sessions/${encodeURIComponent(id)}/push`;
65
+ }
66
+ /**
67
+ * Escape `<` so a hostile push cannot close the wrapper tag early; `&` and
68
+ * `>` stay readable because CI URLs are the common case and the model reads
69
+ * this text, not an XML parser.
70
+ */
71
+ function escapeChannelText(text) {
72
+ return text.replace(/</g, '&lt;');
73
+ }
74
+ /**
75
+ * What the conversation receives. Same `<channel source=…>` shape Claude Code
76
+ * documents for its own channels, so prompts and habits built for one read
77
+ * the same here — and it can never parse as a slash command.
78
+ */
79
+ function formatChannelEvent(msg) {
80
+ return `<channel source="${msg.source}" ts="${new Date(msg.ts).toISOString()}">\n${escapeChannelText(msg.text)}\n</channel>`;
81
+ }
82
+ const defaultFactory = (url, opts) => (0, socket_io_client_1.io)(url, opts);
83
+ class SessionChannel {
84
+ constructor(deps) {
85
+ this.deps = deps;
86
+ this.socket = null;
87
+ this.status = { state: 'connecting' };
88
+ this.stopped = false;
89
+ this.refreshing = false;
90
+ this.policy = 'ask';
91
+ this.queue = [];
92
+ this.seenNonces = new Set();
93
+ /** S13c: nonces delivered but not yet answered by a finished turn. */
94
+ this.awaitingReply = new Set();
95
+ /** Minted once per open; rotated by a re-open after /channel close. */
96
+ this.token = null;
97
+ this.tokenHash = null;
98
+ this.id = deps.sessionId;
99
+ }
100
+ get sessionId() {
101
+ return this.id;
102
+ }
103
+ get state() {
104
+ return this.status;
105
+ }
106
+ get activePolicy() {
107
+ return this.policy;
108
+ }
109
+ /** The push URL a human pastes into CI; the token is NOT part of it. */
110
+ get pushUrl() {
111
+ return channelPushUrl(this.id, this.deps.url);
112
+ }
113
+ /** Shown once by `/channel open` — memory only, never persisted anywhere. */
114
+ get rawToken() {
115
+ return this.token;
116
+ }
117
+ /** Pending pushes, oldest first. A copy: callers cannot mutate the queue. */
118
+ pending() {
119
+ return [...this.queue];
120
+ }
121
+ start(policy = 'ask') {
122
+ const mint = this.deps.mintToken ?? defaultMintToken;
123
+ this.token = mint();
124
+ this.tokenHash = hashChannelToken(this.token);
125
+ this.policy = policy;
126
+ const factory = this.deps.ioFactory ?? defaultFactory;
127
+ const socket = factory(this.deps.url, {
128
+ path: '/socket.io',
129
+ transports: ['websocket'],
130
+ autoUnref: true,
131
+ reconnection: true,
132
+ reconnectionDelay: 1000,
133
+ reconnectionDelayMax: 15000,
134
+ timeout: 10000,
135
+ auth: (cb) => {
136
+ cb({ token: this.deps.tokenProvider() ?? '' });
137
+ },
138
+ });
139
+ this.socket = socket;
140
+ socket.on('connect', () => {
141
+ if (this.stopped)
142
+ return; // a late reconnect after stop must not resurrect the door
143
+ this.setStatus({ state: 'live' });
144
+ // Re-sent on every (re)connect: the mapping is refreshed, and after a
145
+ // blip the door re-opens without the user doing anything.
146
+ this.emitOpen();
147
+ });
148
+ socket.on('disconnect', (reason) => {
149
+ if (!this.stopped)
150
+ this.setStatus({ state: 'offline', detail: String(reason ?? 'disconnected') });
151
+ });
152
+ socket.on('connect_error', (err) => {
153
+ const detail = err?.message ?? 'connect error';
154
+ this.setStatus({ state: 'offline', detail });
155
+ if (this.deps.refreshToken && !this.refreshing && /invalid|expired/i.test(detail)) {
156
+ this.refreshing = true;
157
+ void this.deps
158
+ .refreshToken()
159
+ .catch(() => { })
160
+ .finally(() => {
161
+ this.refreshing = false;
162
+ });
163
+ }
164
+ });
165
+ socket.on('cli:channel-message', (payload) => {
166
+ if (this.stopped)
167
+ return; // an in-flight frame between emit(close) and disconnect
168
+ const msg = this.validateMessage(payload);
169
+ if (!msg)
170
+ return;
171
+ if (this.seenNonces.has(msg.nonce))
172
+ return; // reconnect overlap: one delivery
173
+ if (this.seenNonces.size >= SEEN_NONCE_CAP) {
174
+ this.seenNonces.delete(this.seenNonces.values().next().value);
175
+ }
176
+ this.seenNonces.add(msg.nonce);
177
+ if (this.policy === 'auto') {
178
+ this.deliver(msg, true);
179
+ return;
180
+ }
181
+ if (this.queue.length >= exports.CHANNEL_QUEUE_CAP) {
182
+ this.notice({ kind: 'dropped', msg, reason: 'queue_full' });
183
+ this.ack(msg, 'discarded');
184
+ return;
185
+ }
186
+ this.queue.push(msg);
187
+ this.notice({ kind: 'queued', msg, position: this.queue.length });
188
+ this.ack(msg, 'queued');
189
+ });
190
+ return this;
191
+ }
192
+ /** Switch policy — `auto` drains whatever is already queued, oldest first. */
193
+ setPolicy(policy) {
194
+ if (this.stopped)
195
+ return this.policy;
196
+ this.policy = policy;
197
+ if (policy === 'auto') {
198
+ const queued = this.queue.splice(0);
199
+ for (const msg of queued)
200
+ this.deliver(msg, true);
201
+ }
202
+ return this.policy;
203
+ }
204
+ /** Accept (deliver) one pending push — 1-based `index`, default the oldest. */
205
+ accept(index) {
206
+ const msg = this.take(index);
207
+ if (!msg)
208
+ return null;
209
+ this.deliver(msg, false);
210
+ return msg;
211
+ }
212
+ /** Refuse one pending push — same indexing as accept. */
213
+ discard(index) {
214
+ const msg = this.take(index);
215
+ if (!msg)
216
+ return null;
217
+ this.notice({ kind: 'discarded', msg });
218
+ this.ack(msg, 'discarded');
219
+ return msg;
220
+ }
221
+ /** /clear and /fork: a rebind reuses the token for the new session id. */
222
+ rebind(id) {
223
+ if (this.stopped || !id || id === this.id)
224
+ return;
225
+ this.id = id;
226
+ // The relay stores the SAME hash under the new session id (one mapping
227
+ // key), so a push for the old id starts 404ing and the new id works.
228
+ if (this.socket?.connected)
229
+ this.emitOpen();
230
+ }
231
+ stop(reason = 'closed') {
232
+ if (this.stopped)
233
+ return;
234
+ this.stopped = true;
235
+ this.queue = [];
236
+ // S13c: unanswered pushes die with the door — the token that could read
237
+ // the results is being revoked in the same breath.
238
+ this.awaitingReply.clear();
239
+ if (this.socket?.connected)
240
+ this.emitTo('cli:channel-close', { id: this.id, reason });
241
+ this.token = null;
242
+ this.tokenHash = null;
243
+ try {
244
+ this.socket?.disconnect();
245
+ }
246
+ catch {
247
+ /* closing anyway */
248
+ }
249
+ this.setStatus({ state: 'stopped' });
250
+ }
251
+ take(index) {
252
+ if (this.stopped || this.queue.length === 0)
253
+ return null;
254
+ const at = index === undefined ? 0 : Math.min(Math.max(1, index), this.queue.length) - 1;
255
+ const [msg] = this.queue.splice(at, 1);
256
+ return msg ?? null;
257
+ }
258
+ deliver(msg, auto) {
259
+ let verdict = 'accepted';
260
+ try {
261
+ verdict = this.deps.onDeliver?.(formatChannelEvent(msg), msg) ?? 'accepted';
262
+ }
263
+ catch {
264
+ /* the REPL survives any frame */
265
+ }
266
+ this.notice({ kind: 'delivered', msg, auto, folded: verdict === 'queued' });
267
+ this.ack(msg, verdict);
268
+ // S13c: the message is now the conversation's problem — whatever the turn
269
+ // that consumed it ends up saying is owed back to the source.
270
+ if (this.awaitingReply.size >= AWAITING_REPLY_CAP) {
271
+ this.awaitingReply.delete(this.awaitingReply.values().next().value);
272
+ }
273
+ this.awaitingReply.add(msg.nonce);
274
+ }
275
+ /**
276
+ * S13c — close the loop: hand every delivered-but-unanswered push the
277
+ * closing text of the turn that consumed it (chat.ts calls this when a turn
278
+ * ends; `null`/blank means the turn said nothing useful, which is reported
279
+ * as an EXPLICIT no-text marker rather than silence). Frames are keyed by
280
+ * nonce and stored by the relay, readable only with the channel token.
281
+ * Returns how many nonces were answered.
282
+ */
283
+ publishReplies(reply, opts = {}) {
284
+ if (this.stopped || this.awaitingReply.size === 0)
285
+ return 0;
286
+ const text = (reply ?? '').trim();
287
+ let body;
288
+ if (!text)
289
+ body = { noText: true };
290
+ else if (text.length > exports.CHANNEL_REPLY_MAX_CHARS) {
291
+ body = { reply: text.slice(0, exports.CHANNEL_REPLY_MAX_CHARS), truncated: true };
292
+ }
293
+ else
294
+ body = { reply: text };
295
+ if (opts.interrupted)
296
+ body.interrupted = true;
297
+ let answered = 0;
298
+ for (const nonce of this.awaitingReply) {
299
+ this.emitTo('cli:channel-result', { id: this.id, nonce, ...body });
300
+ answered += 1;
301
+ }
302
+ this.awaitingReply.clear();
303
+ return answered;
304
+ }
305
+ /** Shape-check a pushed frame — the relay is a pipe, delivery trusts nothing. */
306
+ validateMessage(payload) {
307
+ const p = payload;
308
+ if (!p || typeof p !== 'object' || p.id !== this.id)
309
+ return null;
310
+ if (typeof p.nonce !== 'string' || !NONCE_RE.test(p.nonce))
311
+ return null;
312
+ if (typeof p.text !== 'string' || !p.text.trim() || p.text.length > exports.CHANNEL_TEXT_MAX_CHARS)
313
+ return null;
314
+ const source = typeof p.source === 'string' && SOURCE_RE.test(p.source) ? p.source : 'channel';
315
+ const ts = typeof p.ts === 'number' && Number.isFinite(p.ts) ? p.ts : Date.now();
316
+ return { nonce: p.nonce, source, text: p.text, ts };
317
+ }
318
+ ack(msg, status) {
319
+ this.emitTo('cli:channel-ack', { id: this.id, nonce: msg.nonce, status });
320
+ }
321
+ notice(n) {
322
+ try {
323
+ this.deps.onNotice?.(n);
324
+ }
325
+ catch {
326
+ /* notices are cosmetic */
327
+ }
328
+ }
329
+ emitOpen() {
330
+ if (!this.tokenHash)
331
+ return;
332
+ this.emitTo('cli:channel-open', { id: this.id, tokenHash: this.tokenHash });
333
+ }
334
+ emitTo(event, payload) {
335
+ try {
336
+ this.socket?.emit(event, payload);
337
+ }
338
+ catch {
339
+ /* the door must never break the REPL */
340
+ }
341
+ }
342
+ setStatus(next) {
343
+ const same = next.state === this.status.state && next.detail === this.status.detail;
344
+ this.status = next;
345
+ if (!same) {
346
+ try {
347
+ this.deps.onStatus?.(next);
348
+ }
349
+ catch {
350
+ /* status is cosmetic */
351
+ }
352
+ }
353
+ }
354
+ }
355
+ exports.SessionChannel = SessionChannel;
356
+ // ─── The one channel a REPL can have ──────────────────────────────────────────
357
+ let current = null;
358
+ function startSessionChannel(deps, policy = 'ask') {
359
+ current?.stop('replaced');
360
+ current = new SessionChannel(deps).start(policy);
361
+ return current;
362
+ }
363
+ function activeSessionChannel() {
364
+ return current;
365
+ }
366
+ function rebindSessionChannel(id) {
367
+ current?.rebind(id);
368
+ }
369
+ function stopSessionChannel(reason = 'closed') {
370
+ current?.stop(reason);
371
+ current = null;
372
+ }
373
+ //# sourceMappingURL=sessionChannel.js.map
@@ -0,0 +1,104 @@
1
+ import { type SessionEvent } from '../events/sessionEvents';
2
+ /** The slice of a Socket.IO socket this module uses — small enough to fake in tests. */
3
+ export interface ShareSocket {
4
+ readonly connected: boolean;
5
+ on(event: string, handler: (...args: unknown[]) => void): unknown;
6
+ emit(event: string, payload?: unknown): void;
7
+ disconnect(): void;
8
+ }
9
+ export type ShareIoFactory = (url: string, opts: Record<string, unknown>) => ShareSocket;
10
+ export interface ShareStatus {
11
+ state: 'connecting' | 'live' | 'offline' | 'stopped';
12
+ detail?: string;
13
+ }
14
+ export interface SessionShareDeps {
15
+ /** Origin of the platform API — the Socket.IO server shares the host, path /socket.io. */
16
+ url: string;
17
+ sessionId: string;
18
+ /** Computed fresh at every hello: the model (and branch) can change mid-session. */
19
+ meta: () => Record<string, unknown>;
20
+ /** Called before EVERY (re)connect attempt, so a rotated token is picked up. */
21
+ tokenProvider: () => string | null;
22
+ /** Called once after an auth-shaped connect error (an access token that expired mid-session). */
23
+ refreshToken?: () => Promise<boolean>;
24
+ /** Tail of the local JSONL, oldest → newest. Defaults to readEvents(id, {last: PULL_LIMIT}). */
25
+ recent?: (id: string) => SessionEvent[];
26
+ ioFactory?: ShareIoFactory;
27
+ onStatus?: (s: ShareStatus) => void;
28
+ /** §93 S12b: a line the WEB typed, delivered only while drive is on. */
29
+ onRemoteText?: (text: string) => void;
30
+ /** §93 S12b: the web's answer to the pending permission prompt (drive on only). */
31
+ onRemoteAnswer?: (requestId: string, answer: 'y' | 'n') => void;
32
+ }
33
+ /** Frames pushed when a viewer attaches — enough context to see what the session has been doing. */
34
+ export declare const PULL_LIMIT = 200;
35
+ /** Frames re-pushed after a reconnect, to fill the hole the outage left in watching clients. */
36
+ export declare const RECONNECT_FILL = 50;
37
+ /** Bound on a remote input line; matches the relay's own cap (defense in depth). */
38
+ export declare const MAX_REMOTE_INPUT_CHARS = 8192;
39
+ /** §93 S12b: the web's feedback line for one remote frame (accepted / queued / refused / stale). */
40
+ export interface RemoteNoteFrame {
41
+ kind: 'input' | 'answer';
42
+ status: 'accepted' | 'queued' | 'refused' | 'stale';
43
+ reason?: string;
44
+ text?: string;
45
+ requestId?: string;
46
+ }
47
+ /** Where the relay lives. Overridable so a dev stack never needs production. */
48
+ export declare function shareServerUrl(env?: NodeJS.ProcessEnv): string;
49
+ /** The link a human opens to watch — the CLI prints this, nothing else constructs it. */
50
+ export declare function webLiveUrl(id: string, env?: NodeJS.ProcessEnv): string;
51
+ export declare class SessionShare {
52
+ private readonly deps;
53
+ private socket;
54
+ private id;
55
+ private status;
56
+ /** A second connect means the first one dropped: heal the hole for watchers. */
57
+ private everConnected;
58
+ private refreshing;
59
+ private stopped;
60
+ /** §93 S12b: remote driving — the terminal's switch, off until /share drive on. */
61
+ private drive;
62
+ /** §93 S12b: the permission prompt currently open in this terminal (null: none). */
63
+ private pendingPermission;
64
+ constructor(deps: SessionShareDeps);
65
+ get sessionId(): string;
66
+ get state(): ShareStatus;
67
+ start(): this;
68
+ /**
69
+ * §93 S12b — turn remote driving on/off (returning the state now in effect).
70
+ * Off by default: a watch link is read-only until the person AT the terminal
71
+ * says otherwise, and the value is re-announced by every hello so a viewer
72
+ * that missed the toggle frame sees the truth after any reconnect. The
73
+ * terminal keeps every gate — drive can be revoked at any moment with
74
+ * /share drive off, and the destructive confirm stays terminal-only regardless.
75
+ */
76
+ setDrive(on: boolean): boolean;
77
+ isDriveOn(): boolean;
78
+ /**
79
+ * §93 S12b — the permission prompt currently open here, or null when none is.
80
+ * Kept so a viewer attaching MID-prompt is handed it again by the pull (the
81
+ * same healing rule the event tail follows); cleared by the gate when the
82
+ * prompt is done. Like every publish, a frame while disconnected is dropped
83
+ * rather than buffered — the pull replays the current one.
84
+ */
85
+ publishPermission(frame: unknown | null): void;
86
+ /** §93 S12b — tell the web what this terminal did with a remote frame. */
87
+ publishRemoteNote(note: RemoteNoteFrame): void;
88
+ publish(ev: SessionEvent): void;
89
+ /** /clear and /fork move the session to a new id; watching follows it. */
90
+ rebind(id: string): void;
91
+ stop(reason?: string): void;
92
+ private emitTo;
93
+ /** One shape for every hello, so the two call sites cannot drift. */
94
+ private emitHello;
95
+ private pushTail;
96
+ private setStatus;
97
+ }
98
+ export declare function startSessionShare(deps: SessionShareDeps): SessionShare;
99
+ export declare function activeSessionShare(): SessionShare | null;
100
+ /** Called from the event funnel; free when sharing is off. */
101
+ export declare function publishSharedEvent(ev: SessionEvent | null | undefined): void;
102
+ export declare function rebindSessionShare(id: string): void;
103
+ export declare function stopSessionShare(reason?: string): void;
104
+ //# sourceMappingURL=sessionShare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionShare.d.ts","sourceRoot":"","sources":["../../src/share/sessionShare.ts"],"names":[],"mappings":"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"}