agent-issues 0.0.121 → 0.0.126

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 (166) hide show
  1. package/dist/build-info.json +3 -0
  2. package/dist/cli.js +97746 -26
  3. package/kanban/dist/assets/index-CIAg6qj5.css +1 -0
  4. package/kanban/dist/assets/index-DaYQjJS7.js +920 -0
  5. package/kanban/dist/index.html +13 -0
  6. package/package.json +12 -11
  7. package/site/dist/assets/{index-Cx-fLU3e.js → index-D6NM1iDo.js} +181 -144
  8. package/site/dist/index.html +1 -1
  9. package/dist/agent-installer.d.ts +0 -49
  10. package/dist/agent-installer.js +0 -171
  11. package/dist/agent-installer.js.map +0 -1
  12. package/dist/auth-session.d.ts +0 -40
  13. package/dist/auth-session.js +0 -107
  14. package/dist/auth-session.js.map +0 -1
  15. package/dist/body-backfill.d.ts +0 -26
  16. package/dist/body-backfill.js +0 -219
  17. package/dist/body-backfill.js.map +0 -1
  18. package/dist/build-mode.d.ts +0 -1
  19. package/dist/build-mode.js +0 -1
  20. package/dist/build-mode.js.map +0 -1
  21. package/dist/cli/commands/auth.d.ts +0 -61
  22. package/dist/cli/commands/auth.js +0 -134
  23. package/dist/cli/commands/auth.js.map +0 -1
  24. package/dist/cli/commands/backfill.d.ts +0 -8
  25. package/dist/cli/commands/backfill.js +0 -36
  26. package/dist/cli/commands/backfill.js.map +0 -1
  27. package/dist/cli/commands/comments.d.ts +0 -34
  28. package/dist/cli/commands/comments.js +0 -124
  29. package/dist/cli/commands/comments.js.map +0 -1
  30. package/dist/cli/commands/context.d.ts +0 -13
  31. package/dist/cli/commands/context.js +0 -156
  32. package/dist/cli/commands/context.js.map +0 -1
  33. package/dist/cli/commands/entities.d.ts +0 -91
  34. package/dist/cli/commands/entities.js +0 -420
  35. package/dist/cli/commands/entities.js.map +0 -1
  36. package/dist/cli/commands/export.d.ts +0 -20
  37. package/dist/cli/commands/export.js +0 -98
  38. package/dist/cli/commands/export.js.map +0 -1
  39. package/dist/cli/commands/fallback.d.ts +0 -6
  40. package/dist/cli/commands/fallback.js +0 -10
  41. package/dist/cli/commands/fallback.js.map +0 -1
  42. package/dist/cli/commands/handoff.d.ts +0 -1
  43. package/dist/cli/commands/handoff.js +0 -2
  44. package/dist/cli/commands/handoff.js.map +0 -1
  45. package/dist/cli/commands/installers.d.ts +0 -37
  46. package/dist/cli/commands/installers.js +0 -78
  47. package/dist/cli/commands/installers.js.map +0 -1
  48. package/dist/cli/commands/kanban.d.ts +0 -8
  49. package/dist/cli/commands/kanban.js +0 -83
  50. package/dist/cli/commands/kanban.js.map +0 -1
  51. package/dist/cli/commands/meta.d.ts +0 -14
  52. package/dist/cli/commands/meta.js +0 -33
  53. package/dist/cli/commands/meta.js.map +0 -1
  54. package/dist/cli/commands/plan-entries.d.ts +0 -30
  55. package/dist/cli/commands/plan-entries.js +0 -94
  56. package/dist/cli/commands/plan-entries.js.map +0 -1
  57. package/dist/cli/commands/site.d.ts +0 -29
  58. package/dist/cli/commands/site.js +0 -89
  59. package/dist/cli/commands/site.js.map +0 -1
  60. package/dist/cli/commands/sql.d.ts +0 -6
  61. package/dist/cli/commands/sql.js +0 -21
  62. package/dist/cli/commands/sql.js.map +0 -1
  63. package/dist/cli/commands/synchronize.d.ts +0 -12
  64. package/dist/cli/commands/synchronize.js +0 -31
  65. package/dist/cli/commands/synchronize.js.map +0 -1
  66. package/dist/cli/commands/tenants.d.ts +0 -29
  67. package/dist/cli/commands/tenants.js +0 -101
  68. package/dist/cli/commands/tenants.js.map +0 -1
  69. package/dist/cli/index.d.ts +0 -4
  70. package/dist/cli/index.js +0 -120
  71. package/dist/cli/index.js.map +0 -1
  72. package/dist/cli/renderers.d.ts +0 -250
  73. package/dist/cli/renderers.js +0 -286
  74. package/dist/cli/renderers.js.map +0 -1
  75. package/dist/cli/shared.d.ts +0 -97
  76. package/dist/cli/shared.js +0 -192
  77. package/dist/cli/shared.js.map +0 -1
  78. package/dist/cli.d.ts +0 -11
  79. package/dist/cli.js.map +0 -1
  80. package/dist/context-cli.d.ts +0 -16
  81. package/dist/context-cli.js +0 -131
  82. package/dist/context-cli.js.map +0 -1
  83. package/dist/daemon/daemon-lifecycle.d.ts +0 -1
  84. package/dist/daemon/daemon-lifecycle.js +0 -2
  85. package/dist/daemon/daemon-lifecycle.js.map +0 -1
  86. package/dist/daemon/daemon-main.d.ts +0 -14
  87. package/dist/daemon/daemon-main.js +0 -30
  88. package/dist/daemon/daemon-main.js.map +0 -1
  89. package/dist/daemon/local-daemon-store.d.ts +0 -21
  90. package/dist/daemon/local-daemon-store.js +0 -31
  91. package/dist/daemon/local-daemon-store.js.map +0 -1
  92. package/dist/entity-projection.d.ts +0 -141
  93. package/dist/entity-projection.js +0 -147
  94. package/dist/entity-projection.js.map +0 -1
  95. package/dist/entra-device-login.d.ts +0 -12
  96. package/dist/entra-device-login.js +0 -40
  97. package/dist/entra-device-login.js.map +0 -1
  98. package/dist/export-files.d.ts +0 -24
  99. package/dist/export-files.js +0 -230
  100. package/dist/export-files.js.map +0 -1
  101. package/dist/export-markdown.d.ts +0 -24
  102. package/dist/export-markdown.js +0 -343
  103. package/dist/export-markdown.js.map +0 -1
  104. package/dist/help.d.ts +0 -112
  105. package/dist/help.js +0 -1430
  106. package/dist/help.js.map +0 -1
  107. package/dist/kanban/assets.d.ts +0 -3
  108. package/dist/kanban/assets.js +0 -37
  109. package/dist/kanban/assets.js.map +0 -1
  110. package/dist/kanban/index.d.ts +0 -1
  111. package/dist/kanban/index.js +0 -2
  112. package/dist/kanban/index.js.map +0 -1
  113. package/dist/kanban/server.d.ts +0 -28
  114. package/dist/kanban/server.js +0 -118
  115. package/dist/kanban/server.js.map +0 -1
  116. package/dist/mcp-installer.d.ts +0 -32
  117. package/dist/mcp-installer.js +0 -118
  118. package/dist/mcp-installer.js.map +0 -1
  119. package/dist/mcp-server/index.d.ts +0 -11
  120. package/dist/mcp-server/index.js +0 -504
  121. package/dist/mcp-server/index.js.map +0 -1
  122. package/dist/mcp-server/index.test.d.ts +0 -1
  123. package/dist/mcp-server/index.test.js +0 -746
  124. package/dist/mcp-server/index.test.js.map +0 -1
  125. package/dist/mcp-server/mcp-tool-audit.d.ts +0 -6
  126. package/dist/mcp-server/mcp-tool-audit.js +0 -47
  127. package/dist/mcp-server/mcp-tool-audit.js.map +0 -1
  128. package/dist/mcp-server/stdio.d.ts +0 -2
  129. package/dist/mcp-server/stdio.js +0 -7
  130. package/dist/mcp-server/stdio.js.map +0 -1
  131. package/dist/mcp.d.ts +0 -2
  132. package/dist/mcp.js +0 -19
  133. package/dist/mcp.js.map +0 -1
  134. package/dist/open-storage-driver.d.ts +0 -55
  135. package/dist/open-storage-driver.js +0 -73
  136. package/dist/open-storage-driver.js.map +0 -1
  137. package/dist/open-synchronize-stores.d.ts +0 -24
  138. package/dist/open-synchronize-stores.js +0 -34
  139. package/dist/open-synchronize-stores.js.map +0 -1
  140. package/dist/project-identity.d.ts +0 -23
  141. package/dist/project-identity.js +0 -121
  142. package/dist/project-identity.js.map +0 -1
  143. package/dist/runtime-access-boundary.d.ts +0 -7
  144. package/dist/runtime-access-boundary.js +0 -182
  145. package/dist/runtime-access-boundary.js.map +0 -1
  146. package/dist/service-discovery.d.ts +0 -10
  147. package/dist/service-discovery.js +0 -64
  148. package/dist/service-discovery.js.map +0 -1
  149. package/dist/site/assets.d.ts +0 -4
  150. package/dist/site/assets.js +0 -46
  151. package/dist/site/assets.js.map +0 -1
  152. package/dist/site/cloud-events-relay.d.ts +0 -16
  153. package/dist/site/cloud-events-relay.js +0 -78
  154. package/dist/site/cloud-events-relay.js.map +0 -1
  155. package/dist/site/index.d.ts +0 -1
  156. package/dist/site/index.js +0 -2
  157. package/dist/site/index.js.map +0 -1
  158. package/dist/site/server.d.ts +0 -42
  159. package/dist/site/server.js +0 -632
  160. package/dist/site/server.js.map +0 -1
  161. package/dist/skill-installer.d.ts +0 -35
  162. package/dist/skill-installer.js +0 -180
  163. package/dist/skill-installer.js.map +0 -1
  164. package/dist/vitest-setup.d.ts +0 -1
  165. package/dist/vitest-setup.js +0 -7
  166. package/dist/vitest-setup.js.map +0 -1
@@ -1,632 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import { createServer, request as sendRequest } from "node:http";
3
- import { readBuildContentHash, resolveDatabasePath, resolveTenantSlug } from "@agent-issues/api-local";
4
- import { ENTITY_KINDS, mergeProjectChangeEventDetails, projectChangeEventForWrite, rpcMethods, writeMethods } from "@agent-issues/core";
5
- import { getBuiltSiteAssetPath, getContentType } from "./assets.js";
6
- import { subscribeToCloudEvents } from "./cloud-events-relay.js";
7
- import { withStore } from "../cli/shared.js";
8
- import { openStorageDriver } from "../open-storage-driver.js";
9
- const LIVE_SITE_STOP_PATH = "/__agent_issues/stop";
10
- const INITIATIVE_TABS = ["overview", "issues", "plans", "prds", "adrs", "context", "userStories", "debt", "graph"];
11
- const PROJECT_MUTATION_METHODS = new Set([
12
- "applyRelations",
13
- "archiveEntity",
14
- "createEntity",
15
- "createIssueComment",
16
- "createPlanEntry",
17
- "defineContextTerm",
18
- "deleteEntity",
19
- "deleteIssueComment",
20
- "deletePlanEntry",
21
- "forgetContextTerm",
22
- "linkEntities",
23
- "linkPlanEntryIssue",
24
- "moveEntity",
25
- "restoreContextRevision",
26
- "restoreContextTermRevision",
27
- "restoreEntityRevision",
28
- "setEntityBody",
29
- "unlinkEntities",
30
- "unlinkPlanEntryIssue",
31
- "updateEntity",
32
- "updateEntityStatus",
33
- "updateIssueComment",
34
- "updatePlanEntry",
35
- "upsertContext"
36
- ]);
37
- function isInitiativeTab(value) {
38
- return typeof value === "string" && INITIATIVE_TABS.includes(value);
39
- }
40
- export async function startLiveSite(input) {
41
- const currentWorkingDirectory = input.currentWorkingDirectory;
42
- const credentialStoreOptions = input.credentialStoreOptions;
43
- const defaultTenant = resolveTenantSlug({ currentWorkingDirectory, tenant: input.tenant });
44
- const dbPath = resolveDatabasePath(input.dbPath, { tenant: input.tenant });
45
- const host = input.host ?? "127.0.0.1";
46
- const port = input.port ?? 4173;
47
- const pollIntervalMs = input.pollIntervalMs ?? 1000;
48
- const info = {
49
- dbPath,
50
- defaultTenant,
51
- host,
52
- port,
53
- url: `http://${host}:${port}`
54
- };
55
- const clients = new Set();
56
- // Resolved once at startup (ADR13, ADR18): decides whether live-refresh
57
- // polls the local file or relays the cloud API's own SSE channel (ISS56).
58
- // Snapshot/site-config reads re-resolve per request through `withStore`
59
- // instead, since a long-lived cloud session could expire mid-run.
60
- const opened = await openStorageDriver({
61
- dbPath: input.dbPath,
62
- databaseOptions: { currentWorkingDirectory, tenant: input.tenant },
63
- authSessionOptions: credentialStoreOptions,
64
- localDaemon: { buildHash: readBuildContentHash() }
65
- });
66
- await opened.store.close();
67
- if (opened.daemonFallbackWarning) {
68
- process.stderr.write(`Warning: ${opened.daemonFallbackWarning}\n`);
69
- }
70
- let databaseSignature = opened.backend === "local"
71
- ? await readSnapshotSignature(dbPath, defaultTenant, currentWorkingDirectory, credentialStoreOptions)
72
- : undefined;
73
- let pollTimer;
74
- let pollingStopped = false;
75
- let stopCloudEventsRelay;
76
- const server = createServer((request, response) => {
77
- void handleRequest({
78
- request,
79
- response,
80
- dbPath,
81
- clients,
82
- currentWorkingDirectory,
83
- defaultTenant,
84
- server,
85
- credentialStoreOptions,
86
- onLocalMutation: (event, signature) => {
87
- databaseSignature = signature;
88
- broadcast(clients, JSON.stringify(event));
89
- }
90
- });
91
- });
92
- if (opened.backend === "local") {
93
- // A self-rescheduling `setTimeout` (rather than `setInterval`) so a
94
- // slow tick through the storage-driver seam can never overlap with
95
- // the next one - the next poll is only scheduled once the current
96
- // one's `getSnapshotSignature()` call has resolved (ISS191).
97
- const scheduleNextPoll = () => {
98
- if (pollingStopped) {
99
- return;
100
- }
101
- pollTimer = setTimeout(() => {
102
- void readSnapshotSignature(dbPath, defaultTenant, currentWorkingDirectory, credentialStoreOptions).then((nextSignature) => {
103
- if (nextSignature !== databaseSignature) {
104
- databaseSignature = nextSignature;
105
- broadcast(clients, JSON.stringify({ type: "snapshot-changed", at: new Date().toISOString(), category: "unknown" }));
106
- }
107
- scheduleNextPoll();
108
- });
109
- }, pollIntervalMs);
110
- };
111
- scheduleNextPoll();
112
- }
113
- else if (opened.cloudConnection) {
114
- stopCloudEventsRelay = subscribeToCloudEvents(opened.cloudConnection, (event) => {
115
- broadcast(clients, JSON.stringify(event));
116
- });
117
- }
118
- server.on("close", () => {
119
- pollingStopped = true;
120
- if (pollTimer) {
121
- clearTimeout(pollTimer);
122
- }
123
- stopCloudEventsRelay?.();
124
- for (const client of clients) {
125
- client.end();
126
- }
127
- clients.clear();
128
- });
129
- server.on("error", () => {
130
- pollingStopped = true;
131
- if (pollTimer) {
132
- clearTimeout(pollTimer);
133
- }
134
- stopCloudEventsRelay?.();
135
- });
136
- server.listen(port, host);
137
- return {
138
- info,
139
- server,
140
- close: () => {
141
- server.close();
142
- }
143
- };
144
- }
145
- export async function stopLiveSite(input) {
146
- const host = input.host ?? "127.0.0.1";
147
- const port = input.port ?? 4173;
148
- const url = `http://${host}:${port}`;
149
- return await new Promise((resolve, reject) => {
150
- let timedOut = false;
151
- const request = sendRequest({
152
- host,
153
- method: "POST",
154
- path: LIVE_SITE_STOP_PATH,
155
- port
156
- }, (response) => {
157
- response.resume();
158
- response.once("end", () => {
159
- resolve({
160
- host,
161
- port,
162
- reachable: true,
163
- url,
164
- stopped: response.statusCode === 200
165
- });
166
- });
167
- });
168
- request.setTimeout(500, () => {
169
- timedOut = true;
170
- request.destroy(new Error("Timed out waiting for the live site stop response."));
171
- });
172
- request.once("error", (error) => {
173
- const code = error.code;
174
- if (timedOut) {
175
- resolve({ host, port, reachable: true, url, stopped: false });
176
- return;
177
- }
178
- if (code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EPIPE") {
179
- resolve({ host, port, reachable: false, url, stopped: false });
180
- return;
181
- }
182
- reject(error);
183
- });
184
- request.end();
185
- });
186
- }
187
- async function handleRequest(input) {
188
- const requestUrl = new URL(input.request.url ?? "/", "http://127.0.0.1");
189
- const requestedTenant = requestUrl.searchParams.get("tenant")?.trim() || input.defaultTenant;
190
- const requestedProjectIdentity = requestUrl.searchParams.get("project")?.trim() || undefined;
191
- if (requestUrl.pathname === LIVE_SITE_STOP_PATH) {
192
- if (input.request.method !== "POST") {
193
- writeText(input.response, 405, "Method Not Allowed");
194
- return;
195
- }
196
- writeText(input.response, 200, "Stopping live site");
197
- setImmediate(() => {
198
- input.server.close();
199
- });
200
- return;
201
- }
202
- if (requestUrl.pathname === "/api/project-mutation") {
203
- if (input.request.method !== "POST") {
204
- writeText(input.response, 405, "Method Not Allowed");
205
- return;
206
- }
207
- let mutation;
208
- try {
209
- mutation = await readProjectMutationRequest(input.request);
210
- }
211
- catch (error) {
212
- writeText(input.response, 400, error instanceof Error ? error.message : "Invalid project mutation request.");
213
- return;
214
- }
215
- try {
216
- writeJson(input.response, await executeProjectMutation({
217
- credentialStoreOptions: input.credentialStoreOptions,
218
- currentWorkingDirectory: input.currentWorkingDirectory,
219
- dbPath: input.dbPath,
220
- mutation,
221
- onLocalMutation: input.onLocalMutation,
222
- projectId: requestedProjectIdentity,
223
- tenant: requestedTenant
224
- }));
225
- }
226
- catch (error) {
227
- writeText(input.response, 500, error instanceof Error ? error.message : "Project mutation failed.");
228
- }
229
- return;
230
- }
231
- if (input.request.method !== "GET") {
232
- writeText(input.response, 405, "Method Not Allowed");
233
- return;
234
- }
235
- if (requestUrl.pathname === "/site-config.json") {
236
- writeJson(input.response, await readSiteConfig(input.dbPath, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions));
237
- return;
238
- }
239
- if (requestUrl.pathname === "/api/snapshot") {
240
- writeJson(input.response, await readSnapshot(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, requestedProjectIdentity));
241
- return;
242
- }
243
- if (requestUrl.pathname === "/api/project-summary") {
244
- const startedAt = performance.now();
245
- const projectSummary = await readProjectSummary(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, requestedProjectIdentity);
246
- writeJson(input.response, projectSummary, { durationMs: performance.now() - startedAt, metricName: "project-summary" });
247
- return;
248
- }
249
- if (requestUrl.pathname === "/api/entity-detail") {
250
- const entityId = requestUrl.searchParams.get("entity")?.trim();
251
- if (!entityId) {
252
- writeText(input.response, 400, "Invalid entity detail request.");
253
- return;
254
- }
255
- writeJson(input.response, await readEntityDetails(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, entityId, requestedProjectIdentity));
256
- return;
257
- }
258
- if (requestUrl.pathname === "/api/entity-relations") {
259
- const entityId = requestUrl.searchParams.get("entity")?.trim();
260
- if (!entityId) {
261
- writeText(input.response, 400, "Invalid entity relations request.");
262
- return;
263
- }
264
- writeJson(input.response, await readEntityRelations(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, entityId, requestedProjectIdentity));
265
- return;
266
- }
267
- if (requestUrl.pathname === "/api/issue-comments") {
268
- const issueId = requestUrl.searchParams.get("issue")?.trim();
269
- if (!issueId) {
270
- writeText(input.response, 400, "Invalid issue comments request.");
271
- return;
272
- }
273
- const before = requestUrl.searchParams.get("before")?.trim();
274
- const all = requestUrl.searchParams.get("all") === "true";
275
- writeJson(input.response, await readIssueComments(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, requestedProjectIdentity, { issueId, ...(before ? { before } : {}), ...(all ? { all } : {}) }));
276
- return;
277
- }
278
- if (requestUrl.pathname === "/api/plan-entries") {
279
- const planId = requestUrl.searchParams.get("plan")?.trim();
280
- if (!planId) {
281
- writeText(input.response, 400, "Invalid Plan entries request.");
282
- return;
283
- }
284
- const before = requestUrl.searchParams.get("before")?.trim();
285
- const all = requestUrl.searchParams.get("all") === "true";
286
- writeJson(input.response, await readPlanEntryPage(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, requestedProjectIdentity, { planId, ...(before ? { before } : {}), ...(all ? { all } : {}) }));
287
- return;
288
- }
289
- if (requestUrl.pathname === "/api/project-adrs") {
290
- writeJson(input.response, await readProjectAdrs(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, requestedProjectIdentity));
291
- return;
292
- }
293
- if (requestUrl.pathname === "/api/project-debt") {
294
- writeJson(input.response, await readProjectDebt(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, requestedProjectIdentity));
295
- return;
296
- }
297
- if (requestUrl.pathname === "/api/project-context") {
298
- writeJson(input.response, await readProjectContext(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, requestedProjectIdentity));
299
- return;
300
- }
301
- if (requestUrl.pathname === "/api/project-graph") {
302
- writeJson(input.response, await readProjectGraph(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, requestedProjectIdentity));
303
- return;
304
- }
305
- if (requestUrl.pathname === "/api/initiative-tab") {
306
- const initiativeId = requestUrl.searchParams.get("initiative")?.trim();
307
- const tab = requestUrl.searchParams.get("tab");
308
- if (!initiativeId || !isInitiativeTab(tab)) {
309
- writeText(input.response, 400, "Invalid initiative tab request.");
310
- return;
311
- }
312
- writeJson(input.response, await readInitiativeTab(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, initiativeId, tab, requestedProjectIdentity));
313
- return;
314
- }
315
- if (requestUrl.pathname === "/api/initiative-detail") {
316
- const initiativeId = requestUrl.searchParams.get("initiative")?.trim();
317
- if (!initiativeId) {
318
- writeText(input.response, 400, "Invalid initiative detail request.");
319
- return;
320
- }
321
- writeJson(input.response, await readInitiativeDetail(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, initiativeId, requestedProjectIdentity));
322
- return;
323
- }
324
- if (requestUrl.pathname === "/api/projects") {
325
- writeJson(input.response, await readProjectDiscovery(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, requestedProjectIdentity));
326
- return;
327
- }
328
- if (requestUrl.pathname === "/api/search/capability") {
329
- writeJson(input.response, await readSearchCapability(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions));
330
- return;
331
- }
332
- if (requestUrl.pathname === "/api/search") {
333
- const searchRequest = parseSearchRequest(requestUrl);
334
- if (!searchRequest) {
335
- writeText(input.response, 400, "Invalid search request.");
336
- return;
337
- }
338
- writeJson(input.response, await readSearch(input.dbPath, requestedTenant, input.defaultTenant, input.currentWorkingDirectory, input.credentialStoreOptions, searchRequest));
339
- return;
340
- }
341
- if (requestUrl.pathname === "/events") {
342
- input.response.writeHead(200, {
343
- "Content-Type": "text/event-stream; charset=utf-8",
344
- "Cache-Control": "no-cache, no-transform",
345
- Connection: "keep-alive"
346
- });
347
- input.response.write("retry: 1000\n");
348
- input.response.write(`data: ${JSON.stringify({ type: "connected", at: new Date().toISOString() })}\n\n`);
349
- input.clients.add(input.response);
350
- input.request.on("close", () => {
351
- input.clients.delete(input.response);
352
- });
353
- return;
354
- }
355
- const assetPath = getBuiltSiteAssetPath(requestUrl.pathname);
356
- if (assetPath) {
357
- input.response.writeHead(200, {
358
- "Content-Type": getContentType(assetPath),
359
- "Cache-Control": assetPath.endsWith("index.html") ? "no-store" : "public, max-age=31536000, immutable"
360
- });
361
- input.response.end(readFileSync(assetPath));
362
- return;
363
- }
364
- writeText(input.response, 404, "Not Found");
365
- }
366
- async function readSiteConfig(dbPath, defaultTenant, currentWorkingDirectory, credentialStoreOptions) {
367
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant: defaultTenant }, async (store, resolvedDbPath) => {
368
- const availableTenants = await store.listTenants();
369
- const currentTenant = availableTenants.some((tenant) => tenant.id === defaultTenant)
370
- ? defaultTenant
371
- : (availableTenants[0]?.id ?? defaultTenant);
372
- return {
373
- availableTenants,
374
- currentTenant,
375
- dbPath: resolvedDbPath
376
- };
377
- });
378
- }
379
- async function readSnapshot(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectId) {
380
- if (!projectId) {
381
- return { kind: "unavailable" };
382
- }
383
- if (tenant !== defaultTenant) {
384
- const availableTenants = await withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant: defaultTenant }, (store) => store.listTenants());
385
- if (!availableTenants.some((availableTenant) => availableTenant.id === tenant)) {
386
- return { kind: "unavailable" };
387
- }
388
- }
389
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant }, (store) => store.getDatabaseSnapshot({ projectId }));
390
- }
391
- async function readTenantScoped(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity, read) {
392
- if (tenant !== defaultTenant) {
393
- const availableTenants = await withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant: defaultTenant }, (store) => store.listTenants());
394
- if (!availableTenants.some((availableTenant) => availableTenant.id === tenant)) {
395
- return { kind: "unavailable" };
396
- }
397
- }
398
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, projectIdentity, tenant }, read);
399
- }
400
- async function readEntityRelations(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, entityId, projectIdentity) {
401
- return readTenantScoped(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity, async (store) => {
402
- const relations = await store.queryEntityRelations({ entityId });
403
- return await hasSelectedProjectEntity(store, relations.entity.kind, relations.entity.id)
404
- ? relations
405
- : { kind: "unavailable" };
406
- });
407
- }
408
- async function readIssueComments(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity, input) {
409
- return readTenantScoped(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity, (store) => store.listIssueComments(input));
410
- }
411
- async function readPlanEntryPage(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity, input) {
412
- return readTenantScoped(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity, (store) => store.listPlanEntryPage(input));
413
- }
414
- async function readProjectAdrs(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity) {
415
- return readTenantScoped(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity, async (store) => {
416
- const [projectAdrs, initiatives] = await Promise.all([
417
- store.listProjectAdrs(),
418
- store.listEntities("initiative")
419
- ]);
420
- const initiativeAdrs = await Promise.all(initiatives.map(async (initiative) => ({
421
- adrs: (await store.getInitiativeTab({ initiativeId: initiative.id, tab: "adrs" })).records,
422
- initiative
423
- })));
424
- return { initiativeAdrs, projectAdrs };
425
- });
426
- }
427
- async function readProjectDebt(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity) {
428
- return readTenantScoped(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity, async (store) => {
429
- const result = await store.queryEntities({ kind: "debt" });
430
- return { records: result.entities, relations: [] };
431
- });
432
- }
433
- async function readProjectContext(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity) {
434
- return readTenantScoped(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity, (store) => store.getContextDirectory());
435
- }
436
- async function readProjectGraph(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity) {
437
- return readTenantScoped(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectIdentity, async (store) => {
438
- const records = [...new Map((await Promise.all(ENTITY_KINDS.map((kind) => store.listEntities(kind)))).flat().map((record) => [record.id, record])).values()];
439
- const recordIds = new Set(records.map((record) => record.id));
440
- const relations = (await store.listAllRelations()).filter((relation) => recordIds.has(relation.fromId) && recordIds.has(relation.toId));
441
- return { records, relations };
442
- });
443
- }
444
- async function readProjectDiscovery(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectId) {
445
- if (tenant !== defaultTenant) {
446
- const availableTenants = await withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant: defaultTenant }, (store) => store.listTenants());
447
- if (!availableTenants.some((availableTenant) => availableTenant.id === tenant)) {
448
- return { kind: "unavailable" };
449
- }
450
- }
451
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant }, (store) => store.getProjectDiscovery(projectId ? { projectId } : undefined));
452
- }
453
- async function readProjectSummary(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, projectId) {
454
- if (!projectId) {
455
- return { kind: "unavailable" };
456
- }
457
- if (tenant !== defaultTenant) {
458
- const availableTenants = await withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant: defaultTenant }, (store) => store.listTenants());
459
- if (!availableTenants.some((availableTenant) => availableTenant.id === tenant)) {
460
- return { kind: "unavailable" };
461
- }
462
- }
463
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant }, (store) => store.getProjectSummary({ projectId }));
464
- }
465
- async function readEntityDetails(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, entityId, projectIdentity) {
466
- if (tenant !== defaultTenant) {
467
- const availableTenants = await withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant: defaultTenant }, (store) => store.listTenants());
468
- if (!availableTenants.some((availableTenant) => availableTenant.id === tenant)) {
469
- return { kind: "unavailable" };
470
- }
471
- }
472
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, projectIdentity, tenant }, async (store) => {
473
- const details = await store.getEntityDetails(entityId);
474
- return await hasSelectedProjectEntity(store, details.entity.kind, details.entity.id)
475
- ? details
476
- : { kind: "unavailable" };
477
- });
478
- }
479
- async function readInitiativeTab(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, initiativeId, tab, projectIdentity) {
480
- if (tenant !== defaultTenant) {
481
- const availableTenants = await withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant: defaultTenant }, (store) => store.listTenants());
482
- if (!availableTenants.some((availableTenant) => availableTenant.id === tenant)) {
483
- return { kind: "unavailable" };
484
- }
485
- }
486
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, projectIdentity, tenant }, async (store) => await hasSelectedProjectEntity(store, "initiative", initiativeId)
487
- ? store.getInitiativeTab({ initiativeId, tab })
488
- : { kind: "unavailable" });
489
- }
490
- async function readInitiativeDetail(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, initiativeId, projectIdentity) {
491
- if (tenant !== defaultTenant) {
492
- const availableTenants = await withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant: defaultTenant }, (store) => store.listTenants());
493
- if (!availableTenants.some((availableTenant) => availableTenant.id === tenant)) {
494
- return { kind: "unavailable" };
495
- }
496
- }
497
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, projectIdentity, tenant }, async (store) => await hasSelectedProjectEntity(store, "initiative", initiativeId)
498
- ? store.getInitiativeDetail({ initiativeId })
499
- : { kind: "unavailable" });
500
- }
501
- async function hasSelectedProjectEntity(store, kind, entityIdentity) {
502
- return (await store.listEntities(kind)).some((entity) => entity.id === entityIdentity || entity.reference === entityIdentity || entity.shortReference === entityIdentity);
503
- }
504
- async function readSearchCapability(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions) {
505
- if (tenant !== defaultTenant) {
506
- const availableTenants = await withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant: defaultTenant }, (store) => store.listTenants());
507
- if (!availableTenants.some((availableTenant) => availableTenant.id === tenant)) {
508
- return { state: "unsupported" };
509
- }
510
- }
511
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant }, (store) => store.getSearchCapability());
512
- }
513
- async function readSearch(dbPath, tenant, defaultTenant, currentWorkingDirectory, credentialStoreOptions, searchRequest) {
514
- if (tenant !== defaultTenant) {
515
- const availableTenants = await withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant: defaultTenant }, (store) => store.listTenants());
516
- if (!availableTenants.some((availableTenant) => availableTenant.id === tenant)) {
517
- return { state: "unsupported" };
518
- }
519
- }
520
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant }, (store) => store.search(searchRequest));
521
- }
522
- function parseSearchRequest(requestUrl) {
523
- const query = requestUrl.searchParams.get("query")?.trim();
524
- const scope = requestUrl.searchParams.get("scope");
525
- const projectId = requestUrl.searchParams.get("project")?.trim();
526
- const sourceTypes = parseSearchSourceTypes(requestUrl.searchParams.get("sourceTypes"));
527
- const limit = parseSearchLimit(requestUrl.searchParams.get("limit"));
528
- if (!query || !scope || sourceTypes === null || limit === null) {
529
- return null;
530
- }
531
- const filters = sourceTypes.length > 0 ? { sourceTypes } : undefined;
532
- if (scope === "all-projects") {
533
- return { filters, limit: limit ?? undefined, query, scope: { type: "all-projects" } };
534
- }
535
- if (scope === "current-project" && projectId) {
536
- return { filters, limit: limit ?? undefined, query, scope: { projectId, type: "current-project" } };
537
- }
538
- return null;
539
- }
540
- function parseSearchSourceTypes(value) {
541
- if (!value) {
542
- return [];
543
- }
544
- const validSourceTypes = ["entity", "context", "context-term", "issue-comment", "plan-entry"];
545
- const sourceTypes = value.split(",").map((sourceType) => sourceType.trim()).filter(Boolean);
546
- return sourceTypes.every((sourceType) => validSourceTypes.includes(sourceType))
547
- ? [...new Set(sourceTypes)]
548
- : null;
549
- }
550
- function parseSearchLimit(value) {
551
- if (value === null) {
552
- return undefined;
553
- }
554
- if (!/^\d+$/.test(value)) {
555
- return null;
556
- }
557
- const limit = Number(value);
558
- return limit > 0 && limit <= 100 ? limit : null;
559
- }
560
- async function readSnapshotSignature(dbPath, tenant, currentWorkingDirectory, credentialStoreOptions) {
561
- return withStore(dbPath, { credentialStoreOptions, currentWorkingDirectory, tenant }, (store) => store.getSnapshotSignature());
562
- }
563
- async function readProjectMutationRequest(request) {
564
- const chunks = [];
565
- for await (const chunk of request) {
566
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
567
- }
568
- const value = JSON.parse(Buffer.concat(chunks).toString("utf8"));
569
- if (typeof value.correlationId !== "string" ||
570
- value.correlationId.length === 0 ||
571
- typeof value.method !== "string" ||
572
- !writeMethods.has(value.method) ||
573
- !PROJECT_MUTATION_METHODS.has(value.method) ||
574
- !rpcMethods[value.method]) {
575
- throw new Error("Invalid project mutation request.");
576
- }
577
- return { correlationId: value.correlationId, method: value.method, params: value.params };
578
- }
579
- async function executeProjectMutation(input) {
580
- const opened = await openStorageDriver({
581
- authSessionOptions: input.credentialStoreOptions,
582
- correlationId: input.mutation.correlationId,
583
- databaseOptions: { currentWorkingDirectory: input.currentWorkingDirectory, projectIdentity: input.projectId, tenant: input.tenant },
584
- dbPath: input.dbPath,
585
- localDaemon: { buildHash: readBuildContentHash() }
586
- });
587
- if (opened.daemonFallbackWarning) {
588
- process.stderr.write(`Warning: ${opened.daemonFallbackWarning}\n`);
589
- }
590
- const handler = rpcMethods[input.mutation.method];
591
- try {
592
- const before = await projectChangeEventForWrite(opened.store, input.mutation.method, input.projectId, input.mutation.params, undefined, input.mutation.correlationId);
593
- const result = await handler(opened.store, input.mutation.params);
594
- const after = await projectChangeEventForWrite(opened.store, input.mutation.method, input.projectId, input.mutation.params, result, input.mutation.correlationId);
595
- const event = {
596
- ...mergeProjectChangeEventDetails(before, after),
597
- at: new Date().toISOString(),
598
- type: "snapshot-changed"
599
- };
600
- if (opened.backend === "local") {
601
- input.onLocalMutation(event, await opened.store.getSnapshotSignature());
602
- }
603
- return { event, result };
604
- }
605
- finally {
606
- await opened.store.close();
607
- }
608
- }
609
- function broadcast(clients, payload) {
610
- for (const client of clients) {
611
- client.write(`data: ${payload}\n\n`);
612
- }
613
- }
614
- function writeJson(response, payload, diagnostics) {
615
- const body = `${JSON.stringify(payload)}\n`;
616
- const payloadBytes = Buffer.byteLength(body);
617
- response.writeHead(200, {
618
- "Content-Type": "application/json; charset=utf-8",
619
- "Cache-Control": "no-store",
620
- ...(diagnostics ? {
621
- "Server-Timing": `${diagnostics.metricName};dur=${diagnostics.durationMs.toFixed(3)}`,
622
- "X-Agent-Issues-Payload-Bytes": String(payloadBytes),
623
- "X-Agent-Issues-Response-Duration-Ms": String(diagnostics.durationMs)
624
- } : {})
625
- });
626
- response.end(body);
627
- }
628
- function writeText(response, statusCode, body) {
629
- response.writeHead(statusCode, { "Content-Type": "text/plain; charset=utf-8" });
630
- response.end(body);
631
- }
632
- //# sourceMappingURL=server.js.map