From b28e8ac57b30c5da20581b22140aa8c28921101c Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 14 Jul 2026 02:00:16 -0700 Subject: [PATCH 1/2] feat(cli)!: full-cutover rename gittensory-miner/gittensory-miner-mcp/gittensory-mcp CLI binaries to loopover-* Phase 3 of the gittensory -> loopover rebrand (#5705): renames all three CLI executables and their backing bin/*.js files, full cutover per the epic's mandate (no dual-support aliases): - gittensory-miner -> loopover-miner (packages/gittensory-miner) - gittensory-miner-mcp -> loopover-miner-mcp (packages/gittensory-miner) - gittensory-mcp -> loopover-mcp (packages/gittensory-mcp) Updates every downstream reference: package.json bin fields, build scripts, --help/usage text and error messages, shell completion scripts, the Dockerfile ENTRYPOINT + its GITTENSORY_VERSION build ARG (now LOOPOVER_VERSION), CI publish-workflow smoke-test assertions, the deployment-docs-audit.js subcommand-claim regex, the miner/mcp package allowlist checkers, and all CLI-example prose across README.md, DEPLOYMENT.md, and packages/*/docs/*.md. Also fixes two real bugs surfaced while verifying this against the full test suite (not cosmetic renames, functional regressions the rename would otherwise have caused or left in place): - src/services/client-telemetry.ts's x-gittensory-mcp-{package,version, client,client-version} HTTP headers renamed to x-loopover-mcp-* on both the CLI (sender) and server (reader) sides -- fixing only one side would have silently broken MCP client telemetry ingestion. Also fixed clientNameFromPackage's hardcoded "gittensory-mcp" string fallback. - src/db/repositories.ts's summarizeMcpCompatibilityAdoption() had a legacy clientName match (`eq(clientName, "gittensory-mcp")` / `"gittensory-mcp-cli"`) used to select MCP-surfaced usage events that don't set surface="mcp" (e.g. /v1/local/branch-analysis, surface= "api"). Left un-updated, this would have silently excluded every correctly-renamed loopover-mcp-cli event from the MCP compatibility dashboard the moment the client-side rename shipped. BREAKING CHANGE: `gittensory-miner`, `gittensory-miner-mcp`, and `gittensory-mcp` no longer exist as installed binaries; use `loopover-miner`, `loopover-miner-mcp`, and `loopover-mcp`. No dual-read/alias, per the epic's full-cutover mandate. A global npm install/link of the old package names must be reinstalled. --- .github/workflows/ci.yml | 2 +- .github/workflows/publish-mcp.yml | 2 +- .github/workflows/publish-miner.yml | 4 +- README.md | 18 +- .../src/ranked-candidates-api.test.ts | 2 +- .../src/run-state-api.test.ts | 2 +- package-lock.json | 6 +- packages/gittensory-mcp/README.md | 144 +++++++------- .../{gittensory-mcp.js => loopover-mcp.js} | 184 +++++++++--------- packages/gittensory-mcp/package.json | 4 +- packages/gittensory-miner/BENCHMARKS.md | 4 +- packages/gittensory-miner/DEPLOYMENT.md | 30 +-- packages/gittensory-miner/Dockerfile | 12 +- packages/gittensory-miner/README.md | 62 +++--- ...miner-mcp.d.ts => loopover-miner-mcp.d.ts} | 0 ...ory-miner-mcp.js => loopover-miner-mcp.js} | 0 ...{gittensory-miner.js => loopover-miner.js} | 0 .../docs/coding-agent-driver.md | 2 +- .../docs/config-precedence.md | 4 +- .../docs/discovery-plane-operator-guide.md | 4 +- .../docs/miner-selfimprove-calibration.md | 2 +- .../gittensory-miner/docs/observability.md | 14 +- .../docs/operations-runbook.md | 46 ++--- .../docs/repo-agnostic-capability-audit.md | 2 +- packages/gittensory-miner/docs/sizing.md | 16 +- .../docs/unattended-scheduling.md | 28 +-- .../gittensory-miner/lib/attempt-cli.d.ts | 2 +- packages/gittensory-miner/lib/attempt-cli.js | 4 +- .../gittensory-miner/lib/calibration-cli.js | 6 +- .../gittensory-miner/lib/claim-ledger-cli.js | 6 +- packages/gittensory-miner/lib/cli.js | 88 ++++----- packages/gittensory-miner/lib/deny-check.js | 2 +- .../lib/deployment-docs-audit.js | 10 +- packages/gittensory-miner/lib/discover-cli.js | 2 +- .../gittensory-miner/lib/event-ledger-cli.js | 4 +- .../gittensory-miner/lib/feasibility-cli.js | 2 +- .../lib/governor-ledger-cli.js | 10 +- .../lib/governor-metrics-cli.js | 2 +- .../lib/governor-pause-cli.js | 6 +- packages/gittensory-miner/lib/loop-cli.js | 4 +- packages/gittensory-miner/lib/manage-poll.js | 2 +- .../gittensory-miner/lib/manage-status.js | 2 +- packages/gittensory-miner/lib/metrics-cli.js | 2 +- .../gittensory-miner/lib/miner-goal-spec.js | 2 +- packages/gittensory-miner/lib/orb-export.js | 2 +- .../gittensory-miner/lib/plan-store-cli.js | 4 +- .../lib/portfolio-dashboard.js | 4 +- .../lib/portfolio-queue-cli.js | 14 +- packages/gittensory-miner/lib/purge-cli.js | 4 +- .../gittensory-miner/lib/run-state-cli.js | 4 +- packages/gittensory-miner/lib/update-check.js | 2 +- packages/gittensory-miner/package.json | 8 +- packages/gittensory-miner/terraform/README.md | 2 +- scripts/check-mcp-package.mjs | 2 +- scripts/check-miner-package.mjs | 6 +- scripts/mcp-release-candidate-core.mjs | 4 +- src/db/repositories.ts | 2 +- src/services/client-telemetry.ts | 10 +- test/integration/api.test.ts | 16 +- test/unit/check-miner-package.test.ts | 16 +- test/unit/coding-agent-miner.test.ts | 2 +- test/unit/mcp-cli-basics.test.ts | 22 +-- test/unit/mcp-cli-burden-forecast.test.ts | 2 +- test/unit/mcp-cli-doctor.test.ts | 12 +- test/unit/mcp-cli-find-opportunities.test.ts | 2 +- test/unit/mcp-cli-issue-rag.test.ts | 2 +- test/unit/mcp-cli-issue-slop.test.ts | 4 +- test/unit/mcp-cli-label-audit.test.ts | 2 +- test/unit/mcp-cli-lint-pr-text.test.ts | 4 +- test/unit/mcp-cli-maintain.test.ts | 6 +- test/unit/mcp-cli-maintainer-noise.test.ts | 2 +- test/unit/mcp-cli-packets.test.ts | 8 +- test/unit/mcp-cli-profiles.test.ts | 12 +- test/unit/mcp-cli-review-pr.test.ts | 4 +- test/unit/mcp-cli-slop-risk.test.ts | 4 +- test/unit/mcp-cli-tools.test.ts | 6 +- test/unit/mcp-cli-upstream-drift.test.ts | 2 +- test/unit/mcp-cli-validate-config.test.ts | 4 +- test/unit/mcp-compatibility.test.ts | 24 +-- test/unit/mcp-discovery.test.ts | 2 +- test/unit/mcp-feasibility-gate.test.ts | 2 +- test/unit/mcp-release-candidate.test.ts | 2 +- test/unit/mcp-release.test.ts | 2 +- test/unit/mcp-server-telemetry.test.ts | 8 +- test/unit/mcp-tool-rename-aliases.test.ts | 2 +- test/unit/miner-attempt-cli.test.ts | 14 +- test/unit/miner-attempt-runner.test.ts | 2 +- test/unit/miner-claim-ledger-cli.test.ts | 18 +- test/unit/miner-cli-deny-check.test.ts | 6 +- .../miner-cli-json-error-coverage.test.ts | 14 +- test/unit/miner-cli-run-state.test.ts | 8 +- test/unit/miner-cli.test.ts | 18 +- test/unit/miner-deployment-doc.test.ts | 6 +- test/unit/miner-deployment-docs-audit.test.ts | 6 +- test/unit/miner-discover-cli.test.ts | 20 +- test/unit/miner-env-file-indirection.test.ts | 2 +- test/unit/miner-event-ledger-cli.test.ts | 12 +- test/unit/miner-feasibility-cli.test.ts | 12 +- test/unit/miner-governor-metrics-cli.test.ts | 6 +- test/unit/miner-governor-pause-cli.test.ts | 16 +- test/unit/miner-manage-poll.test.ts | 6 +- test/unit/miner-mcp-audit-feed.test.ts | 2 +- test/unit/miner-mcp-client-config-doc.test.ts | 10 +- test/unit/miner-mcp-contract.test.ts | 4 +- .../unit/miner-mcp-governor-decisions.test.ts | 2 +- test/unit/miner-mcp-scaffold.test.ts | 4 +- test/unit/miner-mcp-tool-docs-parity.test.ts | 2 +- test/unit/miner-metrics-cli.test.ts | 10 +- test/unit/miner-operations-runbook.test.ts | 2 +- test/unit/miner-package-skeleton.test.ts | 18 +- test/unit/miner-plan-store-cli.test.ts | 6 +- test/unit/miner-portfolio-dashboard.test.ts | 2 +- test/unit/miner-portfolio-queue-cli.test.ts | 14 +- test/unit/miner-purge-cli.test.ts | 10 +- test/unit/miner-wire-cli-modules.test.ts | 2 +- test/unit/product-usage-mcp-adoption.test.ts | 8 +- test/unit/support/mcp-cli-harness.ts | 2 +- test/unit/support/miner-cli-harness.ts | 2 +- test/unit/worker-entry-boundary.test.ts | 2 +- 119 files changed, 630 insertions(+), 630 deletions(-) rename packages/gittensory-mcp/bin/{gittensory-mcp.js => loopover-mcp.js} (96%) rename packages/gittensory-miner/bin/{gittensory-miner-mcp.d.ts => loopover-miner-mcp.d.ts} (100%) rename packages/gittensory-miner/bin/{gittensory-miner-mcp.js => loopover-miner-mcp.js} (100%) rename packages/gittensory-miner/bin/{gittensory-miner.js => loopover-miner.js} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81653e456d..7cb106e2e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,7 +103,7 @@ jobs: # 6 of the 7 MCP CLI-cluster test files, and ONLY these 6, are truly self-contained w.r.t. root # src/**: verified by direct-import inspection that test/unit/mcp-cli-*.test.ts (5 files) and # their shared test/unit/support/mcp-cli-harness.ts import nothing but node:* builtins + vitest, - # and mcp-discovery.test.ts spawns packages/gittensory-mcp/bin/gittensory-mcp.js as a real + # and mcp-discovery.test.ts spawns packages/gittensory-mcp/bin/loopover-mcp.js as a real # subprocess via StdioClientTransport -- none of the 6 ever load root src/ in-process. This mirrors # the `mcp` filter's own established trust boundary above (a self-contained package build). They are # NOT self-contained w.r.t. packages/gittensory-engine/**, though: gittensory-mcp now has a real diff --git a/.github/workflows/publish-mcp.yml b/.github/workflows/publish-mcp.yml index 69eaa82bcf..fff1db78eb 100644 --- a/.github/workflows/publish-mcp.yml +++ b/.github/workflows/publish-mcp.yml @@ -109,7 +109,7 @@ jobs: TMP="$(mktemp -d)" npm --prefix "$TMP" init -y >/dev/null npm --prefix "$TMP" install "$TARBALL_PATH" >/dev/null - "$TMP/node_modules/.bin/gittensory-mcp" --help >/dev/null + "$TMP/node_modules/.bin/loopover-mcp" --help >/dev/null - name: Upload package tarball uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 diff --git a/.github/workflows/publish-miner.yml b/.github/workflows/publish-miner.yml index 678f785033..15fcca679a 100644 --- a/.github/workflows/publish-miner.yml +++ b/.github/workflows/publish-miner.yml @@ -115,8 +115,8 @@ jobs: TMP="$(mktemp -d)" npm --prefix "$TMP" init -y >/dev/null npm --prefix "$TMP" install "$TARBALL_PATH" >/dev/null - "$TMP/node_modules/.bin/gittensory-miner" --help | grep -q "Foundation CLI for the local Gittensory miner runtime" - "$TMP/node_modules/.bin/gittensory-miner-mcp" --help >/dev/null + "$TMP/node_modules/.bin/loopover-miner" --help | grep -q "Foundation CLI for the local LoopOver miner runtime" + "$TMP/node_modules/.bin/loopover-miner-mcp" --help >/dev/null - name: Upload package tarball uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 diff --git a/README.md b/README.md index 4102e7aa43..f1351c9740 100644 --- a/README.md +++ b/README.md @@ -74,17 +74,17 @@ See [Tuning your reviews](https://gittensory.aethereal.dev/docs/tuning) for the ```sh npm install -g @loopover/mcp@latest -gittensory-mcp login -gittensory-mcp doctor -gittensory-mcp --stdio +loopover-mcp login +loopover-mcp doctor +loopover-mcp --stdio ``` Print editor/client snippets: ```sh -gittensory-mcp init-client --print codex -gittensory-mcp init-client --print claude -gittensory-mcp init-client --print cursor +loopover-mcp init-client --print codex +loopover-mcp init-client --print claude +loopover-mcp init-client --print cursor ``` For full editor setup and stdio configuration, use [MCP client setup](https://gittensory.aethereal.dev/docs/mcp-clients). @@ -92,9 +92,9 @@ For full editor setup and stdio configuration, use [MCP client setup](https://gi Run base-agent commands: ```sh -gittensory-mcp agent plan --login jsonbored --json -gittensory-mcp agent packet --login jsonbored --json -gittensory-mcp agent status --json +loopover-mcp agent plan --login jsonbored --json +loopover-mcp agent packet --login jsonbored --json +loopover-mcp agent status --json ``` ## Local Development diff --git a/apps/gittensory-miner-ui/src/ranked-candidates-api.test.ts b/apps/gittensory-miner-ui/src/ranked-candidates-api.test.ts index 324b5aa37a..1e5003ad3e 100644 --- a/apps/gittensory-miner-ui/src/ranked-candidates-api.test.ts +++ b/apps/gittensory-miner-ui/src/ranked-candidates-api.test.ts @@ -25,7 +25,7 @@ const candidates = [ function deps(overrides: Partial = {}): RankedCandidatesApiDeps { return { loadRankedCandidatesModule: async () => ({ - resolveRankedCandidatesDbPath: () => "/home/miner/.config/gittensory-miner/ranked-candidates.sqlite3", + resolveRankedCandidatesDbPath: () => "/home/miner/.config/loopover-miner/ranked-candidates.sqlite3", listRankedCandidates: () => candidates, }), fileExists: () => true, diff --git a/apps/gittensory-miner-ui/src/run-state-api.test.ts b/apps/gittensory-miner-ui/src/run-state-api.test.ts index 29bcf55fa5..37e6c94b7e 100644 --- a/apps/gittensory-miner-ui/src/run-state-api.test.ts +++ b/apps/gittensory-miner-ui/src/run-state-api.test.ts @@ -7,7 +7,7 @@ const rows = [{ repoFullName: "acme/widgets", state: "idle", updatedAt: "2026-07 function deps(overrides: Partial = {}): RunStateApiDeps { return { loadRunStateModule: async () => ({ - resolveRunStateDbPath: () => "/home/miner/.config/gittensory-miner/run-state.sqlite3", + resolveRunStateDbPath: () => "/home/miner/.config/loopover-miner/run-state.sqlite3", listRunStates: () => rows, }), fileExists: () => true, diff --git a/package-lock.json b/package-lock.json index bcc9bac67a..c6bc5b33f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15894,7 +15894,7 @@ "zod": "^4.4.3" }, "bin": { - "gittensory-mcp": "bin/gittensory-mcp.js" + "loopover-mcp": "bin/loopover-mcp.js" }, "engines": { "node": ">=22.0.0" @@ -15910,8 +15910,8 @@ "zod": "^4.4.3" }, "bin": { - "gittensory-miner": "bin/gittensory-miner.js", - "gittensory-miner-mcp": "bin/gittensory-miner-mcp.js" + "loopover-miner": "bin/loopover-miner.js", + "loopover-miner-mcp": "bin/loopover-miner-mcp.js" }, "engines": { "node": ">=22.13.0" diff --git a/packages/gittensory-mcp/README.md b/packages/gittensory-mcp/README.md index 78995eb6e3..26b3a777e5 100644 --- a/packages/gittensory-mcp/README.md +++ b/packages/gittensory-mcp/README.md @@ -14,7 +14,7 @@ Public npm: ```sh npm install -g @loopover/mcp@latest -gittensory-mcp login +loopover-mcp login ``` From a local checkout: @@ -27,51 +27,51 @@ npm link --workspace @loopover/mcp ## Commands ```sh -gittensory-mcp version -gittensory-mcp version --json -gittensory-mcp tools -gittensory-mcp tools --json -gittensory-mcp login -gittensory-mcp logout -gittensory-mcp whoami -gittensory-mcp config -gittensory-mcp config --json -gittensory-mcp status -gittensory-mcp changelog -gittensory-mcp doctor -gittensory-mcp doctor --exit-code -gittensory-mcp profile list -gittensory-mcp profile create work -gittensory-mcp profile switch work -gittensory-mcp cache status -gittensory-mcp cache list -gittensory-mcp cache clear -gittensory-mcp init-client --print codex -gittensory-mcp init-client --print claude -gittensory-mcp init-client --print cursor -gittensory-mcp init-client --print vscode -gittensory-mcp init-client --print codex --agent-profile miner-planner -gittensory-mcp completion bash -gittensory-mcp completion zsh -gittensory-mcp completion fish -gittensory-mcp completion powershell -gittensory-mcp decision-pack --login jsonbored --json -gittensory-mcp repo-decision --login jsonbored --repo we-promise/sure --json -gittensory-mcp analyze-branch --login jsonbored --json -gittensory-mcp preflight --login jsonbored --json -gittensory-mcp review-pr --login jsonbored --commit "feat(mcp): add doctor grouping" --body "Fixes #160. Validated with npm test." --linked-issue 160 --json -gittensory-mcp lint-pr-text --commit "feat(mcp): add doctor grouping" --body "Fixes #160. Validated with npm test." --linked-issue 160 --json -gittensory-mcp validate-config --file ./.loopover.yml --json -gittensory-mcp slop-risk --changed-file src/widget.ts:80:2 --description "Adds retry handling." --test-file test/unit/widget.test.ts --json -gittensory-mcp issue-slop --title "Add retry handling" --body "Widget reconnects fail without bounded retries." --json -gittensory-mcp agent plan --login jsonbored --json -gittensory-mcp agent packet --login jsonbored --json -gittensory-mcp agent status --json -gittensory-mcp agent explain --json -gittensory-mcp --stdio +loopover-mcp version +loopover-mcp version --json +loopover-mcp tools +loopover-mcp tools --json +loopover-mcp login +loopover-mcp logout +loopover-mcp whoami +loopover-mcp config +loopover-mcp config --json +loopover-mcp status +loopover-mcp changelog +loopover-mcp doctor +loopover-mcp doctor --exit-code +loopover-mcp profile list +loopover-mcp profile create work +loopover-mcp profile switch work +loopover-mcp cache status +loopover-mcp cache list +loopover-mcp cache clear +loopover-mcp init-client --print codex +loopover-mcp init-client --print claude +loopover-mcp init-client --print cursor +loopover-mcp init-client --print vscode +loopover-mcp init-client --print codex --agent-profile miner-planner +loopover-mcp completion bash +loopover-mcp completion zsh +loopover-mcp completion fish +loopover-mcp completion powershell +loopover-mcp decision-pack --login jsonbored --json +loopover-mcp repo-decision --login jsonbored --repo we-promise/sure --json +loopover-mcp analyze-branch --login jsonbored --json +loopover-mcp preflight --login jsonbored --json +loopover-mcp review-pr --login jsonbored --commit "feat(mcp): add doctor grouping" --body "Fixes #160. Validated with npm test." --linked-issue 160 --json +loopover-mcp lint-pr-text --commit "feat(mcp): add doctor grouping" --body "Fixes #160. Validated with npm test." --linked-issue 160 --json +loopover-mcp validate-config --file ./.loopover.yml --json +loopover-mcp slop-risk --changed-file src/widget.ts:80:2 --description "Adds retry handling." --test-file test/unit/widget.test.ts --json +loopover-mcp issue-slop --title "Add retry handling" --body "Widget reconnects fail without bounded retries." --json +loopover-mcp agent plan --login jsonbored --json +loopover-mcp agent packet --login jsonbored --json +loopover-mcp agent status --json +loopover-mcp agent explain --json +loopover-mcp --stdio ``` -`gittensory-mcp version` (aliases `--version` and `-v`) prints the installed package version, the targeted API version, and the Node.js runtime version: +`loopover-mcp version` (aliases `--version` and `-v`) prints the installed package version, the targeted API version, and the Node.js runtime version: ```text @loopover/mcp/0.5.0 (api 0.1.0, node v22.12.0) @@ -88,32 +88,32 @@ Add `--json` for machine-readable output: } ``` -`gittensory-mcp tools` lists every stdio MCP tool the local wrapper registers, with its one-line description. Add `--json` for `{ "count": N, "tools": [{ "name", "description" }, ...] }`. +`loopover-mcp tools` lists every stdio MCP tool the local wrapper registers, with its one-line description. Add `--json` for `{ "count": N, "tools": [{ "name", "description" }, ...] }`. ### Shell completion -`gittensory-mcp completion ` prints a tab-completion script for your shell. It completes top-level commands and the subcommands of `profile`, `cache`, `agent`, and `maintain`. Add `--json` to get `{ "shell": "...", "script": "..." }` for tooling. +`loopover-mcp completion ` prints a tab-completion script for your shell. It completes top-level commands and the subcommands of `profile`, `cache`, `agent`, and `maintain`. Add `--json` to get `{ "shell": "...", "script": "..." }` for tooling. ```sh # bash (add to ~/.bashrc) -source <(gittensory-mcp completion bash) +source <(loopover-mcp completion bash) # zsh (add to a file on your fpath, or to ~/.zshrc) -source <(gittensory-mcp completion zsh) +source <(loopover-mcp completion zsh) # fish -gittensory-mcp completion fish > ~/.config/fish/completions/gittensory-mcp.fish +loopover-mcp completion fish > ~/.config/fish/completions/loopover-mcp.fish ``` ```powershell # PowerShell (add to your $PROFILE) -gittensory-mcp completion powershell | Out-String | Invoke-Expression +loopover-mcp completion powershell | Out-String | Invoke-Expression ``` For near-term what-if scoreability, pass the situational assumptions explicitly: ```sh -gittensory-mcp analyze-branch --login jsonbored \ +loopover-mcp analyze-branch --login jsonbored \ --pending-merged-prs 3 \ --expected-open-prs 0 \ --projected-credibility 0.8 \ @@ -123,14 +123,14 @@ gittensory-mcp analyze-branch --login jsonbored \ ## Review your PR locally before you push -`gittensory-mcp review-pr` composes the existing preflight, slop-risk, and PR-text-lint checks into +`loopover-mcp review-pr` composes the existing preflight, slop-risk, and PR-text-lint checks into ONE report, so your own local agent (Claude Code, Codex, etc.) can see everything the gittensory gate would flag before you ever open a PR. It is a thin composition layer — it calls the same checks `preflight`, `slop-risk`, and `lint-pr-text` already run and merges their output; it does not reimplement any of them. ```sh -gittensory-mcp review-pr --login jsonbored \ +loopover-mcp review-pr --login jsonbored \ --commit "feat(mcp): add review-pr" \ --body "Composes preflight + slop-risk + lint-pr-text. Validated with npm test." \ --linked-issue 1968 \ @@ -149,7 +149,7 @@ The same composed check is exposed to MCP clients as `loopover_review_pr_before_ `login` uses GitHub Device Flow by default. For non-interactive bootstrap: ```sh -gittensory-mcp login --github-token "$(gh auth token)" +loopover-mcp login --github-token "$(gh auth token)" ``` The wrapper stores a Gittensory session token, not a GitHub token. @@ -157,27 +157,27 @@ The wrapper stores a Gittensory session token, not a GitHub token. The default profile keeps normal single-account usage simple. For multiple identities, use named profiles: ```sh -gittensory-mcp login --profile personal --github-token "$(gh auth token)" -gittensory-mcp login --profile work --github-token "$WORK_GITHUB_TOKEN" -gittensory-mcp profile list -gittensory-mcp profile switch work -gittensory-mcp whoami -gittensory-mcp logout --profile work +loopover-mcp login --profile personal --github-token "$(gh auth token)" +loopover-mcp login --profile work --github-token "$WORK_GITHUB_TOKEN" +loopover-mcp profile list +loopover-mcp profile switch work +loopover-mcp whoami +loopover-mcp logout --profile work ``` Use `--profile ` on `login`, `logout`, `whoami`, `config`, `status`, and `doctor`, or set `GITTENSORY_PROFILE`. `logout` only clears the selected local profile unless `--all` is passed. Profile output redacts session tokens and local config paths. -`gittensory-mcp config` prints the resolved effective configuration and the source that supplied each value (`environment`, `profile`, `config`, or `default`): the active API URL and its source, active profile and profile count, whether a config file is present and which environment variable steers its location, the cache-dir source, whether a token is configured and where it came from, and whether `GITTENSORY_UPLOAD_SOURCE` has enabled the unsupported source-upload setting. It never prints token values or local absolute paths. Add `--json` for machine-readable output. +`loopover-mcp config` prints the resolved effective configuration and the source that supplied each value (`environment`, `profile`, `config`, or `default`): the active API URL and its source, active profile and profile count, whether a config file is present and which environment variable steers its location, the cache-dir source, whether a token is configured and where it came from, and whether `GITTENSORY_UPLOAD_SOURCE` has enabled the unsupported source-upload setting. It never prints token values or local absolute paths. Add `--json` for machine-readable output. -By default `gittensory-mcp doctor` always exits 0. Pass `--exit-code` to make it exit non-zero when a diagnostic check fails (`status: "needs_attention"`), so it can gate a CI step or pre-commit hook. Warnings still exit 0. +By default `loopover-mcp doctor` always exits 0. Pass `--exit-code` to make it exit non-zero when a diagnostic check fails (`status: "needs_attention"`), so it can gate a CI step or pre-commit hook. Warnings still exit 0. ## Base-Agent Mode The agent commands are copilot-only. They rank, explain, preflight, and draft public-safe packets, but they do not edit code, open PRs, post comments, close, merge, or label from the local wrapper. ```sh -gittensory-mcp agent plan --login jsonbored --repo we-promise/sure --json -gittensory-mcp agent packet --login jsonbored --repo we-promise/sure --base origin/main --json +loopover-mcp agent plan --login jsonbored --repo we-promise/sure --json +loopover-mcp agent packet --login jsonbored --repo we-promise/sure --base origin/main --json ``` The same capabilities are exposed to MCP clients as: @@ -197,9 +197,9 @@ The same capabilities are exposed to MCP clients as: `init-client` can print optional agent-profile instructions next to the MCP client config: ```sh -gittensory-mcp init-client --print codex --agent-profile miner-planner -gittensory-mcp init-client --print claude --agent-profile maintainer-triage -gittensory-mcp init-client --print cursor --agent-profile repo-owner-intake +loopover-mcp init-client --print codex --agent-profile miner-planner +loopover-mcp init-client --print claude --agent-profile maintainer-triage +loopover-mcp init-client --print cursor --agent-profile repo-owner-intake ``` Profiles are prompt instructions for the coding-agent environment, not autonomous GitHub actors: @@ -229,7 +229,7 @@ Use them when an agent should plan, explain, draft, or prepare packets from Gitt Branch analysis can call a local scorer command that reads branch metadata JSON from stdin and prints one JSON object to stdout. Gittensory never uploads source contents; the scorer runs on your machine. -Metadata-only fallback is used when the command is missing or fails. Run `gittensory-mcp doctor` for setup diagnostics. +Metadata-only fallback is used when the command is missing or fails. Run `loopover-mcp doctor` for setup diagnostics. Reference wrappers ship with the package: @@ -264,10 +264,10 @@ Snake_case aliases such as `source_token_score` are also accepted. The package ships with `CHANGELOG.md`. Run: ```sh -gittensory-mcp changelog +loopover-mcp changelog ``` -`gittensory-mcp status` also reports the local package version, latest npm version when reachable, API health, auth state, and source-upload posture. +`loopover-mcp status` also reports the local package version, latest npm version when reachable, API health, auth state, and source-upload posture. ## Offline decision-pack fallback @@ -276,7 +276,7 @@ Successful `decision-pack` and MCP `loopover_get_decision_pack` calls store a bo The cache excludes source contents and local paths, is bounded, and can be removed with: ```sh -gittensory-mcp cache clear +loopover-mcp cache clear ``` -`gittensory-mcp cache list` shows the cached entries (newest first) with the login, when each was cached, and its API/package version and size — never the cached payload or the auth-cache key. `gittensory-mcp cache status` reports the aggregate entry count. +`loopover-mcp cache list` shows the cached entries (newest first) with the login, when each was cached, and its API/package version and size — never the cached payload or the auth-cache key. `loopover-mcp cache status` reports the aggregate entry count. diff --git a/packages/gittensory-mcp/bin/gittensory-mcp.js b/packages/gittensory-mcp/bin/loopover-mcp.js similarity index 96% rename from packages/gittensory-mcp/bin/gittensory-mcp.js rename to packages/gittensory-mcp/bin/loopover-mcp.js index 93f94cb309..8026e44d59 100755 --- a/packages/gittensory-mcp/bin/gittensory-mcp.js +++ b/packages/gittensory-mcp/bin/loopover-mcp.js @@ -214,7 +214,7 @@ const feasibilityGateShape = { * Returns `null` (fall back to the caller-supplied value unchanged) only when there is genuinely nothing to * look up: no repo/issue supplied, no local install detected (the ledger DB file doesn't exist -- checked * via `existsSync` BEFORE opening anything), or the sibling `@loopover/miner` package isn't - * resolvable at all (a standalone gittensory-mcp install with no miner alongside it). When the ledger DB + * resolvable at all (a standalone loopover-mcp install with no miner alongside it). When the ledger DB * file DOES exist (a real local install IS present) but reading it fails -- corrupt, locked, permission * denied -- this returns `"unknown"` rather than silently falling back to a caller-supplied string that * ground-truth data (which we know exists but can't currently read) might contradict; `"unknown"` is an @@ -233,7 +233,7 @@ async function resolveLedgerClaimStatus(repoFullName, issueNumber) { try { claimLedgerModule = await import("@loopover/miner/lib/claim-ledger.js"); } catch { - /* v8 ignore next -- gittensory-miner genuinely unresolvable (not installed alongside gittensory-mcp); not + /* v8 ignore next -- gittensory-miner genuinely unresolvable (not installed alongside loopover-mcp); not reproducible in this monorepo's workspace-hoisted test environment, where the sibling package always resolves */ return null; @@ -426,7 +426,7 @@ const agentRunIdShape = { }; // Single source of truth for stdio tool name + one-line description (#2233). -// Registration and `gittensory-mcp tools` both read this list. +// Registration and `loopover-mcp tools` both read this list. const STDIO_TOOL_DESCRIPTORS = [ { name: "loopover_get_repo_context", @@ -1271,7 +1271,7 @@ server.registerResource( "gittensory://changelog", { title: "Gittensory MCP Changelog", - description: "Current CHANGELOG.md for the installed gittensory-mcp package.", + description: "Current CHANGELOG.md for the installed loopover-mcp package.", mimeType: "text/markdown", }, async () => { @@ -1711,9 +1711,9 @@ function workspaceRootStatus(roots) { function printMaintainHelp() { process.stdout.write( [ - "Usage: gittensory-mcp maintain --repo owner/repo", + "Usage: loopover-mcp maintain --repo owner/repo", "", - "Maintainer controls for the agent auto-maintain layer (requires maintainer access; run `gittensory-mcp login`).", + "Maintainer controls for the agent auto-maintain layer (requires maintainer access; run `loopover-mcp login`).", "", "Subcommands:", " status List the agent approval queue (auto_with_approval actions awaiting a decision).", @@ -1773,7 +1773,7 @@ async function maintainCli(args) { return; } if (subcommand === "approve" || subcommand === "reject") { - if (!positional) throw new Error(`Pass the pending-action id: gittensory-mcp maintain ${subcommand} --repo owner/repo.`); + if (!positional) throw new Error(`Pass the pending-action id: loopover-mcp maintain ${subcommand} --repo owner/repo.`); // The approval-queue route's decision verb is accept|reject (#779); the CLI exposes approve|reject. const decision = subcommand === "approve" ? "accept" : "reject"; const payload = await apiPost(`${queueBase}/${encodeURIComponent(positional)}/${decision}`, {}); @@ -1788,7 +1788,7 @@ async function maintainCli(args) { if (subcommand === "set-level") { const action = args[1] && !args[1].startsWith("--") ? args[1] : undefined; const level = args[2] && !args[2].startsWith("--") ? args[2] : undefined; - if (!action || !level) throw new Error("Usage: gittensory-mcp maintain set-level --repo owner/repo."); + if (!action || !level) throw new Error("Usage: loopover-mcp maintain set-level --repo owner/repo."); if (!MAINTAIN_ACTION_CLASSES.includes(action)) throw new Error(`Unknown action: ${action}. Use ${MAINTAIN_ACTION_CLASSES.join(", ")}.`); if (!MAINTAIN_AUTONOMY_LEVELS.includes(level)) throw new Error(`Unknown level: ${level}. Use ${MAINTAIN_AUTONOMY_LEVELS.join(", ")}.`); // Read-merge-write so one class is updated without clearing the others. @@ -1850,7 +1850,7 @@ async function runCli(args) { if (command === "review-pr") return reviewPrCli(options); if (command !== "analyze-branch" && command !== "preflight") { const suggestion = suggestCommand(command); - throw new Error(`Unknown command: ${command}.${suggestion ? ` Did you mean \`${suggestion}\`?` : ""} Run \`gittensory-mcp --help\` to list commands.`); + throw new Error(`Unknown command: ${command}.${suggestion ? ` Did you mean \`${suggestion}\`?` : ""} Run \`loopover-mcp --help\` to list commands.`); } const contributorLogin = options.login ?? process.env.GITTENSORY_LOGIN ?? process.env.GITHUB_LOGIN; if (!contributorLogin) throw new Error("Pass --login or set GITTENSORY_LOGIN."); @@ -1911,7 +1911,7 @@ function writeBranchAnalysisTable(result, command) { function printReviewPrHelp() { process.stdout.write( [ - "Usage: gittensory-mcp review-pr --login [--repo owner/repo] [--base origin/main] [--commit ]... [--body ] [--body-file ] [--linked-issue ] [--json]", + "Usage: loopover-mcp review-pr --login [--repo owner/repo] [--base origin/main] [--commit ]... [--body ] [--body-file ] [--linked-issue ] [--json]", "", "Compose the existing preflight + slop-risk + PR-text-lint checks into ONE pre-PR review report,", "so a contributor's own local agent can see everything the gittensory gate would flag before ever opening a PR.", @@ -1993,7 +1993,7 @@ function readCliTextFile(path, label) { function printLintPrTextHelp() { process.stdout.write( [ - "Usage: gittensory-mcp lint-pr-text [--commit ]... [--body ] [--body-file ] [--linked-issue ] [--json]", + "Usage: loopover-mcp lint-pr-text [--commit ]... [--body ] [--body-file ] [--linked-issue ] [--json]", "", "Lint a commit message and PR body against the Gittensory traceability and Conventional Commit rubric.", "Mirrors the loopover_lint_pr_text MCP tool and POST /v1/lint/pr-text. No source upload.", @@ -2035,7 +2035,7 @@ function sanitizePlainTextTerminalOutput(value) { function printValidateConfigHelp() { process.stdout.write( [ - "Usage: gittensory-mcp validate-config --file [--source repo_file|api_record|none] [--json]", + "Usage: loopover-mcp validate-config --file [--source repo_file|api_record|none] [--json]", "", "Validate a .loopover.yml manifest before pushing.", "Mirrors the loopover_validate_config MCP tool and POST /v1/validate/focus-manifest. No source upload.", @@ -2070,7 +2070,7 @@ async function validateConfigCli(args) { function printSlopRiskHelp() { process.stdout.write( [ - "Usage: gittensory-mcp slop-risk [--description ] [--description-file ] [--changed-file ]... [--test ]... [--test-file ]... [--json]", + "Usage: loopover-mcp slop-risk [--description ] [--description-file ] [--changed-file ]... [--test ]... [--test-file ]... [--json]", "", "Assess deterministic slop risk from local diff metadata and a PR description.", "Mirrors the loopover_check_slop_risk MCP tool and POST /v1/lint/slop-risk. No source upload.", @@ -2130,7 +2130,7 @@ async function slopRiskCli(args) { function printIssueSlopHelp() { process.stdout.write( [ - "Usage: gittensory-mcp issue-slop [--title ] [--body ] [--body-file ] [--json]", + "Usage: loopover-mcp issue-slop [--title ] [--body ] [--body-file ] [--json]", "", "Assess deterministic issue slop risk from an issue title and body alone.", "Mirrors the loopover_check_issue_slop MCP tool and POST /v1/lint/issue-slop. Advisory only; no source upload.", @@ -2228,13 +2228,13 @@ async function runAgentCli(args) { } if (subcommand === "status") { const runId = args[1] && !args[1].startsWith("--") ? args[1] : options.runId; - if (!runId) throw new Error("Usage: gittensory-mcp agent status "); + if (!runId) throw new Error("Usage: loopover-mcp agent status "); const payload = await apiGet(`/v1/agent/runs/${encodeURIComponent(runId)}`); return outputAgentPayload(payload, options, `Gittensory agent run ${runId}: ${payload.run?.status ?? "unknown"}`); } if (subcommand === "explain") { const runId = args[1] && !args[1].startsWith("--") ? args[1] : options.runId; - if (!runId) throw new Error("Usage: gittensory-mcp agent explain "); + if (!runId) throw new Error("Usage: loopover-mcp agent explain "); const payload = await apiGet(`/v1/agent/runs/${encodeURIComponent(runId)}`); const topAction = payload.actions?.[0] ?? null; return outputAgentPayload({ ...payload, topAction }, options, topAction ? `Top action: ${topAction.recommendation}` : "No top action is available yet."); @@ -2402,7 +2402,7 @@ function toolsCommand(options) { function completionCommand(args) { const shell = args[0] && !args[0].startsWith("--") ? args[0] : undefined; const options = parseOptions(args.filter((arg) => arg.startsWith("--"))); - if (!shell) throw new Error(`Usage: gittensory-mcp completion <${COMPLETION_SHELLS.join("|")}> [--json]`); + if (!shell) throw new Error(`Usage: loopover-mcp completion <${COMPLETION_SHELLS.join("|")}> [--json]`); if (!COMPLETION_SHELLS.includes(shell)) throw new Error(`Unsupported shell: ${shell}. Supported shells: ${COMPLETION_SHELLS.join(", ")}.`); const script = buildCompletionScript(shell); if (options.json) { @@ -2457,8 +2457,8 @@ function buildBashCompletion(topLevel, withSubcommands) { const subcommandCases = withSubcommands .map(([command, subcommands]) => ` ${command}) COMPREPLY=( $(compgen -W "${subcommands.join(" ")}" -- "$cur") ); return 0;;`) .join("\n"); - return `# gittensory-mcp bash completion. Add to ~/.bashrc: -# source <(gittensory-mcp completion bash) + return `# loopover-mcp bash completion. Add to ~/.bashrc: +# source <(loopover-mcp completion bash) _gittensory_mcp() { local cur prev cword cur="\${COMP_WORDS[COMP_CWORD]}" @@ -2474,16 +2474,16 @@ ${subcommandCases} *) COMPREPLY=( $(compgen -W "--json --format --login --repo --profile --agent-profile --base --cwd" -- "$cur") ); return 0;; esac } -complete -F _gittensory_mcp gittensory-mcp`; +complete -F _gittensory_mcp loopover-mcp`; } function buildZshCompletion(topLevel, withSubcommands) { const subcommandCases = withSubcommands .map(([command, subcommands]) => ` ${command}) _values 'subcommand' ${subcommands.join(" ")} ;;`) .join("\n"); - return `#compdef gittensory-mcp -# gittensory-mcp zsh completion. Add to your fpath, or: -# source <(gittensory-mcp completion zsh) + return `#compdef loopover-mcp +# loopover-mcp zsh completion. Add to your fpath, or: +# source <(loopover-mcp completion zsh) _gittensory_mcp() { local -a commands commands=(${topLevel.join(" ")}) @@ -2500,12 +2500,12 @@ _gittensory_mcp "$@"`; function buildFishCompletion(topLevel, withSubcommands) { const topLevelLines = topLevel - .map((command) => `complete -c gittensory-mcp -n __fish_use_subcommand -a ${command} -d 'gittensory-mcp command'`) + .map((command) => `complete -c loopover-mcp -n __fish_use_subcommand -a ${command} -d 'loopover-mcp command'`) .join("\n"); const subcommandLines = withSubcommands - .map(([command, subcommands]) => `complete -c gittensory-mcp -n '__fish_seen_subcommand_from ${command}' -a '${subcommands.join(" ")}'`) + .map(([command, subcommands]) => `complete -c loopover-mcp -n '__fish_seen_subcommand_from ${command}' -a '${subcommands.join(" ")}'`) .join("\n"); - return `# gittensory-mcp fish completion. Save to: + return `# loopover-mcp fish completion. Save to: # ~/.config/fish/completions/gittensory-mcp.fish ${topLevelLines} ${subcommandLines}`; @@ -2516,9 +2516,9 @@ function buildPowershellCompletion(topLevel, withSubcommands) { const subcommandEntries = withSubcommands .map(([command, subcommands]) => ` '${command}' = @(${subcommands.map((subcommand) => `'${subcommand}'`).join(", ")})`) .join("\n"); - return `# gittensory-mcp PowerShell completion. Add to your $PROFILE: -# gittensory-mcp completion powershell | Out-String | Invoke-Expression -Register-ArgumentCompleter -Native -CommandName gittensory-mcp -ScriptBlock { + return `# loopover-mcp PowerShell completion. Add to your $PROFILE: +# loopover-mcp completion powershell | Out-String | Invoke-Expression +Register-ArgumentCompleter -Native -CommandName loopover-mcp -ScriptBlock { param($wordToComplete, $commandAst, $cursorPosition) $commands = @(${commandList}) $subcommands = @{ @@ -2542,39 +2542,39 @@ ${subcommandEntries} function printHelp() { process.stdout.write(`Usage: - gittensory-mcp --stdio - gittensory-mcp version [--json] - gittensory-mcp tools [--json] - gittensory-mcp completion bash|zsh|fish|powershell [--json] - gittensory-mcp login [--profile name] [--github-token ] [--json] - gittensory-mcp logout [--profile name] [--all] [--json] - gittensory-mcp whoami [--profile name] [--json] - gittensory-mcp config [--profile name] [--json] - gittensory-mcp status [--profile name] [--json] - gittensory-mcp profile list|create|switch|remove [name] [--json] - gittensory-mcp changelog [--json] - gittensory-mcp doctor [--profile name] [--cwd path] [--exit-code] [--json] - gittensory-mcp cache status|list|clear [--json] - gittensory-mcp init-client --print codex|claude|cursor|mcp|vscode [--agent-profile miner-planner|maintainer-triage|repo-owner-intake] [--json] - gittensory-mcp decision-pack --login [--json] - gittensory-mcp repo-decision --login --repo owner/repo [--json] - gittensory-mcp analyze-branch --login [--repo owner/repo] [--base origin/main] [--branch-eligibility eligible|ineligible|unknown] [--pending-merged-prs 3] [--expected-open-prs 0] [--projected-credibility 0.8] [--scenario-note "..."] [--validation "passed|npm test|summary"] [--format table] [--json] - gittensory-mcp preflight --login [--repo owner/repo] [--base origin/main] [--branch-eligibility eligible|ineligible|unknown] [--pending-merged-prs 3] [--expected-open-prs 0] [--projected-credibility 0.8] [--validation "passed|npm test|summary"] [--format table] [--json] - gittensory-mcp review-pr --login [--repo owner/repo] [--base origin/main] [--commit ]... [--body ] [--body-file ] [--linked-issue ] [--json] - gittensory-mcp lint-pr-text [--commit ]... [--body ] [--body-file ] [--linked-issue ] [--json] - gittensory-mcp validate-config --file [--source repo_file|api_record|none] [--json] - gittensory-mcp slop-risk [--description ] [--description-file ] [--changed-file ]... [--test ]... [--test-file ]... [--json] - gittensory-mcp issue-slop [--title ] [--body ] [--body-file ] [--json] - gittensory-mcp agent plan --login [--repo owner/repo] [--json] - gittensory-mcp agent status [--json] - gittensory-mcp agent explain [--json] - gittensory-mcp agent packet --login [--repo owner/repo] [--base origin/main] [--json] + loopover-mcp --stdio + loopover-mcp version [--json] + loopover-mcp tools [--json] + loopover-mcp completion bash|zsh|fish|powershell [--json] + loopover-mcp login [--profile name] [--github-token ] [--json] + loopover-mcp logout [--profile name] [--all] [--json] + loopover-mcp whoami [--profile name] [--json] + loopover-mcp config [--profile name] [--json] + loopover-mcp status [--profile name] [--json] + loopover-mcp profile list|create|switch|remove [name] [--json] + loopover-mcp changelog [--json] + loopover-mcp doctor [--profile name] [--cwd path] [--exit-code] [--json] + loopover-mcp cache status|list|clear [--json] + loopover-mcp init-client --print codex|claude|cursor|mcp|vscode [--agent-profile miner-planner|maintainer-triage|repo-owner-intake] [--json] + loopover-mcp decision-pack --login [--json] + loopover-mcp repo-decision --login --repo owner/repo [--json] + loopover-mcp analyze-branch --login [--repo owner/repo] [--base origin/main] [--branch-eligibility eligible|ineligible|unknown] [--pending-merged-prs 3] [--expected-open-prs 0] [--projected-credibility 0.8] [--scenario-note "..."] [--validation "passed|npm test|summary"] [--format table] [--json] + loopover-mcp preflight --login [--repo owner/repo] [--base origin/main] [--branch-eligibility eligible|ineligible|unknown] [--pending-merged-prs 3] [--expected-open-prs 0] [--projected-credibility 0.8] [--validation "passed|npm test|summary"] [--format table] [--json] + loopover-mcp review-pr --login [--repo owner/repo] [--base origin/main] [--commit ]... [--body ] [--body-file ] [--linked-issue ] [--json] + loopover-mcp lint-pr-text [--commit ]... [--body ] [--body-file ] [--linked-issue ] [--json] + loopover-mcp validate-config --file [--source repo_file|api_record|none] [--json] + loopover-mcp slop-risk [--description ] [--description-file ] [--changed-file ]... [--test ]... [--test-file ]... [--json] + loopover-mcp issue-slop [--title ] [--body ] [--body-file ] [--json] + loopover-mcp agent plan --login [--repo owner/repo] [--json] + loopover-mcp agent status [--json] + loopover-mcp agent explain [--json] + loopover-mcp agent packet --login [--repo owner/repo] [--base origin/main] [--json] Environment: GITTENSORY_API_URL GITTENSORY_PROFILE GITTENSORY_CONFIG_PATH or GITTENSORY_CONFIG_DIR - GITTENSORY_API_TOKEN, GITTENSORY_MCP_TOKEN, GITTENSORY_TOKEN, or a session from gittensory-mcp login + GITTENSORY_API_TOKEN, GITTENSORY_MCP_TOKEN, GITTENSORY_TOKEN, or a session from loopover-mcp login GITHUB_TOKEN for non-interactive login bootstrap GITTENSOR_SCORE_PREVIEW_CMD GITTENSOR_ROOT @@ -2585,9 +2585,9 @@ function printHelp() { function printCacheHelp() { process.stdout.write(`Usage: - gittensory-mcp cache status [--json] - gittensory-mcp cache list [--json | --format ndjson] - gittensory-mcp cache clear [--json] + loopover-mcp cache status [--json] + loopover-mcp cache list [--json | --format ndjson] + loopover-mcp cache clear [--json] Decision-pack cache entries are local-only stale fallbacks for temporary API/network outages. Source upload remains disabled. @@ -2596,10 +2596,10 @@ Source upload remains disabled. function printAgentHelp() { process.stdout.write(`Usage: - gittensory-mcp agent plan --login [--repo owner/repo] [--objective "..."] [--json] - gittensory-mcp agent status [--json] - gittensory-mcp agent explain [--json] - gittensory-mcp agent packet --login [--repo owner/repo] [--base origin/main] [--validation "passed|command|summary"] [--json] + loopover-mcp agent plan --login [--repo owner/repo] [--objective "..."] [--json] + loopover-mcp agent status [--json] + loopover-mcp agent explain [--json] + loopover-mcp agent packet --login [--repo owner/repo] [--base origin/main] [--validation "passed|command|summary"] [--json] The agent is copilot-only: it ranks, explains, and drafts public-safe packets. It does not edit code, open PRs, or post comments from the local MCP wrapper. Source upload remains disabled. @@ -2608,10 +2608,10 @@ Source upload remains disabled. function printProfileHelp() { process.stdout.write(`Usage: - gittensory-mcp profile list [--json | --format ndjson] - gittensory-mcp profile create [--json] - gittensory-mcp profile switch [--json] - gittensory-mcp profile remove [--json] + loopover-mcp profile list [--json | --format ndjson] + loopover-mcp profile create [--json] + loopover-mcp profile switch [--json] + loopover-mcp profile remove [--json] Use --profile or GITTENSORY_PROFILE to run login, logout, whoami, status, doctor, and MCP API calls with a named local session. `); @@ -2740,7 +2740,7 @@ function profileCommand(args) { } const rawName = args[1] && !args[1].startsWith("--") ? args[1] : options.name ?? options.profile; - if (!rawName) throw new Error(`Usage: gittensory-mcp profile ${subcommand} `); + if (!rawName) throw new Error(`Usage: loopover-mcp profile ${subcommand} `); const profileName = normalizeProfileName(rawName); if (subcommand === "create") { @@ -2753,7 +2753,7 @@ function profileCommand(args) { } if (subcommand === "switch" || subcommand === "use") { - if (!config.profiles?.[profileName]) throw new Error(`Profile ${profileName} does not exist. Run \`gittensory-mcp profile create ${profileName}\` or \`gittensory-mcp login --profile ${profileName}\`.`); + if (!config.profiles?.[profileName]) throw new Error(`Profile ${profileName} does not exist. Run \`loopover-mcp profile create ${profileName}\` or \`loopover-mcp login --profile ${profileName}\`.`); const nextConfig = setActiveProfile(config, profileName); saveConfig(nextConfig); const payload = { status: "switched", activeProfile: profileName, profile: profilePublicState(profileName, nextConfig) }; @@ -2907,14 +2907,14 @@ async function doctor(options) { const token = getApiToken(); if (!token) { - add("auth", "fail", `No Gittensory API/session token is configured for profile ${activeProfileName}.`, `Run \`gittensory-mcp login --profile ${activeProfileName}\`.`); + add("auth", "fail", `No Gittensory API/session token is configured for profile ${activeProfileName}.`, `Run \`loopover-mcp login --profile ${activeProfileName}\`.`); } else { try { const session = await apiGet("/v1/auth/session"); authLogin = session.login ?? authLogin; add("auth", "pass", `Profile ${activeProfileName} authenticated as ${session.login}; session expires ${session.expiresAt}.`); } catch (error) { - add("auth", "warn", `A token is configured for profile ${activeProfileName} but no user session was verified: ${error instanceof Error ? error.message : "session_check_failed"}.`, "If this is a static beta token, this can be expected. Otherwise run `gittensory-mcp login`."); + add("auth", "warn", `A token is configured for profile ${activeProfileName} but no user session was verified: ${error instanceof Error ? error.message : "session_check_failed"}.`, "If this is a static beta token, this can be expected. Otherwise run `loopover-mcp login`."); } } @@ -2929,7 +2929,7 @@ async function doctor(options) { "decision_pack_cache", "pass", `Local stale fallback cache has ${decisionPackCache.entries} entr${decisionPackCache.entries === 1 ? "y" : "ies"} and is bounded at ${decisionPackCache.maxEntries}.`, - "Run `gittensory-mcp cache clear` to remove local stale fallback data.", + "Run `loopover-mcp cache clear` to remove local stale fallback data.", ); try { @@ -2945,9 +2945,9 @@ async function doctor(options) { add("git_metadata", "warn", error instanceof Error ? error.message : "git_metadata_failed", "Run from a git repo or pass --repo owner/repo."); } - const commandPath = findExecutable("gittensory-mcp"); - if (commandPath) add("client_path", "pass", "gittensory-mcp is visible on PATH."); - else add("client_path", "warn", "gittensory-mcp was not found on PATH.", "Use an absolute command path in your MCP client config."); + const commandPath = findExecutable("loopover-mcp"); + if (commandPath) add("client_path", "pass", "loopover-mcp is visible on PATH."); + else add("client_path", "warn", "loopover-mcp was not found on PATH.", "Use an absolute command path in your MCP client config."); const scorerCommand = resolveScorePreviewCommand(); if (!scorerCommand) { @@ -2963,7 +2963,7 @@ async function doctor(options) { add("local_scorer", "pass", `Configured scorer responded in ${probe.durationMs ?? 0}ms.`); } else { const remediation = setupGuidanceForLocalScorer(probe).slice(1).join(" "); - add("local_scorer", "warn", `Configured scorer failed (${probe.code ?? "scorer_failed"}): ${probe.reason}`, remediation || "Run gittensory-mcp doctor --json for structured diagnostics."); + add("local_scorer", "warn", `Configured scorer failed (${probe.code ?? "scorer_failed"}): ${probe.reason}`, remediation || "Run loopover-mcp doctor --json for structured diagnostics."); } } @@ -3078,14 +3078,14 @@ function doctorNextCommand(byName, context) { const auth = byName.get("auth"); if (auth?.status === "fail") { return { - command: `gittensory-mcp login --profile ${shellArg(context.profileName ?? "default")}`, + command: `loopover-mcp login --profile ${shellArg(context.profileName ?? "default")}`, reason: "Authenticate the active profile so doctor, plan, preflight, and packet commands can call the API.", }; } const apiHealth = byName.get("api_health"); if (apiHealth?.status === "fail") { return { - command: "gittensory-mcp status --json", + command: "loopover-mcp status --json", reason: "Check API reachability before running planner or preflight commands.", }; } @@ -3099,20 +3099,20 @@ function doctorNextCommand(byName, context) { const gitMetadata = byName.get("git_metadata"); if (gitMetadata?.status === "warn") { return { - command: "gittensory-mcp doctor --repo owner/repo --json", + command: "loopover-mcp doctor --repo owner/repo --json", reason: "Run doctor from a git checkout or pass the repository explicitly.", }; } const localScorer = byName.get("local_scorer"); if (localScorer?.status === "warn" && localScorer.remediation) { - const scorerSetupCommand = localScorer.remediation.startsWith("Example: ") ? localScorer.remediation.replace(/^Example:\s*/, "") : "gittensory-mcp doctor --json"; + const scorerSetupCommand = localScorer.remediation.startsWith("Example: ") ? localScorer.remediation.replace(/^Example:\s*/, "") : "loopover-mcp doctor --json"; return { command: scorerSetupCommand, reason: "Configure the optional local scorer for richer private branch analysis.", }; } return { - command: `gittensory-mcp review-pr --login ${shellArg(context.login ?? "")} --repo ${shellArg(context.repoFullName ?? "owner/repo")} --json`, + command: `loopover-mcp review-pr --login ${shellArg(context.login ?? "")} --repo ${shellArg(context.repoFullName ?? "owner/repo")} --json`, reason: "Run the composed pre-PR review (preflight + slop-risk + PR-text lint) next; source upload remains disabled.", }; } @@ -3126,7 +3126,7 @@ function shellArg(value) { function initClient(options) { const client = String(options.print ?? options.client ?? "").toLowerCase(); if (!client) throw new Error("Pass --print codex, --print claude, --print cursor, --print mcp, or --print vscode."); - const command = options.command ?? "gittensory-mcp"; + const command = options.command ?? "loopover-mcp"; const snippet = clientSnippet(client, command); const agentProfile = resolveAgentProfile(options.agentProfile); const payload = { @@ -3136,7 +3136,7 @@ function initClient(options) { snippet, agentProfile, notes: [ - "Run `gittensory-mcp login` before starting the MCP client.", + "Run `loopover-mcp login` before starting the MCP client.", "Use an absolute command path if the client does not inherit your shell PATH.", "This command prints config only; it does not edit client files.", ...(agentProfile @@ -3718,7 +3718,7 @@ function cacheFallbackMetadata(entry, error) { reason: "api_unavailable", detail: sanitizeDiagnosticText(error instanceof Error ? error.message : "api_unavailable"), rerunGuidance: "Retry when Gittensory API access is restored; cached guidance may be stale.", - clearCommand: "gittensory-mcp cache clear", + clearCommand: "loopover-mcp cache clear", }; } @@ -3780,7 +3780,7 @@ function clearDecisionPackCache() { cache: { source: "local_cache", maxEntries: decisionPackCacheMaxEntries, - clearCommand: "gittensory-mcp cache clear", + clearCommand: "loopover-mcp cache clear", }, }; } @@ -3795,7 +3795,7 @@ function inspectDecisionPackCache() { maxEntries: decisionPackCacheMaxEntries, schemaVersion: decisionPackCacheSchemaVersion, apiVersion: currentApiVersion, - clearCommand: "gittensory-mcp cache clear", + clearCommand: "loopover-mcp cache clear", }; } @@ -3822,7 +3822,7 @@ function listDecisionPackCache() { status: "ok", count: entries.length, maxEntries: decisionPackCacheMaxEntries, - clearCommand: "gittensory-mcp cache clear", + clearCommand: "loopover-mcp cache clear", entries, }; } @@ -3956,7 +3956,7 @@ async function apiPost(path, body) { async function apiFetch(path, init, options = {}) { const token = options.token ?? getApiToken(); if (options.auth !== false && !token) { - const error = new Error("Run `gittensory-mcp login`, or set GITTENSORY_API_TOKEN, GITTENSORY_MCP_TOKEN, or GITTENSORY_TOKEN before starting the MCP wrapper."); + const error = new Error("Run `loopover-mcp login`, or set GITTENSORY_API_TOKEN, GITTENSORY_MCP_TOKEN, or GITTENSORY_TOKEN before starting the MCP wrapper."); error.status = 401; error.code = "missing_auth"; throw error; @@ -3971,9 +3971,9 @@ async function apiFetch(path, init, options = {}) { ...(token && options.auth !== false ? { authorization: `Bearer ${token}` } : {}), "content-type": "application/json", accept: "application/json", - "x-gittensory-mcp-package": packageName, - "x-gittensory-mcp-version": packageVersion, - "x-gittensory-mcp-client": "gittensory-mcp-cli", + "x-loopover-mcp-package": packageName, + "x-loopover-mcp-version": packageVersion, + "x-loopover-mcp-client": "loopover-mcp-cli", }, }).finally(() => clearTimeout(timeout)); const text = await response.text(); diff --git a/packages/gittensory-mcp/package.json b/packages/gittensory-mcp/package.json index 56c481999d..fb77f183c5 100644 --- a/packages/gittensory-mcp/package.json +++ b/packages/gittensory-mcp/package.json @@ -26,7 +26,7 @@ "access": "public" }, "bin": { - "gittensory-mcp": "bin/gittensory-mcp.js" + "loopover-mcp": "bin/loopover-mcp.js" }, "files": [ "bin", @@ -35,7 +35,7 @@ "CHANGELOG.md" ], "scripts": { - "build": "node --check bin/gittensory-mcp.js && node --check lib/local-branch.js && node --check lib/format-table.js && node --check scripts/gittensor-score-preview.mjs" + "build": "node --check bin/loopover-mcp.js && node --check lib/local-branch.js && node --check lib/format-table.js && node --check scripts/gittensor-score-preview.mjs" }, "dependencies": { "@loopover/engine": "^1.0.0", diff --git a/packages/gittensory-miner/BENCHMARKS.md b/packages/gittensory-miner/BENCHMARKS.md index ffffee46b4..6fe0eb76fd 100644 --- a/packages/gittensory-miner/BENCHMARKS.md +++ b/packages/gittensory-miner/BENCHMARKS.md @@ -1,4 +1,4 @@ -# gittensory-miner benchmarks +# loopover-miner benchmarks A small, committed micro-benchmark for the two purely local, synchronous hot paths that have no other signal for a future regression: the discovery fan-out ranking pass and the local-store (SQLite) read/write path. @@ -37,7 +37,7 @@ Captured on a Linux x86_64 dev container, Node.js 22.21.0. Absolute numbers vary rough sense of scale, not a target: ``` -gittensory-miner benchmark +loopover-miner benchmark discovery-fanout-ranking: median ~42ms over 5 runs, ~11,800 ops/sec (n=500) local-store-read-write: median ~38ms over 5 runs, ~26,400 ops/sec (n=1000) diff --git a/packages/gittensory-miner/DEPLOYMENT.md b/packages/gittensory-miner/DEPLOYMENT.md index b26c603bea..b043835f24 100644 --- a/packages/gittensory-miner/DEPLOYMENT.md +++ b/packages/gittensory-miner/DEPLOYMENT.md @@ -6,7 +6,7 @@ Two form factors for running `@loopover/miner`: **laptop mode** (single machine, | ---------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | **Best for** | One contributor machine, local experimentation | Many parallel miner attempts on a host or small cluster | | **Dependencies** | Node.js `>=22.13.0` only | Docker (or compatible runtime) + Node image or custom image | -| **State** | SQLite files under `~/.config/gittensory-miner/` (override with `LOOPOVER_MINER_CONFIG_DIR`) | Same SQLite layout on a mounted `/data` (or `LOOPOVER_MINER_CONFIG_DIR`) volume | +| **State** | SQLite files under `~/.config/loopover-miner/` (override with `LOOPOVER_MINER_CONFIG_DIR`) | Same SQLite layout on a mounted `/data` (or `LOOPOVER_MINER_CONFIG_DIR`) volume | | **Setup** | `npm install -g @loopover/miner` or workspace build | `docker build` + `docker run` with env + volume (see below) | | **Footprint** | One Node process, local disk for ledgers/queues | One container per worker; scale horizontally by adding containers | @@ -29,10 +29,10 @@ For provider selection and the CLI-specific model/timeout overrides, see 2. Inspect what is installed and where local state will live. `status` and `doctor` stay offline; `init --verify-token` is optional and makes one authenticated GitHub call up front: ```sh - gittensory-miner status - gittensory-miner doctor - gittensory-miner init --verify-token # optional: validate GITHUB_TOKEN once before attempts - gittensory-miner init --interactive # optional: guided prompt for GITHUB_TOKEN + provider, writes a starter .env, then reruns doctor + loopover-miner status + loopover-miner doctor + loopover-miner init --verify-token # optional: validate GITHUB_TOKEN once before attempts + loopover-miner init --interactive # optional: guided prompt for GITHUB_TOKEN + provider, writes a starter .env, then reruns doctor ``` `init --interactive` offers "Authorize with GitHub" (device flow -- visit a URL, enter a short code, no @@ -45,7 +45,7 @@ For provider selection and the CLI-specific model/timeout overrides, see 3. Expected layout after first use (default paths): ```text - ~/.config/gittensory-miner/ + ~/.config/loopover-miner/ laptop-state.sqlite3 # laptop-mode setup state, created by `init` portfolio-queue.sqlite3 # prioritized work backlog across tracked repos (#2292) claim-ledger.sqlite3 # soft issue claims (#2314) @@ -80,7 +80,7 @@ For provider selection and the CLI-specific model/timeout overrides, see Build the fleet image from the **monorepo root** (the Dockerfile needs the full workspace on disk before `npm ci` — see comments in [`Dockerfile`](Dockerfile)): ```sh -docker build -f packages/gittensory-miner/Dockerfile -t gittensory-miner:latest . +docker build -f packages/gittensory-miner/Dockerfile -t loopover-miner:latest . ``` Run a disposable worker with persistent SQLite state on a mounted volume. Inject secrets at runtime (never bake them into the image): @@ -90,11 +90,11 @@ docker run --rm -it \ -e LOOPOVER_MINER_CONFIG_DIR=/data/miner \ -e GITHUB_TOKEN \ -v miner-data:/data/miner \ - gittensory-miner:latest \ + loopover-miner:latest \ doctor ``` -The image entrypoint is `gittensory-miner`; pass subcommands after the image name (`status`, `doctor`, `claim`, …). +The image entrypoint is `loopover-miner`; pass subcommands after the image name (`status`, `doctor`, `claim`, …). - **`/data/miner` volume** — holds all SQLite state (`claim-ledger.sqlite3`, `plan-store.sqlite3`, etc.) so containers are disposable. Defaults to `LOOPOVER_MINER_CONFIG_DIR=/data/miner` in the image. - **`GITHUB_TOKEN`** — supplied by the operator at run time; the image contains no credentials. @@ -112,7 +112,7 @@ docker run --rm -it \ -e GITHUB_TOKEN_FILE=/run/secrets/github_token \ -v miner-data:/data/miner \ -v /path/to/your/secret:/run/secrets/github_token:ro \ - gittensory-miner:latest \ + loopover-miner:latest \ doctor ``` @@ -137,25 +137,25 @@ docker compose -f docker-compose.miner.yml up -d --build ## Bare-host (systemd, no Docker) -To run the miner continuously on a plain Linux host without Docker, supervise `gittensory-miner loop` — the autonomous discover → attempt → manage daemon (#5135) — with systemd. [`systemd/gittensory-miner.service.example`](../../systemd/gittensory-miner.service.example) is a ready-to-adapt persistent unit; its header carries the full install steps: +To run the miner continuously on a plain Linux host without Docker, supervise `loopover-miner loop` — the autonomous discover → attempt → manage daemon (#5135) — with systemd. [`systemd/gittensory-miner.service.example`](../../systemd/gittensory-miner.service.example) is a ready-to-adapt persistent unit; its header carries the full install steps: ```sh npm install -g @loopover/miner -gittensory-miner init --verify-token # optional: validate GITHUB_TOKEN before discovery/attempt runs +loopover-miner init --verify-token # optional: validate GITHUB_TOKEN before discovery/attempt runs sudo cp systemd/gittensory-miner.service.example /etc/systemd/system/gittensory-miner.service sudo $EDITOR /etc/systemd/system/gittensory-miner.service # set User / WorkingDirectory / ExecStart / secrets sudo systemctl daemon-reload -sudo systemctl enable --now gittensory-miner.service +sudo systemctl enable --now loopover-miner.service ``` -Because `loop` is a **long-running daemon that schedules its own cycles**, it is a persistent `Type=simple` service (with `Restart=on-failure`) — **not** a oneshot unit driven by a `.timer`, unlike the periodic `loopover-docker-prune.*.example` hygiene job in [`systemd/`](../../systemd/). Keep `GITHUB_TOKEN` (and any coding-agent credentials) in a root-owned `0600` `EnvironmentFile`, never in the unit file. Follow the loop with `journalctl -u gittensory-miner -f`; `systemctl stop` sends SIGTERM, which the loop handles cleanly at its next kill-switch check. +Because `loop` is a **long-running daemon that schedules its own cycles**, it is a persistent `Type=simple` service (with `Restart=on-failure`) — **not** a oneshot unit driven by a `.timer`, unlike the periodic `loopover-docker-prune.*.example` hygiene job in [`systemd/`](../../systemd/). Keep `GITHUB_TOKEN` (and any coding-agent credentials) in a root-owned `0600` `EnvironmentFile`, never in the unit file. Follow the loop with `journalctl -u loopover-miner -f`; `systemctl stop` sends SIGTERM, which the loop handles cleanly at its next kill-switch check. Want the dashboard too? [`systemd/gittensory-miner-ui.service.example`](../../systemd/gittensory-miner-ui.service.example) is a companion unit that serves `apps/gittensory-miner-ui` persistently over the same local state — see that app's [README](../../apps/gittensory-miner-ui/README.md#running-as-a-persistent-service). ## Invariants - Core miner bookkeeping (claims, plans, queues, ledgers) works offline after install. -- `gittensory-miner status` and `gittensory-miner doctor` make **no network calls**. +- `loopover-miner status` and `loopover-miner doctor` make **no network calls**. - Discovery/ranking primitives that touch GitHub only run when explicitly invoked and only perform documented GETs unless a future command says otherwise. - Operators own secret injection; images and packages ship without embedded tokens. diff --git a/packages/gittensory-miner/Dockerfile b/packages/gittensory-miner/Dockerfile index d598684c72..951a50155f 100644 --- a/packages/gittensory-miner/Dockerfile +++ b/packages/gittensory-miner/Dockerfile @@ -1,9 +1,9 @@ # Fleet-mode image for @loopover/miner (#4295). Build context = monorepo root: -# docker build -f packages/gittensory-miner/Dockerfile -t gittensory-miner:latest . +# docker build -f packages/gittensory-miner/Dockerfile -t loopover-miner:latest . # SECRETS ARE NEVER BAKED: supply operator credentials at `docker run` time only. # Persistent SQLite ledgers live on a mounted volume (default LOOPOVER_MINER_CONFIG_DIR=/data/miner). -ARG GITTENSORY_VERSION= +ARG LOOPOVER_VERSION= # --- build: workspace install + engine compile + miner syntax check ---------------------------- FROM public.ecr.aws/docker/library/node:24-slim AS build @@ -20,10 +20,10 @@ RUN npm prune --omit=dev --ignore-scripts # --- runtime: non-root CLI image with a mounted config volume ----------------------------------- FROM public.ecr.aws/docker/library/node:24-slim AS runtime WORKDIR /app -ARG GITTENSORY_VERSION= +ARG LOOPOVER_VERSION= ENV NODE_ENV=production \ LOOPOVER_MINER_CONFIG_DIR=/data/miner \ - LOOPOVER_MINER_VERSION=${GITTENSORY_VERSION} \ + LOOPOVER_MINER_VERSION=${LOOPOVER_VERSION} \ PATH=/app/node_modules/.bin:$PATH COPY --from=build --chown=node:node /app/node_modules ./node_modules COPY --from=build --chown=node:node /app/packages/gittensory-miner ./packages/gittensory-miner @@ -31,8 +31,8 @@ COPY --from=build --chown=node:node /app/packages/gittensory-engine ./packages/g RUN mkdir -p /data/miner && chown -R node:node /data USER node VOLUME ["/data/miner"] -# No HEALTHCHECK: the miner is a batch/CLI workload (`docker run … gittensory-miner `), not a +# No HEALTHCHECK: the miner is a batch/CLI workload (`docker run … loopover-miner `), not a # long-running HTTP service — there is no steady-state endpoint to probe unless an operator wraps # the container in their own supervising loop. -ENTRYPOINT ["gittensory-miner"] +ENTRYPOINT ["loopover-miner"] CMD ["doctor"] diff --git a/packages/gittensory-miner/README.md b/packages/gittensory-miner/README.md index 218c4392bb..588e9ea45a 100644 --- a/packages/gittensory-miner/README.md +++ b/packages/gittensory-miner/README.md @@ -36,7 +36,7 @@ It never clones source and never writes to GitHub. Discovery is per-tenant, not github.com-specific (#4784): `lib/forge-config.js` (`resolveForgeConfig`) holds the forge base URL, API version, request headers, repo path, search endpoint/qualifiers, user-agent, and credential env var behind one resolver with gittensory's github.com values as the only defaults, so the fan-out targets another -forge unchanged. `gittensory-miner discover` surfaces `--api-base-url ` and `--token-env ` and forwards a +forge unchanged. `loopover-miner discover` surfaces `--api-base-url ` and `--token-env ` and forwards a tenant goal spec to the ranker, printing `usedDefaultGoalSpec` so a fall-back to the built-in rubric is explicit rather than silent. See [`docs/repo-agnostic-capability-audit.md`](docs/repo-agnostic-capability-audit.md) for the #4780 audit this executes. @@ -53,7 +53,7 @@ The package also includes an append-only governor decision ledger: `initGovernor persist structured allow/deny/throttle/kill-switch outcomes in local SQLite for contributor audit. Insert-only — no enforcement wiring yet. (#2328) -The package also includes a real, persisted governor pause/resume control surface: `gittensory-miner governor +The package also includes a real, persisted governor pause/resume control surface: `loopover-miner governor pause [--reason ]` / `governor resume` / `governor status` toggle a `paused`/`reason`/`pausedAt` flag on governor-state.js's existing scalar-state row, and `loop-cli.js`'s iteration loop checks it at the same two boundaries as the kill switch (before the first cycle and at the top of every subsequent one) — pausing mid-run @@ -86,11 +86,11 @@ The package also includes the Phase 7 calibration runner: `runHistoricalReplayCa (`lib/calibration-run.js`) scores a completed historical-replay run with the deterministic objective-anchor scorer, folds the composite into the engine's `computePhase7CalibrationLoop` combine alongside the existing `pr_outcome` signal, and persists the combined snapshot as a `calibration_snapshot` event — queryable with -`gittensory-miner ledger list --type calibration_snapshot` or `readCalibrationSnapshots` / +`loopover-miner ledger list --type calibration_snapshot` or `readCalibrationSnapshots` / `latestCalibrationSnapshot`. It measures and records only; acting on the metric (autonomy bumps, threshold tuning) stays maintainer-only. See [`docs/miner-selfimprove-calibration.md`](docs/miner-selfimprove-calibration.md). (#4248) -`gittensory-miner manage status` now also folds each tracked repo's current discover/plan/prepare run state +`loopover-miner manage status` now also folds each tracked repo's current discover/plan/prepare run state (`run-state.js`) alongside its managed PR rows into a "run portfolio" view — `collectRunPortfolio` / `renderRunPortfolioTable` — so a repo actively being discovered or planned shows up even with zero PRs yet. Additive only: the existing `rows` JSON key and PR table are unchanged; `runPortfolio` is a new key printed @@ -132,7 +132,7 @@ confirmed unchanged, it reuses the already-resolved AI-usage-policy verdict inst (identical) doc text (#4843). Every store resolves its file the same way: the store-specific env var above, else `LOOPOVER_MINER_CONFIG_DIR`, -else `XDG_CONFIG_HOME` (falling back to `~/.config`), joined with `gittensory-miner/`. Every store also opens +else `XDG_CONFIG_HOME` (falling back to `~/.config`), joined with `loopover-miner/`. Every store also opens its file with `0700`/`0600` permissions and a shared `PRAGMA busy_timeout` so two instances on the same file serialize writes instead of racing. @@ -170,14 +170,14 @@ Zero-infra local install — no Docker, Redis, or Postgres required: ```sh npm install -g @loopover/miner -gittensory-miner init -gittensory-miner doctor -gittensory-miner status +loopover-miner init +loopover-miner doctor +loopover-miner status ``` -`init` creates `~/.config/gittensory-miner/` (or `LOOPOVER_MINER_CONFIG_DIR` / `XDG_CONFIG_HOME` overrides) and a local `laptop-state.sqlite3` bootstrap file. Re-running `init` is idempotent. Pass `--verify-token` to make one authenticated GitHub API call up front and fail fast if `GITHUB_TOKEN` is invalid or missing repository access scopes. `doctor` reports Node, the state directory, SQLite readiness, and whether Docker is installed (informational only). Every local store already applies its own pending schema migrations automatically the moment some other command first opens it, but `migrate` lets an operator proactively bring every EXISTING store file up to date in one pass (e.g. right after upgrading) instead of relying on whichever command happens to touch a given store first; a store file that hasn't been created yet is reported as skipped, not created. +`init` creates `~/.config/loopover-miner/` (or `LOOPOVER_MINER_CONFIG_DIR` / `XDG_CONFIG_HOME` overrides) and a local `laptop-state.sqlite3` bootstrap file. Re-running `init` is idempotent. Pass `--verify-token` to make one authenticated GitHub API call up front and fail fast if `GITHUB_TOKEN` is invalid or missing repository access scopes. `doctor` reports Node, the state directory, SQLite readiness, and whether Docker is installed (informational only). Every local store already applies its own pending schema migrations automatically the moment some other command first opens it, but `migrate` lets an operator proactively bring every EXISTING store file up to date in one pass (e.g. right after upgrading) instead of relying on whichever command happens to touch a given store first; a store file that hasn't been created yet is reported as skipped, not created. -First-time operators can instead run `gittensory-miner init --interactive` (#5176): a guided prompt for `GITHUB_TOKEN` (input hidden, never echoed or written to any log) and an optional coding-agent provider — plus that provider's model/timeout companion vars, each individually skippable with Enter — writes a starter `.env` to the state dir, then automatically reruns `doctor` against the collected values so setup problems surface immediately. `--interactive` makes no network calls of its own beyond what `doctor` already makes (none); non-interactive `init` invocations are unaffected. +First-time operators can instead run `loopover-miner init --interactive` (#5176): a guided prompt for `GITHUB_TOKEN` (input hidden, never echoed or written to any log) and an optional coding-agent provider — plus that provider's model/timeout companion vars, each individually skippable with Enter — writes a starter `.env` to the state dir, then automatically reruns `doctor` against the collected values so setup problems surface immediately. `--interactive` makes no network calls of its own beyond what `doctor` already makes (none); non-interactive `init` invocations are unaffected. From a local checkout: @@ -207,39 +207,39 @@ When an attempt fails on a `claude-cli` / `codex-cli` provider, the CLI-subproce | Error string / pattern | Symptom | Remediation | | --- | --- | --- | -| `claude_code_error_` | The `claude` CLI ran but its `--output-format json` envelope reported `is_error: true` (e.g. `claude_code_error_invalid_api_key`) — the OAuth token is missing, rejected, or expired. `gittensory-miner doctor` reports the same condition up front as `not authenticated: set CLAUDE_CODE_OAUTH_TOKEN`. | Regenerate a long-lived token with `claude setup-token` and set `CLAUDE_CODE_OAUTH_TOKEN`, then retry. | +| `claude_code_error_` | The `claude` CLI ran but its `--output-format json` envelope reported `is_error: true` (e.g. `claude_code_error_invalid_api_key`) — the OAuth token is missing, rejected, or expired. `loopover-miner doctor` reports the same condition up front as `not authenticated: set CLAUDE_CODE_OAUTH_TOKEN`. | Regenerate a long-lived token with `claude setup-token` and set `CLAUDE_CODE_OAUTH_TOKEN`, then retry. | | `codex_no_auth` | `codex exec` exited non-zero with no structured error in its JSONL stdout and only the `Reading prompt from stdin...` banner on stderr — its `auth.json` credential is missing or expired. The driver appends its own remediation hint (`... auth.json missing or expired -- run codex auth to authenticate`). | Run `codex auth` to re-authenticate; the next attempt reads the refreshed `auth.json` with no further restart. | | `_exit_` | Generic non-zero-exit fallback when neither structured parser matched (e.g. `codex_exit_1: ...`, `claude_exit_1: ...`). The driver appends the redacted stderr slice — an auth failure that neither parser recognized still surfaces here. | Read the appended detail; if it points at authentication, re-run `claude setup-token` or `codex auth` for the failing provider, otherwise address the reported error directly. | ## Commands ```sh -gittensory-miner --help -gittensory-miner help -gittensory-miner --version -gittensory-miner version -gittensory-miner init [--json] [--verify-token] -gittensory-miner status [--json] -gittensory-miner doctor [--json] -gittensory-miner migrate [--json] -gittensory-miner manage status [--json] -gittensory-miner manage poll [--branch ] [--json] +loopover-miner --help +loopover-miner help +loopover-miner --version +loopover-miner version +loopover-miner init [--json] [--verify-token] +loopover-miner status [--json] +loopover-miner doctor [--json] +loopover-miner migrate [--json] +loopover-miner manage status [--json] +loopover-miner manage poll [--branch ] [--json] ``` ## MCP server -The package ships a second bin entry, `gittensory-miner-mcp`, a minimal [Model Context Protocol](https://modelcontextprotocol.io) stdio server that any MCP-compatible client can connect to: +The package ships a second bin entry, `loopover-miner-mcp`, a minimal [Model Context Protocol](https://modelcontextprotocol.io) stdio server that any MCP-compatible client can connect to: ```sh -gittensory-miner-mcp +loopover-miner-mcp ``` It exposes these read-only tools: - `gittensory_miner_ping` (#5153) — a health check returning a static `{ "status": "ok", "tool": "gittensory_miner_ping" }` object. Reads no AMS state, takes no arguments. -- `gittensory_miner_get_portfolio_dashboard` (#5155) — the per-repo portfolio-queue backlog dashboard: status counts (queued / in_progress / done), totals, and the oldest-queued age. Wraps `collectPortfolioDashboard()` (no new logic) — the same data `gittensory-miner queue dashboard --json` prints locally. Read-only, takes no arguments. +- `gittensory_miner_get_portfolio_dashboard` (#5155) — the per-repo portfolio-queue backlog dashboard: status counts (queued / in_progress / done), totals, and the oldest-queued age. Wraps `collectPortfolioDashboard()` (no new logic) — the same data `loopover-miner queue dashboard --json` prints locally. Read-only, takes no arguments. - `gittensory_miner_list_claims` (#5156) — lists the local claim ledger (repo, issue number, status, claimed-at, note) via `listClaims()`. Optional `repoFullName` / `status` filters pass through to the query. Read-only — exposes no claim/release mutation. -- `gittensory_miner_get_audit_feed` (#5158) — read-only, metadata-only event-ledger audit feed (`eventType`, `repoFullName`, `outcome`, `actor`, `detail`, `createdAt`). Wraps `collectEventLedgerAuditFeed()` with the same filters as `gittensory-miner ledger list` (`--repo`, `--since`, `--type`). Never returns `payload_json` or other raw ledger columns. +- `gittensory_miner_get_audit_feed` (#5158) — read-only, metadata-only event-ledger audit feed (`eventType`, `repoFullName`, `outcome`, `actor`, `detail`, `createdAt`). Wraps `collectEventLedgerAuditFeed()` with the same filters as `loopover-miner ledger list` (`--repo`, `--since`, `--type`). Never returns `payload_json` or other raw ledger columns. - `gittensory_miner_get_run_state` (#5160) — read-only per-repo run-state (`idle` / `discovering` / `planning` / `preparing`) via `getRunState` / `listRunStates`. Pass `repoFullName` for one repo (a null state means none recorded yet), or omit it to list all. The read-only analog of ORB's `gittensory_get_automation_state`; adds no state-set mutation. @@ -247,30 +247,30 @@ It exposes these read-only tools: - `gittensory_miner_get_governor_decisions` (#5159) — read-only projection of the governor decision log (`id`, `ts`, `eventType`, `repoFullName`, `actionClass`, `decision`, `reason`), optionally filtered by `repoFullName`. The projection **excludes the sensitive `payload_json` column by construction** — `governor-ledger.js` reads it with an explicit named-column SELECT, never `SELECT *`. -- `gittensory_miner_status` (#5154) — read-only status + doctor diagnostics, returning `{ status, doctor }`: `status` = package/engine versions (and skew), node version, state-dir + config-file paths, and the resolved coding-agent driver (provider name, the model **env-var NAME** never its value, CLI-present boolean); `doctor` = the checks `gittensory-miner doctor` runs (Docker/CLI presence, config validity, …) as `{ name, ok, detail }`. Reuses `collectStatus` / `runDoctorChecks` so it can't drift from the CLI, and returns only names / booleans / paths — never any env-var value, token, or credential. +- `gittensory_miner_status` (#5154) — read-only status + doctor diagnostics, returning `{ status, doctor }`: `status` = package/engine versions (and skew), node version, state-dir + config-file paths, and the resolved coding-agent driver (provider name, the model **env-var NAME** never its value, CLI-present boolean); `doctor` = the checks `loopover-miner doctor` runs (Docker/CLI presence, config validity, …) as `{ name, ok, detail }`. Reuses `collectStatus` / `runDoctorChecks` so it can't drift from the CLI, and returns only names / booleans / paths — never any env-var value, token, or credential. This completes the read-only AMS MCP tool surface (status, portfolio, claims, event-ledger, governor-ledger, run-state, plan-store). ### Client config -`gittensory-mcp` (ORB's hosted contributor-workflow tools) and `gittensory-miner-mcp` (AMS's own local state-visibility tools above) can run as two separate stdio servers in the same MCP client session — useful for a dual-role operator running both ORB and AMS on the same box. Generate ORB's half with `gittensory-mcp init-client --print claude` (see the [`@loopover/mcp` README](../gittensory-mcp/README.md#client-config)); `gittensory-miner-mcp` takes no flags, so its entry is just the bin name. Combined, a Claude Desktop / Claude Code style config looks like: +`loopover-mcp` (ORB's hosted contributor-workflow tools) and `loopover-miner-mcp` (AMS's own local state-visibility tools above) can run as two separate stdio servers in the same MCP client session — useful for a dual-role operator running both ORB and AMS on the same box. Generate ORB's half with `loopover-mcp init-client --print claude` (see the [`@loopover/mcp` README](../gittensory-mcp/README.md#client-config)); `loopover-miner-mcp` takes no flags, so its entry is just the bin name. Combined, a Claude Desktop / Claude Code style config looks like: ```json { "mcpServers": { "gittensory": { - "command": "gittensory-mcp", + "command": "loopover-mcp", "args": ["--stdio"] }, - "gittensory-miner": { - "command": "gittensory-miner-mcp", + "loopover-miner": { + "command": "loopover-miner-mcp", "args": [] } } } ``` -`gittensory` exposes ORB's hosted contributor-workflow tools (issue ranking, PR packet prep, decision packs). `gittensory-miner` exposes AMS's own local state-visibility tools listed above (portfolio dashboard, claims, audit feed, run state, plans) — a fully separate, 100% local tool surface with no shared code or network calls between the two. Both follow the same `gittensory_*` tool-naming convention (`gittensory_...` vs. `gittensory_miner_...`), but back onto different stores: ORB's tools read the hosted gittensory backend, AMS's tools read this machine's own local SQLite files (see [Local storage](#local-storage)) — a handful of AMS tools even name the ORB tool they mirror (e.g. `gittensory_miner_get_run_state` is the read-only analog of `gittensory_get_automation_state`) so the relationship is explicit at the point of use, not just here. +`gittensory` exposes ORB's hosted contributor-workflow tools (issue ranking, PR packet prep, decision packs). `loopover-miner` exposes AMS's own local state-visibility tools listed above (portfolio dashboard, claims, audit feed, run state, plans) — a fully separate, 100% local tool surface with no shared code or network calls between the two. Both follow the same `gittensory_*` tool-naming convention (`gittensory_...` vs. `gittensory_miner_...`), but back onto different stores: ORB's tools read the hosted gittensory backend, AMS's tools read this machine's own local SQLite files (see [Local storage](#local-storage)) — a handful of AMS tools even name the ORB tool they mirror (e.g. `gittensory_miner_get_run_state` is the read-only analog of `gittensory_get_automation_state`) so the relationship is explicit at the point of use, not just here. ## Version check diff --git a/packages/gittensory-miner/bin/gittensory-miner-mcp.d.ts b/packages/gittensory-miner/bin/loopover-miner-mcp.d.ts similarity index 100% rename from packages/gittensory-miner/bin/gittensory-miner-mcp.d.ts rename to packages/gittensory-miner/bin/loopover-miner-mcp.d.ts diff --git a/packages/gittensory-miner/bin/gittensory-miner-mcp.js b/packages/gittensory-miner/bin/loopover-miner-mcp.js similarity index 100% rename from packages/gittensory-miner/bin/gittensory-miner-mcp.js rename to packages/gittensory-miner/bin/loopover-miner-mcp.js diff --git a/packages/gittensory-miner/bin/gittensory-miner.js b/packages/gittensory-miner/bin/loopover-miner.js similarity index 100% rename from packages/gittensory-miner/bin/gittensory-miner.js rename to packages/gittensory-miner/bin/loopover-miner.js diff --git a/packages/gittensory-miner/docs/coding-agent-driver.md b/packages/gittensory-miner/docs/coding-agent-driver.md index c5e8c9d450..8cebafd5d8 100644 --- a/packages/gittensory-miner/docs/coding-agent-driver.md +++ b/packages/gittensory-miner/docs/coding-agent-driver.md @@ -137,4 +137,4 @@ which axis (if any) triggered an abandon, for an operator reading the attempt lo - [`env-reference.md`](env-reference.md) — env vars including ledger path overrides. - [`../DEPLOYMENT.md`](../DEPLOYMENT.md) — laptop vs fleet deployment and state directory layout. - [`miner-goal-spec.md`](miner-goal-spec.md) — per-repo `.gittensory-miner.yml` targeting policy. -- [`../README.md#mcp-server`](../README.md#mcp-server) — the `gittensory-miner-mcp` read-only tool surface for querying this driver's resolved status (provider, model env-var name, CLI presence) and the rest of AMS's local state over MCP. +- [`../README.md#mcp-server`](../README.md#mcp-server) — the `loopover-miner-mcp` read-only tool surface for querying this driver's resolved status (provider, model env-var name, CLI presence) and the rest of AMS's local state over MCP. diff --git a/packages/gittensory-miner/docs/config-precedence.md b/packages/gittensory-miner/docs/config-precedence.md index d130d2afb1..18b48b2528 100644 --- a/packages/gittensory-miner/docs/config-precedence.md +++ b/packages/gittensory-miner/docs/config-precedence.md @@ -8,8 +8,8 @@ AMS does **not** have a single `config.js` resolver. Configuration is layered by | --- | --- | --- | --- | | **Per-target-repo file** | `.gittensory-miner.yml` (or `.github/gittensory-miner.yml`, JSON variants) | One cloned target repo | `lib/miner-goal-spec.js`, engine `parseMinerGoalSpecContent` | | **Operator env** | `LOOPOVER_MINER_*` / `MINER_*` | This miner process / fleet container | `lib/local-store.js`, `lib/governor-kill-switch.js`, `lib/attempt-cli.js`, … | -| **CLI flags** | `gittensory-miner …` argv | One invocation | `lib/attempt-cli.js`, `lib/discover-cli.js`, `lib/loop-cli.js`, … | -| **Operator file (not goal spec)** | `~/.config/gittensory-miner/.gittensory-ams.yml` | Operator execution policy | `lib/ams-policy.js` | +| **CLI flags** | `loopover-miner …` argv | One invocation | `lib/attempt-cli.js`, `lib/discover-cli.js`, `lib/loop-cli.js`, … | +| **Operator file (not goal spec)** | `~/.config/loopover-miner/.gittensory-ams.yml` | Operator execution policy | `lib/ams-policy.js` | `.gittensory-miner.yml` is **maintainer-authored in the target repo**. Operator env and CLI flags are **never overridden by a target repo's goal spec** for operator-owned policy (see `lib/ams-policy.js` header). diff --git a/packages/gittensory-miner/docs/discovery-plane-operator-guide.md b/packages/gittensory-miner/docs/discovery-plane-operator-guide.md index 66dfa052a6..ccc9df7545 100644 --- a/packages/gittensory-miner/docs/discovery-plane-operator-guide.md +++ b/packages/gittensory-miner/docs/discovery-plane-operator-guide.md @@ -1,6 +1,6 @@ # Hosted discovery plane — operator guide (opt-in) -Operator-facing guide for the **optional** Phase 6 hosted discovery-index plane ([#4250](https://github.com/JSONbored/gittensory/issues/4250)). This is the client/miner half of that roadmap item: how a `gittensory-miner` instance opts in, what it may send, and what never leaves the operator's machine. +Operator-facing guide for the **optional** Phase 6 hosted discovery-index plane ([#4250](https://github.com/JSONbored/gittensory/issues/4250)). This is the client/miner half of that roadmap item: how a `loopover-miner` instance opts in, what it may send, and what never leaves the operator's machine. > **Placeholder scope:** the concrete env var names, HTTP paths, and telemetry event types below are **provisional** until the sibling contract/telemetry/client issues land. When those ship, update this file to match the real symbols — do not treat the TBD names as stable API yet. > @@ -75,7 +75,7 @@ Mirrors [`DEPLOYMENT.md`](../DEPLOYMENT.md) tone — concrete guarantees for ope - **Telemetry is a second opt-in** — even with the plane enabled, anonymized telemetry ([#4301](https://github.com/JSONbored/gittensory/issues/4301)) remains separately gated. - **Anonymized identifiers only** — when telemetry ships, repo/issue correlation uses HMAC-hashed identifiers keyed by a **per-instance dedicated secret** the collector never holds (same posture as `getOrCreateAnonSecret` / `hmacField` in `src/selfhost/orb-collector.ts` — key separation from GitHub App / webhook secrets). - **Low-cardinality reason buckets** — any free-text-adjacent telemetry fields use bucketed categories (Orb's `bucketReasonCode` pattern), not raw maintainer or model prose. -- **Core miner still works offline** — claims, plans, queues, and local ledgers do not require the hosted plane; `gittensory-miner doctor` / `status` remain no-network commands. +- **Core miner still works offline** — claims, plans, queues, and local ledgers do not require the hosted plane; `loopover-miner doctor` / `status` remain no-network commands. ### Never included (client → hosted plane) diff --git a/packages/gittensory-miner/docs/miner-selfimprove-calibration.md b/packages/gittensory-miner/docs/miner-selfimprove-calibration.md index 6966a9bc49..0970a4d52b 100644 --- a/packages/gittensory-miner/docs/miner-selfimprove-calibration.md +++ b/packages/gittensory-miner/docs/miner-selfimprove-calibration.md @@ -40,7 +40,7 @@ reduces the per-task scores to one composite `[0, 1]`, folds it into the `Histor engine expects, calls `computePhase7CalibrationLoop` with that **plus the existing `pr_outcome` signal**, and persists the combined snapshot as a `calibration_snapshot` event on the local append-only event ledger (the same typed-event-over-`event-ledger.js` pattern as `pr-outcome.js`). The persisted metric is queryable with -`gittensory-miner ledger list --type calibration_snapshot` and via `readCalibrationSnapshots` / +`loopover-miner ledger list --type calibration_snapshot` and via `readCalibrationSnapshots` / `latestCalibrationSnapshot`. Consistent with the boundary below, the runner is **read/measure-only**: it produces and persists the tracked diff --git a/packages/gittensory-miner/docs/observability.md b/packages/gittensory-miner/docs/observability.md index cfe7aa729c..93b3f19d1a 100644 --- a/packages/gittensory-miner/docs/observability.md +++ b/packages/gittensory-miner/docs/observability.md @@ -7,7 +7,7 @@ operations, see your ops runbook. ## What's observable The miner writes append-only SQLite ledgers under `LOOPOVER_MINER_CONFIG_DIR` (default -`~/.config/gittensory-miner` on a laptop, or `/data/miner` in the fleet Docker image — see +`~/.config/loopover-miner` on a laptop, or `/data/miner` in the fleet Docker image — see [`DEPLOYMENT.md`](../DEPLOYMENT.md)): - **`attempt-log.sqlite3`** — the driver-level attempt event trace (event type, action class, mode, reason, @@ -69,10 +69,10 @@ exposes four Prometheus text-exposition documents for live counters/gauges — a | Command | Metric family | | ------------------------------------ | ------------------------------------------------------------------------------------ | -| `gittensory-miner metrics` | Prediction-calibration counters (`gittensory_miner_prediction*_total`) | -| `gittensory-miner queue metrics` | Portfolio-queue backlog + lease-age gauges (`gittensory_miner_portfolio_queue*`) | -| `gittensory-miner ledger metrics` | Event-ledger counters (`gittensory_miner_events_total`) | -| `gittensory-miner governor metrics` | Write-rate-limit + cap-usage pressure gauges (`gittensory_miner_governor*`) | +| `loopover-miner metrics` | Prediction-calibration counters (`gittensory_miner_prediction*_total`) | +| `loopover-miner queue metrics` | Portfolio-queue backlog + lease-age gauges (`gittensory_miner_portfolio_queue*`) | +| `loopover-miner ledger metrics` | Event-ledger counters (`gittensory_miner_events_total`) | +| `loopover-miner governor metrics` | Write-rate-limit + cap-usage pressure gauges (`gittensory_miner_governor*`) | None of these is a long-running HTTP server — Prometheus can't scrape a one-shot CLI command directly. To opt in, wire [`scripts/export-miner-prometheus-textfile.sh`](../../../scripts/export-miner-prometheus-textfile.sh) into @@ -92,7 +92,7 @@ family's metrics are simply omitted from the file for that run (logged to stderr Then point your own `prometheus.yml` at node_exporter as usual — no changes to this repo's `prometheus/` config are needed. See [`prometheus/rules/alerts.yml`](../../../prometheus/rules/alerts.yml)'s -`gittensory-miner-prediction` / `gittensory-miner-portfolio-queue` / `gittensory-miner-governor` rule groups for +`loopover-miner-prediction` / `loopover-miner-portfolio-queue` / `loopover-miner-governor` rule groups for alert rules that already target these exact metric names. ## Anonymized central telemetry (opt-in, off by default) @@ -102,7 +102,7 @@ of its own PR-outcome history to gittensory's hosted AMS collector — the same self-host collector already sends for maintainers, mirrored for contributors: ```sh -gittensory-miner orb export --enable --send +loopover-miner orb export --enable --send ``` - **`--enable`** alone only builds and prints the anonymized batch locally — no network call, so you can inspect diff --git a/packages/gittensory-miner/docs/operations-runbook.md b/packages/gittensory-miner/docs/operations-runbook.md index aa2efdb4fb..aac515afb4 100644 --- a/packages/gittensory-miner/docs/operations-runbook.md +++ b/packages/gittensory-miner/docs/operations-runbook.md @@ -1,4 +1,4 @@ -# gittensory-miner — operational runbook +# loopover-miner — operational runbook Operator-facing runbook for **local SQLite state**: what the concurrency guarantees actually mean, how to recover from corruption, what to do when two miner processes collide on the same files, and how schema upgrades migrate your on-disk ledgers after a package update. @@ -6,13 +6,13 @@ Operator-facing runbook for **local SQLite state**: what the concurrency guarant ## Local state at a glance -Every miner keeps **independent SQLite files** under one state directory (default `~/.config/gittensory-miner/`, override with `LOOPOVER_MINER_CONFIG_DIR`). Each store has its own file, table, and optional per-store env override — see the table in [`../README.md`](../README.md#local-storage) and [`env-reference.md`](env-reference.md). +Every miner keeps **independent SQLite files** under one state directory (default `~/.config/loopover-miner/`, override with `LOOPOVER_MINER_CONFIG_DIR`). Each store has its own file, table, and optional per-store env override — see the table in [`../README.md`](../README.md#local-storage) and [`env-reference.md`](env-reference.md). Common files you will touch in incidents: | File | Purpose | |------|---------| -| `laptop-state.sqlite3` | Bootstrap metadata (`gittensory-miner init`) | +| `laptop-state.sqlite3` | Bootstrap metadata (`loopover-miner init`) | | `claim-ledger.sqlite3` | Soft issue claims on this machine | | `event-ledger.sqlite3` | Append-only manage-loop audit trail | | `portfolio-queue.sqlite3` | Per-repo portfolio queue | @@ -41,15 +41,15 @@ PRAGMA busy_timeout = 5000; | Two **short-lived** writers on the **same file** (e.g. CLI command finishing while `loop` is idle, or Grafana reading while the miner appends) | SQLite waits up to **5 seconds** for the lock, then proceeds or surfaces `database is locked` | | Append-only ledgers (`event-ledger`, `attempt-log`, …) | Writes use **`BEGIN IMMEDIATE`** (or equivalent single-statement atomicity) so sequence allocation cannot interleave | | Claim / queue stores | **`INSERT … ON CONFLICT`** and **`UPDATE … RETURNING`** patterns avoid read-then-write races **within one file** | -| Two **long-running `gittensory-miner loop` daemons** on the **same `LOOPOVER_MINER_CONFIG_DIR`** | **Unsupported.** `busy_timeout` reduces transient lock errors; it does **not** make multi-process loop workers safe on one volume | +| Two **long-running `loopover-miner loop` daemons** on the **same `LOOPOVER_MINER_CONFIG_DIR`** | **Unsupported.** `busy_timeout` reduces transient lock errors; it does **not** make multi-process loop workers safe on one volume | **Invariant:** one active loop (or one intentional writer set) per state directory. Horizontal scale = **isolated state dirs** (separate compose projects, separate `LOOPOVER_MINER_CONFIG_DIR`, or the k8s StatefulSet pattern in [`../DEPLOYMENT.md`](../DEPLOYMENT.md)). ### Quick health check ```sh -gittensory-miner doctor --json -gittensory-miner status --json +loopover-miner doctor --json +loopover-miner status --json ``` `doctor` includes `laptop-state-sqlite` (file exists + readable) and `state-dir-writable`. It performs **no network I/O**. @@ -68,7 +68,7 @@ gittensory-miner status --json 1. List processes using the state dir: ```sh - STATE_DIR="$(gittensory-miner status --json | jq -r .stateDir)" + STATE_DIR="$(loopover-miner status --json | jq -r .stateDir)" ls -la "$STATE_DIR" # Linux: lsof +D "$STATE_DIR" 2>/dev/null || fuser -v "$STATE_DIR"/*.sqlite3 2>/dev/null ``` @@ -78,9 +78,9 @@ gittensory-miner status --json 3. Inspect soft claims and queue without mutating: ```sh - gittensory-miner claim list --json - gittensory-miner queue list --json - gittensory-miner ledger list --json | tail -20 + loopover-miner claim list --json + loopover-miner queue list --json + loopover-miner ledger list --json | tail -20 ``` **Remediation** @@ -96,7 +96,7 @@ gittensory-miner status --json Or set distinct `LOOPOVER_MINER_CONFIG_DIR` per worker. -3. Re-run `gittensory-miner doctor`. If locks persist with a single process, see **Ledger corrupted** below. +3. Re-run `loopover-miner doctor`. If locks persist with a single process, see **Ledger corrupted** below. 4. **Claims are local bookkeeping only.** Two miners on different machines claiming the same GitHub issue is a **fleet coordination** problem (duplicate-cluster adjudication in the engine), not something SQLite resolves — split state dirs and use operational claim hygiene. @@ -129,7 +129,7 @@ schedule (cron, systemd timer, etc.) so a good restore point always exists befor ```sh sh scripts/restore-miner.sh --yes # newest backup sh scripts/restore-miner.sh --yes /path/to/backups/ # a specific one - gittensory-miner doctor --json # verify afterward + loopover-miner doctor --json # verify afterward ``` Also removes any leftover `-wal`/`-shm` sidecar files from the live directory after restoring each store — @@ -141,7 +141,7 @@ schedule (cron, systemd timer, etc.) so a good restore point always exists befor **Symptoms** - Command throws `corrupted_*_row` (`corrupted_attempt_log_row`, `corrupted_governor_row`, `corrupted_plan_row`, `corrupted_prediction_row`, …) -- `gittensory-miner doctor` reports `laptop-state-sqlite` not readable +- `loopover-miner doctor` reports `laptop-state-sqlite` not readable - `sqlite3` reports `database disk image is malformed` - Partial writes after disk full, forced kill during a migration transaction, or copying a live `.sqlite3` while the miner is writing @@ -173,7 +173,7 @@ schedule (cron, systemd timer, etc.) so a good restore point always exists befor |------|------|--------| | **A — single store reset** | One ledger is corrupt; others healthy; you accept losing that store's history | Remove only the bad `*.sqlite3` (and any `-wal`/`-shm` siblings). Next command recreates an empty store. | | **B — restore from backup** | You have a recent backup from `backup-miner.sh` (see **Backup and restore** above) | Stop miner → `sh scripts/restore-miner.sh --yes` → restart. | - | **C — full re-init** | Multiple files suspect or state is disposable | Archive dir → `gittensory-miner init` → reconfigure env/goals. Rebuild claims/plans from GitHub metadata as needed. | + | **C — full re-init** | Multiple files suspect or state is disposable | Archive dir → `loopover-miner init` → reconfigure env/goals. Rebuild claims/plans from GitHub metadata as needed. | 4. **Never copy a live SQLite file** from a running miner as backup — stop first, or use SQLite's `.backup` command: @@ -181,7 +181,7 @@ schedule (cron, systemd timer, etc.) so a good restore point always exists befor sqlite3 "$DB" ".backup '${DB}.safe-copy'" ``` -5. After recovery, run `gittensory-miner doctor --json` and spot-check read-only listings (`claim list`, `ledger list`). +5. After recovery, run `loopover-miner doctor --json` and spot-check read-only listings (`claim list`, `ledger list`). Append-only stores **do not repair individual bad rows** in place — corrupted payload JSON is rejected on read by design so bad data cannot silently propagate. @@ -202,12 +202,12 @@ Stores use the lightweight **`schema-version.js`** convention ([#4832](https://g 1. **Before upgrading** the `@loopover/miner` package (npm, image tag, or git pull): ```sh - gittensory-miner doctor --json > /tmp/miner-pre-upgrade-doctor.json - STATE_DIR="$(gittensory-miner status --json | jq -r .stateDir)" - tar -czf "/tmp/gittensory-miner-state-$(date +%Y%m%d).tar.gz" -C "$(dirname "$STATE_DIR")" "$(basename "$STATE_DIR")" + loopover-miner doctor --json > /tmp/miner-pre-upgrade-doctor.json + STATE_DIR="$(loopover-miner status --json | jq -r .stateDir)" + tar -czf "/tmp/loopover-miner-state-$(date +%Y%m%d).tar.gz" -C "$(dirname "$STATE_DIR")" "$(basename "$STATE_DIR")" ``` -2. **Stop** supervised loops (`systemctl stop gittensory-miner.service`, `docker compose stop miner`, etc.). +2. **Stop** supervised loops (`systemctl stop loopover-miner.service`, `docker compose stop miner`, etc.). 3. **Install** the new version (`npm install -g @loopover/miner@latest`, rebuild image, …). The CLI prints a one-line npm upgrade nudge when behind registry latest — informational only. @@ -215,7 +215,7 @@ Stores use the lightweight **`schema-version.js`** convention ([#4832](https://g deliberate pass instead of relying on whichever command happens to open a given store first: ```sh - gittensory-miner migrate --json + loopover-miner migrate --json ``` (Pending migrations still apply automatically on first open regardless — e.g. `portfolio-queue` adds @@ -226,9 +226,9 @@ Stores use the lightweight **`schema-version.js`** convention ([#4832](https://g 5. **Start** one miner process, then **verify**: ```sh - gittensory-miner doctor --json - gittensory-miner status --json - gittensory-miner migrate --json # re-run: every store should now report "up-to-date" + loopover-miner doctor --json + loopover-miner status --json + loopover-miner migrate --json # re-run: every store should now report "up-to-date" ``` 6. If a migration throws on startup, **do not delete files immediately** — restore the pre-upgrade tarball, pin the previous package version, and file an issue with the failing `user_version` and store filename. diff --git a/packages/gittensory-miner/docs/repo-agnostic-capability-audit.md b/packages/gittensory-miner/docs/repo-agnostic-capability-audit.md index 13da811319..9350fb9bde 100644 --- a/packages/gittensory-miner/docs/repo-agnostic-capability-audit.md +++ b/packages/gittensory-miner/docs/repo-agnostic-capability-audit.md @@ -36,7 +36,7 @@ Everything else audited is already parameterized (see the last section) and need | 83 | `` `/repos/${owner}/${repo}${suffix}` `` | (5) query construction | Per-forge repo path template. | | 202 | `` `${trimmed} state:open type:issue` `` (search qualifiers) | (5) query construction | Per-forge search dialect (GitHub search syntax is assumed). | | 241 | `"/search/issues"` | (5) query construction | Per-forge search endpoint. | -| 70 | `"user-agent": "gittensory-miner"` | (7) branding | Cosmetic; low priority — a configurable UA string. | +| 70 | `"user-agent": "loopover-miner"` | (7) branding | Cosmetic; low priority — a configurable UA string. | Note: the label extractor (`labelNames`, ~168) and issue projection are already generic — they read whatever label strings the forge returns, with no `gittensor:*` filter. No change needed there. diff --git a/packages/gittensory-miner/docs/sizing.md b/packages/gittensory-miner/docs/sizing.md index 5ab92d8164..fddc24b477 100644 --- a/packages/gittensory-miner/docs/sizing.md +++ b/packages/gittensory-miner/docs/sizing.md @@ -1,4 +1,4 @@ -# gittensory-miner resource sizing +# loopover-miner resource sizing Real, measured CPU/RAM/disk numbers for laptop mode and fleet mode, so an operator can size a host or cluster from data instead of guessing. Neither the operational-runbook issue nor the local-stores @@ -14,7 +14,7 @@ documentation commits to this — this doc is scoped strictly to the numbers and ## Workload measured -Both modes measure `gittensory-miner init` (laptop mode only) followed by `gittensory-miner discover +Both modes measure `loopover-miner init` (laptop mode only) followed by `loopover-miner discover [...] --json` against real, small public repositories (`octocat/Hello-World`, `octocat/Spoon-Knife`) with **no `GITHUB_TOKEN`** — real, unauthenticated GitHub GET requests, metadata fan-out + deterministic ranking, no writes. @@ -44,10 +44,10 @@ dominated by the operator's chosen coding-agent CLI process, not by anything thi ```sh LOOPOVER_MINER_CONFIG_DIR=/tmp/sizing-laptop /usr/bin/time -v \ - node packages/gittensory-miner/bin/gittensory-miner.js init --json + node packages/gittensory-miner/bin/loopover-miner.js init --json LOOPOVER_MINER_CONFIG_DIR=/tmp/sizing-laptop /usr/bin/time -v \ - node packages/gittensory-miner/bin/gittensory-miner.js discover octocat/Hello-World --dry-run --json + node packages/gittensory-miner/bin/loopover-miner.js discover octocat/Hello-World --dry-run --json du -sh /tmp/sizing-laptop ``` @@ -55,11 +55,11 @@ du -sh /tmp/sizing-laptop ### Exact commands (fleet mode, N=1 shown; N=4 repeats the `docker run` with 4 distinct names/volumes) ```sh -docker build -f packages/gittensory-miner/Dockerfile -t gittensory-miner:sizing . +docker build -f packages/gittensory-miner/Dockerfile -t loopover-miner:sizing . docker volume create miner-sizing-1 -docker run -d --name miner-sizing-1 -v miner-sizing-1:/data/miner --entrypoint sh gittensory-miner:sizing \ - -c "gittensory-miner discover octocat/Hello-World octocat/Spoon-Knife --json > /tmp/out.json 2>&1; sleep 20" +docker run -d --name miner-sizing-1 -v miner-sizing-1:/data/miner --entrypoint sh loopover-miner:sizing \ + -c "loopover-miner discover octocat/Hello-World octocat/Spoon-Knife --json > /tmp/out.json 2>&1; sleep 20" for i in $(seq 1 20); do docker stats --no-stream --format '{{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}' miner-sizing-1 @@ -74,7 +74,7 @@ docker run --rm -v miner-sizing-1:/data alpine du -ah /data | --- | --- | --- | --- | --- | --- | | Laptop (`init`) | 1 | 125% (short burst, Node startup) | 74 MB | — | Sandbox above | | Laptop (`discover`, 1 repo, 90 issues) | 1 | 16% (network-bound) | 98 MB | 100 KB (5 SQLite files after `init` + `discover`) | Sandbox above | -| Fleet (Docker, `discover`, 2 repos) | 1 | 54% (short burst) | 46 MB | 92 KB (4 SQLite files) | Sandbox above, `gittensory-miner:sizing` image (333 MB) | +| Fleet (Docker, `discover`, 2 repos) | 1 | 54% (short burst) | 46 MB | 92 KB (4 SQLite files) | Sandbox above, `loopover-miner:sizing` image (333 MB) | | Fleet (Docker, `discover`, 2 repos) | 4 (isolated volumes) | 5–38% per worker (bursts did not line up across workers) | 34–45 MB per worker | 92 KB per worker (368 KB total across 4 isolated volumes) | Sandbox above | **Takeaways:** diff --git a/packages/gittensory-miner/docs/unattended-scheduling.md b/packages/gittensory-miner/docs/unattended-scheduling.md index c816a759fa..cf9f9ca513 100644 --- a/packages/gittensory-miner/docs/unattended-scheduling.md +++ b/packages/gittensory-miner/docs/unattended-scheduling.md @@ -1,4 +1,4 @@ -# gittensory-miner — unattended scheduling & failure alerting +# loopover-miner — unattended scheduling & failure alerting Operational guidance for running the miner's scheduled commands — `manage poll` and `discover` — unattended on a timer (cron or systemd), and for alerting when a run fails. These are the two commands @@ -33,10 +33,10 @@ LOOPOVER_MINER_NO_UPDATE_CHECK=1 # Poll a tracked PR every 10 minutes. The `||` branch fires on any non-zero exit: it logs the failing # code to syslog AND re-raises it with `exit "$status"`, so the failure stays visible to exit-status # monitoring instead of being masked by logger's own success. -*/10 * * * * /usr/local/bin/gittensory-miner manage poll acme/widgets 42 --json || { status=$?; logger -t gittensory-miner "manage poll failed (exit $status)"; exit "$status"; } +*/10 * * * * /usr/local/bin/loopover-miner manage poll acme/widgets 42 --json || { status=$?; logger -t loopover-miner "manage poll failed (exit $status)"; exit "$status"; } # Discover + enqueue candidate work hourly. -0 * * * * /usr/local/bin/gittensory-miner discover --search "label:good-first-issue" --json || { status=$?; logger -t gittensory-miner "discover failed (exit $status)"; exit "$status"; } +0 * * * * /usr/local/bin/loopover-miner discover --search "label:good-first-issue" --json || { status=$?; logger -t loopover-miner "discover failed (exit $status)"; exit "$status"; } ``` Two cron facts to get right here: @@ -53,23 +53,23 @@ Two cron facts to get right here: A `oneshot` service plus a timer is the more observable option: `systemctl status` / `journalctl` capture each run, and `OnFailure=` is a first-class alerting hook. -`gittensory-miner-discover.service`: +`loopover-miner-discover.service`: ```ini [Unit] -Description=gittensory-miner discover -OnFailure=gittensory-miner-alert@%n.service +Description=loopover-miner discover +OnFailure=loopover-miner-alert@%n.service [Service] Type=oneshot Environment=LOOPOVER_MINER_NO_UPDATE_CHECK=1 # A non-zero exit (2) marks the unit failed and triggers OnFailure=. -ExecStart=/usr/local/bin/gittensory-miner discover --search "label:good-first-issue" --json +ExecStart=/usr/local/bin/loopover-miner discover --search "label:good-first-issue" --json ``` -`gittensory-miner-discover.timer`: +`loopover-miner-discover.timer`: ```ini [Unit] -Description=Run gittensory-miner discover hourly +Description=Run loopover-miner discover hourly [Timer] OnCalendar=hourly @@ -79,7 +79,7 @@ Persistent=true WantedBy=timers.target ``` -Enable with `systemctl enable --now gittensory-miner-discover.timer`. +Enable with `systemctl enable --now loopover-miner-discover.timer`. ## Alerting on failure @@ -89,18 +89,18 @@ Every option keys on the same exit-code contract (`2` = failure): capture `$?` before the alert command runs and re-raise it, so the failure isn't masked. Substitute `logger` with a webhook `curl`, a PagerDuty/Slack CLI, etc. (`MAILTO` still mails any output, but is not a reliable signal for a silent failure — see the cron note above.) -- **systemd:** `OnFailure=gittensory-miner-alert@%n.service` runs a templated alert unit on any non-zero +- **systemd:** `OnFailure=loopover-miner-alert@%n.service` runs a templated alert unit on any non-zero exit. A minimal alert unit: ```ini - # gittensory-miner-alert@.service + # loopover-miner-alert@.service [Service] Type=oneshot - ExecStart=/usr/local/bin/notify-failure "gittensory-miner unit %i failed" + ExecStart=/usr/local/bin/notify-failure "loopover-miner unit %i failed" ``` - **wrapper script:** for any scheduler, wrap the command and preserve its exit code: ```sh #!/bin/sh - gittensory-miner "$@" || { status=$?; notify-failure "gittensory-miner $* exited $status"; exit "$status"; } + loopover-miner "$@" || { status=$?; notify-failure "loopover-miner $* exited $status"; exit "$status"; } ``` Keep `--json` on scheduled runs so the alert handler can forward the structured output; the diff --git a/packages/gittensory-miner/lib/attempt-cli.d.ts b/packages/gittensory-miner/lib/attempt-cli.d.ts index 662966ccfe..bbec4cc6d2 100644 --- a/packages/gittensory-miner/lib/attempt-cli.d.ts +++ b/packages/gittensory-miner/lib/attempt-cli.d.ts @@ -26,7 +26,7 @@ type CommonAttemptResultFields = { }; /** The result runAttempt reports at every real return point, threaded to `options.onResult` (in addition to - * the plain exit-code return runAttempt itself still returns, unchanged, so bin/gittensory-miner.js's own + * the plain exit-code return runAttempt itself still returns, unchanged, so bin/loopover-miner.js's own * `process.exit(exitCode)` usage never breaks) -- the loop orchestrator's real caller for this data. */ export type AttemptCliResult = | (CommonAttemptResultFields & { outcome: "dry_run" }) diff --git a/packages/gittensory-miner/lib/attempt-cli.js b/packages/gittensory-miner/lib/attempt-cli.js index 4b8f110fc6..913579c811 100644 --- a/packages/gittensory-miner/lib/attempt-cli.js +++ b/packages/gittensory-miner/lib/attempt-cli.js @@ -1,4 +1,4 @@ -// CLI dispatch for the real attempt pipeline (#5132, Wave 3.5 -- the final assembly). Wires bin/gittensory-miner.js's +// CLI dispatch for the real attempt pipeline (#5132, Wave 3.5 -- the final assembly). Wires bin/loopover-miner.js's // `attempt` subcommand to real infrastructure end to end: worktree allocation + real git preparation // (worktree-allocator.js + attempt-worktree.js), the four ledgers (claim/event/attempt-log/governor), the // real coding-agent driver (#5131) and slop assessor (#5133), a live SelfReviewContext fetch (#5145), a real @@ -39,7 +39,7 @@ import { loadReputationHistory, recordOwnSubmission } from "./governor-state.js" import { runMinerAttempt } from "./attempt-runner.js"; const ATTEMPT_USAGE = - "Usage: gittensory-miner attempt --miner-login [--base ] [--live] [--dry-run] [--json]"; + "Usage: loopover-miner attempt --miner-login [--base ] [--live] [--dry-run] [--json]"; function parseRepoTarget(value) { const trimmed = typeof value === "string" ? value.trim() : ""; diff --git a/packages/gittensory-miner/lib/calibration-cli.js b/packages/gittensory-miner/lib/calibration-cli.js index abc8567610..0e103ff7f5 100644 --- a/packages/gittensory-miner/lib/calibration-cli.js +++ b/packages/gittensory-miner/lib/calibration-cli.js @@ -1,4 +1,4 @@ -// `gittensory-miner calibration [--json]` (#4849): a read-only report joining the miner's own predicted gate +// `loopover-miner calibration [--json]` (#4849): a read-only report joining the miner's own predicted gate // verdicts (prediction-ledger) with the realized PR outcomes it later observed (event-ledger `pr_outcome` // events), via the pure buildCalibrationReport join. Opens both local stores, maps their rows to the // calibration record shapes, renders, and closes. Never modifies the live scoring/calibration logic. @@ -8,7 +8,7 @@ import { MINER_PR_OUTCOME_EVENT } from "./pr-outcome.js"; import { initPredictionLedger, resolvePredictionLedgerDbPath } from "./prediction-ledger.js"; import { reportCliFailure, describeCliError } from "./cli-error.js"; -const CALIBRATION_USAGE = "Usage: gittensory-miner calibration [--json]"; +const CALIBRATION_USAGE = "Usage: loopover-miner calibration [--json]"; /** Map prediction-ledger rows to predicted-verdict records: the target id becomes a string key and the recorded * prediction verdict is the `conclusion`. */ @@ -57,7 +57,7 @@ function renderReportText(report) { } /** - * Run `gittensory-miner calibration [--json]`. Reads the prediction ledger + PR-outcome events, joins them into a + * Run `loopover-miner calibration [--json]`. Reads the prediction ledger + PR-outcome events, joins them into a * calibration report, and prints it (a JSON dump under `--json`, else a per-project text summary). Returns the * process exit code: 0 on success, 1 on an unknown option. * @param {string[]} [args] diff --git a/packages/gittensory-miner/lib/claim-ledger-cli.js b/packages/gittensory-miner/lib/claim-ledger-cli.js index 0aad188880..1b8aa48de9 100644 --- a/packages/gittensory-miner/lib/claim-ledger-cli.js +++ b/packages/gittensory-miner/lib/claim-ledger-cli.js @@ -2,11 +2,11 @@ import { CLAIM_STATUSES, openClaimLedger } from "./claim-ledger.js"; import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js"; const CLAIM_CLAIM_USAGE = - "Usage: gittensory-miner claim claim [--note ] [--api-base-url ] [--dry-run] [--json]"; + "Usage: loopover-miner claim claim [--note ] [--api-base-url ] [--dry-run] [--json]"; const CLAIM_RELEASE_USAGE = - "Usage: gittensory-miner claim release [--api-base-url ] [--dry-run] [--json]"; + "Usage: loopover-miner claim release [--api-base-url ] [--dry-run] [--json]"; const CLAIM_LIST_USAGE = - "Usage: gittensory-miner claim list [--repo ] [--status active|released|expired] [--json]"; + "Usage: loopover-miner claim list [--repo ] [--status active|released|expired] [--json]"; function parseRepoArg(value, usage) { if (!value) return { error: usage }; diff --git a/packages/gittensory-miner/lib/cli.js b/packages/gittensory-miner/lib/cli.js index 3ca7c3fc8c..d2e77a379d 100644 --- a/packages/gittensory-miner/lib/cli.js +++ b/packages/gittensory-miner/lib/cli.js @@ -9,54 +9,54 @@ export function printHelp(input) { [ input.packageName, "", - "Foundation CLI for the local Gittensory miner runtime.", + "Foundation CLI for the local LoopOver miner runtime.", "", "Usage:", - " gittensory-miner --help", - " gittensory-miner --version", - " gittensory-miner help", - " gittensory-miner version", - " gittensory-miner init [--json] [--verify-token] Bootstrap laptop-mode local SQLite state", - " gittensory-miner init --interactive Guided first-run wizard: prompts for GITHUB_TOKEN + provider, writes a starter .env, then runs doctor", - " gittensory-miner status [--json] Show installed versions + local state paths", - " gittensory-miner doctor [--json] Check this laptop is set up correctly", - " gittensory-miner migrate [--json] Apply pending schema migrations to existing local stores", - " gittensory-miner metrics Print prediction-calibration counters in Prometheus text format", - " gittensory-miner manage status [--json] Show managed PR rows from local portfolio + ledger", - " gittensory-miner manage poll [--branch ] [--dry-run] [--json]", - " gittensory-miner discover [...] [--dry-run] [--json]", - " gittensory-miner discover --search [--dry-run] [--json] Fan out, rank, and enqueue candidates", - " gittensory-miner attempt --miner-login [--base ] [--live] [--dry-run] [--json]", - " gittensory-miner loop [...] --miner-login [--base ] [--live] [--dry-run]", - " gittensory-miner loop --search --miner-login [--max-cycles ] [--cycle-delay-ms ] [--dry-run] [--json]", + " loopover-miner --help", + " loopover-miner --version", + " loopover-miner help", + " loopover-miner version", + " loopover-miner init [--json] [--verify-token] Bootstrap laptop-mode local SQLite state", + " loopover-miner init --interactive Guided first-run wizard: prompts for GITHUB_TOKEN + provider, writes a starter .env, then runs doctor", + " loopover-miner status [--json] Show installed versions + local state paths", + " loopover-miner doctor [--json] Check this laptop is set up correctly", + " loopover-miner migrate [--json] Apply pending schema migrations to existing local stores", + " loopover-miner metrics Print prediction-calibration counters in Prometheus text format", + " loopover-miner manage status [--json] Show managed PR rows from local portfolio + ledger", + " loopover-miner manage poll [--branch ] [--dry-run] [--json]", + " loopover-miner discover [...] [--dry-run] [--json]", + " loopover-miner discover --search [--dry-run] [--json] Fan out, rank, and enqueue candidates", + " loopover-miner attempt --miner-login [--base ] [--live] [--dry-run] [--json]", + " loopover-miner loop [...] --miner-login [--base ] [--live] [--dry-run]", + " loopover-miner loop --search --miner-login [--max-cycles ] [--cycle-delay-ms ] [--dry-run] [--json]", " Autonomous discover->claim->attempt->reenter loop", - " gittensory-miner queue list [--repo ] [--json] List portfolio backlog rows", - " gittensory-miner queue next [--global-wip ] [--per-repo-wip ] [--dry-run] [--json]", + " loopover-miner queue list [--repo ] [--json] List portfolio backlog rows", + " loopover-miner queue next [--global-wip ] [--per-repo-wip ] [--dry-run] [--json]", " Claim the highest-priority queued item, optionally WIP-cap-aware", - " gittensory-miner queue claim-batch [--global-wip ] [--per-repo-wip ] [--dry-run] [--json]", - " gittensory-miner queue metrics Print portfolio-queue counters in Prometheus text format", - " gittensory-miner queue done [--dry-run] [--json]", - " gittensory-miner queue release [--dry-run] [--json] Return a claimed item to the queue", - " gittensory-miner queue requeue [--dry-run] [--json] Put a completed item back on the queue", - " gittensory-miner claim claim [--note ] [--dry-run] [--json]", - " gittensory-miner claim release [--dry-run] [--json]", - " gittensory-miner claim list [--repo ] [--status active|released|expired] [--json]", - " gittensory-miner ledger list [--repo ] [--since ] [--type ] [--json]", - " gittensory-miner ledger metrics Print event-ledger counters in Prometheus text format", - " gittensory-miner plan list [--status pending|running|completed|failed] [--json]", - " gittensory-miner plan show [--json]", - " gittensory-miner governor list [--repo ] [--type allowed|denied|throttled|kill_switch] [--json]", - " gittensory-miner governor pause [--reason ] [--dry-run] [--json] Stop the loop before its next cycle", - " gittensory-miner governor resume [--dry-run] [--json] Let a paused loop continue", - " gittensory-miner governor status [--json] Show whether the governor is paused", - " gittensory-miner governor metrics Print governor rate-limit/cap-usage counters in Prometheus text format", - " gittensory-miner calibration [--json] Report predicted-vs-realized gate accuracy", - " gittensory-miner feasibility [--not-found] [--json]", - " gittensory-miner hooks check --tool --input [--json]", - " gittensory-miner state get [--json]", - " gittensory-miner state set [--dry-run] [--json]", - " gittensory-miner orb export [--enable] [--send] [--dry-run] [--json] Build (and optionally send) the opt-in anonymized telemetry batch", - " gittensory-miner purge --repo [--dry-run] [--json]", + " loopover-miner queue claim-batch [--global-wip ] [--per-repo-wip ] [--dry-run] [--json]", + " loopover-miner queue metrics Print portfolio-queue counters in Prometheus text format", + " loopover-miner queue done [--dry-run] [--json]", + " loopover-miner queue release [--dry-run] [--json] Return a claimed item to the queue", + " loopover-miner queue requeue [--dry-run] [--json] Put a completed item back on the queue", + " loopover-miner claim claim [--note ] [--dry-run] [--json]", + " loopover-miner claim release [--dry-run] [--json]", + " loopover-miner claim list [--repo ] [--status active|released|expired] [--json]", + " loopover-miner ledger list [--repo ] [--since ] [--type ] [--json]", + " loopover-miner ledger metrics Print event-ledger counters in Prometheus text format", + " loopover-miner plan list [--status pending|running|completed|failed] [--json]", + " loopover-miner plan show [--json]", + " loopover-miner governor list [--repo ] [--type allowed|denied|throttled|kill_switch] [--json]", + " loopover-miner governor pause [--reason ] [--dry-run] [--json] Stop the loop before its next cycle", + " loopover-miner governor resume [--dry-run] [--json] Let a paused loop continue", + " loopover-miner governor status [--json] Show whether the governor is paused", + " loopover-miner governor metrics Print governor rate-limit/cap-usage counters in Prometheus text format", + " loopover-miner calibration [--json] Report predicted-vs-realized gate accuracy", + " loopover-miner feasibility [--not-found] [--json]", + " loopover-miner hooks check --tool --input [--json]", + " loopover-miner state get [--json]", + " loopover-miner state set [--dry-run] [--json]", + " loopover-miner orb export [--enable] [--send] [--dry-run] [--json] Build (and optionally send) the opt-in anonymized telemetry batch", + " loopover-miner purge --repo [--dry-run] [--json]", " Right-to-be-forgotten: delete a repo's rows from every local store", "", "Options:", diff --git a/packages/gittensory-miner/lib/deny-check.js b/packages/gittensory-miner/lib/deny-check.js index dc1855c0fa..dda33c14cb 100644 --- a/packages/gittensory-miner/lib/deny-check.js +++ b/packages/gittensory-miner/lib/deny-check.js @@ -2,7 +2,7 @@ import { evaluateDenyHooks } from "./deny-hooks.js"; import { argsWantJson, reportCliFailure } from "./cli-error.js"; const DENY_CHECK_USAGE = - "Usage: gittensory-miner hooks check --tool --input [--json]"; + "Usage: loopover-miner hooks check --tool --input [--json]"; function parseToolInput(raw) { if (raw === undefined) { diff --git a/packages/gittensory-miner/lib/deployment-docs-audit.js b/packages/gittensory-miner/lib/deployment-docs-audit.js index b815a7b03c..94f2b6e7fb 100644 --- a/packages/gittensory-miner/lib/deployment-docs-audit.js +++ b/packages/gittensory-miner/lib/deployment-docs-audit.js @@ -1,14 +1,14 @@ // Docs-accuracy audit for the miner's DEPLOYMENT.md (#5180). Mirrors the self-host docs audit // (apps/gittensory-ui/src/lib/selfhost-docs-audit.ts): parse the deployment doc, then assert every -// LOOPOVER_MINER_* / MINER_* env var, repo-relative file path, and `gittensory-miner ` +// LOOPOVER_MINER_* / MINER_* env var, repo-relative file path, and `loopover-miner ` // it documents still exists under packages/gittensory-miner/**. A rename or move that leaves the doc // stale then fails CI with a message naming the exact stale claim, instead of misleading operators. /** The miner's own env-var namespace: LOOPOVER_MINER_* and the shorter MINER_* aliases it reads. */ const ENV_VAR_PATTERN = /\b(?:LOOPOVER_MINER|MINER)_[A-Z0-9_]+\b/g; -/** `gittensory-miner ` CLI invocations, excluding the `@loopover/miner` package spelling. */ -const SUBCOMMAND_PATTERN = /(?` CLI invocations, excluding the `@loopover/miner` package spelling. */ +const SUBCOMMAND_PATTERN = /(?` subcommands DEPLOYMENT.md documents. */ +/** Sorted, de-duplicated `loopover-miner ` subcommands DEPLOYMENT.md documents. */ export function extractSubcommandClaims(markdown) { const commands = new Set(); for (const match of markdown.matchAll(SUBCOMMAND_PATTERN)) { @@ -96,7 +96,7 @@ export function auditDeploymentDocs(claims, reality) { for (const command of claims.subcommands) { if (!reality.isRegisteredCommand(command)) { failures.push( - `CLI subcommand "gittensory-miner ${command}" is documented in DEPLOYMENT.md but is not registered in the CLI command table`, + `CLI subcommand "loopover-miner ${command}" is documented in DEPLOYMENT.md but is not registered in the CLI command table`, ); } } diff --git a/packages/gittensory-miner/lib/discover-cli.js b/packages/gittensory-miner/lib/discover-cli.js index 5c09e17797..77f5430cbf 100644 --- a/packages/gittensory-miner/lib/discover-cli.js +++ b/packages/gittensory-miner/lib/discover-cli.js @@ -14,7 +14,7 @@ import { initRankedCandidatesStore } from "./ranked-candidates.js"; import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js"; const DISCOVER_USAGE = - "Usage: gittensory-miner discover [...] | --search [--dry-run] [--json] [--api-base-url ] [--token-env ]"; + "Usage: loopover-miner discover [...] | --search [--dry-run] [--json] [--api-base-url ] [--token-env ]"; const MAX_DISCOVER_TITLE_DISPLAY_LENGTH = 240; const OSC_SEQUENCE_PATTERN = /\u001b\][\s\S]*?(?:\u0007|\u001b\\)/g; diff --git a/packages/gittensory-miner/lib/event-ledger-cli.js b/packages/gittensory-miner/lib/event-ledger-cli.js index f82aa52834..c45e2ff793 100644 --- a/packages/gittensory-miner/lib/event-ledger-cli.js +++ b/packages/gittensory-miner/lib/event-ledger-cli.js @@ -2,7 +2,7 @@ import { initEventLedger } from "./event-ledger.js"; import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js"; const LEDGER_LIST_USAGE = - "Usage: gittensory-miner ledger list [--repo ] [--since ] [--type ] [--json]"; + "Usage: loopover-miner ledger list [--repo ] [--since ] [--type ] [--json]"; function parseRepoArg(value, usage) { if (!value) return { error: usage }; @@ -165,7 +165,7 @@ export function renderLedgerTable(events) { return [header, ...lines].join("\n"); } -const EVENT_LEDGER_METRICS_USAGE = "Usage: gittensory-miner ledger metrics"; +const EVENT_LEDGER_METRICS_USAGE = "Usage: loopover-miner ledger metrics"; // Prometheus metric name for the per-type event-ledger counter. Mirrors the `loopover_miner_*_total` naming and // the HELP/TYPE/label conventions of the engine's renderMinerPredictionMetrics diff --git a/packages/gittensory-miner/lib/feasibility-cli.js b/packages/gittensory-miner/lib/feasibility-cli.js index 06cfd76757..24f96d8d21 100644 --- a/packages/gittensory-miner/lib/feasibility-cli.js +++ b/packages/gittensory-miner/lib/feasibility-cli.js @@ -9,7 +9,7 @@ const DUPLICATE_CLUSTER_RISKS = ["none", "low", "medium", "high"]; const ISSUE_STATUSES = ["ready", "needs_proof", "hold", "do_not_use", "duplicate", "invalid", "missing"]; const FEASIBILITY_USAGE = - "Usage: gittensory-miner feasibility [--not-found] [--json]\n" + + "Usage: loopover-miner feasibility [--not-found] [--json]\n" + ` claimStatus: ${CLAIM_STATUSES.join("|")}\n` + ` duplicateClusterRisk: ${DUPLICATE_CLUSTER_RISKS.join("|")}\n` + ` issueStatus: ${ISSUE_STATUSES.join("|")}`; diff --git a/packages/gittensory-miner/lib/governor-ledger-cli.js b/packages/gittensory-miner/lib/governor-ledger-cli.js index 872654443d..95aef0363a 100644 --- a/packages/gittensory-miner/lib/governor-ledger-cli.js +++ b/packages/gittensory-miner/lib/governor-ledger-cli.js @@ -12,14 +12,14 @@ const GOVERNOR_LEDGER_EVENT_TYPES = Object.freeze([ ]); const GOVERNOR_LIST_USAGE = - "Usage: gittensory-miner governor list [--repo ] [--type allowed|denied|throttled|kill_switch] [--json]"; + "Usage: loopover-miner governor list [--repo ] [--type allowed|denied|throttled|kill_switch] [--json]"; const GOVERNOR_SUBCOMMAND_USAGE = [ GOVERNOR_LIST_USAGE, - " gittensory-miner governor pause [--reason ] [--json]", - " gittensory-miner governor resume [--json]", - " gittensory-miner governor status [--json]", - " gittensory-miner governor metrics", + " loopover-miner governor pause [--reason ] [--json]", + " loopover-miner governor resume [--json]", + " loopover-miner governor status [--json]", + " loopover-miner governor metrics", ].join("\n"); function parseRepoArg(value, usage) { diff --git a/packages/gittensory-miner/lib/governor-metrics-cli.js b/packages/gittensory-miner/lib/governor-metrics-cli.js index 77eeacefa3..194de79c06 100644 --- a/packages/gittensory-miner/lib/governor-metrics-cli.js +++ b/packages/gittensory-miner/lib/governor-metrics-cli.js @@ -24,7 +24,7 @@ import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js // pair it with here. Using the fleet-wide DEFAULT_AMS_POLICY_SPEC.capLimits is the same approximation // loop-cli.js itself already makes for any repo without its own override. -const GOVERNOR_METRICS_USAGE = "Usage: gittensory-miner governor metrics"; +const GOVERNOR_METRICS_USAGE = "Usage: loopover-miner governor metrics"; export const GOVERNOR_RATE_LIMIT_REMAINING_RATIO = "loopover_miner_governor_rate_limit_remaining_ratio"; export const GOVERNOR_CAP_USAGE_RATIO = "loopover_miner_governor_cap_usage_ratio"; diff --git a/packages/gittensory-miner/lib/governor-pause-cli.js b/packages/gittensory-miner/lib/governor-pause-cli.js index 02bc248b55..05ee172618 100644 --- a/packages/gittensory-miner/lib/governor-pause-cli.js +++ b/packages/gittensory-miner/lib/governor-pause-cli.js @@ -8,9 +8,9 @@ import { openGovernorState } from "./governor-state.js"; -const GOVERNOR_PAUSE_USAGE = "Usage: gittensory-miner governor pause [--reason ] [--dry-run] [--json]"; -const GOVERNOR_RESUME_USAGE = "Usage: gittensory-miner governor resume [--dry-run] [--json]"; -const GOVERNOR_STATUS_USAGE = "Usage: gittensory-miner governor status [--json]"; +const GOVERNOR_PAUSE_USAGE = "Usage: loopover-miner governor pause [--reason ] [--dry-run] [--json]"; +const GOVERNOR_RESUME_USAGE = "Usage: loopover-miner governor resume [--dry-run] [--json]"; +const GOVERNOR_STATUS_USAGE = "Usage: loopover-miner governor status [--json]"; export function parseGovernorPauseArgs(args) { const options = { json: false, dryRun: false, reason: null }; diff --git a/packages/gittensory-miner/lib/loop-cli.js b/packages/gittensory-miner/lib/loop-cli.js index c1edb03db5..ecb53e1f65 100644 --- a/packages/gittensory-miner/lib/loop-cli.js +++ b/packages/gittensory-miner/lib/loop-cli.js @@ -43,7 +43,7 @@ import { parsePrNumberFromExecResult } from "./pr-number-parse.js"; import { DEFAULT_AMS_POLICY_SPEC } from "@loopover/engine"; const LOOP_USAGE = - "Usage: gittensory-miner loop [...] | --search --miner-login [--base ] [--live] [--dry-run] [--max-cycles ] [--cycle-delay-ms ] [--json]"; + "Usage: loopover-miner loop [...] | --search --miner-login [--base ] [--live] [--dry-run] [--max-cycles ] [--cycle-delay-ms ] [--json]"; const DEFAULT_CYCLE_DELAY_MS = 60_000; const ISSUE_IDENTIFIER_PATTERN = /^issue:(\d+)$/; @@ -287,7 +287,7 @@ export async function runLoop(args, options = {}) { // Checked BEFORE any work at all -- including the very first discovery call -- so an already-active kill // switch OR an already-active pause (#4851) halts the loop without ever touching GitHub or the queue. The // pause flag is real, persisted, operator/governor-writable state on governorState (toggled via - // `gittensory-miner governor pause`/`resume`) -- unlike the kill switch, a paused run resumes simply by being + // `loopover-miner governor pause`/`resume`) -- unlike the kill switch, a paused run resumes simply by being // re-invoked: every piece of per-cycle state this loop reads (portfolioQueue, runState, governorState's own // cap usage) is already durable, so clearing the flag and restarting continues exactly where it left off. const initialKillSwitch = checkKillSwitchFn({ env }); diff --git a/packages/gittensory-miner/lib/manage-poll.js b/packages/gittensory-miner/lib/manage-poll.js index 792b98f748..d750e4f918 100644 --- a/packages/gittensory-miner/lib/manage-poll.js +++ b/packages/gittensory-miner/lib/manage-poll.js @@ -8,7 +8,7 @@ import { initPortfolioQueueStore } from "./portfolio-queue.js"; import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js"; const MANAGE_POLL_USAGE = - "Usage: gittensory-miner manage poll [--branch ] [--dry-run] [--json]"; + "Usage: loopover-miner manage poll [--branch ] [--dry-run] [--json]"; function parseRepoArg(value, usage) { if (!value) return { error: usage }; diff --git a/packages/gittensory-miner/lib/manage-status.js b/packages/gittensory-miner/lib/manage-status.js index e3c156dbf2..3101cadb40 100644 --- a/packages/gittensory-miner/lib/manage-status.js +++ b/packages/gittensory-miner/lib/manage-status.js @@ -205,7 +205,7 @@ export function parseManageStatusArgs(args = []) { for (const token of args) { if (token === "--json") continue; if (token.startsWith("-")) return { error: `Unknown option: ${token}` }; - return { error: "Usage: gittensory-miner manage status [--json]" }; + return { error: "Usage: loopover-miner manage status [--json]" }; } return { json: args.includes("--json") }; } diff --git a/packages/gittensory-miner/lib/metrics-cli.js b/packages/gittensory-miner/lib/metrics-cli.js index 5c46a596be..1aaae50ac2 100644 --- a/packages/gittensory-miner/lib/metrics-cli.js +++ b/packages/gittensory-miner/lib/metrics-cli.js @@ -8,7 +8,7 @@ import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js // reads the local prediction ledger and feeds it in, never touching the renderer itself. Strictly local + offline: // no network, no writes. -const METRICS_USAGE = "Usage: gittensory-miner metrics"; +const METRICS_USAGE = "Usage: loopover-miner metrics"; /** * Project prediction-ledger rows onto the engine renderer's metric-row shape -- the predicted `conclusion` only. diff --git a/packages/gittensory-miner/lib/miner-goal-spec.js b/packages/gittensory-miner/lib/miner-goal-spec.js index a61b1d169e..f097121547 100644 --- a/packages/gittensory-miner/lib/miner-goal-spec.js +++ b/packages/gittensory-miner/lib/miner-goal-spec.js @@ -12,7 +12,7 @@ const MAX_MINER_GOAL_SPEC_BYTES = 32_768; // attempt-cli.js flow) -- no extra network round trip needed for a file that's already sitting in the // worktree. -// Same convention as packages/gittensory-mcp/bin/gittensory-mcp.js's readCliTextFile: O_NOFOLLOW on open +// Same convention as packages/gittensory-mcp/bin/loopover-mcp.js's readCliTextFile: O_NOFOLLOW on open // atomically rejects a symlinked path (no separate pre-open lstat -- that would be a check-then-open race, since // a symlink can be swapped in between the lstat and the open). Bounds the READ itself, not just fstat's // reported size, since a regular file can still grow between fstatSync and the read below. diff --git a/packages/gittensory-miner/lib/orb-export.js b/packages/gittensory-miner/lib/orb-export.js index 9bb7d662d6..a4cce7c4bd 100644 --- a/packages/gittensory-miner/lib/orb-export.js +++ b/packages/gittensory-miner/lib/orb-export.js @@ -200,7 +200,7 @@ export async function sendAmsExportBatch({ batch, secret, collectorUrl = resolve return { sent: batch.length }; } -const ORB_EXPORT_USAGE = "Usage: gittensory-miner orb export [--enable] [--send] [--dry-run] [--json]"; +const ORB_EXPORT_USAGE = "Usage: loopover-miner orb export [--enable] [--send] [--dry-run] [--json]"; export function parseOrbExportArgs(args) { const options = { json: false, enable: false, send: false, dryRun: false }; diff --git a/packages/gittensory-miner/lib/plan-store-cli.js b/packages/gittensory-miner/lib/plan-store-cli.js index caa14cc275..11134574be 100644 --- a/packages/gittensory-miner/lib/plan-store-cli.js +++ b/packages/gittensory-miner/lib/plan-store-cli.js @@ -2,8 +2,8 @@ import { PLAN_STATUSES, openPlanStore } from "./plan-store.js"; import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js"; const PLAN_LIST_USAGE = - "Usage: gittensory-miner plan list [--status pending|running|completed|failed] [--json]"; -const PLAN_SHOW_USAGE = "Usage: gittensory-miner plan show [--json]"; + "Usage: loopover-miner plan list [--status pending|running|completed|failed] [--json]"; +const PLAN_SHOW_USAGE = "Usage: loopover-miner plan show [--json]"; function parseJsonFlag(args) { const options = { json: false }; diff --git a/packages/gittensory-miner/lib/portfolio-dashboard.js b/packages/gittensory-miner/lib/portfolio-dashboard.js index 0789943cfb..5082c491dd 100644 --- a/packages/gittensory-miner/lib/portfolio-dashboard.js +++ b/packages/gittensory-miner/lib/portfolio-dashboard.js @@ -82,12 +82,12 @@ export function parsePortfolioDashboardArgs(args = []) { for (const token of args) { if (token === "--json") continue; if (token.startsWith("-")) return { error: `Unknown option: ${token}` }; - return { error: "Usage: gittensory-miner queue dashboard [--json]" }; + return { error: "Usage: loopover-miner queue dashboard [--json]" }; } return { json: args.includes("--json") }; } -/** CLI glue for `gittensory-miner queue dashboard [--json]` (mirrors manage-status.js's `runManageStatus`). */ +/** CLI glue for `loopover-miner queue dashboard [--json]` (mirrors manage-status.js's `runManageStatus`). */ export function runPortfolioDashboard(args = [], options = {}) { const parsed = parsePortfolioDashboardArgs(args); if ("error" in parsed) { diff --git a/packages/gittensory-miner/lib/portfolio-queue-cli.js b/packages/gittensory-miner/lib/portfolio-queue-cli.js index 115d1dbdaa..336f1e5820 100644 --- a/packages/gittensory-miner/lib/portfolio-queue-cli.js +++ b/packages/gittensory-miner/lib/portfolio-queue-cli.js @@ -3,17 +3,17 @@ import { initPortfolioQueueManager } from "./portfolio-queue-manager.js"; import { runPortfolioDashboard } from "./portfolio-dashboard.js"; import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js"; -const QUEUE_LIST_USAGE = "Usage: gittensory-miner queue list [--repo ] [--json]"; +const QUEUE_LIST_USAGE = "Usage: loopover-miner queue list [--repo ] [--json]"; const QUEUE_NEXT_USAGE = - "Usage: gittensory-miner queue next [--global-wip ] [--per-repo-wip ] [--dry-run] [--json]"; + "Usage: loopover-miner queue next [--global-wip ] [--per-repo-wip ] [--dry-run] [--json]"; const QUEUE_DONE_USAGE = - "Usage: gittensory-miner queue done [--api-base-url ] [--dry-run] [--json]"; + "Usage: loopover-miner queue done [--api-base-url ] [--dry-run] [--json]"; const QUEUE_RELEASE_USAGE = - "Usage: gittensory-miner queue release [--api-base-url ] [--dry-run] [--json]"; + "Usage: loopover-miner queue release [--api-base-url ] [--dry-run] [--json]"; const QUEUE_REQUEUE_USAGE = - "Usage: gittensory-miner queue requeue [--api-base-url ] [--dry-run] [--json]"; + "Usage: loopover-miner queue requeue [--api-base-url ] [--dry-run] [--json]"; const QUEUE_CLAIM_BATCH_USAGE = - "Usage: gittensory-miner queue claim-batch [--global-wip ] [--per-repo-wip ] [--dry-run] [--json]"; + "Usage: loopover-miner queue claim-batch [--global-wip ] [--per-repo-wip ] [--dry-run] [--json]"; function parseRepoArg(value, usage) { if (!value) return { error: usage }; @@ -497,7 +497,7 @@ export function runQueueClaimBatch(args, options = {}) { } } -const QUEUE_METRICS_USAGE = "Usage: gittensory-miner queue metrics"; +const QUEUE_METRICS_USAGE = "Usage: loopover-miner queue metrics"; // Prometheus metric names for the portfolio-queue gauges (#5186). Mirrors the `loopover_miner_*` naming and // HELP/TYPE/label conventions of event-ledger-cli.js's renderEventLedgerMetrics / the engine's diff --git a/packages/gittensory-miner/lib/purge-cli.js b/packages/gittensory-miner/lib/purge-cli.js index 81c1e7aa59..77a8227439 100644 --- a/packages/gittensory-miner/lib/purge-cli.js +++ b/packages/gittensory-miner/lib/purge-cli.js @@ -1,4 +1,4 @@ -// `gittensory-miner purge` (#5564): an explicit, operator-invoked right-to-be-forgotten path across the local +// `loopover-miner purge` (#5564): an explicit, operator-invoked right-to-be-forgotten path across the local // ledgers. Deletes every row for one repo from the four stores that have a real `repoColumn` (claim-ledger, // event-ledger, governor-ledger, prediction-ledger), via each store's own `purgeByRepo` method (which reuses // `store-maintenance.js`'s shared, identifier-guarded `purgeStoreByRepo`). `attempt-log.js` is deliberately @@ -25,7 +25,7 @@ import { describeError, } from "./store-maintenance.js"; -const PURGE_USAGE = "Usage: gittensory-miner purge --repo [--dry-run] [--json]"; +const PURGE_USAGE = "Usage: loopover-miner purge --repo [--dry-run] [--json]"; export const ATTEMPT_LOG_NOT_PURGEABLE_NOTE = "attempt-log has no repoFullName column and cannot be purged by repo (#5564); its rows are unaffected"; diff --git a/packages/gittensory-miner/lib/run-state-cli.js b/packages/gittensory-miner/lib/run-state-cli.js index e86b094d12..67a989bc3e 100644 --- a/packages/gittensory-miner/lib/run-state-cli.js +++ b/packages/gittensory-miner/lib/run-state-cli.js @@ -1,9 +1,9 @@ import { RUN_STATES, getRunState, setRunState } from "./run-state.js"; import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js"; -const STATE_GET_USAGE = "Usage: gittensory-miner state get [--api-base-url ] [--json]"; +const STATE_GET_USAGE = "Usage: loopover-miner state get [--api-base-url ] [--json]"; const STATE_SET_USAGE = - "Usage: gittensory-miner state set [--api-base-url ] [--dry-run] [--json]"; + "Usage: loopover-miner state set [--api-base-url ] [--dry-run] [--json]"; const allowedRunStates = new Set(RUN_STATES); diff --git a/packages/gittensory-miner/lib/update-check.js b/packages/gittensory-miner/lib/update-check.js index c918dc4231..a3dde5b0ec 100644 --- a/packages/gittensory-miner/lib/update-check.js +++ b/packages/gittensory-miner/lib/update-check.js @@ -121,7 +121,7 @@ export async function fetchLatestPackageVersion(input) { } // Non-blocking startup nudge: prints one upgrade line when local is behind npm latest. -// Mirrors packages/gittensory-mcp/bin/gittensory-mcp.js packageVersion/npmRegistryUrl/upgradeCommand (#2331). +// Mirrors packages/gittensory-mcp/bin/loopover-mcp.js packageVersion/npmRegistryUrl/upgradeCommand (#2331). export async function maybePrintUpdateNudge(input) { try { const latestVersion = await fetchLatestPackageVersion(input); diff --git a/packages/gittensory-miner/package.json b/packages/gittensory-miner/package.json index d52294aab5..0956e65d91 100644 --- a/packages/gittensory-miner/package.json +++ b/packages/gittensory-miner/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "license": "AGPL-3.0-only", "type": "module", - "description": "Foundation CLI for the local Gittensory miner runtime.", + "description": "Foundation CLI for the local LoopOver miner runtime.", "repository": { "type": "git", "url": "git+https://github.com/JSONbored/gittensory.git", @@ -24,8 +24,8 @@ "access": "public" }, "bin": { - "gittensory-miner": "bin/gittensory-miner.js", - "gittensory-miner-mcp": "bin/gittensory-miner-mcp.js" + "loopover-miner": "bin/loopover-miner.js", + "loopover-miner-mcp": "bin/loopover-miner-mcp.js" }, "files": [ "bin", @@ -38,7 +38,7 @@ ], "scripts": { "benchmark": "node scripts/benchmark.mjs", - "build": "node --check bin/gittensory-miner.js && node --check bin/gittensory-miner-mcp.js && node --check lib/ams-policy.js && node --check lib/attempt-cli.js && node --check lib/attempt-input-builder.js && node --check lib/attempt-log.js && node --check lib/attempt-runner.js && node --check lib/attempt-worktree.js && node --check lib/calibration-run.js && node --check lib/calibration-types.js && node --check lib/calibration.js && node --check lib/ci-poller.js && node --check lib/claim-adjudication.js && node --check lib/claim-conflict-resolver.js && node --check lib/claim-ledger-cli.js && node --check lib/claim-ledger-expiry.js && node --check lib/claim-ledger.js && node --check lib/cli.js && node --check lib/coding-agent-construction.js && node --check lib/coding-agent-house-rules.js && node --check lib/coding-task-spec.js && node --check lib/deny-check.js && node --check lib/deny-hook-synthesis.js && node --check lib/deny-hooks.js && node --check lib/deployment-docs-audit.js && node --check lib/discover-cli.js && node --check lib/event-ledger-cli.js && node --check lib/event-ledger.js && node --check lib/execute-local-write.js && node --check lib/feasibility-cli.js && node --check lib/governor-action-mode.js && node --check lib/governor-chokepoint-persisted.js && node --check lib/governor-chokepoint.js && node --check lib/governor-kill-switch.js && node --check lib/governor-ledger-cli.js && node --check lib/governor-ledger.js && node --check lib/governor-metrics-cli.js && node --check lib/governor-open-pr.js && node --check lib/governor-pause-cli.js && node --check lib/governor-run-halt.js && node --check lib/governor-state.js && node --check lib/governor-write-rate-limit.js && node --check lib/harness-submission-trigger.js && node --check lib/init-wizard.js && node --check lib/laptop-init.js && node --check lib/live-issue-snapshot.js && node --check lib/local-store.js && node --check lib/logger.js && node --check lib/loop-cli.js && node --check lib/loop-closure.js && node --check lib/loop-reentry.js && node --check lib/manage-poll.js && node --check lib/manage-status.js && node --check lib/metrics-cli.js && node --check lib/miner-goal-spec.js && node --check lib/opportunity-fanout.js && node --check lib/opportunity-ranker.js && node --check lib/orb-export.js && node --check lib/plan-store-cli.js && node --check lib/plan-store.js && node --check lib/policy-doc-cache.js && node --check lib/policy-verdict-cache.js && node --check lib/portfolio-dashboard.js && node --check lib/portfolio-discovery.js && node --check lib/portfolio-queue-cli.js && node --check lib/portfolio-queue-manager.js && node --check lib/portfolio-queue.js && node --check lib/portfolio-queue-expiry.js && node --check lib/pr-disposition-poller.js && node --check lib/pr-number-parse.js && node --check lib/pr-outcome.js && node --check lib/prediction-ledger.js && node --check lib/pretooluse-hook.js && node --check lib/purge-cli.js && node --check lib/ranked-candidates.js && node --check lib/rejection-signal.js && node --check lib/rejection-state-machine.js && node --check lib/rejection-templates.js && node --check lib/replay-objective-anchor.js && node --check lib/replay-snapshot.js && node --check lib/replay-task-generation.js && node --check lib/repo-clone.js && node --check lib/run-state-cli.js && node --check lib/run-state.js && node --check lib/self-review-context.js && node --check lib/slop-assessment.js && node --check lib/stack-detection.js && node --check lib/status.js && node --check lib/submission-freshness-check.js && node --check lib/update-check.js && node --check lib/version.js && node --check lib/worktree-allocator.js" + "build": "node --check bin/loopover-miner.js && node --check bin/loopover-miner-mcp.js && node --check lib/ams-policy.js && node --check lib/attempt-cli.js && node --check lib/attempt-input-builder.js && node --check lib/attempt-log.js && node --check lib/attempt-runner.js && node --check lib/attempt-worktree.js && node --check lib/calibration-run.js && node --check lib/calibration-types.js && node --check lib/calibration.js && node --check lib/ci-poller.js && node --check lib/claim-adjudication.js && node --check lib/claim-conflict-resolver.js && node --check lib/claim-ledger-cli.js && node --check lib/claim-ledger-expiry.js && node --check lib/claim-ledger.js && node --check lib/cli.js && node --check lib/coding-agent-construction.js && node --check lib/coding-agent-house-rules.js && node --check lib/coding-task-spec.js && node --check lib/deny-check.js && node --check lib/deny-hook-synthesis.js && node --check lib/deny-hooks.js && node --check lib/deployment-docs-audit.js && node --check lib/discover-cli.js && node --check lib/event-ledger-cli.js && node --check lib/event-ledger.js && node --check lib/execute-local-write.js && node --check lib/feasibility-cli.js && node --check lib/governor-action-mode.js && node --check lib/governor-chokepoint-persisted.js && node --check lib/governor-chokepoint.js && node --check lib/governor-kill-switch.js && node --check lib/governor-ledger-cli.js && node --check lib/governor-ledger.js && node --check lib/governor-metrics-cli.js && node --check lib/governor-open-pr.js && node --check lib/governor-pause-cli.js && node --check lib/governor-run-halt.js && node --check lib/governor-state.js && node --check lib/governor-write-rate-limit.js && node --check lib/harness-submission-trigger.js && node --check lib/init-wizard.js && node --check lib/laptop-init.js && node --check lib/live-issue-snapshot.js && node --check lib/local-store.js && node --check lib/logger.js && node --check lib/loop-cli.js && node --check lib/loop-closure.js && node --check lib/loop-reentry.js && node --check lib/manage-poll.js && node --check lib/manage-status.js && node --check lib/metrics-cli.js && node --check lib/miner-goal-spec.js && node --check lib/opportunity-fanout.js && node --check lib/opportunity-ranker.js && node --check lib/orb-export.js && node --check lib/plan-store-cli.js && node --check lib/plan-store.js && node --check lib/policy-doc-cache.js && node --check lib/policy-verdict-cache.js && node --check lib/portfolio-dashboard.js && node --check lib/portfolio-discovery.js && node --check lib/portfolio-queue-cli.js && node --check lib/portfolio-queue-manager.js && node --check lib/portfolio-queue.js && node --check lib/portfolio-queue-expiry.js && node --check lib/pr-disposition-poller.js && node --check lib/pr-number-parse.js && node --check lib/pr-outcome.js && node --check lib/prediction-ledger.js && node --check lib/pretooluse-hook.js && node --check lib/purge-cli.js && node --check lib/ranked-candidates.js && node --check lib/rejection-signal.js && node --check lib/rejection-state-machine.js && node --check lib/rejection-templates.js && node --check lib/replay-objective-anchor.js && node --check lib/replay-snapshot.js && node --check lib/replay-task-generation.js && node --check lib/repo-clone.js && node --check lib/run-state-cli.js && node --check lib/run-state.js && node --check lib/self-review-context.js && node --check lib/slop-assessment.js && node --check lib/stack-detection.js && node --check lib/status.js && node --check lib/submission-freshness-check.js && node --check lib/update-check.js && node --check lib/version.js && node --check lib/worktree-allocator.js" }, "dependencies": { "@loopover/engine": "*", diff --git a/packages/gittensory-miner/terraform/README.md b/packages/gittensory-miner/terraform/README.md index 38463f9f21..411d78ad4c 100644 --- a/packages/gittensory-miner/terraform/README.md +++ b/packages/gittensory-miner/terraform/README.md @@ -1,7 +1,7 @@ # Fleet-mode AMS host — Terraform starter module A minimal, self-contained Terraform module that provisions a dedicated **fleet-mode** host for the Autonomous -Miner System (AMS / `gittensory-miner`) on Hetzner Cloud — for operators who want the miner running as an +Miner System (AMS / `loopover-miner`) on Hetzner Cloud — for operators who want the miner running as an always-on CLI worker instead of in laptop mode. It stands up a single firewalled VM with Docker pre-installed and a persistent volume mounted at `/data/miner`, diff --git a/scripts/check-mcp-package.mjs b/scripts/check-mcp-package.mjs index 1d97263e2b..f689f25a34 100644 --- a/scripts/check-mcp-package.mjs +++ b/scripts/check-mcp-package.mjs @@ -14,7 +14,7 @@ if (result.status !== 0) { const [pack] = JSON.parse(result.stdout); const files = pack.files.map((file) => file.path).sort(); -const allowed = [/^bin\/gittensory-mcp\.js$/, /^lib\/local-branch\.js$/, /^lib\/format-table\.js$/, /^scripts\/gittensor-score-preview\.(mjs|py)$/, /^package\.json$/, /^README\.md$/, /^CHANGELOG\.md$/, /^LICENSE$/]; +const allowed = [/^bin\/loopover-mcp\.js$/, /^lib\/local-branch\.js$/, /^lib\/format-table\.js$/, /^scripts\/gittensor-score-preview\.(mjs|py)$/, /^package\.json$/, /^README\.md$/, /^CHANGELOG\.md$/, /^LICENSE$/]; const forbiddenPath = /(^|\/)(\.dev\.vars|\.env|\.npmrc|.*\.pem|.*private.*key.*|.*secret.*)$/i; const forbiddenContent = /(BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY|github_pat_[A-Za-z0-9_]+|gh[pousr]_[A-Za-z0-9_]+|gts_[0-9a-f]{64}|[A-Z0-9_]*(TOKEN|SECRET|PRIVATE_KEY)=)/; const stalePackageText = /(private beta|zeronode\.workers\.dev|preview URL)/i; diff --git a/scripts/check-miner-package.mjs b/scripts/check-miner-package.mjs index 34c75490c7..ff61032163 100644 --- a/scripts/check-miner-package.mjs +++ b/scripts/check-miner-package.mjs @@ -6,8 +6,8 @@ import { fileURLToPath } from "node:url"; import { FORBIDDEN_CONTENT } from "./forbidden-content.mjs"; const ALLOWED = [ - /^bin\/gittensory-miner\.js$/, - /^bin\/gittensory-miner-mcp\.(js|d\.ts)$/, + /^bin\/loopover-miner\.js$/, + /^bin\/loopover-miner-mcp\.(js|d\.ts)$/, /^lib\/[a-z0-9-]+\.(js|d\.ts)$/, /^package\.json$/, /^README\.md$/, @@ -19,7 +19,7 @@ const ALLOWED = [ /^schema\/[a-z0-9.-]+\.json$/, ]; const REQUIRED = [ - "bin/gittensory-miner.js", + "bin/loopover-miner.js", "package.json", // The operational files #4874 shipped — asserted present so they can never silently drop out of the package again. "DEPLOYMENT.md", diff --git a/scripts/mcp-release-candidate-core.mjs b/scripts/mcp-release-candidate-core.mjs index 7de99cf004..45931c64ca 100644 --- a/scripts/mcp-release-candidate-core.mjs +++ b/scripts/mcp-release-candidate-core.mjs @@ -17,7 +17,7 @@ export const RELEASE_TAG_PATTERN = /^mcp-v(\d+)\.(\d+)\.(\d+)$/; // Kept in sync with scripts/check-mcp-package.mjs and the publish workflow tarball gate. const ALLOWED_FILE_PATTERNS = [ - /^bin\/gittensory-mcp\.js$/, + /^bin\/loopover-mcp\.js$/, /^lib\/local-branch\.js$/, /^scripts\/gittensor-score-preview\.(mjs|py)$/, /^package\.json$/, @@ -170,7 +170,7 @@ const REMEDIATION = { tag_version_mismatch: "Align the tag with packages/gittensory-mcp/package.json (and the CLI packageVersion) before tagging.", changelog_section_missing: "Run npm run changelog:mcp and commit the generated mcp-v changelog section.", tarball_unsafe: "Remove unexpected or secret-bearing files from the package and rerun the dry-run.", - cli_smoke_failed: "Fix the packed CLI so `gittensory-mcp --help` exits cleanly before tagging.", + cli_smoke_failed: "Fix the packed CLI so `loopover-mcp --help` exits cleanly before tagging.", publish_token_risk: "Restore tokenless trusted publishing (id-token: write + --provenance, no npm token) in publish-mcp.yml.", }; diff --git a/src/db/repositories.ts b/src/db/repositories.ts index 0e163dd74d..35ccc972cd 100644 --- a/src/db/repositories.ts +++ b/src/db/repositories.ts @@ -2378,7 +2378,7 @@ export async function summarizeMcpCompatibilityAdoption( ): Promise { const db = getDb(env.DB); const limit = Math.max(1, Math.min(MCP_COMPATIBILITY_ADOPTION_SCAN_LIMIT, Math.round(options.limit ?? MCP_COMPATIBILITY_ADOPTION_SCAN_LIMIT))); - const mcpClientWhere = or(eq(productUsageEvents.surface, "mcp"), eq(productUsageEvents.clientName, "gittensory-mcp"), eq(productUsageEvents.clientName, "gittensory-mcp-cli")); + const mcpClientWhere = or(eq(productUsageEvents.surface, "mcp"), eq(productUsageEvents.clientName, "loopover-mcp"), eq(productUsageEvents.clientName, "loopover-mcp-cli")); const baseWhere = sinceIso ? and(mcpClientWhere, gte(productUsageEvents.occurredAt, sinceIso)) : mcpClientWhere; const [totalRow] = await db.select({ count: sql`count(*)` }).from(productUsageEvents).where(baseWhere); const [activeActorRow] = await db diff --git a/src/services/client-telemetry.ts b/src/services/client-telemetry.ts index 17edf8af88..4d7d3dd0b2 100644 --- a/src/services/client-telemetry.ts +++ b/src/services/client-telemetry.ts @@ -26,10 +26,10 @@ export type McpClientTelemetry = { }; export function buildMcpClientTelemetry(headers: Headers, options: ClientTelemetryOptions = {}): McpClientTelemetry | null { - const packageName = safePackageHeader(headers.get("x-gittensory-mcp-package")); - const packageVersion = safeVersionHeader(headers.get("x-gittensory-mcp-version")); - const explicitClientName = safeClientHeader(headers.get("x-gittensory-mcp-client")); - const explicitClientVersion = safeVersionHeader(headers.get("x-gittensory-mcp-client-version")); + const packageName = safePackageHeader(headers.get("x-loopover-mcp-package")); + const packageVersion = safeVersionHeader(headers.get("x-loopover-mcp-version")); + const explicitClientName = safeClientHeader(headers.get("x-loopover-mcp-client")); + const explicitClientVersion = safeVersionHeader(headers.get("x-loopover-mcp-client-version")); const protocolVersion = safeProtocolHeader(headers.get("mcp-protocol-version")); const hasGittensoryHeader = Boolean(packageName ?? packageVersion ?? explicitClientName ?? explicitClientVersion); if (options.requireGittensoryHeader && !hasGittensoryHeader) return null; @@ -53,7 +53,7 @@ export function buildMcpClientTelemetry(headers: Headers, options: ClientTelemet function clientNameFromPackage(packageName: string | undefined): string | undefined { if (!packageName) return undefined; - if (packageName === GITTENSORY_MCP_PACKAGE_NAME) return "gittensory-mcp"; + if (packageName === GITTENSORY_MCP_PACKAGE_NAME) return "loopover-mcp"; const tail = packageName.split("/").at(-1); return safeClientHeader(tail); } diff --git a/test/integration/api.test.ts b/test/integration/api.test.ts index 72578cc806..d7de5135a5 100644 --- a/test/integration/api.test.ts +++ b/test/integration/api.test.ts @@ -3594,9 +3594,9 @@ describe("api routes", () => { method: "POST", headers: { ...apiHeaders(env), - "x-gittensory-mcp-package": "@loopover/mcp", - "x-gittensory-mcp-version": "0.4.0", - "x-gittensory-mcp-client": "gittensory-mcp-cli", + "x-loopover-mcp-package": "@loopover/mcp", + "x-loopover-mcp-version": "0.4.0", + "x-loopover-mcp-client": "loopover-mcp-cli", }, body: JSON.stringify({ login: "oktofeesh1", repoFullName: "entrius/allways-ui", branchName: "usage-spine" }), }, @@ -5914,12 +5914,12 @@ describe("api routes", () => { const mcpUsageEvents = await listProductUsageEvents(env, { limit: 100 }); expect(mcpUsageEvents).toEqual( expect.arrayContaining([ - expect.objectContaining({ surface: "mcp", eventName: "mcp_request", outcome: "success", clientName: "gittensory--cli", clientVersion: "0.4.0" }), + expect.objectContaining({ surface: "mcp", eventName: "mcp_request", outcome: "success", clientName: "loopover--cli", clientVersion: "0.4.0" }), expect.objectContaining({ surface: "mcp", eventName: "mcp_tool_called", outcome: "success", - clientName: "gittensory--cli", + clientName: "loopover--cli", clientVersion: "0.4.0", metadata: expect.objectContaining({ toolName: "gittensory_get_bounty_advisory", @@ -6673,9 +6673,9 @@ function mcpHeaders(env: Env, sessionId?: string): Record { accept: "application/json, text/event-stream", "content-type": "application/json", "mcp-protocol-version": "2025-03-26", - "x-gittensory-mcp-package": "@loopover/mcp", - "x-gittensory-mcp-version": "0.4.0", - "x-gittensory-mcp-client": "gittensory-mcp-cli", + "x-loopover-mcp-package": "@loopover/mcp", + "x-loopover-mcp-version": "0.4.0", + "x-loopover-mcp-client": "loopover-mcp-cli", ...(sessionId ? { "mcp-session-id": sessionId } : {}), }; } diff --git a/test/unit/check-miner-package.test.ts b/test/unit/check-miner-package.test.ts index eb228ab1cb..88215568b4 100644 --- a/test/unit/check-miner-package.test.ts +++ b/test/unit/check-miner-package.test.ts @@ -19,7 +19,7 @@ describe("check-miner-package script", () => { const result = runChecker(); expect(result.status).toBe(0); expect(result.out).toMatch(/^Miner package dry-run ok:/); - expect(result.out).toContain("bin/gittensory-miner.js"); + expect(result.out).toContain("bin/loopover-miner.js"); expect(result.out).toContain("package.json"); }); @@ -39,7 +39,7 @@ describe("check-miner-package script", () => { const result = runChecker({ CHECK_MINER_PACK_TEST_FILES: JSON.stringify([ "package.json", - "bin/gittensory-miner.js", + "bin/loopover-miner.js", "bin/gittensory-miner-backdoor.js", "lib/cli.js", ]), @@ -53,7 +53,7 @@ describe("check-miner-package script", () => { const result = runChecker({ CHECK_MINER_PACK_TEST_FILES: JSON.stringify([ "package.json", - "bin/gittensory-miner.js", + "bin/loopover-miner.js", "lib/cli.js", "lib/calibration/index.js", ]), @@ -66,7 +66,7 @@ describe("check-miner-package script", () => { const result = runChecker({ CHECK_MINER_PACK_TEST_FILES: JSON.stringify([ "package.json", - "bin/gittensory-miner.js", + "bin/loopover-miner.js", "lib/cli.js", "lib/calibration/nested/index.js", ]), @@ -80,7 +80,7 @@ describe("check-miner-package script", () => { CHECK_MINER_PACK_TEST_FILES: JSON.stringify(["package.json", "lib/cli.js"]), }); expect(result.status).toBe(1); - expect(result.out).toContain("Miner package is missing required file: bin/gittensory-miner.js"); + expect(result.out).toContain("Miner package is missing required file: bin/loopover-miner.js"); }); it("rejects a package missing lib artifacts", () => { @@ -88,7 +88,7 @@ describe("check-miner-package script", () => { // Every REQUIRED file present so the check reaches (and fails on) the lib-artifacts guard specifically. CHECK_MINER_PACK_TEST_FILES: JSON.stringify([ "package.json", - "bin/gittensory-miner.js", + "bin/loopover-miner.js", "DEPLOYMENT.md", "Dockerfile", "schema/miner-goal-spec.schema.json", @@ -102,7 +102,7 @@ describe("check-miner-package script", () => { it("rejects secret-like content", () => { const probe = ["PROBE", "_", "SECRET", "=", "value"].join(""); const result = runChecker({ - CHECK_MINER_PACK_TEST_FILES: JSON.stringify(["package.json", "bin/gittensory-miner.js", "lib/cli.js"]), + CHECK_MINER_PACK_TEST_FILES: JSON.stringify(["package.json", "bin/loopover-miner.js", "lib/cli.js"]), CHECK_MINER_PACK_TEST_CONTENT: probe, }); expect(result.status).toBe(1); @@ -114,7 +114,7 @@ describe("check-miner-package script", () => { // and the schema — is accepted. const FULL_PACKAGE = [ "package.json", - "bin/gittensory-miner.js", + "bin/loopover-miner.js", "lib/cli.js", "DEPLOYMENT.md", "Dockerfile", diff --git a/test/unit/coding-agent-miner.test.ts b/test/unit/coding-agent-miner.test.ts index 32f59629a2..81ea12f1b2 100644 --- a/test/unit/coding-agent-miner.test.ts +++ b/test/unit/coding-agent-miner.test.ts @@ -623,7 +623,7 @@ describe("lint-guarded edit wrapper (#4276)", () => { expect(classifyLintGuardPackage("apps/gittensory-ui/src/App.tsx")).toBe("ui"); expect(classifyLintGuardPackage("packages/gittensory-engine/src/miner/lint-guard.ts")).toBe("engine"); expect(classifyLintGuardPackage("packages/gittensory-miner/lib/cli.js")).toBe("miner-js"); - expect(classifyLintGuardPackage("packages/gittensory-mcp/bin/gittensory-mcp.js")).toBe("mcp-js"); + expect(classifyLintGuardPackage("packages/gittensory-mcp/bin/loopover-mcp.js")).toBe("mcp-js"); expect(classifyLintGuardPackage("src/review/ops-wire.ts")).toBe("root"); // A hand-written .d.ts under miner/mcp is type-checked by the root tsc, not node --check. expect(classifyLintGuardPackage("packages/gittensory-miner/lib/cli.d.ts")).toBe("root"); diff --git a/test/unit/mcp-cli-basics.test.ts b/test/unit/mcp-cli-basics.test.ts index 0860ccfe7c..458ec5e7ca 100644 --- a/test/unit/mcp-cli-basics.test.ts +++ b/test/unit/mcp-cli-basics.test.ts @@ -5,7 +5,7 @@ import { afterEach, describe, expect, it } from "vitest"; import { closeFixtureServer, createPacketRepo, run, runAsync, startFixtureServer } from "./support/mcp-cli-harness"; import mcpPackageJson from "../../packages/gittensory-mcp/package.json"; -describe("gittensory-mcp CLI — basics", () => { +describe("loopover-mcp CLI — basics", () => { let tempDir: string | null = null; afterEach(async () => { @@ -159,7 +159,7 @@ describe("gittensory-mcp CLI — basics", () => { it("guides unknown commands to --help", () => { expect(() => run(["bogus-command"])).toThrow(/Unknown command: bogus-command/); - expect(() => run(["bogus-command"])).toThrow(/gittensory-mcp --help/); + expect(() => run(["bogus-command"])).toThrow(/loopover-mcp --help/); }); it("suggests the closest command for a near-miss typo", () => { @@ -174,7 +174,7 @@ describe("gittensory-mcp CLI — basics", () => { it("prints shell completion scripts for bash, zsh, and fish", () => { const bash = run(["completion", "bash"]); expect(bash).toContain("_gittensory_mcp()"); - expect(bash).toContain("complete -F _gittensory_mcp gittensory-mcp"); + expect(bash).toContain("complete -F _gittensory_mcp loopover-mcp"); expect(bash).toContain("analyze-branch"); expect(bash).toContain("local commands=\"login logout whoami config status changelog completion version tools doctor"); expect(bash).toContain("version"); @@ -182,22 +182,22 @@ describe("gittensory-mcp CLI — basics", () => { expect(bash).toContain("plan status explain packet"); const zsh = run(["completion", "zsh"]); - expect(zsh).toContain("#compdef gittensory-mcp"); + expect(zsh).toContain("#compdef loopover-mcp"); expect(zsh).toContain("_describe 'command' commands"); expect(zsh).toContain("commands=(login logout whoami config status changelog completion version tools doctor"); expect(zsh).toContain("list create switch remove"); const fish = run(["completion", "fish"]); - expect(fish).toContain("complete -c gittensory-mcp"); - expect(fish).toContain("complete -c gittensory-mcp -n __fish_use_subcommand -a config"); - expect(fish).toContain("complete -c gittensory-mcp -n __fish_use_subcommand -a completion"); - expect(fish).toContain("complete -c gittensory-mcp -n __fish_use_subcommand -a tools"); + expect(fish).toContain("complete -c loopover-mcp"); + expect(fish).toContain("complete -c loopover-mcp -n __fish_use_subcommand -a config"); + expect(fish).toContain("complete -c loopover-mcp -n __fish_use_subcommand -a completion"); + expect(fish).toContain("complete -c loopover-mcp -n __fish_use_subcommand -a tools"); expect(fish).toContain("__fish_seen_subcommand_from agent"); }); it("prints a PowerShell argument-completer script", () => { const ps = run(["completion", "powershell"]); - expect(ps).toContain("Register-ArgumentCompleter -Native -CommandName gittensory-mcp"); + expect(ps).toContain("Register-ArgumentCompleter -Native -CommandName loopover-mcp"); expect(ps).toContain("[System.Management.Automation.CompletionResult]::new"); expect(ps).toContain("$commands = @('login', 'logout'"); expect(ps).toContain("'maintain' = @('status', 'queue', 'approve', 'reject', 'pause', 'resume', 'set-level', 'precision')"); @@ -206,11 +206,11 @@ describe("gittensory-mcp CLI — basics", () => { it("emits completion as machine-readable json", () => { const payload = JSON.parse(run(["completion", "zsh", "--json"])) as { shell: string; script: string }; expect(payload.shell).toBe("zsh"); - expect(payload.script).toContain("#compdef gittensory-mcp"); + expect(payload.script).toContain("#compdef loopover-mcp"); }); it("rejects missing or unsupported completion shells", () => { - expect(() => run(["completion"])).toThrow(/Usage: gittensory-mcp completion /); + expect(() => run(["completion"])).toThrow(/Usage: loopover-mcp completion /); expect(() => run(["completion", "tcsh"])).toThrow(/Unsupported shell: tcsh/); }); diff --git a/test/unit/mcp-cli-burden-forecast.test.ts b/test/unit/mcp-cli-burden-forecast.test.ts index e9eb7f9092..a37fe80bb8 100644 --- a/test/unit/mcp-cli-burden-forecast.test.ts +++ b/test/unit/mcp-cli-burden-forecast.test.ts @@ -6,7 +6,7 @@ import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { closeFixtureServer, startFixtureServer } from "./support/mcp-cli-harness"; -const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); const FORBIDDEN_PUBLIC_TERMS = /wallet\s*[:=]\s*\S+|hotkey\s*[:=]\s*\S+|coldkey\s*[:=]\s*\S+|raw trust score is|your trust score|reward estimate is|estimated reward/i; let client: Client; diff --git a/test/unit/mcp-cli-doctor.test.ts b/test/unit/mcp-cli-doctor.test.ts index c7a8d72d15..01652c04a7 100644 --- a/test/unit/mcp-cli-doctor.test.ts +++ b/test/unit/mcp-cli-doctor.test.ts @@ -14,7 +14,7 @@ const oneMinorAboveLocal = (() => { return `${major}.${minor + 1}.0`; })(); -describe("gittensory-mcp CLI — doctor", () => { +describe("loopover-mcp CLI — doctor", () => { let tempDir: string | null = null; afterEach(async () => { @@ -62,7 +62,7 @@ describe("gittensory-mcp CLI — doctor", () => { ]), ); expect(payload.nextCommand).toMatchObject({ - command: "gittensory-mcp doctor --json", + command: "loopover-mcp doctor --json", reason: expect.stringContaining("local scorer"), }); expect(payload.checks).toEqual( @@ -95,11 +95,11 @@ describe("gittensory-mcp CLI — doctor", () => { }; const payload = JSON.parse(await runAsync(["doctor", "--cwd", tempDir, "--json"], env)) as { nextCommand: { command: string } }; - expect(payload.nextCommand.command).toBe("gittensory-mcp review-pr --login JSONbored --repo 'owner/repo$(touch /tmp/av_pwned)' --json"); + expect(payload.nextCommand.command).toBe("loopover-mcp review-pr --login JSONbored --repo 'owner/repo$(touch /tmp/av_pwned)' --json"); expect(payload.nextCommand.command).not.toContain("--repo owner/repo$("); const humanOutput = await runAsync(["doctor", "--cwd", tempDir], env); - expect(humanOutput).toContain("gittensory-mcp review-pr --login JSONbored --repo 'owner/repo$(touch /tmp/av_pwned)' --json"); + expect(humanOutput).toContain("loopover-mcp review-pr --login JSONbored --repo 'owner/repo$(touch /tmp/av_pwned)' --json"); expect(humanOutput).not.toContain("--repo owner/repo$("); }); @@ -126,7 +126,7 @@ describe("gittensory-mcp CLI — doctor", () => { expect(auth).toMatchObject({ status: "fail" }); expect(auth?.checks).toEqual(expect.arrayContaining([expect.objectContaining({ name: "auth", status: "fail" })])); expect(payload.nextCommand).toMatchObject({ - command: "gittensory-mcp login --profile default", + command: "loopover-mcp login --profile default", reason: expect.stringContaining("Authenticate"), }); expect(JSON.stringify(payload)).not.toContain(tempDir); @@ -391,7 +391,7 @@ describe("gittensory-mcp CLI — doctor", () => { expect(repoReadiness).toMatchObject({ status: "warn" }); expect(repoReadiness?.checks).toEqual(expect.arrayContaining([expect.objectContaining({ name: "git_metadata", status: "warn" })])); expect(payload.nextCommand).toMatchObject({ - command: "gittensory-mcp doctor --repo owner/repo --json", + command: "loopover-mcp doctor --repo owner/repo --json", reason: expect.stringContaining("git checkout"), }); expect(JSON.stringify(payload)).not.toContain(tempDir); diff --git a/test/unit/mcp-cli-find-opportunities.test.ts b/test/unit/mcp-cli-find-opportunities.test.ts index 3d313ab1b3..36dde220e3 100644 --- a/test/unit/mcp-cli-find-opportunities.test.ts +++ b/test/unit/mcp-cli-find-opportunities.test.ts @@ -6,7 +6,7 @@ import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { closeFixtureServer, startFixtureServer } from "./support/mcp-cli-harness"; -const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); const FORBIDDEN_PUBLIC_TERMS = /wallet\s*[:=]\s*\S+|hotkey\s*[:=]\s*\S+|coldkey\s*[:=]\s*\S+|raw trust score is|your trust score|reward estimate is|estimated reward/i; let client: Client; diff --git a/test/unit/mcp-cli-issue-rag.test.ts b/test/unit/mcp-cli-issue-rag.test.ts index 7ed97a42f3..9de744ac48 100644 --- a/test/unit/mcp-cli-issue-rag.test.ts +++ b/test/unit/mcp-cli-issue-rag.test.ts @@ -6,7 +6,7 @@ import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { closeFixtureServer, startFixtureServer } from "./support/mcp-cli-harness"; -const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); const FORBIDDEN_PUBLIC_TERMS = /wallet\s*[:=]\s*\S+|hotkey\s*[:=]\s*\S+|coldkey\s*[:=]\s*\S+|raw trust score is|your trust score|reward estimate is|estimated reward/i; let client: Client; diff --git a/test/unit/mcp-cli-issue-slop.test.ts b/test/unit/mcp-cli-issue-slop.test.ts index 3fb122d680..ba05f0d6c6 100644 --- a/test/unit/mcp-cli-issue-slop.test.ts +++ b/test/unit/mcp-cli-issue-slop.test.ts @@ -4,7 +4,7 @@ import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { closeFixtureServer, run, runAsync, startFixtureServer } from "./support/mcp-cli-harness"; -describe("gittensory-mcp CLI — issue-slop", () => { +describe("loopover-mcp CLI — issue-slop", () => { let tempDir: string | null = null; afterEach(async () => { @@ -94,7 +94,7 @@ describe("gittensory-mcp CLI — issue-slop", () => { const e = await env(); await expect(runAsync(["issue-slop", "--body-file", "/tmp/missing-gittensory-issue-body.md"], e)).rejects.toThrow(/Body file not found/); const help = run(["issue-slop", "--help"]); - expect(help).toMatch(/Usage: gittensory-mcp issue-slop/); + expect(help).toMatch(/Usage: loopover-mcp issue-slop/); expect(help).toMatch(/loopover_check_issue_slop/); expect(help).toMatch(/--body-file/); }); diff --git a/test/unit/mcp-cli-label-audit.test.ts b/test/unit/mcp-cli-label-audit.test.ts index 48e5e811b8..7f18d918cb 100644 --- a/test/unit/mcp-cli-label-audit.test.ts +++ b/test/unit/mcp-cli-label-audit.test.ts @@ -6,7 +6,7 @@ import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { closeFixtureServer, startFixtureServer } from "./support/mcp-cli-harness"; -const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); const FORBIDDEN_PUBLIC_TERMS = /wallet\s*[:=]\s*\S+|hotkey\s*[:=]\s*\S+|coldkey\s*[:=]\s*\S+|raw trust score is|your trust score|reward estimate is|estimated reward/i; let client: Client; diff --git a/test/unit/mcp-cli-lint-pr-text.test.ts b/test/unit/mcp-cli-lint-pr-text.test.ts index 4b1243916c..4e0f8bc6ec 100644 --- a/test/unit/mcp-cli-lint-pr-text.test.ts +++ b/test/unit/mcp-cli-lint-pr-text.test.ts @@ -4,7 +4,7 @@ import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { closeFixtureServer, run, runAsync, startFixtureServer } from "./support/mcp-cli-harness"; -describe("gittensory-mcp CLI — lint-pr-text", () => { +describe("loopover-mcp CLI — lint-pr-text", () => { let tempDir: string | null = null; afterEach(async () => { @@ -101,7 +101,7 @@ describe("gittensory-mcp CLI — lint-pr-text", () => { await expect(runAsync(["lint-pr-text", "--linked-issue", "0"], e)).rejects.toThrow(/positive integer/); await expect(runAsync(["lint-pr-text", "--body-file", "/tmp/missing-gittensory-pr-body.md"], e)).rejects.toThrow(/Body file not found/); const help = run(["lint-pr-text", "--help"]); - expect(help).toMatch(/Usage: gittensory-mcp lint-pr-text/); + expect(help).toMatch(/Usage: loopover-mcp lint-pr-text/); expect(help).toMatch(/loopover_lint_pr_text/); expect(help).toMatch(/--body-file/); }); diff --git a/test/unit/mcp-cli-maintain.test.ts b/test/unit/mcp-cli-maintain.test.ts index e0808219c6..6f709d9d96 100644 --- a/test/unit/mcp-cli-maintain.test.ts +++ b/test/unit/mcp-cli-maintain.test.ts @@ -4,7 +4,7 @@ import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { closeFixtureServer, runAsync, startFixtureServer } from "./support/mcp-cli-harness"; -describe("gittensory-mcp CLI — maintain (#784)", () => { +describe("loopover-mcp CLI — maintain (#784)", () => { let tempDir: string | null = null; afterEach(async () => { @@ -87,7 +87,7 @@ describe("gittensory-mcp CLI — maintain (#784)", () => { await expect(runAsync(["maintain", "status"], e)).rejects.toThrow(/Pass --repo/); await expect(runAsync(["maintain", "approve", "--repo", "owner/repo"], e)).rejects.toThrow(/Pass the pending-action id/); await expect(runAsync(["maintain", "bogus", "--repo", "owner/repo"], e)).rejects.toThrow(/Unknown maintain subcommand/); - await expect(runAsync(["maintain", "set-level", "merge", "--repo", "owner/repo"], e)).rejects.toThrow(/Usage: gittensory-mcp maintain set-level/); + await expect(runAsync(["maintain", "set-level", "merge", "--repo", "owner/repo"], e)).rejects.toThrow(/Usage: loopover-mcp maintain set-level/); await expect(runAsync(["maintain", "set-level", "bogus", "auto", "--repo", "owner/repo"], e)).rejects.toThrow(/Unknown action/); await expect(runAsync(["maintain", "set-level", "merge", "bogus", "--repo", "owner/repo"], e)).rejects.toThrow(/Unknown level/); }, 45_000); @@ -95,7 +95,7 @@ describe("gittensory-mcp CLI — maintain (#784)", () => { it("prints help when invoked with no subcommand", async () => { const e = await env(); const out = await runAsync(["maintain"], e); - expect(out).toMatch(/Usage: gittensory-mcp maintain/); + expect(out).toMatch(/Usage: loopover-mcp maintain/); expect(out).toMatch(/approve /); expect(out).toMatch(/queue/); expect(out).toMatch(/pause/); diff --git a/test/unit/mcp-cli-maintainer-noise.test.ts b/test/unit/mcp-cli-maintainer-noise.test.ts index b35b6286c7..222e7a95cf 100644 --- a/test/unit/mcp-cli-maintainer-noise.test.ts +++ b/test/unit/mcp-cli-maintainer-noise.test.ts @@ -6,7 +6,7 @@ import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { closeFixtureServer, run, startFixtureServer } from "./support/mcp-cli-harness"; -const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); const FORBIDDEN_PUBLIC_TERMS = /wallet\s*[:=]\s*\S+|hotkey\s*[:=]\s*\S+|coldkey\s*[:=]\s*\S+|raw trust score is|your trust score|reward estimate is|estimated reward/i; let client: Client; diff --git a/test/unit/mcp-cli-packets.test.ts b/test/unit/mcp-cli-packets.test.ts index 2987513318..df82e89f33 100644 --- a/test/unit/mcp-cli-packets.test.ts +++ b/test/unit/mcp-cli-packets.test.ts @@ -14,7 +14,7 @@ import { startFixtureServer, } from "./support/mcp-cli-harness"; -describe("gittensory-mcp CLI — packets", () => { +describe("loopover-mcp CLI — packets", () => { let tempDir: string | null = null; afterEach(async () => { @@ -54,7 +54,7 @@ describe("gittensory-mcp CLI — packets", () => { source: "local_cache", stale: true, freshness: "stale", - cache: { source: "local_cache", clearCommand: "gittensory-mcp cache clear" }, + cache: { source: "local_cache", clearCommand: "loopover-mcp cache clear" }, }); expect(offline.cachedAt).toEqual(expect.any(String)); expect(offline.cache.rerunGuidance).toMatch(/Retry when Gittensory API access is restored/); @@ -238,9 +238,9 @@ describe("gittensory-mcp CLI — packets", () => { LOOPOVER_MCP_TOKEN: "", }; - await expect(runAsync(["decision-pack", "--login", "JSONbored", "--json"], withoutToken)).rejects.toThrow(/Run `gittensory-mcp login`/); + await expect(runAsync(["decision-pack", "--login", "JSONbored", "--json"], withoutToken)).rejects.toThrow(/Run `loopover-mcp login`/); await expect(runAsync(["repo-decision", "--login", "JSONbored", "--repo", "JSONbored/gittensory", "--json"], withoutToken)).rejects.toThrow( - /Run `gittensory-mcp login`/, + /Run `loopover-mcp login`/, ); }); diff --git a/test/unit/mcp-cli-profiles.test.ts b/test/unit/mcp-cli-profiles.test.ts index 50a03b8ea0..61907fd165 100644 --- a/test/unit/mcp-cli-profiles.test.ts +++ b/test/unit/mcp-cli-profiles.test.ts @@ -216,13 +216,13 @@ describe("gittensory-mcp CLI — profiles", () => { }); const sessionRequest = requests.find((request) => request.url === "/v1/auth/session"); - expect(sessionRequest?.headers["x-gittensory-mcp-package"]).toBe("@loopover/mcp"); - expect(sessionRequest?.headers["x-gittensory-mcp-version"]).toBe(mcpPackageJson.version); - expect(sessionRequest?.headers["x-gittensory-mcp-client"]).toBe("gittensory-mcp-cli"); + expect(sessionRequest?.headers["x-loopover-mcp-package"]).toBe("@loopover/mcp"); + expect(sessionRequest?.headers["x-loopover-mcp-version"]).toBe(mcpPackageJson.version); + expect(sessionRequest?.headers["x-loopover-mcp-client"]).toBe("loopover-mcp-cli"); const telemetryHeaders = JSON.stringify({ - package: sessionRequest?.headers["x-gittensory-mcp-package"], - version: sessionRequest?.headers["x-gittensory-mcp-version"], - client: sessionRequest?.headers["x-gittensory-mcp-client"], + package: sessionRequest?.headers["x-loopover-mcp-package"], + version: sessionRequest?.headers["x-loopover-mcp-version"], + client: sessionRequest?.headers["x-loopover-mcp-client"], }); expect(telemetryHeaders).not.toContain("session-token"); expect(telemetryHeaders).not.toContain(tempDir); diff --git a/test/unit/mcp-cli-review-pr.test.ts b/test/unit/mcp-cli-review-pr.test.ts index 5a86010cb3..ec220aa0b2 100644 --- a/test/unit/mcp-cli-review-pr.test.ts +++ b/test/unit/mcp-cli-review-pr.test.ts @@ -11,7 +11,7 @@ import { startFixtureServer, } from "./support/mcp-cli-harness"; -describe("gittensory-mcp CLI — review-pr", () => { +describe("loopover-mcp CLI — review-pr", () => { let tempDir: string | null = null; afterEach(async () => { @@ -395,7 +395,7 @@ describe("gittensory-mcp CLI — review-pr", () => { it("prints help", () => { const help = run(["review-pr", "--help"]); - expect(help).toMatch(/Usage: gittensory-mcp review-pr/); + expect(help).toMatch(/Usage: loopover-mcp review-pr/); expect(help).toMatch(/loopover_review_pr_before_push/); expect(help).toMatch(/preflight \+ slop-risk \+ PR-text-lint/); }); diff --git a/test/unit/mcp-cli-slop-risk.test.ts b/test/unit/mcp-cli-slop-risk.test.ts index a1cec9f0f8..be80260b23 100644 --- a/test/unit/mcp-cli-slop-risk.test.ts +++ b/test/unit/mcp-cli-slop-risk.test.ts @@ -4,7 +4,7 @@ import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { closeFixtureServer, run, runAsync, startFixtureServer } from "./support/mcp-cli-harness"; -describe("gittensory-mcp CLI — slop-risk", () => { +describe("loopover-mcp CLI — slop-risk", () => { let tempDir: string | null = null; afterEach(async () => { @@ -118,7 +118,7 @@ describe("gittensory-mcp CLI — slop-risk", () => { await expect(runAsync(["slop-risk", "--changed-file", "src/a.ts:-1"], e)).rejects.toThrow(/Invalid additions/); await expect(runAsync(["slop-risk", "--description-file", "/tmp/missing-gittensory-slop-description.md"], e)).rejects.toThrow(/Description file not found/); const help = run(["slop-risk", "--help"]); - expect(help).toMatch(/Usage: gittensory-mcp slop-risk/); + expect(help).toMatch(/Usage: loopover-mcp slop-risk/); expect(help).toMatch(/loopover_check_slop_risk/); expect(help).toMatch(/--changed-file/); }); diff --git a/test/unit/mcp-cli-tools.test.ts b/test/unit/mcp-cli-tools.test.ts index c8ff7b1703..b837006888 100644 --- a/test/unit/mcp-cli-tools.test.ts +++ b/test/unit/mcp-cli-tools.test.ts @@ -6,9 +6,9 @@ import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { closeFixtureServer, run, startFixtureServer } from "./support/mcp-cli-harness"; -const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); -describe("gittensory-mcp CLI — tools", () => { +describe("loopover-mcp CLI — tools", () => { let configDir: string | null = null; let client: Client | null = null; let transport: StdioClientTransport | null = null; @@ -60,7 +60,7 @@ describe("gittensory-mcp CLI — tools", () => { it("prints name + description rows for humans and documents --json in help", () => { const help = run(["--help"]); - expect(help).toContain("gittensory-mcp tools [--json]"); + expect(help).toContain("loopover-mcp tools [--json]"); const plain = run(["tools"]); const payload = JSON.parse(run(["tools", "--json"])) as { diff --git a/test/unit/mcp-cli-upstream-drift.test.ts b/test/unit/mcp-cli-upstream-drift.test.ts index cb039d2058..9ff5e86d75 100644 --- a/test/unit/mcp-cli-upstream-drift.test.ts +++ b/test/unit/mcp-cli-upstream-drift.test.ts @@ -6,7 +6,7 @@ import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { closeFixtureServer, startFixtureServer } from "./support/mcp-cli-harness"; -const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); const FORBIDDEN_PUBLIC_TERMS = /wallet\s*[:=]\s*\S+|hotkey\s*[:=]\s*\S+|coldkey\s*[:=]\s*\S+|raw trust score is|your trust score|reward estimate is|estimated reward/i; let client: Client; diff --git a/test/unit/mcp-cli-validate-config.test.ts b/test/unit/mcp-cli-validate-config.test.ts index e1c033836d..7ef27887cd 100644 --- a/test/unit/mcp-cli-validate-config.test.ts +++ b/test/unit/mcp-cli-validate-config.test.ts @@ -4,7 +4,7 @@ import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { closeFixtureServer, run, runAsync, startFixtureServer } from "./support/mcp-cli-harness"; -describe("gittensory-mcp CLI — validate-config", () => { +describe("loopover-mcp CLI — validate-config", () => { let tempDir: string | null = null; afterEach(async () => { @@ -57,7 +57,7 @@ describe("gittensory-mcp CLI — validate-config", () => { it("rejects missing --file and prints help", async () => { const e = await env(); const help = run(["validate-config", "--help"]); - expect(help).toMatch(/Usage: gittensory-mcp validate-config/); + expect(help).toMatch(/Usage: loopover-mcp validate-config/); expect(help).toMatch(/loopover_validate_config/); const manifestPath = join(tempDir!, "missing.yml"); diff --git a/test/unit/mcp-compatibility.test.ts b/test/unit/mcp-compatibility.test.ts index f04641942c..2b06d14251 100644 --- a/test/unit/mcp-compatibility.test.ts +++ b/test/unit/mcp-compatibility.test.ts @@ -48,16 +48,16 @@ describe("MCP compatibility telemetry", () => { it("builds bounded telemetry from allowlisted MCP headers", () => { const telemetry = buildMcpClientTelemetry( new Headers({ - "x-gittensory-mcp-package": "@loopover/mcp", - "x-gittensory-mcp-version": "0.2.1", - "x-gittensory-mcp-client": "gittensory-mcp-cli", + "x-loopover-mcp-package": "@loopover/mcp", + "x-loopover-mcp-version": "0.2.1", + "x-loopover-mcp-client": "loopover-mcp-cli", "mcp-protocol-version": "2025-03-26", }), { requireGittensoryHeader: true }, ); expect(telemetry).toMatchObject({ - clientName: "gittensory-mcp-cli", + clientName: "loopover-mcp-cli", clientVersion: "0.2.1", metadata: { packageName: "@loopover/mcp", @@ -71,8 +71,8 @@ describe("MCP compatibility telemetry", () => { it("derives a safe client name from scoped package telemetry when no explicit client is sent", () => { const telemetry = buildMcpClientTelemetry( new Headers({ - "x-gittensory-mcp-package": "@example/custom-mcp", - "x-gittensory-mcp-version": "0.5.0", + "x-loopover-mcp-package": "@example/custom-mcp", + "x-loopover-mcp-version": "0.5.0", }), { requireGittensoryHeader: true }, ); @@ -90,12 +90,12 @@ describe("MCP compatibility telemetry", () => { it("uses the canonical package and default MCP client fallbacks without storing unsafe header data", () => { const canonical = buildMcpClientTelemetry( new Headers({ - "x-gittensory-mcp-package": "@loopover/mcp", - "x-gittensory-mcp-version": "0.4.0", + "x-loopover-mcp-package": "@loopover/mcp", + "x-loopover-mcp-version": "0.4.0", }), { requireGittensoryHeader: true }, ); - expect(canonical).toMatchObject({ clientName: "gittensory-mcp", clientVersion: "0.4.0" }); + expect(canonical).toMatchObject({ clientName: "loopover-mcp", clientVersion: "0.4.0" }); const defaulted = buildMcpClientTelemetry(new Headers(), { defaultClientName: "mcp" }); expect(defaulted).toMatchObject({ @@ -110,9 +110,9 @@ describe("MCP compatibility telemetry", () => { it("drops token-like and local-path-like header values before analytics storage", () => { const telemetry = buildMcpClientTelemetry( new Headers({ - "x-gittensory-mcp-package": "/Users/example/private", - "x-gittensory-mcp-version": "github_pat_secretsecret", - "x-gittensory-mcp-client": "node /tmp/client.js", + "x-loopover-mcp-package": "/Users/example/private", + "x-loopover-mcp-version": "github_pat_secretsecret", + "x-loopover-mcp-client": "node /tmp/client.js", "mcp-protocol-version": "Bearer secret-token-value", }), { requireGittensoryHeader: true }, diff --git a/test/unit/mcp-discovery.test.ts b/test/unit/mcp-discovery.test.ts index 22085171a4..466045d3e9 100644 --- a/test/unit/mcp-discovery.test.ts +++ b/test/unit/mcp-discovery.test.ts @@ -8,7 +8,7 @@ import { join } from "node:path"; import { pathToFileURL } from "node:url"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; -const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); const FORBIDDEN_PUBLIC_TERMS = /wallet\s*[:=]\s*\S+|hotkey\s*[:=]\s*\S+|coldkey\s*[:=]\s*\S+|raw trust score is|your trust score|reward estimate is|estimated reward/i; diff --git a/test/unit/mcp-feasibility-gate.test.ts b/test/unit/mcp-feasibility-gate.test.ts index a92b669ad3..8f114c9726 100644 --- a/test/unit/mcp-feasibility-gate.test.ts +++ b/test/unit/mcp-feasibility-gate.test.ts @@ -7,7 +7,7 @@ import { DatabaseSync } from "node:sqlite"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { openClaimLedger } from "../../packages/gittensory-miner/lib/claim-ledger.js"; -const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); let client: Client; let transport: StdioClientTransport; diff --git a/test/unit/mcp-release-candidate.test.ts b/test/unit/mcp-release-candidate.test.ts index f4b0edf030..2c804063e9 100644 --- a/test/unit/mcp-release-candidate.test.ts +++ b/test/unit/mcp-release-candidate.test.ts @@ -16,7 +16,7 @@ import { const FORBIDDEN_PUBLIC_LANGUAGE = /\b(wallet|hotkey|coldkey|raw trust|trust score|payout|reward estimate|farming|private reviewability|public score estimate)\b/i; // Mirrors the allowlisted shape of the published tarball. -const ALLOWED_FILES = ["bin/gittensory-mcp.js", "lib/local-branch.js", "scripts/gittensor-score-preview.mjs", "package.json", "README.md", "CHANGELOG.md", "LICENSE"]; +const ALLOWED_FILES = ["bin/loopover-mcp.js", "lib/local-branch.js", "scripts/gittensor-score-preview.mjs", "package.json", "README.md", "CHANGELOG.md", "LICENSE"]; const CHANGELOG = "# Changelog\n\n## mcp-v0.4.0 - 2026-06-02\n\n### Features\n- Add a thing\n"; // A tokenless trusted-publishing workflow fixture (same shape as publish-mcp.yml). diff --git a/test/unit/mcp-release.test.ts b/test/unit/mcp-release.test.ts index 095ea8c254..44d2a54145 100644 --- a/test/unit/mcp-release.test.ts +++ b/test/unit/mcp-release.test.ts @@ -60,7 +60,7 @@ describe("MCP release changelog detection", () => { existingChangelog: `# Changelog\n\n${priorSections}`, targetVersion: "0.4.0", generatedAt: "2026-06-02", - commits: [commit("feat(mcp): add local workspace intelligence v2 (#70)", ["packages/gittensory-mcp/bin/gittensory-mcp.js"])], + commits: [commit("feat(mcp): add local workspace intelligence v2 (#70)", ["packages/gittensory-mcp/bin/loopover-mcp.js"])], }); expect(changelog).toContain("## mcp-v0.4.0 - 2026-06-02"); diff --git a/test/unit/mcp-server-telemetry.test.ts b/test/unit/mcp-server-telemetry.test.ts index 647c4c400f..9b11607714 100644 --- a/test/unit/mcp-server-telemetry.test.ts +++ b/test/unit/mcp-server-telemetry.test.ts @@ -23,9 +23,9 @@ describe("MCP server telemetry", () => { headers: { authorization: `Bearer ${env.LOOPOVER_MCP_TOKEN}`, "content-type": "application/json", - "x-gittensory-mcp-package": "@loopover/mcp", - "x-gittensory-mcp-version": "0.5.0", - "x-gittensory-mcp-client": "gittensory-mcp-cli", + "x-loopover-mcp-package": "@loopover/mcp", + "x-loopover-mcp-version": "0.5.0", + "x-loopover-mcp-client": "loopover-mcp-cli", }, body: JSON.stringify({ jsonrpc: "2.0", @@ -53,7 +53,7 @@ describe("MCP server telemetry", () => { surface: "mcp", eventName: "mcp_tool_called", outcome: "error", - clientName: "gittensory--cli", + clientName: "loopover--cli", clientVersion: "0.5.0", metadata: expect.objectContaining({ toolName: "gittensory_local_status", diff --git a/test/unit/mcp-tool-rename-aliases.test.ts b/test/unit/mcp-tool-rename-aliases.test.ts index 25aca92103..13176367ec 100644 --- a/test/unit/mcp-tool-rename-aliases.test.ts +++ b/test/unit/mcp-tool-rename-aliases.test.ts @@ -11,7 +11,7 @@ import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { closeFixtureServer, run, startFixtureServer } from "./support/mcp-cli-harness"; -const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); let client: Client; let transport: StdioClientTransport; diff --git a/test/unit/miner-attempt-cli.test.ts b/test/unit/miner-attempt-cli.test.ts index 4a23d535d0..30cf571cb7 100644 --- a/test/unit/miner-attempt-cli.test.ts +++ b/test/unit/miner-attempt-cli.test.ts @@ -91,7 +91,7 @@ function readyPipelineOptions(overrides: Record = {}) { } function tempLedgers() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-cli-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-attempt-cli-")); roots.push(root); const allocator = openWorktreeAllocator({ dbPath: join(root, "worktree-allocator.sqlite3"), @@ -146,7 +146,7 @@ describe("parseAttemptArgs (#5132)", () => { }); it("requires exactly repo and issue number as positional args", () => { - expect(parseAttemptArgs([])).toEqual({ error: expect.stringContaining("Usage: gittensory-miner attempt") }); + expect(parseAttemptArgs([])).toEqual({ error: expect.stringContaining("Usage: loopover-miner attempt") }); expect(parseAttemptArgs(["acme/widgets"])).toEqual({ error: expect.stringContaining("Usage:") }); expect(parseAttemptArgs(["acme/widgets", "7", "extra", "--miner-login", "alice"])).toEqual({ error: expect.stringContaining("Usage:"), @@ -247,7 +247,7 @@ describe("runAttempt (#5132)", () => { const openWorktreeAllocatorSpy = vi.fn(); const exitCode = await runAttempt([], { openWorktreeAllocator: openWorktreeAllocatorSpy }); expect(exitCode).toBe(2); - expect(error).toHaveBeenCalledWith(expect.stringContaining("Usage: gittensory-miner attempt")); + expect(error).toHaveBeenCalledWith(expect.stringContaining("Usage: loopover-miner attempt")); expect(openWorktreeAllocatorSpy).not.toHaveBeenCalled(); }); @@ -461,7 +461,7 @@ describe("runAttempt (#5132)", () => { it("REGRESSION (#5655 follow-up): when options.recordOwnSubmission is omitted, runAttempt falls back to the REAL governor-state.js default, not a fabricated no-op", async () => { const { allocator, claimLedger, eventLedger, attemptLog, governorLedger } = tempLedgers(); vi.spyOn(console, "log").mockImplementation(() => undefined); - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-cli-governor-state-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-attempt-cli-governor-state-")); roots.push(root); vi.stubEnv("LOOPOVER_MINER_GOVERNOR_STATE_DB", join(root, "governor-state.sqlite3")); const runMinerAttemptSpy = vi.fn().mockResolvedValue({ @@ -612,7 +612,7 @@ describe("runAttempt (#5132)", () => { it("REGRESSION (#5654): when options.getAttemptHistory is omitted, runAttempt falls back to the REAL portfolio-queue.js default, not a fabricated result", async () => { const { allocator, claimLedger, eventLedger, attemptLog, governorLedger } = tempLedgers(); vi.spyOn(console, "log").mockImplementation(() => undefined); - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-cli-portfolio-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-attempt-cli-portfolio-")); roots.push(root); vi.stubEnv("LOOPOVER_MINER_PORTFOLIO_QUEUE_DB", join(root, "portfolio-queue.sqlite3")); const runMinerAttemptSpy = vi.fn().mockResolvedValue({ @@ -1279,7 +1279,7 @@ describe("runAttempt: real per-repo kill switch (#5392)", () => { it("REGRESSION: reads a real .gittensory-miner.yml killSwitch.paused:true from the worktree's real repoPath, end to end", async () => { const { allocator, claimLedger, eventLedger, attemptLog, governorLedger } = tempLedgers(); vi.spyOn(console, "log").mockImplementation(() => undefined); - const repoRoot = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-cli-repo-")); + const repoRoot = mkdtempSync(join(tmpdir(), "loopover-miner-attempt-cli-repo-")); roots.push(repoRoot); writeFileSync(join(repoRoot, ".gittensory-miner.yml"), "killSwitch:\n paused: true\n"); const runMinerAttemptSpy = vi.fn().mockResolvedValue({ outcome: "governed", decision: { allowed: false }, loopResult: fakeLoopResult() }); @@ -1307,7 +1307,7 @@ describe("runAttempt: real per-repo kill switch (#5392)", () => { it("does not gate on a repo pause when no .gittensory-miner.yml exists (real resolver, real empty dir)", async () => { const { allocator, claimLedger, eventLedger, attemptLog, governorLedger } = tempLedgers(); vi.spyOn(console, "log").mockImplementation(() => undefined); - const repoRoot = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-cli-repo-")); + const repoRoot = mkdtempSync(join(tmpdir(), "loopover-miner-attempt-cli-repo-")); roots.push(repoRoot); const runMinerAttemptSpy = vi.fn().mockResolvedValue({ outcome: "abandon", loopResult: fakeLoopResult() }); diff --git a/test/unit/miner-attempt-runner.test.ts b/test/unit/miner-attempt-runner.test.ts index c69328698b..adea527523 100644 --- a/test/unit/miner-attempt-runner.test.ts +++ b/test/unit/miner-attempt-runner.test.ts @@ -43,7 +43,7 @@ function tempGovernorLedger() { } // Isolated per test: without this, evaluateGovernorChokepointGatePersisted's own default-store fallback -// would open the REAL ~/.config/gittensory-miner/governor-state.sqlite3 on whatever machine runs these tests. +// would open the REAL ~/.config/loopover-miner/governor-state.sqlite3 on whatever machine runs these tests. function tempGovernorState() { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-runner-governor-state-")); roots.push(root); diff --git a/test/unit/miner-claim-ledger-cli.test.ts b/test/unit/miner-claim-ledger-cli.test.ts index 0ad13e4fb6..92fbbe51f3 100644 --- a/test/unit/miner-claim-ledger-cli.test.ts +++ b/test/unit/miner-claim-ledger-cli.test.ts @@ -22,7 +22,7 @@ const roots: string[] = []; const ledgers: Array<{ close(): void }> = []; function tempClaimLedger() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-claim-ledger-cli-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-claim-ledger-cli-")); roots.push(root); const ledger = openClaimLedger(join(root, "claim-ledger.sqlite3")); ledgers.push(ledger); @@ -36,7 +36,7 @@ afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); -describe("gittensory-miner claim ledger CLI (#4290)", () => { +describe("loopover-miner claim ledger CLI (#4290)", () => { it("parseClaimClaimArgs, parseClaimReleaseArgs, and parseClaimListArgs validate argv", () => { expect(parseClaimClaimArgs(["acme/widgets", "42", "--note", "wip", "--dry-run", "--json"])).toEqual({ repoFullName: "acme/widgets", @@ -53,7 +53,7 @@ describe("gittensory-miner claim ledger CLI (#4290)", () => { json: false, }); expect(parseClaimClaimArgs(["acme/widgets"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner claim claim"), + error: expect.stringContaining("Usage: loopover-miner claim claim"), }); expect(parseClaimClaimArgs(["acme", "42"])).toEqual({ error: "Repository must be in owner/repo form.", @@ -62,7 +62,7 @@ describe("gittensory-miner claim ledger CLI (#4290)", () => { error: "issue number must be a positive integer.", }); expect(parseClaimClaimArgs(["acme/widgets", "42", "--note"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner claim claim"), + error: expect.stringContaining("Usage: loopover-miner claim claim"), }); expect(parseClaimClaimArgs(["acme/widgets", "42", "--verbose"])).toEqual({ error: "Unknown option: --verbose", @@ -75,7 +75,7 @@ describe("gittensory-miner claim ledger CLI (#4290)", () => { json: true, }); expect(parseClaimReleaseArgs(["acme/widgets"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner claim release"), + error: expect.stringContaining("Usage: loopover-miner claim release"), }); expect(parseClaimReleaseArgs(["acme/widgets", "7", "--bad"])).toEqual({ error: "Unknown option: --bad", @@ -95,10 +95,10 @@ describe("gittensory-miner claim ledger CLI (#4290)", () => { error: "status must be one of: active, released, expired.", }); expect(parseClaimListArgs(["--repo"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner claim list"), + error: expect.stringContaining("Usage: loopover-miner claim list"), }); expect(parseClaimListArgs(["extra"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner claim list"), + error: expect.stringContaining("Usage: loopover-miner claim list"), }); expect(parseClaimListArgs(["--status", "released", "--unknown"])).toEqual({ error: "Unknown option: --unknown", @@ -115,7 +115,7 @@ describe("gittensory-miner claim ledger CLI (#4290)", () => { apiBaseUrl: "https://ghe.example.com/api/v3", }); expect(parseClaimClaimArgs(["acme/widgets", "42", "--api-base-url"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner claim claim"), + error: expect.stringContaining("Usage: loopover-miner claim claim"), }); expect(parseClaimReleaseArgs(["acme/widgets", "7", "--api-base-url", "https://ghe.example.com/api/v3"])).toEqual({ @@ -126,7 +126,7 @@ describe("gittensory-miner claim ledger CLI (#4290)", () => { apiBaseUrl: "https://ghe.example.com/api/v3", }); expect(parseClaimReleaseArgs(["acme/widgets", "7", "--api-base-url"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner claim release"), + error: expect.stringContaining("Usage: loopover-miner claim release"), }); }); diff --git a/test/unit/miner-cli-deny-check.test.ts b/test/unit/miner-cli-deny-check.test.ts index 2758ca473a..08cd008b7d 100644 --- a/test/unit/miner-cli-deny-check.test.ts +++ b/test/unit/miner-cli-deny-check.test.ts @@ -1,13 +1,13 @@ import { describe, expect, it, vi } from "vitest"; import { parseDenyCheckArgs, runDenyCheck } from "../../packages/gittensory-miner/lib/deny-check.js"; -describe("gittensory-miner hooks check command", () => { +describe("loopover-miner hooks check command", () => { it("parseDenyCheckArgs requires tool and JSON input", () => { expect(parseDenyCheckArgs([])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner hooks check"), + error: expect.stringContaining("Usage: loopover-miner hooks check"), }); expect(parseDenyCheckArgs(["--tool", "Write"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner hooks check"), + error: expect.stringContaining("Usage: loopover-miner hooks check"), }); expect(parseDenyCheckArgs(["--tool", "Write", "--input", "[]"])).toEqual({ error: "Tool input must be a JSON object.", diff --git a/test/unit/miner-cli-json-error-coverage.test.ts b/test/unit/miner-cli-json-error-coverage.test.ts index b66780f6b4..08c9bdb7d1 100644 --- a/test/unit/miner-cli-json-error-coverage.test.ts +++ b/test/unit/miner-cli-json-error-coverage.test.ts @@ -101,7 +101,7 @@ describe("miner CLI --json error coverage (#4836)", () => { runQueueClaimBatch(["--global-wip", "nope", "--json"], { initPortfolioQueueManager: () => ({ claimBatch: () => [], close: () => {} }) as never, }), - /Usage: gittensory-miner queue claim-batch/, + /Usage: loopover-miner queue claim-batch/, ); expectJsonError( () => @@ -137,7 +137,7 @@ describe("miner CLI --json error coverage (#4836)", () => { }), "plan_list_db", ); - expectJsonError(() => runPlanShow(["--json"]), /Usage: gittensory-miner plan show/); + expectJsonError(() => runPlanShow(["--json"]), /Usage: loopover-miner plan show/); expectJsonError( () => runPlanShow(["plan-a", "--json"], { @@ -150,7 +150,7 @@ describe("miner CLI --json error coverage (#4836)", () => { }); it("state get/set/cli failures", () => { - expectJsonError(() => runStateGet(["--json"]), /Usage: gittensory-miner state get/); + expectJsonError(() => runStateGet(["--json"]), /Usage: loopover-miner state get/); setRunState.mockImplementation(() => { throw new Error("set_failed"); }); @@ -162,8 +162,8 @@ describe("miner CLI --json error coverage (#4836)", () => { const broken = () => { throw new Error("ledger_broken"); }; - expectJsonError(() => runClaimClaim(["--json"]), /Usage: gittensory-miner claim claim/); - expectJsonError(() => runClaimRelease(["acme/widgets", "--json"]), /Usage: gittensory-miner claim release/); + expectJsonError(() => runClaimClaim(["--json"]), /Usage: loopover-miner claim claim/); + expectJsonError(() => runClaimRelease(["acme/widgets", "--json"]), /Usage: loopover-miner claim release/); expectJsonError(() => runClaimList(["--status", "bogus", "--json"]), /status must be one of/); expectJsonError( () => runClaimClaim(["acme/widgets", "1", "--json"], { openClaimLedger: broken }), @@ -214,10 +214,10 @@ describe("miner CLI --json error coverage (#4836)", () => { }); it("loop parse failure", async () => { - await expectJsonErrorAsync(() => runLoop(["--json"]), /Usage: gittensory-miner loop/); + await expectJsonErrorAsync(() => runLoop(["--json"]), /Usage: loopover-miner loop/); }); it("manage poll parse failure", async () => { - await expectJsonErrorAsync(() => runManagePoll(["--json"]), /Usage: gittensory-miner manage poll/); + await expectJsonErrorAsync(() => runManagePoll(["--json"]), /Usage: loopover-miner manage poll/); }); }); diff --git a/test/unit/miner-cli-run-state.test.ts b/test/unit/miner-cli-run-state.test.ts index 5d8a2704e9..b95722c1da 100644 --- a/test/unit/miner-cli-run-state.test.ts +++ b/test/unit/miner-cli-run-state.test.ts @@ -21,10 +21,10 @@ afterEach(() => { vi.clearAllMocks(); }); -describe("gittensory-miner state CLI", () => { +describe("loopover-miner state CLI", () => { it("parseStateGetArgs and parseStateSetArgs validate argv", () => { expect(parseStateGetArgs([])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner state get"), + error: expect.stringContaining("Usage: loopover-miner state get"), }); expect(parseStateGetArgs(["acme/widgets", "--json"])).toEqual({ repoFullName: "acme/widgets", @@ -48,7 +48,7 @@ describe("gittensory-miner state CLI", () => { apiBaseUrl: "https://ghe.example.com/api/v3", }); expect(parseStateGetArgs(["acme/widgets", "--api-base-url"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner state get"), + error: expect.stringContaining("Usage: loopover-miner state get"), }); expect(parseStateSetArgs(["acme/widgets", "planning", "--api-base-url", "https://ghe.example.com/api/v3"])).toEqual({ repoFullName: "acme/widgets", @@ -58,7 +58,7 @@ describe("gittensory-miner state CLI", () => { apiBaseUrl: "https://ghe.example.com/api/v3", }); expect(parseStateSetArgs(["acme/widgets", "planning", "--api-base-url"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner state set"), + error: expect.stringContaining("Usage: loopover-miner state set"), }); }); diff --git a/test/unit/miner-cli.test.ts b/test/unit/miner-cli.test.ts index fa6e34faa0..1b44938f19 100644 --- a/test/unit/miner-cli.test.ts +++ b/test/unit/miner-cli.test.ts @@ -45,7 +45,7 @@ afterEach(async () => { await closeFixtureServer(); }); -describe("gittensory-miner CLI helpers", () => { +describe("loopover-miner CLI helpers", () => { it("prints the package version with the node runtime", () => { const log = vi.spyOn(console, "log").mockImplementation(() => undefined); printVersion({ @@ -62,11 +62,11 @@ describe("gittensory-miner CLI helpers", () => { const log = vi.spyOn(console, "log").mockImplementation(() => undefined); printHelp({ packageName: "@loopover/miner" }); const text = log.mock.calls[0]?.[0]; - expect(text).toContain("gittensory-miner --help"); - expect(text).toContain("gittensory-miner version"); - expect(text).toContain("gittensory-miner metrics"); - expect(text).toContain("gittensory-miner migrate [--json]"); - expect(text).toContain("gittensory-miner ledger metrics"); + expect(text).toContain("loopover-miner --help"); + expect(text).toContain("loopover-miner version"); + expect(text).toContain("loopover-miner metrics"); + expect(text).toContain("loopover-miner migrate [--json]"); + expect(text).toContain("loopover-miner ledger metrics"); expect(text).toContain("--no-update-check"); }); @@ -104,7 +104,7 @@ describe("gittensory-miner CLI helpers", () => { }); }); -describe("gittensory-miner startup update check (#2331)", () => { +describe("loopover-miner startup update check (#2331)", () => { it("mirrors the mcp npm registry and upgrade command conventions", () => { expect(resolveNpmRegistryUrl({})).toBe("https://registry.npmjs.org"); expect( @@ -170,7 +170,7 @@ describe("gittensory-miner startup update check (#2331)", () => { expect(shouldSkipUpdateCheck(["version"], {})).toBe(false); }); - it("orders semver values the same way as gittensory-mcp", () => { + it("orders semver values the same way as loopover-mcp", () => { expect(compareSemver("0.1.0", "0.2.0")).toBe(-1); expect(compareSemver("0.2.0", "0.1.0")).toBe(1); expect(compareSemver("0.1.0", "0.1.0")).toBe(0); @@ -332,7 +332,7 @@ describe("gittensory-miner startup update check (#2331)", () => { GITTENSORY_NPM_REGISTRY_URL: registryUrl, }); expect(Date.now() - startedAt).toBeLessThan(2000); - expect(output).toContain("gittensory-miner --help"); + expect(output).toContain("loopover-miner --help"); expect(output).not.toContain( "npm install -g @loopover/miner@latest", ); diff --git a/test/unit/miner-deployment-doc.test.ts b/test/unit/miner-deployment-doc.test.ts index 142a8708dc..4b0220e1b2 100644 --- a/test/unit/miner-deployment-doc.test.ts +++ b/test/unit/miner-deployment-doc.test.ts @@ -10,15 +10,15 @@ describe("miner deployment guide (#2330)", () => { const doc = readFileSync(DEPLOYMENT_PATH, "utf8"); expect(doc).toContain("Laptop mode"); expect(doc).toContain("Fleet mode"); - expect(doc).toContain("gittensory-miner status"); - expect(doc).toContain("gittensory-miner doctor"); + expect(doc).toContain("loopover-miner status"); + expect(doc).toContain("loopover-miner doctor"); expect(doc).toContain("LOOPOVER_MINER_CONFIG_DIR"); expect(doc).toContain("100% client-side"); expect(doc).toContain("credentials"); expect(doc).toContain("docker build"); expect(doc).toContain("docker run"); expect(doc).toContain("packages/gittensory-miner/Dockerfile"); - expect(doc).toContain("gittensory-miner:latest"); + expect(doc).toContain("loopover-miner:latest"); expect(doc).toContain("docker-compose.yml"); }); diff --git a/test/unit/miner-deployment-docs-audit.test.ts b/test/unit/miner-deployment-docs-audit.test.ts index 69bfd8cc29..fb3e091d31 100644 --- a/test/unit/miner-deployment-docs-audit.test.ts +++ b/test/unit/miner-deployment-docs-audit.test.ts @@ -18,7 +18,7 @@ const REPO_ROOT = resolve(import.meta.dirname, "../.."); const MINER_DIR = resolve(REPO_ROOT, "packages/gittensory-miner"); const DEPLOYMENT_MD = resolve(MINER_DIR, "DEPLOYMENT.md"); const BIN_DIR = resolve(MINER_DIR, "bin"); -const BIN_ENTRY = resolve(BIN_DIR, "gittensory-miner.js"); +const BIN_ENTRY = resolve(BIN_DIR, "loopover-miner.js"); const LIB_DIR = resolve(MINER_DIR, "lib"); // gittensory-miner's coding-agent driver construction (MINER_CODING_AGENT_*) is implemented in the // gittensory-engine package it depends on, not under packages/gittensory-miner/** -- an env var read only @@ -180,7 +180,7 @@ describe("gittensory-miner DEPLOYMENT.md docs-accuracy audit (#5180)", () => { ); expect(result.ok).toBe(false); expect(result.failures).toHaveLength(1); - expect(result.failures[0]).toContain("gittensory-miner teleport"); + expect(result.failures[0]).toContain("loopover-miner teleport"); expect(result.failures[0]).toContain("not registered"); }); @@ -190,7 +190,7 @@ describe("gittensory-miner DEPLOYMENT.md docs-accuracy audit (#5180)", () => { { envVars: ["LOOPOVER_MINER_GONE"], filePaths: ["gone.yml"], subcommands: ["gone"] }, { hasEnvRead: () => false, pathExists: () => false, isRegisteredCommand: () => false }, ), - ).toThrow(/LOOPOVER_MINER_GONE[\s\S]*gone\.yml[\s\S]*gittensory-miner gone/); + ).toThrow(/LOOPOVER_MINER_GONE[\s\S]*gone\.yml[\s\S]*loopover-miner gone/); }); it("assertDeploymentDocsInSync returns the ok result without throwing when in sync", () => { diff --git a/test/unit/miner-discover-cli.test.ts b/test/unit/miner-discover-cli.test.ts index 83034cb205..b2790d1755 100644 --- a/test/unit/miner-discover-cli.test.ts +++ b/test/unit/miner-discover-cli.test.ts @@ -87,7 +87,7 @@ afterEach(() => { describe("parseDiscoverArgs (#4247)", () => { it("requires either repo targets or --search", () => { expect(parseDiscoverArgs([])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner discover"), + error: expect.stringContaining("Usage: loopover-miner discover"), }); }); @@ -126,10 +126,10 @@ describe("parseDiscoverArgs (#4247)", () => { it("rejects a --search flag missing its query and unknown options", () => { expect(parseDiscoverArgs(["--search"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner discover"), + error: expect.stringContaining("Usage: loopover-miner discover"), }); expect(parseDiscoverArgs(["--search", "--json"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner discover"), + error: expect.stringContaining("Usage: loopover-miner discover"), }); expect(parseDiscoverArgs(["acme/widgets", "--verbose"])).toEqual({ error: "Unknown option: --verbose", @@ -175,16 +175,16 @@ describe("parseDiscoverArgs (#4247)", () => { it("rejects --api-base-url / --token-env missing their value (#4784)", () => { expect(parseDiscoverArgs(["acme/widgets", "--api-base-url"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner discover"), + error: expect.stringContaining("Usage: loopover-miner discover"), }); expect(parseDiscoverArgs(["acme/widgets", "--api-base-url", "--json"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner discover"), + error: expect.stringContaining("Usage: loopover-miner discover"), }); expect(parseDiscoverArgs(["acme/widgets", "--token-env"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner discover"), + error: expect.stringContaining("Usage: loopover-miner discover"), }); expect(parseDiscoverArgs(["acme/widgets", "--token-env", "--json"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner discover"), + error: expect.stringContaining("Usage: loopover-miner discover"), }); }); }); @@ -1035,14 +1035,14 @@ describe("runDiscover (#4247)", () => { }); }); -describe("gittensory-miner discover CLI entrypoint (#4247)", () => { +describe("loopover-miner discover CLI entrypoint (#4247)", () => { it("lists the discover command in --help", () => { const output = runCapture(["--help", "--no-update-check"]); - expect(output).toContain("gittensory-miner discover"); + expect(output).toContain("loopover-miner discover"); }); it("exits 2 with a usage error when neither repo targets nor --search are given", () => { const output = runCapture(["discover"]); - expect(output).toContain("Usage: gittensory-miner discover"); + expect(output).toContain("Usage: loopover-miner discover"); }); }); diff --git a/test/unit/miner-env-file-indirection.test.ts b/test/unit/miner-env-file-indirection.test.ts index 476d5407ab..3aa4e45128 100644 --- a/test/unit/miner-env-file-indirection.test.ts +++ b/test/unit/miner-env-file-indirection.test.ts @@ -127,7 +127,7 @@ describe("loadMinerFileSecrets (#5178)", () => { } }); - describe("wired into the real CLI entry point (bin/gittensory-miner.js)", () => { + describe("wired into the real CLI entry point (bin/loopover-miner.js)", () => { it("resolves GITHUB_TOKEN_FILE end-to-end: status --json reports it without ever printing the value", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-file-secret-")); roots.push(root); diff --git a/test/unit/miner-event-ledger-cli.test.ts b/test/unit/miner-event-ledger-cli.test.ts index ffcbd53d4e..6af5204277 100644 --- a/test/unit/miner-event-ledger-cli.test.ts +++ b/test/unit/miner-event-ledger-cli.test.ts @@ -21,7 +21,7 @@ const roots: string[] = []; const ledgers: Array<{ close(): void }> = []; function tempLedger() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-event-ledger-cli-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-event-ledger-cli-")); roots.push(root); const ledger = initEventLedger(join(root, "event-ledger.sqlite3")); ledgers.push(ledger); @@ -29,7 +29,7 @@ function tempLedger() { } function tempEventDbPath() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-event-ledger-metrics-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-event-ledger-metrics-")); roots.push(root); return join(root, "event-ledger.sqlite3"); } @@ -45,7 +45,7 @@ afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); -describe("gittensory-miner event ledger CLI (#2290)", () => { +describe("loopover-miner event ledger CLI (#2290)", () => { it("parseLedgerListArgs validates argv", () => { expect(parseLedgerListArgs([])).toEqual({ json: false, @@ -154,7 +154,7 @@ describe("gittensory-miner event ledger CLI (#2290)", () => { }); }); -describe("gittensory-miner ledger metrics CLI (#4841)", () => { +describe("loopover-miner ledger metrics CLI (#4841)", () => { it("renderEventLedgerMetrics emits one sorted loopover_miner_events_total series per type", () => { const text = renderEventLedgerMetrics([ metricEntry(1, "manage_pr_update"), @@ -227,12 +227,12 @@ describe("gittensory-miner ledger metrics CLI (#4841)", () => { expect(error).not.toHaveBeenCalled(); expect(JSON.parse(String(log.mock.calls[0]?.[0]))).toEqual({ ok: false, - error: "Usage: gittensory-miner ledger metrics", + error: "Usage: loopover-miner ledger metrics", }); error.mockClear(); log.mockClear(); expect(runLedgerMetrics(["--nope"], { initEventLedger: () => tempLedger() })).toBe(2); - expect(error).toHaveBeenCalledWith("Usage: gittensory-miner ledger metrics"); + expect(error).toHaveBeenCalledWith("Usage: loopover-miner ledger metrics"); expect(log).not.toHaveBeenCalled(); }); diff --git a/test/unit/miner-feasibility-cli.test.ts b/test/unit/miner-feasibility-cli.test.ts index ad3b9e530b..9e79ec3625 100644 --- a/test/unit/miner-feasibility-cli.test.ts +++ b/test/unit/miner-feasibility-cli.test.ts @@ -37,13 +37,13 @@ describe("parseFeasibilityArgs (#4270)", () => { it("requires exactly three positional arguments", () => { expect(parseFeasibilityArgs([])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner feasibility"), + error: expect.stringContaining("Usage: loopover-miner feasibility"), }); expect(parseFeasibilityArgs(["unclaimed", "none"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner feasibility"), + error: expect.stringContaining("Usage: loopover-miner feasibility"), }); expect(parseFeasibilityArgs(["unclaimed", "none", "ready", "extra"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner feasibility"), + error: expect.stringContaining("Usage: loopover-miner feasibility"), }); }); @@ -124,10 +124,10 @@ describe("runFeasibilityCli (#4270)", () => { }); }); -describe("gittensory-miner feasibility CLI entrypoint (#4270)", () => { +describe("loopover-miner feasibility CLI entrypoint (#4270)", () => { it("lists the feasibility command in --help", () => { const output = runCapture(["--help", "--no-update-check"]); - expect(output).toContain("gittensory-miner feasibility"); + expect(output).toContain("loopover-miner feasibility"); }); it("computes a real verdict end-to-end through the compiled engine dependency", () => { @@ -137,7 +137,7 @@ describe("gittensory-miner feasibility CLI entrypoint (#4270)", () => { it("exits 2 with a usage error for a missing argument", () => { const output = runCapture(["feasibility", "unclaimed", "none"]); - expect(output).toContain("Usage: gittensory-miner feasibility"); + expect(output).toContain("Usage: loopover-miner feasibility"); }); }); diff --git a/test/unit/miner-governor-metrics-cli.test.ts b/test/unit/miner-governor-metrics-cli.test.ts index 5004c156be..356adc65a9 100644 --- a/test/unit/miner-governor-metrics-cli.test.ts +++ b/test/unit/miner-governor-metrics-cli.test.ts @@ -15,7 +15,7 @@ const roots: string[] = []; const states: Array<{ close(): void }> = []; function tempGovernorState() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-governor-metrics-cli-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-governor-metrics-cli-")); roots.push(root); const state = openGovernorState(join(root, "governor-state.sqlite3")); states.push(state); @@ -185,7 +185,7 @@ describe("runGovernorMetrics (#5187)", () => { it("rejects unexpected positional args and surfaces a store failure", async () => { const error = vi.spyOn(console, "error").mockImplementation(() => undefined); expect(await runGovernorMetrics(["extra"])).toBe(2); - expect(String(error.mock.calls[0]?.[0])).toContain("Usage: gittensory-miner governor metrics"); + expect(String(error.mock.calls[0]?.[0])).toContain("Usage: loopover-miner governor metrics"); error.mockClear(); expect( @@ -205,7 +205,7 @@ describe("runGovernorMetrics (#5187)", () => { }); it("opens and closes the default on-disk governor state when no override is supplied", async () => { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-governor-metrics-cli-default-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-governor-metrics-cli-default-")); roots.push(root); const dbPath = join(root, "governor-state.sqlite3"); const previousDbPath = process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB; diff --git a/test/unit/miner-governor-pause-cli.test.ts b/test/unit/miner-governor-pause-cli.test.ts index c076881149..4b916020a4 100644 --- a/test/unit/miner-governor-pause-cli.test.ts +++ b/test/unit/miner-governor-pause-cli.test.ts @@ -15,7 +15,7 @@ const roots: string[] = []; const states: Array<{ close(): void }> = []; function tempGovernorState() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-governor-pause-cli-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-governor-pause-cli-")); roots.push(root); const state = openGovernorState(join(root, "governor-state.sqlite3")); states.push(state); @@ -44,10 +44,10 @@ describe("parseGovernorPauseArgs (#4851)", () => { it("rejects a --reason flag missing its value", () => { expect(parseGovernorPauseArgs(["--reason"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner governor pause"), + error: expect.stringContaining("Usage: loopover-miner governor pause"), }); expect(parseGovernorPauseArgs(["--reason", "--json"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner governor pause"), + error: expect.stringContaining("Usage: loopover-miner governor pause"), }); }); @@ -67,12 +67,12 @@ describe("parseGovernorResumeArgs (#4847)", () => { it("rejects an unrecognized token", () => { expect(parseGovernorResumeArgs(["extra"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner governor resume"), + error: expect.stringContaining("Usage: loopover-miner governor resume"), }); }); }); -describe("gittensory-miner governor pause/resume/status CLI (#4851)", () => { +describe("loopover-miner governor pause/resume/status CLI (#4851)", () => { it("pauses with a reason, then resumes, using an injected governor state", async () => { const governorState = tempGovernorState(); const log = vi.spyOn(console, "log").mockImplementation(() => undefined); @@ -118,11 +118,11 @@ describe("gittensory-miner governor pause/resume/status CLI (#4851)", () => { it("resume and status reject stray positional arguments", async () => { const error = vi.spyOn(console, "error").mockImplementation(() => undefined); expect(await runGovernorResume(["extra"])).toBe(2); - expect(String(error.mock.calls[0]?.[0])).toContain("Usage: gittensory-miner governor resume"); + expect(String(error.mock.calls[0]?.[0])).toContain("Usage: loopover-miner governor resume"); error.mockClear(); expect(await runGovernorStatus(["extra"])).toBe(2); - expect(String(error.mock.calls[0]?.[0])).toContain("Usage: gittensory-miner governor status"); + expect(String(error.mock.calls[0]?.[0])).toContain("Usage: loopover-miner governor status"); }); it("#4847: --dry-run reports what pause/resume would do and returns 0 without opening the governor state", async () => { @@ -248,7 +248,7 @@ describe("gittensory-miner governor pause/resume/status CLI (#4851)", () => { }); it("opens and closes the default on-disk governor state when no override is supplied", async () => { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-governor-pause-cli-default-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-governor-pause-cli-default-")); roots.push(root); const dbPath = join(root, "governor-state.sqlite3"); const previousDbPath = process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB; diff --git a/test/unit/miner-manage-poll.test.ts b/test/unit/miner-manage-poll.test.ts index 2e5dab7c7a..4d80353f84 100644 --- a/test/unit/miner-manage-poll.test.ts +++ b/test/unit/miner-manage-poll.test.ts @@ -28,7 +28,7 @@ const roots: string[] = []; const stores: Array<{ close(): void }> = []; function tempStores() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-manage-poll-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-manage-poll-")); roots.push(root); const portfolioQueue = initPortfolioQueueStore(join(root, "portfolio-queue.sqlite3")); const eventLedger = initEventLedger(join(root, "event-ledger.sqlite3")); @@ -53,10 +53,10 @@ afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); -describe("gittensory-miner manage poll (#2323/#2325)", () => { +describe("loopover-miner manage poll (#2323/#2325)", () => { it("parseManagePollArgs validates argv", () => { expect(parseManagePollArgs([])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner manage poll"), + error: expect.stringContaining("Usage: loopover-miner manage poll"), }); expect(parseManagePollArgs(["acme/widgets", "42", "--branch", "feat/x", "--json"])).toEqual({ repoFullName: "acme/widgets", diff --git a/test/unit/miner-mcp-audit-feed.test.ts b/test/unit/miner-mcp-audit-feed.test.ts index c6c6745d8d..ee5e961d29 100644 --- a/test/unit/miner-mcp-audit-feed.test.ts +++ b/test/unit/miner-mcp-audit-feed.test.ts @@ -4,7 +4,7 @@ import { join } from "node:path"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { createMinerMcpServer } from "../../packages/gittensory-miner/bin/gittensory-miner-mcp.js"; +import { createMinerMcpServer } from "../../packages/gittensory-miner/bin/loopover-miner-mcp.js"; import { AUDIT_FEED_ENTRY_FIELDS, collectEventLedgerAuditFeed, diff --git a/test/unit/miner-mcp-client-config-doc.test.ts b/test/unit/miner-mcp-client-config-doc.test.ts index 29fb6d1297..6f75e699a4 100644 --- a/test/unit/miner-mcp-client-config-doc.test.ts +++ b/test/unit/miner-mcp-client-config-doc.test.ts @@ -14,10 +14,10 @@ function extractFirstJsonBlock(markdown: string): string { } describe("miner MCP client config example (#5163)", () => { - it("documents running gittensory-mcp and gittensory-miner-mcp together", () => { + it("documents running loopover-mcp and loopover-miner-mcp together", () => { const readme = readFileSync(README_PATH, "utf8"); expect(readme).toContain("### Client config"); - expect(readme).toContain("gittensory-mcp init-client --print claude"); + expect(readme).toContain("loopover-mcp init-client --print claude"); // Explains what each server is for, not just how to wire it up. expect(readme).toContain("contributor-workflow tools"); expect(readme).toContain("state-visibility tools"); @@ -28,11 +28,11 @@ describe("miner MCP client config example (#5163)", () => { const config = JSON.parse(extractFirstJsonBlock(readme)); expect(config.mcpServers.gittensory).toEqual({ - command: "gittensory-mcp", + command: "loopover-mcp", args: ["--stdio"], }); - expect(config.mcpServers["gittensory-miner"]).toEqual({ - command: "gittensory-miner-mcp", + expect(config.mcpServers["loopover-miner"]).toEqual({ + command: "loopover-miner-mcp", args: [], }); }); diff --git a/test/unit/miner-mcp-contract.test.ts b/test/unit/miner-mcp-contract.test.ts index a61f3a0029..3f4e2d72f4 100644 --- a/test/unit/miner-mcp-contract.test.ts +++ b/test/unit/miner-mcp-contract.test.ts @@ -7,7 +7,7 @@ import { afterAll, describe, expect, it } from "vitest"; import { createMinerMcpServer, type MinerMcpServerOptions, -} from "../../packages/gittensory-miner/bin/gittensory-miner-mcp.js"; +} from "../../packages/gittensory-miner/bin/loopover-miner-mcp.js"; import { initGovernorLedger } from "../../packages/gittensory-miner/lib/governor-ledger.js"; // The SAME secret-shape matcher the miner pack validator uses — imported from its single source of truth (rather // than hand-duplicated here) so the two stay byte-for-byte in sync instead of relying on manual vigilance. @@ -114,7 +114,7 @@ const READ_ONLY_TOOLS: ToolContract[] = [ package: { name: "@loopover/miner", version: "0.1.0" }, engine: { name: "@loopover/engine", version: "1.0.0" }, node: "v22.13.0", - stateDir: "/home/miner/.config/gittensory-miner", + stateDir: "/home/miner/.config/loopover-miner", configFile: null, driver: { provider: "claude-code", modelEnvVar: "MINER_CODING_AGENT_CLAUDE_MODEL", cliPresent: true }, }), diff --git a/test/unit/miner-mcp-governor-decisions.test.ts b/test/unit/miner-mcp-governor-decisions.test.ts index e3a6882b3d..f925a8febf 100644 --- a/test/unit/miner-mcp-governor-decisions.test.ts +++ b/test/unit/miner-mcp-governor-decisions.test.ts @@ -4,7 +4,7 @@ import { join } from "node:path"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js"; import { afterEach, describe, expect, it } from "vitest"; -import { createMinerMcpServer } from "../../packages/gittensory-miner/bin/gittensory-miner-mcp.js"; +import { createMinerMcpServer } from "../../packages/gittensory-miner/bin/loopover-miner-mcp.js"; import { initGovernorLedger } from "../../packages/gittensory-miner/lib/governor-ledger.js"; // gittensory_miner_get_governor_decisions (#5159). Driven against a REAL temp governor ledger (not a fake) so the diff --git a/test/unit/miner-mcp-scaffold.test.ts b/test/unit/miner-mcp-scaffold.test.ts index bbff0a8709..927a7e884f 100644 --- a/test/unit/miner-mcp-scaffold.test.ts +++ b/test/unit/miner-mcp-scaffold.test.ts @@ -5,7 +5,7 @@ import { createMinerMcpServer, MINER_PING_STATUS, type MinerMcpServerOptions, -} from "../../packages/gittensory-miner/bin/gittensory-miner-mcp.js"; +} from "../../packages/gittensory-miner/bin/loopover-miner-mcp.js"; import { collectPortfolioDashboard } from "../../packages/gittensory-miner/lib/portfolio-dashboard.js"; // Tests for the gittensory-miner MCP server: the #5153 ping scaffold and the #5155 read-only @@ -345,7 +345,7 @@ const FAKE_STATUS = { package: { name: "@loopover/miner", version: "0.1.0" }, engine: { name: "@loopover/engine", version: "1.0.0" }, node: "v22.13.0", - stateDir: "/home/miner/.config/gittensory-miner", + stateDir: "/home/miner/.config/loopover-miner", configFile: null, driver: { provider: "claude-code", modelEnvVar: "MINER_CODING_AGENT_CLAUDE_MODEL", cliPresent: true }, }; diff --git a/test/unit/miner-mcp-tool-docs-parity.test.ts b/test/unit/miner-mcp-tool-docs-parity.test.ts index 5cc9f4a1c5..7d8dba6298 100644 --- a/test/unit/miner-mcp-tool-docs-parity.test.ts +++ b/test/unit/miner-mcp-tool-docs-parity.test.ts @@ -2,7 +2,7 @@ import { readFileSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; -const MCP_BIN_PATH = join(process.cwd(), "packages/gittensory-miner/bin/gittensory-miner-mcp.js"); +const MCP_BIN_PATH = join(process.cwd(), "packages/gittensory-miner/bin/loopover-miner-mcp.js"); const README_PATH = join(process.cwd(), "packages/gittensory-miner/README.md"); const CODING_AGENT_DRIVER_DOC_PATH = join(process.cwd(), "packages/gittensory-miner/docs/coding-agent-driver.md"); diff --git a/test/unit/miner-metrics-cli.test.ts b/test/unit/miner-metrics-cli.test.ts index 1fa20ea414..44ea30efaf 100644 --- a/test/unit/miner-metrics-cli.test.ts +++ b/test/unit/miner-metrics-cli.test.ts @@ -13,7 +13,7 @@ const roots: string[] = []; const ledgers: Array<{ close(): void }> = []; function tempLedger(): PredictionLedger { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-metrics-cli-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-metrics-cli-")); roots.push(root); const ledger = initPredictionLedger(join(root, "prediction-ledger.sqlite3")); ledgers.push(ledger); @@ -21,7 +21,7 @@ function tempLedger(): PredictionLedger { } function tempDbPath() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-metrics-cli-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-metrics-cli-")); roots.push(root); return join(root, "prediction-ledger.sqlite3"); } @@ -36,7 +36,7 @@ afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); -describe("gittensory-miner metrics CLI (#4838)", () => { +describe("loopover-miner metrics CLI (#4838)", () => { it("collectPredictionMetricRows projects ledger rows onto the renderer's conclusion-only shape", () => { const ledger = tempLedger(); appendPrediction(ledger, 1, "merge"); @@ -90,12 +90,12 @@ describe("gittensory-miner metrics CLI (#4838)", () => { expect(error).not.toHaveBeenCalled(); expect(JSON.parse(String(log.mock.calls[0]?.[0]))).toEqual({ ok: false, - error: "Usage: gittensory-miner metrics", + error: "Usage: loopover-miner metrics", }); error.mockClear(); log.mockClear(); expect(runMetrics(["--nope"], { initPredictionLedger: () => tempLedger() })).toBe(2); - expect(error).toHaveBeenCalledWith("Usage: gittensory-miner metrics"); + expect(error).toHaveBeenCalledWith("Usage: loopover-miner metrics"); expect(log).not.toHaveBeenCalled(); }); diff --git a/test/unit/miner-operations-runbook.test.ts b/test/unit/miner-operations-runbook.test.ts index ab81fc4e58..7427f1ebb6 100644 --- a/test/unit/miner-operations-runbook.test.ts +++ b/test/unit/miner-operations-runbook.test.ts @@ -10,7 +10,7 @@ const deploymentDocPath = join(repoRoot, "packages/gittensory-miner/DEPLOYMENT.m describe("miner operations runbook (#4875)", () => { it("covers the three operational scenarios from the issue plus the busy_timeout guarantee", () => { const doc = readFileSync(runbookPath, "utf8"); - expect(doc).toContain("# gittensory-miner — operational runbook"); + expect(doc).toContain("# loopover-miner — operational runbook"); expect(doc).toMatch(/ledger corrupted|corrupted_\*_row|corrupted_/i); expect(doc).toMatch(/two miners collided|two miners on one state/i); expect(doc).toMatch(/migrate.*upgrade|package upgrade/i); diff --git a/test/unit/miner-package-skeleton.test.ts b/test/unit/miner-package-skeleton.test.ts index 04bac78591..c44b5fd8a2 100644 --- a/test/unit/miner-package-skeleton.test.ts +++ b/test/unit/miner-package-skeleton.test.ts @@ -25,8 +25,8 @@ function readPackageJson(root: string): PackageJson { return JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as PackageJson; } -describe("gittensory-miner package skeleton (#2287)", () => { - it("mirrors gittensory-mcp packaging conventions", () => { +describe("loopover-miner package skeleton (#2287)", () => { + it("mirrors loopover-mcp packaging conventions", () => { const miner = readPackageJson(minerRoot); const mcp = readPackageJson(mcpRoot); @@ -34,18 +34,18 @@ describe("gittensory-miner package skeleton (#2287)", () => { expect(miner.license).toBe("AGPL-3.0-only"); expect(miner.type).toBe("module"); expect(miner.bin).toEqual({ - "gittensory-miner": "bin/gittensory-miner.js", - "gittensory-miner-mcp": "bin/gittensory-miner-mcp.js", + "loopover-miner": "bin/loopover-miner.js", + "loopover-miner-mcp": "bin/loopover-miner-mcp.js", }); expect(miner.publishConfig).toEqual(mcp.publishConfig); expect(miner.dependencies["@loopover/engine"]).toBeDefined(); expect(miner.engines.node).toMatch(/^>=22(?:\.\d+){0,2}$/); expect(miner.files).toEqual(expect.arrayContaining(["bin", "lib"])); - expect(miner.scripts.build.startsWith("node --check bin/gittensory-miner.js")).toBe(true); + expect(miner.scripts.build.startsWith("node --check bin/loopover-miner.js")).toBe(true); }); it("starts the CLI bin with a node shebang", () => { - const bin = readFileSync(join(minerRoot, "bin/gittensory-miner.js"), "utf8"); + const bin = readFileSync(join(minerRoot, "bin/loopover-miner.js"), "utf8"); expect(bin.startsWith("#!/usr/bin/env node\n")).toBe(true); }); @@ -63,7 +63,7 @@ describe("gittensory-miner package skeleton (#2287)", () => { }); it("serves --help and --version from the bin entry", () => { - expect(runCapture(["--help", "--no-update-check"])).toContain("gittensory-miner --help"); + expect(runCapture(["--help", "--no-update-check"])).toContain("loopover-miner --help"); expect(runCapture(["--version", "--no-update-check"])).toContain("@loopover/miner/"); expect( runCapture(["--version", "--no-update-check"], { @@ -76,7 +76,7 @@ describe("gittensory-miner package skeleton (#2287)", () => { const readme = readFileSync(readmePath, "utf8"); expect(readme).toContain("foundation phase"); expect(readme).toContain("npm link --workspace @loopover/miner"); - expect(readme).toContain("gittensory-miner --help"); - expect(readme).toContain("gittensory-miner --version"); + expect(readme).toContain("loopover-miner --help"); + expect(readme).toContain("loopover-miner --version"); }); }); diff --git a/test/unit/miner-plan-store-cli.test.ts b/test/unit/miner-plan-store-cli.test.ts index 0bf5195874..61f54b9219 100644 --- a/test/unit/miner-plan-store-cli.test.ts +++ b/test/unit/miner-plan-store-cli.test.ts @@ -24,7 +24,7 @@ const PLAN: PlanDag = { }; function tempStore() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-plan-store-cli-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-plan-store-cli-")); roots.push(root); const store = openPlanStore(join(root, "plan-store.sqlite3")); stores.push(store); @@ -37,7 +37,7 @@ afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); -describe("gittensory-miner plan store CLI (#2318)", () => { +describe("loopover-miner plan store CLI (#2318)", () => { it("parsePlanListArgs and parsePlanShowArgs validate argv", () => { expect(parsePlanListArgs(["--status", "running", "--json"])).toEqual({ json: true, @@ -51,7 +51,7 @@ describe("gittensory-miner plan store CLI (#2318)", () => { error: expect.stringMatching(/Invalid status/), }); expect(parsePlanShowArgs([])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner plan show"), + error: expect.stringContaining("Usage: loopover-miner plan show"), }); }); diff --git a/test/unit/miner-portfolio-dashboard.test.ts b/test/unit/miner-portfolio-dashboard.test.ts index b552c15767..de0d965215 100644 --- a/test/unit/miner-portfolio-dashboard.test.ts +++ b/test/unit/miner-portfolio-dashboard.test.ts @@ -70,7 +70,7 @@ describe("parsePortfolioDashboardArgs (#4287)", () => { expect(parsePortfolioDashboardArgs([])).toEqual({ json: false }); expect(parsePortfolioDashboardArgs(["--json"])).toEqual({ json: true }); expect(parsePortfolioDashboardArgs(["--nope"])).toEqual({ error: expect.stringContaining("Unknown option") }); - expect(parsePortfolioDashboardArgs(["extra"])).toEqual({ error: expect.stringContaining("Usage: gittensory-miner queue dashboard") }); + expect(parsePortfolioDashboardArgs(["extra"])).toEqual({ error: expect.stringContaining("Usage: loopover-miner queue dashboard") }); }); }); diff --git a/test/unit/miner-portfolio-queue-cli.test.ts b/test/unit/miner-portfolio-queue-cli.test.ts index d0e712a414..8d29118358 100644 --- a/test/unit/miner-portfolio-queue-cli.test.ts +++ b/test/unit/miner-portfolio-queue-cli.test.ts @@ -29,7 +29,7 @@ const roots: string[] = []; const stores: Array<{ close(): void }> = []; function tempQueueStore() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-portfolio-queue-cli-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-portfolio-queue-cli-")); roots.push(root); const store = initPortfolioQueueStore(join(root, "portfolio-queue.sqlite3")); stores.push(store); @@ -43,7 +43,7 @@ afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); -describe("gittensory-miner portfolio queue CLI (#2292)", () => { +describe("loopover-miner portfolio queue CLI (#2292)", () => { it("parseQueueListArgs, parseQueueNextArgs, and parseQueueDoneArgs validate argv", () => { expect(parseQueueListArgs([])).toEqual({ json: false, repoFullName: null }); expect(parseQueueListArgs(["--repo", "acme/widgets", "--json"])).toEqual({ @@ -58,7 +58,7 @@ describe("gittensory-miner portfolio queue CLI (#2292)", () => { json: true, }); expect(parseQueueDoneArgs(["acme/widgets"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner queue done"), + error: expect.stringContaining("Usage: loopover-miner queue done"), }); }); @@ -255,13 +255,13 @@ describe("gittensory-miner portfolio queue CLI (#2292)", () => { perRepoWipCap: 2, }); expect(parseQueueNextArgs(["--global-wip", "not-a-number"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner queue next"), + error: expect.stringContaining("Usage: loopover-miner queue next"), }); expect(parseQueueNextArgs(["--global-wip"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner queue next"), + error: expect.stringContaining("Usage: loopover-miner queue next"), }); expect(parseQueueNextArgs(["extra-positional"])).toEqual({ - error: expect.stringContaining("Usage: gittensory-miner queue next"), + error: expect.stringContaining("Usage: loopover-miner queue next"), }); expect(parseQueueNextArgs(["--bogus"])).toEqual({ error: "Unknown option: --bogus" }); }); @@ -443,7 +443,7 @@ describe("gittensory-miner portfolio queue CLI (#2292)", () => { it("rejects unexpected positional args and surfaces a store failure", () => { const error = vi.spyOn(console, "error").mockImplementation(() => undefined); expect(runQueueMetrics(["extra"])).toBe(2); - expect(String(error.mock.calls[0]?.[0])).toContain("Usage: gittensory-miner queue metrics"); + expect(String(error.mock.calls[0]?.[0])).toContain("Usage: loopover-miner queue metrics"); error.mockClear(); expect( diff --git a/test/unit/miner-purge-cli.test.ts b/test/unit/miner-purge-cli.test.ts index 2b6f47af8a..c6b9e17d18 100644 --- a/test/unit/miner-purge-cli.test.ts +++ b/test/unit/miner-purge-cli.test.ts @@ -17,7 +17,7 @@ const roots: string[] = []; const closeables: Array<{ close(): void }> = []; function tempDir() { - const root = mkdtempSync(join(tmpdir(), "gittensory-miner-purge-cli-")); + const root = mkdtempSync(join(tmpdir(), "loopover-miner-purge-cli-")); roots.push(root); return root; } @@ -35,7 +35,7 @@ afterEach(() => { describe("parsePurgeArgs (#5564)", () => { it("requires --repo", () => { - expect(parsePurgeArgs([])).toEqual({ error: expect.stringContaining("Usage: gittensory-miner purge") }); + expect(parsePurgeArgs([])).toEqual({ error: expect.stringContaining("Usage: loopover-miner purge") }); }); it("parses --repo, --dry-run, and --json together", () => { @@ -59,8 +59,8 @@ describe("parsePurgeArgs (#5564)", () => { }); it("rejects a --repo flag missing its value", () => { - expect(parsePurgeArgs(["--repo"])).toEqual({ error: expect.stringContaining("Usage: gittensory-miner purge") }); - expect(parsePurgeArgs(["--repo", "--json"])).toEqual({ error: expect.stringContaining("Usage: gittensory-miner purge") }); + expect(parsePurgeArgs(["--repo"])).toEqual({ error: expect.stringContaining("Usage: loopover-miner purge") }); + expect(parsePurgeArgs(["--repo", "--json"])).toEqual({ error: expect.stringContaining("Usage: loopover-miner purge") }); }); it("rejects an unknown option", () => { @@ -229,7 +229,7 @@ describe("runPurge --dry-run (#5564)", () => { it("prints an argument error without opening or counting anything", () => { const error = vi.spyOn(console, "error").mockImplementation(() => undefined); expect(runPurge([])).toBe(2); - expect(error).toHaveBeenCalledWith(expect.stringContaining("Usage: gittensory-miner purge")); + expect(error).toHaveBeenCalledWith(expect.stringContaining("Usage: loopover-miner purge")); }); it("opens the real default on-disk stores in dry-run when no resolveDbPaths override is supplied", () => { diff --git a/test/unit/miner-wire-cli-modules.test.ts b/test/unit/miner-wire-cli-modules.test.ts index 309f61621d..e183bfc3dc 100644 --- a/test/unit/miner-wire-cli-modules.test.ts +++ b/test/unit/miner-wire-cli-modules.test.ts @@ -303,7 +303,7 @@ describe("orb export — wires the anonymized telemetry batch-builder (#4833)", }); it("REGRESSION (#5681 follow-up): when openOrbExportStore/initEventLedger/sendAmsExportBatch are all omitted, runOrbExportCli falls back to the REAL defaults", async () => { - // Isolated tmp DB paths (never touches a real ~/.config/gittensory-miner), matching the pattern already + // Isolated tmp DB paths (never touches a real ~/.config/loopover-miner), matching the pattern already // established for the analogous getAttemptHistory/recordOwnSubmission DI-fallback tests. const dir = tempDir(); vi.stubEnv("LOOPOVER_MINER_ORB_EXPORT_DB", join(dir, "orb-export.sqlite3")); diff --git a/test/unit/product-usage-mcp-adoption.test.ts b/test/unit/product-usage-mcp-adoption.test.ts index 5a84388840..c1ce81c3e8 100644 --- a/test/unit/product-usage-mcp-adoption.test.ts +++ b/test/unit/product-usage-mcp-adoption.test.ts @@ -10,7 +10,7 @@ describe("MCP compatibility adoption summaries", () => { eventName: "local_branch_analysis_completed", actor: "oktofeesh1", sessionId: "cli-session", - clientName: "gittensory-mcp-cli", + clientName: "loopover-mcp-cli", metadata: { packageVersion: "0.2.1", protocolVersion: "2025-03-26", @@ -58,7 +58,7 @@ describe("MCP compatibility adoption summaries", () => { surface: "mcp", eventName: "mcp_request", actor: "alice", - clientName: "gittensory-mcp", + clientName: "loopover-mcp", clientVersion: "0.3.0+alice", metadata: { packageVersion: "0.3.0+alice" }, occurredAt: "2026-05-28T00:03:00.000Z", @@ -67,7 +67,7 @@ describe("MCP compatibility adoption summaries", () => { surface: "mcp", eventName: "mcp_request", actor: "bob", - clientName: "gittensory-mcp", + clientName: "loopover-mcp", clientVersion: "v0.4.0-beta.1+bob", metadata: { packageVersion: "v0.4.0-beta.1+bob" }, occurredAt: "2026-05-28T00:04:00.000Z", @@ -76,7 +76,7 @@ describe("MCP compatibility adoption summaries", () => { surface: "mcp", eventName: "mcp_request", actor: "carol", - clientName: "gittensory-mcp", + clientName: "loopover-mcp", clientVersion: "canary+carol", metadata: { packageVersion: "canary+carol" }, occurredAt: "2026-05-28T00:05:00.000Z", diff --git a/test/unit/support/mcp-cli-harness.ts b/test/unit/support/mcp-cli-harness.ts index 3bc32e3218..af9ccea49c 100644 --- a/test/unit/support/mcp-cli-harness.ts +++ b/test/unit/support/mcp-cli-harness.ts @@ -5,7 +5,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { expect } from "vitest"; -export const bin = join(process.cwd(), "packages/gittensory-mcp/bin/gittensory-mcp.js"); +export const bin = join(process.cwd(), "packages/gittensory-mcp/bin/loopover-mcp.js"); let server: Server | null = null; export async function closeFixtureServer() { diff --git a/test/unit/support/miner-cli-harness.ts b/test/unit/support/miner-cli-harness.ts index fc5b282a35..7ef54f0d88 100644 --- a/test/unit/support/miner-cli-harness.ts +++ b/test/unit/support/miner-cli-harness.ts @@ -21,7 +21,7 @@ export type CliProcessResult = { export const bin = join( process.cwd(), - "packages/gittensory-miner/bin/gittensory-miner.js", + "packages/gittensory-miner/bin/loopover-miner.js", ); let server: Server | null = null; diff --git a/test/unit/worker-entry-boundary.test.ts b/test/unit/worker-entry-boundary.test.ts index 1a06395737..85d7551f68 100644 --- a/test/unit/worker-entry-boundary.test.ts +++ b/test/unit/worker-entry-boundary.test.ts @@ -7,7 +7,7 @@ const root = resolve(dirname(fileURLToPath(import.meta.url)), "../.."); const srcRoot = join(root, "src"); const WORKER_ENTRY = join(srcRoot, "index.ts"); -const MCP_BIN = join(root, "packages/gittensory-mcp/bin/gittensory-mcp.js"); +const MCP_BIN = join(root, "packages/gittensory-mcp/bin/loopover-mcp.js"); const FORBIDDEN_PATH = /(?:^|\/)visual-agent\//; const FORBIDDEN_IDENTIFIERS = /\b(?:pixelmatch|pngjs|visual-diff|gifenc|sharp)\b/; From fd24ae4ff27eda4e9edf12ffe331883241353f4f Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 14 Jul 2026 02:15:11 -0700 Subject: [PATCH 2/2] test(miner): cover the manage-status positional-argument usage error parseManageStatusArgs's "Usage: loopover-miner manage status [--json]" error path (a stray non-flag argument) had no covering test -- only the sibling "Unknown option" (flag-shaped) branch was exercised. --- test/unit/miner-manage-status.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/unit/miner-manage-status.test.ts b/test/unit/miner-manage-status.test.ts index 3b2a958fb8..a73ab416d0 100644 --- a/test/unit/miner-manage-status.test.ts +++ b/test/unit/miner-manage-status.test.ts @@ -280,4 +280,10 @@ describe("gittensory-miner manage status (#2325)", () => { expect(runManageStatus(["--verbose"])).toBe(2); expect(String(error.mock.calls[0]?.[0])).toContain("Unknown option"); }); + + it("rejects a stray positional argument with usage", () => { + const error = vi.spyOn(console, "error").mockImplementation(() => {}); + expect(runManageStatus(["acme/widgets"])).toBe(2); + expect(String(error.mock.calls[0]?.[0])).toContain("Usage: loopover-miner manage status [--json]"); + }); });