@open-agent-toolkit/cli 0.2.5 → 0.2.6
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/assets/docs/cli-utilities/configuration.md +40 -0
- package/assets/docs/cli-utilities/tool-packs.md +31 -0
- package/assets/docs/workflows/projects/artifacts.md +27 -0
- package/assets/docs/workflows/skills/explainer-kit.md +125 -0
- package/assets/docs/workflows/skills/index.md +4 -0
- package/assets/migration/pjm-restructure.md +12 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/explainer-kit/SKILL.md +95 -0
- package/assets/skills/explainer-kit/examples/project-explainer/content.md +31 -0
- package/assets/skills/explainer-kit/examples/project-explainer/fact-base.md +22 -0
- package/assets/skills/explainer-kit/examples/project-recap/content.md +34 -0
- package/assets/skills/explainer-kit/examples/project-recap/fact-base.md +22 -0
- package/assets/skills/explainer-kit/examples/theme-bundle.json +87 -0
- package/assets/skills/explainer-kit/palettes/ember.json +37 -0
- package/assets/skills/explainer-kit/palettes/forest.json +37 -0
- package/assets/skills/explainer-kit/palettes/neutral.json +37 -0
- package/assets/skills/explainer-kit/palettes/ocean.json +37 -0
- package/assets/skills/explainer-kit/palettes/violet.json +37 -0
- package/assets/skills/explainer-kit/profiles/clean.json +42 -0
- package/assets/skills/explainer-kit/profiles/editorial.json +42 -0
- package/assets/skills/explainer-kit/profiles/technical.json +39 -0
- package/assets/skills/explainer-kit/recipes/engineer-tour.json +33 -0
- package/assets/skills/explainer-kit/recipes/program-recap.json +34 -0
- package/assets/skills/explainer-kit/recipes/project-explainer.json +33 -0
- package/assets/skills/explainer-kit/recipes/project-recap.json +34 -0
- package/assets/skills/explainer-kit/references/contracts.md +101 -0
- package/assets/skills/explainer-kit/references/destination-contract.md +94 -0
- package/assets/skills/explainer-kit/references/extension-contract.md +71 -0
- package/assets/skills/explainer-kit/references/fact-base-contract.md +119 -0
- package/assets/skills/explainer-kit/schemas/build-record.schema.json +92 -0
- package/assets/skills/explainer-kit/schemas/durability-evidence.schema.json +53 -0
- package/assets/skills/explainer-kit/schemas/fact-base.schema.json +129 -0
- package/assets/skills/explainer-kit/schemas/manifest.schema.json +193 -0
- package/assets/skills/explainer-kit/schemas/publish-receipt.schema.json +97 -0
- package/assets/skills/explainer-kit/schemas/publish-request.schema.json +32 -0
- package/assets/skills/explainer-kit/schemas/run-request.schema.json +132 -0
- package/assets/skills/explainer-kit/schemas/theme.schema.json +217 -0
- package/assets/skills/explainer-kit/scripts/lib/content-approval.mjs +180 -0
- package/assets/skills/explainer-kit/scripts/lib/contracts.mjs +680 -0
- package/assets/skills/explainer-kit/scripts/lib/durability.mjs +538 -0
- package/assets/skills/explainer-kit/scripts/lib/fact-base.mjs +494 -0
- package/assets/skills/explainer-kit/scripts/lib/fs-safe.mjs +218 -0
- package/assets/skills/explainer-kit/scripts/lib/qa.mjs +512 -0
- package/assets/skills/explainer-kit/scripts/lib/recipes.mjs +289 -0
- package/assets/skills/explainer-kit/scripts/lib/records.mjs +231 -0
- package/assets/skills/explainer-kit/scripts/lib/render.mjs +485 -0
- package/assets/skills/explainer-kit/scripts/lib/s3-static.mjs +587 -0
- package/assets/skills/explainer-kit/scripts/lib/safe-paths.mjs +96 -0
- package/assets/skills/explainer-kit/scripts/lib/theme.mjs +332 -0
- package/assets/skills/explainer-kit/scripts/publish.mjs +76 -0
- package/assets/skills/explainer-kit/scripts/record-durability.mjs +64 -0
- package/assets/skills/explainer-kit/scripts/render-qa.mjs +273 -0
- package/assets/skills/explainer-kit/scripts/run.mjs +778 -0
- package/assets/skills/explainer-kit/scripts/validate.mjs +59 -0
- package/assets/skills/explainer-kit/templates/deck-shell.html +233 -0
- package/assets/skills/explainer-kit/templates/diagram-shell.html +219 -0
- package/assets/skills/explainer-kit/templates/engineer-tour.html +273 -0
- package/assets/skills/explainer-kit/templates/house-style.html +218 -0
- package/assets/skills/oat-explainer-kit/SKILL.md +92 -0
- package/assets/skills/oat-explainer-kit/references/config-contract.md +67 -0
- package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +143 -0
- package/assets/skills/oat-explainer-kit/references/migration.md +143 -0
- package/assets/skills/oat-explainer-kit/scripts/bind-project-sources.mjs +103 -0
- package/assets/skills/oat-explainer-kit/scripts/check-core.mjs +127 -0
- package/assets/skills/oat-explainer-kit/scripts/finalize-tracked-run.mjs +392 -0
- package/assets/skills/oat-explainer-kit/scripts/persist-intent.mjs +130 -0
- package/assets/skills/oat-explainer-kit/scripts/resolve-config.mjs +293 -0
- package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +209 -0
- package/assets/skills/oat-explainer-kit/scripts/resolve-paths.mjs +166 -0
- package/assets/skills/oat-explainer-kit/scripts/run.mjs +284 -0
- package/assets/skills/oat-project-autonomous/SKILL.md +22 -1
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +5 -1
- package/assets/skills/oat-project-complete/SKILL.md +166 -28
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +5 -1
- package/assets/skills/oat-project-implement/SKILL.md +1 -1
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +17 -0
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +5 -1
- package/assets/skills/oat-project-plan/SKILL.md +30 -1
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +5 -1
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +5 -1
- package/assets/skills/oat-project-summary/SKILL.md +20 -1
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +232 -1
- package/dist/commands/init/tools/shared/skill-manifest.d.ts +2 -2
- package/dist/commands/init/tools/shared/skill-manifest.d.ts.map +1 -1
- package/dist/commands/init/tools/shared/skill-manifest.js +2 -0
- package/dist/commands/project/archive/archive-utils.d.ts +12 -0
- package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
- package/dist/commands/project/archive/archive-utils.js +320 -8
- package/dist/commands/project/archive/index.d.ts.map +1 -1
- package/dist/commands/project/archive/index.js +1 -0
- package/dist/commands/project/archive/push-runner.d.ts +1 -0
- package/dist/commands/project/archive/push-runner.d.ts.map +1 -1
- package/dist/commands/project/archive/push-runner.js +9 -2
- package/dist/config/oat-config.d.ts +26 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +88 -0
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +18 -0
- package/dist/validation/project-state.d.ts +3 -0
- package/dist/validation/project-state.d.ts.map +1 -1
- package/dist/validation/project-state.js +91 -0
- package/package.json +2 -2
|
@@ -100,6 +100,46 @@ oat config set tools.project-management true
|
|
|
100
100
|
|
|
101
101
|
The `tools.*` keys are primarily maintained by `oat tools install`, `oat tools update`, and `oat tools remove`, but they are intentionally visible through `oat config` so workflows and operators can inspect or override pack-state signals when needed.
|
|
102
102
|
|
|
103
|
+
### Explainer configuration
|
|
104
|
+
|
|
105
|
+
The `oat-explainer-kit` adapter owns two typed config groups. Build and publish
|
|
106
|
+
plumbing uses `explainers.*`; project lifecycle preferences use
|
|
107
|
+
`workflow.explainers.*`.
|
|
108
|
+
|
|
109
|
+
| Key | Type | Stored scopes | Default |
|
|
110
|
+
| -------------------------------------- | -------------------- | ------------------- | --------- |
|
|
111
|
+
| `explainers.defaults.palette` | non-empty string | local, shared, user | `neutral` |
|
|
112
|
+
| `explainers.defaults.visualProfile` | non-empty string | local, shared, user | `clean` |
|
|
113
|
+
| `explainers.defaults.themeBundlePath` | path | local, shared | unset |
|
|
114
|
+
| `explainers.publish.provider` | `s3-static` | shared | unset |
|
|
115
|
+
| `explainers.publish.s3Uri` | `s3://` URI | shared | unset |
|
|
116
|
+
| `explainers.publish.publicBaseUrl` | HTTPS URL | shared | unset |
|
|
117
|
+
| `explainers.publish.awsRegion` | non-empty string | shared | unset |
|
|
118
|
+
| `explainers.publish.awsProfile` | non-empty string | local, user | unset |
|
|
119
|
+
| `workflow.explainers.projectExplainer` | `always\|ask\|never` | local, shared, user | `ask` |
|
|
120
|
+
| `workflow.explainers.projectRecap` | `always\|ask\|never` | local, shared, user | `ask` |
|
|
121
|
+
|
|
122
|
+
Stored values resolve `local > shared > user > default` where the key permits
|
|
123
|
+
each scope. Explicit runtime inputs take precedence for one invocation without
|
|
124
|
+
mutating stored config. Use `oat config get <key> --json` to inspect both the
|
|
125
|
+
resolved value and its source, and `oat config describe <key>` for its exact
|
|
126
|
+
scope and type contract.
|
|
127
|
+
|
|
128
|
+
Shared theme-bundle paths must be repository-relative. Local paths may be
|
|
129
|
+
repository-relative or absolute; user config cannot set a theme-bundle path.
|
|
130
|
+
A supplied bundle takes precedence over named palette and profile defaults and
|
|
131
|
+
produces a warning.
|
|
132
|
+
|
|
133
|
+
Publishing remains build-only when `explainers.publish.provider` is unset.
|
|
134
|
+
When it is `s3-static`, `s3Uri`, `publicBaseUrl`, and `awsRegion` are all
|
|
135
|
+
required. `awsProfile` is optional; when absent, the standard AWS credential
|
|
136
|
+
chain applies. Config never starts publishing by itself: lifecycle callers must
|
|
137
|
+
still select publish durability explicitly, and publishing remains
|
|
138
|
+
human-gated. Raw AWS credentials are not config keys.
|
|
139
|
+
|
|
140
|
+
See [Explainer Kit](../workflows/skills/explainer-kit.md) for recipes, artifact
|
|
141
|
+
locations, lifecycle behavior, and durability.
|
|
142
|
+
|
|
103
143
|
Workflow gate objects are structured config and use their own command group
|
|
104
144
|
instead of the scalar `oat config set` surface. See
|
|
105
145
|
[Workflow Gates](workflow-gates.md) for the full command surface and examples.
|
|
@@ -45,6 +45,37 @@ present without the utility engine, it fails closed and reports the missing
|
|
|
45
45
|
dependency instead of inventing a fallback route. Non-project analytical
|
|
46
46
|
skills can use the utility engine directly.
|
|
47
47
|
|
|
48
|
+
### Cross-pack explainer dependency
|
|
49
|
+
|
|
50
|
+
The public explainer family also spans two packs:
|
|
51
|
+
|
|
52
|
+
- `utility` owns `explainer-kit`, the destination-neutral core with its
|
|
53
|
+
contracts, recipes, themes, templates, render QA, durability verifier, and
|
|
54
|
+
optional publishing connector.
|
|
55
|
+
- `workflows` owns `oat-explainer-kit`, the adapter that resolves OAT config,
|
|
56
|
+
project artifacts, output paths, and lifecycle intent.
|
|
57
|
+
|
|
58
|
+
Install the core at user scope before using the adapter:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
oat tools install utility --scope user
|
|
62
|
+
oat tools install workflows
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The dependency is one-way: the adapter invokes the core, while the core remains
|
|
66
|
+
usable without OAT. The adapter checks the installed canonical core path and
|
|
67
|
+
minimum compatible version before reading config or running. If the core is
|
|
68
|
+
missing it fails closed with the utility install command; if it is too old it
|
|
69
|
+
reports:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
oat tools update --pack utility --scope user
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
It never falls back to a source checkout or copies core logic into the
|
|
76
|
+
workflows pack. See [Explainer Kit](../workflows/skills/explainer-kit.md) for
|
|
77
|
+
the usage and lifecycle contract.
|
|
78
|
+
|
|
48
79
|
## `oat tools` command group
|
|
49
80
|
|
|
50
81
|
The `oat tools` command group provides a unified interface for managing installed tools (skills and agents) across scopes.
|
|
@@ -31,6 +31,33 @@ Mode-sensitive notes:
|
|
|
31
31
|
- `references/imported-plan.md`: preserved source plan for import mode
|
|
32
32
|
- `references/split-plan.json`: persisted split plan for a coordination parent, used as the durable resume source when `oat-project-split` is interrupted
|
|
33
33
|
|
|
34
|
+
### Explainer artifacts
|
|
35
|
+
|
|
36
|
+
[Explainer Kit](../skills/explainer-kit.md) writes project runs under
|
|
37
|
+
`<resolved-project-path>/explainers/<slug>/`. The two project products have
|
|
38
|
+
different retention contracts:
|
|
39
|
+
|
|
40
|
+
- A `project-explainer` is a working artifact. In a shared project it can be
|
|
41
|
+
tracked while the project is active, but project completion removes it from
|
|
42
|
+
the tracked branch with the active project tree. It remains only in the local
|
|
43
|
+
archived project.
|
|
44
|
+
- A selected final `project-recap` is a durable completion record. Before a
|
|
45
|
+
shared project is removed, archive copies the complete selected run to
|
|
46
|
+
`.oat/repo/reference/project-recaps/<YYYYMMDD-project-slug>/`, verifies its
|
|
47
|
+
manifest artifact hashes, and reports that tracked export path. Summary and
|
|
48
|
+
PR links use this export, never the gitignored local archive.
|
|
49
|
+
|
|
50
|
+
The archive exports at most one selected recap package. It preserves structured
|
|
51
|
+
failure outcomes and successful intermediates, rejects an existing dated
|
|
52
|
+
destination, and fails before deleting the active project if copy or hash
|
|
53
|
+
verification fails.
|
|
54
|
+
|
|
55
|
+
Local-scope projects are not archived through this export path. Their explainer
|
|
56
|
+
packages inherit the local project's untracked posture and remain
|
|
57
|
+
`built-not-durable` unless independent publish evidence exists. Non-project OAT
|
|
58
|
+
explainer runs use `.oat/repo/reference/explainers/<slug>/`; direct core callers
|
|
59
|
+
must provide their own explicit output root.
|
|
60
|
+
|
|
34
61
|
### Gate review frontmatter
|
|
35
62
|
|
|
36
63
|
Review artifacts produced by `oat gate review` use the normal review fields plus
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Explainer Kit
|
|
3
|
+
description: 'Build destination-neutral visual explainers directly or from OAT project lifecycle artifacts.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Explainer Kit
|
|
7
|
+
|
|
8
|
+
The public explainer family separates a destination-neutral core from an
|
|
9
|
+
OAT-aware adapter:
|
|
10
|
+
|
|
11
|
+
- `explainer-kit` validates explicit versioned inputs, reconciles one cited fact
|
|
12
|
+
base, applies a recipe and theme, renders and checks the artifact set, and
|
|
13
|
+
records a manifest and build outcome.
|
|
14
|
+
- `oat-explainer-kit` resolves OAT configuration, project intent, source
|
|
15
|
+
artifacts, and canonical output paths before invoking the same core.
|
|
16
|
+
|
|
17
|
+
The core does not read OAT, user, vault, or destination configuration. Direct
|
|
18
|
+
callers provide a complete `ExplainerRunRequestV1` and an explicit output root.
|
|
19
|
+
OAT lifecycle callers use the adapter.
|
|
20
|
+
|
|
21
|
+
## Recipes
|
|
22
|
+
|
|
23
|
+
The v1 project recipes serve different lifecycle jobs:
|
|
24
|
+
|
|
25
|
+
| Recipe | Lifecycle use | Required narrative |
|
|
26
|
+
| ------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
27
|
+
| `project-explainer` | Working explanation after project planning | planned architecture, decisions, risks, phases, and validation approach |
|
|
28
|
+
| `project-recap` | Final record after implementation and final review | original request, key agent decisions, as-built architecture, implementation record, validation evidence, and outcome |
|
|
29
|
+
|
|
30
|
+
Both recipes bind one project source set. The adapter binds `plan.md`,
|
|
31
|
+
`design.md`, and `spec.md` for a project explainer; a project recap can also
|
|
32
|
+
include `implementation.md` and `summary.md`.
|
|
33
|
+
|
|
34
|
+
## Themes
|
|
35
|
+
|
|
36
|
+
Every artifact set uses one resolved theme. The bundled defaults are the
|
|
37
|
+
`neutral` palette and `clean` visual profile. The core also ships the `ocean`,
|
|
38
|
+
`ember`, `forest`, and `violet` palettes plus `editorial` and `technical`
|
|
39
|
+
profiles.
|
|
40
|
+
|
|
41
|
+
A caller may select named palette/profile values, supply a validated theme
|
|
42
|
+
bundle, or provide per-run art direction. A supplied bundle takes precedence
|
|
43
|
+
over named selections. The resolved concrete bundle is retained with the run;
|
|
44
|
+
raw art-direction text is not retained by default. Themes contain validated
|
|
45
|
+
light and dark modes, while the render strategy chooses either the default mode
|
|
46
|
+
or a user-switchable result.
|
|
47
|
+
|
|
48
|
+
## Build, durability, and publish
|
|
49
|
+
|
|
50
|
+
Missing publish configuration means build-only. A completed build writes the
|
|
51
|
+
source package, resolved theme, `manifest.json`, `build-record.json`, and the
|
|
52
|
+
rendered `site/` tree. Rendering or publishing failures preserve successful
|
|
53
|
+
intermediates and recovery information.
|
|
54
|
+
|
|
55
|
+
Build success and durability are separate:
|
|
56
|
+
|
|
57
|
+
- `built-not-durable` means artifacts exist but verified commit or publish
|
|
58
|
+
evidence is absent.
|
|
59
|
+
- `built-durable` requires verified evidence for every required
|
|
60
|
+
non-rebuildable artifact.
|
|
61
|
+
- `failed` records a failed run without treating partial output as success.
|
|
62
|
+
|
|
63
|
+
The core verifies caller-supplied commit or publish evidence; it never creates
|
|
64
|
+
Git commits. Publishing is always explicitly requested and human-gated. The
|
|
65
|
+
public `s3-static` connector validates corresponding S3 and HTTPS roots with a
|
|
66
|
+
run-unique sentinel, uploads only manifest-declared `site/` files, verifies the
|
|
67
|
+
content type and SHA-256 response bytes at public URLs, and writes
|
|
68
|
+
`publish-receipt.json`. Public roots cannot contain credentials, queries, or
|
|
69
|
+
fragments. Publishing is additive and does not run a root-wide destructive
|
|
70
|
+
sync.
|
|
71
|
+
|
|
72
|
+
Release validation drives the bounded palette/profile/template matrix in a real
|
|
73
|
+
installed Chromium browser and retains machine-readable viewport, clipping,
|
|
74
|
+
motion, keyboard, no-JavaScript, and print measurements. The gate fails closed
|
|
75
|
+
when no supported browser executable is available.
|
|
76
|
+
|
|
77
|
+
Frozen RC runs require both the identity record and the explicit retained
|
|
78
|
+
tarball directory:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
node tools/release/run-explainer-rc.mjs \
|
|
82
|
+
--rc-manifest .oat/repo/reference/explainer-kit-acceptance/v1/rc.json \
|
|
83
|
+
--artifacts-dir dist/explainer-kit-rc \
|
|
84
|
+
--entry scripts/run.mjs \
|
|
85
|
+
--record /path/to/sanitized-execution.json \
|
|
86
|
+
-- --request /path/to/request.json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The packaged CLI emits one complete JSON result document; pretty-printed
|
|
90
|
+
multiline JSON is valid, while progress text and line-by-line guessing are not.
|
|
91
|
+
The resulting execution record binds the canonical request and child-reported
|
|
92
|
+
manifest to the core run ID without retaining private argument values.
|
|
93
|
+
Wrapper-created receipt evidence is produced only after core execution and is
|
|
94
|
+
validated separately against the immutable execution record and manifest.
|
|
95
|
+
|
|
96
|
+
## OAT lifecycle policy
|
|
97
|
+
|
|
98
|
+
Interactive project explainer and recap preferences resolve independently from
|
|
99
|
+
`workflow.explainers.projectExplainer` and
|
|
100
|
+
`workflow.explainers.projectRecap`. Each accepts `always`, `ask`, or `never`;
|
|
101
|
+
the built-in default is `ask`. A resolved project decision in `state.md`
|
|
102
|
+
outranks those preferences.
|
|
103
|
+
|
|
104
|
+
Autonomous mode has stricter policy: it always attempts a project recap, while
|
|
105
|
+
a project explainer runs only when the kickoff request explicitly asks for
|
|
106
|
+
one. Lifecycle-triggered runs do not publish automatically, and recap failure
|
|
107
|
+
does not block project completion.
|
|
108
|
+
|
|
109
|
+
See [Project Artifacts](../projects/artifacts.md) for active and durable output
|
|
110
|
+
locations, and [Configuration](../../cli-utilities/configuration.md) for the
|
|
111
|
+
typed adapter settings.
|
|
112
|
+
|
|
113
|
+
## Private wrappers
|
|
114
|
+
|
|
115
|
+
Private integrations use the core boundary directly: resolve private inputs
|
|
116
|
+
before the run, construct one versioned request, invoke the core once, then
|
|
117
|
+
publish or link the versioned manifest after the run. Wrapper acceptance reads
|
|
118
|
+
the complete post-run `PublishReceiptV1`, verifies every manifest artifact and
|
|
119
|
+
the core run ID, and rejects foreign or stale receipts. Presets, private source
|
|
120
|
+
systems, external-document synchronization, and personal destinations remain
|
|
121
|
+
wrapper-owned.
|
|
122
|
+
|
|
123
|
+
V1 exposes no plugin registry or private mid-pipeline hook. Unsupported
|
|
124
|
+
contract majors and identity mismatches fail closed instead of being guessed
|
|
125
|
+
or coerced.
|
|
@@ -11,6 +11,7 @@ Use this section when you want to choose the right OAT skill for a task. If you
|
|
|
11
11
|
|
|
12
12
|
- [Writing Skills](../../contributing/skills.md) - Contributor guide to skill authoring, contracts, and governance.
|
|
13
13
|
- [Docs Workflows](../../docs-tooling/workflows.md) - How docs CLI helpers and docs skills work together.
|
|
14
|
+
- [Explainer Kit](explainer-kit.md) - Core and OAT adapter usage, recipes, themes, lifecycle policy, durability, and publishing.
|
|
14
15
|
- [Repo Improve](repo-improve.md) - Source modes, external-plan boundaries, optional tracking, and OAT import handoff.
|
|
15
16
|
|
|
16
17
|
## Key Skills by Use Case
|
|
@@ -25,6 +26,7 @@ Use this section when you want to choose the right OAT skill for a task. If you
|
|
|
25
26
|
- Capture a scoped, shippable backlog item: `oat-pjm-add-backlog-item` directly when the work is already scoped, or `oat-brainstorm` when the thought hasn't converged yet — the brainstorm dispatcher's "scoped backlog item" destination pre-fills the title / description / acceptance criteria / scope estimate / priority from the conversation and then runs `oat-pjm-add-backlog-item` with confirmed inputs
|
|
26
27
|
- Manage the repo backlog and reference docs: `oat-pjm-update-repo-reference`, `oat-pjm-review-backlog`
|
|
27
28
|
- Turn a repo audit, maintainability review, backlog review, backlog directory, or backlog item into standalone external implementation plans: `oat-repo-improve`. Plans land under `.oat/repo/reference/external-plans/`; execute them directly or optionally pass one to `oat-project-import-plan` for tracked OAT execution.
|
|
29
|
+
- Build visual project explainers and final project recaps: `oat-explainer-kit`, backed by the destination-neutral `explainer-kit` core. See [Explainer Kit](explainer-kit.md).
|
|
28
30
|
- Work on docs surfaces: `authoring-docs` (general documentation baseline), `oat-docs-authoring` (targeted OAT/Fumadocs authoring), `oat-docs-bootstrap` (guided bootstrap of a new docs app), `oat-docs-analyze`, `oat-docs-apply`, and `oat-project-document`
|
|
29
31
|
- Generate a shipping digest or scheduled recap: `oat-wrap-up`
|
|
30
32
|
- Run a wave program over a corpus of external plans: `oat-wave-program` (durable program artifact: new/refresh/wave-close) and `oat-wave-execute` (one wave as a wrapper project) — see [Wave Workflows](../wave-workflows.md)
|
|
@@ -70,6 +72,7 @@ Use this section when you want to choose the right OAT skill for a task. If you
|
|
|
70
72
|
- `oat-project-pr-progress`
|
|
71
73
|
- `oat-project-pr-final`
|
|
72
74
|
- `oat-project-document`
|
|
75
|
+
- `oat-explainer-kit`
|
|
73
76
|
- `oat-wrap-up`
|
|
74
77
|
- `oat-project-complete`
|
|
75
78
|
- `oat-wave-program`
|
|
@@ -120,6 +123,7 @@ Use this section when you want to choose the right OAT skill for a task. If you
|
|
|
120
123
|
|
|
121
124
|
=== "Scaffolding and utility"
|
|
122
125
|
|
|
126
|
+
- `explainer-kit`
|
|
123
127
|
- `oat-worktree-bootstrap`
|
|
124
128
|
- `oat-worktree-bootstrap-auto`
|
|
125
129
|
- `create-oat-skill`
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
> when the installed CLI lacks the support; the JUDGMENT gates (STEP 4-6) always need you.
|
|
23
23
|
>
|
|
24
24
|
> **Non-negotiable safety rules — read before doing anything:**
|
|
25
|
+
>
|
|
25
26
|
> 1. **Dry-run first, always.** Produce the full plan and the two judgment proposals BEFORE
|
|
26
27
|
> any write. Do not write/move/delete until the user explicitly approves.
|
|
27
28
|
> 2. **Idempotent.** If the repo is already in the new shape, report that and stop.
|
|
@@ -231,6 +232,7 @@ Decision / Consequences exactly as they appeared>
|
|
|
231
232
|
```
|
|
232
233
|
|
|
233
234
|
Rules:
|
|
235
|
+
|
|
234
236
|
- **Preserve the body byte-for-byte** (minus the heading line, which becomes `title`/the
|
|
235
237
|
frontmatter). Do not summarize or reformat.
|
|
236
238
|
- `legacy_id` keeps the original `ADR-NNN`/`DR-NNN` so inbound references still resolve.
|
|
@@ -270,6 +272,7 @@ proposals, operator-steps, profile-baselines, rollouts, wrap-ups, technical`, pl
|
|
|
270
272
|
non-canonical `*.md` in the reference root.
|
|
271
273
|
|
|
272
274
|
For each, infer a classification by skimming its contents:
|
|
275
|
+
|
|
273
276
|
- **Project-scoped** (content is about one specific project/feature) → propose moving into
|
|
274
277
|
that project's reference dir: `.oat/projects/<scope>/<project>/reference/`.
|
|
275
278
|
- **Repo-wide / durable** → propose the canonical destination:
|
|
@@ -291,6 +294,7 @@ For each, infer a classification by skimming its contents:
|
|
|
291
294
|
```
|
|
292
295
|
|
|
293
296
|
Rules:
|
|
297
|
+
|
|
294
298
|
- Ambiguous/unknown → default to **"leave in place, flag"**, never guess.
|
|
295
299
|
- After the user confirms, `git mv` each approved row. Skip rows the user rejects.
|
|
296
300
|
- Optional canonical folders (`research/`, `brainstorms/`, `external-plans/`, `decks/`) are
|
|
@@ -389,6 +393,7 @@ optional folders are created on demand, not pre-created.
|
|
|
389
393
|
be left, refreshed for the two-layer layout, or archived under `reference/archive/`.
|
|
390
394
|
|
|
391
395
|
## IDs
|
|
396
|
+
|
|
392
397
|
- Decisions: `DR-YYMMDD-slug`. Backlog: `BL-YYMMDD-slug`. **ID == filename stem.** The `YYMMDD`
|
|
393
398
|
prefix gives chronological + file-explorer ordering. Allocator-free (no scan, no counter):
|
|
394
399
|
collision only on same-day + same-slug. Migrated records keep their original id in `legacy_id:`.
|
|
@@ -396,14 +401,17 @@ optional folders are created on demand, not pre-created.
|
|
|
396
401
|
(`a, an, the, of, for, and, to, in, on, as, with`) trimmed, so choose concise, meaningful titles.
|
|
397
402
|
|
|
398
403
|
## Skill / content DESTINATIONS
|
|
404
|
+
|
|
399
405
|
- `oat-brainstorm` → `reference/brainstorms/`
|
|
400
406
|
- `oat project import-plan` → `reference/external-plans/` (already its target)
|
|
401
407
|
- research / deep-research → `reference/research/`
|
|
402
408
|
|
|
403
409
|
## Generated indexes — regenerate on conflict
|
|
410
|
+
|
|
404
411
|
`pjm/backlog/index.md` and `reference/decisions/index.md` are generated and COMMITTED (not
|
|
405
412
|
gitignored, no merge driver). They render deterministically from the record files. On a merge
|
|
406
413
|
conflict: run the regenerate command, then `git add`:
|
|
414
|
+
|
|
407
415
|
- backlog: `oat backlog regenerate-index`
|
|
408
416
|
- decisions: `oat decision regenerate-index`
|
|
409
417
|
|
|
@@ -470,6 +478,7 @@ test -f .oat/repo/README.md && echo "present: README.md (allowed by doctor; leav
|
|
|
470
478
|
> (see STEP 4.5) — report it, don't flag it as broken.
|
|
471
479
|
|
|
472
480
|
**Print the final migration report** covering:
|
|
481
|
+
|
|
473
482
|
- files moved (old → new), backlog items re-id'd (old id → new id, any date fallback used),
|
|
474
483
|
- decisions split (old ADR/DR → new `DR-YYMMDD-slug`, count parity),
|
|
475
484
|
- ad-hoc folders reconciled (confirmed destinations),
|
|
@@ -497,4 +506,7 @@ test -f .oat/repo/README.md && echo "present: README.md (allowed by doctor; leav
|
|
|
497
506
|
- Treat `.oat/projects/**` writes (project-scoped folder moves) as confirmed-only.
|
|
498
507
|
- This prompt is safe to re-run: STEP 0's idempotency probe short-circuits an
|
|
499
508
|
already-migrated repo.
|
|
509
|
+
|
|
510
|
+
```
|
|
511
|
+
|
|
500
512
|
```
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: explainer-kit
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: Use when building destination-neutral visual explainer artifacts from explicit, versioned inputs.
|
|
5
|
+
user-invocable: true
|
|
6
|
+
allowed-tools: Read, Write, Edit, Bash, Grep, Glob, Agent, mcp__*
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Explainer Kit
|
|
10
|
+
|
|
11
|
+
Build visual explainer artifact sets from explicit inputs without reading OAT,
|
|
12
|
+
user, vault, or destination configuration.
|
|
13
|
+
|
|
14
|
+
## Responsibilities
|
|
15
|
+
|
|
16
|
+
- Validate versioned run, source, theme, artifact, durability, and publishing
|
|
17
|
+
contracts.
|
|
18
|
+
- Reconcile one cited fact base before producing narrative content.
|
|
19
|
+
- Render neutral, self-contained artifacts from bundled recipes and templates.
|
|
20
|
+
- Record build outcomes and verify caller-supplied durability evidence.
|
|
21
|
+
- Publish only through an explicitly requested, human-gated connector.
|
|
22
|
+
|
|
23
|
+
## Dependency Direction
|
|
24
|
+
|
|
25
|
+
This skill is the canonical core. It must not depend on `oat-explainer-kit` or
|
|
26
|
+
OAT project state. Adapters and private wrappers may construct a core run
|
|
27
|
+
request and consume its manifest, build record, and optional publish receipt.
|
|
28
|
+
|
|
29
|
+
## Wrapper Extension Seam
|
|
30
|
+
|
|
31
|
+
Wrappers own private pre-resolution and post-run work. They resolve presets,
|
|
32
|
+
vaults, external documents, and personal destinations before translating the
|
|
33
|
+
result into one `ExplainerRunRequestV1`; after the core run, they consume the
|
|
34
|
+
versioned manifest and optional receipt to create links or companion records.
|
|
35
|
+
They must not inject private work between core stages or expose private lanes as
|
|
36
|
+
public config. See `references/extension-contract.md` for the frozen sequence,
|
|
37
|
+
version policy, and compatibility fixture.
|
|
38
|
+
|
|
39
|
+
## Asset Resolution
|
|
40
|
+
|
|
41
|
+
Resolve schemas, recipes, templates, scripts, examples, and references relative
|
|
42
|
+
to this installed skill directory. Never resolve runtime assets from a source
|
|
43
|
+
checkout or from absolute operator-specific paths.
|
|
44
|
+
|
|
45
|
+
## Core Run
|
|
46
|
+
|
|
47
|
+
Construct a complete `ExplainerRunRequestV1`, then invoke the packaged core:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
node scripts/run.mjs --request /path/to/request.json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The core composes validation, fact-base processing, bounded recipe/content
|
|
54
|
+
discovery, theme resolution, rendering, QA, and manifest/build-record
|
|
55
|
+
persistence. It runs without OAT files or ambient configuration. Supplied fact
|
|
56
|
+
bases receive only lightweight consistency/freshness checks. Federated inputs
|
|
57
|
+
require a provider-neutral critic callback and invoke it exactly once.
|
|
58
|
+
|
|
59
|
+
Unattended calls use explicit, already-approved source artifacts, persist their
|
|
60
|
+
review provenance in `source/content-approval.json`, and never prompt.
|
|
61
|
+
|
|
62
|
+
Interactive runs stop with an `incomplete` outcome after writing
|
|
63
|
+
`source/content/*.md`. Review and correct that Markdown, then provide an
|
|
64
|
+
explicit JSON decision and rerun the same request:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
node scripts/run.mjs \
|
|
68
|
+
--request /path/to/request.json \
|
|
69
|
+
--reviewed-source /path/to/content-review.json
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
An approval decision resumes the existing run at theme/render; a rejection
|
|
73
|
+
persists its correction list and leaves downstream stages pending. Approval
|
|
74
|
+
does not authorize publishing: a publish request still requires the separate
|
|
75
|
+
human-gated publisher callback. See `references/contracts.md` for source
|
|
76
|
+
formats, callback modules, retained intermediates, and result semantics.
|
|
77
|
+
|
|
78
|
+
Durability and publishing run only when the request selects them and the caller
|
|
79
|
+
supplies the matching callback. The core does not create commits, discover
|
|
80
|
+
destinations, or publish automatically. A successful build remains
|
|
81
|
+
`built-not-durable` until caller-supplied evidence is verified.
|
|
82
|
+
|
|
83
|
+
## Progress Indicators
|
|
84
|
+
|
|
85
|
+
For interactive runs, show a concise banner and stage updates:
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
89
|
+
EXPLAINER KIT
|
|
90
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Report validation, fact-base, content, theme, render, QA, durability, and
|
|
94
|
+
publish stages as they begin and complete. Keep unattended output structured
|
|
95
|
+
and non-interactive.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Signal Relay project explainer
|
|
2
|
+
|
|
3
|
+
## Planned architecture
|
|
4
|
+
|
|
5
|
+
Signed events enter through a narrow HTTP boundary. The service validates each
|
|
6
|
+
envelope before placing it on a durable queue; workers own downstream delivery
|
|
7
|
+
and isolate exhausted retries in a review queue.
|
|
8
|
+
|
|
9
|
+
## Decisions
|
|
10
|
+
|
|
11
|
+
- Keep ingestion stateless so instances can scale independently.
|
|
12
|
+
- Persist accepted events before acknowledging them.
|
|
13
|
+
- Use bounded retries and a separate review queue instead of retrying forever.
|
|
14
|
+
|
|
15
|
+
## Risks
|
|
16
|
+
|
|
17
|
+
The primary risk is an incompatible producer envelope. Contract tests and a
|
|
18
|
+
shadow-ingestion period detect that drift before cutover.
|
|
19
|
+
|
|
20
|
+
## Phases
|
|
21
|
+
|
|
22
|
+
1. Validate contracts against fixtures.
|
|
23
|
+
2. Run shadow ingestion without downstream delivery.
|
|
24
|
+
3. Enable canary delivery and compare outcomes.
|
|
25
|
+
4. Move remaining traffic after recovery drills pass.
|
|
26
|
+
|
|
27
|
+
## Validation approach
|
|
28
|
+
|
|
29
|
+
The release gate combines contract tests, duplicate-delivery tests, queue
|
|
30
|
+
recovery drills, and operator sign-off. Supporting evidence is linked from
|
|
31
|
+
[the example validation plan](https://docs.example.com/signal-relay/validation).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Example fact base: Signal Relay
|
|
2
|
+
|
|
3
|
+
This fictional example demonstrates a pre-implementation project explainer. All
|
|
4
|
+
organizations, systems, and links are illustrative.
|
|
5
|
+
|
|
6
|
+
## Reconciled claims
|
|
7
|
+
|
|
8
|
+
- **F-001 — Planned architecture:** The relay accepts signed events, validates
|
|
9
|
+
their envelopes, and writes accepted events to a durable queue.
|
|
10
|
+
Source: [architecture proposal](https://docs.example.com/signal-relay/architecture).
|
|
11
|
+
- **F-002 — Delivery:** Workers retry transient delivery failures with bounded
|
|
12
|
+
backoff and move exhausted events to a review queue.
|
|
13
|
+
Source: [delivery design](https://docs.example.com/signal-relay/delivery).
|
|
14
|
+
- **F-003 — Validation:** Contract, retry, and recovery tests must pass before
|
|
15
|
+
traffic can move from the existing path.
|
|
16
|
+
Source: [validation plan](https://docs.example.com/signal-relay/validation).
|
|
17
|
+
|
|
18
|
+
## Reconciliation notes
|
|
19
|
+
|
|
20
|
+
The proposal gives the queue ownership to the platform team while an older
|
|
21
|
+
meeting note assigns it to the application team. The proposal is newer, so
|
|
22
|
+
F-001 follows it and records the older assignment as superseded.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Atlas Index project recap
|
|
2
|
+
|
|
3
|
+
## Original request
|
|
4
|
+
|
|
5
|
+
Replace the nightly full rebuild with incremental indexing without changing the
|
|
6
|
+
public query contract.
|
|
7
|
+
|
|
8
|
+
## Key agent decisions
|
|
9
|
+
|
|
10
|
+
- Use partition-local checkpoints to bound replay.
|
|
11
|
+
- Make index writes idempotent before enabling automatic retries.
|
|
12
|
+
- Retain the full rebuild as a documented recovery path.
|
|
13
|
+
|
|
14
|
+
## As-built architecture
|
|
15
|
+
|
|
16
|
+
A change reader resumes from each partition checkpoint and hands batches to
|
|
17
|
+
idempotent workers. A scheduled audit compares source and index samples and
|
|
18
|
+
raises a recovery task when drift exceeds the accepted threshold.
|
|
19
|
+
|
|
20
|
+
## Implementation record
|
|
21
|
+
|
|
22
|
+
The team delivered checkpoint persistence, replay-safe workers, audit reporting,
|
|
23
|
+
and the recovery runbook in three sequential milestones.
|
|
24
|
+
|
|
25
|
+
## Validation evidence
|
|
26
|
+
|
|
27
|
+
Contract tests, interrupted-restart tests, duplicate-batch tests, and sampled
|
|
28
|
+
parity checks passed. See the fictional
|
|
29
|
+
[evidence index](https://docs.example.com/atlas-index/evidence).
|
|
30
|
+
|
|
31
|
+
## Outcome
|
|
32
|
+
|
|
33
|
+
Incremental indexing is active. The nightly rebuild is no longer part of normal
|
|
34
|
+
operation and remains documented for recovery only.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Example fact base: Atlas Index recap
|
|
2
|
+
|
|
3
|
+
This fictional fact base demonstrates a completed-project recap.
|
|
4
|
+
|
|
5
|
+
## Reconciled claims
|
|
6
|
+
|
|
7
|
+
- **F-101 — Request:** Replace a nightly full rebuild with incremental indexing
|
|
8
|
+
while preserving the existing query contract.
|
|
9
|
+
Source: [approved request](https://docs.example.com/atlas-index/request).
|
|
10
|
+
- **F-102 — As built:** A checkpointed change reader feeds idempotent index
|
|
11
|
+
workers; a scheduled audit detects drift.
|
|
12
|
+
Source: [as-built record](https://docs.example.com/atlas-index/as-built).
|
|
13
|
+
- **F-103 — Validation:** Contract, restart, and sampled parity checks passed.
|
|
14
|
+
Source: [validation evidence](https://docs.example.com/atlas-index/evidence).
|
|
15
|
+
- **F-104 — Outcome:** Incremental indexing is active and the nightly rebuild
|
|
16
|
+
remains available only as a recovery procedure.
|
|
17
|
+
Source: [outcome record](https://docs.example.com/atlas-index/outcome).
|
|
18
|
+
|
|
19
|
+
## Reconciliation notes
|
|
20
|
+
|
|
21
|
+
An early plan proposed one shared checkpoint. Implementation evidence records a
|
|
22
|
+
checkpoint per partition, so F-102 treats the implementation as authoritative.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "explainer-kit.theme/v1",
|
|
3
|
+
"name": "neutral-clean",
|
|
4
|
+
"defaultMode": "light",
|
|
5
|
+
"modes": {
|
|
6
|
+
"light": {
|
|
7
|
+
"surface": {
|
|
8
|
+
"canvas": "#ffffff",
|
|
9
|
+
"panel": "#f3f4f6",
|
|
10
|
+
"elevated": "#e5e7eb"
|
|
11
|
+
},
|
|
12
|
+
"ink": { "primary": "#111827", "muted": "#4b5563", "inverse": "#ffffff" },
|
|
13
|
+
"accent": { "primary": "#374151", "secondary": "#4b5563" },
|
|
14
|
+
"status": {
|
|
15
|
+
"success": "#166534",
|
|
16
|
+
"warning": "#854d0e",
|
|
17
|
+
"danger": "#991b1b",
|
|
18
|
+
"info": "#1e40af"
|
|
19
|
+
},
|
|
20
|
+
"diagramSeries": ["#374151", "#1e40af", "#166534", "#854d0e"]
|
|
21
|
+
},
|
|
22
|
+
"dark": {
|
|
23
|
+
"surface": {
|
|
24
|
+
"canvas": "#111827",
|
|
25
|
+
"panel": "#1f2937",
|
|
26
|
+
"elevated": "#374151"
|
|
27
|
+
},
|
|
28
|
+
"ink": { "primary": "#f9fafb", "muted": "#d1d5db", "inverse": "#111827" },
|
|
29
|
+
"accent": { "primary": "#d1d5db", "secondary": "#e5e7eb" },
|
|
30
|
+
"status": {
|
|
31
|
+
"success": "#86efac",
|
|
32
|
+
"warning": "#fde047",
|
|
33
|
+
"danger": "#fca5a5",
|
|
34
|
+
"info": "#93c5fd"
|
|
35
|
+
},
|
|
36
|
+
"diagramSeries": ["#d1d5db", "#93c5fd", "#86efac", "#fde047"]
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"provenance": {
|
|
40
|
+
"palette": "neutral",
|
|
41
|
+
"visualProfile": "clean",
|
|
42
|
+
"derived": false
|
|
43
|
+
},
|
|
44
|
+
"typography": {
|
|
45
|
+
"sans": ["system-ui", "-apple-system", "BlinkMacSystemFont", "sans-serif"],
|
|
46
|
+
"serif": ["ui-serif", "Georgia", "serif"],
|
|
47
|
+
"mono": ["ui-monospace", "SFMono-Regular", "Consolas", "monospace"],
|
|
48
|
+
"scale": {
|
|
49
|
+
"caption": "0.875rem",
|
|
50
|
+
"body": "1rem",
|
|
51
|
+
"title": "1.5rem",
|
|
52
|
+
"display": "2.25rem"
|
|
53
|
+
},
|
|
54
|
+
"lineHeight": { "caption": 1.4, "body": 1.6, "title": 1.25, "display": 1.1 }
|
|
55
|
+
},
|
|
56
|
+
"spacing": {
|
|
57
|
+
"unit": 4,
|
|
58
|
+
"scale": { "xs": 4, "sm": 8, "md": 16, "lg": 24, "xl": 40 }
|
|
59
|
+
},
|
|
60
|
+
"geometry": {
|
|
61
|
+
"radius": { "sm": 4, "md": 8, "lg": 12 },
|
|
62
|
+
"borderWidth": 1
|
|
63
|
+
},
|
|
64
|
+
"elevation": {
|
|
65
|
+
"shadows": {
|
|
66
|
+
"low": "0 1px 2px rgb(0 0 0 / 0.08)",
|
|
67
|
+
"high": "0 12px 28px rgb(0 0 0 / 0.16)"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"density": "comfortable",
|
|
71
|
+
"motion": {
|
|
72
|
+
"enabled": true,
|
|
73
|
+
"durationMs": { "fast": 120, "normal": 200, "slow": 320 },
|
|
74
|
+
"easing": {
|
|
75
|
+
"standard": "ease",
|
|
76
|
+
"emphasized": "cubic-bezier(0.2, 0, 0, 1)"
|
|
77
|
+
},
|
|
78
|
+
"reducedMotion": "disable-nonessential"
|
|
79
|
+
},
|
|
80
|
+
"diagrams": {
|
|
81
|
+
"lineWidth": 2,
|
|
82
|
+
"nodeGap": 32,
|
|
83
|
+
"arrowStyle": "straight",
|
|
84
|
+
"labelTreatment": "boxed"
|
|
85
|
+
},
|
|
86
|
+
"bundleHash": "sha256:7e7b935c2a6d1603fe4e9fb6bdd32859d3a8fc558db38a7b3289d78e8c1396b3"
|
|
87
|
+
}
|