@praxis.guard/auditor-cli 0.0.1

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 (131) hide show
  1. package/README.md +46 -0
  2. package/dist/audit/jsonl.d.ts +7 -0
  3. package/dist/audit/jsonl.d.ts.map +1 -0
  4. package/dist/audit/jsonl.js +16 -0
  5. package/dist/audit/jsonl.js.map +1 -0
  6. package/dist/bridge/shell-approval-bridge.d.ts +28 -0
  7. package/dist/bridge/shell-approval-bridge.d.ts.map +1 -0
  8. package/dist/bridge/shell-approval-bridge.js +63 -0
  9. package/dist/bridge/shell-approval-bridge.js.map +1 -0
  10. package/dist/cli/callable-fetch.d.ts +8 -0
  11. package/dist/cli/callable-fetch.d.ts.map +1 -0
  12. package/dist/cli/callable-fetch.js +30 -0
  13. package/dist/cli/callable-fetch.js.map +1 -0
  14. package/dist/cli/credentials.d.ts +10 -0
  15. package/dist/cli/credentials.d.ts.map +1 -0
  16. package/dist/cli/credentials.js +53 -0
  17. package/dist/cli/credentials.js.map +1 -0
  18. package/dist/cli/cursor-config.d.ts +16 -0
  19. package/dist/cli/cursor-config.d.ts.map +1 -0
  20. package/dist/cli/cursor-config.js +153 -0
  21. package/dist/cli/cursor-config.js.map +1 -0
  22. package/dist/cli/doctor.d.ts +2 -0
  23. package/dist/cli/doctor.d.ts.map +1 -0
  24. package/dist/cli/doctor.js +83 -0
  25. package/dist/cli/doctor.js.map +1 -0
  26. package/dist/cli/firebase-targets.d.ts +7 -0
  27. package/dist/cli/firebase-targets.d.ts.map +1 -0
  28. package/dist/cli/firebase-targets.js +49 -0
  29. package/dist/cli/firebase-targets.js.map +1 -0
  30. package/dist/cli/function-url.d.ts +8 -0
  31. package/dist/cli/function-url.d.ts.map +1 -0
  32. package/dist/cli/function-url.js +20 -0
  33. package/dist/cli/function-url.js.map +1 -0
  34. package/dist/cli/http-fetch.d.ts +7 -0
  35. package/dist/cli/http-fetch.d.ts.map +1 -0
  36. package/dist/cli/http-fetch.js +21 -0
  37. package/dist/cli/http-fetch.js.map +1 -0
  38. package/dist/cli/install-id.d.ts +6 -0
  39. package/dist/cli/install-id.d.ts.map +1 -0
  40. package/dist/cli/install-id.js +30 -0
  41. package/dist/cli/install-id.js.map +1 -0
  42. package/dist/cli/login.d.ts +2 -0
  43. package/dist/cli/login.d.ts.map +1 -0
  44. package/dist/cli/login.js +76 -0
  45. package/dist/cli/login.js.map +1 -0
  46. package/dist/cli/logout.d.ts +2 -0
  47. package/dist/cli/logout.d.ts.map +1 -0
  48. package/dist/cli/logout.js +51 -0
  49. package/dist/cli/logout.js.map +1 -0
  50. package/dist/cli/main.d.ts +2 -0
  51. package/dist/cli/main.d.ts.map +1 -0
  52. package/dist/cli/main.js +158 -0
  53. package/dist/cli/main.js.map +1 -0
  54. package/dist/cli/policies-callable-url.d.ts +24 -0
  55. package/dist/cli/policies-callable-url.d.ts.map +1 -0
  56. package/dist/cli/policies-callable-url.js +66 -0
  57. package/dist/cli/policies-callable-url.js.map +1 -0
  58. package/dist/cli/policies-meta.d.ts +6 -0
  59. package/dist/cli/policies-meta.d.ts.map +1 -0
  60. package/dist/cli/policies-meta.js +18 -0
  61. package/dist/cli/policies-meta.js.map +1 -0
  62. package/dist/cli/policies-sync.d.ts +2 -0
  63. package/dist/cli/policies-sync.d.ts.map +1 -0
  64. package/dist/cli/policies-sync.js +40 -0
  65. package/dist/cli/policies-sync.js.map +1 -0
  66. package/dist/cli/setup-all.d.ts +9 -0
  67. package/dist/cli/setup-all.d.ts.map +1 -0
  68. package/dist/cli/setup-all.js +43 -0
  69. package/dist/cli/setup-all.js.map +1 -0
  70. package/dist/cli/setup-doctor.d.ts +8 -0
  71. package/dist/cli/setup-doctor.d.ts.map +1 -0
  72. package/dist/cli/setup-doctor.js +42 -0
  73. package/dist/cli/setup-doctor.js.map +1 -0
  74. package/dist/cli/setup-hook.d.ts +8 -0
  75. package/dist/cli/setup-hook.d.ts.map +1 -0
  76. package/dist/cli/setup-hook.js +30 -0
  77. package/dist/cli/setup-hook.js.map +1 -0
  78. package/dist/cli/setup-mcp.d.ts +8 -0
  79. package/dist/cli/setup-mcp.d.ts.map +1 -0
  80. package/dist/cli/setup-mcp.js +30 -0
  81. package/dist/cli/setup-mcp.js.map +1 -0
  82. package/dist/cli/touch-last-seen.d.ts +6 -0
  83. package/dist/cli/touch-last-seen.d.ts.map +1 -0
  84. package/dist/cli/touch-last-seen.js +46 -0
  85. package/dist/cli/touch-last-seen.js.map +1 -0
  86. package/dist/cli/version.d.ts +2 -0
  87. package/dist/cli/version.d.ts.map +1 -0
  88. package/dist/cli/version.js +19 -0
  89. package/dist/cli/version.js.map +1 -0
  90. package/dist/cli/whoami.d.ts +2 -0
  91. package/dist/cli/whoami.d.ts.map +1 -0
  92. package/dist/cli/whoami.js +36 -0
  93. package/dist/cli/whoami.js.map +1 -0
  94. package/dist/cli.d.ts +3 -0
  95. package/dist/cli.d.ts.map +1 -0
  96. package/dist/cli.js +19 -0
  97. package/dist/cli.js.map +1 -0
  98. package/dist/hooks/run-before-shell.d.ts +16 -0
  99. package/dist/hooks/run-before-shell.d.ts.map +1 -0
  100. package/dist/hooks/run-before-shell.js +132 -0
  101. package/dist/hooks/run-before-shell.js.map +1 -0
  102. package/dist/index.d.ts +7 -0
  103. package/dist/index.d.ts.map +1 -0
  104. package/dist/index.js +6 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/mcp/server.d.ts +3 -0
  107. package/dist/mcp/server.d.ts.map +1 -0
  108. package/dist/mcp/server.js +252 -0
  109. package/dist/mcp/server.js.map +1 -0
  110. package/dist/policies.v1.json +502 -0
  111. package/dist/policy/index.d.ts +47 -0
  112. package/dist/policy/index.d.ts.map +1 -0
  113. package/dist/policy/index.js +170 -0
  114. package/dist/policy/index.js.map +1 -0
  115. package/dist/shell/evaluate.d.ts +37 -0
  116. package/dist/shell/evaluate.d.ts.map +1 -0
  117. package/dist/shell/evaluate.js +81 -0
  118. package/dist/shell/evaluate.js.map +1 -0
  119. package/dist/shell/governed-tools.d.ts +3 -0
  120. package/dist/shell/governed-tools.d.ts.map +1 -0
  121. package/dist/shell/governed-tools.js +3 -0
  122. package/dist/shell/governed-tools.js.map +1 -0
  123. package/dist/shell/parse.d.ts +2 -0
  124. package/dist/shell/parse.d.ts.map +1 -0
  125. package/dist/shell/parse.js +7 -0
  126. package/dist/shell/parse.js.map +1 -0
  127. package/dist/telemetry/guard-events.d.ts +9 -0
  128. package/dist/telemetry/guard-events.d.ts.map +1 -0
  129. package/dist/telemetry/guard-events.js +86 -0
  130. package/dist/telemetry/guard-events.js.map +1 -0
  131. package/package.json +40 -0
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # @praxis/auditor-cli
2
+
3
+ Shared **guard runtime** for Praxis shell policy: argv parsing (`shell-quote`), `evaluateShellProposal` / `evaluateArgv` / `gateShellCommand`, JSONL audit append, and the **shell approval bridge** under `.cursor/guard/bridge`.
4
+
5
+ ## Single entry: `auditor`
6
+
7
+ Use one built binary for **MCP stdio**, **Cursor hook**, and diagnostics:
8
+
9
+ | Surface | Command |
10
+ |--------|---------|
11
+ | **MCP** (`mcp.json`) | `auditor` + args `["mcp"]`, or `node …/auditor-cli/dist/cli.js mcp` |
12
+ | **Hook** (`.cursor/hooks.json`) | `node …/auditor-cli/dist/cli.js hook before-shell` (or `auditor hook before-shell` if `auditor` is on `PATH`) |
13
+
14
+ **`@praxis/guard-mcp`** remains as a **thin shim** (`dist/server.js` → `@praxis/auditor-cli/mcp`) for older configs that still point at `guard-mcp`.
15
+
16
+ ## Policy source of truth
17
+
18
+ Classification rules live in **`@praxis/auditor-policy`** (`loadPoliciesV1`, `classifyArgv`, `policies.v1.json` via the path resolved from the built policy package). This package re-exports `loadPoliciesV1` for convenience; hooks may still import `classifyArgv` from `@praxis/auditor-policy` when they need hook-specific tier handling.
19
+
20
+ ## Bridge directory contract
21
+
22
+ One-shot approvals for terminal execution use:
23
+
24
+ - **Directory:** `path.resolve(cwd, ".cursor/guard/bridge")`
25
+ - **Files:** `${sha256(JSON.stringify(argv))}_${uuid}.json` with TTL **10 minutes** (`DEFAULT_SHELL_BRIDGE_TTL_MS`).
26
+
27
+ Do not change this layout without updating Cursor + MCP flows that rely on it.
28
+
29
+ ## Python `packages/auditor`
30
+
31
+ The legacy **Python** guard under `packages/auditor/` remains for existing installs; new work should target **`@praxis/auditor-cli`** and Node-based tooling. Long-term migration: shell aliases or install scripts pointing at the `auditor` binary (`npx` / workspace) instead of `python3 guard.py` (see [AUDITOR_CLI_SOLUTION_PLAN.md](../../docs/AUDITOR_CLI_SOLUTION_PLAN.md)).
32
+
33
+ ## CLI (`auditor` binary)
34
+
35
+ After `pnpm -C packages/auditor-cli build`, the **`auditor`** command is available from this package (`package.json` `bin`).
36
+
37
+ | Command | Purpose |
38
+ |--------|---------|
39
+ | `auditor mcp` | **MCP stdio server** (registers tool `guard`). Use in Cursor `mcp.json` as the server command. |
40
+ | `auditor hook before-shell` | Cursor hook: stdin JSON `{ "command", "cwd?" }` → stdout JSON `{ "permission", ... }` (fail-closed on crash). |
41
+ | `auditor doctor` | Prints resolved policy path, bridge dir, audit log path, `Node` version, and `PRAXIS_GUARD_AUDIT_LOG` status. |
42
+ | `auditor whoami` | Prints `uid`, profile email/display name, and token source via the `guardWhoAmI` callable (requires auth like `policies sync`). |
43
+ | `auditor version` | Package version plus `git rev-parse --short HEAD` when run inside a git checkout. |
44
+ | `auditor help` | Usage summary. |
45
+
46
+ From the repo root: `pnpm exec auditor doctor` / `pnpm exec auditor mcp` (after `pnpm -C packages/auditor-cli build`), or `node packages/auditor-cli/dist/cli.js …`.
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @param resolveDefaultRelativeTo When `PRAXIS_GUARD_AUDIT_LOG` is unset, the directory used to
3
+ * resolve `.cursor/guard/audit.jsonl` (usually the workspace root from the hook payload's `cwd`).
4
+ * If omitted or empty, uses `process.cwd()` — which may differ from the workspace when Cursor spawns the hook.
5
+ */
6
+ export declare function appendAuditJsonl(evt: Record<string, unknown>, resolveDefaultRelativeTo?: string | null): Promise<void>;
7
+ //# sourceMappingURL=jsonl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../../src/audit/jsonl.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,iBAY5G"}
@@ -0,0 +1,16 @@
1
+ import { appendFile, mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ /**
4
+ * @param resolveDefaultRelativeTo When `PRAXIS_GUARD_AUDIT_LOG` is unset, the directory used to
5
+ * resolve `.cursor/guard/audit.jsonl` (usually the workspace root from the hook payload's `cwd`).
6
+ * If omitted or empty, uses `process.cwd()` — which may differ from the workspace when Cursor spawns the hook.
7
+ */
8
+ export async function appendAuditJsonl(evt, resolveDefaultRelativeTo) {
9
+ const fromEnv = process.env.PRAXIS_GUARD_AUDIT_LOG?.trim();
10
+ const auditPath = fromEnv && fromEnv.length > 0
11
+ ? fromEnv
12
+ : path.resolve((resolveDefaultRelativeTo && resolveDefaultRelativeTo.trim()) || process.cwd(), ".cursor/guard/audit.jsonl");
13
+ await mkdir(path.dirname(auditPath), { recursive: true });
14
+ await appendFile(auditPath, `${JSON.stringify(evt)}\n`, "utf8");
15
+ }
16
+ //# sourceMappingURL=jsonl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../src/audit/jsonl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAA4B,EAAE,wBAAwC;IAC3G,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,IAAI,EAAE,CAAC;IAC3D,MAAM,SAAS,GACb,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAC3B,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,IAAI,CAAC,OAAO,CACV,CAAC,wBAAwB,IAAI,wBAAwB,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,EAC9E,2BAA2B,CAC5B,CAAC;IAER,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,UAAU,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { Tier } from "../policy/index.js";
2
+ /** Same window as in-process MCP approval tokens (see guard-mcp server). */
3
+ export declare const DEFAULT_SHELL_BRIDGE_TTL_MS: number;
4
+ export declare function shellBridgeDir(cwd?: string): string;
5
+ /** Stable id for argv; must match between MCP record and hook consume. */
6
+ export declare function shellArgvApprovalId(argv: readonly string[]): string;
7
+ /**
8
+ * After MCP `guard` returns allow for a MUTATE shell proposal, record a one-shot
9
+ * bridge so `beforeShellExecution` can allow the matching terminal command once.
10
+ */
11
+ export declare function recordShellApprovalBridge(argv: readonly string[], opts?: {
12
+ cwd?: string;
13
+ ttlMs?: number;
14
+ }): Promise<void>;
15
+ /**
16
+ * If a non-expired bridge file exists for this argv, delete it and return true.
17
+ * Otherwise return false. POC: local filesystem trust boundary only.
18
+ */
19
+ export declare function tryConsumeShellApprovalBridge(argv: readonly string[], opts?: {
20
+ cwd?: string;
21
+ }): Promise<boolean>;
22
+ /** Whether MCP should write a bridge file for this outcome. */
23
+ export declare function shouldRecordShellBridge(opts: {
24
+ decision: "allow" | "require_approval" | "block";
25
+ skipped: boolean;
26
+ tier: Tier;
27
+ }): boolean;
28
+ //# sourceMappingURL=shell-approval-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-approval-bridge.d.ts","sourceRoot":"","sources":["../../src/bridge/shell-approval-bridge.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE/C,4EAA4E;AAC5E,eAAO,MAAM,2BAA2B,QAAiB,CAAC;AAE1D,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEnE;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACtC,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;GAGG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC,OAAO,CAAC,CA2BlB;AAED,+DAA+D;AAC/D,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,QAAQ,EAAE,OAAO,GAAG,kBAAkB,GAAG,OAAO,CAAC;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;CACZ,GAAG,OAAO,CAEV"}
@@ -0,0 +1,63 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { mkdir, readdir, readFile, unlink, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ /** Same window as in-process MCP approval tokens (see guard-mcp server). */
5
+ export const DEFAULT_SHELL_BRIDGE_TTL_MS = 10 * 60 * 1000;
6
+ export function shellBridgeDir(cwd) {
7
+ return path.resolve(cwd ?? process.cwd(), ".cursor/guard/bridge");
8
+ }
9
+ /** Stable id for argv; must match between MCP record and hook consume. */
10
+ export function shellArgvApprovalId(argv) {
11
+ return createHash("sha256").update(JSON.stringify([...argv]), "utf8").digest("hex");
12
+ }
13
+ /**
14
+ * After MCP `guard` returns allow for a MUTATE shell proposal, record a one-shot
15
+ * bridge so `beforeShellExecution` can allow the matching terminal command once.
16
+ */
17
+ export async function recordShellApprovalBridge(argv, opts) {
18
+ const id = shellArgvApprovalId(argv);
19
+ const dir = shellBridgeDir(opts?.cwd);
20
+ await mkdir(dir, { recursive: true });
21
+ const exp = Date.now() + (opts?.ttlMs ?? DEFAULT_SHELL_BRIDGE_TTL_MS);
22
+ const file = path.join(dir, `${id}_${randomUUID()}.json`);
23
+ await writeFile(file, JSON.stringify({ exp, argv: [...argv] }), "utf8");
24
+ }
25
+ /**
26
+ * If a non-expired bridge file exists for this argv, delete it and return true.
27
+ * Otherwise return false. POC: local filesystem trust boundary only.
28
+ */
29
+ export async function tryConsumeShellApprovalBridge(argv, opts) {
30
+ const id = shellArgvApprovalId(argv);
31
+ const dir = shellBridgeDir(opts?.cwd);
32
+ let names = [];
33
+ try {
34
+ names = await readdir(dir);
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ const now = Date.now();
40
+ const candidates = names.filter((n) => n.startsWith(`${id}_`) && n.endsWith(".json"));
41
+ for (const name of candidates) {
42
+ const file = path.join(dir, name);
43
+ try {
44
+ const raw = await readFile(file, "utf8");
45
+ const row = JSON.parse(raw);
46
+ if (typeof row.exp !== "number" || row.exp < now) {
47
+ await unlink(file).catch(() => { });
48
+ continue;
49
+ }
50
+ await unlink(file);
51
+ return true;
52
+ }
53
+ catch {
54
+ continue;
55
+ }
56
+ }
57
+ return false;
58
+ }
59
+ /** Whether MCP should write a bridge file for this outcome. */
60
+ export function shouldRecordShellBridge(opts) {
61
+ return opts.decision === "allow" && !opts.skipped && opts.tier === "MUTATE";
62
+ }
63
+ //# sourceMappingURL=shell-approval-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-approval-bridge.js","sourceRoot":"","sources":["../../src/bridge/shell-approval-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /** Minimal Firebase HTTPS callable client (no firebase SDK dependency). */
2
+ export declare function callHttpsCallable<TReq, TRes>(options: {
3
+ url: string;
4
+ /** Firebase ID token or guard API token (`PRAXIS_GUARD_TOKEN`), depending on what the function accepts. */
5
+ bearerToken: string;
6
+ data: TReq;
7
+ }): Promise<TRes>;
8
+ //# sourceMappingURL=callable-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callable-fetch.d.ts","sourceRoot":"","sources":["../../src/cli/callable-fetch.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAM3E,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;IAC3D,GAAG,EAAE,MAAM,CAAC;IACZ,2GAA2G;IAC3G,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,IAAI,CAAC;CACZ,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BhB"}
@@ -0,0 +1,30 @@
1
+ /** Minimal Firebase HTTPS callable client (no firebase SDK dependency). */
2
+ import { touchLastSeen } from "./touch-last-seen.js";
3
+ export async function callHttpsCallable(options) {
4
+ const res = await fetch(options.url, {
5
+ method: "POST",
6
+ headers: {
7
+ "Content-Type": "application/json",
8
+ Authorization: `Bearer ${options.bearerToken}`,
9
+ },
10
+ body: JSON.stringify({ data: options.data ?? {} }),
11
+ });
12
+ const text = await res.text();
13
+ let json;
14
+ try {
15
+ json = JSON.parse(text);
16
+ }
17
+ catch {
18
+ throw new Error(`Callable ${options.url}: invalid JSON (${res.status}): ${text.slice(0, 200)}`);
19
+ }
20
+ if ("error" in json && json.error) {
21
+ const msg = json.error.message || json.error.status || "callable_error";
22
+ throw new Error(msg);
23
+ }
24
+ if (!("result" in json)) {
25
+ throw new Error(`Callable ${options.url}: missing result (${res.status})`);
26
+ }
27
+ void touchLastSeen();
28
+ return json.result;
29
+ }
30
+ //# sourceMappingURL=callable-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callable-fetch.js","sourceRoot":"","sources":["../../src/cli/callable-fetch.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAa,OAKnD;IACC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACnC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,OAAO,CAAC,WAAW,EAAE;SAC/C;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;KACnD,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,IAA4B,CAAC;IACjC,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA2B,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,YAAY,OAAO,CAAC,GAAG,mBAAmB,GAAG,CAAC,MAAM,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,IAAI,OAAO,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,gBAAgB,CAAC;QACxE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,YAAY,OAAO,CAAC,GAAG,qBAAqB,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7E,CAAC;IAED,KAAK,aAAa,EAAE,CAAC;IACrB,OAAO,IAAI,CAAC,MAAM,CAAC;AACrB,CAAC"}
@@ -0,0 +1,10 @@
1
+ export declare function credentialsPath(): string;
2
+ /**
3
+ * Resolve the guard bearer token.
4
+ * Priority: env var > credential file > null.
5
+ */
6
+ export declare function resolveGuardToken(): string | null;
7
+ export declare function saveCredentials(token: string): void;
8
+ export declare function deleteCredentials(): boolean;
9
+ export declare function readCredentialsFileMode(): number | null;
10
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/cli/credentials.ts"],"names":[],"mappings":"AAKA,wBAAgB,eAAe,IAAI,MAAM,CAIxC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAajD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAKnD;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAO3C;AAED,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAOvD"}
@@ -0,0 +1,53 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ import process from "node:process";
5
+ export function credentialsPath() {
6
+ const xdg = process.env.XDG_CONFIG_HOME?.trim();
7
+ const base = xdg || path.join(os.homedir(), ".config");
8
+ return path.join(base, "praxis", "credentials.json");
9
+ }
10
+ /**
11
+ * Resolve the guard bearer token.
12
+ * Priority: env var > credential file > null.
13
+ */
14
+ export function resolveGuardToken() {
15
+ const envToken = process.env.PRAXIS_GUARD_TOKEN?.trim();
16
+ if (envToken)
17
+ return envToken;
18
+ try {
19
+ const raw = fs.readFileSync(credentialsPath(), "utf8");
20
+ const data = JSON.parse(raw);
21
+ if (typeof data.token === "string" && data.token.length > 0)
22
+ return data.token;
23
+ }
24
+ catch {
25
+ // File doesn't exist or is invalid
26
+ }
27
+ return null;
28
+ }
29
+ export function saveCredentials(token) {
30
+ const p = credentialsPath();
31
+ fs.mkdirSync(path.dirname(p), { recursive: true, mode: 0o700 });
32
+ const payload = JSON.stringify({ token, createdAt: new Date().toISOString() }, null, 2);
33
+ fs.writeFileSync(p, payload + "\n", { mode: 0o600 });
34
+ }
35
+ export function deleteCredentials() {
36
+ try {
37
+ fs.unlinkSync(credentialsPath());
38
+ return true;
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ }
44
+ export function readCredentialsFileMode() {
45
+ try {
46
+ const st = fs.statSync(credentialsPath());
47
+ return st.mode & 0o777;
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/cli/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC;IAChD,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IACvD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC;IACxD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,EAAE,MAAM,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;IACjF,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;IACrC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,CAAC,GAAG,eAAe,EAAE,CAAC;IAC5B,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACxF,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,eAAe,EAAE,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC;QAC1C,OAAO,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ type JsonMap = Record<string, unknown>;
2
+ export type SetupResult = {
3
+ path: string;
4
+ changed: boolean;
5
+ message: string;
6
+ };
7
+ export declare function resolveProjectHooksPath(projectDir: string): string;
8
+ export declare function resolveUserMcpConfigPath(explicitPath?: string): string;
9
+ export declare function hasConfiguredHook(config: JsonMap | null): boolean;
10
+ export declare function upsertHookConfig(projectDir: string, dryRun?: boolean): Promise<SetupResult>;
11
+ export declare function hasConfiguredMcpServer(config: JsonMap | null): boolean;
12
+ export declare function upsertMcpConfig(explicitPath?: string, dryRun?: boolean): Promise<SetupResult>;
13
+ export declare function readHookConfigured(projectDir: string): Promise<boolean>;
14
+ export declare function readMcpConfigured(explicitPath?: string): Promise<boolean>;
15
+ export {};
16
+ //# sourceMappingURL=cursor-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-config.d.ts","sourceRoot":"","sources":["../../src/cli/cursor-config.ts"],"names":[],"mappings":"AAIA,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEvC,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAKF,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,wBAAwB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAGtE;AA0CD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAYjE;AAED,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,CA2C/F;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAQtE;AAED,wBAAsB,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,CA8BjG;AAED,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG7E;AAED,wBAAsB,iBAAiB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG/E"}
@@ -0,0 +1,153 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
4
+ const HOOK_COMMAND = "auditor hook before-shell";
5
+ const MCP_SERVER_KEY = "praxis-guard";
6
+ export function resolveProjectHooksPath(projectDir) {
7
+ return path.join(projectDir, ".cursor", "hooks.json");
8
+ }
9
+ export function resolveUserMcpConfigPath(explicitPath) {
10
+ if (explicitPath?.trim())
11
+ return explicitPath.trim();
12
+ return path.join(os.homedir(), ".cursor", "mcp.json");
13
+ }
14
+ async function readJson(pathname) {
15
+ try {
16
+ const raw = await readFile(pathname, "utf8");
17
+ const parsed = JSON.parse(raw);
18
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
19
+ throw new Error("JSON root must be an object");
20
+ }
21
+ return parsed;
22
+ }
23
+ catch (e) {
24
+ const msg = e instanceof Error ? e.message : String(e);
25
+ if (e.code === "ENOENT")
26
+ return null;
27
+ throw new Error([
28
+ `Invalid JSON at ${pathname}: ${msg}`,
29
+ "Refusing to overwrite existing file.",
30
+ "Fix the JSON manually or back up the file and re-run setup.",
31
+ ].join(" "));
32
+ }
33
+ }
34
+ async function writeJson(pathname, data) {
35
+ await mkdir(path.dirname(pathname), { recursive: true });
36
+ await writeFile(pathname, `${JSON.stringify(data, null, 2)}\n`, "utf8");
37
+ }
38
+ function cloneJsonMap(existing) {
39
+ if (!existing)
40
+ return {};
41
+ return JSON.parse(JSON.stringify(existing));
42
+ }
43
+ function normalizeHooksConfig(existing) {
44
+ const base = existing ?? { version: 1, hooks: {} };
45
+ if (typeof base.version !== "number")
46
+ base.version = 1;
47
+ if (!base.hooks || typeof base.hooks !== "object" || Array.isArray(base.hooks)) {
48
+ base.hooks = {};
49
+ }
50
+ return base;
51
+ }
52
+ export function hasConfiguredHook(config) {
53
+ if (!config)
54
+ return false;
55
+ const hooks = (config.hooks ?? {});
56
+ const arr = hooks.beforeShellExecution;
57
+ if (!Array.isArray(arr))
58
+ return false;
59
+ return arr.some((entry) => entry &&
60
+ typeof entry === "object" &&
61
+ entry.command === HOOK_COMMAND &&
62
+ entry.failClosed === true);
63
+ }
64
+ export async function upsertHookConfig(projectDir, dryRun = false) {
65
+ const hooksPath = resolveProjectHooksPath(projectDir);
66
+ const existing = await readJson(hooksPath);
67
+ const beforeJson = JSON.stringify(existing ?? {});
68
+ const config = normalizeHooksConfig(cloneJsonMap(existing));
69
+ const hooks = config.hooks;
70
+ const before = Array.isArray(hooks.beforeShellExecution) ? [...hooks.beforeShellExecution] : [];
71
+ const rewritten = [];
72
+ let found = false;
73
+ for (const item of before) {
74
+ if (!item || typeof item !== "object") {
75
+ rewritten.push(item);
76
+ continue;
77
+ }
78
+ const map = item;
79
+ if (map.command === HOOK_COMMAND) {
80
+ if (!found) {
81
+ found = true;
82
+ rewritten.push({ ...map, failClosed: true });
83
+ }
84
+ continue;
85
+ }
86
+ rewritten.push(item);
87
+ }
88
+ if (!found)
89
+ rewritten.push({ command: HOOK_COMMAND, failClosed: true });
90
+ hooks.beforeShellExecution = rewritten;
91
+ const changed = beforeJson !== JSON.stringify(config);
92
+ if (changed && !dryRun) {
93
+ await writeJson(hooksPath, config);
94
+ }
95
+ return {
96
+ path: hooksPath,
97
+ changed,
98
+ message: changed
99
+ ? dryRun
100
+ ? "would update hooks config"
101
+ : "updated hooks config"
102
+ : "hooks config already up to date",
103
+ };
104
+ }
105
+ export function hasConfiguredMcpServer(config) {
106
+ if (!config)
107
+ return false;
108
+ const servers = (config.mcpServers ?? {});
109
+ const server = servers[MCP_SERVER_KEY];
110
+ if (!server || typeof server !== "object")
111
+ return false;
112
+ const map = server;
113
+ const args = map.args;
114
+ return map.command === "auditor" && Array.isArray(args) && args.length === 1 && args[0] === "mcp";
115
+ }
116
+ export async function upsertMcpConfig(explicitPath, dryRun = false) {
117
+ const mcpPath = resolveUserMcpConfigPath(explicitPath);
118
+ const existing = await readJson(mcpPath);
119
+ const beforeJson = JSON.stringify(existing ?? {});
120
+ const config = cloneJsonMap(existing);
121
+ if (!config.mcpServers || typeof config.mcpServers !== "object" || Array.isArray(config.mcpServers)) {
122
+ config.mcpServers = {};
123
+ }
124
+ const servers = config.mcpServers;
125
+ const current = servers[MCP_SERVER_KEY];
126
+ servers[MCP_SERVER_KEY] = {
127
+ ...(current && typeof current === "object" ? current : {}),
128
+ command: "auditor",
129
+ args: ["mcp"],
130
+ };
131
+ const changed = beforeJson !== JSON.stringify(config);
132
+ if (changed && !dryRun) {
133
+ await writeJson(mcpPath, config);
134
+ }
135
+ return {
136
+ path: mcpPath,
137
+ changed,
138
+ message: changed
139
+ ? dryRun
140
+ ? "would update MCP config"
141
+ : "updated MCP config"
142
+ : "MCP config already up to date",
143
+ };
144
+ }
145
+ export async function readHookConfigured(projectDir) {
146
+ const config = await readJson(resolveProjectHooksPath(projectDir));
147
+ return hasConfiguredHook(config);
148
+ }
149
+ export async function readMcpConfigured(explicitPath) {
150
+ const config = await readJson(resolveUserMcpConfigPath(explicitPath));
151
+ return hasConfiguredMcpServer(config);
152
+ }
153
+ //# sourceMappingURL=cursor-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-config.js","sourceRoot":"","sources":["../../src/cli/cursor-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runDoctor(): Promise<void>;
2
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AAaA,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAyF/C"}
@@ -0,0 +1,83 @@
1
+ import path from "node:path";
2
+ import process from "node:process";
3
+ import { defaultPoliciesMetaPath, defaultPoliciesV1Path } from "../policy/index.js";
4
+ import { shellBridgeDir } from "../bridge/shell-approval-bridge.js";
5
+ import { fetchJson } from "./http-fetch.js";
6
+ import { credentialsPath, readCredentialsFileMode, resolveGuardToken } from "./credentials.js";
7
+ import { readHookConfigured, readMcpConfigured, resolveUserMcpConfigPath } from "./cursor-config.js";
8
+ import { getInstallId } from "./install-id.js";
9
+ import { functionsHttpUrl } from "./policies-callable-url.js";
10
+ import { readPoliciesMetaFile } from "./policies-meta.js";
11
+ export async function runDoctor() {
12
+ const cwd = process.cwd();
13
+ const auditPath = process.env.PRAXIS_GUARD_AUDIT_LOG ?? path.resolve(cwd, ".cursor/guard/audit.jsonl");
14
+ const policyPath = process.env.PRAXIS_POLICIES_V1_PATH?.trim() || defaultPoliciesV1Path();
15
+ const metaPath = process.env.PRAXIS_POLICIES_META_PATH?.trim() || defaultPoliciesMetaPath();
16
+ const meta = await readPoliciesMetaFile(metaPath);
17
+ const lines = [
18
+ `auditor doctor`,
19
+ `Install ID: ${getInstallId()}`,
20
+ `MCP stdio: auditor mcp (Cursor: command auditor, args [mcp])`,
21
+ `Node: ${process.version}`,
22
+ `Policy file: ${policyPath}`,
23
+ `Policies meta: ${metaPath}`,
24
+ meta
25
+ ? ` Local synced revision: ${meta.revision}${meta.syncedAt ? ` (at ${meta.syncedAt})` : ""}`
26
+ : ` Local synced revision: (no meta file — run "auditor policies sync")`,
27
+ `Bridge dir: ${shellBridgeDir(cwd)}`,
28
+ `Audit log: ${auditPath}`,
29
+ `PRAXIS_GUARD_AUDIT_LOG: ${process.env.PRAXIS_GUARD_AUDIT_LOG ?? "(unset; default above)"}`,
30
+ ];
31
+ const hookConfigured = await readHookConfigured(cwd).catch(() => false);
32
+ const mcpPath = resolveUserMcpConfigPath();
33
+ const mcpConfigured = await readMcpConfigured().catch(() => false);
34
+ lines.push(`Hook setup: ${hookConfigured ? "configured" : "missing (run \`auditor setup hook\`)"} (${path.resolve(cwd, ".cursor/hooks.json")})`);
35
+ lines.push(`MCP setup: ${mcpConfigured ? "configured" : "missing (run \`auditor setup mcp\`)"} (${mcpPath})`);
36
+ const token = resolveGuardToken() || process.env.PRAXIS_FIREBASE_ID_TOKEN?.trim();
37
+ const tokenSource = process.env.PRAXIS_GUARD_TOKEN?.trim()
38
+ ? "env:PRAXIS_GUARD_TOKEN"
39
+ : token
40
+ ? `file:${credentialsPath()}`
41
+ : null;
42
+ lines.push(tokenSource
43
+ ? `Auth: ${tokenSource} (token: ${token.slice(0, 6)}...${token.slice(-3)})`
44
+ : "Auth: (none — run `auditor login`)");
45
+ const credsMode = readCredentialsFileMode();
46
+ if (credsMode !== null) {
47
+ lines.push(credsMode === 0o600
48
+ ? `Credentials mode: 0${credsMode.toString(8)}`
49
+ : `Credentials mode: 0${credsMode.toString(8)} (expected 0600)`);
50
+ }
51
+ const revisionHttpUrl = functionsHttpUrl("policiesGetRevisionHttp");
52
+ if (token) {
53
+ try {
54
+ const rev = await fetchJson({
55
+ url: revisionHttpUrl,
56
+ bearerToken: token,
57
+ });
58
+ const remote = rev.revision;
59
+ lines.push(`Remote Firestore revision: ${remote}`);
60
+ if (meta) {
61
+ lines.push(meta.revision === remote
62
+ ? "Policies: in sync with Firestore revision."
63
+ : `Policies: update available (local ${meta.revision} vs remote ${remote}).`);
64
+ }
65
+ else {
66
+ lines.push(`Policies: remote revision ${remote} (no local sync meta).`);
67
+ }
68
+ }
69
+ catch (e) {
70
+ const msg = e instanceof Error ? e.message : String(e);
71
+ lines.push(`Remote revision check failed: ${msg}`);
72
+ }
73
+ }
74
+ else {
75
+ lines.push("Remote revision: (skip — not authenticated; run `auditor login`)");
76
+ }
77
+ const readySetup = hookConfigured && mcpConfigured;
78
+ const readyAuth = !!token;
79
+ const ready = readySetup && readyAuth;
80
+ lines.push(`Ready: ${ready ? "yes" : "no"} (setup=${readySetup ? "ok" : "missing"}, auth=${readyAuth ? "ok" : "missing"})`);
81
+ process.stdout.write(`${lines.join("\n")}\n`);
82
+ }
83
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function detectFirebaseProjectId(cwd: string): string | null;
2
+ /**
3
+ * Resolve a Firebase Hosting site id for a given target (e.g. target "app" -> site "praxis-app-33b40").
4
+ * This reads `.firebaserc` and finds the first site configured for that hosting target.
5
+ */
6
+ export declare function detectHostingSiteId(cwd: string, projectId: string, hostingTarget: string): string | null;
7
+ //# sourceMappingURL=firebase-targets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firebase-targets.d.ts","sourceRoot":"","sources":["../../src/cli/firebase-targets.ts"],"names":[],"mappings":"AAoBA,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWlE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYxG"}