pure-point-guard 0.3.1 → 0.3.2

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/cli.js CHANGED
@@ -475,7 +475,7 @@ You are a senior engineer reviewing code for quality, readability, and maintaina
475
475
  - Documentation gaps for non-obvious logic
476
476
 
477
477
  ## Output
478
- Write a structured review to {{RESULT_FILE}} with specific file:line references and improvement suggestions.
478
+ Write a structured review with specific file:line references and improvement suggestions.
479
479
  `,
480
480
  "review-security": `# Security Review
481
481
 
@@ -493,7 +493,7 @@ You are a security engineer reviewing code for vulnerabilities and risks.
493
493
  - Secrets or credentials in code
494
494
 
495
495
  ## Output
496
- Write a structured review to {{RESULT_FILE}} with severity ratings and remediation guidance.
496
+ Write a structured review with severity ratings and remediation guidance.
497
497
  `,
498
498
  "review-regression": `# Regression & Risk Review
499
499
 
@@ -511,7 +511,7 @@ You are a QA engineer reviewing code for regression risks and test coverage gaps
511
511
  - Performance regressions
512
512
 
513
513
  ## Output
514
- Write a structured review to {{RESULT_FILE}} with risk ratings and recommended test additions.
514
+ Write a structured review with risk ratings and recommended test additions.
515
515
  `
516
516
  };
517
517
  }
@@ -1002,10 +1002,6 @@ Project root: {{PROJECT_ROOT}}
1002
1002
 
1003
1003
  ## Instructions
1004
1004
  {{PROMPT}}
1005
-
1006
- ## Result Reporting
1007
- When you have completed the task, write your results to:
1008
- {{RESULT_FILE}}
1009
1005
  `;
1010
1006
  }
1011
1007
  });
@@ -4506,13 +4502,17 @@ var init_cron = __esm({
4506
4502
  // src/commands/cron.ts
4507
4503
  var cron_exports = {};
4508
4504
  __export(cron_exports, {
4505
+ cronAddCommand: () => cronAddCommand,
4509
4506
  cronDaemonCommand: () => cronDaemonCommand,
4510
4507
  cronListCommand: () => cronListCommand,
4508
+ cronRemoveCommand: () => cronRemoveCommand,
4511
4509
  cronStartCommand: () => cronStartCommand,
4512
4510
  cronStatusCommand: () => cronStatusCommand,
4513
4511
  cronStopCommand: () => cronStopCommand
4514
4512
  });
4515
4513
  import fs17 from "fs/promises";
4514
+ import path12 from "path";
4515
+ import YAML4 from "yaml";
4516
4516
  async function cronStartCommand(options) {
4517
4517
  const projectRoot = await getRepoRoot();
4518
4518
  await requireInit(projectRoot);
@@ -4647,6 +4647,116 @@ async function cronDaemonCommand() {
4647
4647
  await requireInit(projectRoot);
4648
4648
  await runCronDaemon(projectRoot);
4649
4649
  }
4650
+ async function cronAddCommand(options) {
4651
+ const projectRoot = options.project ?? await getRepoRoot();
4652
+ await requireInit(projectRoot);
4653
+ const SAFE_NAME3 = /^[\w-]+$/;
4654
+ if (!options.name || !SAFE_NAME3.test(options.name)) {
4655
+ throw new PpgError(
4656
+ `Invalid schedule name "${options.name}" \u2014 must be alphanumeric, hyphens, or underscores`,
4657
+ "INVALID_ARGS"
4658
+ );
4659
+ }
4660
+ if (!options.swarm && !options.prompt) {
4661
+ throw new PpgError("Must specify either --swarm or --prompt", "INVALID_ARGS");
4662
+ }
4663
+ if (options.swarm && options.prompt) {
4664
+ throw new PpgError("Specify either --swarm or --prompt, not both", "INVALID_ARGS");
4665
+ }
4666
+ validateCronExpression(options.cron);
4667
+ const entry = {
4668
+ name: options.name,
4669
+ cron: options.cron
4670
+ };
4671
+ if (options.swarm) entry.swarm = options.swarm;
4672
+ if (options.prompt) entry.prompt = options.prompt;
4673
+ if (options.var && options.var.length > 0) {
4674
+ const vars = {};
4675
+ for (const v of options.var) {
4676
+ const eqIdx = v.indexOf("=");
4677
+ if (eqIdx === -1) {
4678
+ throw new PpgError(`Invalid --var format: "${v}" (expected KEY=VALUE)`, "INVALID_ARGS");
4679
+ }
4680
+ const key = v.slice(0, eqIdx);
4681
+ if (key.length === 0) {
4682
+ throw new PpgError(`Invalid --var format: "${v}" (key must not be empty)`, "INVALID_ARGS");
4683
+ }
4684
+ vars[key] = v.slice(eqIdx + 1);
4685
+ }
4686
+ entry.vars = vars;
4687
+ }
4688
+ const filePath = schedulesPath(projectRoot);
4689
+ const ppgDirPath = path12.dirname(filePath);
4690
+ await fs17.mkdir(ppgDirPath, { recursive: true });
4691
+ await updateSchedulesFile(filePath, (config) => {
4692
+ if (config.schedules.some((s) => s.name === options.name)) {
4693
+ throw new PpgError(`Schedule "${options.name}" already exists`, "INVALID_ARGS");
4694
+ }
4695
+ config.schedules.push(entry);
4696
+ return config;
4697
+ });
4698
+ if (options.json) {
4699
+ output({ success: true, name: options.name, schedule: entry }, true);
4700
+ } else {
4701
+ success(`Schedule "${options.name}" added`);
4702
+ }
4703
+ }
4704
+ async function cronRemoveCommand(options) {
4705
+ const projectRoot = options.project ?? await getRepoRoot();
4706
+ await requireInit(projectRoot);
4707
+ const filePath = schedulesPath(projectRoot);
4708
+ await updateSchedulesFile(filePath, (config) => {
4709
+ const idx = config.schedules.findIndex((s) => s.name === options.name);
4710
+ if (idx === -1) {
4711
+ throw new PpgError(`Schedule "${options.name}" not found`, "INVALID_ARGS");
4712
+ }
4713
+ config.schedules.splice(idx, 1);
4714
+ return config;
4715
+ });
4716
+ if (options.json) {
4717
+ output({ success: true, name: options.name }, true);
4718
+ } else {
4719
+ success(`Schedule "${options.name}" removed`);
4720
+ }
4721
+ }
4722
+ async function updateSchedulesFile(filePath, updater) {
4723
+ const lockfile = await getLockfile();
4724
+ const writeFileAtomic = await getWriteFileAtomic();
4725
+ let release;
4726
+ try {
4727
+ release = await lockfile.lock(filePath, {
4728
+ stale: 1e4,
4729
+ retries: { retries: 5, minTimeout: 100, maxTimeout: 1e3 },
4730
+ realpath: false
4731
+ });
4732
+ } catch {
4733
+ throw new PpgError("Could not acquire lock on schedules.yaml", "MANIFEST_LOCK");
4734
+ }
4735
+ try {
4736
+ let config;
4737
+ try {
4738
+ const raw = await fs17.readFile(filePath, "utf-8");
4739
+ const parsed = YAML4.parse(raw);
4740
+ if (!parsed || !Array.isArray(parsed.schedules)) {
4741
+ throw new PpgError(
4742
+ 'Invalid schedules.yaml: missing or malformed "schedules" array. Fix the file manually or delete it to start fresh.',
4743
+ "INVALID_ARGS"
4744
+ );
4745
+ }
4746
+ config = parsed;
4747
+ } catch (err) {
4748
+ if (err.code === "ENOENT") {
4749
+ config = { schedules: [] };
4750
+ } else {
4751
+ throw err;
4752
+ }
4753
+ }
4754
+ const updated = updater(config);
4755
+ await writeFileAtomic(filePath, YAML4.stringify(updated));
4756
+ } finally {
4757
+ if (release) await release();
4758
+ }
4759
+ }
4650
4760
  async function requireInit(projectRoot) {
4651
4761
  try {
4652
4762
  await fs17.access(manifestPath(projectRoot));
@@ -4664,6 +4774,7 @@ var init_cron2 = __esm({
4664
4774
  init_cron();
4665
4775
  init_tmux();
4666
4776
  init_paths();
4777
+ init_cjs_compat();
4667
4778
  init_errors();
4668
4779
  init_output();
4669
4780
  CRON_WINDOW_NAME = "ppg-cron";
@@ -4785,6 +4896,14 @@ cronCmd.command("_daemon", { hidden: true }).description("Internal: run the cron
4785
4896
  const { cronDaemonCommand: cronDaemonCommand2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports));
4786
4897
  await cronDaemonCommand2();
4787
4898
  });
4899
+ cronCmd.command("add").description("Add a new schedule entry").requiredOption("--name <name>", "Schedule name").requiredOption("--cron <expression>", "Cron expression").option("--swarm <name>", "Swarm template name").option("--prompt <name>", "Prompt template name").option("--var <key=value...>", "Template variables", collectVars, []).option("--project <path>", "Project root path").option("--json", "Output as JSON").action(async (options) => {
4900
+ const { cronAddCommand: cronAddCommand2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports));
4901
+ await cronAddCommand2(options);
4902
+ });
4903
+ cronCmd.command("remove").description("Remove a schedule entry").requiredOption("--name <name>", "Schedule name to remove").option("--project <path>", "Project root path").option("--json", "Output as JSON").action(async (options) => {
4904
+ const { cronRemoveCommand: cronRemoveCommand2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports));
4905
+ await cronRemoveCommand2(options);
4906
+ });
4788
4907
  program.exitOverride();
4789
4908
  function collectVars(value, previous) {
4790
4909
  return previous.concat([value]);