paqad-ai 0.1.4 → 0.1.5

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 CHANGED
@@ -360,13 +360,18 @@ function buildDetectedStackProfile(input) {
360
360
  if (input.fallbackStack === "laravel") {
361
361
  frameworks.add("laravel");
362
362
  }
363
- const versionBands = input.packages.filter((pkg) => VERSIONED_PACKAGES.has(pkg.name)).map((pkg) => ({
364
- name: `${pkg.name}:${majorBand(pkg.locked_version || pkg.version_constraint)}`,
365
- package_name: pkg.name,
366
- range: majorBand(pkg.locked_version || pkg.version_constraint),
367
- locked_version: pkg.locked_version,
368
- source: pkg.locked_version !== "" && pkg.locked_version !== pkg.version_constraint ? "lockfile" : "manifest"
369
- })).sort((left, right) => left.package_name.localeCompare(right.package_name));
363
+ const versionBands = Array.from(
364
+ input.packages.filter((pkg) => VERSIONED_PACKAGES.has(pkg.name)).sort(compareVersionBandPackages).reduce(
365
+ (bands, pkg) => bands.has(pkg.name) ? bands : bands.set(pkg.name, {
366
+ name: `${pkg.name}:${majorBand(pkg.locked_version || pkg.version_constraint)}`,
367
+ package_name: pkg.name,
368
+ range: majorBand(pkg.locked_version || pkg.version_constraint),
369
+ locked_version: pkg.locked_version,
370
+ source: pkg.locked_version !== "" && pkg.locked_version !== pkg.version_constraint ? "lockfile" : "manifest"
371
+ }),
372
+ /* @__PURE__ */ new Map()
373
+ ).values()
374
+ ).sort((left, right) => left.package_name.localeCompare(right.package_name));
370
375
  return {
371
376
  frameworks: Array.from(frameworks).sort(compareFrameworks),
372
377
  traits: Array.from(traits).sort(),
@@ -498,6 +503,15 @@ function deriveReviewTargets(changes) {
498
503
  function compareFrameworks(left, right) {
499
504
  return frameworkRank(left) - frameworkRank(right) || left.localeCompare(right);
500
505
  }
506
+ function compareVersionBandPackages(left, right) {
507
+ return rootDepth(left.root) - rootDepth(right.root) || left.name.localeCompare(right.name);
508
+ }
509
+ function rootDepth(root) {
510
+ if (!root || root === ".") {
511
+ return 0;
512
+ }
513
+ return root.split("/").filter(Boolean).length;
514
+ }
501
515
  function frameworkRank(name) {
502
516
  switch (name) {
503
517
  case "laravel":
@@ -749,7 +763,58 @@ var detection_report_schema_default = {
749
763
  }
750
764
  }
751
765
  },
752
- timestamp: { type: "string" }
766
+ timestamp: { type: "string" },
767
+ repository: {
768
+ type: "object",
769
+ additionalProperties: false,
770
+ required: [
771
+ "selected_root",
772
+ "scan_max_depth",
773
+ "ignored_paths",
774
+ "projects",
775
+ "applications",
776
+ "primary_project_root"
777
+ ],
778
+ properties: {
779
+ selected_root: { type: "string" },
780
+ scan_max_depth: { type: "integer" },
781
+ ignored_paths: { type: "array", items: { type: "string" } },
782
+ primary_project_root: { type: ["string", "null"] },
783
+ projects: {
784
+ type: "array",
785
+ items: {
786
+ type: "object",
787
+ additionalProperties: false,
788
+ required: ["root", "role", "parent_root", "markers", "ecosystems"],
789
+ properties: {
790
+ root: { type: "string" },
791
+ role: { type: "string", enum: ["standalone", "component"] },
792
+ parent_root: { type: ["string", "null"] },
793
+ markers: { type: "array", items: { type: "string" } },
794
+ ecosystems: {
795
+ type: "array",
796
+ items: {
797
+ type: "string",
798
+ enum: ["node", "php", "python", "ruby", "jvm", "go", "rust", "dart"]
799
+ }
800
+ }
801
+ }
802
+ }
803
+ },
804
+ applications: {
805
+ type: "array",
806
+ items: {
807
+ type: "object",
808
+ additionalProperties: false,
809
+ required: ["root", "component_roots"],
810
+ properties: {
811
+ root: { type: "string" },
812
+ component_roots: { type: "array", items: { type: "string" } }
813
+ }
814
+ }
815
+ }
816
+ }
817
+ }
753
818
  }
754
819
  };
755
820
 
@@ -885,6 +950,93 @@ var error_catalog_schema_default = {
885
950
  }
886
951
  };
887
952
 
953
+ // src/validators/schemas/feature-development-policy.schema.json
954
+ var feature_development_policy_schema_default = {
955
+ $id: "feature-development-policy",
956
+ type: "object",
957
+ additionalProperties: false,
958
+ required: ["schema_version", "stages"],
959
+ properties: {
960
+ schema_version: { type: "string", const: "1" },
961
+ merge_mode: { type: "string", enum: ["append"] },
962
+ stages: {
963
+ type: "object",
964
+ additionalProperties: false,
965
+ properties: {
966
+ planning: { $ref: "#/$defs/stagePolicy" },
967
+ specification: { $ref: "#/$defs/stagePolicy" },
968
+ development: { $ref: "#/$defs/stagePolicy" },
969
+ review: { $ref: "#/$defs/stagePolicy" },
970
+ checks: { $ref: "#/$defs/stagePolicy" },
971
+ documentation_sync: { $ref: "#/$defs/stagePolicy" }
972
+ }
973
+ }
974
+ },
975
+ $defs: {
976
+ stagePolicy: {
977
+ type: "object",
978
+ additionalProperties: false,
979
+ properties: {
980
+ read: {
981
+ type: "array",
982
+ items: { type: "string" }
983
+ },
984
+ instructions: {
985
+ type: "array",
986
+ items: { type: "string" }
987
+ },
988
+ required_inputs: {
989
+ type: "array",
990
+ items: { type: "string" }
991
+ },
992
+ strictness: {
993
+ type: "object",
994
+ additionalProperties: { type: "boolean" }
995
+ },
996
+ escalation: {
997
+ type: "object",
998
+ additionalProperties: {
999
+ type: "string",
1000
+ enum: ["warn", "ask", "stop"]
1001
+ }
1002
+ },
1003
+ artifacts: {
1004
+ type: "array",
1005
+ items: { type: "string" }
1006
+ },
1007
+ checks: {
1008
+ type: "object",
1009
+ additionalProperties: false,
1010
+ properties: {
1011
+ use_project_profile_commands: { type: "boolean" },
1012
+ commands: {
1013
+ type: "array",
1014
+ items: {
1015
+ type: "string",
1016
+ enum: [
1017
+ "install",
1018
+ "dev",
1019
+ "test",
1020
+ "test_single",
1021
+ "lint",
1022
+ "format",
1023
+ "migrate",
1024
+ "build"
1025
+ ]
1026
+ }
1027
+ },
1028
+ shell_commands: {
1029
+ type: "array",
1030
+ items: { type: "string" }
1031
+ },
1032
+ block_on_failure: { type: "boolean" }
1033
+ }
1034
+ }
1035
+ }
1036
+ }
1037
+ }
1038
+ };
1039
+
888
1040
  // src/validators/schemas/gate-result.schema.json
889
1041
  var gate_result_schema_default = {
890
1042
  $id: "gate-result",
@@ -1004,6 +1156,7 @@ var onboarding_manifest_schema_default = {
1004
1156
  "project_root",
1005
1157
  "profile",
1006
1158
  "detected",
1159
+ "repository",
1007
1160
  "generated_at",
1008
1161
  "generated_artifacts"
1009
1162
  ],
@@ -1013,6 +1166,9 @@ var onboarding_manifest_schema_default = {
1013
1166
  project_root: { type: "string" },
1014
1167
  profile: { $ref: "project-profile" },
1015
1168
  detected: { anyOf: [{ $ref: "detection-report" }, { type: "null" }] },
1169
+ repository: {
1170
+ anyOf: [{ $ref: "detection-report#/properties/repository" }, { type: "null" }]
1171
+ },
1016
1172
  generated_at: { type: "string" },
1017
1173
  generated_artifacts: {
1018
1174
  type: "array",
@@ -1814,6 +1970,7 @@ var SCHEMAS = [
1814
1970
  api_endpoint_doc_schema_default,
1815
1971
  integration_doc_schema_default,
1816
1972
  error_catalog_schema_default,
1973
+ feature_development_policy_schema_default,
1817
1974
  skill_frontmatter_schema_default,
1818
1975
  gate_result_schema_default,
1819
1976
  stack_pack_schema_default
@@ -2607,24 +2764,232 @@ function removeActiveCapability(profile, capability) {
2607
2764
 
2608
2765
  // src/detection/detector.ts
2609
2766
  import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
2610
- import { join as join14 } from "path";
2767
+ import { join as join16 } from "path";
2611
2768
  import fg from "fast-glob";
2612
2769
 
2770
+ // src/introspection/stack-introspector.ts
2771
+ import { join as join14 } from "path";
2772
+
2773
+ // src/repository/discovery.ts
2774
+ import { readdir } from "fs/promises";
2775
+ import { basename as basename3, join as join10 } from "path";
2776
+ var DEFAULT_SCAN_MAX_DEPTH = 5;
2777
+ var PROJECT_MARKERS = /* @__PURE__ */ new Map([
2778
+ ["package.json", "node"],
2779
+ ["composer.json", "php"],
2780
+ ["pubspec.yaml", "dart"],
2781
+ ["pyproject.toml", "python"],
2782
+ ["requirements.txt", "python"],
2783
+ ["Pipfile", "python"],
2784
+ ["setup.py", "python"],
2785
+ ["Gemfile", "ruby"],
2786
+ ["go.mod", "go"],
2787
+ ["Cargo.toml", "rust"],
2788
+ ["pom.xml", "jvm"],
2789
+ ["build.gradle", "jvm"],
2790
+ ["build.gradle.kts", "jvm"],
2791
+ ["artisan", "php"],
2792
+ ["manage.py", "python"]
2793
+ ]);
2794
+ var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
2795
+ ".git",
2796
+ ".next",
2797
+ ".nuxt",
2798
+ ".dart_tool",
2799
+ ".gradle",
2800
+ ".turbo",
2801
+ "build",
2802
+ "coverage",
2803
+ "dist",
2804
+ "node_modules",
2805
+ "out",
2806
+ "target",
2807
+ "vendor"
2808
+ ]);
2809
+ var NON_CANONICAL_DIRECTORIES = /* @__PURE__ */ new Set([
2810
+ "__fixtures__",
2811
+ "demo",
2812
+ "demos",
2813
+ "example",
2814
+ "examples",
2815
+ "fixtures",
2816
+ "test-fixtures",
2817
+ "tmp"
2818
+ ]);
2819
+ var COMPONENT_DIRECTORY_NAMES = /* @__PURE__ */ new Set(["client", "frontend", "ui", "web"]);
2820
+ async function discoverRepositoryContext(projectRoot, options) {
2821
+ const maxDepth = options?.maxDepth ?? DEFAULT_SCAN_MAX_DEPTH;
2822
+ const ignoredPaths = /* @__PURE__ */ new Set();
2823
+ const candidates = /* @__PURE__ */ new Map();
2824
+ await walk(projectRoot, ".", 0, maxDepth, candidates, ignoredPaths);
2825
+ const sortedCandidates = Array.from(candidates.values()).sort(compareCandidates);
2826
+ const projects = classifyProjects(sortedCandidates);
2827
+ const applications = buildApplications(projects);
2828
+ const primaryProjectRoot = resolvePrimaryProjectRoot(projects, applications);
2829
+ return {
2830
+ selected_root: projectRoot,
2831
+ scan_max_depth: maxDepth,
2832
+ ignored_paths: Array.from(ignoredPaths).sort(),
2833
+ projects,
2834
+ applications,
2835
+ primary_project_root: primaryProjectRoot
2836
+ };
2837
+ }
2838
+ function prefixRepositoryPath(root, relativePath) {
2839
+ if (root === "." || root === "") {
2840
+ return relativePath;
2841
+ }
2842
+ return join10(root, relativePath);
2843
+ }
2844
+ async function walk(projectRoot, relativeDir, depth, maxDepth, candidates, ignoredPaths) {
2845
+ const absoluteDir = relativeDir === "." ? projectRoot : join10(projectRoot, relativeDir);
2846
+ let entries;
2847
+ try {
2848
+ entries = await readdir(absoluteDir, { withFileTypes: true });
2849
+ } catch {
2850
+ return;
2851
+ }
2852
+ const entryNames = new Set(entries.map((entry) => entry.name));
2853
+ const markers = Array.from(PROJECT_MARKERS.keys()).filter((marker) => entryNames.has(marker));
2854
+ if (markers.length > 0) {
2855
+ const ecosystems = Array.from(
2856
+ new Set(markers.map((marker) => PROJECT_MARKERS.get(marker)).filter(isDefined))
2857
+ ).sort();
2858
+ candidates.set(relativeDir, {
2859
+ root: relativeDir,
2860
+ role: "standalone",
2861
+ parent_root: null,
2862
+ markers: markers.sort(),
2863
+ ecosystems
2864
+ });
2865
+ }
2866
+ if (depth >= maxDepth) {
2867
+ return;
2868
+ }
2869
+ for (const entry of entries) {
2870
+ if (!entry.isDirectory()) {
2871
+ continue;
2872
+ }
2873
+ const childRelativePath = relativeDir === "." ? entry.name : join10(relativeDir, entry.name);
2874
+ if (IGNORED_DIRECTORIES.has(entry.name) || NON_CANONICAL_DIRECTORIES.has(entry.name)) {
2875
+ ignoredPaths.add(childRelativePath);
2876
+ continue;
2877
+ }
2878
+ await walk(projectRoot, childRelativePath, depth + 1, maxDepth, candidates, ignoredPaths);
2879
+ }
2880
+ }
2881
+ function classifyProjects(candidates) {
2882
+ const byRoot = new Map(candidates.map((candidate) => [candidate.root, candidate]));
2883
+ const result = [];
2884
+ for (const candidate of candidates) {
2885
+ const ancestors = findAncestorCandidates(candidate.root, byRoot);
2886
+ const parent = ancestors[0] ?? null;
2887
+ const role = parent && isLinkedComponent(parent, candidate) ? "component" : "standalone";
2888
+ result.push({
2889
+ ...candidate,
2890
+ role,
2891
+ parent_root: role === "component" ? parent.root : null
2892
+ });
2893
+ }
2894
+ return result.sort(compareCandidates);
2895
+ }
2896
+ function findAncestorCandidates(root, candidates) {
2897
+ if (root === ".") {
2898
+ return [];
2899
+ }
2900
+ const segments = root.split("/").filter(Boolean);
2901
+ const ancestors = [];
2902
+ for (let index = segments.length - 1; index >= 1; index -= 1) {
2903
+ const candidate = candidates.get(segments.slice(0, index).join("/"));
2904
+ if (candidate) {
2905
+ ancestors.push(candidate);
2906
+ }
2907
+ }
2908
+ const selectedRoot = candidates.get(".");
2909
+ if (selectedRoot) {
2910
+ ancestors.push(selectedRoot);
2911
+ }
2912
+ return ancestors.sort(compareCandidates);
2913
+ }
2914
+ function isLinkedComponent(parent, candidate) {
2915
+ const candidateName = basename3(candidate.root);
2916
+ const candidateNodeOnly = candidate.ecosystems.length > 0 && candidate.ecosystems.every((ecosystem) => ecosystem === "node");
2917
+ const parentHasNonNode = parent.ecosystems.some((ecosystem) => ecosystem !== "node");
2918
+ return candidateNodeOnly && parentHasNonNode && COMPONENT_DIRECTORY_NAMES.has(candidateName);
2919
+ }
2920
+ function buildApplications(projects) {
2921
+ const standaloneRoots = projects.filter((project) => project.role === "standalone").map((project) => project.root);
2922
+ return standaloneRoots.map((root) => ({
2923
+ root,
2924
+ component_roots: projects.filter((project) => project.parent_root === root).map((project) => project.root).sort()
2925
+ }));
2926
+ }
2927
+ function resolvePrimaryProjectRoot(projects, applications) {
2928
+ if (applications.length === 0) {
2929
+ return null;
2930
+ }
2931
+ const byRoot = new Map(projects.map((project) => [project.root, project]));
2932
+ return [...applications].sort((left, right) => {
2933
+ const leftProject = byRoot.get(left.root);
2934
+ const rightProject = byRoot.get(right.root);
2935
+ return scoreCandidate(rightProject) - scoreCandidate(leftProject) || compareByRoot(left.root, right.root);
2936
+ })[0]?.root ?? null;
2937
+ }
2938
+ function compareCandidates(left, right) {
2939
+ return compareByRoot(left.root, right.root);
2940
+ }
2941
+ function compareByRoot(left, right) {
2942
+ return depthOf(left) - depthOf(right) || left.localeCompare(right);
2943
+ }
2944
+ function depthOf(root) {
2945
+ return root === "." ? 0 : root.split("/").filter(Boolean).length;
2946
+ }
2947
+ function scoreCandidate(candidate) {
2948
+ if (!candidate) {
2949
+ return -1;
2950
+ }
2951
+ return candidate.markers.reduce((score, marker) => score + markerScore(marker), 0) - depthOf(candidate.root);
2952
+ }
2953
+ function markerScore(marker) {
2954
+ switch (marker) {
2955
+ case "composer.json":
2956
+ case "package.json":
2957
+ case "pubspec.yaml":
2958
+ return 5;
2959
+ case "artisan":
2960
+ case "manage.py":
2961
+ return 4;
2962
+ case "pyproject.toml":
2963
+ case "Gemfile":
2964
+ case "go.mod":
2965
+ case "Cargo.toml":
2966
+ case "pom.xml":
2967
+ case "build.gradle":
2968
+ case "build.gradle.kts":
2969
+ return 3;
2970
+ default:
2971
+ return 1;
2972
+ }
2973
+ }
2974
+ function isDefined(value) {
2975
+ return value !== void 0;
2976
+ }
2977
+
2613
2978
  // src/introspection/cache.ts
2614
2979
  import { createHash as createHash5 } from "crypto";
2615
2980
  import { mkdir as mkdir6, readFile as readFile6, stat as stat2, writeFile as writeFile6 } from "fs/promises";
2616
- import { dirname as dirname9, join as join10 } from "path";
2981
+ import { dirname as dirname9, join as join11 } from "path";
2617
2982
  var StackSnapshotCache = class {
2618
2983
  async read(projectRoot) {
2619
2984
  try {
2620
- const raw = await readFile6(join10(projectRoot, PATHS.STACK_SNAPSHOT), "utf8");
2985
+ const raw = await readFile6(join11(projectRoot, PATHS.STACK_SNAPSHOT), "utf8");
2621
2986
  return JSON.parse(raw);
2622
2987
  } catch {
2623
2988
  return null;
2624
2989
  }
2625
2990
  }
2626
2991
  async write(projectRoot, snapshot) {
2627
- const target = join10(projectRoot, PATHS.STACK_SNAPSHOT);
2992
+ const target = join11(projectRoot, PATHS.STACK_SNAPSHOT);
2628
2993
  await mkdir6(dirname9(target), { recursive: true });
2629
2994
  await writeFile6(target, `${JSON.stringify(snapshot, null, 2)}
2630
2995
  `);
@@ -2633,11 +2998,11 @@ var StackSnapshotCache = class {
2633
2998
  const hashes = {};
2634
2999
  for (const relativePath of relativePaths) {
2635
3000
  try {
2636
- const content = await readFile6(join10(projectRoot, relativePath), "utf8");
3001
+ const content = await readFile6(join11(projectRoot, relativePath), "utf8");
2637
3002
  hashes[relativePath] = `sha256:${createHash5("sha256").update(content).digest("hex")}`;
2638
3003
  } catch {
2639
3004
  try {
2640
- const pathStat = await stat2(join10(projectRoot, relativePath));
3005
+ const pathStat = await stat2(join11(projectRoot, relativePath));
2641
3006
  hashes[relativePath] = pathStat.isDirectory() ? "exists:directory" : "exists:file";
2642
3007
  } catch {
2643
3008
  continue;
@@ -2650,10 +3015,10 @@ var StackSnapshotCache = class {
2650
3015
 
2651
3016
  // src/introspection/ecosystems/shared.ts
2652
3017
  import { readFile as readFile7 } from "fs/promises";
2653
- import { join as join11 } from "path";
3018
+ import { join as join12 } from "path";
2654
3019
  async function readProjectFile(projectRoot, relativePath) {
2655
3020
  try {
2656
- return await readFile7(join11(projectRoot, relativePath), "utf8");
3021
+ return await readFile7(join12(projectRoot, relativePath), "utf8");
2657
3022
  } catch {
2658
3023
  return null;
2659
3024
  }
@@ -3133,7 +3498,7 @@ function createDefaultEcosystemParserRegistry() {
3133
3498
 
3134
3499
  // src/introspection/environment-traits.ts
3135
3500
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
3136
- import { join as join12 } from "path";
3501
+ import { join as join13 } from "path";
3137
3502
  var COMPOSE_FILES = ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"];
3138
3503
  function detectEnvironmentTraits(projectRoot, options) {
3139
3504
  const packageNames = new Set(options?.packageNames ?? []);
@@ -3141,7 +3506,7 @@ function detectEnvironmentTraits(projectRoot, options) {
3141
3506
  const sources = [];
3142
3507
  const signals = [];
3143
3508
  for (const file of COMPOSE_FILES) {
3144
- if (existsSync3(join12(projectRoot, file))) {
3509
+ if (existsSync3(join13(projectRoot, file))) {
3145
3510
  traits.add("compose");
3146
3511
  sources.push({
3147
3512
  file,
@@ -3211,14 +3576,14 @@ function listDockerIndicators(projectRoot) {
3211
3576
  const indicators = [];
3212
3577
  const directFiles = ["Dockerfile", "Dockerfile.dev", "Dockerfile.prod"];
3213
3578
  for (const file of directFiles) {
3214
- if (existsSync3(join12(projectRoot, file))) {
3579
+ if (existsSync3(join13(projectRoot, file))) {
3215
3580
  indicators.push(file);
3216
3581
  }
3217
3582
  }
3218
- if (existsSync3(join12(projectRoot, "docker"))) {
3583
+ if (existsSync3(join13(projectRoot, "docker"))) {
3219
3584
  indicators.push("docker/");
3220
3585
  }
3221
- if (existsSync3(join12(projectRoot, ".docker"))) {
3586
+ if (existsSync3(join13(projectRoot, ".docker"))) {
3222
3587
  indicators.push(".docker/");
3223
3588
  }
3224
3589
  return indicators;
@@ -3230,7 +3595,7 @@ function detectSailReferenceFile(projectRoot) {
3230
3595
  const candidates = ["composer.json", "package.json"];
3231
3596
  for (const relativePath of candidates) {
3232
3597
  try {
3233
- const content = readFileSync3(join12(projectRoot, relativePath), "utf8");
3598
+ const content = readFileSync3(join13(projectRoot, relativePath), "utf8");
3234
3599
  if (content.includes("vendor/bin/sail")) {
3235
3600
  return relativePath;
3236
3601
  }
@@ -3246,50 +3611,101 @@ var StackIntrospector = class {
3246
3611
  cache = new StackSnapshotCache();
3247
3612
  parserRegistry = createDefaultEcosystemParserRegistry();
3248
3613
  async snapshot(projectRoot) {
3249
- const currentHashes = await this.cache.hashFiles(projectRoot, [
3250
- ...this.parserRegistry.getKnownFiles(),
3251
- "docker-compose.yml",
3252
- "docker-compose.yaml",
3253
- "compose.yml",
3254
- "compose.yaml",
3255
- "Dockerfile",
3256
- "Dockerfile.dev",
3257
- "Dockerfile.prod",
3258
- "docker",
3259
- ".docker"
3260
- ]);
3614
+ const repository = await discoverRepositoryContext(projectRoot);
3615
+ const candidateRoots = repository.projects.map((project) => project.root);
3616
+ const currentHashes = await this.cache.hashFiles(
3617
+ projectRoot,
3618
+ buildRepositoryHashInputs(candidateRoots, this.parserRegistry.getKnownFiles())
3619
+ );
3261
3620
  const cached = await this.cache.read(projectRoot);
3262
3621
  if (cached !== null && JSON.stringify(cached.source_hashes) === JSON.stringify(currentHashes)) {
3263
3622
  return cached;
3264
3623
  }
3265
- const results = await this.parserRegistry.parseProject(projectRoot);
3266
- const toolchains = results.map((result) => result.toolchain);
3267
- const packages = results.flatMap((result) => result.packages);
3268
- const environment = detectEnvironmentTraits(projectRoot, {
3269
- packageNames: packages.map((pkg) => pkg.name)
3270
- });
3624
+ const toolchains = [];
3625
+ const packages = [];
3626
+ const environmentSources = [];
3627
+ const environmentTraits = /* @__PURE__ */ new Set();
3628
+ for (const project of repository.projects) {
3629
+ const absoluteRoot = project.root === "." ? projectRoot : join14(projectRoot, project.root);
3630
+ const results = await this.parserRegistry.parseProject(absoluteRoot);
3631
+ for (const result of results) {
3632
+ toolchains.push({
3633
+ ...result.toolchain,
3634
+ lockfile: prefixRepositoryPath(project.root, result.toolchain.lockfile)
3635
+ });
3636
+ packages.push(
3637
+ ...result.packages.map((pkg) => ({
3638
+ ...pkg,
3639
+ root: project.root
3640
+ }))
3641
+ );
3642
+ }
3643
+ const packageNames = packages.filter((pkg) => pkg.root === project.root).map((pkg) => pkg.name);
3644
+ const environment = detectEnvironmentTraits(absoluteRoot, { packageNames });
3645
+ for (const trait of environment.traits) {
3646
+ environmentTraits.add(trait);
3647
+ }
3648
+ environmentSources.push(
3649
+ ...environment.sources.map((source) => ({
3650
+ ...source,
3651
+ file: prefixRepositoryPath(project.root, source.file)
3652
+ }))
3653
+ );
3654
+ }
3271
3655
  const hashedSources = Object.keys(currentHashes).sort().map((file) => ({
3272
3656
  file,
3273
3657
  kind: classifySourceKind(file),
3274
3658
  detail: classifySourceKind(file) === "config" ? "Used for environment trait detection" : "Used for stack detection and version resolution"
3275
3659
  }));
3276
- const sources = dedupeSources([...hashedSources, ...environment.sources]);
3660
+ const sources = dedupeSources([...hashedSources, ...environmentSources]);
3277
3661
  const snapshot = {
3278
3662
  generated_at: (/* @__PURE__ */ new Date()).toISOString(),
3279
3663
  source_hashes: currentHashes,
3280
- toolchains,
3664
+ toolchains: dedupeToolchains(toolchains),
3281
3665
  packages,
3282
3666
  profile: buildDetectedStackProfile({
3283
- toolchains,
3667
+ toolchains: dedupeToolchains(toolchains),
3284
3668
  packages,
3285
3669
  sources,
3286
- detectedTraits: environment.traits
3287
- })
3670
+ detectedTraits: Array.from(environmentTraits).sort()
3671
+ }),
3672
+ repository
3288
3673
  };
3289
3674
  await this.cache.write(projectRoot, snapshot);
3290
3675
  return snapshot;
3291
3676
  }
3292
3677
  };
3678
+ function buildRepositoryHashInputs(candidateRoots, knownFiles) {
3679
+ const inputs = /* @__PURE__ */ new Set();
3680
+ const extraFiles = [
3681
+ "docker-compose.yml",
3682
+ "docker-compose.yaml",
3683
+ "compose.yml",
3684
+ "compose.yaml",
3685
+ "Dockerfile",
3686
+ "Dockerfile.dev",
3687
+ "Dockerfile.prod",
3688
+ "docker",
3689
+ ".docker"
3690
+ ];
3691
+ for (const root of candidateRoots.length > 0 ? candidateRoots : ["."]) {
3692
+ for (const file of [...knownFiles, ...extraFiles]) {
3693
+ inputs.add(prefixRepositoryPath(root, file));
3694
+ }
3695
+ }
3696
+ return Array.from(inputs).sort();
3697
+ }
3698
+ function dedupeToolchains(toolchains) {
3699
+ const seen = /* @__PURE__ */ new Set();
3700
+ return toolchains.filter((toolchain) => {
3701
+ const key = `${toolchain.ecosystem}:${toolchain.package_manager}:${toolchain.lockfile}`;
3702
+ if (seen.has(key)) {
3703
+ return false;
3704
+ }
3705
+ seen.add(key);
3706
+ return true;
3707
+ });
3708
+ }
3293
3709
  function classifySourceKind(file) {
3294
3710
  if (file.endsWith(".lock") || file.includes("lock")) {
3295
3711
  return "lockfile";
@@ -3323,17 +3739,18 @@ function buildDetectionReport(input) {
3323
3739
  detection_phase: input.detectionPhase,
3324
3740
  confidence: input.confidence,
3325
3741
  signals: input.signals,
3326
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
3742
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3743
+ repository: input.repository
3327
3744
  };
3328
3745
  }
3329
3746
 
3330
3747
  // src/detection/signals/short-video.ts
3331
3748
  import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
3332
- import { join as join13 } from "path";
3749
+ import { join as join15 } from "path";
3333
3750
  import { parse } from "yaml";
3334
3751
  function detectShortVideoSignals(projectRoot) {
3335
- const profilePath = join13(projectRoot, ".paqad", "project-profile.yaml");
3336
- const markerPath = join13(projectRoot, ".short-video-project");
3752
+ const profilePath = join15(projectRoot, ".paqad", "project-profile.yaml");
3753
+ const markerPath = join15(projectRoot, ".short-video-project");
3337
3754
  const signals = [];
3338
3755
  if (existsSync4(profilePath)) {
3339
3756
  const profile = parse(readFileSync4(profilePath, "utf8"));
@@ -3363,10 +3780,7 @@ var Detector = class {
3363
3780
  packLoader = new StackPackLoader();
3364
3781
  async detect(projectRoot) {
3365
3782
  const snapshot = await this.introspector.snapshot(projectRoot);
3366
- const packageNames = new Set(snapshot.packages.map((pkg) => pkg.name));
3367
- const environment = detectEnvironmentTraits(projectRoot, {
3368
- packageNames: snapshot.packages.map((pkg) => pkg.name)
3369
- });
3783
+ const repository = snapshot.repository ?? emptyRepositoryContext(projectRoot);
3370
3784
  const registry = this.packLoader.load({
3371
3785
  runtimeRoot: getRuntimeRoot(),
3372
3786
  projectRoot
@@ -3374,17 +3788,24 @@ var Detector = class {
3374
3788
  const allPacks = Array.from(registry.packs.values());
3375
3789
  const frameworkPacks = allPacks.filter((p) => (p.manifest.tier ?? "framework") === "framework");
3376
3790
  const archetypePacks = allPacks.filter((p) => p.manifest.tier === "archetype");
3377
- const frameworkMatches = frameworkPacks.map((pack) => evaluatePack(projectRoot, pack, packageNames)).filter((match) => match !== null).sort(compareMatchedPacks);
3378
- let matchedPacks;
3379
- let detectionPhase;
3380
- if (frameworkMatches.length > 0) {
3381
- matchedPacks = frameworkMatches;
3382
- detectionPhase = "framework";
3383
- } else {
3384
- const archetypeMatches = archetypePacks.map((pack) => evaluatePack(projectRoot, pack, packageNames)).filter((match) => match !== null).sort(compareMatchedPacks);
3385
- matchedPacks = archetypeMatches;
3386
- detectionPhase = archetypeMatches.length > 0 ? "archetype" : "none";
3387
- }
3791
+ const applications = repository.applications.length > 0 ? repository.applications : [{ root: ".", component_roots: [] }];
3792
+ const applicationResults = applications.map(
3793
+ (application) => detectApplication(
3794
+ projectRoot,
3795
+ application,
3796
+ snapshot.packages,
3797
+ frameworkPacks,
3798
+ archetypePacks
3799
+ )
3800
+ ).sort(compareApplicationResults);
3801
+ const primaryResult = applicationResults[0];
3802
+ const matchedPacks = primaryResult?.matches ?? [];
3803
+ const detectionPhase = primaryResult?.detectionPhase ?? "none";
3804
+ const repositoryEnvironment = mergeEnvironmentTraits(
3805
+ projectRoot,
3806
+ repository.projects.map((project) => project.root),
3807
+ snapshot.packages
3808
+ );
3388
3809
  if (matchedPacks.length === 0) {
3389
3810
  const shortVideoSignals = detectShortVideoSignals(projectRoot);
3390
3811
  if (shortVideoSignals.length > 0) {
@@ -3395,58 +3816,97 @@ var Detector = class {
3395
3816
  detectedTraits: [],
3396
3817
  recommendedCapabilities: ["content"],
3397
3818
  detectionPhase: "none",
3398
- signals: [...shortVideoSignals, ...environment.signals],
3399
- capabilities: environment.traits,
3400
- confidence: "low"
3819
+ signals: [...shortVideoSignals, ...repositoryEnvironment.signals],
3820
+ capabilities: repositoryEnvironment.traits,
3821
+ confidence: "low",
3822
+ repository
3401
3823
  });
3402
3824
  }
3403
3825
  return buildDetectionReport({
3404
3826
  domain: null,
3405
3827
  stack: null,
3406
3828
  matchedPacks: [],
3407
- detectedTraits: environment.traits,
3829
+ detectedTraits: repositoryEnvironment.traits,
3408
3830
  recommendedCapabilities: ["content"],
3409
3831
  detectionPhase: "none",
3410
- capabilities: environment.traits,
3411
- signals: environment.signals,
3412
- confidence: "low"
3832
+ capabilities: repositoryEnvironment.traits,
3833
+ signals: repositoryEnvironment.signals,
3834
+ confidence: "low",
3835
+ repository
3413
3836
  });
3414
3837
  }
3415
3838
  const topScore = matchedPacks[0].score;
3416
3839
  const topMatches = matchedPacks.filter((match) => match.score === topScore);
3417
3840
  const ambiguous = topMatches.length > 1;
3418
3841
  const detectedTraits = Array.from(
3419
- /* @__PURE__ */ new Set([...matchedPacks.flatMap((match) => match.traits), ...environment.traits])
3842
+ /* @__PURE__ */ new Set([
3843
+ ...applicationResults.flatMap((result) => result.matches.flatMap((match) => match.traits)),
3844
+ ...repositoryEnvironment.traits
3845
+ ])
3846
+ ).sort();
3847
+ const repositoryMatchedPacks = Array.from(
3848
+ new Set(applicationResults.flatMap((result) => result.matches.map((match) => match.name)))
3420
3849
  ).sort();
3850
+ const confidence = ambiguous ? "low" : applicationResults.length > 1 ? "medium" : scoreToConfidence(topScore);
3421
3851
  return buildDetectionReport({
3422
3852
  domain: ambiguous ? null : "coding",
3423
3853
  stack: ambiguous ? null : matchedPacks[0].name,
3424
- matchedPacks: matchedPacks.map((match) => match.name),
3854
+ matchedPacks: repositoryMatchedPacks,
3425
3855
  detectedTraits,
3426
3856
  recommendedCapabilities: ["content", "coding", "security"],
3427
3857
  detectionPhase,
3428
3858
  capabilities: detectedTraits.filter(isCapability2),
3429
- signals: [...matchedPacks.flatMap((match) => match.signals), ...environment.signals],
3430
- confidence: ambiguous ? "low" : scoreToConfidence(topScore)
3859
+ signals: [
3860
+ ...applicationResults.flatMap((result) => result.matches.flatMap((match) => match.signals)),
3861
+ ...repositoryEnvironment.signals
3862
+ ],
3863
+ confidence,
3864
+ repository
3431
3865
  });
3432
3866
  }
3433
3867
  };
3434
- function evaluatePack(projectRoot, pack, packageNames) {
3868
+ function detectApplication(projectRoot, application, packages, frameworkPacks, archetypePacks) {
3869
+ const roots = [application.root, ...application.component_roots];
3870
+ const packageNames = new Set(
3871
+ packages.filter((pkg) => roots.includes(pkg.root ?? ".")).map((pkg) => pkg.name)
3872
+ );
3873
+ const environment = mergeEnvironmentTraits(projectRoot, roots, packages);
3874
+ const frameworkMatches = frameworkPacks.map((pack) => evaluatePack(projectRoot, roots, pack, packageNames)).filter((match) => match !== null).sort(compareMatchedPacks);
3875
+ if (frameworkMatches.length > 0) {
3876
+ return {
3877
+ application,
3878
+ matches: frameworkMatches,
3879
+ detectionPhase: "framework",
3880
+ environment
3881
+ };
3882
+ }
3883
+ const archetypeMatches = archetypePacks.map((pack) => evaluatePack(projectRoot, roots, pack, packageNames)).filter((match) => match !== null).sort(compareMatchedPacks);
3884
+ return {
3885
+ application,
3886
+ matches: archetypeMatches,
3887
+ detectionPhase: archetypeMatches.length > 0 ? "archetype" : "none",
3888
+ environment
3889
+ };
3890
+ }
3891
+ function evaluatePack(projectRoot, roots, pack, packageNames) {
3435
3892
  const signals = [
3436
3893
  ...evaluateRules(
3437
3894
  projectRoot,
3895
+ roots,
3438
3896
  pack.manifest.name,
3439
3897
  pack.manifest.detection.manifests,
3440
3898
  packageNames
3441
3899
  ),
3442
3900
  ...evaluateRules(
3443
3901
  projectRoot,
3902
+ roots,
3444
3903
  pack.manifest.name,
3445
3904
  pack.manifest.detection.lockfiles,
3446
3905
  packageNames
3447
3906
  ),
3448
3907
  ...evaluateRules(
3449
3908
  projectRoot,
3909
+ roots,
3450
3910
  pack.manifest.name,
3451
3911
  pack.manifest.detection.heuristics,
3452
3912
  packageNames
@@ -3455,7 +3915,7 @@ function evaluatePack(projectRoot, pack, packageNames) {
3455
3915
  if (signals.length === 0) {
3456
3916
  return null;
3457
3917
  }
3458
- const traitMatches = detectTraits(projectRoot, pack.manifest.traits ?? [], packageNames);
3918
+ const traitMatches = detectTraits(projectRoot, roots, pack.manifest.traits ?? [], packageNames);
3459
3919
  const allSignals = [...signals, ...traitMatches.signals];
3460
3920
  return {
3461
3921
  name: pack.manifest.name,
@@ -3464,27 +3924,38 @@ function evaluatePack(projectRoot, pack, packageNames) {
3464
3924
  traits: traitMatches.names
3465
3925
  };
3466
3926
  }
3467
- function evaluateRules(projectRoot, implies, rules, packageNames) {
3468
- return (rules ?? []).map((rule) => evaluateRule(projectRoot, implies, rule, packageNames)).filter((signal) => signal !== null);
3927
+ function evaluateRules(projectRoot, roots, implies, rules, packageNames) {
3928
+ return (rules ?? []).map((rule) => evaluateRule(projectRoot, roots, implies, rule, packageNames)).filter((signal) => signal !== null);
3469
3929
  }
3470
- function evaluateRule(projectRoot, implies, rule, packageNames) {
3471
- const fileMatched = rule.file ? existsSync5(join14(projectRoot, rule.file)) : true;
3472
- const directoryMatched = rule.directory ? existsSync5(join14(projectRoot, rule.directory)) : true;
3930
+ function evaluateRule(projectRoot, roots, implies, rule, packageNames) {
3473
3931
  const packagesMatched = rule.packages === void 0 || rule.packages.every((pkg) => packageNames.has(pkg));
3474
- const patternsMatched = rule.patterns === void 0 || rule.patterns.every((pattern) => fg.sync(pattern, { cwd: projectRoot }).length > 0);
3475
- const contentMatched = rule.content_match === void 0 || rule.file !== void 0 && existsSync5(join14(projectRoot, rule.file)) && readFileSync5(join14(projectRoot, rule.file), "utf8").includes(rule.content_match);
3476
- const fieldsMatched = evaluateFieldRules(projectRoot, rule);
3477
- const fieldAbsentMatched = evaluateFieldAbsentRules(projectRoot, rule);
3478
- if (!fileMatched || !directoryMatched || !packagesMatched || !patternsMatched || !contentMatched || !fieldsMatched || !fieldAbsentMatched) {
3932
+ const matchedRoot = roots.find(
3933
+ (root) => matchesRuleAtRoot(projectRoot, root, rule, packageNames)
3934
+ );
3935
+ if (!packagesMatched || matchedRoot === void 0) {
3479
3936
  return null;
3480
3937
  }
3481
3938
  return {
3482
3939
  signal: buildRuleSignal(rule, implies),
3483
- file: rule.file ?? rule.directory ?? rule.patterns?.[0] ?? "package metadata",
3940
+ file: prefixRepositoryPath(
3941
+ matchedRoot,
3942
+ rule.file ?? rule.directory ?? rule.patterns?.[0] ?? "package metadata"
3943
+ ),
3484
3944
  implies,
3485
3945
  confidence: rule.file && rule.packages ? "high" : rule.file || rule.directory ? "medium" : "low"
3486
3946
  };
3487
3947
  }
3948
+ function matchesRuleAtRoot(projectRoot, root, rule, packageNames) {
3949
+ const absoluteRoot = root === "." ? projectRoot : join16(projectRoot, root);
3950
+ const fileMatched = rule.file ? existsSync5(join16(absoluteRoot, rule.file)) : true;
3951
+ const directoryMatched = rule.directory ? existsSync5(join16(absoluteRoot, rule.directory)) : true;
3952
+ const patternsMatched = rule.patterns === void 0 || rule.patterns.every((pattern) => fg.sync(pattern, { cwd: absoluteRoot }).length > 0);
3953
+ const contentMatched = rule.content_match === void 0 || rule.file !== void 0 && existsSync5(join16(absoluteRoot, rule.file)) && readFileSync5(join16(absoluteRoot, rule.file), "utf8").includes(rule.content_match);
3954
+ const fieldsMatched = evaluateFieldRules(absoluteRoot, rule);
3955
+ const fieldAbsentMatched = evaluateFieldAbsentRules(absoluteRoot, rule);
3956
+ const packagesMatched = rule.packages === void 0 || rule.packages.every((pkg) => packageNames.has(pkg));
3957
+ return fileMatched && directoryMatched && patternsMatched && contentMatched && fieldsMatched && fieldAbsentMatched && packagesMatched;
3958
+ }
3488
3959
  function evaluateFieldRules(projectRoot, rule) {
3489
3960
  if (!rule.fields?.length) return true;
3490
3961
  if (!rule.file) return false;
@@ -3528,7 +3999,7 @@ function getNestedField(obj, dotPath) {
3528
3999
  return current;
3529
4000
  }
3530
4001
  function parseManifestFile(projectRoot, file) {
3531
- const filePath = join14(projectRoot, file);
4002
+ const filePath = join16(projectRoot, file);
3532
4003
  if (!existsSync5(filePath)) return null;
3533
4004
  try {
3534
4005
  const content = readFileSync5(filePath, "utf8");
@@ -3537,7 +4008,7 @@ function parseManifestFile(projectRoot, file) {
3537
4008
  return null;
3538
4009
  }
3539
4010
  }
3540
- function detectTraits(projectRoot, traits, packageNames) {
4011
+ function detectTraits(projectRoot, roots, traits, packageNames) {
3541
4012
  const names = [];
3542
4013
  const signals = [];
3543
4014
  for (const trait of traits) {
@@ -3551,21 +4022,31 @@ function detectTraits(projectRoot, traits, packageNames) {
3551
4022
  });
3552
4023
  continue;
3553
4024
  }
3554
- if (trait.detect_file && existsSync5(join14(projectRoot, trait.detect_file))) {
4025
+ const fileRoot = trait.detect_file ? roots.find(
4026
+ (root) => existsSync5(
4027
+ join16(root === "." ? projectRoot : join16(projectRoot, root), trait.detect_file)
4028
+ )
4029
+ ) : void 0;
4030
+ if (trait.detect_file && fileRoot) {
3555
4031
  names.push(trait.name);
3556
4032
  signals.push({
3557
4033
  signal: `${trait.name} detected from ${trait.detect_file}`,
3558
- file: trait.detect_file,
4034
+ file: prefixRepositoryPath(fileRoot, trait.detect_file),
3559
4035
  implies: trait.name,
3560
4036
  confidence: "medium"
3561
4037
  });
3562
4038
  continue;
3563
4039
  }
3564
- if (trait.detect_directory && existsSync5(join14(projectRoot, trait.detect_directory))) {
4040
+ const directoryRoot = trait.detect_directory ? roots.find(
4041
+ (root) => existsSync5(
4042
+ join16(root === "." ? projectRoot : join16(projectRoot, root), trait.detect_directory)
4043
+ )
4044
+ ) : void 0;
4045
+ if (trait.detect_directory && directoryRoot) {
3565
4046
  names.push(trait.name);
3566
4047
  signals.push({
3567
4048
  signal: `${trait.name} detected from ${trait.detect_directory}`,
3568
- file: trait.detect_directory,
4049
+ file: prefixRepositoryPath(directoryRoot, trait.detect_directory),
3569
4050
  implies: trait.name,
3570
4051
  confidence: "medium"
3571
4052
  });
@@ -3594,12 +4075,68 @@ function buildRuleSignal(rule, implies) {
3594
4075
  function compareMatchedPacks(left, right) {
3595
4076
  return right.score - left.score || left.name.localeCompare(right.name);
3596
4077
  }
4078
+ function compareApplicationResults(left, right) {
4079
+ const leftScore = left.matches[0]?.score ?? -1;
4080
+ const rightScore = right.matches[0]?.score ?? -1;
4081
+ return rightScore - leftScore || left.application.root.localeCompare(right.application.root);
4082
+ }
3597
4083
  function scoreToConfidence(score) {
3598
4084
  if (score >= 2) {
3599
4085
  return "high";
3600
4086
  }
3601
4087
  return "low";
3602
4088
  }
4089
+ function mergeEnvironmentTraits(projectRoot, roots, packages) {
4090
+ const traits = /* @__PURE__ */ new Set();
4091
+ const signals = [];
4092
+ const sources = [];
4093
+ for (const root of roots.length > 0 ? roots : ["."]) {
4094
+ const packageNames = packages.filter((pkg) => (pkg.root ?? ".") === root).map((pkg) => pkg.name);
4095
+ const absoluteRoot = root === "." ? projectRoot : join16(projectRoot, root);
4096
+ const environment = detectEnvironmentTraits(absoluteRoot, { packageNames });
4097
+ for (const trait of environment.traits) {
4098
+ traits.add(trait);
4099
+ }
4100
+ sources.push(
4101
+ ...environment.sources.map((source) => ({
4102
+ ...source,
4103
+ file: prefixRepositoryPath(root, source.file)
4104
+ }))
4105
+ );
4106
+ signals.push(
4107
+ ...environment.signals.map((signal) => ({
4108
+ ...signal,
4109
+ file: prefixRepositoryPath(root, signal.file)
4110
+ }))
4111
+ );
4112
+ }
4113
+ return {
4114
+ traits: Array.from(traits).sort(),
4115
+ sources,
4116
+ signals: dedupeSignals(signals)
4117
+ };
4118
+ }
4119
+ function dedupeSignals(signals) {
4120
+ const seen = /* @__PURE__ */ new Set();
4121
+ return signals.filter((signal) => {
4122
+ const key = `${signal.signal}:${signal.file}:${signal.implies}:${signal.confidence}`;
4123
+ if (seen.has(key)) {
4124
+ return false;
4125
+ }
4126
+ seen.add(key);
4127
+ return true;
4128
+ });
4129
+ }
4130
+ function emptyRepositoryContext(projectRoot) {
4131
+ return {
4132
+ selected_root: projectRoot,
4133
+ scan_max_depth: 0,
4134
+ ignored_paths: [],
4135
+ projects: [],
4136
+ applications: [],
4137
+ primary_project_root: null
4138
+ };
4139
+ }
3603
4140
  function isCapability2(value) {
3604
4141
  return [
3605
4142
  "inertia",
@@ -3623,20 +4160,20 @@ function isCapability2(value) {
3623
4160
 
3624
4161
  // src/detection/signals/flutter.ts
3625
4162
  import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
3626
- import { join as join15 } from "path";
4163
+ import { join as join17 } from "path";
3627
4164
  import { parse as parse2 } from "yaml";
3628
4165
 
3629
4166
  // src/detection/signals/laravel.ts
3630
4167
  import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
3631
- import { join as join16 } from "path";
4168
+ import { join as join18 } from "path";
3632
4169
 
3633
4170
  // src/detection/signals/react.ts
3634
4171
  import { existsSync as existsSync8, readFileSync as readFileSync8 } from "fs";
3635
- import { join as join17 } from "path";
4172
+ import { join as join19 } from "path";
3636
4173
 
3637
4174
  // src/detection/signals/vue.ts
3638
4175
  import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
3639
- import { join as join18 } from "path";
4176
+ import { join as join20 } from "path";
3640
4177
 
3641
4178
  // src/design-tokens/defaults.ts
3642
4179
  var DEFAULT_DESIGN_TOKENS = {
@@ -3750,13 +4287,13 @@ var DEFAULT_DESIGN_TOKENS = {
3750
4287
 
3751
4288
  // src/design-tokens/service.ts
3752
4289
  import { mkdir as mkdir7, readFile as readFile8, writeFile as writeFile7 } from "fs/promises";
3753
- import { dirname as dirname10, join as join19 } from "path";
4290
+ import { dirname as dirname10, join as join21 } from "path";
3754
4291
  var DesignTokenService = class {
3755
4292
  constructor(validator = new SchemaValidator()) {
3756
4293
  this.validator = validator;
3757
4294
  }
3758
4295
  async seed(projectRoot) {
3759
- const target = join19(projectRoot, PATHS.DESIGN_TOKENS_FILE);
4296
+ const target = join21(projectRoot, PATHS.DESIGN_TOKENS_FILE);
3760
4297
  await mkdir7(dirname10(target), { recursive: true });
3761
4298
  await writeFile7(target, `${JSON.stringify(DEFAULT_DESIGN_TOKENS, null, 2)}
3762
4299
  `, {
@@ -3768,7 +4305,7 @@ var DesignTokenService = class {
3768
4305
  });
3769
4306
  }
3770
4307
  async load(projectRoot) {
3771
- const target = join19(projectRoot, PATHS.DESIGN_TOKENS_FILE);
4308
+ const target = join21(projectRoot, PATHS.DESIGN_TOKENS_FILE);
3772
4309
  const raw = await readFile8(target, "utf8");
3773
4310
  const parsed = JSON.parse(raw);
3774
4311
  const validation = this.validator.validate("design-tokens", parsed);
@@ -3785,27 +4322,27 @@ var DesignTokenService = class {
3785
4322
  const sections = groupTokens(flattened);
3786
4323
  return [
3787
4324
  {
3788
- path: join19(PATHS.DESIGN_SYSTEM_DIR, "tokens.md"),
4325
+ path: join21(PATHS.DESIGN_SYSTEM_DIR, "tokens.md"),
3789
4326
  content: buildTokensMarkdown(flattened)
3790
4327
  },
3791
4328
  {
3792
- path: join19(PATHS.DESIGN_SYSTEM_DIR, "components.md"),
4329
+ path: join21(PATHS.DESIGN_SYSTEM_DIR, "components.md"),
3793
4330
  content: buildSectionMarkdown("Component Defaults", sections.components)
3794
4331
  },
3795
4332
  {
3796
- path: join19(PATHS.DESIGN_SYSTEM_DIR, "motion.md"),
4333
+ path: join21(PATHS.DESIGN_SYSTEM_DIR, "motion.md"),
3797
4334
  content: buildSectionMarkdown("Motion", sections.motion)
3798
4335
  },
3799
4336
  {
3800
- path: join19(PATHS.DESIGN_SYSTEM_DIR, "accessibility.md"),
4337
+ path: join21(PATHS.DESIGN_SYSTEM_DIR, "accessibility.md"),
3801
4338
  content: buildSectionMarkdown("Accessibility", sections.accessibility)
3802
4339
  },
3803
4340
  {
3804
- path: join19(PATHS.DESIGN_SYSTEM_DIR, "responsive.md"),
4341
+ path: join21(PATHS.DESIGN_SYSTEM_DIR, "responsive.md"),
3805
4342
  content: buildResponsiveMarkdown(sections.spacing)
3806
4343
  },
3807
4344
  {
3808
- path: join19(PATHS.DESIGN_SYSTEM_DIR, "patterns.md"),
4345
+ path: join21(PATHS.DESIGN_SYSTEM_DIR, "patterns.md"),
3809
4346
  content: buildPatternsMarkdown(flattened)
3810
4347
  }
3811
4348
  ];
@@ -3814,7 +4351,7 @@ var DesignTokenService = class {
3814
4351
  const docs = await this.generateDocs(projectRoot);
3815
4352
  await Promise.all(
3816
4353
  docs.map(async (artifact) => {
3817
- const target = join19(projectRoot, artifact.path);
4354
+ const target = join21(projectRoot, artifact.path);
3818
4355
  await mkdir7(dirname10(target), { recursive: true });
3819
4356
  await writeFile7(target, artifact.content);
3820
4357
  })
@@ -3865,7 +4402,7 @@ ${flutterEntries}
3865
4402
  const artifacts = await this.exportTheme(projectRoot, stack);
3866
4403
  await Promise.all(
3867
4404
  artifacts.map(async (artifact) => {
3868
- const target = join19(projectRoot, artifact.path);
4405
+ const target = join21(projectRoot, artifact.path);
3869
4406
  await mkdir7(dirname10(target), { recursive: true });
3870
4407
  await writeFile7(target, artifact.content);
3871
4408
  })
@@ -3954,7 +4491,7 @@ function toIdentifier(value) {
3954
4491
 
3955
4492
  // src/health/checker.ts
3956
4493
  import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync10, statSync } from "fs";
3957
- import { join as join20 } from "path";
4494
+ import { join as join22 } from "path";
3958
4495
  var STALENESS_WINDOW_MS = 1e3 * 60 * 60 * 24 * 7;
3959
4496
  var HealthChecker = class {
3960
4497
  validator = new SchemaValidator();
@@ -3989,7 +4526,7 @@ var HealthChecker = class {
3989
4526
  return readProjectProfile(projectRoot);
3990
4527
  }
3991
4528
  detectModules(projectRoot) {
3992
- const modulesRoot = join20(projectRoot, "docs/modules");
4529
+ const modulesRoot = join22(projectRoot, "docs/modules");
3993
4530
  if (!existsSync10(modulesRoot)) {
3994
4531
  return [];
3995
4532
  }
@@ -3997,7 +4534,7 @@ var HealthChecker = class {
3997
4534
  }
3998
4535
  checkFrameworkArtifacts(projectRoot) {
3999
4536
  const required = [PATHS.PROJECT_PROFILE, PATHS.FRAMEWORK_VERSION, PATHS.FRAMEWORK_PATH];
4000
- const missing = required.filter((relative11) => !existsSync10(join20(projectRoot, relative11)));
4537
+ const missing = required.filter((relative11) => !existsSync10(join22(projectRoot, relative11)));
4001
4538
  return missing.length === 0 ? pass("Framework artifacts exist", "Framework artifacts are present") : fail(
4002
4539
  "Framework artifacts exist",
4003
4540
  `Missing framework artifacts: ${missing.join(", ")}`,
@@ -4020,15 +4557,15 @@ var HealthChecker = class {
4020
4557
  );
4021
4558
  }
4022
4559
  checkInstructionCopies(projectRoot, profile) {
4023
- const rulesRoot = join20(projectRoot, PATHS.RULES_DIR);
4560
+ const rulesRoot = join22(projectRoot, PATHS.RULES_DIR);
4024
4561
  const stack = profile === null ? null : getPrimaryStack(profile);
4025
- const toolsRoot = stack === null || profile === null || getProfileDomain(profile) !== "coding" ? null : join20(projectRoot, PATHS.TOOLS_DIR, stack);
4562
+ const toolsRoot = stack === null || profile === null || getProfileDomain(profile) !== "coding" ? null : join22(projectRoot, PATHS.TOOLS_DIR, stack);
4026
4563
  const missing = [];
4027
4564
  if (!existsSync10(rulesRoot)) {
4028
4565
  missing.push(PATHS.RULES_DIR);
4029
4566
  }
4030
4567
  if (toolsRoot !== null && !existsSync10(toolsRoot)) {
4031
- missing.push(join20(PATHS.TOOLS_DIR, stack ?? "unknown"));
4568
+ missing.push(join22(PATHS.TOOLS_DIR, stack ?? "unknown"));
4032
4569
  }
4033
4570
  return missing.length === 0 ? pass("Instruction copies exist", "Copied rules and tools are present") : fail(
4034
4571
  "Instruction copies exist",
@@ -4038,9 +4575,9 @@ var HealthChecker = class {
4038
4575
  }
4039
4576
  checkIndexesCurrent(projectRoot) {
4040
4577
  const missing = REGISTRIES.filter(
4041
- (registry) => !existsSync10(join20(projectRoot, PATHS.REGISTRIES_DIR, registry))
4578
+ (registry) => !existsSync10(join22(projectRoot, PATHS.REGISTRIES_DIR, registry))
4042
4579
  );
4043
- const statusPath = join20(projectRoot, ".paqad/indexes/registry-status.json");
4580
+ const statusPath = join22(projectRoot, ".paqad/indexes/registry-status.json");
4044
4581
  if (missing.length > 0 || !existsSync10(statusPath)) {
4045
4582
  return warn(
4046
4583
  "Indexes are current",
@@ -4053,7 +4590,7 @@ var HealthChecker = class {
4053
4590
  }
4054
4591
  checkAdapterConfig(projectRoot) {
4055
4592
  const configs = [PATHS.CLAUDE_MD, PATHS.AGENTS_MD, PATHS.GEMINI_MD];
4056
- const existing = configs.filter((config) => existsSync10(join20(projectRoot, config)));
4593
+ const existing = configs.filter((config) => existsSync10(join22(projectRoot, config)));
4057
4594
  return existing.length > 0 ? pass("Adapter config is present", "Adapter config files are present") : fail(
4058
4595
  "Adapter config is present",
4059
4596
  "No adapter config files were found",
@@ -4083,7 +4620,7 @@ var HealthChecker = class {
4083
4620
  );
4084
4621
  }
4085
4622
  checkStableFrameworkPaths(projectRoot) {
4086
- const frameworkPath = join20(projectRoot, PATHS.FRAMEWORK_PATH);
4623
+ const frameworkPath = join22(projectRoot, PATHS.FRAMEWORK_PATH);
4087
4624
  if (!existsSync10(frameworkPath)) {
4088
4625
  return fail(
4089
4626
  "Stable framework paths only",
@@ -4100,7 +4637,7 @@ var HealthChecker = class {
4100
4637
  ) : pass("Stable framework paths only", "Framework path is stable");
4101
4638
  }
4102
4639
  checkBrokenScaffold(projectRoot) {
4103
- const broken = walk(projectRoot).filter(
4640
+ const broken = walk2(projectRoot).filter(
4104
4641
  (path) => path.endsWith(".partial") || path.endsWith(".tmp")
4105
4642
  );
4106
4643
  return broken.length === 0 ? pass("No broken scaffold state", "No partial scaffold artifacts detected") : fail(
@@ -4114,7 +4651,7 @@ var HealthChecker = class {
4114
4651
  return pass("UI docs present", "UI docs are checked after documentation generation");
4115
4652
  }
4116
4653
  const missing = modules.filter(
4117
- (moduleName) => !existsSync10(join20(projectRoot, "docs/modules", moduleName, "ui/screens.md")) || !existsSync10(join20(projectRoot, "docs/modules", moduleName, "ui/components.md")) || !existsSync10(join20(projectRoot, "docs/modules", moduleName, "ui/states.md"))
4654
+ (moduleName) => !existsSync10(join22(projectRoot, "docs/modules", moduleName, "ui/screens.md")) || !existsSync10(join22(projectRoot, "docs/modules", moduleName, "ui/components.md")) || !existsSync10(join22(projectRoot, "docs/modules", moduleName, "ui/states.md"))
4118
4655
  );
4119
4656
  return missing.length === 0 ? pass("UI docs present", "UI docs are present for all modules with UI docs") : fail(
4120
4657
  "UI docs present",
@@ -4127,7 +4664,7 @@ var HealthChecker = class {
4127
4664
  return pass("API docs present", "API docs are checked after documentation generation");
4128
4665
  }
4129
4666
  const missing = modules.filter(
4130
- (moduleName) => !existsSync10(join20(projectRoot, "docs/modules", moduleName, "api/endpoints.md")) || !existsSync10(join20(projectRoot, "docs/modules", moduleName, "api/schemas.md")) || !existsSync10(join20(projectRoot, "docs/modules", moduleName, "api/error-codes.md"))
4667
+ (moduleName) => !existsSync10(join22(projectRoot, "docs/modules", moduleName, "api/endpoints.md")) || !existsSync10(join22(projectRoot, "docs/modules", moduleName, "api/schemas.md")) || !existsSync10(join22(projectRoot, "docs/modules", moduleName, "api/error-codes.md"))
4131
4668
  );
4132
4669
  return missing.length === 0 ? pass("API docs present", "API docs are present for all modules with APIs") : fail(
4133
4670
  "API docs present",
@@ -4143,7 +4680,7 @@ var HealthChecker = class {
4143
4680
  );
4144
4681
  }
4145
4682
  const missing = modules.filter(
4146
- (moduleName) => !existsSync10(join20(projectRoot, "docs/modules", moduleName, "integration/events.md")) || !existsSync10(join20(projectRoot, "docs/modules", moduleName, "integration/contracts.md"))
4683
+ (moduleName) => !existsSync10(join22(projectRoot, "docs/modules", moduleName, "integration/events.md")) || !existsSync10(join22(projectRoot, "docs/modules", moduleName, "integration/contracts.md"))
4147
4684
  );
4148
4685
  return missing.length === 0 ? pass("Integration docs present", "Integration docs are present for all modules") : fail(
4149
4686
  "Integration docs present",
@@ -4159,7 +4696,7 @@ var HealthChecker = class {
4159
4696
  );
4160
4697
  }
4161
4698
  const missing = modules.filter(
4162
- (moduleName) => !existsSync10(join20(projectRoot, "docs/modules", moduleName, "error-catalog.md"))
4699
+ (moduleName) => !existsSync10(join22(projectRoot, "docs/modules", moduleName, "error-catalog.md"))
4163
4700
  );
4164
4701
  return missing.length === 0 ? pass("Error catalog present", "Error catalogs are present for all modules") : fail(
4165
4702
  "Error catalog present",
@@ -4176,7 +4713,7 @@ var HealthChecker = class {
4176
4713
  );
4177
4714
  }
4178
4715
  const candidates = [".claude/settings.mcp.json", ".codex/mcp.json", ".gemini/mcp.json"];
4179
- const existing = candidates.filter((candidate) => existsSync10(join20(projectRoot, candidate)));
4716
+ const existing = candidates.filter((candidate) => existsSync10(join22(projectRoot, candidate)));
4180
4717
  const expectedServers = getServersForStack(
4181
4718
  getPrimaryStack(profile),
4182
4719
  getLegacyCapabilities(profile)
@@ -4191,7 +4728,7 @@ var HealthChecker = class {
4191
4728
  const configured = /* @__PURE__ */ new Set();
4192
4729
  for (const path of existing) {
4193
4730
  try {
4194
- const parsed = JSON.parse(readFileSync10(join20(projectRoot, path), "utf8"));
4731
+ const parsed = JSON.parse(readFileSync10(join22(projectRoot, path), "utf8"));
4195
4732
  Object.keys(parsed.mcpServers ?? {}).forEach((server) => configured.add(server));
4196
4733
  } catch {
4197
4734
  continue;
@@ -4205,7 +4742,7 @@ var HealthChecker = class {
4205
4742
  );
4206
4743
  }
4207
4744
  checkSkillCache(projectRoot) {
4208
- const cacheDir = join20(projectRoot, PATHS.SKILL_CACHE_DIR);
4745
+ const cacheDir = join22(projectRoot, PATHS.SKILL_CACHE_DIR);
4209
4746
  if (!existsSync10(cacheDir)) {
4210
4747
  return warn(
4211
4748
  "Skill cache healthy",
@@ -4215,7 +4752,7 @@ var HealthChecker = class {
4215
4752
  }
4216
4753
  const corrupt = readdirSync2(cacheDir).filter((entry) => entry.endsWith(".json")).filter((entry) => {
4217
4754
  try {
4218
- JSON.parse(readFileSync10(join20(cacheDir, entry), "utf8"));
4755
+ JSON.parse(readFileSync10(join22(cacheDir, entry), "utf8"));
4219
4756
  return false;
4220
4757
  } catch {
4221
4758
  return true;
@@ -4228,7 +4765,7 @@ var HealthChecker = class {
4228
4765
  );
4229
4766
  }
4230
4767
  checkContextHitRate(projectRoot, profile) {
4231
- const path = join20(projectRoot, PATHS.CONTEXT_HIT_LOG);
4768
+ const path = join22(projectRoot, PATHS.CONTEXT_HIT_LOG);
4232
4769
  if (!existsSync10(path) || profile === null) {
4233
4770
  return pass("Context hit rate acceptable", "No recent context logs yet");
4234
4771
  }
@@ -4250,7 +4787,7 @@ var HealthChecker = class {
4250
4787
  }
4251
4788
  }
4252
4789
  buildEfficiencySummary(projectRoot, profile) {
4253
- const path = join20(projectRoot, PATHS.CONTEXT_HIT_LOG);
4790
+ const path = join22(projectRoot, PATHS.CONTEXT_HIT_LOG);
4254
4791
  let contextHitRate = 1;
4255
4792
  if (existsSync10(path)) {
4256
4793
  try {
@@ -4262,12 +4799,12 @@ var HealthChecker = class {
4262
4799
  }
4263
4800
  return {
4264
4801
  context_hit_rate: contextHitRate,
4265
- skill_cache_hit_rate: existsSync10(join20(projectRoot, PATHS.SKILL_CACHE_DIR)) ? 1 : 0,
4802
+ skill_cache_hit_rate: existsSync10(join22(projectRoot, PATHS.SKILL_CACHE_DIR)) ? 1 : 0,
4266
4803
  mcp_usage_rate: profile?.efficiency?.mcp_first ? 1 : 0
4267
4804
  };
4268
4805
  }
4269
4806
  documentationHasRun(projectRoot) {
4270
- return existsSync10(join20(projectRoot, PATHS.DOC_PROGRESS));
4807
+ return existsSync10(join22(projectRoot, PATHS.DOC_PROGRESS));
4271
4808
  }
4272
4809
  };
4273
4810
  function pass(name, detail) {
@@ -4291,12 +4828,12 @@ function deriveOverallStatus(checks) {
4291
4828
  function isStale(timestampMs) {
4292
4829
  return Date.now() - timestampMs > STALENESS_WINDOW_MS;
4293
4830
  }
4294
- function walk(root) {
4831
+ function walk2(root) {
4295
4832
  const results = [];
4296
4833
  for (const entry of readdirSync2(root, { withFileTypes: true })) {
4297
- const path = join20(root, entry.name);
4834
+ const path = join22(root, entry.name);
4298
4835
  if (entry.isDirectory()) {
4299
- results.push(...walk(path));
4836
+ results.push(...walk2(path));
4300
4837
  continue;
4301
4838
  }
4302
4839
  results.push(path);
@@ -4311,35 +4848,35 @@ import { dirname as dirname12 } from "path";
4311
4848
  // src/onboarding/manifest-writer.ts
4312
4849
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
4313
4850
  import { homedir } from "os";
4314
- import { dirname as dirname11, join as join21 } from "path";
4851
+ import { dirname as dirname11, join as join23 } from "path";
4315
4852
  function writeProjectProfile2(projectRoot, profile) {
4316
4853
  return writeProjectProfile(projectRoot, profile);
4317
4854
  }
4318
4855
  function writeDetectionReport(projectRoot, report) {
4319
- const path = join21(projectRoot, PATHS.DETECTION_REPORT);
4856
+ const path = join23(projectRoot, PATHS.DETECTION_REPORT);
4320
4857
  mkdirSync2(dirname11(path), { recursive: true });
4321
4858
  writeFileSync2(path, JSON.stringify(report, null, 2));
4322
4859
  return path;
4323
4860
  }
4324
4861
  function writeFrameworkMetadata(projectRoot, version) {
4325
- mkdirSync2(dirname11(join21(projectRoot, PATHS.FRAMEWORK_VERSION)), {
4862
+ mkdirSync2(dirname11(join23(projectRoot, PATHS.FRAMEWORK_VERSION)), {
4326
4863
  recursive: true
4327
4864
  });
4328
4865
  const content = `version=${version}
4329
4866
  updated_at=${(/* @__PURE__ */ new Date()).toISOString()}
4330
4867
  `;
4331
- writeFileSync2(join21(projectRoot, PATHS.FRAMEWORK_VERSION), content);
4332
- writeFileSync2(join21(projectRoot, PATHS.FRAMEWORK_PATH), `${resolveFrameworkInstallPath()}
4868
+ writeFileSync2(join23(projectRoot, PATHS.FRAMEWORK_VERSION), content);
4869
+ writeFileSync2(join23(projectRoot, PATHS.FRAMEWORK_PATH), `${resolveFrameworkInstallPath()}
4333
4870
  `);
4334
4871
  }
4335
4872
  function writeOnboardingManifest(projectRoot, manifest) {
4336
- const path = join21(projectRoot, PATHS.ONBOARDING_MANIFEST);
4873
+ const path = join23(projectRoot, PATHS.ONBOARDING_MANIFEST);
4337
4874
  mkdirSync2(dirname11(path), { recursive: true });
4338
4875
  writeFileSync2(path, JSON.stringify(manifest, null, 2));
4339
4876
  return path;
4340
4877
  }
4341
4878
  function resolveFrameworkInstallPath() {
4342
- return process.env.PAQAD_FRAMEWORK_HOME ?? join21(homedir(), ".paqad-ai/current");
4879
+ return process.env.PAQAD_FRAMEWORK_HOME ?? join23(homedir(), ".paqad-ai/current");
4343
4880
  }
4344
4881
 
4345
4882
  // src/install/bootstrap.ts
@@ -4384,23 +4921,23 @@ function isExpectedRuntimeSymlink(runtimeRoot, frameworkHome) {
4384
4921
  }
4385
4922
 
4386
4923
  // src/document/workflow.ts
4387
- import { mkdir as mkdir10, readFile as readFile12, readdir as readdir2, writeFile as writeFile10 } from "fs/promises";
4388
- import { dirname as dirname14, join as join26, relative } from "path";
4924
+ import { mkdir as mkdir10, readFile as readFile12, readdir as readdir3, writeFile as writeFile10 } from "fs/promises";
4925
+ import { dirname as dirname14, join as join28, relative } from "path";
4389
4926
 
4390
4927
  // src/onboarding/registry-generator.ts
4391
- import { readdir } from "fs/promises";
4392
- import { join as join22 } from "path";
4928
+ import { readdir as readdir2 } from "fs/promises";
4929
+ import { join as join24 } from "path";
4393
4930
  async function discoverModules(projectRoot) {
4394
4931
  const candidates = [
4395
- join22(projectRoot, "docs/modules"),
4396
- join22(projectRoot, "app"),
4397
- join22(projectRoot, "lib"),
4398
- join22(projectRoot, "src")
4932
+ join24(projectRoot, "docs/modules"),
4933
+ join24(projectRoot, "app"),
4934
+ join24(projectRoot, "lib"),
4935
+ join24(projectRoot, "src")
4399
4936
  ];
4400
4937
  const modules = /* @__PURE__ */ new Set(["core"]);
4401
4938
  for (const root of candidates) {
4402
4939
  try {
4403
- const entries = await readdir(root, { withFileTypes: true });
4940
+ const entries = await readdir2(root, { withFileTypes: true });
4404
4941
  for (const entry of entries) {
4405
4942
  if (!entry.isDirectory()) {
4406
4943
  continue;
@@ -4419,36 +4956,36 @@ async function discoverModules(projectRoot) {
4419
4956
 
4420
4957
  // src/stack-docs/generator.ts
4421
4958
  import { mkdir as mkdir8, readFile as readFile9, writeFile as writeFile8 } from "fs/promises";
4422
- import { join as join23 } from "path";
4959
+ import { join as join25 } from "path";
4423
4960
  async function writeStackArtifacts(projectRoot, snapshot, previousSnapshot, options = {}) {
4424
4961
  const existingDrift = await readExistingDrift(projectRoot);
4425
4962
  const computedDrift = compareStackProfiles(previousSnapshot?.profile ?? null, snapshot.profile);
4426
4963
  const drift = computedDrift.status === "no-drift" && existingDrift !== null ? existingDrift : computedDrift;
4427
4964
  await writeFile8(
4428
- join23(projectRoot, PATHS.STACK_SNAPSHOT),
4965
+ join25(projectRoot, PATHS.STACK_SNAPSHOT),
4429
4966
  `${JSON.stringify(snapshot, null, 2)}
4430
4967
  `
4431
4968
  );
4432
- await writeFile8(join23(projectRoot, PATHS.STACK_DRIFT), `${JSON.stringify(drift, null, 2)}
4969
+ await writeFile8(join25(projectRoot, PATHS.STACK_DRIFT), `${JSON.stringify(drift, null, 2)}
4433
4970
  `);
4434
4971
  if (!options.writeHumanDocs) {
4435
4972
  return drift;
4436
4973
  }
4437
- await mkdir8(join23(projectRoot, PATHS.FRAMEWORK_STACK_DIR), { recursive: true });
4438
- const stackDir = join23(projectRoot, PATHS.FRAMEWORK_STACK_DIR);
4439
- await writeFile8(join23(stackDir, "overview.md"), await buildOverview(projectRoot, snapshot, drift));
4440
- await writeFile8(join23(stackDir, "frameworks.md"), await buildFrameworks(projectRoot, snapshot));
4441
- await writeFile8(join23(stackDir, "dependencies.md"), buildDependencies(snapshot));
4442
- await writeFile8(join23(stackDir, "tooling.md"), buildTooling(snapshot));
4443
- await writeFile8(join23(stackDir, "version-rules.md"), buildVersionRules(snapshot, drift));
4444
- await writeFile8(join23(stackDir, "sources.md"), buildSources(snapshot));
4445
- await writeFile8(join23(stackDir, "drift-report.md"), buildDriftReport(drift));
4974
+ await mkdir8(join25(projectRoot, PATHS.FRAMEWORK_STACK_DIR), { recursive: true });
4975
+ const stackDir = join25(projectRoot, PATHS.FRAMEWORK_STACK_DIR);
4976
+ await writeFile8(join25(stackDir, "overview.md"), await buildOverview(projectRoot, snapshot, drift));
4977
+ await writeFile8(join25(stackDir, "frameworks.md"), await buildFrameworks(projectRoot, snapshot));
4978
+ await writeFile8(join25(stackDir, "dependencies.md"), buildDependencies(snapshot));
4979
+ await writeFile8(join25(stackDir, "tooling.md"), buildTooling(snapshot));
4980
+ await writeFile8(join25(stackDir, "version-rules.md"), buildVersionRules(snapshot, drift));
4981
+ await writeFile8(join25(stackDir, "sources.md"), buildSources(snapshot));
4982
+ await writeFile8(join25(stackDir, "drift-report.md"), buildDriftReport(drift));
4446
4983
  return drift;
4447
4984
  }
4448
4985
  async function readExistingDrift(projectRoot) {
4449
4986
  try {
4450
4987
  return JSON.parse(
4451
- await readFile9(join23(projectRoot, PATHS.STACK_DRIFT), "utf8")
4988
+ await readFile9(join25(projectRoot, PATHS.STACK_DRIFT), "utf8")
4452
4989
  );
4453
4990
  } catch {
4454
4991
  return null;
@@ -4611,7 +5148,7 @@ async function readTemplate(packRoot, templatePath) {
4611
5148
  return null;
4612
5149
  }
4613
5150
  try {
4614
- return await readFile9(join23(packRoot, templatePath), "utf8");
5151
+ return await readFile9(join25(packRoot, templatePath), "utf8");
4615
5152
  } catch {
4616
5153
  return null;
4617
5154
  }
@@ -4619,7 +5156,7 @@ async function readTemplate(packRoot, templatePath) {
4619
5156
 
4620
5157
  // src/document/progress-tracker.ts
4621
5158
  import { mkdir as mkdir9, readFile as readFile10, rm, writeFile as writeFile9 } from "fs/promises";
4622
- import { dirname as dirname13, join as join24 } from "path";
5159
+ import { dirname as dirname13, join as join26 } from "path";
4623
5160
  var DocumentProgressTracker = class {
4624
5161
  constructor(validator = new SchemaValidator()) {
4625
5162
  this.validator = validator;
@@ -4627,7 +5164,7 @@ var DocumentProgressTracker = class {
4627
5164
  async load(projectRoot) {
4628
5165
  try {
4629
5166
  const parsed = JSON.parse(
4630
- await readFile10(join24(projectRoot, PATHS.DOC_PROGRESS), "utf8")
5167
+ await readFile10(join26(projectRoot, PATHS.DOC_PROGRESS), "utf8")
4631
5168
  );
4632
5169
  const validation = this.validator.validate("doc-progress", parsed);
4633
5170
  if (!validation.valid) {
@@ -4639,7 +5176,7 @@ var DocumentProgressTracker = class {
4639
5176
  }
4640
5177
  }
4641
5178
  async save(projectRoot, progress) {
4642
- const target = join24(projectRoot, PATHS.DOC_PROGRESS);
5179
+ const target = join26(projectRoot, PATHS.DOC_PROGRESS);
4643
5180
  await mkdir9(dirname13(target), { recursive: true });
4644
5181
  await writeFile9(target, `${JSON.stringify(progress, null, 2)}
4645
5182
  `);
@@ -4647,7 +5184,7 @@ var DocumentProgressTracker = class {
4647
5184
  async resetGeneratingEntries(projectRoot, progress) {
4648
5185
  await Promise.all(
4649
5186
  resetGeneratingEntries(progress).map(
4650
- (entry) => rm(join24(projectRoot, entry.output_path), { force: true })
5187
+ (entry) => rm(join26(projectRoot, entry.output_path), { force: true })
4651
5188
  )
4652
5189
  );
4653
5190
  }
@@ -4697,12 +5234,12 @@ function collectEntries(progress) {
4697
5234
  // src/document/staleness.ts
4698
5235
  import { createHash as createHash6 } from "crypto";
4699
5236
  import { readFile as readFile11 } from "fs/promises";
4700
- import { join as join25 } from "path";
5237
+ import { join as join27 } from "path";
4701
5238
  async function hashSourceFiles(projectRoot, sourceFiles) {
4702
5239
  const hash = createHash6("sha1");
4703
5240
  for (const relativePath of sourceFiles) {
4704
5241
  try {
4705
- hash.update(await readFile11(join25(projectRoot, relativePath), "utf8"));
5242
+ hash.update(await readFile11(join27(projectRoot, relativePath), "utf8"));
4706
5243
  } catch {
4707
5244
  hash.update(`missing:${relativePath}`);
4708
5245
  }
@@ -4760,7 +5297,11 @@ var DocumentationWorkflow = class {
4760
5297
  routing,
4761
5298
  stackSnapshot
4762
5299
  );
4763
- const sourceFiles = await gatherSourceFiles(options.projectRoot, routing.stack);
5300
+ const sourceFiles = await gatherSourceFiles(
5301
+ options.projectRoot,
5302
+ routing.stack,
5303
+ stackSnapshot.repository
5304
+ );
4764
5305
  const modules = await discoverModules(options.projectRoot);
4765
5306
  const generated = [];
4766
5307
  const skipped = [];
@@ -4778,13 +5319,13 @@ var DocumentationWorkflow = class {
4778
5319
  { writeHumanDocs: true }
4779
5320
  );
4780
5321
  const stackDocs = [
4781
- join26(PATHS.FRAMEWORK_STACK_DIR, "overview.md"),
4782
- join26(PATHS.FRAMEWORK_STACK_DIR, "frameworks.md"),
4783
- join26(PATHS.FRAMEWORK_STACK_DIR, "dependencies.md"),
4784
- join26(PATHS.FRAMEWORK_STACK_DIR, "tooling.md"),
4785
- join26(PATHS.FRAMEWORK_STACK_DIR, "version-rules.md"),
4786
- join26(PATHS.FRAMEWORK_STACK_DIR, "sources.md"),
4787
- join26(PATHS.FRAMEWORK_STACK_DIR, "drift-report.md")
5322
+ join28(PATHS.FRAMEWORK_STACK_DIR, "overview.md"),
5323
+ join28(PATHS.FRAMEWORK_STACK_DIR, "frameworks.md"),
5324
+ join28(PATHS.FRAMEWORK_STACK_DIR, "dependencies.md"),
5325
+ join28(PATHS.FRAMEWORK_STACK_DIR, "tooling.md"),
5326
+ join28(PATHS.FRAMEWORK_STACK_DIR, "version-rules.md"),
5327
+ join28(PATHS.FRAMEWORK_STACK_DIR, "sources.md"),
5328
+ join28(PATHS.FRAMEWORK_STACK_DIR, "drift-report.md")
4788
5329
  ];
4789
5330
  generated.push(...stackDocs);
4790
5331
  steps.push({
@@ -4803,8 +5344,8 @@ var DocumentationWorkflow = class {
4803
5344
  stackSnapshot,
4804
5345
  profile
4805
5346
  });
4806
- await mkdir10(dirname14(join26(options.projectRoot, contentOutputPath)), { recursive: true });
4807
- await writeFile10(join26(options.projectRoot, contentOutputPath), contentBody);
5347
+ await mkdir10(dirname14(join28(options.projectRoot, contentOutputPath)), { recursive: true });
5348
+ await writeFile10(join28(options.projectRoot, contentOutputPath), contentBody);
4808
5349
  generated.push(contentOutputPath);
4809
5350
  steps.push({
4810
5351
  id: "content-deliverable",
@@ -4827,7 +5368,7 @@ var DocumentationWorkflow = class {
4827
5368
  await processEntry({
4828
5369
  projectRoot: options.projectRoot,
4829
5370
  entry: progress.global.designSystem.designTokens,
4830
- content: await readFile12(join26(options.projectRoot, PATHS.DESIGN_TOKENS_FILE), "utf8"),
5371
+ content: await readFile12(join28(options.projectRoot, PATHS.DESIGN_TOKENS_FILE), "utf8"),
4831
5372
  generated: designSystemGenerated,
4832
5373
  skipped: designSystemSkipped
4833
5374
  });
@@ -4846,8 +5387,8 @@ var DocumentationWorkflow = class {
4846
5387
  }
4847
5388
  await Promise.all(
4848
5389
  themeArtifacts.map(async (artifact) => {
4849
- await mkdir10(dirname14(join26(options.projectRoot, artifact.path)), { recursive: true });
4850
- await writeFile10(join26(options.projectRoot, artifact.path), artifact.content);
5390
+ await mkdir10(dirname14(join28(options.projectRoot, artifact.path)), { recursive: true });
5391
+ await writeFile10(join28(options.projectRoot, artifact.path), artifact.content);
4851
5392
  designSystemGenerated.push(artifact.path);
4852
5393
  })
4853
5394
  );
@@ -4861,15 +5402,15 @@ var DocumentationWorkflow = class {
4861
5402
  });
4862
5403
  progress.global.architecture ??= {};
4863
5404
  progress.global.architecture.overview ??= this.tracker.createEntry(
4864
- join26(PATHS.ARCHITECTURE_DIR, "overview.md"),
5405
+ join28(PATHS.ARCHITECTURE_DIR, "overview.md"),
4865
5406
  sourceFiles
4866
5407
  );
4867
5408
  progress.global.architecture.decisions ??= this.tracker.createEntry(
4868
- join26(PATHS.ARCHITECTURE_DIR, "decisions.md"),
5409
+ join28(PATHS.ARCHITECTURE_DIR, "decisions.md"),
4869
5410
  sourceFiles
4870
5411
  );
4871
5412
  progress.global.architecture.patterns ??= this.tracker.createEntry(
4872
- join26(PATHS.ARCHITECTURE_DIR, "patterns.md"),
5413
+ join28(PATHS.ARCHITECTURE_DIR, "patterns.md"),
4873
5414
  sourceFiles
4874
5415
  );
4875
5416
  const architectureGenerated = [];
@@ -4907,7 +5448,7 @@ var DocumentationWorkflow = class {
4907
5448
  const registrySkipped = [];
4908
5449
  progress.global.registries ??= {};
4909
5450
  for (const registry of REGISTRIES) {
4910
- const path = join26(PATHS.REGISTRIES_DIR, registry);
5451
+ const path = join28(PATHS.REGISTRIES_DIR, registry);
4911
5452
  progress.global.registries[registry] ??= this.tracker.createEntry(path, sourceFiles);
4912
5453
  await processEntry({
4913
5454
  projectRoot: options.projectRoot,
@@ -4927,12 +5468,12 @@ var DocumentationWorkflow = class {
4927
5468
  });
4928
5469
  progress.global.benchmarks ??= {};
4929
5470
  progress.global.benchmarks.index ??= this.tracker.createEntry(
4930
- join26(PATHS.BENCHMARKS_DIR, "index.md"),
5471
+ join28(PATHS.BENCHMARKS_DIR, "index.md"),
4931
5472
  sourceFiles
4932
5473
  );
4933
5474
  progress.global.techDebt ??= {};
4934
5475
  progress.global.techDebt.index ??= this.tracker.createEntry(
4935
- join26(PATHS.TECH_DEBT_DIR, "index.md"),
5476
+ join28(PATHS.TECH_DEBT_DIR, "index.md"),
4936
5477
  sourceFiles
4937
5478
  );
4938
5479
  const maintenanceGenerated = [];
@@ -4972,7 +5513,7 @@ var DocumentationWorkflow = class {
4972
5513
  );
4973
5514
  for (const feature of features) {
4974
5515
  for (const definition of FEATURE_DOCS) {
4975
- const path = join26(
5516
+ const path = join28(
4976
5517
  PATHS.MODULES_DIR,
4977
5518
  moduleName,
4978
5519
  PATHS.MODULE_FEATURES_DIR,
@@ -5005,7 +5546,7 @@ var DocumentationWorkflow = class {
5005
5546
  }
5006
5547
  }
5007
5548
  for (const definition of MODULE_DOCS) {
5008
- const path = join26(PATHS.MODULES_DIR, moduleName, definition.outputPath);
5549
+ const path = join28(PATHS.MODULES_DIR, moduleName, definition.outputPath);
5009
5550
  progress.modules[moduleName][definition.key] ??= this.tracker.createEntry(
5010
5551
  path,
5011
5552
  moduleFiles
@@ -5037,7 +5578,7 @@ var DocumentationWorkflow = class {
5037
5578
  }
5038
5579
  progress.global.handover ??= {};
5039
5580
  progress.global.handover.summary ??= this.tracker.createEntry(
5040
- join26(".paqad/handover", "product-summary.md"),
5581
+ join28(".paqad/handover", "product-summary.md"),
5041
5582
  sourceFiles
5042
5583
  );
5043
5584
  const handoverGenerated = [];
@@ -5062,7 +5603,7 @@ var DocumentationWorkflow = class {
5062
5603
  generated,
5063
5604
  skipped,
5064
5605
  progress_path: PATHS.DOC_PROGRESS,
5065
- handover_path: join26(".paqad/handover", "product-summary.md"),
5606
+ handover_path: join28(".paqad/handover", "product-summary.md"),
5066
5607
  stack_snapshot: stackSnapshot,
5067
5608
  effective_routing: routing,
5068
5609
  profile_updated: profileUpdated,
@@ -5093,7 +5634,8 @@ async function syncOnboardingState(projectRoot, profile, detection, routing, sta
5093
5634
  if (manifest !== null) {
5094
5635
  writeOnboardingManifest(projectRoot, {
5095
5636
  ...manifest,
5096
- profile: updatedProfile
5637
+ profile: updatedProfile,
5638
+ repository: detection.repository ?? stackSnapshot.repository
5097
5639
  });
5098
5640
  }
5099
5641
  return true;
@@ -5133,8 +5675,8 @@ async function processEntry(input) {
5133
5675
  input.entry.state = "generating";
5134
5676
  input.entry.started_at = (/* @__PURE__ */ new Date()).toISOString();
5135
5677
  input.entry.error = null;
5136
- await mkdir10(dirname14(join26(input.projectRoot, input.entry.output_path)), { recursive: true });
5137
- await writeFile10(join26(input.projectRoot, input.entry.output_path), input.content);
5678
+ await mkdir10(dirname14(join28(input.projectRoot, input.entry.output_path)), { recursive: true });
5679
+ await writeFile10(join28(input.projectRoot, input.entry.output_path), input.content);
5138
5680
  input.generated.push(input.entry.output_path);
5139
5681
  input.entry.state = "done";
5140
5682
  input.entry.completed_at = (/* @__PURE__ */ new Date()).toISOString();
@@ -5153,8 +5695,8 @@ async function processEntry(input) {
5153
5695
  }
5154
5696
  return { generated: [input.entry.output_path], skipped: [] };
5155
5697
  }
5156
- async function gatherSourceFiles(projectRoot, stack) {
5157
- const roots = stack === "flutter" ? ["lib", "test", "web", "assets", "pubspec.yaml"] : stack === "short-video" ? ["src", "content", "scripts", "package.json"] : [
5698
+ async function gatherSourceFiles(projectRoot, stack, repository) {
5699
+ const roots = repository?.projects.length ? repository.projects.map((project) => project.root) : stack === "flutter" ? ["lib", "test", "web", "assets", "pubspec.yaml"] : stack === "short-video" ? ["src", "content", "scripts", "package.json"] : [
5158
5700
  "app",
5159
5701
  "routes",
5160
5702
  "config",
@@ -5183,7 +5725,7 @@ async function gatherSourceFiles(projectRoot, stack) {
5183
5725
  const results = /* @__PURE__ */ new Set();
5184
5726
  for (const root of roots) {
5185
5727
  try {
5186
- for (const file of await walk2(join26(projectRoot, root))) {
5728
+ for (const file of await walk3(join28(projectRoot, root))) {
5187
5729
  results.add(relative(projectRoot, file));
5188
5730
  }
5189
5731
  } catch {
@@ -5200,7 +5742,7 @@ async function gatherSourceFiles(projectRoot, stack) {
5200
5742
  }
5201
5743
  async function buildContentDeliverable(input) {
5202
5744
  const styleGuide = await readOptionalFile(
5203
- join26(input.projectRoot, "docs/instructions/rules/writing-style.md")
5745
+ join28(input.projectRoot, "docs/instructions/rules/writing-style.md")
5204
5746
  );
5205
5747
  const codingContext = input.profile.active_capabilities.includes("coding") && input.stackSnapshot.profile.frameworks.length > 0 ? [
5206
5748
  "## Technical Context",
@@ -5248,19 +5790,36 @@ async function readOptionalFile(path) {
5248
5790
  }
5249
5791
  }
5250
5792
  function defaultContentOutputPath(requestText) {
5251
- return join26("content", `${slugify(requestText)}.md`);
5793
+ return join28("content", `${slugify(requestText)}.md`);
5252
5794
  }
5253
5795
  function slugify(requestText) {
5254
5796
  const slug = requestText.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
5255
5797
  return slug.length > 0 ? slug : "content-draft";
5256
5798
  }
5257
- async function walk2(root) {
5258
- const entries = await readdir2(root, { withFileTypes: true });
5799
+ async function walk3(root) {
5800
+ const entries = await readdir3(root, { withFileTypes: true });
5259
5801
  const files = [];
5260
5802
  for (const entry of entries) {
5261
- const target = join26(root, entry.name);
5803
+ const target = join28(root, entry.name);
5262
5804
  if (entry.isDirectory()) {
5263
- files.push(...await walk2(target));
5805
+ if ([
5806
+ ".dart_tool",
5807
+ ".git",
5808
+ ".gradle",
5809
+ ".next",
5810
+ ".nuxt",
5811
+ ".turbo",
5812
+ "build",
5813
+ "coverage",
5814
+ "dist",
5815
+ "node_modules",
5816
+ "out",
5817
+ "target",
5818
+ "vendor"
5819
+ ].includes(entry.name)) {
5820
+ continue;
5821
+ }
5822
+ files.push(...await walk3(target));
5264
5823
  continue;
5265
5824
  }
5266
5825
  files.push(target);
@@ -5301,8 +5860,8 @@ async function discoverFeaturesForModule(projectRoot, moduleName, moduleFiles) {
5301
5860
  }
5302
5861
  async function readExistingFeatures(projectRoot, moduleName) {
5303
5862
  try {
5304
- const root = join26(projectRoot, PATHS.MODULES_DIR, moduleName, PATHS.MODULE_FEATURES_DIR);
5305
- const entries = await readdir2(root, { withFileTypes: true });
5863
+ const root = join28(projectRoot, PATHS.MODULES_DIR, moduleName, PATHS.MODULE_FEATURES_DIR);
5864
+ const entries = await readdir3(root, { withFileTypes: true });
5306
5865
  return entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name).sort();
5307
5866
  } catch {
5308
5867
  return [];
@@ -5321,7 +5880,7 @@ function loadProjectProfile(projectRoot) {
5321
5880
  async function readOnboardingManifest(projectRoot) {
5322
5881
  try {
5323
5882
  return JSON.parse(
5324
- await readFile12(join26(projectRoot, PATHS.ONBOARDING_MANIFEST), "utf8")
5883
+ await readFile12(join28(projectRoot, PATHS.ONBOARDING_MANIFEST), "utf8")
5325
5884
  );
5326
5885
  } catch {
5327
5886
  return null;
@@ -5712,12 +6271,12 @@ function basenameWithoutExtension(path) {
5712
6271
 
5713
6272
  // src/onboarding/file-writer.ts
5714
6273
  import { chmodSync, existsSync as existsSync12, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
5715
- import { dirname as dirname15, join as join27 } from "path";
6274
+ import { dirname as dirname15, join as join29 } from "path";
5716
6275
  function writeGeneratedFiles(projectRoot, files) {
5717
6276
  const written = [];
5718
6277
  const skipped = [];
5719
6278
  for (const file of files) {
5720
- const target = join27(projectRoot, file.path);
6279
+ const target = join29(projectRoot, file.path);
5721
6280
  mkdirSync4(dirname15(target), { recursive: true });
5722
6281
  if (!file.autoUpdate && existsSync12(target)) {
5723
6282
  skipped.push(file.path);
@@ -5732,13 +6291,190 @@ function writeGeneratedFiles(projectRoot, files) {
5732
6291
  return { written, skipped };
5733
6292
  }
5734
6293
 
6294
+ // src/pipeline/feature-development-policy.ts
6295
+ import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
6296
+ import { join as join30 } from "path";
6297
+ import YAML5 from "yaml";
6298
+ function resolveFeatureDevelopmentCheckCommands(checks, profile) {
6299
+ if (checks === null) {
6300
+ return { commands: [], warnings: [] };
6301
+ }
6302
+ const commands = [];
6303
+ const warnings = [];
6304
+ if (checks.use_project_profile_commands) {
6305
+ if (profile === null) {
6306
+ return { commands, warnings };
6307
+ }
6308
+ for (const logicalCommand of checks.commands) {
6309
+ const resolved = profile?.commands?.[logicalCommand];
6310
+ if (!resolved) {
6311
+ warnings.push(
6312
+ `Feature development policy requested project command "${logicalCommand}" but it was not found in ${PATHS.PROJECT_PROFILE}.`
6313
+ );
6314
+ continue;
6315
+ }
6316
+ commands.push({
6317
+ logical_command: logicalCommand,
6318
+ command: resolved,
6319
+ source: "project-profile"
6320
+ });
6321
+ }
6322
+ }
6323
+ for (const shellCommand of checks.shell_commands) {
6324
+ commands.push({
6325
+ logical_command: null,
6326
+ command: shellCommand,
6327
+ source: "policy"
6328
+ });
6329
+ }
6330
+ return { commands, warnings };
6331
+ }
6332
+ function renderDefaultFeatureDevelopmentPolicyYaml() {
6333
+ return `# Feature Development Stage Policy
6334
+ # This file customizes how the built-in feature-development workflow behaves in this project.
6335
+ # The framework still owns routing, phase order, and mandatory safety stages.
6336
+ schema_version: "1"
6337
+ merge_mode: append
6338
+
6339
+ stages:
6340
+ planning:
6341
+ # Extra context to load before planning starts.
6342
+ read:
6343
+ - docs/modules/**
6344
+ - docs/instructions/**
6345
+ instructions:
6346
+ - Review the canonical module and instruction docs before planning the change.
6347
+ - Keep planning scoped to the requested feature and the current repository state.
6348
+ required_inputs:
6349
+ - active request
6350
+ - canonical docs
6351
+ strictness:
6352
+ require_docs_context: true
6353
+ escalation:
6354
+ missing_docs_context: warn
6355
+ artifacts:
6356
+ - implementation sequence
6357
+
6358
+ specification:
6359
+ instructions:
6360
+ - Write or refine the feature specification before implementation when the lane includes specification.
6361
+ required_inputs:
6362
+ - approved spec boundary
6363
+ strictness:
6364
+ require_spec: true
6365
+ escalation:
6366
+ missing_spec: stop
6367
+ artifacts:
6368
+ - specification
6369
+
6370
+ development:
6371
+ instructions:
6372
+ - Implement only the requested feature behavior and avoid unrelated refactors.
6373
+ required_inputs:
6374
+ - approved spec
6375
+ - implementation sequence
6376
+ strictness:
6377
+ avoid_unrelated_refactors: true
6378
+ escalation:
6379
+ scope_expansion: ask
6380
+ artifacts:
6381
+ - code changes
6382
+
6383
+ review:
6384
+ instructions:
6385
+ - Review the change against correctness, regressions, and rollback risk before treating it as complete.
6386
+ required_inputs:
6387
+ - code diff
6388
+ - verification summary
6389
+ strictness:
6390
+ require_review: true
6391
+ escalation:
6392
+ review_findings: stop
6393
+ artifacts:
6394
+ - review summary
6395
+
6396
+ checks:
6397
+ instructions:
6398
+ - Run the project command checks after implementation and before finalizing the feature.
6399
+ required_inputs:
6400
+ - working tree diff
6401
+ strictness:
6402
+ block_on_failure: true
6403
+ escalation:
6404
+ missing_command_mapping: stop
6405
+ artifacts:
6406
+ - verification summary
6407
+ checks:
6408
+ use_project_profile_commands: true
6409
+ commands:
6410
+ - format
6411
+ - test
6412
+ - build
6413
+ shell_commands: []
6414
+ block_on_failure: true
6415
+ # Add project-specific commands here when needed.
6416
+ # shell_commands:
6417
+ # - pnpm typecheck
6418
+
6419
+ documentation_sync:
6420
+ instructions:
6421
+ - Sync canonical docs affected by the feature diff after verification passes.
6422
+ required_inputs:
6423
+ - changed files
6424
+ strictness:
6425
+ require_canonical_sync: true
6426
+ escalation:
6427
+ stale_docs: stop
6428
+ artifacts:
6429
+ - stale doc targets
6430
+ `;
6431
+ }
6432
+ function summarizeFeatureDevelopmentStage(policy, stageName) {
6433
+ if (policy === null) {
6434
+ return null;
6435
+ }
6436
+ const stage = policy.stages[stageName];
6437
+ const fragments = [];
6438
+ if (stage.read.length > 0) {
6439
+ fragments.push(`reads ${stage.read.length} path(s)`);
6440
+ }
6441
+ if (stage.instructions.length > 0) {
6442
+ fragments.push(`${stage.instructions.length} instruction(s)`);
6443
+ }
6444
+ if (stage.required_inputs.length > 0) {
6445
+ fragments.push(`${stage.required_inputs.length} required input(s)`);
6446
+ }
6447
+ if (stage.artifacts.length > 0) {
6448
+ fragments.push(`${stage.artifacts.length} expected artifact(s)`);
6449
+ }
6450
+ if (stage.checks !== null) {
6451
+ const checkCount = stage.checks.commands.length + stage.checks.shell_commands.length;
6452
+ fragments.push(`${checkCount} configured check(s)`);
6453
+ }
6454
+ return fragments.length > 0 ? fragments.join(", ") : null;
6455
+ }
6456
+
6457
+ // src/onboarding/feature-policy-generator.ts
6458
+ function generateFeatureDevelopmentPolicy(domain) {
6459
+ if (domain !== "coding") {
6460
+ return [];
6461
+ }
6462
+ return [
6463
+ {
6464
+ path: `${PATHS.WORKFLOWS_DIR}/feature-development.yaml`,
6465
+ content: renderDefaultFeatureDevelopmentPolicyYaml(),
6466
+ autoUpdate: false
6467
+ }
6468
+ ];
6469
+ }
6470
+
5735
6471
  // src/onboarding/orchestrator.ts
5736
- import { readFileSync as readFileSync12 } from "fs";
5737
- import { join as join33 } from "path";
6472
+ import { readFileSync as readFileSync13 } from "fs";
6473
+ import { join as join36 } from "path";
5738
6474
 
5739
6475
  // src/resolver/resolver.ts
5740
6476
  import fg2 from "fast-glob";
5741
- import { basename as basename3, extname, relative as relative3 } from "pathe";
6477
+ import { basename as basename4, extname, relative as relative3 } from "pathe";
5742
6478
 
5743
6479
  // src/resolver/artifact-types.ts
5744
6480
  var ARTIFACT_TYPES = [
@@ -5776,14 +6512,14 @@ var ARTIFACT_OUTPUT_KEYS = {
5776
6512
  };
5777
6513
 
5778
6514
  // src/resolver/inheritance.ts
5779
- import { join as join29, relative as relative2 } from "pathe";
6515
+ import { join as join32, relative as relative2 } from "pathe";
5780
6516
 
5781
6517
  // src/resolver/capability-resolver.ts
5782
- import { join as join28 } from "pathe";
6518
+ import { join as join31 } from "pathe";
5783
6519
  function resolveCapabilityDirectories(runtimeRoot, stack, capabilities, artifactType) {
5784
6520
  const directoryName = resolveCapabilityArtifactDirectory(artifactType);
5785
6521
  return capabilities.map(
5786
- (capability) => join28(
6522
+ (capability) => join31(
5787
6523
  runtimeRoot,
5788
6524
  "capabilities",
5789
6525
  "coding",
@@ -5800,9 +6536,9 @@ function resolveCapabilityArtifactDirectory(artifactType) {
5800
6536
  case "mcp-configs":
5801
6537
  return "mcp";
5802
6538
  case "patterns":
5803
- return join28("benchmarks", "patterns");
6539
+ return join31("benchmarks", "patterns");
5804
6540
  case "anti-patterns":
5805
- return join28("benchmarks", "anti-patterns");
6541
+ return join31("benchmarks", "anti-patterns");
5806
6542
  default:
5807
6543
  return artifactType;
5808
6544
  }
@@ -5813,18 +6549,18 @@ function getInheritanceDirectories(runtimeRoot, routing, artifactType) {
5813
6549
  if (artifactType === "hooks") {
5814
6550
  return [
5815
6551
  {
5816
- path: join29(runtimeRoot, "hooks"),
6552
+ path: join32(runtimeRoot, "hooks"),
5817
6553
  level: 0,
5818
- source: relative2(runtimeRoot, join29(runtimeRoot, "hooks"))
6554
+ source: relative2(runtimeRoot, join32(runtimeRoot, "hooks"))
5819
6555
  }
5820
6556
  ];
5821
6557
  }
5822
6558
  if (artifactType === "templates") {
5823
6559
  return [
5824
6560
  {
5825
- path: join29(runtimeRoot, "templates"),
6561
+ path: join32(runtimeRoot, "templates"),
5826
6562
  level: 0,
5827
- source: relative2(runtimeRoot, join29(runtimeRoot, "templates"))
6563
+ source: relative2(runtimeRoot, join32(runtimeRoot, "templates"))
5828
6564
  }
5829
6565
  ];
5830
6566
  }
@@ -5834,37 +6570,37 @@ function getInheritanceDirectories(runtimeRoot, routing, artifactType) {
5834
6570
  const traits = deriveTraits(routing);
5835
6571
  const directories = [
5836
6572
  {
5837
- path: join29(runtimeRoot, "base", directoryName),
6573
+ path: join32(runtimeRoot, "base", directoryName),
5838
6574
  level: 0,
5839
- source: relative2(runtimeRoot, join29(runtimeRoot, "base", directoryName))
6575
+ source: relative2(runtimeRoot, join32(runtimeRoot, "base", directoryName))
5840
6576
  },
5841
6577
  {
5842
- path: join29(runtimeRoot, "capabilities", "content", directoryName),
6578
+ path: join32(runtimeRoot, "capabilities", "content", directoryName),
5843
6579
  level: 1,
5844
- source: relative2(runtimeRoot, join29(runtimeRoot, "capabilities", "content", directoryName))
6580
+ source: relative2(runtimeRoot, join32(runtimeRoot, "capabilities", "content", directoryName))
5845
6581
  }
5846
6582
  ];
5847
6583
  if (activeCapabilities.includes("coding")) {
5848
6584
  directories.push(
5849
6585
  {
5850
- path: join29(runtimeRoot, "capabilities", "coding", directoryName),
6586
+ path: join32(runtimeRoot, "capabilities", "coding", directoryName),
5851
6587
  level: 2,
5852
- source: relative2(runtimeRoot, join29(runtimeRoot, "capabilities", "coding", directoryName))
6588
+ source: relative2(runtimeRoot, join32(runtimeRoot, "capabilities", "coding", directoryName))
5853
6589
  },
5854
6590
  {
5855
- path: join29(runtimeRoot, "capabilities", "coding", "stacks", "_shared", directoryName),
6591
+ path: join32(runtimeRoot, "capabilities", "coding", "stacks", "_shared", directoryName),
5856
6592
  level: 3,
5857
6593
  source: relative2(
5858
6594
  runtimeRoot,
5859
- join29(runtimeRoot, "capabilities", "coding", "stacks", "_shared", directoryName)
6595
+ join32(runtimeRoot, "capabilities", "coding", "stacks", "_shared", directoryName)
5860
6596
  )
5861
6597
  },
5862
6598
  ...matchedPacks.map((pack, index) => ({
5863
- path: join29(runtimeRoot, "capabilities", "coding", "stacks", pack, directoryName),
6599
+ path: join32(runtimeRoot, "capabilities", "coding", "stacks", pack, directoryName),
5864
6600
  level: 4 + Math.min(index, 1),
5865
6601
  source: relative2(
5866
6602
  runtimeRoot,
5867
- join29(runtimeRoot, "capabilities", "coding", "stacks", pack, directoryName)
6603
+ join32(runtimeRoot, "capabilities", "coding", "stacks", pack, directoryName)
5868
6604
  )
5869
6605
  })),
5870
6606
  ...matchedPacks.flatMap(
@@ -5878,9 +6614,9 @@ function getInheritanceDirectories(runtimeRoot, routing, artifactType) {
5878
6614
  }
5879
6615
  if (activeCapabilities.includes("security")) {
5880
6616
  directories.push({
5881
- path: join29(runtimeRoot, "capabilities", "security", directoryName),
6617
+ path: join32(runtimeRoot, "capabilities", "security", directoryName),
5882
6618
  level: 6,
5883
- source: relative2(runtimeRoot, join29(runtimeRoot, "capabilities", "security", directoryName))
6619
+ source: relative2(runtimeRoot, join32(runtimeRoot, "capabilities", "security", directoryName))
5884
6620
  });
5885
6621
  }
5886
6622
  return directories;
@@ -5917,9 +6653,9 @@ function resolveArtifactDirectoryName(artifactType) {
5917
6653
  case "mcp-configs":
5918
6654
  return "mcp";
5919
6655
  case "patterns":
5920
- return join29("benchmarks", "patterns");
6656
+ return join32("benchmarks", "patterns");
5921
6657
  case "anti-patterns":
5922
- return join29("benchmarks", "anti-patterns");
6658
+ return join32("benchmarks", "anti-patterns");
5923
6659
  default:
5924
6660
  return artifactType;
5925
6661
  }
@@ -6021,14 +6757,14 @@ function compareRuleSeedOrder(left, right) {
6021
6757
  return left.source.localeCompare(right.source);
6022
6758
  }
6023
6759
  function getRulePriority(filePath) {
6024
- const name = basename3(filePath, extname(filePath));
6760
+ const name = basename4(filePath, extname(filePath));
6025
6761
  const index = RULE_SEED_PRIORITY.indexOf(name);
6026
6762
  return index === -1 ? RULE_SEED_PRIORITY.length : index;
6027
6763
  }
6028
6764
 
6029
6765
  // src/onboarding/gitignore-writer.ts
6030
- import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
6031
- import { join as join30 } from "path";
6766
+ import { existsSync as existsSync14, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
6767
+ import { join as join33 } from "path";
6032
6768
  var PAQAD_MARKER = "# paqad-ai";
6033
6769
  var PAQAD_GITIGNORE_ENTRIES = [
6034
6770
  PAQAD_MARKER,
@@ -6041,8 +6777,8 @@ var PAQAD_GITIGNORE_ENTRIES = [
6041
6777
  ".paqad/theme/"
6042
6778
  ].join("\n");
6043
6779
  function writeGitignore(projectRoot) {
6044
- const gitignorePath = join30(projectRoot, ".gitignore");
6045
- const existing = existsSync13(gitignorePath) ? readFileSync11(gitignorePath, "utf8") : "";
6780
+ const gitignorePath = join33(projectRoot, ".gitignore");
6781
+ const existing = existsSync14(gitignorePath) ? readFileSync12(gitignorePath, "utf8") : "";
6046
6782
  if (existing.includes(PAQAD_MARKER)) {
6047
6783
  return;
6048
6784
  }
@@ -6514,9 +7250,9 @@ function inferSelectionDomain(detection, overrides, snapshot) {
6514
7250
  }
6515
7251
 
6516
7252
  // src/onboarding/reference-generator.ts
6517
- import { existsSync as existsSync14 } from "fs";
7253
+ import { existsSync as existsSync15 } from "fs";
6518
7254
  import { readFile as readFile13 } from "fs/promises";
6519
- import { join as join31, relative as relative4 } from "path";
7255
+ import { join as join34, relative as relative4 } from "path";
6520
7256
  import fg3 from "fast-glob";
6521
7257
  async function generateReferenceGuides(runtimeRoot, context) {
6522
7258
  if (context.domain !== "coding") {
@@ -6527,8 +7263,8 @@ async function generateReferenceGuides(runtimeRoot, context) {
6527
7263
  routing: { domain: context.domain },
6528
7264
  stack_profile: context.stack_profile
6529
7265
  });
6530
- const referencesRoot = join31(runtimeRoot, "capabilities", "coding", "stacks", stack, "references");
6531
- if (!existsSync14(referencesRoot)) {
7266
+ const referencesRoot = join34(runtimeRoot, "capabilities", "coding", "stacks", stack, "references");
7267
+ if (!existsSync15(referencesRoot)) {
6532
7268
  return [buildFallbackReferenceGuide(stack)];
6533
7269
  }
6534
7270
  const entries = await fg3(["tools/*.md", "tools-catalog.md"], {
@@ -6550,14 +7286,14 @@ async function generateReferenceGuides(runtimeRoot, context) {
6550
7286
  function toProjectReferencePath(stack, relativePath) {
6551
7287
  const normalized = relativePath.replaceAll("\\", "/");
6552
7288
  if (normalized === "tools-catalog.md") {
6553
- return join31(PATHS.TOOLS_DIR, stack, "README.md");
7289
+ return join34(PATHS.TOOLS_DIR, stack, "README.md");
6554
7290
  }
6555
- return join31(PATHS.TOOLS_DIR, stack, normalized.replace(/^tools\//, ""));
7291
+ return join34(PATHS.TOOLS_DIR, stack, normalized.replace(/^tools\//, ""));
6556
7292
  }
6557
7293
  function buildFallbackReferenceGuide(stack) {
6558
7294
  const title = stack.split("-").map((segment) => segment.slice(0, 1).toUpperCase() + segment.slice(1)).join(" ");
6559
7295
  return {
6560
- path: join31(PATHS.TOOLS_DIR, stack, "README.md"),
7296
+ path: join34(PATHS.TOOLS_DIR, stack, "README.md"),
6561
7297
  autoUpdate: false,
6562
7298
  content: [
6563
7299
  `# ${title} Tool References`,
@@ -6575,7 +7311,7 @@ function buildFallbackReferenceGuide(stack) {
6575
7311
 
6576
7312
  // src/onboarding/rule-generator.ts
6577
7313
  import { readFile as readFile14 } from "fs/promises";
6578
- import { join as join32 } from "path";
7314
+ import { join as join35 } from "path";
6579
7315
  async function generateProjectRules(rules) {
6580
7316
  return Promise.all(
6581
7317
  rules.map(async (rule) => ({
@@ -6588,22 +7324,22 @@ async function generateProjectRules(rules) {
6588
7324
  function toProjectRulePath(source) {
6589
7325
  const normalized = source.replaceAll("\\", "/");
6590
7326
  if (normalized.startsWith("base/rules/")) {
6591
- return join32(PATHS.RULES_DIR, "_shared", normalized.replace(/^base\/rules\//, ""));
7327
+ return join35(PATHS.RULES_DIR, "_shared", normalized.replace(/^base\/rules\//, ""));
6592
7328
  }
6593
7329
  if (normalized.startsWith("capabilities/")) {
6594
7330
  const capabilityNormalized = normalized.replace(/^capabilities\//, "");
6595
7331
  const [prefix2, suffix2] = capabilityNormalized.split("/rules/");
6596
7332
  if (prefix2 !== void 0 && suffix2 !== void 0) {
6597
7333
  const target2 = suffix2.endsWith("/guide.md") ? suffix2.replace("/guide.md", ".md") : suffix2;
6598
- return join32(PATHS.RULES_DIR, prefix2, target2);
7334
+ return join35(PATHS.RULES_DIR, prefix2, target2);
6599
7335
  }
6600
7336
  }
6601
7337
  const [prefix, suffix] = normalized.split("/rules/");
6602
7338
  if (prefix === void 0 || suffix === void 0) {
6603
- return join32(PATHS.RULES_DIR, normalized);
7339
+ return join35(PATHS.RULES_DIR, normalized);
6604
7340
  }
6605
7341
  const target = suffix.endsWith("/guide.md") ? suffix.replace("/guide.md", ".md") : suffix;
6606
- return join32(PATHS.RULES_DIR, prefix, target);
7342
+ return join35(PATHS.RULES_DIR, prefix, target);
6607
7343
  }
6608
7344
 
6609
7345
  // src/onboarding/orchestrator.ts
@@ -6641,15 +7377,16 @@ var OnboardingOrchestrator = class {
6641
7377
  }
6642
7378
  }
6643
7379
  generatedFiles.push(...await generateProjectRules(resolved.rules));
7380
+ generatedFiles.push(...generateFeatureDevelopmentPolicy(selections.domain));
6644
7381
  generatedFiles.push(
6645
7382
  ...await generateReferenceGuides(runtimeRoot, {
6646
7383
  domain: selections.domain,
6647
7384
  stack_profile: selections.stack_profile
6648
7385
  })
6649
7386
  );
6650
- const silentUpdateSrc = join33(runtimeRoot, "hooks", "silent-update.sh");
7387
+ const silentUpdateSrc = join36(runtimeRoot, "hooks", "silent-update.sh");
6651
7388
  try {
6652
- const hookContent = readFileSync12(silentUpdateSrc, "utf8");
7389
+ const hookContent = readFileSync13(silentUpdateSrc, "utf8");
6653
7390
  generatedFiles.push({
6654
7391
  path: PATHS.HOOKS_SILENT_UPDATE,
6655
7392
  content: hookContent,
@@ -6676,6 +7413,7 @@ var OnboardingOrchestrator = class {
6676
7413
  project_root: options.projectRoot,
6677
7414
  profile,
6678
7415
  detected: detection,
7416
+ repository: detection.repository,
6679
7417
  generated_at: (/* @__PURE__ */ new Date()).toISOString(),
6680
7418
  generated_artifacts: generatedFiles.map((file) => ({
6681
7419
  path: file.path,
@@ -6942,22 +7680,22 @@ function buildRustCommands(usingCompose) {
6942
7680
  }
6943
7681
 
6944
7682
  // src/onboarding/scaffold-generator.ts
6945
- import { join as join34 } from "path";
7683
+ import { join as join37 } from "path";
6946
7684
 
6947
7685
  // src/templates/registry.ts
6948
7686
  import fg4 from "fast-glob";
6949
- import { basename as basename4, relative as relative5 } from "pathe";
7687
+ import { basename as basename5, relative as relative5 } from "pathe";
6950
7688
 
6951
7689
  // src/onboarding/scaffold-generator.ts
6952
7690
  var FEATURE_TEMPLATE_TARGETS = [
6953
- ["business.md.hbs", join34(PATHS.MODULE_FEATURES_DIR, "core", "business.md")],
6954
- ["technical.md.hbs", join34(PATHS.MODULE_FEATURES_DIR, "core", "technical.md")]
7691
+ ["business.md.hbs", join37(PATHS.MODULE_FEATURES_DIR, "core", "business.md")],
7692
+ ["technical.md.hbs", join37(PATHS.MODULE_FEATURES_DIR, "core", "technical.md")]
6955
7693
  ];
6956
7694
 
6957
7695
  // src/packs/manager.ts
6958
7696
  import {
6959
7697
  cpSync,
6960
- existsSync as existsSync15,
7698
+ existsSync as existsSync16,
6961
7699
  mkdirSync as mkdirSync5,
6962
7700
  mkdtempSync,
6963
7701
  readdirSync as readdirSync3,
@@ -6965,14 +7703,14 @@ import {
6965
7703
  writeFileSync as writeFileSync5
6966
7704
  } from "fs";
6967
7705
  import { homedir as homedir2 } from "os";
6968
- import { join as join35, resolve as resolve2 } from "path";
7706
+ import { join as join38, resolve as resolve2 } from "path";
6969
7707
  import { execa } from "execa";
6970
7708
  var SOURCE_ORDER2 = ["built-in", "global", "project"];
6971
7709
  function resolvePackManagerRoots(projectRoot = process.cwd(), overrides = {}) {
6972
7710
  return {
6973
7711
  runtimeRoot: overrides.runtimeRoot ?? getRuntimeRoot(),
6974
- globalPacksRoot: overrides.globalPacksRoot ?? process.env.PAQAD_GLOBAL_PACKS_ROOT ?? join35(homedir2(), ".paqad", "packs"),
6975
- projectPacksRoot: overrides.projectPacksRoot ?? join35(projectRoot, ".paqad", "packs"),
7712
+ globalPacksRoot: overrides.globalPacksRoot ?? process.env.PAQAD_GLOBAL_PACKS_ROOT ?? join38(homedir2(), ".paqad", "packs"),
7713
+ projectPacksRoot: overrides.projectPacksRoot ?? join38(projectRoot, ".paqad", "packs"),
6976
7714
  registryUrl: overrides.registryUrl ?? process.env.PAQAD_PACK_REGISTRY_URL
6977
7715
  };
6978
7716
  }
@@ -7021,7 +7759,7 @@ async function installPack(source, options = {}) {
7021
7759
  if (!pack.validation.valid) {
7022
7760
  throw new Error(formatValidationIssues(pack.validation.issues));
7023
7761
  }
7024
- const destination = join35(installRoot, pack.manifest.name);
7762
+ const destination = join38(installRoot, pack.manifest.name);
7025
7763
  rmSync2(destination, { recursive: true, force: true });
7026
7764
  cpSync(candidateRoot, destination, { recursive: true });
7027
7765
  const installed = loader.validatePack(destination, scope === "project" ? "project" : "global");
@@ -7033,13 +7771,13 @@ async function installPack(source, options = {}) {
7033
7771
  function removePack(name, projectRoot = process.cwd(), scope = "global", overrides = {}) {
7034
7772
  const roots = resolvePackManagerRoots(projectRoot, overrides);
7035
7773
  const targetRoot = scope === "project" ? roots.projectPacksRoot : roots.globalPacksRoot;
7036
- const target = join35(targetRoot, name);
7037
- if (existsSync15(target)) {
7774
+ const target = join38(targetRoot, name);
7775
+ if (existsSync16(target)) {
7038
7776
  rmSync2(target, { recursive: true, force: true });
7039
7777
  return;
7040
7778
  }
7041
- const builtInRoot = join35(roots.runtimeRoot, "capabilities", "coding", "stacks", name);
7042
- if (existsSync15(builtInRoot)) {
7779
+ const builtInRoot = join38(roots.runtimeRoot, "capabilities", "coding", "stacks", name);
7780
+ if (existsSync16(builtInRoot)) {
7043
7781
  throw new Error(
7044
7782
  `Cannot remove built-in pack "${name}"; remove a global or project override instead`
7045
7783
  );
@@ -7057,14 +7795,14 @@ function createPack(name, options = {}) {
7057
7795
  const destinationRoot = options.destinationRoot ?? process.cwd();
7058
7796
  const ecosystem = options.ecosystem ?? "node";
7059
7797
  const tier = options.tier ?? "framework";
7060
- const packRoot = join35(destinationRoot, name);
7061
- if (existsSync15(packRoot)) {
7798
+ const packRoot = join38(destinationRoot, name);
7799
+ if (existsSync16(packRoot)) {
7062
7800
  throw new Error(`Pack scaffold already exists at ${packRoot}`);
7063
7801
  }
7064
- mkdirSync5(join35(packRoot, "rules"), { recursive: true });
7065
- writeFileSync5(join35(packRoot, "pack.yaml"), renderPackTemplate(name, ecosystem, tier));
7802
+ mkdirSync5(join38(packRoot, "rules"), { recursive: true });
7803
+ writeFileSync5(join38(packRoot, "pack.yaml"), renderPackTemplate(name, ecosystem, tier));
7066
7804
  writeFileSync5(
7067
- join35(packRoot, "rules", "conventions.md"),
7805
+ join38(packRoot, "rules", "conventions.md"),
7068
7806
  `# ${name}
7069
7807
 
7070
7808
  Document project-specific conventions for the ${name} stack here.
@@ -7074,14 +7812,14 @@ Document project-specific conventions for the ${name} stack here.
7074
7812
  }
7075
7813
  function listPackNamesForSource(source, roots) {
7076
7814
  const sourceRoot = resolveSourceRoot(source, roots);
7077
- if (!existsSync15(sourceRoot)) {
7815
+ if (!existsSync16(sourceRoot)) {
7078
7816
  return [];
7079
7817
  }
7080
7818
  return readdirSync3(sourceRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
7081
7819
  }
7082
7820
  function resolveSourceRoot(source, roots) {
7083
7821
  if (source === "built-in") {
7084
- return join35(roots.runtimeRoot, "capabilities", "coding", "stacks");
7822
+ return join38(roots.runtimeRoot, "capabilities", "coding", "stacks");
7085
7823
  }
7086
7824
  return source === "global" ? roots.globalPacksRoot : roots.projectPacksRoot;
7087
7825
  }
@@ -7101,13 +7839,13 @@ async function materializePackSource(source, roots) {
7101
7839
  return clonePackSource(buildRegistryPackUrl(roots.registryUrl, source));
7102
7840
  }
7103
7841
  function looksLikeLocalPath(source) {
7104
- return source.startsWith(".") || source.startsWith("/") || existsSync15(resolve2(source));
7842
+ return source.startsWith(".") || source.startsWith("/") || existsSync16(resolve2(source));
7105
7843
  }
7106
7844
  function looksLikeGitUrl(source) {
7107
7845
  return source.startsWith("http://") || source.startsWith("https://") || source.startsWith("ssh://") || source.startsWith("git@") || source.startsWith("file://") || source.endsWith(".git");
7108
7846
  }
7109
7847
  async function clonePackSource(source) {
7110
- const tempRoot = mkdtempSync(join35(homedir2(), ".paqad-pack-clone-"));
7848
+ const tempRoot = mkdtempSync(join38(homedir2(), ".paqad-pack-clone-"));
7111
7849
  try {
7112
7850
  await execa("git", ["clone", "--depth", "1", source, tempRoot]);
7113
7851
  } catch (error) {
@@ -7117,11 +7855,11 @@ async function clonePackSource(source) {
7117
7855
  return findPackRoot(tempRoot);
7118
7856
  }
7119
7857
  function findPackRoot(root) {
7120
- const rootManifest = join35(root, "pack.yaml");
7121
- if (existsSync15(rootManifest)) {
7858
+ const rootManifest = join38(root, "pack.yaml");
7859
+ if (existsSync16(rootManifest)) {
7122
7860
  return root;
7123
7861
  }
7124
- const candidates = readdirSync3(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join35(root, entry.name)).filter((candidate) => existsSync15(join35(candidate, "pack.yaml")));
7862
+ const candidates = readdirSync3(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join38(root, entry.name)).filter((candidate) => existsSync16(join38(candidate, "pack.yaml")));
7125
7863
  if (candidates.length === 1) {
7126
7864
  return candidates[0];
7127
7865
  }
@@ -7239,15 +7977,15 @@ async function queryOsv(packages) {
7239
7977
  }
7240
7978
 
7241
7979
  // src/pentest/progress-tracker.ts
7242
- import { existsSync as existsSync17 } from "fs";
7243
- import { mkdir as mkdir12, readdir as readdir4, readFile as readFile16, writeFile as writeFile12 } from "fs/promises";
7244
- import { dirname as dirname17, join as join37 } from "path";
7980
+ import { existsSync as existsSync18 } from "fs";
7981
+ import { mkdir as mkdir12, readdir as readdir5, readFile as readFile16, writeFile as writeFile12 } from "fs/promises";
7982
+ import { dirname as dirname17, join as join40 } from "path";
7245
7983
 
7246
7984
  // src/pentest/shared.ts
7247
7985
  import { createHash as createHash7 } from "crypto";
7248
- import { existsSync as existsSync16 } from "fs";
7249
- import { mkdir as mkdir11, readFile as readFile15, readdir as readdir3, writeFile as writeFile11 } from "fs/promises";
7250
- import { basename as basename5, dirname as dirname16, join as join36, relative as relative6 } from "path";
7986
+ import { existsSync as existsSync17 } from "fs";
7987
+ import { mkdir as mkdir11, readFile as readFile15, readdir as readdir4, writeFile as writeFile11 } from "fs/promises";
7988
+ import { basename as basename6, dirname as dirname16, join as join39, relative as relative6 } from "path";
7251
7989
  import { execa as execa2 } from "execa";
7252
7990
  import fg5 from "fast-glob";
7253
7991
  function toLocalTimestamp(date) {
@@ -7265,7 +8003,7 @@ async function writeJson(target, data) {
7265
8003
  `);
7266
8004
  }
7267
8005
  async function readJsonIfExists(target) {
7268
- if (!existsSync16(target)) {
8006
+ if (!existsSync17(target)) {
7269
8007
  return null;
7270
8008
  }
7271
8009
  return JSON.parse(await readFile15(target, "utf8"));
@@ -7311,8 +8049,8 @@ async function discoverTargetUrl(projectRoot, stack, explicit) {
7311
8049
  }
7312
8050
  const envFiles = [".env", ".env.local", ".env.example"];
7313
8051
  for (const envFile of envFiles) {
7314
- const path = join36(projectRoot, envFile);
7315
- if (!existsSync16(path)) {
8052
+ const path = join39(projectRoot, envFile);
8053
+ if (!existsSync17(path)) {
7316
8054
  continue;
7317
8055
  }
7318
8056
  const content = await readFile15(path, "utf8");
@@ -7333,11 +8071,11 @@ async function discoverTargetUrl(projectRoot, stack, explicit) {
7333
8071
  return null;
7334
8072
  }
7335
8073
  async function runProjectScript(projectRoot, scriptName, env, logDir) {
7336
- const scriptPath = join36(projectRoot, PATHS.SCRIPTS_DIR, scriptName);
7337
- const stdoutPath = join36(logDir, `${scriptName}.stdout.log`);
7338
- const stderrPath = join36(logDir, `${scriptName}.stderr.log`);
8074
+ const scriptPath = join39(projectRoot, PATHS.SCRIPTS_DIR, scriptName);
8075
+ const stdoutPath = join39(logDir, `${scriptName}.stdout.log`);
8076
+ const stderrPath = join39(logDir, `${scriptName}.stderr.log`);
7339
8077
  await mkdir11(logDir, { recursive: true });
7340
- if (!existsSync16(scriptPath)) {
8078
+ if (!existsSync17(scriptPath)) {
7341
8079
  await writeFile11(stdoutPath, "");
7342
8080
  await writeFile11(stderrPath, `Missing script: ${relative6(projectRoot, scriptPath)}
7343
8081
  `);
@@ -7365,11 +8103,11 @@ async function runProjectScript(projectRoot, scriptName, env, logDir) {
7365
8103
  };
7366
8104
  }
7367
8105
  async function loadModuleDocs(projectRoot, focusModules = []) {
7368
- const moduleRoot = join36(projectRoot, PATHS.MODULES_DIR);
7369
- if (!existsSync16(moduleRoot)) {
8106
+ const moduleRoot = join39(projectRoot, PATHS.MODULES_DIR);
8107
+ if (!existsSync17(moduleRoot)) {
7370
8108
  return [];
7371
8109
  }
7372
- const dirs = (await readdir3(moduleRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((moduleName) => focusModules.length === 0 || focusModules.includes(moduleName)).sort();
8110
+ const dirs = (await readdir4(moduleRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((moduleName) => focusModules.length === 0 || focusModules.includes(moduleName)).sort();
7373
8111
  return Promise.all(
7374
8112
  dirs.map(async (moduleName) => {
7375
8113
  const paths = (await fg5(
@@ -7434,7 +8172,7 @@ function inferSourceArtifacts(baseDir, scriptResults) {
7434
8172
  return [
7435
8173
  ...new Set(
7436
8174
  artifacts.map(
7437
- (artifact) => artifact.startsWith(".") ? artifact : relative6(dirname16(baseDir), join36(dirname16(baseDir), artifact))
8175
+ (artifact) => artifact.startsWith(".") ? artifact : relative6(dirname16(baseDir), join39(dirname16(baseDir), artifact))
7438
8176
  )
7439
8177
  )
7440
8178
  ];
@@ -7508,8 +8246,8 @@ var PentestProgressTracker = class {
7508
8246
  };
7509
8247
  }
7510
8248
  async load(projectRoot, runId) {
7511
- const target = join37(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "progress.json");
7512
- if (!existsSync17(target)) {
8249
+ const target = join40(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "progress.json");
8250
+ if (!existsSync18(target)) {
7513
8251
  return null;
7514
8252
  }
7515
8253
  const parsed = JSON.parse(await readFile16(target, "utf8"));
@@ -7520,7 +8258,7 @@ var PentestProgressTracker = class {
7520
8258
  return parsed;
7521
8259
  }
7522
8260
  async save(projectRoot, progress) {
7523
- const target = join37(projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "progress.json");
8261
+ const target = join40(projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "progress.json");
7524
8262
  progress.updated_at = (/* @__PURE__ */ new Date()).toISOString();
7525
8263
  await mkdir12(dirname17(target), { recursive: true });
7526
8264
  await writeFile12(target, `${JSON.stringify(progress, null, 2)}
@@ -7579,11 +8317,11 @@ var PentestProgressTracker = class {
7579
8317
  return step.status === "completed" && step.input_hash === inputHash;
7580
8318
  }
7581
8319
  async findIncompleteRun(projectRoot, workflow, sourceReportPath) {
7582
- const runsDir = join37(projectRoot, PATHS.PENTEST_RUNS_DIR);
7583
- if (!existsSync17(runsDir)) {
8320
+ const runsDir = join40(projectRoot, PATHS.PENTEST_RUNS_DIR);
8321
+ if (!existsSync18(runsDir)) {
7584
8322
  return null;
7585
8323
  }
7586
- const entries = (await readdir4(runsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
8324
+ const entries = (await readdir5(runsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
7587
8325
  for (const runId of entries) {
7588
8326
  const progress = await this.load(projectRoot, runId);
7589
8327
  if (progress === null) {
@@ -7622,21 +8360,21 @@ var PentestProgressTracker = class {
7622
8360
  }
7623
8361
  };
7624
8362
  function runArtifactsDir(projectRoot, runId) {
7625
- return join37(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "artifacts");
8363
+ return join40(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "artifacts");
7626
8364
  }
7627
8365
  function runLogsDir(projectRoot, runId) {
7628
- return join37(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "logs");
8366
+ return join40(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "logs");
7629
8367
  }
7630
8368
 
7631
8369
  // src/pipeline/lane-runner.ts
7632
- import { existsSync as existsSync20 } from "fs";
8370
+ import { existsSync as existsSync21 } from "fs";
7633
8371
  import { mkdir as mkdir17, readFile as readFile22, writeFile as writeFile17 } from "fs/promises";
7634
- import { dirname as dirname21, join as join46 } from "path";
7635
- import { basename as basename6, dirname as pathDirname } from "pathe";
8372
+ import { dirname as dirname21, join as join49 } from "path";
8373
+ import { basename as basename7, dirname as pathDirname } from "pathe";
7636
8374
  import fg7 from "fast-glob";
7637
8375
 
7638
8376
  // src/skills/frontmatter-parser.ts
7639
- import YAML5 from "yaml";
8377
+ import YAML6 from "yaml";
7640
8378
 
7641
8379
  // src/skills/conditional-processor.ts
7642
8380
  var ConditionalSectionProcessor = class {
@@ -7657,13 +8395,13 @@ var conditionalProcessor = new ConditionalSectionProcessor();
7657
8395
 
7658
8396
  // src/workflows/engine.ts
7659
8397
  import { readFile as readFile18, writeFile as writeFile13, mkdir as mkdir13 } from "fs/promises";
7660
- import { join as join39, dirname as dirname18 } from "path";
8398
+ import { join as join42, dirname as dirname18 } from "path";
7661
8399
  import { randomUUID as randomUUID2 } from "crypto";
7662
8400
 
7663
8401
  // src/workflows/template-loader.ts
7664
- import { readFile as readFile17, readdir as readdir5 } from "fs/promises";
7665
- import { join as join38 } from "path";
7666
- import YAML6 from "yaml";
8402
+ import { readFile as readFile17, readdir as readdir6 } from "fs/promises";
8403
+ import { join as join41 } from "path";
8404
+ import YAML7 from "yaml";
7667
8405
 
7668
8406
  // src/pipeline/phases/shared.ts
7669
8407
  function createPassResult(phase, summary, context, artifacts = [`handoff:${context.phases.length + 1}`]) {
@@ -7725,7 +8463,15 @@ var DocumentationUpdatePhase = class {
7725
8463
  );
7726
8464
  }
7727
8465
  }
7728
- return createPassResult(this.phase, "Canonical docs updated", context);
8466
+ const stageSummary = summarizeFeatureDevelopmentStage(
8467
+ context.feature_policy,
8468
+ "documentation_sync"
8469
+ );
8470
+ return createPassResult(
8471
+ this.phase,
8472
+ stageSummary === null ? "Canonical docs updated" : `Canonical docs updated (${stageSummary})`,
8473
+ context
8474
+ );
7729
8475
  }
7730
8476
  };
7731
8477
 
@@ -7761,7 +8507,12 @@ var ImplementationReviewPhase = class {
7761
8507
  async execute(context) {
7762
8508
  const tier = selectReviewTier(context.classification, context.lane);
7763
8509
  const mode = selectReviewMode(false, 0);
7764
- return createPassResult(this.phase, `Implementation review passed (${tier}, ${mode})`, context);
8510
+ const stageSummary = summarizeFeatureDevelopmentStage(context.feature_policy, "review");
8511
+ return createPassResult(
8512
+ this.phase,
8513
+ stageSummary === null ? `Implementation review passed (${tier}, ${mode})` : `Implementation review passed (${tier}, ${mode}; ${stageSummary})`,
8514
+ context
8515
+ );
7765
8516
  }
7766
8517
  };
7767
8518
 
@@ -7769,7 +8520,12 @@ var ImplementationReviewPhase = class {
7769
8520
  var ImplementationPhase = class {
7770
8521
  phase = "implementation";
7771
8522
  async execute(context) {
7772
- return createPassResult(this.phase, "Implementation completed", context);
8523
+ const stageSummary = summarizeFeatureDevelopmentStage(context.feature_policy, "development");
8524
+ return createPassResult(
8525
+ this.phase,
8526
+ stageSummary === null ? "Implementation completed" : `Implementation completed (${stageSummary})`,
8527
+ context
8528
+ );
7773
8529
  }
7774
8530
  };
7775
8531
 
@@ -7777,18 +8533,23 @@ var ImplementationPhase = class {
7777
8533
  var LoadDocsPhase = class {
7778
8534
  phase = "docs-first-load";
7779
8535
  async execute(context) {
7780
- return createPassResult(this.phase, "Docs-first context prepared", context);
8536
+ const stageSummary = summarizeFeatureDevelopmentStage(context.feature_policy, "planning");
8537
+ return createPassResult(
8538
+ this.phase,
8539
+ stageSummary === null ? "Docs-first context prepared" : `Docs-first context prepared (${stageSummary})`,
8540
+ context
8541
+ );
7781
8542
  }
7782
8543
  };
7783
8544
 
7784
8545
  // src/workflows/pentest.ts
7785
8546
  import { mkdir as mkdir14, writeFile as writeFile14 } from "fs/promises";
7786
- import { join as join42, relative as relative7 } from "path";
8547
+ import { join as join45, relative as relative7 } from "path";
7787
8548
 
7788
8549
  // src/pentest/findings.ts
7789
- import { existsSync as existsSync18 } from "fs";
8550
+ import { existsSync as existsSync19 } from "fs";
7790
8551
  import { readFile as readFile19 } from "fs/promises";
7791
- import { join as join40 } from "path";
8552
+ import { join as join43 } from "path";
7792
8553
  function createFinding(input) {
7793
8554
  return {
7794
8555
  id: "",
@@ -8215,8 +8976,8 @@ function buildModuleFindings(docs, tests) {
8215
8976
  return findings;
8216
8977
  }
8217
8978
  async function buildSecretFindings(artifactDir) {
8218
- const path = join40(artifactDir, "secrets", "matches.txt");
8219
- if (!existsSync18(path)) {
8979
+ const path = join43(artifactDir, "secrets", "matches.txt");
8980
+ if (!existsSync19(path)) {
8220
8981
  return [];
8221
8982
  }
8222
8983
  const matches = parseSecretMatches(await readFile19(path, "utf8"));
@@ -8331,8 +9092,8 @@ function normalizeImpact(content) {
8331
9092
  }
8332
9093
  async function readNativeAuditFindings(artifactDir) {
8333
9094
  const findings = [];
8334
- const dependencyDir = join40(artifactDir, "dependencies");
8335
- const npmAudit = await readJsonMaybe(join40(dependencyDir, "npm-audit.json"));
9095
+ const dependencyDir = join43(artifactDir, "dependencies");
9096
+ const npmAudit = await readJsonMaybe(join43(dependencyDir, "npm-audit.json"));
8336
9097
  for (const [name, vulnerability] of Object.entries(npmAudit?.vulnerabilities ?? {})) {
8337
9098
  const via = (vulnerability.via ?? []).find((entry) => typeof entry === "object");
8338
9099
  findings.push({
@@ -8344,7 +9105,7 @@ async function readNativeAuditFindings(artifactDir) {
8344
9105
  details: via?.url ?? ""
8345
9106
  });
8346
9107
  }
8347
- const pnpmAudit = await readJsonMaybe(join40(dependencyDir, "pnpm-audit.json"));
9108
+ const pnpmAudit = await readJsonMaybe(join43(dependencyDir, "pnpm-audit.json"));
8348
9109
  for (const advisory of Object.values(pnpmAudit?.advisories ?? {})) {
8349
9110
  findings.push({
8350
9111
  package_name: advisory.module_name ?? "unknown",
@@ -8355,7 +9116,7 @@ async function readNativeAuditFindings(artifactDir) {
8355
9116
  details: advisory.overview ?? ""
8356
9117
  });
8357
9118
  }
8358
- const composerAudit = await readJsonMaybe(join40(dependencyDir, "composer-audit.json"));
9119
+ const composerAudit = await readJsonMaybe(join43(dependencyDir, "composer-audit.json"));
8359
9120
  if (Array.isArray(composerAudit?.advisories)) {
8360
9121
  for (const advisory of composerAudit.advisories) {
8361
9122
  findings.push({
@@ -8392,7 +9153,7 @@ async function readNativeAuditFindings(artifactDir) {
8392
9153
  });
8393
9154
  }
8394
9155
  async function readJsonMaybe(path) {
8395
- if (!existsSync18(path)) {
9156
+ if (!existsSync19(path)) {
8396
9157
  return null;
8397
9158
  }
8398
9159
  try {
@@ -8491,7 +9252,7 @@ var FileCheckMapper = class {
8491
9252
 
8492
9253
  // src/pentest/incremental-scanner.ts
8493
9254
  import { readFile as readFile20 } from "fs/promises";
8494
- import { join as join41 } from "path";
9255
+ import { join as join44 } from "path";
8495
9256
  import { createHash as createHash8 } from "crypto";
8496
9257
  import { execa as execa3 } from "execa";
8497
9258
  var IncrementalScanner = class {
@@ -8525,7 +9286,7 @@ var IncrementalScanner = class {
8525
9286
  }
8526
9287
  }
8527
9288
  async gitDiff(projectRoot, lastRunId) {
8528
- const progressPath = join41(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
9289
+ const progressPath = join44(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
8529
9290
  let baseCommit;
8530
9291
  try {
8531
9292
  const raw = await readFile20(progressPath, "utf8");
@@ -8542,7 +9303,7 @@ var IncrementalScanner = class {
8542
9303
  return result.stdout.split("\n").map((f) => f.trim()).filter(Boolean);
8543
9304
  }
8544
9305
  async hashDiff(projectRoot, lastRunId) {
8545
- const manifestPath = join41(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
9306
+ const manifestPath = join44(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
8546
9307
  let fileManifest = {};
8547
9308
  try {
8548
9309
  const raw = await readFile20(manifestPath, "utf8");
@@ -8554,7 +9315,7 @@ var IncrementalScanner = class {
8554
9315
  const changed = [];
8555
9316
  for (const [filePath, storedHash] of Object.entries(fileManifest)) {
8556
9317
  try {
8557
- const content = await readFile20(join41(projectRoot, filePath), "utf8");
9318
+ const content = await readFile20(join44(projectRoot, filePath), "utf8");
8558
9319
  const currentHash = createHash8("sha256").update(content).digest("hex");
8559
9320
  if (currentHash !== storedHash) {
8560
9321
  changed.push(filePath);
@@ -8567,11 +9328,11 @@ var IncrementalScanner = class {
8567
9328
  }
8568
9329
  async warnIfFullScanStale(projectRoot, thresholdDays) {
8569
9330
  try {
8570
- const runsDir = join41(projectRoot, ".paqad", "pentest", "runs");
8571
- const { readdir: readdir8 } = await import("fs/promises");
8572
- const runs = await readdir8(runsDir).catch(() => []);
9331
+ const runsDir = join44(projectRoot, ".paqad", "pentest", "runs");
9332
+ const { readdir: readdir9 } = await import("fs/promises");
9333
+ const runs = await readdir9(runsDir).catch(() => []);
8573
9334
  for (const run of runs.sort().reverse()) {
8574
- const progressPath = join41(runsDir, run, "progress.json");
9335
+ const progressPath = join44(runsDir, run, "progress.json");
8575
9336
  try {
8576
9337
  const raw = await readFile20(progressPath, "utf8");
8577
9338
  const progress = JSON.parse(raw);
@@ -8769,8 +9530,8 @@ var PentestWorkflow = class {
8769
9530
  await this.tracker.save(options.projectRoot, progress);
8770
9531
  const docs = await loadModuleDocs(options.projectRoot, focusModules);
8771
9532
  const tests = await loadTests(options.projectRoot, focusModules);
8772
- const docsPath = join42(artifactsDir, "docs-summary.json");
8773
- const testsPath = join42(artifactsDir, "tests-summary.json");
9533
+ const docsPath = join45(artifactsDir, "docs-summary.json");
9534
+ const testsPath = join45(artifactsDir, "tests-summary.json");
8774
9535
  await writeJson(docsPath, docs);
8775
9536
  await writeJson(
8776
9537
  testsPath,
@@ -8871,7 +9632,7 @@ var PentestWorkflow = class {
8871
9632
  progressRunId: progress.run_id,
8872
9633
  reportTimestamp: new Date(progress.started_at)
8873
9634
  });
8874
- const findingIndexPath = join42(
9635
+ const findingIndexPath = join45(
8875
9636
  options.projectRoot,
8876
9637
  PATHS.PENTEST_RUNS_DIR,
8877
9638
  progress.run_id,
@@ -8888,7 +9649,7 @@ var PentestWorkflow = class {
8888
9649
  }
8889
9650
  if (report === null) {
8890
9651
  const existingSidecar = progress.sidecar_path ? await readJsonIfExists(
8891
- join42(options.projectRoot, progress.sidecar_path)
9652
+ join45(options.projectRoot, progress.sidecar_path)
8892
9653
  ) : null;
8893
9654
  report = existingSidecar;
8894
9655
  }
@@ -8903,18 +9664,18 @@ var PentestWorkflow = class {
8903
9664
  this.tracker.markStepRunning(progress, "write-report", writeHash);
8904
9665
  await this.tracker.save(options.projectRoot, progress);
8905
9666
  await writeJson(
8906
- join42(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "report-preview.json"),
9667
+ join45(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "report-preview.json"),
8907
9668
  { report_id: report.report_id, findings: report.findings.length }
8908
9669
  );
8909
- await writeJson(join42(options.projectRoot, report.sidecar_path), report);
9670
+ await writeJson(join45(options.projectRoot, report.sidecar_path), report);
8910
9671
  await writeJson(
8911
- join42(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "blocked-checks.json"),
9672
+ join45(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "blocked-checks.json"),
8912
9673
  report.blocked_checks
8913
9674
  );
8914
- await mkdir14(join42(options.projectRoot, PATHS.PENTEST_DIR), { recursive: true });
9675
+ await mkdir14(join45(options.projectRoot, PATHS.PENTEST_DIR), { recursive: true });
8915
9676
  const markdown = buildPentestMarkdown(report);
8916
- await writeJson(join42(options.projectRoot, report.sidecar_path), report);
8917
- await writeFile14(join42(options.projectRoot, report.report_path), markdown);
9677
+ await writeJson(join45(options.projectRoot, report.sidecar_path), report);
9678
+ await writeFile14(join45(options.projectRoot, report.report_path), markdown);
8918
9679
  this.tracker.markStepCompleted(
8919
9680
  progress,
8920
9681
  "write-report",
@@ -8941,7 +9702,7 @@ async function buildCurrentPentestReport(input) {
8941
9702
  const docs = await loadModuleDocs(input.projectRoot, input.focusModules);
8942
9703
  const tests = await loadTests(input.projectRoot, input.focusModules);
8943
9704
  const osvFindings = await queryOsv(input.snapshot.packages);
8944
- const osvPath = join42(input.artifactsDir, "dependencies", "osv-results.json");
9705
+ const osvPath = join45(input.artifactsDir, "dependencies", "osv-results.json");
8945
9706
  await writeJson(osvPath, osvFindings);
8946
9707
  const dependencyFindings = await buildDependencyFindings(
8947
9708
  input.snapshot,
@@ -8950,7 +9711,7 @@ async function buildCurrentPentestReport(input) {
8950
9711
  );
8951
9712
  const moduleFindings = buildModuleFindings(docs, tests);
8952
9713
  const secretFindings = await buildSecretFindings(input.artifactsDir);
8953
- const runtimePayload = await readJsonIfExists(join42(input.artifactsDir, "runtime", "runtime-checks.json"));
9714
+ const runtimePayload = await readJsonIfExists(join45(input.artifactsDir, "runtime", "runtime-checks.json"));
8954
9715
  const runtimeStatus = input.targetUrl ? runtimePayload?.reachable ? {
8955
9716
  target_url: input.targetUrl,
8956
9717
  status: "reachable",
@@ -8976,8 +9737,8 @@ async function buildCurrentPentestReport(input) {
8976
9737
  ...runtimeFindings
8977
9738
  ]);
8978
9739
  const timestamp = toLocalTimestamp(input.reportTimestamp);
8979
- const reportPath = join42(PATHS.PENTEST_DIR, `${timestamp}.md`);
8980
- const sidecarPath = join42(PATHS.PENTEST_DIR, `${timestamp}.json`);
9740
+ const reportPath = join45(PATHS.PENTEST_DIR, `${timestamp}.md`);
9741
+ const sidecarPath = join45(PATHS.PENTEST_DIR, `${timestamp}.json`);
8981
9742
  const stack = getPrimaryStack({
8982
9743
  routing: { domain: "coding" },
8983
9744
  stack_profile: input.snapshot.profile
@@ -9030,9 +9791,9 @@ async function buildCurrentPentestReport(input) {
9030
9791
  raw_evidence_paths: [
9031
9792
  relative7(input.projectRoot, osvPath),
9032
9793
  ...[
9033
- join42(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "finding-index.json"),
9034
- join42(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "docs-summary.json"),
9035
- join42(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "tests-summary.json")
9794
+ join45(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "finding-index.json"),
9795
+ join45(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "docs-summary.json"),
9796
+ join45(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "tests-summary.json")
9036
9797
  ]
9037
9798
  ]
9038
9799
  };
@@ -9072,7 +9833,7 @@ var PentestPhase = class {
9072
9833
 
9073
9834
  // src/workflows/pentest-retest.ts
9074
9835
  import { mkdir as mkdir15, writeFile as writeFile15 } from "fs/promises";
9075
- import { dirname as dirname19, join as join43 } from "path";
9836
+ import { dirname as dirname19, join as join46 } from "path";
9076
9837
  var RETEST_STEPS = [
9077
9838
  { id: "load-source-report", title: "Load source pentest report" },
9078
9839
  { id: "rerun-evidence", title: "Collect fresh evidence for source findings" },
@@ -9093,7 +9854,7 @@ var PentestRetestWorkflow = class {
9093
9854
  }
9094
9855
  const normalizedSourcePath = normalizeSidecarPath(sourceReportPath);
9095
9856
  const sourceSidecar = await readJsonIfExists(
9096
- join43(options.projectRoot, normalizedSourcePath)
9857
+ join46(options.projectRoot, normalizedSourcePath)
9097
9858
  );
9098
9859
  if (sourceSidecar === null) {
9099
9860
  throw new Error(`Source pentest sidecar not found at ${normalizedSourcePath}`);
@@ -9118,12 +9879,12 @@ var PentestRetestWorkflow = class {
9118
9879
  if (!this.tracker.shouldSkipStep(progress, "load-source-report", sourceHash)) {
9119
9880
  this.tracker.markStepRunning(progress, "load-source-report", sourceHash);
9120
9881
  await this.tracker.save(options.projectRoot, progress);
9121
- const sourceCopy = join43(artifactsDir, "source-report.json");
9882
+ const sourceCopy = join46(artifactsDir, "source-report.json");
9122
9883
  await writeJson(sourceCopy, sourceSidecar);
9123
9884
  this.tracker.markStepCompleted(
9124
9885
  progress,
9125
9886
  "load-source-report",
9126
- [join43(PATHS.PENTEST_RUNS_DIR, progress.run_id, "artifacts", "source-report.json")],
9887
+ [join46(PATHS.PENTEST_RUNS_DIR, progress.run_id, "artifacts", "source-report.json")],
9127
9888
  [...RETEST_SKILLS.source].map(skillPath)
9128
9889
  );
9129
9890
  await this.tracker.save(options.projectRoot, progress);
@@ -9140,7 +9901,7 @@ var PentestRetestWorkflow = class {
9140
9901
  PENTEST_RUN_ID: progress.run_id,
9141
9902
  PENTEST_ARTIFACT_DIR: artifactsDir,
9142
9903
  PENTEST_TARGET_URL: targetUrl ?? "",
9143
- PENTEST_SOURCE_REPORT: join43(options.projectRoot, normalizedSourcePath),
9904
+ PENTEST_SOURCE_REPORT: join46(options.projectRoot, normalizedSourcePath),
9144
9905
  PENTEST_DB_CONNECTION_NAME: options.dbConnectionName ?? ""
9145
9906
  };
9146
9907
  const scriptResults = await Promise.all([
@@ -9189,8 +9950,8 @@ var PentestRetestWorkflow = class {
9189
9950
  ...currentReport,
9190
9951
  report_id: toReportId("RETEST", new Date(progress.started_at)),
9191
9952
  workflow: "pentest-retest",
9192
- report_path: join43(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.md`),
9193
- sidecar_path: join43(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.json`),
9953
+ report_path: join46(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.md`),
9954
+ sidecar_path: join46(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.json`),
9194
9955
  source_report_path: normalizedSourcePath,
9195
9956
  source_report_id: sourceSidecar.report_id,
9196
9957
  findings: retestFindings,
@@ -9203,7 +9964,7 @@ var PentestRetestWorkflow = class {
9203
9964
  ...[...RETEST_SKILLS.source, ...RETEST_SKILLS.evaluate].map(skillPath)
9204
9965
  ]
9205
9966
  };
9206
- const findingIndexPath = join43(
9967
+ const findingIndexPath = join46(
9207
9968
  options.projectRoot,
9208
9969
  PATHS.PENTEST_RUNS_DIR,
9209
9970
  progress.run_id,
@@ -9213,14 +9974,14 @@ var PentestRetestWorkflow = class {
9213
9974
  this.tracker.markStepCompleted(
9214
9975
  progress,
9215
9976
  "evaluate-source-findings",
9216
- [join43(PATHS.PENTEST_RUNS_DIR, progress.run_id, "finding-index.json")],
9977
+ [join46(PATHS.PENTEST_RUNS_DIR, progress.run_id, "finding-index.json")],
9217
9978
  [...RETEST_SKILLS.evaluate].map(skillPath)
9218
9979
  );
9219
9980
  await this.tracker.save(options.projectRoot, progress);
9220
9981
  }
9221
9982
  if (retestReport === null) {
9222
9983
  const existing = progress.sidecar_path ? await readJsonIfExists(
9223
- join43(options.projectRoot, progress.sidecar_path)
9984
+ join46(options.projectRoot, progress.sidecar_path)
9224
9985
  ) : null;
9225
9986
  retestReport = existing;
9226
9987
  }
@@ -9234,12 +9995,12 @@ var PentestRetestWorkflow = class {
9234
9995
  if (!this.tracker.shouldSkipStep(progress, "write-report", writeHash)) {
9235
9996
  this.tracker.markStepRunning(progress, "write-report", writeHash);
9236
9997
  await this.tracker.save(options.projectRoot, progress);
9237
- await writeJson(join43(options.projectRoot, retestReport.sidecar_path), retestReport);
9238
- await mkdir15(dirname19(join43(options.projectRoot, retestReport.report_path)), {
9998
+ await writeJson(join46(options.projectRoot, retestReport.sidecar_path), retestReport);
9999
+ await mkdir15(dirname19(join46(options.projectRoot, retestReport.report_path)), {
9239
10000
  recursive: true
9240
10001
  });
9241
10002
  await writeFile15(
9242
- join43(options.projectRoot, retestReport.report_path),
10003
+ join46(options.projectRoot, retestReport.report_path),
9243
10004
  buildPentestMarkdown(retestReport)
9244
10005
  );
9245
10006
  this.tracker.markStepCompleted(
@@ -9317,7 +10078,7 @@ var ProjectQuestionPhase = class {
9317
10078
 
9318
10079
  // src/workflows/root-cause-analysis.ts
9319
10080
  import { mkdir as mkdir16, writeFile as writeFile16 } from "fs/promises";
9320
- import { dirname as dirname20, join as join44 } from "path";
10081
+ import { dirname as dirname20, join as join47 } from "path";
9321
10082
  var DEFAULT_TITLE_SLUG = "root-cause-analysis";
9322
10083
  var RCA_SECTIONS = [
9323
10084
  "Summary",
@@ -9336,8 +10097,8 @@ var RootCauseAnalysisWorkflow = class {
9336
10097
  async run(options) {
9337
10098
  const title = deriveTitle(options.classification.request_text);
9338
10099
  const filename = `${toLocalTimestamp2(/* @__PURE__ */ new Date())}-${slugify2(title) || DEFAULT_TITLE_SLUG}.md`;
9339
- const relativePath = join44(PATHS.RCA_DIR, filename);
9340
- const outputPath = join44(options.projectRoot, relativePath);
10100
+ const relativePath = join47(PATHS.RCA_DIR, filename);
10101
+ const outputPath = join47(options.projectRoot, relativePath);
9341
10102
  await mkdir16(dirname20(outputPath), { recursive: true });
9342
10103
  await writeFile16(outputPath, buildRcaDocument(title, options.classification));
9343
10104
  return {
@@ -9445,7 +10206,12 @@ var SpecReviewPhase = class {
9445
10206
  var SpecWritingPhase = class {
9446
10207
  phase = "specification";
9447
10208
  async execute(context) {
9448
- return createPassResult(this.phase, "Specification written", context);
10209
+ const stageSummary = summarizeFeatureDevelopmentStage(context.feature_policy, "specification");
10210
+ return createPassResult(
10211
+ this.phase,
10212
+ stageSummary === null ? "Specification written" : `Specification written (${stageSummary})`,
10213
+ context
10214
+ );
9449
10215
  }
9450
10216
  };
9451
10217
 
@@ -9453,7 +10219,12 @@ var SpecWritingPhase = class {
9453
10219
  var StoryPlanningPhase = class {
9454
10220
  phase = "sequence-planning";
9455
10221
  async execute(context) {
9456
- return createPassResult(this.phase, "Story sequence planned", context);
10222
+ const stageSummary = summarizeFeatureDevelopmentStage(context.feature_policy, "planning");
10223
+ return createPassResult(
10224
+ this.phase,
10225
+ stageSummary === null ? "Story sequence planned" : `Story sequence planned (${stageSummary})`,
10226
+ context
10227
+ );
9457
10228
  }
9458
10229
  };
9459
10230
 
@@ -9461,14 +10232,30 @@ var StoryPlanningPhase = class {
9461
10232
  var VerificationPhase = class {
9462
10233
  phase = "verification-gates";
9463
10234
  async execute(context) {
9464
- return createPassResult(this.phase, "Verification gates passed", context);
10235
+ const profile = readProjectProfile(context.project_root);
10236
+ const stage = context.feature_policy?.stages.checks ?? null;
10237
+ const resolved = resolveFeatureDevelopmentCheckCommands(stage?.checks ?? null, profile);
10238
+ const stageSummary = summarizeFeatureDevelopmentStage(context.feature_policy, "checks");
10239
+ if (resolved.warnings.length > 0 && stage?.checks?.block_on_failure) {
10240
+ return createFailResult(
10241
+ this.phase,
10242
+ `Verification blocked (${resolved.warnings.join(" ")})`,
10243
+ context
10244
+ );
10245
+ }
10246
+ const commandSummary = resolved.commands.length > 0 ? `commands: ${resolved.commands.map((command) => command.command).join("; ")}` : "no configured commands";
10247
+ return createPassResult(
10248
+ this.phase,
10249
+ stageSummary === null ? `Verification gates passed (${commandSummary})` : `Verification gates passed (${stageSummary}; ${commandSummary})`,
10250
+ context
10251
+ );
9465
10252
  }
9466
10253
  };
9467
10254
 
9468
10255
  // src/pipeline/workflow-router.ts
9469
10256
  import { readFile as readFile21 } from "fs/promises";
9470
- import { existsSync as existsSync19 } from "fs";
9471
- import { join as join45, relative as relative8 } from "path";
10257
+ import { existsSync as existsSync20 } from "fs";
10258
+ import { join as join48, relative as relative8 } from "path";
9472
10259
  import fg6 from "fast-glob";
9473
10260
 
9474
10261
  // src/pipeline/lane-runner.ts
@@ -9492,38 +10279,38 @@ var DEFAULT_PHASES = {
9492
10279
 
9493
10280
  // src/pipeline/stream-truncator.ts
9494
10281
  import { appendFile, mkdir as mkdir18 } from "fs/promises";
9495
- import { join as join47, dirname as dirname22 } from "path";
10282
+ import { join as join50, dirname as dirname22 } from "path";
9496
10283
 
9497
10284
  // src/resolver/deduplicator.ts
9498
10285
  import { createHash as createHash9 } from "crypto";
9499
10286
  import { readFile as readFile23, writeFile as writeFile18, mkdir as mkdir19 } from "fs/promises";
9500
- import { join as join48, dirname as dirname23 } from "path";
10287
+ import { join as join51, dirname as dirname23 } from "path";
9501
10288
 
9502
10289
  // src/scripts/generator.ts
9503
10290
  import { chmodSync as chmodSync2 } from "fs";
9504
10291
  import { mkdir as mkdir20, writeFile as writeFile19 } from "fs/promises";
9505
- import { dirname as dirname24, join as join49 } from "path";
10292
+ import { dirname as dirname24, join as join52 } from "path";
9506
10293
 
9507
10294
  // src/skills/cache-manager.ts
9508
10295
  import { createHash as createHash10 } from "crypto";
9509
- import { mkdir as mkdir21, readFile as readFile24, readdir as readdir6, rm as rm2, stat as stat3, writeFile as writeFile20 } from "fs/promises";
9510
- import { join as join50 } from "path";
10296
+ import { mkdir as mkdir21, readFile as readFile24, readdir as readdir7, rm as rm2, stat as stat3, writeFile as writeFile20 } from "fs/promises";
10297
+ import { join as join53 } from "path";
9511
10298
  import fg8 from "fast-glob";
9512
10299
 
9513
10300
  // src/skills/index-generator.ts
9514
10301
  import { mkdir as mkdir22, readFile as readFile25, writeFile as writeFile21 } from "fs/promises";
9515
- import { dirname as dirname25, join as join51, relative as relative9 } from "path";
10302
+ import { dirname as dirname25, join as join54, relative as relative9 } from "path";
9516
10303
  import fg9 from "fast-glob";
9517
10304
 
9518
10305
  // src/skills/loader.ts
9519
10306
  import { readFile as readFile26 } from "fs/promises";
9520
- import { basename as basename7 } from "pathe";
10307
+ import { basename as basename8 } from "pathe";
9521
10308
 
9522
10309
  // src/update/audit.ts
9523
10310
  import { appendFileSync, mkdirSync as mkdirSync6 } from "fs";
9524
- import { dirname as dirname26, join as join52 } from "path";
10311
+ import { dirname as dirname26, join as join55 } from "path";
9525
10312
  function auditPath(projectRoot) {
9526
- return join52(projectRoot, PATHS.AUDIT_LOG);
10313
+ return join55(projectRoot, PATHS.AUDIT_LOG);
9527
10314
  }
9528
10315
  function ts() {
9529
10316
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -9545,16 +10332,16 @@ function appendAuditLogFailure(projectRoot, previous, target, error) {
9545
10332
  }
9546
10333
 
9547
10334
  // src/update/updater.ts
9548
- import { chmodSync as chmodSync3, existsSync as existsSync21, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "fs";
9549
- import { mkdtemp, readdir as readdir7, readFile as readFile27, rm as rm3 } from "fs/promises";
10335
+ import { chmodSync as chmodSync3, existsSync as existsSync22, mkdirSync as mkdirSync7, readFileSync as readFileSync14, writeFileSync as writeFileSync6 } from "fs";
10336
+ import { mkdtemp, readdir as readdir8, readFile as readFile27, rm as rm3 } from "fs/promises";
9550
10337
  import { tmpdir } from "os";
9551
- import { dirname as dirname27, join as join53, relative as relative10 } from "path";
10338
+ import { dirname as dirname27, join as join56, relative as relative10 } from "path";
9552
10339
  var FrameworkUpdater = class {
9553
10340
  constructor(options = {}) {
9554
10341
  this.options = options;
9555
10342
  }
9556
10343
  async run(projectRoot) {
9557
- const previousVersion = readText(join53(projectRoot, PATHS.FRAMEWORK_VERSION));
10344
+ const previousVersion = readText(join56(projectRoot, PATHS.FRAMEWORK_VERSION));
9558
10345
  const manifest = readManifest(projectRoot);
9559
10346
  const artifactPolicy = new Map(
9560
10347
  manifest?.generated_artifacts.map((artifact) => [artifact.path, artifact.auto_update]) ?? []
@@ -9564,13 +10351,13 @@ var FrameworkUpdater = class {
9564
10351
  const skipped = [];
9565
10352
  const newScripts = [];
9566
10353
  for (const candidate of candidates) {
9567
- const target = join53(projectRoot, candidate.path);
9568
- const existed = existsSync21(target);
10354
+ const target = join56(projectRoot, candidate.path);
10355
+ const existed = existsSync22(target);
9569
10356
  const autoUpdate = artifactPolicy.get(candidate.path) ?? candidate.autoUpdate;
9570
10357
  if (existed && autoUpdate === false) {
9571
10358
  skipped.push({
9572
10359
  path: candidate.path,
9573
- before: readFileSync13(target, "utf8"),
10360
+ before: readFileSync14(target, "utf8"),
9574
10361
  after: candidate.content
9575
10362
  });
9576
10363
  continue;
@@ -9585,9 +10372,9 @@ var FrameworkUpdater = class {
9585
10372
  newScripts.push(candidate.path);
9586
10373
  }
9587
10374
  }
9588
- mkdirSync7(dirname27(join53(projectRoot, PATHS.FRAMEWORK_VERSION)), { recursive: true });
10375
+ mkdirSync7(dirname27(join56(projectRoot, PATHS.FRAMEWORK_VERSION)), { recursive: true });
9589
10376
  writeFileSync6(
9590
- join53(projectRoot, PATHS.FRAMEWORK_VERSION),
10377
+ join56(projectRoot, PATHS.FRAMEWORK_VERSION),
9591
10378
  `version=${VERSION}
9592
10379
  updated_at=${(/* @__PURE__ */ new Date()).toISOString()}
9593
10380
  `
@@ -9610,7 +10397,7 @@ updated_at=${(/* @__PURE__ */ new Date()).toISOString()}
9610
10397
  if (profile === null) {
9611
10398
  throw new Error("Cannot update framework-managed artifacts without a project profile");
9612
10399
  }
9613
- const tempRoot = await mkdtemp(join53(tmpdir(), "paqad-ai-update-"));
10400
+ const tempRoot = await mkdtemp(join56(tmpdir(), "paqad-ai-update-"));
9614
10401
  try {
9615
10402
  const result = await new OnboardingOrchestrator().run({
9616
10403
  projectRoot: tempRoot,
@@ -9630,41 +10417,41 @@ updated_at=${(/* @__PURE__ */ new Date()).toISOString()}
9630
10417
  }
9631
10418
  };
9632
10419
  function readManifest(projectRoot) {
9633
- const path = join53(projectRoot, PATHS.ONBOARDING_MANIFEST);
9634
- if (!existsSync21(path)) {
10420
+ const path = join56(projectRoot, PATHS.ONBOARDING_MANIFEST);
10421
+ if (!existsSync22(path)) {
9635
10422
  return null;
9636
10423
  }
9637
- return JSON.parse(readFileSync13(path, "utf8"));
10424
+ return JSON.parse(readFileSync14(path, "utf8"));
9638
10425
  }
9639
10426
  function readProfile(projectRoot) {
9640
10427
  return readProjectProfile(projectRoot);
9641
10428
  }
9642
10429
  function readText(path) {
9643
- if (!existsSync21(path)) {
10430
+ if (!existsSync22(path)) {
9644
10431
  return null;
9645
10432
  }
9646
- const raw = readFileSync13(path, "utf8");
10433
+ const raw = readFileSync14(path, "utf8");
9647
10434
  const match = raw.match(/^version=(.+)$/m);
9648
10435
  return match ? match[1].trim() : raw.trim();
9649
10436
  }
9650
10437
  async function collectFiles(root, generated) {
9651
- const paths = generated.length > 0 ? generated : await walk3(root);
10438
+ const paths = generated.length > 0 ? generated : await walk4(root);
9652
10439
  return Promise.all(
9653
10440
  paths.map(async (file) => ({
9654
10441
  path: file,
9655
- content: await readFile27(join53(root, file), "utf8"),
10442
+ content: await readFile27(join56(root, file), "utf8"),
9656
10443
  autoUpdate: true,
9657
10444
  executable: file.startsWith("scripts/")
9658
10445
  }))
9659
10446
  );
9660
10447
  }
9661
- async function walk3(root, current = root) {
9662
- const entries = await readdir7(current, { withFileTypes: true });
10448
+ async function walk4(root, current = root) {
10449
+ const entries = await readdir8(current, { withFileTypes: true });
9663
10450
  const files = [];
9664
10451
  for (const entry of entries) {
9665
- const absolute = join53(current, entry.name);
10452
+ const absolute = join56(current, entry.name);
9666
10453
  if (entry.isDirectory()) {
9667
- files.push(...await walk3(root, absolute));
10454
+ files.push(...await walk4(root, absolute));
9668
10455
  continue;
9669
10456
  }
9670
10457
  files.push(relative10(root, absolute));
@@ -9673,31 +10460,31 @@ async function walk3(root, current = root) {
9673
10460
  }
9674
10461
 
9675
10462
  // src/verification/gates/documentation-freshness.ts
9676
- import { existsSync as existsSync22 } from "fs";
9677
- import { join as join54 } from "path";
10463
+ import { existsSync as existsSync23 } from "fs";
10464
+ import { join as join57 } from "path";
9678
10465
  var STALENESS_WINDOW_MS2 = 1e3 * 60 * 60 * 24 * 7;
9679
10466
 
9680
10467
  // src/patterns/pattern-store.ts
9681
10468
  import { readFile as readFile28, writeFile as writeFile22, mkdir as mkdir23, unlink } from "fs/promises";
9682
- import { join as join55, dirname as dirname28 } from "path";
10469
+ import { join as join58, dirname as dirname28 } from "path";
9683
10470
  import { homedir as homedir3 } from "os";
9684
- var GLOBAL_PATTERNS_DIR = join55(homedir3(), ".paqad", "patterns");
10471
+ var GLOBAL_PATTERNS_DIR = join58(homedir3(), ".paqad", "patterns");
9685
10472
  var PatternStore = class {
9686
10473
  get indexPath() {
9687
- return join55(GLOBAL_PATTERNS_DIR, "index.json");
10474
+ return join58(GLOBAL_PATTERNS_DIR, "index.json");
9688
10475
  }
9689
10476
  get entriesDir() {
9690
- return join55(GLOBAL_PATTERNS_DIR, "entries");
10477
+ return join58(GLOBAL_PATTERNS_DIR, "entries");
9691
10478
  }
9692
10479
  async save(pattern) {
9693
10480
  await mkdir23(this.entriesDir, { recursive: true });
9694
- const entryPath = join55(this.entriesDir, `${pattern.id}.json`);
10481
+ const entryPath = join58(this.entriesDir, `${pattern.id}.json`);
9695
10482
  await writeFile22(entryPath, JSON.stringify(pattern, null, 2), "utf8");
9696
10483
  await this.updateIndex(pattern);
9697
10484
  }
9698
10485
  async load(id) {
9699
10486
  try {
9700
- const raw = await readFile28(join55(this.entriesDir, `${id}.json`), "utf8");
10487
+ const raw = await readFile28(join58(this.entriesDir, `${id}.json`), "utf8");
9701
10488
  return JSON.parse(raw);
9702
10489
  } catch {
9703
10490
  return null;
@@ -9732,7 +10519,7 @@ var PatternStore = class {
9732
10519
  }
9733
10520
  async delete(id) {
9734
10521
  try {
9735
- await unlink(join55(this.entriesDir, `${id}.json`));
10522
+ await unlink(join58(this.entriesDir, `${id}.json`));
9736
10523
  } catch {
9737
10524
  }
9738
10525
  const index = await this.loadIndex();
@@ -9831,7 +10618,7 @@ ${p.solution}
9831
10618
  };
9832
10619
 
9833
10620
  // src/index.ts
9834
- var VERSION = "0.1.4";
10621
+ var VERSION = "0.1.5";
9835
10622
 
9836
10623
  // src/cli/commands/capabilities.ts
9837
10624
  import { Command } from "commander";
@@ -10010,12 +10797,13 @@ function createPacksCommand() {
10010
10797
 
10011
10798
  // src/cli/commands/refresh.ts
10012
10799
  import { Command as Command7 } from "commander";
10013
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
10014
- import { join as join56 } from "path";
10800
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync7 } from "fs";
10801
+ import { join as join59 } from "path";
10015
10802
  function createRefreshCommand() {
10016
10803
  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) => {
10017
- const shouldRefreshDesignSystem = options.designSystem ?? true;
10018
- const shouldRefreshStack = options.stack ?? true;
10804
+ const hasExplicitTarget = options.designSystem === true || options.stack === true;
10805
+ const shouldRefreshDesignSystem = hasExplicitTarget ? options.designSystem === true : true;
10806
+ const shouldRefreshStack = hasExplicitTarget ? options.stack === true : true;
10019
10807
  if (shouldRefreshDesignSystem) {
10020
10808
  await new DesignTokenService().writeDocs(options.projectRoot);
10021
10809
  }
@@ -10047,14 +10835,14 @@ function createRefreshCommand() {
10047
10835
  });
10048
10836
  }
10049
10837
  function writeRefreshDrift(projectRoot, refreshDrift) {
10050
- const path = join56(projectRoot, PATHS.STACK_DRIFT);
10838
+ const path = join59(projectRoot, PATHS.STACK_DRIFT);
10051
10839
  const current = readExistingJson(path);
10052
10840
  writeFileSync7(path, `${JSON.stringify({ ...current ?? {}, ...refreshDrift }, null, 2)}
10053
10841
  `);
10054
10842
  }
10055
10843
  function readExistingJson(path) {
10056
10844
  try {
10057
- return JSON.parse(readFileSync14(path, "utf8"));
10845
+ return JSON.parse(readFileSync15(path, "utf8"));
10058
10846
  } catch {
10059
10847
  return null;
10060
10848
  }