@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,1145 @@
|
|
|
1
|
+
import { GLOBAL_AGENT_IDS, detectInstalledAdapters } from "./registry.js";
|
|
2
|
+
import { describeBundledComponentCatalog, describeWorkspaceComponentCatalog } from "./component-registry.js";
|
|
3
|
+
import { initWorkspaceComponent, validateWorkspaceComponentsCatalog } from "./component-authoring.js";
|
|
4
|
+
import { importWorkspaceComponent, packWorkspaceComponent } from "./component-distribution.js";
|
|
5
|
+
import { installGlobalHarness, uninstallGlobalHarness, updateGlobalHarness } from "./global-installer.js";
|
|
6
|
+
import { resolveHomeDir, harnessHomePaths } from "./paths.js";
|
|
7
|
+
import { runGlobalDoctorChecks } from "./global-doctor.js";
|
|
8
|
+
import { describeBackupSnapshots, applyRollback, previewRollback } from "./rollback.js";
|
|
9
|
+
import { buildAdapterMatrixReport } from "./adapter-matrix.js";
|
|
10
|
+
import { buildControlPlaneJson, printJson } from "./json-output.js";
|
|
11
|
+
import { runHarnessSetup } from "./setup.js";
|
|
12
|
+
import { buildStatusReport } from "./status.js";
|
|
13
|
+
import { runHarnessSync } from "./sync.js";
|
|
14
|
+
import { runHarnessUpgrade } from "./upgrade.js";
|
|
15
|
+
import { buildExplainJson, buildExplainReport } from "./explain.js";
|
|
16
|
+
import { buildDiffJson, buildDiffReport } from "./diff.js";
|
|
17
|
+
import {
|
|
18
|
+
applyPolicyToOptions,
|
|
19
|
+
buildPolicyJson,
|
|
20
|
+
formatPolicyProfileLabel,
|
|
21
|
+
formatPolicySourceLabel,
|
|
22
|
+
loadPolicyFile,
|
|
23
|
+
resetPolicyFile,
|
|
24
|
+
resolvePolicy,
|
|
25
|
+
savePolicyField
|
|
26
|
+
} from "./policy.js";
|
|
27
|
+
import {
|
|
28
|
+
buildCheckSnapshot,
|
|
29
|
+
formatHistoryEvent,
|
|
30
|
+
getHistoryPath,
|
|
31
|
+
readHistoryEvents,
|
|
32
|
+
readLastHistoryEvent,
|
|
33
|
+
recordPolicyHistory,
|
|
34
|
+
recordRollbackHistory,
|
|
35
|
+
recordSetupHistory,
|
|
36
|
+
recordSyncHistory,
|
|
37
|
+
recordUninstallHistory,
|
|
38
|
+
recordUpgradeHistory
|
|
39
|
+
} from "./history.js";
|
|
40
|
+
import { buildDiagnosticsReport, buildReportJson, DEFAULT_HISTORY_LIMIT, writeReportFile } from "./report.js";
|
|
41
|
+
import { BRAND, commandHeader } from "./brand/index.js";
|
|
42
|
+
import { formatCliCommand } from "./brand/cli.js";
|
|
43
|
+
|
|
44
|
+
export async function runGlobalInstall(options, packageManifest, packageRoot, { update = false } = {}) {
|
|
45
|
+
const homeDir = resolveHomeDir();
|
|
46
|
+
const workspaceRoot = options.cwd;
|
|
47
|
+
const run = update ? updateGlobalHarness : installGlobalHarness;
|
|
48
|
+
const result = await run({
|
|
49
|
+
packageRoot,
|
|
50
|
+
packageName: packageManifest.name,
|
|
51
|
+
cliVersion: packageManifest.version,
|
|
52
|
+
homeDir,
|
|
53
|
+
workspaceRoot,
|
|
54
|
+
agents: options.adapters,
|
|
55
|
+
components: options.components,
|
|
56
|
+
noDefaultComponents: options.noDefaultComponents,
|
|
57
|
+
dryRun: options.dryRun
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
printInstallResult(result, { update, dryRun: options.dryRun });
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function runGlobalSetup(options, packageManifest, packageRoot) {
|
|
65
|
+
const homeDir = resolveHomeDir();
|
|
66
|
+
const preReport = await buildStatusReport(homeDir, { packageRoot, workspaceRoot: options.cwd });
|
|
67
|
+
const checksBefore = buildCheckSnapshot(preReport.counts);
|
|
68
|
+
|
|
69
|
+
const outcome = await runHarnessSetup({
|
|
70
|
+
packageRoot,
|
|
71
|
+
packageName: packageManifest.name,
|
|
72
|
+
cliVersion: packageManifest.version,
|
|
73
|
+
homeDir,
|
|
74
|
+
workspaceRoot: options.cwd,
|
|
75
|
+
agents: options.adapters,
|
|
76
|
+
components: options.components,
|
|
77
|
+
noDefaultComponents: options.noDefaultComponents,
|
|
78
|
+
dryRun: options.dryRun,
|
|
79
|
+
yes: options.yes,
|
|
80
|
+
confirm: options.confirm,
|
|
81
|
+
preflight: options.preflight,
|
|
82
|
+
preflightExplicit: options.preflightExplicit,
|
|
83
|
+
yesExplicit: options.yesExplicit,
|
|
84
|
+
confirmExplicit: options.confirmExplicit,
|
|
85
|
+
json: options.json,
|
|
86
|
+
interactive: options.interactive,
|
|
87
|
+
simple: options.simple
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await recordSetupHistory(homeDir, {
|
|
91
|
+
cliVersion: packageManifest.version,
|
|
92
|
+
options,
|
|
93
|
+
outcome,
|
|
94
|
+
checksBefore,
|
|
95
|
+
packageRoot,
|
|
96
|
+
workspaceRoot: options.cwd
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (outcome.cancelled) return outcome;
|
|
100
|
+
|
|
101
|
+
if (!outcome.usedWizard) {
|
|
102
|
+
printInstallResult(outcome.result, { update: false, dryRun: options.dryRun, command: "setup" });
|
|
103
|
+
}
|
|
104
|
+
return outcome;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function runGlobalStatus(packageRoot, {
|
|
108
|
+
workspaceRoot = process.cwd(),
|
|
109
|
+
setExitCode = true,
|
|
110
|
+
json = false,
|
|
111
|
+
cliVersion = null
|
|
112
|
+
} = {}) {
|
|
113
|
+
const homeDir = resolveHomeDir();
|
|
114
|
+
const report = await buildStatusReport(homeDir, { packageRoot, workspaceRoot });
|
|
115
|
+
|
|
116
|
+
if (json) {
|
|
117
|
+
printJson(buildControlPlaneJson(report, { cliVersion }));
|
|
118
|
+
} else {
|
|
119
|
+
printStatusReport(report);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (setExitCode && !report.ok) process.exitCode = 1;
|
|
123
|
+
return report;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export async function runGlobalSync(options, packageManifest, packageRoot) {
|
|
127
|
+
const homeDir = resolveHomeDir();
|
|
128
|
+
const preReport = await buildStatusReport(homeDir, { packageRoot, workspaceRoot: options.cwd });
|
|
129
|
+
const checksBefore = buildCheckSnapshot(preReport.counts);
|
|
130
|
+
|
|
131
|
+
const outcome = await runHarnessSync({
|
|
132
|
+
packageRoot,
|
|
133
|
+
packageName: packageManifest.name,
|
|
134
|
+
cliVersion: packageManifest.version,
|
|
135
|
+
homeDir,
|
|
136
|
+
workspaceRoot: options.cwd,
|
|
137
|
+
dryRun: options.dryRun,
|
|
138
|
+
yes: options.yes,
|
|
139
|
+
confirm: options.confirm,
|
|
140
|
+
preflight: options.preflight,
|
|
141
|
+
preflightExplicit: options.preflightExplicit,
|
|
142
|
+
yesExplicit: options.yesExplicit,
|
|
143
|
+
confirmExplicit: options.confirmExplicit,
|
|
144
|
+
json: options.json,
|
|
145
|
+
interactive: options.interactive
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
await recordSyncHistory(homeDir, {
|
|
149
|
+
cliVersion: packageManifest.version,
|
|
150
|
+
options,
|
|
151
|
+
outcome,
|
|
152
|
+
checksBefore,
|
|
153
|
+
packageRoot,
|
|
154
|
+
workspaceRoot: options.cwd
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (options.json) {
|
|
158
|
+
printJson(buildControlPlaneJson(outcome.report, {
|
|
159
|
+
cliVersion: packageManifest.version,
|
|
160
|
+
extras: buildSyncJsonExtras(outcome)
|
|
161
|
+
}));
|
|
162
|
+
if (!outcome.report.ok) process.exitCode = 1;
|
|
163
|
+
return outcome;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
console.log(commandHeader("sync — converge local AI ecosystem"));
|
|
167
|
+
|
|
168
|
+
switch (outcome.action) {
|
|
169
|
+
case "setup-required":
|
|
170
|
+
console.log(`No managed state found. Run "${formatCliCommand("setup")}" first.`);
|
|
171
|
+
if (options.dryRun) console.log("Dry run: nothing was written.");
|
|
172
|
+
break;
|
|
173
|
+
case "noop":
|
|
174
|
+
console.log("Ecosystem already in sync. No changes needed.");
|
|
175
|
+
if (options.dryRun) console.log("Dry run: nothing was written.");
|
|
176
|
+
break;
|
|
177
|
+
case "plan":
|
|
178
|
+
printSyncRepairSummary(outcome.result, { dryRun: true });
|
|
179
|
+
break;
|
|
180
|
+
case "repaired":
|
|
181
|
+
printSyncRepairSummary(outcome.result, { dryRun: false });
|
|
182
|
+
break;
|
|
183
|
+
case "cancelled":
|
|
184
|
+
console.log("Sync cancelled. No changes were written.");
|
|
185
|
+
break;
|
|
186
|
+
default: {
|
|
187
|
+
const _exhaustive = outcome.action;
|
|
188
|
+
throw new Error(`Unknown sync action: ${_exhaustive}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
console.log("");
|
|
193
|
+
printStatusReport(outcome.report);
|
|
194
|
+
if (!outcome.report.ok) process.exitCode = 1;
|
|
195
|
+
return outcome;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export async function runGlobalUpgrade(options, packageManifest, packageRoot) {
|
|
199
|
+
const homeDir = resolveHomeDir();
|
|
200
|
+
const preReport = await buildStatusReport(homeDir, { packageRoot, workspaceRoot: options.cwd });
|
|
201
|
+
const checksBefore = buildCheckSnapshot(preReport.counts);
|
|
202
|
+
|
|
203
|
+
const outcome = await runHarnessUpgrade({
|
|
204
|
+
packageRoot,
|
|
205
|
+
packageName: packageManifest.name,
|
|
206
|
+
cliVersion: packageManifest.version,
|
|
207
|
+
homeDir,
|
|
208
|
+
workspaceRoot: options.cwd,
|
|
209
|
+
dryRun: options.dryRun,
|
|
210
|
+
yes: options.yes,
|
|
211
|
+
confirm: options.confirm,
|
|
212
|
+
preflight: options.preflight,
|
|
213
|
+
preflightExplicit: options.preflightExplicit,
|
|
214
|
+
yesExplicit: options.yesExplicit,
|
|
215
|
+
confirmExplicit: options.confirmExplicit,
|
|
216
|
+
json: options.json,
|
|
217
|
+
interactive: options.interactive
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
await recordUpgradeHistory(homeDir, {
|
|
221
|
+
cliVersion: packageManifest.version,
|
|
222
|
+
options,
|
|
223
|
+
outcome,
|
|
224
|
+
checksBefore,
|
|
225
|
+
packageRoot,
|
|
226
|
+
workspaceRoot: options.cwd
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
if (outcome.cancelled) {
|
|
230
|
+
console.log(commandHeader("upgrade — preview or apply managed ecosystem updates"));
|
|
231
|
+
console.log("Upgrade cancelled. No changes were written.");
|
|
232
|
+
return outcome;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
console.log(commandHeader("upgrade — preview or apply managed ecosystem updates"));
|
|
236
|
+
console.log(`Installed CLI: ${outcome.installedVersion}`);
|
|
237
|
+
console.log(`Published latest: ${outcome.latestVersion}`);
|
|
238
|
+
console.log("");
|
|
239
|
+
|
|
240
|
+
if (outcome.dryRun) {
|
|
241
|
+
console.log("Preview only. No configs or ~/.harness state were modified.");
|
|
242
|
+
console.log(`Run latest package preview: ${outcome.previewCommand}`);
|
|
243
|
+
console.log(`Apply with latest package: ${outcome.latestCommand}`);
|
|
244
|
+
console.log("");
|
|
245
|
+
printInstallResult(outcome.result, { update: true, dryRun: true, command: "upgrade" });
|
|
246
|
+
return outcome;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
console.log("Applied upgrade with the current CLI package.");
|
|
250
|
+
console.log(`To converge with npm latest, run: ${outcome.latestCommand}`);
|
|
251
|
+
console.log("");
|
|
252
|
+
printInstallResult(outcome.result, { update: true, dryRun: false, command: "upgrade" });
|
|
253
|
+
return outcome;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function buildSyncJsonExtras(outcome) {
|
|
257
|
+
const extras = {
|
|
258
|
+
action: outcome.action,
|
|
259
|
+
wrote: outcome.wrote
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
if (!outcome.result) return extras;
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
...extras,
|
|
266
|
+
driftDetected: outcome.result.driftDetected,
|
|
267
|
+
assetsRepaired: outcome.result.assetsRepaired,
|
|
268
|
+
assetsUnchanged: outcome.result.assetsUnchanged,
|
|
269
|
+
configsRepaired: outcome.result.configsRepaired,
|
|
270
|
+
repairs: outcome.result.repairs ?? []
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function printStatusReport(report) {
|
|
275
|
+
console.log(commandHeader("status — local AI ecosystem"));
|
|
276
|
+
console.log(`Home: ${report.homeDir}`);
|
|
277
|
+
console.log(`State root: ${report.stateRoot}`);
|
|
278
|
+
console.log(
|
|
279
|
+
report.state
|
|
280
|
+
? `State: installed (cliVersion=${report.state.cliVersion ?? "unknown"})`
|
|
281
|
+
: "State: missing"
|
|
282
|
+
);
|
|
283
|
+
console.log("");
|
|
284
|
+
|
|
285
|
+
console.log("Agents:");
|
|
286
|
+
for (const agent of report.agents) {
|
|
287
|
+
const detected = agent.detected ? "detected" : "not detected";
|
|
288
|
+
const managed = agent.managed ? "managed" : "unmanaged";
|
|
289
|
+
console.log(` ${agent.id.padEnd(10)} ${detected.padEnd(13)} ${managed}`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
console.log("");
|
|
293
|
+
console.log("Components:");
|
|
294
|
+
if (report.components.length === 0) {
|
|
295
|
+
console.log(" none");
|
|
296
|
+
} else {
|
|
297
|
+
for (const component of report.components) {
|
|
298
|
+
console.log(
|
|
299
|
+
` ${component.id.padEnd(14)} ${String(component.version).padEnd(8)} ${component.status}`
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
console.log("");
|
|
305
|
+
console.log("Policy:");
|
|
306
|
+
console.log(` Source: ${formatPolicySourceLabel(report.policy)}`);
|
|
307
|
+
console.log(` Profile: ${formatPolicyProfileLabel(report.policy.profile)}`);
|
|
308
|
+
console.log(` Apply mode: ${report.policy.applyMode}`);
|
|
309
|
+
console.log(` Preflight: ${report.policy.preflight ? "enabled" : "disabled"}`);
|
|
310
|
+
console.log(` Agents: ${report.policy.agents}`);
|
|
311
|
+
console.log(` Components: ${report.policy.components.join(", ") || "none"}`);
|
|
312
|
+
console.log("");
|
|
313
|
+
console.log(`Checks: ok=${report.counts.ok} missing=${report.counts.missing} stale=${report.counts.stale} warning=${report.counts.warning}`);
|
|
314
|
+
console.log(`Backups: ${report.backups} snapshot(s)`);
|
|
315
|
+
console.log(`Overall: ${report.overall.toUpperCase()}`);
|
|
316
|
+
console.log(`Next: ${report.nextAction}`);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function printSyncRepairSummary(result, { dryRun = false } = {}) {
|
|
320
|
+
console.log(dryRun ? "Planned repairs:" : "Applied repairs:");
|
|
321
|
+
console.log(` Drift detected: ${result.driftDetected ? "yes" : "no"}`);
|
|
322
|
+
console.log(` Assets repaired: ${result.assetsRepaired.length}`);
|
|
323
|
+
console.log(` Assets unchanged: ${result.assetsUnchanged.length}`);
|
|
324
|
+
console.log(` Sections repaired: ${result.configsRepaired.length}`);
|
|
325
|
+
console.log(`${dryRun ? "Backups planned" : "Backups"}: ${result.backups.length}`);
|
|
326
|
+
|
|
327
|
+
if (dryRun && result.repairs?.length) {
|
|
328
|
+
for (const repair of result.repairs) {
|
|
329
|
+
console.log(` - [${repair.status.toUpperCase()}] ${repair.name}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (dryRun) {
|
|
334
|
+
console.log("Dry run: nothing was written.");
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function printInstallResult(result, { update = false, dryRun = false, command = null } = {}) {
|
|
339
|
+
const verb = update ? "update" : (command === "setup" ? "setup" : "install");
|
|
340
|
+
const pastLabel = update ? "updated" : (command === "setup" ? "configured" : "installed");
|
|
341
|
+
console.log(`${BRAND.displayName} global ${dryRun ? `${verb} plan` : pastLabel} (scope: agent-global)`);
|
|
342
|
+
console.log(`State root: ${result.stateRoot}`);
|
|
343
|
+
console.log(`Agents: ${result.agents.join(", ")}`);
|
|
344
|
+
console.log(`Components: ${result.components.join(", ") || "none (core plumbing only)"}`);
|
|
345
|
+
console.log(`Core files: ${result.coreFiles.join(", ") || "none"}`);
|
|
346
|
+
|
|
347
|
+
if (update) {
|
|
348
|
+
console.log(`Drift detected: ${result.driftDetected ? "yes" : "no"}`);
|
|
349
|
+
console.log(`Assets repaired: ${result.assetsRepaired.length}`);
|
|
350
|
+
console.log(`Assets unchanged: ${result.assetsUnchanged.length}`);
|
|
351
|
+
console.log(`Sections repaired: ${result.configsRepaired.length}`);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
console.log(`Configs created: ${result.configsCreated.length}`);
|
|
355
|
+
console.log(`Configs updated: ${result.configsUpdated.length}`);
|
|
356
|
+
console.log(`Configs unchanged: ${result.configsUnchanged.length}`);
|
|
357
|
+
console.log(`${dryRun ? "Backups planned" : "Backups"}: ${result.backups.length}`);
|
|
358
|
+
|
|
359
|
+
if (dryRun) {
|
|
360
|
+
if (result.repairs?.length) {
|
|
361
|
+
console.log(`Planned repairs: ${result.repairs.length}`);
|
|
362
|
+
for (const repair of result.repairs) {
|
|
363
|
+
console.log(` - [${repair.status.toUpperCase()}] ${repair.name}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
console.log("Dry run: nothing was written.");
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
console.log(`State tracked in ~/.harness/state.json. Run "${formatCliCommand("status")}" or "${formatCliCommand("doctor")}" to verify.`);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export async function runGlobalUninstall(options, packageManifest) {
|
|
374
|
+
const homeDir = resolveHomeDir();
|
|
375
|
+
const result = await uninstallGlobalHarness({
|
|
376
|
+
homeDir,
|
|
377
|
+
dryRun: options.dryRun
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
await recordUninstallHistory(homeDir, {
|
|
381
|
+
cliVersion: packageManifest?.version ?? null,
|
|
382
|
+
options,
|
|
383
|
+
result
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
console.log(`${BRAND.displayName} global ${options.dryRun ? "uninstall plan" : "uninstalled"} (scope: agent-global)`);
|
|
387
|
+
console.log(`Configs cleaned: ${result.configsCleaned.join(", ") || "none"}`);
|
|
388
|
+
console.log(`Backups: ${result.backups.length}`);
|
|
389
|
+
console.log(`State removed: ${result.stateRemoved ? "yes" : "no state found"}`);
|
|
390
|
+
console.log("Backups under ~/.harness/backups were preserved.");
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export async function runGlobalDoctor(packageRoot, {
|
|
394
|
+
workspaceRoot = process.cwd(),
|
|
395
|
+
json = false,
|
|
396
|
+
cliVersion = null
|
|
397
|
+
} = {}) {
|
|
398
|
+
const homeDir = resolveHomeDir();
|
|
399
|
+
|
|
400
|
+
if (json) {
|
|
401
|
+
const report = await buildStatusReport(homeDir, { packageRoot, workspaceRoot });
|
|
402
|
+
printJson(buildControlPlaneJson(report, { cliVersion }));
|
|
403
|
+
if (!report.ok) process.exitCode = 1;
|
|
404
|
+
return report;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const { checks, ok, hasDrift } = await runGlobalDoctorChecks(homeDir, { packageRoot, workspaceRoot });
|
|
408
|
+
|
|
409
|
+
console.log(`${BRAND.displayName} doctor (scope: agent-global)`);
|
|
410
|
+
console.log(`Home: ${homeDir}`);
|
|
411
|
+
console.log("");
|
|
412
|
+
|
|
413
|
+
for (const check of checks) {
|
|
414
|
+
const label = check.status.toUpperCase().padEnd(8);
|
|
415
|
+
const detail = check.detail ? ` — ${check.detail}` : "";
|
|
416
|
+
console.log(`[${label}] ${check.name}${detail}`);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
console.log("");
|
|
420
|
+
if (ok) {
|
|
421
|
+
console.log("Status: OK");
|
|
422
|
+
} else if (hasDrift) {
|
|
423
|
+
console.log(`Status: DRIFT DETECTED — run "${formatCliCommand("sync")}" to auto-repair managed content`);
|
|
424
|
+
} else {
|
|
425
|
+
console.log("Status: FAILED (missing managed state or configs)");
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (!ok) process.exitCode = 1;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export async function runGlobalAdapters({ json = false, cliVersion = null } = {}) {
|
|
432
|
+
const homeDir = resolveHomeDir();
|
|
433
|
+
const report = await buildAdapterMatrixReport(homeDir);
|
|
434
|
+
|
|
435
|
+
if (json) {
|
|
436
|
+
printJson({
|
|
437
|
+
adapters: report.adapters,
|
|
438
|
+
managedCount: report.managedCount,
|
|
439
|
+
detectedCount: report.detectedCount,
|
|
440
|
+
supportedCount: report.supportedCount,
|
|
441
|
+
cliVersion
|
|
442
|
+
});
|
|
443
|
+
return report;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
printAdapterMatrixReport(report);
|
|
447
|
+
return report;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
export async function runGlobalExplain({ json = false, cliVersion = null } = {}) {
|
|
451
|
+
const homeDir = resolveHomeDir();
|
|
452
|
+
const report = await buildExplainReport(homeDir);
|
|
453
|
+
|
|
454
|
+
if (json) {
|
|
455
|
+
printJson(buildExplainJson(report, { cliVersion }));
|
|
456
|
+
return report;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
printExplainReport(report);
|
|
460
|
+
return report;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function printExplainReport(report) {
|
|
464
|
+
console.log(commandHeader("explain — managed ecosystem audit (read-only)"));
|
|
465
|
+
console.log(`Home: ${report.homeDir}`);
|
|
466
|
+
console.log(`State root: ${report.stateRoot}`);
|
|
467
|
+
console.log("");
|
|
468
|
+
|
|
469
|
+
console.log("Managed markers:");
|
|
470
|
+
console.log(` start: ${report.markers.start}`);
|
|
471
|
+
console.log(` end: ${report.markers.end}`);
|
|
472
|
+
console.log("");
|
|
473
|
+
|
|
474
|
+
console.log("Policy:");
|
|
475
|
+
console.log(` Source: ${formatPolicySourceLabel(report.policy)}`);
|
|
476
|
+
console.log(` Profile: ${formatPolicyProfileLabel(report.policy.profile)}`);
|
|
477
|
+
console.log(` Apply mode: ${report.policy.applyMode}`);
|
|
478
|
+
console.log(` Preflight: ${report.policy.preflight ? "enabled" : "disabled"}`);
|
|
479
|
+
console.log(` Agents: ${report.policy.agents}`);
|
|
480
|
+
console.log(` Components: ${report.policy.components.join(", ") || "none"}`);
|
|
481
|
+
console.log(` File: ${report.policy.path}`);
|
|
482
|
+
console.log("");
|
|
483
|
+
|
|
484
|
+
console.log("Adapters:");
|
|
485
|
+
for (const adapter of report.adapters) {
|
|
486
|
+
const detected = adapter.detected ? "detected" : "not detected";
|
|
487
|
+
const managed = adapter.managed ? "managed" : "unmanaged";
|
|
488
|
+
console.log(` ${adapter.id.padEnd(10)} ${detected.padEnd(13)} ${managed}`);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
console.log("");
|
|
492
|
+
console.log(`${BRAND.displayName} writes to:`);
|
|
493
|
+
for (const target of report.writesTo) {
|
|
494
|
+
console.log(` - ~/${target.replace(/^\//, "")}`);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
console.log("");
|
|
498
|
+
console.log("Config files:");
|
|
499
|
+
if (report.configFiles.length === 0) {
|
|
500
|
+
console.log(" none (run setup to configure managed sections)");
|
|
501
|
+
} else {
|
|
502
|
+
for (const file of report.configFiles) {
|
|
503
|
+
const managedLabel = file.managed ? "managed" : "unmanaged";
|
|
504
|
+
const sectionLabel = file.hasManagedSection ? "has managed section" : "no managed section";
|
|
505
|
+
console.log(` ${file.path} — ${managedLabel}, ${sectionLabel}`);
|
|
506
|
+
|
|
507
|
+
if (file.hasPreservedUserContent) {
|
|
508
|
+
console.log(" user-owned preserved: yes");
|
|
509
|
+
} else if (file.exists && file.hasManagedSection) {
|
|
510
|
+
console.log(" user-owned preserved: no (managed markers only)");
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
console.log("");
|
|
516
|
+
console.log("Components:");
|
|
517
|
+
if (report.components.length === 0) {
|
|
518
|
+
console.log(" none");
|
|
519
|
+
} else {
|
|
520
|
+
for (const component of report.components) {
|
|
521
|
+
console.log(
|
|
522
|
+
` ${component.id.padEnd(14)} ${String(component.version).padEnd(8)} ${component.source} -> ~/.harness/${component.assetDir}`
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
console.log("");
|
|
528
|
+
console.log("Backups:");
|
|
529
|
+
if (report.backups.length === 0) {
|
|
530
|
+
console.log(" none");
|
|
531
|
+
} else {
|
|
532
|
+
for (const snapshot of report.backups) {
|
|
533
|
+
console.log(` - ${snapshot.name} (${snapshot.fileCount} file${snapshot.fileCount === 1 ? "" : "s"})`);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
console.log("");
|
|
538
|
+
console.log(`Next: ${report.nextAction}`);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
export async function runGlobalReport({
|
|
542
|
+
packageManifest,
|
|
543
|
+
packageRoot,
|
|
544
|
+
json = false,
|
|
545
|
+
workspaceRoot = process.cwd(),
|
|
546
|
+
historyLimit = null,
|
|
547
|
+
outPath = null
|
|
548
|
+
} = {}) {
|
|
549
|
+
const homeDir = resolveHomeDir();
|
|
550
|
+
const limit = historyLimit ?? DEFAULT_HISTORY_LIMIT;
|
|
551
|
+
const report = await buildDiagnosticsReport(homeDir, {
|
|
552
|
+
packageRoot,
|
|
553
|
+
packageName: packageManifest.name,
|
|
554
|
+
cliVersion: packageManifest.version,
|
|
555
|
+
workspaceRoot,
|
|
556
|
+
historyLimit: limit
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
if (json) {
|
|
560
|
+
const payload = buildReportJson(report);
|
|
561
|
+
if (outPath) {
|
|
562
|
+
await writeReportFile(outPath, `${JSON.stringify(payload)}\n`);
|
|
563
|
+
console.log(`Diagnostics report written to: ${outPath}`);
|
|
564
|
+
} else {
|
|
565
|
+
printJson(payload);
|
|
566
|
+
}
|
|
567
|
+
if (!report.ok) process.exitCode = 1;
|
|
568
|
+
return report;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const text = formatDiagnosticsReport(report);
|
|
572
|
+
if (outPath) {
|
|
573
|
+
await writeReportFile(outPath, text);
|
|
574
|
+
console.log(`Diagnostics report written to: ${outPath}`);
|
|
575
|
+
} else {
|
|
576
|
+
console.log(text);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (!report.ok) process.exitCode = 1;
|
|
580
|
+
return report;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function formatDiagnosticsReport(report) {
|
|
584
|
+
const lines = [];
|
|
585
|
+
|
|
586
|
+
lines.push(commandHeader("report — local diagnostics (read-only)"));
|
|
587
|
+
lines.push(`CLI version: ${report.cliVersion}`);
|
|
588
|
+
lines.push(`Home: ${report.homeDir}`);
|
|
589
|
+
lines.push("");
|
|
590
|
+
|
|
591
|
+
lines.push("Adapters:");
|
|
592
|
+
lines.push(
|
|
593
|
+
` Supported: ${report.adapters.supportedCount} Detected: ${report.adapters.detectedCount} Managed: ${report.adapters.managedCount}`
|
|
594
|
+
);
|
|
595
|
+
for (const adapter of report.adapters.adapters) {
|
|
596
|
+
const detected = adapter.detected ? "detected" : "not detected";
|
|
597
|
+
const managed = adapter.managed ? "managed" : "unmanaged";
|
|
598
|
+
lines.push(` ${adapter.id.padEnd(10)} ${detected.padEnd(13)} ${managed}`);
|
|
599
|
+
}
|
|
600
|
+
lines.push("");
|
|
601
|
+
|
|
602
|
+
lines.push("Policy:");
|
|
603
|
+
lines.push(` Source: ${formatPolicySourceLabel(report.policy)}`);
|
|
604
|
+
lines.push(` Profile: ${formatPolicyProfileLabel(report.policy.profile)}`);
|
|
605
|
+
lines.push(` Apply mode: ${report.policy.applyMode}`);
|
|
606
|
+
lines.push(` Preflight: ${report.policy.preflight ? "enabled" : "disabled"}`);
|
|
607
|
+
lines.push(` Agents: ${report.policy.agents}`);
|
|
608
|
+
lines.push(` Components: ${report.policy.components.join(", ") || "none"}`);
|
|
609
|
+
lines.push("");
|
|
610
|
+
|
|
611
|
+
lines.push("Status:");
|
|
612
|
+
lines.push(` Overall: ${report.status.overall.toUpperCase()}`);
|
|
613
|
+
lines.push(
|
|
614
|
+
report.status.installed
|
|
615
|
+
? ` State: installed (cliVersion=${report.status.stateCliVersion ?? "unknown"})`
|
|
616
|
+
: " State: missing"
|
|
617
|
+
);
|
|
618
|
+
lines.push(
|
|
619
|
+
` Checks: ok=${report.status.counts.ok} missing=${report.status.counts.missing} stale=${report.status.counts.stale} warning=${report.status.counts.warning}`
|
|
620
|
+
);
|
|
621
|
+
lines.push(` Backups: ${report.status.backups} snapshot(s)`);
|
|
622
|
+
lines.push(` Next: ${report.status.nextAction}`);
|
|
623
|
+
lines.push("");
|
|
624
|
+
|
|
625
|
+
lines.push("Diff:");
|
|
626
|
+
lines.push(` Summary: ${report.diff.summary}`);
|
|
627
|
+
if (report.diff.hasChanges) {
|
|
628
|
+
lines.push(` Planned changes: ${report.diff.changeCount}`);
|
|
629
|
+
for (const change of report.diff.changes) {
|
|
630
|
+
lines.push(` [${change.status}] ${change.kind} ${change.action} -> ${change.target}`);
|
|
631
|
+
}
|
|
632
|
+
} else {
|
|
633
|
+
lines.push(" Drift: none");
|
|
634
|
+
}
|
|
635
|
+
lines.push(` Next: ${report.diff.nextAction}`);
|
|
636
|
+
lines.push("");
|
|
637
|
+
|
|
638
|
+
lines.push(`History (last ${report.history.limit} events):`);
|
|
639
|
+
lines.push(` File: ${report.history.path}`);
|
|
640
|
+
for (const warning of report.history.warnings) {
|
|
641
|
+
lines.push(` Warning: skipped invalid history line ${warning.line}: ${warning.message}`);
|
|
642
|
+
}
|
|
643
|
+
if (report.history.events.length === 0) {
|
|
644
|
+
lines.push(" No managed operations recorded yet.");
|
|
645
|
+
} else {
|
|
646
|
+
for (const event of report.history.events) {
|
|
647
|
+
lines.push(` ${formatHistoryEvent(event)}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
return `${lines.join("\n")}\n`;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
export async function runGlobalDiff({
|
|
655
|
+
packageManifest,
|
|
656
|
+
packageRoot,
|
|
657
|
+
json = false,
|
|
658
|
+
workspaceRoot = process.cwd()
|
|
659
|
+
} = {}) {
|
|
660
|
+
const homeDir = resolveHomeDir();
|
|
661
|
+
const report = await buildDiffReport(homeDir, {
|
|
662
|
+
packageRoot,
|
|
663
|
+
packageName: packageManifest.name,
|
|
664
|
+
cliVersion: packageManifest.version,
|
|
665
|
+
workspaceRoot
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
if (json) {
|
|
669
|
+
printJson(buildDiffJson(report, { cliVersion: packageManifest.version }));
|
|
670
|
+
return report;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
printDiffReport(report);
|
|
674
|
+
return report;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function printDiffReport(report) {
|
|
678
|
+
console.log(commandHeader("diff — managed content preview (read-only)"));
|
|
679
|
+
console.log(`Home: ${report.homeDir}`);
|
|
680
|
+
console.log(`Summary: ${report.summary}`);
|
|
681
|
+
console.log("");
|
|
682
|
+
|
|
683
|
+
if (!report.installed) {
|
|
684
|
+
console.log(`Next: ${report.nextAction}`);
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (!report.hasChanges) {
|
|
689
|
+
console.log("Managed changes: none");
|
|
690
|
+
console.log("");
|
|
691
|
+
if (report.preserved.length > 0) {
|
|
692
|
+
console.log("User-owned preserved content:");
|
|
693
|
+
for (const entry of report.preserved) {
|
|
694
|
+
console.log(` ${entry.path} — intact`);
|
|
695
|
+
}
|
|
696
|
+
console.log("");
|
|
697
|
+
}
|
|
698
|
+
console.log(`Next: ${report.nextAction}`);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
console.log("Planned managed changes:");
|
|
703
|
+
for (const change of report.changes) {
|
|
704
|
+
console.log(
|
|
705
|
+
` [${change.status}] ${change.kind} ${change.action} -> ${change.target}`
|
|
706
|
+
);
|
|
707
|
+
console.log(` ${change.detail}`);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
console.log("");
|
|
711
|
+
if (report.preserved.length > 0) {
|
|
712
|
+
console.log("User-owned preserved content (outside managed markers):");
|
|
713
|
+
for (const entry of report.preserved) {
|
|
714
|
+
console.log(` ${entry.path} — intact`);
|
|
715
|
+
}
|
|
716
|
+
console.log("");
|
|
717
|
+
} else {
|
|
718
|
+
console.log("User-owned preserved content: none detected in affected configs.");
|
|
719
|
+
console.log("");
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
console.log(`Next: ${report.nextAction}`);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
function printAdapterMatrixReport(report) {
|
|
726
|
+
console.log(commandHeader("adapters — supported agent integrations"));
|
|
727
|
+
console.log(`Home: ${report.homeDir}`);
|
|
728
|
+
console.log("");
|
|
729
|
+
console.log(`${BRAND.displayName} does not install Cursor, Codex, OpenCode, or Claude Code.`);
|
|
730
|
+
console.log("It configures managed sections in each agent's config files.");
|
|
731
|
+
console.log("");
|
|
732
|
+
console.log(`Supported: ${report.supportedCount} Detected: ${report.detectedCount} Managed: ${report.managedCount}`);
|
|
733
|
+
console.log("");
|
|
734
|
+
|
|
735
|
+
for (const adapter of report.adapters) {
|
|
736
|
+
const detected = adapter.detected ? "detected" : "not detected";
|
|
737
|
+
const managed = adapter.managed ? "managed" : "unmanaged";
|
|
738
|
+
console.log(`${adapter.id.padEnd(10)} ${adapter.label.padEnd(12)} ${detected.padEnd(13)} ${managed}`);
|
|
739
|
+
console.log(` root: ~/${adapter.rootDir}`);
|
|
740
|
+
console.log(` config: ~/${adapter.configFile}`);
|
|
741
|
+
console.log(` targets: ${adapter.managedTargets.join(", ")}`);
|
|
742
|
+
console.log("");
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
export function printGlobalDetect() {
|
|
747
|
+
const homeDir = resolveHomeDir();
|
|
748
|
+
const detected = detectInstalledAdapters({ homeDir });
|
|
749
|
+
|
|
750
|
+
console.log("Global agents (scope: agent-global)");
|
|
751
|
+
console.log(`Home: ${homeDir}`);
|
|
752
|
+
console.log(`Detected: ${detected.join(", ") || "none"}`);
|
|
753
|
+
console.log(`Supported: ${GLOBAL_AGENT_IDS.join(", ")}`);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
export function printGlobalComponents({ workspaceRoot = process.cwd() } = {}) {
|
|
757
|
+
const bundled = describeBundledComponentCatalog();
|
|
758
|
+
const workspace = describeWorkspaceComponentCatalog(workspaceRoot);
|
|
759
|
+
|
|
760
|
+
console.log(commandHeader("components (scope: agent-global)"));
|
|
761
|
+
console.log(`Bundled: ${bundled.length}`);
|
|
762
|
+
|
|
763
|
+
for (const component of bundled) {
|
|
764
|
+
printComponentEntry(component);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
console.log("");
|
|
768
|
+
console.log(`Workspace: ${workspace.length}`);
|
|
769
|
+
|
|
770
|
+
if (workspace.length === 0) {
|
|
771
|
+
console.log("No workspace catalog at .harness/components/catalog.json");
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
for (const component of workspace) {
|
|
776
|
+
printComponentEntry(component, { workspace: true });
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
function printComponentEntry(component, { workspace = false } = {}) {
|
|
781
|
+
const defaultLabel = workspace ? "workspace" : (component.defaultEnabled ? "default" : "optional");
|
|
782
|
+
console.log("");
|
|
783
|
+
console.log(`${component.id} (${component.version}) [${defaultLabel}]`);
|
|
784
|
+
console.log(` Label: ${component.label}`);
|
|
785
|
+
console.log(` Assets: ${component.assetFiles.join(", ")}`);
|
|
786
|
+
|
|
787
|
+
if (component.instructions) {
|
|
788
|
+
console.log(` Instructions: ${component.instructions}`);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if (component.adapterHints.length > 0) {
|
|
792
|
+
console.log(` Adapter hints: ${component.adapterHints.join(", ")}`);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
export function runComponentsValidate({ workspaceRoot = process.cwd() } = {}) {
|
|
797
|
+
const result = validateWorkspaceComponentsCatalog(workspaceRoot);
|
|
798
|
+
|
|
799
|
+
console.log("Workspace component catalog is valid");
|
|
800
|
+
console.log(`Catalog: .harness/components/catalog.json`);
|
|
801
|
+
console.log(`Components: ${result.components.length}`);
|
|
802
|
+
|
|
803
|
+
for (const component of result.components) {
|
|
804
|
+
console.log(`- ${component.id} (${component.version}) — ${component.assetFiles.join(", ")}`);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
export async function runComponentsInit(options) {
|
|
809
|
+
const result = await initWorkspaceComponent({
|
|
810
|
+
workspaceRoot: options.cwd,
|
|
811
|
+
id: options.componentId,
|
|
812
|
+
label: options.label
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
console.log("Workspace component created");
|
|
816
|
+
console.log(`Id: ${result.entry.id}`);
|
|
817
|
+
console.log(`Label: ${result.entry.label}`);
|
|
818
|
+
console.log(`Version: ${result.entry.version}`);
|
|
819
|
+
console.log(`Catalog: .harness/components/catalog.json`);
|
|
820
|
+
console.log(`Asset: .harness/components/${result.entry.id}/README.md`);
|
|
821
|
+
console.log("");
|
|
822
|
+
console.log("Next:");
|
|
823
|
+
console.log(` 1. Edit .harness/components/${result.entry.id}/README.md`);
|
|
824
|
+
console.log(` 2. ${formatCliCommand("components validate")}`);
|
|
825
|
+
console.log(` 3. ${formatCliCommand(`install --components ${result.entry.id}`)}`);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
export async function runComponentsPack(options) {
|
|
829
|
+
const result = await packWorkspaceComponent({
|
|
830
|
+
workspaceRoot: options.cwd,
|
|
831
|
+
id: options.componentId,
|
|
832
|
+
outPath: options.outPath
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
console.log("Workspace component packed");
|
|
836
|
+
console.log(`Id: ${result.entry.id}`);
|
|
837
|
+
console.log(`Version: ${result.entry.version}`);
|
|
838
|
+
console.log(`Bundle: ${result.outPath}`);
|
|
839
|
+
console.log(`Assets: ${result.entry.assetFiles.join(", ")}`);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
export async function runComponentsImport(options) {
|
|
843
|
+
const result = await importWorkspaceComponent({
|
|
844
|
+
workspaceRoot: options.cwd,
|
|
845
|
+
bundlePath: options.bundlePath
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
console.log("Workspace component imported");
|
|
849
|
+
console.log(`Id: ${result.entry.id}`);
|
|
850
|
+
console.log(`Label: ${result.entry.label}`);
|
|
851
|
+
console.log(`Version: ${result.entry.version}`);
|
|
852
|
+
console.log(`Catalog: .harness/components/catalog.json`);
|
|
853
|
+
console.log(`Assets: ${result.entry.assetFiles.map((asset) => `.harness/components/${result.entry.id}/${asset}`).join(", ")}`);
|
|
854
|
+
console.log("");
|
|
855
|
+
console.log("Next:");
|
|
856
|
+
console.log(` 1. ${formatCliCommand("components validate")}`);
|
|
857
|
+
console.log(` 2. ${formatCliCommand(`install --components ${result.entry.id}`)}`);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
export async function runGlobalBackups() {
|
|
861
|
+
const homeDir = resolveHomeDir();
|
|
862
|
+
const { backupsDir } = harnessHomePaths(homeDir);
|
|
863
|
+
const snapshots = await describeBackupSnapshots(backupsDir);
|
|
864
|
+
|
|
865
|
+
console.log(commandHeader("backups"));
|
|
866
|
+
console.log("Directory: ~/.harness/backups");
|
|
867
|
+
console.log(`Snapshots: ${snapshots.length}`);
|
|
868
|
+
|
|
869
|
+
if (snapshots.length === 0) {
|
|
870
|
+
console.log("No snapshots yet. Backups are created before config changes.");
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
for (const snapshot of snapshots) {
|
|
875
|
+
console.log(`- ${snapshot.name} (${snapshot.fileCount} file${snapshot.fileCount === 1 ? "" : "s"})`);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
export async function runGlobalHistory(options, packageManifest) {
|
|
880
|
+
const homeDir = resolveHomeDir();
|
|
881
|
+
const historyPath = getHistoryPath(homeDir);
|
|
882
|
+
const query = {
|
|
883
|
+
command: options.historyCommand ?? null,
|
|
884
|
+
action: options.historyEventAction ?? null,
|
|
885
|
+
limit: options.limit
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
if (options.historyAction === "last") {
|
|
889
|
+
const { event, warnings } = await readLastHistoryEvent(homeDir, query);
|
|
890
|
+
printHistoryWarnings(warnings);
|
|
891
|
+
|
|
892
|
+
if (options.json) {
|
|
893
|
+
printJson({
|
|
894
|
+
path: historyPath,
|
|
895
|
+
event,
|
|
896
|
+
warnings,
|
|
897
|
+
cliVersion: packageManifest?.version ?? null
|
|
898
|
+
});
|
|
899
|
+
return { event, warnings };
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
console.log(commandHeader("history last — most recent managed operation"));
|
|
903
|
+
console.log(`Home: ${homeDir}`);
|
|
904
|
+
console.log(`File: ${historyPath}`);
|
|
905
|
+
printHistoryFiltersLabel(query);
|
|
906
|
+
|
|
907
|
+
if (!event) {
|
|
908
|
+
console.log("No managed operations recorded yet.");
|
|
909
|
+
return { event: null, warnings };
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
console.log("");
|
|
913
|
+
console.log(formatHistoryEvent(event));
|
|
914
|
+
printHistoryEventDetails(event);
|
|
915
|
+
return { event, warnings };
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
const { events, warnings } = await readHistoryEvents(homeDir, query);
|
|
919
|
+
printHistoryWarnings(warnings);
|
|
920
|
+
|
|
921
|
+
if (options.json) {
|
|
922
|
+
printJson({
|
|
923
|
+
path: historyPath,
|
|
924
|
+
events,
|
|
925
|
+
warnings,
|
|
926
|
+
filters: buildHistoryFiltersJson(query),
|
|
927
|
+
cliVersion: packageManifest?.version ?? null
|
|
928
|
+
});
|
|
929
|
+
return { events, warnings };
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
console.log(commandHeader("history — local operation audit log"));
|
|
933
|
+
console.log(`Home: ${homeDir}`);
|
|
934
|
+
console.log(`File: ${historyPath}`);
|
|
935
|
+
console.log(`Events: ${events.length}`);
|
|
936
|
+
printHistoryFiltersLabel(query);
|
|
937
|
+
|
|
938
|
+
if (events.length === 0) {
|
|
939
|
+
console.log("No managed operations recorded yet.");
|
|
940
|
+
return { events, warnings };
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
console.log("");
|
|
944
|
+
for (const event of events) {
|
|
945
|
+
console.log(formatHistoryEvent(event));
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
return { events, warnings };
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function printHistoryWarnings(warnings) {
|
|
952
|
+
for (const warning of warnings) {
|
|
953
|
+
console.warn(`Warning: skipped invalid history line ${warning.line}: ${warning.message}`);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
function buildHistoryFiltersJson({ command, action, limit }) {
|
|
958
|
+
const filters = {};
|
|
959
|
+
if (command) filters.command = command;
|
|
960
|
+
if (action) filters.action = action;
|
|
961
|
+
if (limit != null) filters.limit = limit;
|
|
962
|
+
return Object.keys(filters).length > 0 ? filters : null;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function printHistoryFiltersLabel({ command, action, limit }) {
|
|
966
|
+
const parts = [];
|
|
967
|
+
if (command) parts.push(`command=${command}`);
|
|
968
|
+
if (action) parts.push(`action=${action}`);
|
|
969
|
+
if (limit != null) parts.push(`limit=${limit}`);
|
|
970
|
+
if (parts.length > 0) {
|
|
971
|
+
console.log(`Filters: ${parts.join(", ")}`);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
function printHistoryEventDetails(event) {
|
|
976
|
+
console.log(` wrote: ${event.wrote ? "yes" : "no"}`);
|
|
977
|
+
console.log(` cliVersion: ${event.cliVersion ?? "unknown"}`);
|
|
978
|
+
|
|
979
|
+
if (event.consentSource) {
|
|
980
|
+
console.log(` consent: ${event.consentSource}`);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
if (Array.isArray(event.backupsCreated) && event.backupsCreated.length > 0) {
|
|
984
|
+
console.log(` backups: ${event.backupsCreated.join(", ")}`);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
if (Array.isArray(event.snapshotsUsed) && event.snapshotsUsed.length > 0) {
|
|
988
|
+
console.log(` snapshots: ${event.snapshotsUsed.join(", ")}`);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
export async function runGlobalRollback(options, packageManifest) {
|
|
993
|
+
if (!options.snapshot) {
|
|
994
|
+
throw new Error(`Missing snapshot. Use: ${formatCliCommand("rollback --to <snapshot>")}`);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
const homeDir = resolveHomeDir();
|
|
998
|
+
|
|
999
|
+
if (options.apply) {
|
|
1000
|
+
const result = await applyRollback({ homeDir, snapshot: options.snapshot });
|
|
1001
|
+
|
|
1002
|
+
await recordRollbackHistory(homeDir, {
|
|
1003
|
+
cliVersion: packageManifest?.version ?? null,
|
|
1004
|
+
snapshot: options.snapshot,
|
|
1005
|
+
result
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
console.log(commandHeader("rollback applied"));
|
|
1009
|
+
console.log(`Snapshot: ${result.snapshot}`);
|
|
1010
|
+
console.log(`Restored: ${result.restored.length}`);
|
|
1011
|
+
|
|
1012
|
+
if (result.noop) {
|
|
1013
|
+
console.log("No files to restore.");
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
if (result.safetyBackup) {
|
|
1018
|
+
console.log(`Safety backup: ${result.safetyBackup}`);
|
|
1019
|
+
}
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
const result = await previewRollback({ homeDir, snapshot: options.snapshot });
|
|
1024
|
+
|
|
1025
|
+
console.log(commandHeader("rollback preview"));
|
|
1026
|
+
console.log(`Snapshot: ${result.snapshot}`);
|
|
1027
|
+
console.log(`Files: ${result.plans.length}`);
|
|
1028
|
+
|
|
1029
|
+
if (result.noop) {
|
|
1030
|
+
console.log("No files to restore.");
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
console.log("Would restore:");
|
|
1035
|
+
for (const plan of result.plans) {
|
|
1036
|
+
console.log(`- ${plan.displayPath}`);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
console.log("");
|
|
1040
|
+
console.log("Run with --apply to restore.");
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
export async function runGlobalPolicy(options, packageManifest) {
|
|
1044
|
+
const homeDir = resolveHomeDir();
|
|
1045
|
+
|
|
1046
|
+
switch (options.policyAction) {
|
|
1047
|
+
case "show": {
|
|
1048
|
+
const rawPolicy = await loadPolicyFile(homeDir);
|
|
1049
|
+
|
|
1050
|
+
if (options.json) {
|
|
1051
|
+
printJson(buildPolicyJson(homeDir, rawPolicy));
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
printPolicyReport(homeDir, rawPolicy);
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
case "set": {
|
|
1059
|
+
const resolved = await savePolicyField(homeDir, options.policyKey, options.policyValue);
|
|
1060
|
+
|
|
1061
|
+
await recordPolicyHistory(homeDir, {
|
|
1062
|
+
cliVersion: packageManifest?.version ?? null,
|
|
1063
|
+
action: "set"
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
if (options.json) {
|
|
1067
|
+
printJson({
|
|
1068
|
+
ok: true,
|
|
1069
|
+
action: "set",
|
|
1070
|
+
key: options.policyKey,
|
|
1071
|
+
value: resolved[options.policyKey],
|
|
1072
|
+
policy: buildPolicyJson(homeDir, await loadPolicyFile(homeDir))
|
|
1073
|
+
});
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
console.log(`Policy updated: ${options.policyKey}=${formatPolicyValue(resolved[options.policyKey])}`);
|
|
1078
|
+
printPolicyReport(homeDir, await loadPolicyFile(homeDir));
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
case "reset": {
|
|
1082
|
+
const removed = await resetPolicyFile(homeDir);
|
|
1083
|
+
|
|
1084
|
+
if (removed) {
|
|
1085
|
+
await recordPolicyHistory(homeDir, {
|
|
1086
|
+
cliVersion: packageManifest?.version ?? null,
|
|
1087
|
+
action: "reset"
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
if (options.json) {
|
|
1092
|
+
printJson({
|
|
1093
|
+
ok: true,
|
|
1094
|
+
action: "reset",
|
|
1095
|
+
removed,
|
|
1096
|
+
policy: buildPolicyJson(homeDir, null)
|
|
1097
|
+
});
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
console.log(removed ? "Policy reset. Using CLI defaults." : "No policy file found.");
|
|
1102
|
+
if (removed) {
|
|
1103
|
+
printPolicyReport(homeDir, null);
|
|
1104
|
+
}
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
default: {
|
|
1108
|
+
const _exhaustive = options.policyAction;
|
|
1109
|
+
throw new Error(`Unknown policy action "${_exhaustive}".`);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
function printPolicyReport(homeDir, rawPolicy) {
|
|
1115
|
+
const resolved = resolvePolicy(rawPolicy ?? {});
|
|
1116
|
+
const policyPath = harnessHomePaths(homeDir).policyPath;
|
|
1117
|
+
|
|
1118
|
+
console.log(commandHeader("policy — local operation preferences"));
|
|
1119
|
+
console.log(`Home: ${homeDir}`);
|
|
1120
|
+
console.log(`File: ${rawPolicy ? policyPath : "(none — using CLI defaults)"}`);
|
|
1121
|
+
console.log("");
|
|
1122
|
+
|
|
1123
|
+
if (resolved.profile) {
|
|
1124
|
+
console.log(`Profile: ${resolved.profile}`);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
console.log(`Apply mode: ${resolved.applyMode}`);
|
|
1128
|
+
console.log(`Preflight: ${resolved.preflight ? "enabled" : "disabled"}`);
|
|
1129
|
+
console.log(`Agents: ${formatPolicyAgents(resolved.agents)}`);
|
|
1130
|
+
console.log(`Components: ${resolved.components.join(", ") || "none"}`);
|
|
1131
|
+
console.log("");
|
|
1132
|
+
console.log("Precedence: CLI flags > policy file > internal defaults.");
|
|
1133
|
+
console.log(`Commands: ${formatCliCommand("policy set <key> <value>")} | ${formatCliCommand("policy reset")}`);
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
function formatPolicyAgents(agents) {
|
|
1137
|
+
if (agents === "detected") return "detected";
|
|
1138
|
+
if (agents === "all") return "all";
|
|
1139
|
+
return agents.join(", ");
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
function formatPolicyValue(value) {
|
|
1143
|
+
if (Array.isArray(value)) return value.join(",");
|
|
1144
|
+
return String(value);
|
|
1145
|
+
}
|