@parkercto/cli 0.1.0 → 0.2.2
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/dist/src/bin/preuninstall.d.ts +10 -0
- package/dist/src/bin/preuninstall.d.ts.map +1 -0
- package/dist/src/bin/preuninstall.js +51 -0
- package/dist/src/bin/preuninstall.js.map +1 -0
- package/dist/src/cli.js +7 -3
- package/dist/src/cli.js.map +1 -1
- package/dist/src/client/api-client.d.ts +22 -0
- package/dist/src/client/api-client.d.ts.map +1 -1
- package/dist/src/client/api-client.js +50 -10
- package/dist/src/client/api-client.js.map +1 -1
- package/dist/src/client/auth.d.ts.map +1 -1
- package/dist/src/client/auth.js +14 -5
- package/dist/src/client/auth.js.map +1 -1
- package/dist/src/commands/auth.js +1 -1
- package/dist/src/commands/auth.js.map +1 -1
- package/dist/src/commands/connect.d.ts +2 -2
- package/dist/src/commands/connect.d.ts.map +1 -1
- package/dist/src/commands/connect.js +93 -8
- package/dist/src/commands/connect.js.map +1 -1
- package/dist/src/commands/disable.d.ts +3 -0
- package/dist/src/commands/disable.d.ts.map +1 -0
- package/dist/src/commands/disable.js +8 -0
- package/dist/src/commands/disable.js.map +1 -0
- package/dist/src/commands/enable.d.ts +3 -0
- package/dist/src/commands/enable.d.ts.map +1 -0
- package/dist/src/commands/enable.js +207 -0
- package/dist/src/commands/enable.js.map +1 -0
- package/dist/src/commands/hook.d.ts +3 -0
- package/dist/src/commands/hook.d.ts.map +1 -0
- package/dist/src/commands/hook.js +214 -0
- package/dist/src/commands/hook.js.map +1 -0
- package/dist/src/commands/join.d.ts +2 -2
- package/dist/src/commands/join.d.ts.map +1 -1
- package/dist/src/commands/join.js +17 -33
- package/dist/src/commands/join.js.map +1 -1
- package/dist/src/commands/update.js +1 -1
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/constants.d.ts +14 -1
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +14 -1
- package/dist/src/constants.js.map +1 -1
- package/dist/src/lib/auto-update.d.ts +4 -0
- package/dist/src/lib/auto-update.d.ts.map +1 -1
- package/dist/src/lib/auto-update.js +15 -2
- package/dist/src/lib/auto-update.js.map +1 -1
- package/dist/src/lib/auto-update_tests.d.ts +2 -0
- package/dist/src/lib/auto-update_tests.d.ts.map +1 -0
- package/dist/src/lib/auto-update_tests.js +36 -0
- package/dist/src/lib/auto-update_tests.js.map +1 -0
- package/dist/src/lib/claude-settings.d.ts +38 -0
- package/dist/src/lib/claude-settings.d.ts.map +1 -0
- package/dist/src/lib/claude-settings.js +66 -0
- package/dist/src/lib/claude-settings.js.map +1 -0
- package/dist/src/lib/claude-settings_tests.d.ts +2 -0
- package/dist/src/lib/claude-settings_tests.d.ts.map +1 -0
- package/dist/src/lib/claude-settings_tests.js +117 -0
- package/dist/src/lib/claude-settings_tests.js.map +1 -0
- package/dist/src/lib/local-git.d.ts.map +1 -1
- package/dist/src/lib/local-git.js +4 -1
- package/dist/src/lib/local-git.js.map +1 -1
- package/dist/src/lib/project-registry.d.ts +13 -0
- package/dist/src/lib/project-registry.d.ts.map +1 -0
- package/dist/src/lib/project-registry.js +115 -0
- package/dist/src/lib/project-registry.js.map +1 -0
- package/dist/src/lib/project-registry_tests.d.ts +2 -0
- package/dist/src/lib/project-registry_tests.d.ts.map +1 -0
- package/dist/src/lib/project-registry_tests.js +75 -0
- package/dist/src/lib/project-registry_tests.js.map +1 -0
- package/dist/src/lib/redact.d.ts +13 -0
- package/dist/src/lib/redact.d.ts.map +1 -0
- package/dist/src/lib/redact.js +33 -0
- package/dist/src/lib/redact.js.map +1 -0
- package/dist/src/lib/redact_tests.d.ts +2 -0
- package/dist/src/lib/redact_tests.d.ts.map +1 -0
- package/dist/src/lib/redact_tests.js +75 -0
- package/dist/src/lib/redact_tests.js.map +1 -0
- package/dist/src/lib/repo-config.d.ts +1 -0
- package/dist/src/lib/repo-config.d.ts.map +1 -1
- package/dist/src/lib/repo-config.js +6 -2
- package/dist/src/lib/repo-config.js.map +1 -1
- package/dist/src/lib/session-state.d.ts +20 -0
- package/dist/src/lib/session-state.d.ts.map +1 -0
- package/dist/src/lib/session-state.js +50 -0
- package/dist/src/lib/session-state.js.map +1 -0
- package/dist/src/lib/session-state_tests.d.ts +2 -0
- package/dist/src/lib/session-state_tests.d.ts.map +1 -0
- package/dist/src/lib/session-state_tests.js +34 -0
- package/dist/src/lib/session-state_tests.js.map +1 -0
- package/dist/src/render/help.js +2 -2
- package/dist/src/render/help.js.map +1 -1
- package/package.json +7 -3
- package/dist/src/commands/init.d.ts +0 -3
- package/dist/src/commands/init.d.ts.map +0 -1
- package/dist/src/commands/init.js +0 -130
- package/dist/src/commands/init.js.map +0 -1
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns true if `candidate` is strictly newer than `current` using semver comparison.
|
|
3
|
+
*/
|
|
4
|
+
export declare function isNewerVersion(candidate: string, current: string): boolean;
|
|
1
5
|
/**
|
|
2
6
|
* Checks for a newer CLI version and, if found, installs it and re-execs
|
|
3
7
|
* the current command transparently. Uses the update-notifier cache so this
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-update.d.ts","sourceRoot":"","sources":["../../../src/lib/auto-update.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auto-update.d.ts","sourceRoot":"","sources":["../../../src/lib/auto-update.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAQ1E;AAmDD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAiCzC"}
|
|
@@ -12,9 +12,22 @@ import { PACKAGE_NAME } from "../constants.js";
|
|
|
12
12
|
const REEXEC_ENV_VAR = "PARKER_SKIP_AUTO_UPDATE";
|
|
13
13
|
/** How often (in ms) to check the npm registry for a newer version. */
|
|
14
14
|
const UPDATE_CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000; // 6 hours
|
|
15
|
+
/**
|
|
16
|
+
* Returns true if `candidate` is strictly newer than `current` using semver comparison.
|
|
17
|
+
*/
|
|
18
|
+
export function isNewerVersion(candidate, current) {
|
|
19
|
+
const parse = (v) => v.split(".").map(Number);
|
|
20
|
+
const [cMajor, cMinor = 0, cPatch = 0] = parse(candidate);
|
|
21
|
+
const [major, minor = 0, patch = 0] = parse(current);
|
|
22
|
+
if (cMajor !== major)
|
|
23
|
+
return cMajor > major;
|
|
24
|
+
if (cMinor !== minor)
|
|
25
|
+
return cMinor > minor;
|
|
26
|
+
return cPatch > patch;
|
|
27
|
+
}
|
|
15
28
|
function loadPackageJson() {
|
|
16
29
|
const require = createRequire(import.meta.url);
|
|
17
|
-
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "
|
|
30
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
18
31
|
return require(resolve(packageRoot, "package.json"));
|
|
19
32
|
}
|
|
20
33
|
/**
|
|
@@ -82,7 +95,7 @@ export function autoUpdateIfNeeded() {
|
|
|
82
95
|
return;
|
|
83
96
|
}
|
|
84
97
|
// Don't "update" to the same or older version (can happen with stale cache).
|
|
85
|
-
if (notifier.update.latest
|
|
98
|
+
if (!isNewerVersion(notifier.update.latest, packageJson.version)) {
|
|
86
99
|
return;
|
|
87
100
|
}
|
|
88
101
|
const installed = installLatestVersion(notifier.update.latest);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-update.js","sourceRoot":"","sources":["../../../src/lib/auto-update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,cAAc,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;;GAGG;AACH,MAAM,cAAc,GAAG,yBAAyB,CAAC;AAEjD,uEAAuE;AACvE,MAAM,wBAAwB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,UAAU;AAO/D,SAAS,eAAe;IACtB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"auto-update.js","sourceRoot":"","sources":["../../../src/lib/auto-update.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-update_tests.d.ts","sourceRoot":"","sources":["../../../src/lib/auto-update_tests.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { isNewerVersion } from "./auto-update.js";
|
|
3
|
+
describe("isNewerVersion", () => {
|
|
4
|
+
it("returns true when candidate major is higher", () => {
|
|
5
|
+
expect(isNewerVersion("2.0.0", "1.0.0")).toBe(true);
|
|
6
|
+
});
|
|
7
|
+
it("returns true when candidate minor is higher", () => {
|
|
8
|
+
expect(isNewerVersion("1.1.0", "1.0.0")).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
it("returns true when candidate patch is higher", () => {
|
|
11
|
+
expect(isNewerVersion("1.0.1", "1.0.0")).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
it("returns false when versions are equal", () => {
|
|
14
|
+
expect(isNewerVersion("1.0.0", "1.0.0")).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
it("returns false when candidate is older", () => {
|
|
17
|
+
expect(isNewerVersion("1.0.0", "1.0.1")).toBe(false);
|
|
18
|
+
expect(isNewerVersion("1.0.0", "1.1.0")).toBe(false);
|
|
19
|
+
expect(isNewerVersion("1.0.0", "2.0.0")).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
it("handles two-segment versions", () => {
|
|
22
|
+
expect(isNewerVersion("1.1", "1.0")).toBe(true);
|
|
23
|
+
expect(isNewerVersion("1.0", "1.1")).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
it("handles higher major but lower minor", () => {
|
|
26
|
+
expect(isNewerVersion("2.0.0", "1.9.9")).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
it("handles higher minor but lower patch", () => {
|
|
29
|
+
expect(isNewerVersion("1.2.0", "1.1.9")).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
it("returns false for NaN segments (pre-release tags)", () => {
|
|
32
|
+
// "1.0.0-beta.1" → [1, 0, NaN] — NaN comparisons return false
|
|
33
|
+
expect(isNewerVersion("1.0.0-beta.1", "1.0.0")).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=auto-update_tests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-update_tests.js","sourceRoot":"","sources":["../../../src/lib/auto-update_tests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,8DAA8D;QAC9D,MAAM,CAAC,cAAc,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types and helpers for reading, writing, and filtering
|
|
3
|
+
* Claude Code hook configuration in .claude/settings.json.
|
|
4
|
+
*
|
|
5
|
+
* Claude Code hooks use a matcher + hooks[] structure per event:
|
|
6
|
+
* { "matcher": "<tool_name|...>", "hooks": [{ "type": "command", "command": "..." }] }
|
|
7
|
+
* An empty matcher string matches all tools.
|
|
8
|
+
*/
|
|
9
|
+
export interface ClaudeHookCommand {
|
|
10
|
+
type: string;
|
|
11
|
+
command: string;
|
|
12
|
+
timeout?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface ClaudeHookGroup {
|
|
15
|
+
matcher: string;
|
|
16
|
+
hooks: ClaudeHookCommand[];
|
|
17
|
+
}
|
|
18
|
+
export type ClaudeHooksMap = Record<string, ClaudeHookGroup[]>;
|
|
19
|
+
export interface ClaudeSettings {
|
|
20
|
+
hooks?: ClaudeHooksMap;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Reads and parses .claude/settings.json from the given project root.
|
|
25
|
+
* Returns an empty object if the file is missing or malformed.
|
|
26
|
+
*/
|
|
27
|
+
export declare function readClaudeSettings(projectRoot: string): ClaudeSettings;
|
|
28
|
+
/**
|
|
29
|
+
* Writes a ClaudeSettings object to .claude/settings.json, creating
|
|
30
|
+
* the .claude directory if it doesn't exist.
|
|
31
|
+
*/
|
|
32
|
+
export declare function writeClaudeSettings(projectRoot: string, settings: ClaudeSettings): void;
|
|
33
|
+
/**
|
|
34
|
+
* Removes all Parker-owned hook groups from a ClaudeSettings object (in place).
|
|
35
|
+
* Returns the number of groups removed.
|
|
36
|
+
*/
|
|
37
|
+
export declare function removeParkerHooks(settings: ClaudeSettings): number;
|
|
38
|
+
//# sourceMappingURL=claude-settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-settings.d.ts","sourceRoot":"","sources":["../../../src/lib/claude-settings.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,iBAAiB,EAAE,CAAC;CAC5B;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,CAYtE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,CAIvF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CA4BlE"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types and helpers for reading, writing, and filtering
|
|
3
|
+
* Claude Code hook configuration in .claude/settings.json.
|
|
4
|
+
*
|
|
5
|
+
* Claude Code hooks use a matcher + hooks[] structure per event:
|
|
6
|
+
* { "matcher": "<tool_name|...>", "hooks": [{ "type": "command", "command": "..." }] }
|
|
7
|
+
* An empty matcher string matches all tools.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { PARKER_HOOK_PREFIX } from "../constants.js";
|
|
12
|
+
/**
|
|
13
|
+
* Reads and parses .claude/settings.json from the given project root.
|
|
14
|
+
* Returns an empty object if the file is missing or malformed.
|
|
15
|
+
*/
|
|
16
|
+
export function readClaudeSettings(projectRoot) {
|
|
17
|
+
const settingsPath = join(projectRoot, ".claude", "settings.json");
|
|
18
|
+
if (!existsSync(settingsPath)) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Writes a ClaudeSettings object to .claude/settings.json, creating
|
|
30
|
+
* the .claude directory if it doesn't exist.
|
|
31
|
+
*/
|
|
32
|
+
export function writeClaudeSettings(projectRoot, settings) {
|
|
33
|
+
mkdirSync(join(projectRoot, ".claude"), { recursive: true });
|
|
34
|
+
const settingsPath = join(projectRoot, ".claude", "settings.json");
|
|
35
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Removes all Parker-owned hook groups from a ClaudeSettings object (in place).
|
|
39
|
+
* Returns the number of groups removed.
|
|
40
|
+
*/
|
|
41
|
+
export function removeParkerHooks(settings) {
|
|
42
|
+
if (!settings.hooks) {
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
let removedCount = 0;
|
|
46
|
+
for (const [event, groups] of Object.entries(settings.hooks)) {
|
|
47
|
+
const filtered = groups.filter((group) => {
|
|
48
|
+
const isParker = group.hooks.some((h) => h.command.startsWith(PARKER_HOOK_PREFIX));
|
|
49
|
+
if (isParker) {
|
|
50
|
+
removedCount++;
|
|
51
|
+
}
|
|
52
|
+
return !isParker;
|
|
53
|
+
});
|
|
54
|
+
if (filtered.length === 0) {
|
|
55
|
+
delete settings.hooks[event];
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
settings.hooks[event] = filtered;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
62
|
+
delete settings.hooks;
|
|
63
|
+
}
|
|
64
|
+
return removedCount;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=claude-settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-settings.js","sourceRoot":"","sources":["../../../src/lib/claude-settings.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAoBrD;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;IAEnE,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAmB,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB,EAAE,QAAwB;IAC/E,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;IACnE,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAwB;IACxD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACpB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACvC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,CAAC;YACnF,IAAI,QAAQ,EAAE,CAAC;gBACb,YAAY,EAAE,CAAC;YACjB,CAAC;YACD,OAAO,CAAC,QAAQ,CAAC;QACnB,CAAC,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;QACnC,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7C,OAAO,QAAQ,CAAC,KAAK,CAAC;IACxB,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-settings_tests.d.ts","sourceRoot":"","sources":["../../../src/lib/claude-settings_tests.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdirSync, writeFileSync, rmSync, readFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { tmpdir } from "os";
|
|
5
|
+
import { readClaudeSettings, writeClaudeSettings, removeParkerHooks, } from "./claude-settings.js";
|
|
6
|
+
describe("claude-settings", () => {
|
|
7
|
+
let projectRoot;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
projectRoot = join(tmpdir(), `parker-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
10
|
+
mkdirSync(join(projectRoot, ".claude"), { recursive: true });
|
|
11
|
+
});
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
14
|
+
});
|
|
15
|
+
describe("readClaudeSettings", () => {
|
|
16
|
+
it("returns empty object when settings file does not exist", () => {
|
|
17
|
+
const emptyRoot = join(tmpdir(), `parker-empty-${Date.now()}`);
|
|
18
|
+
const settings = readClaudeSettings(emptyRoot);
|
|
19
|
+
expect(settings).toEqual({});
|
|
20
|
+
});
|
|
21
|
+
it("returns empty object when settings file is malformed JSON", () => {
|
|
22
|
+
writeFileSync(join(projectRoot, ".claude", "settings.json"), "not json{");
|
|
23
|
+
const settings = readClaudeSettings(projectRoot);
|
|
24
|
+
expect(settings).toEqual({});
|
|
25
|
+
});
|
|
26
|
+
it("reads valid settings", () => {
|
|
27
|
+
const expected = { hooks: {}, customField: "value" };
|
|
28
|
+
writeFileSync(join(projectRoot, ".claude", "settings.json"), JSON.stringify(expected));
|
|
29
|
+
const settings = readClaudeSettings(projectRoot);
|
|
30
|
+
expect(settings).toEqual(expected);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe("writeClaudeSettings", () => {
|
|
34
|
+
it("creates .claude directory if needed", () => {
|
|
35
|
+
const freshRoot = join(tmpdir(), `parker-fresh-${Date.now()}`);
|
|
36
|
+
mkdirSync(freshRoot, { recursive: true });
|
|
37
|
+
writeClaudeSettings(freshRoot, { hooks: {} });
|
|
38
|
+
const written = readFileSync(join(freshRoot, ".claude", "settings.json"), "utf-8");
|
|
39
|
+
expect(JSON.parse(written)).toEqual({ hooks: {} });
|
|
40
|
+
rmSync(freshRoot, { recursive: true, force: true });
|
|
41
|
+
});
|
|
42
|
+
it("pretty-prints with trailing newline", () => {
|
|
43
|
+
writeClaudeSettings(projectRoot, { foo: "bar" });
|
|
44
|
+
const raw = readFileSync(join(projectRoot, ".claude", "settings.json"), "utf-8");
|
|
45
|
+
expect(raw).toBe('{\n "foo": "bar"\n}\n');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe("removeParkerHooks", () => {
|
|
49
|
+
it("returns 0 when there are no hooks", () => {
|
|
50
|
+
const settings = {};
|
|
51
|
+
expect(removeParkerHooks(settings)).toBe(0);
|
|
52
|
+
expect(settings).toEqual({});
|
|
53
|
+
});
|
|
54
|
+
it("removes parker hook groups and leaves others intact", () => {
|
|
55
|
+
const settings = {
|
|
56
|
+
hooks: {
|
|
57
|
+
SessionStart: [
|
|
58
|
+
{
|
|
59
|
+
matcher: "",
|
|
60
|
+
hooks: [{ type: "command", command: "parker hook session-start", timeout: 5 }],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
matcher: "",
|
|
64
|
+
hooks: [{ type: "command", command: "some-other-tool start" }],
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const removed = removeParkerHooks(settings);
|
|
70
|
+
expect(removed).toBe(1);
|
|
71
|
+
expect(settings.hooks["SessionStart"]).toHaveLength(1);
|
|
72
|
+
expect(settings.hooks["SessionStart"][0].hooks[0].command).toBe("some-other-tool start");
|
|
73
|
+
});
|
|
74
|
+
it("deletes the event key when all groups are removed", () => {
|
|
75
|
+
const settings = {
|
|
76
|
+
hooks: {
|
|
77
|
+
SessionStart: [
|
|
78
|
+
{
|
|
79
|
+
matcher: "",
|
|
80
|
+
hooks: [{ type: "command", command: "parker hook session-start" }],
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
removeParkerHooks(settings);
|
|
86
|
+
expect(settings.hooks).toBeUndefined();
|
|
87
|
+
});
|
|
88
|
+
it("deletes hooks key when all events are empty", () => {
|
|
89
|
+
const settings = {
|
|
90
|
+
hooks: {
|
|
91
|
+
SessionStart: [
|
|
92
|
+
{ matcher: "", hooks: [{ type: "command", command: "parker hook session-start" }] },
|
|
93
|
+
],
|
|
94
|
+
Stop: [
|
|
95
|
+
{ matcher: "", hooks: [{ type: "command", command: "parker hook session-end" }] },
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
const removed = removeParkerHooks(settings);
|
|
100
|
+
expect(removed).toBe(2);
|
|
101
|
+
expect(settings.hooks).toBeUndefined();
|
|
102
|
+
});
|
|
103
|
+
it("preserves non-parker events entirely", () => {
|
|
104
|
+
const settings = {
|
|
105
|
+
hooks: {
|
|
106
|
+
PreToolUse: [
|
|
107
|
+
{ matcher: "Bash", hooks: [{ type: "command", command: "lint-check" }] },
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
const removed = removeParkerHooks(settings);
|
|
112
|
+
expect(removed).toBe(0);
|
|
113
|
+
expect(settings.hooks["PreToolUse"]).toHaveLength(1);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=claude-settings_tests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-settings_tests.js","sourceRoot":"","sources":["../../../src/lib/claude-settings_tests.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-git.d.ts","sourceRoot":"","sources":["../../../src/lib/local-git.ts"],"names":[],"mappings":"AAEA,qBAAa,QAAS,SAAQ,KAAK;IAExB,OAAO,EAAE,MAAM;IACf,QAAQ,EAAE,MAAM;gBADhB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM;CAKlB;AAED,wBAAsB,WAAW,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"local-git.d.ts","sourceRoot":"","sources":["../../../src/lib/local-git.ts"],"names":[],"mappings":"AAEA,qBAAa,QAAS,SAAQ,KAAK;IAExB,OAAO,EAAE,MAAM;IACf,QAAQ,EAAE,MAAM;gBADhB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM;CAKlB;AAED,wBAAsB,WAAW,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBpE;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAMlD"}
|
|
@@ -19,7 +19,10 @@ export async function runGitLocal(...args) {
|
|
|
19
19
|
return result;
|
|
20
20
|
}
|
|
21
21
|
catch (error) {
|
|
22
|
-
|
|
22
|
+
const exitCode = error instanceof Error && "status" in error ? error.status : 1;
|
|
23
|
+
const stderr = error instanceof Error && "stderr" in error ? String(error.stderr) : "";
|
|
24
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
25
|
+
throw new GitError(`git ${args.join(" ")}`, exitCode || 1, stderr || message);
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
export async function getGitRoot() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-git.js","sourceRoot":"","sources":["../../../src/lib/local-git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,OAAO,QAAS,SAAQ,KAAK;IAExB;IACA;IAFT,YACS,OAAe,EACf,QAAgB,EACvB,OAAe;QAEf,KAAK,CAAC,uBAAuB,OAAO,KAAK,OAAO,EAAE,CAAC,CAAC;QAJ7C,YAAO,GAAP,OAAO,CAAQ;QACf,aAAQ,GAAR,QAAQ,CAAQ;QAIvB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAG,IAAc;IACjD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE;YACvC,QAAQ,EAAE,MAAM;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"local-git.js","sourceRoot":"","sources":["../../../src/lib/local-git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,OAAO,QAAS,SAAQ,KAAK;IAExB;IACA;IAFT,YACS,OAAe,EACf,QAAgB,EACvB,OAAe;QAEf,KAAK,CAAC,uBAAuB,OAAO,KAAK,OAAO,EAAE,CAAC,CAAC;QAJ7C,YAAO,GAAP,OAAO,CAAQ;QACf,aAAQ,GAAR,QAAQ,CAAQ;QAIvB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAG,IAAc;IACjD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE;YACvC,QAAQ,EAAE,MAAM;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,IAAI,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAE,KAA4B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACxG,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,IAAI,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAE,KAA6B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChH,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,IAAI,QAAQ,CAChB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EACvB,QAAQ,IAAI,CAAC,EACb,MAAM,IAAI,OAAO,CAClB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,WAAW,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers a project root so it can be cleaned up on global uninstall.
|
|
3
|
+
*/
|
|
4
|
+
export declare function registerProject(projectRoot: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* Removes a project root from the registry.
|
|
7
|
+
*/
|
|
8
|
+
export declare function unregisterProject(projectRoot: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* Returns all registered project roots.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getRegisteredProjects(): string[];
|
|
13
|
+
//# sourceMappingURL=project-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-registry.d.ts","sourceRoot":"","sources":["../../../src/lib/project-registry.ts"],"names":[],"mappings":"AA6FA;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAQzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAM3D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, openSync, closeSync, unlinkSync, constants as fsConstants } from "fs";
|
|
2
|
+
import { PARKER_GLOBAL_DIR } from "../constants.js";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
/**
|
|
5
|
+
* Returns the path to the file that tracks which projects have Parker enabled.
|
|
6
|
+
* Computed lazily so that test mocks for PARKER_GLOBAL_DIR take effect.
|
|
7
|
+
*/
|
|
8
|
+
function getRegistryPath() {
|
|
9
|
+
return join(PARKER_GLOBAL_DIR, "projects.json");
|
|
10
|
+
}
|
|
11
|
+
function getLockPath() {
|
|
12
|
+
return join(PARKER_GLOBAL_DIR, "projects.lock");
|
|
13
|
+
}
|
|
14
|
+
const LOCK_RETRY_INTERVAL_MS = 50;
|
|
15
|
+
const LOCK_MAX_RETRIES = 20; // 1 second total
|
|
16
|
+
/**
|
|
17
|
+
* Acquires a file-system lock via O_EXCL (atomic create-or-fail).
|
|
18
|
+
* Returns true if acquired, false if timed out.
|
|
19
|
+
*/
|
|
20
|
+
function acquireLock() {
|
|
21
|
+
mkdirSync(PARKER_GLOBAL_DIR, { recursive: true });
|
|
22
|
+
const lockPath = getLockPath();
|
|
23
|
+
for (let attempt = 0; attempt < LOCK_MAX_RETRIES; attempt++) {
|
|
24
|
+
try {
|
|
25
|
+
const fd = openSync(lockPath, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY);
|
|
26
|
+
closeSync(fd);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
if (err.code !== "EEXIST") {
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
// Lock held by another process — spin briefly
|
|
34
|
+
const start = Date.now();
|
|
35
|
+
while (Date.now() - start < LOCK_RETRY_INTERVAL_MS) {
|
|
36
|
+
// busy-wait (sync context, no async available)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
function releaseLock() {
|
|
43
|
+
try {
|
|
44
|
+
unlinkSync(getLockPath());
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Lock already gone — harmless
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Executes `fn` while holding an exclusive file lock on the registry.
|
|
52
|
+
* If the lock cannot be acquired within ~1 second, proceeds without it
|
|
53
|
+
* (best-effort — avoids blocking the CLI indefinitely).
|
|
54
|
+
*/
|
|
55
|
+
function withRegistryLock(fn) {
|
|
56
|
+
const locked = acquireLock();
|
|
57
|
+
try {
|
|
58
|
+
return fn();
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
if (locked) {
|
|
62
|
+
releaseLock();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function readRegistry() {
|
|
67
|
+
const registryPath = getRegistryPath();
|
|
68
|
+
if (!existsSync(registryPath)) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const raw = readFileSync(registryPath, "utf-8");
|
|
73
|
+
const parsed = JSON.parse(raw);
|
|
74
|
+
if (!Array.isArray(parsed)) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
return parsed.filter((entry) => typeof entry === "string");
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function writeRegistry(projects) {
|
|
84
|
+
mkdirSync(PARKER_GLOBAL_DIR, { recursive: true });
|
|
85
|
+
writeFileSync(getRegistryPath(), JSON.stringify(projects, null, 2) + "\n");
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Registers a project root so it can be cleaned up on global uninstall.
|
|
89
|
+
*/
|
|
90
|
+
export function registerProject(projectRoot) {
|
|
91
|
+
withRegistryLock(() => {
|
|
92
|
+
const projects = readRegistry();
|
|
93
|
+
if (!projects.includes(projectRoot)) {
|
|
94
|
+
projects.push(projectRoot);
|
|
95
|
+
writeRegistry(projects);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Removes a project root from the registry.
|
|
101
|
+
*/
|
|
102
|
+
export function unregisterProject(projectRoot) {
|
|
103
|
+
withRegistryLock(() => {
|
|
104
|
+
const projects = readRegistry();
|
|
105
|
+
const filtered = projects.filter((p) => p !== projectRoot);
|
|
106
|
+
writeRegistry(filtered);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Returns all registered project roots.
|
|
111
|
+
*/
|
|
112
|
+
export function getRegisteredProjects() {
|
|
113
|
+
return readRegistry();
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=project-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-registry.js","sourceRoot":"","sources":["../../../src/lib/project-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-registry_tests.d.ts","sourceRoot":"","sources":["../../../src/lib/project-registry_tests.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdirSync, rmSync, writeFileSync, existsSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { tmpdir } from "os";
|
|
5
|
+
/**
|
|
6
|
+
* project-registry reads PARKER_GLOBAL_DIR from constants, which resolves to ~/.parker.
|
|
7
|
+
* To test in isolation we mock the constant so the registry writes to a temp directory.
|
|
8
|
+
*/
|
|
9
|
+
import { vi } from "vitest";
|
|
10
|
+
let testDir;
|
|
11
|
+
vi.mock("../constants.js", () => {
|
|
12
|
+
// Lazy — testDir is set in beforeEach before any registry function runs
|
|
13
|
+
return {
|
|
14
|
+
get PARKER_GLOBAL_DIR() {
|
|
15
|
+
return testDir;
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
// Import after mock is set up
|
|
20
|
+
const { registerProject, unregisterProject, getRegisteredProjects } = await import("./project-registry.js");
|
|
21
|
+
describe("project-registry", () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
testDir = join(tmpdir(), `parker-reg-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
24
|
+
mkdirSync(testDir, { recursive: true });
|
|
25
|
+
});
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
28
|
+
});
|
|
29
|
+
it("returns empty list when no registry exists", () => {
|
|
30
|
+
expect(getRegisteredProjects()).toEqual([]);
|
|
31
|
+
});
|
|
32
|
+
it("registers a project", () => {
|
|
33
|
+
registerProject("/fake/project-a");
|
|
34
|
+
expect(getRegisteredProjects()).toEqual(["/fake/project-a"]);
|
|
35
|
+
});
|
|
36
|
+
it("does not duplicate an already-registered project", () => {
|
|
37
|
+
registerProject("/fake/project-a");
|
|
38
|
+
registerProject("/fake/project-a");
|
|
39
|
+
expect(getRegisteredProjects()).toEqual(["/fake/project-a"]);
|
|
40
|
+
});
|
|
41
|
+
it("registers multiple projects", () => {
|
|
42
|
+
registerProject("/fake/project-a");
|
|
43
|
+
registerProject("/fake/project-b");
|
|
44
|
+
expect(getRegisteredProjects()).toEqual(["/fake/project-a", "/fake/project-b"]);
|
|
45
|
+
});
|
|
46
|
+
it("unregisters a project", () => {
|
|
47
|
+
registerProject("/fake/project-a");
|
|
48
|
+
registerProject("/fake/project-b");
|
|
49
|
+
unregisterProject("/fake/project-a");
|
|
50
|
+
expect(getRegisteredProjects()).toEqual(["/fake/project-b"]);
|
|
51
|
+
});
|
|
52
|
+
it("unregister is a no-op for unknown project", () => {
|
|
53
|
+
registerProject("/fake/project-a");
|
|
54
|
+
unregisterProject("/fake/nonexistent");
|
|
55
|
+
expect(getRegisteredProjects()).toEqual(["/fake/project-a"]);
|
|
56
|
+
});
|
|
57
|
+
it("handles corrupted registry file gracefully", () => {
|
|
58
|
+
writeFileSync(join(testDir, "projects.json"), "not json{");
|
|
59
|
+
expect(getRegisteredProjects()).toEqual([]);
|
|
60
|
+
});
|
|
61
|
+
it("handles registry file with non-array content", () => {
|
|
62
|
+
writeFileSync(join(testDir, "projects.json"), '{"not": "an array"}');
|
|
63
|
+
expect(getRegisteredProjects()).toEqual([]);
|
|
64
|
+
});
|
|
65
|
+
it("filters out non-string entries", () => {
|
|
66
|
+
writeFileSync(join(testDir, "projects.json"), '["/valid", 42, null, true]');
|
|
67
|
+
expect(getRegisteredProjects()).toEqual(["/valid"]);
|
|
68
|
+
});
|
|
69
|
+
it("creates the global dir if it does not exist", () => {
|
|
70
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
71
|
+
registerProject("/fake/project-a");
|
|
72
|
+
expect(existsSync(join(testDir, "projects.json"))).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=project-registry_tests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-registry_tests.js","sourceRoot":"","sources":["../../../src/lib/project-registry_tests.ts"],"names":[],"mappings":"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"}
|