toolroll 0.9.54 → 0.9.56
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 +19 -0
- package/README.md +29 -12
- package/dist/action-ledger.d.ts +2 -4
- package/dist/action-ledger.js +2 -10
- package/dist/agent-onboard.js +4 -1
- package/dist/approval-policy.d.ts +5 -5
- package/dist/approval-policy.js +4 -4
- package/dist/approval-rules-ui.d.ts +3 -2
- package/dist/approval-rules-ui.js +17 -22
- 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 +14 -15
- package/dist/browser-workspace.js +0 -3
- package/dist/budget-alerts.js +3 -3
- package/dist/chat-actions.d.ts +23 -18
- package/dist/chat-actions.js +110 -88
- package/dist/chat-ask.d.ts +2 -2
- package/dist/chat-ask.js +5 -5
- package/dist/chat-channel.d.ts +15 -15
- package/dist/chat-channel.js +20 -20
- package/dist/chat-controls.d.ts +0 -4
- package/dist/chat-controls.js +0 -1
- package/dist/chat-core.js +1 -1
- package/dist/chat-delivery-state.js +2 -2
- package/dist/chat-delivery.d.ts +2 -2
- package/dist/chat-delivery.js +27 -34
- package/dist/chat-flow.js +3 -3
- package/dist/chat-messages.d.ts +1 -1
- package/dist/chat-messages.js +4 -4
- package/dist/chat-migration.d.ts +1 -1
- package/dist/chat-migration.js +11 -11
- package/dist/chat-polish.d.ts +5 -4
- package/dist/chat-polish.js +9 -10
- package/dist/chat-rooms.js +3 -3
- package/dist/chat-warmth.d.ts +2 -2
- 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 +15 -10
- package/dist/coding-shipping-ui.d.ts +2 -1
- package/dist/coding-shipping-ui.js +6 -6
- package/dist/coding-ui.d.ts +3 -1
- package/dist/coding-ui.js +30 -29
- package/dist/contracts/chat-actions.d.ts +32 -27
- package/dist/contracts/chat-actions.js +29 -11
- package/dist/contracts/chat-content.d.ts +1 -1
- package/dist/contracts/chat-content.js +1 -1
- package/dist/contracts/chat-tables.js +4 -4
- package/dist/contracts/cli.d.ts +1 -3
- package/dist/contracts/console-api.d.ts +7 -7
- package/dist/contracts/console-api.js +13 -12
- package/dist/contracts/flow-propose.d.ts +3 -3
- package/dist/contracts/flow.d.ts +132 -125
- package/dist/contracts/flow.js +27 -12
- package/dist/contracts/health.d.ts +1 -3
- package/dist/contracts/lead-context.d.ts +1 -1
- package/dist/contracts/lead-context.js +2 -2
- package/dist/contracts/lead-tools.d.ts +20 -18
- package/dist/contracts/lead-tools.js +15 -15
- package/dist/contracts/stage-output.d.ts +1 -1
- package/dist/contracts/stage-output.js +1 -1
- package/dist/contracts/store-json.d.ts +23 -22
- package/dist/contracts/store-json.js +17 -17
- package/dist/contracts/{teammate-turn.d.ts → subagent-turn.d.ts} +5 -5
- package/dist/contracts/{teammate-turn.js → subagent-turn.js} +7 -7
- package/dist/control-ui.d.ts +5 -4
- package/dist/control-ui.js +9 -34
- package/dist/converse.d.ts +23 -23
- package/dist/converse.js +28 -28
- package/dist/coordinator-proposals.d.ts +2 -2
- package/dist/coordinator-proposals.js +1 -1
- package/dist/coordinator.js +1 -1
- 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/deprecations.d.ts +12 -0
- package/dist/deprecations.js +20 -0
- package/dist/desktop-update-gate.js +8 -4
- package/dist/desktop-update.js +6 -1
- package/dist/discord-chat.js +6 -6
- package/dist/discord-settings.d.ts +3 -2
- package/dist/discord-settings.js +17 -42
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/envelope.js +10 -1
- package/dist/evidence-pack.d.ts +2 -1
- package/dist/evidence-pack.js +45 -49
- package/dist/export-ui.d.ts +7 -2
- package/dist/export-ui.js +4 -10
- package/dist/export.js +7 -7
- package/dist/flow-engine.d.ts +2 -2
- package/dist/flow-engine.js +21 -21
- package/dist/flow-gallery-ui.d.ts +4 -3
- package/dist/flow-gallery-ui.js +28 -43
- package/dist/flow-insights.d.ts +1 -1
- package/dist/flow-share.js +13 -8
- package/dist/flow-starters-ui.d.ts +2 -1
- package/dist/flow-starters-ui.js +12 -15
- package/dist/flow-steps.d.ts +5 -5
- package/dist/flow-steps.js +19 -19
- package/dist/flow-triggers.d.ts +2 -1
- package/dist/flow-triggers.js +17 -15
- package/dist/flows-cli.js +1 -1
- package/dist/flows-ui.d.ts +4 -3
- package/dist/flows-ui.js +38 -49
- package/dist/flows.js +21 -20
- package/dist/guides.js +112 -6
- 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/invoke.js +1 -1
- package/dist/kits-ui.d.ts +5 -4
- package/dist/kits-ui.js +22 -24
- package/dist/kits.d.ts +12 -12
- package/dist/kits.js +31 -31
- package/dist/knowledge-ui.d.ts +6 -5
- package/dist/knowledge-ui.js +26 -25
- package/dist/{mate-cli.d.ts → lead-cli.d.ts} +11 -11
- package/dist/{mate-cli.js → lead-cli.js} +38 -38
- package/dist/lead-commitments.js +4 -4
- package/dist/lead-context.d.ts +12 -2
- package/dist/lead-context.js +15 -17
- package/dist/{mate-contract.d.ts → lead-contract.d.ts} +3 -3
- package/dist/{mate-contract.js → lead-contract.js} +7 -6
- package/dist/{mate-doors.d.ts → lead-doors.d.ts} +6 -6
- package/dist/{mate-doors.js → lead-doors.js} +24 -24
- package/dist/lead-follow.d.ts +5 -5
- package/dist/lead-follow.js +9 -9
- package/dist/lead-people.d.ts +5 -5
- package/dist/lead-people.js +14 -14
- package/dist/{mate-progress.d.ts → lead-progress.d.ts} +9 -9
- package/dist/{mate-progress.js → lead-progress.js} +3 -3
- package/dist/{mate-tools.d.ts → lead-tools.d.ts} +19 -19
- package/dist/{mate-tools.js → lead-tools.js} +109 -101
- package/dist/{mate.d.ts → lead.d.ts} +27 -27
- package/dist/{mate.js → lead.js} +102 -102
- package/dist/ledger-view.d.ts +2 -1
- package/dist/ledger-view.js +27 -29
- package/dist/limits-ui.d.ts +3 -2
- package/dist/limits-ui.js +8 -8
- package/dist/live-bus.d.ts +50 -8
- package/dist/live-bus.js +133 -50
- package/dist/mcp-connect.d.ts +1 -1
- package/dist/mcp-connect.js +3 -3
- package/dist/mcp-core.js +1 -1
- package/dist/mcp-oauth.js +35 -36
- package/dist/memory-pass.d.ts +2 -2
- package/dist/memory-pass.js +7 -7
- 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/notification-rows.d.ts +2 -2
- package/dist/openrouter-models.d.ts +2 -1
- package/dist/openrouter-models.js +5 -9
- package/dist/operate.d.ts +3 -3
- package/dist/operate.js +46 -41
- 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/policy.d.ts +1 -1
- package/dist/principal.d.ts +1 -1
- package/dist/principal.js +2 -2
- package/dist/project-delete-ui.d.ts +4 -3
- package/dist/project-delete-ui.js +16 -28
- package/dist/project-delete.d.ts +1 -1
- package/dist/project-delete.js +26 -26
- package/dist/project-memory.js +1 -1
- package/dist/project-tools.d.ts +1 -1
- package/dist/project-tools.js +1 -1
- 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/retention.js +4 -4
- package/dist/scope.d.ts +2 -2
- package/dist/scout-report.d.ts +1 -1
- package/dist/scout-report.js +1 -1
- package/dist/serve.d.ts +11 -2
- package/dist/serve.js +105 -99
- package/dist/server/chat.d.ts +7 -10
- package/dist/server/chat.js +984 -1021
- 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 +854 -773
- package/dist/server/guards.d.ts +1 -1
- package/dist/server/guards.js +8 -5
- 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 +581 -573
- package/dist/server/remote.d.ts +4 -7
- package/dist/server/remote.js +39 -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 +154 -0
- package/dist/server/render-settings.js +580 -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 +167 -77
- package/dist/server/runtime.d.ts +28 -20
- 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 +2186 -2121
- 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 +1489 -1420
- package/dist/server-telemetry.d.ts +4 -3
- package/dist/server-telemetry.js +4 -8
- package/dist/setup-guide.d.ts +2 -2
- 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-chat.d.ts +2 -2
- package/dist/slack-chat.js +6 -6
- package/dist/slack-settings.d.ts +3 -2
- package/dist/slack-settings.js +17 -42
- package/dist/spend-ui.d.ts +5 -4
- package/dist/spend-ui.js +17 -40
- package/dist/spend.d.ts +14 -14
- package/dist/spend.js +31 -31
- package/dist/sso-ui.d.ts +3 -2
- package/dist/sso-ui.js +26 -27
- package/dist/storage-ui.d.ts +2 -1
- package/dist/storage-ui.js +14 -33
- package/dist/store-baseline.d.ts +19 -0
- package/dist/store-baseline.js +2873 -0
- package/dist/store.d.ts +197 -249
- package/dist/store.js +747 -3084
- package/dist/subagent-admin.d.ts +53 -0
- package/dist/{teammate-admin.js → subagent-admin.js} +37 -37
- package/dist/{teammate-desk.d.ts → subagent-desk.d.ts} +22 -23
- package/dist/{teammate-desk.js → subagent-desk.js} +26 -35
- package/dist/{teammate-memory.d.ts → subagent-memory.d.ts} +17 -17
- package/dist/{teammate-memory.js → subagent-memory.js} +41 -41
- package/dist/{teammate-question.d.ts → subagent-question.d.ts} +6 -6
- package/dist/{teammate-question.js → subagent-question.js} +17 -17
- package/dist/{teammate-tools.d.ts → subagent-tools.d.ts} +18 -18
- package/dist/{teammate-tools.js → subagent-tools.js} +36 -36
- package/dist/{teammate-week.d.ts → subagent-week.d.ts} +10 -10
- package/dist/{teammate-week.js → subagent-week.js} +23 -23
- package/dist/{teammate-work.d.ts → subagent-work.d.ts} +21 -21
- package/dist/{teammate-work.js → subagent-work.js} +50 -50
- package/dist/subagents-ui.d.ts +22 -0
- package/dist/subagents-ui.js +137 -0
- package/dist/{teammates.d.ts → subagents.d.ts} +11 -11
- package/dist/{teammates.js → subagents.js} +21 -21
- package/dist/subscription-chat.d.ts +13 -13
- package/dist/subscription-chat.js +19 -19
- package/dist/surface.d.ts +19 -2
- package/dist/surface.js +20 -33
- 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-cli.d.ts +1 -0
- package/dist/team-cli.js +14 -2
- package/dist/team-http.d.ts +5 -9
- package/dist/team-http.js +5 -63
- package/dist/team-leads.js +13 -13
- package/dist/team-runtime.d.ts +2 -2
- package/dist/team-runtime.js +8 -8
- package/dist/team-ui.d.ts +2 -1
- package/dist/team-ui.js +2 -5
- package/dist/teams-chat.js +6 -6
- package/dist/teams-settings.d.ts +3 -2
- package/dist/teams-settings.js +20 -31
- package/dist/telegram-flow.d.ts +3 -3
- package/dist/telegram-flow.js +3 -3
- package/dist/{telegram-mate.d.ts → telegram-lead.d.ts} +5 -5
- package/dist/{telegram-mate.js → telegram-lead.js} +27 -27
- package/dist/telegram-settings.d.ts +3 -2
- package/dist/telegram-settings.js +14 -25
- package/dist/telegram-status.js +1 -1
- package/dist/telegram-team.d.ts +1 -1
- package/dist/telegram-team.js +5 -5
- package/dist/telegram.d.ts +1 -1
- package/dist/telegram.js +9 -30
- package/dist/text-limits.d.ts +18 -18
- package/dist/text-limits.js +18 -18
- package/dist/toolroll-update-ui.d.ts +3 -2
- package/dist/toolroll-update-ui.js +35 -39
- package/dist/toolroll-update.d.ts +8 -0
- package/dist/toolroll-update.js +45 -8
- 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 -2
- package/dist/server/shared.d.ts +0 -3151
- package/dist/server/shared.js +0 -12001
- package/dist/teammate-admin.d.ts +0 -53
- package/dist/teammates-ui.d.ts +0 -20
- package/dist/teammates-ui.js +0 -166
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';
|
|
@@ -86,7 +87,7 @@ import { firstRunSteps, signInCommandFor } from "./first-run.js";
|
|
|
86
87
|
import { installMethod } from "./install-method.js";
|
|
87
88
|
import { createIntegrationMonitor } from "./integrations.js";
|
|
88
89
|
import { logEvent } from "./log.js";
|
|
89
|
-
import {
|
|
90
|
+
import { LEAD_MESSAGE_MAX_CHARS } from "./lead.js";
|
|
90
91
|
import {} from "./model-catalog.js";
|
|
91
92
|
import { modeTermsFromJson } from "./modes.js";
|
|
92
93
|
import { envValue } from "./names.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, leadBrowserMessages, leadChatVersion, 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. */
|
|
@@ -446,7 +453,7 @@ export function createDecisionServer(options) {
|
|
|
446
453
|
if (!snapshot?.selected || !snapshot.proposals)
|
|
447
454
|
return reply;
|
|
448
455
|
return { ...reply, snapshot: { ...snapshot, proposals: snapshot.proposals.map(summary => {
|
|
449
|
-
const proposal = store.
|
|
456
|
+
const proposal = store.getLeadProposal(summary.id);
|
|
450
457
|
if (!proposal || proposal.thread !== snapshot.selected.threadId)
|
|
451
458
|
return summary;
|
|
452
459
|
const decision = proposal.kind === 'answer' && typeof proposal.payload['decision'] === 'number' ? store.getDecision(proposal.payload['decision']) : null;
|
|
@@ -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,
|
|
@@ -771,10 +780,10 @@ export function createDecisionServer(options) {
|
|
|
771
780
|
}
|
|
772
781
|
const shared = /^\/chat\/(?:action\/([0-9]{1,15})|proposal\/([0-9]{1,15})\/(?:confirm|dismiss))$/.exec(url.pathname);
|
|
773
782
|
if (shared) {
|
|
774
|
-
const proposal = store.
|
|
783
|
+
const proposal = store.getLeadProposal(Number(shared[1] ?? shared[2]));
|
|
775
784
|
const action = proposal?.kind === 'action' ? sharedActionPayload(proposal.payload) : null;
|
|
776
785
|
const room = proposal ? store.handle.prepare('SELECT id FROM team_conversation WHERE thread=?').get(proposal.thread) : null;
|
|
777
|
-
let admitted = proposal && store.
|
|
786
|
+
let admitted = proposal && store.getLeadThread(proposal.thread)?.approver === who.name;
|
|
778
787
|
if (room && who.via === 'cookie') {
|
|
779
788
|
try {
|
|
780
789
|
team.domain.access({ name: who.name, generation: who.session.generation }, String(room['id']), 'contributor');
|
|
@@ -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() });
|
|
@@ -972,36 +981,36 @@ export function createDecisionServer(options) {
|
|
|
972
981
|
// ---- fleet chat (v13) ----------------------------------------------------
|
|
973
982
|
const chatFetcher = options.chatFetcher ?? fetch;
|
|
974
983
|
const chatEnv = options.chatEnv ?? process.env;
|
|
975
|
-
/** The
|
|
984
|
+
/** The lead's last non-answer per BROWSER session (keyed by its csrf —
|
|
976
985
|
* never by name, so two browsers on one account do not read each other's
|
|
977
986
|
* notes), bound to the mate turn it came from so a note from a session
|
|
978
987
|
* that has since ended never shows; bounded; read once. */
|
|
979
|
-
const
|
|
988
|
+
const leadSaid = new Map();
|
|
980
989
|
/** The unified conversation's rows for one reader (package 2): the SAME
|
|
981
990
|
* rows the page renders and the status poll's fragments re-render, so a
|
|
982
991
|
* live update can never show a card the page would not. A task lens
|
|
983
|
-
* keeps only that task's coordinator cards; the
|
|
992
|
+
* keeps only that task's coordinator cards; the lead's own thread is one
|
|
984
993
|
* thread regardless of lens. */
|
|
985
|
-
function
|
|
994
|
+
function leadConversationRows(who, principal, focusTask, now, chatProject = null) {
|
|
986
995
|
const allCoordinatorRows = store.listCoordinatorProposals({ repos: managedRepos(), states: ["pending", "confirmed", "refused"], limit: 30 });
|
|
987
996
|
const coordinatorProposals = focusTask !== null ? allCoordinatorRows.filter(one => focusTask.family.versions.some(version => version.id === one.payload["task"]))
|
|
988
997
|
: chatProject !== null ? allCoordinatorRows.filter(one => one.repo === chatProject) : allCoordinatorRows;
|
|
989
|
-
const opened = store.
|
|
990
|
-
const proposals = store.
|
|
998
|
+
const opened = store.openLeadThread(who.name, principal.ceilingDigest, now, chatScopeOf(focusTask, chatProject));
|
|
999
|
+
const proposals = store.listLeadProposals(opened.thread.id);
|
|
991
1000
|
// One reply runs at a time per person; this thread shows it only when
|
|
992
1001
|
// the reply is its own.
|
|
993
|
-
const live = store.
|
|
994
|
-
const messages = store.
|
|
1002
|
+
const live = store.liveLeadTurnFor(who.name);
|
|
1003
|
+
const messages = store.listLeadMessages(opened.thread.id, 40);
|
|
995
1004
|
// The lead's question with buttons, while its reply is the last word in the thread.
|
|
996
1005
|
const last = messages.at(-1);
|
|
997
|
-
const ask = last?.role === "assistant" && last.turn !== null && store.
|
|
1006
|
+
const ask = last?.role === "assistant" && last.turn !== null && store.getLeadTurn(last.turn)?.approver === who.name ? store.leadAskOpen(last.turn, now) : null;
|
|
998
1007
|
// Answered questions stay readable above the answer; only their buttons go.
|
|
999
|
-
const asks = new Map(messages.flatMap(one => { const asked = one.role === "assistant" && one.turn !== null ? store.
|
|
1008
|
+
const asks = new Map(messages.flatMap(one => { const asked = one.role === "assistant" && one.turn !== null ? store.leadAsk(one.turn) : null; return asked === null ? [] : [[asked.turn, asked]]; }));
|
|
1000
1009
|
// The thread a ceiling change replaced (ruling 9): read after the open, display only.
|
|
1001
1010
|
const replaced = store.replacedLeadThread(opened.thread);
|
|
1002
|
-
const previousProposals = replaced === null ? [] : store.
|
|
1011
|
+
const previousProposals = replaced === null ? [] : store.listLeadProposals(replaced.id);
|
|
1003
1012
|
return {
|
|
1004
|
-
previous: replaced === null ? null : { messages: store.
|
|
1013
|
+
previous: replaced === null ? null : { messages: store.listLeadMessages(replaced.id, 40), proposals: previousProposals, decisions: decisionsFor(store, previousProposals) },
|
|
1005
1014
|
messages,
|
|
1006
1015
|
ask,
|
|
1007
1016
|
asks,
|
|
@@ -1009,7 +1018,7 @@ export function createDecisionServer(options) {
|
|
|
1009
1018
|
decisions: decisionsFor(store, [...proposals, ...coordinatorProposals]),
|
|
1010
1019
|
coordinatorProposals,
|
|
1011
1020
|
pending: live !== null && live.thread === opened.thread.id ? live : null,
|
|
1012
|
-
recent: store.
|
|
1021
|
+
recent: store.recentLeadTurns(who.name, 5),
|
|
1013
1022
|
};
|
|
1014
1023
|
}
|
|
1015
1024
|
/** The thread a chat surface speaks in (v77): the task's own thread, the
|
|
@@ -1026,21 +1035,21 @@ export function createDecisionServer(options) {
|
|
|
1026
1035
|
if (who.via !== "cookie" || who.role !== "approver" || (focusTask === null && chatProject === null))
|
|
1027
1036
|
return null;
|
|
1028
1037
|
const enabled = chatEnablement();
|
|
1029
|
-
const principal = enabled.ok ?
|
|
1038
|
+
const principal = enabled.ok ? leadPrincipal(who) : null;
|
|
1030
1039
|
if (!enabled.ok || principal === null)
|
|
1031
1040
|
return null;
|
|
1032
|
-
let session = store.
|
|
1041
|
+
let session = store.activeLeadSession(who.name);
|
|
1033
1042
|
if ((session === null || session.ceilingDigest !== principal.ceilingDigest) && enabled.billing === "subscription" && !requestContext.getStore()?.workspaceRead) {
|
|
1034
|
-
|
|
1035
|
-
session = store.
|
|
1043
|
+
startLeadConversation(who, principal, enabled, 0, false, now);
|
|
1044
|
+
session = store.activeLeadSession(who.name);
|
|
1036
1045
|
}
|
|
1037
1046
|
if (session === null || session.ceilingDigest !== principal.ceilingDigest || session.approverGeneration !== principal.generation)
|
|
1038
1047
|
return null;
|
|
1039
|
-
const rows =
|
|
1048
|
+
const rows = leadConversationRows(who, principal, focusTask, now, chatProject);
|
|
1040
1049
|
return {
|
|
1041
|
-
sessionId: session.id, user: session.approver, version:
|
|
1042
|
-
messages:
|
|
1043
|
-
pendingTurnId: rows.pending?.id ?? null, requestId: randomBytes(16).toString("hex"), maxChars:
|
|
1050
|
+
sessionId: session.id, user: session.approver, version: leadChatVersion({ ...rows, focusTask }),
|
|
1051
|
+
messages: leadBrowserMessages(rows, back, { task: focusTask?.id ?? null, project: chatProject }),
|
|
1052
|
+
pendingTurnId: rows.pending?.id ?? null, requestId: randomBytes(16).toString("hex"), maxChars: LEAD_MESSAGE_MAX_CHARS,
|
|
1044
1053
|
taskId: focusTask?.id ?? null, resultRunId, project: focusTask === null ? chatProject : null,
|
|
1045
1054
|
};
|
|
1046
1055
|
}
|
|
@@ -1049,17 +1058,17 @@ export function createDecisionServer(options) {
|
|
|
1049
1058
|
/** Start the person's lead conversation: the session every later turn
|
|
1050
1059
|
* debits (a membership spends nothing; direct API gets a per-conversation
|
|
1051
1060
|
* ceiling) and its thread. Starting ends any older session. */
|
|
1052
|
-
function
|
|
1061
|
+
function startLeadConversation(who, principal, enabled, ceilingUsd, follow, now) {
|
|
1053
1062
|
const ceilingMicrousd = enabled.billing === "subscription" ? 0 : Math.round(ceilingUsd * 1_000_000);
|
|
1054
1063
|
const termsDigest = createHash("sha256").update(`${ceilingMicrousd}\n${principal.ceilingDigest}`).digest("hex");
|
|
1055
|
-
const sessionId = store.
|
|
1056
|
-
const thread = store.
|
|
1064
|
+
const sessionId = store.mintLeadSession({ approver: who.name, approverGeneration: principal.generation, credentialKey: enabled.credentialKey, ceilingMicrousd, ceilingDigest: principal.ceilingDigest, termsDigest }, now);
|
|
1065
|
+
const thread = store.openLeadThread(who.name, principal.ceilingDigest, now).thread;
|
|
1057
1066
|
if (follow)
|
|
1058
|
-
configureLeadFollow(store, principal, store.
|
|
1059
|
-
|
|
1067
|
+
configureLeadFollow(store, principal, store.getLeadSession(sessionId), thread, true, now);
|
|
1068
|
+
leadSaid.delete(who.session.csrf);
|
|
1060
1069
|
return sessionId;
|
|
1061
1070
|
}
|
|
1062
|
-
function
|
|
1071
|
+
function leadPrincipal(who) {
|
|
1063
1072
|
const verified = verifyApproverStanding(store, who.name, who.session.generation, managedRepos());
|
|
1064
1073
|
return verified.ok ? verified.who : null;
|
|
1065
1074
|
}
|
|
@@ -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
|
|
@@ -1230,15 +1237,10 @@ export function createDecisionServer(options) {
|
|
|
1230
1237
|
if (s.workspace?.view?.kind === "flow")
|
|
1231
1238
|
s = { ...s, workspace: { ...s.workspace, view: { ...s.workspace.view, stepUp: { label: ssoFacts.label, fresh: ssoFacts.fresh, confirmHref: `/login/sso?reauth=1&return=${encodeURIComponent(back)}` } } } };
|
|
1232
1239
|
}
|
|
1233
|
-
|
|
1234
|
-
if (teamEntry?.startsWith('/chat') && !s.workspace?.team && !teamEntry.includes('task=') && !teamEntry.includes('proposal=') && demoLeadHere() === null) {
|
|
1235
|
-
s.body = '<p class="team-entry"><a href="/chat?team=1">Open team chat</a></p>' + s.body;
|
|
1236
|
-
if (s.workspace?.conversation)
|
|
1237
|
-
s.workspace.controlsHtml = '<p><a href="/chat?team=1">Open team chat</a></p>' + (s.workspace.controlsHtml ?? '');
|
|
1238
|
-
}
|
|
1240
|
+
// D5: team chat (the central team service) is deprecated; /chat?team=1 still opens this release, but nothing links to it.
|
|
1239
1241
|
const sensitive = s.forceSensitive === true ||
|
|
1240
|
-
SENSITIVE_INPUT.test(s.body) ||
|
|
1241
|
-
(s.chrome?.listPane !== undefined && SENSITIVE_INPUT.test(s.chrome.listPane));
|
|
1242
|
+
SENSITIVE_INPUT.test(htmlString(s.body)) ||
|
|
1243
|
+
(s.chrome?.listPane !== undefined && SENSITIVE_INPUT.test(htmlString(s.chrome.listPane)));
|
|
1242
1244
|
const requestFacts = requestContext.getStore();
|
|
1243
1245
|
if (requestFacts?.browser && s.chrome && !s.forceSensitive && (requestFacts.workspaceRead || browserAssetsAvailable())) {
|
|
1244
1246
|
const path = new URL(requestFacts.returnTo, 'http://standing-orders.local');
|
|
@@ -1248,7 +1250,7 @@ export function createDecisionServer(options) {
|
|
|
1248
1250
|
path.searchParams.set('format', 'workspace');
|
|
1249
1251
|
// The legacy list pane (every task or build as links) duplicates the
|
|
1250
1252
|
// Crew panel and Tasks page; inside the workspace the page stands alone.
|
|
1251
|
-
const pageHtml = s.body;
|
|
1253
|
+
const pageHtml = htmlString(s.body);
|
|
1252
1254
|
const extras = s.workspace ?? {};
|
|
1253
1255
|
const notices = [...(extras.notices ?? [])];
|
|
1254
1256
|
if (s.chrome.modeBanner)
|
|
@@ -1289,7 +1291,7 @@ export function createDecisionServer(options) {
|
|
|
1289
1291
|
try {
|
|
1290
1292
|
const actor = requestFacts.actor ?? '';
|
|
1291
1293
|
if (actor !== '') {
|
|
1292
|
-
chats = store.
|
|
1294
|
+
chats = store.listLeadThreads(actor, 16).flatMap((thread) => {
|
|
1293
1295
|
if (thread.scope.kind === 'project') {
|
|
1294
1296
|
const repo = thread.scope.key;
|
|
1295
1297
|
return visible(repo) && managedRepos().includes(repo) ? [{ kind: 'project', title: projectName(repo), href: projectChatHref(repo), at: thread.lastMessageAt }] : [];
|
|
@@ -1312,12 +1314,12 @@ export function createDecisionServer(options) {
|
|
|
1312
1314
|
...(requestFacts.actor ? { leadName: leadNameOf(store, requestFacts.actor) } : {}),
|
|
1313
1315
|
refreshUrl: path.pathname + path.search,
|
|
1314
1316
|
receipt: conversation !== null && request && REQUEST_TOKEN.test(request)
|
|
1315
|
-
? { request, received: store.
|
|
1317
|
+
? { request, received: store.leadRequestReceipt(conversation.sessionId, request) !== null } : null,
|
|
1316
1318
|
projects: browserProjectsOf(s.chrome.projects ?? []), ...crew,
|
|
1317
1319
|
conversation, ...(extras.team ? { team: extras.team } : {}), focus: extras.focus ?? null, result: extras.result ?? null,
|
|
1318
|
-
catchUpHtml: extras.catchUpHtml
|
|
1320
|
+
catchUpHtml: extras.catchUpHtml === undefined ? '' : htmlString(extras.catchUpHtml), controlsHtml: extras.controlsHtml === undefined ? '' : htmlString(extras.controlsHtml), notices, view: extras.view ?? null,
|
|
1319
1321
|
...(s.chrome.demo ? { demo: { text: DEMO_BANNER, short: DEMO_BANNER_SHORT } } : {}),
|
|
1320
|
-
pageHtml: extras.pageHtml === undefined ? (conversation === null ? pageHtml : null) : extras.pageHtml,
|
|
1322
|
+
pageHtml: extras.pageHtml === undefined ? (conversation === null ? pageHtml : null) : extras.pageHtml === null ? null : htmlString(extras.pageHtml),
|
|
1321
1323
|
navigation: [...browserNavigationOf(currentPath, s.chrome.project, needsYou, tasksProject, s.chrome.inboxLabel), { label: 'Workspace tools', href: '/menu', active: path.pathname === '/menu' }],
|
|
1322
1324
|
chats,
|
|
1323
1325
|
...(s.refreshSeconds === undefined ? {} : { refreshSeconds: Math.max(5, Math.floor(s.refreshSeconds)) }),
|
|
@@ -1355,9 +1357,9 @@ export function createDecisionServer(options) {
|
|
|
1355
1357
|
const script = functional + (chromeLayer ? chromeScript() + WORKSPACE_MOTION_SCRIPT : sensitiveChrome);
|
|
1356
1358
|
const nonce = script === "" ? undefined : randomBytes(16).toString("base64");
|
|
1357
1359
|
const body = chromeLayer
|
|
1358
|
-
? `${s.body}\n${paletteTagCached(s.chrome?.project ?? null)}\n${KBD_HELP}`
|
|
1360
|
+
? html `${s.body}\n${paletteTagCached(s.chrome?.project ?? null)}\n${KBD_HELP}`
|
|
1359
1361
|
: s.body;
|
|
1360
|
-
const
|
|
1362
|
+
const document = shell(s.title, body, {
|
|
1361
1363
|
...(s.chrome === undefined ? {} : { chrome: s.chrome }),
|
|
1362
1364
|
...(sensitive ? { sensitive: true } : {}),
|
|
1363
1365
|
...(s.chrome !== undefined ? { sidebarToggle: true } : {}),
|
|
@@ -1367,7 +1369,7 @@ export function createDecisionServer(options) {
|
|
|
1367
1369
|
// Pages that ship the chrome layer keep connect-src (v28 granted it for
|
|
1368
1370
|
// the since-removed watched-session beat), beside pages whose own
|
|
1369
1371
|
// functional script polls.
|
|
1370
|
-
return page(response, status,
|
|
1372
|
+
return page(response, status, document, nonce, s.functional?.fetches === true || chromeLayer || sensitiveChrome !== "");
|
|
1371
1373
|
}
|
|
1372
1374
|
/** The needs-you count every surface wears, read from this request's own
|
|
1373
1375
|
* Work counts (one query per request, never a cached earlier one), so a
|
|
@@ -1513,41 +1515,30 @@ export function createDecisionServer(options) {
|
|
|
1513
1515
|
if (peekCache.size <= PEEK_CACHE_ENTRIES && peekCacheBytes <= PEEK_CACHE_BYTES)
|
|
1514
1516
|
break;
|
|
1515
1517
|
peekCache.delete(key);
|
|
1516
|
-
peekCacheBytes -=
|
|
1518
|
+
peekCacheBytes -= entry.bytes;
|
|
1517
1519
|
}
|
|
1518
1520
|
};
|
|
1519
1521
|
/** One typed sentence inside the region — plain words, no raw errors.
|
|
1520
1522
|
* `final` marks conditions that cannot heal for this run (finished,
|
|
1521
1523
|
* superseded, wrong machine): the region poller reads the marker and
|
|
1522
1524
|
* stops, instead of refetching a dead build every beat forever. */
|
|
1523
|
-
const peekSay = (message, final = false) => `<p class="meta"${final ?
|
|
1525
|
+
const peekSay = (message, final = false) => html `<p class="meta"${final ? html ` data-region-stop` : ""}>${message}</p>`;
|
|
1524
1526
|
/** The sanitize pipeline (finding 30/35): normalize → mask → escape. */
|
|
1525
1527
|
const peekName = (path) => {
|
|
1526
1528
|
const normalized = path.replace(/[\u0000-\u001f\u007f]/g, "");
|
|
1527
1529
|
const masked = scanForSecrets(normalized).length > 0 ? "[redacted: a credential-shaped name]" : normalized;
|
|
1528
|
-
return
|
|
1530
|
+
return textHtml(masked);
|
|
1529
1531
|
};
|
|
1530
1532
|
async function handlePost(route, url, who, request, response, posted) {
|
|
1531
|
-
|
|
1533
|
+
// Every POST passes the shared mutation guard. Caller, scope, project (including a limited account's posted repo)
|
|
1534
|
+
// and role were admitted by the route table.
|
|
1532
1535
|
const denied = authorizeMutation(request, who, readForm(posted, CONSOLE_FORMS.mutationGuard));
|
|
1533
1536
|
if (denied !== null)
|
|
1534
1537
|
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
|
-
}
|
|
1538
|
+
// Standing can change after a token was minted: a viewer's act stays refused, cookie and bearer alike, except
|
|
1539
|
+
// the row's session-local acts.
|
|
1540
|
+
if (who.role === "viewer" && !route.viewer)
|
|
1541
|
+
return refuse(response, who, 403, "your login can watch, not act — ask an approver to upgrade you");
|
|
1551
1542
|
const now = clock();
|
|
1552
1543
|
// Any accepted mutation may change what the inbox owes; the badge
|
|
1553
1544
|
// re-counts within five seconds either way, this just makes it exact.
|
|
@@ -1568,7 +1559,7 @@ export function createDecisionServer(options) {
|
|
|
1568
1559
|
});
|
|
1569
1560
|
});
|
|
1570
1561
|
// Keep native process custody until shutdown has verified agent/tool exit.
|
|
1571
|
-
// Coding custody does not depend on
|
|
1562
|
+
// Coding custody does not depend on subagents or the lead's follow pass, so
|
|
1572
1563
|
// it closes at once and never waits behind a model turn: a stop must release
|
|
1573
1564
|
// the owner record well inside the service's exit window (Oct 2: deploys
|
|
1574
1565
|
// over 0.9.11 found it still held by a killed process).
|
|
@@ -1588,14 +1579,9 @@ export function createDecisionServer(options) {
|
|
|
1588
1579
|
requestBudget.flush();
|
|
1589
1580
|
}
|
|
1590
1581
|
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
1582
|
flowRooms.close();
|
|
1598
1583
|
taskRooms.close();
|
|
1584
|
+
liveHandlers.close();
|
|
1599
1585
|
detachReads();
|
|
1600
1586
|
liveFollower.close();
|
|
1601
1587
|
void Promise.all([closeCoding(), bounded(team.close()), bounded(leadMaintenance?.stop()), bounded(reads?.close())]).then(() => closeServer(callback)).catch(error => {
|
|
@@ -1654,18 +1640,18 @@ export function createDecisionServer(options) {
|
|
|
1654
1640
|
get flowRooms() { return flowRooms; },
|
|
1655
1641
|
get providerHome() { return providerHome; },
|
|
1656
1642
|
get toolHome() { return toolHome; },
|
|
1657
|
-
get
|
|
1643
|
+
get leadPrincipal() { return leadPrincipal; },
|
|
1658
1644
|
get chatScopeOf() { return chatScopeOf; },
|
|
1659
1645
|
get liveTurns() { return liveTurns; },
|
|
1660
|
-
get
|
|
1661
|
-
get
|
|
1646
|
+
get liveTurnStarted() { return liveTurnStarted; },
|
|
1647
|
+
get leadConversationRows() { return leadConversationRows; },
|
|
1662
1648
|
get demoLeadHere() { return demoLeadHere; },
|
|
1663
1649
|
get teamBrowserReply() { return teamBrowserReply; },
|
|
1664
1650
|
get team() { return team; },
|
|
1665
1651
|
get teamChatProvider() { return teamChatProvider; },
|
|
1666
1652
|
get pullRequestTargetOf() { return pullRequestTargetOf; },
|
|
1667
1653
|
get chatEnablement() { return chatEnablement; },
|
|
1668
|
-
get
|
|
1654
|
+
get startLeadConversation() { return startLeadConversation; },
|
|
1669
1655
|
get projectFamilyPeek() { return projectFamilyPeek; },
|
|
1670
1656
|
get needsYouBadge() { return needsYouBadge; },
|
|
1671
1657
|
get liveRefreshSeconds() { return liveRefreshSeconds; },
|
|
@@ -1698,7 +1684,7 @@ export function createDecisionServer(options) {
|
|
|
1698
1684
|
get deletedRepos() { return deletedRepos; },
|
|
1699
1685
|
get lookupSession() { return lookupSession; },
|
|
1700
1686
|
get authorizeMutation() { return authorizeMutation; },
|
|
1701
|
-
get
|
|
1687
|
+
get leadSaid() { return leadSaid; },
|
|
1702
1688
|
get armTaskResume() { return armTaskResume; },
|
|
1703
1689
|
get chatFetcher() { return chatFetcher; },
|
|
1704
1690
|
get chatCeilingDigest() { return chatCeilingDigest; },
|
|
@@ -1763,7 +1749,6 @@ export function createDecisionServer(options) {
|
|
|
1763
1749
|
get allowedHost() { return allowedHost; },
|
|
1764
1750
|
get team() { return team; },
|
|
1765
1751
|
get teamBrowserReply() { return teamBrowserReply; },
|
|
1766
|
-
get teamStreams() { return teamStreams; },
|
|
1767
1752
|
get requestBudget() { return requestBudget; },
|
|
1768
1753
|
get options() { return options; },
|
|
1769
1754
|
get coding() { return coding; },
|
|
@@ -1781,13 +1766,26 @@ export function createDecisionServer(options) {
|
|
|
1781
1766
|
get teamsSourceBudget() { return teamsSourceBudget; },
|
|
1782
1767
|
get teamsTenantBudget() { return teamsTenantBudget; },
|
|
1783
1768
|
};
|
|
1769
|
+
const liveHandlers = createLiveHandlers(handlerRuntime, { bus: liveBus, workspaceRevision, chatProjectOf: chatHandlers.chatProjectOf });
|
|
1770
|
+
liveTurnStarted = liveHandlers.turnStarted;
|
|
1784
1771
|
const remoteHandlers = createRemoteHandlers(remoteRuntime);
|
|
1785
1772
|
const registry = createHandlerRegistry([
|
|
1786
1773
|
...tasksHandlers.registrations, ...flowsHandlers.registrations, ...chatHandlers.registrations,
|
|
1787
1774
|
...settingsHandlers.registrations, ...peopleHandlers.registrations, ...pagesHandlers.registrations,
|
|
1788
|
-
...remoteHandlers.registrations,
|
|
1775
|
+
...remoteHandlers.registrations, ...liveHandlers.registrations,
|
|
1789
1776
|
]);
|
|
1790
|
-
|
|
1777
|
+
/** The row's role, after admission and before its one handler. */
|
|
1778
|
+
function dispatchConsole(route, ctx) {
|
|
1779
|
+
const { who, response } = ctx;
|
|
1780
|
+
const held = route.role === "any" || ((!route.roleBrowser || who.via === "cookie") &&
|
|
1781
|
+
(route.role === "approver" ? who.role === "approver" : store.isInstanceOperator(who.name)));
|
|
1782
|
+
if (!held) {
|
|
1783
|
+
ctx.request.resume();
|
|
1784
|
+
const refusal = route.roleRefusal;
|
|
1785
|
+
return Promise.resolve("message" in refusal ? refuse(response, who, 403, refusal.message, refusal.back) : respond(response, refusal.status, refusal.type, refusal.body));
|
|
1786
|
+
}
|
|
1787
|
+
return registry.console(route, ctx);
|
|
1788
|
+
}
|
|
1791
1789
|
async function dispatchEdge(route, ctx) {
|
|
1792
1790
|
if (route.callers.length === 1 && route.callers[0] === 'cookie' && ctx.request.headers.authorization !== undefined) {
|
|
1793
1791
|
return respond(ctx.response, 403, 'text/plain; charset=utf-8', 'This address needs a browser sign-in.');
|
|
@@ -1801,4 +1799,12 @@ export function createDecisionServer(options) {
|
|
|
1801
1799
|
}
|
|
1802
1800
|
return Object.assign(server, { mintSignInLink, closeCoding });
|
|
1803
1801
|
}
|
|
1804
|
-
export {
|
|
1802
|
+
export { PAGE_CSS, pinnedTheme, SENSITIVE_INPUT } from "./server/chrome.js";
|
|
1803
|
+
export { redactedPath, SHUTDOWN_WAIT_MS } from "./server/http.js";
|
|
1804
|
+
export { TASK_COMPOSER_MODES } from "./server/render-chat.js";
|
|
1805
|
+
export { inboxFingerprints, parseInboxTab, queueScript } from "./server/render-pages.js";
|
|
1806
|
+
export { ssoStepUps, wrongHostPage } from "./server/render-people.js";
|
|
1807
|
+
export { diffFileAnchor, editorFileHref, needActionOf, orderChangedFiles, plainConclusionOf, rankReviewQueue, reviewFilePriority, reviewPriorityOf, runFactsFragment, withinSignedTouches } from "./server/render-results.js";
|
|
1808
|
+
export { settingsGroups, settingsTiles } from "./server/render-settings.js";
|
|
1809
|
+
export { decisionAnswerScript, earlierVersionsWords, revisionLineageWords } from "./server/render-tasks.js";
|
|
1810
|
+
export { SIGN_IN_LINK_MS, SIGN_IN_LINK_PATH } from "./server/session.js";
|
package/dist/server/chat.d.ts
CHANGED
|
@@ -1,26 +1,23 @@
|
|
|
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
|
-
import type {
|
|
5
|
+
import type { LeadProgress } from "../lead-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";
|
|
18
15
|
}, now: Date) => BrowserPhoneCard | undefined;
|
|
19
16
|
chatProjectOf: (values: string[]) => string | null | undefined;
|
|
20
|
-
beginLiveTurn: (thread: number) => (event:
|
|
17
|
+
beginLiveTurn: (thread: number) => (event: LeadProgress) => void;
|
|
21
18
|
endLiveTurn: (thread: number, ok: boolean) => void;
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
noteLead: (csrf: string, turn: number | null, message: string) => void;
|
|
20
|
+
takeLeadNote: (csrf: string, liveSession: number | null) => string | null;
|
|
24
21
|
demoResultView: (exchange: DemoExchange) => DemoResultView | null;
|
|
25
22
|
storeChatKey: (provider: DirectChatProviderId, key: string) => {
|
|
26
23
|
ok: true;
|