toolroll 0.9.54 → 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 +9 -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-polish.d.ts +5 -4
- package/dist/chat-polish.js +9 -10
- 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/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/health.d.ts +1 -3
- 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-settings.d.ts +3 -2
- package/dist/discord-settings.js +17 -42
- 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/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/mcp-oauth.js +35 -36
- package/dist/models-ui.d.ts +2 -1
- package/dist/models-ui.js +25 -35
- package/dist/monitoring-ui.d.ts +4 -3
- package/dist/monitoring-ui.js +13 -26
- package/dist/openrouter-models.d.ts +2 -1
- package/dist/openrouter-models.js +5 -9
- package/dist/operate.js +11 -7
- package/dist/people-audit-ui.d.ts +2 -1
- package/dist/people-audit-ui.js +13 -13
- 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/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/retention-ui.d.ts +7 -1
- package/dist/retention-ui.js +7 -11
- 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 +2181 -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-settings.d.ts +3 -2
- package/dist/slack-settings.js +17 -42
- 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/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/teammates-ui.d.ts +5 -4
- package/dist/teammates-ui.js +61 -90
- package/dist/teams-settings.d.ts +3 -2
- package/dist/teams-settings.js +20 -31
- package/dist/telegram-settings.d.ts +3 -2
- package/dist/telegram-settings.js +14 -25
- package/dist/toolroll-update-ui.d.ts +3 -2
- package/dist/toolroll-update-ui.js +35 -39
- 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-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/browser-shell.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
2
|
import { type BrowserWorkspace } from './browser-workspace.js';
|
|
3
|
+
import { type Html } from './html.js';
|
|
3
4
|
export declare function browserAssetsAvailable(): boolean;
|
|
4
5
|
export declare function serveBrowserAsset(request: IncomingMessage, response: ServerResponse, path: string): boolean;
|
|
5
6
|
/** Retain the complete native document as the no-JavaScript/unloaded-bundle
|
|
6
7
|
* fallback. React replaces its root only once the local module has loaded.
|
|
7
8
|
* The data script is escaped for HTML parsing, not merely valid JSON. */
|
|
8
|
-
export declare function browserWorkspaceDocument(
|
|
9
|
+
export declare function browserWorkspaceDocument(document: Html, workspace: BrowserWorkspace, nonce: string, functionalScript: string): Html;
|
package/dist/browser-shell.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/** The browser bundle is a presentation client. Only these fixed public assets
|
|
2
2
|
* are readable here; authenticated data stays in the existing page handlers. */
|
|
3
3
|
import { readFileSync } from 'node:fs';
|
|
4
|
-
import {
|
|
4
|
+
import {} from './browser-workspace.js';
|
|
5
|
+
import { html, jsonScript, replaceMarkup, scriptElement } from './html.js';
|
|
5
6
|
const assets = new Map();
|
|
6
7
|
function readAsset(name) {
|
|
7
8
|
// Compiled installation first; the second location supports source-based
|
|
@@ -47,16 +48,15 @@ export function serveBrowserAsset(request, response, path) {
|
|
|
47
48
|
/** Retain the complete native document as the no-JavaScript/unloaded-bundle
|
|
48
49
|
* fallback. React replaces its root only once the local module has loaded.
|
|
49
50
|
* The data script is escaped for HTML parsing, not merely valid JSON. */
|
|
50
|
-
export function browserWorkspaceDocument(
|
|
51
|
+
export function browserWorkspaceDocument(document, workspace, nonce, functionalScript) {
|
|
51
52
|
const initialize = `window.addEventListener('standing-orders:workspace-rendered',function initializeWorkspace(){window.removeEventListener('standing-orders:workspace-rendered',initializeWorkspace);${functionalScript}});`;
|
|
52
53
|
// A cross-page fade the browser gives up on rejects its promises; settle them from the head, before the
|
|
53
54
|
// first frame (the app's own listener arrives too late when a page is revealed before the bundle runs).
|
|
54
55
|
const settleFades = `(function(){function s(e){var f=e.viewTransition;if(f)[f.finished,f.ready,f.updateCallbackDone].forEach(function(p){if(p)p.catch(function(){})})}addEventListener('pageswap',s);addEventListener('pagereveal',s)})();`;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
.replace('</body>', () => `</div><script type="application/json" id="standing-orders-workspace-data" nonce="${nonce}">${serializeBrowserWorkspace(workspace)}</script><script nonce="${nonce}">${initialize}</script><script type="module" src="/assets/workspace.js" nonce="${nonce}"></script></body>`);
|
|
56
|
+
// Each insertion is markup built here; the page's own markup (and its data) is never re-read as a pattern.
|
|
57
|
+
let out = replaceMarkup(document, /<\/head>/, () =>
|
|
58
|
+
// A page showing a password keeps to its one script (the sensitivity contract), so it goes without.
|
|
59
|
+
html `<link rel="stylesheet" href="/assets/workspace.css">${workspace.sensitive ? "" : scriptElement(settleFades, { nonce })}</head>`);
|
|
60
|
+
out = replaceMarkup(out, /<body>/, () => html `<body><div id="standing-orders-workspace">`);
|
|
61
|
+
return replaceMarkup(out, /<\/body>/, () => html `</div>${jsonScript(workspace, { id: "standing-orders-workspace-data", nonce })}${scriptElement(initialize, { nonce })}<script type="module" src="/assets/workspace.js" nonce="${nonce}"></script></body>`);
|
|
62
62
|
}
|
|
@@ -430,9 +430,9 @@ export type BrowserTaskView = {
|
|
|
430
430
|
} | null;
|
|
431
431
|
/** What the agent did last on the live run, and when; the page words it against its own clock (activity-line.ts). */
|
|
432
432
|
activity?: RunActivity | null;
|
|
433
|
-
/** The task's live
|
|
433
|
+
/** The task's live room (GET /live?room=task:<root>): change nudges and who else has it open. */
|
|
434
434
|
live?: {
|
|
435
|
-
|
|
435
|
+
room: string;
|
|
436
436
|
at: string | null;
|
|
437
437
|
} | null;
|
|
438
438
|
/** Stop, on the Building card: the exact live build's stop form (posts its run id). */
|
|
@@ -1276,7 +1276,6 @@ export type BrowserSignIn = {
|
|
|
1276
1276
|
};
|
|
1277
1277
|
/** Safe inside a script[type=application/json] element. JSON escaping alone
|
|
1278
1278
|
* does not stop the HTML parser from closing that element at </script>. */
|
|
1279
|
-
export declare function serializeBrowserWorkspace(workspace: BrowserWorkspace): string;
|
|
1280
1279
|
export declare const BROWSER_CREW_LIMIT = 40;
|
|
1281
1280
|
export type BrowserCrewOptions = {
|
|
1282
1281
|
evidenceRoot?: string;
|
|
@@ -9,9 +9,6 @@ export function needsYouLabelOf(count, projectName, saturated = false) {
|
|
|
9
9
|
}
|
|
10
10
|
/** Safe inside a script[type=application/json] element. JSON escaping alone
|
|
11
11
|
* does not stop the HTML parser from closing that element at </script>. */
|
|
12
|
-
export function serializeBrowserWorkspace(workspace) {
|
|
13
|
-
return JSON.stringify(workspace).replace(/</g, '\\u003c').replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
|
|
14
|
-
}
|
|
15
12
|
export const BROWSER_CREW_LIMIT = 40;
|
|
16
13
|
/** A bounded recent family list. The caller supplies its already admitted
|
|
17
14
|
* access; an optional project can only narrow it. Admission and family grouping
|
package/dist/chat-polish.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
import { type Html } from './html.js';
|
|
1
2
|
import type { ChatSnapshot } from './store.js';
|
|
2
3
|
/** Presentation only. These are recorded completions, not a claim that
|
|
3
4
|
* work happened since the user last visited, or that every result passed. */
|
|
4
5
|
export declare function completedWorkHtml(snapshot: ChatSnapshot, projectLabels: readonly string[], assignments?: Readonly<Record<string, {
|
|
5
6
|
state: string;
|
|
6
|
-
}>>):
|
|
7
|
+
}>>): Html;
|
|
7
8
|
/** Keep activity truthful: the turn's recorded step count is not a
|
|
8
9
|
* percentage or an invented tool phase. Billing detail stays available. */
|
|
9
10
|
export declare function chatWorkingHtml(input: {
|
|
10
11
|
details: string;
|
|
11
|
-
stopForm?:
|
|
12
|
+
stopForm?: Html;
|
|
12
13
|
keyed?: boolean;
|
|
13
|
-
}):
|
|
14
|
+
}): Html;
|
|
14
15
|
/** Recorded activity is inspectable, not a row of performance badges. */
|
|
15
|
-
export declare function chatActivityDetailsHtml(activity: string | null):
|
|
16
|
+
export declare function chatActivityDetailsHtml(activity: string | null): Html;
|
|
16
17
|
export declare const CHAT_POLISH_CSS = "\n /* Quiet workspace surfaces: color signals state, not an AI aesthetic. */\n body { background: var(--background); }\n .chat-workspace .chat-overview, .chat-workspace .chat-plan, .chat-workspace .result-panel,\n .chat-workspace .decide-card { background: var(--card); box-shadow: none; }\n .chat-workspace .result-panel { border-radius: .75rem; }\n .chat-workspace .chat-empty::before { content: none; }\n .chat-workspace .thread .msg.mate::before { background: var(--muted); box-shadow: none; border: 0; }\n .chat-workspace .thread .msg.op { box-shadow: none; border: 0; }\n .chat-workspace .completion-receipt { background: var(--card); box-shadow: none; }\n .chat-workspace .completion-receipt::after { content: none; }\n .chat-workspace .thread { min-height: 0; }\n .chat-workspace .chat-turn-history { margin: 1rem 0; border: 0; border-top: 1px solid var(--border); border-radius: 0; background: transparent; box-shadow: none; padding: 0; }\n .chat-turn-history > summary { display: flex; align-items: center; gap: .75rem; min-height: 44px; cursor: pointer; font-size: .875rem; }\n .chat-turn-history > summary .meta { margin-left: auto; }\n .chat-turn-history .row { display: flex; flex-wrap: wrap; gap: .4rem; }\n .chat-turn-history .row .right { float: none; margin-left: auto; }\n .chat-workspace .task-live-summary { margin-bottom: .75rem; padding-bottom: .25rem; }\n .chat-workspace .task-journey > details, .chat-workspace .result-feedback-history,\n .chat-workspace .chat-limits, .chat-workspace .task-chat-agents {\n border: 0; border-radius: 0; background: transparent; box-shadow: none; padding: 0; margin: .25rem 0;\n }\n .chat-workspace .task-chat-agents > summary { min-height: 44px; cursor: pointer; font-size: .8125rem; color: var(--muted-foreground); }\n .chat-workspace .task-chat-agents p { margin: 0 0 .5rem; }\n .chat-workspace .decide-options .decide-option { border: 0; border-top: 1px solid var(--border); border-radius: 0; background: transparent; padding: .75rem 0; }\n .chat-workspace .chat-plan { padding: 1rem; margin-top: .5rem; }\n .chat-workspace .result-knowledge { margin-bottom: .5rem; }\n .chat-workspace .result-panel [data-result-view] > details { margin-block: 0; padding-block: 0; }\n .chat-workspace .result-panel [data-result-view] > details > summary { min-height: 44px; display: flex; align-items: center; }\n .chat-workspace .result-feedback-history > summary { min-height: 44px; }\n .chat-activity-details { border: 0; background: transparent; box-shadow: none; border-radius: 0; padding: 0; margin: 0; }\n .chat-activity-details > summary { min-height: 44px; display: flex; align-items: center; gap: .4rem; cursor: pointer; color: var(--muted-foreground); font-size: .75rem; }\n .chat-activity-details > summary::after { content: '\u2304'; }\n .chat-activity-details[open] > summary::after { transform: rotate(180deg); }\n .chat-activity-details .chat-activity { gap: .25rem .75rem; }\n .chat-activity-details .chat-activity span { border: 0; padding: 0; border-radius: 0; font: inherit; font-size: .75rem; }\n .chat-workspace .chat-message-foot { justify-content: flex-start; align-items: baseline; margin-top: .25rem; }\n .chat-activity-row { border: 0; background: transparent; box-shadow: none; padding: .5rem 0; min-height: 44px; gap: .65rem; }\n .chat-activity-row details { flex: 1; min-width: 0; border: 0; background: transparent; padding: 0; margin: 0; box-shadow: none; }\n .chat-activity-row summary { min-height: 44px; display: flex; align-items: center; cursor: pointer; width: fit-content; font-size: .875rem; font-weight: 550; }\n .chat-activity-row summary::after { content: '\u2304'; margin-left: .65rem; color: var(--muted-foreground); }\n .chat-activity-row details[open] summary::after { transform: rotate(180deg); }\n .chat-activity-row .meta { padding-bottom: .5rem; overflow-wrap: anywhere; }\n .activity-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }\n .task-live-summary { border-bottom: 1px solid var(--border); margin-bottom: 1rem; padding-bottom: .5rem; }\n .task-live-summary .task-journey, .task-live-summary .task-control { border: 0; border-radius: 0; box-shadow: none; background: transparent; margin: 0; padding: .65rem 0; }\n .task-live-summary .task-journey h2 { font-size: 1rem; }\n .task-live-summary .agents-strip { margin: .4rem 0; }\n .chat-decisions .chat-section-head { margin-bottom: .5rem; }\n .chat-decisions h2 { font-size: .875rem; font-weight: 550; color: var(--muted-foreground); }\n .decision-context summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; font-size: .8125rem; color: var(--muted-foreground); }\n .decision-context { border: 0; padding: 0; margin: 0; background: transparent; box-shadow: none; }\n .decide-options { display: grid; gap: .5rem; }\n .decide-options .decide-option { margin: 0; padding: .65rem .75rem; border: 1px solid var(--border); border-radius: .75rem; background: var(--background); }\n .decide-options .decide-option .meta { display: block; margin-top: .3rem; overflow-wrap: anywhere; }\n .decide-options .decide-option button { min-height: 44px; max-width: 100%; white-space: normal; text-align: left; }\n .chat-completed { margin-top: 1rem; }\n .chat-completed h3 { font-size: .8125rem; font-weight: 550; margin: 0 0 .25rem; color: var(--muted-foreground); }\n .chat-completed-action { flex: none; font-size: .75rem; white-space: nowrap; color: var(--muted-foreground); }\n .chat-overview .chat-overview-stat { box-shadow: none; border: 0; background: transparent; border-radius: 0; }\n .chat-overview .chat-overview-stat + .chat-overview-stat { border-left: 1px solid var(--border); }\n .result-panel .result-request { border-top: 1px solid var(--border); padding-top: 1rem; }\n .result-panel .result-head h2 { color: var(--foreground); }\n .result-panel .result-request h3 { color: var(--foreground); font-size: .875rem; text-transform: none; letter-spacing: 0; }\n .result-panel .result-feedback-actions { display: flex; justify-content: flex-end; align-items: center; flex-wrap: wrap; gap: .5rem; }\n .result-panel .result-feedback-actions > [data-request-changes] { order: 2; background: var(--foreground); color: var(--background); border-color: var(--foreground); box-shadow: none; }\n .result-panel .result-feedback-actions > button { width: auto; min-height: 44px; white-space: nowrap; }\n .result-panel .result-feedback-actions > .quiet { background: transparent; border-color: transparent; box-shadow: none; }\n .result-panel .result-feedback-actions > button:disabled { opacity: .45; cursor: default; }\n .result-panel .result-feedback-link { display: inline-flex; align-items: center; min-height: 44px; font-size: .8125rem; text-underline-offset: 3px; }\n .result-panel .result-pin > summary, .result-panel .result-notes > summary, .result-panel .result-details > summary { min-height: 44px; }\n .result-panel .diff-comment-form textarea { min-height: 80px; margin: 0; font-size: 1rem; }\n .result-panel .result-attention { background: transparent; border: 0; border-radius: 0; box-shadow: none; padding: 0; margin: .75rem 0; color: var(--foreground); }\n .result-panel .result-attention ul { margin: 0; padding-left: 1.15rem; }\n .result-panel .result-attention ul:has(> li:only-child) { list-style: none; padding-left: 0; }\n .result-panel .result-knowledge { border: 0; border-top: 1px solid var(--border); background: transparent; box-shadow: none; border-radius: 0; padding: .25rem 0; }\n .result-panel .revision-from-comments { border: 0; background: transparent; box-shadow: none; padding: .5rem 0; }\n .result-panel .result-pin summary { font-size: .8125rem; min-height: 44px; display: flex; align-items: center; cursor: pointer; }\n .result-panel .diff-comment-limit { font-size: .75rem; }\n .chat-main .chat-plan { box-shadow: none; }\n .proposal-review-notes { margin: .5rem 0; padding-left: 1.15rem; overflow-wrap: anywhere; }\n .proposal-review-notes li + li { margin-top: .5rem; }\n .proposal-actions .button-link, .proposal-actions button { min-height: 44px; white-space: nowrap; }\n .chat-stop-confirm > summary { min-height: 44px; display: flex; align-items: center; cursor: pointer; }\n .task-chat-title-line h1, .task-main-title, .resume-target, .resume-ceremony, .proposal-task_action, .chat-stop-confirm { overflow-wrap: anywhere; }\n .chat-main .chat-task-back { display: none; }\n .knowledge-library .knowledge-intro { padding: .5rem 0 1.25rem; margin-bottom: 1.5rem; border-bottom: 1px solid var(--border); }\n .knowledge-library .knowledge-instructions { line-height: 1.65; margin-bottom: .5rem; }\n .knowledge-library .knowledge-editor summary { width: fit-content; font-size: .875rem; font-weight: 550; }\n .knowledge-library .knowledge-editor, .knowledge-library > details { border: 0; border-bottom: 1px solid var(--border); border-radius: 0; box-shadow: none; background: transparent; padding: 0; }\n .knowledge-library .knowledge-editor { border-bottom: 0; }\n .knowledge-library .card { border: 0; border-bottom: 1px solid var(--border); border-radius: 0; padding: 0 0 .5rem; margin: 0; box-shadow: none; background: transparent; }\n .knowledge-library .card[open] { padding-bottom: 1rem; }\n .knowledge-library .card > summary { padding: .85rem 0; }\n @media (prefers-reduced-motion: no-preference) {\n .chat-activity-row .activity-dot { animation: quiet-activity 1.8s ease-in-out infinite; }\n .chat-completed .chat-overview-item { transition: background-color 140ms ease; }\n @keyframes quiet-activity { 50% { opacity: .35; } }\n }\n @media (max-width: 600px) {\n .chat-workspace .result-panel { background: transparent; border-radius: 0; }\n .chat-completed .chat-overview-item { align-items: flex-start; flex-wrap: wrap; gap: .35rem; }\n .chat-completed .chat-overview-copy { flex-basis: 65%; }\n .task-live-summary .task-journey { gap: .5rem; }\n }\n";
|
package/dist/chat-polish.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { html } from './html.js';
|
|
2
2
|
/** Presentation only. These are recorded completions, not a claim that
|
|
3
3
|
* work happened since the user last visited, or that every result passed. */
|
|
4
4
|
export function completedWorkHtml(snapshot, projectLabels, assignments) {
|
|
@@ -7,23 +7,22 @@ export function completedWorkHtml(snapshot, projectLabels, assignments) {
|
|
|
7
7
|
&& !task.historyProblem && !task.otherActive?.length
|
|
8
8
|
&& task.dispatch?.condition !== 'waiting' : assignments[task.id]?.state === 'complete').slice(0, 3);
|
|
9
9
|
if (!completed.length)
|
|
10
|
-
return
|
|
11
|
-
return `<section class="chat-completed" aria-label="Completed work"><h3>Completed work</h3
|
|
12
|
-
return `<a class="chat-overview-item" href="/t/${encodeURIComponent(task.rootId ?? task.id)}"><span class="chat-overview-copy"><strong>${
|
|
13
|
-
})
|
|
10
|
+
return html ``;
|
|
11
|
+
return html `<section class="chat-completed" aria-label="Completed work"><h3>Completed work</h3>${completed.map(task => {
|
|
12
|
+
return html `<a class="chat-overview-item" href="/t/${encodeURIComponent(task.rootId ?? task.id)}"><span class="chat-overview-copy"><strong>${task.title}</strong><span>${projectLabels[task.repoIndex] ?? `Project ${task.repoIndex + 1}`}</span></span><span class="chat-completed-action">Open task <span aria-hidden="true">→</span></span></a>`;
|
|
13
|
+
})}</section>`;
|
|
14
14
|
}
|
|
15
15
|
/** Keep activity truthful: the turn's recorded step count is not a
|
|
16
16
|
* percentage or an invented tool phase. Billing detail stays available. */
|
|
17
17
|
export function chatWorkingHtml(input) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
(input.stopForm ?? '') + '</div>';
|
|
18
|
+
const activity = html `<span class="activity-dot" aria-hidden="true"></span><details><summary>Working<span class="activity-ellipsis" aria-hidden="true">…</span></summary><p class="meta">${input.details}</p></details>`;
|
|
19
|
+
return html `<div class="chat-thinking chat-activity-row" id="latest" role="status"${input.keyed ? html ` data-key="pending"` : ''}>${activity}${input.stopForm}</div>`;
|
|
21
20
|
}
|
|
22
21
|
/** Recorded activity is inspectable, not a row of performance badges. */
|
|
23
22
|
export function chatActivityDetailsHtml(activity) {
|
|
24
23
|
if (!activity)
|
|
25
|
-
return
|
|
26
|
-
return `<details class="chat-activity-details"><summary>Activity</summary><div class="chat-activity" aria-label="work performed">${activity.split(' · ').map(one => `<span>${
|
|
24
|
+
return html ``;
|
|
25
|
+
return html `<details class="chat-activity-details"><summary>Activity</summary><div class="chat-activity" aria-label="work performed">${activity.split(' · ').map(one => html `<span>${one}</span>`)}</div></details>`;
|
|
27
26
|
}
|
|
28
27
|
// Local primitives adapted from the researched interaction patterns. No
|
|
29
28
|
// imported kit, animation runtime, simulated progress, or changed authority.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* words. One choice (Quick, Full, Off) and the quick command beside the full
|
|
3
3
|
* one. Every change takes the password and lands in the ledger; approving a
|
|
4
4
|
* command restates exactly what will run, unattended, before the yes. */
|
|
5
|
+
import { type Html } from "./html.js";
|
|
5
6
|
import { type CheckLevel } from "./check-levels.js";
|
|
6
7
|
import type { VerifyCommand } from "./store.js";
|
|
7
8
|
export type CheckSettingsView = {
|
|
@@ -26,5 +27,5 @@ export type CheckSettingsView = {
|
|
|
26
27
|
said: string | null;
|
|
27
28
|
problem: string | null;
|
|
28
29
|
};
|
|
29
|
-
export declare function checkSettingsHtml(view: CheckSettingsView):
|
|
30
|
+
export declare function checkSettingsHtml(view: CheckSettingsView): Html;
|
|
30
31
|
export declare const CHECK_SETTINGS_CSS = "\n .check-settings { display: grid; gap: .6rem; max-width: 40rem; }\n .check-settings p, .check-settings h2 { margin: 0; }\n .check-settings h2 { font-size: 1rem; }\n .check-settings fieldset { border: 0; margin: 0; padding: 0; display: grid; gap: .25rem; }\n .check-settings legend { font-weight: 600; margin-bottom: .25rem; }\n .check-settings label { display: grid; gap: .25rem; }\n .check-settings .check-choice { display: flex; align-items: flex-start; gap: .6rem; min-height: 44px; padding: .35rem 0; cursor: pointer; }\n .check-settings .check-choice > span { display: grid; gap: .1rem; }\n .check-settings .check-choice input { margin-top: .2rem; }\n .check-settings input[type=password], .check-settings input[type=number], .check-settings textarea { min-height: 44px; box-sizing: border-box; width: 100%; }\n .check-settings button { min-height: 44px; justify-self: start; }\n .check-settings .check-command { overflow-wrap: anywhere; }\n .check-terms { margin: 0; padding-left: 1.1rem; display: grid; gap: .25rem; }\n @media (max-width: 480px) { .check-settings button { justify-self: stretch; } }\n .follow-ups .follow-up-list { margin: .4rem 0; padding-left: 1.1rem; display: grid; gap: .25rem; }\n .follow-ups .follow-up-acts, .follow-ups .follow-up-act { display: flex; flex-wrap: wrap; gap: .5rem; margin: .5rem 0 0; }\n .follow-ups .follow-up-act { margin: 0; }\n .follow-ups button { min-height: 44px; }\n @media (max-width: 480px) { .follow-ups .follow-up-acts, .follow-ups .follow-up-act { display: grid; } .follow-ups .follow-up-act button { width: 100%; } }\n";
|
package/dist/check-levels-ui.js
CHANGED
|
@@ -2,51 +2,33 @@
|
|
|
2
2
|
* words. One choice (Quick, Full, Off) and the quick command beside the full
|
|
3
3
|
* one. Every change takes the password and lands in the ledger; approving a
|
|
4
4
|
* command restates exactly what will run, unattended, before the yes. */
|
|
5
|
+
import { html, postForm } from "./html.js";
|
|
5
6
|
import { CHECK_LEVELS, CHECK_LEVEL_HINTS, CHECK_LEVEL_WORDS } from "./check-levels.js";
|
|
6
7
|
import { BATCH_HINT } from "./batch-policy.js";
|
|
7
|
-
const escape = (text) => text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
8
8
|
export function checkSettingsHtml(view) {
|
|
9
|
-
const
|
|
10
|
-
const password = `<label>Password<input type="password" name="password" autocomplete="current-password" required></label>`;
|
|
9
|
+
const post = (act, body, attrs) => postForm("/settings/checks", body, { attrs, hidden: { repo: view.repo, act } });
|
|
10
|
+
const password = html `<label>Password<input type="password" name="password" autocomplete="current-password" required></label>`;
|
|
11
11
|
const notes = [
|
|
12
|
-
view.said === null ? "" : `<p class="notice" role="status">${
|
|
13
|
-
view.problem === null ? "" : `<p class="problem" role="alert">${
|
|
14
|
-
]
|
|
15
|
-
const head = `<p class="meta">${
|
|
16
|
-
const command = (one) => `<p class="mono check-command">${
|
|
12
|
+
view.said === null ? "" : html `<p class="notice" role="status">${view.said}</p>`,
|
|
13
|
+
view.problem === null ? "" : html `<p class="problem" role="alert">${view.problem}</p>`,
|
|
14
|
+
];
|
|
15
|
+
const head = html `<p class="meta">${view.name} · <span class="mono">${view.repo}</span></p>${notes}`;
|
|
16
|
+
const command = (one) => html `<p class="mono check-command">${one.command}</p><p class="meta">Up to ${Math.round(one.timeoutMs / 1000)}s · approved by ${one.approvedBy}</p>`;
|
|
17
17
|
// Quick with no quick command runs the full check; say so where the choice is made.
|
|
18
18
|
const fallsBack = view.level === "quick" && view.quick === null;
|
|
19
|
-
const current = `<p><strong>${CHECK_LEVEL_WORDS[view.level]}</strong> · ${
|
|
20
|
-
(fallsBack ? `<p class="meta">No quick command yet, so builds run the full check.</p>` : "") +
|
|
21
|
-
(view.level !== "full" && view.full !== null ? `<p class="meta">The full check still runs when a pull request opens, and Merge waits for it.</p>` : "");
|
|
19
|
+
const current = html `<p><strong>${CHECK_LEVEL_WORDS[view.level]}</strong> · ${CHECK_LEVEL_HINTS[view.level]}</p>${fallsBack ? html `<p class="meta">No quick command yet, so builds run the full check.</p>` : ""}${view.level !== "full" && view.full !== null ? html `<p class="meta">The full check still runs when a pull request opens, and Merge waits for it.</p>` : ""}`;
|
|
22
20
|
if (!view.canChange) {
|
|
23
|
-
return head
|
|
24
|
-
`<section class="card check-settings"><h2>Quick check</h2>${view.quick === null ? `<p class="meta">None yet.</p>` : command(view.quick)}</section>` +
|
|
25
|
-
`<section class="card check-settings"><h2>Full check</h2>${view.full === null ? `<p class="meta">None yet.</p>` : command(view.full)}</section>`;
|
|
21
|
+
return html `${head}<section class="card check-settings">${current}</section>${batchHtml(view, null)}${reviewHtml(view, null)}<section class="card check-settings"><h2>Quick check</h2>${view.quick === null ? html `<p class="meta">None yet.</p>` : command(view.quick)}</section><section class="card check-settings"><h2>Full check</h2>${view.full === null ? html `<p class="meta">None yet.</p>` : command(view.full)}</section>`;
|
|
26
22
|
}
|
|
27
|
-
const choices = CHECK_LEVELS.map(level => `<label class="check-choice"><input type="radio" name="level" value="${level}"${level === view.level ?
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
(fallsBack ? `<p class="meta">No quick command yet, so Quick runs the full check.</p>` : "") +
|
|
32
|
-
`<p class="meta">A task can choose its own checks when it's filed. With Quick or Off, the full check runs when a pull request opens, and Merge waits for it unless you merge anyway.</p>` +
|
|
33
|
-
`${password}<button type="submit">Save</button></form>`;
|
|
34
|
-
const quickTerms = `<ul class="check-terms"><li>Runs unattended right after every Quick build, in that build's checkout.</li><li>Plain environment: no credentials.</li><li>A failure shows on the result; nothing is blocked.</li></ul>`;
|
|
35
|
-
const quickForm = (value, submit) => `<form method="post" action="/settings/checks" class="check-settings">${hidden("quick")}` +
|
|
36
|
-
`<label>Command<textarea name="command" rows="2" maxlength="2000" spellcheck="false" class="mono" required>${escape(value)}</textarea></label>` +
|
|
37
|
-
`<label>Time limit (seconds)<input type="number" name="timeout" min="1" max="3600" value="${view.quick === null ? 180 : Math.round(view.quick.timeoutMs / 1000)}" required></label>` +
|
|
38
|
-
`${quickTerms}${password}<button type="submit">${submit}</button></form>`;
|
|
23
|
+
const choices = CHECK_LEVELS.map(level => html `<label class="check-choice"><input type="radio" name="level" value="${level}"${level === view.level ? html ` checked` : ""}><span><strong>${CHECK_LEVEL_WORDS[level]}</strong><span class="meta">${CHECK_LEVEL_HINTS[level]}</span></span></label>`);
|
|
24
|
+
const levelForm = post("level", html `<fieldset><legend>After each build</legend>${choices}</fieldset>${fallsBack ? html `<p class="meta">No quick command yet, so Quick runs the full check.</p>` : ""}<p class="meta">A task can choose its own checks when it's filed. With Quick or Off, the full check runs when a pull request opens, and Merge waits for it unless you merge anyway.</p>${password}<button type="submit">Save</button>`, { class: "card check-settings" });
|
|
25
|
+
const quickTerms = html `<ul class="check-terms"><li>Runs unattended right after every Quick build, in that build's checkout.</li><li>Plain environment: no credentials.</li><li>A failure shows on the result; nothing is blocked.</li></ul>`;
|
|
26
|
+
const quickForm = (value, submit) => post("quick", html `<label>Command<textarea name="command" rows="2" maxlength="2000" spellcheck="false" class="mono" required>${value}</textarea></label><label>Time limit (seconds)<input type="number" name="timeout" min="1" max="3600" value="${view.quick === null ? 180 : Math.round(view.quick.timeoutMs / 1000)}" required></label>${quickTerms}${password}<button type="submit">${submit}</button>`, { class: "check-settings" });
|
|
39
27
|
const quick = view.quick === null
|
|
40
|
-
? `<section class="card check-settings"><h2>Quick check</h2>`
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
`<details class="settings-more"><summary>Change quick check</summary>${quickForm(view.quick.command, "Approve change")}</details>` +
|
|
45
|
-
`<details class="settings-more"><summary>Remove quick check</summary><form method="post" action="/settings/checks" class="check-settings">${hidden("quick-clear")}` +
|
|
46
|
-
`<p class="meta">Quick builds run the full check instead.</p>${password}<button type="submit" class="danger">Remove</button></form></details></section>`;
|
|
47
|
-
const full = `<details class="settings-more"><summary>Full check</summary><section class="card check-settings">` +
|
|
48
|
-
(view.full === null ? `<p class="meta">None yet. Approve one with <span class="mono">toolroll verify set --repo … --command "…"</span>.</p>` : command(view.full)) + `</section></details>`;
|
|
49
|
-
return head + levelForm + batchHtml(view, password) + reviewHtml(view, password) + quick + full;
|
|
28
|
+
? html `<section class="card check-settings"><h2>Quick check</h2>${view.suggestion === null ? html `<p class="meta">Typecheck and the tests near the change, ideally under 2 minutes.</p>` : html `<p class="meta">Suggested from the project's scripts. Edit it before approving.</p>`}${quickForm(view.suggestion ?? "", "Approve quick check")}</section>`
|
|
29
|
+
: html `<section class="card check-settings"><h2>Quick check</h2>${command(view.quick)}<details class="settings-more"><summary>Change quick check</summary>${quickForm(view.quick.command, "Approve change")}</details><details class="settings-more"><summary>Remove quick check</summary>${post("quick-clear", html `<p class="meta">Quick builds run the full check instead.</p>${password}<button type="submit" class="danger">Remove</button>`, { class: "check-settings" })}</details></section>`;
|
|
30
|
+
const full = html `<details class="settings-more"><summary>Full check</summary><section class="card check-settings">${view.full === null ? html `<p class="meta">None yet. Approve one with <span class="mono">toolroll verify set --repo … --command "…"</span>.</p>` : command(view.full)}</section></details>`;
|
|
31
|
+
return html `${head}${levelForm}${batchHtml(view, password)}${reviewHtml(view, password)}${quick}${full}`;
|
|
50
32
|
}
|
|
51
33
|
/** Batch checks: one state and one sentence; turning it on restates exactly what happens, behind a disclosure with the password. */
|
|
52
34
|
function batchHtml(view, password) {
|
|
@@ -54,17 +36,11 @@ function batchHtml(view, password) {
|
|
|
54
36
|
if (batch === undefined)
|
|
55
37
|
return "";
|
|
56
38
|
const act = batch.on ? "Turn off" : "Turn on";
|
|
57
|
-
const terms = batch.on ? `<p class="meta">Each result runs its own full check again. Results already waiting are checked now.</p>`
|
|
58
|
-
: `<ul class="check-terms"><li>When results finish within 10 minutes of each other, they're merged in a temporary checkout and the full check runs once.</li
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
: `<details class="settings-more"><summary>${act}</summary><form method="post" action="/settings/checks" class="check-settings">` +
|
|
63
|
-
`<input type="hidden" name="csrf" value="${escape(view.csrf)}"><input type="hidden" name="repo" value="${escape(view.repo)}"><input type="hidden" name="act" value="batch">` +
|
|
64
|
-
`<input type="hidden" name="on" value="${batch.on ? "0" : "1"}">${terms}${password}<button type="submit">${act}</button></form></details>`;
|
|
65
|
-
return `<section class="card check-settings" data-batch-checks="${batch.on ? "on" : "off"}"><h2>Batch checks</h2>` +
|
|
66
|
-
`<p><strong>${batch.on ? "On" : "Off"}</strong> · ${escape(BATCH_HINT)}</p>` +
|
|
67
|
-
(batch.on && view.level !== "full" ? `<p class="meta">Only Full checks are batched.</p>` : "") + `${change}</section>`;
|
|
39
|
+
const terms = batch.on ? html `<p class="meta">Each result runs its own full check again. Results already waiting are checked now.</p>`
|
|
40
|
+
: html `<ul class="check-terms"><li>When results finish within 10 minutes of each other, they're merged in a temporary checkout and the full check runs once.</li><li>If it fails, the batch is split until the result that breaks it is found. Results that conflict are checked on their own.</li><li>Nothing is merged into a real branch. Each result still lands on its own.</li></ul>`;
|
|
41
|
+
const change = password === null ? ""
|
|
42
|
+
: html `<details class="settings-more"><summary>${act}</summary>${postForm("/settings/checks", html `${terms}${password}<button type="submit">${act}</button>`, { attrs: { class: "check-settings" }, hidden: { repo: view.repo, act: "batch", on: batch.on ? "0" : "1" } })}</details>`;
|
|
43
|
+
return html `<section class="card check-settings" data-batch-checks="${batch.on ? "on" : "off"}"><h2>Batch checks</h2><p><strong>${batch.on ? "On" : "Off"}</strong> · ${BATCH_HINT}</p>${batch.on && view.level !== "full" ? html `<p class="meta">Only Full checks are batched.</p>` : ""}${change}</section>`;
|
|
68
44
|
}
|
|
69
45
|
/** Automatic review: one state, one sentence, and its one change behind a disclosure (the password). */
|
|
70
46
|
function reviewHtml(view, password) {
|
|
@@ -73,12 +49,9 @@ function reviewHtml(view, password) {
|
|
|
73
49
|
return "";
|
|
74
50
|
const state = review.on ? (review.source === "hands-off" ? "On while hands-off lasts" : "On") : "Off";
|
|
75
51
|
const act = review.on ? "Turn off" : "Turn on";
|
|
76
|
-
const change = password ===
|
|
77
|
-
: `<details class="settings-more"><summary>${act}</summary
|
|
78
|
-
|
|
79
|
-
`<input type="hidden" name="on" value="${review.on ? "0" : "1"}">${password}<button type="submit">${act}</button></form></details>`;
|
|
80
|
-
return `<section class="card check-settings" data-review-switch="${review.on ? "on" : "off"}"><h2>Automatic review</h2>` +
|
|
81
|
-
`<p><strong>${state}</strong> · One read-only review after each build passes its checks. Only high findings send it back, once.</p>${change}</section>`;
|
|
52
|
+
const change = password === null ? ""
|
|
53
|
+
: html `<details class="settings-more"><summary>${act}</summary>${postForm("/settings/checks", html `${password}<button type="submit">${act}</button>`, { attrs: { class: "check-settings" }, hidden: { repo: view.repo, act: "review", on: review.on ? "0" : "1" } })}</details>`;
|
|
54
|
+
return html `<section class="card check-settings" data-review-switch="${review.on ? "on" : "off"}"><h2>Automatic review</h2><p><strong>${state}</strong> · One read-only review after each build passes its checks. Only high findings send it back, once.</p>${change}</section>`;
|
|
82
55
|
}
|
|
83
56
|
export const CHECK_SETTINGS_CSS = `
|
|
84
57
|
.check-settings { display: grid; gap: .6rem; max-width: 40rem; }
|
package/dist/cli.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { type SessionCliOptions } from "./session-cli.js";
|
|
|
15
15
|
import { type TeamCliOptions } from "./team-cli.js";
|
|
16
16
|
import { type RemoteExecOptions } from "./remote-exec.js";
|
|
17
17
|
import { type UpdateCliDeps } from "./toolroll-update-cli.js";
|
|
18
|
+
import { type ReleaseCliDeps } from "./release-cli.js";
|
|
18
19
|
import { type OperateOptions } from "./operate.js";
|
|
19
20
|
export type CliOptions = {
|
|
20
21
|
roots: string[];
|
|
@@ -40,7 +41,7 @@ export type ParseResult = {
|
|
|
40
41
|
error: string;
|
|
41
42
|
};
|
|
42
43
|
type Write = (line: string) => void;
|
|
43
|
-
export declare const HELP = "toolroll \u2014 a control plane for unattended coding agents\n\nUsage\n toolroll [path...] report what is in flight\n toolroll pulls report what is waiting on a person\n toolroll graph report which work graph is already here\n toolroll repos list connected repositories, and how to adjust\n toolroll repos add <path> add a project; it is in the console at once (no path: the repo you are in)\n toolroll repos remove <path>\n take it out of the console; its tasks and results stay\n toolroll repos add-from-github <owner/name> --root <dir>\n preview, then clone and connect (--yes)\n toolroll link put `toolroll` on your PATH\n toolroll unlink take it off again\n toolroll update update to the latest release: verified, drained, undoable\n (preview first; --yes, --now, --at HH:MM, --rollback)\n toolroll contract the machine contract: envelope version + capabilities\n (--commands dumps the declared command guide)\n toolroll skills install --claude-code [--dir <path>]\n install this binary's guides for Claude Code (preview first)\n toolroll skills install teach a repo's agents this queue exists (preview first)\n toolroll skills list the guides this exact binary serves\n toolroll skills get <name> print one guide (version-matched, never stale)\n toolroll demo a seeded throwaway sandbox \u2014 see it working in 90 seconds\n toolroll up app + builder for every saved project \u2014 the normal start\n toolroll onboard make your agent Toolroll's lead: add this repo, install its skill (--yes), offer starter flows (--starter)\n toolroll status running, queued, ready results, release check and plan windows\n toolroll health recent server latency, write waits and live streams\n toolroll integrations which integrations work, and what to do about the ones that don't (--json)\n toolroll session native coding sessions through the running service\n toolroll connect save a private connection to your central service\n toolroll lead named leads on the connected service\n toolroll lead token mint your lead agent's credential: its own work pings nobody\n toolroll lead say \"<text>\" (the lead) one short message in its person's chat\n toolroll conversation shared and private conversations on that service\n toolroll chat --lead <id> --conversation <id> central chat (use --local for local chat)\n\nOperating the queue \u2014 `toolroll task` prints the whole surface,\nand any queue command + --help prints it too\n toolroll approver add <name>\n mint the credential that lets a person say yes\n toolroll ready what could be dispatched right now\n toolroll check-progress <run> current or final approved check progress\n toolroll task wait <id> [--timeout <seconds>]\n wait for this attempt to finish or need a person\n toolroll task add <title> queue work\n toolroll task scope <id> --goal <text>\n state what success is; approval binds to it\n toolroll task approve <id>\n the yes \u2014 nothing builds without one\n toolroll claim <id> --runner <name>\n toolroll heartbeat <lease> / release <lease> / reap\n toolroll tick --runner <name> --token <t> --repo <path>\n one unattended pass over the ready set\n toolroll flows list | show <id> | create | edit | trigger | script | card | archive\n set up and inspect flows (writes preview until --yes)\n toolroll chat --as <you> --token <t>\n talk to the mate: one conversation across every\n project; it proposes, you confirm (--say \"\u2026\" for one turn)\n toolroll serve --repo <path> advanced: run only the console\n (--editor vscode with --runner: file links\n open in VS Code on the device you browse from)\n toolroll watch / daemon install advanced: run only the builder\n toolroll reconcile recover what the last stretch left behind\n\nWith nothing connected it reports everything it can find below the working\ndirectory. Once you connect repositories it reports those instead.\n\nOptions\n --all report everything discoverable, ignoring connected repos\n --depth <n> directory levels to descend (default: 6)\n --hidden include dot-directories, which are skipped by default\n --dirty also read each working tree for uncommitted files\n --local branches only: no network, no pull requests, no issues\n --json emit a machine-readable envelope instead of a report\n -o <file> also write that envelope to a file (requires --json)\n -h, --help show this\n\nNothing is written, installed, or configured. Every repository is read\nthrough git with --no-optional-locks, so a scan never contends for the\nindex lock with an editor you have open.\n\n--dirty is off by default because reading a working tree is unbounded\nwork: on a large or cloud-synced repo `git status` can take minutes,\nwhere listing branches takes milliseconds.\n\nlink shows what it would do and changes nothing; add --yes to apply it,\nor --to <dir> to choose where. It never uses sudo, never leaves your\nhome directory, and never touches a file it did not create.";
|
|
44
|
+
export declare const HELP = "toolroll \u2014 a control plane for unattended coding agents\n\nUsage\n toolroll [path...] report what is in flight\n toolroll pulls report what is waiting on a person\n toolroll graph report which work graph is already here\n toolroll repos list connected repositories, and how to adjust\n toolroll repos add <path> add a project; it is in the console at once (no path: the repo you are in)\n toolroll repos remove <path>\n take it out of the console; its tasks and results stay\n toolroll repos add-from-github <owner/name> --root <dir>\n preview, then clone and connect (--yes)\n toolroll link put `toolroll` on your PATH\n toolroll unlink take it off again\n toolroll update update to the latest release: verified, drained, undoable\n (preview first; --yes, --now, --at HH:MM, --rollback)\n toolroll release <branch> release Toolroll itself: gate, your approval, deploy, merge, tag, publish\n (resumable: rerun to continue; --help)\n toolroll contract the machine contract: envelope version + capabilities\n (--commands dumps the declared command guide)\n toolroll skills install --claude-code [--dir <path>]\n install this binary's guides for Claude Code (preview first)\n toolroll skills install teach a repo's agents this queue exists (preview first)\n toolroll skills list the guides this exact binary serves\n toolroll skills get <name> print one guide (version-matched, never stale)\n toolroll demo a seeded throwaway sandbox \u2014 see it working in 90 seconds\n toolroll up app + builder for every saved project \u2014 the normal start\n toolroll onboard make your agent Toolroll's lead: add this repo, install its skill (--yes), offer starter flows (--starter)\n toolroll status running, queued, ready results, release check and plan windows\n toolroll health recent server latency, write waits and live streams\n toolroll integrations which integrations work, and what to do about the ones that don't (--json)\n toolroll session native coding sessions through the running service\n toolroll connect save a private connection to your central service\n toolroll lead named leads on the connected service\n toolroll lead token mint your lead agent's credential: its own work pings nobody\n toolroll lead say \"<text>\" (the lead) one short message in its person's chat\n toolroll conversation shared and private conversations on that service\n toolroll chat --lead <id> --conversation <id> central chat (use --local for local chat)\n\nOperating the queue \u2014 `toolroll task` prints the whole surface,\nand any queue command + --help prints it too\n toolroll approver add <name>\n mint the credential that lets a person say yes\n toolroll ready what could be dispatched right now\n toolroll check-progress <run> current or final approved check progress\n toolroll task wait <id> [--timeout <seconds>]\n wait for this attempt to finish or need a person\n toolroll task add <title> queue work\n toolroll task scope <id> --goal <text>\n state what success is; approval binds to it\n toolroll task approve <id>\n the yes \u2014 nothing builds without one\n toolroll claim <id> --runner <name>\n toolroll heartbeat <lease> / worker release <lease> / reap\n toolroll tick --runner <name> --token <t> --repo <path>\n one unattended pass over the ready set\n toolroll flows list | show <id> | create | edit | trigger | script | card | archive\n set up and inspect flows (writes preview until --yes)\n toolroll chat --as <you> --token <t>\n talk to the mate: one conversation across every\n project; it proposes, you confirm (--say \"\u2026\" for one turn)\n toolroll serve --repo <path> advanced: run only the console\n (--editor vscode with --runner: file links\n open in VS Code on the device you browse from)\n toolroll watch / daemon install advanced: run only the builder\n toolroll reconcile recover what the last stretch left behind\n\nWith nothing connected it reports everything it can find below the working\ndirectory. Once you connect repositories it reports those instead.\n\nOptions\n --all report everything discoverable, ignoring connected repos\n --depth <n> directory levels to descend (default: 6)\n --hidden include dot-directories, which are skipped by default\n --dirty also read each working tree for uncommitted files\n --local branches only: no network, no pull requests, no issues\n --json emit a machine-readable envelope instead of a report\n -o <file> also write that envelope to a file (requires --json)\n -h, --help show this\n\nNothing is written, installed, or configured. Every repository is read\nthrough git with --no-optional-locks, so a scan never contends for the\nindex lock with an editor you have open.\n\n--dirty is off by default because reading a working tree is unbounded\nwork: on a large or cloud-synced repo `git status` can take minutes,\nwhere listing branches takes milliseconds.\n\nlink shows what it would do and changes nothing; add --yes to apply it,\nor --to <dir> to choose where. It never uses sudo, never leaves your\nhome directory, and never touches a file it did not create.";
|
|
44
45
|
export declare function parseArgs(argv: readonly string[]): ParseResult;
|
|
45
46
|
/** The commands that operate the queue rather than report on the world. */
|
|
46
47
|
/** Every verb the CLI routes OUTSIDE runOperate. Exported (with
|
|
@@ -65,6 +66,7 @@ export type MainOptions = {
|
|
|
65
66
|
clone?: typeof cloneGithubRepo;
|
|
66
67
|
};
|
|
67
68
|
update?: UpdateCliDeps;
|
|
69
|
+
release?: ReleaseCliDeps;
|
|
68
70
|
};
|
|
69
71
|
/**
|
|
70
72
|
* Strip `-o <file>` / `--output <file>` before dispatch. The flag belongs to
|
package/dist/cli.js
CHANGED
|
@@ -35,6 +35,7 @@ import { detectGraphs, chooseBackend, setupOptions, LABELS as GRAPH_LABELS, } fr
|
|
|
35
35
|
import { openStore, openStoreReadOnly, databasePath } from "./store.js";
|
|
36
36
|
import { PACKAGE_VERSION } from "./version.js";
|
|
37
37
|
import { runUpdateCommand } from "./toolroll-update-cli.js";
|
|
38
|
+
import { runReleaseCommand } from "./release-cli.js";
|
|
38
39
|
import { runOperate, OPERATE_HELP } from "./operate.js";
|
|
39
40
|
import { renderReport, renderPulls, renderGraph } from "./render.js";
|
|
40
41
|
import { readRemote } from "./remote.js";
|
|
@@ -57,6 +58,8 @@ Usage
|
|
|
57
58
|
toolroll unlink take it off again
|
|
58
59
|
toolroll update update to the latest release: verified, drained, undoable
|
|
59
60
|
(preview first; --yes, --now, --at HH:MM, --rollback)
|
|
61
|
+
toolroll release <branch> release Toolroll itself: gate, your approval, deploy, merge, tag, publish
|
|
62
|
+
(resumable: rerun to continue; --help)
|
|
60
63
|
toolroll contract the machine contract: envelope version + capabilities
|
|
61
64
|
(--commands dumps the declared command guide)
|
|
62
65
|
toolroll skills install --claude-code [--dir <path>]
|
|
@@ -92,7 +95,7 @@ and any queue command + --help prints it too
|
|
|
92
95
|
toolroll task approve <id>
|
|
93
96
|
the yes — nothing builds without one
|
|
94
97
|
toolroll claim <id> --runner <name>
|
|
95
|
-
toolroll heartbeat <lease> / release <lease> / reap
|
|
98
|
+
toolroll heartbeat <lease> / worker release <lease> / reap
|
|
96
99
|
toolroll tick --runner <name> --token <t> --repo <path>
|
|
97
100
|
one unattended pass over the ready set
|
|
98
101
|
toolroll flows list | show <id> | create | edit | trigger | script | card | archive
|
|
@@ -196,7 +199,7 @@ export function parseArgs(argv) {
|
|
|
196
199
|
* which answers as `scan`. */
|
|
197
200
|
export const TOP_LEVEL_COMMANDS = [
|
|
198
201
|
"", "pulls", "graph", "repos", "repos add", "repos remove", "repos add-from-github",
|
|
199
|
-
"link", "unlink", "update", "contract", "skills list", "skills get", "skills install", "demo",
|
|
202
|
+
"link", "unlink", "update", "release", "contract", "skills list", "skills get", "skills install", "demo",
|
|
200
203
|
...SESSION_CLI_ACTIONS.map(action => `session ${action}`),
|
|
201
204
|
...TEAM_CLI_ACTIONS,
|
|
202
205
|
];
|
|
@@ -230,7 +233,7 @@ export const OPERATE_COMMANDS = new Set([
|
|
|
230
233
|
"models",
|
|
231
234
|
"claim",
|
|
232
235
|
"heartbeat",
|
|
233
|
-
"
|
|
236
|
+
"worker",
|
|
234
237
|
"reap",
|
|
235
238
|
"enroll",
|
|
236
239
|
"grants",
|
|
@@ -417,6 +420,9 @@ async function dispatch(argv, write, mainOptions) {
|
|
|
417
420
|
}
|
|
418
421
|
if (first === "update")
|
|
419
422
|
return runUpdateCommand(rest, write, mainOptions.update);
|
|
423
|
+
if (first === "release") {
|
|
424
|
+
return runReleaseCommand(rest, write, { releaseLease: lease => runOperate("worker", ["release", ...lease], write, mainOptions.operate ?? {}), ...mainOptions.release });
|
|
425
|
+
}
|
|
420
426
|
if (first === "contract")
|
|
421
427
|
return runContractCommand(rest, write);
|
|
422
428
|
if (first === "session")
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CodingHandoffPreview } from './coding-handoff.js';
|
|
2
|
+
import { type Html } from './html.js';
|
|
2
3
|
/** A reviewable handoff. The next screen retains the existing approval terms. */
|
|
3
|
-
export declare function codingShippingHtml(preview: CodingHandoffPreview,
|
|
4
|
+
export declare function codingShippingHtml(preview: CodingHandoffPreview, values?: URLSearchParams, error?: string): Html;
|
|
4
5
|
export declare const CODING_SHIPPING_CSS = ".coding-workspace.coding-handoff{display:block;max-width:780px}.coding-handoff h1{margin-bottom:12px}.coding-handoff>p{margin-top:12px}.coding-workspace .coding-check{display:flex;align-items:center;gap:10px;min-height:44px}.coding-workspace .coding-check input{width:20px;height:20px;flex:0 0 20px}";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { html, postForm } from './html.js';
|
|
2
2
|
/** A reviewable handoff. The next screen retains the existing approval terms. */
|
|
3
|
-
export function codingShippingHtml(preview,
|
|
4
|
-
const hidden = (name, value) => `<input type="hidden" name="${name}" value="${escape(value)}">`;
|
|
3
|
+
export function codingShippingHtml(preview, values, error) {
|
|
5
4
|
const goal = values?.get('goal') ?? preview.title;
|
|
6
5
|
const criteria = values?.get('acceptance') ?? '';
|
|
7
6
|
const notice = error?.startsWith('Review screenshots are not ready.')
|
|
8
|
-
? `<p class="coding-notice" role="alert">Screenshots needed. Ask Codex to capture and commit them, then try again.</p><details><summary>Technical details</summary><p>${
|
|
9
|
-
: error ? `<p class="coding-notice" role="alert">${
|
|
10
|
-
|
|
7
|
+
? html `<p class="coding-notice" role="alert">Screenshots needed. Ask Codex to capture and commit them, then try again.</p><details><summary>Technical details</summary><p>${error}</p></details>`
|
|
8
|
+
: error ? html `<p class="coding-notice" role="alert">${error}</p>` : '';
|
|
9
|
+
const form = postForm(`/code/${preview.sessionId}/ship`, html `<label>Outcome<textarea name="goal" rows="4" required maxlength="16000">${goal}</textarea></label><label>Checks for review<textarea name="acceptance" rows="4" required maxlength="16000" placeholder="One observable result per line">${criteria}</textarea></label><label class="coding-check"><input type="checkbox" name="visual" value="yes"${values?.get('visual') === 'yes' ? html ` checked` : ''}>Include desktop and phone screenshots</label><details><summary>${preview.changedPaths.length} changed files · commit ${preview.candidate.slice(0, 8)}</summary><ul>${preview.changedPaths.map(path => html `<li><code>${path}</code></li>`)}</ul><p class="coding-meta">Review covers the complete change from ${preview.base} to ${preview.candidate}.</p></details><p class="coding-terms">Verification and publication use this project’s existing approval process.</p><button type="submit">Create review task</button>`, { attrs: { class: 'coding-start' }, hidden: { base: preview.base, candidate: preview.candidate, title: preview.title } });
|
|
10
|
+
return html `<section class="coding-workspace coding-handoff" data-coding-session=""><h1>Review for shipping</h1><p>${preview.title}</p>${notice}${form}<p><a href="/code/${preview.sessionId}">Back to coding</a></p></section>`;
|
|
11
11
|
}
|
|
12
12
|
export const CODING_SHIPPING_CSS = `.coding-workspace.coding-handoff{display:block;max-width:780px}.coding-handoff h1{margin-bottom:12px}.coding-handoff>p{margin-top:12px}.coding-workspace .coding-check{display:flex;align-items:center;gap:10px;min-height:44px}.coding-workspace .coding-check input{width:20px;height:20px;flex:0 0 20px}`;
|
package/dist/coding-ui.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CodingSession, CodingSnapshot } from './coding-types.js';
|
|
2
|
+
import { type Html } from './html.js';
|
|
2
3
|
export declare function codingWorkspaceHtml(input: {
|
|
3
4
|
projects: {
|
|
4
5
|
path: string;
|
|
@@ -6,12 +7,13 @@ export declare function codingWorkspaceHtml(input: {
|
|
|
6
7
|
}[];
|
|
7
8
|
sessions: CodingSession[];
|
|
8
9
|
selected: CodingSnapshot | null;
|
|
10
|
+
/** The page script posts with it (data-coding-csrf); the forms get theirs from postForm. */
|
|
9
11
|
csrf: string;
|
|
10
12
|
project: string | null;
|
|
11
13
|
error?: string;
|
|
12
14
|
draft?: string;
|
|
13
15
|
available: boolean;
|
|
14
16
|
owner?: string;
|
|
15
|
-
}):
|
|
17
|
+
}): Html;
|
|
16
18
|
export declare const CODING_CSS = "\n.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}\n.coding-workspace *{box-sizing:border-box}.coding-workspace [hidden]{display:none!important}.coding-workspace h1{font-size:1.45rem;line-height:1.25;margin:0}.coding-workspace h2{font-size:1rem;margin:0}.coding-workspace h3{font-size:1rem;margin:0 0 12px}.coding-workspace p{margin:0 0 12px}.coding-main,.coding-sidebar{min-width:0}.coding-meta,.coding-workspace small{font-size:.83rem;color:var(--muted-foreground,#747981)}\n.coding-sidebar-top,.coding-header,.coding-state-row,.coding-actions{display:flex;align-items:center;gap:12px;justify-content:space-between}.coding-sidebar-top{margin-bottom:12px}.coding-header{align-items:flex-start;margin-bottom:16px}.coding-header .coding-meta{margin:6px 0 0}.coding-session-detail{max-width:220px}.coding-session-detail summary{font-size:.82rem}.coding-session-detail dl{font-size:.82rem}.coding-session-detail dt{font-weight:600;margin-top:8px}.coding-session-detail dd{margin:2px 0 0}.coding-state-row{flex-wrap:wrap;padding:10px 0;border-bottom:1px solid var(--border,#353940);margin-bottom:12px}.coding-state-row p{margin:0;font-weight:600}.coding-state-row form{margin:0}\n.coding-session-list{max-height:74vh;overflow:auto}.coding-sidebar ul{list-style:none;margin:0;padding:0;display:grid;gap:4px}.coding-sidebar nav a{display:block;padding:12px;border-radius:10px;text-decoration:none;color:inherit}.coding-sidebar nav a:hover,.coding-sidebar nav a[aria-current]{background:var(--muted,#22252a)}.coding-sidebar nav a[aria-current]{box-shadow:inset 3px 0 var(--primary,#90bfa7)}.coding-sidebar nav span,.coding-sidebar nav small{display:block}.coding-sidebar nav [data-coding-status-for]{display:inline}.coding-sidebar nav small{margin-top:5px}.coding-mobile-sessions{display:none}\n.coding-workspace form:not(.coding-state-row form){display:grid;gap:12px;margin:0}.coding-workspace label{display:grid;gap:6px;font-size:.9rem;font-weight:500}.coding-workspace input,.coding-workspace textarea,.coding-workspace select{width:100%;min-width:0;max-width:100%;font-size:16px;border:1px solid var(--border,#353940);border-radius:8px;padding:11px 12px;background:var(--background,#14161a);color:var(--foreground,#f0f1f3)}.coding-workspace textarea{resize:vertical;line-height:1.5}.coding-workspace input:focus-visible,.coding-workspace textarea:focus-visible,.coding-workspace select:focus-visible,.coding-workspace button:focus-visible,.coding-workspace summary:focus-visible,.coding-workspace a:focus-visible{outline:2px solid var(--ring,#79acff);outline-offset:3px}.coding-workspace button,.coding-link-button{min-height:44px;padding:10px 15px;white-space:nowrap;border-radius:8px;max-width:100%;font-size:.9rem}.coding-workspace button{justify-self:start;cursor:pointer}.coding-workspace button:disabled{cursor:default;opacity:.55}.coding-workspace .coding-secondary{background:transparent;color:inherit;border:1px solid var(--border,#353940)}.coding-link-button{display:inline-flex;align-items:center;justify-content:center;text-decoration:none;color:inherit;border:1px solid var(--border,#353940)}.coding-workspace summary{cursor:pointer;min-height:44px;padding:12px 0}.coding-actions{justify-content:flex-start;flex-wrap:wrap}.coding-start{max-width:680px}.coding-options label+label{margin-top:12px}.coding-terms{font-size:.9rem;line-height:1.6;margin:0!important}.coding-empty{padding:28px 0}\n.coding-notice{border:1px solid var(--destructive,#bd7674);border-radius:10px;padding:12px;line-height:1.5;margin-bottom:16px}.coding-conversation{max-height:min(58vh,640px);min-height:140px;overflow:auto;overscroll-behavior:contain;scrollbar-gutter:stable;padding:4px 10px 12px 0}.coding-message{padding:14px 0}.coding-message strong{display:block;font-size:.78rem;margin-bottom:7px;color:var(--muted-foreground,#747981)}.coding-user{margin:8px 0 8px 32px;padding:14px 16px;border-radius:12px;background:var(--muted,#22252a)}.coding-text{white-space:pre-wrap;line-height:1.6;overflow-wrap:anywhere}.coding-tool{border-bottom:1px solid var(--border,#353940);font-size:.88rem}.coding-workspace pre{white-space:pre-wrap;overflow-wrap:anywhere;max-width:100%;font-size:.8rem;line-height:1.5;margin:0 0 12px}.coding-tool summary{display:list-item}.coding-tool summary span{margin-left:6px}.coding-composer{border-top:1px solid var(--border,#353940);padding-top:14px;margin-top:8px!important}.coding-composer label{font-size:.83rem}.coding-request{border:1px solid var(--border,#353940);border-radius:12px;padding:16px;margin:12px 0}.coding-permission-detail{max-height:240px;overflow:auto}.coding-changes{margin-top:20px;border-top:1px solid var(--border,#353940)}.coding-changes pre{max-height:min(50dvh,480px);overflow:auto}.coding-change-meta{font-size:.8rem}.coding-workspace #coding-latest{margin:8px 0}.coding-workspace #coding-connection{line-height:1.4}\n.coding-workspace .coding-start>button[type=\"submit\"],.coding-workspace .coding-composer button[type=\"submit\"]{background:var(--primary,#171717);color:var(--primary-foreground,#fff);border:1px solid var(--primary,#171717);font-weight:600;box-shadow:none}.coding-workspace .coding-start>button[type=\"submit\"]:not(:disabled):hover,.coding-workspace .coding-composer button[type=\"submit\"]:not(:disabled):hover{filter:brightness(.9)}\n.coding-workspace:not([data-coding-session=\"\"]) .coding-main{display:flex;flex-direction:column;min-height:calc(100dvh - 180px)}.coding-main>.coding-header,.coding-main>.coding-state-row,.coding-main>#coding-requests,.coding-main>.coding-composer,.coding-main>.coding-changes,.coding-main>.coding-notice,.coding-main>#coding-connection{flex-shrink:0}.coding-workspace:not([data-coding-session=\"\"]) .coding-conversation{flex:1 1 120px;min-height:100px;max-height:min(58dvh,640px)}.coding-workspace .coding-tool{margin:4px 0;padding:0 10px;border-radius:8px}.coding-workspace .coding-session-detail{margin:0;padding:0 10px;flex-shrink:0}.coding-workspace .coding-changes{padding:0 12px;margin-top:12px}.coding-text strong{display:inline;font-size:inherit;color:inherit;margin:0;font-weight:600}.coding-composer textarea{min-height:72px;max-height:180px}\n@media(max-width:760px){.coding-workspace{grid-template-columns:minmax(0,1fr);gap:16px}.coding-sidebar{border-bottom:1px solid var(--border,#353940);padding-bottom:12px}.coding-sidebar-top h2,.coding-session-list{display:none}.coding-sidebar-top{float:right;margin:0 0 8px 12px}.coding-mobile-sessions{display:block;max-width:100%;margin:0}.coding-mobile-sessions>nav{max-height:260px;overflow:auto;clear:both}.coding-mobile-sessions>summary{min-height:44px}.coding-header{display:block}.coding-session-detail{max-width:none;margin-top:4px}.coding-session-detail summary{padding:10px 0}.coding-conversation{max-height:52vh;min-height:100px;padding-right:4px}.coding-user{margin-left:16px}.coding-workspace h1{font-size:1.25rem}.coding-workspace button,.coding-link-button{padding:10px 12px}.coding-start{max-width:none}}\n@media(max-width:760px){.coding-workspace:not([data-coding-session=\"\"]) .coding-main{min-height:calc(100dvh - 245px - env(safe-area-inset-bottom,0px))}.coding-workspace:not([data-coding-session=\"\"]) .coding-conversation{min-height:80px}.coding-header{display:flex;gap:12px}.coding-header>div{min-width:0;flex:1}.coding-header:has(.coding-session-detail[open]){flex-wrap:wrap}.coding-workspace .coding-session-detail{max-width:100px}.coding-workspace .coding-session-detail[open]{max-width:100%;flex-basis:100%}.coding-session-detail summary{white-space:nowrap}.coding-workspace .coding-mobile-sessions{padding:0 12px}.coding-composer{gap:8px!important}.coding-composer textarea{height:72px}.coding-state-row{padding:8px 0;margin-bottom:8px}}\n@media(prefers-reduced-motion:reduce){.coding-workspace *{scroll-behavior:auto!important}}\n";
|
|
17
19
|
export declare function codingWorkspaceScript(): string;
|