forgedock 1.0.16 → 1.0.18
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/README.md +54 -3
- package/bin/cross-publish.mjs +344 -0
- package/bin/forgedock.mjs +2205 -541
- package/bin/github-app-manifest.json.license +2 -0
- package/bin/hooks/session-start.mjs +4 -5
- package/bin/registry.mjs +20 -0
- package/bin/tui.mjs +172 -96
- package/commands/adopt.md +433 -0
- package/commands/analytics.md +2 -0
- package/commands/audit-agents.md +2 -0
- package/commands/audit.md +2 -0
- package/commands/autopilot.md +77 -0
- package/commands/changelog.md +354 -0
- package/commands/cleanup.md +2 -0
- package/commands/compat-audit.md +330 -0
- package/commands/deploy-info.md +6 -5
- package/commands/design-bench.md +176 -0
- package/commands/design-render-critique-loop.md +103 -0
- package/commands/design.md +259 -0
- package/commands/diagnose.md +483 -0
- package/commands/explain.md +349 -0
- package/commands/forge-stats.md +2 -0
- package/commands/forgedock-init.md +2 -0
- package/commands/geo-audit.md +2 -0
- package/commands/incident-response.md +2 -0
- package/commands/issue.md +9 -3
- package/commands/milestone.md +2 -0
- package/commands/optimize.md +411 -0
- package/commands/orchestrate.md +239 -0
- package/commands/pipeline-health.md +60 -1
- package/commands/qa-sweep.md +39 -2
- package/commands/quality-gate.md +67 -0
- package/commands/replay.md +263 -0
- package/commands/resume.md +264 -0
- package/commands/review-pr-agents.md +5 -1
- package/commands/review-pr-staging.md +160 -2
- package/commands/review-pr.md +85 -3
- package/commands/rollback.md +2 -0
- package/commands/scope.md +280 -0
- package/commands/security-audit.md +2 -0
- package/commands/status.md +262 -0
- package/commands/sync-ecosystem.md +2 -0
- package/commands/test-gate.md +929 -0
- package/commands/validate.md +2 -0
- package/commands/work-on/build/architect.md +128 -18
- package/commands/work-on/build/context.md +130 -17
- package/commands/work-on/build/implement.md +7 -3
- package/commands/work-on/build/validate.md +2 -0
- package/commands/work-on/build.md +32 -7
- package/commands/work-on/close.md +85 -0
- package/commands/work-on/decompose.md +2 -0
- package/commands/work-on/investigate.md +30 -3
- package/commands/work-on/review.md +13 -1
- package/commands/work-on-monolithic.md +2 -0
- package/commands/work-on.md +676 -38
- package/docs/BRAND.md +51 -0
- package/docs/CI.md +177 -0
- package/docs/CONFIG.md +94 -0
- package/docs/FORGE-PROTOCOL.md +324 -0
- package/docs/articles/b-vs-c-baseline.md +210 -0
- package/docs/articles/full-abc-benchmark.md +205 -0
- package/docs/articles/per-repo-adaptive-scripts-token-savings.md +174 -0
- package/docs/articles/selective-spec-loading-token-savings.md +140 -0
- package/docs/claude-breakpoints.json +47 -0
- package/docs/design/abc-benchmark.md +195 -0
- package/docs/design/design-architect-rationale.md +123 -0
- package/docs/design/design-memory.md +61 -0
- package/docs/design/design-spec-schema.md +248 -0
- package/docs/design/design-system-lint.md +150 -0
- package/docs/design/divergent-generation.md +106 -0
- package/docs/design/effects-appropriateness.md +133 -0
- package/docs/design/fixtures/briefs/README.md +47 -0
- package/docs/design/fixtures/briefs/cadence.md +39 -0
- package/docs/design/fixtures/briefs/plume.md +39 -0
- package/docs/design/fixtures/briefs/slipstream.md +39 -0
- package/docs/design/fixtures/briefs/tender.md +39 -0
- package/docs/design/fixtures/briefs/voltage.md +39 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/cadence/arm-b/run-1.html +364 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/cadence/arm-b/run-2.html +420 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/cadence/arm-b/run-3.html +506 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/plume/arm-b/run-1.html +611 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/plume/arm-b/run-2.html +594 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/plume/arm-b/run-3.html +817 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/runs.json +175 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/scorecard.json +138 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/slipstream/arm-b/run-1.html +373 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/slipstream/arm-b/run-2.html +398 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/slipstream/arm-b/run-3.html +595 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/tender/arm-b/run-1.html +531 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/tender/arm-b/run-2.html +565 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/tender/arm-b/run-3.html +674 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/voltage/arm-b/run-1.html +388 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/voltage/arm-b/run-2.html +463 -0
- package/docs/design/fixtures/runs/b-vs-c-baseline/voltage/arm-b/run-3.html +568 -0
- package/docs/design/fixtures/runs/full-abc/cadence/arm-a/run-1.html +562 -0
- package/docs/design/fixtures/runs/full-abc/cadence/arm-a/run-2.html +618 -0
- package/docs/design/fixtures/runs/full-abc/cadence/arm-a/run-3.html +618 -0
- package/docs/design/fixtures/runs/full-abc/cadence/arm-b/run-1.html +364 -0
- package/docs/design/fixtures/runs/full-abc/cadence/arm-b/run-2.html +420 -0
- package/docs/design/fixtures/runs/full-abc/cadence/arm-b/run-3.html +506 -0
- package/docs/design/fixtures/runs/full-abc/plume/arm-a/run-1.html +527 -0
- package/docs/design/fixtures/runs/full-abc/plume/arm-a/run-2.html +445 -0
- package/docs/design/fixtures/runs/full-abc/plume/arm-a/run-3.html +483 -0
- package/docs/design/fixtures/runs/full-abc/plume/arm-b/run-1.html +611 -0
- package/docs/design/fixtures/runs/full-abc/plume/arm-b/run-2.html +594 -0
- package/docs/design/fixtures/runs/full-abc/plume/arm-b/run-3.html +817 -0
- package/docs/design/fixtures/runs/full-abc/runs.json +190 -0
- package/docs/design/fixtures/runs/full-abc/scorecard.json +144 -0
- package/docs/design/fixtures/runs/full-abc/slipstream/arm-a/run-1.html +496 -0
- package/docs/design/fixtures/runs/full-abc/slipstream/arm-a/run-2.html +447 -0
- package/docs/design/fixtures/runs/full-abc/slipstream/arm-a/run-3.html +564 -0
- package/docs/design/fixtures/runs/full-abc/slipstream/arm-b/run-1.html +373 -0
- package/docs/design/fixtures/runs/full-abc/slipstream/arm-b/run-2.html +398 -0
- package/docs/design/fixtures/runs/full-abc/slipstream/arm-b/run-3.html +595 -0
- package/docs/design/fixtures/runs/full-abc/tender/arm-a/run-1.html +622 -0
- package/docs/design/fixtures/runs/full-abc/tender/arm-a/run-2.html +475 -0
- package/docs/design/fixtures/runs/full-abc/tender/arm-a/run-3.html +660 -0
- package/docs/design/fixtures/runs/full-abc/tender/arm-b/run-1.html +531 -0
- package/docs/design/fixtures/runs/full-abc/tender/arm-b/run-2.html +565 -0
- package/docs/design/fixtures/runs/full-abc/tender/arm-b/run-3.html +674 -0
- package/docs/design/fixtures/runs/full-abc/voltage/arm-a/run-1.html +525 -0
- package/docs/design/fixtures/runs/full-abc/voltage/arm-a/run-2.html +446 -0
- package/docs/design/fixtures/runs/full-abc/voltage/arm-a/run-3.html +463 -0
- package/docs/design/fixtures/runs/full-abc/voltage/arm-b/run-1.html +388 -0
- package/docs/design/fixtures/runs/full-abc/voltage/arm-b/run-2.html +463 -0
- package/docs/design/fixtures/runs/full-abc/voltage/arm-b/run-3.html +568 -0
- package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-a/run-1.html +1068 -0
- package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-a/run-2.html +1423 -0
- package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-a/run-3.html +1245 -0
- package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-b/run-1.html +305 -0
- package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-b/run-2.html +327 -0
- package/docs/design/fixtures/runs/full-abc-opus/cadence/arm-b/run-3.html +428 -0
- package/docs/design/fixtures/runs/full-abc-opus/plume/arm-a/run-1.html +1270 -0
- package/docs/design/fixtures/runs/full-abc-opus/plume/arm-a/run-2.html +1172 -0
- package/docs/design/fixtures/runs/full-abc-opus/plume/arm-a/run-3.html +1532 -0
- package/docs/design/fixtures/runs/full-abc-opus/plume/arm-b/run-1.html +315 -0
- package/docs/design/fixtures/runs/full-abc-opus/plume/arm-b/run-2.html +342 -0
- package/docs/design/fixtures/runs/full-abc-opus/plume/arm-b/run-3.html +353 -0
- package/docs/design/fixtures/runs/full-abc-opus/runs.json +190 -0
- package/docs/design/fixtures/runs/full-abc-opus/scorecard.json +144 -0
- package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-a/run-1.html +345 -0
- package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-a/run-2.html +396 -0
- package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-a/run-3.html +502 -0
- package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-b/run-1.html +408 -0
- package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-b/run-2.html +446 -0
- package/docs/design/fixtures/runs/full-abc-opus/slipstream/arm-b/run-3.html +496 -0
- package/docs/design/fixtures/runs/full-abc-opus/tender/arm-a/run-1.html +813 -0
- package/docs/design/fixtures/runs/full-abc-opus/tender/arm-a/run-2.html +711 -0
- package/docs/design/fixtures/runs/full-abc-opus/tender/arm-a/run-3.html +721 -0
- package/docs/design/fixtures/runs/full-abc-opus/tender/arm-b/run-1.html +280 -0
- package/docs/design/fixtures/runs/full-abc-opus/tender/arm-b/run-2.html +291 -0
- package/docs/design/fixtures/runs/full-abc-opus/tender/arm-b/run-3.html +366 -0
- package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-a/run-1.html +1010 -0
- package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-a/run-2.html +836 -0
- package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-a/run-3.html +930 -0
- package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-b/run-1.html +407 -0
- package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-b/run-2.html +396 -0
- package/docs/design/fixtures/runs/full-abc-opus/voltage/arm-b/run-3.html +529 -0
- package/docs/design/foundations/brutalist.css +294 -0
- package/docs/design/foundations/editorial.css +300 -0
- package/docs/design/foundations/minimal-luxury.css +295 -0
- package/docs/design/foundations/technical.css +293 -0
- package/docs/design/foundations/warm-photo.css +299 -0
- package/docs/design/reference-corpus.md +1726 -0
- package/docs/design/render-critique-loop.md +57 -0
- package/docs/site/getting-started.md +21 -0
- package/docs/spec-graph-schema.md +397 -0
- package/package.json +3 -3
- package/scripts/bench-scorecard.mjs +239 -0
- package/scripts/build-spec-graph.mjs +509 -0
- package/scripts/classify-lane.sh +138 -0
- package/scripts/design-system-lint.mjs +993 -0
- package/scripts/graph-query.sh +486 -0
- package/scripts/transition-label.sh +169 -0
- package/scripts/validate-pr-target.sh +30 -0
- package/scripts/validate-spec-graph.sh +423 -0
- package/templates/devdocs/README.md +72 -0
- package/templates/devdocs/agent/using-forgedock.md +3 -0
- package/templates/devdocs/agent/using-github.md +3 -0
- package/templates/devdocs/index.yaml +162 -0
- package/templates/devdocs/project/architecture.md +3 -0
- package/templates/devdocs/project/conventions.md +3 -0
- package/templates/devdocs/project/custom-instructions.md +3 -0
- package/templates/devdocs/project/glossary.md +3 -0
- package/templates/devdocs/project/stack.md +3 -0
- package/templates/devdocs/templates/commit-convention.md +3 -0
- package/templates/devdocs/templates/issue.md +3 -0
- package/templates/devdocs/templates/pull-request.md +3 -0
- package/templates/devdocs/templates/review-finding.md +3 -0
- package/templates/workflows/forgedock-review.yml +96 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Render → vision-critique → iterate loop
|
|
2
|
+
|
|
3
|
+
> **Status**: committed methodology doc for the UI Taste Harness (#882).
|
|
4
|
+
> Executed by [`/design-render-critique-loop`](../../commands/design-render-critique-loop.md).
|
|
5
|
+
> Consumes: [`FORGE:DESIGN_SPEC`](design-spec-schema.md) (#881), the deterministic linter `scripts/design-system-lint.mjs` (#884), the perceptual negatives N3/N8–N12 in [reference-corpus](reference-corpus.md) (#880), the #878/#875 Playwright render protocol.
|
|
6
|
+
> Independent from the [ABC benchmark judge](abc-benchmark.md) (#878) — anti-Goodhart.
|
|
7
|
+
> Part of #877.
|
|
8
|
+
|
|
9
|
+
## The thesis
|
|
10
|
+
|
|
11
|
+
AI UI is generic because UI generation has **no feedback loop**: the model writes markup blind, never sees the rendered
|
|
12
|
+
pixels, and defends whatever it produced. Every other lever in the harness — the spec (#881), the effects doctrine
|
|
13
|
+
(#885), divergent generation (#883) — still operates *before* a pixel exists. This loop is the one stage that closes
|
|
14
|
+
the loop: render the page, *look at it*, and feed a correction back in. It is the missing reward signal.
|
|
15
|
+
|
|
16
|
+
## Why a loop, not a one-shot check
|
|
17
|
+
|
|
18
|
+
A single post-hoc lint pass catches deterministic tells but cannot see whether the *rendered* page has hierarchy,
|
|
19
|
+
whether an effect served the content, or whether the composition is generic. Those are perceptual judgements that only
|
|
20
|
+
exist once pixels are on screen, and fixing one often surfaces another. So the correction must **iterate**: critique →
|
|
21
|
+
fix → re-render → re-critique, until the page passes or the budget is spent.
|
|
22
|
+
|
|
23
|
+
## Iteration protocol
|
|
24
|
+
|
|
25
|
+
1. **Deterministic floor first.** Run the linter (#884) before every render. Never spend a render on a page that fails
|
|
26
|
+
a hard rule. This keeps the expensive perceptual step off pages a cheap check already rejects.
|
|
27
|
+
2. **Render** at desktop + mobile, using the same Playwright protocol as the benchmark (#878/#875).
|
|
28
|
+
3. **Vision-critique the pixels** against the perceptual negatives the linter declares out of scope — N3 (centered / no
|
|
29
|
+
asymmetry), N8 (stock / generic 3D), N9 (glassmorphism overuse), N10 (no hierarchy), N11 (abstract copy / no product
|
|
30
|
+
shown), N12 (decorative effects that serve nothing) — plus the spec's own acceptance and the `effects_plan`
|
|
31
|
+
justifications (#885).
|
|
32
|
+
4. **Emit a `FORGE:CRITIQUE`** per iteration so the improvement trajectory is auditable.
|
|
33
|
+
5. **Iterate** until no perceptual findings remain (PASS) or `max_iters` is reached (BUDGET-EXHAUSTED with residuals).
|
|
34
|
+
|
|
35
|
+
## Division of labour (no duplication)
|
|
36
|
+
|
|
37
|
+
| Stage | Owns | Nature |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| Linter (#884) | deterministic negatives (N1, N2, N4-structural, contrast floor, off-scale spacing) | cheap, hard gate, runs first |
|
|
40
|
+
| This critic (#882) | perceptual negatives N3, N8–N12 + spec acceptance | iterative, perceptual |
|
|
41
|
+
| Perf gate (#875) | `effects_plan.budget` (LCP/CLS/INP/JS-kb) | hard, objective |
|
|
42
|
+
|
|
43
|
+
The critic never re-checks a deterministic rule; the linter never judges perception. Each negative has exactly one
|
|
44
|
+
owner.
|
|
45
|
+
|
|
46
|
+
## Anti-Goodhart independence
|
|
47
|
+
|
|
48
|
+
The loop's critic is **not** the ABC benchmark judge (#878) and **not** the divergent-generation taste-judge (#883).
|
|
49
|
+
The benchmark judge is the independent scoreboard that tells us whether the harness improved; optimizing the loop
|
|
50
|
+
against it would be training on the test set. The taste-judge scores pre-render candidate directions. Three judges,
|
|
51
|
+
three jobs — the separation is what keeps the reward signal honest.
|
|
52
|
+
|
|
53
|
+
## Success measure
|
|
54
|
+
|
|
55
|
+
The loop is working when a page **measurably improves across iterations**, and when — on the seed set, scored by the
|
|
56
|
+
independent benchmark (#878) against the #879 baseline — *A-with-loop* > *A-without-loop* > *raw B*. The loop produces
|
|
57
|
+
the improvement; the benchmark, which the loop never sees, confirms it.
|
|
@@ -17,6 +17,27 @@ This tutorial gets you from zero to your first autonomous pipeline run in under
|
|
|
17
17
|
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated
|
|
18
18
|
- Git and GitHub CLI (`gh`) installed and authenticated (`gh auth login`)
|
|
19
19
|
- Node.js 18 or higher
|
|
20
|
+
- [`yq`](https://github.com/mikefarah/yq) — YAML parser used by all pipeline commands to read `forge.yaml`
|
|
21
|
+
|
|
22
|
+
**Install `yq`:**
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# macOS
|
|
26
|
+
brew install yq
|
|
27
|
+
|
|
28
|
+
# Ubuntu / Debian
|
|
29
|
+
sudo apt-get install yq
|
|
30
|
+
# or: sudo snap install yq
|
|
31
|
+
|
|
32
|
+
# Windows
|
|
33
|
+
winget install mikefarah.yq
|
|
34
|
+
# or: choco install yq
|
|
35
|
+
|
|
36
|
+
# Any platform (via Go)
|
|
37
|
+
go install github.com/mikefarah/yq/v4@latest
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
> **Note:** Without `yq`, pipeline commands that read `forge.yaml` (including `/work-on`, `/scope`, `/orchestrate`, and most others) will fall back to defaults or skip config-driven steps silently.
|
|
20
41
|
|
|
21
42
|
---
|
|
22
43
|
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios
|
|
3
|
+
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Spec Knowledge Graph — Schema & Builder
|
|
7
|
+
|
|
8
|
+
The **spec knowledge graph** is a queryable, zero-dependency self-map of
|
|
9
|
+
ForgeDock's own command specs. It lets agents load only task-relevant specs and
|
|
10
|
+
run impact analysis on the pipeline's information flow ("which command writes
|
|
11
|
+
`FORGE:CONTRACT`? which commands read it?").
|
|
12
|
+
|
|
13
|
+
It is a native replication of code-graph tooling (codegraph,
|
|
14
|
+
codebase-memory-mcp) adapted to **prose specs** — no tree-sitter, SQLite, or MCP
|
|
15
|
+
dependency. The builder is a single Node `.mjs` artifact using Node built-ins
|
|
16
|
+
only (`fs`, `path`, `url`).
|
|
17
|
+
|
|
18
|
+
## Building the graph
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
node scripts/build-spec-graph.mjs # writes .forgedock/graph/spec-graph.json
|
|
22
|
+
node scripts/build-spec-graph.mjs --stdout # print to stdout (no file write)
|
|
23
|
+
node scripts/build-spec-graph.mjs --help # full options
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The builder is **idempotent**: all node/edge arrays are sorted by a stable
|
|
27
|
+
composite key and JSON is emitted with recursively sorted object keys, so
|
|
28
|
+
re-runs produce byte-identical output. It runs in well under 1s on the current
|
|
29
|
+
spec set (~90 nodes / ~120 edges, ~60ms).
|
|
30
|
+
|
|
31
|
+
Output is written to `.forgedock/graph/spec-graph.json` and is **gitignored by
|
|
32
|
+
default** (see `.gitignore`). This mirrors how per-repo adaptive scripts are
|
|
33
|
+
treated — opt in to commit the graph if you want it versioned.
|
|
34
|
+
|
|
35
|
+
## Output document
|
|
36
|
+
|
|
37
|
+
A single JSON document:
|
|
38
|
+
|
|
39
|
+
```jsonc
|
|
40
|
+
{
|
|
41
|
+
"graph": {
|
|
42
|
+
"schemaVersion": 1,
|
|
43
|
+
"generator": "build-spec-graph.mjs",
|
|
44
|
+
"root": ".",
|
|
45
|
+
"builtFromHash": "716dae74…", // sha256 of the scanned spec corpus
|
|
46
|
+
"stats": {
|
|
47
|
+
"nodes": 92,
|
|
48
|
+
"edges": 120,
|
|
49
|
+
"nodesByType": { "annotation": 30, "command": 35, "...": 0 },
|
|
50
|
+
"edgesByType": { "WRITES": 28, "READS": 45, "...": 0 }
|
|
51
|
+
},
|
|
52
|
+
"nodes": [ /* sorted by id */ ],
|
|
53
|
+
"edges": [ /* sorted by (from, type, to) */ ]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
It is `jq`-queryable. Examples:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
GRAPH=.forgedock/graph/spec-graph.json
|
|
62
|
+
|
|
63
|
+
# What does work-on write?
|
|
64
|
+
jq -r '.graph.edges[] | select(.from=="cmd:work-on" and .type=="WRITES") | .to' "$GRAPH"
|
|
65
|
+
|
|
66
|
+
# Who reads FORGE:CONTRACT?
|
|
67
|
+
jq -r '.graph.edges[] | select(.type=="READS" and .to=="ann:FORGE:CONTRACT") | .from' "$GRAPH"
|
|
68
|
+
|
|
69
|
+
# Which commands transition workflow:merged?
|
|
70
|
+
jq -r '.graph.edges[] | select(.type=="TRANSITIONS" and .to=="label:workflow:merged") | .from' "$GRAPH"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `builtFromHash` — input fingerprint
|
|
74
|
+
|
|
75
|
+
`graph.builtFromHash` is a **sha256 fingerprint of the input corpus** the graph
|
|
76
|
+
was built from: every `commands/**/*.md`, `scripts/*.sh`, and `devdocs/**/*.md`
|
|
77
|
+
file's repo-relative path + content, hashed in sorted order. It is **purely
|
|
78
|
+
input-derived** — no timestamps, mtimes, or absolute paths — so identical inputs
|
|
79
|
+
always produce the same hash and the emitted graph stays byte-identical
|
|
80
|
+
(idempotency is preserved).
|
|
81
|
+
|
|
82
|
+
It is the basis for **staleness detection without a daemon**. Recompute it
|
|
83
|
+
cheaply at any time with the builder's `--hash` mode (no full graph build):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
node scripts/build-spec-graph.mjs --hash # prints just the sha256, exits
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If `node scripts/build-spec-graph.mjs --hash` differs from the persisted
|
|
90
|
+
graph's `builtFromHash`, the spec corpus changed since the graph was built — the
|
|
91
|
+
graph is stale. `graph-query.sh` performs exactly this comparison on every query
|
|
92
|
+
(see below).
|
|
93
|
+
|
|
94
|
+
## Querying the graph (`graph-query.sh`)
|
|
95
|
+
|
|
96
|
+
`scripts/graph-query.sh` is the consumer-facing query API over the graph, so
|
|
97
|
+
agents (and humans) don't hand-write `jq`. It is a **universal-tier**,
|
|
98
|
+
**read-only** script: `bash` + `jq`, with `node` used to recompute the staleness
|
|
99
|
+
fingerprint and to auto-build/rebuild the graph (to a temp file) when the
|
|
100
|
+
persisted JSON is absent or stale. No committed graph is required.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
graph-query.sh <subcommand> <arg> [--human] [--graph <path>] [--strict-stale] [--no-stale-check]
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
| Subcommand | Returns |
|
|
107
|
+
|-----------------------|-------------------------------------------------------------------|
|
|
108
|
+
| `readers <annotation>`| commands/specs that **READ** the annotation |
|
|
109
|
+
| `writers <annotation>`| commands/specs that **WRITE** (post) the annotation |
|
|
110
|
+
| `impact <node>` | blast radius — everything transitively affected if `<node>` changes |
|
|
111
|
+
| `deps <command>` | a command's full input/output set, grouped by edge type |
|
|
112
|
+
| `load-set <command>` | minimal spec set to read for a command — the command plus its transitively reachable sub-phases (`CONTAINS`) and required devdocs (`REQUIRES`), as a flat list of repo-relative file paths |
|
|
113
|
+
| `search <term>` | substring lookup over node ids / names / paths |
|
|
114
|
+
|
|
115
|
+
Arguments are normalized, so all of these resolve to the same node:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
graph-query.sh readers CONTRACT # == readers FORGE:CONTRACT == readers ann:FORGE:CONTRACT
|
|
119
|
+
graph-query.sh deps work-on # == deps cmd:work-on
|
|
120
|
+
graph-query.sh deps work-on:build:implement # sub-phases use the Skill() `:`-delimited form
|
|
121
|
+
graph-query.sh load-set work-on # == load-set cmd:work-on
|
|
122
|
+
graph-query.sh impact classify-lane.sh # == impact script:classify-lane.sh
|
|
123
|
+
graph-query.sh impact workflow:merged # == impact label:workflow:merged
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`impact` is **transitive reverse-reachability**: it seeds at `<node>` and
|
|
127
|
+
collects every command that (directly or transitively) `READS`/`WRITES`/
|
|
128
|
+
`INVOKES`/`REQUIRES`/`CONTAINS` it, walking up parent commands via `CONTAINS`.
|
|
129
|
+
So `impact FORGE:CONTRACT` returns not only its direct readers/writers but also
|
|
130
|
+
the parent commands that contain them (e.g. `cmd:orchestrate`, `cmd:milestone`).
|
|
131
|
+
|
|
132
|
+
`load-set` is the **forward inverse of `impact`**: it seeds at `<command>` and
|
|
133
|
+
walks `CONTAINS` (sub-phases) and `REQUIRES` (devdocs) edges in the *forward*
|
|
134
|
+
direction to a fixpoint, then maps the reachable nodes to their repo-relative
|
|
135
|
+
file `path`s. The result is the **minimal spec set** an agent must read to run
|
|
136
|
+
that command — the command itself plus only the sub-phases and devdocs actually
|
|
137
|
+
reachable from it, never the full ~27-command corpus. It is the resolver that
|
|
138
|
+
powers selective spec loading (Phase 0 of `work-on`). `READS`/`WRITES`/
|
|
139
|
+
`TRANSITIONS`/`INVOKES` edges are *not* followed — annotations and labels have
|
|
140
|
+
no spec file, and scripts are resolved separately at invoke time. The walk shares
|
|
141
|
+
`impact`'s cycle-safe termination, so a self-referential `CONTAINS` edge cannot
|
|
142
|
+
loop forever.
|
|
143
|
+
|
|
144
|
+
### Output
|
|
145
|
+
|
|
146
|
+
Default output is **compact, agent-consumable JSON** — a JSON array for
|
|
147
|
+
`readers`/`writers`/`impact`/`search`, a JSON object keyed by edge type for
|
|
148
|
+
`deps`, and a sorted, de-duplicated JSON array of file paths for `load-set`.
|
|
149
|
+
Pass `--human` for an aligned table instead.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
$ graph-query.sh writers FORGE:CONTRACT
|
|
153
|
+
["cmd:work-on","cmd:work-on:build"]
|
|
154
|
+
|
|
155
|
+
$ graph-query.sh deps work-on:build:implement
|
|
156
|
+
{"READS":["ann:FORGE:ARCHITECT","ann:FORGE:CONTEXT","ann:FORGE:CONTRACT","ann:FORGE:INVESTIGATOR"],"WRITES":["ann:FORGE:BUILDER"]}
|
|
157
|
+
|
|
158
|
+
$ graph-query.sh load-set work-on
|
|
159
|
+
["commands/review-pr.md","commands/work-on.md","commands/work-on/build.md","commands/work-on/build/architect.md","commands/work-on/build/context.md","commands/work-on/build/implement.md","commands/work-on/build/validate.md","commands/work-on/close.md","commands/work-on/decompose.md","commands/work-on/investigate.md","commands/work-on/review.md"]
|
|
160
|
+
|
|
161
|
+
$ graph-query.sh writers FORGE:CONTRACT --human
|
|
162
|
+
Specs that WRITE ann:FORGE:CONTRACT:
|
|
163
|
+
cmd:work-on
|
|
164
|
+
cmd:work-on:build
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Flags & behavior
|
|
168
|
+
|
|
169
|
+
- `--graph <path>` — query a specific graph JSON (default:
|
|
170
|
+
`.forgedock/graph/spec-graph.json`). When the default path is absent (it is
|
|
171
|
+
gitignored), the graph is **auto-built on the fly** via `build-spec-graph.mjs`
|
|
172
|
+
into a temp file (cleaned up on exit).
|
|
173
|
+
- `--human` — render an aligned table instead of compact JSON.
|
|
174
|
+
- `--strict-stale` — do **not** auto-rebuild a stale persisted graph; error
|
|
175
|
+
(exit 1) instead. Useful in CI to assert a committed graph is fresh.
|
|
176
|
+
- `--no-stale-check` — skip the staleness check entirely and query the persisted
|
|
177
|
+
graph as-is, even if the spec corpus has changed.
|
|
178
|
+
- Exit codes: `0` on success, `1` on bad args, missing `jq`/`node`, an unknown
|
|
179
|
+
node (the error suggests `graph-query.sh search <term>`), or a stale graph
|
|
180
|
+
under `--strict-stale`.
|
|
181
|
+
|
|
182
|
+
### Staleness detection (no daemon)
|
|
183
|
+
|
|
184
|
+
ForgeDock targets non-coders, so there is **no file-watcher daemon**. Staleness
|
|
185
|
+
is detected **pull-based, on query**:
|
|
186
|
+
|
|
187
|
+
1. When a query uses a **persisted** graph (the default
|
|
188
|
+
`.forgedock/graph/spec-graph.json`, or an explicit `--graph <path>`),
|
|
189
|
+
`graph-query.sh` recomputes the current corpus fingerprint via
|
|
190
|
+
`build-spec-graph.mjs --hash` and compares it to the graph's stored
|
|
191
|
+
`builtFromHash`.
|
|
192
|
+
2. **Match** → the persisted graph is used as-is. The no-change path is a single
|
|
193
|
+
cheap hash compare — no rebuild, no perceptible latency, no background
|
|
194
|
+
process.
|
|
195
|
+
3. **Mismatch** (or a graph predating `builtFromHash`) → the graph is stale. By
|
|
196
|
+
default a `stale-graph` banner is printed to **stderr** and the graph is
|
|
197
|
+
transparently **rebuilt** for this query; **stdout stays pure JSON**. With
|
|
198
|
+
`--strict-stale` the query errors instead; with `--no-stale-check` the check
|
|
199
|
+
is skipped.
|
|
200
|
+
4. When **no persisted graph exists** (the common case — the graph is
|
|
201
|
+
gitignored), `graph-query.sh` auto-builds a fresh graph to a temp file. A
|
|
202
|
+
freshly built graph is current by construction, so no staleness check runs.
|
|
203
|
+
|
|
204
|
+
This means editing any `commands/*.md` (or `scripts/*.sh` / `devdocs/**`) is
|
|
205
|
+
detected on the next query and the rebuild produces a fresh hash — with no daemon
|
|
206
|
+
and no cost on the no-change path.
|
|
207
|
+
|
|
208
|
+
### Optional: rebuild-on-commit hook
|
|
209
|
+
|
|
210
|
+
For contributors who choose to keep a **committed** graph in sync, an **opt-in**
|
|
211
|
+
git pre-commit hook ships at `.githooks/pre-commit`. It is never auto-installed.
|
|
212
|
+
Enable it with:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
git config core.hooksPath .githooks
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
When enabled, the hook rebuilds `.forgedock/graph/spec-graph.json` and stages it
|
|
219
|
+
**only if** (a) a persisted graph already exists and (b) the commit stages a file
|
|
220
|
+
under `commands/`, `scripts/`, or `devdocs/`. If no persisted graph exists (the
|
|
221
|
+
default), the hook is a no-op. It never blocks a commit on rebuild failure.
|
|
222
|
+
|
|
223
|
+
## Validating the graph (`validate-spec-graph.sh`)
|
|
224
|
+
|
|
225
|
+
`scripts/validate-spec-graph.sh` is the **self-consistency validator** over the
|
|
226
|
+
graph. It catches drift that is invisible in the ~1.2 MB prose corpus and is
|
|
227
|
+
wired into `quality-gate` (the `FORGE_GRAPH` domain) so it runs whenever
|
|
228
|
+
`commands/*.md` or `scripts/*` files change. Like `graph-query.sh`, it is a
|
|
229
|
+
**universal-tier**, **read-only** script (`bash` + `jq`, `node` only for the
|
|
230
|
+
on-the-fly auto-build) that auto-builds the graph when the gitignored JSON is
|
|
231
|
+
absent — no committed graph is required.
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
validate-spec-graph.sh [--soft] [--graph <path>] [--root <dir>] [--quiet] [--json]
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
It performs three checks, partitioned by severity:
|
|
238
|
+
|
|
239
|
+
| Check | Severity | Detects |
|
|
240
|
+
|---------------------------|--------------|-------------------------------------------------------------------------|
|
|
241
|
+
| **Orphan annotations** | SOFT (warn) | a `FORGE:*` marker WRITTEN but never READ, or READ but never WRITTEN |
|
|
242
|
+
| **Dangling cross-refs** | HARD (fail) | a `Skill(skill="X")` whose target is no real command/sub-phase node |
|
|
243
|
+
| **Broken transitions** | HARD (fail) | a `workflow:*` label set by **no** command (no `--add-label` edge) |
|
|
244
|
+
|
|
245
|
+
Inline doc-scaffolding markers (`FORGE:DISPATCHER`, `FORGE:PHASE_COMPLETE`,
|
|
246
|
+
`FORGE:TYPE`, …) legitimately have neither a WRITES nor a READS edge — they
|
|
247
|
+
annotate the spec prose itself and are never posted via `gh ... comment`. They
|
|
248
|
+
are reported as **INFO** (via a curated allowlist in the script), never as
|
|
249
|
+
orphans. A non-allowlisted isolated marker is surfaced as SOFT so new
|
|
250
|
+
scaffolding gets triaged.
|
|
251
|
+
|
|
252
|
+
**Why dangling refs are scanned from prose, not edges**: the builder *drops*
|
|
253
|
+
unresolved `Skill()`/script/devdoc references (it only emits an edge when the
|
|
254
|
+
target resolves to a real node — see `if (nodes.has(targetId))` in
|
|
255
|
+
`build-spec-graph.mjs`). So a dangling reference never appears as a graph edge.
|
|
256
|
+
The validator therefore scans `commands/**/*.md` for `Skill(skill="X")`
|
|
257
|
+
directly and cross-checks each `X` against the command/sub-phase node set. Only
|
|
258
|
+
the structured `Skill()` form is checked — loose `.sh`/filename mentions in
|
|
259
|
+
prose are illustrative and are intentionally not flagged.
|
|
260
|
+
|
|
261
|
+
### Flags & exit codes
|
|
262
|
+
|
|
263
|
+
- `--soft` — warn-only mode: HARD findings are still reported, but the exit code
|
|
264
|
+
is forced to `0`. Used when first wiring into CI so the documented baseline
|
|
265
|
+
orphans/refs do not break the build before triage. `quality-gate` invokes the
|
|
266
|
+
validator with `--soft` and re-surfaces any `[HARD]` line as a HIGH finding.
|
|
267
|
+
- `--graph <path>` — validate a specific graph JSON (default
|
|
268
|
+
`.forgedock/graph/spec-graph.json`, auto-built when absent).
|
|
269
|
+
- `--root <dir>` — repo root to scan for `Skill()` refs and to auto-build from.
|
|
270
|
+
- `--quiet` — print only the summary line. `--json` — emit findings as a single
|
|
271
|
+
JSON object (`{summary:{hard,soft,info}, findings:[{severity,class,message}]}`).
|
|
272
|
+
- Exit codes: `0` when there are no HARD findings (or `--soft`); `1` on a HARD
|
|
273
|
+
inconsistency, bad args, or a missing dependency. Output is deterministic
|
|
274
|
+
(findings sorted by severity → class → message), so re-runs are byte-stable.
|
|
275
|
+
|
|
276
|
+
## Node types
|
|
277
|
+
|
|
278
|
+
| `type` | `id` shape | Source |
|
|
279
|
+
|--------------|----------------------------------|-----------------------------------------|
|
|
280
|
+
| `command` | `cmd:<name>` | top-level `commands/<name>.md` |
|
|
281
|
+
| `sub-phase` | `cmd:<a>:<b>[:<c>]` | nested `commands/<a>/<b>[/<c>].md` |
|
|
282
|
+
| `annotation` | `ann:FORGE:<NAME>` | distinct `FORGE:*` HTML-comment marker |
|
|
283
|
+
| `label` | `label:workflow:<name>` | distinct `workflow:*` label |
|
|
284
|
+
| `script` | `script:<file>.sh` | `scripts/*.sh` file on disk |
|
|
285
|
+
| `devdoc` | `devdoc:devdocs/<path>.md` | `devdocs/**/*.md` reference doc |
|
|
286
|
+
|
|
287
|
+
Sub-phase names use the same `:`-delimited convention as `Skill(skill="...")`
|
|
288
|
+
targets, so `commands/work-on/build/implement.md` → `cmd:work-on:build:implement`.
|
|
289
|
+
|
|
290
|
+
Every node carries `id`, `type`, `name`; file-backed nodes also carry `path`
|
|
291
|
+
(repo-relative).
|
|
292
|
+
|
|
293
|
+
## Edge types
|
|
294
|
+
|
|
295
|
+
All edges originate from a `command` or `sub-phase` node.
|
|
296
|
+
|
|
297
|
+
| `type` | Target | Meaning |
|
|
298
|
+
|---------------|-------------|------------------------------------------------------|
|
|
299
|
+
| `WRITES` | annotation | command **posts** the FORGE annotation |
|
|
300
|
+
| `READS` | annotation | command **consumes** the FORGE annotation |
|
|
301
|
+
| `TRANSITIONS` | label | command **sets** the workflow label |
|
|
302
|
+
| `CONTAINS` | sub-phase | parent → nested phase (directory) or `Skill()` invoke |
|
|
303
|
+
| `INVOKES` | script | command runs a `scripts/*.sh` file |
|
|
304
|
+
| `REQUIRES` | devdoc | command **must read** a devdoc (authority: required) |
|
|
305
|
+
|
|
306
|
+
Each edge carries `from`, `type`, `to`, and an `evidence` object with the
|
|
307
|
+
source `file`/`line` (and `via`/`authority` where relevant).
|
|
308
|
+
|
|
309
|
+
## Extraction heuristics
|
|
310
|
+
|
|
311
|
+
The builder regex-scans each `commands/**/*.md` line by line:
|
|
312
|
+
|
|
313
|
+
- **WRITES** — line matches `gh (issue|pr) comment ... --body` and a
|
|
314
|
+
`<!-- FORGE:X -->` marker appears in the body portion (same line or the
|
|
315
|
+
immediately following line, since `--body` blocks often wrap). This captures
|
|
316
|
+
the *posting* form only.
|
|
317
|
+
- **READS** — line matches `contains("FORGE:X")` (the jq-select consume form) or
|
|
318
|
+
prose `read[s]/re-read the FORGE:X` (the narrative consume form).
|
|
319
|
+
- **TRANSITIONS** — line matches `--add-label "...workflow:X..."`. A single
|
|
320
|
+
`--add-label` may carry a comma-separated list; each label becomes an edge.
|
|
321
|
+
- **CONTAINS** — two sources: (a) directory nesting (`cmd:work-on` →
|
|
322
|
+
`cmd:work-on:build` → `cmd:work-on:build:implement`), and (b)
|
|
323
|
+
`Skill(skill="X")` invocations where `X` resolves to a known command/sub-phase
|
|
324
|
+
node.
|
|
325
|
+
- **INVOKES** — any `*.sh` token in the spec that matches a real `scripts/*.sh`
|
|
326
|
+
filename on disk. Tokens that don't correspond to a real script are ignored.
|
|
327
|
+
- **REQUIRES** — a line that references a `devdocs/*.md` path **and** carries a
|
|
328
|
+
requirement verb (`Read` / `required` / `must` / `before`), with
|
|
329
|
+
`authority: "required"`.
|
|
330
|
+
|
|
331
|
+
### WRITES vs READS — false-positive handling
|
|
332
|
+
|
|
333
|
+
The hardest distinction is **WRITES vs READS** of the same annotation. The
|
|
334
|
+
distinguishing signal is the surrounding command, not the marker itself:
|
|
335
|
+
|
|
336
|
+
- A spec that says *post* `<!-- FORGE:BUILDER -->` (via `gh ... comment --body`)
|
|
337
|
+
**writes** it.
|
|
338
|
+
- A spec that says *read* the `FORGE:CONTRACT` (via `contains("FORGE:CONTRACT")`
|
|
339
|
+
or "read the FORGE:CONTRACT") **reads** it.
|
|
340
|
+
|
|
341
|
+
Documentation scaffolding markers — inline `<!-- FORGE:PHASE_COMPLETE -->` and
|
|
342
|
+
`<!-- FORGE:DISPATCHER -->` HTML comments used to annotate the spec prose itself
|
|
343
|
+
— are **not** counted as WRITES, because they never appear inside a
|
|
344
|
+
`gh ... comment --body` posting. They still get `annotation` nodes (they are
|
|
345
|
+
real markers in the corpus) but produce no spurious WRITES edges. This guard is
|
|
346
|
+
verified by the builder's self-check.
|
|
347
|
+
|
|
348
|
+
## Self-check
|
|
349
|
+
|
|
350
|
+
On every run the builder asserts three acceptance spot-checks and exits non-zero
|
|
351
|
+
if any fails:
|
|
352
|
+
|
|
353
|
+
1. `work-on` **WRITES** `FORGE:TRAJECTORY`.
|
|
354
|
+
2. `review-pr` **READS** `FORGE:CONTRACT`.
|
|
355
|
+
3. `builtFromHash` is present and is a 64-char sha256 hex digest.
|
|
356
|
+
|
|
357
|
+
## Adding new node or edge types
|
|
358
|
+
|
|
359
|
+
Extend `commandNodeFromPath()` / the node-discovery passes for new node types,
|
|
360
|
+
and add a new heuristic block in the per-line loop of `build()` for new edge
|
|
361
|
+
types. Keep all output sorted to preserve idempotency, and add a self-check
|
|
362
|
+
assertion for any new invariant.
|
|
363
|
+
|
|
364
|
+
## Open-core boundary
|
|
365
|
+
|
|
366
|
+
The graph is **open-core, CLI-side, local-only**. The builder, store, and query
|
|
367
|
+
tools (`build-spec-graph.mjs`, `graph-query.sh`, `validate-spec-graph.sh`) are
|
|
368
|
+
AGPL code in this repo; they run entirely on-disk and emit a structured JSON
|
|
369
|
+
artifact (`.forgedock/graph/spec-graph.json`, gitignored by default).
|
|
370
|
+
|
|
371
|
+
That JSON is the boundary. The Platform's L1 observability dashboard *renders*
|
|
372
|
+
the graph as a pipeline self-map (runs, timelines, stall detection) — that
|
|
373
|
+
visualization is the **commercial value-add**. The Platform consumes the emitted
|
|
374
|
+
JSON; it never imports, embeds, vendors, or links the AGPL builder/query code
|
|
375
|
+
(see `devdocs/project/architecture.md` → Boundary Rules). The CLI does not know
|
|
376
|
+
or care whether the Platform exists — emitting the JSON is the entire contract.
|
|
377
|
+
|
|
378
|
+
## Optional context hook (deferred — off by default)
|
|
379
|
+
|
|
380
|
+
A future opt-in Claude Code `PreToolUse` hook can use the graph to inject
|
|
381
|
+
"relevant specs per graph" as context when an agent greps `commands/`, mirroring
|
|
382
|
+
codegraph's `PreToolUse` pattern. It would shell out to
|
|
383
|
+
`graph-query.sh load-set <command>` (or `readers`/`deps`) and surface the
|
|
384
|
+
task-relevant spec set instead of letting the agent load blindly.
|
|
385
|
+
|
|
386
|
+
**Decision: deferred — not shipped in this milestone.** It must be:
|
|
387
|
+
|
|
388
|
+
- **Opt-in, off by default** — gated behind an explicit setting (e.g. a
|
|
389
|
+
`hooks.spec_graph_context` flag in `forge.yaml` or the user's Claude Code
|
|
390
|
+
settings), so the graph imposes nothing on users who do not enable it.
|
|
391
|
+
- **Non-blocking** — a `PreToolUse` hook that only *adds* context and never
|
|
392
|
+
rejects a tool call; a missing or stale graph degrades to a no-op.
|
|
393
|
+
- **CLI-side** — the hook reads the local JSON via the AGPL query scripts; it
|
|
394
|
+
introduces no Platform dependency.
|
|
395
|
+
|
|
396
|
+
Shipping the wiring is deferred because no hook-infrastructure layer exists in
|
|
397
|
+
the repo yet; this section is the spec that a later issue implements against.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forgedock",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"description": "GitHub as a knowledge graph for AI agents. Autonomous dev pipeline for Claude Code.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"forgedock": "bin/forgedock.mjs"
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"type": "git",
|
|
28
28
|
"url": "git+https://github.com/RapierCraftStudios/ForgeDock.git"
|
|
29
29
|
},
|
|
30
|
-
"homepage": "https://
|
|
30
|
+
"homepage": "https://forgedock.dev",
|
|
31
31
|
"bugs": {
|
|
32
32
|
"url": "https://github.com/RapierCraftStudios/ForgeDock/issues"
|
|
33
33
|
},
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"peerDependenciesMeta": {
|
|
54
54
|
"@anthropic-ai/claude-code": {
|
|
55
|
-
"optional":
|
|
55
|
+
"optional": true
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
}
|