@nexrall/code-core 1.4.76 → 1.4.77

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 (110) hide show
  1. package/dist/agent/goal.d.ts +55 -0
  2. package/dist/agent/goal.d.ts.map +1 -0
  3. package/dist/agent/goal.js +120 -0
  4. package/dist/agent/handoffBrief.d.ts +82 -0
  5. package/dist/agent/handoffBrief.d.ts.map +1 -0
  6. package/dist/agent/handoffBrief.js +121 -0
  7. package/dist/agent/modelCatalogue.d.ts +23 -0
  8. package/dist/agent/modelCatalogue.d.ts.map +1 -1
  9. package/dist/agent/modelCatalogue.js +28 -0
  10. package/dist/agent/outputStyles.d.ts +27 -0
  11. package/dist/agent/outputStyles.d.ts.map +1 -0
  12. package/dist/agent/outputStyles.js +174 -0
  13. package/dist/agent/skills.d.ts.map +1 -1
  14. package/dist/agent/skills.js +7 -0
  15. package/dist/api/billingLines.d.ts +11 -0
  16. package/dist/api/billingLines.d.ts.map +1 -0
  17. package/dist/api/billingLines.js +56 -0
  18. package/dist/api/client.d.ts +2 -0
  19. package/dist/api/client.d.ts.map +1 -1
  20. package/dist/api/scheduleLines.d.ts +53 -0
  21. package/dist/api/scheduleLines.d.ts.map +1 -0
  22. package/dist/api/scheduleLines.js +150 -0
  23. package/dist/context/contextFiles.d.ts +81 -0
  24. package/dist/context/contextFiles.d.ts.map +1 -0
  25. package/dist/context/contextFiles.js +310 -0
  26. package/dist/diff/collect.d.ts +25 -0
  27. package/dist/diff/collect.d.ts.map +1 -0
  28. package/dist/diff/collect.js +169 -0
  29. package/dist/diff/diffView.d.ts +57 -0
  30. package/dist/diff/diffView.d.ts.map +1 -0
  31. package/dist/diff/diffView.js +231 -0
  32. package/dist/diff/reviewQueue.d.ts +53 -0
  33. package/dist/diff/reviewQueue.d.ts.map +1 -0
  34. package/dist/diff/reviewQueue.js +349 -0
  35. package/dist/events/recap.d.ts +54 -0
  36. package/dist/events/recap.d.ts.map +1 -0
  37. package/dist/events/recap.js +161 -0
  38. package/dist/events/sessionEvents.d.ts +54 -0
  39. package/dist/events/sessionEvents.d.ts.map +1 -0
  40. package/dist/events/sessionEvents.js +324 -0
  41. package/dist/events/sessionStats.d.ts +89 -0
  42. package/dist/events/sessionStats.d.ts.map +1 -0
  43. package/dist/events/sessionStats.js +264 -0
  44. package/dist/import/claudeImport.d.ts +44 -0
  45. package/dist/import/claudeImport.d.ts.map +1 -0
  46. package/dist/import/claudeImport.js +337 -0
  47. package/dist/index.d.ts +33 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +33 -0
  50. package/dist/project/projectCommands.d.ts +33 -0
  51. package/dist/project/projectCommands.d.ts.map +1 -0
  52. package/dist/project/projectCommands.js +246 -0
  53. package/dist/search/conversationTurns.d.ts +53 -0
  54. package/dist/search/conversationTurns.d.ts.map +1 -0
  55. package/dist/search/conversationTurns.js +170 -0
  56. package/dist/search/globalSearch.d.ts +144 -0
  57. package/dist/search/globalSearch.d.ts.map +1 -0
  58. package/dist/search/globalSearch.js +350 -0
  59. package/dist/share/sessionChannel.d.ts +136 -0
  60. package/dist/share/sessionChannel.d.ts.map +1 -0
  61. package/dist/share/sessionChannel.js +373 -0
  62. package/dist/share/sessionShare.d.ts +104 -0
  63. package/dist/share/sessionShare.d.ts.map +1 -0
  64. package/dist/share/sessionShare.js +336 -0
  65. package/dist/ui/configCmd.d.ts +48 -0
  66. package/dist/ui/configCmd.d.ts.map +1 -0
  67. package/dist/ui/configCmd.js +146 -0
  68. package/dist/ui/deployPanel.d.ts +91 -0
  69. package/dist/ui/deployPanel.d.ts.map +1 -0
  70. package/dist/ui/deployPanel.js +442 -0
  71. package/dist/ui/mergeAssistant.d.ts +120 -0
  72. package/dist/ui/mergeAssistant.d.ts.map +1 -0
  73. package/dist/ui/mergeAssistant.js +391 -0
  74. package/dist/ui/notify.d.ts +114 -0
  75. package/dist/ui/notify.d.ts.map +1 -0
  76. package/dist/ui/notify.js +235 -0
  77. package/dist/ui/promptSuggest.d.ts +56 -0
  78. package/dist/ui/promptSuggest.d.ts.map +1 -0
  79. package/dist/ui/promptSuggest.js +160 -0
  80. package/dist/ui/taskGraph.d.ts +44 -0
  81. package/dist/ui/taskGraph.d.ts.map +1 -0
  82. package/dist/ui/taskGraph.js +289 -0
  83. package/dist/util/addDir.d.ts +31 -0
  84. package/dist/util/addDir.d.ts.map +1 -0
  85. package/dist/util/addDir.js +124 -0
  86. package/dist/util/batch.d.ts +16 -0
  87. package/dist/util/batch.d.ts.map +1 -0
  88. package/dist/util/batch.js +92 -0
  89. package/dist/util/cellWidth.d.ts +12 -0
  90. package/dist/util/cellWidth.d.ts.map +1 -0
  91. package/dist/util/cellWidth.js +161 -0
  92. package/dist/util/duration.d.ts +8 -0
  93. package/dist/util/duration.d.ts.map +1 -0
  94. package/dist/util/duration.js +50 -0
  95. package/dist/util/loopJobs.d.ts +67 -0
  96. package/dist/util/loopJobs.d.ts.map +1 -0
  97. package/dist/util/loopJobs.js +169 -0
  98. package/dist/util/settingsFile.d.ts +14 -0
  99. package/dist/util/settingsFile.d.ts.map +1 -0
  100. package/dist/util/settingsFile.js +99 -0
  101. package/dist/util/toolLabel.d.ts +2 -0
  102. package/dist/util/toolLabel.d.ts.map +1 -0
  103. package/dist/util/toolLabel.js +17 -0
  104. package/dist/verify/failureTimeline.d.ts +100 -0
  105. package/dist/verify/failureTimeline.d.ts.map +1 -0
  106. package/dist/verify/failureTimeline.js +253 -0
  107. package/dist/verify/verification.d.ts +75 -0
  108. package/dist/verify/verification.d.ts.map +1 -0
  109. package/dist/verify/verification.js +315 -0
  110. package/package.json +5 -4
@@ -0,0 +1,350 @@
1
+ "use strict";
2
+ // Lives in core (moved from the CLI's ui/globalSearch.ts, 2026-10-04) so
3
+ // /find searches with the same engine in the VS Code panel; the CLI module is
4
+ // a re-export shim.
5
+ // §52 Global search — one query across files, conversation, tools, git, errors and agents.
6
+ //
7
+ // WHY: every scope already had its own command (/diff, /expand, /failures, /agents, /find), so
8
+ // answering "where does JWT show up at all?" meant running five of them and remembering which
9
+ // one held the answer. This module is the missing index over the sources the session already
10
+ // holds — pure functions, so a count is exactly what the scope contains and nothing is invented.
11
+ // It finds and ranks; the per-scope commands still do the jumping.
12
+ //
13
+ // Pure (no Ink, no console, no fs) so ranking, clipping and the counts block are unit-testable.
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.LABEL_CLIP = exports.DETAIL_CLIP = exports.MAX_PER_SCOPE = exports.SCOPE_LABEL = exports.SCOPES = void 0;
16
+ exports.fitLine = fitLine;
17
+ exports.scoreText = scoreText;
18
+ exports.searchFiles = searchFiles;
19
+ exports.searchConversation = searchConversation;
20
+ exports.searchTools = searchTools;
21
+ exports.searchGit = searchGit;
22
+ exports.searchErrors = searchErrors;
23
+ exports.searchAgents = searchAgents;
24
+ exports.globalSearch = globalSearch;
25
+ exports.filterScope = filterScope;
26
+ exports.formatCounts = formatCounts;
27
+ exports.formatHits = formatHits;
28
+ exports.scopeHint = scopeHint;
29
+ exports.parseSearchArgs = parseSearchArgs;
30
+ exports.searchUsage = searchUsage;
31
+ const cellWidth_1 = require("../util/cellWidth");
32
+ /** Display order — §52 lists files first because that is where a code query usually lives. */
33
+ exports.SCOPES = ['files', 'conversation', 'tools', 'git', 'errors', 'agents'];
34
+ exports.SCOPE_LABEL = {
35
+ files: 'Files',
36
+ conversation: 'Conversation',
37
+ tools: 'Tools',
38
+ git: 'Git',
39
+ errors: 'Errors',
40
+ agents: 'Agents',
41
+ };
42
+ /** Flags accepted after the query, including the short forms a user is likely to try first. */
43
+ const SCOPE_FLAG = {
44
+ '--files': 'files',
45
+ '--file': 'files',
46
+ '--chat': 'conversation',
47
+ '--conversation': 'conversation',
48
+ '--conv': 'conversation',
49
+ '--tools': 'tools',
50
+ '--tool': 'tools',
51
+ '--git': 'git',
52
+ '--errors': 'errors',
53
+ '--error': 'errors',
54
+ '--agents': 'agents',
55
+ '--agent': 'agents',
56
+ };
57
+ /** Hits printed per scope. The counts line stays complete — only the list is capped. */
58
+ exports.MAX_PER_SCOPE = 5;
59
+ /** A matched line kept for context, so a hit is recognisable without opening anything. */
60
+ exports.DETAIL_CLIP = 96;
61
+ exports.LABEL_CLIP = 72;
62
+ function clip(s, max) {
63
+ const flat = s.replace(/\s+/g, ' ').trim();
64
+ return (0, cellWidth_1.truncateCells)(flat, max);
65
+ }
66
+ /**
67
+ * Shorten an ASSEMBLED line to `cols`, keeping its leading indent.
68
+ *
69
+ * `clip` flattens whitespace, which is right for a path or a matched line but destroys a row
70
+ * whose alignment is the point: `clip(' Files 12')` returns `Files 12`, and every column in
71
+ * the counts block collapses. Measured on the first run of the tests in this module.
72
+ */
73
+ function fitLine(body, cols, indent = '') {
74
+ const room = Math.max(1, cols - (0, cellWidth_1.visibleLen)(indent));
75
+ if ((0, cellWidth_1.visibleLen)(body) <= room)
76
+ return indent + body;
77
+ const cut = (0, cellWidth_1.truncateCells)(body, room);
78
+ // A cut lands mid-style (the closing code of the run it interrupted is never reached), and an
79
+ // SGR left open bleeds into every row printed after it. Only styled rows get the reset, so
80
+ // NO_COLOR output stays byte-identical to what it always was.
81
+ return indent + (cut.includes('\u001b') ? cut + '\u001b[0m' : cut);
82
+ }
83
+ /**
84
+ * Rank one text against the query. `Infinity` = no match.
85
+ *
86
+ * Substring only, case-insensitive — this is a search box for code, where a fuzzy match is
87
+ * noise. The ladder, weakest last:
88
+ *
89
+ * 0 the text IS the query `auth` vs `auth`
90
+ * 1 the text begins with the query `auth.ts` vs `auth`
91
+ * 2 the query begins a word `src/auth.ts`, `jwt-refresh.ts`
92
+ * 3 the query starts mid-word `myjwthelper.ts`, `contest/a.ts`
93
+ *
94
+ * Rung 1 exists on its own because a tie between `auth.ts` and `x/auth-mid.ts` used to be
95
+ * settled by whatever order the scope listed them in, which put the worse match first.
96
+ */
97
+ function scoreText(query, text) {
98
+ const q = query.toLowerCase();
99
+ if (!q)
100
+ return Infinity;
101
+ const t = text.toLowerCase();
102
+ const at = t.indexOf(q);
103
+ if (at < 0)
104
+ return Infinity;
105
+ if (t === q)
106
+ return 0;
107
+ if (at === 0)
108
+ return 1;
109
+ if (!/[a-z0-9]/.test(t[at - 1]))
110
+ return 2;
111
+ return 3;
112
+ }
113
+ /** Best first: score, then the order the source listed them in. */
114
+ function top(hits, limit) {
115
+ const sorted = hits.sort((a, b) => a.score - b.score || a.index - b.index);
116
+ return limit === Infinity ? sorted : sorted.slice(0, limit);
117
+ }
118
+ function push(hits, scope, index, label, detail, score) {
119
+ hits.push({
120
+ scope,
121
+ key: `${scope}:${index}`,
122
+ label: clip(label, exports.LABEL_CLIP),
123
+ detail: detail && clip(detail, exports.DETAIL_CLIP),
124
+ score,
125
+ index,
126
+ });
127
+ }
128
+ // ─── Per-scope matchers ───────────────────────────────────────────────────────
129
+ /** Files: the path itself. */
130
+ function searchFiles(query, files) {
131
+ const hits = [];
132
+ files.forEach((f, i) => {
133
+ const score = scoreText(query, f);
134
+ if (score !== Infinity)
135
+ push(hits, 'files', i + 1, f, undefined, score);
136
+ });
137
+ return top(hits, Infinity);
138
+ }
139
+ /** Conversation: prompts and reply lines, via the transcript the turn navigation already builds. */
140
+ function searchConversation(query, turns) {
141
+ const hits = [];
142
+ turns.forEach((t) => {
143
+ const score = scoreText(query, t.prompt);
144
+ if (score !== Infinity)
145
+ push(hits, 'conversation', t.index, `turn ${t.index} you ${t.prompt}`, undefined, score);
146
+ t.lines.forEach((line) => {
147
+ const s = scoreText(query, line);
148
+ if (s !== Infinity)
149
+ push(hits, 'conversation', t.index, `turn ${t.index}`, line, s + 1);
150
+ });
151
+ });
152
+ return top(hits, Infinity);
153
+ }
154
+ /** Tools: the call label and the output the transcript folded away. */
155
+ function searchTools(query, entries) {
156
+ const hits = [];
157
+ entries.forEach((e) => {
158
+ const label = `${e.name}: ${e.label}`;
159
+ let best = scoreText(query, label);
160
+ let detail;
161
+ for (const line of e.output.split('\n')) {
162
+ const s = scoreText(query, line);
163
+ if (s !== Infinity) {
164
+ if (s + 1 < best)
165
+ best = s + 1;
166
+ detail = line; // one output line is enough to recognise the call; /expand <id> shows the rest
167
+ break;
168
+ }
169
+ }
170
+ // ONE row per tool call: the count then answers "how many calls mention this", and the
171
+ // command that is itself the query does not show up as a second, identical-looking hit.
172
+ if (best !== Infinity)
173
+ push(hits, 'tools', e.id, `#${e.id} ${label}`, detail, best);
174
+ });
175
+ return top(hits, Infinity);
176
+ }
177
+ /** Git: changed paths, with the status letter kept in front so `M`/`??` is visible. */
178
+ function searchGit(query, changes) {
179
+ const hits = [];
180
+ changes.forEach((c, i) => {
181
+ const score = scoreText(query, c.path);
182
+ if (score !== Infinity)
183
+ push(hits, 'git', i + 1, `${c.status ? c.status + ' ' : ''}${c.path}`, undefined, score);
184
+ });
185
+ return top(hits, Infinity);
186
+ }
187
+ /** Errors: the failing command, the files it touched, and the re-tests. */
188
+ function searchErrors(query, incidents) {
189
+ const hits = [];
190
+ incidents.forEach((inc) => {
191
+ const head = `#${inc.id} ${inc.command}`;
192
+ const inHead = scoreText(query, head);
193
+ if (inHead !== Infinity)
194
+ push(hits, 'errors', inc.id, head, undefined, inHead);
195
+ for (const f of inc.files) {
196
+ const s = scoreText(query, f);
197
+ if (s !== Infinity)
198
+ push(hits, 'errors', inc.id, head, f, s + 1);
199
+ }
200
+ for (const r of inc.retests) {
201
+ const s = scoreText(query, r.command);
202
+ if (s !== Infinity)
203
+ push(hits, 'errors', inc.id, head, `[${r.ok ? 'ok' : 'fail'}] ${r.command}`, s + 1);
204
+ }
205
+ });
206
+ return top(hits, Infinity);
207
+ }
208
+ /** Agents: type, task label and the files each one touched. */
209
+ function searchAgents(query, nodes) {
210
+ const hits = [];
211
+ nodes.forEach((n, i) => {
212
+ const head = `${n.name} ${n.label}`;
213
+ const inHead = scoreText(query, head);
214
+ if (inHead !== Infinity)
215
+ push(hits, 'agents', i + 1, head, n.error, inHead);
216
+ for (const f of n.files) {
217
+ const s = scoreText(query, f);
218
+ if (s !== Infinity)
219
+ push(hits, 'agents', i + 1, head, f, s + 1);
220
+ }
221
+ if (n.report) {
222
+ const s = scoreText(query, n.report);
223
+ if (s !== Infinity)
224
+ push(hits, 'agents', i + 1, head, 'report', s + 2);
225
+ }
226
+ });
227
+ return top(hits, Infinity);
228
+ }
229
+ // ─── The search itself ───────────────────────────────────────────────────────
230
+ function globalSearch(query, sources, perScope = exports.MAX_PER_SCOPE) {
231
+ const q = query.trim();
232
+ if (!q)
233
+ return { query: '', hits: [], counts: [] };
234
+ const all = [];
235
+ if (sources.files)
236
+ all.push(...searchFiles(q, sources.files));
237
+ if (sources.turns)
238
+ all.push(...searchConversation(q, sources.turns));
239
+ if (sources.tools)
240
+ all.push(...searchTools(q, sources.tools));
241
+ if (sources.git)
242
+ all.push(...searchGit(q, sources.git));
243
+ if (sources.errors)
244
+ all.push(...searchErrors(q, sources.errors));
245
+ if (sources.agents)
246
+ all.push(...searchAgents(q, sources.agents));
247
+ const counts = exports.SCOPES.map((scope) => ({ scope, count: all.filter((h) => h.scope === scope).length })).filter((c) => c.count > 0);
248
+ const hits = [];
249
+ for (const scope of exports.SCOPES) {
250
+ hits.push(...top(all.filter((h) => h.scope === scope), perScope));
251
+ }
252
+ return { query: q, hits, counts };
253
+ }
254
+ function filterScope(hits, scope) {
255
+ return scope ? hits.filter((h) => h.scope === scope) : hits;
256
+ }
257
+ // ─── Rendering ────────────────────────────────────────────────────────────────
258
+ /**
259
+ * The §52 counts block:
260
+ *
261
+ * > JWT
262
+ *
263
+ * Files 12
264
+ * Conversation 8
265
+ * Git 3
266
+ * Agents 2
267
+ *
268
+ * Labels pad to the widest, counts right-align to the widest — so the numbers line up even
269
+ * when "Conversation" sits next to "Files". Every line is clipped to `cols`; at narrow widths
270
+ * the label is what gets cut, never the count.
271
+ */
272
+ function formatCounts(result, cols, opts = {}) {
273
+ const out = [];
274
+ if (!result.query)
275
+ return out;
276
+ out.push(fitLine(`> ${result.query}`, cols));
277
+ if (!result.counts.length) {
278
+ out.push('');
279
+ out.push(fitLine('No match in files, conversation, tools, git, errors or agents.', cols, ' '));
280
+ return out;
281
+ }
282
+ // With one scope selected the section heading below already carries its count (`Git 1`),
283
+ // so the table would only repeat it — but the `> query` header still belongs to the result.
284
+ if (opts.table === false)
285
+ return out;
286
+ const labelW = Math.max(...result.counts.map((c) => exports.SCOPE_LABEL[c.scope].length)) + 1;
287
+ const numW = Math.max(...result.counts.map((c) => String(c.count).length));
288
+ out.push('');
289
+ for (const c of result.counts) {
290
+ const label = exports.SCOPE_LABEL[c.scope].padEnd(labelW);
291
+ const num = String(c.count).padStart(numW);
292
+ out.push(fitLine(`${label}${num}`, cols, ' '));
293
+ }
294
+ return out;
295
+ }
296
+ /**
297
+ * One printed row per hit: ` 3. Git M src/app.js`, with the matched line under it when the
298
+ * label alone would not say why it matched.
299
+ *
300
+ * `tag` prepends the 3-letter scope — on when the rows are mixed, off inside a per-scope
301
+ * section where the heading already said it.
302
+ */
303
+ function formatHits(hits, cols, indent = ' ', tag = true) {
304
+ const out = [];
305
+ hits.forEach((h, i) => {
306
+ const n = String(i + 1).padStart(3);
307
+ const mark = tag ? `${exports.SCOPE_LABEL[h.scope].slice(0, 3)} ` : '';
308
+ out.push(fitLine(`${n}. ${mark}${h.label}`, cols, indent));
309
+ if (h.detail && h.detail !== h.label)
310
+ out.push(fitLine(h.detail, cols, indent + ' '));
311
+ });
312
+ return out;
313
+ }
314
+ /** `Scopes: /find <q> --files --git` — only the flags that would actually narrow this result. */
315
+ function scopeHint(counts) {
316
+ if (!counts.length)
317
+ return '';
318
+ const flags = counts.map((c) => '--' + c.scope);
319
+ return `Scopes: /find <query> ${flags.join(' ')}`;
320
+ }
321
+ /** `/find JWT --git --tools` → query "JWT", scopes [git, tools]. `--all` clears the narrowing. */
322
+ function parseSearchArgs(arg) {
323
+ const words = arg.trim().split(/\s+/).filter(Boolean);
324
+ const scopes = [];
325
+ const bad = [];
326
+ const rest = [];
327
+ let all = false;
328
+ for (const w of words) {
329
+ const scope = SCOPE_FLAG[w.toLowerCase()];
330
+ if (scope) {
331
+ scopes.push(scope);
332
+ continue;
333
+ }
334
+ if (w.toLowerCase() === '--all') {
335
+ all = true;
336
+ continue;
337
+ }
338
+ if (w.startsWith('--')) {
339
+ bad.push(w);
340
+ continue;
341
+ }
342
+ rest.push(w);
343
+ }
344
+ return { query: rest.join(' '), scopes: all || !scopes.length ? null : [...new Set(scopes)], bad };
345
+ }
346
+ function searchUsage() {
347
+ const flags = exports.SCOPES.map((s) => (s === 'conversation' ? '--conversation|--chat' : `--${s}`));
348
+ return `Usage: /find <text> ${flags.map((f) => `[${f}]`).join(' ')}`;
349
+ }
350
+ //# sourceMappingURL=globalSearch.js.map
@@ -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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"}