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
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { html, postForm } from "./html.js";
|
|
1
2
|
import { effectiveLimits, limitOverrides, PER_DAY_MAX, PER_MINUTE_MAX, REQUEST_BUDGET_DEFAULTS } from "./request-budget.js";
|
|
2
|
-
const e = (value) => String(value ?? "").replace(/[&<>"']/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
3
3
|
const n = (value) => value.toLocaleString("en-US");
|
|
4
4
|
export const REQUEST_LIMITS_CSS = `.credentials .limits{display:grid;gap:14px}.credentials .limits form{display:grid;gap:10px}.credentials .limits label{display:grid;gap:6px}` +
|
|
5
5
|
`.credentials .limits input,.credentials .limits select{box-sizing:border-box;width:100%;min-width:0}.credentials .limits .pair{display:grid;grid-template-columns:1fr 1fr;gap:10px}.credentials .limits .actions{display:flex;flex-wrap:wrap;gap:8px}` +
|
|
@@ -10,22 +10,22 @@ export function tokenLimitWords(db, token) {
|
|
|
10
10
|
return `${n(limits.perMinute)} requests a minute · ${n(limits.perDay)} a day`;
|
|
11
11
|
}
|
|
12
12
|
/** The operator's disclosure: everyone's tokens, or one token. Blank fields use the default shown. */
|
|
13
|
-
export function requestLimitsHtml(db, tokens,
|
|
13
|
+
export function requestLimitsHtml(db, tokens, now) {
|
|
14
14
|
const overrides = limitOverrides(db);
|
|
15
15
|
const everyone = overrides.get("*") ?? { readPerMinute: null, actPerMinute: null, perDay: null };
|
|
16
|
-
const field = (name, label, value, placeholder, max) => `<label>${label}<input type="number" name="${name}" min="1" max="${max}" step="1" inputmode="numeric" value="${value === null ? "" : value}" placeholder="${placeholder}"></label>`;
|
|
17
|
-
const password = `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password"></label>`;
|
|
18
|
-
const buttons = `<div class="actions"><button name="action" value="save">Save limits</button><button class="secondary" name="action" value="clear">Use defaults</button></div>`;
|
|
16
|
+
const field = (name, label, value, placeholder, max) => html `<label>${label}<input type="number" name="${name}" min="1" max="${max}" step="1" inputmode="numeric" value="${value === null ? "" : value}" placeholder="${placeholder}"></label>`;
|
|
17
|
+
const password = html `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password"></label>`;
|
|
18
|
+
const buttons = html `<div class="actions"><button name="action" value="save">Save limits</button><button class="secondary" name="action" value="clear">Use defaults</button></div>`;
|
|
19
19
|
const live = tokens.filter(one => one.revokedAt === null && Date.parse(one.expiresAt) > now);
|
|
20
|
-
const installation =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const one = live.length === 0 ? "" :
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return `<details class="card"><summary>Request limits</summary><div class="limits">${installation}${one}</div></details>`;
|
|
20
|
+
const installation = postForm("/settings/request-limits", html `\
|
|
21
|
+
<h3>Everyone's tokens</h3><div class="pair">${field("read-per-minute", "Read tokens, a minute", everyone.readPerMinute, String(REQUEST_BUDGET_DEFAULTS.read), PER_MINUTE_MAX)}\
|
|
22
|
+
${field("act-per-minute", "Act tokens, a minute", everyone.actPerMinute, String(REQUEST_BUDGET_DEFAULTS.act), PER_MINUTE_MAX)}</div>\
|
|
23
|
+
${field("per-day", "Each token, a day", everyone.perDay, String(REQUEST_BUDGET_DEFAULTS.day), PER_DAY_MAX)}${password}${buttons}`, { hidden: { target: "*" } });
|
|
24
|
+
const one = live.length === 0 ? "" : postForm("/settings/request-limits", html `\
|
|
25
|
+
<h3>One token</h3><label>Token<select name="target">${live.map(row => {
|
|
26
|
+
const set = overrides.get(row.id);
|
|
27
|
+
return html `<option value="${row.id}">${row.name} (${row.account}, ${row.access === "act" ? "act" : "read"})${set === undefined ? "" : " · own limits"}</option>`;
|
|
28
|
+
})}</select></label>\
|
|
29
|
+
<div class="pair">${field("per-minute", "A minute", null, "Everyone's", PER_MINUTE_MAX)}${field("per-day", "A day", null, "Everyone's", PER_DAY_MAX)}</div>${password}${buttons}`);
|
|
30
|
+
return html `<details class="card"><summary>Request limits</summary><div class="limits">${installation}${one}</div></details>`;
|
|
31
31
|
}
|
package/dist/result-review.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Nothing here reads a database or renders a full page. The server
|
|
6
6
|
* assembles the same verified records it already reads (handoff, proof,
|
|
7
7
|
* diff, matrix, publication, report) into `SharedResultFacts`; every
|
|
8
|
-
* surface prints those facts through `
|
|
8
|
+
* surface prints those facts through `resultFactsAttributeMap` (as html attributes), so a test —
|
|
9
9
|
* or a person — can check that chat, run detail, and review agree on the
|
|
10
10
|
* run, its head, its checks, its caveats, and its publication.
|
|
11
11
|
*
|
|
@@ -141,8 +141,7 @@ export type SharedResultFacts = {
|
|
|
141
141
|
/** The shared facts as the panel's data attributes, unescaped (the rebuilt
|
|
142
142
|
* result page sets them through React). */
|
|
143
143
|
export declare function resultFactsAttributeMap(facts: SharedResultFacts): Record<string, string>;
|
|
144
|
-
|
|
145
|
-
/** The shared fact names, in the order `resultFactsAttributes` writes them. */
|
|
144
|
+
/** The shared fact names, in the order `resultFactsAttributeMap` lists them. */
|
|
146
145
|
export declare const RESULT_FACT_KEYS: readonly ["run", "head", "base", "head-source", "checks", "caveats", "evidence", "publication"];
|
|
147
146
|
/** Parse the shared facts back — the test-side and proof-side reader.
|
|
148
147
|
* Only the shared keys are read; a panel's own presentation attributes
|
package/dist/result-review.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Nothing here reads a database or renders a full page. The server
|
|
6
6
|
* assembles the same verified records it already reads (handoff, proof,
|
|
7
7
|
* diff, matrix, publication, report) into `SharedResultFacts`; every
|
|
8
|
-
* surface prints those facts through `
|
|
8
|
+
* surface prints those facts through `resultFactsAttributeMap` (as html attributes), so a test —
|
|
9
9
|
* or a person — can check that chat, run detail, and review agree on the
|
|
10
10
|
* run, its head, its checks, its caveats, and its publication.
|
|
11
11
|
*
|
|
@@ -126,10 +126,7 @@ export function resultFactsAttributeMap(facts) {
|
|
|
126
126
|
"data-result-publication": facts.publicationState,
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
|
-
|
|
130
|
-
return Object.entries(resultFactsAttributeMap(facts)).map(([name, value]) => ` ${name}="${escapeAttribute(value)}"`).join("");
|
|
131
|
-
}
|
|
132
|
-
/** The shared fact names, in the order `resultFactsAttributes` writes them. */
|
|
129
|
+
/** The shared fact names, in the order `resultFactsAttributeMap` lists them. */
|
|
133
130
|
export const RESULT_FACT_KEYS = ["run", "head", "base", "head-source", "checks", "caveats", "evidence", "publication"];
|
|
134
131
|
/** Parse the shared facts back — the test-side and proof-side reader.
|
|
135
132
|
* Only the shared keys are read; a panel's own presentation attributes
|
|
@@ -426,9 +423,6 @@ export const RESULT_REVIEW_SCRIPT = String.raw `
|
|
|
426
423
|
}
|
|
427
424
|
}
|
|
428
425
|
})();`;
|
|
429
|
-
function escapeAttribute(text) {
|
|
430
|
-
return text.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
431
|
-
}
|
|
432
426
|
function unescapeAttribute(text) {
|
|
433
|
-
return text.replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
427
|
+
return text.replace(/"/g, '"').replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
434
428
|
}
|
package/dist/retention-ui.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings → Retention (v105): how long each kind of data is kept, and what
|
|
3
|
+
* the next daily sweep would remove. An instance operator's page; changes
|
|
4
|
+
* take a step-up.
|
|
5
|
+
*/
|
|
6
|
+
import { type Html } from "./html.js";
|
|
1
7
|
import { type RetentionCount, type RetentionKind, type RetentionPeriods } from "./retention.js";
|
|
2
8
|
export declare const RETENTION_CSS: string;
|
|
3
9
|
/** `chosen`: the kinds someone chose a period for; the rest keep their default. */
|
|
@@ -11,4 +17,4 @@ export type RetentionView = {
|
|
|
11
17
|
export declare function retentionHtml(view: RetentionView, notice: {
|
|
12
18
|
said?: string | null;
|
|
13
19
|
problem?: string | null;
|
|
14
|
-
}):
|
|
20
|
+
}): Html;
|
package/dist/retention-ui.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* the next daily sweep would remove. An instance operator's page; changes
|
|
4
4
|
* take a step-up.
|
|
5
5
|
*/
|
|
6
|
+
import { html, postForm } from "./html.js";
|
|
6
7
|
import { bytesWords } from "./storage.js";
|
|
7
8
|
import { RETENTION_KINDS, countWords, periodChoices, periodLabel } from "./retention.js";
|
|
8
|
-
const e = (value) => String(value ?? "").replace(/[&<>"']/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
9
9
|
export const RETENTION_CSS = `.retention{max-width:720px;min-width:0}.retention-next{margin:0 0 16px}` +
|
|
10
10
|
`.retention form{display:grid;gap:0}.retention .kind{display:grid;grid-template-columns:minmax(0,1fr) 11rem;gap:4px 16px;align-items:center;padding:12px 0;border-bottom:1px solid var(--border)}` +
|
|
11
11
|
`.retention .kind .name{font-weight:500;font-size:.875rem}.retention .kind .meta{grid-column:1;margin:0}.retention .kind select{grid-column:2;grid-row:1/span 2;width:100%;min-height:44px}` +
|
|
@@ -23,17 +23,13 @@ function nextWords(view) {
|
|
|
23
23
|
return `The next daily sweep removes ${listWords(due.map(countWords))} (about ${bytesWords(bytes)}).`;
|
|
24
24
|
}
|
|
25
25
|
export function retentionHtml(view, notice) {
|
|
26
|
-
const note = notice.problem ? `<p class="problem" role="alert">${
|
|
26
|
+
const note = notice.problem ? html `<p class="problem" role="alert">${notice.problem}</p>` : notice.said ? html `<p role="status">${notice.said}</p>` : "";
|
|
27
27
|
const rows = RETENTION_KINDS.map(({ kind, label, detail }) => {
|
|
28
28
|
const current = view.periods[kind];
|
|
29
29
|
const chosen = view.chosen.includes(kind);
|
|
30
|
-
const options = periodChoices(kind, current).map(days => `<option value="${days === null ? "forever" : days}"${days === current ?
|
|
31
|
-
return `<div class="kind" data-kind="${kind}"><label class="name" for="keep-${kind}">${
|
|
32
|
-
})
|
|
33
|
-
const last = view.lastSweep === null ? "" : ` Last sweep ${
|
|
34
|
-
return `<article class="retention">${note}<p class="retention-next" data-retention-next>${
|
|
35
|
-
`<form method="post" action="/settings/retention"><input type="hidden" name="csrf" value="${e(view.csrf)}">${rows}` +
|
|
36
|
-
`<label class="step-up">Your Toolroll password<input type="password" name="password" autocomplete="current-password" required></label>` +
|
|
37
|
-
`<button type="submit">Save</button></form>` +
|
|
38
|
-
`<p class="meta">Never removed: the action ledger, and anything a task still needs (unfinished tasks, results Ready for review, anything on hold).</p></article>`;
|
|
30
|
+
const options = periodChoices(kind, current).map(days => html `<option value="${days === null ? "forever" : days}"${days === current ? html ` selected` : ""}>${periodLabel(kind, days, chosen || days !== current)}</option>`);
|
|
31
|
+
return html `<div class="kind" data-kind="${kind}"><label class="name" for="keep-${kind}">${label}</label><p class="meta">${detail}</p><select id="keep-${kind}" name="${kind}">${options}</select></div>`;
|
|
32
|
+
});
|
|
33
|
+
const last = view.lastSweep === null ? "" : ` Last sweep ${view.lastSweep.slice(0, 10)}.`;
|
|
34
|
+
return html `<article class="retention">${note}<p class="retention-next" data-retention-next>${nextWords(view)}${last}</p>${postForm("/settings/retention", html `${rows}<label class="step-up">Your Toolroll password<input type="password" name="password" autocomplete="current-password" required></label><button type="submit">Save</button>`)}<p class="meta">Never removed: the action ledger, and anything a task still needs (unfinished tasks, results Ready for review, anything on hold).</p></article>`;
|
|
39
35
|
}
|
package/dist/serve.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ServeOptions } from "./server/http.js";
|
|
2
|
+
import { type DecisionServer } from "./server/session.js";
|
|
2
3
|
export declare function createDecisionServer(options: ServeOptions): DecisionServer;
|
|
3
|
-
export {
|
|
4
|
+
export { PAGE_CSS, pinnedTheme, SENSITIVE_INPUT } from "./server/chrome.js";
|
|
5
|
+
export { redactedPath, SHUTDOWN_WAIT_MS, type ServeOptions } from "./server/http.js";
|
|
6
|
+
export { TASK_COMPOSER_MODES, type TaskComposerMode } from "./server/render-chat.js";
|
|
7
|
+
export { inboxFingerprints, parseInboxTab, queueScript, type InboxTab } from "./server/render-pages.js";
|
|
8
|
+
export { ssoStepUps, wrongHostPage } from "./server/render-people.js";
|
|
9
|
+
export { diffFileAnchor, editorFileHref, needActionOf, orderChangedFiles, plainConclusionOf, rankReviewQueue, reviewFilePriority, reviewPriorityOf, runFactsFragment, withinSignedTouches, type ReviewFileRow, type ReviewPriority, type ReviewQueueFacts } from "./server/render-results.js";
|
|
10
|
+
export { settingsGroups, settingsTiles } from "./server/render-settings.js";
|
|
11
|
+
export { decisionAnswerScript, earlierVersionsWords, revisionLineageWords, type RouteView } from "./server/render-tasks.js";
|
|
12
|
+
export { SIGN_IN_LINK_MS, SIGN_IN_LINK_PATH, type DecisionServer } from "./server/session.js";
|
package/dist/serve.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { html, htmlString, jsonScript, textHtml } from "./html.js";
|
|
1
2
|
import { browserAssetsAvailable, browserWorkspaceDocument } from './browser-shell.js';
|
|
2
3
|
import { browserCrewFromIndex, browserCrewOf, browserNavigationOf, browserProjectsOf, needsYouLabelOf } from './browser-workspace.js';
|
|
3
4
|
import { sharedActionPayload } from './chat-actions.js';
|
|
@@ -111,11 +112,18 @@ import { isAlive as runnerAlive } from "./runner.js";
|
|
|
111
112
|
import { freshIdentitySignIn } from "./scope.js";
|
|
112
113
|
import { instrumentRequest } from "./server-telemetry.js";
|
|
113
114
|
import { createChatHandlers } from './server/chat.js';
|
|
115
|
+
import { createLiveHandlers } from './server/live.js';
|
|
114
116
|
import { createFlowsHandlers } from './server/flows.js';
|
|
115
117
|
import { createPagesHandlers } from './server/pages.js';
|
|
116
118
|
import { createPeopleHandlers } from './server/people-tokens.js';
|
|
117
119
|
import { createSettingsHandlers } from './server/settings.js';
|
|
118
|
-
import {
|
|
120
|
+
import { requestContext } from "./server/request-context.js";
|
|
121
|
+
import { chromeScript, DEMO_BANNER, DEMO_BANNER_SHORT, focusDocument, KBD_HELP, pinnedTheme, QUEUE_VIEW, refuse, screen, SENSITIVE_INPUT, shell, sidebarScript } from "./server/chrome.js";
|
|
122
|
+
import { BODY_CAP, form, loginHref, matchTaskPath, page, projectChatHref, redactedPath, redirect, respond, safeReturn, SHUTDOWN_WAIT_MS, taskChatHref } from "./server/http.js";
|
|
123
|
+
import { decisionsFor, LEAD_BY_DEFAULT_FACT, mateBrowserMessages, mateChatVersion, teamProposalCardParts } from "./server/render-chat.js";
|
|
124
|
+
import {} from "./server/render-pages.js";
|
|
125
|
+
import { ssoStepUps, wrongHostPage } from "./server/render-people.js";
|
|
126
|
+
import { NO_PROJECT, NO_TOUCH_FRAGMENTS, NONCE_CAP, NONCE_TTL_MS, PersistentSessions, SESSION_ABSOLUTE_MS, SESSION_IDLE_MS, SIGN_IN_LINK_MS, SIGN_IN_LINK_PATH } from "./server/session.js";
|
|
119
127
|
import { createTasksHandlers } from './server/tasks.js';
|
|
120
128
|
import { DEFAULT_GUARD_POLICY, passwordGuardOf, provenPasswordAccount, SourceBudget, withPasswordSource } from "./sign-in-guard.js";
|
|
121
129
|
import { sourceKey } from "./source-key.js";
|
|
@@ -421,9 +429,8 @@ export function createDecisionServer(options) {
|
|
|
421
429
|
};
|
|
422
430
|
};
|
|
423
431
|
const codingProjects = () => [...new Set([...managedRepos(), ...store.listProjects().map(project => project.path)])].filter(repo => rowVisible(liveCeiling(), repo));
|
|
424
|
-
const teamStreams = new Set();
|
|
425
432
|
/** Open chat streams (live replies), ended when the server closes. */
|
|
426
|
-
|
|
433
|
+
let liveTurnStarted = () => { };
|
|
427
434
|
/** Google sign-ins in progress (v89): each consent visit's state, for 10 minutes. */
|
|
428
435
|
const googleVisits = new Map();
|
|
429
436
|
/** One-click connections on their way: the service's sign-in page and back, 15 minutes at most. */
|
|
@@ -625,12 +632,13 @@ export function createDecisionServer(options) {
|
|
|
625
632
|
}
|
|
626
633
|
if (edgeRoute === null && isEdgeAddress(url.pathname))
|
|
627
634
|
return refuseEdge(request, response, url.pathname, wrongMethodEdge);
|
|
628
|
-
|
|
635
|
+
// Live rooms share the browser identity/context below; their adapter carries token limits into each room.
|
|
636
|
+
if (edgeRoute !== null && edgeRoute.domain !== 'people' && edgeRoute.domain !== 'live')
|
|
629
637
|
return dispatchEdge(edgeRoute, { url, who: null, request, response, method });
|
|
630
638
|
// Passive polls authenticate without extending the browser session.
|
|
631
639
|
const fragmentName = url.searchParams.get("fragment");
|
|
632
640
|
const workspaceRead = method === "GET" && url.searchParams.get('format') === 'workspace';
|
|
633
|
-
const touch = !(method === "GET" && (workspaceRead || (fragmentName !== null && NO_TOUCH_FRAGMENTS.has(fragmentName)) || /^\/code\/[a-f0-9]{32}\/state$/.test(url.pathname)));
|
|
641
|
+
const touch = !(method === "GET" && (edgeRoute?.domain === 'live' || workspaceRead || (fragmentName !== null && NO_TOUCH_FRAGMENTS.has(fragmentName)) || /^\/code\/[a-f0-9]{32}\/state$/.test(url.pathname)));
|
|
634
642
|
const refuseBudget = (admitted) => {
|
|
635
643
|
if (admitted.ok)
|
|
636
644
|
return false;
|
|
@@ -644,7 +652,7 @@ export function createDecisionServer(options) {
|
|
|
644
652
|
if (refuseBudget(admitPasswordSource(request)))
|
|
645
653
|
return;
|
|
646
654
|
const refusedToken = {};
|
|
647
|
-
const who = identify(request, touch,
|
|
655
|
+
const who = identify(request, touch, edgeRoute?.domain === 'live', refusedToken);
|
|
648
656
|
if (refusedToken.principal !== undefined) {
|
|
649
657
|
if (refuseBudget(requestBudget.admit(refusedToken.principal.tokenId, "api")))
|
|
650
658
|
return;
|
|
@@ -685,8 +693,9 @@ export function createDecisionServer(options) {
|
|
|
685
693
|
// An empty password stands for a fresh identity-provider sign-in, for this person only (v100).
|
|
686
694
|
if (method === "GET" || method === "POST")
|
|
687
695
|
return freshIdentitySignIn.run({ actor: requestFacts.sso?.fresh === true ? who.name : null }, () => provenPasswordAccount.run(passwordProof, () => requestContext.run(requestFacts, async () => {
|
|
688
|
-
|
|
689
|
-
|
|
696
|
+
if (edgeRoute?.domain === 'live')
|
|
697
|
+
return dispatchEdge(edgeRoute, { url, who, request, response, method });
|
|
698
|
+
const body = method === "POST" ? await form(request, (matchedRoute?.stage === "console" ? matchedRoute.bodyCap : undefined) ?? BODY_CAP) : null;
|
|
690
699
|
const target = actionTarget(url, who, request, body === null ? null : readForm(body, CONSOLE_FORMS.ledgerTarget));
|
|
691
700
|
const execute = async () => {
|
|
692
701
|
// THE ROUTE TABLE (server/route-table.ts): nothing reaches a handler unless a row declares this method and
|
|
@@ -717,7 +726,7 @@ export function createDecisionServer(options) {
|
|
|
717
726
|
// Authorize every read before considering a conditional response.
|
|
718
727
|
// Task/result opening and receipt reconciliation always re-read work.
|
|
719
728
|
const facts = requestContext.getStore();
|
|
720
|
-
if (facts?.workspaceRead && who.via === 'cookie' &&
|
|
729
|
+
if (facts?.workspaceRead && who.via === 'cookie' && route.id === 'chat.page' &&
|
|
721
730
|
!url.searchParams.has('task') && !url.searchParams.has('result') && !url.searchParams.has('request')) {
|
|
722
731
|
const key = createHash('sha256').update(JSON.stringify([workspaceIncarnation, who.name,
|
|
723
732
|
who.session.generation, who.session.csrf, who.session.project, who.session.projectRevision,
|
|
@@ -819,7 +828,7 @@ export function createDecisionServer(options) {
|
|
|
819
828
|
// A project link is a read context, not a session-changing operation.
|
|
820
829
|
// Prove it against both admission and the known project catalog before
|
|
821
830
|
// collection queries; unknown/foreign paths reveal no work.
|
|
822
|
-
if ((
|
|
831
|
+
if ((route.id === 'work' || route.id === 'system') && url.searchParams.has('project')) {
|
|
823
832
|
const wanted = url.searchParams.get('project') ?? '';
|
|
824
833
|
if (url.searchParams.getAll('project').length !== 1 || !visible(wanted) ||
|
|
825
834
|
![...managedRepos(), ...store.listProjects().map(one => one.path)].includes(wanted)) {
|
|
@@ -836,7 +845,7 @@ export function createDecisionServer(options) {
|
|
|
836
845
|
// viewing a result never changes the session's selected project, and
|
|
837
846
|
// the page's project switch keeps showing the person's own choice.
|
|
838
847
|
const chosenProject = project;
|
|
839
|
-
if (
|
|
848
|
+
if (route.id === "review" && url.searchParams.has("result")) {
|
|
840
849
|
const wanted = url.searchParams.get("result") ?? "";
|
|
841
850
|
const ref = wanted.length > 0 && wanted.length <= 64 && !hasForbiddenControls(wanted) ? store.lookupRef(wanted) : null;
|
|
842
851
|
const namedProject = url.searchParams.get("project");
|
|
@@ -867,8 +876,8 @@ export function createDecisionServer(options) {
|
|
|
867
876
|
// and the all-projects board carry their own read context.
|
|
868
877
|
const needsProject = who.via === "cookie" && project === null && !unscopedMode &&
|
|
869
878
|
route.needsProject &&
|
|
870
|
-
!(
|
|
871
|
-
!(
|
|
879
|
+
!(route.id === "review" && url.searchParams.has("result")) &&
|
|
880
|
+
!(route.id === "board" && url.searchParams.get("scope") === "all");
|
|
872
881
|
if (needsProject)
|
|
873
882
|
return redirect(response, `/projects?return=${encodeURIComponent(safeReturn(url.pathname + url.search))}`);
|
|
874
883
|
return dispatchConsole(route, { url, who, request, response, route, now, project, chosenProject, posted: new URLSearchParams() });
|
|
@@ -1039,7 +1048,7 @@ export function createDecisionServer(options) {
|
|
|
1039
1048
|
const rows = mateConversationRows(who, principal, focusTask, now, chatProject);
|
|
1040
1049
|
return {
|
|
1041
1050
|
sessionId: session.id, user: session.approver, version: mateChatVersion({ ...rows, focusTask }),
|
|
1042
|
-
messages: mateBrowserMessages(rows,
|
|
1051
|
+
messages: mateBrowserMessages(rows, back, { task: focusTask?.id ?? null, project: chatProject }),
|
|
1043
1052
|
pendingTurnId: rows.pending?.id ?? null, requestId: randomBytes(16).toString("hex"), maxChars: MATE_MESSAGE_MAX_CHARS,
|
|
1044
1053
|
taskId: focusTask?.id ?? null, resultRunId, project: focusTask === null ? chatProject : null,
|
|
1045
1054
|
};
|
|
@@ -1187,9 +1196,7 @@ export function createDecisionServer(options) {
|
|
|
1187
1196
|
}
|
|
1188
1197
|
const saturated = open.length > 200;
|
|
1189
1198
|
const safeEntries = restricted() ? entries.filter(one => ["/work", "/work?view=needs-you", "/", "/board", "/flows", "/done", "/review", "/tasks", "/runs", "/projects", "/ledger"].includes(one.href) || one.href.startsWith("/t/")) : entries;
|
|
1190
|
-
|
|
1191
|
-
.replace(/</g, "\\u003c");
|
|
1192
|
-
return `<script type="application/json" id="palette-index">${json}</script>`;
|
|
1199
|
+
return jsonScript(saturated ? [...safeEntries, { label: "… more in the task list", href: "/tasks" }] : safeEntries, { id: "palette-index" });
|
|
1193
1200
|
}
|
|
1194
1201
|
/**
|
|
1195
1202
|
* The palette cache (arc 4, finding 6), and its honest contract: a
|
|
@@ -1232,13 +1239,13 @@ export function createDecisionServer(options) {
|
|
|
1232
1239
|
}
|
|
1233
1240
|
const teamEntry = requestContext.getStore()?.returnTo;
|
|
1234
1241
|
if (teamEntry?.startsWith('/chat') && !s.workspace?.team && !teamEntry.includes('task=') && !teamEntry.includes('proposal=') && demoLeadHere() === null) {
|
|
1235
|
-
s.body =
|
|
1242
|
+
s.body = html `<p class="team-entry"><a href="/chat?team=1">Open team chat</a></p>${s.body}`;
|
|
1236
1243
|
if (s.workspace?.conversation)
|
|
1237
|
-
s.workspace.controlsHtml =
|
|
1244
|
+
s.workspace.controlsHtml = html `<p><a href="/chat?team=1">Open team chat</a></p>${s.workspace.controlsHtml}`;
|
|
1238
1245
|
}
|
|
1239
1246
|
const sensitive = s.forceSensitive === true ||
|
|
1240
|
-
SENSITIVE_INPUT.test(s.body) ||
|
|
1241
|
-
(s.chrome?.listPane !== undefined && SENSITIVE_INPUT.test(s.chrome.listPane));
|
|
1247
|
+
SENSITIVE_INPUT.test(htmlString(s.body)) ||
|
|
1248
|
+
(s.chrome?.listPane !== undefined && SENSITIVE_INPUT.test(htmlString(s.chrome.listPane)));
|
|
1242
1249
|
const requestFacts = requestContext.getStore();
|
|
1243
1250
|
if (requestFacts?.browser && s.chrome && !s.forceSensitive && (requestFacts.workspaceRead || browserAssetsAvailable())) {
|
|
1244
1251
|
const path = new URL(requestFacts.returnTo, 'http://standing-orders.local');
|
|
@@ -1248,7 +1255,7 @@ export function createDecisionServer(options) {
|
|
|
1248
1255
|
path.searchParams.set('format', 'workspace');
|
|
1249
1256
|
// The legacy list pane (every task or build as links) duplicates the
|
|
1250
1257
|
// Crew panel and Tasks page; inside the workspace the page stands alone.
|
|
1251
|
-
const pageHtml = s.body;
|
|
1258
|
+
const pageHtml = htmlString(s.body);
|
|
1252
1259
|
const extras = s.workspace ?? {};
|
|
1253
1260
|
const notices = [...(extras.notices ?? [])];
|
|
1254
1261
|
if (s.chrome.modeBanner)
|
|
@@ -1315,9 +1322,9 @@ export function createDecisionServer(options) {
|
|
|
1315
1322
|
? { request, received: store.mateRequestReceipt(conversation.sessionId, request) !== null } : null,
|
|
1316
1323
|
projects: browserProjectsOf(s.chrome.projects ?? []), ...crew,
|
|
1317
1324
|
conversation, ...(extras.team ? { team: extras.team } : {}), focus: extras.focus ?? null, result: extras.result ?? null,
|
|
1318
|
-
catchUpHtml: extras.catchUpHtml
|
|
1325
|
+
catchUpHtml: extras.catchUpHtml === undefined ? '' : htmlString(extras.catchUpHtml), controlsHtml: extras.controlsHtml === undefined ? '' : htmlString(extras.controlsHtml), notices, view: extras.view ?? null,
|
|
1319
1326
|
...(s.chrome.demo ? { demo: { text: DEMO_BANNER, short: DEMO_BANNER_SHORT } } : {}),
|
|
1320
|
-
pageHtml: extras.pageHtml === undefined ? (conversation === null ? pageHtml : null) : extras.pageHtml,
|
|
1327
|
+
pageHtml: extras.pageHtml === undefined ? (conversation === null ? pageHtml : null) : extras.pageHtml === null ? null : htmlString(extras.pageHtml),
|
|
1321
1328
|
navigation: [...browserNavigationOf(currentPath, s.chrome.project, needsYou, tasksProject, s.chrome.inboxLabel), { label: 'Workspace tools', href: '/menu', active: path.pathname === '/menu' }],
|
|
1322
1329
|
chats,
|
|
1323
1330
|
...(s.refreshSeconds === undefined ? {} : { refreshSeconds: Math.max(5, Math.floor(s.refreshSeconds)) }),
|
|
@@ -1355,9 +1362,9 @@ export function createDecisionServer(options) {
|
|
|
1355
1362
|
const script = functional + (chromeLayer ? chromeScript() + WORKSPACE_MOTION_SCRIPT : sensitiveChrome);
|
|
1356
1363
|
const nonce = script === "" ? undefined : randomBytes(16).toString("base64");
|
|
1357
1364
|
const body = chromeLayer
|
|
1358
|
-
? `${s.body}\n${paletteTagCached(s.chrome?.project ?? null)}\n${KBD_HELP}`
|
|
1365
|
+
? html `${s.body}\n${paletteTagCached(s.chrome?.project ?? null)}\n${KBD_HELP}`
|
|
1359
1366
|
: s.body;
|
|
1360
|
-
const
|
|
1367
|
+
const document = shell(s.title, body, {
|
|
1361
1368
|
...(s.chrome === undefined ? {} : { chrome: s.chrome }),
|
|
1362
1369
|
...(sensitive ? { sensitive: true } : {}),
|
|
1363
1370
|
...(s.chrome !== undefined ? { sidebarToggle: true } : {}),
|
|
@@ -1367,7 +1374,7 @@ export function createDecisionServer(options) {
|
|
|
1367
1374
|
// Pages that ship the chrome layer keep connect-src (v28 granted it for
|
|
1368
1375
|
// the since-removed watched-session beat), beside pages whose own
|
|
1369
1376
|
// functional script polls.
|
|
1370
|
-
return page(response, status,
|
|
1377
|
+
return page(response, status, document, nonce, s.functional?.fetches === true || chromeLayer || sensitiveChrome !== "");
|
|
1371
1378
|
}
|
|
1372
1379
|
/** The needs-you count every surface wears, read from this request's own
|
|
1373
1380
|
* Work counts (one query per request, never a cached earlier one), so a
|
|
@@ -1513,41 +1520,30 @@ export function createDecisionServer(options) {
|
|
|
1513
1520
|
if (peekCache.size <= PEEK_CACHE_ENTRIES && peekCacheBytes <= PEEK_CACHE_BYTES)
|
|
1514
1521
|
break;
|
|
1515
1522
|
peekCache.delete(key);
|
|
1516
|
-
peekCacheBytes -=
|
|
1523
|
+
peekCacheBytes -= entry.bytes;
|
|
1517
1524
|
}
|
|
1518
1525
|
};
|
|
1519
1526
|
/** One typed sentence inside the region — plain words, no raw errors.
|
|
1520
1527
|
* `final` marks conditions that cannot heal for this run (finished,
|
|
1521
1528
|
* superseded, wrong machine): the region poller reads the marker and
|
|
1522
1529
|
* stops, instead of refetching a dead build every beat forever. */
|
|
1523
|
-
const peekSay = (message, final = false) => `<p class="meta"${final ?
|
|
1530
|
+
const peekSay = (message, final = false) => html `<p class="meta"${final ? html ` data-region-stop` : ""}>${message}</p>`;
|
|
1524
1531
|
/** The sanitize pipeline (finding 30/35): normalize → mask → escape. */
|
|
1525
1532
|
const peekName = (path) => {
|
|
1526
1533
|
const normalized = path.replace(/[\u0000-\u001f\u007f]/g, "");
|
|
1527
1534
|
const masked = scanForSecrets(normalized).length > 0 ? "[redacted: a credential-shaped name]" : normalized;
|
|
1528
|
-
return
|
|
1535
|
+
return textHtml(masked);
|
|
1529
1536
|
};
|
|
1530
1537
|
async function handlePost(route, url, who, request, response, posted) {
|
|
1531
|
-
|
|
1538
|
+
// Every POST passes the shared mutation guard. Caller, scope, project (including a limited account's posted repo)
|
|
1539
|
+
// and role were admitted by the route table.
|
|
1532
1540
|
const denied = authorizeMutation(request, who, readForm(posted, CONSOLE_FORMS.mutationGuard));
|
|
1533
1541
|
if (denied !== null)
|
|
1534
1542
|
return refuse(response, who, denied.status, denied.message);
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
if (
|
|
1538
|
-
|
|
1539
|
-
if (repos.length > 1 || repos.some(repo => repo.trim() !== "" && !visible(repo.trim())))
|
|
1540
|
-
return refuse(response, who, 403, "That project is outside your access.", "/projects");
|
|
1541
|
-
}
|
|
1542
|
-
// THE CENTRAL VIEWER GATE (modes chain, D2/E2): consequential POSTs
|
|
1543
|
-
// require ACTIVE approver standing — cookie and bearer alike — with
|
|
1544
|
-
// an EXACT allowlist of session-local acts, never a prefix. /login,
|
|
1545
|
-
// /logout and /join answer before this handler.
|
|
1546
|
-
if (who.role === "viewer") {
|
|
1547
|
-
if (route.viewer !== true) {
|
|
1548
|
-
return refuse(response, who, 403, "your login can watch, not act — ask an approver to upgrade you");
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1543
|
+
// Standing can change after a token was minted: a viewer's act stays refused, cookie and bearer alike, except
|
|
1544
|
+
// the row's session-local acts.
|
|
1545
|
+
if (who.role === "viewer" && !route.viewer)
|
|
1546
|
+
return refuse(response, who, 403, "your login can watch, not act — ask an approver to upgrade you");
|
|
1551
1547
|
const now = clock();
|
|
1552
1548
|
// Any accepted mutation may change what the inbox owes; the badge
|
|
1553
1549
|
// re-counts within five seconds either way, this just makes it exact.
|
|
@@ -1588,14 +1584,9 @@ export function createDecisionServer(options) {
|
|
|
1588
1584
|
requestBudget.flush();
|
|
1589
1585
|
}
|
|
1590
1586
|
catch { /* saved again on the close event when it can be */ }
|
|
1591
|
-
for (const stream of teamStreams)
|
|
1592
|
-
stream.end();
|
|
1593
|
-
teamStreams.clear();
|
|
1594
|
-
for (const stream of chatStreams)
|
|
1595
|
-
stream.end();
|
|
1596
|
-
chatStreams.clear();
|
|
1597
1587
|
flowRooms.close();
|
|
1598
1588
|
taskRooms.close();
|
|
1589
|
+
liveHandlers.close();
|
|
1599
1590
|
detachReads();
|
|
1600
1591
|
liveFollower.close();
|
|
1601
1592
|
void Promise.all([closeCoding(), bounded(team.close()), bounded(leadMaintenance?.stop()), bounded(reads?.close())]).then(() => closeServer(callback)).catch(error => {
|
|
@@ -1657,7 +1648,7 @@ export function createDecisionServer(options) {
|
|
|
1657
1648
|
get matePrincipal() { return matePrincipal; },
|
|
1658
1649
|
get chatScopeOf() { return chatScopeOf; },
|
|
1659
1650
|
get liveTurns() { return liveTurns; },
|
|
1660
|
-
get
|
|
1651
|
+
get liveTurnStarted() { return liveTurnStarted; },
|
|
1661
1652
|
get mateConversationRows() { return mateConversationRows; },
|
|
1662
1653
|
get demoLeadHere() { return demoLeadHere; },
|
|
1663
1654
|
get teamBrowserReply() { return teamBrowserReply; },
|
|
@@ -1763,7 +1754,6 @@ export function createDecisionServer(options) {
|
|
|
1763
1754
|
get allowedHost() { return allowedHost; },
|
|
1764
1755
|
get team() { return team; },
|
|
1765
1756
|
get teamBrowserReply() { return teamBrowserReply; },
|
|
1766
|
-
get teamStreams() { return teamStreams; },
|
|
1767
1757
|
get requestBudget() { return requestBudget; },
|
|
1768
1758
|
get options() { return options; },
|
|
1769
1759
|
get coding() { return coding; },
|
|
@@ -1781,13 +1771,26 @@ export function createDecisionServer(options) {
|
|
|
1781
1771
|
get teamsSourceBudget() { return teamsSourceBudget; },
|
|
1782
1772
|
get teamsTenantBudget() { return teamsTenantBudget; },
|
|
1783
1773
|
};
|
|
1774
|
+
const liveHandlers = createLiveHandlers(handlerRuntime, { bus: liveBus, workspaceRevision, chatProjectOf: chatHandlers.chatProjectOf });
|
|
1775
|
+
liveTurnStarted = liveHandlers.turnStarted;
|
|
1784
1776
|
const remoteHandlers = createRemoteHandlers(remoteRuntime);
|
|
1785
1777
|
const registry = createHandlerRegistry([
|
|
1786
1778
|
...tasksHandlers.registrations, ...flowsHandlers.registrations, ...chatHandlers.registrations,
|
|
1787
1779
|
...settingsHandlers.registrations, ...peopleHandlers.registrations, ...pagesHandlers.registrations,
|
|
1788
|
-
...remoteHandlers.registrations,
|
|
1780
|
+
...remoteHandlers.registrations, ...liveHandlers.registrations,
|
|
1789
1781
|
]);
|
|
1790
|
-
|
|
1782
|
+
/** The row's role, after admission and before its one handler. */
|
|
1783
|
+
function dispatchConsole(route, ctx) {
|
|
1784
|
+
const { who, response } = ctx;
|
|
1785
|
+
const held = route.role === "any" || ((!route.roleBrowser || who.via === "cookie") &&
|
|
1786
|
+
(route.role === "approver" ? who.role === "approver" : store.isInstanceOperator(who.name)));
|
|
1787
|
+
if (!held) {
|
|
1788
|
+
ctx.request.resume();
|
|
1789
|
+
const refusal = route.roleRefusal;
|
|
1790
|
+
return Promise.resolve("message" in refusal ? refuse(response, who, 403, refusal.message, refusal.back) : respond(response, refusal.status, refusal.type, refusal.body));
|
|
1791
|
+
}
|
|
1792
|
+
return registry.console(route, ctx);
|
|
1793
|
+
}
|
|
1791
1794
|
async function dispatchEdge(route, ctx) {
|
|
1792
1795
|
if (route.callers.length === 1 && route.callers[0] === 'cookie' && ctx.request.headers.authorization !== undefined) {
|
|
1793
1796
|
return respond(ctx.response, 403, 'text/plain; charset=utf-8', 'This address needs a browser sign-in.');
|
|
@@ -1801,4 +1804,12 @@ export function createDecisionServer(options) {
|
|
|
1801
1804
|
}
|
|
1802
1805
|
return Object.assign(server, { mintSignInLink, closeCoding });
|
|
1803
1806
|
}
|
|
1804
|
-
export {
|
|
1807
|
+
export { PAGE_CSS, pinnedTheme, SENSITIVE_INPUT } from "./server/chrome.js";
|
|
1808
|
+
export { redactedPath, SHUTDOWN_WAIT_MS } from "./server/http.js";
|
|
1809
|
+
export { TASK_COMPOSER_MODES } from "./server/render-chat.js";
|
|
1810
|
+
export { inboxFingerprints, parseInboxTab, queueScript } from "./server/render-pages.js";
|
|
1811
|
+
export { ssoStepUps, wrongHostPage } from "./server/render-people.js";
|
|
1812
|
+
export { diffFileAnchor, editorFileHref, needActionOf, orderChangedFiles, plainConclusionOf, rankReviewQueue, reviewFilePriority, reviewPriorityOf, runFactsFragment, withinSignedTouches } from "./server/render-results.js";
|
|
1813
|
+
export { settingsGroups, settingsTiles } from "./server/render-settings.js";
|
|
1814
|
+
export { decisionAnswerScript, earlierVersionsWords, revisionLineageWords } from "./server/render-tasks.js";
|
|
1815
|
+
export { SIGN_IN_LINK_MS, SIGN_IN_LINK_PATH } from "./server/session.js";
|
package/dist/server/chat.d.ts
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import type { Registration } from './handler-registry.js';
|
|
2
1
|
import { type BrowserFirstRun, type BrowserHome, type BrowserPhoneCard } from '../browser-workspace.js';
|
|
3
2
|
import { type DemoResultView } from "../demo-chat.js";
|
|
4
3
|
import type { DemoExchange } from "../demo.js";
|
|
5
4
|
import { type FirstTaskSuggestion } from "../first-run.js";
|
|
6
5
|
import type { MateProgress } from "../mate-progress.js";
|
|
7
6
|
import type { DirectChatProviderId } from "../store.js";
|
|
8
|
-
import type { HandlerContext } from './handler-context.js';
|
|
9
7
|
import type { ServerRuntime } from './runtime.js';
|
|
10
|
-
import { type ChatEnablement
|
|
8
|
+
import { type ChatEnablement } from "./render-chat.js";
|
|
9
|
+
import { type Session, type Who } from "./session.js";
|
|
11
10
|
export declare function createChatHandlers(runtime: ServerRuntime): {
|
|
12
|
-
registrations: Registration[];
|
|
13
|
-
get: (ctx: HandlerContext) => Promise<void>;
|
|
14
|
-
post: (ctx: HandlerContext) => Promise<void>;
|
|
11
|
+
registrations: import("./handler-registry.js").Registration[];
|
|
15
12
|
chatFirstRun: (now: Date, project: string | null) => BrowserFirstRun | undefined;
|
|
16
13
|
phoneCard: (who: Who & {
|
|
17
14
|
via: "cookie";
|