ai-forge-cli 3.0.3__tar.gz → 3.0.4__tar.gz
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.
- {ai_forge_cli-3.0.3/src/ai_forge_cli.egg-info → ai_forge_cli-3.0.4}/PKG-INFO +5 -1
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/README.md +4 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/pyproject.toml +1 -1
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4/src/ai_forge_cli.egg-info}/PKG-INFO +5 -1
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/ai_forge_cli.egg-info/SOURCES.txt +3 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/assets/audit_template.html +264 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/commands/__init__.py +2 -1
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/commands/audit.py +219 -3
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/commands/context.py +54 -7
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/commands/init.py +35 -0
- ai_forge_cli-3.0.4/src/cli/commands/knowledge.py +69 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/crawler.py +190 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/forge.py +2 -1
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-build/SKILL.md +9 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-business/SKILL.md +8 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-hydrate/SKILL.md +9 -0
- ai_forge_cli-3.0.4/src/cli/resources/skills/forge-orchestrator/SKILL.md +81 -0
- ai_forge_cli-3.0.4/src/cli/resources/skills/forge-orchestrator/agents/openai.yaml +4 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-review/SKILL.md +9 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-schema/SKILL.md +9 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-security/SKILL.md +9 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/tests/test_context.py +113 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/tests/test_crawler.py +72 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/MANIFEST.in +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/setup.cfg +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/setup.py +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/ai_forge_cli.egg-info/dependency_links.txt +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/ai_forge_cli.egg-info/entry_points.txt +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/ai_forge_cli.egg-info/requires.txt +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/ai_forge_cli.egg-info/top_level.txt +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/__init__.py +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/__main__.py +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/assets/forge_full_logo.drawio.svg +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/assets/forge_white_small.drawio.svg +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/commands/base.py +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/commands/crawl.py +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/common.py +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/FRAMEWORK_V4.md +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/SCHEMA_REFERENCE_V4.md +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-build/agents/openai.yaml +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-business/agents/openai.yaml +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-hydrate/agents/openai.yaml +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-review/agents/openai.yaml +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-schema/FRAMEWORK_REUSE_DRAFT.md +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-schema/agents/openai.yaml +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/resources/skills/forge-security/agents/openai.yaml +0 -0
- {ai_forge_cli-3.0.3 → ai_forge_cli-3.0.4}/src/cli/yaml_io.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ai-forge-cli
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.4
|
|
4
4
|
Summary: Forge V4 architecture context CLI
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -36,6 +36,8 @@ scoped context, validation, and audit artifacts to the active skill.
|
|
|
36
36
|
- `forge crawl`: extract the merged V4 model from central files and code annotations
|
|
37
37
|
- `forge context`: render scoped context for a system, flow, container, entity,
|
|
38
38
|
component, operation, or data shape
|
|
39
|
+
- `forge knowledge`: list supporting Markdown knowledge docs attached to Forge
|
|
40
|
+
refs such as containers, flows, entities, components, and operations
|
|
39
41
|
- `forge audit`: generate a self-contained architecture audit dashboard
|
|
40
42
|
|
|
41
43
|
## What Forge Is
|
|
@@ -44,6 +46,8 @@ scoped context, validation, and audit artifacts to the active skill.
|
|
|
44
46
|
- a skills-first workflow for moving from business discovery to one thin build slice
|
|
45
47
|
- a scoped context generator for build, review, and security tasks
|
|
46
48
|
- an audit artifact generator for human review
|
|
49
|
+
- a lightweight index for repo-native delivery knowledge such as runbooks,
|
|
50
|
+
testing notes, security notes, operations notes, and domain glossaries
|
|
47
51
|
|
|
48
52
|
## What Forge Is Not
|
|
49
53
|
|
|
@@ -21,6 +21,8 @@ scoped context, validation, and audit artifacts to the active skill.
|
|
|
21
21
|
- `forge crawl`: extract the merged V4 model from central files and code annotations
|
|
22
22
|
- `forge context`: render scoped context for a system, flow, container, entity,
|
|
23
23
|
component, operation, or data shape
|
|
24
|
+
- `forge knowledge`: list supporting Markdown knowledge docs attached to Forge
|
|
25
|
+
refs such as containers, flows, entities, components, and operations
|
|
24
26
|
- `forge audit`: generate a self-contained architecture audit dashboard
|
|
25
27
|
|
|
26
28
|
## What Forge Is
|
|
@@ -29,6 +31,8 @@ scoped context, validation, and audit artifacts to the active skill.
|
|
|
29
31
|
- a skills-first workflow for moving from business discovery to one thin build slice
|
|
30
32
|
- a scoped context generator for build, review, and security tasks
|
|
31
33
|
- an audit artifact generator for human review
|
|
34
|
+
- a lightweight index for repo-native delivery knowledge such as runbooks,
|
|
35
|
+
testing notes, security notes, operations notes, and domain glossaries
|
|
32
36
|
|
|
33
37
|
## What Forge Is Not
|
|
34
38
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ai-forge-cli
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.4
|
|
4
4
|
Summary: Forge V4 architecture context CLI
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -36,6 +36,8 @@ scoped context, validation, and audit artifacts to the active skill.
|
|
|
36
36
|
- `forge crawl`: extract the merged V4 model from central files and code annotations
|
|
37
37
|
- `forge context`: render scoped context for a system, flow, container, entity,
|
|
38
38
|
component, operation, or data shape
|
|
39
|
+
- `forge knowledge`: list supporting Markdown knowledge docs attached to Forge
|
|
40
|
+
refs such as containers, flows, entities, components, and operations
|
|
39
41
|
- `forge audit`: generate a self-contained architecture audit dashboard
|
|
40
42
|
|
|
41
43
|
## What Forge Is
|
|
@@ -44,6 +46,8 @@ scoped context, validation, and audit artifacts to the active skill.
|
|
|
44
46
|
- a skills-first workflow for moving from business discovery to one thin build slice
|
|
45
47
|
- a scoped context generator for build, review, and security tasks
|
|
46
48
|
- an audit artifact generator for human review
|
|
49
|
+
- a lightweight index for repo-native delivery knowledge such as runbooks,
|
|
50
|
+
testing notes, security notes, operations notes, and domain glossaries
|
|
47
51
|
|
|
48
52
|
## What Forge Is Not
|
|
49
53
|
|
|
@@ -23,6 +23,7 @@ src/cli/commands/base.py
|
|
|
23
23
|
src/cli/commands/context.py
|
|
24
24
|
src/cli/commands/crawl.py
|
|
25
25
|
src/cli/commands/init.py
|
|
26
|
+
src/cli/commands/knowledge.py
|
|
26
27
|
src/cli/resources/FRAMEWORK_V4.md
|
|
27
28
|
src/cli/resources/SCHEMA_REFERENCE_V4.md
|
|
28
29
|
src/cli/resources/skills/forge-build/SKILL.md
|
|
@@ -31,6 +32,8 @@ src/cli/resources/skills/forge-business/SKILL.md
|
|
|
31
32
|
src/cli/resources/skills/forge-business/agents/openai.yaml
|
|
32
33
|
src/cli/resources/skills/forge-hydrate/SKILL.md
|
|
33
34
|
src/cli/resources/skills/forge-hydrate/agents/openai.yaml
|
|
35
|
+
src/cli/resources/skills/forge-orchestrator/SKILL.md
|
|
36
|
+
src/cli/resources/skills/forge-orchestrator/agents/openai.yaml
|
|
34
37
|
src/cli/resources/skills/forge-review/SKILL.md
|
|
35
38
|
src/cli/resources/skills/forge-review/agents/openai.yaml
|
|
36
39
|
src/cli/resources/skills/forge-schema/FRAMEWORK_REUSE_DRAFT.md
|
|
@@ -598,6 +598,247 @@
|
|
|
598
598
|
.decision-field li + li {
|
|
599
599
|
margin-top: 2px;
|
|
600
600
|
}
|
|
601
|
+
.knowledge-type-grid {
|
|
602
|
+
display: grid;
|
|
603
|
+
grid-auto-flow: column;
|
|
604
|
+
grid-auto-columns: minmax(86px, 1fr);
|
|
605
|
+
gap: 8px;
|
|
606
|
+
margin-bottom: 18px;
|
|
607
|
+
overflow-x: auto;
|
|
608
|
+
padding-bottom: 2px;
|
|
609
|
+
}
|
|
610
|
+
.knowledge-type-grid .card {
|
|
611
|
+
min-width: 0;
|
|
612
|
+
padding: 10px 12px;
|
|
613
|
+
border-radius: 8px;
|
|
614
|
+
}
|
|
615
|
+
.knowledge-type-grid .card h3 {
|
|
616
|
+
margin: 0 0 6px;
|
|
617
|
+
font-size: 13px;
|
|
618
|
+
line-height: 1.15;
|
|
619
|
+
overflow-wrap: anywhere;
|
|
620
|
+
}
|
|
621
|
+
.knowledge-type-grid .card p {
|
|
622
|
+
margin: 0;
|
|
623
|
+
font-size: 12px;
|
|
624
|
+
line-height: 1.15;
|
|
625
|
+
}
|
|
626
|
+
.related-knowledge-block {
|
|
627
|
+
display: grid;
|
|
628
|
+
gap: 14px;
|
|
629
|
+
}
|
|
630
|
+
.knowledge-doc-grid {
|
|
631
|
+
display: grid;
|
|
632
|
+
gap: 14px;
|
|
633
|
+
}
|
|
634
|
+
.knowledge-type-group {
|
|
635
|
+
display: grid;
|
|
636
|
+
gap: 10px;
|
|
637
|
+
min-width: 0;
|
|
638
|
+
}
|
|
639
|
+
.knowledge-type-group-summary {
|
|
640
|
+
display: grid;
|
|
641
|
+
grid-template-columns: minmax(0, 1fr) auto 18px;
|
|
642
|
+
gap: 10px;
|
|
643
|
+
align-items: center;
|
|
644
|
+
padding: 8px 12px;
|
|
645
|
+
border: 1px solid var(--border);
|
|
646
|
+
border-radius: 8px;
|
|
647
|
+
background: var(--panel-alt);
|
|
648
|
+
cursor: pointer;
|
|
649
|
+
list-style: none;
|
|
650
|
+
}
|
|
651
|
+
.knowledge-type-group-summary::-webkit-details-marker {
|
|
652
|
+
display: none;
|
|
653
|
+
}
|
|
654
|
+
.knowledge-type-group-summary::marker {
|
|
655
|
+
content: "";
|
|
656
|
+
}
|
|
657
|
+
.knowledge-type-group-summary span:first-child {
|
|
658
|
+
color: var(--text);
|
|
659
|
+
font-size: 13px;
|
|
660
|
+
font-weight: 700;
|
|
661
|
+
}
|
|
662
|
+
.knowledge-type-group-summary strong {
|
|
663
|
+
display: inline-flex;
|
|
664
|
+
align-items: center;
|
|
665
|
+
justify-content: center;
|
|
666
|
+
min-width: 24px;
|
|
667
|
+
min-height: 20px;
|
|
668
|
+
padding: 0 7px;
|
|
669
|
+
border: 1px solid var(--border);
|
|
670
|
+
border-radius: 999px;
|
|
671
|
+
background: var(--panel);
|
|
672
|
+
color: var(--muted);
|
|
673
|
+
font-size: 12px;
|
|
674
|
+
line-height: 1;
|
|
675
|
+
}
|
|
676
|
+
.knowledge-type-group-docs {
|
|
677
|
+
display: grid;
|
|
678
|
+
gap: 10px;
|
|
679
|
+
}
|
|
680
|
+
.related-knowledge-block {
|
|
681
|
+
margin-top: 18px;
|
|
682
|
+
}
|
|
683
|
+
.knowledge-inline-header {
|
|
684
|
+
margin-bottom: 0;
|
|
685
|
+
}
|
|
686
|
+
.knowledge-doc-card {
|
|
687
|
+
padding: 0;
|
|
688
|
+
overflow: hidden;
|
|
689
|
+
min-width: 0;
|
|
690
|
+
}
|
|
691
|
+
.knowledge-doc-summary {
|
|
692
|
+
display: grid;
|
|
693
|
+
grid-template-columns: minmax(0, 1fr) minmax(260px, auto) 18px;
|
|
694
|
+
gap: 4px 14px;
|
|
695
|
+
align-items: start;
|
|
696
|
+
padding: 12px 14px;
|
|
697
|
+
background: var(--panel);
|
|
698
|
+
cursor: pointer;
|
|
699
|
+
list-style: none;
|
|
700
|
+
min-width: 0;
|
|
701
|
+
}
|
|
702
|
+
.knowledge-doc-summary::-webkit-details-marker {
|
|
703
|
+
display: none;
|
|
704
|
+
}
|
|
705
|
+
.knowledge-doc-summary::marker {
|
|
706
|
+
content: "";
|
|
707
|
+
}
|
|
708
|
+
.knowledge-doc-summary:hover {
|
|
709
|
+
background: var(--hover);
|
|
710
|
+
}
|
|
711
|
+
.knowledge-doc-identity,
|
|
712
|
+
.knowledge-doc-meta {
|
|
713
|
+
min-width: 0;
|
|
714
|
+
}
|
|
715
|
+
.knowledge-doc-identity {
|
|
716
|
+
display: contents;
|
|
717
|
+
}
|
|
718
|
+
.knowledge-doc-summary h4 {
|
|
719
|
+
grid-column: 1;
|
|
720
|
+
grid-row: 1;
|
|
721
|
+
margin: 0;
|
|
722
|
+
font-size: 14px;
|
|
723
|
+
line-height: 1.15;
|
|
724
|
+
}
|
|
725
|
+
.knowledge-doc-summary span {
|
|
726
|
+
color: var(--muted);
|
|
727
|
+
font-size: 12px;
|
|
728
|
+
line-height: 1.15;
|
|
729
|
+
}
|
|
730
|
+
.knowledge-doc-meta {
|
|
731
|
+
display: grid;
|
|
732
|
+
grid-template-columns: auto auto;
|
|
733
|
+
align-items: start;
|
|
734
|
+
justify-content: end;
|
|
735
|
+
gap: 4px 6px;
|
|
736
|
+
grid-column: 2;
|
|
737
|
+
grid-row: 1;
|
|
738
|
+
color: var(--muted);
|
|
739
|
+
font-size: 12px;
|
|
740
|
+
text-align: left;
|
|
741
|
+
}
|
|
742
|
+
.knowledge-doc-meta strong,
|
|
743
|
+
.knowledge-doc-meta em {
|
|
744
|
+
display: inline-flex;
|
|
745
|
+
align-items: center;
|
|
746
|
+
min-height: 20px;
|
|
747
|
+
padding: 0 7px;
|
|
748
|
+
border: 1px solid var(--border);
|
|
749
|
+
border-radius: 999px;
|
|
750
|
+
background: var(--panel-alt);
|
|
751
|
+
font-style: normal;
|
|
752
|
+
font-weight: 600;
|
|
753
|
+
}
|
|
754
|
+
.knowledge-doc-meta-row {
|
|
755
|
+
grid-column: 1;
|
|
756
|
+
display: grid;
|
|
757
|
+
grid-template-columns: 42px minmax(0, 1fr);
|
|
758
|
+
gap: 8px;
|
|
759
|
+
align-items: baseline;
|
|
760
|
+
min-width: 0;
|
|
761
|
+
text-align: left;
|
|
762
|
+
}
|
|
763
|
+
.knowledge-doc-identity .knowledge-doc-meta-row:nth-of-type(1) {
|
|
764
|
+
grid-row: 2;
|
|
765
|
+
}
|
|
766
|
+
.knowledge-doc-identity .knowledge-doc-meta-row:nth-of-type(2) {
|
|
767
|
+
grid-row: 3;
|
|
768
|
+
}
|
|
769
|
+
.knowledge-doc-meta-row span {
|
|
770
|
+
color: var(--subtle);
|
|
771
|
+
font-size: 11px;
|
|
772
|
+
font-weight: 700;
|
|
773
|
+
line-height: 1.15;
|
|
774
|
+
text-transform: uppercase;
|
|
775
|
+
}
|
|
776
|
+
.knowledge-doc-meta-row p {
|
|
777
|
+
margin: 0;
|
|
778
|
+
color: var(--muted);
|
|
779
|
+
font-size: 12px;
|
|
780
|
+
line-height: 1.15;
|
|
781
|
+
}
|
|
782
|
+
.knowledge-doc-file {
|
|
783
|
+
grid-column: 2;
|
|
784
|
+
grid-row: 3;
|
|
785
|
+
justify-self: end;
|
|
786
|
+
align-self: baseline;
|
|
787
|
+
color: var(--muted);
|
|
788
|
+
font-size: 12px;
|
|
789
|
+
line-height: 1.15;
|
|
790
|
+
max-width: 420px;
|
|
791
|
+
overflow-wrap: anywhere;
|
|
792
|
+
text-align: right;
|
|
793
|
+
}
|
|
794
|
+
.knowledge-doc-summary .entity-shape-chevron {
|
|
795
|
+
grid-column: 3;
|
|
796
|
+
grid-row: 1;
|
|
797
|
+
margin-top: 2px;
|
|
798
|
+
}
|
|
799
|
+
.knowledge-doc-summary .entity-shape-chevron::before,
|
|
800
|
+
.knowledge-type-group-summary .entity-shape-chevron::before {
|
|
801
|
+
content: "▶";
|
|
802
|
+
}
|
|
803
|
+
.knowledge-doc-card[open] > .knowledge-doc-summary .entity-shape-chevron::before,
|
|
804
|
+
.knowledge-type-group[open] > .knowledge-type-group-summary .entity-shape-chevron::before {
|
|
805
|
+
content: "▼";
|
|
806
|
+
}
|
|
807
|
+
.knowledge-doc-body {
|
|
808
|
+
padding: 0 18px 16px;
|
|
809
|
+
color: var(--text);
|
|
810
|
+
border-top: 1px solid var(--border);
|
|
811
|
+
}
|
|
812
|
+
.knowledge-doc-body h1,
|
|
813
|
+
.knowledge-doc-body h2,
|
|
814
|
+
.knowledge-doc-body h3,
|
|
815
|
+
.knowledge-doc-body h4 {
|
|
816
|
+
margin: 16px 0 8px;
|
|
817
|
+
font-size: 15px;
|
|
818
|
+
line-height: 1.25;
|
|
819
|
+
}
|
|
820
|
+
.knowledge-doc-body p,
|
|
821
|
+
.knowledge-doc-body li {
|
|
822
|
+
color: var(--muted);
|
|
823
|
+
font-size: 13px;
|
|
824
|
+
line-height: 1.5;
|
|
825
|
+
}
|
|
826
|
+
.knowledge-doc-body p {
|
|
827
|
+
margin: 8px 0 0;
|
|
828
|
+
}
|
|
829
|
+
.knowledge-doc-body ul {
|
|
830
|
+
margin: 8px 0 0;
|
|
831
|
+
padding-left: 20px;
|
|
832
|
+
}
|
|
833
|
+
.knowledge-doc-body pre {
|
|
834
|
+
margin: 10px 0 0;
|
|
835
|
+
padding: 12px;
|
|
836
|
+
border: 1px solid var(--border);
|
|
837
|
+
border-radius: 6px;
|
|
838
|
+
background: var(--panel-alt);
|
|
839
|
+
overflow-x: auto;
|
|
840
|
+
font-size: 12px;
|
|
841
|
+
}
|
|
601
842
|
.annotation-filter {
|
|
602
843
|
display: flex;
|
|
603
844
|
flex-wrap: wrap;
|
|
@@ -2314,6 +2555,24 @@
|
|
|
2314
2555
|
.record-meta {
|
|
2315
2556
|
text-align: left;
|
|
2316
2557
|
}
|
|
2558
|
+
.knowledge-doc-summary {
|
|
2559
|
+
grid-template-columns: minmax(0, 1fr) 18px;
|
|
2560
|
+
}
|
|
2561
|
+
.knowledge-doc-meta {
|
|
2562
|
+
grid-column: 1 / -1;
|
|
2563
|
+
justify-content: start;
|
|
2564
|
+
margin-top: 6px;
|
|
2565
|
+
}
|
|
2566
|
+
.knowledge-doc-file {
|
|
2567
|
+
grid-column: 1 / -1;
|
|
2568
|
+
grid-row: auto;
|
|
2569
|
+
justify-self: start;
|
|
2570
|
+
max-width: none;
|
|
2571
|
+
text-align: left;
|
|
2572
|
+
}
|
|
2573
|
+
.knowledge-doc-summary .entity-shape-chevron {
|
|
2574
|
+
grid-column: 2;
|
|
2575
|
+
}
|
|
2317
2576
|
.runtime-container-header {
|
|
2318
2577
|
grid-template-columns: minmax(0, 1fr);
|
|
2319
2578
|
}
|
|
@@ -2346,6 +2605,7 @@
|
|
|
2346
2605
|
<button class="tab" data-group="Flows">Flows</button>
|
|
2347
2606
|
<button class="tab" data-group="Runtime">Runtime</button>
|
|
2348
2607
|
<button class="tab" data-group="Data">Data</button>
|
|
2608
|
+
<button class="tab" data-group="Knowledge">Knowledge</button>
|
|
2349
2609
|
<button class="tab" data-group="Validation">Validation</button>
|
|
2350
2610
|
<button class="tab" data-group="Quality Assurance">Quality Assurance</button>
|
|
2351
2611
|
</nav>
|
|
@@ -2369,6 +2629,9 @@
|
|
|
2369
2629
|
</div>
|
|
2370
2630
|
<div data-slot="data-body">__DATA_BODY__</div>
|
|
2371
2631
|
</section>
|
|
2632
|
+
<section class="section" id="knowledge-overview" data-group="Knowledge">
|
|
2633
|
+
<div data-slot="knowledge-body">__KNOWLEDGE_BODY__</div>
|
|
2634
|
+
</section>
|
|
2372
2635
|
<section class="section" id="verticals-overview" data-group="Validation">
|
|
2373
2636
|
<div data-slot="verticals-body">__VERTICALS_BODY__</div>
|
|
2374
2637
|
</section>
|
|
@@ -2422,6 +2685,7 @@
|
|
|
2422
2685
|
System: 'system-overview',
|
|
2423
2686
|
Runtime: 'runtime-overview',
|
|
2424
2687
|
Data: 'data-overview',
|
|
2688
|
+
Knowledge: 'knowledge-overview',
|
|
2425
2689
|
Validation: 'verticals-overview',
|
|
2426
2690
|
'Quality Assurance': 'quality-assurance-overview',
|
|
2427
2691
|
};
|
|
@@ -2,5 +2,6 @@ from cli.commands.audit import register_audit
|
|
|
2
2
|
from cli.commands.context import register_context
|
|
3
3
|
from cli.commands.crawl import register_crawl
|
|
4
4
|
from cli.commands.init import register_init
|
|
5
|
+
from cli.commands.knowledge import register_knowledge
|
|
5
6
|
|
|
6
|
-
__all__ = ["register_context", "register_init", "register_audit", "register_crawl"]
|
|
7
|
+
__all__ = ["register_context", "register_init", "register_audit", "register_crawl", "register_knowledge"]
|
|
@@ -5,6 +5,7 @@ import errno
|
|
|
5
5
|
import hashlib
|
|
6
6
|
import json
|
|
7
7
|
import platform
|
|
8
|
+
import re
|
|
8
9
|
import subprocess
|
|
9
10
|
from argparse import Namespace
|
|
10
11
|
from html import escape
|
|
@@ -134,6 +135,7 @@ def render_v4_audit_html(result: ForgeCrawlResult) -> str:
|
|
|
134
135
|
{"id": "system-overview", "group": "System", "label": "System"},
|
|
135
136
|
{"id": "runtime-overview", "group": "Runtime", "label": "Runtime Overview"},
|
|
136
137
|
{"id": "data-overview", "group": "Data", "label": "Entities & Data"},
|
|
138
|
+
{"id": "knowledge-overview", "group": "Knowledge", "label": "Knowledge"},
|
|
137
139
|
{"id": "verticals-overview", "group": "Validation", "label": "Findings"},
|
|
138
140
|
{"id": "quality-assurance-overview", "group": "Quality Assurance", "label": "Quality Assurance"},
|
|
139
141
|
]
|
|
@@ -147,7 +149,7 @@ def render_v4_audit_html(result: ForgeCrawlResult) -> str:
|
|
|
147
149
|
"Flows",
|
|
148
150
|
f"Flow: {flow['id']}",
|
|
149
151
|
"Container-level flow across runtime boundaries.",
|
|
150
|
-
_render_v4_flow_section(flow, model),
|
|
152
|
+
_render_v4_flow_section(flow, model) + _render_related_knowledge(model, [f"flow:{flow['id']}"]),
|
|
151
153
|
str(system.get("id", "forge")),
|
|
152
154
|
with_header=False,
|
|
153
155
|
)
|
|
@@ -161,7 +163,7 @@ def render_v4_audit_html(result: ForgeCrawlResult) -> str:
|
|
|
161
163
|
"Runtime",
|
|
162
164
|
f"Container: {container['id']}",
|
|
163
165
|
"Source-root components, data shapes, and extracted operations.",
|
|
164
|
-
_render_v4_container_section(container),
|
|
166
|
+
_render_v4_container_section(container) + _render_related_knowledge(model, [f"container:{container['id']}"]),
|
|
165
167
|
str(system.get("id", "forge")),
|
|
166
168
|
with_header=False,
|
|
167
169
|
)
|
|
@@ -175,7 +177,7 @@ def render_v4_audit_html(result: ForgeCrawlResult) -> str:
|
|
|
175
177
|
"Data",
|
|
176
178
|
f"Entity: {entity['id']}",
|
|
177
179
|
"Business state, canonical shape, ownership, and persistence.",
|
|
178
|
-
_render_v4_entity_section(entity, model),
|
|
180
|
+
_render_v4_entity_section(entity, model) + _render_related_knowledge(model, [f"entity:{entity['id']}"]),
|
|
179
181
|
str(system.get("id", "forge")),
|
|
180
182
|
with_header=False,
|
|
181
183
|
)
|
|
@@ -215,6 +217,7 @@ def render_v4_audit_html(result: ForgeCrawlResult) -> str:
|
|
|
215
217
|
"__SYSTEM_BODY__": _render_v4_system_section(model),
|
|
216
218
|
"__RUNTIME_BODY__": _render_v4_runtime_section(model),
|
|
217
219
|
"__DATA_BODY__": _render_v4_data_section(model),
|
|
220
|
+
"__KNOWLEDGE_BODY__": _render_v4_knowledge_section(model),
|
|
218
221
|
"__VERTICALS_BODY__": _render_v4_findings_overview(model),
|
|
219
222
|
"__QUALITY_ASSURANCE_BODY__": _render_quality_assurance_overview(str(system.get("id", "forge"))),
|
|
220
223
|
"__DEPLOYMENT_BODY__": "",
|
|
@@ -238,6 +241,7 @@ def _render_v4_overview_section(model: dict[str, object]) -> str:
|
|
|
238
241
|
("System", str(system.get("id", "forge")), "system-overview"),
|
|
239
242
|
("Containers", str(summary.get("containers", 0)), "runtime-overview"),
|
|
240
243
|
("Flows", str(summary.get("container_flows", 0)), "flow-" + str(model["container_flows"][0]["id"]) if model["container_flows"] else "runtime-overview"),
|
|
244
|
+
("Knowledge", str(summary.get("knowledge", 0)), "knowledge-overview"),
|
|
241
245
|
("Findings", str(summary.get("validation_findings", 0)), "verticals-overview"),
|
|
242
246
|
]
|
|
243
247
|
summary_html = "".join(
|
|
@@ -336,6 +340,217 @@ def _render_v4_data_section(model: dict[str, object]) -> str:
|
|
|
336
340
|
return '<div class="record-list">' + "".join(rows) + "</div>"
|
|
337
341
|
|
|
338
342
|
|
|
343
|
+
def _render_v4_knowledge_section(model: dict[str, object]) -> str:
|
|
344
|
+
knowledge = [doc for doc in model.get("knowledge", []) if isinstance(doc, dict)]
|
|
345
|
+
if not knowledge:
|
|
346
|
+
return (
|
|
347
|
+
_section_header(
|
|
348
|
+
"knowledge-overview",
|
|
349
|
+
f"{model['system'].get('id', 'forge')} / Knowledge",
|
|
350
|
+
"Knowledge",
|
|
351
|
+
"Supporting Markdown docs attached to Forge objects.",
|
|
352
|
+
)
|
|
353
|
+
+ '<div class="card"><p>No knowledge docs found under <code>forge/knowledge</code>.</p></div>'
|
|
354
|
+
)
|
|
355
|
+
types = sorted({str(doc.get("type", "unknown") or "unknown") for doc in knowledge})
|
|
356
|
+
summary_cards = "".join(
|
|
357
|
+
'<div class="card card-defined">'
|
|
358
|
+
f'<h3>{escape(type_)}</h3>'
|
|
359
|
+
f'<p>{sum(1 for doc in knowledge if str(doc.get("type", "unknown") or "unknown") == type_)}</p>'
|
|
360
|
+
'</div>'
|
|
361
|
+
for type_ in types
|
|
362
|
+
)
|
|
363
|
+
docs = _knowledge_doc_groups(knowledge, expanded=True)
|
|
364
|
+
return (
|
|
365
|
+
_section_header(
|
|
366
|
+
"knowledge-overview",
|
|
367
|
+
f"{model['system'].get('id', 'forge')} / Knowledge",
|
|
368
|
+
"Knowledge",
|
|
369
|
+
"Runbooks, test suites, security notes, operations notes, glossaries, and guides attached to Forge refs.",
|
|
370
|
+
)
|
|
371
|
+
+ f'<div class="knowledge-type-grid">{summary_cards}</div>'
|
|
372
|
+
+ f'<div class="knowledge-doc-grid">{docs}</div>'
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _render_related_knowledge(model: dict[str, object], refs: list[str]) -> str:
|
|
377
|
+
knowledge = _knowledge_for_refs(model, refs)
|
|
378
|
+
if not knowledge:
|
|
379
|
+
return ""
|
|
380
|
+
return (
|
|
381
|
+
'<section class="related-knowledge-block">'
|
|
382
|
+
'<div class="section-header knowledge-inline-header">'
|
|
383
|
+
'<h3 class="section-title">Related Knowledge</h3>'
|
|
384
|
+
'<p class="section-description">Supporting docs attached to this Forge object.</p>'
|
|
385
|
+
'</div>'
|
|
386
|
+
f'{_knowledge_cards(knowledge, expanded=False)}'
|
|
387
|
+
'</section>'
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _knowledge_for_refs(model: dict[str, object], refs: list[str]) -> list[dict[str, object]]:
|
|
392
|
+
wanted = set(refs)
|
|
393
|
+
return [
|
|
394
|
+
doc
|
|
395
|
+
for doc in model.get("knowledge", [])
|
|
396
|
+
if isinstance(doc, dict) and wanted.intersection(doc.get("refs", []))
|
|
397
|
+
]
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def _knowledge_doc_groups(knowledge: list[dict[str, object]], *, expanded: bool) -> str:
|
|
401
|
+
grouped: dict[str, list[dict[str, object]]] = {}
|
|
402
|
+
for doc in knowledge:
|
|
403
|
+
type_ = str(doc.get("type", "unknown") or "unknown")
|
|
404
|
+
grouped.setdefault(type_, []).append(doc)
|
|
405
|
+
|
|
406
|
+
blocks: list[str] = []
|
|
407
|
+
for type_ in sorted(grouped):
|
|
408
|
+
docs = grouped[type_]
|
|
409
|
+
if len(docs) == 1:
|
|
410
|
+
blocks.append(_knowledge_cards(docs, expanded=expanded))
|
|
411
|
+
continue
|
|
412
|
+
open_attr = " open" if expanded else ""
|
|
413
|
+
blocks.append(
|
|
414
|
+
f'<details class="knowledge-type-group"{open_attr}>'
|
|
415
|
+
'<summary class="knowledge-type-group-summary">'
|
|
416
|
+
f'<span>{escape(type_)}</span>'
|
|
417
|
+
f'<strong>{len(docs)}</strong>'
|
|
418
|
+
'<span class="entity-shape-chevron" aria-hidden="true"></span>'
|
|
419
|
+
'</summary>'
|
|
420
|
+
'<div class="knowledge-type-group-docs">'
|
|
421
|
+
f'{_knowledge_cards(docs, expanded=expanded)}'
|
|
422
|
+
'</div>'
|
|
423
|
+
'</details>'
|
|
424
|
+
)
|
|
425
|
+
return "".join(blocks)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def _knowledge_cards(knowledge: list[dict[str, object]], *, expanded: bool) -> str:
|
|
429
|
+
if not knowledge:
|
|
430
|
+
return "<p>No related knowledge docs.</p>"
|
|
431
|
+
cards: list[str] = []
|
|
432
|
+
for doc in sorted(knowledge, key=lambda item: str(item.get("title") or item.get("path", "")).casefold()):
|
|
433
|
+
type_ = str(doc.get("type", "") or "unknown")
|
|
434
|
+
status = str(doc.get("status", "") or "")
|
|
435
|
+
refs = doc.get("refs", [])
|
|
436
|
+
tags = doc.get("tags", [])
|
|
437
|
+
body = str(doc.get("body") or doc.get("excerpt") or "").strip()
|
|
438
|
+
body_html = _markdown_to_html(body)
|
|
439
|
+
summary = (
|
|
440
|
+
'<div class="knowledge-doc-identity">'
|
|
441
|
+
f'<h4>{escape(str(doc.get("title") or doc.get("path", "")))}</h4>'
|
|
442
|
+
f'{_knowledge_doc_meta_row("Refs", refs)}'
|
|
443
|
+
f'{_knowledge_doc_meta_row("Tags", tags)}'
|
|
444
|
+
'</div>'
|
|
445
|
+
'<div class="knowledge-doc-meta">'
|
|
446
|
+
f'<strong>{escape(type_)}</strong>'
|
|
447
|
+
f'{f"<em>{escape(status)}</em>" if status else ""}'
|
|
448
|
+
'</div>'
|
|
449
|
+
f'<span class="knowledge-doc-file">{escape(str(doc.get("path", "")))}</span>'
|
|
450
|
+
'<span class="entity-shape-chevron" aria-hidden="true"></span>'
|
|
451
|
+
)
|
|
452
|
+
open_attr = " open" if expanded else ""
|
|
453
|
+
cards.append(
|
|
454
|
+
f'<details class="card knowledge-doc-card"{open_attr}>'
|
|
455
|
+
'<summary class="knowledge-doc-summary">'
|
|
456
|
+
f'{summary}'
|
|
457
|
+
'</summary>'
|
|
458
|
+
f'<article class="knowledge-doc-body">{body_html}</article>'
|
|
459
|
+
'</details>'
|
|
460
|
+
)
|
|
461
|
+
return "".join(cards)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def _knowledge_doc_meta_row(label: str, values: object) -> str:
|
|
465
|
+
if not isinstance(values, list):
|
|
466
|
+
return ""
|
|
467
|
+
value_text = ", ".join(
|
|
468
|
+
str(value)
|
|
469
|
+
for value in values
|
|
470
|
+
if str(value).strip()
|
|
471
|
+
)
|
|
472
|
+
if not value_text:
|
|
473
|
+
return ""
|
|
474
|
+
return (
|
|
475
|
+
'<div class="knowledge-doc-meta-row">'
|
|
476
|
+
f'<span>{escape(label)}</span>'
|
|
477
|
+
f'<p>{escape(value_text)}</p>'
|
|
478
|
+
'</div>'
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def _markdown_to_html(markdown: str) -> str:
|
|
483
|
+
lines = markdown.splitlines()
|
|
484
|
+
html: list[str] = []
|
|
485
|
+
paragraph: list[str] = []
|
|
486
|
+
list_items: list[str] = []
|
|
487
|
+
list_tag = "ul"
|
|
488
|
+
code_lines: list[str] = []
|
|
489
|
+
in_code = False
|
|
490
|
+
|
|
491
|
+
def flush_paragraph() -> None:
|
|
492
|
+
if paragraph:
|
|
493
|
+
html.append(f"<p>{escape(' '.join(paragraph))}</p>")
|
|
494
|
+
paragraph.clear()
|
|
495
|
+
|
|
496
|
+
def flush_list() -> None:
|
|
497
|
+
if list_items:
|
|
498
|
+
html.append(f"<{list_tag}>" + "".join(f"<li>{escape(item)}</li>" for item in list_items) + f"</{list_tag}>")
|
|
499
|
+
list_items.clear()
|
|
500
|
+
|
|
501
|
+
for line in lines:
|
|
502
|
+
stripped = line.strip()
|
|
503
|
+
ordered_match = re.match(r"^(\d+)\.\s+(.*)$", stripped)
|
|
504
|
+
if stripped.startswith("```"):
|
|
505
|
+
flush_paragraph()
|
|
506
|
+
flush_list()
|
|
507
|
+
if in_code:
|
|
508
|
+
html.append(f"<pre><code>{escape(chr(10).join(code_lines))}</code></pre>")
|
|
509
|
+
code_lines.clear()
|
|
510
|
+
in_code = False
|
|
511
|
+
else:
|
|
512
|
+
in_code = True
|
|
513
|
+
continue
|
|
514
|
+
if in_code:
|
|
515
|
+
code_lines.append(line)
|
|
516
|
+
continue
|
|
517
|
+
if not stripped:
|
|
518
|
+
flush_paragraph()
|
|
519
|
+
flush_list()
|
|
520
|
+
continue
|
|
521
|
+
if list_items and (line.startswith(" ") or line.startswith("\t")) and not stripped.startswith(("- ", "* ")) and not ordered_match:
|
|
522
|
+
list_items[-1] = f"{list_items[-1]} {stripped}"
|
|
523
|
+
continue
|
|
524
|
+
if stripped.startswith("#"):
|
|
525
|
+
flush_paragraph()
|
|
526
|
+
flush_list()
|
|
527
|
+
level = min(len(stripped) - len(stripped.lstrip("#")), 4)
|
|
528
|
+
title = stripped[level:].strip()
|
|
529
|
+
html.append(f"<h{level}>{escape(title)}</h{level}>")
|
|
530
|
+
continue
|
|
531
|
+
if stripped.startswith(("- ", "* ")):
|
|
532
|
+
flush_paragraph()
|
|
533
|
+
if list_items and list_tag != "ul":
|
|
534
|
+
flush_list()
|
|
535
|
+
list_tag = "ul"
|
|
536
|
+
list_items.append(stripped[2:].strip())
|
|
537
|
+
continue
|
|
538
|
+
if ordered_match:
|
|
539
|
+
flush_paragraph()
|
|
540
|
+
if list_items and list_tag != "ol":
|
|
541
|
+
flush_list()
|
|
542
|
+
list_tag = "ol"
|
|
543
|
+
list_items.append(ordered_match.group(2).strip())
|
|
544
|
+
continue
|
|
545
|
+
flush_list()
|
|
546
|
+
paragraph.append(stripped)
|
|
547
|
+
flush_paragraph()
|
|
548
|
+
flush_list()
|
|
549
|
+
if in_code:
|
|
550
|
+
html.append(f"<pre><code>{escape(chr(10).join(code_lines))}</code></pre>")
|
|
551
|
+
return "".join(html) if html else "<p>No content.</p>"
|
|
552
|
+
|
|
553
|
+
|
|
339
554
|
def _v4_data_overview_chips(entity: dict[str, object], persistence: dict[str, object] | None) -> str:
|
|
340
555
|
chip_specs = [("chip-persistent", str(entity.get("category", "")))]
|
|
341
556
|
if persistence:
|
|
@@ -2153,6 +2368,7 @@ def _toolbar_sections(sections: list[dict[str, str]]) -> list[dict[str, str]]:
|
|
|
2153
2368
|
"system-overview",
|
|
2154
2369
|
"runtime-overview",
|
|
2155
2370
|
"data-overview",
|
|
2371
|
+
"knowledge-overview",
|
|
2156
2372
|
"verticals-overview",
|
|
2157
2373
|
"quality-assurance-overview",
|
|
2158
2374
|
"deployment-overview",
|