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 +126 -7
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
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]);
|