@xynogen/pix-gate 0.1.11 → 0.1.13

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.
package/README.md CHANGED
@@ -35,18 +35,24 @@ rules as the bash tool (auto-deny on match, no prompt).
35
35
 
36
36
  ## Configuration
37
37
 
38
- `~/.pi/agent/pix-gate.json`:
38
+ Gate rules are read from the **`gate` section of `~/.pi/agent/pix.json`** (the unified config file). The legacy `~/.pi/agent/pix-gate.json` file is no longer used.
39
39
 
40
- ```json
40
+ `~/.pi/agent/pix.json` — `gate` section:
41
+
42
+ ```jsonc
41
43
  {
42
- "disableDefaults": false,
43
- "extraRules": [
44
- { "pattern": "rm -rf /my-dir", "severity": "critical", "reason": "Deletes project root" }
45
- ],
46
- "autoApprove": ["^echo "]
44
+ "gate": {
45
+ "disableDefaults": false,
46
+ "extraRules": [
47
+ { "pattern": "rm -rf /my-dir", "severity": "critical", "reason": "Deletes project root" }
48
+ ],
49
+ "autoApprove": ["^echo "]
50
+ }
47
51
  }
48
52
  ```
49
53
 
54
+ The schema is identical to the old `pix-gate.json` — move your existing config into `pix.json` under the `gate` key.
55
+
50
56
  ## Full distro
51
57
 
52
58
  Source: [github.com/xynogen/pix-mono](https://github.com/xynogen/pix-mono)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xynogen/pix-gate",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Pi extension — permission gate for dangerous bash commands (confirm/block with TUI dialog)",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -42,7 +42,8 @@
42
42
  "access": "public"
43
43
  },
44
44
  "dependencies": {
45
- "@xynogen/pix-pretty": "^1.7.9"
45
+ "@xynogen/pix-pretty": "^1.7.9",
46
+ "@xynogen/pix-data": "workspace:*"
46
47
  },
47
48
  "peerDependencies": {
48
49
  "@earendil-works/pi-coding-agent": "*",
package/src/gate.test.ts CHANGED
@@ -131,8 +131,9 @@ describe("buildRules", () => {
131
131
 
132
132
  test("autoApprove strings compile to regexes", () => {
133
133
  const { autoApprove } = buildRules({ autoApprove: ["^npm publish"] });
134
- expect(autoApprove[0].test("npm publish --access public")).toBe(true);
135
- expect(autoApprove[0].test("yarn publish")).toBe(false);
134
+ const rule0 = autoApprove[0] as RegExp;
135
+ expect(rule0.test("npm publish --access public")).toBe(true);
136
+ expect(rule0.test("yarn publish")).toBe(false);
136
137
  });
137
138
 
138
139
  test("defaults included when disableDefaults absent", () => {
package/src/index.ts CHANGED
@@ -88,7 +88,13 @@ export default function (pi: ExtensionAPI): void {
88
88
  });
89
89
 
90
90
  // ── Unified bash gate (path + command concerns in ONE dialog) ───────────
91
- const SEVERITY_TIER: Record<string, number> = {
91
+ const SEVERITY_TIER: {
92
+ critical: number;
93
+ block: number;
94
+ dangerous: number;
95
+ warn: number;
96
+ risky: number;
97
+ } = {
92
98
  critical: 5,
93
99
  block: 4,
94
100
  dangerous: 3,
package/src/lib.ts CHANGED
@@ -2,9 +2,7 @@
2
2
  * Pure helpers for pix-gate — no Pi API deps, fully unit-testable.
3
3
  */
4
4
 
5
- import { existsSync, readFileSync } from "node:fs";
6
- import { homedir } from "node:os";
7
- import { join } from "node:path";
5
+ import { type GateRuleConfig, pixConfig } from "@xynogen/pix-data/pix-config";
8
6
 
9
7
  export type Severity = "critical" | "dangerous" | "risky";
10
8
 
@@ -132,13 +130,21 @@ export const DEFAULT_RULES: Rule[] = [
132
130
  ];
133
131
 
134
132
  export function loadUserConfig(): UserConfig {
135
- const path = join(homedir(), ".pi", "agent", "pix-gate.json");
136
- if (!existsSync(path)) return {};
137
- try {
138
- return JSON.parse(readFileSync(path, "utf-8")) as UserConfig;
139
- } catch {
140
- return {};
141
- }
133
+ // Read from ~/.pi/agent/pix.json gate section
134
+ const pix = pixConfig().gate;
135
+ return {
136
+ disableDefaults: pix.disableDefaults || undefined,
137
+ autoApprove: pix.autoApprove.length > 0 ? pix.autoApprove : undefined,
138
+ extraRules:
139
+ pix.extraRules.length > 0
140
+ ? pix.extraRules.map((r: GateRuleConfig) => ({
141
+ pattern: r.pattern,
142
+ flags: r.flags,
143
+ severity: r.severity as Severity | undefined,
144
+ reason: r.reason,
145
+ }))
146
+ : undefined,
147
+ };
142
148
  }
143
149
 
144
150
  export function buildRules(cfg: UserConfig): {
@@ -276,7 +282,7 @@ export function extractPathsFromBash(cmd: string): string[] {
276
282
  const out: string[] = [];
277
283
  const re =
278
284
  /(?:^|[\s=><|;&"'`(])((?:\.\.\/|\/|~\/|\.)[^\s"'`<>|;&)]+|\.env(?:\.[A-Za-z0-9_-]+)?|[A-Za-z0-9_./-]+\.(?:pem|key|p12|pfx|crt|cer|env|envrc|netrc))/g;
279
- for (const m of cmd.matchAll(re)) out.push(m[1] as string);
285
+ for (const m of cmd.matchAll(re)) out.push(m[1] ?? "");
280
286
  return out;
281
287
  }
282
288
 
package/src/prompt.ts CHANGED
@@ -126,7 +126,13 @@ export async function promptPathDecision(
126
126
  }
127
127
 
128
128
  /** Tier for dialog behavior — higher = more restrictive (deny-first, shorter timeout). */
129
- const SEVERITY_TIER: Record<string, number> = {
129
+ const SEVERITY_TIER: {
130
+ critical: number;
131
+ block: number;
132
+ dangerous: number;
133
+ warn: number;
134
+ risky: number;
135
+ } = {
130
136
  critical: 5,
131
137
  block: 4,
132
138
  dangerous: 3,
@@ -146,6 +152,8 @@ export async function promptMergedGateDecision(
146
152
  // Sort by tier desc so the highest-severity concern drives dialog behavior.
147
153
  const sorted = [...concerns].sort((a, b) => b.tier - a.tier);
148
154
  const highest = sorted[0];
155
+ if (!highest)
156
+ throw new Error("promptMergedGateDecision requires at least one concern");
149
157
  const isRestrictive = highest.tier >= SEVERITY_TIER.block; // block or critical
150
158
 
151
159
  // Title: unique severity types, joined with " + "