paqad-ai 0.1.1 → 0.1.3

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 (40) hide show
  1. package/dist/cli/index.js +540 -163
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/index.d.ts +12 -2
  4. package/dist/index.js +555 -219
  5. package/dist/index.js.map +1 -1
  6. package/package.json +1 -1
  7. package/runtime/base/rules/design-system.md +13 -0
  8. package/runtime/capabilities/coding/stacks/flutter/pack.yaml +5 -1
  9. package/runtime/capabilities/coding/stacks/laravel/pack.yaml +15 -1
  10. package/runtime/capabilities/coding/stacks/react/pack.yaml +6 -2
  11. package/runtime/capabilities/coding/stacks/vue/pack.yaml +6 -2
  12. package/runtime/capabilities/security/rules/pentest.md +169 -0
  13. package/runtime/capabilities/security/skills/auth-mechanism-review/SKILL.md +88 -0
  14. package/runtime/capabilities/security/skills/auth-mechanism-review/agents/openai.yaml +3 -0
  15. package/runtime/capabilities/security/skills/auth-mechanism-review/references/auth-attack-checklist.md +84 -0
  16. package/runtime/capabilities/security/skills/business-logic-abuse-review/references/abuse-cases.md +33 -5
  17. package/runtime/capabilities/security/skills/cryptographic-review/SKILL.md +72 -0
  18. package/runtime/capabilities/security/skills/cryptographic-review/agents/openai.yaml +3 -0
  19. package/runtime/capabilities/security/skills/cryptographic-review/references/crypto-weakness-patterns.md +156 -0
  20. package/runtime/capabilities/security/skills/dependency-advisory-triage/references/advisory-normalization.md +33 -1
  21. package/runtime/capabilities/security/skills/input-validation-review/SKILL.md +75 -0
  22. package/runtime/capabilities/security/skills/input-validation-review/agents/openai.yaml +3 -0
  23. package/runtime/capabilities/security/skills/input-validation-review/references/input-attack-patterns.md +74 -0
  24. package/runtime/capabilities/security/skills/logging-monitoring-review/SKILL.md +72 -0
  25. package/runtime/capabilities/security/skills/logging-monitoring-review/agents/openai.yaml +3 -0
  26. package/runtime/capabilities/security/skills/logging-monitoring-review/references/logging-gaps-checklist.md +77 -0
  27. package/runtime/capabilities/security/skills/permission-boundary-review/references/boundary-checklist.md +31 -1
  28. package/runtime/capabilities/security/skills/rate-limiting-review/SKILL.md +67 -0
  29. package/runtime/capabilities/security/skills/rate-limiting-review/agents/openai.yaml +3 -0
  30. package/runtime/capabilities/security/skills/rate-limiting-review/references/rate-limit-signals.md +153 -0
  31. package/runtime/capabilities/security/skills/runtime-surface-probing/references/runtime-surface-checks.md +57 -3
  32. package/runtime/capabilities/security/skills/stride-threat-model/SKILL.md +60 -0
  33. package/runtime/capabilities/security/skills/stride-threat-model/agents/openai.yaml +3 -0
  34. package/runtime/capabilities/security/skills/stride-threat-model/references/stride-checklist.md +69 -0
  35. package/runtime/hooks/silent-update.sh +115 -0
  36. package/runtime/templates/agent-configs/agents.md.hbs +10 -0
  37. package/runtime/templates/agent-configs/claude.md.hbs +10 -0
  38. package/runtime/templates/agent-configs/gemini.md.hbs +10 -0
  39. package/runtime/templates/agent-configs/junie.md.hbs +11 -0
  40. package/scripts/deprecate-old-versions.sh +55 -0
package/dist/cli/index.js CHANGED
@@ -96,7 +96,12 @@ var PATHS = {
96
96
  CLAUDE_MD: "CLAUDE.md",
97
97
  AGENTS_MD: "AGENTS.md",
98
98
  GEMINI_MD: "GEMINI.md",
99
- SCRIPTS_DIR: "scripts"
99
+ SCRIPTS_DIR: "scripts",
100
+ HOOKS_DIR: ".paqad/hooks",
101
+ LOGS_DIR: ".paqad/logs",
102
+ LOCKS_DIR: ".paqad/locks",
103
+ AUTO_UPDATE_LOG: ".paqad/logs/auto-update.log",
104
+ HOOKS_SILENT_UPDATE: ".paqad/hooks/silent-update.sh"
100
105
  };
101
106
  var REGISTRIES = [
102
107
  "module-registry.md",
@@ -4137,8 +4142,10 @@ function writeFrameworkMetadata(projectRoot, version) {
4137
4142
  mkdirSync2(dirname11(join21(projectRoot, PATHS.FRAMEWORK_VERSION)), {
4138
4143
  recursive: true
4139
4144
  });
4140
- writeFileSync2(join21(projectRoot, PATHS.FRAMEWORK_VERSION), `${version}
4141
- `);
4145
+ const content = `version=${version}
4146
+ updated_at=${(/* @__PURE__ */ new Date()).toISOString()}
4147
+ `;
4148
+ writeFileSync2(join21(projectRoot, PATHS.FRAMEWORK_VERSION), content);
4142
4149
  writeFileSync2(join21(projectRoot, PATHS.FRAMEWORK_PATH), `${resolveFrameworkInstallPath()}
4143
4150
  `);
4144
4151
  }
@@ -5518,6 +5525,10 @@ function writeGeneratedFiles(projectRoot, files) {
5518
5525
  return { written, skipped };
5519
5526
  }
5520
5527
 
5528
+ // src/onboarding/orchestrator.ts
5529
+ import { readFileSync as readFileSync12 } from "fs";
5530
+ import { join as join33 } from "path";
5531
+
5521
5532
  // src/resolver/resolver.ts
5522
5533
  import fg2 from "fast-glob";
5523
5534
  import { basename as basename3, extname, relative as relative3 } from "pathe";
@@ -5711,6 +5722,8 @@ function resolveArtifactDirectoryName(artifactType) {
5711
5722
  var RULE_SEED_PRIORITY = [
5712
5723
  "constitution",
5713
5724
  "security",
5725
+ "pentest",
5726
+ "design-system",
5714
5727
  "content-rules",
5715
5728
  "testing",
5716
5729
  "documentation",
@@ -5806,9 +5819,34 @@ function getRulePriority(filePath) {
5806
5819
  return index === -1 ? RULE_SEED_PRIORITY.length : index;
5807
5820
  }
5808
5821
 
5822
+ // src/onboarding/gitignore-writer.ts
5823
+ import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
5824
+ import { join as join30 } from "path";
5825
+ var PAQAD_MARKER = "# paqad-ai";
5826
+ var PAQAD_GITIGNORE_ENTRIES = [
5827
+ PAQAD_MARKER,
5828
+ ".paqad/cache/",
5829
+ ".paqad/session/",
5830
+ ".paqad/context/",
5831
+ ".paqad/workflows/",
5832
+ ".paqad/indexes/",
5833
+ ".paqad/pentest/",
5834
+ ".paqad/theme/"
5835
+ ].join("\n");
5836
+ function writeGitignore(projectRoot) {
5837
+ const gitignorePath = join30(projectRoot, ".gitignore");
5838
+ const existing = existsSync13(gitignorePath) ? readFileSync11(gitignorePath, "utf8") : "";
5839
+ if (existing.includes(PAQAD_MARKER)) {
5840
+ return;
5841
+ }
5842
+ const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
5843
+ writeFileSync4(gitignorePath, `${existing}${separator}
5844
+ ${PAQAD_GITIGNORE_ENTRIES}
5845
+ `);
5846
+ }
5847
+
5809
5848
  // src/onboarding/prompts.ts
5810
5849
  import { checkbox, select } from "@inquirer/prompts";
5811
- var ALL_PROVIDERS = ["codex-cli", "claude-code", "gemini-cli", "junie"];
5812
5850
  function isInteractive() {
5813
5851
  return Boolean(process.stdout.isTTY && process.stdin.isTTY);
5814
5852
  }
@@ -5842,7 +5880,7 @@ function buildFromOverridesAndDetection(detection, snapshot, overrides) {
5842
5880
  snapshot
5843
5881
  ));
5844
5882
  return {
5845
- providers: overrides?.providers ?? ALL_PROVIDERS,
5883
+ providers: overrides?.providers ?? ["claude-code"],
5846
5884
  domain,
5847
5885
  stack_profile: stackProfile,
5848
5886
  stack: overrides?.stack ?? (snapshot?.profile ? getPrimaryStack({
@@ -6233,9 +6271,9 @@ function inferSelectionDomain(detection, overrides, snapshot) {
6233
6271
  }
6234
6272
 
6235
6273
  // src/onboarding/reference-generator.ts
6236
- import { existsSync as existsSync13 } from "fs";
6274
+ import { existsSync as existsSync14 } from "fs";
6237
6275
  import { readFile as readFile13 } from "fs/promises";
6238
- import { join as join30, relative as relative4 } from "path";
6276
+ import { join as join31, relative as relative4 } from "path";
6239
6277
  import fg3 from "fast-glob";
6240
6278
  async function generateReferenceGuides(runtimeRoot, context) {
6241
6279
  if (context.domain !== "coding") {
@@ -6246,8 +6284,8 @@ async function generateReferenceGuides(runtimeRoot, context) {
6246
6284
  routing: { domain: context.domain },
6247
6285
  stack_profile: context.stack_profile
6248
6286
  });
6249
- const referencesRoot = join30(runtimeRoot, "capabilities", "coding", "stacks", stack, "references");
6250
- if (!existsSync13(referencesRoot)) {
6287
+ const referencesRoot = join31(runtimeRoot, "capabilities", "coding", "stacks", stack, "references");
6288
+ if (!existsSync14(referencesRoot)) {
6251
6289
  return [buildFallbackReferenceGuide(stack)];
6252
6290
  }
6253
6291
  const entries = await fg3(["tools/*.md", "tools-catalog.md"], {
@@ -6269,14 +6307,14 @@ async function generateReferenceGuides(runtimeRoot, context) {
6269
6307
  function toProjectReferencePath(stack, relativePath) {
6270
6308
  const normalized = relativePath.replaceAll("\\", "/");
6271
6309
  if (normalized === "tools-catalog.md") {
6272
- return join30(PATHS.TOOLS_DIR, stack, "README.md");
6310
+ return join31(PATHS.TOOLS_DIR, stack, "README.md");
6273
6311
  }
6274
- return join30(PATHS.TOOLS_DIR, stack, normalized.replace(/^tools\//, ""));
6312
+ return join31(PATHS.TOOLS_DIR, stack, normalized.replace(/^tools\//, ""));
6275
6313
  }
6276
6314
  function buildFallbackReferenceGuide(stack) {
6277
6315
  const title = stack.split("-").map((segment) => segment.slice(0, 1).toUpperCase() + segment.slice(1)).join(" ");
6278
6316
  return {
6279
- path: join30(PATHS.TOOLS_DIR, stack, "README.md"),
6317
+ path: join31(PATHS.TOOLS_DIR, stack, "README.md"),
6280
6318
  autoUpdate: false,
6281
6319
  content: [
6282
6320
  `# ${title} Tool References`,
@@ -6294,7 +6332,7 @@ function buildFallbackReferenceGuide(stack) {
6294
6332
 
6295
6333
  // src/onboarding/rule-generator.ts
6296
6334
  import { readFile as readFile14 } from "fs/promises";
6297
- import { join as join31 } from "path";
6335
+ import { join as join32 } from "path";
6298
6336
  async function generateProjectRules(rules) {
6299
6337
  return Promise.all(
6300
6338
  rules.map(async (rule) => ({
@@ -6307,22 +6345,22 @@ async function generateProjectRules(rules) {
6307
6345
  function toProjectRulePath(source) {
6308
6346
  const normalized = source.replaceAll("\\", "/");
6309
6347
  if (normalized.startsWith("base/rules/")) {
6310
- return join31(PATHS.RULES_DIR, "_shared", normalized.replace(/^base\/rules\//, ""));
6348
+ return join32(PATHS.RULES_DIR, "_shared", normalized.replace(/^base\/rules\//, ""));
6311
6349
  }
6312
6350
  if (normalized.startsWith("capabilities/")) {
6313
6351
  const capabilityNormalized = normalized.replace(/^capabilities\//, "");
6314
6352
  const [prefix2, suffix2] = capabilityNormalized.split("/rules/");
6315
6353
  if (prefix2 !== void 0 && suffix2 !== void 0) {
6316
6354
  const target2 = suffix2.endsWith("/guide.md") ? suffix2.replace("/guide.md", ".md") : suffix2;
6317
- return join31(PATHS.RULES_DIR, prefix2, target2);
6355
+ return join32(PATHS.RULES_DIR, prefix2, target2);
6318
6356
  }
6319
6357
  }
6320
6358
  const [prefix, suffix] = normalized.split("/rules/");
6321
6359
  if (prefix === void 0 || suffix === void 0) {
6322
- return join31(PATHS.RULES_DIR, normalized);
6360
+ return join32(PATHS.RULES_DIR, normalized);
6323
6361
  }
6324
6362
  const target = suffix.endsWith("/guide.md") ? suffix.replace("/guide.md", ".md") : suffix;
6325
- return join31(PATHS.RULES_DIR, prefix, target);
6363
+ return join32(PATHS.RULES_DIR, prefix, target);
6326
6364
  }
6327
6365
 
6328
6366
  // src/onboarding/orchestrator.ts
@@ -6337,7 +6375,7 @@ var OnboardingOrchestrator = class {
6337
6375
  const runtimeRoot = options.runtimeRoot ?? getRuntimeRoot();
6338
6376
  const resolver = new Resolver({ runtimeRoot });
6339
6377
  const resolved = await resolver.resolve(selections);
6340
- const adapters = options.adapters ?? selections.providers ?? ["claude-code", "codex-cli", "gemini-cli", "junie"];
6378
+ const adapters = options.adapters ?? selections.providers ?? ["claude-code"];
6341
6379
  const profile = buildProjectProfile(selections, liveSnapshot, options.profileOverrides);
6342
6380
  const validator = new SchemaValidator();
6343
6381
  const validation = validator.validate("project-profile", profile);
@@ -6366,6 +6404,17 @@ var OnboardingOrchestrator = class {
6366
6404
  stack_profile: selections.stack_profile
6367
6405
  })
6368
6406
  );
6407
+ const silentUpdateSrc = join33(runtimeRoot, "..", "hooks", "silent-update.sh");
6408
+ try {
6409
+ const hookContent = readFileSync12(silentUpdateSrc, "utf8");
6410
+ generatedFiles.push({
6411
+ path: PATHS.HOOKS_SILENT_UPDATE,
6412
+ content: hookContent,
6413
+ autoUpdate: true,
6414
+ executable: true
6415
+ });
6416
+ } catch {
6417
+ }
6369
6418
  const writeResult = writeGeneratedFiles(options.projectRoot, generatedFiles);
6370
6419
  const drift = await writeStackArtifacts(
6371
6420
  options.projectRoot,
@@ -6374,7 +6423,9 @@ var OnboardingOrchestrator = class {
6374
6423
  { writeHumanDocs: false }
6375
6424
  );
6376
6425
  writeProjectProfile2(options.projectRoot, profile);
6426
+ writeGitignore(options.projectRoot);
6377
6427
  writeDetectionReport(options.projectRoot, detection);
6428
+ writeFrameworkMetadata(options.projectRoot, VERSION);
6378
6429
  bootstrapFramework(options.projectRoot);
6379
6430
  const manifestPath = writeOnboardingManifest(options.projectRoot, {
6380
6431
  framework_version: VERSION,
@@ -6648,7 +6699,7 @@ function buildRustCommands(usingCompose) {
6648
6699
  }
6649
6700
 
6650
6701
  // src/onboarding/scaffold-generator.ts
6651
- import { join as join32 } from "path";
6702
+ import { join as join34 } from "path";
6652
6703
 
6653
6704
  // src/templates/registry.ts
6654
6705
  import fg4 from "fast-glob";
@@ -6656,29 +6707,29 @@ import { basename as basename4, relative as relative5 } from "pathe";
6656
6707
 
6657
6708
  // src/onboarding/scaffold-generator.ts
6658
6709
  var FEATURE_TEMPLATE_TARGETS = [
6659
- ["business.md.hbs", join32(PATHS.MODULE_FEATURES_DIR, "core", "business.md")],
6660
- ["technical.md.hbs", join32(PATHS.MODULE_FEATURES_DIR, "core", "technical.md")]
6710
+ ["business.md.hbs", join34(PATHS.MODULE_FEATURES_DIR, "core", "business.md")],
6711
+ ["technical.md.hbs", join34(PATHS.MODULE_FEATURES_DIR, "core", "technical.md")]
6661
6712
  ];
6662
6713
 
6663
6714
  // src/packs/manager.ts
6664
6715
  import {
6665
6716
  cpSync,
6666
- existsSync as existsSync14,
6717
+ existsSync as existsSync15,
6667
6718
  mkdirSync as mkdirSync5,
6668
6719
  mkdtempSync,
6669
6720
  readdirSync as readdirSync3,
6670
6721
  rmSync as rmSync2,
6671
- writeFileSync as writeFileSync4
6722
+ writeFileSync as writeFileSync5
6672
6723
  } from "fs";
6673
6724
  import { homedir as homedir2 } from "os";
6674
- import { join as join33, resolve as resolve2 } from "path";
6725
+ import { join as join35, resolve as resolve2 } from "path";
6675
6726
  import { execa } from "execa";
6676
6727
  var SOURCE_ORDER2 = ["built-in", "global", "project"];
6677
6728
  function resolvePackManagerRoots(projectRoot = process.cwd(), overrides = {}) {
6678
6729
  return {
6679
6730
  runtimeRoot: overrides.runtimeRoot ?? getRuntimeRoot(),
6680
- globalPacksRoot: overrides.globalPacksRoot ?? process.env.PAQAD_GLOBAL_PACKS_ROOT ?? join33(homedir2(), ".paqad", "packs"),
6681
- projectPacksRoot: overrides.projectPacksRoot ?? join33(projectRoot, ".paqad", "packs"),
6731
+ globalPacksRoot: overrides.globalPacksRoot ?? process.env.PAQAD_GLOBAL_PACKS_ROOT ?? join35(homedir2(), ".paqad", "packs"),
6732
+ projectPacksRoot: overrides.projectPacksRoot ?? join35(projectRoot, ".paqad", "packs"),
6682
6733
  registryUrl: overrides.registryUrl ?? process.env.PAQAD_PACK_REGISTRY_URL
6683
6734
  };
6684
6735
  }
@@ -6726,7 +6777,7 @@ async function installPack(source, options = {}) {
6726
6777
  if (!pack.validation.valid) {
6727
6778
  throw new Error(formatValidationIssues(pack.validation.issues));
6728
6779
  }
6729
- const destination = join33(installRoot, pack.manifest.name);
6780
+ const destination = join35(installRoot, pack.manifest.name);
6730
6781
  rmSync2(destination, { recursive: true, force: true });
6731
6782
  cpSync(candidateRoot, destination, { recursive: true });
6732
6783
  const installed = loader.validatePack(destination, scope === "project" ? "project" : "global");
@@ -6738,13 +6789,13 @@ async function installPack(source, options = {}) {
6738
6789
  function removePack(name, projectRoot = process.cwd(), scope = "global", overrides = {}) {
6739
6790
  const roots = resolvePackManagerRoots(projectRoot, overrides);
6740
6791
  const targetRoot = scope === "project" ? roots.projectPacksRoot : roots.globalPacksRoot;
6741
- const target = join33(targetRoot, name);
6742
- if (existsSync14(target)) {
6792
+ const target = join35(targetRoot, name);
6793
+ if (existsSync15(target)) {
6743
6794
  rmSync2(target, { recursive: true, force: true });
6744
6795
  return;
6745
6796
  }
6746
- const builtInRoot = join33(roots.runtimeRoot, "capabilities", "coding", "stacks", name);
6747
- if (existsSync14(builtInRoot)) {
6797
+ const builtInRoot = join35(roots.runtimeRoot, "capabilities", "coding", "stacks", name);
6798
+ if (existsSync15(builtInRoot)) {
6748
6799
  throw new Error(
6749
6800
  `Cannot remove built-in pack "${name}"; remove a global or project override instead`
6750
6801
  );
@@ -6761,14 +6812,14 @@ function validatePackAt(path) {
6761
6812
  function createPack(name, options = {}) {
6762
6813
  const destinationRoot = options.destinationRoot ?? process.cwd();
6763
6814
  const ecosystem = options.ecosystem ?? "node";
6764
- const packRoot = join33(destinationRoot, name);
6765
- if (existsSync14(packRoot)) {
6815
+ const packRoot = join35(destinationRoot, name);
6816
+ if (existsSync15(packRoot)) {
6766
6817
  throw new Error(`Pack scaffold already exists at ${packRoot}`);
6767
6818
  }
6768
- mkdirSync5(join33(packRoot, "rules"), { recursive: true });
6769
- writeFileSync4(join33(packRoot, "pack.yaml"), renderPackTemplate(name, ecosystem));
6770
- writeFileSync4(
6771
- join33(packRoot, "rules", "conventions.md"),
6819
+ mkdirSync5(join35(packRoot, "rules"), { recursive: true });
6820
+ writeFileSync5(join35(packRoot, "pack.yaml"), renderPackTemplate(name, ecosystem));
6821
+ writeFileSync5(
6822
+ join35(packRoot, "rules", "conventions.md"),
6772
6823
  `# ${name}
6773
6824
 
6774
6825
  Document project-specific conventions for the ${name} stack here.
@@ -6778,14 +6829,14 @@ Document project-specific conventions for the ${name} stack here.
6778
6829
  }
6779
6830
  function listPackNamesForSource(source, roots) {
6780
6831
  const sourceRoot = resolveSourceRoot(source, roots);
6781
- if (!existsSync14(sourceRoot)) {
6832
+ if (!existsSync15(sourceRoot)) {
6782
6833
  return [];
6783
6834
  }
6784
6835
  return readdirSync3(sourceRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
6785
6836
  }
6786
6837
  function resolveSourceRoot(source, roots) {
6787
6838
  if (source === "built-in") {
6788
- return join33(roots.runtimeRoot, "capabilities", "coding", "stacks");
6839
+ return join35(roots.runtimeRoot, "capabilities", "coding", "stacks");
6789
6840
  }
6790
6841
  return source === "global" ? roots.globalPacksRoot : roots.projectPacksRoot;
6791
6842
  }
@@ -6805,13 +6856,13 @@ async function materializePackSource(source, roots) {
6805
6856
  return clonePackSource(buildRegistryPackUrl(roots.registryUrl, source));
6806
6857
  }
6807
6858
  function looksLikeLocalPath(source) {
6808
- return source.startsWith(".") || source.startsWith("/") || existsSync14(resolve2(source));
6859
+ return source.startsWith(".") || source.startsWith("/") || existsSync15(resolve2(source));
6809
6860
  }
6810
6861
  function looksLikeGitUrl(source) {
6811
6862
  return source.startsWith("http://") || source.startsWith("https://") || source.startsWith("ssh://") || source.startsWith("git@") || source.startsWith("file://") || source.endsWith(".git");
6812
6863
  }
6813
6864
  async function clonePackSource(source) {
6814
- const tempRoot = mkdtempSync(join33(homedir2(), ".paqad-pack-clone-"));
6865
+ const tempRoot = mkdtempSync(join35(homedir2(), ".paqad-pack-clone-"));
6815
6866
  try {
6816
6867
  await execa("git", ["clone", "--depth", "1", source, tempRoot]);
6817
6868
  } catch (error) {
@@ -6821,11 +6872,11 @@ async function clonePackSource(source) {
6821
6872
  return findPackRoot(tempRoot);
6822
6873
  }
6823
6874
  function findPackRoot(root) {
6824
- const rootManifest = join33(root, "pack.yaml");
6825
- if (existsSync14(rootManifest)) {
6875
+ const rootManifest = join35(root, "pack.yaml");
6876
+ if (existsSync15(rootManifest)) {
6826
6877
  return root;
6827
6878
  }
6828
- const candidates = readdirSync3(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join33(root, entry.name)).filter((candidate) => existsSync14(join33(candidate, "pack.yaml")));
6879
+ const candidates = readdirSync3(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join35(root, entry.name)).filter((candidate) => existsSync15(join35(candidate, "pack.yaml")));
6829
6880
  if (candidates.length === 1) {
6830
6881
  return candidates[0];
6831
6882
  }
@@ -6924,15 +6975,15 @@ async function queryOsv(packages) {
6924
6975
  }
6925
6976
 
6926
6977
  // src/pentest/progress-tracker.ts
6927
- import { existsSync as existsSync16 } from "fs";
6978
+ import { existsSync as existsSync17 } from "fs";
6928
6979
  import { mkdir as mkdir12, readdir as readdir4, readFile as readFile16, writeFile as writeFile12 } from "fs/promises";
6929
- import { dirname as dirname17, join as join35 } from "path";
6980
+ import { dirname as dirname17, join as join37 } from "path";
6930
6981
 
6931
6982
  // src/pentest/shared.ts
6932
6983
  import { createHash as createHash7 } from "crypto";
6933
- import { existsSync as existsSync15 } from "fs";
6984
+ import { existsSync as existsSync16 } from "fs";
6934
6985
  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 join34, relative as relative6 } from "path";
6986
+ import { basename as basename5, dirname as dirname16, join as join36, relative as relative6 } from "path";
6936
6987
  import { execa as execa2 } from "execa";
6937
6988
  import fg5 from "fast-glob";
6938
6989
  function toLocalTimestamp(date) {
@@ -6950,7 +7001,7 @@ async function writeJson(target, data) {
6950
7001
  `);
6951
7002
  }
6952
7003
  async function readJsonIfExists(target) {
6953
- if (!existsSync15(target)) {
7004
+ if (!existsSync16(target)) {
6954
7005
  return null;
6955
7006
  }
6956
7007
  return JSON.parse(await readFile15(target, "utf8"));
@@ -6996,8 +7047,8 @@ async function discoverTargetUrl(projectRoot, stack, explicit) {
6996
7047
  }
6997
7048
  const envFiles = [".env", ".env.local", ".env.example"];
6998
7049
  for (const envFile of envFiles) {
6999
- const path = join34(projectRoot, envFile);
7000
- if (!existsSync15(path)) {
7050
+ const path = join36(projectRoot, envFile);
7051
+ if (!existsSync16(path)) {
7001
7052
  continue;
7002
7053
  }
7003
7054
  const content = await readFile15(path, "utf8");
@@ -7018,11 +7069,11 @@ async function discoverTargetUrl(projectRoot, stack, explicit) {
7018
7069
  return null;
7019
7070
  }
7020
7071
  async function runProjectScript(projectRoot, scriptName, env, logDir) {
7021
- const scriptPath = join34(projectRoot, PATHS.SCRIPTS_DIR, scriptName);
7022
- const stdoutPath = join34(logDir, `${scriptName}.stdout.log`);
7023
- const stderrPath = join34(logDir, `${scriptName}.stderr.log`);
7072
+ const scriptPath = join36(projectRoot, PATHS.SCRIPTS_DIR, scriptName);
7073
+ const stdoutPath = join36(logDir, `${scriptName}.stdout.log`);
7074
+ const stderrPath = join36(logDir, `${scriptName}.stderr.log`);
7024
7075
  await mkdir11(logDir, { recursive: true });
7025
- if (!existsSync15(scriptPath)) {
7076
+ if (!existsSync16(scriptPath)) {
7026
7077
  await writeFile11(stdoutPath, "");
7027
7078
  await writeFile11(stderrPath, `Missing script: ${relative6(projectRoot, scriptPath)}
7028
7079
  `);
@@ -7050,8 +7101,8 @@ async function runProjectScript(projectRoot, scriptName, env, logDir) {
7050
7101
  };
7051
7102
  }
7052
7103
  async function loadModuleDocs(projectRoot, focusModules = []) {
7053
- const moduleRoot = join34(projectRoot, PATHS.MODULES_DIR);
7054
- if (!existsSync15(moduleRoot)) {
7104
+ const moduleRoot = join36(projectRoot, PATHS.MODULES_DIR);
7105
+ if (!existsSync16(moduleRoot)) {
7055
7106
  return [];
7056
7107
  }
7057
7108
  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 +7170,7 @@ function inferSourceArtifacts(baseDir, scriptResults) {
7119
7170
  return [
7120
7171
  ...new Set(
7121
7172
  artifacts.map(
7122
- (artifact) => artifact.startsWith(".") ? artifact : relative6(dirname16(baseDir), join34(dirname16(baseDir), artifact))
7173
+ (artifact) => artifact.startsWith(".") ? artifact : relative6(dirname16(baseDir), join36(dirname16(baseDir), artifact))
7123
7174
  )
7124
7175
  )
7125
7176
  ];
@@ -7193,8 +7244,8 @@ var PentestProgressTracker = class {
7193
7244
  };
7194
7245
  }
7195
7246
  async load(projectRoot, runId) {
7196
- const target = join35(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "progress.json");
7197
- if (!existsSync16(target)) {
7247
+ const target = join37(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "progress.json");
7248
+ if (!existsSync17(target)) {
7198
7249
  return null;
7199
7250
  }
7200
7251
  const parsed = JSON.parse(await readFile16(target, "utf8"));
@@ -7205,7 +7256,7 @@ var PentestProgressTracker = class {
7205
7256
  return parsed;
7206
7257
  }
7207
7258
  async save(projectRoot, progress) {
7208
- const target = join35(projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "progress.json");
7259
+ const target = join37(projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "progress.json");
7209
7260
  progress.updated_at = (/* @__PURE__ */ new Date()).toISOString();
7210
7261
  await mkdir12(dirname17(target), { recursive: true });
7211
7262
  await writeFile12(target, `${JSON.stringify(progress, null, 2)}
@@ -7264,8 +7315,8 @@ var PentestProgressTracker = class {
7264
7315
  return step.status === "completed" && step.input_hash === inputHash;
7265
7316
  }
7266
7317
  async findIncompleteRun(projectRoot, workflow, sourceReportPath) {
7267
- const runsDir = join35(projectRoot, PATHS.PENTEST_RUNS_DIR);
7268
- if (!existsSync16(runsDir)) {
7318
+ const runsDir = join37(projectRoot, PATHS.PENTEST_RUNS_DIR);
7319
+ if (!existsSync17(runsDir)) {
7269
7320
  return null;
7270
7321
  }
7271
7322
  const entries = (await readdir4(runsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
@@ -7307,15 +7358,15 @@ var PentestProgressTracker = class {
7307
7358
  }
7308
7359
  };
7309
7360
  function runArtifactsDir(projectRoot, runId) {
7310
- return join35(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "artifacts");
7361
+ return join37(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "artifacts");
7311
7362
  }
7312
7363
  function runLogsDir(projectRoot, runId) {
7313
- return join35(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "logs");
7364
+ return join37(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "logs");
7314
7365
  }
7315
7366
 
7316
7367
  // src/pipeline/lane-runner.ts
7317
7368
  import { mkdir as mkdir16, writeFile as writeFile16 } from "fs/promises";
7318
- import { dirname as dirname20, join as join41 } from "path";
7369
+ import { dirname as dirname20, join as join43 } from "path";
7319
7370
 
7320
7371
  // src/pipeline/phases/shared.ts
7321
7372
  function createPassResult(phase, summary, context, artifacts = [`handoff:${context.phases.length + 1}`]) {
@@ -7435,12 +7486,12 @@ var LoadDocsPhase = class {
7435
7486
 
7436
7487
  // src/workflows/pentest.ts
7437
7488
  import { mkdir as mkdir13, writeFile as writeFile13 } from "fs/promises";
7438
- import { join as join38, relative as relative7 } from "path";
7489
+ import { join as join40, relative as relative7 } from "path";
7439
7490
 
7440
7491
  // src/pentest/findings.ts
7441
- import { existsSync as existsSync17 } from "fs";
7492
+ import { existsSync as existsSync18 } from "fs";
7442
7493
  import { readFile as readFile17 } from "fs/promises";
7443
- import { join as join36 } from "path";
7494
+ import { join as join38 } from "path";
7444
7495
  function createFinding(input) {
7445
7496
  return {
7446
7497
  id: "",
@@ -7610,12 +7661,265 @@ function buildModuleFindings(docs, tests) {
7610
7661
  );
7611
7662
  }
7612
7663
  }
7664
+ const authMechanismTests = extractRelevantTestPaths(tests, moduleDoc.module, [
7665
+ "algorithm",
7666
+ "expir",
7667
+ "signature",
7668
+ "refresh",
7669
+ "revok",
7670
+ "logout",
7671
+ "session.invalidat",
7672
+ "alg:none",
7673
+ "jwt"
7674
+ ]);
7675
+ if (hasAtLeast(lowered, 2, [
7676
+ "jwt",
7677
+ "token",
7678
+ "bearer",
7679
+ "session",
7680
+ "cookie",
7681
+ "oauth",
7682
+ "saml",
7683
+ "oidc",
7684
+ "sanctum"
7685
+ ])) {
7686
+ if (authMechanismTests.length === 0) {
7687
+ findings.push(
7688
+ createFinding({
7689
+ title: `Auth token lifecycle checks are thin for ${moduleDoc.module}`,
7690
+ description: "Module docs describe authentication tokens, sessions, or OAuth flows, but the current tests do not show evidence of token expiry, signature validation, session invalidation, or logout handling.",
7691
+ impact: "high",
7692
+ effort: "medium",
7693
+ possible_solution_direction: "Add tests for token expiry enforcement, alg:none rejection, session invalidation on logout, and refresh token rotation for the documented auth flows.",
7694
+ how_to_reproduce: [
7695
+ `Review ${moduleDoc.paths.join(", ")} for token or session handling.`,
7696
+ "Search tests for algorithm, expiry, signature, revocation, and logout coverage for that module."
7697
+ ],
7698
+ impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
7699
+ evidence: [
7700
+ ...moduleDoc.paths.map((path) => `Doc evidence: ${path}`),
7701
+ "No matching auth token lifecycle test evidence found for this module."
7702
+ ],
7703
+ category: "auth-mechanism",
7704
+ status: "open",
7705
+ confidence: 0.71,
7706
+ source_types: ["docs", "tests"],
7707
+ affected_modules: [moduleDoc.module],
7708
+ affected_packages: [],
7709
+ runtime_required: false,
7710
+ manual_follow_up: true
7711
+ })
7712
+ );
7713
+ }
7714
+ }
7715
+ const ssrfTests = extractRelevantTestPaths(tests, moduleDoc.module, [
7716
+ "ssrf",
7717
+ "redirect",
7718
+ "allowlist",
7719
+ "block",
7720
+ "internal",
7721
+ "private",
7722
+ "localhost",
7723
+ "metadata"
7724
+ ]);
7725
+ if (hasAtLeast(lowered, 2, [
7726
+ "url",
7727
+ "redirect",
7728
+ "callback",
7729
+ "webhook",
7730
+ "fetch",
7731
+ "http",
7732
+ "proxy",
7733
+ "curl",
7734
+ "axios"
7735
+ ])) {
7736
+ if (ssrfTests.length === 0) {
7737
+ findings.push(
7738
+ createFinding({
7739
+ title: `Outbound request / redirect surface lacks abuse validation for ${moduleDoc.module}`,
7740
+ description: "Module docs describe outbound HTTP calls, URL parameters, webhooks, or redirect flows, but the current tests do not show evidence of SSRF prevention, redirect allowlist validation, or private-range blocking.",
7741
+ impact: "high",
7742
+ effort: "medium",
7743
+ possible_solution_direction: "Add tests that verify SSRF prevention (blocked private ranges, redirect chain validation) and open-redirect protection for the documented outbound request surfaces.",
7744
+ how_to_reproduce: [
7745
+ `Review ${moduleDoc.paths.join(", ")} for URL, redirect, or webhook parameter handling.`,
7746
+ "Test with SSRF payloads: 127.0.0.1, 169.254.169.254, [::1], redirect chain to internal IP."
7747
+ ],
7748
+ impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
7749
+ evidence: [
7750
+ ...moduleDoc.paths.map((path) => `Doc evidence: ${path}`),
7751
+ "No matching SSRF or redirect validation test evidence found for this module."
7752
+ ],
7753
+ category: "input-validation",
7754
+ status: "open",
7755
+ confidence: 0.7,
7756
+ source_types: ["docs", "tests"],
7757
+ affected_modules: [moduleDoc.module],
7758
+ affected_packages: [],
7759
+ runtime_required: false,
7760
+ manual_follow_up: true
7761
+ })
7762
+ );
7763
+ }
7764
+ }
7765
+ const massAssignTests = extractRelevantTestPaths(tests, moduleDoc.module, [
7766
+ "mass",
7767
+ "assign",
7768
+ "fillable",
7769
+ "guarded",
7770
+ "allowlist",
7771
+ "forbidden",
7772
+ "attr_protected",
7773
+ "protected"
7774
+ ]);
7775
+ if (hasAtLeast(lowered, 2, [
7776
+ "fill",
7777
+ "create",
7778
+ "update",
7779
+ "patch",
7780
+ "assign",
7781
+ "body",
7782
+ "request",
7783
+ "fillable",
7784
+ "guarded"
7785
+ ])) {
7786
+ if (massAssignTests.length === 0) {
7787
+ findings.push(
7788
+ createFinding({
7789
+ title: `Mass assignment protection evidence is absent for ${moduleDoc.module}`,
7790
+ description: "Module docs describe model creation or update flows accepting request body fields, but the current tests do not show evidence of mass assignment protection (fillable allowlist, guarded fields, or forbidden-field rejection).",
7791
+ impact: "medium",
7792
+ effort: "low",
7793
+ possible_solution_direction: "Verify the model uses an explicit $fillable allowlist or $guarded blocklist. Add tests that confirm unintended fields (is_admin, role, price, balance) are rejected when submitted in the request body.",
7794
+ how_to_reproduce: [
7795
+ `Review ${moduleDoc.paths.join(", ")} for model create/update operations.`,
7796
+ "Submit a PATCH/POST request with extra privileged fields: is_admin=true, role=admin, price=0."
7797
+ ],
7798
+ impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
7799
+ evidence: [
7800
+ ...moduleDoc.paths.map((path) => `Doc evidence: ${path}`),
7801
+ "No matching mass assignment protection test evidence found for this module."
7802
+ ],
7803
+ category: "input-validation",
7804
+ status: "open",
7805
+ confidence: 0.68,
7806
+ source_types: ["docs", "tests"],
7807
+ affected_modules: [moduleDoc.module],
7808
+ affected_packages: [],
7809
+ runtime_required: false,
7810
+ manual_follow_up: false
7811
+ })
7812
+ );
7813
+ }
7814
+ }
7815
+ const cryptoTests = extractRelevantTestPaths(tests, moduleDoc.module, [
7816
+ "crypto",
7817
+ "encrypt",
7818
+ "hash.strength",
7819
+ "key.rotation",
7820
+ "salt",
7821
+ "entropy",
7822
+ "randomBytes",
7823
+ "bcrypt",
7824
+ "argon"
7825
+ ]);
7826
+ if (hasAtLeast(lowered, 2, [
7827
+ "encrypt",
7828
+ "decrypt",
7829
+ "hash",
7830
+ "md5",
7831
+ "sha1",
7832
+ "secret",
7833
+ "key",
7834
+ "cipher",
7835
+ "aes",
7836
+ "rsa",
7837
+ "hmac"
7838
+ ])) {
7839
+ if (cryptoTests.length === 0) {
7840
+ findings.push(
7841
+ createFinding({
7842
+ title: `Cryptographic implementation lacks verification coverage for ${moduleDoc.module}`,
7843
+ description: "Module docs describe encryption, hashing, or key management, but the current tests do not show evidence of cryptographic strength validation (algorithm checks, key rotation, salt uniqueness, or secure PRNG usage).",
7844
+ impact: "high",
7845
+ effort: "medium",
7846
+ possible_solution_direction: "Add tests that verify password hashing uses bcrypt/argon2 with a sufficient cost factor, encryption uses a secure algorithm with a randomly generated IV, and tokens are generated with a cryptographically secure PRNG.",
7847
+ how_to_reproduce: [
7848
+ `Review ${moduleDoc.paths.join(", ")} for cryptographic operations.`,
7849
+ "Check for MD5/SHA1 password hashing, hardcoded IVs, or Math.random() for token generation."
7850
+ ],
7851
+ impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
7852
+ evidence: [
7853
+ ...moduleDoc.paths.map((path) => `Doc evidence: ${path}`),
7854
+ "No matching cryptographic strength or key management test evidence found for this module."
7855
+ ],
7856
+ category: "cryptographic",
7857
+ status: "open",
7858
+ confidence: 0.67,
7859
+ source_types: ["docs", "tests"],
7860
+ affected_modules: [moduleDoc.module],
7861
+ affected_packages: [],
7862
+ runtime_required: false,
7863
+ manual_follow_up: true
7864
+ })
7865
+ );
7866
+ }
7867
+ }
7868
+ const loggingTests = extractRelevantTestPaths(tests, moduleDoc.module, [
7869
+ "audit",
7870
+ "log.assert",
7871
+ "event.dispatch",
7872
+ "trail",
7873
+ "activity",
7874
+ "log.entry",
7875
+ "logged",
7876
+ "event"
7877
+ ]);
7878
+ if (hasAtLeast(lowered, 2, [
7879
+ "log",
7880
+ "audit",
7881
+ "event",
7882
+ "track",
7883
+ "monitor",
7884
+ "alert",
7885
+ "sentry",
7886
+ "activity"
7887
+ ])) {
7888
+ if (loggingTests.length === 0) {
7889
+ findings.push(
7890
+ createFinding({
7891
+ title: `Security-relevant actions lack audit logging evidence for ${moduleDoc.module}`,
7892
+ description: "Module docs describe operations that should be audited (authentication, financial transactions, admin actions, or data exports), but the current tests do not show evidence of audit log assertions or event dispatch verification.",
7893
+ impact: "medium",
7894
+ effort: "medium",
7895
+ possible_solution_direction: "Add tests that assert audit log entries are written for high-value actions with actor identity, IP, and timestamp. Verify sensitive data (passwords, tokens) is not included in log output.",
7896
+ how_to_reproduce: [
7897
+ `Review ${moduleDoc.paths.join(", ")} for operations that must be auditable.`,
7898
+ "Check logging configuration and assert that log entries are created with sufficient context for forensic analysis."
7899
+ ],
7900
+ impact_area: [...moduleDoc.paths, `module:${moduleDoc.module}`],
7901
+ evidence: [
7902
+ ...moduleDoc.paths.map((path) => `Doc evidence: ${path}`),
7903
+ "No matching audit logging or event dispatch test evidence found for this module."
7904
+ ],
7905
+ category: "logging-monitoring",
7906
+ status: "open",
7907
+ confidence: 0.65,
7908
+ source_types: ["docs", "tests"],
7909
+ affected_modules: [moduleDoc.module],
7910
+ affected_packages: [],
7911
+ runtime_required: false,
7912
+ manual_follow_up: false
7913
+ })
7914
+ );
7915
+ }
7916
+ }
7613
7917
  }
7614
7918
  return findings;
7615
7919
  }
7616
7920
  async function buildSecretFindings(artifactDir) {
7617
- const path = join36(artifactDir, "secrets", "matches.txt");
7618
- if (!existsSync17(path)) {
7921
+ const path = join38(artifactDir, "secrets", "matches.txt");
7922
+ if (!existsSync18(path)) {
7619
7923
  return [];
7620
7924
  }
7621
7925
  const matches = parseSecretMatches(await readFile17(path, "utf8"));
@@ -7715,6 +8019,9 @@ function evaluateRetestStatus(sourceFinding, currentFindings, runtimeStatus, blo
7715
8019
  function hasAny(content, tokens) {
7716
8020
  return tokens.some((token) => content.includes(token));
7717
8021
  }
8022
+ function hasAtLeast(content, count, tokens) {
8023
+ return tokens.filter((token) => content.includes(token)).length >= count;
8024
+ }
7718
8025
  function normalizeImpact(content) {
7719
8026
  const lowered = content.toLowerCase();
7720
8027
  if (lowered.includes("critical") || lowered.includes("remote code execution") || lowered.includes("credential") || lowered.includes("auth bypass")) {
@@ -7727,8 +8034,8 @@ function normalizeImpact(content) {
7727
8034
  }
7728
8035
  async function readNativeAuditFindings(artifactDir) {
7729
8036
  const findings = [];
7730
- const dependencyDir = join36(artifactDir, "dependencies");
7731
- const npmAudit = await readJsonMaybe(join36(dependencyDir, "npm-audit.json"));
8037
+ const dependencyDir = join38(artifactDir, "dependencies");
8038
+ const npmAudit = await readJsonMaybe(join38(dependencyDir, "npm-audit.json"));
7732
8039
  for (const [name, vulnerability] of Object.entries(npmAudit?.vulnerabilities ?? {})) {
7733
8040
  const via = (vulnerability.via ?? []).find((entry) => typeof entry === "object");
7734
8041
  findings.push({
@@ -7740,7 +8047,7 @@ async function readNativeAuditFindings(artifactDir) {
7740
8047
  details: via?.url ?? ""
7741
8048
  });
7742
8049
  }
7743
- const pnpmAudit = await readJsonMaybe(join36(dependencyDir, "pnpm-audit.json"));
8050
+ const pnpmAudit = await readJsonMaybe(join38(dependencyDir, "pnpm-audit.json"));
7744
8051
  for (const advisory of Object.values(pnpmAudit?.advisories ?? {})) {
7745
8052
  findings.push({
7746
8053
  package_name: advisory.module_name ?? "unknown",
@@ -7751,7 +8058,7 @@ async function readNativeAuditFindings(artifactDir) {
7751
8058
  details: advisory.overview ?? ""
7752
8059
  });
7753
8060
  }
7754
- const composerAudit = await readJsonMaybe(join36(dependencyDir, "composer-audit.json"));
8061
+ const composerAudit = await readJsonMaybe(join38(dependencyDir, "composer-audit.json"));
7755
8062
  if (Array.isArray(composerAudit?.advisories)) {
7756
8063
  for (const advisory of composerAudit.advisories) {
7757
8064
  findings.push({
@@ -7788,7 +8095,7 @@ async function readNativeAuditFindings(artifactDir) {
7788
8095
  });
7789
8096
  }
7790
8097
  async function readJsonMaybe(path) {
7791
- if (!existsSync17(path)) {
8098
+ if (!existsSync18(path)) {
7792
8099
  return null;
7793
8100
  }
7794
8101
  try {
@@ -7800,10 +8107,33 @@ async function readJsonMaybe(path) {
7800
8107
 
7801
8108
  // src/pentest/file-check-mapper.ts
7802
8109
  var GENERIC_SECURITY_MAP = [
7803
- { glob: "**/auth*", checks: ["permission-boundary-review", "runtime-surface-probing"] },
8110
+ {
8111
+ glob: "**/auth*",
8112
+ checks: ["permission-boundary-review", "runtime-surface-probing", "auth-mechanism-review"]
8113
+ },
7804
8114
  { glob: "**/guard*", checks: ["permission-boundary-review"] },
7805
- { glob: "**/.env*", checks: ["runtime-surface-probing"] },
7806
- { glob: "**/config*", checks: ["runtime-surface-probing"] }
8115
+ { glob: "**/.env*", checks: ["runtime-surface-probing", "cryptographic-review"] },
8116
+ { glob: "**/config*", checks: ["runtime-surface-probing"] },
8117
+ // Auth / session files
8118
+ { glob: "**/jwt*", checks: ["auth-mechanism-review"] },
8119
+ { glob: "**/token*", checks: ["auth-mechanism-review"] },
8120
+ { glob: "**/passport*", checks: ["auth-mechanism-review"] },
8121
+ { glob: "**/session*", checks: ["auth-mechanism-review"] },
8122
+ // GraphQL schema and resolvers
8123
+ { glob: "**/*.graphql", checks: ["input-validation-review", "permission-boundary-review"] },
8124
+ { glob: "**/schema.graphql", checks: ["input-validation-review", "permission-boundary-review"] },
8125
+ { glob: "**/resolvers/**", checks: ["input-validation-review", "permission-boundary-review"] },
8126
+ // Logging and audit
8127
+ { glob: "**/log*", checks: ["logging-monitoring-review"] },
8128
+ { glob: "**/audit*", checks: ["logging-monitoring-review"] },
8129
+ { glob: "**/monitor*", checks: ["logging-monitoring-review"] },
8130
+ // Cryptography
8131
+ { glob: "**/*crypt*", checks: ["cryptographic-review"] },
8132
+ { glob: "**/*cipher*", checks: ["cryptographic-review"] },
8133
+ { glob: "**/*hash*", checks: ["cryptographic-review"] },
8134
+ // File uploads and input
8135
+ { glob: "**/upload*", checks: ["input-validation-review"] },
8136
+ { glob: "**/file*", checks: ["input-validation-review"] }
7807
8137
  ];
7808
8138
  var FileCheckMapper = class {
7809
8139
  constructor(frameworks, projectRoot) {
@@ -7864,7 +8194,7 @@ var FileCheckMapper = class {
7864
8194
 
7865
8195
  // src/pentest/incremental-scanner.ts
7866
8196
  import { readFile as readFile18 } from "fs/promises";
7867
- import { join as join37 } from "path";
8197
+ import { join as join39 } from "path";
7868
8198
  import { createHash as createHash8 } from "crypto";
7869
8199
  import { execa as execa3 } from "execa";
7870
8200
  var IncrementalScanner = class {
@@ -7898,7 +8228,7 @@ var IncrementalScanner = class {
7898
8228
  }
7899
8229
  }
7900
8230
  async gitDiff(projectRoot, lastRunId) {
7901
- const progressPath = join37(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
8231
+ const progressPath = join39(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
7902
8232
  let baseCommit;
7903
8233
  try {
7904
8234
  const raw = await readFile18(progressPath, "utf8");
@@ -7915,7 +8245,7 @@ var IncrementalScanner = class {
7915
8245
  return result.stdout.split("\n").map((f) => f.trim()).filter(Boolean);
7916
8246
  }
7917
8247
  async hashDiff(projectRoot, lastRunId) {
7918
- const manifestPath = join37(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
8248
+ const manifestPath = join39(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
7919
8249
  let fileManifest = {};
7920
8250
  try {
7921
8251
  const raw = await readFile18(manifestPath, "utf8");
@@ -7927,7 +8257,7 @@ var IncrementalScanner = class {
7927
8257
  const changed = [];
7928
8258
  for (const [filePath, storedHash] of Object.entries(fileManifest)) {
7929
8259
  try {
7930
- const content = await readFile18(join37(projectRoot, filePath), "utf8");
8260
+ const content = await readFile18(join39(projectRoot, filePath), "utf8");
7931
8261
  const currentHash = createHash8("sha256").update(content).digest("hex");
7932
8262
  if (currentHash !== storedHash) {
7933
8263
  changed.push(filePath);
@@ -7940,11 +8270,11 @@ var IncrementalScanner = class {
7940
8270
  }
7941
8271
  async warnIfFullScanStale(projectRoot, thresholdDays) {
7942
8272
  try {
7943
- const runsDir = join37(projectRoot, ".paqad", "pentest", "runs");
8273
+ const runsDir = join39(projectRoot, ".paqad", "pentest", "runs");
7944
8274
  const { readdir: readdir8 } = await import("fs/promises");
7945
8275
  const runs = await readdir8(runsDir).catch(() => []);
7946
8276
  for (const run of runs.sort().reverse()) {
7947
- const progressPath = join37(runsDir, run, "progress.json");
8277
+ const progressPath = join39(runsDir, run, "progress.json");
7948
8278
  try {
7949
8279
  const raw = await readFile18(progressPath, "utf8");
7950
8280
  const progress = JSON.parse(raw);
@@ -8142,8 +8472,8 @@ var PentestWorkflow = class {
8142
8472
  await this.tracker.save(options.projectRoot, progress);
8143
8473
  const docs = await loadModuleDocs(options.projectRoot, focusModules);
8144
8474
  const tests = await loadTests(options.projectRoot, focusModules);
8145
- const docsPath = join38(artifactsDir, "docs-summary.json");
8146
- const testsPath = join38(artifactsDir, "tests-summary.json");
8475
+ const docsPath = join40(artifactsDir, "docs-summary.json");
8476
+ const testsPath = join40(artifactsDir, "tests-summary.json");
8147
8477
  await writeJson(docsPath, docs);
8148
8478
  await writeJson(
8149
8479
  testsPath,
@@ -8244,7 +8574,7 @@ var PentestWorkflow = class {
8244
8574
  progressRunId: progress.run_id,
8245
8575
  reportTimestamp: new Date(progress.started_at)
8246
8576
  });
8247
- const findingIndexPath = join38(
8577
+ const findingIndexPath = join40(
8248
8578
  options.projectRoot,
8249
8579
  PATHS.PENTEST_RUNS_DIR,
8250
8580
  progress.run_id,
@@ -8261,7 +8591,7 @@ var PentestWorkflow = class {
8261
8591
  }
8262
8592
  if (report === null) {
8263
8593
  const existingSidecar = progress.sidecar_path ? await readJsonIfExists(
8264
- join38(options.projectRoot, progress.sidecar_path)
8594
+ join40(options.projectRoot, progress.sidecar_path)
8265
8595
  ) : null;
8266
8596
  report = existingSidecar;
8267
8597
  }
@@ -8276,18 +8606,18 @@ var PentestWorkflow = class {
8276
8606
  this.tracker.markStepRunning(progress, "write-report", writeHash);
8277
8607
  await this.tracker.save(options.projectRoot, progress);
8278
8608
  await writeJson(
8279
- join38(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "report-preview.json"),
8609
+ join40(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "report-preview.json"),
8280
8610
  { report_id: report.report_id, findings: report.findings.length }
8281
8611
  );
8282
- await writeJson(join38(options.projectRoot, report.sidecar_path), report);
8612
+ await writeJson(join40(options.projectRoot, report.sidecar_path), report);
8283
8613
  await writeJson(
8284
- join38(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "blocked-checks.json"),
8614
+ join40(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "blocked-checks.json"),
8285
8615
  report.blocked_checks
8286
8616
  );
8287
- await mkdir13(join38(options.projectRoot, PATHS.PENTEST_DIR), { recursive: true });
8617
+ await mkdir13(join40(options.projectRoot, PATHS.PENTEST_DIR), { recursive: true });
8288
8618
  const markdown = buildPentestMarkdown(report);
8289
- await writeJson(join38(options.projectRoot, report.sidecar_path), report);
8290
- await writeFile13(join38(options.projectRoot, report.report_path), markdown);
8619
+ await writeJson(join40(options.projectRoot, report.sidecar_path), report);
8620
+ await writeFile13(join40(options.projectRoot, report.report_path), markdown);
8291
8621
  this.tracker.markStepCompleted(
8292
8622
  progress,
8293
8623
  "write-report",
@@ -8314,7 +8644,7 @@ async function buildCurrentPentestReport(input) {
8314
8644
  const docs = await loadModuleDocs(input.projectRoot, input.focusModules);
8315
8645
  const tests = await loadTests(input.projectRoot, input.focusModules);
8316
8646
  const osvFindings = await queryOsv(input.snapshot.packages);
8317
- const osvPath = join38(input.artifactsDir, "dependencies", "osv-results.json");
8647
+ const osvPath = join40(input.artifactsDir, "dependencies", "osv-results.json");
8318
8648
  await writeJson(osvPath, osvFindings);
8319
8649
  const dependencyFindings = await buildDependencyFindings(
8320
8650
  input.snapshot,
@@ -8323,7 +8653,7 @@ async function buildCurrentPentestReport(input) {
8323
8653
  );
8324
8654
  const moduleFindings = buildModuleFindings(docs, tests);
8325
8655
  const secretFindings = await buildSecretFindings(input.artifactsDir);
8326
- const runtimePayload = await readJsonIfExists(join38(input.artifactsDir, "runtime", "runtime-checks.json"));
8656
+ const runtimePayload = await readJsonIfExists(join40(input.artifactsDir, "runtime", "runtime-checks.json"));
8327
8657
  const runtimeStatus = input.targetUrl ? runtimePayload?.reachable ? {
8328
8658
  target_url: input.targetUrl,
8329
8659
  status: "reachable",
@@ -8349,8 +8679,8 @@ async function buildCurrentPentestReport(input) {
8349
8679
  ...runtimeFindings
8350
8680
  ]);
8351
8681
  const timestamp = toLocalTimestamp(input.reportTimestamp);
8352
- const reportPath = join38(PATHS.PENTEST_DIR, `${timestamp}.md`);
8353
- const sidecarPath = join38(PATHS.PENTEST_DIR, `${timestamp}.json`);
8682
+ const reportPath = join40(PATHS.PENTEST_DIR, `${timestamp}.md`);
8683
+ const sidecarPath = join40(PATHS.PENTEST_DIR, `${timestamp}.json`);
8354
8684
  const stack = getPrimaryStack({
8355
8685
  routing: { domain: "coding" },
8356
8686
  stack_profile: input.snapshot.profile
@@ -8403,9 +8733,9 @@ async function buildCurrentPentestReport(input) {
8403
8733
  raw_evidence_paths: [
8404
8734
  relative7(input.projectRoot, osvPath),
8405
8735
  ...[
8406
- join38(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "finding-index.json"),
8407
- join38(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "docs-summary.json"),
8408
- join38(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "tests-summary.json")
8736
+ join40(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "finding-index.json"),
8737
+ join40(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "docs-summary.json"),
8738
+ join40(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "tests-summary.json")
8409
8739
  ]
8410
8740
  ]
8411
8741
  };
@@ -8445,7 +8775,7 @@ var PentestPhase = class {
8445
8775
 
8446
8776
  // src/workflows/pentest-retest.ts
8447
8777
  import { mkdir as mkdir14, writeFile as writeFile14 } from "fs/promises";
8448
- import { dirname as dirname18, join as join39 } from "path";
8778
+ import { dirname as dirname18, join as join41 } from "path";
8449
8779
  var RETEST_STEPS = [
8450
8780
  { id: "load-source-report", title: "Load source pentest report" },
8451
8781
  { id: "rerun-evidence", title: "Collect fresh evidence for source findings" },
@@ -8466,7 +8796,7 @@ var PentestRetestWorkflow = class {
8466
8796
  }
8467
8797
  const normalizedSourcePath = normalizeSidecarPath(sourceReportPath);
8468
8798
  const sourceSidecar = await readJsonIfExists(
8469
- join39(options.projectRoot, normalizedSourcePath)
8799
+ join41(options.projectRoot, normalizedSourcePath)
8470
8800
  );
8471
8801
  if (sourceSidecar === null) {
8472
8802
  throw new Error(`Source pentest sidecar not found at ${normalizedSourcePath}`);
@@ -8491,12 +8821,12 @@ var PentestRetestWorkflow = class {
8491
8821
  if (!this.tracker.shouldSkipStep(progress, "load-source-report", sourceHash)) {
8492
8822
  this.tracker.markStepRunning(progress, "load-source-report", sourceHash);
8493
8823
  await this.tracker.save(options.projectRoot, progress);
8494
- const sourceCopy = join39(artifactsDir, "source-report.json");
8824
+ const sourceCopy = join41(artifactsDir, "source-report.json");
8495
8825
  await writeJson(sourceCopy, sourceSidecar);
8496
8826
  this.tracker.markStepCompleted(
8497
8827
  progress,
8498
8828
  "load-source-report",
8499
- [join39(PATHS.PENTEST_RUNS_DIR, progress.run_id, "artifacts", "source-report.json")],
8829
+ [join41(PATHS.PENTEST_RUNS_DIR, progress.run_id, "artifacts", "source-report.json")],
8500
8830
  [...RETEST_SKILLS.source].map(skillPath)
8501
8831
  );
8502
8832
  await this.tracker.save(options.projectRoot, progress);
@@ -8513,7 +8843,7 @@ var PentestRetestWorkflow = class {
8513
8843
  PENTEST_RUN_ID: progress.run_id,
8514
8844
  PENTEST_ARTIFACT_DIR: artifactsDir,
8515
8845
  PENTEST_TARGET_URL: targetUrl ?? "",
8516
- PENTEST_SOURCE_REPORT: join39(options.projectRoot, normalizedSourcePath),
8846
+ PENTEST_SOURCE_REPORT: join41(options.projectRoot, normalizedSourcePath),
8517
8847
  PENTEST_DB_CONNECTION_NAME: options.dbConnectionName ?? ""
8518
8848
  };
8519
8849
  const scriptResults = await Promise.all([
@@ -8562,8 +8892,8 @@ var PentestRetestWorkflow = class {
8562
8892
  ...currentReport,
8563
8893
  report_id: toReportId("RETEST", new Date(progress.started_at)),
8564
8894
  workflow: "pentest-retest",
8565
- report_path: join39(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.md`),
8566
- sidecar_path: join39(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.json`),
8895
+ report_path: join41(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.md`),
8896
+ sidecar_path: join41(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.json`),
8567
8897
  source_report_path: normalizedSourcePath,
8568
8898
  source_report_id: sourceSidecar.report_id,
8569
8899
  findings: retestFindings,
@@ -8576,7 +8906,7 @@ var PentestRetestWorkflow = class {
8576
8906
  ...[...RETEST_SKILLS.source, ...RETEST_SKILLS.evaluate].map(skillPath)
8577
8907
  ]
8578
8908
  };
8579
- const findingIndexPath = join39(
8909
+ const findingIndexPath = join41(
8580
8910
  options.projectRoot,
8581
8911
  PATHS.PENTEST_RUNS_DIR,
8582
8912
  progress.run_id,
@@ -8586,14 +8916,14 @@ var PentestRetestWorkflow = class {
8586
8916
  this.tracker.markStepCompleted(
8587
8917
  progress,
8588
8918
  "evaluate-source-findings",
8589
- [join39(PATHS.PENTEST_RUNS_DIR, progress.run_id, "finding-index.json")],
8919
+ [join41(PATHS.PENTEST_RUNS_DIR, progress.run_id, "finding-index.json")],
8590
8920
  [...RETEST_SKILLS.evaluate].map(skillPath)
8591
8921
  );
8592
8922
  await this.tracker.save(options.projectRoot, progress);
8593
8923
  }
8594
8924
  if (retestReport === null) {
8595
8925
  const existing = progress.sidecar_path ? await readJsonIfExists(
8596
- join39(options.projectRoot, progress.sidecar_path)
8926
+ join41(options.projectRoot, progress.sidecar_path)
8597
8927
  ) : null;
8598
8928
  retestReport = existing;
8599
8929
  }
@@ -8607,12 +8937,12 @@ var PentestRetestWorkflow = class {
8607
8937
  if (!this.tracker.shouldSkipStep(progress, "write-report", writeHash)) {
8608
8938
  this.tracker.markStepRunning(progress, "write-report", writeHash);
8609
8939
  await this.tracker.save(options.projectRoot, progress);
8610
- await writeJson(join39(options.projectRoot, retestReport.sidecar_path), retestReport);
8611
- await mkdir14(dirname18(join39(options.projectRoot, retestReport.report_path)), {
8940
+ await writeJson(join41(options.projectRoot, retestReport.sidecar_path), retestReport);
8941
+ await mkdir14(dirname18(join41(options.projectRoot, retestReport.report_path)), {
8612
8942
  recursive: true
8613
8943
  });
8614
8944
  await writeFile14(
8615
- join39(options.projectRoot, retestReport.report_path),
8945
+ join41(options.projectRoot, retestReport.report_path),
8616
8946
  buildPentestMarkdown(retestReport)
8617
8947
  );
8618
8948
  this.tracker.markStepCompleted(
@@ -8690,7 +9020,7 @@ var ProjectQuestionPhase = class {
8690
9020
 
8691
9021
  // src/workflows/root-cause-analysis.ts
8692
9022
  import { mkdir as mkdir15, writeFile as writeFile15 } from "fs/promises";
8693
- import { dirname as dirname19, join as join40 } from "path";
9023
+ import { dirname as dirname19, join as join42 } from "path";
8694
9024
  var DEFAULT_TITLE_SLUG = "root-cause-analysis";
8695
9025
  var RCA_SECTIONS = [
8696
9026
  "Summary",
@@ -8709,8 +9039,8 @@ var RootCauseAnalysisWorkflow = class {
8709
9039
  async run(options) {
8710
9040
  const title = deriveTitle(options.classification.request_text);
8711
9041
  const filename = `${toLocalTimestamp2(/* @__PURE__ */ new Date())}-${slugify2(title) || DEFAULT_TITLE_SLUG}.md`;
8712
- const relativePath = join40(PATHS.RCA_DIR, filename);
8713
- const outputPath = join40(options.projectRoot, relativePath);
9042
+ const relativePath = join42(PATHS.RCA_DIR, filename);
9043
+ const outputPath = join42(options.projectRoot, relativePath);
8714
9044
  await mkdir15(dirname19(outputPath), { recursive: true });
8715
9045
  await writeFile15(outputPath, buildRcaDocument(title, options.classification));
8716
9046
  return {
@@ -8859,22 +9189,22 @@ var DEFAULT_PHASES = {
8859
9189
 
8860
9190
  // src/pipeline/stream-truncator.ts
8861
9191
  import { appendFile, mkdir as mkdir17 } from "fs/promises";
8862
- import { join as join42, dirname as dirname21 } from "path";
9192
+ import { join as join44, dirname as dirname21 } from "path";
8863
9193
 
8864
9194
  // src/resolver/deduplicator.ts
8865
9195
  import { createHash as createHash9 } from "crypto";
8866
9196
  import { readFile as readFile19, writeFile as writeFile17, mkdir as mkdir18 } from "fs/promises";
8867
- import { join as join43, dirname as dirname22 } from "path";
9197
+ import { join as join45, dirname as dirname22 } from "path";
8868
9198
 
8869
9199
  // src/scripts/generator.ts
8870
9200
  import { chmodSync as chmodSync2 } from "fs";
8871
9201
  import { mkdir as mkdir19, writeFile as writeFile18 } from "fs/promises";
8872
- import { dirname as dirname23, join as join44 } from "path";
9202
+ import { dirname as dirname23, join as join46 } from "path";
8873
9203
 
8874
9204
  // src/skills/cache-manager.ts
8875
9205
  import { createHash as createHash10 } from "crypto";
8876
9206
  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 join45 } from "path";
9207
+ import { join as join47 } from "path";
8878
9208
  import fg6 from "fast-glob";
8879
9209
 
8880
9210
  // src/skills/frontmatter-parser.ts
@@ -8899,24 +9229,49 @@ var conditionalProcessor = new ConditionalSectionProcessor();
8899
9229
 
8900
9230
  // src/skills/index-generator.ts
8901
9231
  import { mkdir as mkdir21, readFile as readFile21, writeFile as writeFile20 } from "fs/promises";
8902
- import { dirname as dirname24, join as join46, relative as relative8 } from "path";
9232
+ import { dirname as dirname24, join as join48, relative as relative8 } from "path";
8903
9233
  import fg7 from "fast-glob";
8904
9234
 
8905
9235
  // src/skills/loader.ts
8906
9236
  import { readFile as readFile22 } from "fs/promises";
8907
9237
  import { basename as basename6 } from "pathe";
8908
9238
 
9239
+ // src/update/audit.ts
9240
+ import { appendFileSync, mkdirSync as mkdirSync6 } from "fs";
9241
+ import { dirname as dirname25, join as join49 } from "path";
9242
+ function auditPath(projectRoot) {
9243
+ return join49(projectRoot, PATHS.AUDIT_LOG);
9244
+ }
9245
+ function ts() {
9246
+ return (/* @__PURE__ */ new Date()).toISOString();
9247
+ }
9248
+ function appendAuditLog2(projectRoot, previous, updated) {
9249
+ const path = auditPath(projectRoot);
9250
+ mkdirSync6(dirname25(path), { recursive: true });
9251
+ const line = `[${ts()}] INFO silent-update previous=${previous ?? "unknown"} updated=${updated}
9252
+ `;
9253
+ appendFileSync(path, line);
9254
+ }
9255
+ function appendAuditLogFailure(projectRoot, previous, target, error) {
9256
+ const path = auditPath(projectRoot);
9257
+ mkdirSync6(dirname25(path), { recursive: true });
9258
+ const sanitized = error.replace(/"/g, "'");
9259
+ const line = `[${ts()}] WARN silent-update-failed previous=${previous ?? "unknown"} target=${target} error="${sanitized}"
9260
+ `;
9261
+ appendFileSync(path, line);
9262
+ }
9263
+
8909
9264
  // src/update/updater.ts
8910
- import { chmodSync as chmodSync3, existsSync as existsSync18, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "fs";
9265
+ import { chmodSync as chmodSync3, existsSync as existsSync19, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "fs";
8911
9266
  import { mkdtemp, readdir as readdir6, readFile as readFile23, rm as rm3 } from "fs/promises";
8912
9267
  import { tmpdir } from "os";
8913
- import { dirname as dirname25, join as join47, relative as relative9 } from "path";
9268
+ import { dirname as dirname26, join as join50, relative as relative9 } from "path";
8914
9269
  var FrameworkUpdater = class {
8915
9270
  constructor(options = {}) {
8916
9271
  this.options = options;
8917
9272
  }
8918
9273
  async run(projectRoot) {
8919
- const previousVersion = readText(join47(projectRoot, PATHS.FRAMEWORK_VERSION));
9274
+ const previousVersion = readText(join50(projectRoot, PATHS.FRAMEWORK_VERSION));
8920
9275
  const manifest = readManifest(projectRoot);
8921
9276
  const artifactPolicy = new Map(
8922
9277
  manifest?.generated_artifacts.map((artifact) => [artifact.path, artifact.auto_update]) ?? []
@@ -8926,19 +9281,19 @@ var FrameworkUpdater = class {
8926
9281
  const skipped = [];
8927
9282
  const newScripts = [];
8928
9283
  for (const candidate of candidates) {
8929
- const target = join47(projectRoot, candidate.path);
8930
- const existed = existsSync18(target);
9284
+ const target = join50(projectRoot, candidate.path);
9285
+ const existed = existsSync19(target);
8931
9286
  const autoUpdate = artifactPolicy.get(candidate.path) ?? candidate.autoUpdate;
8932
9287
  if (existed && autoUpdate === false) {
8933
9288
  skipped.push({
8934
9289
  path: candidate.path,
8935
- before: readFileSync11(target, "utf8"),
9290
+ before: readFileSync13(target, "utf8"),
8936
9291
  after: candidate.content
8937
9292
  });
8938
9293
  continue;
8939
9294
  }
8940
- mkdirSync6(dirname25(target), { recursive: true });
8941
- writeFileSync5(target, candidate.content);
9295
+ mkdirSync7(dirname26(target), { recursive: true });
9296
+ writeFileSync6(target, candidate.content);
8942
9297
  if (candidate.executable === true) {
8943
9298
  chmodSync3(target, 493);
8944
9299
  }
@@ -8947,9 +9302,13 @@ var FrameworkUpdater = class {
8947
9302
  newScripts.push(candidate.path);
8948
9303
  }
8949
9304
  }
8950
- mkdirSync6(dirname25(join47(projectRoot, PATHS.FRAMEWORK_VERSION)), { recursive: true });
8951
- writeFileSync5(join47(projectRoot, PATHS.FRAMEWORK_VERSION), `${VERSION}
8952
- `);
9305
+ mkdirSync7(dirname26(join50(projectRoot, PATHS.FRAMEWORK_VERSION)), { recursive: true });
9306
+ writeFileSync6(
9307
+ join50(projectRoot, PATHS.FRAMEWORK_VERSION),
9308
+ `version=${VERSION}
9309
+ updated_at=${(/* @__PURE__ */ new Date()).toISOString()}
9310
+ `
9311
+ );
8953
9312
  return {
8954
9313
  previous_version: previousVersion,
8955
9314
  target_version: VERSION,
@@ -8968,7 +9327,7 @@ var FrameworkUpdater = class {
8968
9327
  if (profile === null) {
8969
9328
  throw new Error("Cannot update framework-managed artifacts without a project profile");
8970
9329
  }
8971
- const tempRoot = await mkdtemp(join47(tmpdir(), "paqad-ai-update-"));
9330
+ const tempRoot = await mkdtemp(join50(tmpdir(), "paqad-ai-update-"));
8972
9331
  try {
8973
9332
  const result = await new OnboardingOrchestrator().run({
8974
9333
  projectRoot: tempRoot,
@@ -8988,27 +9347,29 @@ var FrameworkUpdater = class {
8988
9347
  }
8989
9348
  };
8990
9349
  function readManifest(projectRoot) {
8991
- const path = join47(projectRoot, PATHS.ONBOARDING_MANIFEST);
8992
- if (!existsSync18(path)) {
9350
+ const path = join50(projectRoot, PATHS.ONBOARDING_MANIFEST);
9351
+ if (!existsSync19(path)) {
8993
9352
  return null;
8994
9353
  }
8995
- return JSON.parse(readFileSync11(path, "utf8"));
9354
+ return JSON.parse(readFileSync13(path, "utf8"));
8996
9355
  }
8997
9356
  function readProfile(projectRoot) {
8998
9357
  return readProjectProfile(projectRoot);
8999
9358
  }
9000
9359
  function readText(path) {
9001
- if (!existsSync18(path)) {
9360
+ if (!existsSync19(path)) {
9002
9361
  return null;
9003
9362
  }
9004
- return readFileSync11(path, "utf8").trim();
9363
+ const raw = readFileSync13(path, "utf8");
9364
+ const match = raw.match(/^version=(.+)$/m);
9365
+ return match ? match[1].trim() : raw.trim();
9005
9366
  }
9006
9367
  async function collectFiles(root, generated) {
9007
9368
  const paths = generated.length > 0 ? generated : await walk3(root);
9008
9369
  return Promise.all(
9009
9370
  paths.map(async (file) => ({
9010
9371
  path: file,
9011
- content: await readFile23(join47(root, file), "utf8"),
9372
+ content: await readFile23(join50(root, file), "utf8"),
9012
9373
  autoUpdate: true,
9013
9374
  executable: file.startsWith("scripts/")
9014
9375
  }))
@@ -9018,7 +9379,7 @@ async function walk3(root, current = root) {
9018
9379
  const entries = await readdir6(current, { withFileTypes: true });
9019
9380
  const files = [];
9020
9381
  for (const entry of entries) {
9021
- const absolute = join47(current, entry.name);
9382
+ const absolute = join50(current, entry.name);
9022
9383
  if (entry.isDirectory()) {
9023
9384
  files.push(...await walk3(root, absolute));
9024
9385
  continue;
@@ -9029,31 +9390,31 @@ async function walk3(root, current = root) {
9029
9390
  }
9030
9391
 
9031
9392
  // src/verification/gates/documentation-freshness.ts
9032
- import { existsSync as existsSync19 } from "fs";
9033
- import { join as join48 } from "path";
9393
+ import { existsSync as existsSync20 } from "fs";
9394
+ import { join as join51 } from "path";
9034
9395
  var STALENESS_WINDOW_MS2 = 1e3 * 60 * 60 * 24 * 7;
9035
9396
 
9036
9397
  // src/patterns/pattern-store.ts
9037
9398
  import { readFile as readFile24, writeFile as writeFile21, mkdir as mkdir22, unlink } from "fs/promises";
9038
- import { join as join49, dirname as dirname26 } from "path";
9399
+ import { join as join52, dirname as dirname27 } from "path";
9039
9400
  import { homedir as homedir3 } from "os";
9040
- var GLOBAL_PATTERNS_DIR = join49(homedir3(), ".paqad", "patterns");
9401
+ var GLOBAL_PATTERNS_DIR = join52(homedir3(), ".paqad", "patterns");
9041
9402
  var PatternStore = class {
9042
9403
  get indexPath() {
9043
- return join49(GLOBAL_PATTERNS_DIR, "index.json");
9404
+ return join52(GLOBAL_PATTERNS_DIR, "index.json");
9044
9405
  }
9045
9406
  get entriesDir() {
9046
- return join49(GLOBAL_PATTERNS_DIR, "entries");
9407
+ return join52(GLOBAL_PATTERNS_DIR, "entries");
9047
9408
  }
9048
9409
  async save(pattern) {
9049
9410
  await mkdir22(this.entriesDir, { recursive: true });
9050
- const entryPath = join49(this.entriesDir, `${pattern.id}.json`);
9411
+ const entryPath = join52(this.entriesDir, `${pattern.id}.json`);
9051
9412
  await writeFile21(entryPath, JSON.stringify(pattern, null, 2), "utf8");
9052
9413
  await this.updateIndex(pattern);
9053
9414
  }
9054
9415
  async load(id) {
9055
9416
  try {
9056
- const raw = await readFile24(join49(this.entriesDir, `${id}.json`), "utf8");
9417
+ const raw = await readFile24(join52(this.entriesDir, `${id}.json`), "utf8");
9057
9418
  return JSON.parse(raw);
9058
9419
  } catch {
9059
9420
  return null;
@@ -9083,12 +9444,12 @@ var PatternStore = class {
9083
9444
  } else {
9084
9445
  index.entries.push(entry);
9085
9446
  }
9086
- await mkdir22(dirname26(this.indexPath), { recursive: true });
9447
+ await mkdir22(dirname27(this.indexPath), { recursive: true });
9087
9448
  await writeFile21(this.indexPath, JSON.stringify(index, null, 2), "utf8");
9088
9449
  }
9089
9450
  async delete(id) {
9090
9451
  try {
9091
- await unlink(join49(this.entriesDir, `${id}.json`));
9452
+ await unlink(join52(this.entriesDir, `${id}.json`));
9092
9453
  } catch {
9093
9454
  }
9094
9455
  const index = await this.loadIndex();
@@ -9188,16 +9549,16 @@ ${p.solution}
9188
9549
 
9189
9550
  // src/workflows/template-loader.ts
9190
9551
  import { readFile as readFile25, readdir as readdir7 } from "fs/promises";
9191
- import { join as join50 } from "path";
9552
+ import { join as join53 } from "path";
9192
9553
  import YAML6 from "yaml";
9193
9554
 
9194
9555
  // src/workflows/engine.ts
9195
9556
  import { readFile as readFile26, writeFile as writeFile23, mkdir as mkdir23 } from "fs/promises";
9196
- import { join as join51, dirname as dirname27 } from "path";
9557
+ import { join as join54, dirname as dirname28 } from "path";
9197
9558
  import { randomUUID as randomUUID3 } from "crypto";
9198
9559
 
9199
9560
  // src/index.ts
9200
- var VERSION = "0.1.0";
9561
+ var VERSION = "0.1.3";
9201
9562
 
9202
9563
  // src/cli/commands/capabilities.ts
9203
9564
  import { Command } from "commander";
@@ -9373,8 +9734,8 @@ function createPacksCommand() {
9373
9734
 
9374
9735
  // src/cli/commands/refresh.ts
9375
9736
  import { Command as Command7 } from "commander";
9376
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "fs";
9377
- import { join as join52 } from "path";
9737
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
9738
+ import { join as join55 } from "path";
9378
9739
  function createRefreshCommand() {
9379
9740
  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
9741
  const shouldRefreshDesignSystem = options.designSystem ?? true;
@@ -9410,14 +9771,14 @@ function createRefreshCommand() {
9410
9771
  });
9411
9772
  }
9412
9773
  function writeRefreshDrift(projectRoot, refreshDrift) {
9413
- const path = join52(projectRoot, PATHS.STACK_DRIFT);
9774
+ const path = join55(projectRoot, PATHS.STACK_DRIFT);
9414
9775
  const current = readExistingJson(path);
9415
- writeFileSync6(path, `${JSON.stringify({ ...current ?? {}, ...refreshDrift }, null, 2)}
9776
+ writeFileSync7(path, `${JSON.stringify({ ...current ?? {}, ...refreshDrift }, null, 2)}
9416
9777
  `);
9417
9778
  }
9418
9779
  function readExistingJson(path) {
9419
9780
  try {
9420
- return JSON.parse(readFileSync12(path, "utf8"));
9781
+ return JSON.parse(readFileSync14(path, "utf8"));
9421
9782
  } catch {
9422
9783
  return null;
9423
9784
  }
@@ -9426,9 +9787,25 @@ function readExistingJson(path) {
9426
9787
  // src/cli/commands/update.ts
9427
9788
  import { Command as Command8 } from "commander";
9428
9789
  function createUpdateCommand() {
9429
- return new Command8("update").description("Update framework-managed artifacts").option("--project-root <path>", "Project root", process.cwd()).action(async (options) => {
9430
- const report = await new FrameworkUpdater().run(options.projectRoot);
9431
- console.log(JSON.stringify(report, null, 2));
9790
+ return new Command8("update").description("Update framework-managed artifacts").option("--project-root <path>", "Project root", process.cwd()).option("--silent", "Suppress output; write results to audit log only").action(async (options) => {
9791
+ try {
9792
+ const report = await new FrameworkUpdater().run(options.projectRoot);
9793
+ if (!options.silent) {
9794
+ console.log(JSON.stringify(report, null, 2));
9795
+ }
9796
+ appendAuditLog2(options.projectRoot, report.previous_version, report.target_version);
9797
+ } catch (err) {
9798
+ if (!options.silent) {
9799
+ throw err;
9800
+ }
9801
+ appendAuditLogFailure(
9802
+ options.projectRoot,
9803
+ null,
9804
+ VERSION,
9805
+ err instanceof Error ? err.message : String(err)
9806
+ );
9807
+ process.exit(0);
9808
+ }
9432
9809
  });
9433
9810
  }
9434
9811