@loopover/miner 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/DEPLOYMENT.md +156 -0
  2. package/Dockerfile +38 -0
  3. package/README.md +269 -0
  4. package/bin/gittensory-miner-mcp.d.ts +64 -0
  5. package/bin/gittensory-miner-mcp.js +279 -0
  6. package/bin/gittensory-miner.js +196 -0
  7. package/docs/coding-agent-driver.md +140 -0
  8. package/docs/config-precedence.md +96 -0
  9. package/docs/cross-repo-discovery-phase1.md +55 -0
  10. package/docs/discovery-index-contract.md +60 -0
  11. package/docs/discovery-plane-operator-guide.md +101 -0
  12. package/docs/env-reference.md +30 -0
  13. package/docs/fleet-run-manifest.md +50 -0
  14. package/docs/miner-goal-spec.md +76 -0
  15. package/docs/miner-selfimprove-calibration.md +105 -0
  16. package/docs/observability.md +60 -0
  17. package/docs/operations-runbook.md +209 -0
  18. package/docs/repo-agnostic-capability-audit.md +129 -0
  19. package/docs/unattended-scheduling.md +107 -0
  20. package/expected-engine.version +1 -0
  21. package/lib/ams-policy.d.ts +20 -0
  22. package/lib/ams-policy.js +68 -0
  23. package/lib/attempt-cli.d.ts +99 -0
  24. package/lib/attempt-cli.js +523 -0
  25. package/lib/attempt-input-builder.d.ts +24 -0
  26. package/lib/attempt-input-builder.js +91 -0
  27. package/lib/attempt-log.d.ts +37 -0
  28. package/lib/attempt-log.js +177 -0
  29. package/lib/attempt-runner.d.ts +59 -0
  30. package/lib/attempt-runner.js +164 -0
  31. package/lib/attempt-worktree.d.ts +31 -0
  32. package/lib/attempt-worktree.js +94 -0
  33. package/lib/calibration-cli.d.ts +1 -0
  34. package/lib/calibration-cli.js +92 -0
  35. package/lib/calibration-run.d.ts +161 -0
  36. package/lib/calibration-run.js +232 -0
  37. package/lib/calibration-types.d.ts +46 -0
  38. package/lib/calibration-types.js +74 -0
  39. package/lib/calibration.d.ts +24 -0
  40. package/lib/calibration.js +99 -0
  41. package/lib/ci-poller.d.ts +33 -0
  42. package/lib/ci-poller.js +234 -0
  43. package/lib/claim-adjudication.d.ts +21 -0
  44. package/lib/claim-adjudication.js +36 -0
  45. package/lib/claim-conflict-resolver.d.ts +29 -0
  46. package/lib/claim-conflict-resolver.js +101 -0
  47. package/lib/claim-ledger-cli.d.ts +59 -0
  48. package/lib/claim-ledger-cli.js +320 -0
  49. package/lib/claim-ledger-expiry.d.ts +20 -0
  50. package/lib/claim-ledger-expiry.js +41 -0
  51. package/lib/claim-ledger.d.ts +63 -0
  52. package/lib/claim-ledger.js +303 -0
  53. package/lib/cli-error.d.ts +3 -0
  54. package/lib/cli-error.js +27 -0
  55. package/lib/cli.d.ts +3 -0
  56. package/lib/cli.js +72 -0
  57. package/lib/coding-agent-construction.d.ts +17 -0
  58. package/lib/coding-agent-construction.js +103 -0
  59. package/lib/coding-agent-house-rules.d.ts +24 -0
  60. package/lib/coding-agent-house-rules.js +64 -0
  61. package/lib/coding-task-spec.d.ts +44 -0
  62. package/lib/coding-task-spec.js +183 -0
  63. package/lib/config-precedence.d.ts +25 -0
  64. package/lib/config-precedence.js +38 -0
  65. package/lib/deny-check.d.ts +11 -0
  66. package/lib/deny-check.js +76 -0
  67. package/lib/deny-hook-synthesis.d.ts +93 -0
  68. package/lib/deny-hook-synthesis.js +399 -0
  69. package/lib/deny-hooks.d.ts +28 -0
  70. package/lib/deny-hooks.js +155 -0
  71. package/lib/deployment-docs-audit.d.ts +41 -0
  72. package/lib/deployment-docs-audit.js +115 -0
  73. package/lib/discover-cli.d.ts +94 -0
  74. package/lib/discover-cli.js +284 -0
  75. package/lib/discovery-throttle.d.ts +8 -0
  76. package/lib/discovery-throttle.js +33 -0
  77. package/lib/env-file-indirection.d.ts +4 -0
  78. package/lib/env-file-indirection.js +45 -0
  79. package/lib/event-ledger-cli.d.ts +82 -0
  80. package/lib/event-ledger-cli.js +266 -0
  81. package/lib/event-ledger.d.ts +37 -0
  82. package/lib/event-ledger.js +210 -0
  83. package/lib/execute-local-write.d.ts +14 -0
  84. package/lib/execute-local-write.js +50 -0
  85. package/lib/feasibility-cli.d.ts +25 -0
  86. package/lib/feasibility-cli.js +80 -0
  87. package/lib/forge-config.d.ts +17 -0
  88. package/lib/forge-config.js +37 -0
  89. package/lib/governor-action-mode.d.ts +26 -0
  90. package/lib/governor-action-mode.js +47 -0
  91. package/lib/governor-chokepoint-persisted.d.ts +18 -0
  92. package/lib/governor-chokepoint-persisted.js +46 -0
  93. package/lib/governor-chokepoint.d.ts +14 -0
  94. package/lib/governor-chokepoint.js +52 -0
  95. package/lib/governor-kill-switch.d.ts +26 -0
  96. package/lib/governor-kill-switch.js +47 -0
  97. package/lib/governor-ledger-cli.d.ts +32 -0
  98. package/lib/governor-ledger-cli.js +155 -0
  99. package/lib/governor-ledger.d.ts +46 -0
  100. package/lib/governor-ledger.js +203 -0
  101. package/lib/governor-open-pr.d.ts +21 -0
  102. package/lib/governor-open-pr.js +27 -0
  103. package/lib/governor-pause-cli.d.ts +23 -0
  104. package/lib/governor-pause-cli.js +171 -0
  105. package/lib/governor-run-halt.d.ts +37 -0
  106. package/lib/governor-run-halt.js +58 -0
  107. package/lib/governor-state.d.ts +63 -0
  108. package/lib/governor-state.js +363 -0
  109. package/lib/governor-write-rate-limit.d.ts +30 -0
  110. package/lib/governor-write-rate-limit.js +64 -0
  111. package/lib/harness-submission-trigger.d.ts +69 -0
  112. package/lib/harness-submission-trigger.js +138 -0
  113. package/lib/http-retry.d.ts +12 -0
  114. package/lib/http-retry.js +52 -0
  115. package/lib/laptop-init.d.ts +53 -0
  116. package/lib/laptop-init.js +332 -0
  117. package/lib/live-issue-snapshot.d.ts +16 -0
  118. package/lib/live-issue-snapshot.js +117 -0
  119. package/lib/local-store.d.ts +18 -0
  120. package/lib/local-store.js +62 -0
  121. package/lib/logger.d.ts +58 -0
  122. package/lib/logger.js +167 -0
  123. package/lib/loop-cli.d.ts +66 -0
  124. package/lib/loop-cli.js +540 -0
  125. package/lib/loop-closure.d.ts +35 -0
  126. package/lib/loop-closure.js +66 -0
  127. package/lib/loop-reentry.d.ts +51 -0
  128. package/lib/loop-reentry.js +124 -0
  129. package/lib/manage-poll.d.ts +79 -0
  130. package/lib/manage-poll.js +254 -0
  131. package/lib/manage-status.d.ts +70 -0
  132. package/lib/manage-status.js +241 -0
  133. package/lib/metrics-cli.d.ts +9 -0
  134. package/lib/metrics-cli.js +50 -0
  135. package/lib/migrate-cli.d.ts +24 -0
  136. package/lib/migrate-cli.js +111 -0
  137. package/lib/miner-goal-spec.d.ts +12 -0
  138. package/lib/miner-goal-spec.js +67 -0
  139. package/lib/opportunity-fanout.d.ts +86 -0
  140. package/lib/opportunity-fanout.js +597 -0
  141. package/lib/opportunity-ranker.d.ts +36 -0
  142. package/lib/opportunity-ranker.js +118 -0
  143. package/lib/orb-export.d.ts +54 -0
  144. package/lib/orb-export.js +206 -0
  145. package/lib/plan-store-cli.d.ts +37 -0
  146. package/lib/plan-store-cli.js +151 -0
  147. package/lib/plan-store.d.ts +51 -0
  148. package/lib/plan-store.js +231 -0
  149. package/lib/policy-doc-cache.d.ts +25 -0
  150. package/lib/policy-doc-cache.js +79 -0
  151. package/lib/policy-verdict-cache.d.ts +35 -0
  152. package/lib/policy-verdict-cache.js +106 -0
  153. package/lib/portfolio-dashboard.d.ts +30 -0
  154. package/lib/portfolio-dashboard.js +105 -0
  155. package/lib/portfolio-discovery.d.ts +29 -0
  156. package/lib/portfolio-discovery.js +100 -0
  157. package/lib/portfolio-queue-cli.d.ts +87 -0
  158. package/lib/portfolio-queue-cli.js +509 -0
  159. package/lib/portfolio-queue-expiry.d.ts +20 -0
  160. package/lib/portfolio-queue-expiry.js +51 -0
  161. package/lib/portfolio-queue-manager.d.ts +50 -0
  162. package/lib/portfolio-queue-manager.js +134 -0
  163. package/lib/portfolio-queue.d.ts +62 -0
  164. package/lib/portfolio-queue.js +351 -0
  165. package/lib/pr-disposition-poller.d.ts +26 -0
  166. package/lib/pr-disposition-poller.js +163 -0
  167. package/lib/pr-number-parse.d.ts +4 -0
  168. package/lib/pr-number-parse.js +23 -0
  169. package/lib/pr-outcome.d.ts +41 -0
  170. package/lib/pr-outcome.js +90 -0
  171. package/lib/prediction-ledger.d.ts +47 -0
  172. package/lib/prediction-ledger.js +222 -0
  173. package/lib/pretooluse-hook.d.ts +31 -0
  174. package/lib/pretooluse-hook.js +93 -0
  175. package/lib/process-lifecycle.d.ts +31 -0
  176. package/lib/process-lifecycle.js +106 -0
  177. package/lib/purge-cli.d.ts +44 -0
  178. package/lib/purge-cli.js +198 -0
  179. package/lib/rejection-signal.d.ts +6 -0
  180. package/lib/rejection-signal.js +101 -0
  181. package/lib/rejection-state-machine.d.ts +37 -0
  182. package/lib/rejection-state-machine.js +81 -0
  183. package/lib/rejection-templates.d.ts +12 -0
  184. package/lib/rejection-templates.js +71 -0
  185. package/lib/replay-objective-anchor.d.ts +79 -0
  186. package/lib/replay-objective-anchor.js +179 -0
  187. package/lib/replay-snapshot.d.ts +41 -0
  188. package/lib/replay-snapshot.js +288 -0
  189. package/lib/replay-task-generation.d.ts +126 -0
  190. package/lib/replay-task-generation.js +223 -0
  191. package/lib/repo-clone.d.ts +19 -0
  192. package/lib/repo-clone.js +102 -0
  193. package/lib/run-state-cli.d.ts +27 -0
  194. package/lib/run-state-cli.js +154 -0
  195. package/lib/run-state.d.ts +37 -0
  196. package/lib/run-state.js +150 -0
  197. package/lib/schema-version.d.ts +17 -0
  198. package/lib/schema-version.js +71 -0
  199. package/lib/self-review-context.d.ts +28 -0
  200. package/lib/self-review-context.js +339 -0
  201. package/lib/slop-assessment.d.ts +3 -0
  202. package/lib/slop-assessment.js +20 -0
  203. package/lib/stack-detection.d.ts +41 -0
  204. package/lib/stack-detection.js +248 -0
  205. package/lib/status.d.ts +64 -0
  206. package/lib/status.js +441 -0
  207. package/lib/store-maintenance.d.ts +31 -0
  208. package/lib/store-maintenance.js +183 -0
  209. package/lib/submission-freshness-check.d.ts +32 -0
  210. package/lib/submission-freshness-check.js +93 -0
  211. package/lib/update-check.d.ts +36 -0
  212. package/lib/update-check.js +161 -0
  213. package/lib/version.d.ts +3 -0
  214. package/lib/version.js +10 -0
  215. package/lib/worktree-allocator.d.ts +39 -0
  216. package/lib/worktree-allocator.js +262 -0
  217. package/package.json +50 -0
  218. package/schema/miner-goal-spec.schema.json +111 -0
@@ -0,0 +1,262 @@
1
+ import { chmodSync, mkdirSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ import { DatabaseSync } from "node:sqlite";
5
+
6
+ // Git-worktree-per-attempt allocator (#4297): durable local bookkeeping for which worktree paths are
7
+ // allocated to which fleet attempts. Mirrors the package's existing local-store pattern (run-state.js,
8
+ // claim-ledger.js, portfolio-queue.js) — plain JS + node:sqlite, never phones home.
9
+
10
+ const defaultDbFileName = "worktree-allocator.sqlite3";
11
+ const defaultWorktreeDirName = "worktrees";
12
+ const defaultMaxConcurrency = 2;
13
+ let defaultWorktreeAllocator = null;
14
+
15
+ export function resolveWorktreeAllocatorDbPath(env = process.env) {
16
+ const explicitPath = typeof env.GITTENSORY_MINER_WORKTREE_ALLOCATOR_DB === "string"
17
+ ? env.GITTENSORY_MINER_WORKTREE_ALLOCATOR_DB.trim()
18
+ : "";
19
+ if (explicitPath) return explicitPath;
20
+
21
+ const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string"
22
+ ? env.GITTENSORY_MINER_CONFIG_DIR.trim()
23
+ : "";
24
+ if (explicitConfigDir) return join(explicitConfigDir, defaultDbFileName);
25
+
26
+ const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim()
27
+ ? env.XDG_CONFIG_HOME.trim()
28
+ : join(homedir(), ".config");
29
+ return join(configHome, "gittensory-miner", defaultDbFileName);
30
+ }
31
+
32
+ export function resolveWorktreeBaseDir(env = process.env) {
33
+ const explicitPath = typeof env.GITTENSORY_MINER_WORKTREE_DIR === "string"
34
+ ? env.GITTENSORY_MINER_WORKTREE_DIR.trim()
35
+ : "";
36
+ if (explicitPath) return explicitPath;
37
+
38
+ const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string"
39
+ ? env.GITTENSORY_MINER_CONFIG_DIR.trim()
40
+ : "";
41
+ if (explicitConfigDir) return join(explicitConfigDir, defaultWorktreeDirName);
42
+
43
+ const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim()
44
+ ? env.XDG_CONFIG_HOME.trim()
45
+ : join(homedir(), ".config");
46
+ return join(configHome, "gittensory-miner", defaultWorktreeDirName);
47
+ }
48
+
49
+ function normalizeDbPath(dbPath) {
50
+ const path = (dbPath ?? resolveWorktreeAllocatorDbPath()).trim();
51
+ if (!path) throw new Error("invalid_worktree_allocator_db_path");
52
+ return path;
53
+ }
54
+
55
+ function normalizeWorktreeBaseDir(worktreeBaseDir) {
56
+ const path = (worktreeBaseDir ?? resolveWorktreeBaseDir()).trim();
57
+ if (!path) throw new Error("invalid_worktree_base_dir");
58
+ return path;
59
+ }
60
+
61
+ function normalizeMaxConcurrency(value) {
62
+ if (value === undefined || value === null) return defaultMaxConcurrency;
63
+ if (!Number.isInteger(value) || value < 1) throw new Error("invalid_max_concurrency");
64
+ return value;
65
+ }
66
+
67
+ function normalizeRepoFullName(repoFullName) {
68
+ if (typeof repoFullName !== "string") throw new Error("invalid_repo_full_name");
69
+ const [owner, repo, extra] = repoFullName.trim().split("/");
70
+ if (!owner || !repo || extra !== undefined) throw new Error("invalid_repo_full_name");
71
+ return `${owner}/${repo}`;
72
+ }
73
+
74
+ function normalizeAttemptId(attemptId) {
75
+ if (typeof attemptId !== "string") throw new Error("invalid_attempt_id");
76
+ const trimmed = attemptId.trim();
77
+ if (!trimmed) throw new Error("invalid_attempt_id");
78
+ return trimmed;
79
+ }
80
+
81
+ export function isProcessAlive(pid) {
82
+ if (!Number.isInteger(pid) || pid <= 0) return false;
83
+ try {
84
+ process.kill(pid, 0);
85
+ return true;
86
+ } catch (error) {
87
+ // ESRCH = no such process; EPERM (or similar) means the process exists but we lack signal rights.
88
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH"
89
+ ? false
90
+ : true;
91
+ }
92
+ }
93
+
94
+ function rowToAllocation(row) {
95
+ return {
96
+ slotIndex: row.slot_index,
97
+ worktreePath: row.worktree_path,
98
+ attemptId: row.attempt_id,
99
+ repoFullName: row.repo_full_name,
100
+ status: row.status,
101
+ ownerPid: row.owner_pid,
102
+ allocatedAt: row.allocated_at,
103
+ };
104
+ }
105
+
106
+ function ensureSlotTable(db) {
107
+ db.exec(`
108
+ CREATE TABLE IF NOT EXISTS worktree_slots (
109
+ slot_index INTEGER PRIMARY KEY,
110
+ worktree_path TEXT NOT NULL UNIQUE,
111
+ attempt_id TEXT UNIQUE,
112
+ repo_full_name TEXT,
113
+ status TEXT NOT NULL CHECK (status IN ('free', 'active')),
114
+ owner_pid INTEGER,
115
+ allocated_at TEXT
116
+ )
117
+ `);
118
+ }
119
+
120
+ function ensureSlots(db, worktreeBaseDir, maxConcurrency) {
121
+ mkdirSync(worktreeBaseDir, { recursive: true, mode: 0o700 });
122
+ const insert = db.prepare(`
123
+ INSERT OR IGNORE INTO worktree_slots (slot_index, worktree_path, status)
124
+ VALUES (?, ?, 'free')
125
+ `);
126
+ for (let slotIndex = 0; slotIndex < maxConcurrency; slotIndex += 1) {
127
+ const worktreePath = join(worktreeBaseDir, `slot-${slotIndex}`);
128
+ insert.run(slotIndex, worktreePath);
129
+ mkdirSync(worktreePath, { recursive: true, mode: 0o700 });
130
+ }
131
+ }
132
+
133
+ function reclaimOrphanedAllocations(db) {
134
+ const orphans = db
135
+ .prepare("SELECT slot_index, owner_pid FROM worktree_slots WHERE status = 'active'")
136
+ .all();
137
+ const reclaim = db.prepare(`
138
+ UPDATE worktree_slots
139
+ SET status = 'free', attempt_id = NULL, repo_full_name = NULL, owner_pid = NULL, allocated_at = NULL
140
+ WHERE slot_index = ?
141
+ `);
142
+ for (const row of orphans) {
143
+ if (row.owner_pid !== null && isProcessAlive(row.owner_pid)) continue;
144
+ reclaim.run(row.slot_index);
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Opens the local worktree allocator store. Reclaims orphaned active slots from dead owner processes on startup.
150
+ */
151
+ export function openWorktreeAllocator(options = {}) {
152
+ const resolvedPath = normalizeDbPath(options.dbPath);
153
+ const worktreeBaseDir = normalizeWorktreeBaseDir(options.worktreeBaseDir);
154
+ const maxConcurrency = normalizeMaxConcurrency(options.maxConcurrency);
155
+ const processPid = Number.isInteger(options.processPid) ? options.processPid : process.pid;
156
+
157
+ mkdirSync(dirname(resolvedPath), { recursive: true, mode: 0o700 });
158
+ const db = new DatabaseSync(resolvedPath);
159
+ chmodSync(resolvedPath, 0o600);
160
+ db.exec("PRAGMA busy_timeout = 5000");
161
+ ensureSlotTable(db);
162
+ ensureSlots(db, worktreeBaseDir, maxConcurrency);
163
+ reclaimOrphanedAllocations(db);
164
+
165
+ const getByAttempt = db.prepare(
166
+ "SELECT slot_index, worktree_path, attempt_id, repo_full_name, status, owner_pid, allocated_at FROM worktree_slots WHERE attempt_id = ?",
167
+ );
168
+ const countActive = db.prepare("SELECT COUNT(*) AS count FROM worktree_slots WHERE status = 'active'");
169
+ const selectFreeSlot = db.prepare(`
170
+ SELECT slot_index, worktree_path, attempt_id, repo_full_name, status, owner_pid, allocated_at
171
+ FROM worktree_slots
172
+ WHERE status = 'free'
173
+ ORDER BY slot_index
174
+ LIMIT 1
175
+ `);
176
+ const markActive = db.prepare(`
177
+ UPDATE worktree_slots
178
+ SET status = 'active', attempt_id = ?, repo_full_name = ?, owner_pid = ?, allocated_at = ?
179
+ WHERE slot_index = ?
180
+ `);
181
+ const releaseByAttempt = db.prepare(`
182
+ UPDATE worktree_slots
183
+ SET status = 'free', attempt_id = NULL, repo_full_name = NULL, owner_pid = NULL, allocated_at = NULL
184
+ WHERE attempt_id = ? AND status = 'active'
185
+ RETURNING slot_index, worktree_path, attempt_id, repo_full_name, status, owner_pid, allocated_at
186
+ `);
187
+ const listSlots = db.prepare(
188
+ "SELECT slot_index, worktree_path, attempt_id, repo_full_name, status, owner_pid, allocated_at FROM worktree_slots ORDER BY slot_index",
189
+ );
190
+
191
+ const allocator = {
192
+ dbPath: resolvedPath,
193
+ worktreeBaseDir,
194
+ maxConcurrency,
195
+ processPid,
196
+ acquire(attemptId, repoFullName) {
197
+ const normalizedAttempt = normalizeAttemptId(attemptId);
198
+ const normalizedRepo = normalizeRepoFullName(repoFullName);
199
+ const existing = getByAttempt.get(normalizedAttempt);
200
+ if (existing?.status === "active") return rowToAllocation(existing);
201
+
202
+ db.exec("BEGIN IMMEDIATE");
203
+ try {
204
+ const raced = getByAttempt.get(normalizedAttempt);
205
+ if (raced?.status === "active") {
206
+ db.exec("COMMIT");
207
+ return rowToAllocation(raced);
208
+ }
209
+ const activeCount = countActive.get().count;
210
+ if (activeCount >= maxConcurrency) throw new Error("worktree_capacity_exceeded");
211
+ const slot = selectFreeSlot.get();
212
+ if (!slot) throw new Error("worktree_capacity_exceeded");
213
+ const allocatedAt = new Date().toISOString();
214
+ markActive.run(normalizedAttempt, normalizedRepo, processPid, allocatedAt, slot.slot_index);
215
+ db.exec("COMMIT");
216
+ return rowToAllocation({
217
+ ...slot,
218
+ attempt_id: normalizedAttempt,
219
+ repo_full_name: normalizedRepo,
220
+ status: "active",
221
+ owner_pid: processPid,
222
+ allocated_at: allocatedAt,
223
+ });
224
+ } catch (error) {
225
+ db.exec("ROLLBACK");
226
+ throw error;
227
+ }
228
+ },
229
+ release(attemptId) {
230
+ const normalizedAttempt = normalizeAttemptId(attemptId);
231
+ const row = releaseByAttempt.get(normalizedAttempt);
232
+ return row ? rowToAllocation(row) : null;
233
+ },
234
+ listSlots() {
235
+ return listSlots.all().map(rowToAllocation);
236
+ },
237
+ close() {
238
+ db.close();
239
+ },
240
+ };
241
+
242
+ return allocator;
243
+ }
244
+
245
+ function getDefaultWorktreeAllocator() {
246
+ defaultWorktreeAllocator ??= openWorktreeAllocator();
247
+ return defaultWorktreeAllocator;
248
+ }
249
+
250
+ export function acquireWorktree(attemptId, repoFullName) {
251
+ return getDefaultWorktreeAllocator().acquire(attemptId, repoFullName);
252
+ }
253
+
254
+ export function releaseWorktree(attemptId) {
255
+ return getDefaultWorktreeAllocator().release(attemptId);
256
+ }
257
+
258
+ export function closeDefaultWorktreeAllocator() {
259
+ if (!defaultWorktreeAllocator) return;
260
+ defaultWorktreeAllocator.close();
261
+ defaultWorktreeAllocator = null;
262
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@loopover/miner",
3
+ "version": "0.1.0",
4
+ "license": "AGPL-3.0-only",
5
+ "type": "module",
6
+ "description": "Foundation CLI for the local Gittensory miner runtime.",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/JSONbored/gittensory.git",
10
+ "directory": "packages/gittensory-miner"
11
+ },
12
+ "homepage": "https://github.com/JSONbored/gittensory#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/JSONbored/gittensory/issues"
15
+ },
16
+ "keywords": [
17
+ "gittensor",
18
+ "gittensory",
19
+ "miner",
20
+ "cli",
21
+ "agent"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "bin": {
27
+ "gittensory-miner": "bin/gittensory-miner.js",
28
+ "gittensory-miner-mcp": "bin/gittensory-miner-mcp.js"
29
+ },
30
+ "files": [
31
+ "bin",
32
+ "lib",
33
+ "docs",
34
+ "schema",
35
+ "DEPLOYMENT.md",
36
+ "Dockerfile",
37
+ "expected-engine.version"
38
+ ],
39
+ "scripts": {
40
+ "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-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/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/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"
41
+ },
42
+ "dependencies": {
43
+ "@loopover/engine": "*",
44
+ "@modelcontextprotocol/sdk": "1.29.0",
45
+ "zod": "^4.4.3"
46
+ },
47
+ "engines": {
48
+ "node": ">=22.13.0"
49
+ }
50
+ }
@@ -0,0 +1,111 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://jsonbored.dev/schemas/gittensory-miner-goal-spec.json",
4
+ "title": "MinerGoalSpec",
5
+ "description": "Per-repo miner configuration parsed from `.gittensory-miner.yml` (see packages/gittensory-miner/docs/miner-goal-spec.md).",
6
+ "type": "object",
7
+ "additionalProperties": true,
8
+ "properties": {
9
+ "minerEnabled": {
10
+ "type": "boolean",
11
+ "default": true,
12
+ "description": "Whether autonomous miners may target this repo. Default: true."
13
+ },
14
+ "wantedPaths": {
15
+ "type": "array",
16
+ "items": { "type": "string", "minLength": 1 },
17
+ "default": [],
18
+ "description": "Work areas a miner should prefer. Glob list. Default: []."
19
+ },
20
+ "blockedPaths": {
21
+ "type": "array",
22
+ "items": { "type": "string", "minLength": 1 },
23
+ "default": [],
24
+ "description": "Paths a miner must skip. Glob list. Default: []."
25
+ },
26
+ "preferredLabels": {
27
+ "type": "array",
28
+ "items": { "type": "string", "minLength": 1 },
29
+ "default": [],
30
+ "description": "Issue labels a miner should favor. Default: []."
31
+ },
32
+ "blockedLabels": {
33
+ "type": "array",
34
+ "items": { "type": "string", "minLength": 1 },
35
+ "default": [],
36
+ "description": "Issue labels a miner must skip. Default: []."
37
+ },
38
+ "maxConcurrentClaims": {
39
+ "type": "integer",
40
+ "minimum": 1,
41
+ "default": 1,
42
+ "description": "Maximum active claims one miner may hold on this repo. Default: 1."
43
+ },
44
+ "issueDiscoveryPolicy": {
45
+ "type": "string",
46
+ "enum": ["encouraged", "neutral", "discouraged"],
47
+ "default": "neutral",
48
+ "description": "How strongly opening discovery issues is encouraged. Default: neutral."
49
+ },
50
+ "feasibilityGate": {
51
+ "type": "object",
52
+ "additionalProperties": true,
53
+ "default": { "enabled": true, "suppressedReasons": [] },
54
+ "description": "Per-repo tuning for the feasibility gate a miner consults before starting work. Default: { enabled: true, suppressedReasons: [] }.",
55
+ "properties": {
56
+ "enabled": {
57
+ "type": "boolean",
58
+ "default": true,
59
+ "description": "Whether the feasibility gate is consulted at all before a miner starts work. Default: true."
60
+ },
61
+ "suppressedReasons": {
62
+ "type": "array",
63
+ "items": { "type": "string", "minLength": 1 },
64
+ "default": [],
65
+ "description": "buildFeasibilityVerdict avoid/raise reason codes this repo wants ignored. Default: []."
66
+ }
67
+ }
68
+ },
69
+ "selfPlagiarism": {
70
+ "type": "object",
71
+ "additionalProperties": true,
72
+ "default": { "similarityThreshold": 0.85 },
73
+ "description": "Self-plagiarism throttle consulted before open_pr (#2345). Default: { similarityThreshold: 0.85 }.",
74
+ "properties": {
75
+ "similarityThreshold": {
76
+ "type": "number",
77
+ "minimum": 0,
78
+ "maximum": 1,
79
+ "default": 0.85,
80
+ "description": "Jaccard similarity threshold for near-duplicate diff fingerprints. Default: 0.85."
81
+ }
82
+ }
83
+ },
84
+ "killSwitch": {
85
+ "type": "object",
86
+ "additionalProperties": true,
87
+ "default": { "paused": false },
88
+ "description": "Per-repo kill-switch consulted by the Governor chokepoint before every write action (#2341). Default: { paused: false }.",
89
+ "properties": {
90
+ "paused": {
91
+ "type": "boolean",
92
+ "default": false,
93
+ "description": "Halts all miner WRITE actions for this repo without deregistering it from targeting/discovery. Default: false."
94
+ }
95
+ }
96
+ },
97
+ "execution": {
98
+ "type": "object",
99
+ "additionalProperties": true,
100
+ "default": { "liveModeOptIn": null },
101
+ "description": "Per-repo dry-run/live execution opt-in consulted by the Governor chokepoint (#2342). Default: { liveModeOptIn: null }.",
102
+ "properties": {
103
+ "liveModeOptIn": {
104
+ "type": ["string", "null"],
105
+ "default": null,
106
+ "description": "Must equal exactly \"live\" to opt this repo into live write execution; any other value stays dry-run. Also requires the operator's own global opt-in (GITTENSORY_MINER_LIVE_MODE=live) unless the operator's own config already grants it. Default: null."
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }