yadflow 3.19.0-next.2 → 4.0.0-next.3
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 +371 -0
- package/README.md +160 -22
- package/bin/commands.mjs +46 -0
- package/bin/yad.mjs +506 -117
- package/cli/artifact-status.mjs +30 -11
- package/cli/capture.mjs +417 -0
- package/cli/checkpoint.mjs +47 -27
- package/cli/claims.mjs +165 -0
- package/cli/codeowners-command.mjs +170 -0
- package/cli/codeowners.mjs +397 -0
- package/cli/commit.mjs +13 -9
- package/cli/dial.mjs +183 -0
- package/cli/docs.mjs +88 -32
- package/cli/doctor.mjs +1682 -90
- package/cli/epic-state.mjs +3460 -211
- package/cli/epic.mjs +506 -0
- package/cli/errors.mjs +3 -0
- package/cli/fold.mjs +247 -0
- package/cli/gate-local.mjs +296 -0
- package/cli/gate.mjs +977 -183
- package/cli/history.mjs +556 -0
- package/cli/hook.mjs +264 -53
- package/cli/hubcommit.mjs +9 -19
- package/cli/index-command.mjs +87 -0
- package/cli/ledger.mjs +54 -4
- package/cli/lib.mjs +161 -9
- package/cli/manifest.mjs +376 -38
- package/cli/migrate.mjs +683 -52
- package/cli/mode.mjs +170 -0
- package/cli/next.mjs +365 -86
- package/cli/openpr.mjs +193 -34
- package/cli/owners.mjs +266 -0
- package/cli/people.mjs +657 -0
- package/cli/plan.mjs +466 -125
- package/cli/platform.mjs +109 -128
- package/cli/product-index.mjs +287 -0
- package/cli/protection.mjs +706 -0
- package/cli/reconcile.mjs +40 -12
- package/cli/repo-publish.mjs +24 -26
- package/cli/repo.mjs +23 -14
- package/cli/report.mjs +24 -14
- package/cli/review.mjs +19 -22
- package/cli/riskmap-command.mjs +289 -0
- package/cli/riskmap.mjs +373 -0
- package/cli/setup.mjs +127 -279
- package/cli/ship.mjs +6 -5
- package/cli/skill.mjs +180 -0
- package/cli/skip.mjs +211 -30
- package/cli/thread.mjs +41 -16
- package/cli/tidy.mjs +18 -18
- package/cli/update-commit.mjs +21 -21
- package/cli/usage.mjs +115 -109
- package/package.json +3 -3
- package/skills/sdlc/config.yaml +149 -70
- package/skills/sdlc/module-help.csv +24 -24
- package/skills/yad-analysis/SKILL.md +121 -59
- package/skills/yad-architecture/SKILL.md +30 -18
- package/skills/yad-architecture/references/contract-format.md +8 -5
- package/skills/yad-backfill/SKILL.md +10 -4
- package/skills/yad-backfill/references/backfill.md +8 -1
- package/skills/yad-backfill/templates/checks/backfill-check.sh +10 -2
- package/skills/yad-change/SKILL.md +119 -42
- package/skills/yad-change/references/triage.md +42 -27
- package/skills/yad-checks/SKILL.md +68 -35
- package/skills/yad-checks/references/check-gates.md +310 -85
- package/skills/yad-checks/templates/checks/commit-message.sh +17 -3
- package/skills/yad-checks/templates/checks/contract-check.sh +130 -9
- package/skills/yad-checks/templates/checks/epic-open.sh +2 -2
- package/skills/yad-checks/templates/checks/ledger-guard.sh +55 -8
- package/skills/yad-checks/templates/checks/lineage-check.sh +23 -9
- package/skills/yad-checks/templates/checks/reconcile-debt-check.sh +1 -1
- package/skills/yad-checks/templates/checks/risk-map-check.sh +438 -0
- package/skills/yad-checks/templates/checks/verified-commits.sh +20 -46
- package/skills/yad-checks/templates/github/yad-checks.yml +13 -2
- package/skills/yad-checks/templates/github/yad-hub-checks.yml +5 -5
- package/skills/yad-checks/templates/github/yad-update-guard.yml +7 -5
- package/skills/yad-checks/templates/github/yad-verified-commits.yml +4 -4
- package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +10 -1
- package/skills/yad-checks/templates/gitlab/yad-hub-checks.gitlab-ci.yml +5 -5
- package/skills/yad-checks/templates/gitlab/yad-verified-commits.gitlab-ci.yml +3 -3
- package/skills/yad-checks/templates/hooks/ledger-guard-cursor.sh +91 -0
- package/skills/yad-checks/templates/hooks/ledger-guard.sh +37 -6
- package/skills/yad-checks/templates/hooks/yad-capture.sh +53 -0
- package/skills/yad-commit/SKILL.md +4 -4
- package/skills/yad-connect-design/SKILL.md +5 -5
- package/skills/yad-connect-design/references/design-context.md +1 -1
- package/skills/yad-connect-design/references/design-registry.md +2 -2
- package/skills/yad-connect-docs/SKILL.md +11 -11
- package/skills/yad-connect-docs/references/docs-registry.md +1 -1
- package/skills/yad-connect-learning/SKILL.md +5 -5
- package/skills/yad-connect-learning/references/learning-registry.md +2 -2
- package/skills/yad-connect-repos/SKILL.md +66 -45
- package/skills/yad-connect-repos/references/code-context.md +4 -4
- package/skills/yad-connect-repos/references/hub-config.md +47 -51
- package/skills/yad-connect-repos/references/repos-registry.md +8 -7
- package/skills/yad-connect-repos/references/risk-map.md +81 -0
- package/skills/yad-connect-testing/SKILL.md +5 -5
- package/skills/yad-connect-testing/references/testing-context.md +3 -4
- package/skills/yad-connect-testing/references/testing-registry.md +2 -2
- package/skills/yad-defects/SKILL.md +7 -7
- package/skills/yad-discovery/SKILL.md +131 -94
- package/skills/yad-discovery/references/discovery-schema.md +22 -6
- package/skills/yad-discovery/references/foundation-schema.md +374 -0
- package/skills/yad-docs/SKILL.md +13 -8
- package/skills/yad-docs/references/data-mapping.md +9 -7
- package/skills/yad-docs/templates/app/package-lock.json +3 -3
- package/skills/yad-docs-overview/SKILL.md +30 -15
- package/skills/yad-docs-overview/references/pipeline-model.md +33 -20
- package/skills/yad-docs-sync/SKILL.md +10 -5
- package/skills/yad-docs-sync/references/staleness.md +8 -7
- package/skills/yad-engineer-review/SKILL.md +81 -17
- package/skills/yad-engineer-review/references/ship-and-record.md +17 -8
- package/skills/yad-epic/SKILL.md +173 -92
- package/skills/yad-epic/references/state-schema.md +610 -94
- package/skills/yad-hub-bridge/SKILL.md +57 -38
- package/skills/yad-hub-bridge/references/bridge.md +94 -67
- package/skills/yad-hub-bridge/references/login-roster.md +163 -70
- package/skills/yad-hub-bridge/templates/checks/hub-route.sh +22 -19
- package/skills/yad-hub-bridge/templates/github/yad-gate-sync.yml +34 -14
- package/skills/yad-hub-bridge/templates/gitlab/gitlab-ci.include-root.yml +2 -2
- package/skills/yad-hub-bridge/templates/gitlab/yad-gate-sync.gitlab-ci.yml +21 -11
- package/skills/yad-implement/SKILL.md +27 -13
- package/skills/yad-implement/references/implement-conventions.md +2 -2
- package/skills/yad-learn/SKILL.md +9 -9
- package/skills/yad-learn/references/learning-state.md +2 -2
- package/skills/yad-open-pr/SKILL.md +61 -26
- package/skills/yad-pair-review/SKILL.md +7 -5
- package/skills/yad-pair-review/references/session-state.md +1 -1
- package/skills/yad-pr-template/SKILL.md +47 -26
- package/skills/yad-pr-template/references/risk-routing.md +97 -24
- package/skills/yad-pr-template/templates/checks/pr-template.sh +34 -11
- package/skills/yad-pr-template/templates/checks/pr-title.sh +32 -9
- package/skills/yad-pr-template/templates/checks/risk-route.sh +107 -14
- package/skills/yad-pr-template/templates/github/pull_request_template.md +7 -5
- package/skills/yad-pr-template/templates/gitlab/merge_request_templates/Default.md +7 -5
- package/skills/yad-pr-template/templates/hub/github/pull_request_template.md +14 -13
- package/skills/yad-pr-template/templates/hub/gitlab/merge_request_templates/Default.md +14 -12
- package/skills/yad-reconcile/SKILL.md +3 -3
- package/skills/yad-report/SKILL.md +5 -5
- package/skills/yad-review-companion/SKILL.md +6 -3
- package/skills/yad-review-gate/SKILL.md +203 -93
- package/skills/yad-review-gate/references/gating.md +232 -54
- package/skills/yad-run/SKILL.md +81 -51
- package/skills/yad-run/references/run-loop.md +61 -39
- package/skills/yad-ship/SKILL.md +15 -11
- package/skills/yad-spec/SKILL.md +21 -6
- package/skills/yad-spec/references/spec-handoff.md +17 -5
- package/skills/yad-status/SKILL.md +115 -50
- package/skills/yad-stories/SKILL.md +37 -21
- package/skills/yad-stories/references/story-schema.md +7 -6
- package/skills/yad-stub/SKILL.md +58 -47
- package/skills/yad-sync-repos/SKILL.md +2 -2
- package/skills/yad-test-cases/SKILL.md +32 -23
- package/skills/yad-test-cases/references/test-cases-schema.md +7 -4
- package/skills/yad-timeline/SKILL.md +8 -7
- package/skills/yad-ui/SKILL.md +41 -18
- package/cli/roster.mjs +0 -164
- package/skills/sdlc/install.sh +0 -68
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# yad-managed: yad-checks
|
|
2
|
-
# verified-commits gate for the PRODUCT
|
|
3
|
-
# must contain only commits whose signature the platform marks Verified
|
|
4
|
-
#
|
|
5
|
-
# Standalone workflow so it never collides with the
|
|
2
|
+
# verified-commits gate for the PRODUCT: every PR (including the Shape review/EP-* PRs)
|
|
3
|
+
# must contain only commits whose signature the platform marks Verified. Who may author them is who has
|
|
4
|
+
# write access to the repo — yadflow keeps no author list.
|
|
5
|
+
# Standalone workflow so it never collides with the Product-flavored yad-checks workflow.
|
|
6
6
|
name: yad-verified-commits
|
|
7
7
|
on:
|
|
8
8
|
pull_request:
|
|
@@ -53,6 +53,15 @@ yad-contract-check:
|
|
|
53
53
|
script:
|
|
54
54
|
- bash checks/contract-check.sh "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
|
|
55
55
|
|
|
56
|
+
# E65/E66 — the risk map (.sdlc/risk-map: a risk level per directory, no names). Warnings, and the
|
|
57
|
+
# approver count read from the base branch's map. It never fails the pipeline (the count is reported,
|
|
58
|
+
# not enforced), so the job needs no allow_failure.
|
|
59
|
+
yad-risk-map:
|
|
60
|
+
extends: .sdlc_mr_only
|
|
61
|
+
needs: []
|
|
62
|
+
script:
|
|
63
|
+
- bash checks/risk-map-check.sh "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
|
|
64
|
+
|
|
56
65
|
yad-build-test-lint:
|
|
57
66
|
extends: .sdlc_mr_only
|
|
58
67
|
needs: []
|
|
@@ -102,7 +111,7 @@ yad-pr-template:
|
|
|
102
111
|
- body="$(mktemp)"; printf '%s' "$CI_MERGE_REQUEST_DESCRIPTION" > "$body"
|
|
103
112
|
- bash checks/pr-template.sh --profile code "$body"
|
|
104
113
|
|
|
105
|
-
# No unverified commits
|
|
114
|
+
# No unverified commits: a platform-Verified signature on every commit (write access decides who authors).
|
|
106
115
|
# Needs a CI/CD variable GITLAB_TOKEN (or SDLC_API_TOKEN) with read_api scope — CI_JOB_TOKEN cannot
|
|
107
116
|
# read the commit-signature API. Without it the job FAILS closed with guidance.
|
|
108
117
|
yad-verified-commits:
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# yad-managed-include: yad-checks
|
|
2
|
-
# Pattern gates for the PRODUCT
|
|
2
|
+
# Pattern gates for the PRODUCT, as an INCLUDABLE fragment. Pulled into the Product's root
|
|
3
3
|
# .gitlab-ci.yml via:
|
|
4
4
|
# include:
|
|
5
5
|
# - local: '.gitlab/ci/yad-hub-checks.yml'
|
|
6
6
|
# MRs run with `--profile hub` and split by source branch: review/EP-* MRs are Shape artifact-
|
|
7
|
-
# review vehicles (a `review: <artifact> (EP-<slug>)` title + the
|
|
8
|
-
# every other MR is a tooling/code change to the
|
|
7
|
+
# review vehicles (a `review: <artifact> (EP-<slug>)` title + the Product artifact-review template body);
|
|
8
|
+
# every other MR is a tooling/code change to the Product itself and follows the code convention (a
|
|
9
9
|
# Conventional-Commits title + the code task template body). The source branch is passed via --head so
|
|
10
10
|
# the gate can tell the two apart. Commit subjects are always Conventional-Commits.
|
|
11
11
|
# Job names are yad-hub-prefixed so they coexist with any code-repo fragment in one pipeline; jobs use
|
|
@@ -33,14 +33,14 @@ yad-hub-pr-title:
|
|
|
33
33
|
extends: .yad_hub_mr_only
|
|
34
34
|
needs: []
|
|
35
35
|
script:
|
|
36
|
-
- changed="$(mktemp)"; git diff --name-only "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME...HEAD" > "$changed"
|
|
36
|
+
- changed="$(mktemp)"; git -c core.quotePath=false diff --no-renames --name-only "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME...HEAD" > "$changed"
|
|
37
37
|
- bash checks/pr-title.sh --profile hub --head "$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" --changed "$changed" "$CI_MERGE_REQUEST_TITLE"
|
|
38
38
|
|
|
39
39
|
yad-hub-pr-template:
|
|
40
40
|
extends: .yad_hub_mr_only
|
|
41
41
|
needs: []
|
|
42
42
|
script:
|
|
43
|
-
- changed="$(mktemp)"; git diff --name-only "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME...HEAD" > "$changed"
|
|
43
|
+
- changed="$(mktemp)"; git -c core.quotePath=false diff --no-renames --name-only "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME...HEAD" > "$changed"
|
|
44
44
|
- body="$(mktemp)"; printf '%s' "$CI_MERGE_REQUEST_DESCRIPTION" > "$body"
|
|
45
45
|
- bash checks/pr-template.sh --profile hub --head "$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" --changed "$changed" "$body"
|
|
46
46
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# yad-managed-include: yad-checks
|
|
2
|
-
# verified-commits gate for the PRODUCT
|
|
2
|
+
# verified-commits gate for the PRODUCT, as an INCLUDABLE fragment. Pulled into the Product's root
|
|
3
3
|
# .gitlab-ci.yml via:
|
|
4
4
|
# include:
|
|
5
5
|
# - local: '.gitlab/ci/yad-verified-commits.yml'
|
|
6
6
|
# Every MR (including the Shape review/EP-* MRs) must contain only commits whose signature the
|
|
7
|
-
# platform marks Verified
|
|
7
|
+
# platform marks Verified. Who may author them is who has write access to the repo — no author list.
|
|
8
8
|
#
|
|
9
9
|
# Needs a CI/CD variable GITLAB_TOKEN (or SDLC_API_TOKEN) with read_api scope — CI_JOB_TOKEN cannot
|
|
10
|
-
# read the commit-signature API. The
|
|
10
|
+
# read the commit-signature API. The Product's SDLC_GATE_TOKEN (from the gate-sync wiring) also works:
|
|
11
11
|
# set GITLAB_TOKEN: $SDLC_GATE_TOKEN in the job if you prefer one token.
|
|
12
12
|
# Job name is yad-hub-prefixed so it can coexist with the code-repo fragment in one pipeline.
|
|
13
13
|
yad-hub-verified-commits:
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ledger-guard CURSOR ADAPTER — the same guard, answered in the protocol Cursor requires (E11).
|
|
3
|
+
#
|
|
4
|
+
# Cursor's `preToolUse` is a PERMISSION hook, and its docs are explicit: for a permission hook,
|
|
5
|
+
# "invalid JSON or a response that doesn't match the hook's schema blocks the action". Empty stdout is
|
|
6
|
+
# invalid JSON. The plain `ledger-guard.sh` prints nothing when it allows — so wiring it directly
|
|
7
|
+
# would have blocked EVERY file write in a verified project, which is the exact opposite of this
|
|
8
|
+
# guard's fail-open design.
|
|
9
|
+
#
|
|
10
|
+
# This wrapper guarantees one thing: a permission answer on stdout, always, whatever happens below.
|
|
11
|
+
#
|
|
12
|
+
# allow {"permission":"allow"} exit 0
|
|
13
|
+
# deny {"permission":"deny","user_message":"<reason>","agent_message":"<reason>"} exit 0
|
|
14
|
+
#
|
|
15
|
+
# A deny exits 0 because the JSON is the authoritative answer and exit 0 is what tells Cursor to read
|
|
16
|
+
# it; exit 2 blocks too, but is documented as the code for "no JSON to read" and would discard the
|
|
17
|
+
# reason — and naming the command that owns the transition is the whole point of speaking at edit time.
|
|
18
|
+
#
|
|
19
|
+
# It takes NO arguments, deliberately. Cursor's `hooks.json` holds one command STRING and does not
|
|
20
|
+
# document whether it is run through a shell, so a command with a flag in it might never be split into
|
|
21
|
+
# program and argument — a command not found, silently, on every call.
|
|
22
|
+
set -uo pipefail
|
|
23
|
+
|
|
24
|
+
# `CDPATH=` is load-bearing, and the Cursor entry is what makes it so: that entry invokes the script
|
|
25
|
+
# by a RELATIVE path, so `${BASH_SOURCE[0]}` is relative and `cd` consults $CDPATH before the current
|
|
26
|
+
# directory. An exported CDPATH in a login profile — an ordinary thing to have, and inherited by the
|
|
27
|
+
# harness — would resolve `hooks` to some other tree entirely, and the guard would fail open on every
|
|
28
|
+
# write for as long as that profile lived.
|
|
29
|
+
#
|
|
30
|
+
# The loop resolves a symlinked SCRIPT, which `cd -P` does not: `-P` resolves the directory path, and
|
|
31
|
+
# a script reached through a link in another directory would otherwise look for its sibling beside the
|
|
32
|
+
# LINK and not find it. `readlink` without `-f` because `-f` is not portable to macOS.
|
|
33
|
+
_src="${BASH_SOURCE[0]}"
|
|
34
|
+
while [ -L "$_src" ]; do
|
|
35
|
+
_dir="$(CDPATH= cd -P -- "$(dirname -- "$_src")" && pwd)"
|
|
36
|
+
_src="$(readlink -- "$_src")"
|
|
37
|
+
case "$_src" in /*) ;; *) _src="$_dir/$_src" ;; esac
|
|
38
|
+
done
|
|
39
|
+
HOOK_DIR="$(CDPATH= cd -P -- "$(dirname -- "$_src")" && pwd)"
|
|
40
|
+
ALLOW='{"permission":"allow"}'
|
|
41
|
+
|
|
42
|
+
# Every failure below this line resolves to ALLOW, because this guard fails open by design and CI is
|
|
43
|
+
# what fails closed. A wrapper that blocked when it could not reach `yad` would stop an agent editing
|
|
44
|
+
# anything at all the moment an install went sideways.
|
|
45
|
+
if [ ! -x "$HOOK_DIR/ledger-guard.sh" ]; then
|
|
46
|
+
echo " • yad hook: $HOOK_DIR/ledger-guard.sh is missing or not executable — allowing (run \`yad check --fix\`)" >&2
|
|
47
|
+
echo "$ALLOW"
|
|
48
|
+
exit 0
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# stdout is CAPTURED (the JSON verdict), stderr is not (it flows through to Cursor's log). stdin is
|
|
52
|
+
# inherited by the command substitution, so the tool-call payload still reaches the guard.
|
|
53
|
+
raw="$("$HOOK_DIR/ledger-guard.sh" --format cursor)"
|
|
54
|
+
rc=$?
|
|
55
|
+
|
|
56
|
+
# THE VERDICT IS THE LAST NON-EMPTY LINE, not the whole of stdout, and it is recognised by containing
|
|
57
|
+
# a `"permission"` key rather than by starting with one.
|
|
58
|
+
#
|
|
59
|
+
# Both halves of that matter. `yad`'s own top-level failure handler prints to STDOUT, so a usage error
|
|
60
|
+
# or a crash banner can land in front of the JSON; a prefix test would then fail to recognise our own
|
|
61
|
+
# deny and fall through to the allow below, turning a real refusal into a permitted write with nothing
|
|
62
|
+
# on stderr to say so. And a containment test does not care what order the JSON's properties are in,
|
|
63
|
+
# so the deny answer's shape on the other side of this language boundary is not silently load-bearing.
|
|
64
|
+
verdict="$(printf '%s\n' "$raw" | awk 'NF { line = $0 } END { print line }')"
|
|
65
|
+
|
|
66
|
+
# `ledger-guard.sh` has its own fail-open branches that exit 0 with EMPTY stdout — no `yad` on PATH,
|
|
67
|
+
# an install it cannot resolve — and each one of those would otherwise reach Cursor as invalid JSON
|
|
68
|
+
# and block the write.
|
|
69
|
+
case "$verdict" in
|
|
70
|
+
*'"permission"'*) echo "$verdict"; exit 0 ;;
|
|
71
|
+
esac
|
|
72
|
+
|
|
73
|
+
# EXIT 2 IS A DENY, even with nothing on stdout — and this branch is reached in a real, ordinary case.
|
|
74
|
+
# `ledger-guard.sh` resolves `yad` from the Product's own `node_modules/yadflow` BEFORE `PATH`, so a
|
|
75
|
+
# project pinned to a yadflow older than `--format` parses the flag, ignores it, and answers in the
|
|
76
|
+
# exit protocol: exit 2, empty stdout. Falling through to the generic allow below would turn a real
|
|
77
|
+
# refusal into a permitted write, and print "exited 2 — allowing" while doing it.
|
|
78
|
+
#
|
|
79
|
+
# The message is a FIXED literal with nothing interpolated. The reason the older `yad` printed has
|
|
80
|
+
# already gone to stderr, where Cursor logs it; escaping arbitrary multi-line text into JSON in bash
|
|
81
|
+
# is exactly the sort of thing that produces an off-schema response, and there is no need to risk it.
|
|
82
|
+
if [ "$rc" -eq 2 ]; then
|
|
83
|
+
echo '{"permission":"deny","user_message":"yad: this edit touches CI-owned gate state.","agent_message":"This edit touches CI-owned gate state, which CI is the sole writer of. Do not edit the ledger by hand: use `yad gate open` for the transition, and commit only the artifact. The installed yadflow is older than this hook, so the full reason is in the hook log rather than here — `yad doctor` will name the version gap."}'
|
|
84
|
+
exit 0
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
if [ "$rc" -ne 0 ]; then
|
|
88
|
+
echo " • yad hook: ledger-guard.sh exited $rc — allowing (run \`yad doctor\` to check the install)" >&2
|
|
89
|
+
fi
|
|
90
|
+
echo "$ALLOW"
|
|
91
|
+
exit 0
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
# ledger-guard HARNESS HOOK — the local half of the CI gate of the same name (#171).
|
|
3
3
|
#
|
|
4
4
|
# The gate ledger is CI-owned in verified mode: `checks/ledger-guard.sh` rejects any non-bot commit
|
|
5
|
-
# that changes `epics/*/.sdlc/{state,approvals,comments,hub-prs}.json` or `epics/*/reviews/*.md
|
|
5
|
+
# that changes `epics/*/.sdlc/{state,approvals,comments,product-prs,hub-prs}.json` or `epics/*/reviews/*.md`,
|
|
6
|
+
# and the same files for the Foundation in `foundation/.sdlc/` and `foundation/reviews/` (E75).
|
|
6
7
|
# This hook says so at the moment an agent tries the edit, instead of twenty minutes later in a
|
|
7
8
|
# failed pipeline, and names the command that owns the transition (`yad gate open`).
|
|
8
9
|
#
|
|
@@ -14,21 +15,51 @@
|
|
|
14
15
|
# exit 0 allow
|
|
15
16
|
# exit 2 deny, reason on stderr
|
|
16
17
|
#
|
|
17
|
-
# Wired
|
|
18
|
-
#
|
|
18
|
+
# Wired by `yad check --fix` for every harness that can refuse a write BEFORE it lands:
|
|
19
|
+
# Claude Code a `PreToolUse` hook in `.claude/settings.json`, pointing straight at THIS script
|
|
20
|
+
# Cursor a `preToolUse` hook in `.cursor/hooks.json`, pointing at `ledger-guard-cursor.sh`
|
|
21
|
+
#
|
|
22
|
+
# DO NOT WIRE THIS SCRIPT INTO CURSOR DIRECTLY, and check the same thing before wiring it into any
|
|
23
|
+
# other harness by hand. Cursor's `preToolUse` is a PERMISSION hook: it wants a JSON verdict on
|
|
24
|
+
# stdout, and treats an empty or off-schema answer as a refusal. This script prints NOTHING when it
|
|
25
|
+
# allows — so wired there directly it would block every file write in the project, which is the
|
|
26
|
+
# opposite of the fail-open stance below. `ledger-guard-cursor.sh` exists to speak that protocol.
|
|
27
|
+
#
|
|
28
|
+
# A harness that reads the EXIT CODE can use this script as it stands. A hook that only fires AFTER
|
|
29
|
+
# the write — Cursor's `afterFileEdit`, for one — is deliberately not used: it could report the edit
|
|
30
|
+
# but never refuse it, and reporting is what the CI gate already does.
|
|
31
|
+
#
|
|
32
|
+
# The project root is resolved from this script's own location below, so it does not matter which
|
|
33
|
+
# variable the harness sets ($CLAUDE_PROJECT_DIR, $CURSOR_PROJECT_DIR) or where it runs the command
|
|
34
|
+
# from; those variables appear only in the wiring, to point at this file.
|
|
19
35
|
#
|
|
20
36
|
# FAIL-OPEN: if no `yad` can be found, this ALLOWS and says why on stderr. A guardrail that blocked
|
|
21
37
|
# every edit the moment an install went sideways would be worse than the problem. The CI gate fails
|
|
22
38
|
# CLOSED and is what actually protects the ledger.
|
|
23
39
|
set -uo pipefail
|
|
24
40
|
|
|
25
|
-
# The
|
|
41
|
+
# The Product root is this script's grandparent — hooks/ledger-guard.sh — so the resolution below does
|
|
26
42
|
# not depend on the harness's working directory.
|
|
27
|
-
|
|
43
|
+
# `CDPATH=` is load-bearing, and the Cursor entry is what makes it so: that entry invokes the script
|
|
44
|
+
# by a RELATIVE path, so `${BASH_SOURCE[0]}` is relative and `cd` consults $CDPATH before the current
|
|
45
|
+
# directory. An exported CDPATH in a login profile — an ordinary thing to have, and inherited by the
|
|
46
|
+
# harness — would resolve `hooks` to some other tree entirely, and the guard would fail open on every
|
|
47
|
+
# write for as long as that profile lived.
|
|
48
|
+
#
|
|
49
|
+
# The loop resolves a symlinked SCRIPT, which `cd -P` does not: `-P` resolves the directory path, and
|
|
50
|
+
# a script reached through a link in another directory would otherwise look for its sibling beside the
|
|
51
|
+
# LINK and not find it. `readlink` without `-f` because `-f` is not portable to macOS.
|
|
52
|
+
_src="${BASH_SOURCE[0]}"
|
|
53
|
+
while [ -L "$_src" ]; do
|
|
54
|
+
_dir="$(CDPATH= cd -P -- "$(dirname -- "$_src")" && pwd)"
|
|
55
|
+
_src="$(readlink -- "$_src")"
|
|
56
|
+
case "$_src" in /*) ;; *) _src="$_dir/$_src" ;; esac
|
|
57
|
+
done
|
|
58
|
+
HOOK_DIR="$(CDPATH= cd -P -- "$(dirname -- "$_src")" && pwd)"
|
|
28
59
|
HUB_ROOT="$(dirname -- "$HOOK_DIR")"
|
|
29
60
|
|
|
30
61
|
# Resolution order, cheapest and most specific first: an explicit override, then the copy installed
|
|
31
|
-
# in this
|
|
62
|
+
# in this Product, then whatever is on PATH, then a network-free npx. `--no-install` matters — a hook
|
|
32
63
|
# runs on every tool call and must never pause an agent to download a package.
|
|
33
64
|
CMD=()
|
|
34
65
|
_yad_bin="${YAD_BIN:-}"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# yad-capture HARNESS HOOK — background capture of Shape artifacts (E43).
|
|
3
|
+
#
|
|
4
|
+
# Runs AFTER an agent edits a file, and snapshots every changed artifact of the Product onto the
|
|
5
|
+
# person's private `yad/wip/<name>/<epic>` branches — built with git plumbing, so the checkout, the
|
|
6
|
+
# index and the current branch are never touched. The push runs in the background, at most once
|
|
7
|
+
# every few minutes. The decision lives in `yad capture --hook`; this file only locates `yad`.
|
|
8
|
+
#
|
|
9
|
+
# Wired by `yad check --fix`, in BOTH ledger modes:
|
|
10
|
+
# Claude Code a `PostToolUse` hook in `.claude/settings.json`
|
|
11
|
+
# Cursor an `afterFileEdit` hook in `.cursor/hooks.json`
|
|
12
|
+
# Any other harness: run this script (or `yad capture --hook`) after a file write.
|
|
13
|
+
#
|
|
14
|
+
# The contract: it ALWAYS exits 0 — a capture must never block or slow an agent. A problem is one line on
|
|
15
|
+
# stderr. Stdout carries ONE thing, and only under Claude Code: when a file this edit changed is also being
|
|
16
|
+
# edited by someone else (E46 claims), a PostToolUse JSON note the agent reads. Otherwise it prints nothing.
|
|
17
|
+
# `YAD_CAPTURE=0`, or `"capture": false` in the Product config, turns it off.
|
|
18
|
+
set -uo pipefail
|
|
19
|
+
# Drain the payload the harness sends on stdin, so it never sees a broken pipe — but never wait on it: not
|
|
20
|
+
# at all from a terminal (someone ran this by hand), and at most a second on a pipe that never closes.
|
|
21
|
+
if [ ! -t 0 ]; then
|
|
22
|
+
while IFS= read -r -t 1 _ 2>/dev/null; do :; done
|
|
23
|
+
fi
|
|
24
|
+
_src="${BASH_SOURCE[0]}"
|
|
25
|
+
while [ -L "$_src" ]; do
|
|
26
|
+
_dir="$(CDPATH= cd -P -- "$(dirname -- "$_src")" && pwd)"
|
|
27
|
+
_src="$(readlink -- "$_src")"
|
|
28
|
+
case "$_src" in /*) ;; *) _src="$_dir/$_src" ;; esac
|
|
29
|
+
done
|
|
30
|
+
HOOK_DIR="$(CDPATH= cd -P -- "$(dirname -- "$_src")" && pwd)"
|
|
31
|
+
HUB_ROOT="$(dirname -- "$HOOK_DIR")"
|
|
32
|
+
[ "${YAD_CAPTURE:-}" = "0" ] && exit 0
|
|
33
|
+
CMD=()
|
|
34
|
+
_yad_bin="${YAD_BIN:-}"
|
|
35
|
+
if [ -n "${_yad_bin//[[:space:]]/}" ]; then
|
|
36
|
+
read -r -a CMD <<< "$_yad_bin"
|
|
37
|
+
elif [ -f "$HUB_ROOT/node_modules/yadflow/bin/yad.mjs" ] && command -v node >/dev/null 2>&1; then
|
|
38
|
+
CMD=(node "$HUB_ROOT/node_modules/yadflow/bin/yad.mjs")
|
|
39
|
+
elif command -v yad >/dev/null 2>&1; then
|
|
40
|
+
CMD=(yad)
|
|
41
|
+
elif command -v npx >/dev/null 2>&1; then
|
|
42
|
+
CMD=(npx --no-install yadflow)
|
|
43
|
+
else
|
|
44
|
+
echo " • yad capture: no \`yad\` on PATH and none installed in $HUB_ROOT — nothing captured" >&2
|
|
45
|
+
exit 0
|
|
46
|
+
fi
|
|
47
|
+
[ "${#CMD[@]}" -eq 0 ] && exit 0
|
|
48
|
+
# Claude Code sets CLAUDE_PROJECT_DIR for its hooks; it reads JSON back. Cursor reads nothing back.
|
|
49
|
+
FORMAT=()
|
|
50
|
+
[ -n "${CLAUDE_PROJECT_DIR:-}" ] && FORMAT=(--format claude)
|
|
51
|
+
# `${FORMAT[@]+…}`: bash 3.2 (macOS) calls an empty array unbound under `set -u`.
|
|
52
|
+
"${CMD[@]}" capture --hook ${FORMAT[@]+"${FORMAT[@]}"} --dir "$HUB_ROOT" </dev/null
|
|
53
|
+
exit 0
|
|
@@ -14,7 +14,7 @@ and `yad-ship` use. It **never auto-advances**; it just commits.
|
|
|
14
14
|
## Conventions
|
|
15
15
|
|
|
16
16
|
- Run **inside the repo holding the staged change** — a code repo under
|
|
17
|
-
`{project-root}/demo-repos/<repo>/`, or the
|
|
17
|
+
`{project-root}/demo-repos/<repo>/`, or the Product itself. Use absolute paths.
|
|
18
18
|
- **Stage first.** Only the staged (`git add`) atomic change is committed. The guard refuses more than
|
|
19
19
|
`ATOMIC_FILE_LIMIT` (3) staged files unless `--force` — split the change instead.
|
|
20
20
|
- **Subject** — `<type>: <lowercase imperative description, no trailing period>`; types are
|
|
@@ -22,8 +22,8 @@ and `yad-ship` use. It **never auto-advances**; it just commits.
|
|
|
22
22
|
- **Task trailer** — required on a code repo (anchors the `spec-link` + `commit-message` gates). Given
|
|
23
23
|
with `--task` (a `<story>-T<NN>` id — an explicit value is validated against the `spec-link`
|
|
24
24
|
contract, so a malformed id like a bare `EP-x-S01` fails locally instead of after a push), else
|
|
25
|
-
derived from the branch (`feat/<story>-<task>-…`).
|
|
26
|
-
task-scoped, so the trailer is optional there — a missing-Task warning is informational on the
|
|
25
|
+
derived from the branch (`feat/<story>-<task>-…`). Product commits are not
|
|
26
|
+
task-scoped, so the trailer is optional there — a missing-Task warning is informational on the Product
|
|
27
27
|
(`spec-link` is a code-repo gate) and only flags a real gate failure in a code repo.
|
|
28
28
|
- **Contract-Change trailer** — `--contract-change` only when the diff touches the locked contract
|
|
29
29
|
surface; it routes the change back to the architecture gate.
|
|
@@ -70,6 +70,6 @@ the architecture gate. To also open the PR/MR in the same step, use `yad-ship`.
|
|
|
70
70
|
|
|
71
71
|
## Reference
|
|
72
72
|
- Branch/commit conventions + the file-boundary rule: `../yad-implement/references/implement-conventions.md`.
|
|
73
|
-
- The full convention text: `CONTRIBUTING.md`; the config:
|
|
73
|
+
- The full convention text: `CONTRIBUTING.md`; the config: `.sdlc/config.yaml` `build`.
|
|
74
74
|
- The gate that enforces the subject pattern: `../yad-checks/references/check-gates.md` (`commit-message`).
|
|
75
75
|
- Open the PR/MR after committing: `../yad-open-pr/SKILL.md`; both at once: `../yad-ship/SKILL.md`.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yad-connect-design
|
|
3
|
-
description: 'Connects a design tool (Figma, or another tool — pluggable) to the
|
|
3
|
+
description: 'Connects a design tool (Figma, or another tool — pluggable) to the Product so the UI design step can materialize the full feature design (mobile screens / web pages) inside it, not just Markdown. Registers the tool into the project-wide .sdlc/design.json (local-user / MCP-session auth, no stored tokens), detecting whether a design-tool MCP is available and degrading to markdown-only when it is not. Run at setup or any time the design tool changes. Reusable, idempotent, refreshable. Use when the user says "connect Figma", "connect a design tool", "refresh the design connection", or "list the design connection".'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# SDLC — Connect a Design Tool (make the UI step design-tool aware)
|
|
7
7
|
|
|
8
8
|
**Goal:** Let the UI design step (`yad-ui`) produce the **actual feature design** — the mobile screens
|
|
9
9
|
and/or web pages — inside a design tool such as **Figma**, alongside the Markdown artifacts
|
|
10
|
-
(`ui-design.md` / `DESIGN.md`). This skill **connects** a design tool to the
|
|
10
|
+
(`ui-design.md` / `DESIGN.md`). This skill **connects** a design tool to the Product and records
|
|
11
11
|
*how* to reach it (the tool, the project/file references, which MCP renders it) — never a credential.
|
|
12
12
|
|
|
13
13
|
This is **setup/maintenance**, not a gated Shape step — it never touches `.sdlc/state.json` or any
|
|
@@ -18,7 +18,7 @@ markdown-only exactly as before.
|
|
|
18
18
|
|
|
19
19
|
## Conventions
|
|
20
20
|
|
|
21
|
-
- `{project-root}` resolves from the project working directory (the **
|
|
21
|
+
- `{project-root}` resolves from the project working directory (the **Product**).
|
|
22
22
|
- The integration is **Figma-first but pluggable** (`config.yaml` `design.tools`): a design-tool
|
|
23
23
|
*adapter*, like the GitHub/GitLab platform adapter. Figma is the primary provider; `pencil`
|
|
24
24
|
(the `.pen` web/mobile editor) is a second, write-capable provider; `none` → markdown-only.
|
|
@@ -29,7 +29,7 @@ markdown-only exactly as before.
|
|
|
29
29
|
the sibling of `.sdlc/repos.json` and `.sdlc/hub.json`.
|
|
30
30
|
- Per-epic screen→frame links are written later by `yad-ui` (`epics/EP-<slug>/.sdlc/design-links.json`),
|
|
31
31
|
not here.
|
|
32
|
-
- Speak in the
|
|
32
|
+
- Speak in the `communication_language` set in `{project-root}/.sdlc/config.yaml`; write documents in `document_output_language`.
|
|
33
33
|
|
|
34
34
|
## Inputs
|
|
35
35
|
|
|
@@ -94,7 +94,7 @@ Nothing auto-advances; this is setup.
|
|
|
94
94
|
**available/unavailable** flag for the MCP (best-effort, the user's own session). No design tool
|
|
95
95
|
connected ⇒ "markdown-only".
|
|
96
96
|
- **`disconnect`** — remove the registry file (or set `tool: "none"`). The design tool's own
|
|
97
|
-
project/files are **never touched** — only the
|
|
97
|
+
project/files are **never touched** — only the Product's record of them.
|
|
98
98
|
|
|
99
99
|
## Hard rules
|
|
100
100
|
|
|
@@ -46,7 +46,7 @@ a screen, capture its node id + URL, and map components/tokens into `DESIGN.md`.
|
|
|
46
46
|
|
|
47
47
|
Either direction ends by writing `epics/EP-<slug>/.sdlc/design-links.json` — the machine-readable
|
|
48
48
|
screen→frame map — and a `## Design (<tool>)` section in `ui-design.md` linking each screen to its frame
|
|
49
|
-
URL. The design itself lives in the tool; the
|
|
49
|
+
URL. The design itself lives in the tool; the Product keeps the *links* and the Markdown spec beside the
|
|
50
50
|
other epic artifacts.
|
|
51
51
|
|
|
52
52
|
## Degrade path (no MCP / no tool)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Design registry — schema + freshness rule
|
|
2
2
|
|
|
3
|
-
The registry is the
|
|
3
|
+
The registry is the Product's record of which design tool is connected and how to reach it. It is
|
|
4
4
|
**project-wide** (one design tool per project, shared across every epic), so it lives at the product
|
|
5
5
|
root, not under any `epics/EP-<slug>/.sdlc/`.
|
|
6
6
|
|
|
@@ -51,6 +51,6 @@ only). This mirrors how `repos.json` and `hub.json` are committed.
|
|
|
51
51
|
|
|
52
52
|
## Greenfield
|
|
53
53
|
|
|
54
|
-
A brand-new
|
|
54
|
+
A brand-new Product has no `design.json`. That is valid — `yad-ui` treats "no design tool connected"
|
|
55
55
|
the same as `tool: "none"` and produces the Markdown artifacts only. The registry appears the first time
|
|
56
56
|
`connect` runs.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yad-connect-docs
|
|
3
|
-
description: 'Connects a docs/Pages publishing target to the
|
|
3
|
+
description: 'Connects a docs/Pages publishing target to the Product so the interactive-docs steps can build and deploy the generated SPA — not just commit its source. Registers the target into the project-wide .sdlc/docs.json (GitHub Pages / GitLab Pages / build-only), auto-detecting the platform from .sdlc/hub.json and resolving the Vite base path, with local-user auth and no stored tokens. Detects whether gh/glab is present and degrades to build-only when absent. Run at setup or any time the publish target changes. Reusable, idempotent, refreshable. Use when the user says "connect docs", "connect Pages", "refresh the docs connection", or "list the docs connection".'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# SDLC — Connect a Docs/Pages Target (make the docs steps publishable)
|
|
7
7
|
|
|
8
8
|
**Goal:** Let the interactive-docs steps (`yad-docs` per epic, `yad-docs-overview` project-wide)
|
|
9
9
|
**build and deploy** the generated React/Vite SPA to a real URL — a GitHub Pages or GitLab Pages site —
|
|
10
|
-
instead of only committing its source. This skill **connects** a publishing target to the
|
|
10
|
+
instead of only committing its source. This skill **connects** a publishing target to the Product
|
|
11
11
|
and records *how* to reach it (the platform, the publish scope, the base path) — never a credential.
|
|
12
12
|
|
|
13
13
|
This is **setup/maintenance**, not a gated Shape step — it never touches `.sdlc/state.json` or any
|
|
@@ -18,9 +18,9 @@ at a local `dist/` — build-only, no publish, exactly as before.
|
|
|
18
18
|
|
|
19
19
|
## Conventions
|
|
20
20
|
|
|
21
|
-
- `{project-root}` resolves from the project working directory (the **
|
|
21
|
+
- `{project-root}` resolves from the project working directory (the **Product**).
|
|
22
22
|
- The target is **GitHub-Pages-first but pluggable** — a *publish adapter*, mirroring the GitHub/GitLab
|
|
23
|
-
platform adapter the
|
|
23
|
+
platform adapter the Product already uses. `github-pages` and `gitlab-pages` are the providers; `none` →
|
|
24
24
|
build-only (deliberate, no error).
|
|
25
25
|
- The platform CLI (`gh` / `glab`) is a **subprocess**, used read/deploy-only via the user's own auth —
|
|
26
26
|
never installed by this skill, never given a token. Absent ⇒ degrade to build-only (`source:
|
|
@@ -29,15 +29,15 @@ at a local `dist/` — build-only, no publish, exactly as before.
|
|
|
29
29
|
NOT per-epic), the sibling of `.sdlc/hub.json`, `.sdlc/repos.json`, and `.sdlc/design.json`.
|
|
30
30
|
- Per-epic / overview build manifests (`docs-build.json`) are written later by `yad-docs` /
|
|
31
31
|
`yad-docs-overview`, not here. This skill describes the *connection*; it does not build.
|
|
32
|
-
- Speak in the
|
|
32
|
+
- Speak in the `communication_language` set in `{project-root}/.sdlc/config.yaml`; write documents in `document_output_language`.
|
|
33
33
|
|
|
34
34
|
## Inputs
|
|
35
35
|
|
|
36
36
|
- `action` — `connect` (default) | `refresh` | `list` | `disconnect`.
|
|
37
37
|
- `target` — `github-pages` | `gitlab-pages` | `none`. Default **auto-detected** from `.sdlc/hub.json`
|
|
38
|
-
`platform` (github → `github-pages`, gitlab → `gitlab-pages`, null/no
|
|
38
|
+
`platform` (github → `github-pages`, gitlab → `gitlab-pages`, null/no Product → `none`).
|
|
39
39
|
- `scope` — `hub` (default) | `<repo-name>` | `dedicated`. Where the Pages site is published from (the
|
|
40
|
-
|
|
40
|
+
Product repo, one connected code repo, or a dedicated docs repo).
|
|
41
41
|
- `public` — `true` (default) | `false`. Whether the published site is public.
|
|
42
42
|
- `base_path` — optional explicit override of the Vite `base` (otherwise resolved, Step 2).
|
|
43
43
|
|
|
@@ -45,7 +45,7 @@ at a local `dist/` — build-only, no publish, exactly as before.
|
|
|
45
45
|
|
|
46
46
|
### Step 1 — Resolve the target + detect the platform (the publish adapter)
|
|
47
47
|
Determine the `target`. If not given, read `{project-root}/.sdlc/hub.json` `platform` and map it the same
|
|
48
|
-
way the
|
|
48
|
+
way the Product bridge maps repos: `github` → `github-pages`, `gitlab` → `gitlab-pages`, `null`/no Product →
|
|
49
49
|
`none` (deliberate build-only). Reject a `target` value outside the three providers (fall back to the
|
|
50
50
|
detected default with a warning, the way `registerRepo` falls back on an unknown platform).
|
|
51
51
|
|
|
@@ -61,7 +61,7 @@ tokens**; everything in the registry is a plain reference. Do **not** install a
|
|
|
61
61
|
|
|
62
62
|
### Step 2 — Decide the publish scope + resolve the base path
|
|
63
63
|
Resolve `scope` → `publishRepo`:
|
|
64
|
-
- `hub` (default) → publish from the
|
|
64
|
+
- `hub` (default) → publish from the Product repo (read its name from `hub.json` `git_url`).
|
|
65
65
|
- `<repo-name>` → publish from that connected code repo (must exist in `.sdlc/repos.json`).
|
|
66
66
|
- `dedicated` → a dedicated docs repo the user names (recorded as `publishRepo`).
|
|
67
67
|
|
|
@@ -109,7 +109,7 @@ the site here — `yad-docs` builds.**
|
|
|
109
109
|
**available/unavailable** flag for the platform CLI (best-effort, the user's own session). No target
|
|
110
110
|
connected ⇒ "build-only".
|
|
111
111
|
- **`disconnect`** — remove the registry file (or set `target: "none"`). The platform's own Pages site is
|
|
112
|
-
**never touched** — only the
|
|
112
|
+
**never touched** — only the Product's record of it.
|
|
113
113
|
|
|
114
114
|
## Hard rules
|
|
115
115
|
|
|
@@ -127,6 +127,6 @@ the site here — `yad-docs` builds.**
|
|
|
127
127
|
- Registry schema, the base-path resolution table, and the freshness/degrade rules:
|
|
128
128
|
`references/docs-registry.md`.
|
|
129
129
|
- The connect pattern this mirrors (design tool): `../yad-connect-design/SKILL.md`.
|
|
130
|
-
- The connect pattern this mirrors (code repos +
|
|
130
|
+
- The connect pattern this mirrors (code repos + Product detection): `../yad-connect-repos/SKILL.md`.
|
|
131
131
|
- The consumers — how `yad-docs` / `yad-docs-overview` build + deploy: `../yad-docs/SKILL.md`,
|
|
132
132
|
`../yad-docs-overview/SKILL.md`.
|
|
@@ -38,7 +38,7 @@ Holds **no credentials** — every field is a plain reference. Auth is always th
|
|
|
38
38
|
|
|
39
39
|
## Platform auto-detection (from `.sdlc/hub.json`)
|
|
40
40
|
|
|
41
|
-
When `target` is not given, map the
|
|
41
|
+
When `target` is not given, map the Product's `platform` the same way `yad-connect-repos` maps a repo host:
|
|
42
42
|
|
|
43
43
|
| `hub.json` `platform` | default `target` |
|
|
44
44
|
|-----------------------|------------------|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yad-connect-learning
|
|
3
|
-
description: 'Connects a learning/tutoring tool (DeepTutor, or another tool — pluggable) to the
|
|
3
|
+
description: 'Connects a learning/tutoring tool (DeepTutor, or another tool — pluggable) to the Product so the cross-cutting learning layer can tutor any team member, at any SDLC stage, in the context of what is being built. Registers the tool into the project-wide .sdlc/learning.json (local-user auth, no stored tokens), detecting whether the DeepTutor CLI is on PATH and degrading to harness-native tutoring (the harness model reading project artifacts) when it is not. Optionally builds a project knowledge base from the SDLC artifacts + secret-scanned code-maps so tutoring is grounded. Run at setup or any time the learning tool changes. Reusable, idempotent, refreshable. Use when the user says "connect DeepTutor", "connect a learning tool", "refresh the learning connection", or "list the learning connection".'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# SDLC — Connect a Learning Tool (the cross-cutting learning layer)
|
|
7
7
|
|
|
8
8
|
**Goal:** Let any team member pause at **any** SDLC stage and ask to learn a concept — and get tutored
|
|
9
9
|
*in the context of what the team is actually building*. This skill **connects** a learning tool such as
|
|
10
|
-
**DeepTutor** to the
|
|
10
|
+
**DeepTutor** to the Product and records *how* to reach it (the tool, the CLI, an optional grounded
|
|
11
11
|
knowledge base) — never a credential. The consumer skill **`yad-learn`** does the tutoring per request
|
|
12
12
|
and records the team's skills.
|
|
13
13
|
|
|
@@ -19,7 +19,7 @@ explains the concept. The learning layer is **purely opt-in and never blocks a g
|
|
|
19
19
|
|
|
20
20
|
## Conventions
|
|
21
21
|
|
|
22
|
-
- `{project-root}` resolves from the project working directory (the **
|
|
22
|
+
- `{project-root}` resolves from the project working directory (the **Product**).
|
|
23
23
|
- The integration is **DeepTutor-first but pluggable** (`config.yaml` `learning.tools`): a learning-tool
|
|
24
24
|
*adapter*, like the design/testing adapters. `none` → harness-native (yad-learn still tutors via the
|
|
25
25
|
harness model).
|
|
@@ -30,7 +30,7 @@ explains the concept. The learning layer is **purely opt-in and never blocks a g
|
|
|
30
30
|
the sibling of `.sdlc/repos.json`, `.sdlc/hub.json`, `.sdlc/design.json`, and `.sdlc/testing.json`.
|
|
31
31
|
- Per-epic, per-member learning records + rendered tutorials are written later by `yad-learn`
|
|
32
32
|
(`epics/EP-<slug>/.sdlc/learning-records.json` and `epics/EP-<slug>/learning/`), not here.
|
|
33
|
-
- Speak in the
|
|
33
|
+
- Speak in the `communication_language` set in `{project-root}/.sdlc/config.yaml`; write documents in `document_output_language`.
|
|
34
34
|
|
|
35
35
|
## Inputs
|
|
36
36
|
|
|
@@ -113,7 +113,7 @@ auto-advances; this is setup.
|
|
|
113
113
|
**available/harness-native** flag for the CLI (best-effort). No learning tool connected ⇒
|
|
114
114
|
"harness-native".
|
|
115
115
|
- **`disconnect`** — remove the registry file (or set `tool: "none"`). DeepTutor's own config and
|
|
116
|
-
knowledge bases are **never touched** — only the
|
|
116
|
+
knowledge bases are **never touched** — only the Product's record of them.
|
|
117
117
|
|
|
118
118
|
## Hard rules
|
|
119
119
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Learning registry — schema + freshness rule
|
|
2
2
|
|
|
3
|
-
The registry is the
|
|
3
|
+
The registry is the Product's record of which learning tool is connected and how to reach it. It is
|
|
4
4
|
**project-wide** (one learning tool per project, shared across every epic), so it lives at the product
|
|
5
5
|
root, not under any `epics/EP-<slug>/.sdlc/`.
|
|
6
6
|
|
|
@@ -55,6 +55,6 @@ only). This mirrors how `repos.json`, `hub.json`, `design.json`, and `testing.js
|
|
|
55
55
|
|
|
56
56
|
## Greenfield
|
|
57
57
|
|
|
58
|
-
A brand-new
|
|
58
|
+
A brand-new Product has no `learning.json`. That is valid — `yad-learn` treats "no learning tool
|
|
59
59
|
connected" the same as `tool: "none"` and tutors harness-native. The registry appears the first time
|
|
60
60
|
`connect` runs.
|