baldart 4.18.0 → 4.21.0
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/CHANGELOG.md +47 -0
- package/README.md +15 -9
- package/VERSION +1 -1
- package/framework/.claude/agents/REGISTRY.md +3 -2
- package/framework/.claude/agents/api-perf-cost-auditor.md +2 -3
- package/framework/.claude/agents/code-reviewer.md +2 -2
- package/framework/.claude/agents/codebase-architect.md +31 -52
- package/framework/.claude/agents/coder.md +1 -2
- package/framework/.claude/agents/doc-graph-aligner.md +72 -0
- package/framework/.claude/agents/doc-reviewer.md +3 -39
- package/framework/.claude/agents/plan-auditor.md +2 -3
- package/framework/.claude/agents/prd-card-writer.md +1 -1
- package/framework/.claude/agents/qa-sentinel.md +1 -2
- package/framework/.claude/agents/security-reviewer.md +2 -3
- package/framework/.claude/agents/senior-researcher.md +2 -3
- package/framework/.claude/agents/wiki-curator.md +19 -74
- package/framework/.claude/commands/codexreview.md +5 -6
- package/framework/.claude/skills/bug/SKILL.md +9 -8
- package/framework/.claude/skills/capture/SKILL.md +12 -14
- package/framework/.claude/skills/context-primer/SKILL.md +21 -69
- package/framework/.claude/skills/graph-align/SKILL.md +80 -0
- package/framework/.claude/skills/graphify-bootstrap/SKILL.md +125 -0
- package/framework/.claude/skills/issue-review/SKILL.md +1 -1
- package/framework/.claude/skills/new/SKILL.md +1 -1
- package/framework/.claude/skills/new/references/implement.md +1 -1
- package/framework/.claude/skills/prd/SKILL.md +12 -11
- package/framework/.claude/skills/prd/references/discovery-phase.md +79 -5
- package/framework/.claude/skills/simplify/SKILL.md +3 -0
- package/framework/agents/code-graph-protocol.md +108 -0
- package/framework/agents/code-search-protocol.md +27 -21
- package/framework/agents/index.md +4 -2
- package/framework/agents/llm-wiki-methodology.md +42 -78
- package/framework/docs/CODE-GRAPH-LAYER.md +104 -0
- package/framework/docs/LSP-LAYER.md +6 -6
- package/framework/docs/MCP-INTEGRATION.md +4 -4
- package/framework/docs/PROJECT-CONFIGURATION.md +11 -0
- package/framework/routines/doc-graph-align.routine.yml +53 -0
- package/framework/routines/index.yml +14 -4
- package/framework/routines/wiki-review.routine.yml +8 -5
- package/framework/templates/baldart.config.template.yml +32 -5
- package/package.json +1 -1
- package/src/commands/configure.js +67 -1
- package/src/commands/doctor.js +91 -0
- package/src/commands/update.js +6 -0
- package/src/utils/graphify-installer.js +239 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Code Graph Layer (Graphify) — Operator Guide
|
|
2
|
+
|
|
3
|
+
> Since v4.21.0. Opt-in, gated on `features.has_code_graph`. The **runtime**
|
|
4
|
+
> protocol (when to use the graph vs LSP vs Grep) lives in
|
|
5
|
+
> [`framework/agents/code-graph-protocol.md`](../agents/code-graph-protocol.md);
|
|
6
|
+
> this document covers the *plumbing* — install, config, lifecycle, fallback.
|
|
7
|
+
|
|
8
|
+
## 1. Why this exists
|
|
9
|
+
|
|
10
|
+
After removing the (unused, costly) RAG engine in v4.20.0, BALDART needed a
|
|
11
|
+
retrieval tier for **structural / relational** code questions — "what connects X
|
|
12
|
+
to Y", blast-radius of a change, which modules cluster — that Grep and even LSP
|
|
13
|
+
answer poorly. [Graphify](https://github.com/safishamsi/graphify) builds a code
|
|
14
|
+
knowledge graph (tree-sitter, 28 languages, **local/offline**) with native Leiden
|
|
15
|
+
community detection. The same graph also **re-activates the Karpathy LLM-wiki
|
|
16
|
+
auto-learning loop**: its native `GRAPH_REPORT.md` (god nodes, communities,
|
|
17
|
+
suggested questions) is the gap signal that feeds synthesis candidates.
|
|
18
|
+
|
|
19
|
+
## 2. What BALDART adds vs what Graphify already ships
|
|
20
|
+
|
|
21
|
+
Graphify is a complete tool on its own — it installs its **own** skill, an
|
|
22
|
+
always-on pre-tool hook, a post-commit git hook, and an MCP server. BALDART does
|
|
23
|
+
**not** reimplement any of that. It adds only:
|
|
24
|
+
|
|
25
|
+
- **Gating + config** (`features.has_code_graph` + `graph:` block).
|
|
26
|
+
- **Opt-in install** (`configure` interactive branch, `/graphify-bootstrap`, `doctor` backfill).
|
|
27
|
+
- **A retrieval protocol** telling BALDART's own agents *when* the graph is the right tier.
|
|
28
|
+
- **The wiki rebind** (wiki-curator / capture / `doc-graph-align` consume `GRAPH_REPORT.md`).
|
|
29
|
+
- **Fallback discipline** (silent degrade to LSP→Grep→Git).
|
|
30
|
+
|
|
31
|
+
Everything mutating is a thin wrapper over Graphify's native commands in
|
|
32
|
+
[`src/utils/graphify-installer.js`](../../src/utils/graphify-installer.js).
|
|
33
|
+
There is **no per-language adapter registry** (unlike LSP) — Graphify is one
|
|
34
|
+
language-agnostic tool.
|
|
35
|
+
|
|
36
|
+
## 3. The moving parts
|
|
37
|
+
|
|
38
|
+
| Part | Where | Role |
|
|
39
|
+
|------|-------|------|
|
|
40
|
+
| Config flag + block | `framework/templates/baldart.config.template.yml` | `features.has_code_graph` + `graph.{output_dir,auto_rebuild_hook,register_mcp}` |
|
|
41
|
+
| Installer wrapper | `src/utils/graphify-installer.js` | `detect/install/verify/buildGraph/installGitHook/installAlwaysOn/registerMcp/isStale` |
|
|
42
|
+
| Configure | `src/commands/configure.js` | autodetect (binary on PATH) + prompt + interactive install/build/wire |
|
|
43
|
+
| Update detector | `src/commands/update.js` | diffs the `graph:` block → offers `configure` (extended to diff nested top-level blocks) |
|
|
44
|
+
| Doctor | `src/commands/doctor.js` | `Code graph` line + `graph-install` / `graph-rebuild` / `graph-hook` actions |
|
|
45
|
+
| Retrieval protocol | `framework/agents/code-graph-protocol.md` | when to use the graph; budget; fallback |
|
|
46
|
+
| Wiki rebind | `llm-wiki-methodology.md`, `wiki-curator.md`, `wiki-review.routine.yml`, `capture` | GRAPH_REPORT.md → synthesis candidates |
|
|
47
|
+
| Nightly command | agent `doc-graph-aligner` + routine `doc-graph-align` + skill `/graph-align` | doc↔graph alignment |
|
|
48
|
+
| Bootstrap skill | `/graphify-bootstrap` | explicit install path (CI-safe backfill) |
|
|
49
|
+
|
|
50
|
+
## 4. Install lifecycle
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
features.has_code_graph: true
|
|
54
|
+
│
|
|
55
|
+
├─ baldart configure (INTERACTIVE) ─→ pipx install graphifyy
|
|
56
|
+
│ → graphify update . (build, offline)
|
|
57
|
+
│ → graphify <tool> install (always-on per tools.enabled)
|
|
58
|
+
│ → graphify hook install (auto-rebuild, if auto_rebuild_hook)
|
|
59
|
+
│ → claude mcp add … graphify-mcp (if register_mcp)
|
|
60
|
+
│
|
|
61
|
+
├─ baldart configure --yes / CI ──→ writes the flag ONLY (no silent
|
|
62
|
+
│ Python install) → doctor backfills
|
|
63
|
+
│
|
|
64
|
+
├─ /graphify-bootstrap ───────────→ the explicit, full install path
|
|
65
|
+
│
|
|
66
|
+
└─ baldart doctor ────────────────→ graph-install (binary missing)
|
|
67
|
+
graph-rebuild (stale: built_at_commit ≠ HEAD) · graph-hook (hook missing)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**CI behavior is deliberate**: a Python tool is never installed silently in
|
|
71
|
+
`--yes`/non-interactive runs. The flag is written from autodetect; `doctor` and
|
|
72
|
+
`/graphify-bootstrap` own the actual install.
|
|
73
|
+
|
|
74
|
+
## 5. Native commands BALDART relies on (all offline, 0 API cost)
|
|
75
|
+
|
|
76
|
+
| Purpose | Command |
|
|
77
|
+
|---------|---------|
|
|
78
|
+
| Build / refresh graph | `graphify update <root>` → `<root>/graphify-out/{graph.json, GRAPH_REPORT.md, graph.html}` |
|
|
79
|
+
| Auto-rebuild on commit | `graphify hook install` (post-commit + graph.json union merge-driver) |
|
|
80
|
+
| Always-on per tool | `graphify claude install` / `graphify codex install` / … |
|
|
81
|
+
| Query (relational) | `graphify query "…"`, `graphify path "A" "B"`, `graphify explain "X"`, `graphify affected "X"` |
|
|
82
|
+
| MCP server | `graphify-mcp [graph.json]` (stdio default; `--transport http` available) |
|
|
83
|
+
| Staleness (cron-safe) | `graphify check-update <root>`, or compare `graph.json.built_at_commit` to `git rev-parse HEAD` |
|
|
84
|
+
|
|
85
|
+
LLM API keys are needed **only** for `--wiki` / community naming (`graphify label`)
|
|
86
|
+
/ URL & vision ingestion — all optional. The structural graph + report are free.
|
|
87
|
+
|
|
88
|
+
## 6. Invariants
|
|
89
|
+
|
|
90
|
+
- **The graph is never canonical.** Synthesis candidates it produces cite repo
|
|
91
|
+
SSOT and carry `canonicality: derived`.
|
|
92
|
+
- **Silent fallback.** No task aborts because the graph is missing — degrade to
|
|
93
|
+
LSP→Grep→Git; surface setup gaps via `baldart doctor`, never mid-task.
|
|
94
|
+
- **`graphify-out/` is generated** — must be in `.gitignore`, never versioned.
|
|
95
|
+
- **No per-language registry.** Add nothing per language; Graphify handles 28 via
|
|
96
|
+
tree-sitter. The wrapper composes native commands, never reimplements them.
|
|
97
|
+
- **Schema-change propagation** applies to `features.has_code_graph` + `graph.*`.
|
|
98
|
+
|
|
99
|
+
## 7. Adding capability later
|
|
100
|
+
|
|
101
|
+
The retrieval tier ships CLI-first; the MCP path is opt-in. To deepen the
|
|
102
|
+
integration (e.g. wire `graphify-mcp` as a first-class MCP tool, or use `--wiki`
|
|
103
|
+
community pages directly as wiki concept pages), extend `graphify-installer.js`
|
|
104
|
+
and the protocol module — do not fork Graphify's native behavior.
|
|
@@ -13,7 +13,7 @@ A complete operator + agent reference for the LSP retrieval tier introduced in
|
|
|
13
13
|
- a contributor wants to add a new language adapter or change the fallback
|
|
14
14
|
rules.
|
|
15
15
|
|
|
16
|
-
For the *runtime* protocol (
|
|
16
|
+
For the *runtime* protocol (LSP → Grep → Git, query-type
|
|
17
17
|
discrimination, budget) read [`framework/agents/code-search-protocol.md`](../agents/code-search-protocol.md).
|
|
18
18
|
This document covers the *plumbing*: how the layer is installed, configured,
|
|
19
19
|
verified, and wired into agents/skills.
|
|
@@ -24,7 +24,7 @@ verified, and wired into agents/skills.
|
|
|
24
24
|
|
|
25
25
|
Pre-v3.10, every BALDART code-exploration flow ran:
|
|
26
26
|
|
|
27
|
-
>
|
|
27
|
+
> canonical-doc routing → `git log` → **Grep** → read files.
|
|
28
28
|
|
|
29
29
|
Grep collapses semantically distinct symbols that share a name. A search for
|
|
30
30
|
`handleSubmit` in a medium repo dumps every form handler, every CLI utility,
|
|
@@ -41,7 +41,7 @@ unrelated `handleSubmit` is filtered out before any file is read.
|
|
|
41
41
|
The layer is **opt-in** (some consumers don't want a global npm install for a
|
|
42
42
|
language server, some target languages we don't have an adapter for yet) and
|
|
43
43
|
**degrades gracefully** (when
|
|
44
|
-
LSP is unavailable, agents silently fall back to the
|
|
44
|
+
LSP is unavailable, agents silently fall back to the Grep flow,
|
|
45
45
|
so existing behavior is preserved).
|
|
46
46
|
|
|
47
47
|
---
|
|
@@ -217,14 +217,14 @@ When `codebase-architect` or one of the code-exploration skills (`bug`,
|
|
|
217
217
|
`prd`, `new`, `simplify`, `context-primer`) is invoked:
|
|
218
218
|
|
|
219
219
|
1. Read `baldart.config.yml`. If `features.has_lsp_layer !== true`, behave
|
|
220
|
-
|
|
220
|
+
as the Grep → Git flow.
|
|
221
221
|
2. Otherwise: classify the query.
|
|
222
222
|
- Identifier-shaped (function name, type name, class, exported symbol) →
|
|
223
223
|
**LSP first** (`ToolSearch("LSP")` → `find-references` / `definition`).
|
|
224
224
|
- Free text / phrase / comment / path / regex → **Grep first**, LSP is
|
|
225
225
|
useless here.
|
|
226
|
-
- Mixed (e.g. "refactor function X used in 5 places") →
|
|
227
|
-
conceptual context, then LSP for the structural part.
|
|
226
|
+
- Mixed (e.g. "refactor function X used in 5 places") → Grep to disambiguate
|
|
227
|
+
the conceptual context, then LSP for the structural part.
|
|
228
228
|
3. Budget: max **3 LSP calls per task**. After 3 calls without convergence,
|
|
229
229
|
escalate to direct file reads — don't ping-pong references.
|
|
230
230
|
4. If LSP tool isn't loaded / plugin missing / timeout > 8s / zero
|
|
@@ -27,8 +27,8 @@ Non è un'imposizione: BALDART non installa MCP, non li valida, non li richiede.
|
|
|
27
27
|
### Browser automation
|
|
28
28
|
- **Playwright MCP** (`@modelcontextprotocol/server-playwright`) — usato da [bug](../.claude/skills/bug/SKILL.md) e [webapp-testing](../.claude/skills/webapp-testing/SKILL.md) per cattura visiva, network, console.
|
|
29
29
|
|
|
30
|
-
###
|
|
31
|
-
- **
|
|
30
|
+
### Code knowledge graph (Graphify)
|
|
31
|
+
- **Graphify** (`pipx install graphifyy` → CLI `graphify` + MCP server `graphify-mcp`) — code knowledge graph (tree-sitter, locale/offline, Leiden nativo). Gatato da `features.has_code_graph`. Usato da [codebase-architect](../.claude/agents/codebase-architect.md) e dalle skill di esplorazione per query **strutturali/relazionali** (`graphify query`/`path`/`explain`/`affected`), e dal layer wiki (`wiki-curator`, `/capture`, routine `doc-graph-align`) che si alimenta del `GRAPH_REPORT.md` nativo. **CLI-first** (sempre disponibile post-install); l'MCP `graphify-mcp` è opt-in (`graph.register_mcp`, best-effort `claude mcp add`). Fallback: degrada a LSP→Grep→Git. Vedi [code-graph-protocol.md](../agents/code-graph-protocol.md) e [CODE-GRAPH-LAYER.md](CODE-GRAPH-LAYER.md).
|
|
32
32
|
|
|
33
33
|
### Database
|
|
34
34
|
- **Firebase MCP** (`@modelcontextprotocol/server-firebase` — già integrato come plugin BALDART quando `stack.database.primary` è Firestore) — ispezione documenti, query collection, transazioni.
|
|
@@ -86,8 +86,8 @@ Subito dopo la sezione `## Project Context` (o, in mancanza, subito dopo il fron
|
|
|
86
86
|
### Esempi nel framework corrente
|
|
87
87
|
|
|
88
88
|
Vedi le seguenti dichiarazioni per pattern di riferimento:
|
|
89
|
-
- [framework/.claude/agents/codebase-architect.md](../.claude/agents/codebase-architect.md) — `## MCP dependencies` con
|
|
90
|
-
- [framework/.claude/skills/bug/SKILL.md](../.claude/skills/bug/SKILL.md) — Playwright required per UI bug,
|
|
89
|
+
- [framework/.claude/agents/codebase-architect.md](../.claude/agents/codebase-architect.md) — `## MCP dependencies` con Graphify (code graph) + LSP-related optional.
|
|
90
|
+
- [framework/.claude/skills/bug/SKILL.md](../.claude/skills/bug/SKILL.md) — Playwright required per UI bug, Firestore optional.
|
|
91
91
|
- [framework/.claude/skills/playwright-skill/SKILL.md](../.claude/skills/playwright-skill/SKILL.md) — esempio di sezione "None" (la skill usa Playwright Test CLI, non MCP).
|
|
92
92
|
|
|
93
93
|
---
|
|
@@ -209,6 +209,7 @@ Every flag MUST be present as `true` or `false` once `baldart configure` has run
|
|
|
209
209
|
| `has_prd_workflow` | PRD workflow (`paths.prd_dir`). `/prd` and `/prd-add` skills refuse to run without it. |
|
|
210
210
|
| `has_wiki_overlay` | LLM-wiki overlay (`paths.wiki_dir`). `/capture` skill refuses to run without it. |
|
|
211
211
|
| `has_lsp_layer` | LSP symbol-search layer (since v3.10.0). When `true`, `codebase-architect`, `context-primer`, `bug`, `prd`, `new`, and `simplify` prefer LSP `find-references` / `go-to-definition` over Grep for identifier queries. Wired by `framework/agents/code-search-protocol.md`. The flag also triggers `baldart configure` (and the `/lsp-bootstrap` skill) to install the matching language servers. |
|
|
212
|
+
| `has_code_graph` | Code knowledge graph layer (Graphify, since v4.21.0). When `true`, agents prefer the graph for **structural/relational** queries (`graphify query`/`path`/`affected`) via `framework/agents/code-graph-protocol.md`, and the LLM-wiki overlay is fed by Graphify's native `GRAPH_REPORT.md`. Triggers `baldart configure` / `/graphify-bootstrap` to install Graphify (`pipx install graphifyy`). Install is never silent in CI — `baldart doctor` backfills. Falls back silently to LSP→Grep→Git. |
|
|
212
213
|
|
|
213
214
|
### 4.6 `lsp` — installed language servers (since v3.10.0)
|
|
214
215
|
|
|
@@ -219,6 +220,16 @@ Populated by `baldart configure` and the `/lsp-bootstrap` skill when `features.h
|
|
|
219
220
|
| `lsp.installed_servers` | List of language IDs (`typescript`, `python`, `go`, `rust`, `ruby`, …) whose server BALDART has recorded for this project. Identifiers map 1:1 to adapter files under `src/utils/lsp-adapters/`. |
|
|
220
221
|
| `lsp.auto_verify` | When `true` (default), `baldart doctor` re-verifies the binaries are reachable **on `$PATH`** (via `command -v`, mirroring how the Claude Code LSP tool spawns them) on every run. Disable on CI if the verify step is too noisy. |
|
|
221
222
|
|
|
223
|
+
### 4.7 `graph` — code knowledge graph state (since v4.21.0)
|
|
224
|
+
|
|
225
|
+
Populated by `baldart configure` / the `/graphify-bootstrap` skill when `features.has_code_graph: true`. Scalars only (no arrays) by design. See `framework/docs/CODE-GRAPH-LAYER.md`.
|
|
226
|
+
|
|
227
|
+
| Key | Meaning |
|
|
228
|
+
|---|---|
|
|
229
|
+
| `graph.output_dir` | Directory Graphify writes the graph + report to (relative to the graphed root). Graphify's native default is `graphify-out`. Add it to `.gitignore` — generated artifact, never versioned. |
|
|
230
|
+
| `graph.auto_rebuild_hook` | When `true` (default), `configure` / `/graphify-bootstrap` run Graphify's native `graphify hook install` (post-commit hook that rebuilds the graph, no API cost). `baldart doctor` restores it if missing. |
|
|
231
|
+
| `graph.register_mcp` | When `true`, register Graphify's MCP server (`graphify-mcp`) with the AI tool (best-effort `claude mcp add`). Opt-in: the CLI path (`graphify query`) works without it. |
|
|
232
|
+
|
|
222
233
|
**Install modes per adapter:**
|
|
223
234
|
|
|
224
235
|
- `typescript`, `python` — installed globally via npm (`npm install -g typescript-language-server typescript` / `pyright`). Global on purpose: the consumer spawns the server by name from `$PATH`, so a project-local devDep under `node_modules/.bin/` would never be reachable. A binary present only in `node_modules` is reported `installed-but-unreachable`, not `verified`.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: doc-graph-align
|
|
2
|
+
description: Nightly documentation alignment via the Graphify code knowledge graph — rebuilds the graph offline and surfaces uncovered core code, stale docs, and registry drift.
|
|
3
|
+
since_version: 4.21.0
|
|
4
|
+
|
|
5
|
+
schedule:
|
|
6
|
+
cron: "0 4 * * *" # 04:00 UTC daily (after wiki-review at 02:00)
|
|
7
|
+
timezone: UTC
|
|
8
|
+
jitter_minutes: 0
|
|
9
|
+
cadence_label: nightly
|
|
10
|
+
|
|
11
|
+
agent: doc-graph-aligner
|
|
12
|
+
|
|
13
|
+
prompt: |
|
|
14
|
+
Run the nightly doc–graph alignment pass (only if `features.has_code_graph: true`
|
|
15
|
+
AND the `graphify` CLI is installed — otherwise emit
|
|
16
|
+
`doc-graph-align skipped: graphify not installed` and exit cleanly):
|
|
17
|
+
|
|
18
|
+
1. Refresh the graph offline: `graphify update .` (rebuilds
|
|
19
|
+
`${graph.output_dir}/graph.json` + `GRAPH_REPORT.md`, no API cost).
|
|
20
|
+
2. Read `${graph.output_dir}/GRAPH_REPORT.md` (god nodes, Leiden communities,
|
|
21
|
+
surprising connections, suggested questions, freshness).
|
|
22
|
+
3. Cross-check graph → docs and flag:
|
|
23
|
+
- Uncovered core code: god nodes / communities with no page under
|
|
24
|
+
`${paths.wiki_dir}/syntheses/` and no canonical reference doc → append a
|
|
25
|
+
synthesis candidate to `${paths.wiki_dir}/log.md`
|
|
26
|
+
(`entry_type: synthesis_candidate`, cite the graph node/community id).
|
|
27
|
+
- Stale docs: doc files referencing symbols/files absent from the graph
|
|
28
|
+
(deleted/renamed code) → drift finding for doc-reviewer follow-up.
|
|
29
|
+
- Registry drift: large graph communities with no
|
|
30
|
+
`${paths.references_dir}/ssot-registry.md` entry, or registry features whose
|
|
31
|
+
code cluster is unrecognizable in the graph.
|
|
32
|
+
4. Emit a consolidated report under
|
|
33
|
+
`docs/reports/{{YYYYMMDD}}-doc-graph-align.md`.
|
|
34
|
+
|
|
35
|
+
Propose, don't author: do NOT rewrite canonical SSOT or wiki pages. The graph
|
|
36
|
+
is never canonical — synthesis candidates must cite repo SSOT.
|
|
37
|
+
|
|
38
|
+
output:
|
|
39
|
+
path: docs/reports/{{YYYYMMDD}}-doc-graph-align.md
|
|
40
|
+
commit:
|
|
41
|
+
enabled: true
|
|
42
|
+
prefix: "[DOC-GRAPH-ALIGN]"
|
|
43
|
+
branch: main
|
|
44
|
+
|
|
45
|
+
required_artifacts:
|
|
46
|
+
- .claude/agents/doc-graph-aligner.md
|
|
47
|
+
|
|
48
|
+
optional: true # routine is silently skipped when the agent / graph layer is absent
|
|
49
|
+
|
|
50
|
+
backend_hints:
|
|
51
|
+
- claude-code-cloud
|
|
52
|
+
- github-actions
|
|
53
|
+
- cron
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# RemoteTrigger, GitHub Actions, cron, …) is chosen at install time via
|
|
6
6
|
# `npx baldart routines install <name>`.
|
|
7
7
|
#
|
|
8
|
-
# Routines are designed to make the framework's
|
|
8
|
+
# Routines are designed to make the framework's maintenance and drift-
|
|
9
9
|
# detection loops actually run. Without these schedules, agents like
|
|
10
10
|
# wiki-curator or skill-improver are dormant.
|
|
11
11
|
#
|
|
@@ -37,9 +37,19 @@ routines:
|
|
|
37
37
|
cadence: nightly
|
|
38
38
|
since_version: 2.1.0
|
|
39
39
|
summary: |
|
|
40
|
-
Nightly wiki review —
|
|
41
|
-
Surfaces synthesis candidates
|
|
42
|
-
|
|
40
|
+
Nightly wiki review — maintains the derived LLM-wiki overlay.
|
|
41
|
+
Surfaces synthesis candidates (from recent ADRs/PRDs), validates
|
|
42
|
+
anchors, and checks frontmatter discipline.
|
|
43
|
+
|
|
44
|
+
- name: doc-graph-align
|
|
45
|
+
file: doc-graph-align.routine.yml
|
|
46
|
+
cadence: nightly
|
|
47
|
+
since_version: 4.21.0
|
|
48
|
+
summary: |
|
|
49
|
+
Nightly documentation alignment via the Graphify code knowledge graph —
|
|
50
|
+
rebuilds the graph offline and surfaces uncovered core code, stale docs,
|
|
51
|
+
and registry drift. Optional (only runs when features.has_code_graph is
|
|
52
|
+
true and Graphify is installed).
|
|
43
53
|
|
|
44
54
|
# Weekly cadence ----------------------------------------------------------
|
|
45
55
|
- name: skill-improve
|
|
@@ -17,13 +17,16 @@ prompt: |
|
|
|
17
17
|
(provider swap, schema change, auth change, API contract, multi-card
|
|
18
18
|
epic) propose a synthesis page candidate and append it to
|
|
19
19
|
`${paths.wiki_dir}/log.md` with `entry_type: synthesis_candidate`.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
1b. (only if `features.has_code_graph: true` AND `${graph.output_dir}/GRAPH_REPORT.md`
|
|
21
|
+
exists) Cross-check the code graph: god nodes / Leiden communities / suggested
|
|
22
|
+
questions in GRAPH_REPORT.md with no corresponding page under
|
|
23
|
+
`${paths.wiki_dir}/syntheses/` → propose a synthesis candidate (cite the graph
|
|
24
|
+
node/community id as provenance). Skip silently if Graphify is absent.
|
|
25
|
+
2. Validate anchor slugs across all wiki pages (internal and cross-file).
|
|
23
26
|
Flag `WIKI_ANCHOR_BROKEN` and fix in-place when possible.
|
|
24
|
-
|
|
27
|
+
3. Verify frontmatter discipline on every wiki page. Run the project's
|
|
25
28
|
frontmatter validator if it exists.
|
|
26
|
-
|
|
29
|
+
4. Emit a consolidated report under `docs/reports/{{YYYYMMDD}}-wiki-review.md`.
|
|
27
30
|
|
|
28
31
|
Do NOT create canonical truth in the wiki layer. SSOT always wins.
|
|
29
32
|
|
|
@@ -50,11 +50,6 @@ paths:
|
|
|
50
50
|
# Default convention is "docs/metrics" — set explicitly to override.
|
|
51
51
|
metrics: "" # e.g. docs/metrics
|
|
52
52
|
|
|
53
|
-
# Optional telemetry tap for the wiki auto-learning loop. When set, skills
|
|
54
|
-
# append retrieval signal here; when empty, the tap is skipped with a
|
|
55
|
-
# WARNING (never a silent no-op). Only meaningful with has_wiki_overlay.
|
|
56
|
-
wiki_log: "" # e.g. tools/doc-rag/wiki_log.py
|
|
57
|
-
|
|
58
53
|
# High-risk module paths used by RISK DETECTORS (review-profile escalation,
|
|
59
54
|
# security/perf signal detection). A portable list of repo-relative globs
|
|
60
55
|
# the project considers sensitive (auth, payments, billing, core engines).
|
|
@@ -162,6 +157,18 @@ features:
|
|
|
162
157
|
# `baldart configure` installs the relevant language servers when enabled.
|
|
163
158
|
has_lsp_layer: false
|
|
164
159
|
|
|
160
|
+
# Code knowledge graph layer (Graphify) — since v4.21.0. When true, agents and
|
|
161
|
+
# skills that explore code prefer Graphify for STRUCTURAL / RELATIONAL queries
|
|
162
|
+
# ("what connects X to Y", neighbours, communities, impact) over LSP/Grep, and
|
|
163
|
+
# the LLM-wiki overlay (capture/wiki-curator) is fed by Graphify's native
|
|
164
|
+
# GRAPH_REPORT.md (god nodes, communities, suggested questions). Falls back
|
|
165
|
+
# silently to LSP -> Grep -> Git when the graph is unavailable. Graphify is a
|
|
166
|
+
# single language-agnostic tool (tree-sitter, local/offline; pip pkg
|
|
167
|
+
# `graphifyy`, CLI `graphify`). `baldart configure` / `/graphify-bootstrap`
|
|
168
|
+
# install it. See framework/agents/code-graph-protocol.md and
|
|
169
|
+
# framework/docs/CODE-GRAPH-LAYER.md.
|
|
170
|
+
has_code_graph: false
|
|
171
|
+
|
|
165
172
|
# End-to-end review BLOCKING gate (since v3.18.0). When true, /new Phase 2.6
|
|
166
173
|
# invokes the /e2e-review skill, which combines functional E2E (Playwright
|
|
167
174
|
# spec written by `coder`, executed via playwright-skill) with visual
|
|
@@ -214,6 +221,26 @@ lsp:
|
|
|
214
221
|
# every run. Disable on CI if the verify step is too noisy.
|
|
215
222
|
auto_verify: true
|
|
216
223
|
|
|
224
|
+
# ─── CODE GRAPH ────────────────────────────────────────────────────────────
|
|
225
|
+
# State of the Graphify code-knowledge-graph layer. Populated by
|
|
226
|
+
# `baldart configure` / the `/graphify-bootstrap` skill. Only meaningful when
|
|
227
|
+
# `features.has_code_graph: true`. Scalars only (no arrays) by design.
|
|
228
|
+
graph:
|
|
229
|
+
# Directory Graphify writes the graph + report to (relative to the graphed
|
|
230
|
+
# root). Graphify's own default is `graphify-out`. Add it to `.gitignore` —
|
|
231
|
+
# it is a generated artifact, never versioned.
|
|
232
|
+
output_dir: graphify-out
|
|
233
|
+
|
|
234
|
+
# When true, `baldart configure` / `/graphify-bootstrap` run Graphify's
|
|
235
|
+
# NATIVE `graphify hook install` (post-commit git hook that rebuilds the
|
|
236
|
+
# graph after each commit, no API cost) so the graph never goes stale.
|
|
237
|
+
auto_rebuild_hook: true
|
|
238
|
+
|
|
239
|
+
# When true, register Graphify's MCP server (`graphify-mcp`) with the AI tool
|
|
240
|
+
# (best-effort `claude mcp add`). Opt-in: the CLI path (`graphify query`) works
|
|
241
|
+
# without it, so this is an enhancement, not a requirement.
|
|
242
|
+
register_mcp: false
|
|
243
|
+
|
|
217
244
|
# ─── GIT ─────────────────────────────────────────────────────────────────
|
|
218
245
|
# Controls how worktree-manager (`/mw`) integrates a worktree's feature
|
|
219
246
|
# branch back into the integration trunk.
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ const UI = require('../utils/ui');
|
|
|
5
5
|
const toolAdapters = require('../utils/tool-adapters');
|
|
6
6
|
const LspInstaller = require('../utils/lsp-installer');
|
|
7
7
|
const lspAdapters = require('../utils/lsp-adapters');
|
|
8
|
+
const GraphifyInstaller = require('../utils/graphify-installer');
|
|
8
9
|
|
|
9
10
|
const CONFIG_FILE = 'baldart.config.yml';
|
|
10
11
|
// The subtree pull copies the entire BALDART repo (which itself has a
|
|
@@ -375,7 +376,6 @@ function detect(cwd = process.cwd()) {
|
|
|
375
376
|
wiki_dir: exists('docs/wiki') ? 'docs/wiki' : '',
|
|
376
377
|
e2e_tests_dir: e2eTestsDir,
|
|
377
378
|
metrics: exists('docs/metrics') ? 'docs/metrics' : '',
|
|
378
|
-
wiki_log: exists('tools/doc-rag/wiki_log.py') ? 'tools/doc-rag/wiki_log.py' : '',
|
|
379
379
|
high_risk_modules: [],
|
|
380
380
|
},
|
|
381
381
|
identity: {
|
|
@@ -428,6 +428,10 @@ function detect(cwd = process.cwd()) {
|
|
|
428
428
|
// LSP recommended when any supported language server adapter would
|
|
429
429
|
// detect this project. Drives the default for the configure prompt.
|
|
430
430
|
has_lsp_layer: lspAdapters.detectAll(cwd).length > 0,
|
|
431
|
+
// Code graph recommended when the Graphify CLI is already on PATH.
|
|
432
|
+
// Drives the default for the configure prompt; the install/build side
|
|
433
|
+
// effects only run in the interactive branch (see below).
|
|
434
|
+
has_code_graph: new GraphifyInstaller(cwd).detect(),
|
|
431
435
|
},
|
|
432
436
|
tools: {
|
|
433
437
|
enabled: toolAdapters.defaultEnabled(cwd)
|
|
@@ -595,6 +599,7 @@ async function interactivePrompts(merged, detected) {
|
|
|
595
599
|
['has_prd_workflow', 'Project uses PRD workflow (docs/prd/)?'],
|
|
596
600
|
['has_wiki_overlay', 'Project has LLM-wiki overlay (docs/wiki/)?'],
|
|
597
601
|
['has_lsp_layer', 'Enable LSP symbol-search layer? (recommended for large codebases)'],
|
|
602
|
+
['has_code_graph', 'Enable Graphify code-knowledge-graph layer? (structural queries + wiki feed; recommended for large codebases)'],
|
|
598
603
|
['has_e2e_review', 'Enable BLOCKING end-to-end review (Phase 2.6 of /new invokes /e2e-review — functional + visual fidelity gate)?'],
|
|
599
604
|
]) {
|
|
600
605
|
const [key, question] = flag;
|
|
@@ -817,6 +822,67 @@ async function interactivePrompts(merged, detected) {
|
|
|
817
822
|
merged.lsp.installed_servers = [];
|
|
818
823
|
}
|
|
819
824
|
|
|
825
|
+
// ---- Code graph layer (Graphify, since v4.21.0) -----------------------
|
|
826
|
+
// Single language-agnostic tool — no per-language adapters. This block lives
|
|
827
|
+
// inside interactivePrompts (so it only runs in the interactive path; CI /
|
|
828
|
+
// `--yes` writes the flag from autodetect and `baldart doctor` backfills the
|
|
829
|
+
// install). Everything is a thin wrapper over Graphify's native commands.
|
|
830
|
+
merged.graph = merged.graph || { output_dir: 'graphify-out', auto_rebuild_hook: true, register_mcp: false };
|
|
831
|
+
if (merged.features.has_code_graph === true) {
|
|
832
|
+
UI.section('Code graph layer (Graphify — structural retrieval + wiki feed)');
|
|
833
|
+
const gi = new GraphifyInstaller(process.cwd());
|
|
834
|
+
let present = gi.detect();
|
|
835
|
+
|
|
836
|
+
if (!present) {
|
|
837
|
+
const want = await UI.confirm('Graphify CLI not found. Install it now (`pipx install graphifyy`)?', true);
|
|
838
|
+
if (want) {
|
|
839
|
+
const res = gi.install();
|
|
840
|
+
if (res.ok) { UI.success(`Graphify installed (${res.method}).`); present = true; }
|
|
841
|
+
else { UI.warning(`Graphify install failed: ${res.error}`); UI.info('Run `/graphify-bootstrap` or `pipx install graphifyy` later, then `baldart doctor`.'); }
|
|
842
|
+
} else {
|
|
843
|
+
UI.info('Skipping install. Run `/graphify-bootstrap` later — `baldart doctor` will flag the missing binary.');
|
|
844
|
+
}
|
|
845
|
+
} else {
|
|
846
|
+
const v = gi.verify();
|
|
847
|
+
UI.info(`Graphify present (${v.version || 'version unknown'}).`);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (present) {
|
|
851
|
+
// Initial offline graph build (no API cost).
|
|
852
|
+
if (await UI.confirm('Build the code graph now (`graphify update .`, offline)?', true)) {
|
|
853
|
+
const b = gi.buildGraph(process.cwd());
|
|
854
|
+
if (!b.ok) UI.warning(`Graph build failed: ${b.error}`);
|
|
855
|
+
}
|
|
856
|
+
// Always-on wiring for each enabled AI tool (graph-first instructions + pre-tool hook).
|
|
857
|
+
const aw = gi.installAlwaysOn(merged.tools.enabled || ['claude']);
|
|
858
|
+
if (aw.wired.length) UI.success(`Graphify always-on wired for: ${aw.wired.join(', ')}`);
|
|
859
|
+
for (const s of aw.skipped) UI.info(`Always-on skipped for ${s.tool}: ${s.reason}`);
|
|
860
|
+
// Native post-commit git hook (auto-rebuild) when opted in.
|
|
861
|
+
if (merged.graph.auto_rebuild_hook !== false) {
|
|
862
|
+
const h = gi.installGitHook();
|
|
863
|
+
if (h.ok) UI.success('Graphify git hook installed (auto-rebuild on commit).');
|
|
864
|
+
else UI.info(`Git hook not installed: ${h.error}`);
|
|
865
|
+
}
|
|
866
|
+
// Optional MCP registration (CLI path works without it).
|
|
867
|
+
if (merged.graph.register_mcp === true) {
|
|
868
|
+
const m = gi.registerMcp(process.cwd(), merged.graph.output_dir || 'graphify-out');
|
|
869
|
+
if (m.ok) UI.success('Graphify MCP server registered (`graphify-mcp`).');
|
|
870
|
+
else UI.info(`MCP registration skipped: ${m.reason}`);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// Certification — attest binary + first run + freshness + hook in one shot.
|
|
874
|
+
const cert = gi.certify(process.cwd(), {
|
|
875
|
+
outputDir: merged.graph.output_dir || 'graphify-out',
|
|
876
|
+
expectHook: merged.graph.auto_rebuild_hook !== false,
|
|
877
|
+
});
|
|
878
|
+
if (cert.ok && cert.fresh && cert.hook) {
|
|
879
|
+
UI.success(`Code graph CERTIFIED: graphify ${cert.version || ''} present, first graph built (${cert.builtAtCommit || 'commit n/a'}), auto-rebuild hook active.`);
|
|
880
|
+
} else {
|
|
881
|
+
UI.warning(`Code graph NOT fully certified — ${cert.details}${cert.hook ? '' : ' · auto-rebuild hook missing'}. Run \`baldart doctor\` or \`/graphify-bootstrap\` to finish.`);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
820
886
|
UI.section('Stack (autodetected from package.json — confirm or override)');
|
|
821
887
|
const charting = merged.stack.charting;
|
|
822
888
|
const chartingCanonical = await promptForKey(
|
package/src/commands/doctor.js
CHANGED
|
@@ -32,6 +32,7 @@ const State = require('../utils/state');
|
|
|
32
32
|
const Hooks = require('../utils/hooks');
|
|
33
33
|
const GitHooks = require('../utils/githooks');
|
|
34
34
|
const LspInstaller = require('../utils/lsp-installer');
|
|
35
|
+
const GraphifyInstaller = require('../utils/graphify-installer');
|
|
35
36
|
const UpdateNotifier = require('../utils/update-notifier');
|
|
36
37
|
const cliPackageJson = require('../../package.json');
|
|
37
38
|
|
|
@@ -363,6 +364,30 @@ async function detectState(cwd, opts = {}) {
|
|
|
363
364
|
}
|
|
364
365
|
}
|
|
365
366
|
} catch (_) { /* never block doctor on LSP probe */ }
|
|
367
|
+
|
|
368
|
+
// ---- Code graph layer (Graphify, since v4.21.0) --------------------
|
|
369
|
+
state.graphEnabled = false;
|
|
370
|
+
state.graphBinaryMissing = false;
|
|
371
|
+
state.graphStale = false;
|
|
372
|
+
state.graphNotBuilt = false;
|
|
373
|
+
state.graphHookMissing = false;
|
|
374
|
+
try {
|
|
375
|
+
if (config && !config.__malformed && config.features && config.features.has_code_graph === true) {
|
|
376
|
+
state.graphEnabled = true;
|
|
377
|
+
const gi = new GraphifyInstaller(cwd);
|
|
378
|
+
if (!gi.detect()) {
|
|
379
|
+
state.graphBinaryMissing = true;
|
|
380
|
+
} else {
|
|
381
|
+
const outDir = (config.graph && config.graph.output_dir) || 'graphify-out';
|
|
382
|
+
const st = gi.isStale(cwd, outDir);
|
|
383
|
+
state.graphNotBuilt = !st.built;
|
|
384
|
+
state.graphStale = st.stale === true;
|
|
385
|
+
if (config.graph && config.graph.auto_rebuild_hook !== false) {
|
|
386
|
+
state.graphHookMissing = gi.hookStatus(cwd).installed === false;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
} catch (_) { /* never block doctor on graph probe */ }
|
|
366
391
|
}
|
|
367
392
|
|
|
368
393
|
return state;
|
|
@@ -702,6 +727,60 @@ function planActions(state) {
|
|
|
702
727
|
});
|
|
703
728
|
}
|
|
704
729
|
|
|
730
|
+
// ---- Code graph layer (Graphify, since v4.21.0) ----------------------
|
|
731
|
+
// The install side effects of `configure` only run interactively (a Python
|
|
732
|
+
// tool is never installed silently in CI). So doctor is the backfill: it
|
|
733
|
+
// installs the binary, (re)builds a stale/missing graph, and restores the
|
|
734
|
+
// native auto-rebuild git hook.
|
|
735
|
+
if (state.graphEnabled && state.graphBinaryMissing) {
|
|
736
|
+
actions.push({
|
|
737
|
+
key: 'graph-install',
|
|
738
|
+
label: 'Install Graphify code-graph tool',
|
|
739
|
+
why: 'features.has_code_graph is true but the `graphify` CLI is not on $PATH. Agents fall back to LSP/Grep and the wiki feed is dormant until it is installed (`pipx install graphifyy`).',
|
|
740
|
+
autoOk: false, // installs a Python package; let the user confirm
|
|
741
|
+
run: async () => {
|
|
742
|
+
const gi = new GraphifyInstaller(state.cwd);
|
|
743
|
+
const res = gi.install();
|
|
744
|
+
if (res.ok) {
|
|
745
|
+
UI.success(`Graphify installed (${res.method}).`);
|
|
746
|
+
const b = gi.buildGraph(state.cwd);
|
|
747
|
+
if (!b.ok) UI.warning(`Initial graph build failed: ${b.error}`);
|
|
748
|
+
} else {
|
|
749
|
+
UI.warning(`Install failed: ${res.error}`);
|
|
750
|
+
}
|
|
751
|
+
},
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
if (state.graphEnabled && !state.graphBinaryMissing && (state.graphStale || state.graphNotBuilt)) {
|
|
755
|
+
actions.push({
|
|
756
|
+
key: 'graph-rebuild',
|
|
757
|
+
label: state.graphNotBuilt ? 'Build the code graph (not built yet)' : 'Rebuild the stale code graph',
|
|
758
|
+
why: state.graphNotBuilt
|
|
759
|
+
? 'features.has_code_graph is true but no graph.json exists yet. Build it (`graphify update .`, offline, no API cost).'
|
|
760
|
+
: 'The code graph was built from an older commit than HEAD (built_at_commit ≠ HEAD). Rebuild so structural queries and the wiki feed reflect current code.',
|
|
761
|
+
autoOk: true, // offline, idempotent, no API cost
|
|
762
|
+
run: async () => {
|
|
763
|
+
const gi = new GraphifyInstaller(state.cwd);
|
|
764
|
+
const b = gi.buildGraph(state.cwd);
|
|
765
|
+
if (!b.ok) UI.warning(`Graph build failed: ${b.error}`);
|
|
766
|
+
},
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
if (state.graphEnabled && !state.graphBinaryMissing && state.graphHookMissing) {
|
|
770
|
+
actions.push({
|
|
771
|
+
key: 'graph-hook',
|
|
772
|
+
label: 'Install Graphify auto-rebuild git hook',
|
|
773
|
+
why: 'graph.auto_rebuild_hook is true but Graphify\'s native post-commit hook is not installed, so the graph will drift after commits. `graphify hook install` restores it.',
|
|
774
|
+
autoOk: true,
|
|
775
|
+
run: async () => {
|
|
776
|
+
const gi = new GraphifyInstaller(state.cwd);
|
|
777
|
+
const h = gi.installGitHook(state.cwd);
|
|
778
|
+
if (h.ok) UI.success('Graphify git hook installed.');
|
|
779
|
+
else UI.warning(`Hook install failed: ${h.error}`);
|
|
780
|
+
},
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
|
|
705
784
|
// v3.25.0+: drift detection is authoritative via VERSION compare (isAligned).
|
|
706
785
|
// The HEAD...FETCH_HEAD commit count is subtree-merge noise and never reaches
|
|
707
786
|
// 0, so we MUST NOT use it as the "needs update" signal.
|
|
@@ -946,6 +1025,18 @@ function renderDiagnostic(state) {
|
|
|
946
1025
|
console.log(statusLine('LSP layer', 'disabled', 'ok'));
|
|
947
1026
|
}
|
|
948
1027
|
|
|
1028
|
+
if (state.graphEnabled) {
|
|
1029
|
+
let value, severity;
|
|
1030
|
+
if (state.graphBinaryMissing) { value = 'enabled but graphify CLI missing'; severity = 'warn'; }
|
|
1031
|
+
else if (state.graphNotBuilt) { value = 'enabled, graph not built yet'; severity = 'warn'; }
|
|
1032
|
+
else if (state.graphStale) { value = 'enabled, graph stale (behind HEAD)'; severity = 'warn'; }
|
|
1033
|
+
else if (state.graphHookMissing) { value = 'enabled, verified (auto-rebuild hook missing)'; severity = 'warn'; }
|
|
1034
|
+
else { value = 'enabled, graph fresh'; severity = 'ok'; }
|
|
1035
|
+
console.log(statusLine('Code graph', value, severity));
|
|
1036
|
+
} else {
|
|
1037
|
+
console.log(statusLine('Code graph', 'disabled', 'ok'));
|
|
1038
|
+
}
|
|
1039
|
+
|
|
949
1040
|
console.log();
|
|
950
1041
|
}
|
|
951
1042
|
|
package/src/commands/update.js
CHANGED
|
@@ -1291,11 +1291,17 @@ async function update(options = {}, unknownArgs = []) {
|
|
|
1291
1291
|
const missingStack = Object.keys(tpl.stack || {})
|
|
1292
1292
|
.filter((k) => typeof tpl.stack[k] === 'string')
|
|
1293
1293
|
.filter((k) => !(k in (cur2.stack || {})));
|
|
1294
|
+
// Top-level nested config namespaces (e.g. `graph:` since v4.21.0).
|
|
1295
|
+
// Unlike `lsp:` (which propagates only via its `has_lsp_layer` flag),
|
|
1296
|
+
// diff the block's own scalar keys so a new sub-key surfaces too.
|
|
1297
|
+
const missingGraph = Object.keys(tpl.graph || {})
|
|
1298
|
+
.filter((k) => !(k in (cur2.graph || {})));
|
|
1294
1299
|
const allMissing = [
|
|
1295
1300
|
...missingPaths,
|
|
1296
1301
|
...missingFeatures,
|
|
1297
1302
|
...missingGit.map((k) => `git.${k}`),
|
|
1298
1303
|
...missingStack.map((k) => `stack.${k}`),
|
|
1304
|
+
...missingGraph.map((k) => `graph.${k}`),
|
|
1299
1305
|
];
|
|
1300
1306
|
if (allMissing.length) {
|
|
1301
1307
|
UI.newline();
|