toolroll 0.9.53 → 0.9.55
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.
- package/CHANGELOG.md +17 -0
- package/README.md +5 -4
- package/dist/agent-onboard.js +4 -1
- package/dist/approval-rules-ui.d.ts +3 -2
- package/dist/approval-rules-ui.js +15 -20
- package/dist/assignment-ui.d.ts +3 -2
- package/dist/assignment-ui.js +4 -11
- package/dist/backup-ui.d.ts +2 -1
- package/dist/backup-ui.js +16 -27
- package/dist/brand-mark.d.ts +3 -2
- package/dist/brand-mark.js +4 -4
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +25 -25
- package/dist/browser-shell.d.ts +2 -1
- package/dist/browser-shell.js +9 -9
- package/dist/browser-workspace.d.ts +2 -3
- package/dist/browser-workspace.js +0 -3
- package/dist/chat-ask.js +8 -8
- package/dist/chat-core.d.ts +171 -0
- package/dist/chat-core.js +288 -0
- package/dist/chat-decide.d.ts +10 -8
- package/dist/chat-decide.js +26 -21
- package/dist/chat-delivery-state.d.ts +51 -75
- package/dist/chat-delivery-state.js +140 -170
- package/dist/chat-delivery.d.ts +21 -2
- package/dist/chat-delivery.js +313 -194
- package/dist/chat-flow.d.ts +29 -1
- package/dist/chat-flow.js +24 -50
- package/dist/chat-messages.d.ts +319 -0
- package/dist/chat-messages.js +841 -0
- package/dist/chat-migration.d.ts +30 -0
- package/dist/chat-migration.js +802 -0
- package/dist/chat-polish.d.ts +5 -4
- package/dist/chat-polish.js +9 -10
- package/dist/chat-quiet.d.ts +3 -0
- package/dist/chat-quiet.js +5 -0
- package/dist/check-levels-ui.d.ts +2 -1
- package/dist/check-levels-ui.js +26 -53
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +9 -3
- package/dist/coding-shipping-ui.d.ts +2 -1
- package/dist/coding-shipping-ui.js +6 -6
- package/dist/coding-ui.d.ts +3 -1
- package/dist/coding-ui.js +30 -29
- package/dist/contracts/chat-content.d.ts +71 -2
- package/dist/contracts/chat-content.js +22 -3
- package/dist/contracts/chat-tables.d.ts +11 -4
- package/dist/contracts/chat-tables.js +165 -87
- package/dist/contracts/cli.d.ts +1 -3
- package/dist/contracts/console-api.d.ts +1 -1
- package/dist/contracts/console-api.js +6 -5
- package/dist/contracts/discord-callback.js +2 -1
- package/dist/contracts/health.d.ts +1 -3
- package/dist/contracts/slack-callback.js +3 -2
- package/dist/contracts/store-json.d.ts +1 -5
- package/dist/contracts/store-json.js +1 -4
- package/dist/contracts/teams-callback.js +2 -1
- package/dist/control-ui.d.ts +5 -4
- package/dist/control-ui.js +9 -34
- package/dist/credentials-ui.d.ts +5 -4
- package/dist/credentials-ui.js +23 -24
- package/dist/demo-chat.d.ts +3 -3
- package/dist/demo-chat.js +29 -76
- package/dist/discord-chat.js +19 -38
- package/dist/discord-settings.d.ts +3 -2
- package/dist/discord-settings.js +21 -55
- package/dist/discord.js +4 -14
- package/dist/envelope.js +10 -0
- package/dist/evidence-pack.d.ts +2 -1
- package/dist/evidence-pack.js +45 -49
- package/dist/export-ui.d.ts +7 -2
- package/dist/export-ui.js +4 -10
- package/dist/export.js +4 -4
- package/dist/flow-gallery-ui.d.ts +4 -3
- package/dist/flow-gallery-ui.js +28 -43
- package/dist/flow-starters-ui.d.ts +2 -1
- package/dist/flow-starters-ui.js +12 -15
- package/dist/flow-triggers.d.ts +1 -0
- package/dist/flow-triggers.js +16 -14
- package/dist/flows-ui.d.ts +4 -3
- package/dist/flows-ui.js +19 -30
- package/dist/flows.js +2 -1
- package/dist/guides.js +108 -3
- package/dist/html.d.ts +76 -0
- package/dist/html.js +173 -0
- package/dist/integrations-ui.d.ts +2 -1
- package/dist/integrations-ui.js +19 -23
- package/dist/kits-ui.d.ts +5 -4
- package/dist/kits-ui.js +18 -20
- package/dist/knowledge-ui.d.ts +6 -5
- package/dist/knowledge-ui.js +26 -25
- package/dist/lead-context.d.ts +11 -1
- package/dist/lead-context.js +6 -8
- package/dist/ledger-view.d.ts +2 -1
- package/dist/ledger-view.js +27 -29
- package/dist/limits-ui.d.ts +2 -1
- package/dist/limits-ui.js +7 -7
- package/dist/live-bus.d.ts +50 -8
- package/dist/live-bus.js +133 -50
- package/dist/mate-tools.js +3 -2
- package/dist/mcp-oauth.js +35 -36
- package/dist/models-ui.d.ts +2 -1
- package/dist/models-ui.js +25 -35
- package/dist/modes.d.ts +13 -1
- package/dist/modes.js +17 -1
- package/dist/monitoring-ui.d.ts +4 -3
- package/dist/monitoring-ui.js +13 -26
- package/dist/notification-rows.d.ts +30 -0
- package/dist/notification-rows.js +102 -0
- package/dist/openrouter-models.d.ts +2 -1
- package/dist/openrouter-models.js +5 -9
- package/dist/operate.js +16 -9
- package/dist/people-audit-ui.d.ts +2 -1
- package/dist/people-audit-ui.js +13 -13
- package/dist/plane-review.js +5 -11
- package/dist/policy-ui.d.ts +3 -2
- package/dist/policy-ui.js +17 -23
- package/dist/project-delete-ui.d.ts +4 -3
- package/dist/project-delete-ui.js +15 -27
- package/dist/project-delete.js +21 -26
- package/dist/pull-request-ui.d.ts +2 -1
- package/dist/pull-request-ui.js +17 -32
- package/dist/recipe-ui.d.ts +8 -7
- package/dist/recipe-ui.js +39 -32
- package/dist/release-adapters.d.ts +60 -0
- package/dist/release-adapters.js +435 -0
- package/dist/release-cli.d.ts +24 -0
- package/dist/release-cli.js +181 -0
- package/dist/release-gate.d.ts +80 -0
- package/dist/release-gate.js +150 -0
- package/dist/release-links.d.ts +29 -0
- package/dist/release-links.js +102 -0
- package/dist/release.d.ts +331 -0
- package/dist/release.js +550 -0
- package/dist/reply-shape.d.ts +2 -1
- package/dist/reply-shape.js +5 -5
- package/dist/repository-context-ui.d.ts +2 -1
- package/dist/repository-context-ui.js +2 -7
- package/dist/request-budget-ui.d.ts +2 -1
- package/dist/request-budget-ui.js +16 -16
- package/dist/result-review.d.ts +2 -3
- package/dist/result-review.js +3 -9
- package/dist/result-shots.js +2 -2
- package/dist/retention-ui.d.ts +7 -1
- package/dist/retention-ui.js +7 -11
- package/dist/retention.js +1 -1
- package/dist/serve.d.ts +11 -2
- package/dist/serve.js +69 -58
- package/dist/server/chat.d.ts +3 -6
- package/dist/server/chat.js +969 -1006
- package/dist/server/chrome.d.ts +291 -0
- package/dist/server/chrome.js +747 -0
- package/dist/server/console.css +2819 -0
- package/dist/server/flows.d.ts +2 -6
- package/dist/server/flows.js +840 -766
- package/dist/server/guards.d.ts +1 -1
- package/dist/server/guards.js +5 -2
- package/dist/server/handler-context.d.ts +1 -1
- package/dist/server/handler-context.js +1 -1
- package/dist/server/handler-registry.d.ts +8 -6
- package/dist/server/handler-registry.js +14 -2
- package/dist/server/http.d.ts +274 -0
- package/dist/server/http.js +239 -0
- package/dist/server/live.d.ts +34 -0
- package/dist/server/live.js +309 -0
- package/dist/server/pages.d.ts +2 -6
- package/dist/server/pages.js +808 -789
- package/dist/server/people-tokens.d.ts +1 -6
- package/dist/server/people-tokens.js +580 -572
- package/dist/server/remote.d.ts +4 -7
- package/dist/server/remote.js +37 -70
- package/dist/server/render-chat.d.ts +402 -0
- package/dist/server/render-chat.js +927 -0
- package/dist/server/render-pages.d.ts +535 -0
- package/dist/server/render-pages.js +1277 -0
- package/dist/server/render-people.d.ts +32 -0
- package/dist/server/render-people.js +121 -0
- package/dist/server/render-results.d.ts +744 -0
- package/dist/server/render-results.js +2237 -0
- package/dist/server/render-settings.d.ts +147 -0
- package/dist/server/render-settings.js +577 -0
- package/dist/server/render-tasks.d.ts +632 -0
- package/dist/server/render-tasks.js +2345 -0
- package/dist/server/request-context.d.ts +46 -0
- package/dist/server/request-context.js +17 -0
- package/dist/server/route-table.d.ts +25 -3
- package/dist/server/route-table.js +163 -75
- package/dist/server/runtime.d.ts +15 -7
- package/dist/server/runtime.js +7 -1
- package/dist/server/session.d.ts +138 -0
- package/dist/server/session.js +94 -0
- package/dist/server/settings.d.ts +1 -5
- package/dist/server/settings.js +2182 -2117
- package/dist/server/task-views.d.ts +11 -4
- package/dist/server/task-views.js +26 -22
- package/dist/server/tasks.d.ts +9 -9
- package/dist/server/tasks.js +1486 -1418
- package/dist/server-telemetry.d.ts +4 -3
- package/dist/server-telemetry.js +4 -8
- package/dist/skills-ui.d.ts +4 -3
- package/dist/skills-ui.js +14 -17
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +2 -1
- package/dist/slack-api.d.ts +5 -1
- package/dist/slack-api.js +2 -2
- package/dist/slack-chat.d.ts +9 -4
- package/dist/slack-chat.js +29 -52
- package/dist/slack-settings.d.ts +3 -2
- package/dist/slack-settings.js +23 -57
- package/dist/slack.js +6 -16
- package/dist/spend-ui.d.ts +2 -1
- package/dist/spend-ui.js +9 -32
- package/dist/sso-ui.d.ts +3 -2
- package/dist/sso-ui.js +26 -27
- package/dist/storage-ui.d.ts +2 -1
- package/dist/storage-ui.js +14 -33
- package/dist/store.d.ts +97 -364
- package/dist/store.js +207 -1531
- package/dist/surface.js +14 -3
- package/dist/task-composer.d.ts +2 -1
- package/dist/task-composer.js +7 -7
- package/dist/task-status.d.ts +4 -3
- package/dist/task-status.js +15 -16
- package/dist/team-http.d.ts +5 -9
- package/dist/team-http.js +5 -63
- package/dist/team-ui.d.ts +2 -1
- package/dist/team-ui.js +2 -5
- package/dist/teammate-question.js +12 -12
- package/dist/teammates-ui.d.ts +5 -4
- package/dist/teammates-ui.js +61 -90
- package/dist/teams-chat.js +12 -9
- package/dist/teams-settings.d.ts +3 -2
- package/dist/teams-settings.js +22 -33
- package/dist/teams.js +4 -5
- package/dist/telegram-flow.js +5 -5
- package/dist/telegram-settings.d.ts +3 -2
- package/dist/telegram-settings.js +14 -25
- package/dist/telegram.js +4 -4
- package/dist/toolroll-update-ui.d.ts +3 -2
- package/dist/toolroll-update-ui.js +35 -39
- package/dist/toolroll-update.d.ts +10 -0
- package/dist/toolroll-update.js +50 -3
- package/dist/tools-ui.d.ts +5 -2
- package/dist/tools-ui.js +31 -31
- package/dist/when-html.d.ts +11 -3
- package/dist/when-html.js +5 -6
- package/dist/workspace-revision.js +3 -1
- package/dist/workspace-ui.d.ts +4 -2
- package/dist/workspace-ui.js +10 -10
- package/package.json +1 -1
- package/dist/server/shared.d.ts +0 -3151
- package/dist/server/shared.js +0 -12001
- package/dist/slack-state.d.ts +0 -13
- package/dist/slack-state.js +0 -10
package/dist/coding-ui.js
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
|
|
3
|
-
const hidden = (values) => Object.entries(values).map(([name, value]) => `<input type="hidden" name="${escape(name)}" value="${escape(value)}">`).join('');
|
|
2
|
+
import { html, joinHtml, postForm } from './html.js';
|
|
4
3
|
function linkedText(text) {
|
|
5
4
|
const pattern = /\[([^\]\n]+)\]\((https?:\/\/[^\s)]+)\)|\x60([^\x60\n]+)\x60|\*\*([^*\n]+)\*\*|(https?:\/\/[^\s<>]+)/g;
|
|
6
5
|
let end = 0;
|
|
7
|
-
|
|
6
|
+
const output = [];
|
|
8
7
|
for (const match of text.matchAll(pattern)) {
|
|
9
|
-
output
|
|
8
|
+
output.push(html `${text.slice(end, match.index)}`);
|
|
10
9
|
if (match[3] !== undefined)
|
|
11
|
-
output
|
|
10
|
+
output.push(html `<code>${match[3]}</code>`);
|
|
12
11
|
else if (match[4] !== undefined)
|
|
13
|
-
output
|
|
12
|
+
output.push(html `<strong>${match[4]}</strong>`);
|
|
14
13
|
else {
|
|
15
14
|
const raw = match[2] ?? match[5];
|
|
16
15
|
const url = raw.replace(/[.,;!?]+$/, '');
|
|
17
|
-
output
|
|
16
|
+
output.push(html `<a href="${url}" target="_blank" rel="noopener noreferrer">${match[1] ?? url}</a>${raw.slice(url.length)}`);
|
|
18
17
|
}
|
|
19
18
|
end = match.index + match[0].length;
|
|
20
19
|
}
|
|
21
|
-
return output
|
|
20
|
+
return html `${output}${text.slice(end)}`;
|
|
22
21
|
}
|
|
23
22
|
function friendlyCodingError(message) {
|
|
24
23
|
return /already has an active writer/i.test(message)
|
|
@@ -27,57 +26,59 @@ function friendlyCodingError(message) {
|
|
|
27
26
|
}
|
|
28
27
|
function noticeHtml(message) {
|
|
29
28
|
const friendly = friendlyCodingError(message);
|
|
30
|
-
return
|
|
29
|
+
return html `${friendly}${friendly === message ? '' : html `<details><summary>Technical details</summary><pre>${message}</pre></details>`}`;
|
|
31
30
|
}
|
|
32
31
|
const sessionUrl = (id) => `/code/${encodeURIComponent(id)}`;
|
|
33
32
|
const active = (status) => ['starting', 'working', 'needs-input', 'stopping'].includes(status);
|
|
34
33
|
const stateLabel = (session, requests = []) => ({ starting: 'Starting Codex', ready: 'Ready', working: 'Working', 'needs-input': requests.some(r => r.kind !== 'questions') ? 'Permission needed' : 'Needs your answer', stopping: 'Stopping', interrupted: 'Stopped', failed: 'Stopped with an error', uncertain: 'Delivery not confirmed', closed: 'Session closed' }[session.status]);
|
|
35
34
|
function itemHtml(item) {
|
|
36
35
|
if (item.type === 'reasoning')
|
|
37
|
-
return
|
|
36
|
+
return html ``;
|
|
38
37
|
const role = ['user', 'userMessage'].includes(item.type) ? 'You' : ['agent', 'assistant', 'agentMessage'].includes(item.type) ? 'Codex' : null;
|
|
39
38
|
if (role)
|
|
40
|
-
return `<article class="coding-message${role === 'You' ? ' coding-user' : ''}" data-coding-item="${
|
|
39
|
+
return html `<article class="coding-message${role === 'You' ? ' coding-user' : ''}" data-coding-item="${item.id}"><strong>${role}</strong><div class="coding-text">${linkedText(item.text)}</div></article>`;
|
|
41
40
|
const title = { commandExecution: 'Command', fileChange: 'File changes', mcpToolCall: 'Tool', reasoning: 'Reasoning', plan: 'Plan', error: 'Error' }[item.type] ?? 'Activity';
|
|
42
|
-
return `<details class="coding-tool" data-coding-item="${
|
|
41
|
+
return html `<details class="coding-tool" data-coding-item="${item.id}"><summary>${title}${item.status ? html ` <span class="coding-meta">${item.status}</span>` : ''}</summary><pre>${item.text}</pre></details>`;
|
|
43
42
|
}
|
|
44
|
-
function requestHtml(request, session
|
|
43
|
+
function requestHtml(request, session) {
|
|
45
44
|
const questions = request.kind === 'questions';
|
|
46
|
-
const body = questions ? request.questions.map((q, index) => `<label>${
|
|
47
|
-
return `<section class="coding-request" data-coding-request="${
|
|
45
|
+
const body = questions ? request.questions.map((q, index) => html `<label>${q.question}<input type="text" name="question:${q.id}"${q.options.length ? html ` list="coding-options-${request.id}-${index}"` : ''} required autocomplete="off">${q.options.length ? html `<datalist id="coding-options-${request.id}-${index}">${q.options.map(o => html `<option value="${o.label}">${o.description}</option>`)}</datalist>` : ''}</label>`) : html `<pre class="coding-permission-detail">${request.detail}</pre><label>Password to approve this request<input type="password" name="password" autocomplete="current-password" required></label>`;
|
|
46
|
+
return html `<section class="coding-request" data-coding-request="${request.id}"><h3>${request.title || (questions ? 'Your answer' : 'Allow extra access?')}</h3>${postForm(`${sessionUrl(session)}/answer`, html `${body}<div class="coding-actions"><button type="submit" name="decision" value="accept">${questions ? 'Send answer' : 'Approve access'}</button><button type="submit" name="decision" value="decline" formnovalidate class="coding-secondary">${questions ? 'Cancel question' : 'Decline'}</button></div>`, { attrs: { 'data-coding-form': 'answer' }, hidden: { requestId: request.id } })}</section>`;
|
|
48
47
|
}
|
|
49
|
-
function controlsHtml(session
|
|
48
|
+
function controlsHtml(session) {
|
|
50
49
|
if (active(session.status) && session.turnId)
|
|
51
|
-
return
|
|
50
|
+
return postForm(`${sessionUrl(session.id)}/stop`, html `<button class="coding-secondary"${session.status === 'stopping' ? html ` disabled` : ''}>Stop</button>`, { attrs: { 'data-coding-form': 'stop' } });
|
|
52
51
|
if (session.status === 'uncertain')
|
|
53
|
-
return
|
|
52
|
+
return postForm(`${sessionUrl(session.id)}/${session.deliveryReviewRequired ? 'continue' : 'recover'}`, html `<button>${session.deliveryReviewRequired ? (session.nativeThreadId ? 'Continue with saved work' : 'Keep work and close session') : 'Check saved session'}</button>`, { attrs: { 'data-coding-form': 'recover' } });
|
|
54
53
|
if (!session.nativeThreadId && ['closed', 'failed', 'interrupted'].includes(session.status))
|
|
55
|
-
return
|
|
54
|
+
return html ``;
|
|
56
55
|
if (['failed', 'interrupted'].includes(session.status))
|
|
57
|
-
return
|
|
58
|
-
return
|
|
56
|
+
return postForm(`${sessionUrl(session.id)}/resume`, html `<button>Resume session</button>`, { attrs: { 'data-coding-form': 'resume' } });
|
|
57
|
+
return html ``;
|
|
59
58
|
}
|
|
60
59
|
export function codingWorkspaceHtml(input) {
|
|
61
60
|
const { selected, csrf } = input;
|
|
62
61
|
const selectedRepo = selected?.session.repo ?? input.project;
|
|
63
62
|
const projectName = (repo) => input.projects.find(p => p.path === repo)?.name ?? repo.split('/').filter(Boolean).at(-1) ?? repo;
|
|
64
63
|
const newUrl = `/code${selectedRepo ? `?project=${encodeURIComponent(selectedRepo)}` : ''}`;
|
|
65
|
-
const sessions = input.sessions.map(session => `<li><a href="${sessionUrl(session.id)}"${selected?.session.id === session.id ?
|
|
66
|
-
const
|
|
67
|
-
const
|
|
64
|
+
const sessions = joinHtml(input.sessions.map(session => html `<li><a href="${sessionUrl(session.id)}"${selected?.session.id === session.id ? html ` aria-current="page"` : ''}><span>${session.title}</span><small>${projectName(session.repo)} · <span data-coding-status-for="${session.id}">${stateLabel(session)}</span></small></a></li>`));
|
|
65
|
+
const sessionItems = input.sessions.length ? sessions : html `<li class="coding-meta">No sessions yet.</li>`;
|
|
66
|
+
const sidebar = html `<aside class="coding-sidebar"><div class="coding-sidebar-top"><h2>Sessions</h2>${selected ? html `<a class="coding-link-button" href="${newUrl}">New session</a>` : ''}</div><nav class="coding-session-list" aria-label="Coding sessions"><ul>${sessionItems}</ul></nav><details class="coding-mobile-sessions"><summary>Sessions${input.sessions.length ? ` (${input.sessions.length})` : ''}</summary><nav aria-label="Coding sessions"><ul>${sessionItems}</ul></nav></details></aside>`;
|
|
67
|
+
const warning = !input.available ? html `<p class="coding-notice">Codex is unavailable on this installation. Install and sign in to Codex on the host to start coding.</p>` : '';
|
|
68
68
|
const error = input.error ?? selected?.session.error ?? '';
|
|
69
69
|
let main;
|
|
70
70
|
if (!selected) {
|
|
71
|
-
const options = input.projects.map(p => `<option value="${
|
|
72
|
-
main = `<header class="coding-header"><h1>Build with Codex</h1></header>${warning}${input.projects.length ?
|
|
71
|
+
const options = input.projects.map(p => html `<option value="${p.path}"${selectedRepo === p.path ? html ` selected` : ''}>${p.name}</option>`);
|
|
72
|
+
main = html `<header class="coding-header"><h1>Build with Codex</h1></header>${warning}${input.projects.length ? postForm('/code/start', html `<label>Project<select name="repo" required>${options}</select></label><label>What would you like to change?<textarea name="prompt" rows="5" required maxlength="24000" placeholder="Describe the result you want…">${input.draft ?? ''}</textarea></label><details class="coding-options"><summary>Session options</summary><label>Title <span class="coding-meta">Optional</span><input name="title" maxlength="160" autocomplete="off"></label><label>Model <span class="coding-meta">Optional; uses the installed default</span><input name="model" maxlength="120" placeholder="Installed default" autocomplete="off"></label></details><p class="coding-terms">Codex uses this installation’s login and edits a separate copy of this project. It can run commands and read files outside the project. Connected tools (MCP servers) keep their own access to this computer and connected services. Additional command and file access requires your approval.</p><label>Password to start<input type="password" name="password" autocomplete="current-password" required></label><button type="submit"${input.available ? '' : html ` disabled`}>Start coding</button>`, { attrs: { 'data-coding-form': 'start', class: 'coding-start' }, hidden: { requestId: randomUUID() } }) : html `<div class="coding-empty"><p>Add a project to start coding.</p><a class="coding-link-button" href="/projects">Open projects</a></div>`}`;
|
|
73
73
|
}
|
|
74
74
|
else {
|
|
75
75
|
const s = selected.session;
|
|
76
76
|
const blocked = !s.nativeThreadId || !['ready', 'working', 'failed', 'interrupted'].includes(s.status);
|
|
77
|
-
const messages = selected.items.filter(item => item.type !== 'reasoning').map(itemHtml)
|
|
78
|
-
|
|
77
|
+
const messages = selected.items.filter(item => item.type !== 'reasoning').map(itemHtml);
|
|
78
|
+
const composer = postForm(`${sessionUrl(s.id)}/send`, html `<label for="coding-prompt">Message Codex</label><textarea id="coding-prompt" name="prompt" rows="2" maxlength="24000" required placeholder="Describe a change or ask about the result…">${input.draft ?? ''}</textarea><div class="coding-actions"><button type="submit"${blocked ? html ` disabled` : ''}>${s.status === 'working' ? 'Send update' : 'Send message'}</button></div>`, { attrs: { 'data-coding-form': 'send', class: 'coding-composer', hidden: s.status === 'closed' }, hidden: { requestId: randomUUID() } });
|
|
79
|
+
main = html `<header class="coding-header"><div><h1>${s.title}</h1><p class="coding-meta">${projectName(s.repo)} · Codex${s.model ? html ` · ${s.model}` : ''}</p></div><details class="coding-session-detail"><summary aria-label="Session details">Details</summary><dl><dt>Branch</dt><dd>${s.branch}</dd><dt>Worktree</dt><dd>${s.worktree}</dd><dt>Native session</dt><dd>${s.nativeThreadId ?? 'Not established'}</dd>${s.initialRequest ? html `<dt>Initial request</dt><dd class="coding-text">${s.initialRequest.prompt}</dd>` : ''}</dl></details></header><div class="coding-state-row"><p id="coding-state" role="status">${stateLabel(s, selected.requests)}</p><div id="coding-controls">${controlsHtml(s)}</div></div><div id="coding-requests">${selected.requests.map(r => requestHtml(r, s.id))}</div><div id="coding-conversation" class="coding-conversation" tabindex="0" aria-label="Conversation"${s.status === 'closed' && messages.length === 0 ? html ` hidden` : ''}>${messages.length ? messages : html `<p class="coding-meta coding-no-messages">No messages yet.</p>`}</div><button type="button" id="coding-latest" class="coding-secondary" hidden>Latest update ↓</button>${composer}<details id="coding-changes" class="coding-changes"><summary>Changes</summary><div id="coding-change-content"><p class="coding-meta">Open to load the current changes.</p></div><button type="button" id="coding-refresh-changes" class="coding-secondary">Refresh changes</button><noscript><a href="${sessionUrl(s.id)}/changes">View changes</a></noscript><p id="coding-shipping"${['closed', 'uncertain'].includes(s.status) ? html ` hidden` : ''}><a class="coding-link-button" href="${sessionUrl(s.id)}/ship">Review for shipping</a></p></details>`;
|
|
79
80
|
}
|
|
80
|
-
return `<section class="coding-workspace" data-coding-session="${
|
|
81
|
+
return html `<section class="coding-workspace" data-coding-session="${selected?.session.id ?? ''}" data-coding-owner="${selected?.session.owner ?? input.owner ?? ''}" data-coding-project="${selectedRepo ?? input.projects[0]?.path ?? ''}" data-coding-status="${selected?.session.status ?? ''}" data-coding-native-thread="${String(Boolean(selected?.session.nativeThreadId))}" data-coding-revision="${selected?.revision ?? -1}" data-coding-csrf="${csrf}">${sidebar}<div class="coding-main"><div id="coding-error" class="coding-notice" role="alert"${error ? '' : html ` hidden`}>${noticeHtml(error)}</div><p id="coding-connection" class="coding-meta" role="status" hidden></p>${main}</div></section>`;
|
|
81
82
|
}
|
|
82
83
|
export const CODING_CSS = `
|
|
83
84
|
.coding-workspace{display:grid;grid-template-columns:224px minmax(0,1fr);gap:24px;max-width:1220px;min-width:0;margin:0 auto;overflow-wrap:anywhere}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* What
|
|
2
|
+
* What every chat app keeps between steps (chat-delivery-state.ts, and Telegram's store methods): one schema for a received event's body
|
|
3
3
|
* (`chat_event.payload`, by the event's kind) and one for a planned message part (`chat_part.payload`), the message a
|
|
4
4
|
* button rides and the content a delivery repaints. Both are saved with `version`; a body or part saved before they
|
|
5
5
|
* carried one reads as it did then (its known fields; a reader then passed any others by unread).
|
|
6
6
|
*
|
|
7
|
-
* An event body lives only until the event is handled (then it is `{}
|
|
7
|
+
* An event body lives only until the event is handled (then it is `{}`; a Telegram message keeps its words as its
|
|
8
|
+
* record until its chat is unpaired); a part lives as long as its message.
|
|
8
9
|
*/
|
|
9
10
|
import { z } from "zod";
|
|
10
11
|
import { type ContractResult } from "./contract.js";
|
|
12
|
+
/** A Toolroll button's one-time token, as every chat app carries it: 32 hex, or `d:` and 24 hex for a decide button
|
|
13
|
+
* (chat-decide.ts: a result's, plan's, failure's or pull request's own buttons). */
|
|
14
|
+
export declare const CHAT_BUTTON_TOKEN: RegExp;
|
|
11
15
|
/** One planned message part, as delivery reads it. */
|
|
12
16
|
export declare const chatContentShape: {
|
|
13
17
|
text: z.ZodString;
|
|
@@ -78,6 +82,31 @@ export declare const chatContentShape: {
|
|
|
78
82
|
}, z.core.$strict>>;
|
|
79
83
|
/** The lead's own reply, already shaped (reply-shape.ts): the channel renders its bold anchors and labelled links in its own format. */
|
|
80
84
|
voice: z.ZodOptional<z.ZodLiteral<true>>;
|
|
85
|
+
/** Telegram: the person's message the first reply part answers. */
|
|
86
|
+
replyTo: z.ZodOptional<z.ZodString>;
|
|
87
|
+
/** Telegram: the part's buttons exactly as sent, their tokens minted with the part (a resend carries the same ones). */
|
|
88
|
+
keyboard: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
|
|
89
|
+
text: z.ZodString;
|
|
90
|
+
callback_data: z.ZodString;
|
|
91
|
+
}, z.core.$loose>>>>;
|
|
92
|
+
/** Telegram: a proposal card, still one after its proposal is gone. */
|
|
93
|
+
card: z.ZodOptional<z.ZodLiteral<true>>;
|
|
94
|
+
/** A result's, plan's, failure's or pull request's own buttons (chat-decide.ts), minted with the part: each an act's
|
|
95
|
+
* one-time token or a link. They ride the message once it is sent. */
|
|
96
|
+
decide: z.ZodOptional<z.ZodObject<{
|
|
97
|
+
rows: z.ZodArray<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
98
|
+
label: z.ZodString;
|
|
99
|
+
token: z.ZodString;
|
|
100
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
101
|
+
label: z.ZodString;
|
|
102
|
+
link: z.ZodObject<{
|
|
103
|
+
label: z.ZodString;
|
|
104
|
+
path: z.ZodString;
|
|
105
|
+
}, z.core.$strict>;
|
|
106
|
+
}, z.core.$strict>]>>>;
|
|
107
|
+
}, z.core.$strict>>;
|
|
108
|
+
/** The "What should change?" this part asks (chat-decide.ts): a reply to its message is the feedback. */
|
|
109
|
+
prompt: z.ZodOptional<z.ZodInt>;
|
|
81
110
|
};
|
|
82
111
|
export declare const chatContentSchema: z.ZodObject<{
|
|
83
112
|
text: z.ZodString;
|
|
@@ -138,6 +167,25 @@ export declare const chatContentSchema: z.ZodObject<{
|
|
|
138
167
|
options: z.ZodArray<z.ZodString>;
|
|
139
168
|
}, z.core.$strict>>;
|
|
140
169
|
voice: z.ZodOptional<z.ZodLiteral<true>>;
|
|
170
|
+
replyTo: z.ZodOptional<z.ZodString>;
|
|
171
|
+
keyboard: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
|
|
172
|
+
text: z.ZodString;
|
|
173
|
+
callback_data: z.ZodString;
|
|
174
|
+
}, z.core.$loose>>>>;
|
|
175
|
+
card: z.ZodOptional<z.ZodLiteral<true>>;
|
|
176
|
+
decide: z.ZodOptional<z.ZodObject<{
|
|
177
|
+
rows: z.ZodArray<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
178
|
+
label: z.ZodString;
|
|
179
|
+
token: z.ZodString;
|
|
180
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
181
|
+
label: z.ZodString;
|
|
182
|
+
link: z.ZodObject<{
|
|
183
|
+
label: z.ZodString;
|
|
184
|
+
path: z.ZodString;
|
|
185
|
+
}, z.core.$strict>;
|
|
186
|
+
}, z.core.$strict>]>>>;
|
|
187
|
+
}, z.core.$strict>>;
|
|
188
|
+
prompt: z.ZodOptional<z.ZodInt>;
|
|
141
189
|
}, z.core.$strict>;
|
|
142
190
|
export type ChatContent = z.infer<typeof chatContentSchema>;
|
|
143
191
|
export declare const CHAT_PART_VERSION = 1;
|
|
@@ -201,6 +249,25 @@ export declare const savedChatPartSchema: z.ZodObject<{
|
|
|
201
249
|
options: z.ZodArray<z.ZodString>;
|
|
202
250
|
}, z.core.$strict>>;
|
|
203
251
|
voice: z.ZodOptional<z.ZodLiteral<true>>;
|
|
252
|
+
replyTo: z.ZodOptional<z.ZodString>;
|
|
253
|
+
keyboard: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
|
|
254
|
+
text: z.ZodString;
|
|
255
|
+
callback_data: z.ZodString;
|
|
256
|
+
}, z.core.$loose>>>>;
|
|
257
|
+
card: z.ZodOptional<z.ZodLiteral<true>>;
|
|
258
|
+
decide: z.ZodOptional<z.ZodObject<{
|
|
259
|
+
rows: z.ZodArray<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
260
|
+
label: z.ZodString;
|
|
261
|
+
token: z.ZodString;
|
|
262
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
263
|
+
label: z.ZodString;
|
|
264
|
+
link: z.ZodObject<{
|
|
265
|
+
label: z.ZodString;
|
|
266
|
+
path: z.ZodString;
|
|
267
|
+
}, z.core.$strict>;
|
|
268
|
+
}, z.core.$strict>]>>>;
|
|
269
|
+
}, z.core.$strict>>;
|
|
270
|
+
prompt: z.ZodOptional<z.ZodInt>;
|
|
204
271
|
}, z.core.$strict>;
|
|
205
272
|
/** A saved part's content (`version` is the saved form's, not the content's). */
|
|
206
273
|
export declare function readChatPart(raw: string): ContractResult<ChatContent>;
|
|
@@ -227,6 +294,8 @@ export declare const chatMessageBodySchema: z.ZodObject<{
|
|
|
227
294
|
run: z.ZodNullable<z.ZodInt>;
|
|
228
295
|
}, z.core.$strict>>;
|
|
229
296
|
lead: z.ZodOptional<z.ZodLiteral<true>>;
|
|
297
|
+
context: z.ZodOptional<z.ZodString>;
|
|
298
|
+
request: z.ZodOptional<z.ZodString>;
|
|
230
299
|
}, z.core.$strict>;
|
|
231
300
|
/**
|
|
232
301
|
* A button: the one-time token it carried, or, when the app's callback came from the paired person but its data
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* What
|
|
2
|
+
* What every chat app keeps between steps (chat-delivery-state.ts, and Telegram's store methods): one schema for a received event's body
|
|
3
3
|
* (`chat_event.payload`, by the event's kind) and one for a planned message part (`chat_part.payload`), the message a
|
|
4
4
|
* button rides and the content a delivery repaints. Both are saved with `version`; a body or part saved before they
|
|
5
5
|
* carried one reads as it did then (its known fields; a reader then passed any others by unread).
|
|
6
6
|
*
|
|
7
|
-
* An event body lives only until the event is handled (then it is `{}
|
|
7
|
+
* An event body lives only until the event is handled (then it is `{}`; a Telegram message keeps its words as its
|
|
8
|
+
* record until its chat is unpaired); a part lives as long as its message.
|
|
8
9
|
*/
|
|
9
10
|
import { z } from "zod";
|
|
10
11
|
import { parseContract, readVersioned, versioned } from "./contract.js";
|
|
11
12
|
const id = z.int().min(1);
|
|
12
13
|
const link = z.strictObject({ label: z.string(), path: z.string() });
|
|
14
|
+
/** A Toolroll button's one-time token, as every chat app carries it: 32 hex, or `d:` and 24 hex for a decide button
|
|
15
|
+
* (chat-decide.ts: a result's, plan's, failure's or pull request's own buttons). */
|
|
16
|
+
export const CHAT_BUTTON_TOKEN = /^(?:[a-f0-9]{32}|d:[a-f0-9]{24})$/;
|
|
13
17
|
/** One planned message part, as delivery reads it. */
|
|
14
18
|
export const chatContentShape = {
|
|
15
19
|
text: z.string(),
|
|
@@ -39,6 +43,17 @@ export const chatContentShape = {
|
|
|
39
43
|
ask: z.strictObject({ turn: id, options: z.array(z.string()) }).optional(),
|
|
40
44
|
/** The lead's own reply, already shaped (reply-shape.ts): the channel renders its bold anchors and labelled links in its own format. */
|
|
41
45
|
voice: z.literal(true).optional(),
|
|
46
|
+
/** Telegram: the person's message the first reply part answers. */
|
|
47
|
+
replyTo: z.string().optional(),
|
|
48
|
+
/** Telegram: the part's buttons exactly as sent, their tokens minted with the part (a resend carries the same ones). */
|
|
49
|
+
keyboard: z.array(z.array(z.looseObject({ text: z.string(), callback_data: z.string() }))).optional(),
|
|
50
|
+
/** Telegram: a proposal card, still one after its proposal is gone. */
|
|
51
|
+
card: z.literal(true).optional(),
|
|
52
|
+
/** A result's, plan's, failure's or pull request's own buttons (chat-decide.ts), minted with the part: each an act's
|
|
53
|
+
* one-time token or a link. They ride the message once it is sent. */
|
|
54
|
+
decide: z.strictObject({ rows: z.array(z.array(z.union([z.strictObject({ label: z.string(), token: z.string().regex(CHAT_BUTTON_TOKEN) }), z.strictObject({ label: z.string(), link })]))) }).optional(),
|
|
55
|
+
/** The "What should change?" this part asks (chat-decide.ts): a reply to its message is the feedback. */
|
|
56
|
+
prompt: id.optional(),
|
|
42
57
|
};
|
|
43
58
|
export const chatContentSchema = z.strictObject(chatContentShape);
|
|
44
59
|
export const CHAT_PART_VERSION = 1;
|
|
@@ -92,12 +107,16 @@ export const chatMessageBodySchema = versioned(CHAT_EVENT_VERSION, {
|
|
|
92
107
|
unsupported: z.string().optional(),
|
|
93
108
|
about: z.strictObject({ task: z.string(), run: z.int().nullable() }).optional(),
|
|
94
109
|
lead: z.literal(true).optional(),
|
|
110
|
+
/** Telegram: the server-authored context its turn carries (the exact task or result a reply bound to). */
|
|
111
|
+
context: z.string().optional(),
|
|
112
|
+
/** Telegram: the request identity the lead's engine receipts the turn under. */
|
|
113
|
+
request: z.string().optional(),
|
|
95
114
|
});
|
|
96
115
|
/**
|
|
97
116
|
* A button: the one-time token it carried, or, when the app's callback came from the paired person but its data
|
|
98
117
|
* couldn't be read, the path-named line saying why — answered plainly, and nothing is done.
|
|
99
118
|
*/
|
|
100
|
-
export const chatTokenBodySchema = versioned(CHAT_EVENT_VERSION, { token: z.string().regex(
|
|
119
|
+
export const chatTokenBodySchema = versioned(CHAT_EVENT_VERSION, { token: z.string().regex(CHAT_BUTTON_TOKEN, { error: "must be a Toolroll button token" }) });
|
|
101
120
|
export const chatProblemBodySchema = versioned(CHAT_EVENT_VERSION, { problem: z.string().min(1) });
|
|
102
121
|
export const chatActionBodySchema = z.union([chatTokenBodySchema, chatProblemBodySchema]);
|
|
103
122
|
/** A notice carries its parts, not a body. */
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
3
|
-
*
|
|
2
|
+
* The one set of chat tables every chat app shares (v116): Telegram, Slack, Discord and Teams keep their pairings,
|
|
3
|
+
* received events, planned message parts, buttons, rooms and delivery receipts here, each row keyed by `provider`.
|
|
4
|
+
* A row's identity is (provider, id): ids carried over from the per-app tables keep their numbers, and nothing infers
|
|
5
|
+
* the app from an id. A leaf: it imports nothing, so the store creates these tables without loading the chat modules.
|
|
4
6
|
*/
|
|
5
|
-
export declare const
|
|
6
|
-
export
|
|
7
|
+
export declare const CHAT_PROVIDERS: readonly ["telegram", "slack", "discord", "teams"];
|
|
8
|
+
export type ChatProvider = (typeof CHAT_PROVIDERS)[number];
|
|
9
|
+
export declare const isChatProvider: (value: unknown) => value is ChatProvider;
|
|
10
|
+
export declare const CHAT_SCHEMA: string;
|
|
11
|
+
/** Every shared chat table, parents before children. */
|
|
12
|
+
export declare const CHAT_TABLES: readonly ["chat_binding", "chat_pair", "chat_event", "chat_part", "chat_action", "chat_progress", "chat_runtime", "chat_room", "chat_meta", "chat_flow_action", "chat_flow_prompt", "chat_flow_choice", "chat_flow_note", "chat_question_action", "chat_question_prompt", "chat_ask_action", "chat_message_ref", "chat_note_draft", "chat_digest"];
|
|
13
|
+
export type ChatTable = (typeof CHAT_TABLES)[number];
|