cleargate 0.11.5 → 0.13.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 (50) hide show
  1. package/dist/MANIFEST.json +15 -15
  2. package/dist/admin-api/index.cjs +3 -1
  3. package/dist/admin-api/index.cjs.map +1 -1
  4. package/dist/admin-api/index.d.cts +1 -0
  5. package/dist/admin-api/index.d.ts +1 -0
  6. package/dist/admin-api/index.js +3 -1
  7. package/dist/admin-api/index.js.map +1 -1
  8. package/dist/{chunk-HZPJ5QX4.js → chunk-EG6YGT2O.js} +315 -33
  9. package/dist/chunk-EG6YGT2O.js.map +1 -0
  10. package/dist/cli.cjs +855 -359
  11. package/dist/cli.cjs.map +1 -1
  12. package/dist/cli.js +316 -108
  13. package/dist/cli.js.map +1 -1
  14. package/dist/lib/lifecycle-reconcile.cjs +318 -34
  15. package/dist/lib/lifecycle-reconcile.cjs.map +1 -1
  16. package/dist/lib/lifecycle-reconcile.d.cts +55 -4
  17. package/dist/lib/lifecycle-reconcile.d.ts +55 -4
  18. package/dist/lib/lifecycle-reconcile.js +7 -3
  19. package/dist/templates/cleargate-planning/.claude/agents/architect.md +6 -4
  20. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +1 -1
  21. package/dist/templates/cleargate-planning/.claude/agents/developer.md +8 -4
  22. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +2 -0
  23. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +138 -0
  24. package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +162 -0
  25. package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +1 -1
  26. package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +1 -1
  27. package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +1 -1
  28. package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +1 -1
  29. package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +1 -1
  30. package/dist/templates/cleargate-planning/.cleargate/templates/sprint_report.md +1 -1
  31. package/dist/templates/cleargate-planning/.cleargate/templates/story.md +1 -1
  32. package/dist/templates/cleargate-planning/CLAUDE.md +4 -0
  33. package/dist/templates/cleargate-planning/MANIFEST.json +15 -15
  34. package/package.json +8 -9
  35. package/templates/cleargate-planning/.claude/agents/architect.md +6 -4
  36. package/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +1 -1
  37. package/templates/cleargate-planning/.claude/agents/developer.md +8 -4
  38. package/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +2 -0
  39. package/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +138 -0
  40. package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +162 -0
  41. package/templates/cleargate-planning/.cleargate/templates/Bug.md +1 -1
  42. package/templates/cleargate-planning/.cleargate/templates/CR.md +1 -1
  43. package/templates/cleargate-planning/.cleargate/templates/epic.md +1 -1
  44. package/templates/cleargate-planning/.cleargate/templates/hotfix.md +1 -1
  45. package/templates/cleargate-planning/.cleargate/templates/initiative.md +1 -1
  46. package/templates/cleargate-planning/.cleargate/templates/sprint_report.md +1 -1
  47. package/templates/cleargate-planning/.cleargate/templates/story.md +1 -1
  48. package/templates/cleargate-planning/CLAUDE.md +4 -0
  49. package/templates/cleargate-planning/MANIFEST.json +15 -15
  50. package/dist/chunk-HZPJ5QX4.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  {
2
- "cleargate_version": "0.11.5",
3
- "generated_at": "2026-05-11T22:02:23.454Z",
2
+ "cleargate_version": "0.13.0",
3
+ "generated_at": "2026-05-18T17:11:10.027Z",
4
4
  "files": [
5
5
  {
6
6
  "path": ".claude/agents/architect.md",
7
- "sha256": "a2d11d6a7f21bce22730ba9076af9ddde44b258082e33aa99fcd57c14ad75f55",
7
+ "sha256": "823db34b934d080e648955326dcc3cd31899e90f62ecfa4a9344f5b473237084",
8
8
  "tier": "agent",
9
9
  "overwrite_policy": "always",
10
10
  "preserve_on_uninstall": false
@@ -25,7 +25,7 @@
25
25
  },
26
26
  {
27
27
  "path": ".claude/agents/cleargate-wiki-lint.md",
28
- "sha256": "42067fd728e64ac1ff1ace5822b8f8c3ddf1ba70fd0fbddf0e8cb19d5d699e77",
28
+ "sha256": "2a9212d81df9a68e167ec7a18093a73c6da0208f13685c6887d5bd832b56fb3d",
29
29
  "tier": "agent",
30
30
  "overwrite_policy": "always",
31
31
  "preserve_on_uninstall": false
@@ -39,7 +39,7 @@
39
39
  },
40
40
  {
41
41
  "path": ".claude/agents/developer.md",
42
- "sha256": "36f75fe9f8dc8412eb22706dfd021f5db5694c81d73e0c938e701a83c0149126",
42
+ "sha256": "db7963778d68654f2dc96658d60433fa79305a10eec937807f2f0ed0cd05ce89",
43
43
  "tier": "agent",
44
44
  "overwrite_policy": "always",
45
45
  "preserve_on_uninstall": false
@@ -74,7 +74,7 @@
74
74
  },
75
75
  {
76
76
  "path": ".claude/hooks/pre-commit-surface-gate.sh",
77
- "sha256": "6741422cd8ca75b45e26bd0e9cb54126ad9e933f763c9094ceba6b84794b761a",
77
+ "sha256": "8dd817fbe75ee53753e2fe1fc2ccd2b6efdb2b3c0b6ad3191bebd9640afdd6f8",
78
78
  "tier": "hook",
79
79
  "overwrite_policy": "always",
80
80
  "preserve_on_uninstall": false
@@ -165,7 +165,7 @@
165
165
  },
166
166
  {
167
167
  "path": ".cleargate/knowledge/cleargate-protocol.md",
168
- "sha256": "50e999717b9c9e1c11638f3f2433f413d177ed8ddf3cffdbb20b50c8807b1fc5",
168
+ "sha256": "0380e74efa8aa782b77952fa68cc0171de035653e777d5c241d84c6e0414957b",
169
169
  "tier": "protocol",
170
170
  "overwrite_policy": "merge-3way",
171
171
  "preserve_on_uninstall": false
@@ -200,7 +200,7 @@
200
200
  },
201
201
  {
202
202
  "path": ".cleargate/scripts/close_sprint.mjs",
203
- "sha256": "1807e5b27f1501476c9dec41cbb350c432d2894cb0727d8da0c860ad3f9181c7",
203
+ "sha256": "b14b65f15c5ad57a845df89c069b5417195651b7d3aa7f7f5736416d0db0b868",
204
204
  "tier": "script",
205
205
  "overwrite_policy": "always",
206
206
  "preserve_on_uninstall": false
@@ -396,35 +396,35 @@
396
396
  },
397
397
  {
398
398
  "path": ".cleargate/templates/Bug.md",
399
- "sha256": "570112e3a60856c891652837307fc6f296cc39acc20451f8bde62da0fe033026",
399
+ "sha256": "cebca344b6b820525c603444cf52626e120ebaa1ac28da099dc19c9cff39302c",
400
400
  "tier": "template",
401
401
  "overwrite_policy": "merge-3way",
402
402
  "preserve_on_uninstall": false
403
403
  },
404
404
  {
405
405
  "path": ".cleargate/templates/CR.md",
406
- "sha256": "ab111792dc79fd5181b44a63c76ac696fa4e456161ac44e2c4d0dc609e8dd904",
406
+ "sha256": "ea5acf2087808e0d52806a87a6a7f1ced7473b591857f322fab5285adc80d25a",
407
407
  "tier": "template",
408
408
  "overwrite_policy": "merge-3way",
409
409
  "preserve_on_uninstall": false
410
410
  },
411
411
  {
412
412
  "path": ".cleargate/templates/epic.md",
413
- "sha256": "fd3b54de89befe7c5bcef65e2fa5550fc7f371d55c8f15143ae73d84f3ae6d36",
413
+ "sha256": "f9cf44db19288f0756b76bc8b13a075d4089990324db6febd072f5cf93d59cd0",
414
414
  "tier": "template",
415
415
  "overwrite_policy": "merge-3way",
416
416
  "preserve_on_uninstall": false
417
417
  },
418
418
  {
419
419
  "path": ".cleargate/templates/hotfix.md",
420
- "sha256": "b75dd154c156e68a44ae01b85eff7ec16f54050e4fe7eb71f59e17d87c03a298",
420
+ "sha256": "de788497b4d224500036773f854801c056d73b08c3c0d66fdb641f17a1610bca",
421
421
  "tier": "template",
422
422
  "overwrite_policy": "merge-3way",
423
423
  "preserve_on_uninstall": false
424
424
  },
425
425
  {
426
426
  "path": ".cleargate/templates/initiative.md",
427
- "sha256": "28680917228e5d9887c8820193cc21bfecc6aad3bc0658e8a59087adf63551fd",
427
+ "sha256": "1170e595f5813c62f86212d6ca1955d84465f396c81aaf34498b8e2d4595d681",
428
428
  "tier": "template",
429
429
  "overwrite_policy": "merge-3way",
430
430
  "preserve_on_uninstall": false
@@ -445,14 +445,14 @@
445
445
  },
446
446
  {
447
447
  "path": ".cleargate/templates/sprint_report.md",
448
- "sha256": "84e32e956eb1e8a9c97be1c346b695df316a9e47e17402f3d6581e3ffdbc4d2d",
448
+ "sha256": "5914d54080f6110be5a5e905e3312811f3d0f80978121b1e15707d5be05cc5b1",
449
449
  "tier": "template",
450
450
  "overwrite_policy": "merge-3way",
451
451
  "preserve_on_uninstall": false
452
452
  },
453
453
  {
454
454
  "path": ".cleargate/templates/story.md",
455
- "sha256": "56d793983614d832e84193d99ee5318c061d2f3ea4f019cefb861c026513cb31",
455
+ "sha256": "0badf01a080bca552a06fb64becd9b8c88fbf104e30f32667263522c3ff81051",
456
456
  "tier": "template",
457
457
  "overwrite_policy": "merge-3way",
458
458
  "preserve_on_uninstall": false
@@ -92,7 +92,9 @@ var InviteCreatedSchema = import_zod.z.object({
92
92
  member: MemberSchema,
93
93
  invite_url: import_zod.z.string(),
94
94
  invite_token: import_zod.z.string(),
95
- invite_expires_in: import_zod.z.number().int()
95
+ invite_expires_in: import_zod.z.number().int(),
96
+ /** Whether the invite email was sent successfully (CR-062) */
97
+ mail_sent: import_zod.z.boolean()
96
98
  }).strict();
97
99
  var TokenMetaSchema = import_zod.z.object({
98
100
  id: import_zod.z.string(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/admin-api/index.ts","../../src/admin-api/errors.ts","../../src/admin-api/responses.ts","../../src/admin-api/redact.ts","../../src/admin-api/client.ts","../../src/admin-api/admin-auth.ts"],"sourcesContent":["/**\n * Barrel export for admin-api module.\n * Consumed by cleargate-admin commands via cleargate/admin-api.\n */\nexport * from './client.js';\nexport * from './errors.js';\nexport * from './redact.js';\nexport * from './responses.js';\nexport * from './admin-auth.js';\n","/**\n * Typed error class for all admin API failures.\n * kind → exit code mapping lives in mcp/scripts/commands/_render-error.ts\n */\nexport class AdminApiError extends Error {\n constructor(\n public readonly kind:\n | 'network'\n | 'auth'\n | 'forbidden'\n | 'not_found'\n | 'invalid_request'\n | 'server'\n | 'response_shape',\n public readonly status: number | null,\n public readonly details: unknown,\n message: string,\n ) {\n super(message);\n this.name = 'AdminApiError';\n }\n}\n","/**\n * Vendored Zod response schemas — hand-authored from\n * mcp/src/admin-api/__snapshots__/openapi.test.ts.snap\n *\n * Snapshot drift is detected by cleargate-cli/test/admin-api/snapshot-drift.test.ts,\n * which reads the snapshot file at runtime and asserts field-set equality.\n */\nimport { z } from 'zod';\n\nexport const ProjectSchema = z\n .object({\n id: z.string(),\n name: z.string(),\n created_by: z.string(),\n created_at: z.string(),\n deleted_at: z.string().nullable(),\n })\n .strict();\n\nexport type Project = z.infer<typeof ProjectSchema>;\n\nexport const MemberSchema = z\n .object({\n id: z.string(),\n project_id: z.string(),\n email: z.string(),\n role: z.string(),\n display_name: z.string().nullable().optional(),\n created_at: z.string(),\n status: z.enum(['pending', 'active', 'expired']),\n })\n .strict();\n\nexport type Member = z.infer<typeof MemberSchema>;\n\nexport const InviteCreatedSchema = z\n .object({\n member: MemberSchema,\n invite_url: z.string(),\n invite_token: z.string(),\n invite_expires_in: z.number().int(),\n })\n .strict();\n\nexport type InviteCreated = z.infer<typeof InviteCreatedSchema>;\n\nexport const TokenMetaSchema = z\n .object({\n id: z.string(),\n member_id: z.string(),\n name: z.string(),\n created_at: z.string(),\n expires_at: z.string().nullable().optional(),\n last_used_at: z.string().nullable().optional(),\n revoked_at: z.string().nullable().optional(),\n })\n .strict();\n\nexport type TokenMeta = z.infer<typeof TokenMetaSchema>;\n\n// TokenIssued = TokenMeta + plaintext token field (returned exactly once)\nexport const TokenIssuedSchema = z\n .object({\n id: z.string(),\n member_id: z.string(),\n name: z.string(),\n created_at: z.string(),\n expires_at: z.string().nullable().optional(),\n last_used_at: z.string().nullable().optional(),\n revoked_at: z.string().nullable().optional(),\n token: z.string(),\n })\n .strict();\n\nexport type TokenIssued = z.infer<typeof TokenIssuedSchema>;\n\nexport const AuthExchangeResponseSchema = z\n .object({\n admin_token: z.string(),\n expires_at: z.string(),\n })\n .strict();\n\nexport type AuthExchangeResponse = z.infer<typeof AuthExchangeResponseSchema>;\n\nexport const ErrorBodySchema = z\n .object({\n error: z.string(),\n details: z.record(z.string(), z.unknown()).optional(),\n })\n .strict();\n\nexport type ErrorBody = z.infer<typeof ErrorBodySchema>;\n\n// ── Items admin API (STORY-004-09) ───────────────────────────────────────────\n\nexport const ItemSummarySchema = z\n .object({\n id: z.string(),\n cleargate_id: z.string(),\n type: z.string(),\n title: z.string(),\n status: z.string(),\n remote_id: z.string().nullable(),\n last_pushed_at: z.string().nullable(),\n pushed_by_member_id: z.string().nullable(),\n version: z.number().int(),\n updated_at: z.string(),\n current_payload: z.record(z.string(), z.unknown()).default({}),\n })\n .strict();\n\nexport type ItemSummary = z.infer<typeof ItemSummarySchema>;\n\nexport const ItemsListResponseSchema = z\n .object({\n items: z.array(ItemSummarySchema),\n next_cursor: z.string().nullable(),\n })\n .strict();\n\nexport type ItemsListResponse = z.infer<typeof ItemsListResponseSchema>;\n\nexport const ItemVersionSchema = z\n .object({\n version: z.number().int(),\n pushed_by_member_id: z.string().nullable(),\n pushed_at: z.string(),\n status: z.string(),\n diff_summary: z.string().nullable(),\n })\n .strict();\n\nexport type ItemVersion = z.infer<typeof ItemVersionSchema>;\n\nexport const ItemVersionsResponseSchema = z\n .object({\n versions: z.array(ItemVersionSchema),\n })\n .strict();\n\nexport type ItemVersionsResponse = z.infer<typeof ItemVersionsResponseSchema>;\n\n// ── Device-flow schemas (STORY-005-06) ───────────────────────────────────────\n\nexport const DeviceStartResponseSchema = z\n .object({\n device_code: z.string(),\n user_code: z.string(),\n verification_uri: z.string(),\n expires_in: z.number().int(),\n interval: z.number().int(),\n })\n .strict();\n\nexport type DeviceStartResponse = z.infer<typeof DeviceStartResponseSchema>;\n\nexport const DevicePollPendingResponseSchema = z\n .object({\n pending: z.literal(true),\n retry_after: z.number().int().optional(),\n })\n .strict();\n\nexport type DevicePollPendingResponse = z.infer<typeof DevicePollPendingResponseSchema>;\n\nexport const DevicePollSuccessResponseSchema = z\n .object({\n pending: z.literal(false),\n admin_token: z.string(),\n expires_at: z.string(),\n admin_user_id: z.string(),\n })\n .strict();\n\nexport type DevicePollSuccessResponse = z.infer<typeof DevicePollSuccessResponseSchema>;\n\n// ── Admin users API (STORY-006-09) ───────────────────────────────────────────\n\nexport const AdminUserSchema = z\n .object({\n id: z.string(),\n github_handle: z.string(),\n github_user_id: z.string().nullable(),\n is_root: z.boolean(),\n disabled_at: z.string().nullable(),\n created_at: z.string(),\n created_by: z.string().nullable(),\n })\n .strict();\n\nexport type AdminUser = z.infer<typeof AdminUserSchema>;\n\nexport const AdminUsersListResponseSchema = z\n .object({\n admin_users: z.array(AdminUserSchema),\n })\n .strict();\n\nexport type AdminUsersListResponse = z.infer<typeof AdminUsersListResponseSchema>;\n\nexport const UsersMeResponseSchema = z\n .object({\n id: z.string(),\n github_handle: z.string(),\n is_root: z.boolean(),\n })\n .strict();\n\nexport type UsersMeResponse = z.infer<typeof UsersMeResponseSchema>;\n","/**\n * Recursively replaces sensitive key values with '<redacted>'.\n * Used in debug log paths — never in success output.\n * Keys stripped: token, refresh_token, invite_token\n */\nconst SENSITIVE_KEYS = new Set(['token', 'refresh_token', 'invite_token']);\n\nexport function redactSensitive(obj: unknown): unknown {\n if (Array.isArray(obj)) {\n return obj.map((item) => redactSensitive(item));\n }\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (SENSITIVE_KEYS.has(key)) {\n result[key] = '<redacted>';\n } else {\n result[key] = redactSensitive(value);\n }\n }\n return result;\n }\n return obj;\n}\n","/**\n * AdminApiClient — typed HTTP client for the ClearGate admin API.\n *\n * Key implementation notes:\n * - CLI method args are camelCase; wire bodies are snake_case (converted internally)\n * - DELETE requests MUST omit Content-Type (Fastify 5 FST_ERR_CTP_EMPTY_JSON_BODY)\n * - All 2xx responses are validated through vendored Zod schemas\n * - Errors map to AdminApiError with kind → exit code table in D6\n */\nimport { AdminApiError } from './errors.js';\nimport {\n ProjectSchema,\n InviteCreatedSchema,\n TokenIssuedSchema,\n type Project,\n type InviteCreated,\n type TokenIssued,\n} from './responses.js';\nimport { redactSensitive } from './redact.js';\n\nexport interface AdminApiClientOptions {\n baseUrl: string;\n token: string;\n fetch?: typeof globalThis.fetch;\n warn?: (msg: string) => void;\n userAgent?: string;\n}\n\nexport interface AdminApiClient {\n createProject(input: { name: string }): Promise<Project>;\n inviteMember(input: {\n projectId: string;\n email: string;\n role: 'user' | 'service';\n displayName?: string;\n }): Promise<InviteCreated>;\n issueToken(input: {\n projectId: string;\n memberId: string;\n name: string;\n expiresAt?: string;\n }): Promise<TokenIssued>;\n revokeToken(input: { tokenId: string }): Promise<void>;\n}\n\nfunction defaultWarn(msg: string): void {\n process.stderr.write(msg + '\\n');\n}\n\nclass AdminApiClientImpl implements AdminApiClient {\n private readonly baseUrl: string;\n private readonly token: string;\n private readonly fetchFn: typeof globalThis.fetch;\n private readonly warn: (msg: string) => void;\n private readonly userAgent: string;\n\n constructor(opts: AdminApiClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '');\n this.token = opts.token;\n this.fetchFn = opts.fetch ?? globalThis.fetch;\n this.warn = opts.warn ?? defaultWarn;\n this.userAgent = opts.userAgent ?? `cleargate`;\n }\n\n private debugLog(method: string, path: string, status: number, body: unknown): void {\n if (process.env['CLEARGATE_LOG_LEVEL'] === 'debug') {\n const redacted = redactSensitive(body);\n this.warn(`[admin-api] ${method} ${path} → ${status} ${JSON.stringify(redacted)}`);\n }\n }\n\n private async request<T>(\n method: string,\n urlPath: string,\n body?: Record<string, unknown>,\n ): Promise<T> {\n const url = `${this.baseUrl}/admin-api/v1${urlPath}`;\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.token}`,\n 'User-Agent': this.userAgent,\n Accept: 'application/json',\n };\n\n // CRITICAL: omit Content-Type on requests without body (DELETE)\n // Fastify 5 throws FST_ERR_CTP_EMPTY_JSON_BODY if Content-Type is set with empty body\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n let response: Response;\n try {\n response = await this.fetchFn(url, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n } catch (err) {\n throw new AdminApiError(\n 'network',\n null,\n err,\n `cannot reach ${this.baseUrl} (${err instanceof Error ? err.message : String(err)})`,\n );\n }\n\n // Parse response body when present\n let responseBody: unknown = null;\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n try {\n responseBody = await response.json();\n } catch {\n responseBody = null;\n }\n }\n\n this.debugLog(method, urlPath, response.status, responseBody);\n\n // Map HTTP status to AdminApiError kinds\n if (!response.ok) {\n const errBody = responseBody as { error?: string; details?: unknown } | null;\n if (response.status === 401) {\n throw new AdminApiError('auth', 401, responseBody, 'Admin token rejected.');\n }\n if (response.status === 403) {\n throw new AdminApiError('forbidden', 403, responseBody, 'Token is not admin-role.');\n }\n if (response.status === 404) {\n throw new AdminApiError('not_found', 404, responseBody, 'Not found.');\n }\n if (response.status === 400 || response.status === 409) {\n throw new AdminApiError(\n 'invalid_request',\n response.status,\n errBody?.details ?? responseBody,\n `Invalid request: ${errBody?.error ?? 'unknown'}`,\n );\n }\n if (response.status >= 500) {\n throw new AdminApiError(\n 'server',\n response.status,\n responseBody,\n `Server error ${response.status}.`,\n );\n }\n throw new AdminApiError(\n 'server',\n response.status,\n responseBody,\n `Unexpected status ${response.status}.`,\n );\n }\n\n return responseBody as T;\n }\n\n async createProject(input: { name: string }): Promise<Project> {\n const raw = await this.request<unknown>('POST', '/projects', { name: input.name });\n const parsed = ProjectSchema.safeParse(raw);\n if (!parsed.success) {\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async inviteMember(input: {\n projectId: string;\n email: string;\n role: 'user' | 'service';\n displayName?: string;\n }): Promise<InviteCreated> {\n const body: Record<string, unknown> = {\n email: input.email,\n role: input.role,\n };\n if (input.displayName !== undefined) {\n body['display_name'] = input.displayName;\n }\n const raw = await this.request<unknown>(\n 'POST',\n `/projects/${input.projectId}/members`,\n body,\n );\n const parsed = InviteCreatedSchema.safeParse(raw);\n if (!parsed.success) {\n // Try MemberSchema in case the server returned a member-only response\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async issueToken(input: {\n projectId: string;\n memberId: string;\n name: string;\n expiresAt?: string;\n }): Promise<TokenIssued> {\n const body: Record<string, unknown> = {\n member_id: input.memberId,\n name: input.name,\n };\n if (input.expiresAt !== undefined) {\n body['expires_at'] = input.expiresAt;\n }\n const raw = await this.request<unknown>(\n 'POST',\n `/projects/${input.projectId}/tokens`,\n body,\n );\n const parsed = TokenIssuedSchema.safeParse(raw);\n if (!parsed.success) {\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async revokeToken(input: { tokenId: string }): Promise<void> {\n // No body — Content-Type must be omitted (Fastify 5 CTP quirk)\n await this.request<unknown>('DELETE', `/tokens/${input.tokenId}`, undefined);\n }\n}\n\nexport function createAdminApiClient(opts: AdminApiClientOptions): AdminApiClient {\n return new AdminApiClientImpl(opts);\n}\n","/**\n * Loads an admin JWT for use with cleargate-admin CLI commands.\n *\n * Load order:\n * 1. CLEARGATE_ADMIN_TOKEN env var (wins immediately — file is not read)\n * 2. ~/.cleargate/admin-auth.json (shape: { version: 1, token: string })\n *\n * DISTINCT from FileTokenStore: that file holds user profile → refresh-token maps.\n * This file holds a single admin JWT acquired out-of-band via dev-issue-token.\n */\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { z } from 'zod';\n\nexport const AdminAuthFileSchema = z\n .object({\n version: z.literal(1),\n token: z.string().min(1),\n })\n .strict();\n\nexport interface LoadAdminAuthOptions {\n env?: NodeJS.ProcessEnv;\n filePath?: string;\n homedir?: () => string;\n warn?: (msg: string) => void;\n}\n\nexport interface AdminAuth {\n token: string;\n source: 'env' | 'file';\n}\n\nconst MISSING_TOKEN_ERROR =\n 'No admin token. Set CLEARGATE_ADMIN_TOKEN or write ~/.cleargate/admin-auth.json (chmod 600). See README §admin-jwt.';\n\nexport function loadAdminAuth(opts?: LoadAdminAuthOptions): AdminAuth {\n const env = opts?.env ?? process.env;\n const warn = opts?.warn ?? ((msg: string) => process.stderr.write(msg + '\\n'));\n\n // Env wins — file is not read at all when env is set\n const envToken = env['CLEARGATE_ADMIN_TOKEN'];\n if (envToken) {\n return { token: envToken, source: 'env' };\n }\n\n // Resolve file path\n const homedirFn = opts?.homedir ?? os.homedir;\n const filePath =\n opts?.filePath ?? path.join(homedirFn(), '.cleargate', 'admin-auth.json');\n\n // Try file\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf8');\n } catch (err) {\n if (err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error(MISSING_TOKEN_ERROR);\n }\n throw new Error(`Failed to read admin-auth file at ${filePath}: ${String(err)}`);\n }\n\n // Check file permissions (warn if too permissive)\n try {\n const stat = fs.statSync(filePath);\n const mode = stat.mode & 0o777;\n if (mode & 0o077) {\n warn(\n `cleargate-admin: warning: ${filePath} is group/world readable (mode ${(mode).toString(8).padStart(3, '0')}). Run: chmod 600 ${filePath}`,\n );\n }\n } catch {\n // If we can't stat the file, ignore — the read already succeeded\n }\n\n // Parse JSON\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(`Failed to parse admin-auth file at ${filePath}: invalid JSON`);\n }\n\n // Validate with strict schema\n const result = AdminAuthFileSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(\n `Invalid admin-auth file at ${filePath}: ${result.error.message}`,\n );\n }\n\n return { token: result.data.token, source: 'file' };\n}\n"],"mappings":"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","names":["path","import_zod"]}
1
+ {"version":3,"sources":["../../src/admin-api/index.ts","../../src/admin-api/errors.ts","../../src/admin-api/responses.ts","../../src/admin-api/redact.ts","../../src/admin-api/client.ts","../../src/admin-api/admin-auth.ts"],"sourcesContent":["/**\n * Barrel export for admin-api module.\n * Consumed by cleargate-admin commands via cleargate/admin-api.\n */\nexport * from './client.js';\nexport * from './errors.js';\nexport * from './redact.js';\nexport * from './responses.js';\nexport * from './admin-auth.js';\n","/**\n * Typed error class for all admin API failures.\n * kind → exit code mapping lives in mcp/scripts/commands/_render-error.ts\n */\nexport class AdminApiError extends Error {\n constructor(\n public readonly kind:\n | 'network'\n | 'auth'\n | 'forbidden'\n | 'not_found'\n | 'invalid_request'\n | 'server'\n | 'response_shape',\n public readonly status: number | null,\n public readonly details: unknown,\n message: string,\n ) {\n super(message);\n this.name = 'AdminApiError';\n }\n}\n","/**\n * Vendored Zod response schemas — hand-authored from\n * mcp/src/admin-api/__snapshots__/openapi.test.ts.snap\n *\n * Snapshot drift is detected by cleargate-cli/test/admin-api/snapshot-drift.test.ts,\n * which reads the snapshot file at runtime and asserts field-set equality.\n */\nimport { z } from 'zod';\n\nexport const ProjectSchema = z\n .object({\n id: z.string(),\n name: z.string(),\n created_by: z.string(),\n created_at: z.string(),\n deleted_at: z.string().nullable(),\n })\n .strict();\n\nexport type Project = z.infer<typeof ProjectSchema>;\n\nexport const MemberSchema = z\n .object({\n id: z.string(),\n project_id: z.string(),\n email: z.string(),\n role: z.string(),\n display_name: z.string().nullable().optional(),\n created_at: z.string(),\n status: z.enum(['pending', 'active', 'expired']),\n })\n .strict();\n\nexport type Member = z.infer<typeof MemberSchema>;\n\nexport const InviteCreatedSchema = z\n .object({\n member: MemberSchema,\n invite_url: z.string(),\n invite_token: z.string(),\n invite_expires_in: z.number().int(),\n /** Whether the invite email was sent successfully (CR-062) */\n mail_sent: z.boolean(),\n })\n .strict();\n\nexport type InviteCreated = z.infer<typeof InviteCreatedSchema>;\n\nexport const TokenMetaSchema = z\n .object({\n id: z.string(),\n member_id: z.string(),\n name: z.string(),\n created_at: z.string(),\n expires_at: z.string().nullable().optional(),\n last_used_at: z.string().nullable().optional(),\n revoked_at: z.string().nullable().optional(),\n })\n .strict();\n\nexport type TokenMeta = z.infer<typeof TokenMetaSchema>;\n\n// TokenIssued = TokenMeta + plaintext token field (returned exactly once)\nexport const TokenIssuedSchema = z\n .object({\n id: z.string(),\n member_id: z.string(),\n name: z.string(),\n created_at: z.string(),\n expires_at: z.string().nullable().optional(),\n last_used_at: z.string().nullable().optional(),\n revoked_at: z.string().nullable().optional(),\n token: z.string(),\n })\n .strict();\n\nexport type TokenIssued = z.infer<typeof TokenIssuedSchema>;\n\nexport const AuthExchangeResponseSchema = z\n .object({\n admin_token: z.string(),\n expires_at: z.string(),\n })\n .strict();\n\nexport type AuthExchangeResponse = z.infer<typeof AuthExchangeResponseSchema>;\n\nexport const ErrorBodySchema = z\n .object({\n error: z.string(),\n details: z.record(z.string(), z.unknown()).optional(),\n })\n .strict();\n\nexport type ErrorBody = z.infer<typeof ErrorBodySchema>;\n\n// ── Items admin API (STORY-004-09) ───────────────────────────────────────────\n\nexport const ItemSummarySchema = z\n .object({\n id: z.string(),\n cleargate_id: z.string(),\n type: z.string(),\n title: z.string(),\n status: z.string(),\n remote_id: z.string().nullable(),\n last_pushed_at: z.string().nullable(),\n pushed_by_member_id: z.string().nullable(),\n version: z.number().int(),\n updated_at: z.string(),\n current_payload: z.record(z.string(), z.unknown()).default({}),\n })\n .strict();\n\nexport type ItemSummary = z.infer<typeof ItemSummarySchema>;\n\nexport const ItemsListResponseSchema = z\n .object({\n items: z.array(ItemSummarySchema),\n next_cursor: z.string().nullable(),\n })\n .strict();\n\nexport type ItemsListResponse = z.infer<typeof ItemsListResponseSchema>;\n\nexport const ItemVersionSchema = z\n .object({\n version: z.number().int(),\n pushed_by_member_id: z.string().nullable(),\n pushed_at: z.string(),\n status: z.string(),\n diff_summary: z.string().nullable(),\n })\n .strict();\n\nexport type ItemVersion = z.infer<typeof ItemVersionSchema>;\n\nexport const ItemVersionsResponseSchema = z\n .object({\n versions: z.array(ItemVersionSchema),\n })\n .strict();\n\nexport type ItemVersionsResponse = z.infer<typeof ItemVersionsResponseSchema>;\n\n// ── Device-flow schemas (STORY-005-06) ───────────────────────────────────────\n\nexport const DeviceStartResponseSchema = z\n .object({\n device_code: z.string(),\n user_code: z.string(),\n verification_uri: z.string(),\n expires_in: z.number().int(),\n interval: z.number().int(),\n })\n .strict();\n\nexport type DeviceStartResponse = z.infer<typeof DeviceStartResponseSchema>;\n\nexport const DevicePollPendingResponseSchema = z\n .object({\n pending: z.literal(true),\n retry_after: z.number().int().optional(),\n })\n .strict();\n\nexport type DevicePollPendingResponse = z.infer<typeof DevicePollPendingResponseSchema>;\n\nexport const DevicePollSuccessResponseSchema = z\n .object({\n pending: z.literal(false),\n admin_token: z.string(),\n expires_at: z.string(),\n admin_user_id: z.string(),\n })\n .strict();\n\nexport type DevicePollSuccessResponse = z.infer<typeof DevicePollSuccessResponseSchema>;\n\n// ── Admin users API (STORY-006-09) ───────────────────────────────────────────\n\nexport const AdminUserSchema = z\n .object({\n id: z.string(),\n github_handle: z.string(),\n github_user_id: z.string().nullable(),\n is_root: z.boolean(),\n disabled_at: z.string().nullable(),\n created_at: z.string(),\n created_by: z.string().nullable(),\n })\n .strict();\n\nexport type AdminUser = z.infer<typeof AdminUserSchema>;\n\nexport const AdminUsersListResponseSchema = z\n .object({\n admin_users: z.array(AdminUserSchema),\n })\n .strict();\n\nexport type AdminUsersListResponse = z.infer<typeof AdminUsersListResponseSchema>;\n\nexport const UsersMeResponseSchema = z\n .object({\n id: z.string(),\n github_handle: z.string(),\n is_root: z.boolean(),\n })\n .strict();\n\nexport type UsersMeResponse = z.infer<typeof UsersMeResponseSchema>;\n","/**\n * Recursively replaces sensitive key values with '<redacted>'.\n * Used in debug log paths — never in success output.\n * Keys stripped: token, refresh_token, invite_token\n */\nconst SENSITIVE_KEYS = new Set(['token', 'refresh_token', 'invite_token']);\n\nexport function redactSensitive(obj: unknown): unknown {\n if (Array.isArray(obj)) {\n return obj.map((item) => redactSensitive(item));\n }\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (SENSITIVE_KEYS.has(key)) {\n result[key] = '<redacted>';\n } else {\n result[key] = redactSensitive(value);\n }\n }\n return result;\n }\n return obj;\n}\n","/**\n * AdminApiClient — typed HTTP client for the ClearGate admin API.\n *\n * Key implementation notes:\n * - CLI method args are camelCase; wire bodies are snake_case (converted internally)\n * - DELETE requests MUST omit Content-Type (Fastify 5 FST_ERR_CTP_EMPTY_JSON_BODY)\n * - All 2xx responses are validated through vendored Zod schemas\n * - Errors map to AdminApiError with kind → exit code table in D6\n */\nimport { AdminApiError } from './errors.js';\nimport {\n ProjectSchema,\n InviteCreatedSchema,\n TokenIssuedSchema,\n type Project,\n type InviteCreated,\n type TokenIssued,\n} from './responses.js';\nimport { redactSensitive } from './redact.js';\n\nexport interface AdminApiClientOptions {\n baseUrl: string;\n token: string;\n fetch?: typeof globalThis.fetch;\n warn?: (msg: string) => void;\n userAgent?: string;\n}\n\nexport interface AdminApiClient {\n createProject(input: { name: string }): Promise<Project>;\n inviteMember(input: {\n projectId: string;\n email: string;\n role: 'user' | 'service';\n displayName?: string;\n }): Promise<InviteCreated>;\n issueToken(input: {\n projectId: string;\n memberId: string;\n name: string;\n expiresAt?: string;\n }): Promise<TokenIssued>;\n revokeToken(input: { tokenId: string }): Promise<void>;\n}\n\nfunction defaultWarn(msg: string): void {\n process.stderr.write(msg + '\\n');\n}\n\nclass AdminApiClientImpl implements AdminApiClient {\n private readonly baseUrl: string;\n private readonly token: string;\n private readonly fetchFn: typeof globalThis.fetch;\n private readonly warn: (msg: string) => void;\n private readonly userAgent: string;\n\n constructor(opts: AdminApiClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '');\n this.token = opts.token;\n this.fetchFn = opts.fetch ?? globalThis.fetch;\n this.warn = opts.warn ?? defaultWarn;\n this.userAgent = opts.userAgent ?? `cleargate`;\n }\n\n private debugLog(method: string, path: string, status: number, body: unknown): void {\n if (process.env['CLEARGATE_LOG_LEVEL'] === 'debug') {\n const redacted = redactSensitive(body);\n this.warn(`[admin-api] ${method} ${path} → ${status} ${JSON.stringify(redacted)}`);\n }\n }\n\n private async request<T>(\n method: string,\n urlPath: string,\n body?: Record<string, unknown>,\n ): Promise<T> {\n const url = `${this.baseUrl}/admin-api/v1${urlPath}`;\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.token}`,\n 'User-Agent': this.userAgent,\n Accept: 'application/json',\n };\n\n // CRITICAL: omit Content-Type on requests without body (DELETE)\n // Fastify 5 throws FST_ERR_CTP_EMPTY_JSON_BODY if Content-Type is set with empty body\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n let response: Response;\n try {\n response = await this.fetchFn(url, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n } catch (err) {\n throw new AdminApiError(\n 'network',\n null,\n err,\n `cannot reach ${this.baseUrl} (${err instanceof Error ? err.message : String(err)})`,\n );\n }\n\n // Parse response body when present\n let responseBody: unknown = null;\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n try {\n responseBody = await response.json();\n } catch {\n responseBody = null;\n }\n }\n\n this.debugLog(method, urlPath, response.status, responseBody);\n\n // Map HTTP status to AdminApiError kinds\n if (!response.ok) {\n const errBody = responseBody as { error?: string; details?: unknown } | null;\n if (response.status === 401) {\n throw new AdminApiError('auth', 401, responseBody, 'Admin token rejected.');\n }\n if (response.status === 403) {\n throw new AdminApiError('forbidden', 403, responseBody, 'Token is not admin-role.');\n }\n if (response.status === 404) {\n throw new AdminApiError('not_found', 404, responseBody, 'Not found.');\n }\n if (response.status === 400 || response.status === 409) {\n throw new AdminApiError(\n 'invalid_request',\n response.status,\n errBody?.details ?? responseBody,\n `Invalid request: ${errBody?.error ?? 'unknown'}`,\n );\n }\n if (response.status >= 500) {\n throw new AdminApiError(\n 'server',\n response.status,\n responseBody,\n `Server error ${response.status}.`,\n );\n }\n throw new AdminApiError(\n 'server',\n response.status,\n responseBody,\n `Unexpected status ${response.status}.`,\n );\n }\n\n return responseBody as T;\n }\n\n async createProject(input: { name: string }): Promise<Project> {\n const raw = await this.request<unknown>('POST', '/projects', { name: input.name });\n const parsed = ProjectSchema.safeParse(raw);\n if (!parsed.success) {\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async inviteMember(input: {\n projectId: string;\n email: string;\n role: 'user' | 'service';\n displayName?: string;\n }): Promise<InviteCreated> {\n const body: Record<string, unknown> = {\n email: input.email,\n role: input.role,\n };\n if (input.displayName !== undefined) {\n body['display_name'] = input.displayName;\n }\n const raw = await this.request<unknown>(\n 'POST',\n `/projects/${input.projectId}/members`,\n body,\n );\n const parsed = InviteCreatedSchema.safeParse(raw);\n if (!parsed.success) {\n // Try MemberSchema in case the server returned a member-only response\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async issueToken(input: {\n projectId: string;\n memberId: string;\n name: string;\n expiresAt?: string;\n }): Promise<TokenIssued> {\n const body: Record<string, unknown> = {\n member_id: input.memberId,\n name: input.name,\n };\n if (input.expiresAt !== undefined) {\n body['expires_at'] = input.expiresAt;\n }\n const raw = await this.request<unknown>(\n 'POST',\n `/projects/${input.projectId}/tokens`,\n body,\n );\n const parsed = TokenIssuedSchema.safeParse(raw);\n if (!parsed.success) {\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async revokeToken(input: { tokenId: string }): Promise<void> {\n // No body — Content-Type must be omitted (Fastify 5 CTP quirk)\n await this.request<unknown>('DELETE', `/tokens/${input.tokenId}`, undefined);\n }\n}\n\nexport function createAdminApiClient(opts: AdminApiClientOptions): AdminApiClient {\n return new AdminApiClientImpl(opts);\n}\n","/**\n * Loads an admin JWT for use with cleargate-admin CLI commands.\n *\n * Load order:\n * 1. CLEARGATE_ADMIN_TOKEN env var (wins immediately — file is not read)\n * 2. ~/.cleargate/admin-auth.json (shape: { version: 1, token: string })\n *\n * DISTINCT from FileTokenStore: that file holds user profile → refresh-token maps.\n * This file holds a single admin JWT acquired out-of-band via dev-issue-token.\n */\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { z } from 'zod';\n\nexport const AdminAuthFileSchema = z\n .object({\n version: z.literal(1),\n token: z.string().min(1),\n })\n .strict();\n\nexport interface LoadAdminAuthOptions {\n env?: NodeJS.ProcessEnv;\n filePath?: string;\n homedir?: () => string;\n warn?: (msg: string) => void;\n}\n\nexport interface AdminAuth {\n token: string;\n source: 'env' | 'file';\n}\n\nconst MISSING_TOKEN_ERROR =\n 'No admin token. Set CLEARGATE_ADMIN_TOKEN or write ~/.cleargate/admin-auth.json (chmod 600). See README §admin-jwt.';\n\nexport function loadAdminAuth(opts?: LoadAdminAuthOptions): AdminAuth {\n const env = opts?.env ?? process.env;\n const warn = opts?.warn ?? ((msg: string) => process.stderr.write(msg + '\\n'));\n\n // Env wins — file is not read at all when env is set\n const envToken = env['CLEARGATE_ADMIN_TOKEN'];\n if (envToken) {\n return { token: envToken, source: 'env' };\n }\n\n // Resolve file path\n const homedirFn = opts?.homedir ?? os.homedir;\n const filePath =\n opts?.filePath ?? path.join(homedirFn(), '.cleargate', 'admin-auth.json');\n\n // Try file\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf8');\n } catch (err) {\n if (err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error(MISSING_TOKEN_ERROR);\n }\n throw new Error(`Failed to read admin-auth file at ${filePath}: ${String(err)}`);\n }\n\n // Check file permissions (warn if too permissive)\n try {\n const stat = fs.statSync(filePath);\n const mode = stat.mode & 0o777;\n if (mode & 0o077) {\n warn(\n `cleargate-admin: warning: ${filePath} is group/world readable (mode ${(mode).toString(8).padStart(3, '0')}). Run: chmod 600 ${filePath}`,\n );\n }\n } catch {\n // If we can't stat the file, ignore — the read already succeeded\n }\n\n // Parse JSON\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(`Failed to parse admin-auth file at ${filePath}: invalid JSON`);\n }\n\n // Validate with strict schema\n const result = AdminAuthFileSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(\n `Invalid admin-auth file at ${filePath}: ${result.error.message}`,\n );\n }\n\n return { token: result.data.token, source: 'file' };\n}\n"],"mappings":"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","names":["path","import_zod"]}
@@ -47,6 +47,7 @@ declare const InviteCreatedSchema: z.ZodObject<{
47
47
  invite_url: z.ZodString;
48
48
  invite_token: z.ZodString;
49
49
  invite_expires_in: z.ZodNumber;
50
+ mail_sent: z.ZodBoolean;
50
51
  }, z.core.$strict>;
51
52
  type InviteCreated = z.infer<typeof InviteCreatedSchema>;
52
53
  declare const TokenMetaSchema: z.ZodObject<{
@@ -47,6 +47,7 @@ declare const InviteCreatedSchema: z.ZodObject<{
47
47
  invite_url: z.ZodString;
48
48
  invite_token: z.ZodString;
49
49
  invite_expires_in: z.ZodNumber;
50
+ mail_sent: z.ZodBoolean;
50
51
  }, z.core.$strict>;
51
52
  type InviteCreated = z.infer<typeof InviteCreatedSchema>;
52
53
  declare const TokenMetaSchema: z.ZodObject<{
@@ -36,7 +36,9 @@ var InviteCreatedSchema = z.object({
36
36
  member: MemberSchema,
37
37
  invite_url: z.string(),
38
38
  invite_token: z.string(),
39
- invite_expires_in: z.number().int()
39
+ invite_expires_in: z.number().int(),
40
+ /** Whether the invite email was sent successfully (CR-062) */
41
+ mail_sent: z.boolean()
40
42
  }).strict();
41
43
  var TokenMetaSchema = z.object({
42
44
  id: z.string(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/admin-api/errors.ts","../../src/admin-api/responses.ts","../../src/admin-api/redact.ts","../../src/admin-api/client.ts","../../src/admin-api/admin-auth.ts"],"sourcesContent":["/**\n * Typed error class for all admin API failures.\n * kind → exit code mapping lives in mcp/scripts/commands/_render-error.ts\n */\nexport class AdminApiError extends Error {\n constructor(\n public readonly kind:\n | 'network'\n | 'auth'\n | 'forbidden'\n | 'not_found'\n | 'invalid_request'\n | 'server'\n | 'response_shape',\n public readonly status: number | null,\n public readonly details: unknown,\n message: string,\n ) {\n super(message);\n this.name = 'AdminApiError';\n }\n}\n","/**\n * Vendored Zod response schemas — hand-authored from\n * mcp/src/admin-api/__snapshots__/openapi.test.ts.snap\n *\n * Snapshot drift is detected by cleargate-cli/test/admin-api/snapshot-drift.test.ts,\n * which reads the snapshot file at runtime and asserts field-set equality.\n */\nimport { z } from 'zod';\n\nexport const ProjectSchema = z\n .object({\n id: z.string(),\n name: z.string(),\n created_by: z.string(),\n created_at: z.string(),\n deleted_at: z.string().nullable(),\n })\n .strict();\n\nexport type Project = z.infer<typeof ProjectSchema>;\n\nexport const MemberSchema = z\n .object({\n id: z.string(),\n project_id: z.string(),\n email: z.string(),\n role: z.string(),\n display_name: z.string().nullable().optional(),\n created_at: z.string(),\n status: z.enum(['pending', 'active', 'expired']),\n })\n .strict();\n\nexport type Member = z.infer<typeof MemberSchema>;\n\nexport const InviteCreatedSchema = z\n .object({\n member: MemberSchema,\n invite_url: z.string(),\n invite_token: z.string(),\n invite_expires_in: z.number().int(),\n })\n .strict();\n\nexport type InviteCreated = z.infer<typeof InviteCreatedSchema>;\n\nexport const TokenMetaSchema = z\n .object({\n id: z.string(),\n member_id: z.string(),\n name: z.string(),\n created_at: z.string(),\n expires_at: z.string().nullable().optional(),\n last_used_at: z.string().nullable().optional(),\n revoked_at: z.string().nullable().optional(),\n })\n .strict();\n\nexport type TokenMeta = z.infer<typeof TokenMetaSchema>;\n\n// TokenIssued = TokenMeta + plaintext token field (returned exactly once)\nexport const TokenIssuedSchema = z\n .object({\n id: z.string(),\n member_id: z.string(),\n name: z.string(),\n created_at: z.string(),\n expires_at: z.string().nullable().optional(),\n last_used_at: z.string().nullable().optional(),\n revoked_at: z.string().nullable().optional(),\n token: z.string(),\n })\n .strict();\n\nexport type TokenIssued = z.infer<typeof TokenIssuedSchema>;\n\nexport const AuthExchangeResponseSchema = z\n .object({\n admin_token: z.string(),\n expires_at: z.string(),\n })\n .strict();\n\nexport type AuthExchangeResponse = z.infer<typeof AuthExchangeResponseSchema>;\n\nexport const ErrorBodySchema = z\n .object({\n error: z.string(),\n details: z.record(z.string(), z.unknown()).optional(),\n })\n .strict();\n\nexport type ErrorBody = z.infer<typeof ErrorBodySchema>;\n\n// ── Items admin API (STORY-004-09) ───────────────────────────────────────────\n\nexport const ItemSummarySchema = z\n .object({\n id: z.string(),\n cleargate_id: z.string(),\n type: z.string(),\n title: z.string(),\n status: z.string(),\n remote_id: z.string().nullable(),\n last_pushed_at: z.string().nullable(),\n pushed_by_member_id: z.string().nullable(),\n version: z.number().int(),\n updated_at: z.string(),\n current_payload: z.record(z.string(), z.unknown()).default({}),\n })\n .strict();\n\nexport type ItemSummary = z.infer<typeof ItemSummarySchema>;\n\nexport const ItemsListResponseSchema = z\n .object({\n items: z.array(ItemSummarySchema),\n next_cursor: z.string().nullable(),\n })\n .strict();\n\nexport type ItemsListResponse = z.infer<typeof ItemsListResponseSchema>;\n\nexport const ItemVersionSchema = z\n .object({\n version: z.number().int(),\n pushed_by_member_id: z.string().nullable(),\n pushed_at: z.string(),\n status: z.string(),\n diff_summary: z.string().nullable(),\n })\n .strict();\n\nexport type ItemVersion = z.infer<typeof ItemVersionSchema>;\n\nexport const ItemVersionsResponseSchema = z\n .object({\n versions: z.array(ItemVersionSchema),\n })\n .strict();\n\nexport type ItemVersionsResponse = z.infer<typeof ItemVersionsResponseSchema>;\n\n// ── Device-flow schemas (STORY-005-06) ───────────────────────────────────────\n\nexport const DeviceStartResponseSchema = z\n .object({\n device_code: z.string(),\n user_code: z.string(),\n verification_uri: z.string(),\n expires_in: z.number().int(),\n interval: z.number().int(),\n })\n .strict();\n\nexport type DeviceStartResponse = z.infer<typeof DeviceStartResponseSchema>;\n\nexport const DevicePollPendingResponseSchema = z\n .object({\n pending: z.literal(true),\n retry_after: z.number().int().optional(),\n })\n .strict();\n\nexport type DevicePollPendingResponse = z.infer<typeof DevicePollPendingResponseSchema>;\n\nexport const DevicePollSuccessResponseSchema = z\n .object({\n pending: z.literal(false),\n admin_token: z.string(),\n expires_at: z.string(),\n admin_user_id: z.string(),\n })\n .strict();\n\nexport type DevicePollSuccessResponse = z.infer<typeof DevicePollSuccessResponseSchema>;\n\n// ── Admin users API (STORY-006-09) ───────────────────────────────────────────\n\nexport const AdminUserSchema = z\n .object({\n id: z.string(),\n github_handle: z.string(),\n github_user_id: z.string().nullable(),\n is_root: z.boolean(),\n disabled_at: z.string().nullable(),\n created_at: z.string(),\n created_by: z.string().nullable(),\n })\n .strict();\n\nexport type AdminUser = z.infer<typeof AdminUserSchema>;\n\nexport const AdminUsersListResponseSchema = z\n .object({\n admin_users: z.array(AdminUserSchema),\n })\n .strict();\n\nexport type AdminUsersListResponse = z.infer<typeof AdminUsersListResponseSchema>;\n\nexport const UsersMeResponseSchema = z\n .object({\n id: z.string(),\n github_handle: z.string(),\n is_root: z.boolean(),\n })\n .strict();\n\nexport type UsersMeResponse = z.infer<typeof UsersMeResponseSchema>;\n","/**\n * Recursively replaces sensitive key values with '<redacted>'.\n * Used in debug log paths — never in success output.\n * Keys stripped: token, refresh_token, invite_token\n */\nconst SENSITIVE_KEYS = new Set(['token', 'refresh_token', 'invite_token']);\n\nexport function redactSensitive(obj: unknown): unknown {\n if (Array.isArray(obj)) {\n return obj.map((item) => redactSensitive(item));\n }\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (SENSITIVE_KEYS.has(key)) {\n result[key] = '<redacted>';\n } else {\n result[key] = redactSensitive(value);\n }\n }\n return result;\n }\n return obj;\n}\n","/**\n * AdminApiClient — typed HTTP client for the ClearGate admin API.\n *\n * Key implementation notes:\n * - CLI method args are camelCase; wire bodies are snake_case (converted internally)\n * - DELETE requests MUST omit Content-Type (Fastify 5 FST_ERR_CTP_EMPTY_JSON_BODY)\n * - All 2xx responses are validated through vendored Zod schemas\n * - Errors map to AdminApiError with kind → exit code table in D6\n */\nimport { AdminApiError } from './errors.js';\nimport {\n ProjectSchema,\n InviteCreatedSchema,\n TokenIssuedSchema,\n type Project,\n type InviteCreated,\n type TokenIssued,\n} from './responses.js';\nimport { redactSensitive } from './redact.js';\n\nexport interface AdminApiClientOptions {\n baseUrl: string;\n token: string;\n fetch?: typeof globalThis.fetch;\n warn?: (msg: string) => void;\n userAgent?: string;\n}\n\nexport interface AdminApiClient {\n createProject(input: { name: string }): Promise<Project>;\n inviteMember(input: {\n projectId: string;\n email: string;\n role: 'user' | 'service';\n displayName?: string;\n }): Promise<InviteCreated>;\n issueToken(input: {\n projectId: string;\n memberId: string;\n name: string;\n expiresAt?: string;\n }): Promise<TokenIssued>;\n revokeToken(input: { tokenId: string }): Promise<void>;\n}\n\nfunction defaultWarn(msg: string): void {\n process.stderr.write(msg + '\\n');\n}\n\nclass AdminApiClientImpl implements AdminApiClient {\n private readonly baseUrl: string;\n private readonly token: string;\n private readonly fetchFn: typeof globalThis.fetch;\n private readonly warn: (msg: string) => void;\n private readonly userAgent: string;\n\n constructor(opts: AdminApiClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '');\n this.token = opts.token;\n this.fetchFn = opts.fetch ?? globalThis.fetch;\n this.warn = opts.warn ?? defaultWarn;\n this.userAgent = opts.userAgent ?? `cleargate`;\n }\n\n private debugLog(method: string, path: string, status: number, body: unknown): void {\n if (process.env['CLEARGATE_LOG_LEVEL'] === 'debug') {\n const redacted = redactSensitive(body);\n this.warn(`[admin-api] ${method} ${path} → ${status} ${JSON.stringify(redacted)}`);\n }\n }\n\n private async request<T>(\n method: string,\n urlPath: string,\n body?: Record<string, unknown>,\n ): Promise<T> {\n const url = `${this.baseUrl}/admin-api/v1${urlPath}`;\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.token}`,\n 'User-Agent': this.userAgent,\n Accept: 'application/json',\n };\n\n // CRITICAL: omit Content-Type on requests without body (DELETE)\n // Fastify 5 throws FST_ERR_CTP_EMPTY_JSON_BODY if Content-Type is set with empty body\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n let response: Response;\n try {\n response = await this.fetchFn(url, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n } catch (err) {\n throw new AdminApiError(\n 'network',\n null,\n err,\n `cannot reach ${this.baseUrl} (${err instanceof Error ? err.message : String(err)})`,\n );\n }\n\n // Parse response body when present\n let responseBody: unknown = null;\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n try {\n responseBody = await response.json();\n } catch {\n responseBody = null;\n }\n }\n\n this.debugLog(method, urlPath, response.status, responseBody);\n\n // Map HTTP status to AdminApiError kinds\n if (!response.ok) {\n const errBody = responseBody as { error?: string; details?: unknown } | null;\n if (response.status === 401) {\n throw new AdminApiError('auth', 401, responseBody, 'Admin token rejected.');\n }\n if (response.status === 403) {\n throw new AdminApiError('forbidden', 403, responseBody, 'Token is not admin-role.');\n }\n if (response.status === 404) {\n throw new AdminApiError('not_found', 404, responseBody, 'Not found.');\n }\n if (response.status === 400 || response.status === 409) {\n throw new AdminApiError(\n 'invalid_request',\n response.status,\n errBody?.details ?? responseBody,\n `Invalid request: ${errBody?.error ?? 'unknown'}`,\n );\n }\n if (response.status >= 500) {\n throw new AdminApiError(\n 'server',\n response.status,\n responseBody,\n `Server error ${response.status}.`,\n );\n }\n throw new AdminApiError(\n 'server',\n response.status,\n responseBody,\n `Unexpected status ${response.status}.`,\n );\n }\n\n return responseBody as T;\n }\n\n async createProject(input: { name: string }): Promise<Project> {\n const raw = await this.request<unknown>('POST', '/projects', { name: input.name });\n const parsed = ProjectSchema.safeParse(raw);\n if (!parsed.success) {\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async inviteMember(input: {\n projectId: string;\n email: string;\n role: 'user' | 'service';\n displayName?: string;\n }): Promise<InviteCreated> {\n const body: Record<string, unknown> = {\n email: input.email,\n role: input.role,\n };\n if (input.displayName !== undefined) {\n body['display_name'] = input.displayName;\n }\n const raw = await this.request<unknown>(\n 'POST',\n `/projects/${input.projectId}/members`,\n body,\n );\n const parsed = InviteCreatedSchema.safeParse(raw);\n if (!parsed.success) {\n // Try MemberSchema in case the server returned a member-only response\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async issueToken(input: {\n projectId: string;\n memberId: string;\n name: string;\n expiresAt?: string;\n }): Promise<TokenIssued> {\n const body: Record<string, unknown> = {\n member_id: input.memberId,\n name: input.name,\n };\n if (input.expiresAt !== undefined) {\n body['expires_at'] = input.expiresAt;\n }\n const raw = await this.request<unknown>(\n 'POST',\n `/projects/${input.projectId}/tokens`,\n body,\n );\n const parsed = TokenIssuedSchema.safeParse(raw);\n if (!parsed.success) {\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async revokeToken(input: { tokenId: string }): Promise<void> {\n // No body — Content-Type must be omitted (Fastify 5 CTP quirk)\n await this.request<unknown>('DELETE', `/tokens/${input.tokenId}`, undefined);\n }\n}\n\nexport function createAdminApiClient(opts: AdminApiClientOptions): AdminApiClient {\n return new AdminApiClientImpl(opts);\n}\n","/**\n * Loads an admin JWT for use with cleargate-admin CLI commands.\n *\n * Load order:\n * 1. CLEARGATE_ADMIN_TOKEN env var (wins immediately — file is not read)\n * 2. ~/.cleargate/admin-auth.json (shape: { version: 1, token: string })\n *\n * DISTINCT from FileTokenStore: that file holds user profile → refresh-token maps.\n * This file holds a single admin JWT acquired out-of-band via dev-issue-token.\n */\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { z } from 'zod';\n\nexport const AdminAuthFileSchema = z\n .object({\n version: z.literal(1),\n token: z.string().min(1),\n })\n .strict();\n\nexport interface LoadAdminAuthOptions {\n env?: NodeJS.ProcessEnv;\n filePath?: string;\n homedir?: () => string;\n warn?: (msg: string) => void;\n}\n\nexport interface AdminAuth {\n token: string;\n source: 'env' | 'file';\n}\n\nconst MISSING_TOKEN_ERROR =\n 'No admin token. Set CLEARGATE_ADMIN_TOKEN or write ~/.cleargate/admin-auth.json (chmod 600). See README §admin-jwt.';\n\nexport function loadAdminAuth(opts?: LoadAdminAuthOptions): AdminAuth {\n const env = opts?.env ?? process.env;\n const warn = opts?.warn ?? ((msg: string) => process.stderr.write(msg + '\\n'));\n\n // Env wins — file is not read at all when env is set\n const envToken = env['CLEARGATE_ADMIN_TOKEN'];\n if (envToken) {\n return { token: envToken, source: 'env' };\n }\n\n // Resolve file path\n const homedirFn = opts?.homedir ?? os.homedir;\n const filePath =\n opts?.filePath ?? path.join(homedirFn(), '.cleargate', 'admin-auth.json');\n\n // Try file\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf8');\n } catch (err) {\n if (err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error(MISSING_TOKEN_ERROR);\n }\n throw new Error(`Failed to read admin-auth file at ${filePath}: ${String(err)}`);\n }\n\n // Check file permissions (warn if too permissive)\n try {\n const stat = fs.statSync(filePath);\n const mode = stat.mode & 0o777;\n if (mode & 0o077) {\n warn(\n `cleargate-admin: warning: ${filePath} is group/world readable (mode ${(mode).toString(8).padStart(3, '0')}). Run: chmod 600 ${filePath}`,\n );\n }\n } catch {\n // If we can't stat the file, ignore — the read already succeeded\n }\n\n // Parse JSON\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(`Failed to parse admin-auth file at ${filePath}: invalid JSON`);\n }\n\n // Validate with strict schema\n const result = AdminAuthFileSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(\n `Invalid admin-auth file at ${filePath}: ${result.error.message}`,\n );\n }\n\n return { token: result.data.token, source: 'file' };\n}\n"],"mappings":"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","names":["path","z"]}
1
+ {"version":3,"sources":["../../src/admin-api/errors.ts","../../src/admin-api/responses.ts","../../src/admin-api/redact.ts","../../src/admin-api/client.ts","../../src/admin-api/admin-auth.ts"],"sourcesContent":["/**\n * Typed error class for all admin API failures.\n * kind → exit code mapping lives in mcp/scripts/commands/_render-error.ts\n */\nexport class AdminApiError extends Error {\n constructor(\n public readonly kind:\n | 'network'\n | 'auth'\n | 'forbidden'\n | 'not_found'\n | 'invalid_request'\n | 'server'\n | 'response_shape',\n public readonly status: number | null,\n public readonly details: unknown,\n message: string,\n ) {\n super(message);\n this.name = 'AdminApiError';\n }\n}\n","/**\n * Vendored Zod response schemas — hand-authored from\n * mcp/src/admin-api/__snapshots__/openapi.test.ts.snap\n *\n * Snapshot drift is detected by cleargate-cli/test/admin-api/snapshot-drift.test.ts,\n * which reads the snapshot file at runtime and asserts field-set equality.\n */\nimport { z } from 'zod';\n\nexport const ProjectSchema = z\n .object({\n id: z.string(),\n name: z.string(),\n created_by: z.string(),\n created_at: z.string(),\n deleted_at: z.string().nullable(),\n })\n .strict();\n\nexport type Project = z.infer<typeof ProjectSchema>;\n\nexport const MemberSchema = z\n .object({\n id: z.string(),\n project_id: z.string(),\n email: z.string(),\n role: z.string(),\n display_name: z.string().nullable().optional(),\n created_at: z.string(),\n status: z.enum(['pending', 'active', 'expired']),\n })\n .strict();\n\nexport type Member = z.infer<typeof MemberSchema>;\n\nexport const InviteCreatedSchema = z\n .object({\n member: MemberSchema,\n invite_url: z.string(),\n invite_token: z.string(),\n invite_expires_in: z.number().int(),\n /** Whether the invite email was sent successfully (CR-062) */\n mail_sent: z.boolean(),\n })\n .strict();\n\nexport type InviteCreated = z.infer<typeof InviteCreatedSchema>;\n\nexport const TokenMetaSchema = z\n .object({\n id: z.string(),\n member_id: z.string(),\n name: z.string(),\n created_at: z.string(),\n expires_at: z.string().nullable().optional(),\n last_used_at: z.string().nullable().optional(),\n revoked_at: z.string().nullable().optional(),\n })\n .strict();\n\nexport type TokenMeta = z.infer<typeof TokenMetaSchema>;\n\n// TokenIssued = TokenMeta + plaintext token field (returned exactly once)\nexport const TokenIssuedSchema = z\n .object({\n id: z.string(),\n member_id: z.string(),\n name: z.string(),\n created_at: z.string(),\n expires_at: z.string().nullable().optional(),\n last_used_at: z.string().nullable().optional(),\n revoked_at: z.string().nullable().optional(),\n token: z.string(),\n })\n .strict();\n\nexport type TokenIssued = z.infer<typeof TokenIssuedSchema>;\n\nexport const AuthExchangeResponseSchema = z\n .object({\n admin_token: z.string(),\n expires_at: z.string(),\n })\n .strict();\n\nexport type AuthExchangeResponse = z.infer<typeof AuthExchangeResponseSchema>;\n\nexport const ErrorBodySchema = z\n .object({\n error: z.string(),\n details: z.record(z.string(), z.unknown()).optional(),\n })\n .strict();\n\nexport type ErrorBody = z.infer<typeof ErrorBodySchema>;\n\n// ── Items admin API (STORY-004-09) ───────────────────────────────────────────\n\nexport const ItemSummarySchema = z\n .object({\n id: z.string(),\n cleargate_id: z.string(),\n type: z.string(),\n title: z.string(),\n status: z.string(),\n remote_id: z.string().nullable(),\n last_pushed_at: z.string().nullable(),\n pushed_by_member_id: z.string().nullable(),\n version: z.number().int(),\n updated_at: z.string(),\n current_payload: z.record(z.string(), z.unknown()).default({}),\n })\n .strict();\n\nexport type ItemSummary = z.infer<typeof ItemSummarySchema>;\n\nexport const ItemsListResponseSchema = z\n .object({\n items: z.array(ItemSummarySchema),\n next_cursor: z.string().nullable(),\n })\n .strict();\n\nexport type ItemsListResponse = z.infer<typeof ItemsListResponseSchema>;\n\nexport const ItemVersionSchema = z\n .object({\n version: z.number().int(),\n pushed_by_member_id: z.string().nullable(),\n pushed_at: z.string(),\n status: z.string(),\n diff_summary: z.string().nullable(),\n })\n .strict();\n\nexport type ItemVersion = z.infer<typeof ItemVersionSchema>;\n\nexport const ItemVersionsResponseSchema = z\n .object({\n versions: z.array(ItemVersionSchema),\n })\n .strict();\n\nexport type ItemVersionsResponse = z.infer<typeof ItemVersionsResponseSchema>;\n\n// ── Device-flow schemas (STORY-005-06) ───────────────────────────────────────\n\nexport const DeviceStartResponseSchema = z\n .object({\n device_code: z.string(),\n user_code: z.string(),\n verification_uri: z.string(),\n expires_in: z.number().int(),\n interval: z.number().int(),\n })\n .strict();\n\nexport type DeviceStartResponse = z.infer<typeof DeviceStartResponseSchema>;\n\nexport const DevicePollPendingResponseSchema = z\n .object({\n pending: z.literal(true),\n retry_after: z.number().int().optional(),\n })\n .strict();\n\nexport type DevicePollPendingResponse = z.infer<typeof DevicePollPendingResponseSchema>;\n\nexport const DevicePollSuccessResponseSchema = z\n .object({\n pending: z.literal(false),\n admin_token: z.string(),\n expires_at: z.string(),\n admin_user_id: z.string(),\n })\n .strict();\n\nexport type DevicePollSuccessResponse = z.infer<typeof DevicePollSuccessResponseSchema>;\n\n// ── Admin users API (STORY-006-09) ───────────────────────────────────────────\n\nexport const AdminUserSchema = z\n .object({\n id: z.string(),\n github_handle: z.string(),\n github_user_id: z.string().nullable(),\n is_root: z.boolean(),\n disabled_at: z.string().nullable(),\n created_at: z.string(),\n created_by: z.string().nullable(),\n })\n .strict();\n\nexport type AdminUser = z.infer<typeof AdminUserSchema>;\n\nexport const AdminUsersListResponseSchema = z\n .object({\n admin_users: z.array(AdminUserSchema),\n })\n .strict();\n\nexport type AdminUsersListResponse = z.infer<typeof AdminUsersListResponseSchema>;\n\nexport const UsersMeResponseSchema = z\n .object({\n id: z.string(),\n github_handle: z.string(),\n is_root: z.boolean(),\n })\n .strict();\n\nexport type UsersMeResponse = z.infer<typeof UsersMeResponseSchema>;\n","/**\n * Recursively replaces sensitive key values with '<redacted>'.\n * Used in debug log paths — never in success output.\n * Keys stripped: token, refresh_token, invite_token\n */\nconst SENSITIVE_KEYS = new Set(['token', 'refresh_token', 'invite_token']);\n\nexport function redactSensitive(obj: unknown): unknown {\n if (Array.isArray(obj)) {\n return obj.map((item) => redactSensitive(item));\n }\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (SENSITIVE_KEYS.has(key)) {\n result[key] = '<redacted>';\n } else {\n result[key] = redactSensitive(value);\n }\n }\n return result;\n }\n return obj;\n}\n","/**\n * AdminApiClient — typed HTTP client for the ClearGate admin API.\n *\n * Key implementation notes:\n * - CLI method args are camelCase; wire bodies are snake_case (converted internally)\n * - DELETE requests MUST omit Content-Type (Fastify 5 FST_ERR_CTP_EMPTY_JSON_BODY)\n * - All 2xx responses are validated through vendored Zod schemas\n * - Errors map to AdminApiError with kind → exit code table in D6\n */\nimport { AdminApiError } from './errors.js';\nimport {\n ProjectSchema,\n InviteCreatedSchema,\n TokenIssuedSchema,\n type Project,\n type InviteCreated,\n type TokenIssued,\n} from './responses.js';\nimport { redactSensitive } from './redact.js';\n\nexport interface AdminApiClientOptions {\n baseUrl: string;\n token: string;\n fetch?: typeof globalThis.fetch;\n warn?: (msg: string) => void;\n userAgent?: string;\n}\n\nexport interface AdminApiClient {\n createProject(input: { name: string }): Promise<Project>;\n inviteMember(input: {\n projectId: string;\n email: string;\n role: 'user' | 'service';\n displayName?: string;\n }): Promise<InviteCreated>;\n issueToken(input: {\n projectId: string;\n memberId: string;\n name: string;\n expiresAt?: string;\n }): Promise<TokenIssued>;\n revokeToken(input: { tokenId: string }): Promise<void>;\n}\n\nfunction defaultWarn(msg: string): void {\n process.stderr.write(msg + '\\n');\n}\n\nclass AdminApiClientImpl implements AdminApiClient {\n private readonly baseUrl: string;\n private readonly token: string;\n private readonly fetchFn: typeof globalThis.fetch;\n private readonly warn: (msg: string) => void;\n private readonly userAgent: string;\n\n constructor(opts: AdminApiClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, '');\n this.token = opts.token;\n this.fetchFn = opts.fetch ?? globalThis.fetch;\n this.warn = opts.warn ?? defaultWarn;\n this.userAgent = opts.userAgent ?? `cleargate`;\n }\n\n private debugLog(method: string, path: string, status: number, body: unknown): void {\n if (process.env['CLEARGATE_LOG_LEVEL'] === 'debug') {\n const redacted = redactSensitive(body);\n this.warn(`[admin-api] ${method} ${path} → ${status} ${JSON.stringify(redacted)}`);\n }\n }\n\n private async request<T>(\n method: string,\n urlPath: string,\n body?: Record<string, unknown>,\n ): Promise<T> {\n const url = `${this.baseUrl}/admin-api/v1${urlPath}`;\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.token}`,\n 'User-Agent': this.userAgent,\n Accept: 'application/json',\n };\n\n // CRITICAL: omit Content-Type on requests without body (DELETE)\n // Fastify 5 throws FST_ERR_CTP_EMPTY_JSON_BODY if Content-Type is set with empty body\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n let response: Response;\n try {\n response = await this.fetchFn(url, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n } catch (err) {\n throw new AdminApiError(\n 'network',\n null,\n err,\n `cannot reach ${this.baseUrl} (${err instanceof Error ? err.message : String(err)})`,\n );\n }\n\n // Parse response body when present\n let responseBody: unknown = null;\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n try {\n responseBody = await response.json();\n } catch {\n responseBody = null;\n }\n }\n\n this.debugLog(method, urlPath, response.status, responseBody);\n\n // Map HTTP status to AdminApiError kinds\n if (!response.ok) {\n const errBody = responseBody as { error?: string; details?: unknown } | null;\n if (response.status === 401) {\n throw new AdminApiError('auth', 401, responseBody, 'Admin token rejected.');\n }\n if (response.status === 403) {\n throw new AdminApiError('forbidden', 403, responseBody, 'Token is not admin-role.');\n }\n if (response.status === 404) {\n throw new AdminApiError('not_found', 404, responseBody, 'Not found.');\n }\n if (response.status === 400 || response.status === 409) {\n throw new AdminApiError(\n 'invalid_request',\n response.status,\n errBody?.details ?? responseBody,\n `Invalid request: ${errBody?.error ?? 'unknown'}`,\n );\n }\n if (response.status >= 500) {\n throw new AdminApiError(\n 'server',\n response.status,\n responseBody,\n `Server error ${response.status}.`,\n );\n }\n throw new AdminApiError(\n 'server',\n response.status,\n responseBody,\n `Unexpected status ${response.status}.`,\n );\n }\n\n return responseBody as T;\n }\n\n async createProject(input: { name: string }): Promise<Project> {\n const raw = await this.request<unknown>('POST', '/projects', { name: input.name });\n const parsed = ProjectSchema.safeParse(raw);\n if (!parsed.success) {\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async inviteMember(input: {\n projectId: string;\n email: string;\n role: 'user' | 'service';\n displayName?: string;\n }): Promise<InviteCreated> {\n const body: Record<string, unknown> = {\n email: input.email,\n role: input.role,\n };\n if (input.displayName !== undefined) {\n body['display_name'] = input.displayName;\n }\n const raw = await this.request<unknown>(\n 'POST',\n `/projects/${input.projectId}/members`,\n body,\n );\n const parsed = InviteCreatedSchema.safeParse(raw);\n if (!parsed.success) {\n // Try MemberSchema in case the server returned a member-only response\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async issueToken(input: {\n projectId: string;\n memberId: string;\n name: string;\n expiresAt?: string;\n }): Promise<TokenIssued> {\n const body: Record<string, unknown> = {\n member_id: input.memberId,\n name: input.name,\n };\n if (input.expiresAt !== undefined) {\n body['expires_at'] = input.expiresAt;\n }\n const raw = await this.request<unknown>(\n 'POST',\n `/projects/${input.projectId}/tokens`,\n body,\n );\n const parsed = TokenIssuedSchema.safeParse(raw);\n if (!parsed.success) {\n throw new AdminApiError(\n 'response_shape',\n null,\n parsed.error,\n 'Server returned unexpected response shape (CLI may be out of date).',\n );\n }\n return parsed.data;\n }\n\n async revokeToken(input: { tokenId: string }): Promise<void> {\n // No body — Content-Type must be omitted (Fastify 5 CTP quirk)\n await this.request<unknown>('DELETE', `/tokens/${input.tokenId}`, undefined);\n }\n}\n\nexport function createAdminApiClient(opts: AdminApiClientOptions): AdminApiClient {\n return new AdminApiClientImpl(opts);\n}\n","/**\n * Loads an admin JWT for use with cleargate-admin CLI commands.\n *\n * Load order:\n * 1. CLEARGATE_ADMIN_TOKEN env var (wins immediately — file is not read)\n * 2. ~/.cleargate/admin-auth.json (shape: { version: 1, token: string })\n *\n * DISTINCT from FileTokenStore: that file holds user profile → refresh-token maps.\n * This file holds a single admin JWT acquired out-of-band via dev-issue-token.\n */\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { z } from 'zod';\n\nexport const AdminAuthFileSchema = z\n .object({\n version: z.literal(1),\n token: z.string().min(1),\n })\n .strict();\n\nexport interface LoadAdminAuthOptions {\n env?: NodeJS.ProcessEnv;\n filePath?: string;\n homedir?: () => string;\n warn?: (msg: string) => void;\n}\n\nexport interface AdminAuth {\n token: string;\n source: 'env' | 'file';\n}\n\nconst MISSING_TOKEN_ERROR =\n 'No admin token. Set CLEARGATE_ADMIN_TOKEN or write ~/.cleargate/admin-auth.json (chmod 600). See README §admin-jwt.';\n\nexport function loadAdminAuth(opts?: LoadAdminAuthOptions): AdminAuth {\n const env = opts?.env ?? process.env;\n const warn = opts?.warn ?? ((msg: string) => process.stderr.write(msg + '\\n'));\n\n // Env wins — file is not read at all when env is set\n const envToken = env['CLEARGATE_ADMIN_TOKEN'];\n if (envToken) {\n return { token: envToken, source: 'env' };\n }\n\n // Resolve file path\n const homedirFn = opts?.homedir ?? os.homedir;\n const filePath =\n opts?.filePath ?? path.join(homedirFn(), '.cleargate', 'admin-auth.json');\n\n // Try file\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf8');\n } catch (err) {\n if (err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error(MISSING_TOKEN_ERROR);\n }\n throw new Error(`Failed to read admin-auth file at ${filePath}: ${String(err)}`);\n }\n\n // Check file permissions (warn if too permissive)\n try {\n const stat = fs.statSync(filePath);\n const mode = stat.mode & 0o777;\n if (mode & 0o077) {\n warn(\n `cleargate-admin: warning: ${filePath} is group/world readable (mode ${(mode).toString(8).padStart(3, '0')}). Run: chmod 600 ${filePath}`,\n );\n }\n } catch {\n // If we can't stat the file, ignore — the read already succeeded\n }\n\n // Parse JSON\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(`Failed to parse admin-auth file at ${filePath}: invalid JSON`);\n }\n\n // Validate with strict schema\n const result = AdminAuthFileSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(\n `Invalid admin-auth file at ${filePath}: ${result.error.message}`,\n );\n }\n\n return { token: result.data.token, source: 'file' };\n}\n"],"mappings":"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","names":["path","z"]}