terminalhire 0.30.1 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/claim-push-bg.js +2 -2
- package/dist/bin/jpi-bounties.js +2 -2
- package/dist/bin/jpi-chat-read.js +2 -2
- package/dist/bin/jpi-chat.js +2 -2
- package/dist/bin/jpi-claim.js +181 -33
- package/dist/bin/jpi-contribute.js +2 -2
- package/dist/bin/jpi-devs.js +29 -3
- package/dist/bin/jpi-dispatch.js +730 -568
- package/dist/bin/jpi-hub.js +29 -3
- package/dist/bin/jpi-inbox.js +2 -2
- package/dist/bin/jpi-intro.js +2 -2
- package/dist/bin/jpi-jobs.js +2 -2
- package/dist/bin/jpi-learn.js +2 -2
- package/dist/bin/jpi-login.js +2 -2
- package/dist/bin/jpi-profile.js +2 -2
- package/dist/bin/jpi-refresh.js +12 -12
- package/dist/bin/jpi-save.js +2 -2
- package/dist/bin/jpi-sync.js +2 -2
- package/dist/bin/jpi-trajectory.js +2 -2
- package/dist/src/chat-client.js +2 -2
- package/dist/src/chat-keystore.js +2 -2
- package/dist/src/github-auth.js +2 -2
- package/dist/src/intro.js +2 -2
- package/dist/src/profile.js +2 -2
- package/dist/src/repo-policy.js +87 -16
- package/dist/src/trajectory.js +2 -2
- package/package.json +1 -1
|
@@ -45,9 +45,9 @@ var init_keytar = __esm({
|
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
// node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
|
|
48
|
+
// node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node
|
|
49
49
|
var require_keytar = __commonJS({
|
|
50
|
-
"node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
50
|
+
"node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
51
51
|
"use strict";
|
|
52
52
|
init_keytar();
|
|
53
53
|
try {
|
package/dist/bin/jpi-bounties.js
CHANGED
|
@@ -8062,9 +8062,9 @@ var init_keytar = __esm({
|
|
|
8062
8062
|
}
|
|
8063
8063
|
});
|
|
8064
8064
|
|
|
8065
|
-
// node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
|
|
8065
|
+
// node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node
|
|
8066
8066
|
var require_keytar = __commonJS({
|
|
8067
|
-
"node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
8067
|
+
"node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
8068
8068
|
"use strict";
|
|
8069
8069
|
init_keytar();
|
|
8070
8070
|
try {
|
|
@@ -4043,9 +4043,9 @@ var init_keytar = __esm({
|
|
|
4043
4043
|
}
|
|
4044
4044
|
});
|
|
4045
4045
|
|
|
4046
|
-
// node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
|
|
4046
|
+
// node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node
|
|
4047
4047
|
var require_keytar = __commonJS({
|
|
4048
|
-
"node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
4048
|
+
"node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
4049
4049
|
"use strict";
|
|
4050
4050
|
init_keytar();
|
|
4051
4051
|
try {
|
package/dist/bin/jpi-chat.js
CHANGED
|
@@ -4071,9 +4071,9 @@ var init_keytar = __esm({
|
|
|
4071
4071
|
}
|
|
4072
4072
|
});
|
|
4073
4073
|
|
|
4074
|
-
// node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
|
|
4074
|
+
// node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node
|
|
4075
4075
|
var require_keytar = __commonJS({
|
|
4076
|
-
"node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
4076
|
+
"node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
4077
4077
|
"use strict";
|
|
4078
4078
|
init_keytar();
|
|
4079
4079
|
try {
|
package/dist/bin/jpi-claim.js
CHANGED
|
@@ -8185,9 +8185,9 @@ var init_keytar = __esm({
|
|
|
8185
8185
|
}
|
|
8186
8186
|
});
|
|
8187
8187
|
|
|
8188
|
-
// node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
|
|
8188
|
+
// node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node
|
|
8189
8189
|
var require_keytar = __commonJS({
|
|
8190
|
-
"node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
8190
|
+
"node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
8191
8191
|
"use strict";
|
|
8192
8192
|
init_keytar();
|
|
8193
8193
|
try {
|
|
@@ -8239,6 +8239,8 @@ var require_keytar2 = __commonJS({
|
|
|
8239
8239
|
// src/repo-policy.ts
|
|
8240
8240
|
var repo_policy_exports = {};
|
|
8241
8241
|
__export(repo_policy_exports, {
|
|
8242
|
+
POLICY_RULESET_VERSION: () => POLICY_RULESET_VERSION,
|
|
8243
|
+
auditContent: () => auditContent,
|
|
8242
8244
|
checkRepoPolicy: () => checkRepoPolicy
|
|
8243
8245
|
});
|
|
8244
8246
|
async function fetchContentsFile(fetchImpl, repoFullName, path) {
|
|
@@ -8260,23 +8262,50 @@ async function fetchContentsFile(fetchImpl, repoFullName, path) {
|
|
|
8260
8262
|
return { ok: false, missing: false, content: null };
|
|
8261
8263
|
}
|
|
8262
8264
|
}
|
|
8263
|
-
function
|
|
8264
|
-
|
|
8265
|
+
function classifyLine(line) {
|
|
8266
|
+
if (PROHIBITED_PATTERNS.some((re) => re.test(line))) return "prohibited";
|
|
8267
|
+
if (DISCLOSURE_PATTERNS.some((re) => re.test(line))) return "disclosure-required";
|
|
8268
|
+
if (AI_SIGNAL_PATTERNS.some((p) => p.re.test(line))) return "ai-mentioned";
|
|
8269
|
+
return null;
|
|
8270
|
+
}
|
|
8271
|
+
function sanitizeExcerpt(text) {
|
|
8272
|
+
return text.replace(/[\x00-\x08\x0B-\x1F\x7F-\x9F]/g, "");
|
|
8273
|
+
}
|
|
8274
|
+
function excerptAround(lines, i) {
|
|
8275
|
+
const start = Math.max(0, i - 2);
|
|
8276
|
+
const end = Math.min(lines.length, i + 3);
|
|
8277
|
+
return sanitizeExcerpt(lines.slice(start, end).join("\n"));
|
|
8278
|
+
}
|
|
8279
|
+
function auditContent(files) {
|
|
8265
8280
|
const hits = [];
|
|
8266
|
-
|
|
8267
|
-
|
|
8268
|
-
|
|
8269
|
-
const
|
|
8270
|
-
|
|
8271
|
-
|
|
8281
|
+
const requirements = [];
|
|
8282
|
+
const seenKinds = /* @__PURE__ */ new Set();
|
|
8283
|
+
for (const { file, content } of files) {
|
|
8284
|
+
const lines = content.split("\n");
|
|
8285
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8286
|
+
const rule = classifyLine(lines[i]);
|
|
8287
|
+
if (rule) hits.push({ file, excerpt: excerptAround(lines, i), rule });
|
|
8288
|
+
for (const { kind, re } of REQUIREMENT_PATTERNS) {
|
|
8289
|
+
if (seenKinds.has(kind) || !re.test(lines[i])) continue;
|
|
8290
|
+
seenKinds.add(kind);
|
|
8291
|
+
requirements.push({ kind, file, excerpt: excerptAround(lines, i) });
|
|
8292
|
+
}
|
|
8293
|
+
}
|
|
8272
8294
|
}
|
|
8273
|
-
|
|
8295
|
+
let verdict = "clean";
|
|
8296
|
+
for (const h of hits) {
|
|
8297
|
+
if (verdict === "clean" || VERDICT_SEVERITY[h.rule] > VERDICT_SEVERITY[verdict]) {
|
|
8298
|
+
verdict = h.rule;
|
|
8299
|
+
}
|
|
8300
|
+
}
|
|
8301
|
+
const assignment = seenKinds.has("take-bot") ? "take-bot" : seenKinds.has("assignment-required") ? "required" : "none";
|
|
8302
|
+
return { hits, requirements, verdict, assignment };
|
|
8274
8303
|
}
|
|
8275
8304
|
async function checkRepoPolicy(repoFullName, opts = {}) {
|
|
8276
8305
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
8277
8306
|
let requestsUsed = 0;
|
|
8278
8307
|
let hadError = false;
|
|
8279
|
-
const
|
|
8308
|
+
const files = [];
|
|
8280
8309
|
outer: for (const group of CANDIDATE_GROUPS) {
|
|
8281
8310
|
for (const path of group) {
|
|
8282
8311
|
if (requestsUsed >= MAX_REQUESTS) break outer;
|
|
@@ -8287,21 +8316,27 @@ async function checkRepoPolicy(repoFullName, opts = {}) {
|
|
|
8287
8316
|
continue;
|
|
8288
8317
|
}
|
|
8289
8318
|
if (outcome.missing) continue;
|
|
8290
|
-
if (outcome.content)
|
|
8319
|
+
if (outcome.content) files.push({ file: path, content: outcome.content });
|
|
8291
8320
|
break;
|
|
8292
8321
|
}
|
|
8293
8322
|
}
|
|
8294
|
-
|
|
8295
|
-
if (
|
|
8296
|
-
|
|
8323
|
+
const { hits, requirements, verdict, assignment } = auditContent(files);
|
|
8324
|
+
if (hits.length > 0) {
|
|
8325
|
+
return { status: "flagged", verdict, hits, requirements, assignment, rulesetVersion: POLICY_RULESET_VERSION };
|
|
8326
|
+
}
|
|
8327
|
+
if (hadError) {
|
|
8328
|
+
return { status: "unavailable", verdict: "unavailable", hits: [], requirements, assignment, rulesetVersion: POLICY_RULESET_VERSION };
|
|
8329
|
+
}
|
|
8330
|
+
return { status: "clean", verdict: "clean", hits: [], requirements, assignment, rulesetVersion: POLICY_RULESET_VERSION };
|
|
8297
8331
|
}
|
|
8298
|
-
var GH_API, GH_HEADERS, MAX_REQUESTS, AI_SIGNAL_PATTERNS, CANDIDATE_GROUPS;
|
|
8332
|
+
var GH_API, GH_HEADERS, MAX_REQUESTS, POLICY_RULESET_VERSION, AI_SIGNAL_PATTERNS, AI_TERM, PROHIBITED_PATTERNS, DISCLOSURE_PATTERNS, REQUIREMENT_PATTERNS, CANDIDATE_GROUPS, VERDICT_SEVERITY;
|
|
8299
8333
|
var init_repo_policy = __esm({
|
|
8300
8334
|
"src/repo-policy.ts"() {
|
|
8301
8335
|
"use strict";
|
|
8302
8336
|
GH_API = "https://api.github.com";
|
|
8303
8337
|
GH_HEADERS = { "User-Agent": "terminalhire-claim", Accept: "application/vnd.github+json" };
|
|
8304
8338
|
MAX_REQUESTS = 4;
|
|
8339
|
+
POLICY_RULESET_VERSION = 2;
|
|
8305
8340
|
AI_SIGNAL_PATTERNS = [
|
|
8306
8341
|
{ label: "AI", re: /\bAI\b/i },
|
|
8307
8342
|
{ label: "artificial intelligence", re: /artificial intelligence/i },
|
|
@@ -8313,11 +8348,47 @@ var init_repo_policy = __esm({
|
|
|
8313
8348
|
{ label: "generative", re: /\bgenerative\b/i },
|
|
8314
8349
|
{ label: "machine-generated", re: /machine[\s-]generated/i }
|
|
8315
8350
|
];
|
|
8351
|
+
AI_TERM = "(?:ai|llms?|generative(?:\\s+ai)?|artificial intelligence|language models?|copilot|chatgpt|claude|machine[\\s-]generated)";
|
|
8352
|
+
PROHIBITED_PATTERNS = [
|
|
8353
|
+
new RegExp(`prohibit\\w*[^.\\n]{0,60}\\b${AI_TERM}`, "i"),
|
|
8354
|
+
/did not write the code yourself/i,
|
|
8355
|
+
new RegExp(`(?:not|never|don'?t|won'?t)\\s+accept\\w*[^.\\n]{0,60}\\b${AI_TERM}`, "i"),
|
|
8356
|
+
new RegExp(`\\bno\\s+${AI_TERM}[^.\\n]{0,40}\\b(?:prs?|pull requests?|contributions?|code|patch(?:es)?|commits?|submissions?)\\b`, "i"),
|
|
8357
|
+
new RegExp(
|
|
8358
|
+
`\\b${AI_TERM}[^.\\n]{0,60}\\b(?:is|are|will be)\\s+(?:\\w+\\s+)?(?:not accepted|not allowed|banned|rejected|removed|closed|reverted|prohibited|forbidden)`,
|
|
8359
|
+
"i"
|
|
8360
|
+
)
|
|
8361
|
+
];
|
|
8362
|
+
DISCLOSURE_PATTERNS = [
|
|
8363
|
+
new RegExp(`disclos\\w+[^.\\n]{0,60}\\b${AI_TERM}`, "i"),
|
|
8364
|
+
new RegExp(`\\b${AI_TERM}[^.\\n]{0,60}disclos`, "i"),
|
|
8365
|
+
new RegExp(`\\b${AI_TERM}[\\s-]assist\\w*[^.\\n]{0,60}\\b(?:must|should|required?)\\b`, "i"),
|
|
8366
|
+
// PR-template checkbox, e.g. "- [ ] I used AI tools and have reviewed the output"
|
|
8367
|
+
new RegExp(`\\[ \\][^\\n]{0,80}\\b${AI_TERM}`, "i")
|
|
8368
|
+
];
|
|
8369
|
+
REQUIREMENT_PATTERNS = [
|
|
8370
|
+
// `/take` bot first: its docs usually also say "assign", and the bot is the
|
|
8371
|
+
// more specific expectation (post exactly `/take`, not a prose request).
|
|
8372
|
+
{ kind: "take-bot", re: /(?:^|[\s`"'(])\/take\b/m },
|
|
8373
|
+
{ kind: "assignment-required", re: /(?:request|ask|wait)[^.\n]{0,40}\bassign/i },
|
|
8374
|
+
{ kind: "assignment-required", re: /\bassigned before\b/i },
|
|
8375
|
+
{ kind: "assignment-required", re: /\bself[\s-]assign/i },
|
|
8376
|
+
{ kind: "assignment-required", re: /do not (?:open|submit)[^.\n]{0,40}\b(?:prs?|pull requests?)\b/i },
|
|
8377
|
+
{ kind: "cla-required", re: /\bCLA\b/ },
|
|
8378
|
+
{ kind: "cla-required", re: /contributor licen[cs]e agreement/i },
|
|
8379
|
+
{ kind: "discussion-first", re: /open an issue (?:first|before)/i },
|
|
8380
|
+
{ kind: "discussion-first", re: /discuss\w*[^.\n]{0,40}\bbefore\b/i }
|
|
8381
|
+
];
|
|
8316
8382
|
CANDIDATE_GROUPS = [
|
|
8317
8383
|
["CONTRIBUTING.md", ".github/CONTRIBUTING.md", "docs/CONTRIBUTING.md"],
|
|
8318
|
-
[".
|
|
8319
|
-
["
|
|
8384
|
+
["AGENTS.md", "AGENTS.MD"],
|
|
8385
|
+
[".github/PULL_REQUEST_TEMPLATE.md", "PULL_REQUEST_TEMPLATE.md"]
|
|
8320
8386
|
];
|
|
8387
|
+
VERDICT_SEVERITY = {
|
|
8388
|
+
"ai-mentioned": 1,
|
|
8389
|
+
"disclosure-required": 2,
|
|
8390
|
+
prohibited: 3
|
|
8391
|
+
};
|
|
8321
8392
|
}
|
|
8322
8393
|
});
|
|
8323
8394
|
|
|
@@ -9010,17 +9081,38 @@ function buildSubmitBody(issueNumber, opts = {}) {
|
|
|
9010
9081
|
return `${closesLine}${main}${AI_DISCLOSURE_NOTE}`;
|
|
9011
9082
|
}
|
|
9012
9083
|
function printPolicySection(policy) {
|
|
9013
|
-
|
|
9084
|
+
const verdict = policy.verdict ?? (policy.status === "flagged" ? "ai-mentioned" : policy.status);
|
|
9085
|
+
if (verdict === "prohibited") {
|
|
9086
|
+
console.log("\n POLICY: \u2717 this repo PROHIBITS AI-generated contributions \u2014 READ BEFORE CLAIMING:");
|
|
9087
|
+
} else if (verdict === "disclosure-required") {
|
|
9088
|
+
console.log("\n POLICY: \u26A0 this repo requires disclosing AI assistance \u2014 READ BEFORE WORKING:");
|
|
9089
|
+
} else if (verdict === "ai-mentioned") {
|
|
9014
9090
|
console.log("\n POLICY: \u26A0 possible AI-assistance policy language found \u2014 READ BEFORE WORKING:");
|
|
9015
|
-
for (const hit of policy.hits) {
|
|
9016
|
-
console.log(` [${hit.file}]`);
|
|
9017
|
-
for (const line of hit.excerpt.split("\n")) console.log(` ${line}`);
|
|
9018
|
-
}
|
|
9019
9091
|
} else if (policy.status === "unavailable") {
|
|
9020
9092
|
console.log("\n POLICY: could not read this repo's CONTRIBUTING/PR-template/AGENTS docs (rate-limited or unreachable) \u2014 read them yourself before working.");
|
|
9021
9093
|
} else {
|
|
9022
9094
|
console.log(" policy: no AI-assistance policy language detected in CONTRIBUTING/PR-template/AGENTS docs");
|
|
9023
9095
|
}
|
|
9096
|
+
for (const hit of policy.hits ?? []) {
|
|
9097
|
+
console.log(` [${hit.file}]`);
|
|
9098
|
+
for (const line of hit.excerpt.split("\n")) console.log(` ${line}`);
|
|
9099
|
+
}
|
|
9100
|
+
const requirements = policy.requirements ?? [];
|
|
9101
|
+
if (requirements.length > 0) {
|
|
9102
|
+
console.log("\n REQUIREMENTS: this repo sets contribution expectations \u2014 in its own words:");
|
|
9103
|
+
for (const req of requirements) {
|
|
9104
|
+
console.log(` ${req.kind} [${req.file}]`);
|
|
9105
|
+
for (const line of req.excerpt.split("\n")) console.log(` ${line}`);
|
|
9106
|
+
}
|
|
9107
|
+
}
|
|
9108
|
+
const assignment = policy.assignment ?? "none";
|
|
9109
|
+
if (assignment === "take-bot") {
|
|
9110
|
+
console.log(" assignment: repo self-assigns via a /take comment \u2014 `claim start` will post `/take` on the issue");
|
|
9111
|
+
} else if (assignment === "required") {
|
|
9112
|
+
console.log(" assignment: repo expects you to request assignment \u2014 `claim start` will post a request comment on the issue");
|
|
9113
|
+
} else {
|
|
9114
|
+
console.log(" assignment: no assignment expectation found in repo docs \u2014 `claim start` will not comment (pass --assign to request anyway)");
|
|
9115
|
+
}
|
|
9024
9116
|
}
|
|
9025
9117
|
var pExecFile = promisify2(execFile2);
|
|
9026
9118
|
async function sh(cmd, args, opts = {}) {
|
|
@@ -9291,9 +9383,9 @@ async function fetchIssue(repoFullName, issueNumber) {
|
|
|
9291
9383
|
}
|
|
9292
9384
|
var ASSIGNMENT_MARKER = "<!-- terminalhire:assignment-request -->";
|
|
9293
9385
|
var TAKE_BOT_REPOS = /* @__PURE__ */ new Set(["paradedb/paradedb"]);
|
|
9294
|
-
function buildAssignmentComment(repoFullName) {
|
|
9295
|
-
const usesTakeBot = TAKE_BOT_REPOS.has(repoFullName.toLowerCase());
|
|
9296
|
-
const body = usesTakeBot ? "/take" : `I'd like to work on this
|
|
9386
|
+
function buildAssignmentComment(repoFullName, opts = {}) {
|
|
9387
|
+
const usesTakeBot = TAKE_BOT_REPOS.has(repoFullName.toLowerCase()) || Boolean(opts.takeBot);
|
|
9388
|
+
const body = usesTakeBot ? "/take" : `Hi! I'd like to work on this issue. Could you assign it to me? Thanks!
|
|
9297
9389
|
|
|
9298
9390
|
${ASSIGNMENT_MARKER}`;
|
|
9299
9391
|
return { usesTakeBot, body };
|
|
@@ -9314,6 +9406,11 @@ async function hasPriorAssignmentRequest(repoFullName, issueNumber, login) {
|
|
|
9314
9406
|
return false;
|
|
9315
9407
|
}
|
|
9316
9408
|
}
|
|
9409
|
+
function shouldRequestAssignment(claim, flags = {}) {
|
|
9410
|
+
const expectation = claim && claim.policy ? claim.policy.assignment : void 0;
|
|
9411
|
+
const post = Boolean(flags.assign) || expectation === void 0 || expectation === "required" || expectation === "take-bot";
|
|
9412
|
+
return { post, takeBot: expectation === "take-bot" };
|
|
9413
|
+
}
|
|
9317
9414
|
async function requestIssueAssignment(claim, flags = {}, ghUser) {
|
|
9318
9415
|
if (flags["no-assign"]) {
|
|
9319
9416
|
console.log(" (--no-assign \u2014 skipping the assignment request; request it manually before working)");
|
|
@@ -9322,6 +9419,11 @@ async function requestIssueAssignment(claim, flags = {}, ghUser) {
|
|
|
9322
9419
|
const parsed = parseGitHubUrl(claim.issueUrl);
|
|
9323
9420
|
if (!parsed) return;
|
|
9324
9421
|
const { repoFullName, number } = parsed;
|
|
9422
|
+
const expectation = shouldRequestAssignment(claim, flags);
|
|
9423
|
+
if (!expectation.post) {
|
|
9424
|
+
console.log(" (no assignment expectation found in repo docs \u2014 pass --assign to request assignment anyway)");
|
|
9425
|
+
return;
|
|
9426
|
+
}
|
|
9325
9427
|
let login = ghUser;
|
|
9326
9428
|
if (!login) {
|
|
9327
9429
|
try {
|
|
@@ -9336,11 +9438,21 @@ async function requestIssueAssignment(claim, flags = {}, ghUser) {
|
|
|
9336
9438
|
console.log(` \u2713 Already assigned to @${login} on ${repoFullName}#${number}.`);
|
|
9337
9439
|
return;
|
|
9338
9440
|
}
|
|
9339
|
-
const { usesTakeBot, body } = buildAssignmentComment(repoFullName);
|
|
9441
|
+
const { usesTakeBot, body } = buildAssignmentComment(repoFullName, { takeBot: expectation.takeBot });
|
|
9340
9442
|
if (!usesTakeBot && await hasPriorAssignmentRequest(repoFullName, number, login)) {
|
|
9341
9443
|
console.log(` \u2713 Assignment already requested on ${repoFullName}#${number}.`);
|
|
9342
9444
|
return;
|
|
9343
9445
|
}
|
|
9446
|
+
if (process.stdin.isTTY) {
|
|
9447
|
+
console.log(`
|
|
9448
|
+
About to comment on ${repoFullName}#${number} as @${login}:`);
|
|
9449
|
+
for (const line of body.split("\n")) console.log(` ${line}`);
|
|
9450
|
+
const go = await confirm(" Post it? (y/N) ");
|
|
9451
|
+
if (!go) {
|
|
9452
|
+
console.log(" (skipped \u2014 request assignment manually before working)");
|
|
9453
|
+
return;
|
|
9454
|
+
}
|
|
9455
|
+
}
|
|
9344
9456
|
try {
|
|
9345
9457
|
await sh("gh", ["issue", "comment", String(number), "--repo", repoFullName, "--body", body]);
|
|
9346
9458
|
console.log(
|
|
@@ -9473,7 +9585,7 @@ function fmtContestedWarning(b) {
|
|
|
9473
9585
|
async function cmdRecord(arg, flags = {}) {
|
|
9474
9586
|
const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
|
|
9475
9587
|
if (!arg) {
|
|
9476
|
-
console.error("Usage: terminalhire claim record <bountyId|issueUrl> [--ack-policy] [--ack-contested]");
|
|
9588
|
+
console.error("Usage: terminalhire claim record <bountyId|issueUrl> [--ack-policy] [--ack-policy-prohibited] [--ack-contested]");
|
|
9477
9589
|
console.error(" Run `terminalhire bounties` first to populate the local index cache,");
|
|
9478
9590
|
console.error(" then pass the id shown in its output \u2014 or pass a GitHub issue URL directly.");
|
|
9479
9591
|
process.exit(1);
|
|
@@ -9511,8 +9623,25 @@ ${contestedWarning}`);
|
|
|
9511
9623
|
const policy = await checkRepoPolicy2(b.repoFullName);
|
|
9512
9624
|
printPolicySection(policy);
|
|
9513
9625
|
let ackedAt = null;
|
|
9514
|
-
if (policy.
|
|
9515
|
-
|
|
9626
|
+
if (policy.verdict === "prohibited") {
|
|
9627
|
+
let acked = Boolean(flags["ack-policy-prohibited"]);
|
|
9628
|
+
if (!acked && process.stdin.isTTY) {
|
|
9629
|
+
acked = await confirm(
|
|
9630
|
+
"\n This repo PROHIBITS AI-generated contributions \u2014 continuing means everything you submit must be hand-written by you. Continue? (y/N) "
|
|
9631
|
+
);
|
|
9632
|
+
}
|
|
9633
|
+
if (!acked) {
|
|
9634
|
+
console.error(
|
|
9635
|
+
`
|
|
9636
|
+
terminalhire claim: refusing to record \u2014 ${b.repoFullName} prohibits AI-generated contributions.
|
|
9637
|
+
Read the excerpts above. If you will hand-write the work yourself, re-run with
|
|
9638
|
+
--ack-policy-prohibited (or confirm interactively). --ack-policy is not enough here.`
|
|
9639
|
+
);
|
|
9640
|
+
process.exit(1);
|
|
9641
|
+
}
|
|
9642
|
+
ackedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9643
|
+
} else if (policy.status === "flagged" || policy.status === "unavailable") {
|
|
9644
|
+
const reason = policy.status === "flagged" ? "This repo has AI-assistance policy language" : "This repo's contribution policy could not be checked";
|
|
9516
9645
|
let acked = Boolean(flags["ack-policy"]);
|
|
9517
9646
|
if (!acked && process.stdin.isTTY) {
|
|
9518
9647
|
acked = await confirm(`
|
|
@@ -9542,7 +9671,18 @@ terminalhire claim: refusing to record \u2014 read ${b.repoFullName}'s contribut
|
|
|
9542
9671
|
amountUSD: b.amountUSD,
|
|
9543
9672
|
openPRsAtClaim: b.openPRs,
|
|
9544
9673
|
kind,
|
|
9545
|
-
|
|
9674
|
+
// Persist the full audit verdict (not just the coarse status) so `claim
|
|
9675
|
+
// start` can drive the assignment decision from it and `claim audit` can
|
|
9676
|
+
// show what ruleset the dev acknowledged. Excerpts are NOT persisted —
|
|
9677
|
+
// the record stores the conclusion; the docs stay the source of truth.
|
|
9678
|
+
policy: {
|
|
9679
|
+
status: policy.status,
|
|
9680
|
+
verdict: policy.verdict,
|
|
9681
|
+
assignment: policy.assignment,
|
|
9682
|
+
requirements: (policy.requirements ?? []).map((r) => r.kind),
|
|
9683
|
+
rulesetVersion: policy.rulesetVersion,
|
|
9684
|
+
ackedAt
|
|
9685
|
+
}
|
|
9546
9686
|
});
|
|
9547
9687
|
} catch (err) {
|
|
9548
9688
|
console.error(`terminalhire claim: ${err.message ?? err}`);
|
|
@@ -9604,7 +9744,14 @@ async function cmdPreview(arg, { json } = {}) {
|
|
|
9604
9744
|
openPRs: b.openPRs,
|
|
9605
9745
|
assignees: b.assignees,
|
|
9606
9746
|
contested: isContested(b),
|
|
9607
|
-
policy: {
|
|
9747
|
+
policy: {
|
|
9748
|
+
status: policy.status,
|
|
9749
|
+
verdict: policy.verdict,
|
|
9750
|
+
assignment: policy.assignment,
|
|
9751
|
+
rulesetVersion: policy.rulesetVersion,
|
|
9752
|
+
hits: policy.hits,
|
|
9753
|
+
requirements: policy.requirements
|
|
9754
|
+
}
|
|
9608
9755
|
}) + "\n"
|
|
9609
9756
|
);
|
|
9610
9757
|
return;
|
|
@@ -10736,6 +10883,7 @@ export {
|
|
|
10736
10883
|
run,
|
|
10737
10884
|
selectCompetingPrs,
|
|
10738
10885
|
selectPushRemote,
|
|
10886
|
+
shouldRequestAssignment,
|
|
10739
10887
|
startBranchFor,
|
|
10740
10888
|
workDirFor
|
|
10741
10889
|
};
|
|
@@ -1413,9 +1413,9 @@ var init_keytar = __esm({
|
|
|
1413
1413
|
}
|
|
1414
1414
|
});
|
|
1415
1415
|
|
|
1416
|
-
// node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
|
|
1416
|
+
// node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node
|
|
1417
1417
|
var require_keytar = __commonJS({
|
|
1418
|
-
"node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
1418
|
+
"node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
1419
1419
|
"use strict";
|
|
1420
1420
|
init_keytar();
|
|
1421
1421
|
try {
|
package/dist/bin/jpi-devs.js
CHANGED
|
@@ -8062,9 +8062,9 @@ var init_keytar = __esm({
|
|
|
8062
8062
|
}
|
|
8063
8063
|
});
|
|
8064
8064
|
|
|
8065
|
-
// node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node
|
|
8065
|
+
// node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node
|
|
8066
8066
|
var require_keytar = __commonJS({
|
|
8067
|
-
"node-file:/Users/ericgang/job-placement-inline/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
8067
|
+
"node-file:/Users/ericgang/job-placement-inline/.claude/worktrees/agent-a0bc554500876cd51/node_modules/keytar/build/Release/keytar.node"(exports, module) {
|
|
8068
8068
|
"use strict";
|
|
8069
8069
|
init_keytar();
|
|
8070
8070
|
try {
|
|
@@ -8467,6 +8467,31 @@ function linkTitle(title, url) {
|
|
|
8467
8467
|
return href ? `${safeTitle} (${href})` : safeTitle;
|
|
8468
8468
|
}
|
|
8469
8469
|
|
|
8470
|
+
// bin/match-slots.js
|
|
8471
|
+
var ROTATE_WINDOW_MS = 5 * 60 * 1e3;
|
|
8472
|
+
var ROLE_HEAD_ROTATE_MS = 60 * 60 * 1e3;
|
|
8473
|
+
function rotate(list, now, windowMs = ROTATE_WINDOW_MS) {
|
|
8474
|
+
if (!Array.isArray(list) || list.length === 0) return [];
|
|
8475
|
+
const idx = Math.floor(now / windowMs) % list.length;
|
|
8476
|
+
return [...list.slice(idx), ...list.slice(0, idx)];
|
|
8477
|
+
}
|
|
8478
|
+
|
|
8479
|
+
// bin/directory-select.js
|
|
8480
|
+
var DEVS_STABLE_HEAD = 5;
|
|
8481
|
+
var DEVS_ROTATE_WINDOW = 15;
|
|
8482
|
+
var DEVS_ROTATE_MS = 5 * 60 * 1e3;
|
|
8483
|
+
function selectDirectoryDevs(results, { limit, now = Date.now() } = {}) {
|
|
8484
|
+
const list = Array.isArray(results) ? results : [];
|
|
8485
|
+
if (list.length === 0) return [];
|
|
8486
|
+
if (limit >= list.length) return list;
|
|
8487
|
+
const head = list.slice(0, Math.min(DEVS_STABLE_HEAD, limit));
|
|
8488
|
+
const tailPool = list.slice(head.length, head.length + DEVS_ROTATE_WINDOW);
|
|
8489
|
+
const tailSelected = rotate(tailPool, now, DEVS_ROTATE_MS).slice(0, limit - head.length);
|
|
8490
|
+
const rankOf = new Map(list.map((item, idx) => [item, idx]));
|
|
8491
|
+
const tail = [...tailSelected].sort((a, b) => rankOf.get(a) - rankOf.get(b));
|
|
8492
|
+
return [...head, ...tail];
|
|
8493
|
+
}
|
|
8494
|
+
|
|
8470
8495
|
// bin/jpi-devs.js
|
|
8471
8496
|
var API_URL2 = process.env["TERMINALHIRE_API_URL"] ?? process.env["JPI_API_URL"] ?? "https://terminalhire.com";
|
|
8472
8497
|
var DEFAULT_LIMIT = 10;
|
|
@@ -8526,7 +8551,7 @@ async function getDevs({ quiet = false, offline = false } = {}) {
|
|
|
8526
8551
|
}
|
|
8527
8552
|
const cards = index.cards ?? [];
|
|
8528
8553
|
if (cards.length === 0) return { status: "no-cards", fp };
|
|
8529
|
-
let results = match2(fp, cards,
|
|
8554
|
+
let results = match2(fp, cards, cards.length);
|
|
8530
8555
|
let ownLogin;
|
|
8531
8556
|
try {
|
|
8532
8557
|
const { readProfile: readProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
|
|
@@ -8534,6 +8559,7 @@ async function getDevs({ quiet = false, offline = false } = {}) {
|
|
|
8534
8559
|
} catch {
|
|
8535
8560
|
}
|
|
8536
8561
|
results = excludeOwnCard(results, ownLogin);
|
|
8562
|
+
if (!SHOW_ALL) results = selectDirectoryDevs(results, { limit: LIMIT });
|
|
8537
8563
|
if (results.length === 0) return { status: "no-matches", fp };
|
|
8538
8564
|
return { status: "ok", results, fp };
|
|
8539
8565
|
}
|