@brainervirus/workit-pi 2.3.0 → 2.5.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 (2) hide show
  1. package/dist/workit.js +259 -47
  2. package/package.json +1 -1
package/dist/workit.js CHANGED
@@ -12056,6 +12056,15 @@ var validateBranchNameFor = (workspaceRoot, name) => {
12056
12056
  }
12057
12057
  };
12058
12058
  var resolveBranchPolicyFor = (workspaceRoot, profileName) => effectiveWorkspacePolicy(workspaceRoot, "branch", profileName).branchPolicy;
12059
+ var policy = (root) => resolveBranchPolicyFor(root);
12060
+ var isProtected = (root, name) => policy(root).protected.has(name.toLowerCase());
12061
+ var isProtectedTarget = (root, name) => {
12062
+ try {
12063
+ return isProtected(root, name);
12064
+ } catch {
12065
+ return true;
12066
+ }
12067
+ };
12059
12068
  var verifyPushIdentity = (root, provider, account) => {
12060
12069
  if (!account || typeof account !== "string")
12061
12070
  return { ok: false, error: "push identity requires a configured area account" };
@@ -17322,39 +17331,7 @@ import fs9 from "node:fs";
17322
17331
  import path15 from "node:path";
17323
17332
  import { spawnSync as spawnSync5 } from "node:child_process";
17324
17333
  import { pathToFileURL } from "node:url";
17325
- var remoteRepoPath = (remote) => {
17326
- const raw = remote.trim();
17327
- if (!raw)
17328
- return null;
17329
- if (!raw.includes("://")) {
17330
- const scp = /^(?:[^@\s]+@)?([^:]+):(.+)$/u.exec(raw);
17331
- if (scp)
17332
- return {
17333
- host: scp[1].toLowerCase(),
17334
- path: scp[2].replace(/^\//u, "").replace(/\.git$/u, ""),
17335
- protocol: "ssh:"
17336
- };
17337
- }
17338
- try {
17339
- const url = new URL(raw);
17340
- return {
17341
- host: url.hostname.toLowerCase(),
17342
- path: url.pathname.replace(/^\//u, "").replace(/\.git$/u, "").replace(/\/$/u, ""),
17343
- protocol: url.protocol
17344
- };
17345
- } catch {
17346
- return null;
17347
- }
17348
- };
17349
- var cliRepository = (remote, provider, cfg) => {
17350
- const parsed = remoteRepoPath(remote);
17351
- if (!parsed?.path)
17352
- return null;
17353
- const host = String(provider === "github" ? cfg.github?.host ?? "github.com" : cfg.gitlab?.host ?? "gitlab.com").toLowerCase();
17354
- if (provider === "github")
17355
- return `${host}/${parsed.path}`;
17356
- return host === "gitlab.com" ? parsed.path : `https://${host}/${parsed.path}`;
17357
- };
17334
+ // packages/workit-core/src/forge/pr-body.ts
17358
17335
  function parseGhIssue(value) {
17359
17336
  const m = /issues\/(\d+)/.exec(value);
17360
17337
  return m ? m[1] : String(value).trim().replace(/^#/, "");
@@ -17405,6 +17382,41 @@ function buildBody(body, branch, linkIssues, baseUrl, ytIssue, ghLinkOnPr, ghIss
17405
17382
 
17406
17383
  ${line}` : line;
17407
17384
  }
17385
+
17386
+ // packages/workit-core/src/core/pr-create.ts
17387
+ var remoteRepoPath = (remote) => {
17388
+ const raw = remote.trim();
17389
+ if (!raw)
17390
+ return null;
17391
+ if (!raw.includes("://")) {
17392
+ const scp = /^(?:[^@\s]+@)?([^:]+):(.+)$/u.exec(raw);
17393
+ if (scp)
17394
+ return {
17395
+ host: scp[1].toLowerCase(),
17396
+ path: scp[2].replace(/^\//u, "").replace(/\.git$/u, ""),
17397
+ protocol: "ssh:"
17398
+ };
17399
+ }
17400
+ try {
17401
+ const url = new URL(raw);
17402
+ return {
17403
+ host: url.hostname.toLowerCase(),
17404
+ path: url.pathname.replace(/^\//u, "").replace(/\.git$/u, "").replace(/\/$/u, ""),
17405
+ protocol: url.protocol
17406
+ };
17407
+ } catch {
17408
+ return null;
17409
+ }
17410
+ };
17411
+ var cliRepository = (remote, provider, cfg) => {
17412
+ const parsed = remoteRepoPath(remote);
17413
+ if (!parsed?.path)
17414
+ return null;
17415
+ const host = String(provider === "github" ? cfg.github?.host ?? "github.com" : cfg.gitlab?.host ?? "gitlab.com").toLowerCase();
17416
+ if (provider === "github")
17417
+ return `${host}/${parsed.path}`;
17418
+ return host === "gitlab.com" ? parsed.path : `https://${host}/${parsed.path}`;
17419
+ };
17408
17420
  function whichOnPath(tool) {
17409
17421
  const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
17410
17422
  for (const dir of (process.env.PATH ?? "").split(path15.delimiter)) {
@@ -19048,7 +19060,7 @@ async function logTimeUpdate(input, operation = defaultOperations) {
19048
19060
  // packages/workit-core/src/core/external-action-effects.ts
19049
19061
  import fs12 from "node:fs";
19050
19062
  import path19 from "node:path";
19051
- import { spawnSync as spawnSync8 } from "node:child_process";
19063
+ import { spawnSync as spawnSync9 } from "node:child_process";
19052
19064
 
19053
19065
  // packages/workit-core/src/core/changelog.ts
19054
19066
  import fs11 from "node:fs";
@@ -19379,6 +19391,212 @@ function changelogApply({
19379
19391
  }
19380
19392
  }
19381
19393
 
19394
+ // packages/workit-core/src/forge/redact.ts
19395
+ var R = "[REDACTED]";
19396
+ var TOKEN_PATTERNS = [
19397
+ /\b(?:gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,})/gu,
19398
+ /\bgl[a-z]{1,8}-[A-Za-z0-9_-]{16,}/gu,
19399
+ /\bnpm_[A-Za-z0-9]{30,}/gu,
19400
+ /\bxox[abposr]-[A-Za-z0-9-]{10,}/gu,
19401
+ /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/gu,
19402
+ /\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{20,}/gu,
19403
+ /\b[sr]k_(?:live|test)_[A-Za-z0-9]{16,}/gu,
19404
+ /\bAIza[0-9A-Za-z_-]{35}/gu,
19405
+ /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/gu
19406
+ ];
19407
+ var WEBHOOK = /\b(https?:\/\/(?:hooks\.slack\.com\/(?:services|workflows|triggers)|discord(?:app)?\.com\/api\/webhooks))\/[^\s"'<>]+/giu;
19408
+ var URL_USERINFO = /\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/giu;
19409
+ var CURL_USER = /(\s(?:-u|--user)(?:\s+|=))(["']?)[^\s"':]+:[^\s"']+\2/gu;
19410
+ var KEY = String.raw`[A-Za-z0-9_.-]*?(?:token|secret|password|passwd|pwd|api[_-]?key|access[_-]?key|account[_-]?key|private[_-]?key|client[_-]?secret|credentials?|authorization|cookie|signature)[A-Za-z0-9_.-]*`;
19411
+ var ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*["']?)((?:bearer|basic|token|digest)\s+)?([^\s"',;&]+)`, "giu");
19412
+ var BEARER = /\b(bearer\s+)[A-Za-z0-9._~+/-]{12,}=*/giu;
19413
+ var QUOTED_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9])(["']?${KEY}["']?\s*[:=]\s*)(["'])([^"'\n]*[^\s"'][^"'\n]*)\2`, "giu");
19414
+ var NETRC = /\b((?:machine|login)\s+\S+\s+(?:login\s+\S+\s+)?password\s+)\S+/giu;
19415
+ var FLAG_SECRETS = [
19416
+ /\b(sshpass\s+-p\s*)\S+/gu,
19417
+ /\b(mysql(?:dump|admin|import|show)?\b[^\n]*?\s-p)(?!\s|$)\S+/gu
19418
+ ];
19419
+ var QUERY_SECRET = /([?&;](?:sig|signature|token|access_token|api_key|apikey|key|password|secret|client_secret|X-Amz-Signature|X-Goog-Signature)=)[^&\s#"']+/giu;
19420
+ var PRIVATE_KEY = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY(?: BLOCK)?-----[\s\S]*?(?:-----END [A-Z0-9 ]*PRIVATE KEY(?: BLOCK)?-----|$)/gu;
19421
+ var BASE64 = /[A-Za-z0-9+/]{32,}={0,2}/gu;
19422
+ var ANSI = new RegExp(String.raw`\u001b\[[0-9;?]*[ -/]*[@-~]|\u001b\][^\u0007]*\u0007`, "gu");
19423
+ var stripAnsi = (value) => value.replace(ANSI, "");
19424
+ var decodesToSecret = (blob) => {
19425
+ if (/^[0-9a-f]+$/iu.test(blob))
19426
+ return false;
19427
+ let decoded;
19428
+ try {
19429
+ decoded = Buffer.from(blob, "base64").toString("utf8");
19430
+ } catch {
19431
+ return false;
19432
+ }
19433
+ if (!/^[\x20-\x7e\s]+$/u.test(decoded))
19434
+ return false;
19435
+ return TOKEN_PATTERNS.some((pattern) => new RegExp(pattern.source, "u").test(decoded)) || /^[^\s:]{1,64}:[^\s]{6,}$/u.test(decoded.trim());
19436
+ };
19437
+ function redactText(value) {
19438
+ let out = stripAnsi(value).replace(PRIVATE_KEY, "[REDACTED PRIVATE KEY]");
19439
+ out = out.replace(WEBHOOK, `$1/${R}`);
19440
+ out = out.replace(URL_USERINFO, `$1${R}@`);
19441
+ for (const pattern of TOKEN_PATTERNS)
19442
+ out = out.replace(pattern, R);
19443
+ out = out.replace(CURL_USER, `$1$2${R}$2`);
19444
+ out = out.replace(BEARER, `$1${R}`);
19445
+ out = out.replace(QUOTED_ASSIGNMENT, (match, lead, quote, secret) => secret.startsWith(R) ? match : `${lead}${quote}${R}${quote}`);
19446
+ out = out.replace(NETRC, `$1${R}`);
19447
+ for (const pattern of FLAG_SECRETS)
19448
+ out = out.replace(pattern, `$1${R}`);
19449
+ out = out.replace(QUERY_SECRET, `$1${R}`);
19450
+ out = out.replace(ASSIGNMENT, (match, lead, scheme, secret) => secret.startsWith(R) ? match : `${lead}${scheme ?? ""}${R}`);
19451
+ return out.split(`
19452
+ `).map((line) => line.replace(BASE64, (blob) => /\bbase64\b/iu.test(line) || decodesToSecret(blob) ? R : blob)).join(`
19453
+ `);
19454
+ }
19455
+
19456
+ // packages/workit-core/src/git/rev.ts
19457
+ import { spawnSync as spawnSync8 } from "node:child_process";
19458
+ var MAX_BUFFER = 256 * 1024 * 1024;
19459
+ var GIT_TIMEOUTS = { local: 20000, worktree: 120000, network: 15000 };
19460
+ var git = (cwd, args, options = {}) => {
19461
+ const result = spawnSync8("git", args, {
19462
+ cwd,
19463
+ encoding: "utf8",
19464
+ env: options.env ?? process.env,
19465
+ input: options.input,
19466
+ maxBuffer: MAX_BUFFER,
19467
+ timeout: options.timeoutMs ?? GIT_TIMEOUTS.local,
19468
+ killSignal: "SIGKILL",
19469
+ windowsHide: true
19470
+ });
19471
+ const error = result.error;
19472
+ return {
19473
+ ok: result.status === 0,
19474
+ stdout: result.stdout ?? "",
19475
+ stderr: result.stderr ?? "",
19476
+ timedOut: error?.code === "ETIMEDOUT"
19477
+ };
19478
+ };
19479
+ var line = (run) => {
19480
+ if (!run.ok)
19481
+ return null;
19482
+ const value = run.stdout.trim();
19483
+ return value ? value : null;
19484
+ };
19485
+ function networkGitInvocation(cwd, args, timeoutMs) {
19486
+ const seconds = Math.max(1, Math.ceil(timeoutMs / 1000));
19487
+ const env = {
19488
+ ...process.env,
19489
+ GIT_TERMINAL_PROMPT: "0",
19490
+ GIT_ASKPASS: "",
19491
+ SSH_ASKPASS: "",
19492
+ SSH_ASKPASS_REQUIRE: "never",
19493
+ GCM_INTERACTIVE: "never"
19494
+ };
19495
+ const base = process.env.GIT_SSH_COMMAND || line(git(cwd, ["config", "--get", "core.sshCommand"])) || (process.env.GIT_SSH ? null : "ssh");
19496
+ if (base)
19497
+ env.GIT_SSH_COMMAND = `${base} -o BatchMode=yes -o ConnectTimeout=${Math.min(10, seconds)}`;
19498
+ return {
19499
+ args: ["-c", "http.lowSpeedLimit=1", "-c", `http.lowSpeedTime=${seconds}`, ...args],
19500
+ env
19501
+ };
19502
+ }
19503
+ var WATCHDOG = `
19504
+ const cp = require("node:child_process");
19505
+ const { ms, args } = JSON.parse(process.env.WORKIT_GIT_WATCHDOG);
19506
+ delete process.env.WORKIT_GIT_WATCHDOG;
19507
+ const win = process.platform === "win32";
19508
+ const child = cp.spawn("git", args, { stdio: "inherit", detached: !win, windowsHide: true });
19509
+ const killTree = () => {
19510
+ if (!child.pid) return;
19511
+ if (win) cp.spawnSync("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
19512
+ else try { process.kill(-child.pid, "SIGKILL"); } catch {}
19513
+ };
19514
+ let timedOut = false;
19515
+ const timer = setTimeout(() => { timedOut = true; killTree(); }, ms);
19516
+ child.on("error", () => { clearTimeout(timer); process.exit(127); });
19517
+ child.on("exit", (code) => {
19518
+ clearTimeout(timer);
19519
+ if (!win) killTree();
19520
+ process.exit(timedOut ? 124 : code ?? 1);
19521
+ });
19522
+ `;
19523
+ var WATCHDOG_TIMEOUT_EXIT = 124;
19524
+ var gitNetwork = (cwd, args, timeoutMs) => {
19525
+ const invocation = networkGitInvocation(cwd, args, timeoutMs);
19526
+ const result = spawnSync8(process.execPath, ["-e", WATCHDOG], {
19527
+ cwd,
19528
+ encoding: "utf8",
19529
+ env: {
19530
+ ...invocation.env,
19531
+ WORKIT_GIT_WATCHDOG: JSON.stringify({ ms: timeoutMs, args: invocation.args })
19532
+ },
19533
+ maxBuffer: MAX_BUFFER,
19534
+ timeout: timeoutMs + 1e4,
19535
+ killSignal: "SIGKILL",
19536
+ windowsHide: true
19537
+ });
19538
+ const error = result.error;
19539
+ return {
19540
+ ok: result.status === 0,
19541
+ stdout: result.stdout ?? "",
19542
+ stderr: result.stderr ?? "",
19543
+ timedOut: result.status === WATCHDOG_TIMEOUT_EXIT || error?.code === "ETIMEDOUT"
19544
+ };
19545
+ };
19546
+ var MAX_UNTRACKED_BYTES = 5 * 1024 * 1024;
19547
+
19548
+ // packages/workit-core/src/ledger.ts
19549
+ var PASSING = new Set(["verified", "tests-verified", "type-check-only"]);
19550
+ var FAILING = new Set(["failed", "blocked"]);
19551
+ var PR_ROW_TYPES = new Set(["pr.created", "pr.status", "pr.merged"]);
19552
+ var NETWORK_FS_TYPES = new Set([
19553
+ 26985,
19554
+ 20859,
19555
+ 4266872130,
19556
+ 4283649346,
19557
+ 1702057286,
19558
+ 1397113167,
19559
+ 12805120,
19560
+ 16914839,
19561
+ 1196443219,
19562
+ 198183888
19563
+ ]);
19564
+ var OBSERVED_ONLY = new Set(["check", ...PR_ROW_TYPES]);
19565
+
19566
+ // packages/workit-core/src/git/ops.ts
19567
+ var COMMIT_TIMEOUT_MS = 10 * 60000;
19568
+ var PUSH_TIMEOUT_MS = 120000;
19569
+ var gitError = (run, max = 3) => {
19570
+ const lines = redactText(`${run.stderr}
19571
+ ${run.stdout ?? ""}`).split(/\r?\n/u).map((value) => value.trim()).filter((value) => value && !value.startsWith("hint:"));
19572
+ return lines.slice(-max).join(" / ").slice(0, 400) || "git failed";
19573
+ };
19574
+ var SHA = /^[0-9a-f]{40,64}$/u;
19575
+ function deleteRemoteBranch(cwd, target, branch, expectedTip, options = {}) {
19576
+ if (target.startsWith("-") || branch.startsWith("-") || !SHA.test(expectedTip))
19577
+ return { ok: false, lease: false, error: "invalid branch deletion target" };
19578
+ if (isProtectedTarget(cwd, branch))
19579
+ return {
19580
+ ok: false,
19581
+ lease: false,
19582
+ error: `${branch} is a protected branch; it is never deleted`
19583
+ };
19584
+ const run = gitNetwork(cwd, [
19585
+ "push",
19586
+ "--no-follow-tags",
19587
+ "--recurse-submodules=no",
19588
+ `--force-with-lease=refs/heads/${branch}:${expectedTip}`,
19589
+ "--delete",
19590
+ target,
19591
+ branch
19592
+ ], options.timeoutMs ?? PUSH_TIMEOUT_MS);
19593
+ if (run.ok)
19594
+ return { ok: true };
19595
+ const text = `${run.stderr}
19596
+ ${run.stdout}`;
19597
+ return /stale info|cannot lock ref|fetch first|non-fast-forward/iu.test(text) ? { ok: false, lease: true, error: "the remote branch tip changed before deletion" } : { ok: false, lease: false, error: gitError(run) };
19598
+ }
19599
+
19382
19600
  // packages/workit-core/src/core/external-action-effects.ts
19383
19601
  var run3 = (root, args) => {
19384
19602
  return run2(root, "git", args);
@@ -19784,7 +20002,7 @@ var hostingProvider = (root, remote) => {
19784
20002
  };
19785
20003
  var remoteBranchTip = (root, provider, host, repo, branch) => {
19786
20004
  const endpoint = provider === "github" ? `repos/${repo}/git/ref/heads/${branch.split("/").map(encodeURIComponent).join("/")}` : `projects/${encodeURIComponent(repo)}/repository/branches/${encodeURIComponent(branch)}`;
19787
- const response = spawnSync8(provider === "github" ? "gh" : "glab", ["api", endpoint], {
20005
+ const response = spawnSync9(provider === "github" ? "gh" : "glab", ["api", endpoint], {
19788
20006
  cwd: root,
19789
20007
  encoding: "utf8",
19790
20008
  env: hostingCliEnv(provider, host)
@@ -19792,7 +20010,7 @@ var remoteBranchTip = (root, provider, host, repo, branch) => {
19792
20010
  if (response.status !== 0) {
19793
20011
  if (/\b404\b/.test(response.stderr ?? "")) {
19794
20012
  const project = provider === "github" ? `repos/${repo}` : `projects/${encodeURIComponent(repo)}`;
19795
- const visible = spawnSync8(provider === "github" ? "gh" : "glab", ["api", project], {
20013
+ const visible = spawnSync9(provider === "github" ? "gh" : "glab", ["api", project], {
19796
20014
  cwd: root,
19797
20015
  encoding: "utf8",
19798
20016
  env: hostingCliEnv(provider, host)
@@ -19848,7 +20066,7 @@ var mergedBranch = (root, branch) => {
19848
20066
  outcome: "not_started"
19849
20067
  });
19850
20068
  const endpoint = provider === "github" ? `repos/${repo}/pulls?state=closed&head=${encodeURIComponent(`${repo.split("/")[0]}:${branch}`)}&per_page=100` : `projects/${encodeURIComponent(repo)}/merge_requests?state=merged&source_branch=${encodeURIComponent(branch)}&per_page=100`;
19851
- const response = spawnSync8(provider === "github" ? "gh" : "glab", ["api", endpoint], {
20069
+ const response = spawnSync9(provider === "github" ? "gh" : "glab", ["api", endpoint], {
19852
20070
  cwd: root,
19853
20071
  encoding: "utf8",
19854
20072
  env: hostingCliEnv(provider, auth.host)
@@ -19910,7 +20128,7 @@ var readHostingAction = async (root, resolved, actionRef) => {
19910
20128
  return unknownHostingEvidence(operation);
19911
20129
  const endpoint = cfg.provider === "github" ? `repos/${repo}/pulls?state=all&head=${encodeURIComponent(`${repo.split("/")[0]}:${branch}`)}&base=${encodeURIComponent(target)}&per_page=100&page=1` : `projects/${encodeURIComponent(repo)}/merge_requests?state=all&source_branch=${encodeURIComponent(branch)}&target_branch=${encodeURIComponent(target)}&per_page=100&page=1`;
19912
20130
  const cli = cfg.provider === "github" ? "gh" : "glab";
19913
- const response = spawnSync8(cli, ["api", endpoint], {
20131
+ const response = spawnSync9(cli, ["api", endpoint], {
19914
20132
  cwd: root,
19915
20133
  encoding: "utf8",
19916
20134
  env: hostingCliEnv(cfg.provider, auth.host)
@@ -20806,16 +21024,10 @@ var executeConcreteExternalAction = async (request, root, marker, dateMs, step,
20806
21024
  outcome: "not_started"
20807
21025
  });
20808
21026
  const branch = request.payload.branch;
20809
- const result = run3(root, [
20810
- "push",
20811
- `--force-with-lease=refs/heads/${branch}:${approvedTip}`,
20812
- "--delete",
20813
- target,
20814
- branch
20815
- ]);
20816
- if (result.exitCode === 0)
21027
+ const result = deleteRemoteBranch(root, target, branch, approvedTip);
21028
+ if (result.ok)
20817
21029
  return success(null, null, { branch, deletedTip: approvedTip });
20818
- return /stale info|cannot lock ref|fetch first|non-fast-forward/i.test(result.stderr) ? failure2("capability_unavailable", "remote branch tip changed before deletion", {
21030
+ return result.lease ? failure2("capability_unavailable", "remote branch tip changed before deletion", {
20819
21031
  outcome: "not_started"
20820
21032
  }) : unknown2(request.operation);
20821
21033
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-pi",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "description": "Workit native extension for Pi — tools, method skills, and session continuity",
5
5
  "keywords": [
6
6
  "agentic-coding",