@teamscala/service-boot 0.23.345 → 0.23.347

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/package.json +1064 -1093
  2. package/src/fn-routers/index.ts +0 -2
  3. package/src/two-phase-boot.ts +2 -1
  4. package/src/agreement-gate.d.ts +0 -19
  5. package/src/asset-cache-key.d.ts +0 -11
  6. package/src/asset-optimize.d.ts +0 -17
  7. package/src/asset-proxy.d.ts +0 -11
  8. package/src/asset-social-card.d.ts +0 -17
  9. package/src/attach-agreement-magic.d.ts +0 -20
  10. package/src/attach-portal-members.d.ts +0 -23
  11. package/src/attach-proposal-accept.d.ts +0 -26
  12. package/src/attach-proposal-magic.d.ts +0 -18
  13. package/src/attach-transfers-upload.d.ts +0 -27
  14. package/src/auth-gate.d.ts +0 -29
  15. package/src/bind-page-handler.d.ts +0 -18
  16. package/src/build-client-assets/input-hashing.d.ts +0 -25
  17. package/src/build-client-assets/source-candidates.d.ts +0 -27
  18. package/src/build-client-assets.d.ts +0 -50
  19. package/src/compose-page-title.d.ts +0 -41
  20. package/src/content-gate/access.d.ts +0 -15
  21. package/src/content-gate/config-types.d.ts +0 -99
  22. package/src/content-gate/gate.d.ts +0 -13
  23. package/src/content-gate/parse-cookie.d.ts +0 -9
  24. package/src/content-gate/token.d.ts +0 -48
  25. package/src/content-page-floor.d.ts +0 -39
  26. package/src/discover-blocks.d.ts +0 -28
  27. package/src/expand-roster.d.ts +0 -34
  28. package/src/fn-routers/agreement-completion-email.d.ts +0 -14
  29. package/src/fn-routers/agreement-send-router.d.ts +0 -82
  30. package/src/fn-routers/ai-health-router.d.ts +0 -35
  31. package/src/fn-routers/auth-router.d.ts +0 -47
  32. package/src/fn-routers/cache-admin-router.d.ts +0 -57
  33. package/src/fn-routers/chat-session-router.d.ts +0 -219
  34. package/src/fn-routers/email-defaults.d.ts +0 -1
  35. package/src/fn-routers/email-link-ttl.d.ts +0 -1
  36. package/src/fn-routers/index.d.ts +0 -18
  37. package/src/fn-routers/orchestrator-registration-router.d.ts +0 -60
  38. package/src/fn-routers/orchestrator-registration-router.ts +0 -77
  39. package/src/fn-routers/orchestrator-registration.live.test.ts +0 -70
  40. package/src/fn-routers/orchestrator-registration.test.ts +0 -23
  41. package/src/fn-routers/panel-data-router.d.ts +0 -19
  42. package/src/fn-routers/persist-chat-messages.d.ts +0 -36
  43. package/src/fn-routers/plans-router.d.ts +0 -25
  44. package/src/fn-routers/proposal-send-router.d.ts +0 -58
  45. package/src/fn-routers/public-agreement-router.d.ts +0 -289
  46. package/src/fn-routers/public-assessment-router.d.ts +0 -68
  47. package/src/fn-routers/public-gpt-session-router.d.ts +0 -143
  48. package/src/fn-routers/sign-in-flow-router.d.ts +0 -107
  49. package/src/fn-routers/task-sync-assign.d.ts +0 -307
  50. package/src/fn-routers/task-sync-brief.d.ts +0 -98
  51. package/src/fn-routers/task-sync-close.d.ts +0 -41
  52. package/src/fn-routers/task-sync-dispatch.d.ts +0 -47
  53. package/src/fn-routers/task-sync-dispatch.ts +0 -81
  54. package/src/fn-routers/task-sync-lane.d.ts +0 -49
  55. package/src/fn-routers/task-sync-lane.ts +0 -114
  56. package/src/fn-routers/task-sync-projection.d.ts +0 -144
  57. package/src/fn-routers/task-sync-rename.d.ts +0 -91
  58. package/src/fn-routers/task-sync-router.d.ts +0 -455
  59. package/src/fn-routers/task-sync-router.test.ts +0 -361
  60. package/src/fn-routers/task-sync-router.ts +0 -1075
  61. package/src/fn-routers/tasks-router.d.ts +0 -25
  62. package/src/fn-routers/user-preferences-router.d.ts +0 -77
  63. package/src/fn-routers/work-items-router.d.ts +0 -102
  64. package/src/gate-ttls.d.ts +0 -6
  65. package/src/gpt-gate.d.ts +0 -25
  66. package/src/handlers/bun-stable-watch.d.ts +0 -1
  67. package/src/handlers/pane-outbox-drain.d.ts +0 -1
  68. package/src/handlers/projects-digest.d.ts +0 -26
  69. package/src/handlers/prune-stale-data.d.ts +0 -30
  70. package/src/handlers/registry-stale-inactive-sweep.d.ts +0 -1
  71. package/src/handlers/scala-tools-currency-watch.d.ts +0 -1
  72. package/src/handlers/singleton-tools-currency-watch.d.ts +0 -1
  73. package/src/handlers/sweep-event-log.d.ts +0 -1
  74. package/src/handlers/sweep-host-cache.d.ts +0 -24
  75. package/src/handlers/upstream-issue-sync.d.ts +0 -1
  76. package/src/handlers/whatsapp-liveness-logic.d.ts +0 -34
  77. package/src/handlers/whatsapp-liveness.d.ts +0 -4
  78. package/src/hono-error-handler.d.ts +0 -25
  79. package/src/install-harness.d.ts +0 -45
  80. package/src/install-logging.d.ts +0 -34
  81. package/src/load-service-install-row.d.ts +0 -24
  82. package/src/load-service-prisma-client.d.ts +0 -18
  83. package/src/mount-orpc-router.d.ts +0 -15
  84. package/src/mount-server-packages.d.ts +0 -29
  85. package/src/mount.d.ts +0 -9
  86. package/src/mutable-app-ref.d.ts +0 -44
  87. package/src/page-route-shell-types.d.ts +0 -12
  88. package/src/page-server-orpc/audit-revert-router.d.ts +0 -37
  89. package/src/page-server-orpc/hub-mcp-client.d.ts +0 -12
  90. package/src/page-server-orpc/portal-diagnostics-router.d.ts +0 -49
  91. package/src/page-server-orpc/puck-pages-router.d.ts +0 -58
  92. package/src/page-server-orpc/server-client.d.ts +0 -16
  93. package/src/page-server-orpc/templates-router.d.ts +0 -34
  94. package/src/page-server-orpc/user-preferences-router.d.ts +0 -79
  95. package/src/pg-boss-handler-registry.d.ts +0 -27
  96. package/src/pg-boss-mount.d.ts +0 -42
  97. package/src/proposal-authorized-emails.d.ts +0 -28
  98. package/src/proposal-chat-inject.d.ts +0 -17
  99. package/src/proposal-gate.d.ts +0 -18
  100. package/src/read-html-template.d.ts +0 -38
  101. package/src/read-viewport-from-request.d.ts +0 -18
  102. package/src/readiness-gate.d.ts +0 -16
  103. package/src/register-api-routes.d.ts +0 -18
  104. package/src/register-crash-handlers.d.ts +0 -15
  105. package/src/register-page-routes.d.ts +0 -27
  106. package/src/register-page-server-client.d.ts +0 -11
  107. package/src/register-registry-page-route/ai-chat-prefetch.d.ts +0 -13
  108. package/src/register-registry-page-route/graph-cache.d.ts +0 -30
  109. package/src/register-registry-page-route/meta-title.d.ts +0 -2
  110. package/src/register-registry-page-route/proposal-approval-email-token.d.ts +0 -14
  111. package/src/register-registry-page-route/proposal-brand-stamping.d.ts +0 -28
  112. package/src/register-registry-page-route/resolve-page-data.d.ts +0 -1
  113. package/src/register-registry-page-route.d.ts +0 -27
  114. package/src/register-static-assets.d.ts +0 -13
  115. package/src/register-ws-routes.d.ts +0 -28
  116. package/src/resolve-app-base-url.d.ts +0 -13
  117. package/src/resolve-brand-favicon.d.ts +0 -28
  118. package/src/resolve-from-loader-config.d.ts +0 -32
  119. package/src/resolve-service-context.d.ts +0 -17
  120. package/src/resolve-service-port.d.ts +0 -75
  121. package/src/resolve-theme-mode.d.ts +0 -42
  122. package/src/resolvers/fetch-org-brand.d.ts +0 -2
  123. package/src/resolvers/portal-route-paths.d.ts +0 -39
  124. package/src/resolvers/website-by-host-map.d.ts +0 -12
  125. package/src/resource-chat-inject.d.ts +0 -46
  126. package/src/resource-not-found.d.ts +0 -60
  127. package/src/run-boot-hook-list.d.ts +0 -19
  128. package/src/run-boot-hooks.d.ts +0 -31
  129. package/src/scala-tools-currency-watchdog.d.ts +0 -10
  130. package/src/security-headers.d.ts +0 -12
  131. package/src/serve/serve.d.ts +0 -46
  132. package/src/serve/stamp-transport-identity.d.ts +0 -39
  133. package/src/server-error-page.d.ts +0 -29
  134. package/src/start-scheduled-jobs.d.ts +0 -18
  135. package/src/two-phase-boot.d.ts +0 -176
  136. package/src/types.d.ts +0 -46
  137. package/src/ui-service.d.ts +0 -46
  138. package/src/ws-boot-self-test.d.ts +0 -19
@@ -1,143 +0,0 @@
1
- /**
2
- * @system service-boot
3
- * @status handwritten
4
- * @edit edit directly
5
- *
6
- * ORPC procedures for public GPT session management.
7
- * Creates/restores conversations and messages for public-facing GPT pages.
8
- */
9
- import * as v from "valibot";
10
- interface Context {
11
- prisma: any;
12
- headers: Headers;
13
- resolveUser?: (headers: Headers, prisma: any) => Promise<any>;
14
- }
15
- export declare const publicGptSessionRouter: {
16
- createOrRestore: import("@orpc/server").DecoratedProcedure<Context & Record<never, never>, Context, v.ObjectSchema<{
17
- readonly contactName: v.StringSchema<undefined>;
18
- readonly email: v.StringSchema<undefined>;
19
- readonly phone: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
20
- readonly gptId: v.StringSchema<undefined>;
21
- readonly orgId: v.StringSchema<undefined>;
22
- readonly sourceUrl: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
23
- }, undefined>, import("@orpc/contract").Schema<{
24
- conversationId: string;
25
- contactName: any;
26
- contactPhone: any;
27
- messages: any;
28
- tokenTotals: {
29
- inputTokens: number;
30
- outputTokens: number;
31
- };
32
- } | {
33
- conversationId: any;
34
- contactName: any;
35
- contactPhone: any;
36
- messages: never[];
37
- tokenTotals: {
38
- inputTokens: number;
39
- outputTokens: number;
40
- };
41
- }, {
42
- conversationId: string;
43
- contactName: any;
44
- contactPhone: any;
45
- messages: any;
46
- tokenTotals: {
47
- inputTokens: number;
48
- outputTokens: number;
49
- };
50
- } | {
51
- conversationId: any;
52
- contactName: any;
53
- contactPhone: any;
54
- messages: never[];
55
- tokenTotals: {
56
- inputTokens: number;
57
- outputTokens: number;
58
- };
59
- }>, Record<never, never>, Record<never, never>>;
60
- load: import("@orpc/server").DecoratedProcedure<Context & Record<never, never>, Context, v.ObjectSchema<{
61
- readonly conversationId: v.StringSchema<undefined>;
62
- }, undefined>, import("@orpc/contract").Schema<{
63
- conversationId: any;
64
- contactName: string;
65
- contactEmail: string;
66
- messages: any;
67
- tokenTotals: {
68
- inputTokens: number;
69
- outputTokens: number;
70
- };
71
- } | null, {
72
- conversationId: any;
73
- contactName: string;
74
- contactEmail: string;
75
- messages: any;
76
- tokenTotals: {
77
- inputTokens: number;
78
- outputTokens: number;
79
- };
80
- } | null>, Record<never, never>, Record<never, never>>;
81
- saveMessages: import("@orpc/server").DecoratedProcedure<Context & Record<never, never>, Context, v.ObjectSchema<{
82
- readonly conversationId: v.StringSchema<undefined>;
83
- readonly messages: v.ArraySchema<v.ObjectSchema<{
84
- readonly id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
85
- readonly role: v.StringSchema<undefined>;
86
- readonly content: v.StringSchema<undefined>;
87
- readonly parts: v.OptionalSchema<v.ArraySchema<v.AnySchema, undefined>, undefined>;
88
- readonly metadata: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.AnySchema, undefined>, undefined>;
89
- }, undefined>, undefined>;
90
- }, undefined>, import("@orpc/contract").Schema<void, void>, Record<never, never>, Record<never, never>>;
91
- clear: import("@orpc/server").DecoratedProcedure<Context & Record<never, never>, Context, v.ObjectSchema<{
92
- readonly conversationId: v.StringSchema<undefined>;
93
- }, undefined>, import("@orpc/contract").Schema<{
94
- conversationId: any;
95
- contactName: string;
96
- contactPhone: string | undefined;
97
- messages: Array<{
98
- role: string;
99
- content: string;
100
- parts?: unknown[];
101
- }>;
102
- tokenTotals: {
103
- inputTokens: number;
104
- outputTokens: number;
105
- };
106
- }, {
107
- conversationId: any;
108
- contactName: string;
109
- contactPhone: string | undefined;
110
- messages: Array<{
111
- role: string;
112
- content: string;
113
- parts?: unknown[];
114
- }>;
115
- tokenTotals: {
116
- inputTokens: number;
117
- outputTokens: number;
118
- };
119
- }>, Record<never, never>, Record<never, never>>;
120
- checkIdentity: import("@orpc/server").DecoratedProcedure<Context & Record<never, never>, Context, v.ObjectSchema<{
121
- readonly email: v.StringSchema<undefined>;
122
- }, undefined>, import("@orpc/contract").Schema<{
123
- isPlatformUser: boolean;
124
- }, {
125
- isPlatformUser: boolean;
126
- }>, Record<never, never>, Record<never, never>>;
127
- upload: import("@orpc/server").DecoratedProcedure<Context & Record<never, never>, Context, v.ObjectSchema<{
128
- readonly conversationId: v.StringSchema<undefined>;
129
- readonly fileData: v.StringSchema<undefined>;
130
- readonly fileName: v.StringSchema<undefined>;
131
- readonly fileType: v.StringSchema<undefined>;
132
- readonly fileSize: v.NumberSchema<undefined>;
133
- }, undefined>, import("@orpc/contract").Schema<{
134
- success: true;
135
- url: string;
136
- type: string;
137
- }, {
138
- success: true;
139
- url: string;
140
- type: string;
141
- }>, Record<never, never>, Record<never, never>>;
142
- };
143
- export {};
@@ -1,107 +0,0 @@
1
- /**
2
- * @system service-boot
3
- * @status handwritten
4
- * @edit edit directly
5
- *
6
- * `fn.signInFlow` — typed ORPC procedures for the sign-in flow's client-facing
7
- * reads (flow config, session check, portal list). Replaces the former
8
- * `/api/data/{sign-in-flow-config,check-session,portals}` HANDLER_MAP entries
9
- * from the deleted register-data-routes.ts (orpc-is-the-only-api: every API surface is a
10
- * typed ORPC procedure, never a hand-written Hono route). Logic ported
11
- * verbatim from those handlers — these are anonymous-allowed reads (they
12
- * return an empty result for an unauthenticated caller, never throw), so they
13
- * use a public base procedure reading `context.headers` for the session, NOT
14
- * the `authed` middleware (which throws UNAUTHORIZED).
15
- *
16
- * EXPAND phase: this router is ADDITIVE — registered into the `fn` namespace
17
- * but not yet retargeted by @teamscala/auth's use-sign-in-flow client (which
18
- * still hits the /api/data/* routes). The HANDLER_MAP entries stay until the
19
- * client retarget + round-trip verify land (post-incident, when the auth-flow
20
- * test harness can run), then are removed (CONTRACT).
21
- */
22
- import type { Context } from "./auth-router.ts";
23
- export declare const signInFlowRouter: {
24
- getSignInFlowConfig: import("@orpc/server").DecoratedProcedure<Context & Record<never, never>, Context, import("@orpc/contract").Schema<unknown, unknown>, import("@orpc/contract").Schema<{
25
- signInPath: string;
26
- portalPathPrefix: string;
27
- redirectQueryParam: string;
28
- sessionCheckEndpoint: string;
29
- portalsEndpoint: string;
30
- clearStaleCookiesEndpoint: string;
31
- portalRedirects: {
32
- orgDashboardPathTemplate: string;
33
- individualDashboardPathTemplate: string;
34
- };
35
- }, {
36
- signInPath: string;
37
- portalPathPrefix: string;
38
- redirectQueryParam: string;
39
- sessionCheckEndpoint: string;
40
- portalsEndpoint: string;
41
- clearStaleCookiesEndpoint: string;
42
- portalRedirects: {
43
- orgDashboardPathTemplate: string;
44
- individualDashboardPathTemplate: string;
45
- };
46
- }>, Record<never, never>, Record<never, never>>;
47
- checkSession: import("@orpc/server").DecoratedProcedure<Context & Record<never, never>, Context, import("@orpc/contract").Schema<unknown, unknown>, import("@orpc/contract").Schema<{
48
- user?: undefined;
49
- redirectUrl?: undefined;
50
- portalCount?: undefined;
51
- } | {
52
- user: {
53
- id: string;
54
- email: string;
55
- name: string | null;
56
- role: string | null;
57
- };
58
- redirectUrl: string;
59
- portalCount: number;
60
- }, {
61
- user?: undefined;
62
- redirectUrl?: undefined;
63
- portalCount?: undefined;
64
- } | {
65
- user: {
66
- id: string;
67
- email: string;
68
- name: string | null;
69
- role: string | null;
70
- };
71
- redirectUrl: string;
72
- portalCount: number;
73
- }>, Record<never, never>, Record<never, never>>;
74
- listPortals: import("@orpc/server").DecoratedProcedure<Context & Record<never, never>, Context, import("@orpc/contract").Schema<unknown, unknown>, import("@orpc/contract").Schema<{
75
- portals: never[];
76
- userOrgId: null;
77
- userName: string | null;
78
- } | {
79
- portals: {
80
- id: unknown;
81
- name: {};
82
- slug: {} | null;
83
- status: {} | null;
84
- website_type: {} | null;
85
- organisation_id: {} | null;
86
- portal_type: {} | null;
87
- }[];
88
- userOrgId: string;
89
- userName: string | null;
90
- }, {
91
- portals: never[];
92
- userOrgId: null;
93
- userName: string | null;
94
- } | {
95
- portals: {
96
- id: unknown;
97
- name: {};
98
- slug: {} | null;
99
- status: {} | null;
100
- website_type: {} | null;
101
- organisation_id: {} | null;
102
- portal_type: {} | null;
103
- }[];
104
- userOrgId: string;
105
- userName: string | null;
106
- }>, Record<never, never>, Record<never, never>>;
107
- };
@@ -1,307 +0,0 @@
1
- /**
2
- * @system service-boot
3
- * @status handwritten
4
- * @indivisible-unit
5
- * @edit edit directly
6
- *
7
- * Lane DISPATCH by assignment — the WRITE half of dispatch-by-assignment. The
8
- * operator's contract (verbatim intent): you create a task (the NAME), you write
9
- * the first COMMENT (which IS the prompt/brief), and THEN you assign it to an AI
10
- * agent — and the assignment is the TRIGGER that spawns the lane. Assignment
11
- * last, always, because by the time the agent exists every piece of information
12
- * it needs is already in the row.
13
- *
14
- * This file owns the two pure halves of that flow, split out of task-sync-router
15
- * (which sits at its 1000-line commit gate, so any new task-sync unit lands in a
16
- * sibling — the same reason task-sync-brief/lane/dispatch exist):
17
- * createTaskWithBriefComment — create the task AND its first comment (the
18
- * description IS the first comment IS the brief) in one transaction. An
19
- * incomplete task is UNCONSTRUCTIBLE: the ORPC `.input()` schema
20
- * (`assignTaskInput`) requires name + description TOGETHER, so oRPC rejects
21
- * the call before the handler runs (`prevention-over-detection` — require at
22
- * the signature, never validate after the fact).
23
- * buildAssignmentSpawnPayload — shape the spawn emission that the assignment
24
- * emits. It carries the task id and NO initialPrompt, because the spawned
25
- * lane PULLS its brief from the DB by its own session id
26
- * (`task-sync-brief.ts` readAssignedBrief → latest comment). That deletes the
27
- * keystroke-brief failure class (a ~4400-char initialPrompt fails outright;
28
- * a ~2600-char one arrives intact and is never submitted, then the pane is
29
- * reaped for producing no turn): when the brief is a row, no keystroke can
30
- * lose it.
31
- *
32
- * THE EMISSION is a row write followed by an emission that triggers the spawn
33
- * (`actions-are-rows-then-emissions`): the assignment writes the task + comment,
34
- * then emits; the host-command bus consumer reacts by spawning. State lives in
35
- * the row, never in a return value a caller may never receive. The exact bus
36
- * surface this file emits through is INJECTED (AssignmentEmitter) rather than
37
- * hard-coded, so it composes with whichever surface the host-command-bus cutover
38
- * lands — one mechanism, not two (`no-silent-reverts` on the spawn path).
39
- *
40
- * BINDING (the gap this flow exposes). A lane resolves its task by its CLI-native
41
- * session id (`kind_data.lane.session`, minted by the CLI at boot — never by us).
42
- * Today `ensureLaneTask`/`bindLane` CREATE a fresh parent task at SessionStart.
43
- * But assignment PRE-CREATES the task (with the brief as its first comment, no
44
- * session yet), so SessionStart must ADOPT THAT EXISTING TASK BY ID — writing the
45
- * freshly-minted session onto its `kind_data.lane.session` — instead of creating
46
- * a new one, or the brief-task is orphaned and the lane self-briefs to nothing.
47
- * The task is created `status:"active"` with no session, so `resolveLaneTask`
48
- * (which filters `kind_data.lane.session`) cannot see it until bind writes the
49
- * session — exactly right: the lane resolves it only after it is bound.
50
- *
51
- * CAPABILITY HARVEST (capability-harvest-on-split): APP-LOCAL, not a capability
52
- * candidate. Bound to the work_items + comments schema and to task-sync's own
53
- * kind_data.lane.session convention; no unrelated app could install this
54
- * unmodified.
55
- */
56
- import * as v from "valibot";
57
- import type { Prisma, WorkItem } from "./task-sync-router.ts";
58
- import { type Context } from "./auth-router.ts";
59
- export declare const assignTaskInput: v.ObjectSchema<{
60
- readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, "name is required — the lane's real work label">, v.CheckAction<string, "name must carry the lane's real work name, not the generic sentinel 'Lane'">]>;
61
- readonly description: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, "description is required — it is the brief (first comment)">]>;
62
- readonly parent_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
63
- readonly organisation_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
64
- readonly slug: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
65
- readonly windowName: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
66
- readonly idempotencyKey: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
67
- }, undefined>;
68
- /** The resolved (post-schema) shape the handlers operate on. */
69
- export type AssignTaskInput = v.InferOutput<typeof assignTaskInput>;
70
- /**
71
- * bindLane ORPC input. Declaring the schema is the documented remedy for the
72
- * schema-less-body gap (`upsertFromTaskListInput` cites the same measured bug):
73
- * oRPC does NOT parse a JSON body into `input` for a procedure with no
74
- * `.input()`, so a SessionStart adapter that POSTs the work item id as a DIRECT
75
- * body field (`{lane:{...}, parent_id}`) arrives as an EMPTY input — `parent_id`
76
- * is silently dropped, `adoptAssignmentTask` gets null, no adoption happens, and
77
- * `readAssignedBrief` returns nulls for a session that has nothing bound to it.
78
- * That is a DATA gap (nothing bound to the session), never a serving one — which
79
- * is exactly the misdiagnosis this closes: a prior lane read those nulls as
80
- * "fn.taskSync is 404" and reached for serving changes, when the row was simply
81
- * never bound because the body never parsed.
82
- *
83
- * ROOT-OPTIONAL (`v.optional(v.object(...))`) so it tolerates a caller that sends
84
- * a DIRECT body or none at all: oRPC extracts `input` from the `{json:{...}}` RPC
85
- * envelope, so a raw-object or empty POST yields `undefined`, which the optional
86
- * root ACCEPTS — the handler then falls back to its headers, exactly as it did
87
- * schema-less (a header-only caller like zerostack is unchanged). An adapter that
88
- * wants the body path (pi's `parent_id`) POSTs the `{json:{...}}` envelope and
89
- * `parent_id` is parsed + reaches `adoptAssignmentTask` — the same envelope
90
- * convention pi ALREADY uses for upsertFromTaskList. A raw-object POST is NOT
91
- * parsed (oRPC hands the handler `undefined`), which is why pi's bindLaneTask
92
- * must move to the envelope to deliver `parent_id`. Every field is optional with
93
- * a header fallback, so the schema ADDS the body path without removing the header.
94
- */
95
- export declare const bindLaneInput: v.OptionalSchema<v.ObjectSchema<{
96
- readonly lane: v.OptionalSchema<v.ObjectSchema<{
97
- readonly pane: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
98
- readonly session: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
99
- readonly cli_kind: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
100
- readonly role: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
101
- readonly organisation_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
102
- }, undefined>, undefined>;
103
- readonly title: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
104
- readonly parent_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
105
- }, undefined>, undefined>;
106
- /**
107
- * Resolve the org a dispatched task is created under. Pure: the platform org is
108
- * INJECTED (resolved by the caller at the handler boundary, where a registry
109
- * read is appropriate) rather than pulled from the registry inside this module,
110
- * so the create logic is unit-testable with no DB (`configured-primitives`:
111
- * config arrives from the caller, never pulled from DB/Env inside a primitive).
112
- */
113
- export declare function resolveAssignOrg(explicit?: string, platformOrg?: string): string;
114
- /**
115
- * Create a dispatched task AND its first comment (the description = the brief) in
116
- * one transaction. The task is `kind:"task"`, `status:"active"`, with NO
117
- * `kind_data.lane.session` yet — the session is minted by the CLI at spawn and
118
- * written onto the row by SessionStart's adopt-existing bind. Until then the
119
- * task is invisible to `resolveLaneTask` (which filters on the session), which is
120
- * correct: the lane may only resolve its task once it is bound to it.
121
- *
122
- * Pure over an injected prisma (no module-level I/O) so the atomic create +
123
- * first-comment decision is unit-testable with a fake transaction. `userId`
124
- * stamps `created_by`/`updated_by` on the task and `user_id` on the comment.
125
- */
126
- export declare function createTaskWithBriefComment(prisma: Prisma, input: {
127
- name: string;
128
- description: string;
129
- parent_id?: string;
130
- organisation_id: string;
131
- }, userId: string): Promise<WorkItem>;
132
- /**
133
- * ADOPT a pre-created assignment task at SessionStart: write the lane's
134
- * freshly-minted session onto an EXISTING task row instead of creating a new
135
- * one. `bindLane` calls this when the spawn carried a `workItemId` that resolves
136
- * to a `kind:"task"` row (the assignment task whose first comment IS the brief).
137
- * Without this, bindLane would CREATE a new task and orphan the brief-task — the
138
- * lane would `readAssignedBrief` to nothing.
139
- *
140
- * Realizes OWNERSHIP too: sets `assignee_id` to the lane's session (its stable
141
- * identity, `lane-identity-is-cli-session-id`), so the compliance gate can
142
- * distinguish a task the CALLER owes from one a dispatched lane owns (the
143
- * orchestrator supervises, not implements — `anthropic-models-orchestrate-not-
144
- * implement`). "Is the caller the assignee" becomes a simple equality on the
145
- * session.
146
- *
147
- * RE-BINDS a task another session already owns. Migration 109
148
- * (`work_items_one_active_task_per_lane`) makes `(kind_data->'lane'->>'pane')`
149
- * unique WHERE active, so when a lane is re-spawned on a pane whose prior task is
150
- * still active under a STALE session (the lane died, the row survived),
151
- * `resolveLaneTask(newSession)` finds nothing and `create` P2002s — measured
152
- * fleet-wide 2026-08-01: every real lane's bindLane 500'd on this constraint.
153
- * Refusing to steal (the original design) routes every re-spawn into that
154
- * dead-end. An assignment task belongs to whichever lane was dispatched to it,
155
- * and a stale session is by definition dead, so re-binding to the fresh session
156
- * is the correct recovery: the pane's unique slot moves to the live lane and
157
- * the brief follows. Returns null only when `maybeTaskId` is absent or not a
158
- * task — caller falls through to create for an exploratory lane (no workItemId).
159
- */
160
- export declare function adoptAssignmentTask(prisma: Prisma, maybeTaskId: string | null | undefined, lane: {
161
- session: string;
162
- pane: string | null;
163
- cli_kind?: string;
164
- role?: string;
165
- }): Promise<WorkItem | null>;
166
- /**
167
- * The bind decision AFTER attempting to adopt the spawn's referenced task. PURE
168
- * over the adopt result + whether the referenced row exists, so the
169
- * "a spawn that cannot bind fails loudly rather than orphaning" invariant
170
- * (`absent-input-reads-as-success`) is unit-testable without standing up the
171
- * ORPC handler. `bindLane` calls `adoptAssignmentTask` then this, then acts.
172
- *
173
- * `use` — adopt succeeded; bind the lane to that task.
174
- * `create` — no task to adopt: an exploratory lane (no workItemId) or the
175
- * referenced id is a PROJECT the task is created under.
176
- * `refuse` — the spawn named a workItemId the lane should adopt, but NO task
177
- * exists with that id. Silently creating a NEW task here would
178
- * abandon the spawn's referenced brief and bind the lane to an
179
- * empty task it was never meant to own — exactly the orphan
180
- * `absent-input-reads-as-success` forbids (a caller that stated
181
- * adopt-intent reads "success" while the referenced row rots).
182
- * Failing loudly surfaces the malformed spawn instead.
183
- */
184
- export type BindAction = {
185
- action: "use";
186
- task: WorkItem;
187
- } | {
188
- action: "create";
189
- scope: "exploratory" | "project-parent";
190
- } | {
191
- action: "refuse";
192
- reason: "missing-referenced-task";
193
- workItemId: string;
194
- };
195
- export declare function resolveBindAction(args: {
196
- adopted: WorkItem | null;
197
- workItemId: string | null;
198
- /** The kind of the row at workItemId, or null when no such row exists. */
199
- referencedKind: string | null;
200
- }): BindAction;
201
- /**
202
- * Bind a task to a KNOWN session — the RESUME path. Unlike a fresh spawn (the
203
- * CLI mints the session at boot, so SessionStart must adopt), a resumed/switched
204
- * lane knows its session id up front (`resumeId`). So the assignment binds the
205
- * task to `resumeId` directly and writes a NEW comment as the continuation brief,
206
- * before emitting the spawn with `resumeId`. `readAssignedBrief(resumeId)` then
207
- * returns that continuation — so `DEFAULT_CONTINUATION_PROMPT`'s job (which rode
208
- * the now-retired keystroke path) moves to a row write at assign time. Also sets
209
- * `assignee_id` (ownership) for the same reason as the fresh-spawn adopt.
210
- */
211
- export declare function bindTaskToKnownSession(prisma: Prisma, taskId: string, lane: {
212
- session: string;
213
- pane: string | null;
214
- cli_kind?: string;
215
- role?: string;
216
- }): Promise<WorkItem | null>;
217
- /**
218
- * The spawn payload an assignment emits. Carries the task id (as `workItemId`,
219
- * which the picker exports into the pane so SessionStart can ADOPT the existing
220
- * task) and NEVER an `initialPrompt` — the lane pulls its brief from the DB by
221
- * its own session id. This is the contract whatever host-command surface lands:
222
- * command `spawn_agent_tab`, payload `{ workItemId, slug?, windowName?,
223
- * idempotencyKey? }`.
224
- *
225
- * Pure (no I/O) so the "no keystroke brief, taskId-only" invariant is
226
- * unit-testable and regression-locked: a test asserting `initialPrompt` is
227
- * absent fails the moment someone re-adds keystroke delivery.
228
- */
229
- export declare function buildAssignmentSpawnPayload(task: Pick<WorkItem, "id">, options: {
230
- slug?: string;
231
- windowName?: string;
232
- idempotencyKey?: string;
233
- }): {
234
- command: "spawn_agent_tab";
235
- payload: {
236
- workItemId: string;
237
- slug?: string;
238
- windowName?: string;
239
- idempotencyKey?: string;
240
- };
241
- };
242
- /**
243
- * The emission surface an assignment writes the spawn intent to. Injected (not
244
- * imported) so this file composes with whichever bus surface the host-command-bus
245
- * cutover settles on, rather than hard-coding a second mechanism. Implementations
246
- * write a durable row the consumer reacts to (`actions-are-rows-then-emissions`):
247
- * fire-and-forget from the caller's perspective — the caller states intent and
248
- * proceeds; the consumer spawns the lane and the lane self-briefs.
249
- */
250
- export interface AssignmentEmitter {
251
- /** Write the spawn intent as a durable row the host-command consumer reacts to. */
252
- emitSpawn(payload: ReturnType<typeof buildAssignmentSpawnPayload>): Promise<void>;
253
- }
254
- /**
255
- * The outcome of assigning a task: the created/confirmed task and confirmation
256
- * that the spawn intent was emitted (not that the lane spawned — that is the
257
- * consumer's reaction, observed separately). The caller proceeds on the row.
258
- */
259
- export interface AssignmentResult {
260
- task: WorkItem;
261
- emitted: boolean;
262
- }
263
- /**
264
- * createBriefTask ORPC input. The MINT entry point a spawner calls to turn a
265
- * raw brief into the task row a lane self-briefs from. `name` is the lane's work
266
- * label (the spawner's windowName); `description` is the brief, stored as the
267
- * task's FIRST COMMENT — never on the task row itself, so "the brief" has
268
- * exactly one home (`task-sync-brief.ts` readLatestTaskComment, newest-first).
269
- * Mirrors `assignTaskInput` minus the spawn-shaping fields (slug/windowName/
270
- * idempotencyKey), which belong on the spawn emission, not the mint.
271
- */
272
- export declare const createBriefTaskInput: v.ObjectSchema<{
273
- readonly name: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, "name is required — the lane's real work label">, v.CheckAction<string, "name must carry the lane's real work name, not the generic sentinel 'Lane'">]>;
274
- readonly description: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, "description is required — it is the brief (first comment)">]>;
275
- readonly parent_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
276
- readonly organisation_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
277
- }, undefined>;
278
- /**
279
- * createBriefTask ORPC handler. `spawn_agent_tab` calls this when it receives
280
- * an `initialPrompt` with no `workItemId`: the prompt becomes the task's first
281
- * comment, the returned `work_item_id` rides the spawn payload as `workItemId`,
282
- * and the lane PULLS the brief at boot (`readAssignedBrief`) — no keystroke, no
283
- * channel send, no positional argument. That deletes the keystroke-brief
284
- * failure class by construction (`buildAssignmentSpawnPayload` already carries
285
- * `workItemId` and never `initialPrompt`).
286
- *
287
- * Wraps the pure `createTaskWithBriefComment` (atomic task + first comment). The
288
- * task is `kind:"task"`, `status:"active"`, `assignee_type:"agent"`, with NO
289
- * `kind_data.lane.session`: the CLI mints the session at spawn and SessionStart
290
- * ADOPTS this task by id (`adoptAssignmentTask`), which binds the brief to the
291
- * lane. Returns only the `work_item_id` — the single fact the spawner needs to
292
- * carry the brief without writing it into the spawn payload. Same transport as
293
- * `readAssignedBrief`: page-gate-exempt (fn.taskSync), localhost super-admin.
294
- */
295
- export declare const createBriefTaskHandler: import("@orpc/server").DecoratedProcedure<import("@orpc/server").MergedInitialContext<Context & Record<never, never>, Context, Context>, import("@orpc/server").MergedCurrentContext<Context, {
296
- headers: Headers;
297
- resolveUser?: (headers: Headers, prisma: any) => Promise<import("./auth-router.ts").User | null>;
298
- prisma: any;
299
- user: import("./auth-router.ts").User;
300
- orgId: string | null | undefined;
301
- }>, import("@orpc/contract").Schema<unknown, unknown>, import("@orpc/contract").Schema<{
302
- work_item_id: string;
303
- comment_id: string;
304
- }, {
305
- work_item_id: string;
306
- comment_id: string;
307
- }>, Record<never, never>, Record<never, never>>;
@@ -1,98 +0,0 @@
1
- /**
2
- * @system service-boot
3
- * @status handwritten
4
- * @edit edit directly
5
- *
6
- * Lane BRIEF resolution for task-sync: a spawned lane PULLS its own brief. The
7
- * lane's CLI extension reads its own session id on load, resolves the task
8
- * assigned to that session, and reads the brief from that task's FIRST comment.
9
- * Nothing is pasted, typed, passed as an argument or sent over a channel
10
- * (`scala-docs/reference/action-emission-architecture.md` "The lane PULLS its
11
- * brief"). This file owns the readAssignedBrief ORPC handler + its pure helper;
12
- * the router mounts the handler.
13
- *
14
- * Split out of task-sync-router.ts for the same reason task-sync-lane.ts +
15
- * task-sync-projection.ts exist: the router sits at its 1000-line commit gate,
16
- * so every cohesive unit that can live in a sibling does. The self-brief leg is
17
- * one unit — the handler + the response-shaping decision belong together.
18
- *
19
- * CAPABILITY HARVEST (capability-harvest-on-split): APP-LOCAL, not a capability
20
- * candidate. Bound to the work_items + comments schema and to task-sync's own
21
- * kind_data.lane.session convention; no unrelated app could install this
22
- * unmodified.
23
- */
24
- import type { Prisma, CommentRow } from "./task-sync-router.ts";
25
- import { type Context } from "./auth-router.ts";
26
- /**
27
- * The outcome of a brief read, single-sourced here so every CLI's self-brief
28
- * hook (zerostack/codex shell, opencode/pi TS) branches on ONE field rather
29
- * than each re-deriving "is the brief missing" from null/empty probes — the
30
- * seam at which absent-input-reads-as-success hid (`the-severe-bugs-live-at-seams`).
31
- *
32
- * The hook decides ACTION from this; the classification lives here. A fleet
33
- * lane (SCALA_LANE_WORK_ITEM set) treats anything but "ready" as a hard halt.
34
- */
35
- export type BriefReadStatus = "ready" | "empty_brief" | "no_comment" | "unbound";
36
- /**
37
- * Shape the readAssignedBrief response from a resolved task + its first
38
- * comment. Pure (no prisma) so the decision — "no task/comment ⇒ nulls, never a
39
- * verdict from no data" (`no-verdict-from-no-data`) — is unit-testable.
40
- *
41
- * `work_item_id` is set iff the TASK resolved (independent of whether a comment
42
- * exists), and `status` distinguishes the four states a hook must act on:
43
- * - "ready" — task + a non-empty comment: inject the brief.
44
- * - "empty_brief" — task resolved, comment exists but content is blank: the
45
- * spawn minted a task with no usable brief — broken.
46
- * - "no_comment" — task resolved, no comment at all: same broken class.
47
- * - "unbound" — no task resolved: the lane has no brief task (a non-fleet
48
- * operator tab, or — for the session-only path — a bind
49
- * that has not yet commit; the work_item_id path cannot
50
- * reach this for a fleet lane).
51
- *
52
- * "empty_brief" / "no_comment" with the task resolved is the state the
53
- * absent-input fix exists to catch: a fleet lane whose spawn succeeded MUST
54
- * have a non-empty brief comment, so its absence is a defect the hook halts on
55
- * rather than reading as success.
56
- */
57
- export declare function shapeBriefResponse(task: {
58
- id: string;
59
- } | null, comment: Pick<CommentRow, "id" | "content" | "created_at"> | null): {
60
- work_item_id: string | null;
61
- comment_id: string | null;
62
- brief: string | null;
63
- comment_created_at: string | null;
64
- status: BriefReadStatus;
65
- };
66
- /**
67
- * Read the immutable FIRST comment on a work_items task. It is the launch brief;
68
- * later comments are conversation and must never change the launch identity.
69
- * Oldest-first by created_at with id as a deterministic tie-breaker. Returns null
70
- * when the task has no comment yet.
71
- */
72
- export declare function readFirstTaskComment(prisma: Prisma, workItemId: string): Promise<CommentRow | null>;
73
- /**
74
- * readAssignedBrief ORPC handler. A lane's CLI extension calls this with its
75
- * own session id to pull its brief. Same transport as bindLane/readTaskList: the
76
- * session id arrives on x-lane-session (and body.lane_session as fallback). The
77
- * procedure is page-gate-exempt (fn.taskSync), so a localhost pane shell
78
- * authenticates as super-admin via resolveUser with no session cookie.
79
- */
80
- export declare const readAssignedBriefHandler: import("@orpc/server").DecoratedProcedure<import("@orpc/server").MergedInitialContext<Context & Record<never, never>, Context, Context>, import("@orpc/server").MergedCurrentContext<Context, {
81
- headers: Headers;
82
- resolveUser?: (headers: Headers, prisma: any) => Promise<import("./auth-router.ts").User | null>;
83
- prisma: any;
84
- user: import("./auth-router.ts").User;
85
- orgId: string | null | undefined;
86
- }>, import("@orpc/contract").Schema<unknown, unknown>, import("@orpc/contract").Schema<{
87
- work_item_id: string | null;
88
- comment_id: string | null;
89
- brief: string | null;
90
- comment_created_at: string | null;
91
- status: BriefReadStatus;
92
- }, {
93
- work_item_id: string | null;
94
- comment_id: string | null;
95
- brief: string | null;
96
- comment_created_at: string | null;
97
- status: BriefReadStatus;
98
- }>, Record<never, never>, Record<never, never>>;