paqad-ai 0.1.1 → 0.1.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/index.js +178 -150
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +207 -206
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/runtime/base/rules/design-system.md +13 -0
- package/runtime/capabilities/security/rules/pentest.md +69 -0
- package/runtime/templates/agent-configs/agents.md.hbs +2 -0
- package/runtime/templates/agent-configs/claude.md.hbs +2 -0
- package/runtime/templates/agent-configs/gemini.md.hbs +2 -0
- package/runtime/templates/agent-configs/junie.md.hbs +3 -0
package/dist/cli/index.js
CHANGED
|
@@ -5711,6 +5711,8 @@ function resolveArtifactDirectoryName(artifactType) {
|
|
|
5711
5711
|
var RULE_SEED_PRIORITY = [
|
|
5712
5712
|
"constitution",
|
|
5713
5713
|
"security",
|
|
5714
|
+
"pentest",
|
|
5715
|
+
"design-system",
|
|
5714
5716
|
"content-rules",
|
|
5715
5717
|
"testing",
|
|
5716
5718
|
"documentation",
|
|
@@ -5806,9 +5808,34 @@ function getRulePriority(filePath) {
|
|
|
5806
5808
|
return index === -1 ? RULE_SEED_PRIORITY.length : index;
|
|
5807
5809
|
}
|
|
5808
5810
|
|
|
5811
|
+
// src/onboarding/gitignore-writer.ts
|
|
5812
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
|
|
5813
|
+
import { join as join30 } from "path";
|
|
5814
|
+
var PAQAD_MARKER = "# paqad-ai";
|
|
5815
|
+
var PAQAD_GITIGNORE_ENTRIES = [
|
|
5816
|
+
PAQAD_MARKER,
|
|
5817
|
+
".paqad/cache/",
|
|
5818
|
+
".paqad/session/",
|
|
5819
|
+
".paqad/context/",
|
|
5820
|
+
".paqad/workflows/",
|
|
5821
|
+
".paqad/indexes/",
|
|
5822
|
+
".paqad/pentest/",
|
|
5823
|
+
".paqad/theme/"
|
|
5824
|
+
].join("\n");
|
|
5825
|
+
function writeGitignore(projectRoot) {
|
|
5826
|
+
const gitignorePath = join30(projectRoot, ".gitignore");
|
|
5827
|
+
const existing = existsSync13(gitignorePath) ? readFileSync11(gitignorePath, "utf8") : "";
|
|
5828
|
+
if (existing.includes(PAQAD_MARKER)) {
|
|
5829
|
+
return;
|
|
5830
|
+
}
|
|
5831
|
+
const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
5832
|
+
writeFileSync4(gitignorePath, `${existing}${separator}
|
|
5833
|
+
${PAQAD_GITIGNORE_ENTRIES}
|
|
5834
|
+
`);
|
|
5835
|
+
}
|
|
5836
|
+
|
|
5809
5837
|
// src/onboarding/prompts.ts
|
|
5810
5838
|
import { checkbox, select } from "@inquirer/prompts";
|
|
5811
|
-
var ALL_PROVIDERS = ["codex-cli", "claude-code", "gemini-cli", "junie"];
|
|
5812
5839
|
function isInteractive() {
|
|
5813
5840
|
return Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
5814
5841
|
}
|
|
@@ -5842,7 +5869,7 @@ function buildFromOverridesAndDetection(detection, snapshot, overrides) {
|
|
|
5842
5869
|
snapshot
|
|
5843
5870
|
));
|
|
5844
5871
|
return {
|
|
5845
|
-
providers: overrides?.providers ??
|
|
5872
|
+
providers: overrides?.providers ?? ["claude-code"],
|
|
5846
5873
|
domain,
|
|
5847
5874
|
stack_profile: stackProfile,
|
|
5848
5875
|
stack: overrides?.stack ?? (snapshot?.profile ? getPrimaryStack({
|
|
@@ -6233,9 +6260,9 @@ function inferSelectionDomain(detection, overrides, snapshot) {
|
|
|
6233
6260
|
}
|
|
6234
6261
|
|
|
6235
6262
|
// src/onboarding/reference-generator.ts
|
|
6236
|
-
import { existsSync as
|
|
6263
|
+
import { existsSync as existsSync14 } from "fs";
|
|
6237
6264
|
import { readFile as readFile13 } from "fs/promises";
|
|
6238
|
-
import { join as
|
|
6265
|
+
import { join as join31, relative as relative4 } from "path";
|
|
6239
6266
|
import fg3 from "fast-glob";
|
|
6240
6267
|
async function generateReferenceGuides(runtimeRoot, context) {
|
|
6241
6268
|
if (context.domain !== "coding") {
|
|
@@ -6246,8 +6273,8 @@ async function generateReferenceGuides(runtimeRoot, context) {
|
|
|
6246
6273
|
routing: { domain: context.domain },
|
|
6247
6274
|
stack_profile: context.stack_profile
|
|
6248
6275
|
});
|
|
6249
|
-
const referencesRoot =
|
|
6250
|
-
if (!
|
|
6276
|
+
const referencesRoot = join31(runtimeRoot, "capabilities", "coding", "stacks", stack, "references");
|
|
6277
|
+
if (!existsSync14(referencesRoot)) {
|
|
6251
6278
|
return [buildFallbackReferenceGuide(stack)];
|
|
6252
6279
|
}
|
|
6253
6280
|
const entries = await fg3(["tools/*.md", "tools-catalog.md"], {
|
|
@@ -6269,14 +6296,14 @@ async function generateReferenceGuides(runtimeRoot, context) {
|
|
|
6269
6296
|
function toProjectReferencePath(stack, relativePath) {
|
|
6270
6297
|
const normalized = relativePath.replaceAll("\\", "/");
|
|
6271
6298
|
if (normalized === "tools-catalog.md") {
|
|
6272
|
-
return
|
|
6299
|
+
return join31(PATHS.TOOLS_DIR, stack, "README.md");
|
|
6273
6300
|
}
|
|
6274
|
-
return
|
|
6301
|
+
return join31(PATHS.TOOLS_DIR, stack, normalized.replace(/^tools\//, ""));
|
|
6275
6302
|
}
|
|
6276
6303
|
function buildFallbackReferenceGuide(stack) {
|
|
6277
6304
|
const title = stack.split("-").map((segment) => segment.slice(0, 1).toUpperCase() + segment.slice(1)).join(" ");
|
|
6278
6305
|
return {
|
|
6279
|
-
path:
|
|
6306
|
+
path: join31(PATHS.TOOLS_DIR, stack, "README.md"),
|
|
6280
6307
|
autoUpdate: false,
|
|
6281
6308
|
content: [
|
|
6282
6309
|
`# ${title} Tool References`,
|
|
@@ -6294,7 +6321,7 @@ function buildFallbackReferenceGuide(stack) {
|
|
|
6294
6321
|
|
|
6295
6322
|
// src/onboarding/rule-generator.ts
|
|
6296
6323
|
import { readFile as readFile14 } from "fs/promises";
|
|
6297
|
-
import { join as
|
|
6324
|
+
import { join as join32 } from "path";
|
|
6298
6325
|
async function generateProjectRules(rules) {
|
|
6299
6326
|
return Promise.all(
|
|
6300
6327
|
rules.map(async (rule) => ({
|
|
@@ -6307,22 +6334,22 @@ async function generateProjectRules(rules) {
|
|
|
6307
6334
|
function toProjectRulePath(source) {
|
|
6308
6335
|
const normalized = source.replaceAll("\\", "/");
|
|
6309
6336
|
if (normalized.startsWith("base/rules/")) {
|
|
6310
|
-
return
|
|
6337
|
+
return join32(PATHS.RULES_DIR, "_shared", normalized.replace(/^base\/rules\//, ""));
|
|
6311
6338
|
}
|
|
6312
6339
|
if (normalized.startsWith("capabilities/")) {
|
|
6313
6340
|
const capabilityNormalized = normalized.replace(/^capabilities\//, "");
|
|
6314
6341
|
const [prefix2, suffix2] = capabilityNormalized.split("/rules/");
|
|
6315
6342
|
if (prefix2 !== void 0 && suffix2 !== void 0) {
|
|
6316
6343
|
const target2 = suffix2.endsWith("/guide.md") ? suffix2.replace("/guide.md", ".md") : suffix2;
|
|
6317
|
-
return
|
|
6344
|
+
return join32(PATHS.RULES_DIR, prefix2, target2);
|
|
6318
6345
|
}
|
|
6319
6346
|
}
|
|
6320
6347
|
const [prefix, suffix] = normalized.split("/rules/");
|
|
6321
6348
|
if (prefix === void 0 || suffix === void 0) {
|
|
6322
|
-
return
|
|
6349
|
+
return join32(PATHS.RULES_DIR, normalized);
|
|
6323
6350
|
}
|
|
6324
6351
|
const target = suffix.endsWith("/guide.md") ? suffix.replace("/guide.md", ".md") : suffix;
|
|
6325
|
-
return
|
|
6352
|
+
return join32(PATHS.RULES_DIR, prefix, target);
|
|
6326
6353
|
}
|
|
6327
6354
|
|
|
6328
6355
|
// src/onboarding/orchestrator.ts
|
|
@@ -6337,7 +6364,7 @@ var OnboardingOrchestrator = class {
|
|
|
6337
6364
|
const runtimeRoot = options.runtimeRoot ?? getRuntimeRoot();
|
|
6338
6365
|
const resolver = new Resolver({ runtimeRoot });
|
|
6339
6366
|
const resolved = await resolver.resolve(selections);
|
|
6340
|
-
const adapters = options.adapters ?? selections.providers ?? ["claude-code"
|
|
6367
|
+
const adapters = options.adapters ?? selections.providers ?? ["claude-code"];
|
|
6341
6368
|
const profile = buildProjectProfile(selections, liveSnapshot, options.profileOverrides);
|
|
6342
6369
|
const validator = new SchemaValidator();
|
|
6343
6370
|
const validation = validator.validate("project-profile", profile);
|
|
@@ -6374,6 +6401,7 @@ var OnboardingOrchestrator = class {
|
|
|
6374
6401
|
{ writeHumanDocs: false }
|
|
6375
6402
|
);
|
|
6376
6403
|
writeProjectProfile2(options.projectRoot, profile);
|
|
6404
|
+
writeGitignore(options.projectRoot);
|
|
6377
6405
|
writeDetectionReport(options.projectRoot, detection);
|
|
6378
6406
|
bootstrapFramework(options.projectRoot);
|
|
6379
6407
|
const manifestPath = writeOnboardingManifest(options.projectRoot, {
|
|
@@ -6648,7 +6676,7 @@ function buildRustCommands(usingCompose) {
|
|
|
6648
6676
|
}
|
|
6649
6677
|
|
|
6650
6678
|
// src/onboarding/scaffold-generator.ts
|
|
6651
|
-
import { join as
|
|
6679
|
+
import { join as join33 } from "path";
|
|
6652
6680
|
|
|
6653
6681
|
// src/templates/registry.ts
|
|
6654
6682
|
import fg4 from "fast-glob";
|
|
@@ -6656,29 +6684,29 @@ import { basename as basename4, relative as relative5 } from "pathe";
|
|
|
6656
6684
|
|
|
6657
6685
|
// src/onboarding/scaffold-generator.ts
|
|
6658
6686
|
var FEATURE_TEMPLATE_TARGETS = [
|
|
6659
|
-
["business.md.hbs",
|
|
6660
|
-
["technical.md.hbs",
|
|
6687
|
+
["business.md.hbs", join33(PATHS.MODULE_FEATURES_DIR, "core", "business.md")],
|
|
6688
|
+
["technical.md.hbs", join33(PATHS.MODULE_FEATURES_DIR, "core", "technical.md")]
|
|
6661
6689
|
];
|
|
6662
6690
|
|
|
6663
6691
|
// src/packs/manager.ts
|
|
6664
6692
|
import {
|
|
6665
6693
|
cpSync,
|
|
6666
|
-
existsSync as
|
|
6694
|
+
existsSync as existsSync15,
|
|
6667
6695
|
mkdirSync as mkdirSync5,
|
|
6668
6696
|
mkdtempSync,
|
|
6669
6697
|
readdirSync as readdirSync3,
|
|
6670
6698
|
rmSync as rmSync2,
|
|
6671
|
-
writeFileSync as
|
|
6699
|
+
writeFileSync as writeFileSync5
|
|
6672
6700
|
} from "fs";
|
|
6673
6701
|
import { homedir as homedir2 } from "os";
|
|
6674
|
-
import { join as
|
|
6702
|
+
import { join as join34, resolve as resolve2 } from "path";
|
|
6675
6703
|
import { execa } from "execa";
|
|
6676
6704
|
var SOURCE_ORDER2 = ["built-in", "global", "project"];
|
|
6677
6705
|
function resolvePackManagerRoots(projectRoot = process.cwd(), overrides = {}) {
|
|
6678
6706
|
return {
|
|
6679
6707
|
runtimeRoot: overrides.runtimeRoot ?? getRuntimeRoot(),
|
|
6680
|
-
globalPacksRoot: overrides.globalPacksRoot ?? process.env.PAQAD_GLOBAL_PACKS_ROOT ??
|
|
6681
|
-
projectPacksRoot: overrides.projectPacksRoot ??
|
|
6708
|
+
globalPacksRoot: overrides.globalPacksRoot ?? process.env.PAQAD_GLOBAL_PACKS_ROOT ?? join34(homedir2(), ".paqad", "packs"),
|
|
6709
|
+
projectPacksRoot: overrides.projectPacksRoot ?? join34(projectRoot, ".paqad", "packs"),
|
|
6682
6710
|
registryUrl: overrides.registryUrl ?? process.env.PAQAD_PACK_REGISTRY_URL
|
|
6683
6711
|
};
|
|
6684
6712
|
}
|
|
@@ -6726,7 +6754,7 @@ async function installPack(source, options = {}) {
|
|
|
6726
6754
|
if (!pack.validation.valid) {
|
|
6727
6755
|
throw new Error(formatValidationIssues(pack.validation.issues));
|
|
6728
6756
|
}
|
|
6729
|
-
const destination =
|
|
6757
|
+
const destination = join34(installRoot, pack.manifest.name);
|
|
6730
6758
|
rmSync2(destination, { recursive: true, force: true });
|
|
6731
6759
|
cpSync(candidateRoot, destination, { recursive: true });
|
|
6732
6760
|
const installed = loader.validatePack(destination, scope === "project" ? "project" : "global");
|
|
@@ -6738,13 +6766,13 @@ async function installPack(source, options = {}) {
|
|
|
6738
6766
|
function removePack(name, projectRoot = process.cwd(), scope = "global", overrides = {}) {
|
|
6739
6767
|
const roots = resolvePackManagerRoots(projectRoot, overrides);
|
|
6740
6768
|
const targetRoot = scope === "project" ? roots.projectPacksRoot : roots.globalPacksRoot;
|
|
6741
|
-
const target =
|
|
6742
|
-
if (
|
|
6769
|
+
const target = join34(targetRoot, name);
|
|
6770
|
+
if (existsSync15(target)) {
|
|
6743
6771
|
rmSync2(target, { recursive: true, force: true });
|
|
6744
6772
|
return;
|
|
6745
6773
|
}
|
|
6746
|
-
const builtInRoot =
|
|
6747
|
-
if (
|
|
6774
|
+
const builtInRoot = join34(roots.runtimeRoot, "capabilities", "coding", "stacks", name);
|
|
6775
|
+
if (existsSync15(builtInRoot)) {
|
|
6748
6776
|
throw new Error(
|
|
6749
6777
|
`Cannot remove built-in pack "${name}"; remove a global or project override instead`
|
|
6750
6778
|
);
|
|
@@ -6761,14 +6789,14 @@ function validatePackAt(path) {
|
|
|
6761
6789
|
function createPack(name, options = {}) {
|
|
6762
6790
|
const destinationRoot = options.destinationRoot ?? process.cwd();
|
|
6763
6791
|
const ecosystem = options.ecosystem ?? "node";
|
|
6764
|
-
const packRoot =
|
|
6765
|
-
if (
|
|
6792
|
+
const packRoot = join34(destinationRoot, name);
|
|
6793
|
+
if (existsSync15(packRoot)) {
|
|
6766
6794
|
throw new Error(`Pack scaffold already exists at ${packRoot}`);
|
|
6767
6795
|
}
|
|
6768
|
-
mkdirSync5(
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6796
|
+
mkdirSync5(join34(packRoot, "rules"), { recursive: true });
|
|
6797
|
+
writeFileSync5(join34(packRoot, "pack.yaml"), renderPackTemplate(name, ecosystem));
|
|
6798
|
+
writeFileSync5(
|
|
6799
|
+
join34(packRoot, "rules", "conventions.md"),
|
|
6772
6800
|
`# ${name}
|
|
6773
6801
|
|
|
6774
6802
|
Document project-specific conventions for the ${name} stack here.
|
|
@@ -6778,14 +6806,14 @@ Document project-specific conventions for the ${name} stack here.
|
|
|
6778
6806
|
}
|
|
6779
6807
|
function listPackNamesForSource(source, roots) {
|
|
6780
6808
|
const sourceRoot = resolveSourceRoot(source, roots);
|
|
6781
|
-
if (!
|
|
6809
|
+
if (!existsSync15(sourceRoot)) {
|
|
6782
6810
|
return [];
|
|
6783
6811
|
}
|
|
6784
6812
|
return readdirSync3(sourceRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
6785
6813
|
}
|
|
6786
6814
|
function resolveSourceRoot(source, roots) {
|
|
6787
6815
|
if (source === "built-in") {
|
|
6788
|
-
return
|
|
6816
|
+
return join34(roots.runtimeRoot, "capabilities", "coding", "stacks");
|
|
6789
6817
|
}
|
|
6790
6818
|
return source === "global" ? roots.globalPacksRoot : roots.projectPacksRoot;
|
|
6791
6819
|
}
|
|
@@ -6805,13 +6833,13 @@ async function materializePackSource(source, roots) {
|
|
|
6805
6833
|
return clonePackSource(buildRegistryPackUrl(roots.registryUrl, source));
|
|
6806
6834
|
}
|
|
6807
6835
|
function looksLikeLocalPath(source) {
|
|
6808
|
-
return source.startsWith(".") || source.startsWith("/") ||
|
|
6836
|
+
return source.startsWith(".") || source.startsWith("/") || existsSync15(resolve2(source));
|
|
6809
6837
|
}
|
|
6810
6838
|
function looksLikeGitUrl(source) {
|
|
6811
6839
|
return source.startsWith("http://") || source.startsWith("https://") || source.startsWith("ssh://") || source.startsWith("git@") || source.startsWith("file://") || source.endsWith(".git");
|
|
6812
6840
|
}
|
|
6813
6841
|
async function clonePackSource(source) {
|
|
6814
|
-
const tempRoot = mkdtempSync(
|
|
6842
|
+
const tempRoot = mkdtempSync(join34(homedir2(), ".paqad-pack-clone-"));
|
|
6815
6843
|
try {
|
|
6816
6844
|
await execa("git", ["clone", "--depth", "1", source, tempRoot]);
|
|
6817
6845
|
} catch (error) {
|
|
@@ -6821,11 +6849,11 @@ async function clonePackSource(source) {
|
|
|
6821
6849
|
return findPackRoot(tempRoot);
|
|
6822
6850
|
}
|
|
6823
6851
|
function findPackRoot(root) {
|
|
6824
|
-
const rootManifest =
|
|
6825
|
-
if (
|
|
6852
|
+
const rootManifest = join34(root, "pack.yaml");
|
|
6853
|
+
if (existsSync15(rootManifest)) {
|
|
6826
6854
|
return root;
|
|
6827
6855
|
}
|
|
6828
|
-
const candidates = readdirSync3(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) =>
|
|
6856
|
+
const candidates = readdirSync3(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join34(root, entry.name)).filter((candidate) => existsSync15(join34(candidate, "pack.yaml")));
|
|
6829
6857
|
if (candidates.length === 1) {
|
|
6830
6858
|
return candidates[0];
|
|
6831
6859
|
}
|
|
@@ -6924,15 +6952,15 @@ async function queryOsv(packages) {
|
|
|
6924
6952
|
}
|
|
6925
6953
|
|
|
6926
6954
|
// src/pentest/progress-tracker.ts
|
|
6927
|
-
import { existsSync as
|
|
6955
|
+
import { existsSync as existsSync17 } from "fs";
|
|
6928
6956
|
import { mkdir as mkdir12, readdir as readdir4, readFile as readFile16, writeFile as writeFile12 } from "fs/promises";
|
|
6929
|
-
import { dirname as dirname17, join as
|
|
6957
|
+
import { dirname as dirname17, join as join36 } from "path";
|
|
6930
6958
|
|
|
6931
6959
|
// src/pentest/shared.ts
|
|
6932
6960
|
import { createHash as createHash7 } from "crypto";
|
|
6933
|
-
import { existsSync as
|
|
6961
|
+
import { existsSync as existsSync16 } from "fs";
|
|
6934
6962
|
import { mkdir as mkdir11, readFile as readFile15, readdir as readdir3, writeFile as writeFile11 } from "fs/promises";
|
|
6935
|
-
import { basename as basename5, dirname as dirname16, join as
|
|
6963
|
+
import { basename as basename5, dirname as dirname16, join as join35, relative as relative6 } from "path";
|
|
6936
6964
|
import { execa as execa2 } from "execa";
|
|
6937
6965
|
import fg5 from "fast-glob";
|
|
6938
6966
|
function toLocalTimestamp(date) {
|
|
@@ -6950,7 +6978,7 @@ async function writeJson(target, data) {
|
|
|
6950
6978
|
`);
|
|
6951
6979
|
}
|
|
6952
6980
|
async function readJsonIfExists(target) {
|
|
6953
|
-
if (!
|
|
6981
|
+
if (!existsSync16(target)) {
|
|
6954
6982
|
return null;
|
|
6955
6983
|
}
|
|
6956
6984
|
return JSON.parse(await readFile15(target, "utf8"));
|
|
@@ -6996,8 +7024,8 @@ async function discoverTargetUrl(projectRoot, stack, explicit) {
|
|
|
6996
7024
|
}
|
|
6997
7025
|
const envFiles = [".env", ".env.local", ".env.example"];
|
|
6998
7026
|
for (const envFile of envFiles) {
|
|
6999
|
-
const path =
|
|
7000
|
-
if (!
|
|
7027
|
+
const path = join35(projectRoot, envFile);
|
|
7028
|
+
if (!existsSync16(path)) {
|
|
7001
7029
|
continue;
|
|
7002
7030
|
}
|
|
7003
7031
|
const content = await readFile15(path, "utf8");
|
|
@@ -7018,11 +7046,11 @@ async function discoverTargetUrl(projectRoot, stack, explicit) {
|
|
|
7018
7046
|
return null;
|
|
7019
7047
|
}
|
|
7020
7048
|
async function runProjectScript(projectRoot, scriptName, env, logDir) {
|
|
7021
|
-
const scriptPath =
|
|
7022
|
-
const stdoutPath =
|
|
7023
|
-
const stderrPath =
|
|
7049
|
+
const scriptPath = join35(projectRoot, PATHS.SCRIPTS_DIR, scriptName);
|
|
7050
|
+
const stdoutPath = join35(logDir, `${scriptName}.stdout.log`);
|
|
7051
|
+
const stderrPath = join35(logDir, `${scriptName}.stderr.log`);
|
|
7024
7052
|
await mkdir11(logDir, { recursive: true });
|
|
7025
|
-
if (!
|
|
7053
|
+
if (!existsSync16(scriptPath)) {
|
|
7026
7054
|
await writeFile11(stdoutPath, "");
|
|
7027
7055
|
await writeFile11(stderrPath, `Missing script: ${relative6(projectRoot, scriptPath)}
|
|
7028
7056
|
`);
|
|
@@ -7050,8 +7078,8 @@ async function runProjectScript(projectRoot, scriptName, env, logDir) {
|
|
|
7050
7078
|
};
|
|
7051
7079
|
}
|
|
7052
7080
|
async function loadModuleDocs(projectRoot, focusModules = []) {
|
|
7053
|
-
const moduleRoot =
|
|
7054
|
-
if (!
|
|
7081
|
+
const moduleRoot = join35(projectRoot, PATHS.MODULES_DIR);
|
|
7082
|
+
if (!existsSync16(moduleRoot)) {
|
|
7055
7083
|
return [];
|
|
7056
7084
|
}
|
|
7057
7085
|
const dirs = (await readdir3(moduleRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((moduleName) => focusModules.length === 0 || focusModules.includes(moduleName)).sort();
|
|
@@ -7119,7 +7147,7 @@ function inferSourceArtifacts(baseDir, scriptResults) {
|
|
|
7119
7147
|
return [
|
|
7120
7148
|
...new Set(
|
|
7121
7149
|
artifacts.map(
|
|
7122
|
-
(artifact) => artifact.startsWith(".") ? artifact : relative6(dirname16(baseDir),
|
|
7150
|
+
(artifact) => artifact.startsWith(".") ? artifact : relative6(dirname16(baseDir), join35(dirname16(baseDir), artifact))
|
|
7123
7151
|
)
|
|
7124
7152
|
)
|
|
7125
7153
|
];
|
|
@@ -7193,8 +7221,8 @@ var PentestProgressTracker = class {
|
|
|
7193
7221
|
};
|
|
7194
7222
|
}
|
|
7195
7223
|
async load(projectRoot, runId) {
|
|
7196
|
-
const target =
|
|
7197
|
-
if (!
|
|
7224
|
+
const target = join36(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "progress.json");
|
|
7225
|
+
if (!existsSync17(target)) {
|
|
7198
7226
|
return null;
|
|
7199
7227
|
}
|
|
7200
7228
|
const parsed = JSON.parse(await readFile16(target, "utf8"));
|
|
@@ -7205,7 +7233,7 @@ var PentestProgressTracker = class {
|
|
|
7205
7233
|
return parsed;
|
|
7206
7234
|
}
|
|
7207
7235
|
async save(projectRoot, progress) {
|
|
7208
|
-
const target =
|
|
7236
|
+
const target = join36(projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "progress.json");
|
|
7209
7237
|
progress.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
7210
7238
|
await mkdir12(dirname17(target), { recursive: true });
|
|
7211
7239
|
await writeFile12(target, `${JSON.stringify(progress, null, 2)}
|
|
@@ -7264,8 +7292,8 @@ var PentestProgressTracker = class {
|
|
|
7264
7292
|
return step.status === "completed" && step.input_hash === inputHash;
|
|
7265
7293
|
}
|
|
7266
7294
|
async findIncompleteRun(projectRoot, workflow, sourceReportPath) {
|
|
7267
|
-
const runsDir =
|
|
7268
|
-
if (!
|
|
7295
|
+
const runsDir = join36(projectRoot, PATHS.PENTEST_RUNS_DIR);
|
|
7296
|
+
if (!existsSync17(runsDir)) {
|
|
7269
7297
|
return null;
|
|
7270
7298
|
}
|
|
7271
7299
|
const entries = (await readdir4(runsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
|
|
@@ -7307,15 +7335,15 @@ var PentestProgressTracker = class {
|
|
|
7307
7335
|
}
|
|
7308
7336
|
};
|
|
7309
7337
|
function runArtifactsDir(projectRoot, runId) {
|
|
7310
|
-
return
|
|
7338
|
+
return join36(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "artifacts");
|
|
7311
7339
|
}
|
|
7312
7340
|
function runLogsDir(projectRoot, runId) {
|
|
7313
|
-
return
|
|
7341
|
+
return join36(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "logs");
|
|
7314
7342
|
}
|
|
7315
7343
|
|
|
7316
7344
|
// src/pipeline/lane-runner.ts
|
|
7317
7345
|
import { mkdir as mkdir16, writeFile as writeFile16 } from "fs/promises";
|
|
7318
|
-
import { dirname as dirname20, join as
|
|
7346
|
+
import { dirname as dirname20, join as join42 } from "path";
|
|
7319
7347
|
|
|
7320
7348
|
// src/pipeline/phases/shared.ts
|
|
7321
7349
|
function createPassResult(phase, summary, context, artifacts = [`handoff:${context.phases.length + 1}`]) {
|
|
@@ -7435,12 +7463,12 @@ var LoadDocsPhase = class {
|
|
|
7435
7463
|
|
|
7436
7464
|
// src/workflows/pentest.ts
|
|
7437
7465
|
import { mkdir as mkdir13, writeFile as writeFile13 } from "fs/promises";
|
|
7438
|
-
import { join as
|
|
7466
|
+
import { join as join39, relative as relative7 } from "path";
|
|
7439
7467
|
|
|
7440
7468
|
// src/pentest/findings.ts
|
|
7441
|
-
import { existsSync as
|
|
7469
|
+
import { existsSync as existsSync18 } from "fs";
|
|
7442
7470
|
import { readFile as readFile17 } from "fs/promises";
|
|
7443
|
-
import { join as
|
|
7471
|
+
import { join as join37 } from "path";
|
|
7444
7472
|
function createFinding(input) {
|
|
7445
7473
|
return {
|
|
7446
7474
|
id: "",
|
|
@@ -7614,8 +7642,8 @@ function buildModuleFindings(docs, tests) {
|
|
|
7614
7642
|
return findings;
|
|
7615
7643
|
}
|
|
7616
7644
|
async function buildSecretFindings(artifactDir) {
|
|
7617
|
-
const path =
|
|
7618
|
-
if (!
|
|
7645
|
+
const path = join37(artifactDir, "secrets", "matches.txt");
|
|
7646
|
+
if (!existsSync18(path)) {
|
|
7619
7647
|
return [];
|
|
7620
7648
|
}
|
|
7621
7649
|
const matches = parseSecretMatches(await readFile17(path, "utf8"));
|
|
@@ -7727,8 +7755,8 @@ function normalizeImpact(content) {
|
|
|
7727
7755
|
}
|
|
7728
7756
|
async function readNativeAuditFindings(artifactDir) {
|
|
7729
7757
|
const findings = [];
|
|
7730
|
-
const dependencyDir =
|
|
7731
|
-
const npmAudit = await readJsonMaybe(
|
|
7758
|
+
const dependencyDir = join37(artifactDir, "dependencies");
|
|
7759
|
+
const npmAudit = await readJsonMaybe(join37(dependencyDir, "npm-audit.json"));
|
|
7732
7760
|
for (const [name, vulnerability] of Object.entries(npmAudit?.vulnerabilities ?? {})) {
|
|
7733
7761
|
const via = (vulnerability.via ?? []).find((entry) => typeof entry === "object");
|
|
7734
7762
|
findings.push({
|
|
@@ -7740,7 +7768,7 @@ async function readNativeAuditFindings(artifactDir) {
|
|
|
7740
7768
|
details: via?.url ?? ""
|
|
7741
7769
|
});
|
|
7742
7770
|
}
|
|
7743
|
-
const pnpmAudit = await readJsonMaybe(
|
|
7771
|
+
const pnpmAudit = await readJsonMaybe(join37(dependencyDir, "pnpm-audit.json"));
|
|
7744
7772
|
for (const advisory of Object.values(pnpmAudit?.advisories ?? {})) {
|
|
7745
7773
|
findings.push({
|
|
7746
7774
|
package_name: advisory.module_name ?? "unknown",
|
|
@@ -7751,7 +7779,7 @@ async function readNativeAuditFindings(artifactDir) {
|
|
|
7751
7779
|
details: advisory.overview ?? ""
|
|
7752
7780
|
});
|
|
7753
7781
|
}
|
|
7754
|
-
const composerAudit = await readJsonMaybe(
|
|
7782
|
+
const composerAudit = await readJsonMaybe(join37(dependencyDir, "composer-audit.json"));
|
|
7755
7783
|
if (Array.isArray(composerAudit?.advisories)) {
|
|
7756
7784
|
for (const advisory of composerAudit.advisories) {
|
|
7757
7785
|
findings.push({
|
|
@@ -7788,7 +7816,7 @@ async function readNativeAuditFindings(artifactDir) {
|
|
|
7788
7816
|
});
|
|
7789
7817
|
}
|
|
7790
7818
|
async function readJsonMaybe(path) {
|
|
7791
|
-
if (!
|
|
7819
|
+
if (!existsSync18(path)) {
|
|
7792
7820
|
return null;
|
|
7793
7821
|
}
|
|
7794
7822
|
try {
|
|
@@ -7864,7 +7892,7 @@ var FileCheckMapper = class {
|
|
|
7864
7892
|
|
|
7865
7893
|
// src/pentest/incremental-scanner.ts
|
|
7866
7894
|
import { readFile as readFile18 } from "fs/promises";
|
|
7867
|
-
import { join as
|
|
7895
|
+
import { join as join38 } from "path";
|
|
7868
7896
|
import { createHash as createHash8 } from "crypto";
|
|
7869
7897
|
import { execa as execa3 } from "execa";
|
|
7870
7898
|
var IncrementalScanner = class {
|
|
@@ -7898,7 +7926,7 @@ var IncrementalScanner = class {
|
|
|
7898
7926
|
}
|
|
7899
7927
|
}
|
|
7900
7928
|
async gitDiff(projectRoot, lastRunId) {
|
|
7901
|
-
const progressPath =
|
|
7929
|
+
const progressPath = join38(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
|
|
7902
7930
|
let baseCommit;
|
|
7903
7931
|
try {
|
|
7904
7932
|
const raw = await readFile18(progressPath, "utf8");
|
|
@@ -7915,7 +7943,7 @@ var IncrementalScanner = class {
|
|
|
7915
7943
|
return result.stdout.split("\n").map((f) => f.trim()).filter(Boolean);
|
|
7916
7944
|
}
|
|
7917
7945
|
async hashDiff(projectRoot, lastRunId) {
|
|
7918
|
-
const manifestPath =
|
|
7946
|
+
const manifestPath = join38(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
|
|
7919
7947
|
let fileManifest = {};
|
|
7920
7948
|
try {
|
|
7921
7949
|
const raw = await readFile18(manifestPath, "utf8");
|
|
@@ -7927,7 +7955,7 @@ var IncrementalScanner = class {
|
|
|
7927
7955
|
const changed = [];
|
|
7928
7956
|
for (const [filePath, storedHash] of Object.entries(fileManifest)) {
|
|
7929
7957
|
try {
|
|
7930
|
-
const content = await readFile18(
|
|
7958
|
+
const content = await readFile18(join38(projectRoot, filePath), "utf8");
|
|
7931
7959
|
const currentHash = createHash8("sha256").update(content).digest("hex");
|
|
7932
7960
|
if (currentHash !== storedHash) {
|
|
7933
7961
|
changed.push(filePath);
|
|
@@ -7940,11 +7968,11 @@ var IncrementalScanner = class {
|
|
|
7940
7968
|
}
|
|
7941
7969
|
async warnIfFullScanStale(projectRoot, thresholdDays) {
|
|
7942
7970
|
try {
|
|
7943
|
-
const runsDir =
|
|
7971
|
+
const runsDir = join38(projectRoot, ".paqad", "pentest", "runs");
|
|
7944
7972
|
const { readdir: readdir8 } = await import("fs/promises");
|
|
7945
7973
|
const runs = await readdir8(runsDir).catch(() => []);
|
|
7946
7974
|
for (const run of runs.sort().reverse()) {
|
|
7947
|
-
const progressPath =
|
|
7975
|
+
const progressPath = join38(runsDir, run, "progress.json");
|
|
7948
7976
|
try {
|
|
7949
7977
|
const raw = await readFile18(progressPath, "utf8");
|
|
7950
7978
|
const progress = JSON.parse(raw);
|
|
@@ -8142,8 +8170,8 @@ var PentestWorkflow = class {
|
|
|
8142
8170
|
await this.tracker.save(options.projectRoot, progress);
|
|
8143
8171
|
const docs = await loadModuleDocs(options.projectRoot, focusModules);
|
|
8144
8172
|
const tests = await loadTests(options.projectRoot, focusModules);
|
|
8145
|
-
const docsPath =
|
|
8146
|
-
const testsPath =
|
|
8173
|
+
const docsPath = join39(artifactsDir, "docs-summary.json");
|
|
8174
|
+
const testsPath = join39(artifactsDir, "tests-summary.json");
|
|
8147
8175
|
await writeJson(docsPath, docs);
|
|
8148
8176
|
await writeJson(
|
|
8149
8177
|
testsPath,
|
|
@@ -8244,7 +8272,7 @@ var PentestWorkflow = class {
|
|
|
8244
8272
|
progressRunId: progress.run_id,
|
|
8245
8273
|
reportTimestamp: new Date(progress.started_at)
|
|
8246
8274
|
});
|
|
8247
|
-
const findingIndexPath =
|
|
8275
|
+
const findingIndexPath = join39(
|
|
8248
8276
|
options.projectRoot,
|
|
8249
8277
|
PATHS.PENTEST_RUNS_DIR,
|
|
8250
8278
|
progress.run_id,
|
|
@@ -8261,7 +8289,7 @@ var PentestWorkflow = class {
|
|
|
8261
8289
|
}
|
|
8262
8290
|
if (report === null) {
|
|
8263
8291
|
const existingSidecar = progress.sidecar_path ? await readJsonIfExists(
|
|
8264
|
-
|
|
8292
|
+
join39(options.projectRoot, progress.sidecar_path)
|
|
8265
8293
|
) : null;
|
|
8266
8294
|
report = existingSidecar;
|
|
8267
8295
|
}
|
|
@@ -8276,18 +8304,18 @@ var PentestWorkflow = class {
|
|
|
8276
8304
|
this.tracker.markStepRunning(progress, "write-report", writeHash);
|
|
8277
8305
|
await this.tracker.save(options.projectRoot, progress);
|
|
8278
8306
|
await writeJson(
|
|
8279
|
-
|
|
8307
|
+
join39(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "report-preview.json"),
|
|
8280
8308
|
{ report_id: report.report_id, findings: report.findings.length }
|
|
8281
8309
|
);
|
|
8282
|
-
await writeJson(
|
|
8310
|
+
await writeJson(join39(options.projectRoot, report.sidecar_path), report);
|
|
8283
8311
|
await writeJson(
|
|
8284
|
-
|
|
8312
|
+
join39(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "blocked-checks.json"),
|
|
8285
8313
|
report.blocked_checks
|
|
8286
8314
|
);
|
|
8287
|
-
await mkdir13(
|
|
8315
|
+
await mkdir13(join39(options.projectRoot, PATHS.PENTEST_DIR), { recursive: true });
|
|
8288
8316
|
const markdown = buildPentestMarkdown(report);
|
|
8289
|
-
await writeJson(
|
|
8290
|
-
await writeFile13(
|
|
8317
|
+
await writeJson(join39(options.projectRoot, report.sidecar_path), report);
|
|
8318
|
+
await writeFile13(join39(options.projectRoot, report.report_path), markdown);
|
|
8291
8319
|
this.tracker.markStepCompleted(
|
|
8292
8320
|
progress,
|
|
8293
8321
|
"write-report",
|
|
@@ -8314,7 +8342,7 @@ async function buildCurrentPentestReport(input) {
|
|
|
8314
8342
|
const docs = await loadModuleDocs(input.projectRoot, input.focusModules);
|
|
8315
8343
|
const tests = await loadTests(input.projectRoot, input.focusModules);
|
|
8316
8344
|
const osvFindings = await queryOsv(input.snapshot.packages);
|
|
8317
|
-
const osvPath =
|
|
8345
|
+
const osvPath = join39(input.artifactsDir, "dependencies", "osv-results.json");
|
|
8318
8346
|
await writeJson(osvPath, osvFindings);
|
|
8319
8347
|
const dependencyFindings = await buildDependencyFindings(
|
|
8320
8348
|
input.snapshot,
|
|
@@ -8323,7 +8351,7 @@ async function buildCurrentPentestReport(input) {
|
|
|
8323
8351
|
);
|
|
8324
8352
|
const moduleFindings = buildModuleFindings(docs, tests);
|
|
8325
8353
|
const secretFindings = await buildSecretFindings(input.artifactsDir);
|
|
8326
|
-
const runtimePayload = await readJsonIfExists(
|
|
8354
|
+
const runtimePayload = await readJsonIfExists(join39(input.artifactsDir, "runtime", "runtime-checks.json"));
|
|
8327
8355
|
const runtimeStatus = input.targetUrl ? runtimePayload?.reachable ? {
|
|
8328
8356
|
target_url: input.targetUrl,
|
|
8329
8357
|
status: "reachable",
|
|
@@ -8349,8 +8377,8 @@ async function buildCurrentPentestReport(input) {
|
|
|
8349
8377
|
...runtimeFindings
|
|
8350
8378
|
]);
|
|
8351
8379
|
const timestamp = toLocalTimestamp(input.reportTimestamp);
|
|
8352
|
-
const reportPath =
|
|
8353
|
-
const sidecarPath =
|
|
8380
|
+
const reportPath = join39(PATHS.PENTEST_DIR, `${timestamp}.md`);
|
|
8381
|
+
const sidecarPath = join39(PATHS.PENTEST_DIR, `${timestamp}.json`);
|
|
8354
8382
|
const stack = getPrimaryStack({
|
|
8355
8383
|
routing: { domain: "coding" },
|
|
8356
8384
|
stack_profile: input.snapshot.profile
|
|
@@ -8403,9 +8431,9 @@ async function buildCurrentPentestReport(input) {
|
|
|
8403
8431
|
raw_evidence_paths: [
|
|
8404
8432
|
relative7(input.projectRoot, osvPath),
|
|
8405
8433
|
...[
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8434
|
+
join39(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "finding-index.json"),
|
|
8435
|
+
join39(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "docs-summary.json"),
|
|
8436
|
+
join39(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "tests-summary.json")
|
|
8409
8437
|
]
|
|
8410
8438
|
]
|
|
8411
8439
|
};
|
|
@@ -8445,7 +8473,7 @@ var PentestPhase = class {
|
|
|
8445
8473
|
|
|
8446
8474
|
// src/workflows/pentest-retest.ts
|
|
8447
8475
|
import { mkdir as mkdir14, writeFile as writeFile14 } from "fs/promises";
|
|
8448
|
-
import { dirname as dirname18, join as
|
|
8476
|
+
import { dirname as dirname18, join as join40 } from "path";
|
|
8449
8477
|
var RETEST_STEPS = [
|
|
8450
8478
|
{ id: "load-source-report", title: "Load source pentest report" },
|
|
8451
8479
|
{ id: "rerun-evidence", title: "Collect fresh evidence for source findings" },
|
|
@@ -8466,7 +8494,7 @@ var PentestRetestWorkflow = class {
|
|
|
8466
8494
|
}
|
|
8467
8495
|
const normalizedSourcePath = normalizeSidecarPath(sourceReportPath);
|
|
8468
8496
|
const sourceSidecar = await readJsonIfExists(
|
|
8469
|
-
|
|
8497
|
+
join40(options.projectRoot, normalizedSourcePath)
|
|
8470
8498
|
);
|
|
8471
8499
|
if (sourceSidecar === null) {
|
|
8472
8500
|
throw new Error(`Source pentest sidecar not found at ${normalizedSourcePath}`);
|
|
@@ -8491,12 +8519,12 @@ var PentestRetestWorkflow = class {
|
|
|
8491
8519
|
if (!this.tracker.shouldSkipStep(progress, "load-source-report", sourceHash)) {
|
|
8492
8520
|
this.tracker.markStepRunning(progress, "load-source-report", sourceHash);
|
|
8493
8521
|
await this.tracker.save(options.projectRoot, progress);
|
|
8494
|
-
const sourceCopy =
|
|
8522
|
+
const sourceCopy = join40(artifactsDir, "source-report.json");
|
|
8495
8523
|
await writeJson(sourceCopy, sourceSidecar);
|
|
8496
8524
|
this.tracker.markStepCompleted(
|
|
8497
8525
|
progress,
|
|
8498
8526
|
"load-source-report",
|
|
8499
|
-
[
|
|
8527
|
+
[join40(PATHS.PENTEST_RUNS_DIR, progress.run_id, "artifacts", "source-report.json")],
|
|
8500
8528
|
[...RETEST_SKILLS.source].map(skillPath)
|
|
8501
8529
|
);
|
|
8502
8530
|
await this.tracker.save(options.projectRoot, progress);
|
|
@@ -8513,7 +8541,7 @@ var PentestRetestWorkflow = class {
|
|
|
8513
8541
|
PENTEST_RUN_ID: progress.run_id,
|
|
8514
8542
|
PENTEST_ARTIFACT_DIR: artifactsDir,
|
|
8515
8543
|
PENTEST_TARGET_URL: targetUrl ?? "",
|
|
8516
|
-
PENTEST_SOURCE_REPORT:
|
|
8544
|
+
PENTEST_SOURCE_REPORT: join40(options.projectRoot, normalizedSourcePath),
|
|
8517
8545
|
PENTEST_DB_CONNECTION_NAME: options.dbConnectionName ?? ""
|
|
8518
8546
|
};
|
|
8519
8547
|
const scriptResults = await Promise.all([
|
|
@@ -8562,8 +8590,8 @@ var PentestRetestWorkflow = class {
|
|
|
8562
8590
|
...currentReport,
|
|
8563
8591
|
report_id: toReportId("RETEST", new Date(progress.started_at)),
|
|
8564
8592
|
workflow: "pentest-retest",
|
|
8565
|
-
report_path:
|
|
8566
|
-
sidecar_path:
|
|
8593
|
+
report_path: join40(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.md`),
|
|
8594
|
+
sidecar_path: join40(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.json`),
|
|
8567
8595
|
source_report_path: normalizedSourcePath,
|
|
8568
8596
|
source_report_id: sourceSidecar.report_id,
|
|
8569
8597
|
findings: retestFindings,
|
|
@@ -8576,7 +8604,7 @@ var PentestRetestWorkflow = class {
|
|
|
8576
8604
|
...[...RETEST_SKILLS.source, ...RETEST_SKILLS.evaluate].map(skillPath)
|
|
8577
8605
|
]
|
|
8578
8606
|
};
|
|
8579
|
-
const findingIndexPath =
|
|
8607
|
+
const findingIndexPath = join40(
|
|
8580
8608
|
options.projectRoot,
|
|
8581
8609
|
PATHS.PENTEST_RUNS_DIR,
|
|
8582
8610
|
progress.run_id,
|
|
@@ -8586,14 +8614,14 @@ var PentestRetestWorkflow = class {
|
|
|
8586
8614
|
this.tracker.markStepCompleted(
|
|
8587
8615
|
progress,
|
|
8588
8616
|
"evaluate-source-findings",
|
|
8589
|
-
[
|
|
8617
|
+
[join40(PATHS.PENTEST_RUNS_DIR, progress.run_id, "finding-index.json")],
|
|
8590
8618
|
[...RETEST_SKILLS.evaluate].map(skillPath)
|
|
8591
8619
|
);
|
|
8592
8620
|
await this.tracker.save(options.projectRoot, progress);
|
|
8593
8621
|
}
|
|
8594
8622
|
if (retestReport === null) {
|
|
8595
8623
|
const existing = progress.sidecar_path ? await readJsonIfExists(
|
|
8596
|
-
|
|
8624
|
+
join40(options.projectRoot, progress.sidecar_path)
|
|
8597
8625
|
) : null;
|
|
8598
8626
|
retestReport = existing;
|
|
8599
8627
|
}
|
|
@@ -8607,12 +8635,12 @@ var PentestRetestWorkflow = class {
|
|
|
8607
8635
|
if (!this.tracker.shouldSkipStep(progress, "write-report", writeHash)) {
|
|
8608
8636
|
this.tracker.markStepRunning(progress, "write-report", writeHash);
|
|
8609
8637
|
await this.tracker.save(options.projectRoot, progress);
|
|
8610
|
-
await writeJson(
|
|
8611
|
-
await mkdir14(dirname18(
|
|
8638
|
+
await writeJson(join40(options.projectRoot, retestReport.sidecar_path), retestReport);
|
|
8639
|
+
await mkdir14(dirname18(join40(options.projectRoot, retestReport.report_path)), {
|
|
8612
8640
|
recursive: true
|
|
8613
8641
|
});
|
|
8614
8642
|
await writeFile14(
|
|
8615
|
-
|
|
8643
|
+
join40(options.projectRoot, retestReport.report_path),
|
|
8616
8644
|
buildPentestMarkdown(retestReport)
|
|
8617
8645
|
);
|
|
8618
8646
|
this.tracker.markStepCompleted(
|
|
@@ -8690,7 +8718,7 @@ var ProjectQuestionPhase = class {
|
|
|
8690
8718
|
|
|
8691
8719
|
// src/workflows/root-cause-analysis.ts
|
|
8692
8720
|
import { mkdir as mkdir15, writeFile as writeFile15 } from "fs/promises";
|
|
8693
|
-
import { dirname as dirname19, join as
|
|
8721
|
+
import { dirname as dirname19, join as join41 } from "path";
|
|
8694
8722
|
var DEFAULT_TITLE_SLUG = "root-cause-analysis";
|
|
8695
8723
|
var RCA_SECTIONS = [
|
|
8696
8724
|
"Summary",
|
|
@@ -8709,8 +8737,8 @@ var RootCauseAnalysisWorkflow = class {
|
|
|
8709
8737
|
async run(options) {
|
|
8710
8738
|
const title = deriveTitle(options.classification.request_text);
|
|
8711
8739
|
const filename = `${toLocalTimestamp2(/* @__PURE__ */ new Date())}-${slugify2(title) || DEFAULT_TITLE_SLUG}.md`;
|
|
8712
|
-
const relativePath =
|
|
8713
|
-
const outputPath =
|
|
8740
|
+
const relativePath = join41(PATHS.RCA_DIR, filename);
|
|
8741
|
+
const outputPath = join41(options.projectRoot, relativePath);
|
|
8714
8742
|
await mkdir15(dirname19(outputPath), { recursive: true });
|
|
8715
8743
|
await writeFile15(outputPath, buildRcaDocument(title, options.classification));
|
|
8716
8744
|
return {
|
|
@@ -8859,22 +8887,22 @@ var DEFAULT_PHASES = {
|
|
|
8859
8887
|
|
|
8860
8888
|
// src/pipeline/stream-truncator.ts
|
|
8861
8889
|
import { appendFile, mkdir as mkdir17 } from "fs/promises";
|
|
8862
|
-
import { join as
|
|
8890
|
+
import { join as join43, dirname as dirname21 } from "path";
|
|
8863
8891
|
|
|
8864
8892
|
// src/resolver/deduplicator.ts
|
|
8865
8893
|
import { createHash as createHash9 } from "crypto";
|
|
8866
8894
|
import { readFile as readFile19, writeFile as writeFile17, mkdir as mkdir18 } from "fs/promises";
|
|
8867
|
-
import { join as
|
|
8895
|
+
import { join as join44, dirname as dirname22 } from "path";
|
|
8868
8896
|
|
|
8869
8897
|
// src/scripts/generator.ts
|
|
8870
8898
|
import { chmodSync as chmodSync2 } from "fs";
|
|
8871
8899
|
import { mkdir as mkdir19, writeFile as writeFile18 } from "fs/promises";
|
|
8872
|
-
import { dirname as dirname23, join as
|
|
8900
|
+
import { dirname as dirname23, join as join45 } from "path";
|
|
8873
8901
|
|
|
8874
8902
|
// src/skills/cache-manager.ts
|
|
8875
8903
|
import { createHash as createHash10 } from "crypto";
|
|
8876
8904
|
import { mkdir as mkdir20, readFile as readFile20, readdir as readdir5, rm as rm2, stat as stat3, writeFile as writeFile19 } from "fs/promises";
|
|
8877
|
-
import { join as
|
|
8905
|
+
import { join as join46 } from "path";
|
|
8878
8906
|
import fg6 from "fast-glob";
|
|
8879
8907
|
|
|
8880
8908
|
// src/skills/frontmatter-parser.ts
|
|
@@ -8899,7 +8927,7 @@ var conditionalProcessor = new ConditionalSectionProcessor();
|
|
|
8899
8927
|
|
|
8900
8928
|
// src/skills/index-generator.ts
|
|
8901
8929
|
import { mkdir as mkdir21, readFile as readFile21, writeFile as writeFile20 } from "fs/promises";
|
|
8902
|
-
import { dirname as dirname24, join as
|
|
8930
|
+
import { dirname as dirname24, join as join47, relative as relative8 } from "path";
|
|
8903
8931
|
import fg7 from "fast-glob";
|
|
8904
8932
|
|
|
8905
8933
|
// src/skills/loader.ts
|
|
@@ -8907,16 +8935,16 @@ import { readFile as readFile22 } from "fs/promises";
|
|
|
8907
8935
|
import { basename as basename6 } from "pathe";
|
|
8908
8936
|
|
|
8909
8937
|
// src/update/updater.ts
|
|
8910
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
8938
|
+
import { chmodSync as chmodSync3, existsSync as existsSync19, mkdirSync as mkdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "fs";
|
|
8911
8939
|
import { mkdtemp, readdir as readdir6, readFile as readFile23, rm as rm3 } from "fs/promises";
|
|
8912
8940
|
import { tmpdir } from "os";
|
|
8913
|
-
import { dirname as dirname25, join as
|
|
8941
|
+
import { dirname as dirname25, join as join48, relative as relative9 } from "path";
|
|
8914
8942
|
var FrameworkUpdater = class {
|
|
8915
8943
|
constructor(options = {}) {
|
|
8916
8944
|
this.options = options;
|
|
8917
8945
|
}
|
|
8918
8946
|
async run(projectRoot) {
|
|
8919
|
-
const previousVersion = readText(
|
|
8947
|
+
const previousVersion = readText(join48(projectRoot, PATHS.FRAMEWORK_VERSION));
|
|
8920
8948
|
const manifest = readManifest(projectRoot);
|
|
8921
8949
|
const artifactPolicy = new Map(
|
|
8922
8950
|
manifest?.generated_artifacts.map((artifact) => [artifact.path, artifact.auto_update]) ?? []
|
|
@@ -8926,19 +8954,19 @@ var FrameworkUpdater = class {
|
|
|
8926
8954
|
const skipped = [];
|
|
8927
8955
|
const newScripts = [];
|
|
8928
8956
|
for (const candidate of candidates) {
|
|
8929
|
-
const target =
|
|
8930
|
-
const existed =
|
|
8957
|
+
const target = join48(projectRoot, candidate.path);
|
|
8958
|
+
const existed = existsSync19(target);
|
|
8931
8959
|
const autoUpdate = artifactPolicy.get(candidate.path) ?? candidate.autoUpdate;
|
|
8932
8960
|
if (existed && autoUpdate === false) {
|
|
8933
8961
|
skipped.push({
|
|
8934
8962
|
path: candidate.path,
|
|
8935
|
-
before:
|
|
8963
|
+
before: readFileSync12(target, "utf8"),
|
|
8936
8964
|
after: candidate.content
|
|
8937
8965
|
});
|
|
8938
8966
|
continue;
|
|
8939
8967
|
}
|
|
8940
8968
|
mkdirSync6(dirname25(target), { recursive: true });
|
|
8941
|
-
|
|
8969
|
+
writeFileSync6(target, candidate.content);
|
|
8942
8970
|
if (candidate.executable === true) {
|
|
8943
8971
|
chmodSync3(target, 493);
|
|
8944
8972
|
}
|
|
@@ -8947,8 +8975,8 @@ var FrameworkUpdater = class {
|
|
|
8947
8975
|
newScripts.push(candidate.path);
|
|
8948
8976
|
}
|
|
8949
8977
|
}
|
|
8950
|
-
mkdirSync6(dirname25(
|
|
8951
|
-
|
|
8978
|
+
mkdirSync6(dirname25(join48(projectRoot, PATHS.FRAMEWORK_VERSION)), { recursive: true });
|
|
8979
|
+
writeFileSync6(join48(projectRoot, PATHS.FRAMEWORK_VERSION), `${VERSION}
|
|
8952
8980
|
`);
|
|
8953
8981
|
return {
|
|
8954
8982
|
previous_version: previousVersion,
|
|
@@ -8968,7 +8996,7 @@ var FrameworkUpdater = class {
|
|
|
8968
8996
|
if (profile === null) {
|
|
8969
8997
|
throw new Error("Cannot update framework-managed artifacts without a project profile");
|
|
8970
8998
|
}
|
|
8971
|
-
const tempRoot = await mkdtemp(
|
|
8999
|
+
const tempRoot = await mkdtemp(join48(tmpdir(), "paqad-ai-update-"));
|
|
8972
9000
|
try {
|
|
8973
9001
|
const result = await new OnboardingOrchestrator().run({
|
|
8974
9002
|
projectRoot: tempRoot,
|
|
@@ -8988,27 +9016,27 @@ var FrameworkUpdater = class {
|
|
|
8988
9016
|
}
|
|
8989
9017
|
};
|
|
8990
9018
|
function readManifest(projectRoot) {
|
|
8991
|
-
const path =
|
|
8992
|
-
if (!
|
|
9019
|
+
const path = join48(projectRoot, PATHS.ONBOARDING_MANIFEST);
|
|
9020
|
+
if (!existsSync19(path)) {
|
|
8993
9021
|
return null;
|
|
8994
9022
|
}
|
|
8995
|
-
return JSON.parse(
|
|
9023
|
+
return JSON.parse(readFileSync12(path, "utf8"));
|
|
8996
9024
|
}
|
|
8997
9025
|
function readProfile(projectRoot) {
|
|
8998
9026
|
return readProjectProfile(projectRoot);
|
|
8999
9027
|
}
|
|
9000
9028
|
function readText(path) {
|
|
9001
|
-
if (!
|
|
9029
|
+
if (!existsSync19(path)) {
|
|
9002
9030
|
return null;
|
|
9003
9031
|
}
|
|
9004
|
-
return
|
|
9032
|
+
return readFileSync12(path, "utf8").trim();
|
|
9005
9033
|
}
|
|
9006
9034
|
async function collectFiles(root, generated) {
|
|
9007
9035
|
const paths = generated.length > 0 ? generated : await walk3(root);
|
|
9008
9036
|
return Promise.all(
|
|
9009
9037
|
paths.map(async (file) => ({
|
|
9010
9038
|
path: file,
|
|
9011
|
-
content: await readFile23(
|
|
9039
|
+
content: await readFile23(join48(root, file), "utf8"),
|
|
9012
9040
|
autoUpdate: true,
|
|
9013
9041
|
executable: file.startsWith("scripts/")
|
|
9014
9042
|
}))
|
|
@@ -9018,7 +9046,7 @@ async function walk3(root, current = root) {
|
|
|
9018
9046
|
const entries = await readdir6(current, { withFileTypes: true });
|
|
9019
9047
|
const files = [];
|
|
9020
9048
|
for (const entry of entries) {
|
|
9021
|
-
const absolute =
|
|
9049
|
+
const absolute = join48(current, entry.name);
|
|
9022
9050
|
if (entry.isDirectory()) {
|
|
9023
9051
|
files.push(...await walk3(root, absolute));
|
|
9024
9052
|
continue;
|
|
@@ -9029,31 +9057,31 @@ async function walk3(root, current = root) {
|
|
|
9029
9057
|
}
|
|
9030
9058
|
|
|
9031
9059
|
// src/verification/gates/documentation-freshness.ts
|
|
9032
|
-
import { existsSync as
|
|
9033
|
-
import { join as
|
|
9060
|
+
import { existsSync as existsSync20 } from "fs";
|
|
9061
|
+
import { join as join49 } from "path";
|
|
9034
9062
|
var STALENESS_WINDOW_MS2 = 1e3 * 60 * 60 * 24 * 7;
|
|
9035
9063
|
|
|
9036
9064
|
// src/patterns/pattern-store.ts
|
|
9037
9065
|
import { readFile as readFile24, writeFile as writeFile21, mkdir as mkdir22, unlink } from "fs/promises";
|
|
9038
|
-
import { join as
|
|
9066
|
+
import { join as join50, dirname as dirname26 } from "path";
|
|
9039
9067
|
import { homedir as homedir3 } from "os";
|
|
9040
|
-
var GLOBAL_PATTERNS_DIR =
|
|
9068
|
+
var GLOBAL_PATTERNS_DIR = join50(homedir3(), ".paqad", "patterns");
|
|
9041
9069
|
var PatternStore = class {
|
|
9042
9070
|
get indexPath() {
|
|
9043
|
-
return
|
|
9071
|
+
return join50(GLOBAL_PATTERNS_DIR, "index.json");
|
|
9044
9072
|
}
|
|
9045
9073
|
get entriesDir() {
|
|
9046
|
-
return
|
|
9074
|
+
return join50(GLOBAL_PATTERNS_DIR, "entries");
|
|
9047
9075
|
}
|
|
9048
9076
|
async save(pattern) {
|
|
9049
9077
|
await mkdir22(this.entriesDir, { recursive: true });
|
|
9050
|
-
const entryPath =
|
|
9078
|
+
const entryPath = join50(this.entriesDir, `${pattern.id}.json`);
|
|
9051
9079
|
await writeFile21(entryPath, JSON.stringify(pattern, null, 2), "utf8");
|
|
9052
9080
|
await this.updateIndex(pattern);
|
|
9053
9081
|
}
|
|
9054
9082
|
async load(id) {
|
|
9055
9083
|
try {
|
|
9056
|
-
const raw = await readFile24(
|
|
9084
|
+
const raw = await readFile24(join50(this.entriesDir, `${id}.json`), "utf8");
|
|
9057
9085
|
return JSON.parse(raw);
|
|
9058
9086
|
} catch {
|
|
9059
9087
|
return null;
|
|
@@ -9088,7 +9116,7 @@ var PatternStore = class {
|
|
|
9088
9116
|
}
|
|
9089
9117
|
async delete(id) {
|
|
9090
9118
|
try {
|
|
9091
|
-
await unlink(
|
|
9119
|
+
await unlink(join50(this.entriesDir, `${id}.json`));
|
|
9092
9120
|
} catch {
|
|
9093
9121
|
}
|
|
9094
9122
|
const index = await this.loadIndex();
|
|
@@ -9188,12 +9216,12 @@ ${p.solution}
|
|
|
9188
9216
|
|
|
9189
9217
|
// src/workflows/template-loader.ts
|
|
9190
9218
|
import { readFile as readFile25, readdir as readdir7 } from "fs/promises";
|
|
9191
|
-
import { join as
|
|
9219
|
+
import { join as join51 } from "path";
|
|
9192
9220
|
import YAML6 from "yaml";
|
|
9193
9221
|
|
|
9194
9222
|
// src/workflows/engine.ts
|
|
9195
9223
|
import { readFile as readFile26, writeFile as writeFile23, mkdir as mkdir23 } from "fs/promises";
|
|
9196
|
-
import { join as
|
|
9224
|
+
import { join as join52, dirname as dirname27 } from "path";
|
|
9197
9225
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
9198
9226
|
|
|
9199
9227
|
// src/index.ts
|
|
@@ -9373,8 +9401,8 @@ function createPacksCommand() {
|
|
|
9373
9401
|
|
|
9374
9402
|
// src/cli/commands/refresh.ts
|
|
9375
9403
|
import { Command as Command7 } from "commander";
|
|
9376
|
-
import { readFileSync as
|
|
9377
|
-
import { join as
|
|
9404
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "fs";
|
|
9405
|
+
import { join as join53 } from "path";
|
|
9378
9406
|
function createRefreshCommand() {
|
|
9379
9407
|
return new Command7("refresh").description("Refresh derived framework artifacts").option("--project-root <path>", "Project root", process.cwd()).option("--design-system", "Refresh design-system markdown from design tokens").option("--stack", "Refresh the cached stack snapshot").action(async (options) => {
|
|
9380
9408
|
const shouldRefreshDesignSystem = options.designSystem ?? true;
|
|
@@ -9410,14 +9438,14 @@ function createRefreshCommand() {
|
|
|
9410
9438
|
});
|
|
9411
9439
|
}
|
|
9412
9440
|
function writeRefreshDrift(projectRoot, refreshDrift) {
|
|
9413
|
-
const path =
|
|
9441
|
+
const path = join53(projectRoot, PATHS.STACK_DRIFT);
|
|
9414
9442
|
const current = readExistingJson(path);
|
|
9415
|
-
|
|
9443
|
+
writeFileSync7(path, `${JSON.stringify({ ...current ?? {}, ...refreshDrift }, null, 2)}
|
|
9416
9444
|
`);
|
|
9417
9445
|
}
|
|
9418
9446
|
function readExistingJson(path) {
|
|
9419
9447
|
try {
|
|
9420
|
-
return JSON.parse(
|
|
9448
|
+
return JSON.parse(readFileSync13(path, "utf8"));
|
|
9421
9449
|
} catch {
|
|
9422
9450
|
return null;
|
|
9423
9451
|
}
|