Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions packages/loopover-miner/lib/pr-number-parse.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export function parsePrNumberFromExecResult(
execResult: { stdout?: string | undefined; code?: number | null | undefined; timedOut?: boolean | undefined } | null | undefined,
repoFullName: string,
): number | null;
/** `gh pr create` (local-write-tools.ts's `buildOpenPrSpec` -- no `--json` flag) prints the created PR's own
* URL to stdout on success; this is `gh`'s real, documented, stable CLI behavior, not an invented contract.
* Scoped to the exact target repo so an unrelated URL elsewhere in stdout/stderr noise can never match.
*/
export declare function parsePrNumberFromExecResult(execResult: {
stdout?: string | undefined;
code?: number | null | undefined;
timedOut?: boolean | undefined;
} | null | undefined, repoFullName: string): number | null;
23 changes: 10 additions & 13 deletions packages/loopover-miner/lib/pr-number-parse.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions packages/loopover-miner/lib/pr-number-parse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Shared PR-number extraction from a real `gh pr create` executeLocalWrite result (#4848). `gh pr create`
// prints the new PR's URL to stdout on success -- this is the one place that URL is authoritatively parsed,
// so loop-cli.js's CI/gate-status polling and attempt-cli.js's post-submission claim-conflict check agree on
// exactly how a PR number is recovered from a real command's raw output.

/** `gh pr create` (local-write-tools.ts's `buildOpenPrSpec` -- no `--json` flag) prints the created PR's own
* URL to stdout on success; this is `gh`'s real, documented, stable CLI behavior, not an invented contract.
* Scoped to the exact target repo so an unrelated URL elsewhere in stdout/stderr noise can never match.
*/
export function parsePrNumberFromExecResult(
execResult: { stdout?: string | undefined; code?: number | null | undefined; timedOut?: boolean | undefined } | null | undefined,
repoFullName: string,
): number | null {
if (!execResult || execResult.timedOut || execResult.code !== 0 || typeof execResult.stdout !== "string") {
return null;
}
const escapedRepo = repoFullName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const match = execResult.stdout.match(new RegExp(`github\\.com/${escapedRepo}/pull/(\\d+)`));
if (!match) return null;
const prNumber = Number(match[1]);
return Number.isInteger(prNumber) && prNumber > 0 ? prNumber : null;
}
12 changes: 10 additions & 2 deletions packages/loopover-miner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,27 @@
"schema",
"DEPLOYMENT.md",
"Dockerfile",
"expected-engine.version"
"expected-engine.version",
"!bin/**/*.ts",
"!lib/**/*.ts",
"bin/**/*.d.ts",
"lib/**/*.d.ts"
],
"scripts": {
"benchmark": "node scripts/benchmark.mjs",
"cross-repo-eval": "node scripts/cross-repo-evaluation.mjs",
"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/chat-action-dispatch.js && node --check lib/chat-action-registry.js && node --check lib/chat-discover-attempt-actions.js && node --check lib/chat-governor-actions.js && node --check lib/chat-portfolio-actions.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/contribution-profile.js && node --check lib/contribution-profile-cache.js && node --check lib/contribution-profile-extract.js && node --check lib/contribution-profile-filter.js && node --check lib/cross-repo-evaluation.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/discovery-index-client.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-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-pause-cli.js && node --check lib/governor-run-halt.js && node --check lib/governor-state.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-bridge.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/sentry.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": "tsc -p tsconfig.json && 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/chat-action-dispatch.js && node --check lib/chat-action-registry.js && node --check lib/chat-discover-attempt-actions.js && node --check lib/chat-governor-actions.js && node --check lib/chat-portfolio-actions.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/contribution-profile.js && node --check lib/contribution-profile-cache.js && node --check lib/contribution-profile-extract.js && node --check lib/contribution-profile-filter.js && node --check lib/cross-repo-evaluation.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/discovery-index-client.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-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-pause-cli.js && node --check lib/governor-run-halt.js && node --check lib/governor-state.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-bridge.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/sentry.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": "^3.4.0",
"@modelcontextprotocol/sdk": "1.29.0",
"@sentry/node": "^10.63.0",
"zod": "^4.4.3"
},
"devDependencies": {
"@types/node": "^22.20.0",
"typescript": "^5.9.3"
},
"engines": {
"node": ">=22.13.0"
}
Expand Down
31 changes: 31 additions & 0 deletions packages/loopover-miner/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"types": ["node"],
"declaration": true,
// Inline (not a separate .js.map) so the compiled output stays exactly the same file set the
// package has always shipped -- no new file type to teach the npm-pack allowlist about. Vitest's
// v8 coverage provider still remaps through it fine, attributing coverage to the .ts source.
"inlineSourceMap": true,
"noEmit": false,
// Overrides the root config's "dist" so each converted file compiles in place next to its .ts
// source (e.g. lib/foo.ts -> lib/foo.js) -- the package's published bin/lib layout never changes
// as more files convert, so no consumer (in this repo or published) ever needs a different import
// path depending on a given file's migration status.
"rootDir": ".",
"outDir": ".",
// Without this, the inherited root value ("./.tsbuildinfo") resolves relative to the ROOT config's
// location, not this one -- both packages would then read/write the exact same cache file at the
// repo root and corrupt each other's incremental state.
"tsBuildInfoFile": "./.tsbuildinfo"
},
// Only files already converted to real TypeScript are included -- everything else in bin/lib stays
// plain, hand-maintained .js + .d.ts until its own migration PR lands (#7290). No edits needed here as
// later phases convert more files: the glob picks them up automatically.
"include": ["bin/**/*.ts", "lib/**/*.ts"],
// Without this, tsc's default exclude list (which always adds outDir) resolves to "." -- the whole
// package root -- and silently excludes every include match, since outDir is "." for in-place emit.
"exclude": []
}
2 changes: 1 addition & 1 deletion test/unit/miner-package-skeleton.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe("loopover-miner package skeleton (#2287)", () => {
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/loopover-miner.js")).toBe(true);
expect(miner.scripts.build.startsWith("tsc -p tsconfig.json && node --check bin/loopover-miner.js")).toBe(true);
});

it("starts the CLI bin with a node shebang", () => {
Expand Down
10 changes: 9 additions & 1 deletion vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export default defineConfig({
"src/**/*.ts",
"packages/loopover-engine/src/**/*.ts",
"packages/loopover-miner/lib/**/*.js",
// Files already converted to real TypeScript (#7290) execute as the compiled .js above, but
// v8's coverage provider remaps through the inline sourcemap tsc emits, attributing coverage to
// the .ts source instead -- this entry is what keeps that remapped file in the report.
"packages/loopover-miner/lib/**/*.ts",
"packages/discovery-index/src/**/*.ts",
// review-enrichment is a standalone (non-workspace) package with its own node:test suite; its
// coverage is collected separately via `npm run rees:coverage` (c8 over the built dist, remapped
Expand All @@ -40,7 +44,11 @@ export default defineConfig({
// as a side effect of import) -- like the main app's own src/server.ts, it's exercised by a Docker
// build+boot path, not unit-coverable without actually binding a port. See codecov.yml's matching
// ignore entry; app.ts (everything server.ts wires together) is what tests actually import.
exclude: ["src/env.d.ts", "apps/**", "packages/discovery-index/src/server.ts"],
//
// packages/loopover-miner/lib/**/*.ts (above) also glob-matches its own still-hand-maintained
// *.d.ts siblings (a ".d.ts" path ends in ".ts" too) -- those aren't real modules and can't be
// parsed as coverage source, so they're excluded the same way src/env.d.ts already is.
exclude: ["src/env.d.ts", "apps/**", "packages/discovery-index/src/server.ts", "packages/loopover-miner/lib/**/*.d.ts"],
// Emit lcov for Codecov to compute patch (changed-lines) coverage.
reporter: ["text", "lcov"],
// The 99% requirement now lives in codecov.yml as a *patch* gate (changed
Expand Down
Loading