@drafthq/draft 3.0.0 → 3.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +3 -3
  3. package/bin/README.md +4 -7
  4. package/core/shared/condensation.md +8 -8
  5. package/core/shared/draft-context-loading.md +5 -9
  6. package/core/shared/graph-query.md +36 -30
  7. package/core/shared/graph-usage-report.md +1 -1
  8. package/core/shared/pattern-learning.md +2 -2
  9. package/core/shared/red-flags.md +3 -3
  10. package/core/templates/ai-context.md +1 -1
  11. package/core/templates/architecture.md +3 -3
  12. package/integrations/agents/AGENTS.md +165 -142
  13. package/integrations/copilot/.github/copilot-instructions.md +165 -142
  14. package/package.json +1 -1
  15. package/scripts/lib.sh +1 -3
  16. package/scripts/tools/adr-index.sh +2 -2
  17. package/scripts/tools/check-scope-conflicts.sh +2 -2
  18. package/scripts/tools/check-skill-line-caps.sh +2 -2
  19. package/scripts/tools/cycle-detect.sh +5 -1
  20. package/scripts/tools/diff-templates-vs-tracks.sh +2 -2
  21. package/scripts/tools/fix-whitespace.sh +15 -9
  22. package/scripts/tools/graph-arch.sh +72 -0
  23. package/scripts/tools/graph-impact.sh +1 -0
  24. package/scripts/tools/graph-init.sh +3 -3
  25. package/scripts/tools/graph-snapshot.sh +52 -51
  26. package/scripts/tools/hotspot-rank.sh +2 -0
  27. package/scripts/tools/manage-symlinks.sh +1 -1
  28. package/scripts/tools/parse-reports.sh +1 -1
  29. package/scripts/tools/verify-doc-anchors.sh +2 -2
  30. package/scripts/tools/verify-graph-binary.sh +1 -1
  31. package/skills/GRAPH.md +2 -2
  32. package/skills/bughunt/SKILL.md +1 -1
  33. package/skills/debug/SKILL.md +3 -3
  34. package/skills/decompose/SKILL.md +5 -5
  35. package/skills/deep-review/SKILL.md +2 -2
  36. package/skills/deploy-checklist/SKILL.md +2 -2
  37. package/skills/graph/SKILL.md +1 -1
  38. package/skills/implement/SKILL.md +1 -1
  39. package/skills/init/SKILL.md +62 -42
  40. package/skills/init/references/architecture-spec.md +12 -11
  41. package/skills/learn/SKILL.md +5 -5
  42. package/skills/quick-review/SKILL.md +3 -3
  43. package/skills/review/SKILL.md +7 -7
  44. package/skills/tech-debt/SKILL.md +2 -2
  45. package/scripts/tools/okf-bundle.sh +0 -141
  46. package/scripts/tools/okf-check.sh +0 -137
  47. package/scripts/tools/okf-emit.sh +0 -161
@@ -1,137 +0,0 @@
1
- #!/usr/bin/env bash
2
- # okf-check.sh — validate a directory against the Open Knowledge Format v0.1 spec.
3
- #
4
- # Implements the §9 conformance criteria of OKF v0.1
5
- # (https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md):
6
- #
7
- # §9.1 Every non-reserved .md file has a parseable YAML frontmatter block.
8
- # §9.2 Every such frontmatter block has a non-empty `type` field.
9
- # §9.3 Reserved files follow their structure when present:
10
- # index.md (§6) — contains NO frontmatter, EXCEPT the bundle-root
11
- # index.md MAY carry frontmatter holding only
12
- # `okf_version` (§11).
13
- # log.md (§7) — `## ` date headings MUST be ISO 8601 (YYYY-MM-DD).
14
- #
15
- # Consumers are required to be permissive, so this checker only enforces the
16
- # three hard rules above; everything else in the spec is soft guidance.
17
- #
18
- # Usage: scripts/tools/okf-check.sh [--dir DIR] [--quiet]
19
- # Exit codes: 0 conformant, 1 violations found, 2 dir missing.
20
- set -euo pipefail
21
-
22
- DIR="draft"
23
- QUIET=0
24
-
25
- usage() {
26
- cat <<'EOF'
27
- okf-check.sh — validate a directory against Open Knowledge Format v0.1 (§9).
28
-
29
- Usage:
30
- scripts/tools/okf-check.sh [--dir DIR] [--quiet]
31
-
32
- Flags:
33
- --dir DIR Bundle root to validate (default: draft).
34
- --quiet Print only the summary line, not per-file violations.
35
- --help Show this help.
36
-
37
- Exit 0 when conformant, 1 when violations are found, 2 when DIR is absent.
38
- EOF
39
- }
40
-
41
- while [[ $# -gt 0 ]]; do
42
- case "$1" in
43
- --dir) DIR="$2"; shift 2;;
44
- --quiet) QUIET=1; shift;;
45
- --help|-h) usage; exit 0;;
46
- -*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
47
- *) echo "Unexpected arg: $1" >&2; usage >&2; exit 1;;
48
- esac
49
- done
50
-
51
- [[ -d "$DIR" ]] || { echo "ERROR: --dir '$DIR' is not a directory" >&2; exit 2; }
52
- DIR="${DIR%/}"
53
-
54
- # fm_scan FILE -> "STATUS|TYPE|KEYS" (pipe-delimited; '|' is not IFS-whitespace,
55
- # so empty TYPE/KEYS fields survive `read` instead of collapsing).
56
- # STATUS: nofm (no frontmatter) | ok (closed block) | unterminated
57
- # TYPE: value of the top-level `type:` key, if any
58
- # KEYS: comma-separated top-level frontmatter keys
59
- fm_scan() {
60
- awk '
61
- NR==1 { if ($0 != "---") { print "nofm||"; exit } ; inblock=1; next }
62
- inblock && /^---[[:space:]]*$/ { print "ok|" type "|" keys; closed=1; exit }
63
- inblock {
64
- if (match($0, /^[A-Za-z_][A-Za-z0-9_]*:/)) {
65
- k = substr($0, 1, RLENGTH-1)
66
- keys = keys (keys=="" ? "" : ",") k
67
- if (k == "type") {
68
- v = substr($0, RLENGTH+1)
69
- gsub(/^[ \t]+|[ \t]+$/, "", v)
70
- gsub(/^"|"$/, "", v)
71
- type = v
72
- }
73
- }
74
- next
75
- }
76
- END { if (inblock && !closed) print "unterminated|" type "|" keys }
77
- ' "$1"
78
- }
79
-
80
- violations=0
81
- concepts=0
82
- reserved=0
83
-
84
- report() { # relpath message
85
- violations=$((violations + 1))
86
- [[ "$QUIET" == "1" ]] || echo "FAIL $1: $2" >&2
87
- }
88
-
89
- while IFS= read -r -d '' file; do
90
- rel="${file#"$DIR"/}"
91
- base="$(basename "$file")"
92
-
93
- case "$base" in
94
- index.md)
95
- reserved=$((reserved + 1))
96
- IFS='|' read -r status _ keys < <(fm_scan "$file")
97
- if [[ "$status" != "nofm" ]]; then
98
- if [[ "$rel" == "index.md" ]]; then
99
- # Bundle-root index.md: frontmatter allowed, but only okf_version (§11).
100
- IFS=',' read -ra ks <<< "$keys"
101
- for k in "${ks[@]}"; do
102
- [[ -z "$k" || "$k" == "okf_version" ]] && continue
103
- report "$rel" "root index.md frontmatter may only hold 'okf_version' (§11); found '$k'"
104
- done
105
- else
106
- report "$rel" "index.md must not contain frontmatter (§6)"
107
- fi
108
- fi
109
- ;;
110
- log.md)
111
- reserved=$((reserved + 1))
112
- while IFS= read -r h; do
113
- if ! [[ "$h" =~ ^##[[:space:]]+[0-9]{4}-[0-9]{2}-[0-9]{2} ]]; then
114
- report "$rel" "log.md date heading not ISO 8601 (§7): '$h'"
115
- fi
116
- done < <(grep -E '^## ' "$file" 2>/dev/null || true)
117
- ;;
118
- *)
119
- concepts=$((concepts + 1))
120
- IFS='|' read -r status type _ < <(fm_scan "$file")
121
- case "$status" in
122
- nofm) report "$rel" "missing YAML frontmatter block (§9.1)";;
123
- unterminated) report "$rel" "unterminated frontmatter block — no closing '---' (§9.1)";;
124
- ok)
125
- [[ -n "$type" ]] || report "$rel" "frontmatter missing required non-empty 'type' (§9.2)"
126
- ;;
127
- esac
128
- ;;
129
- esac
130
- done < <(find "$DIR" -type f -name '*.md' -print0 | sort -z)
131
-
132
- if [[ "$violations" -eq 0 ]]; then
133
- echo "OKF v0.1 conformant — $concepts concept file(s), $reserved reserved file(s), 0 violations. ($DIR)"
134
- exit 0
135
- fi
136
- echo "OKF v0.1 NON-CONFORMANT — $violations violation(s) across $concepts concept + $reserved reserved file(s). ($DIR)" >&2
137
- exit 1
@@ -1,161 +0,0 @@
1
- #!/usr/bin/env bash
2
- # okf-emit.sh — emit an Open Knowledge Format (OKF) bundle from a graph snapshot.
3
- #
4
- # OKF is an open, vendor-neutral spec (Google Cloud): a directory of markdown
5
- # files with YAML frontmatter, one file per concept, where the file path is the
6
- # concept's identity and concepts cross-link with normal markdown links. The
7
- # only required frontmatter field is `type`. This makes Draft's knowledge graph
8
- # portable — consumable by any OKF reader (visualizers, catalogs, other agents).
9
- # https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing
10
- #
11
- # Reads a graph snapshot's architecture.json and writes a conformant bundle:
12
- # index.md type: Repository — bundle root + progressive disclosure
13
- # modules/<slug>.md type: Module — one concept per package, cross-linked
14
- #
15
- # Degrades gracefully: with no packages/boundaries in the snapshot it still emits
16
- # index.md (counts, languages, hotspots) and an empty modules/ directory.
17
- #
18
- # Usage: scripts/tools/okf-emit.sh [--repo DIR] [--snapshot DIR] [--out DIR]
19
- # Exit codes: 0 OK, 1 invocation error, 2 snapshot/architecture.json unavailable.
20
- set -euo pipefail
21
-
22
- REPO="."
23
- SNAPSHOT=""
24
- OUT=""
25
-
26
- usage() {
27
- cat <<'EOF'
28
- okf-emit.sh — emit an Open Knowledge Format (OKF) bundle from a graph snapshot.
29
-
30
- Usage:
31
- scripts/tools/okf-emit.sh [--repo DIR] [--snapshot DIR] [--out DIR]
32
-
33
- Flags:
34
- --repo DIR Repository root (default: cwd).
35
- --snapshot DIR Snapshot dir holding architecture.json (default: <repo>/draft/graph).
36
- --out DIR Bundle output dir (default: <snapshot>/okf).
37
- --help Show this help.
38
-
39
- Writes index.md + modules/<slug>.md (OKF v0.1). Exit 0 on success, 2 when no
40
- architecture.json is available (nothing emitted).
41
- EOF
42
- }
43
-
44
- while [[ $# -gt 0 ]]; do
45
- case "$1" in
46
- --repo) REPO="$2"; shift 2;;
47
- --snapshot) SNAPSHOT="$2"; shift 2;;
48
- --out) OUT="$2"; shift 2;;
49
- --help|-h) usage; exit 0;;
50
- -*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
51
- *) echo "Unexpected arg: $1" >&2; usage >&2; exit 1;;
52
- esac
53
- done
54
-
55
- [[ -d "$REPO" ]] || { echo "ERROR: --repo '$REPO' is not a directory" >&2; exit 1; }
56
- REPO_ABS="$(cd "$REPO" && pwd)"
57
- SNAP="${SNAPSHOT:-$REPO_ABS/draft/graph}"
58
- ARCH="$SNAP/architecture.json"
59
- OUT="${OUT:-$SNAP/okf}"
60
-
61
- command -v jq >/dev/null 2>&1 || { echo "jq required for OKF emit" >&2; exit 2; }
62
- [[ -f "$ARCH" ]] || { echo "no architecture.json at $ARCH — nothing to emit" >&2; exit 2; }
63
-
64
- # slugify a concept name into a filesystem- and link-safe identifier.
65
- slug() {
66
- local s
67
- s="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]' \
68
- | sed -e 's#[^a-z0-9]\{1,\}#-#g' -e 's#^-##' -e 's#-$##')"
69
- [[ -n "$s" ]] || s="module"
70
- printf '%s' "$s"
71
- }
72
-
73
- # escape a value for a YAML double-quoted scalar.
74
- yesc() {
75
- local s="$1"
76
- s="${s//\\/\\\\}"
77
- s="${s//\"/\\\"}"
78
- printf '%s' "$s"
79
- }
80
-
81
- TS="$(date -Iseconds 2>/dev/null || date)"
82
- PROJECT="$(jq -r '.project // "repository"' "$ARCH")"
83
- TOTAL_NODES="$(jq -r '.total_nodes // 0' "$ARCH")"
84
- TOTAL_EDGES="$(jq -r '.total_edges // 0' "$ARCH")"
85
-
86
- PKGS="$(jq -r '.packages[]? | [.name, (.node_count//0), (.fan_in//0), (.fan_out//0)] | @tsv' "$ARCH")"
87
- BOUNDS="$(jq -r '.boundaries[]? | [.from, .to, (.call_count//0)] | @tsv' "$ARCH")"
88
-
89
- mkdir -p "$OUT/modules"
90
-
91
- # --- One concept file per package, cross-linked via boundaries ---
92
- PKG_COUNT=0
93
- if [[ -n "$PKGS" ]]; then
94
- while IFS=$'\t' read -r name nc fi fo; do
95
- [[ -n "$name" ]] || continue
96
- PKG_COUNT=$((PKG_COUNT + 1))
97
- s="$(slug "$name")"
98
- {
99
- printf -- '---\n'
100
- printf 'type: Module\n'
101
- printf 'title: "%s"\n' "$(yesc "$name")"
102
- printf 'description: "Code module %s: %s nodes, fan-in %s, fan-out %s."\n' \
103
- "$(yesc "$name")" "$nc" "$fi" "$fo"
104
- printf 'tags: [module, knowledge-graph]\n'
105
- printf 'timestamp: "%s"\n' "$TS"
106
- printf -- '---\n\n'
107
- printf '# %s\n\n' "$name"
108
- printf 'Structural module derived from the knowledge graph. Nodes: %s, fan-in: %s, fan-out: %s.\n' \
109
- "$nc" "$fi" "$fo"
110
-
111
- # Depends on (outbound boundaries)
112
- outs="$(awk -F'\t' -v n="$name" '$1==n && $2!="" {print $2"\t"$3}' <<< "$BOUNDS")"
113
- if [[ -n "$outs" ]]; then
114
- printf '\n## Depends on\n\n'
115
- while IFS=$'\t' read -r to cc; do
116
- [[ -n "$to" ]] || continue
117
- printf -- '- [%s](%s.md) — %s call(s)\n' "$to" "$(slug "$to")" "$cc"
118
- done <<< "$outs"
119
- fi
120
-
121
- # Depended on by (inbound boundaries)
122
- ins="$(awk -F'\t' -v n="$name" '$2==n && $1!="" {print $1"\t"$3}' <<< "$BOUNDS")"
123
- if [[ -n "$ins" ]]; then
124
- printf '\n## Depended on by\n\n'
125
- while IFS=$'\t' read -r from cc; do
126
- [[ -n "$from" ]] || continue
127
- printf -- '- [%s](%s.md) — %s call(s)\n' "$from" "$(slug "$from")" "$cc"
128
- done <<< "$ins"
129
- fi
130
- } > "$OUT/modules/$s.md"
131
- done <<< "$PKGS"
132
- fi
133
-
134
- # --- Bundle index.md (reserved file: no frontmatter, §6 progressive disclosure) ---
135
- {
136
- printf '# %s\n\n' "$PROJECT"
137
- printf 'Open Knowledge Format bundle generated by Draft from the codebase-memory-mcp knowledge graph. Nodes: %s, edges: %s, modules: %s.\n' \
138
- "$TOTAL_NODES" "$TOTAL_EDGES" "$PKG_COUNT"
139
-
140
- langs="$(jq -r '.languages[]? | "* \(.language) - \(.file_count) file(s)"' "$ARCH")"
141
- if [[ -n "$langs" ]]; then
142
- printf '\n# Languages\n\n%s\n' "$langs"
143
- fi
144
-
145
- if [[ "$PKG_COUNT" -gt 0 ]]; then
146
- printf '\n# Modules\n\n'
147
- while IFS=$'\t' read -r name nc fi fo; do
148
- [[ -n "$name" ]] || continue
149
- printf -- '* [%s](modules/%s.md) - %s nodes, fan-in %s, fan-out %s\n' \
150
- "$name" "$(slug "$name")" "$nc" "$fi" "$fo"
151
- done < <(printf '%s\n' "$PKGS" | sort)
152
- fi
153
-
154
- hot="$(jq -r '.hotspots[:10][]? | "* \(.name) - fan-in \(.fan_in)"' "$ARCH")"
155
- if [[ -n "$hot" ]]; then
156
- printf '\n# Top hotspots\n\n%s\n' "$hot"
157
- fi
158
- } > "$OUT/index.md"
159
-
160
- echo "OKF bundle written to $OUT (modules=$PKG_COUNT)"
161
- exit 0