@uluops/setup 0.4.0 → 0.6.3
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/LICENSE +21 -0
- package/README.md +75 -60
- package/assets/auto-tracker-save.mjs +142 -0
- package/assets/{agents → claude-code/agents}/api-contract-validator-agent.md +9 -228
- package/assets/{agents → claude-code/agents}/aristotle-analyst-agent.md +51 -4
- package/assets/{agents → claude-code/agents}/aristotle-explorer-agent.md +6 -2
- package/assets/{agents → claude-code/agents}/aristotle-forecaster-agent.md +15 -230
- package/assets/{agents → claude-code/agents}/aristotle-validator-agent.md +12 -252
- package/assets/{agents → claude-code/agents}/assumption-excavator-agent.md +21 -247
- package/assets/{agents → claude-code/agents}/code-auditor-agent.md +12 -255
- package/assets/{agents → claude-code/agents}/code-optimizer-agent.md +15 -236
- package/assets/{agents → claude-code/agents}/code-validator-agent.md +31 -300
- package/assets/claude-code/agents/docs-validator-agent.md +472 -0
- package/assets/{agents → claude-code/agents}/frontend-validator-agent.md +15 -258
- package/assets/{agents → claude-code/agents}/mcp-validator-agent.md +8 -252
- package/assets/{agents → claude-code/agents}/pre-implementation-architect-agent.md +8 -224
- package/assets/{agents → claude-code/agents}/prompt-engineer-agent.md +57 -290
- package/assets/{agents → claude-code/agents}/prompt-pattern-analyzer-agent.md +10 -225
- package/assets/{agents → claude-code/agents}/prompt-quality-validator-agent.md +11 -249
- package/assets/{agents → claude-code/agents}/public-interface-validator-agent.md +15 -268
- package/assets/claude-code/agents/release-readiness-agent.md +495 -0
- package/assets/{agents → claude-code/agents}/security-analyst-agent.md +236 -480
- package/assets/{agents → claude-code/agents}/test-architect-agent.md +16 -259
- package/assets/{agents → claude-code/agents}/type-safety-validator-agent.md +23 -266
- package/assets/{agents → claude-code/agents}/workflow-synthesis-agent.md +23 -226
- package/assets/{commands → claude-code/commands}/agents/anxiety-reader.md +12 -15
- package/assets/{commands → claude-code/commands}/agents/api-contract.md +156 -136
- package/assets/{commands → claude-code/commands}/agents/architect.md +156 -136
- package/assets/claude-code/commands/agents/aristotle-analyst.md +157 -0
- package/assets/claude-code/commands/agents/aristotle-explorer.md +157 -0
- package/assets/claude-code/commands/agents/aristotle-forecaster.md +157 -0
- package/assets/claude-code/commands/agents/aristotle-validator.md +157 -0
- package/assets/{commands → claude-code/commands}/agents/assumption-excavator.md +49 -7
- package/assets/{commands → claude-code/commands}/agents/audit.md +156 -137
- package/assets/{commands → claude-code/commands}/agents/docs-validate.md +156 -134
- package/assets/{commands → claude-code/commands}/agents/frontend.md +156 -136
- package/assets/{commands → claude-code/commands}/agents/mcp-validate.md +156 -137
- package/assets/{commands → claude-code/commands}/agents/optimize.md +156 -134
- package/assets/{commands → claude-code/commands}/agents/pattern-analyzer.md +150 -127
- package/assets/{commands → claude-code/commands}/agents/prompt-quality.md +155 -135
- package/assets/claude-code/commands/agents/prompt-validate.md +155 -0
- package/assets/{commands → claude-code/commands}/agents/public-interface.md +156 -135
- package/assets/{commands → claude-code/commands}/agents/release.md +156 -136
- package/assets/{commands → claude-code/commands}/agents/security.md +156 -138
- package/assets/{commands → claude-code/commands}/agents/test-review.md +156 -137
- package/assets/{commands → claude-code/commands}/agents/type-safety.md +156 -136
- package/assets/{commands/agents/code-validate.md → claude-code/commands/agents/validate.md} +156 -135
- package/assets/claude-code/commands/agents/workflow-synthesis.md +157 -0
- package/assets/{commands → claude-code/commands}/pipelines/aristotle.md +8 -8
- package/assets/{commands → claude-code/commands}/pipelines/ship.md +8 -8
- package/assets/claude-code/commands/workflows/post-implementation.md +60 -0
- package/assets/claude-code/commands/workflows/pre-implementation.md +46 -0
- package/assets/{commands → claude-code/commands}/workflows/prompt-audit.md +2 -2
- package/assets/codex/agents/anxiety-reader-agent.toml +462 -0
- package/assets/codex/agents/api-contract-validator-agent.toml +738 -0
- package/assets/codex/agents/aristotle-analyst-agent.toml +750 -0
- package/assets/codex/agents/aristotle-explorer-agent.toml +155 -0
- package/assets/codex/agents/aristotle-forecaster-agent.toml +449 -0
- package/assets/codex/agents/aristotle-validator-agent.toml +424 -0
- package/assets/codex/agents/assumption-excavator-agent.toml +1126 -0
- package/assets/codex/agents/code-auditor-agent.toml +815 -0
- package/assets/codex/agents/code-optimizer-agent.toml +652 -0
- package/assets/codex/agents/code-validator-agent.toml +573 -0
- package/assets/codex/agents/docs-validator-agent.toml +468 -0
- package/assets/codex/agents/frontend-validator-agent.toml +598 -0
- package/assets/codex/agents/mcp-validator-agent.toml +580 -0
- package/assets/codex/agents/pre-implementation-architect-agent.toml +817 -0
- package/assets/codex/agents/prompt-engineer-agent.toml +922 -0
- package/assets/codex/agents/prompt-pattern-analyzer-agent.toml +689 -0
- package/assets/codex/agents/prompt-quality-validator-agent.toml +777 -0
- package/assets/codex/agents/public-interface-validator-agent.toml +695 -0
- package/assets/codex/agents/release-readiness-agent.toml +491 -0
- package/assets/codex/agents/security-analyst-agent.toml +847 -0
- package/assets/codex/agents/test-architect-agent.toml +615 -0
- package/assets/codex/agents/type-safety-validator-agent.toml +686 -0
- package/assets/codex/agents/workflow-synthesis-agent.toml +631 -0
- package/assets/gemini-cli/agents/anxiety-reader-agent.md +470 -0
- package/assets/gemini-cli/agents/api-contract-validator-agent.md +747 -0
- package/assets/gemini-cli/agents/aristotle-analyst-agent.md +758 -0
- package/assets/gemini-cli/agents/aristotle-explorer-agent.md +163 -0
- package/assets/gemini-cli/agents/aristotle-forecaster-agent.md +457 -0
- package/assets/gemini-cli/agents/aristotle-validator-agent.md +432 -0
- package/assets/gemini-cli/agents/assumption-excavator-agent.md +1134 -0
- package/assets/gemini-cli/agents/code-auditor-agent.md +827 -0
- package/assets/gemini-cli/agents/code-optimizer-agent.md +661 -0
- package/assets/gemini-cli/agents/code-validator-agent.md +582 -0
- package/assets/gemini-cli/agents/docs-validator-agent.md +477 -0
- package/assets/gemini-cli/agents/frontend-validator-agent.md +610 -0
- package/assets/gemini-cli/agents/mcp-validator-agent.md +589 -0
- package/assets/gemini-cli/agents/pre-implementation-architect-agent.md +826 -0
- package/assets/gemini-cli/agents/prompt-engineer-agent.md +931 -0
- package/assets/gemini-cli/agents/prompt-pattern-analyzer-agent.md +698 -0
- package/assets/gemini-cli/agents/prompt-quality-validator-agent.md +786 -0
- package/assets/gemini-cli/agents/public-interface-validator-agent.md +707 -0
- package/assets/gemini-cli/agents/release-readiness-agent.md +500 -0
- package/assets/gemini-cli/agents/security-analyst-agent.md +859 -0
- package/assets/gemini-cli/agents/test-architect-agent.md +624 -0
- package/assets/gemini-cli/agents/type-safety-validator-agent.md +695 -0
- package/assets/gemini-cli/agents/workflow-synthesis-agent.md +639 -0
- package/assets/gemini-cli/commands/agents/anxiety-reader.toml +155 -0
- package/assets/gemini-cli/commands/agents/api-contract.toml +154 -0
- package/assets/gemini-cli/commands/agents/architect.toml +154 -0
- package/assets/gemini-cli/commands/agents/aristotle-analyst.toml +155 -0
- package/assets/gemini-cli/commands/agents/aristotle-explorer.toml +155 -0
- package/assets/gemini-cli/commands/agents/aristotle-forecaster.toml +155 -0
- package/assets/gemini-cli/commands/agents/aristotle-validator.toml +155 -0
- package/assets/gemini-cli/commands/agents/assumption-excavator.toml +155 -0
- package/assets/gemini-cli/commands/agents/audit.toml +154 -0
- package/assets/gemini-cli/commands/agents/docs-validate.toml +154 -0
- package/assets/gemini-cli/commands/agents/frontend.toml +154 -0
- package/assets/gemini-cli/commands/agents/mcp-validate.toml +154 -0
- package/assets/gemini-cli/commands/agents/optimize.toml +154 -0
- package/assets/gemini-cli/commands/agents/pattern-analyzer.toml +148 -0
- package/assets/gemini-cli/commands/agents/prompt-quality.toml +153 -0
- package/assets/gemini-cli/commands/agents/prompt-validate.toml +153 -0
- package/assets/gemini-cli/commands/agents/public-interface.toml +154 -0
- package/assets/gemini-cli/commands/agents/release.toml +154 -0
- package/assets/gemini-cli/commands/agents/security.toml +154 -0
- package/assets/gemini-cli/commands/agents/test-review.toml +154 -0
- package/assets/gemini-cli/commands/agents/type-safety.toml +154 -0
- package/assets/gemini-cli/commands/agents/validate.toml +154 -0
- package/assets/gemini-cli/commands/agents/workflow-synthesis.toml +155 -0
- package/assets/gemini-cli/commands/pipelines/aristotle.toml +139 -0
- package/assets/gemini-cli/commands/pipelines/ship.toml +184 -0
- package/assets/gemini-cli/commands/workflows/post-implementation.toml +56 -0
- package/assets/gemini-cli/commands/workflows/pre-implementation.toml +42 -0
- package/assets/gemini-cli/commands/workflows/prompt-audit.toml +40 -0
- package/assets/opencode/agents/anxiety-reader-agent.md +472 -0
- package/assets/opencode/agents/api-contract-validator-agent.md +749 -0
- package/assets/opencode/agents/aristotle-analyst-agent.md +760 -0
- package/assets/opencode/agents/aristotle-explorer-agent.md +164 -0
- package/assets/opencode/agents/aristotle-forecaster-agent.md +459 -0
- package/assets/opencode/agents/aristotle-validator-agent.md +434 -0
- package/assets/opencode/agents/assumption-excavator-agent.md +1136 -0
- package/assets/opencode/agents/code-auditor-agent.md +826 -0
- package/assets/opencode/agents/code-optimizer-agent.md +663 -0
- package/assets/opencode/agents/code-validator-agent.md +584 -0
- package/assets/opencode/agents/docs-validator-agent.md +479 -0
- package/assets/opencode/agents/frontend-validator-agent.md +609 -0
- package/assets/opencode/agents/mcp-validator-agent.md +591 -0
- package/assets/opencode/agents/pre-implementation-architect-agent.md +828 -0
- package/assets/opencode/agents/prompt-engineer-agent.md +933 -0
- package/assets/opencode/agents/prompt-pattern-analyzer-agent.md +700 -0
- package/assets/opencode/agents/prompt-quality-validator-agent.md +788 -0
- package/assets/opencode/agents/public-interface-validator-agent.md +706 -0
- package/assets/opencode/agents/release-readiness-agent.md +502 -0
- package/assets/opencode/agents/security-analyst-agent.md +858 -0
- package/assets/opencode/agents/test-architect-agent.md +626 -0
- package/assets/opencode/agents/type-safety-validator-agent.md +697 -0
- package/assets/opencode/agents/workflow-synthesis-agent.md +641 -0
- package/dist/cli.js +49 -416
- package/dist/commands/helpers.d.ts +73 -0
- package/dist/commands/helpers.js +311 -0
- package/dist/commands/setup.d.ts +13 -0
- package/dist/commands/setup.js +93 -0
- package/dist/commands/uninstall.d.ts +3 -0
- package/dist/commands/uninstall.js +126 -0
- package/dist/commands/verify.d.ts +1 -0
- package/dist/commands/verify.js +28 -0
- package/dist/harnesses/claude-code.d.ts +1 -1
- package/dist/harnesses/claude-code.js +3 -1
- package/dist/harnesses/codex.js +6 -5
- package/dist/harnesses/gemini-cli.d.ts +4 -8
- package/dist/harnesses/gemini-cli.js +47 -21
- package/dist/harnesses/index.d.ts +10 -1
- package/dist/harnesses/index.js +11 -2
- package/dist/harnesses/opencode.d.ts +1 -1
- package/dist/harnesses/opencode.js +17 -8
- package/dist/harnesses/types.d.ts +19 -0
- package/dist/harnesses/types.js +2 -0
- package/dist/lib/asset-catalog.js +2 -2
- package/dist/lib/config-merger.d.ts +2 -1
- package/dist/lib/config-merger.js +15 -7
- package/dist/lib/file-ops.d.ts +5 -0
- package/dist/lib/file-ops.js +18 -3
- package/dist/lib/hash.d.ts +1 -1
- package/dist/lib/hash.js +2 -2
- package/dist/lib/manifest.d.ts +30 -1
- package/dist/lib/manifest.js +5 -7
- package/dist/lib/paths.d.ts +16 -1
- package/dist/lib/paths.js +31 -3
- package/dist/lib/settings-merger.d.ts +24 -9
- package/dist/lib/settings-merger.js +57 -22
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.js +10 -0
- package/dist/steps/agents.d.ts +1 -2
- package/dist/steps/agents.js +7 -18
- package/dist/steps/auth.d.ts +6 -0
- package/dist/steps/auth.js +19 -2
- package/dist/steps/cli.d.ts +53 -0
- package/dist/steps/cli.js +90 -0
- package/dist/steps/commands.d.ts +1 -1
- package/dist/steps/commands.js +20 -71
- package/dist/steps/detect.js +4 -0
- package/dist/steps/mcp.js +7 -15
- package/dist/steps/metrics.d.ts +12 -0
- package/dist/steps/metrics.js +52 -22
- package/dist/steps/shell.js +11 -1
- package/dist/steps/signup.d.ts +2 -2
- package/dist/steps/signup.js +9 -12
- package/dist/steps/verify.js +47 -8
- package/package.json +12 -11
- package/assets/agents/docs-validator-agent.md +0 -490
- package/assets/agents/release-readiness-agent.md +0 -482
- package/assets/commands/agents/aristotle-analyst.md +0 -116
- package/assets/commands/agents/aristotle-explorer.md +0 -93
- package/assets/commands/agents/aristotle-forecaster.md +0 -115
- package/assets/commands/agents/aristotle-validator.md +0 -115
- package/assets/commands/agents/prompt-validate.md +0 -136
- package/assets/commands/agents/workflow-synthesis.md +0 -102
- package/assets/commands/workflows/post-implementation.md +0 -577
- package/assets/commands/workflows/pre-implementation.md +0 -670
- /package/assets/{agents → claude-code/agents}/anxiety-reader-agent.md +0 -0
|
@@ -1,41 +1,67 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Gemini CLI Harness Profile
|
|
2
|
+
* Gemini CLI Harness Profile
|
|
3
3
|
*
|
|
4
4
|
* Paths and metadata are verified from vendor docs.
|
|
5
5
|
* MCP config uses `mcpServers` key (same shape as Claude Code)
|
|
6
6
|
* but at a different file path (~/.gemini/settings.json).
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Note: Gemini CLI cannot have underscores in MCP server names
|
|
12
|
-
* (FQN format mcp_serverName_toolName uses underscore as delimiter).
|
|
13
|
-
* Our names use hyphens — safe.
|
|
8
|
+
* Gemini CLI requires `trust: true` in MCP server config to
|
|
9
|
+
* allow automatic tool execution without confirmation prompts.
|
|
14
10
|
*/
|
|
15
11
|
import { homedir } from "node:os";
|
|
16
12
|
import { join } from "node:path";
|
|
17
|
-
import {
|
|
13
|
+
import { ULUOPS_SERVERS, } from "./types.js";
|
|
14
|
+
import { readConfig, mergeUluopsMcp, removeUluopsMcp, writeConfig, } from "../lib/config-merger.js";
|
|
15
|
+
import { readSettings, writeSettings, mergeUluopsHook, removeUluopsHook, hasUluopsHook, } from "../lib/settings-merger.js";
|
|
18
16
|
class GeminiMcpConfig {
|
|
19
|
-
async read() {
|
|
20
|
-
|
|
17
|
+
async read(path) {
|
|
18
|
+
return readConfig(path);
|
|
19
|
+
}
|
|
20
|
+
merge(config, apiKey) {
|
|
21
|
+
// Gemini CLI requires trust: true for a smooth experience
|
|
22
|
+
return mergeUluopsMcp(config, apiKey, true);
|
|
23
|
+
}
|
|
24
|
+
remove(config) {
|
|
25
|
+
return removeUluopsMcp(config);
|
|
21
26
|
}
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
async write(path, config) {
|
|
28
|
+
await writeConfig(path, config);
|
|
24
29
|
}
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
check(config) {
|
|
31
|
+
const servers = config["mcpServers"];
|
|
32
|
+
if (!servers)
|
|
33
|
+
return false;
|
|
34
|
+
return ULUOPS_SERVERS.every((name) => name in servers);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
class GeminiHooks {
|
|
38
|
+
static HOOK_TYPE = "AfterTool";
|
|
39
|
+
static MATCHER = "invoke_agent";
|
|
40
|
+
async install(settingsPath, hookCommand, dryRun) {
|
|
41
|
+
if (dryRun)
|
|
42
|
+
return true;
|
|
43
|
+
const settings = await readSettings(settingsPath);
|
|
44
|
+
const merged = mergeUluopsHook(settings, hookCommand, GeminiHooks.HOOK_TYPE, GeminiHooks.MATCHER);
|
|
45
|
+
await writeSettings(settingsPath, merged);
|
|
46
|
+
return true;
|
|
27
47
|
}
|
|
28
|
-
async
|
|
29
|
-
|
|
48
|
+
async remove(settingsPath, dryRun) {
|
|
49
|
+
if (dryRun)
|
|
50
|
+
return;
|
|
51
|
+
const settings = await readSettings(settingsPath);
|
|
52
|
+
const cleaned = removeUluopsHook(settings, GeminiHooks.HOOK_TYPE);
|
|
53
|
+
await writeSettings(settingsPath, cleaned);
|
|
30
54
|
}
|
|
31
|
-
check() {
|
|
32
|
-
|
|
55
|
+
async check(settingsPath) {
|
|
56
|
+
const settings = await readSettings(settingsPath);
|
|
57
|
+
return hasUluopsHook(settings, GeminiHooks.HOOK_TYPE);
|
|
33
58
|
}
|
|
34
59
|
}
|
|
35
60
|
const home = join(homedir(), ".gemini");
|
|
36
61
|
export const geminiCliProfile = {
|
|
37
62
|
name: "gemini-cli",
|
|
38
63
|
displayName: "Gemini CLI",
|
|
64
|
+
status: "stable",
|
|
39
65
|
homeDir: home,
|
|
40
66
|
agentFormat: "markdown",
|
|
41
67
|
factoryTarget: "gemini-cli",
|
|
@@ -46,9 +72,9 @@ export const geminiCliProfile = {
|
|
|
46
72
|
localMcpConfig: ".gemini/settings.json",
|
|
47
73
|
agentsDir: join(home, "agents"),
|
|
48
74
|
commandsDir: join(home, "commands"),
|
|
49
|
-
settingsPath:
|
|
50
|
-
toolsDir:
|
|
75
|
+
settingsPath: join(home, "settings.json"),
|
|
76
|
+
toolsDir: join(home, "tools", "agent-metrics"),
|
|
51
77
|
},
|
|
52
78
|
mcpConfig: new GeminiMcpConfig(),
|
|
53
|
-
hooks:
|
|
79
|
+
hooks: new GeminiHooks(),
|
|
54
80
|
};
|
|
@@ -12,7 +12,16 @@ export declare const ALL_PROFILES: readonly HarnessProfile[];
|
|
|
12
12
|
export declare function resolveHarnessName(input: string): string;
|
|
13
13
|
/** Get a harness profile by name or alias. Throws if not found. */
|
|
14
14
|
export declare function getProfile(name: string): HarnessProfile;
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Detect which harnesses are installed by probing home directories.
|
|
17
|
+
*
|
|
18
|
+
* Excludes experimental profiles even when their home dir is present:
|
|
19
|
+
* auto-detection should never return a profile that will throw
|
|
20
|
+
* HarnessNotTestedError on use. Users can still opt in with
|
|
21
|
+
* `--harness <name>`, which goes through getProfile() and surfaces the
|
|
22
|
+
* explicit error message — the relational promise "in the detected
|
|
23
|
+
* list = safe to install" is preserved.
|
|
24
|
+
*/
|
|
16
25
|
export declare function detectHarnesses(): HarnessProfile[];
|
|
17
26
|
/** List all available harness names (not aliases). */
|
|
18
27
|
export declare function listHarnesses(): string[];
|
package/dist/harnesses/index.js
CHANGED
|
@@ -35,9 +35,18 @@ export function getProfile(name) {
|
|
|
35
35
|
}
|
|
36
36
|
return profile;
|
|
37
37
|
}
|
|
38
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Detect which harnesses are installed by probing home directories.
|
|
40
|
+
*
|
|
41
|
+
* Excludes experimental profiles even when their home dir is present:
|
|
42
|
+
* auto-detection should never return a profile that will throw
|
|
43
|
+
* HarnessNotTestedError on use. Users can still opt in with
|
|
44
|
+
* `--harness <name>`, which goes through getProfile() and surfaces the
|
|
45
|
+
* explicit error message — the relational promise "in the detected
|
|
46
|
+
* list = safe to install" is preserved.
|
|
47
|
+
*/
|
|
39
48
|
export function detectHarnesses() {
|
|
40
|
-
return ALL_PROFILES.filter((p) => existsSync(p.paths.home));
|
|
49
|
+
return ALL_PROFILES.filter((p) => p.status === "stable" && existsSync(p.paths.home));
|
|
41
50
|
}
|
|
42
51
|
/** List all available harness names (not aliases). */
|
|
43
52
|
export function listHarnesses() {
|
|
@@ -12,11 +12,10 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { readFile } from "node:fs/promises";
|
|
14
14
|
import { homedir } from "node:os";
|
|
15
|
-
import { join } from "node:path";
|
|
15
|
+
import { join, isAbsolute } from "node:path";
|
|
16
16
|
import { parse as parseJsonc } from "jsonc-parser";
|
|
17
|
-
import { ConfigParseError } from "./types.js";
|
|
17
|
+
import { ULUOPS_SERVERS, ConfigParseError } from "./types.js";
|
|
18
18
|
import { atomicWrite } from "../lib/atomic-write.js";
|
|
19
|
-
const ULUOPS_SERVERS = ["uluops-tracker", "uluops-registry"];
|
|
20
19
|
class OpenCodeMcpConfig {
|
|
21
20
|
/** Maps requested path → actual resolved path (for .jsonc fallback). */
|
|
22
21
|
resolvedPaths = new Map();
|
|
@@ -50,17 +49,17 @@ class OpenCodeMcpConfig {
|
|
|
50
49
|
const existing = (typeof raw === "object" && raw !== null ? raw : {});
|
|
51
50
|
const tracker = {
|
|
52
51
|
type: "local",
|
|
53
|
-
command: ["npx", "-y", "uluops-
|
|
52
|
+
command: ["npx", "-y", "@uluops/ops-mcp"],
|
|
54
53
|
enabled: true,
|
|
55
54
|
timeout: 30000,
|
|
56
55
|
environment: {
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
ULUOPS_BASE_URL: "https://api.uluops.ai/api/v1",
|
|
57
|
+
ULUOPS_API_KEY: apiKey,
|
|
59
58
|
},
|
|
60
59
|
};
|
|
61
60
|
const registry = {
|
|
62
61
|
type: "local",
|
|
63
|
-
command: ["npx", "-y", "uluops
|
|
62
|
+
command: ["npx", "-y", "@uluops/registry-mcp"],
|
|
64
63
|
enabled: true,
|
|
65
64
|
timeout: 30000,
|
|
66
65
|
environment: {
|
|
@@ -107,11 +106,21 @@ class OpenCodeMcpConfig {
|
|
|
107
106
|
return ULUOPS_SERVERS.every((name) => name in mcp);
|
|
108
107
|
}
|
|
109
108
|
}
|
|
110
|
-
const xdgConfig =
|
|
109
|
+
const xdgConfig = (() => {
|
|
110
|
+
const env = process.env["XDG_CONFIG_HOME"];
|
|
111
|
+
if (env) {
|
|
112
|
+
if (!isAbsolute(env) || env.includes("..")) {
|
|
113
|
+
throw new Error(`XDG_CONFIG_HOME must be an absolute path without traversal: ${env}`);
|
|
114
|
+
}
|
|
115
|
+
return env;
|
|
116
|
+
}
|
|
117
|
+
return join(homedir(), ".config");
|
|
118
|
+
})();
|
|
111
119
|
const home = join(xdgConfig, "opencode");
|
|
112
120
|
export const opencodeProfile = {
|
|
113
121
|
name: "opencode",
|
|
114
122
|
displayName: "OpenCode",
|
|
123
|
+
status: "stable",
|
|
115
124
|
homeDir: home,
|
|
116
125
|
agentFormat: "markdown",
|
|
117
126
|
factoryTarget: "opencode",
|
|
@@ -5,12 +5,29 @@
|
|
|
5
5
|
* Each harness (Claude Code, OpenCode, Codex, Gemini CLI) implements
|
|
6
6
|
* these interfaces to encapsulate its config format, paths, and capabilities.
|
|
7
7
|
*/
|
|
8
|
+
/**
|
|
9
|
+
* Maturity status of a harness profile.
|
|
10
|
+
*
|
|
11
|
+
* - `"stable"` — implementation is tested end-to-end and safe to auto-detect.
|
|
12
|
+
* detectHarnesses() returns these.
|
|
13
|
+
* - `"experimental"` — scaffold only; throws HarnessNotTestedError on most
|
|
14
|
+
* operations. getProfile() still resolves these (so `--harness <name>`
|
|
15
|
+
* surfaces the explicit error), but detectHarnesses() filters them out so
|
|
16
|
+
* automatic install never picks an unusable profile.
|
|
17
|
+
*/
|
|
18
|
+
export type HarnessStatus = "stable" | "experimental";
|
|
8
19
|
/** Static definition of a harness — no runtime state. */
|
|
9
20
|
export interface HarnessProfile {
|
|
10
21
|
/** Canonical name (e.g., 'claude-code', 'opencode', 'codex', 'gemini-cli') */
|
|
11
22
|
readonly name: string;
|
|
12
23
|
/** Display name for CLI output (e.g., 'Claude Code', 'OpenCode') */
|
|
13
24
|
readonly displayName: string;
|
|
25
|
+
/**
|
|
26
|
+
* Maturity status. Experimental profiles are excluded from auto-detection
|
|
27
|
+
* but still accept an explicit `--harness` flag so users can opt in to
|
|
28
|
+
* the not-yet-tested error surface.
|
|
29
|
+
*/
|
|
30
|
+
readonly status: HarnessStatus;
|
|
14
31
|
/** Home directory for this harness */
|
|
15
32
|
readonly homeDir: string;
|
|
16
33
|
/** Agent definition format */
|
|
@@ -76,6 +93,8 @@ export interface HookStrategy {
|
|
|
76
93
|
/** Check if hook is currently installed. */
|
|
77
94
|
check(settingsPath: string): Promise<boolean>;
|
|
78
95
|
}
|
|
96
|
+
/** MCP server names installed by UluOps setup. Shared across all harnesses. */
|
|
97
|
+
export declare const ULUOPS_SERVERS: readonly ["uluops-tracker", "uluops-registry"];
|
|
79
98
|
/** Thrown when a harness config file cannot be parsed. */
|
|
80
99
|
export declare class ConfigParseError extends Error {
|
|
81
100
|
readonly path: string;
|
package/dist/harnesses/types.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* Each harness (Claude Code, OpenCode, Codex, Gemini CLI) implements
|
|
6
6
|
* these interfaces to encapsulate its config format, paths, and capabilities.
|
|
7
7
|
*/
|
|
8
|
+
/** MCP server names installed by UluOps setup. Shared across all harnesses. */
|
|
9
|
+
export const ULUOPS_SERVERS = ["uluops-tracker", "uluops-registry"];
|
|
8
10
|
/** Thrown when a harness config file cannot be parsed. */
|
|
9
11
|
export class ConfigParseError extends Error {
|
|
10
12
|
path;
|
|
@@ -48,9 +48,9 @@ async function scanCommandDir(dir) {
|
|
|
48
48
|
}
|
|
49
49
|
/** Get all agent command entries from assets. */
|
|
50
50
|
export async function getAgentCommands() {
|
|
51
|
-
return scanCommandDir(join(ASSETS_DIR, "commands", "agents"));
|
|
51
|
+
return scanCommandDir(join(ASSETS_DIR, "claude-code", "commands", "agents"));
|
|
52
52
|
}
|
|
53
53
|
/** Get all workflow command entries from assets. */
|
|
54
54
|
export async function getWorkflowCommands() {
|
|
55
|
-
return scanCommandDir(join(ASSETS_DIR, "commands", "workflows"));
|
|
55
|
+
return scanCommandDir(join(ASSETS_DIR, "claude-code", "commands", "workflows"));
|
|
56
56
|
}
|
|
@@ -2,6 +2,7 @@ interface McpServerConfig {
|
|
|
2
2
|
command: string;
|
|
3
3
|
args: string[];
|
|
4
4
|
env: Record<string, string>;
|
|
5
|
+
trust?: boolean;
|
|
5
6
|
}
|
|
6
7
|
export interface ClaudeConfig {
|
|
7
8
|
mcpServers?: Record<string, McpServerConfig>;
|
|
@@ -20,7 +21,7 @@ export declare function readConfig(path: string): Promise<ClaudeConfig>;
|
|
|
20
21
|
/**
|
|
21
22
|
* Merge UluOps MCP server entries into a config, preserving all other keys.
|
|
22
23
|
*/
|
|
23
|
-
export declare function mergeUluopsMcp(config: ClaudeConfig, apiKey: string): ClaudeConfig;
|
|
24
|
+
export declare function mergeUluopsMcp(config: ClaudeConfig, apiKey: string, trust?: boolean): ClaudeConfig;
|
|
24
25
|
/**
|
|
25
26
|
* Remove UluOps MCP server entries from a config.
|
|
26
27
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { atomicWrite } from "./atomic-write.js";
|
|
3
|
-
const MCP_PACKAGES = ["uluops-
|
|
3
|
+
const MCP_PACKAGES = ["@uluops/ops-mcp", "@uluops/registry-mcp"];
|
|
4
4
|
/** Check whether the UluOps MCP client packages exist on the npm registry. Returns lists of available and missing packages. */
|
|
5
5
|
export async function checkMcpPackageAvailability() {
|
|
6
6
|
const available = [];
|
|
@@ -36,32 +36,40 @@ export async function readConfig(path) {
|
|
|
36
36
|
catch {
|
|
37
37
|
return {}; // File doesn't exist — fresh config
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(raw);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
throw new Error(`Failed to parse config at ${path} — file contains invalid JSON`);
|
|
44
|
+
}
|
|
40
45
|
}
|
|
41
46
|
/**
|
|
42
47
|
* Merge UluOps MCP server entries into a config, preserving all other keys.
|
|
43
48
|
*/
|
|
44
|
-
export function mergeUluopsMcp(config, apiKey) {
|
|
49
|
+
export function mergeUluopsMcp(config, apiKey, trust = false) {
|
|
45
50
|
const existing = config.mcpServers ?? {};
|
|
51
|
+
const trustField = trust ? { trust: true } : {};
|
|
46
52
|
return {
|
|
47
53
|
...config,
|
|
48
54
|
mcpServers: {
|
|
49
55
|
...existing,
|
|
50
56
|
"uluops-tracker": {
|
|
51
57
|
command: "npx",
|
|
52
|
-
args: ["-y", "uluops-
|
|
58
|
+
args: ["-y", "@uluops/ops-mcp"],
|
|
53
59
|
env: {
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
ULUOPS_BASE_URL: "https://api.uluops.ai/api/v1",
|
|
61
|
+
ULUOPS_API_KEY: apiKey,
|
|
56
62
|
},
|
|
63
|
+
...trustField,
|
|
57
64
|
},
|
|
58
65
|
"uluops-registry": {
|
|
59
66
|
command: "npx",
|
|
60
|
-
args: ["-y", "uluops
|
|
67
|
+
args: ["-y", "@uluops/registry-mcp"],
|
|
61
68
|
env: {
|
|
62
69
|
ULUOPS_REGISTRY_URL: "https://api.uluops.ai/api/v1/registry",
|
|
63
70
|
ULUOPS_API_KEY: apiKey,
|
|
64
71
|
},
|
|
72
|
+
...trustField,
|
|
65
73
|
},
|
|
66
74
|
},
|
|
67
75
|
};
|
package/dist/lib/file-ops.d.ts
CHANGED
|
@@ -27,3 +27,8 @@ export declare function syncAssets(opts: {
|
|
|
27
27
|
removed: number;
|
|
28
28
|
files: string[];
|
|
29
29
|
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Back up a file to the UluOps backup directory before modifying it.
|
|
32
|
+
* No-op if the source file doesn't exist.
|
|
33
|
+
*/
|
|
34
|
+
export declare function backupFile(srcPath: string, backupDir: string): Promise<void>;
|
package/dist/lib/file-ops.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readFile, writeFile, mkdir, unlink } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
1
|
+
import { readFile, writeFile, mkdir, unlink, access, copyFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { join, basename } from "node:path";
|
|
3
3
|
import { fileHash } from "./hash.js";
|
|
4
4
|
/**
|
|
5
5
|
* Copy a file if its content has changed (hash comparison). Returns "copied" or "skipped".
|
|
@@ -62,7 +62,6 @@ export async function unlinkFiles(dir, files) {
|
|
|
62
62
|
* Returns list of copied files, skipped count, and removed count (for old manifest entries).
|
|
63
63
|
*/
|
|
64
64
|
export async function syncAssets(opts) {
|
|
65
|
-
const { readdir } = await import("node:fs/promises");
|
|
66
65
|
if (!opts.dryRun) {
|
|
67
66
|
await mkdir(opts.destDir, { recursive: true });
|
|
68
67
|
}
|
|
@@ -105,3 +104,19 @@ export async function syncAssets(opts) {
|
|
|
105
104
|
}
|
|
106
105
|
return { copied, skipped, removed, files: assetFiles };
|
|
107
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Back up a file to the UluOps backup directory before modifying it.
|
|
109
|
+
* No-op if the source file doesn't exist.
|
|
110
|
+
*/
|
|
111
|
+
export async function backupFile(srcPath, backupDir) {
|
|
112
|
+
try {
|
|
113
|
+
await access(srcPath);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return; // Nothing to back up
|
|
117
|
+
}
|
|
118
|
+
await mkdir(backupDir, { recursive: true });
|
|
119
|
+
const filename = basename(srcPath);
|
|
120
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
121
|
+
await copyFile(srcPath, join(backupDir, `${filename}.${timestamp}.bak`));
|
|
122
|
+
}
|
package/dist/lib/hash.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** Return
|
|
1
|
+
/** Return the full SHA-256 hash (64 hex chars) of the given string content. */
|
|
2
2
|
export declare function fileHash(content: string): string;
|
package/dist/lib/hash.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
/** Return
|
|
2
|
+
/** Return the full SHA-256 hash (64 hex chars) of the given string content. */
|
|
3
3
|
export function fileHash(content) {
|
|
4
|
-
return createHash("sha256").update(content).digest("hex")
|
|
4
|
+
return createHash("sha256").update(content).digest("hex");
|
|
5
5
|
}
|
package/dist/lib/manifest.d.ts
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identifier for a single harness installation in the manifest.
|
|
3
|
+
*
|
|
4
|
+
* Today this is the profile name (e.g. `"claude-code"`), assuming a
|
|
5
|
+
* one-to-one mapping between profiles and installations. The day that
|
|
6
|
+
* assumption breaks — multiple Claude Code installs (project vs global,
|
|
7
|
+
* NVM versions, parallel beta channels) — this becomes the seam where
|
|
8
|
+
* fracture surfaces. When that happens, the right migration is to extend
|
|
9
|
+
* keys to `{profile.name}@{stable-instance-id}` (e.g. a hash of toolsDir)
|
|
10
|
+
* rather than overwriting silently. The type alias exists so the
|
|
11
|
+
* assumption is documented in the schema, not the comments.
|
|
12
|
+
*/
|
|
13
|
+
export type HarnessInstanceKey = string;
|
|
1
14
|
/** Per-harness installation state. */
|
|
2
15
|
export interface HarnessManifest {
|
|
3
16
|
installedAt: string;
|
|
@@ -9,13 +22,29 @@ export interface HarnessManifest {
|
|
|
9
22
|
agents: string[];
|
|
10
23
|
commands: string[];
|
|
11
24
|
hooksInstalled: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Version of @uluops/agent-metrics whose dist/ was copied into the harness tree.
|
|
27
|
+
* Null when hooks are not installed or when the manifest predates this field.
|
|
28
|
+
* Verify uses this to detect drift between installed and currently-resolvable versions —
|
|
29
|
+
* the shared version ledger across the setup↔agent-metrics seam.
|
|
30
|
+
*/
|
|
31
|
+
hooksInstalledVersion?: string | null;
|
|
12
32
|
}
|
|
13
33
|
/** Top-level manifest with per-harness entries. */
|
|
14
34
|
export interface Manifest {
|
|
15
35
|
version: string;
|
|
16
36
|
installedAt: string;
|
|
17
37
|
shellModified: boolean;
|
|
18
|
-
harnesses: Record<
|
|
38
|
+
harnesses: Record<HarnessInstanceKey, HarnessManifest>;
|
|
39
|
+
/**
|
|
40
|
+
* Tracks whether `@uluops/cli` was installed globally by this setup run.
|
|
41
|
+
* Null/false when not installed by setup (user-installed or never installed).
|
|
42
|
+
* Uninstall only removes the global package when this is true — we don't
|
|
43
|
+
* remove what we didn't install.
|
|
44
|
+
*/
|
|
45
|
+
cliInstalled?: boolean;
|
|
46
|
+
/** Version reported by `ulu --version` at install time, for drift detection. */
|
|
47
|
+
cliInstalledVersion?: string | null;
|
|
19
48
|
contentHash?: string;
|
|
20
49
|
}
|
|
21
50
|
export interface ManifestValidationResult {
|
package/dist/lib/manifest.js
CHANGED
|
@@ -110,13 +110,11 @@ async function pathExists(p) {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
async function findMissingFiles(baseDir, subDir, files) {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
return missing;
|
|
113
|
+
const results = await Promise.all(files.map(async (file) => ({
|
|
114
|
+
file,
|
|
115
|
+
exists: await pathExists(join(baseDir, subDir, file)),
|
|
116
|
+
})));
|
|
117
|
+
return results.filter((r) => !r.exists).map((r) => r.file);
|
|
120
118
|
}
|
|
121
119
|
async function readManifestFile(path) {
|
|
122
120
|
try {
|
package/dist/lib/paths.d.ts
CHANGED
|
@@ -17,7 +17,22 @@ export declare function getUluopsDir(): string;
|
|
|
17
17
|
export declare function getManifestPath(): string;
|
|
18
18
|
/** Return the legacy manifest path for migration. */
|
|
19
19
|
export declare function getLegacyManifestPath(): string;
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Return the backup directory for a harness's **config** files.
|
|
22
|
+
*
|
|
23
|
+
* Scope is deliberately narrow: this directory holds copies of mutable
|
|
24
|
+
* user-owned config surfaces (the MCP config file, the shell profile),
|
|
25
|
+
* NOT vendor-owned tool files in `~/.claude/tools/agent-metrics/`. Tool
|
|
26
|
+
* files are treated as disposable — they can be regenerated by re-running
|
|
27
|
+
* setup, and the source of truth lives in the npm-installed
|
|
28
|
+
* `@uluops/agent-metrics` package. Backing them up would require a
|
|
29
|
+
* different ritual (versioned snapshots tied to the manifest's
|
|
30
|
+
* hooksInstalledVersion) and is not provided here.
|
|
31
|
+
*
|
|
32
|
+
* Renaming this to `getConfigBackupDir` would be more honest but is a
|
|
33
|
+
* public surface change deferred until we have a tool-file backup to
|
|
34
|
+
* disambiguate against.
|
|
35
|
+
*/
|
|
21
36
|
export declare function getBackupDir(harnessName: string): string;
|
|
22
37
|
/** Detect the user's shell and return its name and profile path, or null if unsupported. */
|
|
23
38
|
export declare function getShellProfile(): {
|
package/dist/lib/paths.js
CHANGED
|
@@ -54,15 +54,28 @@ async function isProjectMarker(dir) {
|
|
|
54
54
|
}
|
|
55
55
|
return false;
|
|
56
56
|
}
|
|
57
|
+
/** Validate an env-var-supplied path: must be absolute and contain no traversal sequences. */
|
|
58
|
+
function validateEnvPath(value, varName) {
|
|
59
|
+
if (!isAbsolute(value)) {
|
|
60
|
+
throw new Error(`${varName} must be an absolute path, got: ${value}`);
|
|
61
|
+
}
|
|
62
|
+
if (value.includes("..")) {
|
|
63
|
+
throw new Error(`${varName} must not contain traversal sequences: ${value}`);
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
57
67
|
/** Return the Claude config home directory (~/.claude by default, or CLAUDE_HOME env override). */
|
|
58
68
|
export function getClaudeHome() {
|
|
59
|
-
|
|
69
|
+
const envHome = process.env["CLAUDE_HOME"];
|
|
70
|
+
if (envHome)
|
|
71
|
+
return validateEnvPath(envHome, "CLAUDE_HOME");
|
|
72
|
+
return join(homedir(), ".claude");
|
|
60
73
|
}
|
|
61
74
|
/** Return the path to Claude's global config file (~/.claude.json by default, or CLAUDE_JSON_PATH env override). */
|
|
62
75
|
export function getClaudeJsonPath() {
|
|
63
76
|
const envPath = process.env["CLAUDE_JSON_PATH"];
|
|
64
77
|
if (envPath)
|
|
65
|
-
return envPath;
|
|
78
|
+
return validateEnvPath(envPath, "CLAUDE_JSON_PATH");
|
|
66
79
|
return join(homedir(), ".claude.json");
|
|
67
80
|
}
|
|
68
81
|
/** Return the path to the project-local MCP config file (.mcp.json in project root). */
|
|
@@ -81,7 +94,22 @@ export function getManifestPath() {
|
|
|
81
94
|
export function getLegacyManifestPath() {
|
|
82
95
|
return join(getClaudeHome(), "uluops-manifest.json");
|
|
83
96
|
}
|
|
84
|
-
/**
|
|
97
|
+
/**
|
|
98
|
+
* Return the backup directory for a harness's **config** files.
|
|
99
|
+
*
|
|
100
|
+
* Scope is deliberately narrow: this directory holds copies of mutable
|
|
101
|
+
* user-owned config surfaces (the MCP config file, the shell profile),
|
|
102
|
+
* NOT vendor-owned tool files in `~/.claude/tools/agent-metrics/`. Tool
|
|
103
|
+
* files are treated as disposable — they can be regenerated by re-running
|
|
104
|
+
* setup, and the source of truth lives in the npm-installed
|
|
105
|
+
* `@uluops/agent-metrics` package. Backing them up would require a
|
|
106
|
+
* different ritual (versioned snapshots tied to the manifest's
|
|
107
|
+
* hooksInstalledVersion) and is not provided here.
|
|
108
|
+
*
|
|
109
|
+
* Renaming this to `getConfigBackupDir` would be more honest but is a
|
|
110
|
+
* public surface change deferred until we have a tool-file backup to
|
|
111
|
+
* disambiguate against.
|
|
112
|
+
*/
|
|
85
113
|
export function getBackupDir(harnessName) {
|
|
86
114
|
return join(getUluopsDir(), "backups", harnessName);
|
|
87
115
|
}
|
|
@@ -13,39 +13,54 @@ interface HookMatcher {
|
|
|
13
13
|
matcher?: string;
|
|
14
14
|
hooks: HookEntry[];
|
|
15
15
|
}
|
|
16
|
-
export interface
|
|
16
|
+
export interface HarnessSettings {
|
|
17
17
|
permissions?: Record<string, unknown>;
|
|
18
18
|
hooks?: Record<string, HookMatcher[]>;
|
|
19
19
|
[key: string]: unknown;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Supported hook event types in Claude Code's settings.json schema.
|
|
23
|
+
*
|
|
24
|
+
* This set is a snapshot of the harness's vocabulary. When Claude Code
|
|
25
|
+
* adds, renames, or removes hook types, this set rots — the `probeHookSupport`
|
|
26
|
+
* warning will fire on legitimate user configs and (worse) train users to
|
|
27
|
+
* ignore it. The snapshot test in `settings-merger.test.ts` exists to make
|
|
28
|
+
* any change to the set visible in PR review so the warning logic can be
|
|
29
|
+
* re-evaluated.
|
|
30
|
+
*
|
|
31
|
+
* Exported for that test only — runtime callers should use `probeHookSupport`.
|
|
32
|
+
*/
|
|
33
|
+
export declare const CLAUDE_HOOK_TYPES: Set<string>;
|
|
34
|
+
/** Default Claude Code hook event used when no override is configured. */
|
|
35
|
+
export declare const DEFAULT_CLAUDE_HOOK_TYPE = "SubagentStop";
|
|
21
36
|
export interface HookProbeResult {
|
|
22
37
|
hookType: string;
|
|
23
38
|
supported: boolean;
|
|
24
39
|
warning?: string;
|
|
25
40
|
}
|
|
26
41
|
/** Check whether the configured hook event type is in the known supported set. Returns the resolved hook type and a warning if unsupported. */
|
|
27
|
-
export declare function probeHookSupport(): HookProbeResult;
|
|
42
|
+
export declare function probeHookSupport(hookTypeOverride?: string): HookProbeResult;
|
|
28
43
|
/**
|
|
29
44
|
* Read an existing settings.json, or return empty object if it doesn't exist.
|
|
30
45
|
* Throws on malformed JSON to prevent silent data loss during merge+write.
|
|
31
46
|
*/
|
|
32
|
-
export declare function readSettings(path: string): Promise<
|
|
47
|
+
export declare function readSettings(path: string): Promise<HarnessSettings>;
|
|
33
48
|
/**
|
|
34
49
|
* Write settings back to file with stable formatting.
|
|
35
50
|
*/
|
|
36
|
-
export declare function writeSettings(path: string, settings:
|
|
51
|
+
export declare function writeSettings(path: string, settings: HarnessSettings): Promise<void>;
|
|
37
52
|
/**
|
|
38
|
-
* Merge the UluOps
|
|
53
|
+
* Merge the UluOps hook into settings, preserving all other
|
|
39
54
|
* hooks and settings. If a UluOps hook already exists, it is replaced.
|
|
40
55
|
*/
|
|
41
|
-
export declare function mergeUluopsHook(settings:
|
|
56
|
+
export declare function mergeUluopsHook(settings: HarnessSettings, hookCommand: string, hookTypeOverride?: string, matcher?: string): HarnessSettings;
|
|
42
57
|
/**
|
|
43
|
-
* Remove UluOps hook entries from settings. If
|
|
58
|
+
* Remove UluOps hook entries from settings. If a hook type becomes empty,
|
|
44
59
|
* the key is removed. If hooks becomes empty, the key is removed.
|
|
45
60
|
*/
|
|
46
|
-
export declare function removeUluopsHook(settings:
|
|
61
|
+
export declare function removeUluopsHook(settings: HarnessSettings, hookTypeOverride?: string): HarnessSettings;
|
|
47
62
|
/**
|
|
48
63
|
* Check if a UluOps hook is configured in settings.
|
|
49
64
|
*/
|
|
50
|
-
export declare function hasUluopsHook(settings:
|
|
65
|
+
export declare function hasUluopsHook(settings: HarnessSettings, hookTypeOverride?: string): boolean;
|
|
51
66
|
export {};
|