paqad-ai 0.0.1 → 0.0.4
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 +1259 -231
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +160 -22
- package/dist/index.js +1273 -251
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/runtime/hooks/block-destructive.sh +26 -2
- package/runtime/hooks/context-hit-tracker.sh +20 -5
- package/runtime/hooks/pre-commit-check.sh +19 -8
- package/runtime/hooks/pre-compact-preserve.sh +8 -2
- package/runtime/hooks/skill-cache-check.mjs +12 -0
- package/runtime/hooks/track-file-changes.sh +8 -2
- package/runtime/templates/module-scaffold/business.md.hbs +29 -0
- package/runtime/templates/module-scaffold/technical.md.hbs +37 -0
- package/runtime/templates/runner-scripts/analyze-context-hits.sh.hbs +20 -5
- package/runtime/templates/runner-scripts/build-handover-package.sh.hbs +3 -0
- package/runtime/templates/runner-scripts/check-stack-drift.sh.hbs +3 -0
- package/runtime/templates/runner-scripts/document-project.sh.hbs +3 -0
- package/runtime/templates/runner-scripts/export-theme.sh.hbs +3 -0
- package/runtime/templates/runner-scripts/extract-ui-inventory.sh.hbs +3 -0
- package/runtime/templates/runner-scripts/refresh-design-docs.sh.hbs +3 -0
- package/runtime/templates/runner-scripts/verify.sh.hbs +39 -5
package/dist/cli/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { realpathSync } from "fs";
|
|
|
5
5
|
import { pathToFileURL } from "url";
|
|
6
6
|
|
|
7
7
|
// src/cli/program.ts
|
|
8
|
-
import { Command as
|
|
8
|
+
import { Command as Command7 } from "commander";
|
|
9
9
|
|
|
10
10
|
// src/adapters/shared/base-adapter.ts
|
|
11
11
|
import { readFile as readFile2 } from "fs/promises";
|
|
@@ -367,6 +367,8 @@ var AdapterFactory = class {
|
|
|
367
367
|
// src/core/constants/paths.ts
|
|
368
368
|
var PATHS = {
|
|
369
369
|
AGENCY_DIR: ".agency",
|
|
370
|
+
AGENCY_CACHE_DIR: ".agency/cache",
|
|
371
|
+
AGENCY_SESSION_DIR: ".agency/session",
|
|
370
372
|
PROJECT_PROFILE: ".agency/project-profile.yaml",
|
|
371
373
|
DETECTION_REPORT: ".agency/detection-report.json",
|
|
372
374
|
ONBOARDING_MANIFEST: ".agency/onboarding-manifest.json",
|
|
@@ -377,11 +379,16 @@ var PATHS = {
|
|
|
377
379
|
CHANGED_FILES: ".agency/session/changed-files.json",
|
|
378
380
|
CONTEXT_HIT_LOG: ".agency/session/context-hit-log.json",
|
|
379
381
|
SKILL_CACHE_DIR: ".agency/cache/skill-results",
|
|
382
|
+
STACK_SNAPSHOT: ".agency/cache/stack-snapshot.json",
|
|
383
|
+
DOC_PROGRESS: ".agency/doc-progress.json",
|
|
384
|
+
DOC_RUN_SESSION: ".agency/session/doc-run.json",
|
|
380
385
|
INDEXES_DIR: ".agency/indexes",
|
|
381
386
|
DOCS_DIR: "docs",
|
|
382
387
|
RULES_DIR: "docs/rules",
|
|
383
|
-
|
|
384
|
-
|
|
388
|
+
INSTRUCTIONS_DIR: "docs/instructions",
|
|
389
|
+
ARCHITECTURE_DIR: "docs/instructions/architecture",
|
|
390
|
+
DESIGN_SYSTEM_DIR: "docs/instructions/design-system",
|
|
391
|
+
DESIGN_TOKENS_FILE: "docs/instructions/architecture/design-tokens.json",
|
|
385
392
|
MODULES_DIR: "docs/modules",
|
|
386
393
|
BENCHMARKS_DIR: "docs/benchmarks",
|
|
387
394
|
TECH_DEBT_DIR: "docs/tech-debt",
|
|
@@ -618,12 +625,119 @@ var Detector = class {
|
|
|
618
625
|
}
|
|
619
626
|
};
|
|
620
627
|
|
|
621
|
-
// src/
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
628
|
+
// src/design-tokens/defaults.ts
|
|
629
|
+
var DEFAULT_DESIGN_TOKENS = {
|
|
630
|
+
color: {
|
|
631
|
+
primary: { $value: "#0F766E", $type: "color", $description: "Primary brand color." },
|
|
632
|
+
secondary: { $value: "#0F172A", $type: "color", $description: "Secondary brand color." },
|
|
633
|
+
accent: { $value: "#F59E0B", $type: "color", $description: "Accent color." },
|
|
634
|
+
surface: { $value: "#FFFFFF", $type: "color", $description: "Default surface color." },
|
|
635
|
+
text: {
|
|
636
|
+
default: { $value: "#0F172A", $type: "color", $description: "Default text color." },
|
|
637
|
+
muted: { $value: "#475569", $type: "color", $description: "Muted text color." }
|
|
638
|
+
},
|
|
639
|
+
semantic: {
|
|
640
|
+
success: { $value: "#16A34A", $type: "color" },
|
|
641
|
+
warning: { $value: "#EAB308", $type: "color" },
|
|
642
|
+
error: { $value: "#DC2626", $type: "color" },
|
|
643
|
+
info: { $value: "#2563EB", $type: "color" }
|
|
644
|
+
}
|
|
645
|
+
},
|
|
646
|
+
typography: {
|
|
647
|
+
fontFamily: {
|
|
648
|
+
body: { $value: "Inter, system-ui, sans-serif", $type: "fontFamily" },
|
|
649
|
+
display: { $value: "Satoshi, system-ui, sans-serif", $type: "fontFamily" },
|
|
650
|
+
mono: { $value: "JetBrains Mono, monospace", $type: "fontFamily" }
|
|
651
|
+
},
|
|
652
|
+
heading: {
|
|
653
|
+
h1: {
|
|
654
|
+
$value: {
|
|
655
|
+
fontFamily: "{typography.fontFamily.display.$value}",
|
|
656
|
+
fontSize: "3rem",
|
|
657
|
+
fontWeight: 700,
|
|
658
|
+
lineHeight: 1.1
|
|
659
|
+
},
|
|
660
|
+
$type: "typography"
|
|
661
|
+
},
|
|
662
|
+
h2: {
|
|
663
|
+
$value: {
|
|
664
|
+
fontFamily: "{typography.fontFamily.display.$value}",
|
|
665
|
+
fontSize: "2.25rem",
|
|
666
|
+
fontWeight: 600,
|
|
667
|
+
lineHeight: 1.2
|
|
668
|
+
},
|
|
669
|
+
$type: "typography"
|
|
670
|
+
},
|
|
671
|
+
body: {
|
|
672
|
+
$value: {
|
|
673
|
+
fontFamily: "{typography.fontFamily.body.$value}",
|
|
674
|
+
fontSize: "1rem",
|
|
675
|
+
fontWeight: 400,
|
|
676
|
+
lineHeight: 1.5
|
|
677
|
+
},
|
|
678
|
+
$type: "typography"
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
},
|
|
682
|
+
spacing: {
|
|
683
|
+
xs: { $value: "0.25rem", $type: "dimension" },
|
|
684
|
+
sm: { $value: "0.5rem", $type: "dimension" },
|
|
685
|
+
md: { $value: "1rem", $type: "dimension" },
|
|
686
|
+
lg: { $value: "1.5rem", $type: "dimension" },
|
|
687
|
+
xl: { $value: "2rem", $type: "dimension" }
|
|
688
|
+
},
|
|
689
|
+
radius: {
|
|
690
|
+
sm: { $value: "0.25rem", $type: "dimension" },
|
|
691
|
+
md: { $value: "0.5rem", $type: "dimension" },
|
|
692
|
+
lg: { $value: "1rem", $type: "dimension" },
|
|
693
|
+
full: { $value: "9999px", $type: "dimension" }
|
|
694
|
+
},
|
|
695
|
+
shadow: {
|
|
696
|
+
sm: {
|
|
697
|
+
$value: { color: "#0000001a", offsetX: "0px", offsetY: "1px", blur: "2px", spread: "0px" },
|
|
698
|
+
$type: "shadow"
|
|
699
|
+
},
|
|
700
|
+
md: {
|
|
701
|
+
$value: {
|
|
702
|
+
color: "#0000001a",
|
|
703
|
+
offsetX: "0px",
|
|
704
|
+
offsetY: "4px",
|
|
705
|
+
blur: "6px",
|
|
706
|
+
spread: "-1px"
|
|
707
|
+
},
|
|
708
|
+
$type: "shadow"
|
|
709
|
+
}
|
|
710
|
+
},
|
|
711
|
+
motion: {
|
|
712
|
+
duration: {
|
|
713
|
+
fast: { $value: "150ms", $type: "duration" },
|
|
714
|
+
normal: { $value: "300ms", $type: "duration" }
|
|
715
|
+
},
|
|
716
|
+
easing: {
|
|
717
|
+
emphasis: { $value: [0.2, 0, 0, 1], $type: "cubicBezier" }
|
|
718
|
+
}
|
|
719
|
+
},
|
|
720
|
+
components: {
|
|
721
|
+
button: {
|
|
722
|
+
radius: { $value: "{radius.md.$value}", $type: "dimension" },
|
|
723
|
+
paddingX: { $value: "{spacing.md.$value}", $type: "dimension" },
|
|
724
|
+
paddingY: { $value: "{spacing.sm.$value}", $type: "dimension" }
|
|
725
|
+
},
|
|
726
|
+
card: {
|
|
727
|
+
radius: { $value: "{radius.lg.$value}", $type: "dimension" },
|
|
728
|
+
shadow: { $value: "{shadow.md.$value}", $type: "shadow" }
|
|
729
|
+
}
|
|
730
|
+
},
|
|
731
|
+
accessibility: {
|
|
732
|
+
contrast: { $value: "WCAG 2.1 AA", $type: "string" },
|
|
733
|
+
focusRing: { $value: "2px solid {color.accent.$value}", $type: "string" },
|
|
734
|
+
reduceMotion: { $value: true, $type: "boolean" }
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
// src/design-tokens/service.ts
|
|
739
|
+
import { mkdir, readFile as readFile3, writeFile } from "fs/promises";
|
|
740
|
+
import { dirname as dirname2, join as join6 } from "path";
|
|
627
741
|
|
|
628
742
|
// src/validators/validator.ts
|
|
629
743
|
import Ajv from "ajv";
|
|
@@ -766,6 +880,117 @@ var detection_report_schema_default = {
|
|
|
766
880
|
}
|
|
767
881
|
};
|
|
768
882
|
|
|
883
|
+
// src/validators/schemas/design-tokens.schema.json
|
|
884
|
+
var design_tokens_schema_default = {
|
|
885
|
+
$id: "design-tokens",
|
|
886
|
+
type: "object",
|
|
887
|
+
additionalProperties: {
|
|
888
|
+
$ref: "#/$defs/node"
|
|
889
|
+
},
|
|
890
|
+
$defs: {
|
|
891
|
+
leaf: {
|
|
892
|
+
type: "object",
|
|
893
|
+
required: ["$value", "$type"],
|
|
894
|
+
properties: {
|
|
895
|
+
$value: {},
|
|
896
|
+
$type: { type: "string" },
|
|
897
|
+
$description: { type: "string" }
|
|
898
|
+
},
|
|
899
|
+
additionalProperties: true
|
|
900
|
+
},
|
|
901
|
+
group: {
|
|
902
|
+
type: "object",
|
|
903
|
+
minProperties: 1,
|
|
904
|
+
additionalProperties: {
|
|
905
|
+
$ref: "#/$defs/node"
|
|
906
|
+
}
|
|
907
|
+
},
|
|
908
|
+
node: {
|
|
909
|
+
anyOf: [{ $ref: "#/$defs/leaf" }, { $ref: "#/$defs/group" }]
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
|
|
914
|
+
// src/validators/schemas/doc-progress.schema.json
|
|
915
|
+
var doc_progress_schema_default = {
|
|
916
|
+
$id: "doc-progress",
|
|
917
|
+
type: "object",
|
|
918
|
+
required: ["schema_version", "generated_by", "framework_version", "modules", "global"],
|
|
919
|
+
properties: {
|
|
920
|
+
schema_version: { const: "1" },
|
|
921
|
+
generated_by: { const: "paqad-ai" },
|
|
922
|
+
framework_version: { type: "string" },
|
|
923
|
+
modules: {
|
|
924
|
+
type: "object",
|
|
925
|
+
additionalProperties: {
|
|
926
|
+
type: "object",
|
|
927
|
+
additionalProperties: { $ref: "#/$defs/entry" }
|
|
928
|
+
}
|
|
929
|
+
},
|
|
930
|
+
global: {
|
|
931
|
+
type: "object",
|
|
932
|
+
additionalProperties: {
|
|
933
|
+
type: "object",
|
|
934
|
+
additionalProperties: { $ref: "#/$defs/entry" }
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
},
|
|
938
|
+
$defs: {
|
|
939
|
+
state: {
|
|
940
|
+
enum: ["not_started", "generating", "done", "failed"]
|
|
941
|
+
},
|
|
942
|
+
entry: {
|
|
943
|
+
type: "object",
|
|
944
|
+
required: [
|
|
945
|
+
"output_path",
|
|
946
|
+
"state",
|
|
947
|
+
"started_at",
|
|
948
|
+
"completed_at",
|
|
949
|
+
"source_files",
|
|
950
|
+
"source_hash",
|
|
951
|
+
"tokens_used",
|
|
952
|
+
"error"
|
|
953
|
+
],
|
|
954
|
+
properties: {
|
|
955
|
+
output_path: { type: "string" },
|
|
956
|
+
state: { $ref: "#/$defs/state" },
|
|
957
|
+
started_at: { type: ["string", "null"] },
|
|
958
|
+
completed_at: { type: ["string", "null"] },
|
|
959
|
+
source_files: {
|
|
960
|
+
type: "array",
|
|
961
|
+
items: { type: "string" }
|
|
962
|
+
},
|
|
963
|
+
source_hash: { type: ["string", "null"] },
|
|
964
|
+
tokens_used: { type: ["number", "null"] },
|
|
965
|
+
error: { type: ["string", "null"] },
|
|
966
|
+
design_tokens: {
|
|
967
|
+
type: "object",
|
|
968
|
+
required: [
|
|
969
|
+
"extraction_state",
|
|
970
|
+
"total_tokens_found",
|
|
971
|
+
"placeholder_count",
|
|
972
|
+
"populated_count",
|
|
973
|
+
"placeholder_keys"
|
|
974
|
+
],
|
|
975
|
+
properties: {
|
|
976
|
+
extraction_state: { $ref: "#/$defs/state" },
|
|
977
|
+
total_tokens_found: { type: "number" },
|
|
978
|
+
placeholder_count: { type: "number" },
|
|
979
|
+
populated_count: { type: "number" },
|
|
980
|
+
placeholder_keys: {
|
|
981
|
+
type: "array",
|
|
982
|
+
items: { type: "string" }
|
|
983
|
+
}
|
|
984
|
+
},
|
|
985
|
+
additionalProperties: false
|
|
986
|
+
}
|
|
987
|
+
},
|
|
988
|
+
additionalProperties: false
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
additionalProperties: false
|
|
992
|
+
};
|
|
993
|
+
|
|
769
994
|
// src/validators/schemas/error-catalog.schema.json
|
|
770
995
|
var error_catalog_schema_default = {
|
|
771
996
|
$id: "error-catalog",
|
|
@@ -1137,6 +1362,8 @@ var skill_frontmatter_schema_default = {
|
|
|
1137
1362
|
var SCHEMAS = [
|
|
1138
1363
|
project_profile_schema_default,
|
|
1139
1364
|
detection_report_schema_default,
|
|
1365
|
+
design_tokens_schema_default,
|
|
1366
|
+
doc_progress_schema_default,
|
|
1140
1367
|
onboarding_manifest_schema_default,
|
|
1141
1368
|
handoff_artifact_schema_default,
|
|
1142
1369
|
adversarial_review_report_schema_default,
|
|
@@ -1182,7 +1409,214 @@ var SchemaValidator = class {
|
|
|
1182
1409
|
}
|
|
1183
1410
|
};
|
|
1184
1411
|
|
|
1412
|
+
// src/design-tokens/service.ts
|
|
1413
|
+
var DesignTokenService = class {
|
|
1414
|
+
constructor(validator = new SchemaValidator()) {
|
|
1415
|
+
this.validator = validator;
|
|
1416
|
+
}
|
|
1417
|
+
async seed(projectRoot) {
|
|
1418
|
+
const target = join6(projectRoot, PATHS.DESIGN_TOKENS_FILE);
|
|
1419
|
+
await mkdir(dirname2(target), { recursive: true });
|
|
1420
|
+
await writeFile(target, `${JSON.stringify(DEFAULT_DESIGN_TOKENS, null, 2)}
|
|
1421
|
+
`, {
|
|
1422
|
+
flag: "wx"
|
|
1423
|
+
}).catch((error) => {
|
|
1424
|
+
if (error.code !== "EEXIST") {
|
|
1425
|
+
throw error;
|
|
1426
|
+
}
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1429
|
+
async load(projectRoot) {
|
|
1430
|
+
const target = join6(projectRoot, PATHS.DESIGN_TOKENS_FILE);
|
|
1431
|
+
const raw = await readFile3(target, "utf8");
|
|
1432
|
+
const parsed = JSON.parse(raw);
|
|
1433
|
+
const validation = this.validator.validate("design-tokens", parsed);
|
|
1434
|
+
if (!validation.valid) {
|
|
1435
|
+
throw new Error(
|
|
1436
|
+
`Invalid design token file: ${validation.errors.map((error) => error.message).join("; ")}`
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1439
|
+
return parsed;
|
|
1440
|
+
}
|
|
1441
|
+
async generateDocs(projectRoot) {
|
|
1442
|
+
const tokens = await this.load(projectRoot);
|
|
1443
|
+
const flattened = flattenTokens(tokens);
|
|
1444
|
+
const sections = groupTokens(flattened);
|
|
1445
|
+
return [
|
|
1446
|
+
{
|
|
1447
|
+
path: join6(PATHS.DESIGN_SYSTEM_DIR, "tokens.md"),
|
|
1448
|
+
content: buildTokensMarkdown(flattened)
|
|
1449
|
+
},
|
|
1450
|
+
{
|
|
1451
|
+
path: join6(PATHS.DESIGN_SYSTEM_DIR, "components.md"),
|
|
1452
|
+
content: buildSectionMarkdown("Component Defaults", sections.components)
|
|
1453
|
+
},
|
|
1454
|
+
{
|
|
1455
|
+
path: join6(PATHS.DESIGN_SYSTEM_DIR, "motion.md"),
|
|
1456
|
+
content: buildSectionMarkdown("Motion", sections.motion)
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
path: join6(PATHS.DESIGN_SYSTEM_DIR, "accessibility.md"),
|
|
1460
|
+
content: buildSectionMarkdown("Accessibility", sections.accessibility)
|
|
1461
|
+
},
|
|
1462
|
+
{
|
|
1463
|
+
path: join6(PATHS.DESIGN_SYSTEM_DIR, "responsive.md"),
|
|
1464
|
+
content: buildResponsiveMarkdown(sections.spacing)
|
|
1465
|
+
},
|
|
1466
|
+
{
|
|
1467
|
+
path: join6(PATHS.DESIGN_SYSTEM_DIR, "patterns.md"),
|
|
1468
|
+
content: buildPatternsMarkdown(flattened)
|
|
1469
|
+
}
|
|
1470
|
+
];
|
|
1471
|
+
}
|
|
1472
|
+
async writeDocs(projectRoot) {
|
|
1473
|
+
const docs = await this.generateDocs(projectRoot);
|
|
1474
|
+
await Promise.all(
|
|
1475
|
+
docs.map(async (artifact) => {
|
|
1476
|
+
const target = join6(projectRoot, artifact.path);
|
|
1477
|
+
await mkdir(dirname2(target), { recursive: true });
|
|
1478
|
+
await writeFile(target, artifact.content);
|
|
1479
|
+
})
|
|
1480
|
+
);
|
|
1481
|
+
return docs.map((artifact) => artifact.path);
|
|
1482
|
+
}
|
|
1483
|
+
async exportTheme(projectRoot, stack) {
|
|
1484
|
+
const flattened = flattenTokens(await this.load(projectRoot));
|
|
1485
|
+
const cssVariables = flattened.map((token) => ` --${token.key.replace(/\./g, "-")}: ${stringifyValue(token.value)};`).join("\n");
|
|
1486
|
+
const tailwindEntries = flattened.map((token) => ` '${token.key.replace(/\./g, "-")}' : '${stringifyValue(token.value)}',`).join("\n");
|
|
1487
|
+
const flutterEntries = flattened.filter((token) => token.type === "color").map(
|
|
1488
|
+
(token) => ` static const String ${toIdentifier(token.key)} = '${stringifyValue(token.value)}';`
|
|
1489
|
+
).join("\n");
|
|
1490
|
+
const artifacts = [
|
|
1491
|
+
{
|
|
1492
|
+
path: ".agency/theme/theme.css",
|
|
1493
|
+
content: `:root {
|
|
1494
|
+
${cssVariables}
|
|
1495
|
+
}
|
|
1496
|
+
`
|
|
1497
|
+
},
|
|
1498
|
+
{
|
|
1499
|
+
path: ".agency/theme/tailwind.theme.cjs",
|
|
1500
|
+
content: `module.exports = {
|
|
1501
|
+
theme: {
|
|
1502
|
+
extend: {
|
|
1503
|
+
colors: {
|
|
1504
|
+
${tailwindEntries}
|
|
1505
|
+
},
|
|
1506
|
+
},
|
|
1507
|
+
},
|
|
1508
|
+
};
|
|
1509
|
+
`
|
|
1510
|
+
}
|
|
1511
|
+
];
|
|
1512
|
+
if (stack === "flutter") {
|
|
1513
|
+
artifacts.push({
|
|
1514
|
+
path: ".agency/theme/theme_tokens.dart",
|
|
1515
|
+
content: `class ThemeTokens {
|
|
1516
|
+
${flutterEntries}
|
|
1517
|
+
}
|
|
1518
|
+
`
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
return artifacts;
|
|
1522
|
+
}
|
|
1523
|
+
async writeThemeExports(projectRoot, stack) {
|
|
1524
|
+
const artifacts = await this.exportTheme(projectRoot, stack);
|
|
1525
|
+
await Promise.all(
|
|
1526
|
+
artifacts.map(async (artifact) => {
|
|
1527
|
+
const target = join6(projectRoot, artifact.path);
|
|
1528
|
+
await mkdir(dirname2(target), { recursive: true });
|
|
1529
|
+
await writeFile(target, artifact.content);
|
|
1530
|
+
})
|
|
1531
|
+
);
|
|
1532
|
+
return artifacts.map((artifact) => artifact.path);
|
|
1533
|
+
}
|
|
1534
|
+
};
|
|
1535
|
+
function flattenTokens(node, pathSegments = [], tokens = []) {
|
|
1536
|
+
for (const [key, value] of Object.entries(node)) {
|
|
1537
|
+
const nextPath = [...pathSegments, key];
|
|
1538
|
+
if (isTokenLeaf(value)) {
|
|
1539
|
+
tokens.push({
|
|
1540
|
+
key: nextPath.join("."),
|
|
1541
|
+
type: value.$type,
|
|
1542
|
+
value: value.$value,
|
|
1543
|
+
description: value.$description
|
|
1544
|
+
});
|
|
1545
|
+
continue;
|
|
1546
|
+
}
|
|
1547
|
+
flattenTokens(value, nextPath, tokens);
|
|
1548
|
+
}
|
|
1549
|
+
return tokens.sort((left, right) => left.key.localeCompare(right.key));
|
|
1550
|
+
}
|
|
1551
|
+
function isTokenLeaf(value) {
|
|
1552
|
+
return typeof value === "object" && value !== null && "$value" in value && "$type" in value && typeof value.$type === "string";
|
|
1553
|
+
}
|
|
1554
|
+
function groupTokens(tokens) {
|
|
1555
|
+
return {
|
|
1556
|
+
components: tokens.filter((token) => token.key.startsWith("components.")),
|
|
1557
|
+
motion: tokens.filter((token) => token.key.startsWith("motion.")),
|
|
1558
|
+
accessibility: tokens.filter((token) => token.key.startsWith("accessibility.")),
|
|
1559
|
+
spacing: tokens.filter((token) => token.key.startsWith("spacing."))
|
|
1560
|
+
};
|
|
1561
|
+
}
|
|
1562
|
+
function buildTokensMarkdown(tokens) {
|
|
1563
|
+
const lines = ["# Design Tokens", "", "| Token | Type | Value |", "| --- | --- | --- |"];
|
|
1564
|
+
for (const token of tokens) {
|
|
1565
|
+
lines.push(`| \`${token.key}\` | \`${token.type}\` | \`${stringifyValue(token.value)}\` |`);
|
|
1566
|
+
}
|
|
1567
|
+
return `${lines.join("\n")}
|
|
1568
|
+
`;
|
|
1569
|
+
}
|
|
1570
|
+
function buildSectionMarkdown(title, tokens) {
|
|
1571
|
+
const lines = [`# ${title}`, ""];
|
|
1572
|
+
if (tokens.length === 0) {
|
|
1573
|
+
lines.push("No tokens defined yet.", "");
|
|
1574
|
+
return lines.join("\n");
|
|
1575
|
+
}
|
|
1576
|
+
for (const token of tokens) {
|
|
1577
|
+
lines.push(`- \`${token.key}\`: \`${stringifyValue(token.value)}\``);
|
|
1578
|
+
}
|
|
1579
|
+
lines.push("");
|
|
1580
|
+
return lines.join("\n");
|
|
1581
|
+
}
|
|
1582
|
+
function buildResponsiveMarkdown(tokens) {
|
|
1583
|
+
const lines = ["# Responsive Design", "", "## Spacing Scale", ""];
|
|
1584
|
+
for (const token of tokens) {
|
|
1585
|
+
lines.push(`- \`${token.key}\`: \`${stringifyValue(token.value)}\``);
|
|
1586
|
+
}
|
|
1587
|
+
lines.push("", "Use the spacing scale as the basis for layout density and breakpoints.", "");
|
|
1588
|
+
return lines.join("\n");
|
|
1589
|
+
}
|
|
1590
|
+
function buildPatternsMarkdown(tokens) {
|
|
1591
|
+
const highlighted = tokens.filter(
|
|
1592
|
+
(token) => ["color.primary", "color.secondary", "typography.heading.h1", "components.button.radius"].some(
|
|
1593
|
+
(prefix) => token.key.startsWith(prefix)
|
|
1594
|
+
)
|
|
1595
|
+
);
|
|
1596
|
+
const lines = ["# Design Patterns", "", "## Framework Guidance", ""];
|
|
1597
|
+
for (const token of highlighted) {
|
|
1598
|
+
lines.push(`- Base pattern from \`${token.key}\`: \`${stringifyValue(token.value)}\``);
|
|
1599
|
+
}
|
|
1600
|
+
lines.push(
|
|
1601
|
+
"",
|
|
1602
|
+
"Keep generated UI aligned with these tokens before introducing new variants.",
|
|
1603
|
+
""
|
|
1604
|
+
);
|
|
1605
|
+
return lines.join("\n");
|
|
1606
|
+
}
|
|
1607
|
+
function stringifyValue(value) {
|
|
1608
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
1609
|
+
}
|
|
1610
|
+
function toIdentifier(value) {
|
|
1611
|
+
return value.replace(/[^a-zA-Z0-9]+(.)/g, (_, character) => character.toUpperCase());
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1185
1614
|
// src/health/checker.ts
|
|
1615
|
+
import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync4, statSync } from "fs";
|
|
1616
|
+
import { access } from "fs/promises";
|
|
1617
|
+
import { constants as fsConstants } from "fs";
|
|
1618
|
+
import { join as join7 } from "path";
|
|
1619
|
+
import YAML from "yaml";
|
|
1186
1620
|
var STALENESS_WINDOW_MS = 1e3 * 60 * 60 * 24 * 7;
|
|
1187
1621
|
var HealthChecker = class {
|
|
1188
1622
|
validator = new SchemaValidator();
|
|
@@ -1216,7 +1650,7 @@ var HealthChecker = class {
|
|
|
1216
1650
|
};
|
|
1217
1651
|
}
|
|
1218
1652
|
readProfile(projectRoot) {
|
|
1219
|
-
const path =
|
|
1653
|
+
const path = join7(projectRoot, PATHS.PROJECT_PROFILE);
|
|
1220
1654
|
if (!existsSync4(path)) {
|
|
1221
1655
|
return null;
|
|
1222
1656
|
}
|
|
@@ -1227,7 +1661,7 @@ var HealthChecker = class {
|
|
|
1227
1661
|
}
|
|
1228
1662
|
}
|
|
1229
1663
|
detectModules(projectRoot) {
|
|
1230
|
-
const modulesRoot =
|
|
1664
|
+
const modulesRoot = join7(projectRoot, "docs/modules");
|
|
1231
1665
|
if (!existsSync4(modulesRoot)) {
|
|
1232
1666
|
return [];
|
|
1233
1667
|
}
|
|
@@ -1241,7 +1675,7 @@ var HealthChecker = class {
|
|
|
1241
1675
|
"scripts",
|
|
1242
1676
|
"docs/modules/core"
|
|
1243
1677
|
];
|
|
1244
|
-
const missing = required.filter((
|
|
1678
|
+
const missing = required.filter((relative7) => !existsSync4(join7(projectRoot, relative7)));
|
|
1245
1679
|
return missing.length === 0 ? pass("Framework artifacts exist", "Framework artifacts are present") : fail(
|
|
1246
1680
|
"Framework artifacts exist",
|
|
1247
1681
|
`Missing framework artifacts: ${missing.join(", ")}`,
|
|
@@ -1272,7 +1706,7 @@ var HealthChecker = class {
|
|
|
1272
1706
|
"docs/modules/core/integration/contracts.md",
|
|
1273
1707
|
"docs/modules/core/error-catalog.md"
|
|
1274
1708
|
];
|
|
1275
|
-
const missing = required.filter((
|
|
1709
|
+
const missing = required.filter((relative7) => !existsSync4(join7(projectRoot, relative7)));
|
|
1276
1710
|
return missing.length === 0 ? pass("Docs scaffold exists", "Documentation scaffold is complete") : fail(
|
|
1277
1711
|
"Docs scaffold exists",
|
|
1278
1712
|
`Missing scaffold files: ${missing.join(", ")}`,
|
|
@@ -1281,9 +1715,9 @@ var HealthChecker = class {
|
|
|
1281
1715
|
}
|
|
1282
1716
|
checkIndexesCurrent(projectRoot) {
|
|
1283
1717
|
const missing = REGISTRIES.filter(
|
|
1284
|
-
(registry) => !existsSync4(
|
|
1718
|
+
(registry) => !existsSync4(join7(projectRoot, "docs", registry))
|
|
1285
1719
|
);
|
|
1286
|
-
const statusPath =
|
|
1720
|
+
const statusPath = join7(projectRoot, ".agency/indexes/registry-status.json");
|
|
1287
1721
|
if (missing.length > 0 || !existsSync4(statusPath)) {
|
|
1288
1722
|
return fail(
|
|
1289
1723
|
"Indexes are current",
|
|
@@ -1299,7 +1733,7 @@ var HealthChecker = class {
|
|
|
1299
1733
|
const missing = [];
|
|
1300
1734
|
const nonExecutable = [];
|
|
1301
1735
|
for (const script of required) {
|
|
1302
|
-
const path =
|
|
1736
|
+
const path = join7(projectRoot, "scripts", script);
|
|
1303
1737
|
if (!existsSync4(path)) {
|
|
1304
1738
|
missing.push(script);
|
|
1305
1739
|
continue;
|
|
@@ -1318,7 +1752,7 @@ var HealthChecker = class {
|
|
|
1318
1752
|
}
|
|
1319
1753
|
checkHooks(projectRoot) {
|
|
1320
1754
|
const candidates = [".claude/settings.hooks.json", ".codex/hooks.json", ".gemini/hooks.json"];
|
|
1321
|
-
return candidates.some((candidate) => existsSync4(
|
|
1755
|
+
return candidates.some((candidate) => existsSync4(join7(projectRoot, candidate))) ? pass("Hooks are active", "Hook registration files are present") : fail(
|
|
1322
1756
|
"Hooks are active",
|
|
1323
1757
|
"No hook registration files were found",
|
|
1324
1758
|
"Regenerate adapter hook configuration."
|
|
@@ -1326,7 +1760,7 @@ var HealthChecker = class {
|
|
|
1326
1760
|
}
|
|
1327
1761
|
checkAdapterConfig(projectRoot) {
|
|
1328
1762
|
const configs = [PATHS.CLAUDE_MD, PATHS.AGENTS_MD, PATHS.GEMINI_MD];
|
|
1329
|
-
const existing = configs.filter((config) => existsSync4(
|
|
1763
|
+
const existing = configs.filter((config) => existsSync4(join7(projectRoot, config)));
|
|
1330
1764
|
return existing.length > 0 ? pass("Adapter config is present", "Adapter config files are present") : fail(
|
|
1331
1765
|
"Adapter config is present",
|
|
1332
1766
|
"No adapter config files were found",
|
|
@@ -1356,7 +1790,7 @@ var HealthChecker = class {
|
|
|
1356
1790
|
);
|
|
1357
1791
|
}
|
|
1358
1792
|
checkStableFrameworkPaths(projectRoot) {
|
|
1359
|
-
const frameworkPath =
|
|
1793
|
+
const frameworkPath = join7(projectRoot, PATHS.FRAMEWORK_PATH);
|
|
1360
1794
|
if (!existsSync4(frameworkPath)) {
|
|
1361
1795
|
return fail(
|
|
1362
1796
|
"Stable framework paths only",
|
|
@@ -1384,7 +1818,7 @@ var HealthChecker = class {
|
|
|
1384
1818
|
}
|
|
1385
1819
|
checkUiDocs(projectRoot, modules) {
|
|
1386
1820
|
const missing = modules.filter(
|
|
1387
|
-
(moduleName) => !existsSync4(
|
|
1821
|
+
(moduleName) => !existsSync4(join7(projectRoot, "docs/modules", moduleName, "ui/screens.md")) || !existsSync4(join7(projectRoot, "docs/modules", moduleName, "ui/components.md")) || !existsSync4(join7(projectRoot, "docs/modules", moduleName, "ui/states.md"))
|
|
1388
1822
|
);
|
|
1389
1823
|
return missing.length === 0 ? pass("UI docs present", "UI docs are present for all modules with UI docs") : fail(
|
|
1390
1824
|
"UI docs present",
|
|
@@ -1394,7 +1828,7 @@ var HealthChecker = class {
|
|
|
1394
1828
|
}
|
|
1395
1829
|
checkApiDocs(projectRoot, modules) {
|
|
1396
1830
|
const missing = modules.filter(
|
|
1397
|
-
(moduleName) => !existsSync4(
|
|
1831
|
+
(moduleName) => !existsSync4(join7(projectRoot, "docs/modules", moduleName, "api/endpoints.md")) || !existsSync4(join7(projectRoot, "docs/modules", moduleName, "api/schemas.md")) || !existsSync4(join7(projectRoot, "docs/modules", moduleName, "api/error-codes.md"))
|
|
1398
1832
|
);
|
|
1399
1833
|
return missing.length === 0 ? pass("API docs present", "API docs are present for all modules with APIs") : fail(
|
|
1400
1834
|
"API docs present",
|
|
@@ -1404,7 +1838,7 @@ var HealthChecker = class {
|
|
|
1404
1838
|
}
|
|
1405
1839
|
checkIntegrationDocs(projectRoot, modules) {
|
|
1406
1840
|
const missing = modules.filter(
|
|
1407
|
-
(moduleName) => !existsSync4(
|
|
1841
|
+
(moduleName) => !existsSync4(join7(projectRoot, "docs/modules", moduleName, "integration/events.md")) || !existsSync4(join7(projectRoot, "docs/modules", moduleName, "integration/contracts.md"))
|
|
1408
1842
|
);
|
|
1409
1843
|
return missing.length === 0 ? pass("Integration docs present", "Integration docs are present for all modules") : fail(
|
|
1410
1844
|
"Integration docs present",
|
|
@@ -1414,7 +1848,7 @@ var HealthChecker = class {
|
|
|
1414
1848
|
}
|
|
1415
1849
|
checkErrorCatalog(projectRoot, modules) {
|
|
1416
1850
|
const missing = modules.filter(
|
|
1417
|
-
(moduleName) => !existsSync4(
|
|
1851
|
+
(moduleName) => !existsSync4(join7(projectRoot, "docs/modules", moduleName, "error-catalog.md"))
|
|
1418
1852
|
);
|
|
1419
1853
|
return missing.length === 0 ? pass("Error catalog present", "Error catalogs are present for all modules") : fail(
|
|
1420
1854
|
"Error catalog present",
|
|
@@ -1431,7 +1865,7 @@ var HealthChecker = class {
|
|
|
1431
1865
|
);
|
|
1432
1866
|
}
|
|
1433
1867
|
const candidates = [".claude/settings.mcp.json", ".codex/mcp.json", ".gemini/mcp.json"];
|
|
1434
|
-
const existing = candidates.filter((candidate) => existsSync4(
|
|
1868
|
+
const existing = candidates.filter((candidate) => existsSync4(join7(projectRoot, candidate)));
|
|
1435
1869
|
const expectedServers = getServersForStack(profile.routing.stack, profile.routing.capabilities).filter((server) => server.name !== "figma").map((server) => server.name);
|
|
1436
1870
|
if (existing.length === 0) {
|
|
1437
1871
|
return warn(
|
|
@@ -1443,7 +1877,7 @@ var HealthChecker = class {
|
|
|
1443
1877
|
const configured = /* @__PURE__ */ new Set();
|
|
1444
1878
|
for (const path of existing) {
|
|
1445
1879
|
try {
|
|
1446
|
-
const parsed = JSON.parse(readFileSync4(
|
|
1880
|
+
const parsed = JSON.parse(readFileSync4(join7(projectRoot, path), "utf8"));
|
|
1447
1881
|
Object.keys(parsed.mcpServers ?? {}).forEach((server) => configured.add(server));
|
|
1448
1882
|
} catch {
|
|
1449
1883
|
continue;
|
|
@@ -1457,7 +1891,7 @@ var HealthChecker = class {
|
|
|
1457
1891
|
);
|
|
1458
1892
|
}
|
|
1459
1893
|
checkSkillCache(projectRoot) {
|
|
1460
|
-
const cacheDir =
|
|
1894
|
+
const cacheDir = join7(projectRoot, PATHS.SKILL_CACHE_DIR);
|
|
1461
1895
|
if (!existsSync4(cacheDir)) {
|
|
1462
1896
|
return warn(
|
|
1463
1897
|
"Skill cache healthy",
|
|
@@ -1467,7 +1901,7 @@ var HealthChecker = class {
|
|
|
1467
1901
|
}
|
|
1468
1902
|
const corrupt = readdirSync(cacheDir).filter((entry) => entry.endsWith(".json")).filter((entry) => {
|
|
1469
1903
|
try {
|
|
1470
|
-
JSON.parse(readFileSync4(
|
|
1904
|
+
JSON.parse(readFileSync4(join7(cacheDir, entry), "utf8"));
|
|
1471
1905
|
return false;
|
|
1472
1906
|
} catch {
|
|
1473
1907
|
return true;
|
|
@@ -1480,7 +1914,7 @@ var HealthChecker = class {
|
|
|
1480
1914
|
);
|
|
1481
1915
|
}
|
|
1482
1916
|
checkContextHitRate(projectRoot, profile) {
|
|
1483
|
-
const path =
|
|
1917
|
+
const path = join7(projectRoot, PATHS.CONTEXT_HIT_LOG);
|
|
1484
1918
|
if (!existsSync4(path) || profile === null) {
|
|
1485
1919
|
return pass("Context hit rate acceptable", "No recent context logs yet");
|
|
1486
1920
|
}
|
|
@@ -1502,7 +1936,7 @@ var HealthChecker = class {
|
|
|
1502
1936
|
}
|
|
1503
1937
|
}
|
|
1504
1938
|
buildEfficiencySummary(projectRoot, profile) {
|
|
1505
|
-
const path =
|
|
1939
|
+
const path = join7(projectRoot, PATHS.CONTEXT_HIT_LOG);
|
|
1506
1940
|
let contextHitRate = 1;
|
|
1507
1941
|
if (existsSync4(path)) {
|
|
1508
1942
|
try {
|
|
@@ -1514,7 +1948,7 @@ var HealthChecker = class {
|
|
|
1514
1948
|
}
|
|
1515
1949
|
return {
|
|
1516
1950
|
context_hit_rate: contextHitRate,
|
|
1517
|
-
skill_cache_hit_rate: existsSync4(
|
|
1951
|
+
skill_cache_hit_rate: existsSync4(join7(projectRoot, PATHS.SKILL_CACHE_DIR)) ? 1 : 0,
|
|
1518
1952
|
mcp_usage_rate: profile?.efficiency?.mcp_first ? 1 : 0
|
|
1519
1953
|
};
|
|
1520
1954
|
}
|
|
@@ -1543,7 +1977,7 @@ function isStale(timestampMs) {
|
|
|
1543
1977
|
function walk(root) {
|
|
1544
1978
|
const results = [];
|
|
1545
1979
|
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
1546
|
-
const path =
|
|
1980
|
+
const path = join7(root, entry.name);
|
|
1547
1981
|
if (entry.isDirectory()) {
|
|
1548
1982
|
results.push(...walk(path));
|
|
1549
1983
|
continue;
|
|
@@ -1559,37 +1993,37 @@ import { mkdirSync as mkdirSync2 } from "fs";
|
|
|
1559
1993
|
// src/onboarding/manifest-writer.ts
|
|
1560
1994
|
import { mkdirSync, writeFileSync } from "fs";
|
|
1561
1995
|
import { homedir } from "os";
|
|
1562
|
-
import { dirname as
|
|
1996
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
1563
1997
|
import YAML2 from "yaml";
|
|
1564
1998
|
function writeProjectProfile(projectRoot, profile) {
|
|
1565
|
-
const path =
|
|
1566
|
-
mkdirSync(
|
|
1999
|
+
const path = join8(projectRoot, PATHS.PROJECT_PROFILE);
|
|
2000
|
+
mkdirSync(dirname3(path), { recursive: true });
|
|
1567
2001
|
writeFileSync(path, YAML2.stringify(profile));
|
|
1568
2002
|
return path;
|
|
1569
2003
|
}
|
|
1570
2004
|
function writeDetectionReport(projectRoot, report) {
|
|
1571
|
-
const path =
|
|
1572
|
-
mkdirSync(
|
|
2005
|
+
const path = join8(projectRoot, PATHS.DETECTION_REPORT);
|
|
2006
|
+
mkdirSync(dirname3(path), { recursive: true });
|
|
1573
2007
|
writeFileSync(path, JSON.stringify(report, null, 2));
|
|
1574
2008
|
return path;
|
|
1575
2009
|
}
|
|
1576
2010
|
function writeFrameworkMetadata(projectRoot, version) {
|
|
1577
|
-
mkdirSync(
|
|
2011
|
+
mkdirSync(dirname3(join8(projectRoot, PATHS.FRAMEWORK_VERSION)), {
|
|
1578
2012
|
recursive: true
|
|
1579
2013
|
});
|
|
1580
|
-
writeFileSync(
|
|
2014
|
+
writeFileSync(join8(projectRoot, PATHS.FRAMEWORK_VERSION), `${version}
|
|
1581
2015
|
`);
|
|
1582
|
-
writeFileSync(
|
|
2016
|
+
writeFileSync(join8(projectRoot, PATHS.FRAMEWORK_PATH), `${resolveFrameworkInstallPath()}
|
|
1583
2017
|
`);
|
|
1584
2018
|
}
|
|
1585
2019
|
function writeOnboardingManifest(projectRoot, manifest) {
|
|
1586
|
-
const path =
|
|
1587
|
-
mkdirSync(
|
|
2020
|
+
const path = join8(projectRoot, PATHS.ONBOARDING_MANIFEST);
|
|
2021
|
+
mkdirSync(dirname3(path), { recursive: true });
|
|
1588
2022
|
writeFileSync(path, JSON.stringify(manifest, null, 2));
|
|
1589
2023
|
return path;
|
|
1590
2024
|
}
|
|
1591
2025
|
function resolveFrameworkInstallPath() {
|
|
1592
|
-
return process.env.PAQAD_FRAMEWORK_HOME ??
|
|
2026
|
+
return process.env.PAQAD_FRAMEWORK_HOME ?? join8(homedir(), ".paqad-ai/current");
|
|
1593
2027
|
}
|
|
1594
2028
|
|
|
1595
2029
|
// src/install/bootstrap.ts
|
|
@@ -1604,15 +2038,675 @@ function bootstrapFramework(projectRoot) {
|
|
|
1604
2038
|
};
|
|
1605
2039
|
}
|
|
1606
2040
|
|
|
2041
|
+
// src/introspection/cache.ts
|
|
2042
|
+
import { createHash } from "crypto";
|
|
2043
|
+
import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
|
|
2044
|
+
import { dirname as dirname4, join as join9 } from "path";
|
|
2045
|
+
var StackSnapshotCache = class {
|
|
2046
|
+
async read(projectRoot) {
|
|
2047
|
+
try {
|
|
2048
|
+
const raw = await readFile4(join9(projectRoot, PATHS.STACK_SNAPSHOT), "utf8");
|
|
2049
|
+
return JSON.parse(raw);
|
|
2050
|
+
} catch {
|
|
2051
|
+
return null;
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
async write(projectRoot, snapshot) {
|
|
2055
|
+
const target = join9(projectRoot, PATHS.STACK_SNAPSHOT);
|
|
2056
|
+
await mkdir2(dirname4(target), { recursive: true });
|
|
2057
|
+
await writeFile2(target, `${JSON.stringify(snapshot, null, 2)}
|
|
2058
|
+
`);
|
|
2059
|
+
}
|
|
2060
|
+
async hashFiles(projectRoot, relativePaths) {
|
|
2061
|
+
const hashes = {};
|
|
2062
|
+
for (const relativePath of relativePaths) {
|
|
2063
|
+
try {
|
|
2064
|
+
const content = await readFile4(join9(projectRoot, relativePath), "utf8");
|
|
2065
|
+
hashes[relativePath] = `sha256:${createHash("sha256").update(content).digest("hex")}`;
|
|
2066
|
+
} catch {
|
|
2067
|
+
continue;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
return hashes;
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
|
|
2074
|
+
// src/introspection/parsers/shared.ts
|
|
2075
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
2076
|
+
import { join as join10 } from "path";
|
|
2077
|
+
async function readJsonFile2(projectRoot, relativePath) {
|
|
2078
|
+
try {
|
|
2079
|
+
return JSON.parse(await readFile5(join10(projectRoot, relativePath), "utf8"));
|
|
2080
|
+
} catch {
|
|
2081
|
+
return null;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
async function readTextFile(projectRoot, relativePath) {
|
|
2085
|
+
try {
|
|
2086
|
+
return await readFile5(join10(projectRoot, relativePath), "utf8");
|
|
2087
|
+
} catch {
|
|
2088
|
+
return null;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
// src/introspection/parsers/composer.ts
|
|
2093
|
+
async function parseComposerProject(projectRoot) {
|
|
2094
|
+
const composerJson = await readJsonFile2(projectRoot, "composer.json");
|
|
2095
|
+
const composerLock = await readJsonFile2(projectRoot, "composer.lock");
|
|
2096
|
+
if (composerJson === null) {
|
|
2097
|
+
return null;
|
|
2098
|
+
}
|
|
2099
|
+
const lockedVersions = /* @__PURE__ */ new Map();
|
|
2100
|
+
for (const pkg of composerLock?.packages ?? []) {
|
|
2101
|
+
lockedVersions.set(pkg.name, pkg.version);
|
|
2102
|
+
}
|
|
2103
|
+
for (const pkg of composerLock?.["packages-dev"] ?? []) {
|
|
2104
|
+
lockedVersions.set(pkg.name, pkg.version);
|
|
2105
|
+
}
|
|
2106
|
+
return {
|
|
2107
|
+
toolchain: {
|
|
2108
|
+
ecosystem: "php",
|
|
2109
|
+
package_manager: "composer",
|
|
2110
|
+
lockfile: "composer.lock"
|
|
2111
|
+
},
|
|
2112
|
+
packages: [
|
|
2113
|
+
...Object.entries(composerJson.require ?? {}).map(([name, version_constraint]) => ({
|
|
2114
|
+
name,
|
|
2115
|
+
version_constraint,
|
|
2116
|
+
locked_version: lockedVersions.get(name) ?? version_constraint,
|
|
2117
|
+
ecosystem: "php",
|
|
2118
|
+
is_dev: false
|
|
2119
|
+
})),
|
|
2120
|
+
...Object.entries(composerJson["require-dev"] ?? {}).map(([name, version_constraint]) => ({
|
|
2121
|
+
name,
|
|
2122
|
+
version_constraint,
|
|
2123
|
+
locked_version: lockedVersions.get(name) ?? version_constraint,
|
|
2124
|
+
ecosystem: "php",
|
|
2125
|
+
is_dev: true
|
|
2126
|
+
}))
|
|
2127
|
+
].sort((left, right) => left.name.localeCompare(right.name))
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
// src/introspection/parsers/dart.ts
|
|
2132
|
+
import YAML3 from "yaml";
|
|
2133
|
+
async function parseDartProject(projectRoot) {
|
|
2134
|
+
const pubspecText = await readTextFile(projectRoot, "pubspec.yaml");
|
|
2135
|
+
if (pubspecText === null) {
|
|
2136
|
+
return null;
|
|
2137
|
+
}
|
|
2138
|
+
const pubspec = YAML3.parse(pubspecText);
|
|
2139
|
+
const pubspecLockText = await readTextFile(projectRoot, "pubspec.lock");
|
|
2140
|
+
const pubspecLock = pubspecLockText ? YAML3.parse(pubspecLockText) : null;
|
|
2141
|
+
const lockedVersions = /* @__PURE__ */ new Map();
|
|
2142
|
+
for (const [name, value] of Object.entries(pubspecLock?.packages ?? {})) {
|
|
2143
|
+
if (value.version) {
|
|
2144
|
+
lockedVersions.set(name, value.version);
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
return {
|
|
2148
|
+
toolchain: {
|
|
2149
|
+
ecosystem: "dart",
|
|
2150
|
+
package_manager: "pub",
|
|
2151
|
+
lockfile: "pubspec.lock"
|
|
2152
|
+
},
|
|
2153
|
+
packages: [
|
|
2154
|
+
...buildPackages(pubspec.dependencies ?? {}, lockedVersions, false),
|
|
2155
|
+
...buildPackages(pubspec.dev_dependencies ?? {}, lockedVersions, true)
|
|
2156
|
+
].sort((left, right) => left.name.localeCompare(right.name))
|
|
2157
|
+
};
|
|
2158
|
+
}
|
|
2159
|
+
function buildPackages(dependencies, lockedVersions, is_dev) {
|
|
2160
|
+
return Object.entries(dependencies).map(([name, value]) => {
|
|
2161
|
+
const version_constraint = typeof value === "string" ? value : value.sdk !== void 0 ? `sdk:${value.sdk}` : "unknown";
|
|
2162
|
+
return {
|
|
2163
|
+
name,
|
|
2164
|
+
version_constraint,
|
|
2165
|
+
locked_version: lockedVersions.get(name) ?? version_constraint,
|
|
2166
|
+
ecosystem: "dart",
|
|
2167
|
+
is_dev
|
|
2168
|
+
};
|
|
2169
|
+
});
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
// src/introspection/parsers/npm.ts
|
|
2173
|
+
async function parseNpmProject(projectRoot) {
|
|
2174
|
+
const packageJson = await readJsonFile2(projectRoot, "package.json");
|
|
2175
|
+
const packageLock = await readJsonFile2(projectRoot, "package-lock.json");
|
|
2176
|
+
if (packageJson === null) {
|
|
2177
|
+
return null;
|
|
2178
|
+
}
|
|
2179
|
+
const lockedVersions = /* @__PURE__ */ new Map();
|
|
2180
|
+
for (const [key, value] of Object.entries(packageLock?.packages ?? {})) {
|
|
2181
|
+
if (!key.startsWith("node_modules/") || value.version === void 0) {
|
|
2182
|
+
continue;
|
|
2183
|
+
}
|
|
2184
|
+
lockedVersions.set(key.replace(/^node_modules\//, ""), value.version);
|
|
2185
|
+
}
|
|
2186
|
+
return {
|
|
2187
|
+
toolchain: {
|
|
2188
|
+
ecosystem: "node",
|
|
2189
|
+
package_manager: "npm",
|
|
2190
|
+
lockfile: "package-lock.json"
|
|
2191
|
+
},
|
|
2192
|
+
packages: buildNodePackages(packageJson, lockedVersions)
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
2195
|
+
function buildNodePackages(packageJson, lockedVersions) {
|
|
2196
|
+
const runtime = Object.entries(packageJson.dependencies ?? {}).map(
|
|
2197
|
+
([name, version_constraint]) => ({
|
|
2198
|
+
name,
|
|
2199
|
+
version_constraint,
|
|
2200
|
+
locked_version: lockedVersions.get(name) ?? version_constraint,
|
|
2201
|
+
ecosystem: "node",
|
|
2202
|
+
is_dev: false
|
|
2203
|
+
})
|
|
2204
|
+
);
|
|
2205
|
+
const dev = Object.entries(packageJson.devDependencies ?? {}).map(
|
|
2206
|
+
([name, version_constraint]) => ({
|
|
2207
|
+
name,
|
|
2208
|
+
version_constraint,
|
|
2209
|
+
locked_version: lockedVersions.get(name) ?? version_constraint,
|
|
2210
|
+
ecosystem: "node",
|
|
2211
|
+
is_dev: true
|
|
2212
|
+
})
|
|
2213
|
+
);
|
|
2214
|
+
return [...runtime, ...dev].sort((left, right) => left.name.localeCompare(right.name));
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
// src/introspection/parsers/pnpm.ts
|
|
2218
|
+
import YAML4 from "yaml";
|
|
2219
|
+
async function parsePnpmProject(projectRoot) {
|
|
2220
|
+
const packageJson = await readJsonFile2(projectRoot, "package.json");
|
|
2221
|
+
const lockfile = await readTextFile(projectRoot, "pnpm-lock.yaml");
|
|
2222
|
+
if (packageJson === null) {
|
|
2223
|
+
return null;
|
|
2224
|
+
}
|
|
2225
|
+
const parsedLock = lockfile ? YAML4.parse(lockfile) : null;
|
|
2226
|
+
const lockedVersions = /* @__PURE__ */ new Map();
|
|
2227
|
+
for (const [key, value] of Object.entries(parsedLock?.packages ?? {})) {
|
|
2228
|
+
const match = key.match(/^\/?(@?[^@/]+(?:\/[^@/]+)?)@/);
|
|
2229
|
+
if (match?.[1] && value.version) {
|
|
2230
|
+
lockedVersions.set(match[1], value.version);
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
return {
|
|
2234
|
+
toolchain: {
|
|
2235
|
+
ecosystem: "node",
|
|
2236
|
+
package_manager: "pnpm",
|
|
2237
|
+
lockfile: "pnpm-lock.yaml"
|
|
2238
|
+
},
|
|
2239
|
+
packages: buildNodePackages2(packageJson, lockedVersions)
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2242
|
+
function buildNodePackages2(packageJson, lockedVersions) {
|
|
2243
|
+
const runtime = Object.entries(packageJson.dependencies ?? {}).map(
|
|
2244
|
+
([name, version_constraint]) => ({
|
|
2245
|
+
name,
|
|
2246
|
+
version_constraint,
|
|
2247
|
+
locked_version: lockedVersions.get(name) ?? version_constraint,
|
|
2248
|
+
ecosystem: "node",
|
|
2249
|
+
is_dev: false
|
|
2250
|
+
})
|
|
2251
|
+
);
|
|
2252
|
+
const dev = Object.entries(packageJson.devDependencies ?? {}).map(
|
|
2253
|
+
([name, version_constraint]) => ({
|
|
2254
|
+
name,
|
|
2255
|
+
version_constraint,
|
|
2256
|
+
locked_version: lockedVersions.get(name) ?? version_constraint,
|
|
2257
|
+
ecosystem: "node",
|
|
2258
|
+
is_dev: true
|
|
2259
|
+
})
|
|
2260
|
+
);
|
|
2261
|
+
return [...runtime, ...dev].sort((left, right) => left.name.localeCompare(right.name));
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
// src/introspection/stack-introspector.ts
|
|
2265
|
+
var StackIntrospector = class {
|
|
2266
|
+
cache = new StackSnapshotCache();
|
|
2267
|
+
async snapshot(projectRoot) {
|
|
2268
|
+
const currentHashes = await this.cache.hashFiles(projectRoot, [
|
|
2269
|
+
"package.json",
|
|
2270
|
+
"pnpm-lock.yaml",
|
|
2271
|
+
"package-lock.json",
|
|
2272
|
+
"composer.json",
|
|
2273
|
+
"composer.lock",
|
|
2274
|
+
"pubspec.yaml",
|
|
2275
|
+
"pubspec.lock"
|
|
2276
|
+
]);
|
|
2277
|
+
const cached = await this.cache.read(projectRoot);
|
|
2278
|
+
if (cached !== null && JSON.stringify(cached.source_hashes) === JSON.stringify(currentHashes)) {
|
|
2279
|
+
return cached;
|
|
2280
|
+
}
|
|
2281
|
+
const results = await Promise.all([
|
|
2282
|
+
parsePnpmProject(projectRoot),
|
|
2283
|
+
parseNpmProject(projectRoot),
|
|
2284
|
+
parseComposerProject(projectRoot),
|
|
2285
|
+
parseDartProject(projectRoot)
|
|
2286
|
+
]);
|
|
2287
|
+
const toolchains = results.flatMap((result) => result ? [result.toolchain] : []);
|
|
2288
|
+
const packages = results.flatMap((result) => result ? result.packages : []);
|
|
2289
|
+
const snapshot = {
|
|
2290
|
+
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2291
|
+
source_hashes: currentHashes,
|
|
2292
|
+
toolchains,
|
|
2293
|
+
packages
|
|
2294
|
+
};
|
|
2295
|
+
await this.cache.write(projectRoot, snapshot);
|
|
2296
|
+
return snapshot;
|
|
2297
|
+
}
|
|
2298
|
+
};
|
|
2299
|
+
|
|
2300
|
+
// src/document/pipeline.ts
|
|
2301
|
+
import { mkdir as mkdir4, readdir as readdir2, writeFile as writeFile4 } from "fs/promises";
|
|
2302
|
+
import { dirname as dirname6, join as join14, relative } from "path";
|
|
2303
|
+
|
|
2304
|
+
// src/onboarding/registry-generator.ts
|
|
2305
|
+
import { readdir } from "fs/promises";
|
|
2306
|
+
import { join as join11 } from "path";
|
|
2307
|
+
async function generateInitialRegistries(projectRoot) {
|
|
2308
|
+
const modules = await discoverModules(projectRoot);
|
|
2309
|
+
return [
|
|
2310
|
+
{
|
|
2311
|
+
path: ".agency/indexes/registry-status.json",
|
|
2312
|
+
content: JSON.stringify(
|
|
2313
|
+
{
|
|
2314
|
+
generated: true,
|
|
2315
|
+
modules,
|
|
2316
|
+
generated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2317
|
+
},
|
|
2318
|
+
null,
|
|
2319
|
+
2
|
|
2320
|
+
),
|
|
2321
|
+
autoUpdate: true
|
|
2322
|
+
},
|
|
2323
|
+
{
|
|
2324
|
+
path: ".agency/cache/skill-results/.gitkeep",
|
|
2325
|
+
content: "",
|
|
2326
|
+
autoUpdate: true
|
|
2327
|
+
},
|
|
2328
|
+
{
|
|
2329
|
+
path: PATHS.GLOSSARY,
|
|
2330
|
+
content: "# Glossary\n\n",
|
|
2331
|
+
autoUpdate: true
|
|
2332
|
+
},
|
|
2333
|
+
...REGISTRIES.map((registry) => ({
|
|
2334
|
+
path: join11("docs", registry),
|
|
2335
|
+
content: registry === "module-registry.md" ? buildModuleRegistry(modules) : `# ${registry}
|
|
2336
|
+
|
|
2337
|
+
`,
|
|
2338
|
+
autoUpdate: true
|
|
2339
|
+
}))
|
|
2340
|
+
];
|
|
2341
|
+
}
|
|
2342
|
+
async function discoverModules(projectRoot) {
|
|
2343
|
+
const candidates = [
|
|
2344
|
+
join11(projectRoot, "docs/modules"),
|
|
2345
|
+
join11(projectRoot, "app"),
|
|
2346
|
+
join11(projectRoot, "lib")
|
|
2347
|
+
];
|
|
2348
|
+
const modules = /* @__PURE__ */ new Set(["core"]);
|
|
2349
|
+
for (const root of candidates) {
|
|
2350
|
+
try {
|
|
2351
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
2352
|
+
for (const entry of entries) {
|
|
2353
|
+
if (!entry.isDirectory()) {
|
|
2354
|
+
continue;
|
|
2355
|
+
}
|
|
2356
|
+
const name = entry.name;
|
|
2357
|
+
if (name !== "" && !name.startsWith(".")) {
|
|
2358
|
+
modules.add(name);
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
} catch {
|
|
2362
|
+
continue;
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
return Array.from(modules).sort();
|
|
2366
|
+
}
|
|
2367
|
+
function buildModuleRegistry(modules) {
|
|
2368
|
+
return ["# module-registry.md", "", ...modules.map((module) => `- ${module}`), ""].join("\n");
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
// src/document/progress-tracker.ts
|
|
2372
|
+
import { mkdir as mkdir3, readFile as readFile6, rm, writeFile as writeFile3 } from "fs/promises";
|
|
2373
|
+
import { dirname as dirname5, join as join12 } from "path";
|
|
2374
|
+
var DocumentProgressTracker = class {
|
|
2375
|
+
constructor(validator = new SchemaValidator()) {
|
|
2376
|
+
this.validator = validator;
|
|
2377
|
+
}
|
|
2378
|
+
async load(projectRoot) {
|
|
2379
|
+
try {
|
|
2380
|
+
const parsed = JSON.parse(
|
|
2381
|
+
await readFile6(join12(projectRoot, PATHS.DOC_PROGRESS), "utf8")
|
|
2382
|
+
);
|
|
2383
|
+
const validation = this.validator.validate("doc-progress", parsed);
|
|
2384
|
+
if (!validation.valid) {
|
|
2385
|
+
throw new Error(validation.errors.map((error) => error.message).join("; "));
|
|
2386
|
+
}
|
|
2387
|
+
return parsed;
|
|
2388
|
+
} catch {
|
|
2389
|
+
return this.createEmpty();
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
async save(projectRoot, progress) {
|
|
2393
|
+
const target = join12(projectRoot, PATHS.DOC_PROGRESS);
|
|
2394
|
+
await mkdir3(dirname5(target), { recursive: true });
|
|
2395
|
+
await writeFile3(target, `${JSON.stringify(progress, null, 2)}
|
|
2396
|
+
`);
|
|
2397
|
+
}
|
|
2398
|
+
async resetGeneratingEntries(projectRoot, progress) {
|
|
2399
|
+
const entries = collectEntries(progress);
|
|
2400
|
+
await Promise.all(
|
|
2401
|
+
entries.map(async (entry) => {
|
|
2402
|
+
if (entry.state !== "generating") {
|
|
2403
|
+
return;
|
|
2404
|
+
}
|
|
2405
|
+
entry.state = "not_started";
|
|
2406
|
+
entry.started_at = null;
|
|
2407
|
+
entry.completed_at = null;
|
|
2408
|
+
entry.error = null;
|
|
2409
|
+
await rm(join12(projectRoot, entry.output_path), { force: true });
|
|
2410
|
+
})
|
|
2411
|
+
);
|
|
2412
|
+
}
|
|
2413
|
+
createEntry(output_path, source_files) {
|
|
2414
|
+
return {
|
|
2415
|
+
output_path,
|
|
2416
|
+
state: "not_started",
|
|
2417
|
+
started_at: null,
|
|
2418
|
+
completed_at: null,
|
|
2419
|
+
source_files,
|
|
2420
|
+
source_hash: null,
|
|
2421
|
+
tokens_used: null,
|
|
2422
|
+
error: null
|
|
2423
|
+
};
|
|
2424
|
+
}
|
|
2425
|
+
createEmpty() {
|
|
2426
|
+
return {
|
|
2427
|
+
schema_version: "1",
|
|
2428
|
+
generated_by: "paqad-ai",
|
|
2429
|
+
framework_version: VERSION,
|
|
2430
|
+
modules: {},
|
|
2431
|
+
global: {}
|
|
2432
|
+
};
|
|
2433
|
+
}
|
|
2434
|
+
};
|
|
2435
|
+
function collectEntries(progress) {
|
|
2436
|
+
return [
|
|
2437
|
+
...Object.values(progress.modules).flatMap((group) => Object.values(group)),
|
|
2438
|
+
...Object.values(progress.global).flatMap((group) => Object.values(group))
|
|
2439
|
+
];
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
// src/document/staleness.ts
|
|
2443
|
+
import { createHash as createHash2 } from "crypto";
|
|
2444
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
2445
|
+
import { join as join13 } from "path";
|
|
2446
|
+
async function hashSourceFiles(projectRoot, sourceFiles) {
|
|
2447
|
+
const hash = createHash2("sha1");
|
|
2448
|
+
for (const relativePath of sourceFiles) {
|
|
2449
|
+
try {
|
|
2450
|
+
hash.update(await readFile7(join13(projectRoot, relativePath), "utf8"));
|
|
2451
|
+
} catch {
|
|
2452
|
+
hash.update(`missing:${relativePath}`);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
return `sha1:${hash.digest("hex").slice(0, 7)}`;
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
// src/document/pipeline.ts
|
|
2459
|
+
var DocumentPipeline = class {
|
|
2460
|
+
tracker = new DocumentProgressTracker();
|
|
2461
|
+
async run(options) {
|
|
2462
|
+
const progress = await this.tracker.load(options.projectRoot);
|
|
2463
|
+
await this.tracker.resetGeneratingEntries(options.projectRoot, progress);
|
|
2464
|
+
const stackSnapshot = options.refreshStack === true || options.scope === "full" ? await new StackIntrospector().snapshot(options.projectRoot) : null;
|
|
2465
|
+
if (options.refreshTokens === true || options.scope === "ui" || options.scope === "full") {
|
|
2466
|
+
await new DesignTokenService().writeDocs(options.projectRoot);
|
|
2467
|
+
}
|
|
2468
|
+
const sourceFiles = await gatherSourceFiles(options.projectRoot);
|
|
2469
|
+
const modules = await discoverModules(options.projectRoot);
|
|
2470
|
+
const generated = [];
|
|
2471
|
+
const skipped = [];
|
|
2472
|
+
if (shouldGenerateModuleDocs(options.scope)) {
|
|
2473
|
+
for (const moduleName of modules) {
|
|
2474
|
+
progress.modules[moduleName] ??= {};
|
|
2475
|
+
const businessPath = join14(PATHS.MODULES_DIR, moduleName, "business.md");
|
|
2476
|
+
const technicalPath = join14(PATHS.MODULES_DIR, moduleName, "technical.md");
|
|
2477
|
+
progress.modules[moduleName].business ??= this.tracker.createEntry(
|
|
2478
|
+
businessPath,
|
|
2479
|
+
sourceFiles
|
|
2480
|
+
);
|
|
2481
|
+
progress.modules[moduleName].technical ??= this.tracker.createEntry(
|
|
2482
|
+
technicalPath,
|
|
2483
|
+
sourceFiles
|
|
2484
|
+
);
|
|
2485
|
+
if (shouldGenerateBusinessDoc(options.scope)) {
|
|
2486
|
+
await processEntry({
|
|
2487
|
+
projectRoot: options.projectRoot,
|
|
2488
|
+
entry: progress.modules[moduleName].business,
|
|
2489
|
+
content: buildBusinessDoc(moduleName, sourceFiles),
|
|
2490
|
+
generated,
|
|
2491
|
+
skipped,
|
|
2492
|
+
dryRun: options.dryRun === true
|
|
2493
|
+
});
|
|
2494
|
+
}
|
|
2495
|
+
if (shouldGenerateTechnicalDoc(options.scope)) {
|
|
2496
|
+
await processEntry({
|
|
2497
|
+
projectRoot: options.projectRoot,
|
|
2498
|
+
entry: progress.modules[moduleName].technical,
|
|
2499
|
+
content: buildTechnicalDoc(moduleName, sourceFiles, stackSnapshot),
|
|
2500
|
+
generated,
|
|
2501
|
+
skipped,
|
|
2502
|
+
dryRun: options.dryRun === true
|
|
2503
|
+
});
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
progress.global.designSystem ??= {};
|
|
2508
|
+
progress.global.designSystem.tokens ??= this.tracker.createEntry(
|
|
2509
|
+
join14(PATHS.DESIGN_SYSTEM_DIR, "tokens.md"),
|
|
2510
|
+
[PATHS.DESIGN_TOKENS_FILE]
|
|
2511
|
+
);
|
|
2512
|
+
progress.global.architecture ??= {};
|
|
2513
|
+
progress.global.architecture.overview ??= this.tracker.createEntry(
|
|
2514
|
+
join14(PATHS.ARCHITECTURE_DIR, "overview.md"),
|
|
2515
|
+
sourceFiles
|
|
2516
|
+
);
|
|
2517
|
+
if (shouldGenerateArchitectureDocs(options.scope)) {
|
|
2518
|
+
await processEntry({
|
|
2519
|
+
projectRoot: options.projectRoot,
|
|
2520
|
+
entry: progress.global.architecture.overview,
|
|
2521
|
+
content: buildArchitectureOverview(modules, stackSnapshot),
|
|
2522
|
+
generated,
|
|
2523
|
+
skipped,
|
|
2524
|
+
dryRun: options.dryRun === true
|
|
2525
|
+
});
|
|
2526
|
+
}
|
|
2527
|
+
const handoverPath = join14(".agency/handover", "product-summary.md");
|
|
2528
|
+
if (!options.dryRun && shouldGenerateHandover(options.scope)) {
|
|
2529
|
+
await mkdir4(dirname6(join14(options.projectRoot, handoverPath)), { recursive: true });
|
|
2530
|
+
await writeFile4(
|
|
2531
|
+
join14(options.projectRoot, handoverPath),
|
|
2532
|
+
buildHandoverSummary(modules, generated, stackSnapshot)
|
|
2533
|
+
);
|
|
2534
|
+
generated.push(handoverPath);
|
|
2535
|
+
}
|
|
2536
|
+
await this.tracker.save(options.projectRoot, progress);
|
|
2537
|
+
return {
|
|
2538
|
+
generated,
|
|
2539
|
+
skipped,
|
|
2540
|
+
progress_path: PATHS.DOC_PROGRESS,
|
|
2541
|
+
handover_path: handoverPath,
|
|
2542
|
+
stack_snapshot: stackSnapshot
|
|
2543
|
+
};
|
|
2544
|
+
}
|
|
2545
|
+
};
|
|
2546
|
+
function shouldGenerateModuleDocs(scope) {
|
|
2547
|
+
return scope === "full" || scope === "ui" || scope === "api" || scope === "database";
|
|
2548
|
+
}
|
|
2549
|
+
function shouldGenerateBusinessDoc(scope) {
|
|
2550
|
+
return scope === "full" || scope === "ui";
|
|
2551
|
+
}
|
|
2552
|
+
function shouldGenerateTechnicalDoc(scope) {
|
|
2553
|
+
return scope === "full" || scope === "ui" || scope === "api" || scope === "database";
|
|
2554
|
+
}
|
|
2555
|
+
function shouldGenerateArchitectureDocs(scope) {
|
|
2556
|
+
return scope === "full" || scope === "architecture";
|
|
2557
|
+
}
|
|
2558
|
+
function shouldGenerateHandover(scope) {
|
|
2559
|
+
return scope === "full";
|
|
2560
|
+
}
|
|
2561
|
+
async function processEntry(input) {
|
|
2562
|
+
const currentHash = await hashSourceFiles(input.projectRoot, input.entry.source_files);
|
|
2563
|
+
if (input.entry.state === "done" && input.entry.source_hash === currentHash) {
|
|
2564
|
+
input.skipped.push(input.entry.output_path);
|
|
2565
|
+
return;
|
|
2566
|
+
}
|
|
2567
|
+
input.entry.state = "generating";
|
|
2568
|
+
input.entry.started_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
2569
|
+
input.entry.error = null;
|
|
2570
|
+
if (!input.dryRun) {
|
|
2571
|
+
await mkdir4(dirname6(join14(input.projectRoot, input.entry.output_path)), { recursive: true });
|
|
2572
|
+
await writeFile4(join14(input.projectRoot, input.entry.output_path), input.content);
|
|
2573
|
+
input.generated.push(input.entry.output_path);
|
|
2574
|
+
}
|
|
2575
|
+
input.entry.state = "done";
|
|
2576
|
+
input.entry.completed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
2577
|
+
input.entry.source_hash = currentHash;
|
|
2578
|
+
input.entry.tokens_used = Math.max(32, Math.round(input.content.length / 4));
|
|
2579
|
+
if (input.entry.output_path.endsWith("tokens.md")) {
|
|
2580
|
+
input.entry.design_tokens = {
|
|
2581
|
+
extraction_state: "done",
|
|
2582
|
+
total_tokens_found: (input.content.match(/`/g) ?? []).length / 2,
|
|
2583
|
+
placeholder_count: (input.content.match(/\{[^}]+\}/g) ?? []).length,
|
|
2584
|
+
populated_count: Math.max(0, input.content.split("\n").length - 4),
|
|
2585
|
+
placeholder_keys: Array.from(
|
|
2586
|
+
new Set((input.content.match(/\{[^}]+\}/g) ?? []).map((item) => item.slice(1, -1)))
|
|
2587
|
+
).slice(0, 10)
|
|
2588
|
+
};
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
async function gatherSourceFiles(projectRoot) {
|
|
2592
|
+
const roots = ["src", "app", "lib", "routes", "resources", "config"];
|
|
2593
|
+
const results = /* @__PURE__ */ new Set();
|
|
2594
|
+
for (const root of roots) {
|
|
2595
|
+
try {
|
|
2596
|
+
for (const file of await walk2(join14(projectRoot, root))) {
|
|
2597
|
+
results.add(relative(projectRoot, file));
|
|
2598
|
+
}
|
|
2599
|
+
} catch {
|
|
2600
|
+
continue;
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
if (results.size === 0) {
|
|
2604
|
+
results.add("package.json");
|
|
2605
|
+
}
|
|
2606
|
+
return Array.from(results).sort();
|
|
2607
|
+
}
|
|
2608
|
+
async function walk2(root) {
|
|
2609
|
+
const entries = await readdir2(root, { withFileTypes: true });
|
|
2610
|
+
const files = [];
|
|
2611
|
+
for (const entry of entries) {
|
|
2612
|
+
const target = join14(root, entry.name);
|
|
2613
|
+
if (entry.isDirectory()) {
|
|
2614
|
+
files.push(...await walk2(target));
|
|
2615
|
+
continue;
|
|
2616
|
+
}
|
|
2617
|
+
files.push(target);
|
|
2618
|
+
}
|
|
2619
|
+
return files;
|
|
2620
|
+
}
|
|
2621
|
+
function buildBusinessDoc(moduleName, sourceFiles) {
|
|
2622
|
+
return [
|
|
2623
|
+
`# ${titleize(moduleName)} Business`,
|
|
2624
|
+
"",
|
|
2625
|
+
"## Overview",
|
|
2626
|
+
"",
|
|
2627
|
+
`${titleize(moduleName)} is documented from the current codebase snapshot.`,
|
|
2628
|
+
"",
|
|
2629
|
+
"## User Flows",
|
|
2630
|
+
"",
|
|
2631
|
+
...sourceFiles.slice(0, 5).map((file, index) => `${index + 1}. Flow signal from \`${file}\`.`),
|
|
2632
|
+
"",
|
|
2633
|
+
"## Business Rules",
|
|
2634
|
+
"",
|
|
2635
|
+
"- Preserve the documented behaviors inferred from the current implementation.",
|
|
2636
|
+
""
|
|
2637
|
+
].join("\n");
|
|
2638
|
+
}
|
|
2639
|
+
function buildTechnicalDoc(moduleName, sourceFiles, stackSnapshot) {
|
|
2640
|
+
const packageLines = stackSnapshot?.packages.slice(0, 6).map((pkg) => `- \`${pkg.name}\` @ \`${pkg.locked_version}\``) ?? ["- No snapshot available."];
|
|
2641
|
+
return [
|
|
2642
|
+
`# ${titleize(moduleName)} Technical`,
|
|
2643
|
+
"",
|
|
2644
|
+
"## Module Boundaries",
|
|
2645
|
+
"",
|
|
2646
|
+
...sourceFiles.slice(0, 8).map((file) => `- \`${file}\``),
|
|
2647
|
+
"",
|
|
2648
|
+
"## Dependencies",
|
|
2649
|
+
"",
|
|
2650
|
+
...packageLines,
|
|
2651
|
+
"",
|
|
2652
|
+
"## Testing Entry Points",
|
|
2653
|
+
"",
|
|
2654
|
+
`- Update module coverage under \`tests/\` for ${moduleName}.`,
|
|
2655
|
+
""
|
|
2656
|
+
].join("\n");
|
|
2657
|
+
}
|
|
2658
|
+
function buildArchitectureOverview(modules, stackSnapshot) {
|
|
2659
|
+
return [
|
|
2660
|
+
"# Architecture Overview",
|
|
2661
|
+
"",
|
|
2662
|
+
"## Modules",
|
|
2663
|
+
"",
|
|
2664
|
+
...modules.map((moduleName) => `- ${moduleName}`),
|
|
2665
|
+
"",
|
|
2666
|
+
"## Toolchains",
|
|
2667
|
+
"",
|
|
2668
|
+
...stackSnapshot?.toolchains.map(
|
|
2669
|
+
(toolchain) => `- ${toolchain.ecosystem}: ${toolchain.package_manager} (${toolchain.lockfile})`
|
|
2670
|
+
) ?? ["- No toolchain snapshot available."],
|
|
2671
|
+
""
|
|
2672
|
+
].join("\n");
|
|
2673
|
+
}
|
|
2674
|
+
function buildHandoverSummary(modules, generated, stackSnapshot) {
|
|
2675
|
+
return [
|
|
2676
|
+
"# Product Summary",
|
|
2677
|
+
"",
|
|
2678
|
+
`Generated documentation for ${modules.length} module(s).`,
|
|
2679
|
+
"",
|
|
2680
|
+
`Artifacts written: ${generated.length}.`,
|
|
2681
|
+
"",
|
|
2682
|
+
`Package snapshot entries: ${stackSnapshot?.packages.length ?? 0}.`,
|
|
2683
|
+
""
|
|
2684
|
+
].join("\n");
|
|
2685
|
+
}
|
|
2686
|
+
function titleize(value) {
|
|
2687
|
+
return value.replace(/[-_]/g, " ").replace(/\b\w/g, (character) => character.toUpperCase());
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
// src/document/command.ts
|
|
2691
|
+
async function runDocumentCommand(options) {
|
|
2692
|
+
return new DocumentPipeline().run({
|
|
2693
|
+
projectRoot: options.projectRoot,
|
|
2694
|
+
scope: options.scope,
|
|
2695
|
+
dryRun: options.dryRun,
|
|
2696
|
+
refreshStack: options.refreshStack ?? options.scope === "full",
|
|
2697
|
+
refreshTokens: options.refreshTokens ?? (options.scope === "ui" || options.scope === "full")
|
|
2698
|
+
});
|
|
2699
|
+
}
|
|
2700
|
+
|
|
1607
2701
|
// src/onboarding/file-writer.ts
|
|
1608
2702
|
import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
1609
|
-
import { dirname as
|
|
2703
|
+
import { dirname as dirname7, join as join15 } from "path";
|
|
1610
2704
|
function writeGeneratedFiles(projectRoot, files) {
|
|
1611
2705
|
const written = [];
|
|
1612
2706
|
const skipped = [];
|
|
1613
2707
|
for (const file of files) {
|
|
1614
|
-
const target =
|
|
1615
|
-
mkdirSync3(
|
|
2708
|
+
const target = join15(projectRoot, file.path);
|
|
2709
|
+
mkdirSync3(dirname7(target), { recursive: true });
|
|
1616
2710
|
if (!file.autoUpdate && existsSync5(target)) {
|
|
1617
2711
|
skipped.push(file.path);
|
|
1618
2712
|
continue;
|
|
@@ -1628,7 +2722,7 @@ function writeGeneratedFiles(projectRoot, files) {
|
|
|
1628
2722
|
|
|
1629
2723
|
// src/resolver/resolver.ts
|
|
1630
2724
|
import fg from "fast-glob";
|
|
1631
|
-
import { basename as basename2, extname, relative as
|
|
2725
|
+
import { basename as basename2, extname, relative as relative3 } from "pathe";
|
|
1632
2726
|
|
|
1633
2727
|
// src/resolver/artifact-types.ts
|
|
1634
2728
|
var ARTIFACT_TYPES = [
|
|
@@ -1666,14 +2760,14 @@ var ARTIFACT_OUTPUT_KEYS = {
|
|
|
1666
2760
|
};
|
|
1667
2761
|
|
|
1668
2762
|
// src/resolver/inheritance.ts
|
|
1669
|
-
import { join as
|
|
2763
|
+
import { join as join17, relative as relative2 } from "pathe";
|
|
1670
2764
|
|
|
1671
2765
|
// src/resolver/capability-resolver.ts
|
|
1672
|
-
import { join as
|
|
2766
|
+
import { join as join16 } from "pathe";
|
|
1673
2767
|
function resolveCapabilityDirectories(runtimeRoot, domain, stack, capabilities, artifactType) {
|
|
1674
2768
|
const directoryName = resolveCapabilityArtifactDirectory(artifactType);
|
|
1675
2769
|
return capabilities.map(
|
|
1676
|
-
(capability) =>
|
|
2770
|
+
(capability) => join16(
|
|
1677
2771
|
runtimeRoot,
|
|
1678
2772
|
"domains",
|
|
1679
2773
|
domain,
|
|
@@ -1690,9 +2784,9 @@ function resolveCapabilityArtifactDirectory(artifactType) {
|
|
|
1690
2784
|
case "mcp-configs":
|
|
1691
2785
|
return "mcp";
|
|
1692
2786
|
case "patterns":
|
|
1693
|
-
return
|
|
2787
|
+
return join16("benchmarks", "patterns");
|
|
1694
2788
|
case "anti-patterns":
|
|
1695
|
-
return
|
|
2789
|
+
return join16("benchmarks", "anti-patterns");
|
|
1696
2790
|
default:
|
|
1697
2791
|
return artifactType;
|
|
1698
2792
|
}
|
|
@@ -1703,48 +2797,48 @@ function getInheritanceDirectories(runtimeRoot, routing, artifactType) {
|
|
|
1703
2797
|
if (artifactType === "hooks") {
|
|
1704
2798
|
return [
|
|
1705
2799
|
{
|
|
1706
|
-
path:
|
|
2800
|
+
path: join17(runtimeRoot, "hooks"),
|
|
1707
2801
|
level: 0,
|
|
1708
|
-
source:
|
|
2802
|
+
source: relative2(runtimeRoot, join17(runtimeRoot, "hooks"))
|
|
1709
2803
|
}
|
|
1710
2804
|
];
|
|
1711
2805
|
}
|
|
1712
2806
|
if (artifactType === "templates") {
|
|
1713
2807
|
return [
|
|
1714
2808
|
{
|
|
1715
|
-
path:
|
|
2809
|
+
path: join17(runtimeRoot, "templates"),
|
|
1716
2810
|
level: 0,
|
|
1717
|
-
source:
|
|
2811
|
+
source: relative2(runtimeRoot, join17(runtimeRoot, "templates"))
|
|
1718
2812
|
}
|
|
1719
2813
|
];
|
|
1720
2814
|
}
|
|
1721
|
-
const basePath =
|
|
2815
|
+
const basePath = join17(runtimeRoot, "domains");
|
|
1722
2816
|
const directoryName = resolveArtifactDirectoryName(artifactType);
|
|
1723
2817
|
const directories = [
|
|
1724
2818
|
{
|
|
1725
|
-
path:
|
|
2819
|
+
path: join17(basePath, "_shared", directoryName),
|
|
1726
2820
|
level: 0,
|
|
1727
|
-
source:
|
|
2821
|
+
source: relative2(runtimeRoot, join17(basePath, "_shared", directoryName))
|
|
1728
2822
|
},
|
|
1729
2823
|
{
|
|
1730
|
-
path:
|
|
2824
|
+
path: join17(basePath, routing.domain, directoryName),
|
|
1731
2825
|
level: 1,
|
|
1732
|
-
source:
|
|
2826
|
+
source: relative2(runtimeRoot, join17(basePath, routing.domain, directoryName))
|
|
1733
2827
|
},
|
|
1734
2828
|
{
|
|
1735
|
-
path:
|
|
2829
|
+
path: join17(basePath, routing.domain, "stacks", "_shared", directoryName),
|
|
1736
2830
|
level: 2,
|
|
1737
|
-
source:
|
|
2831
|
+
source: relative2(
|
|
1738
2832
|
runtimeRoot,
|
|
1739
|
-
|
|
2833
|
+
join17(basePath, routing.domain, "stacks", "_shared", directoryName)
|
|
1740
2834
|
)
|
|
1741
2835
|
},
|
|
1742
2836
|
{
|
|
1743
|
-
path:
|
|
2837
|
+
path: join17(basePath, routing.domain, "stacks", routing.stack, directoryName),
|
|
1744
2838
|
level: 2,
|
|
1745
|
-
source:
|
|
2839
|
+
source: relative2(
|
|
1746
2840
|
runtimeRoot,
|
|
1747
|
-
|
|
2841
|
+
join17(basePath, routing.domain, "stacks", routing.stack, directoryName)
|
|
1748
2842
|
)
|
|
1749
2843
|
}
|
|
1750
2844
|
];
|
|
@@ -1757,7 +2851,7 @@ function getInheritanceDirectories(runtimeRoot, routing, artifactType) {
|
|
|
1757
2851
|
).map((path) => ({
|
|
1758
2852
|
path,
|
|
1759
2853
|
level: 3,
|
|
1760
|
-
source:
|
|
2854
|
+
source: relative2(runtimeRoot, path)
|
|
1761
2855
|
}));
|
|
1762
2856
|
return [...directories, ...capabilityDirectories];
|
|
1763
2857
|
}
|
|
@@ -1766,9 +2860,9 @@ function resolveArtifactDirectoryName(artifactType) {
|
|
|
1766
2860
|
case "mcp-configs":
|
|
1767
2861
|
return "mcp";
|
|
1768
2862
|
case "patterns":
|
|
1769
|
-
return
|
|
2863
|
+
return join17("benchmarks", "patterns");
|
|
1770
2864
|
case "anti-patterns":
|
|
1771
|
-
return
|
|
2865
|
+
return join17("benchmarks", "anti-patterns");
|
|
1772
2866
|
default:
|
|
1773
2867
|
return artifactType;
|
|
1774
2868
|
}
|
|
@@ -1832,13 +2926,13 @@ var Resolver = class {
|
|
|
1832
2926
|
const artifact = {
|
|
1833
2927
|
path: file,
|
|
1834
2928
|
level: directory.level,
|
|
1835
|
-
source:
|
|
2929
|
+
source: relative3(this.runtimeRoot, file)
|
|
1836
2930
|
};
|
|
1837
2931
|
if (COLLISION_MAP[artifactType] === "additive-merge") {
|
|
1838
2932
|
entries.push(artifact);
|
|
1839
2933
|
continue;
|
|
1840
2934
|
}
|
|
1841
|
-
overrides.set(
|
|
2935
|
+
overrides.set(relative3(directory.path, file), artifact);
|
|
1842
2936
|
}
|
|
1843
2937
|
}
|
|
1844
2938
|
const resolved = COLLISION_MAP[artifactType] === "additive-merge" ? entries : Array.from(overrides.values());
|
|
@@ -1864,8 +2958,8 @@ function getRulePriority(filePath) {
|
|
|
1864
2958
|
|
|
1865
2959
|
// src/scripts/generator.ts
|
|
1866
2960
|
import { chmodSync as chmodSync2 } from "fs";
|
|
1867
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
1868
|
-
import { dirname as
|
|
2961
|
+
import { mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
|
|
2962
|
+
import { dirname as dirname8, join as join18 } from "path";
|
|
1869
2963
|
|
|
1870
2964
|
// src/templates/context-builders/runner-scripts.ts
|
|
1871
2965
|
function buildRunnerScriptContext(input) {
|
|
@@ -1874,7 +2968,7 @@ function buildRunnerScriptContext(input) {
|
|
|
1874
2968
|
|
|
1875
2969
|
// src/templates/registry.ts
|
|
1876
2970
|
import fg2 from "fast-glob";
|
|
1877
|
-
import { basename as basename3, relative as
|
|
2971
|
+
import { basename as basename3, relative as relative4 } from "pathe";
|
|
1878
2972
|
var TemplateRegistry = class {
|
|
1879
2973
|
constructor(templatesRoot) {
|
|
1880
2974
|
this.templatesRoot = templatesRoot;
|
|
@@ -1888,7 +2982,7 @@ var TemplateRegistry = class {
|
|
|
1888
2982
|
return files.sort().map((path) => ({
|
|
1889
2983
|
name: basename3(path),
|
|
1890
2984
|
path,
|
|
1891
|
-
relativePath:
|
|
2985
|
+
relativePath: relative4(this.templatesRoot, path)
|
|
1892
2986
|
}));
|
|
1893
2987
|
}
|
|
1894
2988
|
};
|
|
@@ -1897,11 +2991,11 @@ var TemplateRegistry = class {
|
|
|
1897
2991
|
var RunnerScriptGenerator = class {
|
|
1898
2992
|
engine = new TemplateEngine();
|
|
1899
2993
|
async generate(profile) {
|
|
1900
|
-
const registry = new TemplateRegistry(
|
|
2994
|
+
const registry = new TemplateRegistry(join18(getRuntimeTemplatesRoot(), "runner-scripts"));
|
|
1901
2995
|
const templates = await registry.discover();
|
|
1902
2996
|
return Promise.all(
|
|
1903
2997
|
templates.map(async (template) => ({
|
|
1904
|
-
path:
|
|
2998
|
+
path: join18("scripts", template.relativePath.replace(/\.hbs$/, "")),
|
|
1905
2999
|
content: await this.engine.render(template.path, buildScriptContext(profile)),
|
|
1906
3000
|
autoUpdate: true,
|
|
1907
3001
|
executable: true
|
|
@@ -1912,9 +3006,9 @@ var RunnerScriptGenerator = class {
|
|
|
1912
3006
|
const generated = await this.generate(profile);
|
|
1913
3007
|
const written = [];
|
|
1914
3008
|
for (const file of generated) {
|
|
1915
|
-
const target =
|
|
1916
|
-
await
|
|
1917
|
-
await
|
|
3009
|
+
const target = join18(projectRoot, file.path);
|
|
3010
|
+
await mkdir5(dirname8(target), { recursive: true });
|
|
3011
|
+
await writeFile5(target, file.content);
|
|
1918
3012
|
chmodSync2(target, 493);
|
|
1919
3013
|
written.push(file.path);
|
|
1920
3014
|
}
|
|
@@ -1944,83 +3038,16 @@ async function resolveSelections(detection, overrides) {
|
|
|
1944
3038
|
};
|
|
1945
3039
|
}
|
|
1946
3040
|
|
|
1947
|
-
// src/onboarding/registry-generator.ts
|
|
1948
|
-
import { readdir } from "fs/promises";
|
|
1949
|
-
import { join as join12 } from "path";
|
|
1950
|
-
async function generateInitialRegistries(projectRoot) {
|
|
1951
|
-
const modules = await discoverModules(projectRoot);
|
|
1952
|
-
return [
|
|
1953
|
-
{
|
|
1954
|
-
path: ".agency/indexes/registry-status.json",
|
|
1955
|
-
content: JSON.stringify(
|
|
1956
|
-
{
|
|
1957
|
-
generated: true,
|
|
1958
|
-
modules,
|
|
1959
|
-
generated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1960
|
-
},
|
|
1961
|
-
null,
|
|
1962
|
-
2
|
|
1963
|
-
),
|
|
1964
|
-
autoUpdate: true
|
|
1965
|
-
},
|
|
1966
|
-
{
|
|
1967
|
-
path: ".agency/cache/skill-results/.gitkeep",
|
|
1968
|
-
content: "",
|
|
1969
|
-
autoUpdate: true
|
|
1970
|
-
},
|
|
1971
|
-
{
|
|
1972
|
-
path: PATHS.GLOSSARY,
|
|
1973
|
-
content: "# Glossary\n\n",
|
|
1974
|
-
autoUpdate: true
|
|
1975
|
-
},
|
|
1976
|
-
...REGISTRIES.map((registry) => ({
|
|
1977
|
-
path: join12("docs", registry),
|
|
1978
|
-
content: registry === "module-registry.md" ? buildModuleRegistry(modules) : `# ${registry}
|
|
1979
|
-
|
|
1980
|
-
`,
|
|
1981
|
-
autoUpdate: true
|
|
1982
|
-
}))
|
|
1983
|
-
];
|
|
1984
|
-
}
|
|
1985
|
-
async function discoverModules(projectRoot) {
|
|
1986
|
-
const candidates = [
|
|
1987
|
-
join12(projectRoot, "docs/modules"),
|
|
1988
|
-
join12(projectRoot, "app"),
|
|
1989
|
-
join12(projectRoot, "lib")
|
|
1990
|
-
];
|
|
1991
|
-
const modules = /* @__PURE__ */ new Set(["core"]);
|
|
1992
|
-
for (const root of candidates) {
|
|
1993
|
-
try {
|
|
1994
|
-
const entries = await readdir(root, { withFileTypes: true });
|
|
1995
|
-
for (const entry of entries) {
|
|
1996
|
-
if (!entry.isDirectory()) {
|
|
1997
|
-
continue;
|
|
1998
|
-
}
|
|
1999
|
-
const name = entry.name;
|
|
2000
|
-
if (name !== "" && !name.startsWith(".")) {
|
|
2001
|
-
modules.add(name);
|
|
2002
|
-
}
|
|
2003
|
-
}
|
|
2004
|
-
} catch {
|
|
2005
|
-
continue;
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
return Array.from(modules).sort();
|
|
2009
|
-
}
|
|
2010
|
-
function buildModuleRegistry(modules) {
|
|
2011
|
-
return ["# module-registry.md", "", ...modules.map((module) => `- ${module}`), ""].join("\n");
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
3041
|
// src/onboarding/reference-generator.ts
|
|
2015
|
-
import { readFile as
|
|
2016
|
-
import { join as
|
|
3042
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
3043
|
+
import { join as join19, relative as relative5 } from "path";
|
|
2017
3044
|
import fg3 from "fast-glob";
|
|
2018
3045
|
async function generateReferenceGuides(runtimeRoot, routing) {
|
|
2019
3046
|
const stack = routing.stack;
|
|
2020
3047
|
if (routing.domain !== "coding" || stack !== "laravel" && stack !== "flutter") {
|
|
2021
3048
|
return [];
|
|
2022
3049
|
}
|
|
2023
|
-
const referencesRoot =
|
|
3050
|
+
const referencesRoot = join19(runtimeRoot, "domains", "coding", "stacks", stack, "references");
|
|
2024
3051
|
const entries = await fg3(["tools/*.md", "tools-catalog.md"], {
|
|
2025
3052
|
cwd: referencesRoot,
|
|
2026
3053
|
onlyFiles: true,
|
|
@@ -2028,8 +3055,8 @@ async function generateReferenceGuides(runtimeRoot, routing) {
|
|
|
2028
3055
|
});
|
|
2029
3056
|
return Promise.all(
|
|
2030
3057
|
entries.sort().map(async (entry) => ({
|
|
2031
|
-
path: toProjectReferencePath(stack,
|
|
2032
|
-
content: await
|
|
3058
|
+
path: toProjectReferencePath(stack, relative5(referencesRoot, entry)),
|
|
3059
|
+
content: await readFile8(entry, "utf8"),
|
|
2033
3060
|
autoUpdate: false
|
|
2034
3061
|
}))
|
|
2035
3062
|
);
|
|
@@ -2037,19 +3064,19 @@ async function generateReferenceGuides(runtimeRoot, routing) {
|
|
|
2037
3064
|
function toProjectReferencePath(stack, relativePath) {
|
|
2038
3065
|
const normalized = relativePath.replaceAll("\\", "/");
|
|
2039
3066
|
if (normalized === "tools-catalog.md") {
|
|
2040
|
-
return
|
|
3067
|
+
return join19("docs/tools", stack, "README.md");
|
|
2041
3068
|
}
|
|
2042
|
-
return
|
|
3069
|
+
return join19("docs/tools", stack, normalized.replace(/^tools\//, ""));
|
|
2043
3070
|
}
|
|
2044
3071
|
|
|
2045
3072
|
// src/onboarding/rule-generator.ts
|
|
2046
|
-
import { readFile as
|
|
2047
|
-
import { join as
|
|
3073
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
3074
|
+
import { join as join20 } from "path";
|
|
2048
3075
|
async function generateProjectRules(rules) {
|
|
2049
3076
|
return Promise.all(
|
|
2050
3077
|
rules.map(async (rule) => ({
|
|
2051
3078
|
path: toProjectRulePath(rule.source),
|
|
2052
|
-
content: await
|
|
3079
|
+
content: await readFile9(rule.path, "utf8"),
|
|
2053
3080
|
autoUpdate: false
|
|
2054
3081
|
}))
|
|
2055
3082
|
);
|
|
@@ -2058,19 +3085,14 @@ function toProjectRulePath(source) {
|
|
|
2058
3085
|
const normalized = source.replace(/^domains\//, "");
|
|
2059
3086
|
const [prefix, suffix] = normalized.split("/rules/");
|
|
2060
3087
|
if (prefix === void 0 || suffix === void 0) {
|
|
2061
|
-
return
|
|
3088
|
+
return join20("docs/rules", normalized);
|
|
2062
3089
|
}
|
|
2063
3090
|
const target = suffix.endsWith("/guide.md") ? suffix.replace("/guide.md", ".md") : suffix;
|
|
2064
|
-
return
|
|
3091
|
+
return join20("docs/rules", prefix, target);
|
|
2065
3092
|
}
|
|
2066
3093
|
|
|
2067
3094
|
// src/onboarding/scaffold-generator.ts
|
|
2068
|
-
import { join as
|
|
2069
|
-
|
|
2070
|
-
// src/templates/context-builders/design-system.ts
|
|
2071
|
-
function buildDesignSystemContext(projectName) {
|
|
2072
|
-
return { projectName };
|
|
2073
|
-
}
|
|
3095
|
+
import { join as join21 } from "path";
|
|
2074
3096
|
|
|
2075
3097
|
// src/templates/context-builders/module-scaffold.ts
|
|
2076
3098
|
function buildModuleScaffoldContext(moduleName) {
|
|
@@ -2082,6 +3104,8 @@ function buildModuleScaffoldContext(moduleName) {
|
|
|
2082
3104
|
|
|
2083
3105
|
// src/onboarding/scaffold-generator.ts
|
|
2084
3106
|
var MODULE_TEMPLATE_TARGETS = [
|
|
3107
|
+
["business.md.hbs", "business.md"],
|
|
3108
|
+
["technical.md.hbs", "technical.md"],
|
|
2085
3109
|
["summary.md.hbs", "index/summary.md"],
|
|
2086
3110
|
["schema.md.hbs", "database/schema.md"],
|
|
2087
3111
|
["indexes.md.hbs", "database/indexes.md"],
|
|
@@ -2102,40 +3126,29 @@ async function generateDocumentationScaffold(moduleNames = ["core"]) {
|
|
|
2102
3126
|
for (const moduleName of Array.from(new Set(moduleNames)).sort()) {
|
|
2103
3127
|
files.push(...await generateModuleScaffold(moduleName));
|
|
2104
3128
|
}
|
|
2105
|
-
const engine = new TemplateEngine();
|
|
2106
|
-
for (const [templateName, target] of DESIGN_SYSTEM_TEMPLATE_TARGETS) {
|
|
2107
|
-
files.push({
|
|
2108
|
-
path: target,
|
|
2109
|
-
content: await engine.render(
|
|
2110
|
-
join15(getRuntimeTemplatesRoot(), "design-system", templateName),
|
|
2111
|
-
buildDesignSystemContext("Paqad")
|
|
2112
|
-
),
|
|
2113
|
-
autoUpdate: true
|
|
2114
|
-
});
|
|
2115
|
-
}
|
|
2116
3129
|
files.push(
|
|
2117
3130
|
{
|
|
2118
|
-
path:
|
|
3131
|
+
path: join21(PATHS.ARCHITECTURE_DIR, "overview.md"),
|
|
2119
3132
|
content: "# Architecture Overview\n\n",
|
|
2120
3133
|
autoUpdate: true
|
|
2121
3134
|
},
|
|
2122
3135
|
{
|
|
2123
|
-
path:
|
|
3136
|
+
path: join21(PATHS.ARCHITECTURE_DIR, "decisions.md"),
|
|
2124
3137
|
content: "# Architecture Decisions\n\n",
|
|
2125
3138
|
autoUpdate: true
|
|
2126
3139
|
},
|
|
2127
3140
|
{
|
|
2128
|
-
path:
|
|
3141
|
+
path: join21(PATHS.ARCHITECTURE_DIR, "patterns.md"),
|
|
2129
3142
|
content: "# Architecture Patterns\n\n",
|
|
2130
3143
|
autoUpdate: true
|
|
2131
3144
|
},
|
|
2132
3145
|
{
|
|
2133
|
-
path:
|
|
3146
|
+
path: join21(PATHS.BENCHMARKS_DIR, "index.md"),
|
|
2134
3147
|
content: "# Benchmarks\n\n",
|
|
2135
3148
|
autoUpdate: true
|
|
2136
3149
|
},
|
|
2137
3150
|
{
|
|
2138
|
-
path:
|
|
3151
|
+
path: join21(PATHS.TECH_DEBT_DIR, "index.md"),
|
|
2139
3152
|
content: "# Technical Debt\n\n",
|
|
2140
3153
|
autoUpdate: true
|
|
2141
3154
|
}
|
|
@@ -2156,9 +3169,9 @@ async function generateModuleScaffold(moduleName) {
|
|
|
2156
3169
|
const files = [];
|
|
2157
3170
|
for (const [templateName, relativeTarget] of MODULE_TEMPLATE_TARGETS) {
|
|
2158
3171
|
files.push({
|
|
2159
|
-
path:
|
|
3172
|
+
path: join21(PATHS.MODULES_DIR, moduleName, relativeTarget),
|
|
2160
3173
|
content: await engine.render(
|
|
2161
|
-
|
|
3174
|
+
join21(getRuntimeTemplatesRoot(), "module-scaffold", templateName),
|
|
2162
3175
|
context
|
|
2163
3176
|
),
|
|
2164
3177
|
autoUpdate: false
|
|
@@ -2166,14 +3179,6 @@ async function generateModuleScaffold(moduleName) {
|
|
|
2166
3179
|
}
|
|
2167
3180
|
return files;
|
|
2168
3181
|
}
|
|
2169
|
-
var DESIGN_SYSTEM_TEMPLATE_TARGETS = [
|
|
2170
|
-
["tokens.md.hbs", "docs/design-system/tokens.md"],
|
|
2171
|
-
["components.md.hbs", "docs/design-system/components.md"],
|
|
2172
|
-
["motion.md.hbs", "docs/design-system/motion.md"],
|
|
2173
|
-
["accessibility.md.hbs", "docs/design-system/accessibility.md"],
|
|
2174
|
-
["responsive.md.hbs", "docs/design-system/responsive.md"],
|
|
2175
|
-
["patterns.md.hbs", "docs/design-system/patterns.md"]
|
|
2176
|
-
];
|
|
2177
3182
|
|
|
2178
3183
|
// src/onboarding/orchestrator.ts
|
|
2179
3184
|
var OnboardingOrchestrator = class {
|
|
@@ -2215,6 +3220,10 @@ var OnboardingOrchestrator = class {
|
|
|
2215
3220
|
generatedFiles.push(...await generateInitialRegistries(options.projectRoot));
|
|
2216
3221
|
generatedFiles.push(...await new RunnerScriptGenerator().generate(profile));
|
|
2217
3222
|
const writeResult = writeGeneratedFiles(options.projectRoot, generatedFiles);
|
|
3223
|
+
const designTokens = new DesignTokenService();
|
|
3224
|
+
await designTokens.seed(options.projectRoot);
|
|
3225
|
+
await designTokens.writeDocs(options.projectRoot);
|
|
3226
|
+
await designTokens.writeThemeExports(options.projectRoot, selections.stack);
|
|
2218
3227
|
writeProjectProfile(options.projectRoot, profile);
|
|
2219
3228
|
writeDetectionReport(options.projectRoot, detection);
|
|
2220
3229
|
writeFrameworkMetadata(options.projectRoot, VERSION);
|
|
@@ -2302,8 +3311,8 @@ function buildProjectProfile(selections, overrides) {
|
|
|
2302
3311
|
}
|
|
2303
3312
|
|
|
2304
3313
|
// src/pipeline/lane-runner.ts
|
|
2305
|
-
import { mkdir as
|
|
2306
|
-
import { dirname as
|
|
3314
|
+
import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
|
|
3315
|
+
import { dirname as dirname9, join as join22 } from "path";
|
|
2307
3316
|
|
|
2308
3317
|
// src/pipeline/phases/shared.ts
|
|
2309
3318
|
function createPassResult(phase, summary, context) {
|
|
@@ -2459,29 +3468,29 @@ var DEFAULT_PHASES = {
|
|
|
2459
3468
|
};
|
|
2460
3469
|
|
|
2461
3470
|
// src/skills/cache-manager.ts
|
|
2462
|
-
import { createHash } from "crypto";
|
|
2463
|
-
import { mkdir as
|
|
2464
|
-
import { join as
|
|
3471
|
+
import { createHash as createHash3 } from "crypto";
|
|
3472
|
+
import { mkdir as mkdir7, readFile as readFile10, readdir as readdir3, rm as rm2, stat, writeFile as writeFile7 } from "fs/promises";
|
|
3473
|
+
import { join as join23 } from "path";
|
|
2465
3474
|
import fg4 from "fast-glob";
|
|
2466
3475
|
|
|
2467
3476
|
// src/skills/frontmatter-parser.ts
|
|
2468
|
-
import
|
|
3477
|
+
import YAML5 from "yaml";
|
|
2469
3478
|
|
|
2470
3479
|
// src/skills/loader.ts
|
|
2471
|
-
import { readFile as
|
|
3480
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
2472
3481
|
|
|
2473
3482
|
// src/update/updater.ts
|
|
2474
3483
|
import { chmodSync as chmodSync3, existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
2475
|
-
import { mkdtemp, readdir as
|
|
3484
|
+
import { mkdtemp, readdir as readdir4, readFile as readFile12, rm as rm3 } from "fs/promises";
|
|
2476
3485
|
import { tmpdir } from "os";
|
|
2477
|
-
import { dirname as
|
|
2478
|
-
import
|
|
3486
|
+
import { dirname as dirname10, join as join24, relative as relative6 } from "path";
|
|
3487
|
+
import YAML6 from "yaml";
|
|
2479
3488
|
var FrameworkUpdater = class {
|
|
2480
3489
|
constructor(options = {}) {
|
|
2481
3490
|
this.options = options;
|
|
2482
3491
|
}
|
|
2483
3492
|
async run(projectRoot) {
|
|
2484
|
-
const previousVersion = readText(
|
|
3493
|
+
const previousVersion = readText(join24(projectRoot, PATHS.FRAMEWORK_VERSION));
|
|
2485
3494
|
const manifest = readManifest(projectRoot);
|
|
2486
3495
|
const artifactPolicy = new Map(
|
|
2487
3496
|
manifest?.generated_artifacts.map((artifact) => [artifact.path, artifact.auto_update]) ?? []
|
|
@@ -2491,7 +3500,7 @@ var FrameworkUpdater = class {
|
|
|
2491
3500
|
const skipped = [];
|
|
2492
3501
|
const newScripts = [];
|
|
2493
3502
|
for (const candidate of candidates) {
|
|
2494
|
-
const target =
|
|
3503
|
+
const target = join24(projectRoot, candidate.path);
|
|
2495
3504
|
const existed = existsSync6(target);
|
|
2496
3505
|
const autoUpdate = artifactPolicy.get(candidate.path) ?? candidate.autoUpdate;
|
|
2497
3506
|
if (existed && autoUpdate === false) {
|
|
@@ -2502,7 +3511,7 @@ var FrameworkUpdater = class {
|
|
|
2502
3511
|
});
|
|
2503
3512
|
continue;
|
|
2504
3513
|
}
|
|
2505
|
-
mkdirSync4(
|
|
3514
|
+
mkdirSync4(dirname10(target), { recursive: true });
|
|
2506
3515
|
writeFileSync3(target, candidate.content);
|
|
2507
3516
|
if (candidate.executable === true) {
|
|
2508
3517
|
chmodSync3(target, 493);
|
|
@@ -2512,8 +3521,8 @@ var FrameworkUpdater = class {
|
|
|
2512
3521
|
newScripts.push(candidate.path);
|
|
2513
3522
|
}
|
|
2514
3523
|
}
|
|
2515
|
-
mkdirSync4(
|
|
2516
|
-
writeFileSync3(
|
|
3524
|
+
mkdirSync4(dirname10(join24(projectRoot, PATHS.FRAMEWORK_VERSION)), { recursive: true });
|
|
3525
|
+
writeFileSync3(join24(projectRoot, PATHS.FRAMEWORK_VERSION), `${VERSION}
|
|
2517
3526
|
`);
|
|
2518
3527
|
return {
|
|
2519
3528
|
previous_version: previousVersion,
|
|
@@ -2533,7 +3542,7 @@ var FrameworkUpdater = class {
|
|
|
2533
3542
|
if (profile === null) {
|
|
2534
3543
|
throw new Error("Cannot update framework-managed artifacts without a project profile");
|
|
2535
3544
|
}
|
|
2536
|
-
const tempRoot = await mkdtemp(
|
|
3545
|
+
const tempRoot = await mkdtemp(join24(tmpdir(), "paqad-ai-update-"));
|
|
2537
3546
|
try {
|
|
2538
3547
|
const result = await new OnboardingOrchestrator().run({
|
|
2539
3548
|
projectRoot: tempRoot,
|
|
@@ -2543,23 +3552,23 @@ var FrameworkUpdater = class {
|
|
|
2543
3552
|
const files = await collectFiles(tempRoot, result.generated_files);
|
|
2544
3553
|
return files;
|
|
2545
3554
|
} finally {
|
|
2546
|
-
await
|
|
3555
|
+
await rm3(tempRoot, { recursive: true, force: true });
|
|
2547
3556
|
}
|
|
2548
3557
|
}
|
|
2549
3558
|
};
|
|
2550
3559
|
function readManifest(projectRoot) {
|
|
2551
|
-
const path =
|
|
3560
|
+
const path = join24(projectRoot, PATHS.ONBOARDING_MANIFEST);
|
|
2552
3561
|
if (!existsSync6(path)) {
|
|
2553
3562
|
return null;
|
|
2554
3563
|
}
|
|
2555
3564
|
return JSON.parse(readFileSync5(path, "utf8"));
|
|
2556
3565
|
}
|
|
2557
3566
|
function readProfile(projectRoot) {
|
|
2558
|
-
const path =
|
|
3567
|
+
const path = join24(projectRoot, PATHS.PROJECT_PROFILE);
|
|
2559
3568
|
if (!existsSync6(path)) {
|
|
2560
3569
|
return null;
|
|
2561
3570
|
}
|
|
2562
|
-
return
|
|
3571
|
+
return YAML6.parse(readFileSync5(path, "utf8"));
|
|
2563
3572
|
}
|
|
2564
3573
|
function readText(path) {
|
|
2565
3574
|
if (!existsSync6(path)) {
|
|
@@ -2568,42 +3577,52 @@ function readText(path) {
|
|
|
2568
3577
|
return readFileSync5(path, "utf8").trim();
|
|
2569
3578
|
}
|
|
2570
3579
|
async function collectFiles(root, generated) {
|
|
2571
|
-
const paths = generated.length > 0 ? generated : await
|
|
3580
|
+
const paths = generated.length > 0 ? generated : await walk3(root);
|
|
2572
3581
|
return Promise.all(
|
|
2573
3582
|
paths.map(async (file) => ({
|
|
2574
3583
|
path: file,
|
|
2575
|
-
content: await
|
|
3584
|
+
content: await readFile12(join24(root, file), "utf8"),
|
|
2576
3585
|
autoUpdate: true,
|
|
2577
3586
|
executable: file.startsWith("scripts/")
|
|
2578
3587
|
}))
|
|
2579
3588
|
);
|
|
2580
3589
|
}
|
|
2581
|
-
async function
|
|
2582
|
-
const entries = await
|
|
3590
|
+
async function walk3(root, current = root) {
|
|
3591
|
+
const entries = await readdir4(current, { withFileTypes: true });
|
|
2583
3592
|
const files = [];
|
|
2584
3593
|
for (const entry of entries) {
|
|
2585
|
-
const absolute =
|
|
3594
|
+
const absolute = join24(current, entry.name);
|
|
2586
3595
|
if (entry.isDirectory()) {
|
|
2587
|
-
files.push(...await
|
|
3596
|
+
files.push(...await walk3(root, absolute));
|
|
2588
3597
|
continue;
|
|
2589
3598
|
}
|
|
2590
|
-
files.push(
|
|
3599
|
+
files.push(relative6(root, absolute));
|
|
2591
3600
|
}
|
|
2592
3601
|
return files.sort();
|
|
2593
3602
|
}
|
|
2594
3603
|
|
|
2595
3604
|
// src/verification/gates/documentation-freshness.ts
|
|
2596
3605
|
import { existsSync as existsSync7 } from "fs";
|
|
2597
|
-
import { join as
|
|
3606
|
+
import { join as join25 } from "path";
|
|
2598
3607
|
var STALENESS_WINDOW_MS2 = 1e3 * 60 * 60 * 24 * 7;
|
|
2599
3608
|
|
|
2600
3609
|
// src/index.ts
|
|
2601
|
-
var VERSION = "0.0.
|
|
3610
|
+
var VERSION = "0.0.4";
|
|
2602
3611
|
|
|
2603
|
-
// src/cli/commands/
|
|
3612
|
+
// src/cli/commands/document.ts
|
|
2604
3613
|
import { Command } from "commander";
|
|
3614
|
+
function createDocumentCommand() {
|
|
3615
|
+
return new Command("document").description("Generate project documentation from the current codebase").option("--project-root <path>", "Project root", process.cwd()).option("--scope <scope>", "Scope to generate", "full").option("--dry-run", "Preview without writing files").option("--resume", "Resume from the existing progress tracker").option("--refresh-stack", "Refresh stack introspection before generation").option("--refresh-tokens", "Refresh design-system docs before generation").action(
|
|
3616
|
+
async (options) => {
|
|
3617
|
+
await runDocumentCommand(options);
|
|
3618
|
+
}
|
|
3619
|
+
);
|
|
3620
|
+
}
|
|
3621
|
+
|
|
3622
|
+
// src/cli/commands/doctor.ts
|
|
3623
|
+
import { Command as Command2 } from "commander";
|
|
2605
3624
|
function createDoctorCommand() {
|
|
2606
|
-
return new
|
|
3625
|
+
return new Command2("doctor").description("Check framework health and suggest fixes").option("--project-root <path>", "Project root", process.cwd()).action(async (options) => {
|
|
2607
3626
|
const report = await new HealthChecker().run(options.projectRoot);
|
|
2608
3627
|
console.log(JSON.stringify(report, null, 2));
|
|
2609
3628
|
process.exitCode = report.overall_status === "fail" ? 1 : 0;
|
|
@@ -2611,18 +3630,18 @@ function createDoctorCommand() {
|
|
|
2611
3630
|
}
|
|
2612
3631
|
|
|
2613
3632
|
// src/cli/commands/install.ts
|
|
2614
|
-
import { Command as
|
|
3633
|
+
import { Command as Command3 } from "commander";
|
|
2615
3634
|
function createInstallCommand() {
|
|
2616
|
-
return new
|
|
3635
|
+
return new Command3("install").description("Bootstrap the framework into the current project").option("--project-root <path>", "Project root", process.cwd()).action((options) => {
|
|
2617
3636
|
const result = bootstrapFramework(options.projectRoot);
|
|
2618
3637
|
console.log(JSON.stringify(result, null, 2));
|
|
2619
3638
|
});
|
|
2620
3639
|
}
|
|
2621
3640
|
|
|
2622
3641
|
// src/cli/commands/onboard.ts
|
|
2623
|
-
import { Command as
|
|
3642
|
+
import { Command as Command4 } from "commander";
|
|
2624
3643
|
function createOnboardCommand() {
|
|
2625
|
-
return new
|
|
3644
|
+
return new Command4("onboard").description("Full project onboarding").option("--project-root <path>", "Project root", process.cwd()).option("--domain <domain>", "Force the target domain").option("--stack <stack>", "Force the target stack").option("--capability <capability...>", "Add one or more capabilities").action(
|
|
2626
3645
|
async (options) => {
|
|
2627
3646
|
const orchestrator = new OnboardingOrchestrator();
|
|
2628
3647
|
await orchestrator.run({
|
|
@@ -2638,16 +3657,24 @@ function createOnboardCommand() {
|
|
|
2638
3657
|
}
|
|
2639
3658
|
|
|
2640
3659
|
// src/cli/commands/refresh.ts
|
|
2641
|
-
import { Command as
|
|
3660
|
+
import { Command as Command5 } from "commander";
|
|
2642
3661
|
function createRefreshCommand() {
|
|
2643
|
-
return new
|
|
3662
|
+
return new Command5("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) => {
|
|
3663
|
+
const shouldRefreshDesignSystem = options.designSystem ?? true;
|
|
3664
|
+
const shouldRefreshStack = options.stack ?? true;
|
|
3665
|
+
if (shouldRefreshDesignSystem) {
|
|
3666
|
+
await new DesignTokenService().writeDocs(options.projectRoot);
|
|
3667
|
+
}
|
|
3668
|
+
if (shouldRefreshStack) {
|
|
3669
|
+
await new StackIntrospector().snapshot(options.projectRoot);
|
|
3670
|
+
}
|
|
2644
3671
|
});
|
|
2645
3672
|
}
|
|
2646
3673
|
|
|
2647
3674
|
// src/cli/commands/update.ts
|
|
2648
|
-
import { Command as
|
|
3675
|
+
import { Command as Command6 } from "commander";
|
|
2649
3676
|
function createUpdateCommand() {
|
|
2650
|
-
return new
|
|
3677
|
+
return new Command6("update").description("Update framework-managed artifacts").option("--project-root <path>", "Project root", process.cwd()).action(async (options) => {
|
|
2651
3678
|
const report = await new FrameworkUpdater().run(options.projectRoot);
|
|
2652
3679
|
console.log(JSON.stringify(report, null, 2));
|
|
2653
3680
|
});
|
|
@@ -2655,10 +3682,11 @@ function createUpdateCommand() {
|
|
|
2655
3682
|
|
|
2656
3683
|
// src/cli/program.ts
|
|
2657
3684
|
function createProgram() {
|
|
2658
|
-
const program = new
|
|
3685
|
+
const program = new Command7();
|
|
2659
3686
|
program.name("paqad-ai").description("AI Agency Framework for software agencies").version(VERSION).showSuggestionAfterError(true);
|
|
2660
3687
|
program.addCommand(createInstallCommand());
|
|
2661
3688
|
program.addCommand(createDoctorCommand());
|
|
3689
|
+
program.addCommand(createDocumentCommand());
|
|
2662
3690
|
program.addCommand(createOnboardCommand());
|
|
2663
3691
|
program.addCommand(createRefreshCommand());
|
|
2664
3692
|
program.addCommand(createUpdateCommand());
|