@4pm/cli 1.19.7 → 1.19.9

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/index.js CHANGED
@@ -37191,7 +37191,6 @@ var toolRuleSchema = external_exports.string().min(1).max(500);
37191
37191
  var agentToolsPermissionsSchema = external_exports.object({
37192
37192
  defaultMode: external_exports.enum(["default", "acceptEdits", "plan", "bypassPermissions"]),
37193
37193
  allow: external_exports.array(toolRuleSchema).max(500),
37194
- ask: external_exports.array(toolRuleSchema).max(500),
37195
37194
  deny: external_exports.array(toolRuleSchema).max(500)
37196
37195
  });
37197
37196
  var agentToolsReadQuerySchema = external_exports.object({
@@ -37681,6 +37680,50 @@ async function commitAndPushSubmodules(root, submodules, emit) {
37681
37680
  emit("submodule-push-failed", `Submodules committed locally but the push failed: ${msg}`);
37682
37681
  }
37683
37682
  }
37683
+ function providerSlug(url) {
37684
+ const provider = /github\.com/i.test(url) ? "gh" : /gitlab\.com/i.test(url) ? "glab" : null;
37685
+ const m2 = /(?:github|gitlab)\.com[/:]+([^/]+\/.+?)(?:\.git)?\/?$/i.exec(url);
37686
+ return { provider, slug: m2?.[1] ?? "" };
37687
+ }
37688
+ async function commitAndOpenPr(root, repo, emit) {
37689
+ emit("commit", "Committing the scaffolded project\u2026");
37690
+ await run2("git", ["add", "-A"], { cwd: root, timeout: 6e4 });
37691
+ const staged = (await run2("git", ["diff", "--cached", "--name-only"], { cwd: root, timeout: 3e4 })).stdout.trim();
37692
+ if (!staged) {
37693
+ emit("commit", "Nothing to commit \u2014 skipping the pull request.");
37694
+ return;
37695
+ }
37696
+ const commitArgs = ["commit", "-m", "chore: scaffold project (4PM)"];
37697
+ try {
37698
+ await run2("git", commitArgs, { cwd: root, timeout: 6e4 });
37699
+ } catch {
37700
+ await run2("git", ["-c", "user.name=4PM", "-c", "user.email=noreply@4pm.app", ...commitArgs], { cwd: root, timeout: 6e4 });
37701
+ }
37702
+ const branch = (repo.branch ?? "").trim();
37703
+ emit("push", "Pushing the scaffold branch\u2026");
37704
+ try {
37705
+ await run2("git", ["push", "-u", "origin", ...branch ? [branch] : ["HEAD"]], { cwd: root, timeout: 12e4 });
37706
+ } catch (err) {
37707
+ const msg = err instanceof Error ? err.message : String(err);
37708
+ emit("push-failed", `Scaffold committed locally but the push failed: ${msg} \u2014 push it from the Git tab when credentials are available.`);
37709
+ return;
37710
+ }
37711
+ const { provider, slug } = providerSlug(repo.url ?? "");
37712
+ if (!provider) {
37713
+ emit("pr", "Unknown git host \u2014 skipping the pull request.");
37714
+ return;
37715
+ }
37716
+ emit("pr", `Opening a pull request via ${provider}\u2026`);
37717
+ try {
37718
+ const args = provider === "glab" ? ["mr", "create", "--fill", ...slug ? ["-R", slug] : []] : ["pr", "create", "--fill", ...slug ? ["-R", slug] : []];
37719
+ const { stdout } = await run2(provider, args, { cwd: root, timeout: 12e4 });
37720
+ const link2 = stdout.trim().split(/\s+/).find((s3) => /^https?:\/\//.test(s3)) ?? stdout.trim().split("\n").pop() ?? "";
37721
+ emit("pr", `Pull request opened${link2 ? `: ${link2}` : "."}`);
37722
+ } catch (err) {
37723
+ const msg = err instanceof Error ? err.message : String(err);
37724
+ emit("pr-failed", `Could not open a pull request (${provider}): ${msg}`);
37725
+ }
37726
+ }
37684
37727
  function cloneArgs(url, dest, branch) {
37685
37728
  const b2 = (branch ?? "").trim();
37686
37729
  return b2 ? ["clone", "-b", b2, url, dest] : ["clone", url, dest];
@@ -37787,18 +37830,20 @@ async function scaffoldProject(payload, profileDir2, onProgress) {
37787
37830
  if (!repo) throw new Error("A project must declare one repo (ADR-0314).");
37788
37831
  emit("git", "Cloning repository\u2026");
37789
37832
  await provisionRepo(target, repo, emit, { createMissingBranch: true });
37790
- await scaffoldRepo(target, payload.projectName, payload.spec, emit);
37833
+ await scaffoldRepo(target, payload.projectName, payload.spec, emit, { resetClaude: true });
37791
37834
  await attachSubmodules(target, submodulesOf(reposOf(payload.spec)), emit, true);
37792
37835
  emit("version", "Writing .4pm/.4pm.json\u2026");
37793
37836
  await writeTemplateMarker(target);
37837
+ await commitAndOpenPr(target, repo, emit);
37794
37838
  onProgress?.({ projectId: payload.projectId, step: "done", message: "Scaffold complete.", done: true });
37795
37839
  return { ok: true, path: target };
37796
37840
  } catch (err) {
37797
37841
  return { ok: false, error: err instanceof Error ? err.message : String(err), step: lastStep };
37798
37842
  }
37799
37843
  }
37800
- async function scaffoldRepo(dir2, label, spec, emit) {
37844
+ async function scaffoldRepo(dir2, label, spec, emit, opts = {}) {
37801
37845
  await mkdir(dir2, { recursive: true });
37846
+ if (opts.resetClaude) await resetTemplateManagedClaude(dir2, label, emit);
37802
37847
  emit("copy", `Copying the sample template into ${label}\u2026`);
37803
37848
  await cp(sampleDir(), dir2, { recursive: true, force: false, errorOnExist: false });
37804
37849
  if (spec) {
@@ -37807,6 +37852,13 @@ async function scaffoldRepo(dir2, label, spec, emit) {
37807
37852
  await aiInit(dir2, spec, emit);
37808
37853
  }
37809
37854
  }
37855
+ async function resetTemplateManagedClaude(dir2, label, emit) {
37856
+ const claude = join6(dir2, ".claude");
37857
+ if (!existsSync4(claude)) return;
37858
+ emit("copy", `Resetting template .claude config in ${label}\u2026`);
37859
+ await rm(join6(claude, "settings.json"), { force: true });
37860
+ await rm(join6(claude, "skills"), { recursive: true, force: true });
37861
+ }
37810
37862
  async function writeTemplateMarker(target) {
37811
37863
  const dir2 = join6(target, ".4pm");
37812
37864
  await mkdir(dir2, { recursive: true });
@@ -37854,15 +37906,20 @@ ${specJson}`
37854
37906
  ${specJson}` + (guideInstructions ? `
37855
37907
  Also incorporate these additional instructions/content:
37856
37908
  ${guideInstructions}
37857
- ` : "")
37909
+ ` : ""),
37910
+ guideInstructions
37858
37911
  );
37859
37912
  }
37860
- async function generateFile(path, prompt) {
37913
+ async function generateFile(path, prompt, fallback) {
37861
37914
  try {
37862
37915
  const text = await aiGenerate(prompt);
37863
- if (text.trim()) await writeFile(path, text.trim() + "\n", "utf8");
37916
+ if (text.trim()) {
37917
+ await writeFile(path, text.trim() + "\n", "utf8");
37918
+ return;
37919
+ }
37864
37920
  } catch {
37865
37921
  }
37922
+ if (fallback && fallback.trim()) await writeFile(path, fallback.trim() + "\n", "utf8");
37866
37923
  }
37867
37924
  async function addProject(payload, profileDir2, onProgress) {
37868
37925
  let lastStep = "start";
@@ -42360,7 +42417,8 @@ async function gitRepos(root) {
42360
42417
  if (!top || !(top === base || top.startsWith(base + sep8))) return { repos: [] };
42361
42418
  const repos = [];
42362
42419
  const rootRemote = (await git(base, ["remote", "get-url", "origin"])).trim();
42363
- repos.push({ subdir: "", name: "", remote: rootRemote || null });
42420
+ const rootBranch = (await git(base, ["rev-parse", "--abbrev-ref", "HEAD"])).trim();
42421
+ repos.push({ subdir: "", name: "", remote: rootRemote || null, branch: rootBranch || null });
42364
42422
  const subOut = await git(base, ["submodule", "status"]);
42365
42423
  for (const line of subOut.split("\n")) {
42366
42424
  const m2 = line.trim().match(/^[-+U ]?[0-9a-f]{7,40}\s+(\S+)/);
@@ -42369,7 +42427,8 @@ async function gitRepos(root) {
42369
42427
  const abs = resolve8(base, subPath);
42370
42428
  if (!(abs === base || abs.startsWith(base + sep8))) continue;
42371
42429
  const remote = (await git(abs, ["remote", "get-url", "origin"])).trim();
42372
- repos.push({ subdir: subPath, name: subPath, remote: remote || null });
42430
+ const branch = (await git(abs, ["rev-parse", "--abbrev-ref", "HEAD"])).trim();
42431
+ repos.push({ subdir: subPath, name: subPath, remote: remote || null, branch: branch || null });
42373
42432
  }
42374
42433
  return { repos };
42375
42434
  }
@@ -43039,7 +43098,6 @@ import { dirname as dirname8, join as join26 } from "path";
43039
43098
  var SHARED_REL = ".claude/settings.json";
43040
43099
  var LOCAL_REL = ".claude/settings.local.json";
43041
43100
  var SECRETS_DENY = "Read(./project.secrets.json)";
43042
- var MODES = ["default", "acceptEdits", "plan", "bypassPermissions"];
43043
43101
  function fileFor(root, scope) {
43044
43102
  return join26(root, scope === "shared" ? SHARED_REL : LOCAL_REL);
43045
43103
  }
@@ -43053,9 +43111,8 @@ async function readSettingsObject(path) {
43053
43111
  }
43054
43112
  function normalizePermissions(raw) {
43055
43113
  const p2 = raw && typeof raw === "object" ? raw : {};
43056
- const mode = MODES.includes(p2.defaultMode) ? p2.defaultMode : "default";
43057
43114
  const list = (v2) => Array.isArray(v2) ? v2.filter((x) => typeof x === "string") : [];
43058
- return { defaultMode: mode, allow: list(p2.allow), ask: list(p2.ask), deny: list(p2.deny) };
43115
+ return { defaultMode: "bypassPermissions", allow: list(p2.allow), deny: list(p2.deny) };
43059
43116
  }
43060
43117
  async function readAgentTools(root, scope) {
43061
43118
  const obj = await readSettingsObject(fileFor(root, scope));
@@ -8,7 +8,6 @@
8
8
  "permissions": {
9
9
  "defaultMode": "bypassPermissions",
10
10
  "allow": [],
11
- "ask": [],
12
11
  "deny": []
13
12
  },
14
13
  "enableAllProjectMcpServers": true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4pm/cli",
3
- "version": "1.19.7",
3
+ "version": "1.19.9",
4
4
  "private": false,
5
5
  "description": "4PM CLI — drives Claude/Codex CLIs on AI worker machines (Node + TypeScript)",
6
6
  "license": "LicenseRef-4PM-Source-Available",