@kal-elsam/kairo-runtime 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +937 -0
- package/bin/harness.js +11 -0
- package/bin/kairo-runtime.js +11 -0
- package/bin/kairo.js +11 -0
- package/global-template/components/catalog.json +25 -0
- package/global-template/components/orchestrator/orchestrator.md +55 -0
- package/global-template/components/sdd-core/handoff.md +38 -0
- package/global-template/components/sdd-core/spec-sizing.md +38 -0
- package/global-template/components/sdd-core/workflow.md +31 -0
- package/global-template/core/orchestrator.md +55 -0
- package/package.json +64 -0
- package/prompts/HARNESS_ENFORCEMENT_UPGRADE.md +11 -0
- package/prompts/HARNESS_ENTERPRISE.md +33 -0
- package/prompts/HARNESS_INSTALLER_MASTER.md +853 -0
- package/prompts/HARNESS_MINIMAL.md +30 -0
- package/prompts/HARNESS_SPEC_SIZING_UPGRADE.md +41 -0
- package/prompts/HARNESS_STANDARD.md +35 -0
- package/prompts/HARNESS_UNIVERSAL_PARITY.md +56 -0
- package/repo-template/.claude/agents/adapter-parity-reviewer.md +17 -0
- package/repo-template/.claude/agents/architect.md +17 -0
- package/repo-template/.claude/agents/eval-engineer.md +17 -0
- package/repo-template/.claude/agents/reviewer.md +17 -0
- package/repo-template/.claude/agents/sdd-reviewer.md +17 -0
- package/repo-template/.claude/agents/sdd-spec-writer.md +17 -0
- package/repo-template/.claude/skills/checkpoint/SKILL.md +13 -0
- package/repo-template/.claude/skills/eval-design/SKILL.md +3 -0
- package/repo-template/.claude/skills/evals/SKILL.md +13 -0
- package/repo-template/.claude/skills/loop-engineering/SKILL.md +16 -0
- package/repo-template/.claude/skills/maintainability-review/SKILL.md +3 -0
- package/repo-template/.claude/skills/quality-gate-review/SKILL.md +3 -0
- package/repo-template/.claude/skills/sdd/SKILL.md +13 -0
- package/repo-template/.claude/skills/spec-complexity-classifier/SKILL.md +10 -0
- package/repo-template/.claude/skills/spec-escalation-review/SKILL.md +10 -0
- package/repo-template/.claude/skills/spec-intake/SKILL.md +10 -0
- package/repo-template/.claude/skills/tdd/SKILL.md +13 -0
- package/repo-template/.claude/skills/trust-review/SKILL.md +3 -0
- package/repo-template/.codex/skills/adapter-parity/SKILL.md +29 -0
- package/repo-template/.codex/skills/checkpoint/SKILL.md +36 -0
- package/repo-template/.codex/skills/eval-design/SKILL.md +3 -0
- package/repo-template/.codex/skills/evals/SKILL.md +28 -0
- package/repo-template/.codex/skills/loop-engineering/SKILL.md +24 -0
- package/repo-template/.codex/skills/maintainability-review/SKILL.md +3 -0
- package/repo-template/.codex/skills/quality-gate-review/SKILL.md +3 -0
- package/repo-template/.codex/skills/sdd/SKILL.md +30 -0
- package/repo-template/.codex/skills/spec-complexity-classifier/SKILL.md +10 -0
- package/repo-template/.codex/skills/spec-escalation-review/SKILL.md +10 -0
- package/repo-template/.codex/skills/spec-intake/SKILL.md +10 -0
- package/repo-template/.codex/skills/tdd/SKILL.md +27 -0
- package/repo-template/.codex/skills/trust-review/SKILL.md +3 -0
- package/repo-template/.cursor/agents/adapter-parity-reviewer.md +29 -0
- package/repo-template/.cursor/agents/architect.md +27 -0
- package/repo-template/.cursor/agents/context-engineer.md +27 -0
- package/repo-template/.cursor/agents/debugger.md +27 -0
- package/repo-template/.cursor/agents/eval-engineer.md +27 -0
- package/repo-template/.cursor/agents/harness-orchestrator.md +27 -0
- package/repo-template/.cursor/agents/loop-controller.md +17 -0
- package/repo-template/.cursor/agents/loop-debugger.md +16 -0
- package/repo-template/.cursor/agents/reviewer.md +27 -0
- package/repo-template/.cursor/agents/sdd/sdd-acceptance-reviewer.md +31 -0
- package/repo-template/.cursor/agents/sdd/sdd-implementation-guardian.md +31 -0
- package/repo-template/.cursor/agents/sdd/sdd-intake-analyst.md +31 -0
- package/repo-template/.cursor/agents/sdd/sdd-orchestrator.md +31 -0
- package/repo-template/.cursor/agents/sdd/sdd-spec-reviewer.md +31 -0
- package/repo-template/.cursor/agents/sdd/sdd-spec-writer.md +31 -0
- package/repo-template/.cursor/agents/sdd/sdd-task-breakdown.md +31 -0
- package/repo-template/.cursor/agents/sdd/sdd-technical-planner.md +31 -0
- package/repo-template/.cursor/agents/sdd/sdd-test-planner.md +31 -0
- package/repo-template/.cursor/agents/spec-intake-analyst.md +14 -0
- package/repo-template/.cursor/agents/test-engineer.md +27 -0
- package/repo-template/.cursor/commands/adapter-parity.md +34 -0
- package/repo-template/.cursor/commands/checkpoint.md +30 -0
- package/repo-template/.cursor/commands/debug.md +13 -0
- package/repo-template/.cursor/commands/init-eval.md +12 -0
- package/repo-template/.cursor/commands/init-feature.md +12 -0
- package/repo-template/.cursor/commands/init-harness.md +13 -0
- package/repo-template/.cursor/commands/loop-debug.md +3 -0
- package/repo-template/.cursor/commands/loop-review.md +3 -0
- package/repo-template/.cursor/commands/loop-run.md +5 -0
- package/repo-template/.cursor/commands/review.md +21 -0
- package/repo-template/.cursor/commands/sdd-intake.md +18 -0
- package/repo-template/.cursor/commands/sdd-plan.md +18 -0
- package/repo-template/.cursor/commands/sdd-spec.md +18 -0
- package/repo-template/.cursor/commands/sdd-tasks.md +18 -0
- package/repo-template/.cursor/commands/sdd-validate.md +18 -0
- package/repo-template/.cursor/commands/spec-escalate.md +9 -0
- package/repo-template/.cursor/commands/spec-intake.md +10 -0
- package/repo-template/.cursor/commands/spec-size.md +21 -0
- package/repo-template/.cursor/rules/adapter-parity.mdc +20 -0
- package/repo-template/.cursor/rules/api.mdc +12 -0
- package/repo-template/.cursor/rules/core.mdc +21 -0
- package/repo-template/.cursor/rules/enforcement.mdc +16 -0
- package/repo-template/.cursor/rules/evals.mdc +10 -0
- package/repo-template/.cursor/rules/git.mdc +19 -0
- package/repo-template/.cursor/rules/harness.mdc +14 -0
- package/repo-template/.cursor/rules/loops.mdc +17 -0
- package/repo-template/.cursor/rules/testing.mdc +13 -0
- package/repo-template/.cursor/rules/ui.mdc +13 -0
- package/repo-template/.cursor/skills/api-design/SKILL.md +23 -0
- package/repo-template/.cursor/skills/architecture/SKILL.md +23 -0
- package/repo-template/.cursor/skills/code-review/SKILL.md +23 -0
- package/repo-template/.cursor/skills/context-graph/SKILL.md +23 -0
- package/repo-template/.cursor/skills/debugging/SKILL.md +23 -0
- package/repo-template/.cursor/skills/evals/SKILL.md +23 -0
- package/repo-template/.cursor/skills/git-workflow/SKILL.md +23 -0
- package/repo-template/.cursor/skills/testing/SKILL.md +23 -0
- package/repo-template/.cursor/skills/ui-design/SKILL.md +23 -0
- package/repo-template/.gentle-ai/README.md +37 -0
- package/repo-template/.gentle-ai/loops/README.md +27 -0
- package/repo-template/.gentle-ai/loops/sdd-tdd-repair.loop.md +27 -0
- package/repo-template/.gentle-ai/model-routing.md +25 -0
- package/repo-template/.github/copilot-instructions.md +37 -0
- package/repo-template/.github/dependabot.yml +11 -0
- package/repo-template/.github/instructions/harness.instructions.md +11 -0
- package/repo-template/.github/workflows/harness-quality-gate.yml +67 -0
- package/repo-template/.github/workflows/harness-security-gate.yml +32 -0
- package/repo-template/.harness/spec-sizing.json +33 -0
- package/repo-template/.opencode/README.md +71 -0
- package/repo-template/.opencode/agents/adapter-parity-reviewer.md +23 -0
- package/repo-template/.opencode/agents/architect.md +38 -0
- package/repo-template/.opencode/agents/checkpoint-reviewer.md +38 -0
- package/repo-template/.opencode/agents/eval-engineer.md +38 -0
- package/repo-template/.opencode/agents/loop-controller.md +38 -0
- package/repo-template/.opencode/agents/loop-debugger.md +38 -0
- package/repo-template/.opencode/agents/model-router.md +38 -0
- package/repo-template/.opencode/agents/sdd-orchestrator.md +38 -0
- package/repo-template/.opencode/agents/sdd-spec-reviewer.md +38 -0
- package/repo-template/.opencode/agents/spec-intake-analyst.md +19 -0
- package/repo-template/.opencode/agents/tdd-engineer.md +38 -0
- package/repo-template/.opencode/commands/checkpoint.md +3 -0
- package/repo-template/.opencode/commands/eval-design.md +3 -0
- package/repo-template/.opencode/commands/maintainability-review.md +3 -0
- package/repo-template/.opencode/commands/quality-gate.md +3 -0
- package/repo-template/.opencode/commands/spec-escalate.md +9 -0
- package/repo-template/.opencode/commands/spec-intake.md +10 -0
- package/repo-template/.opencode/commands/spec-size.md +21 -0
- package/repo-template/.opencode/commands/trust-review.md +3 -0
- package/repo-template/.opencode/loops/ai-behavior-improvement.loop.md +15 -0
- package/repo-template/.opencode/loops/bug-repair.loop.md +16 -0
- package/repo-template/.opencode/loops/documentation-sync.loop.md +13 -0
- package/repo-template/.opencode/loops/feature-development.loop.md +25 -0
- package/repo-template/.opencode/skills/spec-complexity-classifier/SKILL.md +10 -0
- package/repo-template/.opencode/skills/spec-escalation-review/SKILL.md +10 -0
- package/repo-template/.opencode/skills/spec-intake/SKILL.md +10 -0
- package/repo-template/.pi/README.md +21 -0
- package/repo-template/.pi/prompts/checkpoint.md +11 -0
- package/repo-template/.pi/prompts/loop-run.md +10 -0
- package/repo-template/.pi/prompts/sdd-plan.md +11 -0
- package/repo-template/.pi/prompts/sdd-spec.md +13 -0
- package/repo-template/.pi/prompts/spec-escalate.md +9 -0
- package/repo-template/.pi/prompts/spec-intake.md +10 -0
- package/repo-template/.pi/prompts/spec-size.md +21 -0
- package/repo-template/.pi/skills/adapter-parity/SKILL.md +7 -0
- package/repo-template/.pi/skills/checkpoint/SKILL.md +7 -0
- package/repo-template/.pi/skills/eval-design/SKILL.md +3 -0
- package/repo-template/.pi/skills/evals/SKILL.md +7 -0
- package/repo-template/.pi/skills/loop-engineering/SKILL.md +7 -0
- package/repo-template/.pi/skills/maintainability-review/SKILL.md +3 -0
- package/repo-template/.pi/skills/quality-gate-review/SKILL.md +3 -0
- package/repo-template/.pi/skills/sdd/SKILL.md +7 -0
- package/repo-template/.pi/skills/spec-complexity-classifier/SKILL.md +10 -0
- package/repo-template/.pi/skills/spec-escalation-review/SKILL.md +10 -0
- package/repo-template/.pi/skills/spec-intake/SKILL.md +10 -0
- package/repo-template/.pi/skills/tdd/SKILL.md +7 -0
- package/repo-template/.pi/skills/trust-review/SKILL.md +3 -0
- package/repo-template/AGENT.md +8 -0
- package/repo-template/AGENTS.md +165 -0
- package/repo-template/CLAUDE.md +9 -0
- package/repo-template/GEMINI.md +9 -0
- package/repo-template/docs/ai/adapter-parity.md +135 -0
- package/repo-template/docs/ai/agent-workflow.md +45 -0
- package/repo-template/docs/ai/api.md +28 -0
- package/repo-template/docs/ai/architecture.md +53 -0
- package/repo-template/docs/ai/context-budget.md +54 -0
- package/repo-template/docs/ai/context-graph.md +39 -0
- package/repo-template/docs/ai/conventions.md +34 -0
- package/repo-template/docs/ai/decision-log.md +5 -0
- package/repo-template/docs/ai/enforcement.md +63 -0
- package/repo-template/docs/ai/eval-strategy.md +42 -0
- package/repo-template/docs/ai/evals.md +44 -0
- package/repo-template/docs/ai/git-workflow.md +35 -0
- package/repo-template/docs/ai/governance.md +61 -0
- package/repo-template/docs/ai/harness.md +49 -0
- package/repo-template/docs/ai/installer-cli.md +34 -0
- package/repo-template/docs/ai/loop-log.md +5 -0
- package/repo-template/docs/ai/loop-observability.md +57 -0
- package/repo-template/docs/ai/loop-policy.md +86 -0
- package/repo-template/docs/ai/loops.md +95 -0
- package/repo-template/docs/ai/maintainability-gates.md +26 -0
- package/repo-template/docs/ai/memory.md +71 -0
- package/repo-template/docs/ai/model-policy.md +105 -0
- package/repo-template/docs/ai/observability-runtime.md +48 -0
- package/repo-template/docs/ai/provider-routing.md +138 -0
- package/repo-template/docs/ai/quality-gates.md +48 -0
- package/repo-template/docs/ai/rollback-runtime.md +25 -0
- package/repo-template/docs/ai/security.md +12 -0
- package/repo-template/docs/ai/spec-driven-development.md +124 -0
- package/repo-template/docs/ai/spec-escalation.md +44 -0
- package/repo-template/docs/ai/spec-intake.md +46 -0
- package/repo-template/docs/ai/spec-sizing.md +207 -0
- package/repo-template/docs/ai/test-driven-development.md +35 -0
- package/repo-template/docs/ai/testing.md +28 -0
- package/repo-template/docs/ai/tool-adapters.md +186 -0
- package/repo-template/docs/ai/trust-allowlist.md +5 -0
- package/repo-template/docs/ai/trust-policy.md +41 -0
- package/repo-template/docs/ai/ui.md +17 -0
- package/repo-template/docs/skills/adapter-parity-review.md +46 -0
- package/repo-template/docs/skills/api-design.md +37 -0
- package/repo-template/docs/skills/architecture.md +37 -0
- package/repo-template/docs/skills/code-review.md +37 -0
- package/repo-template/docs/skills/context-graph.md +38 -0
- package/repo-template/docs/skills/debugging.md +37 -0
- package/repo-template/docs/skills/eval-design.md +12 -0
- package/repo-template/docs/skills/evals.md +37 -0
- package/repo-template/docs/skills/git-workflow.md +37 -0
- package/repo-template/docs/skills/look-trust-review.md +12 -0
- package/repo-template/docs/skills/loop-debugging.md +16 -0
- package/repo-template/docs/skills/loop-design.md +39 -0
- package/repo-template/docs/skills/loop-retrospective.md +15 -0
- package/repo-template/docs/skills/loop-review.md +16 -0
- package/repo-template/docs/skills/maintainability-review.md +12 -0
- package/repo-template/docs/skills/model-selection.md +36 -0
- package/repo-template/docs/skills/quality-gate-review.md +12 -0
- package/repo-template/docs/skills/spec-complexity-classifier.md +41 -0
- package/repo-template/docs/skills/spec-escalation-review.md +34 -0
- package/repo-template/docs/skills/spec-intake.md +25 -0
- package/repo-template/docs/skills/testing.md +37 -0
- package/repo-template/docs/skills/tool-adapter-sync.md +36 -0
- package/repo-template/docs/skills/ui-design.md +37 -0
- package/repo-template/docs/specs/README.md +9 -0
- package/repo-template/docs/specs/templates/basic-spec.md +41 -0
- package/repo-template/docs/specs/templates/complex-spec.md +145 -0
- package/repo-template/docs/specs/templates/standard-spec.md +58 -0
- package/repo-template/evals/README.md +11 -0
- package/repo-template/evals/golden/sample-golden.json +12 -0
- package/repo-template/evals/loop-regression/README.md +11 -0
- package/repo-template/evals/regression/sample-regression.json +12 -0
- package/repo-template/evals/schema/sample-schema.json +12 -0
- package/repo-template/evals/tool-calls/sample-tool-calls.json +12 -0
- package/repo-template/opencode.json.sample +29 -0
- package/repo-template/scripts/harness/backup.mjs +7 -0
- package/repo-template/scripts/harness/doctor.mjs +20 -0
- package/repo-template/scripts/harness/run-evals.mjs +27 -0
- package/repo-template/setup-agent-links.sh +54 -0
- package/scripts/check-published-release.mjs +127 -0
- package/scripts/check-release-commit.mjs +32 -0
- package/scripts/install.sh +225 -0
- package/scripts/installer-smoke-test.sh +155 -0
- package/scripts/lib/attribution-guard.mjs +59 -0
- package/scripts/registry-smoke-test.sh +149 -0
- package/scripts/smoke-test.sh +197 -0
- package/scripts/ux-smoke-test.sh +140 -0
- package/src/cli.js +625 -0
- package/src/doctor.js +68 -0
- package/src/global/adapter-context.js +27 -0
- package/src/global/adapter-matrix.js +38 -0
- package/src/global/adapters/claude.js +8 -0
- package/src/global/adapters/codex.js +8 -0
- package/src/global/adapters/cursor.js +8 -0
- package/src/global/adapters/opencode.js +8 -0
- package/src/global/agents.js +7 -0
- package/src/global/apply-confirmation.js +62 -0
- package/src/global/backups.js +54 -0
- package/src/global/brand/cli.js +52 -0
- package/src/global/brand/index.js +85 -0
- package/src/global/clack/setup-preview.js +48 -0
- package/src/global/clack/setup-wizard-constants.js +6 -0
- package/src/global/clack/setup-wizard.js +207 -0
- package/src/global/clack/theme.js +145 -0
- package/src/global/component-authoring.js +121 -0
- package/src/global/component-builders.js +43 -0
- package/src/global/component-distribution.js +270 -0
- package/src/global/component-installer.js +106 -0
- package/src/global/component-paths.js +22 -0
- package/src/global/component-registry.js +89 -0
- package/src/global/components/orchestrator.js +14 -0
- package/src/global/components/sdd-core.js +17 -0
- package/src/global/diff.js +233 -0
- package/src/global/drift.js +264 -0
- package/src/global/explain.js +144 -0
- package/src/global/global-cli.js +1145 -0
- package/src/global/global-doctor.js +67 -0
- package/src/global/global-installer.js +284 -0
- package/src/global/history.js +313 -0
- package/src/global/ink/run-setup-ink.js +77 -0
- package/src/global/ink/setup-app.js +278 -0
- package/src/global/ink/setup-routing.js +51 -0
- package/src/global/ink/setup-state.js +180 -0
- package/src/global/ink/terminal.js +13 -0
- package/src/global/json-output.js +22 -0
- package/src/global/load-component-catalog.js +41 -0
- package/src/global/load-workspace-component-catalog.js +123 -0
- package/src/global/managed-body.js +28 -0
- package/src/global/managed-config-adapter.js +134 -0
- package/src/global/managed-section.js +73 -0
- package/src/global/npm-registry.js +25 -0
- package/src/global/paths.js +22 -0
- package/src/global/policy.js +344 -0
- package/src/global/preflight.js +65 -0
- package/src/global/registry.js +79 -0
- package/src/global/report.js +110 -0
- package/src/global/rollback.js +126 -0
- package/src/global/setup.js +284 -0
- package/src/global/state-migration.js +65 -0
- package/src/global/state.js +50 -0
- package/src/global/status.js +94 -0
- package/src/global/sync.js +129 -0
- package/src/global/upgrade.js +145 -0
- package/src/harness-files.js +145 -0
- package/src/harness-updater.js +120 -0
- package/src/hash.js +5 -0
- package/src/manifest.js +36 -0
- package/src/project-detection.js +105 -0
- package/src/template-installer.js +72 -0
- package/src/text-template.js +24 -0
- package/src/workspace-cli.js +115 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { DEFAULT_COMPONENT_IDS } from "./component-registry.js";
|
|
4
|
+
import { GLOBAL_AGENT_IDS, detectInstalledAdapters } from "./registry.js";
|
|
5
|
+
import { shouldPromptApplyConfirmation } from "./apply-confirmation.js";
|
|
6
|
+
import { harnessHomePaths } from "./paths.js";
|
|
7
|
+
|
|
8
|
+
export const POLICY_PROFILES = {
|
|
9
|
+
safe: { applyMode: "prompt", preflight: true },
|
|
10
|
+
ci: { applyMode: "confirm", preflight: true },
|
|
11
|
+
fast: { applyMode: "confirm", preflight: true }
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const DEFAULT_POLICY = {
|
|
15
|
+
applyMode: "prompt",
|
|
16
|
+
preflight: true,
|
|
17
|
+
agents: "detected",
|
|
18
|
+
components: [...DEFAULT_COMPONENT_IDS]
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const POLICY_KEYS = new Set(["profile", "applyMode", "preflight", "agents", "components"]);
|
|
22
|
+
const APPLY_MODES = new Set(["prompt", "confirm"]);
|
|
23
|
+
const AGENT_MODES = new Set(["detected", "all", ...GLOBAL_AGENT_IDS]);
|
|
24
|
+
|
|
25
|
+
export function getPolicyPath(homeDir) {
|
|
26
|
+
return harnessHomePaths(homeDir).policyPath;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function loadPolicyFile(homeDir) {
|
|
30
|
+
const policyPath = getPolicyPath(homeDir);
|
|
31
|
+
if (!existsSync(policyPath)) return null;
|
|
32
|
+
|
|
33
|
+
let parsed;
|
|
34
|
+
try {
|
|
35
|
+
parsed = JSON.parse(await readFile(policyPath, "utf8"));
|
|
36
|
+
} catch (error) {
|
|
37
|
+
throw new Error(`Invalid policy file at ${policyPath}: ${error.message}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
41
|
+
throw new Error(`Invalid policy file at ${policyPath}: expected a JSON object.`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return parsed;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function resolvePolicy(rawPolicy = {}) {
|
|
48
|
+
const profileName = rawPolicy.profile ?? null;
|
|
49
|
+
const profileDefaults = profileName ? POLICY_PROFILES[profileName] : null;
|
|
50
|
+
|
|
51
|
+
if (profileName && !profileDefaults) {
|
|
52
|
+
throw new Error(`Unknown policy profile "${profileName}". Use safe, ci, or fast.`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const resolved = {
|
|
56
|
+
...DEFAULT_POLICY,
|
|
57
|
+
...(profileDefaults ?? {}),
|
|
58
|
+
...pickPolicyFields(rawPolicy)
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (profileName) {
|
|
62
|
+
resolved.profile = profileName;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
validateResolvedPolicy(resolved);
|
|
66
|
+
return resolved;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function buildPolicyJson(homeDir, rawPolicy) {
|
|
70
|
+
const policyPath = getPolicyPath(homeDir);
|
|
71
|
+
const hasFile = rawPolicy != null;
|
|
72
|
+
const resolved = resolvePolicy(rawPolicy ?? {});
|
|
73
|
+
const effective = buildEffectivePolicyFromRaw(homeDir, rawPolicy);
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
profile: rawPolicy?.profile ?? null,
|
|
77
|
+
applyMode: resolved.applyMode,
|
|
78
|
+
preflight: resolved.preflight,
|
|
79
|
+
agents: resolved.agents,
|
|
80
|
+
components: resolved.components,
|
|
81
|
+
source: hasFile ? "file" : "defaults",
|
|
82
|
+
path: policyPath,
|
|
83
|
+
effective
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function buildEffectivePolicy(homeDir) {
|
|
88
|
+
const rawPolicy = await loadPolicyFile(homeDir);
|
|
89
|
+
return buildEffectivePolicyFromRaw(homeDir, rawPolicy);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function buildEffectivePolicyFromRaw(homeDir, rawPolicy) {
|
|
93
|
+
const resolved = resolvePolicy(rawPolicy ?? {});
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
source: rawPolicy ? "file" : "none",
|
|
97
|
+
profile: resolved.profile ?? null,
|
|
98
|
+
applyMode: resolved.applyMode,
|
|
99
|
+
preflight: resolved.preflight,
|
|
100
|
+
agents: formatPolicyAgentsLabel(resolved.agents, homeDir),
|
|
101
|
+
components: [...resolved.components],
|
|
102
|
+
path: getPolicyPath(homeDir)
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function formatPolicyAgentsLabel(agents, homeDir) {
|
|
107
|
+
if (agents === "detected") return "detected";
|
|
108
|
+
if (agents === "all") return "all";
|
|
109
|
+
return agents.join(", ");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function formatPolicySourceLabel(policy) {
|
|
113
|
+
if (policy.source === "file") {
|
|
114
|
+
return `file (${policy.path})`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return "none (defaults, no policy file)";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function formatPolicyProfileLabel(profile) {
|
|
121
|
+
return profile ?? "none";
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function resolveConsentAudit({
|
|
125
|
+
yes = false,
|
|
126
|
+
confirm = false,
|
|
127
|
+
yesExplicit = false,
|
|
128
|
+
confirmExplicit = false,
|
|
129
|
+
noPreflight = false,
|
|
130
|
+
preflightExplicit = false,
|
|
131
|
+
rawPolicy = null,
|
|
132
|
+
interactive = false,
|
|
133
|
+
applying = true,
|
|
134
|
+
dryRun = false,
|
|
135
|
+
json = false
|
|
136
|
+
}) {
|
|
137
|
+
const policyProfile = formatPolicyProfileLabel(rawPolicy?.profile ?? null);
|
|
138
|
+
|
|
139
|
+
if (!applying || dryRun || json) {
|
|
140
|
+
return { consentSource: "none", policyProfile };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (yesExplicit || confirmExplicit || (noPreflight && preflightExplicit)) {
|
|
144
|
+
return { consentSource: "cli", policyProfile };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (rawPolicy && confirm && !yesExplicit && !confirmExplicit) {
|
|
148
|
+
const resolved = resolvePolicy(rawPolicy);
|
|
149
|
+
if (resolved.applyMode === "confirm") {
|
|
150
|
+
return { consentSource: "policy", policyProfile };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (shouldPromptApplyConfirmation({ applying, dryRun, json, confirm, interactive })) {
|
|
155
|
+
return { consentSource: "interactive", policyProfile };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (yes || confirm) {
|
|
159
|
+
return { consentSource: "cli", policyProfile };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { consentSource: "none", policyProfile };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export async function loadConsentAudit(homeDir, options) {
|
|
166
|
+
const rawPolicy = await loadPolicyFile(homeDir);
|
|
167
|
+
const consent = resolveConsentAudit({
|
|
168
|
+
yes: options.yes,
|
|
169
|
+
confirm: options.confirm,
|
|
170
|
+
yesExplicit: options.yesExplicit,
|
|
171
|
+
confirmExplicit: options.confirmExplicit,
|
|
172
|
+
noPreflight: !options.preflight,
|
|
173
|
+
preflightExplicit: options.preflightExplicit,
|
|
174
|
+
rawPolicy,
|
|
175
|
+
interactive: options.interactive,
|
|
176
|
+
applying: options.applying,
|
|
177
|
+
dryRun: options.dryRun,
|
|
178
|
+
json: options.json
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
return { rawPolicy, ...consent };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function applyPolicyToOptions(options, rawPolicy) {
|
|
185
|
+
if (rawPolicy == null) return options;
|
|
186
|
+
|
|
187
|
+
const resolved = resolvePolicy(rawPolicy);
|
|
188
|
+
const merged = { ...options };
|
|
189
|
+
|
|
190
|
+
if (!options.preflightExplicit && resolved.preflight != null) {
|
|
191
|
+
merged.preflight = resolved.preflight;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (!options.yesExplicit && !options.confirmExplicit && resolved.applyMode === "confirm") {
|
|
195
|
+
merged.confirm = true;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!options.adaptersExplicit) {
|
|
199
|
+
merged.adapters = resolvePolicyAgents(resolved.agents);
|
|
200
|
+
merged.allAdapters = resolved.agents === "all";
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!options.componentsExplicit && resolved.components != null) {
|
|
204
|
+
merged.components = [...resolved.components];
|
|
205
|
+
merged.noDefaultComponents = resolved.components.length === 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return merged;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export async function savePolicyField(homeDir, key, value) {
|
|
212
|
+
validatePolicyKey(key);
|
|
213
|
+
const parsedValue = parsePolicyValue(key, value);
|
|
214
|
+
const current = (await loadPolicyFile(homeDir)) ?? {};
|
|
215
|
+
const next = { ...current, [key]: parsedValue };
|
|
216
|
+
|
|
217
|
+
if (key === "profile") {
|
|
218
|
+
delete next.applyMode;
|
|
219
|
+
delete next.preflight;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
await writePolicyFile(homeDir, next);
|
|
223
|
+
return resolvePolicy(next);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export async function resetPolicyFile(homeDir) {
|
|
227
|
+
const policyPath = getPolicyPath(homeDir);
|
|
228
|
+
if (!existsSync(policyPath)) return false;
|
|
229
|
+
await unlink(policyPath);
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export async function writePolicyFile(homeDir, policy) {
|
|
234
|
+
const { root, policyPath } = harnessHomePaths(homeDir);
|
|
235
|
+
await mkdir(root, { recursive: true });
|
|
236
|
+
validateResolvedPolicy(resolvePolicy(policy));
|
|
237
|
+
await writeFile(policyPath, `${JSON.stringify(policy, null, 2)}\n`, "utf8");
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function pickPolicyFields(rawPolicy) {
|
|
241
|
+
const picked = {};
|
|
242
|
+
|
|
243
|
+
for (const key of POLICY_KEYS) {
|
|
244
|
+
if (rawPolicy[key] !== undefined) {
|
|
245
|
+
picked[key] = rawPolicy[key];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return picked;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function resolvePolicyAgents(agents) {
|
|
253
|
+
if (agents === "detected") return null;
|
|
254
|
+
if (agents === "all") return ["all"];
|
|
255
|
+
if (Array.isArray(agents)) return [...agents];
|
|
256
|
+
throw new Error(`Invalid policy agents value "${agents}".`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function validatePolicyKey(key) {
|
|
260
|
+
if (!POLICY_KEYS.has(key)) {
|
|
261
|
+
throw new Error(`Unknown policy key "${key}". Use ${[...POLICY_KEYS].join(", ")}.`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function parsePolicyValue(key, value) {
|
|
266
|
+
switch (key) {
|
|
267
|
+
case "profile": {
|
|
268
|
+
if (!POLICY_PROFILES[value]) {
|
|
269
|
+
throw new Error(`Unknown policy profile "${value}". Use safe, ci, or fast.`);
|
|
270
|
+
}
|
|
271
|
+
return value;
|
|
272
|
+
}
|
|
273
|
+
case "applyMode": {
|
|
274
|
+
if (!APPLY_MODES.has(value)) {
|
|
275
|
+
throw new Error(`Invalid applyMode "${value}". Use prompt or confirm.`);
|
|
276
|
+
}
|
|
277
|
+
return value;
|
|
278
|
+
}
|
|
279
|
+
case "preflight": {
|
|
280
|
+
return parseBooleanValue(value, "preflight");
|
|
281
|
+
}
|
|
282
|
+
case "agents": {
|
|
283
|
+
if (AGENT_MODES.has(value)) return value;
|
|
284
|
+
const items = parseListValue(value);
|
|
285
|
+
for (const item of items) {
|
|
286
|
+
if (!GLOBAL_AGENT_IDS.includes(item)) {
|
|
287
|
+
throw new Error(`Unknown agent "${item}". Use ${GLOBAL_AGENT_IDS.join(", ")}, detected, or all.`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return items;
|
|
291
|
+
}
|
|
292
|
+
case "components": {
|
|
293
|
+
return parseListValue(value);
|
|
294
|
+
}
|
|
295
|
+
default: {
|
|
296
|
+
const _exhaustive = key;
|
|
297
|
+
throw new Error(`Unknown policy key "${_exhaustive}".`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function parseBooleanValue(value, label) {
|
|
303
|
+
if (value === "true") return true;
|
|
304
|
+
if (value === "false") return false;
|
|
305
|
+
throw new Error(`Invalid ${label} value "${value}". Use true or false.`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function parseListValue(value) {
|
|
309
|
+
if (!value) return [];
|
|
310
|
+
return [...new Set(
|
|
311
|
+
value
|
|
312
|
+
.split(",")
|
|
313
|
+
.map((item) => item.trim())
|
|
314
|
+
.filter(Boolean)
|
|
315
|
+
)];
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function validateResolvedPolicy(policy) {
|
|
319
|
+
if (!APPLY_MODES.has(policy.applyMode)) {
|
|
320
|
+
throw new Error(`Invalid applyMode "${policy.applyMode}". Use prompt or confirm.`);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (typeof policy.preflight !== "boolean") {
|
|
324
|
+
throw new Error("Policy preflight must be a boolean.");
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (policy.agents === "detected" || policy.agents === "all") {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (!Array.isArray(policy.agents)) {
|
|
332
|
+
throw new Error('Policy agents must be "detected", "all", or an agent list.');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
for (const agent of policy.agents) {
|
|
336
|
+
if (!GLOBAL_AGENT_IDS.includes(agent)) {
|
|
337
|
+
throw new Error(`Unknown agent "${agent}" in policy.`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (!Array.isArray(policy.components)) {
|
|
342
|
+
throw new Error("Policy components must be an array.");
|
|
343
|
+
}
|
|
344
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { commandHeader } from "./brand/index.js";
|
|
2
|
+
import { SECTION_END, SECTION_START } from "./managed-section.js";
|
|
3
|
+
|
|
4
|
+
export function shouldShowPreflight({
|
|
5
|
+
preflight = true,
|
|
6
|
+
dryRun = false,
|
|
7
|
+
json = false,
|
|
8
|
+
applying = true
|
|
9
|
+
}) {
|
|
10
|
+
return preflight && applying && !dryRun && !json;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function printManagedPreflight({
|
|
14
|
+
command,
|
|
15
|
+
summary,
|
|
16
|
+
changes,
|
|
17
|
+
preserved,
|
|
18
|
+
markers = {
|
|
19
|
+
start: SECTION_START,
|
|
20
|
+
end: SECTION_END
|
|
21
|
+
},
|
|
22
|
+
consentSource = "none",
|
|
23
|
+
policyProfile = "none"
|
|
24
|
+
}) {
|
|
25
|
+
console.log(commandHeader(`preflight — ${command}`));
|
|
26
|
+
console.log(`Consent source: ${consentSource}`);
|
|
27
|
+
console.log(`Policy profile: ${policyProfile}`);
|
|
28
|
+
console.log(`Summary: ${summary}`);
|
|
29
|
+
console.log("");
|
|
30
|
+
console.log("Managed markers:");
|
|
31
|
+
console.log(` start: ${markers.start}`);
|
|
32
|
+
console.log(` end: ${markers.end}`);
|
|
33
|
+
console.log("");
|
|
34
|
+
|
|
35
|
+
if (changes.length === 0) {
|
|
36
|
+
console.log("Planned managed changes: none");
|
|
37
|
+
} else {
|
|
38
|
+
console.log("Planned managed changes:");
|
|
39
|
+
for (const change of changes) {
|
|
40
|
+
console.log(
|
|
41
|
+
` ${change.action} ${change.target} [${change.kind}]`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log("");
|
|
47
|
+
if (preserved.length > 0) {
|
|
48
|
+
console.log("User-owned content preserved (outside managed markers):");
|
|
49
|
+
for (const entry of preserved) {
|
|
50
|
+
console.log(` ${entry.path}`);
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
console.log("User-owned content preserved: none detected in affected configs.");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log("");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function summarizeDiffPreflight(diffReport) {
|
|
60
|
+
return {
|
|
61
|
+
summary: diffReport.summary,
|
|
62
|
+
changes: diffReport.changes,
|
|
63
|
+
preserved: diffReport.preserved
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import claude from "./adapters/claude.js";
|
|
4
|
+
import codex from "./adapters/codex.js";
|
|
5
|
+
import cursor from "./adapters/cursor.js";
|
|
6
|
+
import opencode from "./adapters/opencode.js";
|
|
7
|
+
|
|
8
|
+
const ADAPTERS = [cursor, codex, opencode, claude];
|
|
9
|
+
|
|
10
|
+
export const GLOBAL_AGENT_IDS = ADAPTERS.map((adapter) => adapter.id);
|
|
11
|
+
|
|
12
|
+
export function isAllAgentsSelection(requestedIds) {
|
|
13
|
+
return requestedIds?.length === 1 && requestedIds[0] === "all";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function resolveAgentIds(requestedIds, context) {
|
|
17
|
+
if (requestedIds == null) {
|
|
18
|
+
const detected = detectInstalledAdapters(context);
|
|
19
|
+
return detected.length > 0 ? detected : [...GLOBAL_AGENT_IDS];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (isAllAgentsSelection(requestedIds)) {
|
|
23
|
+
return [...GLOBAL_AGENT_IDS];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return validateAdapterIds(requestedIds);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function listAdapters() {
|
|
30
|
+
return [...ADAPTERS];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function resolveAdapter(id) {
|
|
34
|
+
const adapter = ADAPTERS.find((candidate) => candidate.id === id);
|
|
35
|
+
|
|
36
|
+
if (!adapter) {
|
|
37
|
+
throw new Error(`Unknown agent "${id}". Use ${GLOBAL_AGENT_IDS.join(", ")}.`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return adapter;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function validateAdapterIds(ids) {
|
|
44
|
+
return ids.map((id) => resolveAdapter(id).id);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function detectInstalledAdapters(context) {
|
|
48
|
+
return ADAPTERS
|
|
49
|
+
.filter((adapter) => adapter.detect(context))
|
|
50
|
+
.map((adapter) => adapter.id);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function resolveTargetAdapters(context, requestedIds = null) {
|
|
54
|
+
if (requestedIds == null) {
|
|
55
|
+
const detected = detectInstalledAdapters(context);
|
|
56
|
+
return detected.length > 0
|
|
57
|
+
? detected.map((id) => resolveAdapter(id))
|
|
58
|
+
: [...ADAPTERS];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (isAllAgentsSelection(requestedIds)) {
|
|
62
|
+
return [...ADAPTERS];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return validateAdapterIds(requestedIds).map((id) => resolveAdapter(id));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function buildAdapterStateEntry(adapter, homeDir) {
|
|
69
|
+
const configPath = join(homeDir, adapter.assets.configFile);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
id: adapter.id,
|
|
73
|
+
label: adapter.label,
|
|
74
|
+
rootDir: adapter.assets.rootDir,
|
|
75
|
+
configFile: adapter.assets.configFile,
|
|
76
|
+
managedTargets: [...adapter.assets.managedTargets],
|
|
77
|
+
present: existsSync(configPath)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
2
|
+
import { buildAdapterMatrixReport } from "./adapter-matrix.js";
|
|
3
|
+
import { buildDiffJson, buildDiffReport } from "./diff.js";
|
|
4
|
+
import { getHistoryPath, readHistoryEvents } from "./history.js";
|
|
5
|
+
import { buildEffectivePolicy } from "./policy.js";
|
|
6
|
+
import { buildStatusReport } from "./status.js";
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_HISTORY_LIMIT = 20;
|
|
9
|
+
|
|
10
|
+
export async function buildDiagnosticsReport(homeDir, {
|
|
11
|
+
packageRoot,
|
|
12
|
+
packageName,
|
|
13
|
+
cliVersion,
|
|
14
|
+
workspaceRoot = null,
|
|
15
|
+
historyLimit = DEFAULT_HISTORY_LIMIT
|
|
16
|
+
} = {}) {
|
|
17
|
+
const statusReport = await buildStatusReport(homeDir, { packageRoot, workspaceRoot });
|
|
18
|
+
const adapterReport = await buildAdapterMatrixReport(homeDir);
|
|
19
|
+
const diffReport = await buildDiffReport(homeDir, {
|
|
20
|
+
packageRoot,
|
|
21
|
+
packageName,
|
|
22
|
+
cliVersion,
|
|
23
|
+
workspaceRoot
|
|
24
|
+
});
|
|
25
|
+
const policy = await buildEffectivePolicy(homeDir);
|
|
26
|
+
const { events, warnings } = await readHistoryEvents(homeDir, { limit: historyLimit });
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
homeDir,
|
|
30
|
+
cliVersion,
|
|
31
|
+
adapters: summarizeAdapters(adapterReport),
|
|
32
|
+
policy,
|
|
33
|
+
status: summarizeStatus(statusReport),
|
|
34
|
+
diff: summarizeDiff(diffReport),
|
|
35
|
+
history: {
|
|
36
|
+
path: getHistoryPath(homeDir),
|
|
37
|
+
limit: historyLimit,
|
|
38
|
+
events,
|
|
39
|
+
warnings
|
|
40
|
+
},
|
|
41
|
+
ok: statusReport.ok
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function summarizeAdapters(report) {
|
|
46
|
+
return {
|
|
47
|
+
supportedCount: report.supportedCount,
|
|
48
|
+
detectedCount: report.detectedCount,
|
|
49
|
+
managedCount: report.managedCount,
|
|
50
|
+
adapters: report.adapters.map((adapter) => ({
|
|
51
|
+
id: adapter.id,
|
|
52
|
+
label: adapter.label,
|
|
53
|
+
detected: adapter.detected,
|
|
54
|
+
managed: adapter.managed,
|
|
55
|
+
rootDir: adapter.rootDir,
|
|
56
|
+
configFile: adapter.configFile,
|
|
57
|
+
managedTargets: adapter.managedTargets
|
|
58
|
+
}))
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function summarizeStatus(report) {
|
|
63
|
+
return {
|
|
64
|
+
overall: report.overall,
|
|
65
|
+
ok: report.ok,
|
|
66
|
+
stateRoot: report.stateRoot,
|
|
67
|
+
installed: report.state != null,
|
|
68
|
+
stateCliVersion: report.state?.cliVersion ?? null,
|
|
69
|
+
agents: report.agents,
|
|
70
|
+
components: report.components,
|
|
71
|
+
counts: report.counts,
|
|
72
|
+
backups: report.backups,
|
|
73
|
+
nextAction: report.nextAction
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function summarizeDiff(report) {
|
|
78
|
+
return {
|
|
79
|
+
installed: report.installed,
|
|
80
|
+
status: report.status,
|
|
81
|
+
hasChanges: report.hasChanges,
|
|
82
|
+
summary: report.summary,
|
|
83
|
+
nextAction: report.nextAction,
|
|
84
|
+
changeCount: report.changes.length,
|
|
85
|
+
changes: report.changes.map((change) => ({
|
|
86
|
+
kind: change.kind,
|
|
87
|
+
action: change.action,
|
|
88
|
+
target: change.target,
|
|
89
|
+
status: change.status
|
|
90
|
+
})),
|
|
91
|
+
preservedCount: report.preserved.length
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function buildReportJson(report) {
|
|
96
|
+
return {
|
|
97
|
+
ok: report.ok,
|
|
98
|
+
cliVersion: report.cliVersion,
|
|
99
|
+
homeDir: report.homeDir,
|
|
100
|
+
adapters: report.adapters,
|
|
101
|
+
policy: report.policy,
|
|
102
|
+
status: report.status,
|
|
103
|
+
diff: report.diff,
|
|
104
|
+
history: report.history
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function writeReportFile(outPath, content) {
|
|
109
|
+
await writeFile(outPath, content, "utf8");
|
|
110
|
+
}
|