@zhixuan92/multi-model-agent 3.0.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 (169) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +217 -0
  3. package/dist/cli/index.d.ts +61 -0
  4. package/dist/cli/index.d.ts.map +1 -0
  5. package/dist/cli/index.js +252 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/cli/install-skill.d.ts +158 -0
  8. package/dist/cli/install-skill.d.ts.map +1 -0
  9. package/dist/cli/install-skill.js +425 -0
  10. package/dist/cli/install-skill.js.map +1 -0
  11. package/dist/cli/print-token.d.ts +18 -0
  12. package/dist/cli/print-token.d.ts.map +1 -0
  13. package/dist/cli/print-token.js +60 -0
  14. package/dist/cli/print-token.js.map +1 -0
  15. package/dist/cli/serve.d.ts +44 -0
  16. package/dist/cli/serve.d.ts.map +1 -0
  17. package/dist/cli/serve.js +61 -0
  18. package/dist/cli/serve.js.map +1 -0
  19. package/dist/cli/status.d.ts +49 -0
  20. package/dist/cli/status.d.ts.map +1 -0
  21. package/dist/cli/status.js +155 -0
  22. package/dist/cli/status.js.map +1 -0
  23. package/dist/http/async-dispatch.d.ts +32 -0
  24. package/dist/http/async-dispatch.d.ts.map +1 -0
  25. package/dist/http/async-dispatch.js +53 -0
  26. package/dist/http/async-dispatch.js.map +1 -0
  27. package/dist/http/auth.d.ts +26 -0
  28. package/dist/http/auth.d.ts.map +1 -0
  29. package/dist/http/auth.js +64 -0
  30. package/dist/http/auth.js.map +1 -0
  31. package/dist/http/cwd-validator.d.ts +11 -0
  32. package/dist/http/cwd-validator.d.ts.map +1 -0
  33. package/dist/http/cwd-validator.js +115 -0
  34. package/dist/http/cwd-validator.js.map +1 -0
  35. package/dist/http/errors.d.ts +4 -0
  36. package/dist/http/errors.d.ts.map +1 -0
  37. package/dist/http/errors.js +9 -0
  38. package/dist/http/errors.js.map +1 -0
  39. package/dist/http/execution-context.d.ts +15 -0
  40. package/dist/http/execution-context.d.ts.map +1 -0
  41. package/dist/http/execution-context.js +35 -0
  42. package/dist/http/execution-context.js.map +1 -0
  43. package/dist/http/handler-deps.d.ts +16 -0
  44. package/dist/http/handler-deps.d.ts.map +1 -0
  45. package/dist/http/handler-deps.js +2 -0
  46. package/dist/http/handler-deps.js.map +1 -0
  47. package/dist/http/handlers/control/batch.d.ts +24 -0
  48. package/dist/http/handlers/control/batch.d.ts.map +1 -0
  49. package/dist/http/handlers/control/batch.js +81 -0
  50. package/dist/http/handlers/control/batch.js.map +1 -0
  51. package/dist/http/handlers/control/clarifications.d.ts +19 -0
  52. package/dist/http/handlers/control/clarifications.d.ts.map +1 -0
  53. package/dist/http/handlers/control/clarifications.js +58 -0
  54. package/dist/http/handlers/control/clarifications.js.map +1 -0
  55. package/dist/http/handlers/control/context-blocks.d.ts +22 -0
  56. package/dist/http/handlers/control/context-blocks.d.ts.map +1 -0
  57. package/dist/http/handlers/control/context-blocks.js +88 -0
  58. package/dist/http/handlers/control/context-blocks.js.map +1 -0
  59. package/dist/http/handlers/introspection/health.d.ts +13 -0
  60. package/dist/http/handlers/introspection/health.d.ts.map +1 -0
  61. package/dist/http/handlers/introspection/health.js +17 -0
  62. package/dist/http/handlers/introspection/health.js.map +1 -0
  63. package/dist/http/handlers/introspection/status.d.ts +26 -0
  64. package/dist/http/handlers/introspection/status.d.ts.map +1 -0
  65. package/dist/http/handlers/introspection/status.js +136 -0
  66. package/dist/http/handlers/introspection/status.js.map +1 -0
  67. package/dist/http/handlers/introspection/tools-list.d.ts +9 -0
  68. package/dist/http/handlers/introspection/tools-list.d.ts.map +1 -0
  69. package/dist/http/handlers/introspection/tools-list.js +28 -0
  70. package/dist/http/handlers/introspection/tools-list.js.map +1 -0
  71. package/dist/http/handlers/tools/audit.d.ts +4 -0
  72. package/dist/http/handlers/tools/audit.d.ts.map +1 -0
  73. package/dist/http/handlers/tools/audit.js +39 -0
  74. package/dist/http/handlers/tools/audit.js.map +1 -0
  75. package/dist/http/handlers/tools/debug.d.ts +4 -0
  76. package/dist/http/handlers/tools/debug.d.ts.map +1 -0
  77. package/dist/http/handlers/tools/debug.js +39 -0
  78. package/dist/http/handlers/tools/debug.js.map +1 -0
  79. package/dist/http/handlers/tools/delegate.d.ts +4 -0
  80. package/dist/http/handlers/tools/delegate.d.ts.map +1 -0
  81. package/dist/http/handlers/tools/delegate.js +57 -0
  82. package/dist/http/handlers/tools/delegate.js.map +1 -0
  83. package/dist/http/handlers/tools/execute-plan.d.ts +4 -0
  84. package/dist/http/handlers/tools/execute-plan.d.ts.map +1 -0
  85. package/dist/http/handlers/tools/execute-plan.js +39 -0
  86. package/dist/http/handlers/tools/execute-plan.js.map +1 -0
  87. package/dist/http/handlers/tools/retry.d.ts +4 -0
  88. package/dist/http/handlers/tools/retry.d.ts.map +1 -0
  89. package/dist/http/handlers/tools/retry.js +52 -0
  90. package/dist/http/handlers/tools/retry.js.map +1 -0
  91. package/dist/http/handlers/tools/review.d.ts +4 -0
  92. package/dist/http/handlers/tools/review.d.ts.map +1 -0
  93. package/dist/http/handlers/tools/review.js +39 -0
  94. package/dist/http/handlers/tools/review.js.map +1 -0
  95. package/dist/http/handlers/tools/verify.d.ts +4 -0
  96. package/dist/http/handlers/tools/verify.d.ts.map +1 -0
  97. package/dist/http/handlers/tools/verify.js +39 -0
  98. package/dist/http/handlers/tools/verify.js.map +1 -0
  99. package/dist/http/loopback.d.ts +17 -0
  100. package/dist/http/loopback.d.ts.map +1 -0
  101. package/dist/http/loopback.js +43 -0
  102. package/dist/http/loopback.js.map +1 -0
  103. package/dist/http/middleware/body-reader.d.ts +16 -0
  104. package/dist/http/middleware/body-reader.d.ts.map +1 -0
  105. package/dist/http/middleware/body-reader.js +44 -0
  106. package/dist/http/middleware/body-reader.js.map +1 -0
  107. package/dist/http/project-registry.d.ts +54 -0
  108. package/dist/http/project-registry.d.ts.map +1 -0
  109. package/dist/http/project-registry.js +132 -0
  110. package/dist/http/project-registry.js.map +1 -0
  111. package/dist/http/router.d.ts +14 -0
  112. package/dist/http/router.d.ts.map +1 -0
  113. package/dist/http/router.js +41 -0
  114. package/dist/http/router.js.map +1 -0
  115. package/dist/http/server.d.ts +16 -0
  116. package/dist/http/server.d.ts.map +1 -0
  117. package/dist/http/server.js +235 -0
  118. package/dist/http/server.js.map +1 -0
  119. package/dist/http/types.d.ts +9 -0
  120. package/dist/http/types.d.ts.map +1 -0
  121. package/dist/http/types.js +2 -0
  122. package/dist/http/types.js.map +1 -0
  123. package/dist/index.d.ts +2 -0
  124. package/dist/index.d.ts.map +1 -0
  125. package/dist/index.js +2 -0
  126. package/dist/index.js.map +1 -0
  127. package/dist/install/claude-code.d.ts +43 -0
  128. package/dist/install/claude-code.d.ts.map +1 -0
  129. package/dist/install/claude-code.js +65 -0
  130. package/dist/install/claude-code.js.map +1 -0
  131. package/dist/install/codex-cli.d.ts +39 -0
  132. package/dist/install/codex-cli.d.ts.map +1 -0
  133. package/dist/install/codex-cli.js +318 -0
  134. package/dist/install/codex-cli.js.map +1 -0
  135. package/dist/install/cursor.d.ts +72 -0
  136. package/dist/install/cursor.d.ts.map +1 -0
  137. package/dist/install/cursor.js +81 -0
  138. package/dist/install/cursor.js.map +1 -0
  139. package/dist/install/gemini-cli.d.ts +66 -0
  140. package/dist/install/gemini-cli.d.ts.map +1 -0
  141. package/dist/install/gemini-cli.js +111 -0
  142. package/dist/install/gemini-cli.js.map +1 -0
  143. package/dist/install/include-utils.d.ts +27 -0
  144. package/dist/install/include-utils.d.ts.map +1 -0
  145. package/dist/install/include-utils.js +90 -0
  146. package/dist/install/include-utils.js.map +1 -0
  147. package/dist/install/manifest.d.ts +90 -0
  148. package/dist/install/manifest.d.ts.map +1 -0
  149. package/dist/install/manifest.js +200 -0
  150. package/dist/install/manifest.js.map +1 -0
  151. package/dist/openapi.d.ts +15 -0
  152. package/dist/openapi.d.ts.map +1 -0
  153. package/dist/openapi.js +314 -0
  154. package/dist/openapi.js.map +1 -0
  155. package/dist/skills/_shared/auth.md +32 -0
  156. package/dist/skills/_shared/error-handling.md +31 -0
  157. package/dist/skills/_shared/polling.md +40 -0
  158. package/dist/skills/_shared/response-shape.md +46 -0
  159. package/dist/skills/mma-audit/SKILL.md +55 -0
  160. package/dist/skills/mma-clarifications/SKILL.md +68 -0
  161. package/dist/skills/mma-context-blocks/SKILL.md +69 -0
  162. package/dist/skills/mma-debug/SKILL.md +59 -0
  163. package/dist/skills/mma-delegate/SKILL.md +63 -0
  164. package/dist/skills/mma-execute-plan/SKILL.md +63 -0
  165. package/dist/skills/mma-retry/SKILL.md +54 -0
  166. package/dist/skills/mma-review/SKILL.md +55 -0
  167. package/dist/skills/mma-verify/SKILL.md +57 -0
  168. package/dist/skills/multi-model-agent/SKILL.md +55 -0
  169. package/package.json +60 -0
@@ -0,0 +1,115 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ const SEP = path.sep;
4
+ /**
5
+ * Walk each path component and check if any symlink points outside its
6
+ * containing parent directory (symlink escape). Returns true if a symlink
7
+ * escape is detected.
8
+ *
9
+ * Algorithm: build the path incrementally. At each component that is a symlink,
10
+ * canonicalize both the parent directory and the symlink's resolved target via
11
+ * realpathSync, then verify that the resolved target is a descendant of the
12
+ * canonical parent. This handles macOS-style double-indirection (e.g. /var →
13
+ * /private/var) without false positives.
14
+ */
15
+ function hasSymlinkEscape(cwd) {
16
+ const parts = cwd.split(SEP).filter(Boolean); // ['a','b','c'] for /a/b/c
17
+ // We track the "logical" accumulated path (not yet canonicalized) so lstat
18
+ // finds the right inode even when earlier symlinks changed the real prefix.
19
+ // We will resolve it when we need to compare.
20
+ let logicalAccum = SEP;
21
+ for (const part of parts) {
22
+ const logicalCurrent = path.join(logicalAccum, part);
23
+ // Resolve logicalAccum to its canonical form so lstat finds the right path.
24
+ let canonAccum;
25
+ try {
26
+ canonAccum = fs.realpathSync(logicalAccum);
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ const canonCurrent = path.join(canonAccum, part);
32
+ let lstat;
33
+ try {
34
+ lstat = fs.lstatSync(canonCurrent);
35
+ }
36
+ catch {
37
+ // Path doesn't exist — validateCwd will catch this
38
+ return false;
39
+ }
40
+ if (lstat.isSymbolicLink()) {
41
+ let target;
42
+ try {
43
+ target = fs.readlinkSync(canonCurrent);
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ // Resolve target relative to the canonical parent directory of the symlink.
49
+ const resolvedTarget = path.isAbsolute(target)
50
+ ? target
51
+ : path.resolve(canonAccum, target);
52
+ // Canonicalize the resolved target and the parent dir for stable comparison.
53
+ let canonResolvedTarget;
54
+ try {
55
+ canonResolvedTarget = fs.realpathSync(resolvedTarget);
56
+ }
57
+ catch {
58
+ // Target doesn't exist — validateCwd will catch this
59
+ return false;
60
+ }
61
+ // The parent dir that should "contain" this symlink is canonAccum.
62
+ const parentWithSep = canonAccum.endsWith(SEP) ? canonAccum : canonAccum + SEP;
63
+ const resolvedWithSep = canonResolvedTarget.endsWith(SEP)
64
+ ? canonResolvedTarget
65
+ : canonResolvedTarget + SEP;
66
+ if (!resolvedWithSep.startsWith(parentWithSep)) {
67
+ // Symlink escapes its parent directory
68
+ return true;
69
+ }
70
+ logicalAccum = resolvedTarget;
71
+ }
72
+ else {
73
+ logicalAccum = logicalCurrent;
74
+ }
75
+ }
76
+ return false;
77
+ }
78
+ export function validateCwd(cwd) {
79
+ if (!cwd)
80
+ return { ok: false, error: 'missing_cwd', message: "required query param 'cwd' not provided" };
81
+ if (!path.isAbsolute(cwd))
82
+ return { ok: false, error: 'invalid_cwd', message: `cwd must be absolute: ${cwd}` };
83
+ let canonical;
84
+ try {
85
+ canonical = fs.realpathSync(cwd);
86
+ }
87
+ catch (err) {
88
+ const code = err.code;
89
+ if (code === 'ENOENT')
90
+ return { ok: false, error: 'cwd_not_dir', message: `cwd does not exist: ${cwd}` };
91
+ if (code === 'EACCES' || code === 'EPERM')
92
+ return { ok: false, error: 'cwd_not_dir', message: `cwd is not accessible (permission denied): ${cwd}` };
93
+ return { ok: false, error: 'cwd_not_dir', message: `cwd cannot be resolved (${code ?? 'unknown error'}): ${cwd}` };
94
+ }
95
+ let stat;
96
+ try {
97
+ stat = fs.statSync(canonical);
98
+ }
99
+ catch {
100
+ return { ok: false, error: 'cwd_not_dir', message: `cwd realpath is not accessible: ${cwd} → ${canonical}` };
101
+ }
102
+ if (!stat.isDirectory())
103
+ return { ok: false, error: 'cwd_not_dir', message: `cwd is not a directory: ${cwd}` };
104
+ // ── Symlink-escape check ──────────────────────────────────────────────────
105
+ // Detect symlinks whose target escapes the containing parent directory.
106
+ if (hasSymlinkEscape(cwd)) {
107
+ return {
108
+ ok: false,
109
+ error: 'forbidden_cwd',
110
+ message: `cwd contains a symlink that escapes its parent directory: ${cwd}`,
111
+ };
112
+ }
113
+ return { ok: true, canonicalCwd: canonical };
114
+ }
115
+ //# sourceMappingURL=cwd-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cwd-validator.js","sourceRoot":"","sources":["../../src/http/cwd-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ServerResponse } from 'node:http';
2
+ export declare function sendError(res: ServerResponse, status: number, code: string, message: string, details?: unknown): void;
3
+ export declare function sendJson(res: ServerResponse, status: number, body: unknown): void;
4
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/http/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,wBAAgB,SAAS,CACvB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI,CAGN;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAGjF"}
@@ -0,0 +1,9 @@
1
+ export function sendError(res, status, code, message, details) {
2
+ res.writeHead(status, { 'content-type': 'application/json' });
3
+ res.end(JSON.stringify({ error: { code, message, ...(details !== undefined ? { details } : {}) } }));
4
+ }
5
+ export function sendJson(res, status, body) {
6
+ res.writeHead(status, { 'content-type': 'application/json' });
7
+ res.end(JSON.stringify(body));
8
+ }
9
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/http/errors.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CACvB,GAAmB,EACnB,MAAc,EACd,IAAY,EACZ,OAAe,EACf,OAAiB;IAEjB,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AACvG,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IACzE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { ProjectContext } from '@zhixuan92/multi-model-agent-core';
2
+ import type { ExecutionContext } from '@zhixuan92/multi-model-agent-core/executors/types';
3
+ import type { HandlerDeps } from './handler-deps.js';
4
+ /**
5
+ * Builds the ExecutionContext passed to every executor.
6
+ *
7
+ * awaitClarification wires to the BatchRegistry clarification flow:
8
+ * 1. Sets entry.resolveClarification BEFORE calling requestClarification
9
+ * (order matters — requestClarification changes state; resolver must be
10
+ * registered first so resumeFromClarification can call it later).
11
+ * 2. Returns a Promise that resolves when resumeFromClarification is called
12
+ * by the POST /batch/:id/clarify handler (Phase 7).
13
+ */
14
+ export declare function buildExecutionContext(deps: HandlerDeps, pc: ProjectContext, batchId: string): ExecutionContext;
15
+ //# sourceMappingURL=execution-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-context.d.ts","sourceRoot":"","sources":["../../src/http/execution-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,gBAAgB,EAAyB,MAAM,mDAAmD,CAAC;AACjH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,cAAc,EAClB,OAAO,EAAE,MAAM,GACd,gBAAgB,CAqBlB"}
@@ -0,0 +1,35 @@
1
+ // packages/server/src/http/execution-context.ts
2
+ import { createProvider } from '@zhixuan92/multi-model-agent-core';
3
+ /**
4
+ * Builds the ExecutionContext passed to every executor.
5
+ *
6
+ * awaitClarification wires to the BatchRegistry clarification flow:
7
+ * 1. Sets entry.resolveClarification BEFORE calling requestClarification
8
+ * (order matters — requestClarification changes state; resolver must be
9
+ * registered first so resumeFromClarification can call it later).
10
+ * 2. Returns a Promise that resolves when resumeFromClarification is called
11
+ * by the POST /batch/:id/clarify handler (Phase 7).
12
+ */
13
+ export function buildExecutionContext(deps, pc, batchId) {
14
+ return {
15
+ projectContext: pc,
16
+ config: deps.config,
17
+ logger: deps.logger,
18
+ contextBlockStore: pc.contextBlocks,
19
+ providerFactory: (profile) => createProvider(profile, deps.config),
20
+ parentModel: process.env['PARENT_MODEL_NAME'],
21
+ onProgress: undefined,
22
+ awaitClarification: async (proposal) => {
23
+ return new Promise((resolve) => {
24
+ const entry = deps.batchRegistry.get(batchId);
25
+ if (entry) {
26
+ // Register resolver BEFORE transitioning state so resumeFromClarification
27
+ // can call it immediately if it races ahead.
28
+ entry.resolveClarification = (interpretation) => resolve({ interpretation });
29
+ }
30
+ deps.batchRegistry.requestClarification(batchId, proposal.interpretation);
31
+ });
32
+ },
33
+ };
34
+ }
35
+ //# sourceMappingURL=execution-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-context.js","sourceRoot":"","sources":["../../src/http/execution-context.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAKnE;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAAiB,EACjB,EAAkB,EAClB,OAAe;IAEf,OAAO;QACL,cAAc,EAAE,EAAE;QAClB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,iBAAiB,EAAE,EAAE,CAAC,aAAa;QACnC,eAAe,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,cAAc,CAAC,OAAiC,EAAE,IAAI,CAAC,MAAM,CAAC;QACpG,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAC7C,UAAU,EAAE,SAAS;QACrB,kBAAkB,EAAE,KAAK,EAAE,QAA+B,EAAE,EAAE;YAC5D,OAAO,IAAI,OAAO,CAA6B,CAAC,OAAO,EAAE,EAAE;gBACzD,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC9C,IAAI,KAAK,EAAE,CAAC;oBACV,0EAA0E;oBAC1E,6CAA6C;oBAC7C,KAAK,CAAC,oBAAoB,GAAG,CAAC,cAAsB,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC;gBACvF,CAAC;gBACD,IAAI,CAAC,aAAa,CAAC,oBAAoB,CAAC,OAAO,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;YAC5E,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { MultiModelConfig } from '@zhixuan92/multi-model-agent-core';
2
+ import type { DiagnosticLogger } from '@zhixuan92/multi-model-agent-core';
3
+ import type { ProjectRegistry } from './project-registry.js';
4
+ import type { BatchRegistry } from '@zhixuan92/multi-model-agent-core';
5
+ /**
6
+ * Dependencies injected into every handler factory at server startup.
7
+ * Built once; passed to buildDelegateHandler, buildAuditHandler, etc.
8
+ */
9
+ export interface HandlerDeps {
10
+ /** Full multi-model config (agents + defaults). May be undefined in unit tests. */
11
+ config: MultiModelConfig;
12
+ logger: DiagnosticLogger;
13
+ projectRegistry: ProjectRegistry;
14
+ batchRegistry: BatchRegistry;
15
+ }
16
+ //# sourceMappingURL=handler-deps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-deps.d.ts","sourceRoot":"","sources":["../../src/http/handler-deps.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAEvE;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,mFAAmF;IACnF,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,gBAAgB,CAAC;IACzB,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;CAC9B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=handler-deps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-deps.js","sourceRoot":"","sources":["../../src/http/handler-deps.ts"],"names":[],"mappings":""}
@@ -0,0 +1,24 @@
1
+ import type { RawHandler } from '../../router.js';
2
+ import type { BatchRegistry } from '@zhixuan92/multi-model-agent-core';
3
+ export interface BatchHandlerDeps {
4
+ batchRegistry: BatchRegistry;
5
+ }
6
+ /**
7
+ * GET /batch/:batchId — poll the current state of a batch.
8
+ * Optional ?taskIndex=N query param slices a single task result from a
9
+ * complete batch.
10
+ *
11
+ * State mapping:
12
+ * pending → 200 { state, startedAt }
13
+ * awaiting_clarification → 200 { state, proposedInterpretation }
14
+ * complete → 200 { state, result } (or sliced if taskIndex given)
15
+ * failed → 200 { state, error }
16
+ * expired → 200 { state: 'expired' }
17
+ *
18
+ * Errors:
19
+ * unknown batchId → 404 not_found
20
+ * non-numeric taskIndex → 400 invalid_task_index
21
+ * taskIndex ≥ results.len → 404 unknown_task_index
22
+ */
23
+ export declare function buildBatchHandler(deps: BatchHandlerDeps): RawHandler;
24
+ //# sourceMappingURL=batch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../../../src/http/handlers/control/batch.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAEvE,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,UAAU,CAiFpE"}
@@ -0,0 +1,81 @@
1
+ import { sendError, sendJson } from '../../errors.js';
2
+ /**
3
+ * GET /batch/:batchId — poll the current state of a batch.
4
+ * Optional ?taskIndex=N query param slices a single task result from a
5
+ * complete batch.
6
+ *
7
+ * State mapping:
8
+ * pending → 200 { state, startedAt }
9
+ * awaiting_clarification → 200 { state, proposedInterpretation }
10
+ * complete → 200 { state, result } (or sliced if taskIndex given)
11
+ * failed → 200 { state, error }
12
+ * expired → 200 { state: 'expired' }
13
+ *
14
+ * Errors:
15
+ * unknown batchId → 404 not_found
16
+ * non-numeric taskIndex → 400 invalid_task_index
17
+ * taskIndex ≥ results.len → 404 unknown_task_index
18
+ */
19
+ export function buildBatchHandler(deps) {
20
+ return async (_req, res, params, ctx) => {
21
+ const { batchId } = params;
22
+ // ── 1. Lookup ──────────────────────────────────────────────────────────
23
+ const entry = deps.batchRegistry.get(batchId);
24
+ if (!entry) {
25
+ sendError(res, 404, 'not_found', `Batch ${batchId} not found`);
26
+ return;
27
+ }
28
+ // ── 2. Parse optional taskIndex ────────────────────────────────────────
29
+ const rawTaskIndex = ctx.url.searchParams.get('taskIndex');
30
+ let taskIndex = null;
31
+ if (rawTaskIndex !== null) {
32
+ if (!/^\d+$/.test(rawTaskIndex)) {
33
+ sendError(res, 400, 'invalid_task_index', `taskIndex must be a non-negative integer; got: ${JSON.stringify(rawTaskIndex)}`);
34
+ return;
35
+ }
36
+ taskIndex = parseInt(rawTaskIndex, 10);
37
+ }
38
+ // ── 3. State mapping ───────────────────────────────────────────────────
39
+ switch (entry.state) {
40
+ case 'pending':
41
+ sendJson(res, 200, { state: 'pending', startedAt: entry.startedAt });
42
+ return;
43
+ case 'awaiting_clarification':
44
+ sendJson(res, 200, {
45
+ state: 'awaiting_clarification',
46
+ proposedInterpretation: entry.proposedInterpretation,
47
+ });
48
+ return;
49
+ case 'complete': {
50
+ const fullResult = entry.result;
51
+ if (taskIndex !== null) {
52
+ const results = fullResult?.results;
53
+ if (!Array.isArray(results) || taskIndex >= results.length) {
54
+ sendError(res, 404, 'unknown_task_index', `taskIndex ${taskIndex} is out of range (batch has ${Array.isArray(results) ? results.length : 0} result(s))`);
55
+ return;
56
+ }
57
+ // Return the full result shape with only the sliced task
58
+ sendJson(res, 200, {
59
+ state: 'complete',
60
+ result: { ...fullResult, results: [results[taskIndex]] },
61
+ });
62
+ return;
63
+ }
64
+ sendJson(res, 200, { state: 'complete', result: fullResult });
65
+ return;
66
+ }
67
+ case 'failed':
68
+ sendJson(res, 200, { state: 'failed', error: entry.error });
69
+ return;
70
+ case 'expired':
71
+ sendJson(res, 200, { state: 'expired' });
72
+ return;
73
+ default: {
74
+ // Exhaustiveness guard — should never happen
75
+ const _never = entry.state;
76
+ sendError(res, 500, 'internal_error', `Unexpected batch state: ${String(_never)}`);
77
+ }
78
+ }
79
+ };
80
+ }
81
+ //# sourceMappingURL=batch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../../../src/http/handlers/control/batch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { RawHandler } from '../../router.js';
2
+ import type { BatchRegistry } from '@zhixuan92/multi-model-agent-core';
3
+ export interface ClarificationsHandlerDeps {
4
+ batchRegistry: BatchRegistry;
5
+ }
6
+ /**
7
+ * POST /clarifications/confirm — confirms (or idempotently re-confirms) an
8
+ * awaiting_clarification batch by providing the caller's chosen interpretation.
9
+ *
10
+ * Auth required; NOT cwd-gated (operates on a batchId, not a project cwd).
11
+ *
12
+ * Success → 200 { batchId, state: <current state after confirmation> }
13
+ * Errors:
14
+ * invalid body → 400 invalid_request
15
+ * unknown batchId → 404 not_found
16
+ * wrong state w/ different interpretation → 409 invalid_batch_state
17
+ */
18
+ export declare function buildClarificationsHandler(deps: ClarificationsHandlerDeps): RawHandler;
19
+ //# sourceMappingURL=clarifications.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clarifications.d.ts","sourceRoot":"","sources":["../../../../src/http/handlers/control/clarifications.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAEvE,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,aAAa,CAAC;CAC9B;AAOD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,yBAAyB,GAAG,UAAU,CA8CtF"}
@@ -0,0 +1,58 @@
1
+ import { z } from 'zod';
2
+ import { InvalidBatchStateError } from '@zhixuan92/multi-model-agent-core';
3
+ import { sendError, sendJson } from '../../errors.js';
4
+ const confirmBodySchema = z.object({
5
+ batchId: z.string().uuid(),
6
+ interpretation: z.string().min(1),
7
+ });
8
+ /**
9
+ * POST /clarifications/confirm — confirms (or idempotently re-confirms) an
10
+ * awaiting_clarification batch by providing the caller's chosen interpretation.
11
+ *
12
+ * Auth required; NOT cwd-gated (operates on a batchId, not a project cwd).
13
+ *
14
+ * Success → 200 { batchId, state: <current state after confirmation> }
15
+ * Errors:
16
+ * invalid body → 400 invalid_request
17
+ * unknown batchId → 404 not_found
18
+ * wrong state w/ different interpretation → 409 invalid_batch_state
19
+ */
20
+ export function buildClarificationsHandler(deps) {
21
+ return async (_req, res, _params, ctx) => {
22
+ // ── 1. Validate body ───────────────────────────────────────────────────
23
+ const parsed = confirmBodySchema.safeParse(ctx.body);
24
+ if (!parsed.success) {
25
+ sendError(res, 400, 'invalid_request', 'Request body validation failed', {
26
+ fieldErrors: parsed.error.flatten(),
27
+ });
28
+ return;
29
+ }
30
+ const { batchId, interpretation } = parsed.data;
31
+ // ── 2. Lookup ──────────────────────────────────────────────────────────
32
+ const entry = deps.batchRegistry.get(batchId);
33
+ if (!entry) {
34
+ sendError(res, 404, 'not_found', `Batch ${batchId} not found`);
35
+ return;
36
+ }
37
+ // ── 3. Resume (handles idempotency + state validation) ─────────────────
38
+ try {
39
+ deps.batchRegistry.resumeFromClarification(batchId, interpretation);
40
+ }
41
+ catch (err) {
42
+ if (err instanceof InvalidBatchStateError) {
43
+ sendError(res, 409, 'invalid_batch_state', `Cannot confirm clarification: batch is in state '${err.currentState}'`, {
44
+ currentState: err.currentState,
45
+ });
46
+ return;
47
+ }
48
+ throw err;
49
+ }
50
+ // ── 4. Echo current state ──────────────────────────────────────────────
51
+ // Re-read the entry after resumeFromClarification — the batch may have
52
+ // already completed if the executor was waiting.
53
+ const updatedEntry = deps.batchRegistry.get(batchId);
54
+ const currentState = updatedEntry?.state ?? 'pending';
55
+ sendJson(res, 200, { batchId, state: currentState });
56
+ };
57
+ }
58
+ //# sourceMappingURL=clarifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clarifications.js","sourceRoot":"","sources":["../../../../src/http/handlers/control/clarifications.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAQtD,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IAC1B,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAClC,CAAC,CAAC;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAA+B;IACxE,OAAO,KAAK,EACV,IAAqB,EACrB,GAAmB,EACnB,OAA+B,EAC/B,GAAG,EACH,EAAE;QACF,0EAA0E;QAC1E,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,gCAAgC,EAAE;gBACvE,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;aACpC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;QAEhD,0EAA0E;QAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,SAAS,OAAO,YAAY,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAED,0EAA0E;QAC1E,IAAI,CAAC;YACH,IAAI,CAAC,aAAa,CAAC,uBAAuB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,sBAAsB,EAAE,CAAC;gBAC1C,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,qBAAqB,EAAE,oDAAoD,GAAG,CAAC,YAAY,GAAG,EAAE;oBAClH,YAAY,EAAE,GAAG,CAAC,YAAY;iBAC/B,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,0EAA0E;QAC1E,uEAAuE;QACvE,iDAAiD;QACjD,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,YAAY,GAAG,YAAY,EAAE,KAAK,IAAI,SAAS,CAAC;QAEtD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { RawHandler } from '../../router.js';
2
+ import type { ProjectRegistry } from '../../project-registry.js';
3
+ import type { ServerConfig } from '@zhixuan92/multi-model-agent-core';
4
+ export interface ContextBlockHandlerDeps {
5
+ projectRegistry: ProjectRegistry;
6
+ config: ServerConfig;
7
+ }
8
+ export interface DeleteContextBlockHandlerDeps {
9
+ projectRegistry: ProjectRegistry;
10
+ }
11
+ /**
12
+ * POST /context-blocks — stores a new context block for the authenticated cwd.
13
+ * Requires cwd query param (cwd-gated).
14
+ */
15
+ export declare function buildCreateContextBlockHandler(deps: ContextBlockHandlerDeps): RawHandler;
16
+ /**
17
+ * DELETE /context-blocks/:blockId — removes a context block belonging to the
18
+ * authenticated cwd. Returns 404 if the block does not exist or belongs to
19
+ * a different project (isolation).
20
+ */
21
+ export declare function buildDeleteContextBlockHandler(deps: DeleteContextBlockHandlerDeps): RawHandler;
22
+ //# sourceMappingURL=context-blocks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-blocks.d.ts","sourceRoot":"","sources":["../../../../src/http/handlers/control/context-blocks.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEtE,MAAM,WAAW,uBAAuB;IACtC,eAAe,EAAE,eAAe,CAAC;IACjC,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,6BAA6B;IAC5C,eAAe,EAAE,eAAe,CAAC;CAClC;AAOD;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,uBAAuB,GAAG,UAAU,CA4DxF;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,6BAA6B,GAAG,UAAU,CA0C9F"}
@@ -0,0 +1,88 @@
1
+ import { z } from 'zod';
2
+ import { sendError, sendJson } from '../../errors.js';
3
+ const createBodySchema = z.object({
4
+ content: z.string().min(1),
5
+ ttlMs: z.number().int().positive().optional(),
6
+ });
7
+ /**
8
+ * POST /context-blocks — stores a new context block for the authenticated cwd.
9
+ * Requires cwd query param (cwd-gated).
10
+ */
11
+ export function buildCreateContextBlockHandler(deps) {
12
+ return async (_req, res, _params, ctx) => {
13
+ const cwd = ctx.cwd;
14
+ // ── 1. Validate body ───────────────────────────────────────────────────
15
+ const parsed = createBodySchema.safeParse(ctx.body);
16
+ if (!parsed.success) {
17
+ sendError(res, 400, 'invalid_request', 'Request body validation failed', {
18
+ fieldErrors: parsed.error.flatten(),
19
+ });
20
+ return;
21
+ }
22
+ const { content } = parsed.data;
23
+ // ── 2. Content byte-size check ─────────────────────────────────────────
24
+ const byteLen = Buffer.byteLength(content, 'utf8');
25
+ const maxBytes = deps.config.server.limits.maxContextBlockBytes;
26
+ if (byteLen > maxBytes) {
27
+ sendError(res, 413, 'payload_too_large', `Context block content exceeds the ${maxBytes}-byte limit (got ${byteLen} bytes)`);
28
+ return;
29
+ }
30
+ // ── 3. Get project context ─────────────────────────────────────────────
31
+ const reserveResult = deps.projectRegistry.reserveProject(cwd);
32
+ if (!reserveResult.ok) {
33
+ sendError(res, 503, reserveResult.error, reserveResult.message);
34
+ return;
35
+ }
36
+ const pc = reserveResult.projectContext;
37
+ pc.lastActivityAt = Date.now();
38
+ deps.projectRegistry.cancelReservation(cwd);
39
+ // ── 4. Cap check ───────────────────────────────────────────────────────
40
+ const maxBlocks = deps.config.server.limits.maxContextBlocksPerProject;
41
+ if (pc.contextBlocks.size >= maxBlocks) {
42
+ sendError(res, 409, 'cap_exhausted', `Project context block cap of ${maxBlocks} reached; delete unused blocks before creating new ones`);
43
+ return;
44
+ }
45
+ // ── 5. Create block ────────────────────────────────────────────────────
46
+ const registered = pc.contextBlocks.register(content);
47
+ sendJson(res, 201, { id: registered.id });
48
+ };
49
+ }
50
+ /**
51
+ * DELETE /context-blocks/:blockId — removes a context block belonging to the
52
+ * authenticated cwd. Returns 404 if the block does not exist or belongs to
53
+ * a different project (isolation).
54
+ */
55
+ export function buildDeleteContextBlockHandler(deps) {
56
+ return async (_req, res, params, ctx) => {
57
+ const cwd = ctx.cwd;
58
+ const { blockId } = params;
59
+ // ── 1. Get project context ─────────────────────────────────────────────
60
+ // Look up without reserving — we need to check if the project exists at all
61
+ const pc = deps.projectRegistry.get(cwd);
62
+ if (!pc) {
63
+ // Project doesn't exist — no blocks can belong to it
64
+ sendError(res, 404, 'not_found', `Context block ${blockId} not found`);
65
+ return;
66
+ }
67
+ // ── 2. Existence + isolation check ─────────────────────────────────────
68
+ // Since contextBlocks is per-project, any block in pc.contextBlocks belongs
69
+ // to this cwd. If the id isn't in this store, it either doesn't exist or
70
+ // belongs to a different project — both map to 404.
71
+ const content = pc.contextBlocks.get(blockId);
72
+ if (content === undefined) {
73
+ sendError(res, 404, 'not_found', `Context block ${blockId} not found`);
74
+ return;
75
+ }
76
+ // ── 3. Pin check ───────────────────────────────────────────────────────
77
+ const refcount = pc.contextBlocks.refcount(blockId);
78
+ if (refcount > 0) {
79
+ sendError(res, 409, 'pinned', `Context block ${blockId} is in use by ${refcount} active batch(es)`, { refcount });
80
+ return;
81
+ }
82
+ // ── 4. Delete ──────────────────────────────────────────────────────────
83
+ pc.contextBlocks.delete(blockId);
84
+ pc.lastActivityAt = Date.now();
85
+ sendJson(res, 200, { ok: true });
86
+ };
87
+ }
88
+ //# sourceMappingURL=context-blocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-blocks.js","sourceRoot":"","sources":["../../../../src/http/handlers/control/context-blocks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { RawHandler } from '../../router.js';
2
+ /**
3
+ * GET /health — lightweight liveness probe.
4
+ *
5
+ * This is the only unauthenticated route. It intentionally returns only
6
+ * `{ ok: true }` — no counters, no project data. Richer operator data
7
+ * lives on GET /status.
8
+ *
9
+ * Loopback guard is applied by the server pipeline before the handler
10
+ * is invoked (see LOOPBACK_ONLY_PATHS in server.ts).
11
+ */
12
+ export declare function buildHealthHandler(): RawHandler;
13
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../../src/http/handlers/introspection/health.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAI/C"}
@@ -0,0 +1,17 @@
1
+ import { sendJson } from '../../errors.js';
2
+ /**
3
+ * GET /health — lightweight liveness probe.
4
+ *
5
+ * This is the only unauthenticated route. It intentionally returns only
6
+ * `{ ok: true }` — no counters, no project data. Richer operator data
7
+ * lives on GET /status.
8
+ *
9
+ * Loopback guard is applied by the server pipeline before the handler
10
+ * is invoked (see LOOPBACK_ONLY_PATHS in server.ts).
11
+ */
12
+ export function buildHealthHandler() {
13
+ return (_req, res) => {
14
+ sendJson(res, 200, { ok: true });
15
+ };
16
+ }
17
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../../../src/http/handlers/introspection/health.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,CAAC,IAAqB,EAAE,GAAmB,EAAE,EAAE;QACpD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC;AACJ,CAAC"}