@supaku/agentfactory-nextjs 0.3.0

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 (101) hide show
  1. package/LICENSE +21 -0
  2. package/dist/src/factory.d.ts +105 -0
  3. package/dist/src/factory.d.ts.map +1 -0
  4. package/dist/src/factory.js +89 -0
  5. package/dist/src/handlers/cleanup.d.ts +44 -0
  6. package/dist/src/handlers/cleanup.d.ts.map +1 -0
  7. package/dist/src/handlers/cleanup.js +34 -0
  8. package/dist/src/handlers/public/session-detail.d.ts +31 -0
  9. package/dist/src/handlers/public/session-detail.d.ts.map +1 -0
  10. package/dist/src/handlers/public/session-detail.js +91 -0
  11. package/dist/src/handlers/public/sessions-list.d.ts +20 -0
  12. package/dist/src/handlers/public/sessions-list.d.ts.map +1 -0
  13. package/dist/src/handlers/public/sessions-list.js +73 -0
  14. package/dist/src/handlers/public/stats.d.ts +22 -0
  15. package/dist/src/handlers/public/stats.d.ts.map +1 -0
  16. package/dist/src/handlers/public/stats.js +53 -0
  17. package/dist/src/handlers/sessions/activity.d.ts +15 -0
  18. package/dist/src/handlers/sessions/activity.d.ts.map +1 -0
  19. package/dist/src/handlers/sessions/activity.js +77 -0
  20. package/dist/src/handlers/sessions/claim.d.ts +15 -0
  21. package/dist/src/handlers/sessions/claim.d.ts.map +1 -0
  22. package/dist/src/handlers/sessions/claim.js +87 -0
  23. package/dist/src/handlers/sessions/completion.d.ts +16 -0
  24. package/dist/src/handlers/sessions/completion.d.ts.map +1 -0
  25. package/dist/src/handlers/sessions/completion.js +82 -0
  26. package/dist/src/handlers/sessions/external-urls.d.ts +15 -0
  27. package/dist/src/handlers/sessions/external-urls.d.ts.map +1 -0
  28. package/dist/src/handlers/sessions/external-urls.js +59 -0
  29. package/dist/src/handlers/sessions/get.d.ts +19 -0
  30. package/dist/src/handlers/sessions/get.d.ts.map +1 -0
  31. package/dist/src/handlers/sessions/get.js +46 -0
  32. package/dist/src/handlers/sessions/list.d.ts +26 -0
  33. package/dist/src/handlers/sessions/list.d.ts.map +1 -0
  34. package/dist/src/handlers/sessions/list.js +50 -0
  35. package/dist/src/handlers/sessions/lock-refresh.d.ts +14 -0
  36. package/dist/src/handlers/sessions/lock-refresh.d.ts.map +1 -0
  37. package/dist/src/handlers/sessions/lock-refresh.js +38 -0
  38. package/dist/src/handlers/sessions/progress.d.ts +15 -0
  39. package/dist/src/handlers/sessions/progress.d.ts.map +1 -0
  40. package/dist/src/handlers/sessions/progress.js +82 -0
  41. package/dist/src/handlers/sessions/prompts.d.ts +15 -0
  42. package/dist/src/handlers/sessions/prompts.d.ts.map +1 -0
  43. package/dist/src/handlers/sessions/prompts.js +91 -0
  44. package/dist/src/handlers/sessions/status.d.ts +18 -0
  45. package/dist/src/handlers/sessions/status.d.ts.map +1 -0
  46. package/dist/src/handlers/sessions/status.js +131 -0
  47. package/dist/src/handlers/sessions/tool-error.d.ts +15 -0
  48. package/dist/src/handlers/sessions/tool-error.d.ts.map +1 -0
  49. package/dist/src/handlers/sessions/tool-error.js +91 -0
  50. package/dist/src/handlers/sessions/transfer-ownership.d.ts +14 -0
  51. package/dist/src/handlers/sessions/transfer-ownership.d.ts.map +1 -0
  52. package/dist/src/handlers/sessions/transfer-ownership.js +56 -0
  53. package/dist/src/handlers/workers/get-delete.d.ts +15 -0
  54. package/dist/src/handlers/workers/get-delete.d.ts.map +1 -0
  55. package/dist/src/handlers/workers/get-delete.js +58 -0
  56. package/dist/src/handlers/workers/heartbeat.d.ts +14 -0
  57. package/dist/src/handlers/workers/heartbeat.d.ts.map +1 -0
  58. package/dist/src/handlers/workers/heartbeat.js +42 -0
  59. package/dist/src/handlers/workers/list.d.ts +22 -0
  60. package/dist/src/handlers/workers/list.d.ts.map +1 -0
  61. package/dist/src/handlers/workers/list.js +33 -0
  62. package/dist/src/handlers/workers/poll.d.ts +14 -0
  63. package/dist/src/handlers/workers/poll.d.ts.map +1 -0
  64. package/dist/src/handlers/workers/poll.js +78 -0
  65. package/dist/src/handlers/workers/register.d.ts +9 -0
  66. package/dist/src/handlers/workers/register.d.ts.map +1 -0
  67. package/dist/src/handlers/workers/register.js +41 -0
  68. package/dist/src/index.d.ts +39 -0
  69. package/dist/src/index.d.ts.map +1 -0
  70. package/dist/src/index.js +41 -0
  71. package/dist/src/middleware/cron-auth.d.ts +21 -0
  72. package/dist/src/middleware/cron-auth.d.ts.map +1 -0
  73. package/dist/src/middleware/cron-auth.js +46 -0
  74. package/dist/src/middleware/worker-auth.d.ts +25 -0
  75. package/dist/src/middleware/worker-auth.d.ts.map +1 -0
  76. package/dist/src/middleware/worker-auth.js +43 -0
  77. package/dist/src/types.d.ts +62 -0
  78. package/dist/src/types.d.ts.map +1 -0
  79. package/dist/src/types.js +7 -0
  80. package/dist/src/webhook/handlers/issue-updated.d.ts +14 -0
  81. package/dist/src/webhook/handlers/issue-updated.d.ts.map +1 -0
  82. package/dist/src/webhook/handlers/issue-updated.js +462 -0
  83. package/dist/src/webhook/handlers/session-created.d.ts +9 -0
  84. package/dist/src/webhook/handlers/session-created.d.ts.map +1 -0
  85. package/dist/src/webhook/handlers/session-created.js +229 -0
  86. package/dist/src/webhook/handlers/session-prompted.d.ts +9 -0
  87. package/dist/src/webhook/handlers/session-prompted.d.ts.map +1 -0
  88. package/dist/src/webhook/handlers/session-prompted.js +197 -0
  89. package/dist/src/webhook/handlers/session-updated.d.ts +9 -0
  90. package/dist/src/webhook/handlers/session-updated.d.ts.map +1 -0
  91. package/dist/src/webhook/handlers/session-updated.js +29 -0
  92. package/dist/src/webhook/processor.d.ts +22 -0
  93. package/dist/src/webhook/processor.d.ts.map +1 -0
  94. package/dist/src/webhook/processor.js +98 -0
  95. package/dist/src/webhook/signature.d.ts +16 -0
  96. package/dist/src/webhook/signature.d.ts.map +1 -0
  97. package/dist/src/webhook/signature.js +23 -0
  98. package/dist/src/webhook/utils.d.ts +61 -0
  99. package/dist/src/webhook/utils.d.ts.map +1 -0
  100. package/dist/src/webhook/utils.js +159 -0
  101. package/package.json +66 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Supaku
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Factory — @supaku/agentfactory-nextjs
3
+ *
4
+ * Wires all handlers together from a single configuration object.
5
+ * Consumers call `createAllRoutes(config)` and get back a nested
6
+ * route tree that maps 1:1 onto Next.js App Router exports.
7
+ */
8
+ import type { RouteHandler, WebhookConfig, CronConfig } from './types.js';
9
+ export interface AllRoutes {
10
+ workers: {
11
+ register: {
12
+ POST: RouteHandler;
13
+ };
14
+ list: {
15
+ GET: RouteHandler;
16
+ };
17
+ detail: {
18
+ GET: RouteHandler;
19
+ DELETE: RouteHandler;
20
+ };
21
+ heartbeat: {
22
+ POST: RouteHandler;
23
+ };
24
+ poll: {
25
+ GET: RouteHandler;
26
+ };
27
+ };
28
+ sessions: {
29
+ list: {
30
+ GET: RouteHandler;
31
+ };
32
+ detail: {
33
+ GET: RouteHandler;
34
+ };
35
+ claim: {
36
+ POST: RouteHandler;
37
+ };
38
+ status: {
39
+ GET: RouteHandler;
40
+ POST: RouteHandler;
41
+ };
42
+ lockRefresh: {
43
+ POST: RouteHandler;
44
+ };
45
+ prompts: {
46
+ GET: RouteHandler;
47
+ POST: RouteHandler;
48
+ };
49
+ transferOwnership: {
50
+ POST: RouteHandler;
51
+ };
52
+ activity: {
53
+ POST: RouteHandler;
54
+ };
55
+ completion: {
56
+ POST: RouteHandler;
57
+ };
58
+ externalUrls: {
59
+ POST: RouteHandler;
60
+ };
61
+ progress: {
62
+ POST: RouteHandler;
63
+ };
64
+ toolError: {
65
+ POST: RouteHandler;
66
+ };
67
+ };
68
+ public: {
69
+ stats: {
70
+ GET: RouteHandler;
71
+ };
72
+ sessions: {
73
+ GET: RouteHandler;
74
+ };
75
+ sessionDetail: {
76
+ GET: RouteHandler;
77
+ };
78
+ };
79
+ cleanup: {
80
+ POST: RouteHandler;
81
+ GET: RouteHandler;
82
+ };
83
+ webhook: {
84
+ POST: RouteHandler;
85
+ GET: RouteHandler;
86
+ };
87
+ }
88
+ /**
89
+ * Create all route handlers from a single config object.
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * import { createAllRoutes } from '@supaku/agentfactory-nextjs'
94
+ *
95
+ * const routes = createAllRoutes({
96
+ * linearClient: { getClient: async (orgId) => getLinearClient(orgId) },
97
+ * generatePrompt: (id, workType) => `Work on ${id}`,
98
+ * })
99
+ *
100
+ * // In app/api/workers/register/route.ts:
101
+ * export const POST = routes.workers.register.POST
102
+ * ```
103
+ */
104
+ export declare function createAllRoutes(config: WebhookConfig & CronConfig): AllRoutes;
105
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/factory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAe,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAoCtF,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE;QACP,QAAQ,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAChC,IAAI,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC3B,MAAM,EAAE;YAAE,GAAG,EAAE,YAAY,CAAC;YAAC,MAAM,EAAE,YAAY,CAAA;SAAE,CAAA;QACnD,SAAS,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACjC,IAAI,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;KAC5B,CAAA;IACD,QAAQ,EAAE;QACR,IAAI,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC3B,MAAM,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC7B,KAAK,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAC7B,MAAM,EAAE;YAAE,GAAG,EAAE,YAAY,CAAC;YAAC,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACjD,WAAW,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACnC,OAAO,EAAE;YAAE,GAAG,EAAE,YAAY,CAAC;YAAC,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAClD,iBAAiB,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACzC,QAAQ,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAChC,UAAU,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAClC,YAAY,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACpC,QAAQ,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAChC,SAAS,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;KAClC,CAAA;IACD,MAAM,EAAE;QACN,KAAK,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC5B,QAAQ,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC/B,aAAa,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;KACrC,CAAA;IACD,OAAO,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,GAAG,EAAE,YAAY,CAAA;KAAE,CAAA;IAClD,OAAO,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,GAAG,EAAE,YAAY,CAAA;KAAE,CAAA;CACnD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,GAAG,SAAS,CAuC7E"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Factory — @supaku/agentfactory-nextjs
3
+ *
4
+ * Wires all handlers together from a single configuration object.
5
+ * Consumers call `createAllRoutes(config)` and get back a nested
6
+ * route tree that maps 1:1 onto Next.js App Router exports.
7
+ */
8
+ // Worker handlers
9
+ import { createWorkerRegisterHandler } from './handlers/workers/register.js';
10
+ import { createWorkerListHandler } from './handlers/workers/list.js';
11
+ import { createWorkerGetHandler, createWorkerDeleteHandler } from './handlers/workers/get-delete.js';
12
+ import { createWorkerHeartbeatHandler } from './handlers/workers/heartbeat.js';
13
+ import { createWorkerPollHandler } from './handlers/workers/poll.js';
14
+ // Session handlers (no Linear)
15
+ import { createSessionListHandler } from './handlers/sessions/list.js';
16
+ import { createSessionGetHandler } from './handlers/sessions/get.js';
17
+ import { createSessionClaimHandler } from './handlers/sessions/claim.js';
18
+ import { createSessionStatusPostHandler, createSessionStatusGetHandler } from './handlers/sessions/status.js';
19
+ import { createSessionLockRefreshHandler } from './handlers/sessions/lock-refresh.js';
20
+ import { createSessionPromptsGetHandler, createSessionPromptsPostHandler } from './handlers/sessions/prompts.js';
21
+ import { createSessionTransferOwnershipHandler } from './handlers/sessions/transfer-ownership.js';
22
+ // Session handlers (Linear forwarding)
23
+ import { createSessionActivityHandler } from './handlers/sessions/activity.js';
24
+ import { createSessionCompletionHandler } from './handlers/sessions/completion.js';
25
+ import { createSessionExternalUrlsHandler } from './handlers/sessions/external-urls.js';
26
+ import { createSessionProgressHandler } from './handlers/sessions/progress.js';
27
+ import { createSessionToolErrorHandler } from './handlers/sessions/tool-error.js';
28
+ // Public handlers
29
+ import { createPublicStatsHandler } from './handlers/public/stats.js';
30
+ import { createPublicSessionsListHandler } from './handlers/public/sessions-list.js';
31
+ import { createPublicSessionDetailHandler } from './handlers/public/session-detail.js';
32
+ // Cleanup handler
33
+ import { createCleanupHandler } from './handlers/cleanup.js';
34
+ // Webhook processor
35
+ import { createWebhookHandler } from './webhook/processor.js';
36
+ /**
37
+ * Create all route handlers from a single config object.
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * import { createAllRoutes } from '@supaku/agentfactory-nextjs'
42
+ *
43
+ * const routes = createAllRoutes({
44
+ * linearClient: { getClient: async (orgId) => getLinearClient(orgId) },
45
+ * generatePrompt: (id, workType) => `Work on ${id}`,
46
+ * })
47
+ *
48
+ * // In app/api/workers/register/route.ts:
49
+ * export const POST = routes.workers.register.POST
50
+ * ```
51
+ */
52
+ export function createAllRoutes(config) {
53
+ const routeConfig = {
54
+ linearClient: config.linearClient,
55
+ appUrl: config.appUrl,
56
+ };
57
+ const cleanup = createCleanupHandler(config);
58
+ const webhook = createWebhookHandler(config);
59
+ return {
60
+ workers: {
61
+ register: { POST: createWorkerRegisterHandler() },
62
+ list: { GET: createWorkerListHandler() },
63
+ detail: { GET: createWorkerGetHandler(), DELETE: createWorkerDeleteHandler() },
64
+ heartbeat: { POST: createWorkerHeartbeatHandler() },
65
+ poll: { GET: createWorkerPollHandler() },
66
+ },
67
+ sessions: {
68
+ list: { GET: createSessionListHandler() },
69
+ detail: { GET: createSessionGetHandler() },
70
+ claim: { POST: createSessionClaimHandler() },
71
+ status: { GET: createSessionStatusGetHandler(), POST: createSessionStatusPostHandler() },
72
+ lockRefresh: { POST: createSessionLockRefreshHandler() },
73
+ prompts: { GET: createSessionPromptsGetHandler(), POST: createSessionPromptsPostHandler() },
74
+ transferOwnership: { POST: createSessionTransferOwnershipHandler() },
75
+ activity: { POST: createSessionActivityHandler(routeConfig) },
76
+ completion: { POST: createSessionCompletionHandler(routeConfig) },
77
+ externalUrls: { POST: createSessionExternalUrlsHandler(routeConfig) },
78
+ progress: { POST: createSessionProgressHandler(routeConfig) },
79
+ toolError: { POST: createSessionToolErrorHandler(routeConfig) },
80
+ },
81
+ public: {
82
+ stats: { GET: createPublicStatsHandler() },
83
+ sessions: { GET: createPublicSessionsListHandler() },
84
+ sessionDetail: { GET: createPublicSessionDetailHandler() },
85
+ },
86
+ cleanup: { POST: cleanup.POST, GET: cleanup.GET },
87
+ webhook: { POST: webhook.POST, GET: webhook.GET },
88
+ };
89
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * POST, GET /api/cleanup
3
+ *
4
+ * Trigger orphan session cleanup.
5
+ */
6
+ import { NextRequest, NextResponse } from 'next/server';
7
+ import type { CronConfig } from '../types.js';
8
+ export declare function createCleanupHandler(config?: CronConfig): {
9
+ POST: (request: NextRequest) => Promise<NextResponse<{
10
+ checked: number;
11
+ orphaned: number;
12
+ requeued: number;
13
+ failed: number;
14
+ details: Array<{
15
+ sessionId: string;
16
+ issueIdentifier: string;
17
+ action: "requeued" | "failed";
18
+ reason?: string;
19
+ worktreePath?: string;
20
+ }>;
21
+ worktreePathsToCleanup: string[];
22
+ success: boolean;
23
+ }> | NextResponse<{
24
+ error: string;
25
+ }>>;
26
+ GET: (request: NextRequest) => Promise<NextResponse<{
27
+ checked: number;
28
+ orphaned: number;
29
+ requeued: number;
30
+ failed: number;
31
+ details: Array<{
32
+ sessionId: string;
33
+ issueIdentifier: string;
34
+ action: "requeued" | "failed";
35
+ reason?: string;
36
+ worktreePath?: string;
37
+ }>;
38
+ worktreePathsToCleanup: string[];
39
+ success: boolean;
40
+ }> | NextResponse<{
41
+ error: string;
42
+ }>>;
43
+ };
44
+ //# sourceMappingURL=cleanup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../../src/handlers/cleanup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAGvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAI7C,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,UAAU;oBAChB,WAAW;;;;;;;;;kBAgC2b,CAAC;wBAAkG,CAAC;;;;;;;mBAhC1iB,WAAW;;;;;;;;;kBAgC2b,CAAC;wBAAkG,CAAC;;;;;;;EADjlB"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * POST, GET /api/cleanup
3
+ *
4
+ * Trigger orphan session cleanup.
5
+ */
6
+ import { NextResponse } from 'next/server';
7
+ import { cleanupOrphanedSessions, createLogger } from '@supaku/agentfactory-server';
8
+ import { verifyCronAuth } from '../middleware/cron-auth.js';
9
+ const log = createLogger('api:cleanup');
10
+ export function createCleanupHandler(config) {
11
+ async function handleCleanup(request) {
12
+ const authResult = verifyCronAuth(request, config?.cronSecret);
13
+ if (!authResult.authorized) {
14
+ log.warn('Unauthorized cleanup request', { reason: authResult.reason });
15
+ return NextResponse.json({ error: 'Unauthorized', message: authResult.reason }, { status: 401 });
16
+ }
17
+ try {
18
+ log.info('Running orphan cleanup');
19
+ const result = await cleanupOrphanedSessions();
20
+ return NextResponse.json({
21
+ success: true,
22
+ ...result,
23
+ });
24
+ }
25
+ catch (error) {
26
+ log.error('Cleanup failed', { error });
27
+ return NextResponse.json({ error: 'Cleanup failed' }, { status: 500 });
28
+ }
29
+ }
30
+ return {
31
+ POST: handleCleanup,
32
+ GET: handleCleanup,
33
+ };
34
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * GET /api/public/sessions/:id
3
+ *
4
+ * Returns sanitized session detail for a single session.
5
+ */
6
+ import { NextRequest, NextResponse } from 'next/server';
7
+ export interface PublicSessionDetailResponse {
8
+ id: string;
9
+ identifier: string;
10
+ status: 'queued' | 'parked' | 'working' | 'completed' | 'failed';
11
+ workType: string;
12
+ startedAt: string;
13
+ duration: number;
14
+ timeline: {
15
+ created: string;
16
+ queued?: string;
17
+ started?: string;
18
+ completed?: string;
19
+ };
20
+ }
21
+ export declare function createPublicSessionDetailHandler(): (_request: NextRequest, { params }: {
22
+ params: Promise<{
23
+ id: string;
24
+ }>;
25
+ }) => Promise<NextResponse<{
26
+ error: string;
27
+ }> | NextResponse<{
28
+ session: PublicSessionDetailResponse;
29
+ timestamp: string;
30
+ }>>;
31
+ //# sourceMappingURL=session-detail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-detail.d.ts","sourceRoot":"","sources":["../../../../src/handlers/public/session-detail.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAYvD,MAAM,WAAW,2BAA2B;IAC1C,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAA;IAChE,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,CAAA;QACf,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,CAAA;CACF;AA6ED,wBAAgB,gCAAgC,KAE5C,UAAU,WAAW,EACrB,YAAY;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE;;;;;IAoClD"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * GET /api/public/sessions/:id
3
+ *
4
+ * Returns sanitized session detail for a single session.
5
+ */
6
+ import { NextResponse } from 'next/server';
7
+ import { getAllSessions, isSessionInQueue, hashSessionId, isValidPublicId, createLogger, } from '@supaku/agentfactory-server';
8
+ const log = createLogger('api/public/sessions/[id]');
9
+ function toPublicStatus(status, isParked = false) {
10
+ switch (status) {
11
+ case 'pending':
12
+ return isParked ? 'parked' : 'queued';
13
+ case 'claimed':
14
+ case 'running':
15
+ return 'working';
16
+ case 'completed':
17
+ return 'completed';
18
+ case 'failed':
19
+ case 'stopped':
20
+ return 'failed';
21
+ default:
22
+ return 'queued';
23
+ }
24
+ }
25
+ async function toPublicSessionDetail(session) {
26
+ const now = Math.floor(Date.now() / 1000);
27
+ const startTime = session.queuedAt
28
+ ? Math.floor(session.queuedAt / 1000)
29
+ : session.createdAt;
30
+ const endTime = ['completed', 'failed', 'stopped'].includes(session.status)
31
+ ? session.updatedAt
32
+ : now;
33
+ const isComplete = ['completed', 'failed', 'stopped'].includes(session.status);
34
+ let isParked = false;
35
+ if (session.status === 'pending') {
36
+ const inQueue = await isSessionInQueue(session.linearSessionId);
37
+ isParked = !inQueue;
38
+ }
39
+ return {
40
+ id: hashSessionId(session.linearSessionId),
41
+ identifier: session.issueIdentifier || 'Unknown',
42
+ status: toPublicStatus(session.status, isParked),
43
+ workType: session.workType || 'development',
44
+ startedAt: new Date(startTime * 1000).toISOString(),
45
+ duration: endTime - startTime,
46
+ timeline: {
47
+ created: new Date(session.createdAt * 1000).toISOString(),
48
+ queued: session.queuedAt
49
+ ? new Date(session.queuedAt).toISOString()
50
+ : undefined,
51
+ started: session.claimedAt
52
+ ? new Date(session.claimedAt * 1000).toISOString()
53
+ : undefined,
54
+ completed: isComplete
55
+ ? new Date(session.updatedAt * 1000).toISOString()
56
+ : undefined,
57
+ },
58
+ };
59
+ }
60
+ async function findSessionByPublicId(publicId) {
61
+ const allSessions = await getAllSessions();
62
+ for (const session of allSessions) {
63
+ if (hashSessionId(session.linearSessionId) === publicId) {
64
+ return session;
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ export function createPublicSessionDetailHandler() {
70
+ return async function GET(_request, { params }) {
71
+ const { id: publicId } = await params;
72
+ if (!isValidPublicId(publicId)) {
73
+ return NextResponse.json({ error: 'Invalid session ID format' }, { status: 400 });
74
+ }
75
+ try {
76
+ const session = await findSessionByPublicId(publicId);
77
+ if (!session) {
78
+ return NextResponse.json({ error: 'Session not found' }, { status: 404 });
79
+ }
80
+ const publicSession = await toPublicSessionDetail(session);
81
+ return NextResponse.json({
82
+ session: publicSession,
83
+ timestamp: new Date().toISOString(),
84
+ });
85
+ }
86
+ catch (error) {
87
+ log.error('Failed to fetch public session detail', { error, publicId });
88
+ return NextResponse.json({ error: 'Failed to fetch session' }, { status: 500 });
89
+ }
90
+ };
91
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * GET /api/public/sessions
3
+ *
4
+ * Returns sanitized session data for public display.
5
+ */
6
+ import { NextResponse } from 'next/server';
7
+ export interface PublicSessionResponse {
8
+ id: string;
9
+ identifier: string;
10
+ status: 'queued' | 'parked' | 'working' | 'completed' | 'failed' | 'stopped';
11
+ workType: string;
12
+ startedAt: string;
13
+ duration: number;
14
+ }
15
+ export declare function createPublicSessionsListHandler(): () => Promise<NextResponse<{
16
+ sessions: PublicSessionResponse[];
17
+ count: number;
18
+ timestamp: string;
19
+ }>>;
20
+ //# sourceMappingURL=sessions-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions-list.d.ts","sourceRoot":"","sources":["../../../../src/handlers/public/sessions-list.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAW1C,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;IAC5E,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAmDD,wBAAgB,+BAA+B;;;;IA6B9C"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * GET /api/public/sessions
3
+ *
4
+ * Returns sanitized session data for public display.
5
+ */
6
+ import { NextResponse } from 'next/server';
7
+ import { getAllSessions, isSessionInQueue, hashSessionId, createLogger, } from '@supaku/agentfactory-server';
8
+ const log = createLogger('api/public/sessions');
9
+ function toPublicStatus(status, isParked = false) {
10
+ switch (status) {
11
+ case 'pending':
12
+ return isParked ? 'parked' : 'queued';
13
+ case 'claimed':
14
+ case 'running':
15
+ case 'finalizing':
16
+ return 'working';
17
+ case 'completed':
18
+ return 'completed';
19
+ case 'failed':
20
+ return 'failed';
21
+ case 'stopped':
22
+ return 'stopped';
23
+ default:
24
+ return 'queued';
25
+ }
26
+ }
27
+ async function toPublicSession(session) {
28
+ const now = Math.floor(Date.now() / 1000);
29
+ const startTime = session.queuedAt
30
+ ? Math.floor(session.queuedAt / 1000)
31
+ : session.createdAt;
32
+ const endTime = ['completed', 'failed', 'stopped'].includes(session.status)
33
+ ? session.updatedAt
34
+ : now;
35
+ let isParked = false;
36
+ if (session.status === 'pending') {
37
+ const inQueue = await isSessionInQueue(session.linearSessionId);
38
+ isParked = !inQueue;
39
+ }
40
+ return {
41
+ id: hashSessionId(session.linearSessionId),
42
+ identifier: session.issueIdentifier || 'Unknown',
43
+ status: toPublicStatus(session.status, isParked),
44
+ workType: session.workType || 'development',
45
+ startedAt: new Date(startTime * 1000).toISOString(),
46
+ duration: endTime - startTime,
47
+ };
48
+ }
49
+ export function createPublicSessionsListHandler() {
50
+ return async function GET() {
51
+ try {
52
+ const allSessions = await getAllSessions();
53
+ const publicSessions = await Promise.all(allSessions.map(toPublicSession));
54
+ publicSessions.sort((a, b) => {
55
+ return new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime();
56
+ });
57
+ return NextResponse.json({
58
+ sessions: publicSessions,
59
+ count: publicSessions.length,
60
+ timestamp: new Date().toISOString(),
61
+ });
62
+ }
63
+ catch (error) {
64
+ log.error('Failed to fetch public sessions', { error });
65
+ return NextResponse.json({
66
+ sessions: [],
67
+ count: 0,
68
+ timestamp: new Date().toISOString(),
69
+ error: 'Failed to fetch sessions',
70
+ }, { status: 500 });
71
+ }
72
+ };
73
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * GET /api/public/stats
3
+ *
4
+ * Returns aggregate statistics only - no sensitive data.
5
+ */
6
+ import { NextResponse } from 'next/server';
7
+ export interface PublicStatsResponse {
8
+ workersOnline: number;
9
+ agentsWorking: number;
10
+ queueDepth: number;
11
+ completedToday: number;
12
+ availableCapacity: number;
13
+ }
14
+ export declare function createPublicStatsHandler(): () => Promise<NextResponse<{
15
+ timestamp: string;
16
+ workersOnline: number;
17
+ agentsWorking: number;
18
+ queueDepth: number;
19
+ completedToday: number;
20
+ availableCapacity: number;
21
+ }>>;
22
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../../src/handlers/public/stats.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAK1C,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;CAC1B;AAUD,wBAAgB,wBAAwB;;mBAfvB,MAAM;mBACN,MAAM;gBACT,MAAM;oBACF,MAAM;uBACH,MAAM;IAgE1B"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * GET /api/public/stats
3
+ *
4
+ * Returns aggregate statistics only - no sensitive data.
5
+ */
6
+ import { NextResponse } from 'next/server';
7
+ import { getAllSessions, listWorkers, getTotalCapacity, getQueueLength, createLogger } from '@supaku/agentfactory-server';
8
+ const log = createLogger('api/public/stats');
9
+ function getTodayStart() {
10
+ const now = new Date();
11
+ const todayStart = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
12
+ return Math.floor(todayStart.getTime() / 1000);
13
+ }
14
+ export function createPublicStatsHandler() {
15
+ return async function GET() {
16
+ try {
17
+ const [allSessions, workers, capacity, queueLength] = await Promise.all([
18
+ getAllSessions(),
19
+ listWorkers(),
20
+ getTotalCapacity(),
21
+ getQueueLength(),
22
+ ]);
23
+ const todayStart = getTodayStart();
24
+ const agentsWorking = allSessions.filter((s) => s.status === 'running' || s.status === 'claimed').length;
25
+ const completedToday = allSessions.filter((s) => s.status === 'completed' &&
26
+ s.updatedAt >= todayStart).length;
27
+ const workersOnline = workers.filter((w) => w.status === 'active').length;
28
+ const stats = {
29
+ workersOnline,
30
+ agentsWorking,
31
+ queueDepth: queueLength,
32
+ completedToday,
33
+ availableCapacity: capacity.availableCapacity,
34
+ };
35
+ return NextResponse.json({
36
+ ...stats,
37
+ timestamp: new Date().toISOString(),
38
+ });
39
+ }
40
+ catch (error) {
41
+ log.error('Failed to get public stats', { error });
42
+ return NextResponse.json({
43
+ workersOnline: 0,
44
+ agentsWorking: 0,
45
+ queueDepth: 0,
46
+ completedToday: 0,
47
+ availableCapacity: 0,
48
+ error: 'Failed to fetch stats',
49
+ timestamp: new Date().toISOString(),
50
+ }, { status: 500 });
51
+ }
52
+ };
53
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * POST /api/sessions/[id]/activity
3
+ *
4
+ * Report agent activity to be forwarded to Linear.
5
+ */
6
+ import { NextRequest, NextResponse } from 'next/server';
7
+ import type { RouteConfig } from '../../types.js';
8
+ interface RouteParams {
9
+ params: Promise<{
10
+ id: string;
11
+ }>;
12
+ }
13
+ export declare function createSessionActivityHandler(config: RouteConfig): (request: NextRequest, { params }: RouteParams) => Promise<NextResponse<unknown>>;
14
+ export {};
15
+ //# sourceMappingURL=activity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../../../src/handlers/sessions/activity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAIvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAIjD,UAAU,WAAW;IACnB,MAAM,EAAE,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAChC;AAUD,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,WAAW,IACnC,SAAS,WAAW,EAAE,YAAY,WAAW,oCA8FzE"}