@delete101020/aidlc 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTOMATION.md +148 -0
- package/README.md +684 -0
- package/dist/assets/annotate-artifact.skill.md +121 -0
- package/dist/assets/epic-context.skill.md +55 -0
- package/dist/bundle.js +49470 -0
- package/dist/templates/ainative/agents/native-engineer.md +66 -0
- package/dist/templates/ainative/agents/native-operator.md +71 -0
- package/dist/templates/ainative/agents/native-originator.md +56 -0
- package/dist/templates/ainative/agents/native-product-owner.md +68 -0
- package/dist/templates/ainative/agents/native-reviewer.md +65 -0
- package/dist/templates/ainative/agents/native-verifier.md +58 -0
- package/dist/templates/ainative/artifacts/build-plan.md +56 -0
- package/dist/templates/ainative/artifacts/implement.md +55 -0
- package/dist/templates/ainative/artifacts/intent.md +50 -0
- package/dist/templates/ainative/artifacts/maintain.md +85 -0
- package/dist/templates/ainative/artifacts/review.md +68 -0
- package/dist/templates/ainative/artifacts/spec.md +69 -0
- package/dist/templates/ainative/artifacts/verify.md +55 -0
- package/dist/templates/ainative/skills/native-build-plan.md +74 -0
- package/dist/templates/ainative/skills/native-implement.md +62 -0
- package/dist/templates/ainative/skills/native-intent.md +50 -0
- package/dist/templates/ainative/skills/native-maintain.md +94 -0
- package/dist/templates/ainative/skills/native-review.md +82 -0
- package/dist/templates/ainative/skills/native-spec.md +83 -0
- package/dist/templates/ainative/skills/native-verify.md +60 -0
- package/dist/templates/sdlc/agents/designer.md +87 -0
- package/dist/templates/sdlc/agents/developer.md +178 -0
- package/dist/templates/sdlc/agents/example-with-skills.md +59 -0
- package/dist/templates/sdlc/agents/orchestrator.md +186 -0
- package/dist/templates/sdlc/agents/po.md +115 -0
- package/dist/templates/sdlc/agents/qa.md +141 -0
- package/dist/templates/sdlc/agents/tech-lead.md +124 -0
- package/dist/templates/sdlc/artifacts/design.md +130 -0
- package/dist/templates/sdlc/artifacts/execute-test.md +64 -0
- package/dist/templates/sdlc/artifacts/implement.backend.md +96 -0
- package/dist/templates/sdlc/artifacts/implement.md +70 -0
- package/dist/templates/sdlc/artifacts/implement.web-react.md +109 -0
- package/dist/templates/sdlc/artifacts/implement.web.md +99 -0
- package/dist/templates/sdlc/artifacts/plan.md +97 -0
- package/dist/templates/sdlc/artifacts/prototype.md +141 -0
- package/dist/templates/sdlc/artifacts/test-cases.md +47 -0
- package/dist/templates/sdlc/artifacts/test-plan.md +100 -0
- package/dist/templates/sdlc/artifacts/unit-test.md +32 -0
- package/dist/templates/sdlc/profiles/agile-lite.yaml +29 -0
- package/dist/templates/sdlc/profiles/hybrid.yaml +43 -0
- package/dist/templates/sdlc/profiles/iso-ieee.yaml +67 -0
- package/dist/templates/sdlc/profiles/none.yaml +21 -0
- package/dist/templates/sdlc/skills/advance-epic.md +77 -0
- package/dist/templates/sdlc/skills/analyze-requirements.md +279 -0
- package/dist/templates/sdlc/skills/discovery-gate.md +118 -0
- package/dist/templates/sdlc/skills/execute-test.md +74 -0
- package/dist/templates/sdlc/skills/generate-test-cases.md +77 -0
- package/dist/templates/sdlc/skills/implement.md +74 -0
- package/dist/templates/sdlc/skills/prd.md +114 -0
- package/dist/templates/sdlc/skills/prototype.md +128 -0
- package/dist/templates/sdlc/skills/tech-design.md +134 -0
- package/dist/templates/sdlc/skills/test-plan.md +115 -0
- package/dist/templates/sdlc/skills/test-report.md +38 -0
- package/dist/templates/sdlc/skills/unit-test.md +43 -0
- package/dist/templates/sdlc/validators/ci.mjs +49 -0
- package/dist/templates/sdlc/validators/traceability.mjs +244 -0
- package/dist/templates/speckit/agents/analyst.md +42 -0
- package/dist/templates/speckit/agents/speckit-developer.md +36 -0
- package/dist/templates/speckit/agents/speckit-qa.md +38 -0
- package/dist/templates/speckit/agents/speckit-tech-lead.md +40 -0
- package/dist/templates/speckit/artifacts/analyze.md +48 -0
- package/dist/templates/speckit/artifacts/clarify.md +64 -0
- package/dist/templates/speckit/artifacts/plan.md +57 -0
- package/dist/templates/speckit/artifacts/specify.md +64 -0
- package/dist/templates/speckit/artifacts/tasks.md +33 -0
- package/dist/templates/speckit/skills/analyze.md +50 -0
- package/dist/templates/speckit/skills/clarify.md +31 -0
- package/dist/templates/speckit/skills/plan.md +56 -0
- package/dist/templates/speckit/skills/specify.md +52 -0
- package/dist/templates/speckit/skills/speckit-implement.md +33 -0
- package/dist/templates/speckit/skills/tasks.md +38 -0
- package/dist/tools/epic-memory-hook.mjs +78 -0
- package/dist/tools/epic-memory.mjs +130 -0
- package/dist/tools/md-to-html.mjs +478 -0
- package/dist/tools/vendor/marked.esm.mjs +2432 -0
- package/dist/vendor/annotron/LICENSE +21 -0
- package/dist/vendor/annotron/README.md +213 -0
- package/dist/vendor/annotron/bin/annotron +467 -0
- package/dist/vendor/annotron/commands/annotron.md +11 -0
- package/dist/vendor/annotron/hooks/annotron-hook.sh +38 -0
- package/dist/vendor/annotron/hooks/hooks.json +50 -0
- package/dist/vendor/annotron/package.json +72 -0
- package/dist/vendor/annotron/skills/annotron-review/SKILL.md +86 -0
- package/dist/vendor/annotron/src/chrome.html +2029 -0
- package/dist/vendor/annotron/src/mdRender.js +208 -0
- package/dist/vendor/annotron/src/sdk.js +1042 -0
- package/dist/vendor/annotron/src/server.js +780 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
# @delete101020/aidlc
|
|
2
|
+
|
|
3
|
+
[](https://github.com/delete101020/ai-native-sdlc/blob/main/LICENSE)
|
|
4
|
+
[](https://www.npmjs.com/package/@delete101020/aidlc)
|
|
5
|
+
|
|
6
|
+
Terminal CLI for AIDLC — drives Claude through pipelines you declare in
|
|
7
|
+
`.aidlc/workspace.yaml`. Manages the workspace, executes runs end-to-end via
|
|
8
|
+
the `claude` CLI, and shares state with the VS Code extension over the
|
|
9
|
+
filesystem (no daemon, no IPC).
|
|
10
|
+
|
|
11
|
+
**Claude only.** The CLI shells out to `claude --print --append-system-prompt
|
|
12
|
+
<skill>`. No Anthropic SDK calls, no other model runners.
|
|
13
|
+
|
|
14
|
+
### New in 0.8
|
|
15
|
+
|
|
16
|
+
`aidlc globals install` now also installs the **artifact annotation** tooling under
|
|
17
|
+
`~/.claude` — a zero-dependency Markdown→HTML renderer, a vendored
|
|
18
|
+
[annotron](https://www.npmjs.com/package/annotron) review editor (no global install), a
|
|
19
|
+
per-epic **memory** tool, and the `/annotate-artifact` + `/epic-context` skills. Review epic
|
|
20
|
+
artifacts in a browser and apply feedback back to the Markdown — from a plain terminal +
|
|
21
|
+
Claude Code, no VS Code required. Optional `aidlc globals memory-hook enable` auto-loads an
|
|
22
|
+
epic's memory whenever a prompt mentions it. See the [`globals`](#globals--built-in-workflow-agents--skills-under-claude) command.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
The CLI of **AIDLC Native**, a fork of [`aidlc-io/aidlc`](https://github.com/aidlc-io/aidlc)
|
|
27
|
+
(not affiliated with the upstream author). The package is scoped because the
|
|
28
|
+
upstream owns `aidlc` on npm; the command it installs is still `aidlc`:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npm install -g @delete101020/aidlc
|
|
32
|
+
aidlc --version
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If the upstream `aidlc` package is installed globally, `npm uninstall -g aidlc`
|
|
36
|
+
first — both provide the `aidlc` command.
|
|
37
|
+
|
|
38
|
+
To run unreleased changes, build it from the repo:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
pnpm install # at repo root
|
|
42
|
+
pnpm -r compile
|
|
43
|
+
cd packages/cli && pnpm bundle && npm link # makes `aidlc` available globally
|
|
44
|
+
aidlc --version # 3.5.1
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`npm link` points at the working tree, so a later `pnpm bundle` is enough to
|
|
48
|
+
pick up changes — no reinstall.
|
|
49
|
+
|
|
50
|
+
## Prerequisites
|
|
51
|
+
|
|
52
|
+
- **Node.js ≥ 18**
|
|
53
|
+
- **`claude` CLI** on PATH — install from https://github.com/anthropics/claude-code
|
|
54
|
+
- **Authentication** — any mode Claude Code supports: `claude login`, `ANTHROPIC_API_KEY`,
|
|
55
|
+
AWS Bedrock (`CLAUDE_CODE_USE_BEDROCK=1` + AWS profile/credentials), Google Vertex
|
|
56
|
+
(`CLAUDE_CODE_USE_VERTEX=1`), or a gateway `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_BASE_URL`
|
|
57
|
+
|
|
58
|
+
Run `aidlc doctor` to verify all of the above.
|
|
59
|
+
|
|
60
|
+
## Five-minute walkthrough
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
# 1. New workspace from scratch
|
|
64
|
+
mkdir my-pipeline && cd my-pipeline
|
|
65
|
+
aidlc init
|
|
66
|
+
aidlc doctor # confirm claude is wired up
|
|
67
|
+
|
|
68
|
+
# 2. Drop in a built-in preset (or build manually with skill/agent/pipeline add)
|
|
69
|
+
aidlc preset apply code-review
|
|
70
|
+
aidlc list # see the agents, skills, pipeline you got
|
|
71
|
+
|
|
72
|
+
# 3. Kick off a run and let Claude do the work
|
|
73
|
+
aidlc run start review-pipeline --context diff=$(git diff HEAD~1)
|
|
74
|
+
aidlc run exec <runId> # streams claude output, advances on success
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Command reference
|
|
78
|
+
|
|
79
|
+
Global flags available on every subcommand:
|
|
80
|
+
|
|
81
|
+
| Flag | Default | Purpose |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| `-w, --workspace <path>` | `cwd` | Workspace root (containing `.aidlc/`). Also reads `AIDLC_WORKSPACE` env. |
|
|
84
|
+
| `-q, --quiet` | off | Suppress decorative progress output (errors and `--json` still print). |
|
|
85
|
+
|
|
86
|
+
### `guide` — getting-started reference
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
aidlc guide
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Prints a static, no-LLM getting-started card (prerequisites → bootstrap →
|
|
93
|
+
build config → run → watch). Works before any workspace or `claude` exists.
|
|
94
|
+
|
|
95
|
+
### `ask` — ask Claude about AIDLC
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
aidlc ask "how do I start a run?"
|
|
99
|
+
aidlc ask how do I set up the code-review preset
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Asks the local `claude` CLI a question about AIDLC — what it is, how to set it
|
|
103
|
+
up, and which command does what — grounded in a built-in reference so answers
|
|
104
|
+
stay accurate. Needs `claude` on PATH (run `aidlc doctor` to verify); works even
|
|
105
|
+
before a workspace is initialized.
|
|
106
|
+
|
|
107
|
+
### `init` — bootstrap a workspace
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
aidlc init [--name "Workspace Name"]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Creates `.aidlc/workspace.yaml` (commented starter), `.aidlc/skills/`, `.aidlc/runs/`.
|
|
114
|
+
Idempotent — skips anything that already exists.
|
|
115
|
+
|
|
116
|
+
### `doctor` — health check
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
aidlc doctor [--json]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Verifies `workspace.yaml` parses + Zod-validates, `claude` binary is on PATH,
|
|
123
|
+
authentication works, all skill paths exist, custom runner files exist, and
|
|
124
|
+
run-state JSON files are parseable. Exit 1 on any failure (including skill /
|
|
125
|
+
runner / runtime checks). `--json` emits every section as
|
|
126
|
+
`{ ok, failures, sections }` — a parseable CI preflight.
|
|
127
|
+
|
|
128
|
+
### `mcp` — give another CLI the ast-graph server
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
aidlc mcp status
|
|
132
|
+
aidlc mcp register [--runner codex] [--dry-run]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The VS Code extension registers the `ast-graph` MCP server with Claude
|
|
136
|
+
automatically, project-scoped. Codex keeps MCP servers in `~/.codex/config.toml`,
|
|
137
|
+
which is per-user: registering there points every Codex session on the machine
|
|
138
|
+
at this workspace's graph, so it stays an explicit command. `register` copies
|
|
139
|
+
the binary and db path out of the registration Claude already has — run
|
|
140
|
+
**AIDLC Native: Rescan AST Graph** in VS Code once first.
|
|
141
|
+
|
|
142
|
+
### `validate` — schema + cross-reference check
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
aidlc validate [--strict] [--json]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Stricter than the `doctor` workspace section: enumerates every Zod issue with
|
|
149
|
+
its `path[]` for editor jump-to-line. Also reports dangling cross-references
|
|
150
|
+
(a pipeline step naming an undefined agent, an agent listing a missing skill, a
|
|
151
|
+
recipe pointing at an unknown pipeline/step) as warnings. Pass `--strict` to
|
|
152
|
+
exit non-zero on those too — handy as a CI gate. `--json` emits the structured
|
|
153
|
+
result (`{ ok, configPath, counts, refIssues }`).
|
|
154
|
+
|
|
155
|
+
### `list` — print workspace contents
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
aidlc list [--json]
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Pretty table by default, structured JSON for piping into `jq`.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### Skills
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
aidlc skill add --id <id> --template <name> # bundled template (5 available)
|
|
169
|
+
aidlc skill add --id <id> --path .aidlc/skills/my.md # reference your own .md
|
|
170
|
+
aidlc skill list [--json] [--templates] # `--templates` lists the 5 built-ins
|
|
171
|
+
aidlc skill show <id> # prints the rendered .md content
|
|
172
|
+
aidlc skill remove <id> # removes from yaml (does NOT delete .md)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Built-in templates: `hello-world`, `code-reviewer`, `test-converter`,
|
|
176
|
+
`doc-writer`, `release-notes`. Run `aidlc skill list --templates` for a one-line
|
|
177
|
+
description of each.
|
|
178
|
+
|
|
179
|
+
### Agents
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
aidlc agent add --id <id> --name <n> --skill <skillId>
|
|
183
|
+
[--model claude-sonnet-4-5]
|
|
184
|
+
[--capabilities files,github,jira]
|
|
185
|
+
[--description "…"]
|
|
186
|
+
[--runner default|codex|custom] [--runner-path .aidlc/runners/foo.js]
|
|
187
|
+
aidlc agent list [--json]
|
|
188
|
+
aidlc agent show <id>
|
|
189
|
+
aidlc agent remove <id>
|
|
190
|
+
aidlc agent run <id> [--message "…"] [--context k=v,…] [--dry-run]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`agent run` is one-shot — spawns `claude` with the agent's skill + your
|
|
194
|
+
message, streams to stdout, no run state created. Useful for quick checks and
|
|
195
|
+
piping into shell scripts.
|
|
196
|
+
|
|
197
|
+
**Runners.** `default` shells out to `claude`; `codex` shells out to
|
|
198
|
+
`codex exec`; `custom` loads your own `runner_path` module. AIDLC composes the
|
|
199
|
+
same three layers — persona, project instructions, skills — into whichever
|
|
200
|
+
prompt that harness needs, so the phase is the same work either way. What
|
|
201
|
+
differs is what the harness supplies by itself: Claude Code reads `CLAUDE.md`
|
|
202
|
+
and gets it once, Codex is handed `AGENTS.md` (or `CLAUDE.md` when the repo has
|
|
203
|
+
no `AGENTS.md`) inline. `aidlc doctor` prints the resolved layers per agent.
|
|
204
|
+
|
|
205
|
+
Two things do *not* carry across on their own — a tier alias and a price — and
|
|
206
|
+
both are settled in one place, the optional `providers:` block:
|
|
207
|
+
|
|
208
|
+
```yaml
|
|
209
|
+
providers:
|
|
210
|
+
codex:
|
|
211
|
+
model_aliases:
|
|
212
|
+
sonnet: gpt-5-codex # tier → concrete model
|
|
213
|
+
rates:
|
|
214
|
+
"*": { input_per_mtok: 1.25, output_per_mtok: 10.0 } # USD per 1M tokens
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`model_aliases` translates a `model:` value for one runner. Without it, a Claude
|
|
218
|
+
tier alias (`opus` / `sonnet` / `haiku`) resolves to no `--model` at all and the
|
|
219
|
+
provider CLI applies its own default. AIDLC ships **no** built-in tier map: saying
|
|
220
|
+
`sonnet` equals some other vendor's model is a claim about your work that only you
|
|
221
|
+
can make, and a guessed model id fails the run outright.
|
|
222
|
+
|
|
223
|
+
`rates` prices the tokens a CLI reports, for the providers that report tokens
|
|
224
|
+
rather than dollars (Codex does; Claude Code reports a measured
|
|
225
|
+
`total_cost_usd`, which always wins). AIDLC ships **no** built-in prices either —
|
|
226
|
+
a stale rate produces a plausible total instead of failing loudly, and your real
|
|
227
|
+
rate depends on your account. Without rates, a Codex step still sums as $0 and
|
|
228
|
+
`aidlc doctor` names it.
|
|
229
|
+
|
|
230
|
+
Either way the number is labelled: a total containing an estimate prints as
|
|
231
|
+
`≥ ~$2.5000 (includes estimates from declared rates)`, and one missing a step
|
|
232
|
+
entirely says `1 step reported no cost`.
|
|
233
|
+
|
|
234
|
+
### Pipelines
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
aidlc pipeline add --id <id> --steps agent1,agent2,agent3
|
|
238
|
+
[--human-review] # mark all steps as gated
|
|
239
|
+
[--produces "p1.md:p2.md,p3.md"] # colon between steps, comma between artifacts
|
|
240
|
+
[--on-failure stop|continue]
|
|
241
|
+
aidlc pipeline list [--json]
|
|
242
|
+
aidlc pipeline show <id> # numbered step graph
|
|
243
|
+
aidlc pipeline remove <id>
|
|
244
|
+
aidlc pipeline recipes # list task-type recipes (bugfix, refactor, …)
|
|
245
|
+
aidlc pipeline classify "<brief>" # which recipe fits this task
|
|
246
|
+
aidlc pipeline generate # assemble a pipeline from a recipe
|
|
247
|
+
aidlc recipe init # back-fill built-in recipes into older workspaces
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Presets
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
aidlc preset list [--json] # shows built-ins and saved snapshots
|
|
254
|
+
aidlc preset apply <name> # merges into current workspace (no overwrite)
|
|
255
|
+
aidlc preset save <name> # snapshot current workspace to .aidlc/presets/<name>.json
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Built-in presets: `code-review`, `release-notes`, `sdlc` (full 9-phase SDLC
|
|
259
|
+
pipeline ported from the legacy AIDLC).
|
|
260
|
+
|
|
261
|
+
### Epics
|
|
262
|
+
|
|
263
|
+
Mirrors the extension's "Epic Pipeline" panel — reads each epic's `state.json`
|
|
264
|
+
under whatever `state.root` your `workspace.yaml` declares (default
|
|
265
|
+
`docs/epics/`).
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
aidlc epic list [--status pending|in_progress|done|failed] [--json]
|
|
269
|
+
aidlc epic status <id> [--json] # phase-by-phase view
|
|
270
|
+
aidlc epic show <id> # alias for status
|
|
271
|
+
aidlc epic start <id> --brief "…" [--llm] # classify the brief → recipe → assembled pipeline
|
|
272
|
+
aidlc epic start <id> --recipe <recipeId> # or pick the recipe yourself
|
|
273
|
+
aidlc epic start <id> --pipeline <pipelineId> # or use an existing pipeline as-is
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
`epic start` mirrors the extension's smart **Start Epic**: `--brief` classifies
|
|
277
|
+
the requirement into a task-type recipe (heuristic by default, `--llm` for
|
|
278
|
+
model-backed classification) and assembles a right-sized pipeline.
|
|
279
|
+
|
|
280
|
+
In v2 an **epic** is a domain entity persisted on disk (one folder per epic
|
|
281
|
+
with a `state.json`); it's distinct from a pipeline **run**. An epic can exist
|
|
282
|
+
without a run, and a run can exist without an epic — `epic` reads the former,
|
|
283
|
+
`run` / `status` read the latter.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### `maintain` — stage 6, the AI-Native return path
|
|
288
|
+
|
|
289
|
+
Every other stage is entered by a person already looking at the screen. This one
|
|
290
|
+
is entered by an alert, so it has a door a webhook forwarder, a cron job or a
|
|
291
|
+
shell script can open.
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
aidlc maintain --signal signal.json # register the signal as an incident epic
|
|
295
|
+
aidlc maintain --signal - # …or read it from stdin
|
|
296
|
+
aidlc maintain follow-up <incidentEpic> # open the work the diagnosis found
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
A **signal** is five fields, and the schema is the contract — not the transport.
|
|
300
|
+
A human pasting JSON, a Sentry webhook and an OTel threshold rule all fill the
|
|
301
|
+
same shape, so adding a source later is an adapter, never a schema change:
|
|
302
|
+
|
|
303
|
+
```json
|
|
304
|
+
{
|
|
305
|
+
"source": "sentry",
|
|
306
|
+
"observedAt": "2026-08-30T02:14:00Z",
|
|
307
|
+
"symptom": "Checkout returns 500 for saved cards",
|
|
308
|
+
"scope": "~40 users/hour, EU region only",
|
|
309
|
+
"evidence": "TypeError: cannot read property token of undefined"
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
`maintain` scaffolds an epic named after the symptom (`INC-CHECKOUT-RETURNS-500`,
|
|
314
|
+
readable on purpose — the id ends up in a branch name and every later reference)
|
|
315
|
+
and writes the payload to `<epic>/signal.json`, where the `native-maintain` skill
|
|
316
|
+
looks for it. Then `/maintain <epic>` in Claude produces `incident.md`.
|
|
317
|
+
|
|
318
|
+
The split into two commands is not ceremony. Whether a signal deserves five
|
|
319
|
+
stages is a judgment made against the code, and it belongs to the Operator agent
|
|
320
|
+
that runs *between* the two calls — not to the flag that woke it up. When the
|
|
321
|
+
diagnosis does call for work, `follow-up` scaffolds the next epic with its
|
|
322
|
+
`intent.md` already written, reading the signal back from the incident epic:
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
aidlc maintain follow-up INC-CHECKOUT-RETURNS-500 \
|
|
326
|
+
--problem "Customers with a saved card cannot complete a purchase." \
|
|
327
|
+
--who-hurts "Returning EU shoppers paying with a stored card." \
|
|
328
|
+
--done "A saved-card checkout succeeds under the failing condition." \
|
|
329
|
+
--question "Did this start with the 2026-08-29 deploy?"
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Anything you leave out is written into the artifact as an explicit open question
|
|
333
|
+
rather than filled with a plausible sentence — a gap a human can see gets
|
|
334
|
+
answered, a fabricated line gets believed. The new epic starts at **stage 1
|
|
335
|
+
behind its human gate**: an intent written by an agent at 3am from a single alert
|
|
336
|
+
is exactly the kind of document that deserves a person's eyes. Pass
|
|
337
|
+
`--intent <file>` to supply the markdown yourself, `--json` for machine callers.
|
|
338
|
+
|
|
339
|
+
Requires the recipes the AI-Native preset ships (`aidlc preset apply ai-native`).
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
### `analyze` — import requirements
|
|
344
|
+
|
|
345
|
+
Analyzes a requirements source and scaffolds a task breakdown folder
|
|
346
|
+
(`docs/task-breakdowns/REQ-NNN/`). Supports Jira, GitHub Issues, Linear,
|
|
347
|
+
Redmine, or a local file/URL. Runs interactively when options are omitted;
|
|
348
|
+
fully non-interactive with `--source`/`--platform`/`--parent`. Works without a
|
|
349
|
+
`workspace.yaml`.
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
aidlc analyze # interactive wizard
|
|
353
|
+
aidlc analyze --platform jira --parent PROJ-100 -y # Jira epic, skip confirm
|
|
354
|
+
aidlc analyze --source ./requirements.csv --platform redmine --brief
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Options:
|
|
358
|
+
|
|
359
|
+
| Flag | Description |
|
|
360
|
+
|------|-------------|
|
|
361
|
+
| `--source <path-or-url>` | Requirements file path or URL |
|
|
362
|
+
| `--text <text>` | Inline requirements text |
|
|
363
|
+
| `--platform <jira\|github\|linear\|redmine\|local>` | Source platform |
|
|
364
|
+
| `--parent <ref>` | Parent epic/issue ref (Jira epic key, GitHub `owner/repo`, etc.) |
|
|
365
|
+
| `--brief` | Brief task list (titles + 1-line desc, skip ACs/points) |
|
|
366
|
+
| `--instruction <text>` | Custom guidance for task creation |
|
|
367
|
+
| `--id <runId>` | Use this run ID instead of auto-generated REQ-NNN |
|
|
368
|
+
| `-y, --yes` | Skip confirmation prompt |
|
|
369
|
+
|
|
370
|
+
Outputs a `docs/task-breakdowns/REQ-NNN/` folder with the scaffolded breakdown.
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
### `run` — pipeline lifecycle
|
|
375
|
+
|
|
376
|
+
These wrap `@aidlc/core`'s `PipelineRunner` and write atomically through
|
|
377
|
+
`RunStateStore`. The VS Code sidebar updates within ~200ms.
|
|
378
|
+
|
|
379
|
+
```
|
|
380
|
+
aidlc run start <pipelineId> [--id <runId>] [--context k=v ...] [--context-file <path>]
|
|
381
|
+
aidlc run mark-done <runId> # validates produces paths, advances or awaits review
|
|
382
|
+
aidlc run approve <runId> [--comment "…"]
|
|
383
|
+
aidlc run reject <runId> --reason "…"
|
|
384
|
+
aidlc run rerun <runId> [--feedback "…"]
|
|
385
|
+
aidlc run request-update <runId> <step> [--feedback "…"] # reopen an already-approved step for changes
|
|
386
|
+
aidlc run delete <runId> [--force]
|
|
387
|
+
aidlc run open <runId> [--path] # prints state.json content (or just file path)
|
|
388
|
+
aidlc run exec <runId> [--until <step>] [--auto-approve] [--require-complete] [--json] [--dry-run]
|
|
389
|
+
aidlc run verify <runId> [--json] # re-checks recorded artifacts still exist + pass produces_contains
|
|
390
|
+
aidlc run report <runId> [--format md|json] [--output <file>] # shareable run history (Markdown/JSON)
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**Exit codes for `run exec`** (so CI can branch): `0` completed (or stopped at
|
|
394
|
+
`--until`, or `--dry-run`), `2` paused on a gate (awaiting review / rejected /
|
|
395
|
+
budget), `1` error. `--require-complete` maps any non-completed outcome to `1`.
|
|
396
|
+
`--json` prints a final summary object to stdout (claude's stream goes to stderr).
|
|
397
|
+
See [AUTOMATION.md](AUTOMATION.md) for the full headless guide +
|
|
398
|
+
a GitHub Action recipe.
|
|
399
|
+
|
|
400
|
+
**`run verify`** is a read-only post-run drift check: a `completed` run still
|
|
401
|
+
claims its artifacts exist, but someone may have since deleted or gutted one.
|
|
402
|
+
It re-validates every step's recorded `artifactsProduced` (existence + the same
|
|
403
|
+
`produces_contains` markers the gate applied) and exits non-zero when any step
|
|
404
|
+
has drifted — handy as a CI post-check.
|
|
405
|
+
|
|
406
|
+
**`run report`** renders the run history (steps, revisions, durations, reject
|
|
407
|
+
reasons, approve comments, cost when reported) as Markdown to paste into a PR
|
|
408
|
+
description or status update. `--format json` dumps the raw state instead.
|
|
409
|
+
|
|
410
|
+
**`run exec`** is the unique unlock: it spawns `claude` for the current step,
|
|
411
|
+
streams stdout to your terminal, validates the produced artifacts, and advances
|
|
412
|
+
to the next step automatically. Steps declaring `auto_review: true` have their
|
|
413
|
+
`auto_review_runner` validator executed headlessly between produce-validation
|
|
414
|
+
and approval — a `pass` advances the step, a `reject` stops with a rerun hint.
|
|
415
|
+
With `--auto-approve` it also clears `human_review` gates without pausing — a
|
|
416
|
+
single command then drives the entire pipeline end-to-end.
|
|
417
|
+
|
|
418
|
+
**`run request-update`** reopens an already-approved step (bumps its revision,
|
|
419
|
+
resets downstream steps), mirroring the extension's "Request update" action.
|
|
420
|
+
|
|
421
|
+
`run start` defaults `runId` to `<pipelineId>-<timestamp>` if `--id` is omitted.
|
|
422
|
+
|
|
423
|
+
#### Cost guard (`budget`)
|
|
424
|
+
|
|
425
|
+
Because `run exec --auto-approve` can drive a whole pipeline unattended (and a
|
|
426
|
+
self-fixing agent loop can quietly escalate spend), a pipeline may declare an
|
|
427
|
+
optional cost ceiling. After each step the autopilot sums the per-step LLM cost
|
|
428
|
+
and stops once a ceiling is crossed. Manual `mark-done` is never gated.
|
|
429
|
+
|
|
430
|
+
A step's cost is one of three things, and the guard treats them differently:
|
|
431
|
+
|
|
432
|
+
| | Where it comes from | Counts toward the ceiling |
|
|
433
|
+
|---|---|---|
|
|
434
|
+
| **measured** | the CLI reported dollars (`claude`) | yes |
|
|
435
|
+
| **estimated** | tokens × your `providers.<runner>.rates` | yes, and it says so |
|
|
436
|
+
| **blind** | the CLI reported neither | no — it sums as $0 |
|
|
437
|
+
|
|
438
|
+
An estimate is counted because the alternative is a provider with no ceiling at
|
|
439
|
+
all. It is never presented as measured: the running line reads
|
|
440
|
+
`budget: ≥ $2.5000 / $5.00 ($2.2500 estimated; 1 step reported no cost)`.
|
|
441
|
+
|
|
442
|
+
```yaml
|
|
443
|
+
pipelines:
|
|
444
|
+
- id: my-pipeline
|
|
445
|
+
budget:
|
|
446
|
+
max_usd: 5.00 # hard ceiling on cumulative cost for the run
|
|
447
|
+
max_usd_per_step: 1.50 # optional — a single pricey step trips it too
|
|
448
|
+
on_exceed: pause # pause (default) → stop the loop; fail → exit non-zero
|
|
449
|
+
steps: [...]
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
On `pause` the loop stops and you can raise the budget or resume; on `fail` it
|
|
453
|
+
exits non-zero (handy in CI).
|
|
454
|
+
|
|
455
|
+
### `step` — direct step control
|
|
456
|
+
|
|
457
|
+
The `run` commands operate on the current step. `step` operates on **any**
|
|
458
|
+
step regardless of pipeline order, for when reality doesn't match the
|
|
459
|
+
pipeline (work done outside the tool, phases that don't apply this time,
|
|
460
|
+
hopping back to redo something).
|
|
461
|
+
|
|
462
|
+
```
|
|
463
|
+
aidlc step start <runId> <step> # → awaiting_work, moves pointer (demotes the old current step to pending)
|
|
464
|
+
aidlc step done <runId> <step> [--reason "…"] # → approved (no produces validation)
|
|
465
|
+
aidlc step skip <runId> <step> # → approved with skip note
|
|
466
|
+
aidlc step reset <runId> <step> # → pending (no cascade)
|
|
467
|
+
aidlc step set <runId> <step> <status> # raw — any of: pending | awaiting_work | awaiting_review | approved | rejected
|
|
468
|
+
aidlc step jump <runId> <step> # moves pointer + auto-approves earlier pending steps
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
`<step>` accepts a 0-based index (`0`, `1`, `2`) or an agent id (`reviewer`,
|
|
472
|
+
`planner`) — whichever is easier in context.
|
|
473
|
+
|
|
474
|
+
`step done` and `step skip` only advance the pointer when the step they touch
|
|
475
|
+
is the **current** step; touching an earlier step won't drag the pointer
|
|
476
|
+
backward.
|
|
477
|
+
|
|
478
|
+
### `status` — list runs / inspect one
|
|
479
|
+
|
|
480
|
+
```
|
|
481
|
+
aidlc status # all runs in .aidlc/runs/
|
|
482
|
+
aidlc status <runId> # detailed view of one run
|
|
483
|
+
aidlc status [runId] --json # raw RunState JSON
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### `watch` — live re-render of run state
|
|
487
|
+
|
|
488
|
+
Uses `chokidar` on `.aidlc/runs/*.json` with a 150ms debounce. Clears the
|
|
489
|
+
visible terminal area on every redraw (preserves scrollback so you can scroll
|
|
490
|
+
up to past frames).
|
|
491
|
+
|
|
492
|
+
```
|
|
493
|
+
aidlc watch # multi-run table, all runs
|
|
494
|
+
aidlc watch <runId> # single-run focus mode (step pipeline)
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### `tail` — stream state transitions
|
|
498
|
+
|
|
499
|
+
Same chokidar watch as `watch`, but emits one timestamped line per detected
|
|
500
|
+
change instead of redrawing a table. Useful for CI logs or piping.
|
|
501
|
+
|
|
502
|
+
```
|
|
503
|
+
aidlc tail # all runs
|
|
504
|
+
aidlc tail <runId> # one run
|
|
505
|
+
aidlc tail [runId] --json # one NDJSON event per transition (pipe into jq / a notifier)
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
`--json` events: `seed`, `run_new`, `run_status`, `pointer`, `step_status`,
|
|
509
|
+
`step_revision`, `run_gone` — each with `ts` and `runId`.
|
|
510
|
+
|
|
511
|
+
Output shape:
|
|
512
|
+
|
|
513
|
+
```
|
|
514
|
+
[16:42:01] ABC-123 step 0 awaiting_work → approved
|
|
515
|
+
[16:42:01] ABC-123 pointer 0 → 1
|
|
516
|
+
[16:42:01] ABC-123 step 1 pending → awaiting_work
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### `dashboard` — browser UI with action buttons
|
|
520
|
+
|
|
521
|
+
Single-process HTTP server, no build step. Same data as `watch`; adds
|
|
522
|
+
click-to-approve / reject / rerun buttons. Updates push via SSE so the page
|
|
523
|
+
refreshes within ~100ms when files change.
|
|
524
|
+
|
|
525
|
+
```
|
|
526
|
+
aidlc dashboard # http://127.0.0.1:8787
|
|
527
|
+
aidlc dashboard --port 3000
|
|
528
|
+
aidlc dashboard --host 0.0.0.0 # expose on LAN (use with care)
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
Endpoints (handy for scripts): `GET /api/runs`, `GET /api/runs/:id`,
|
|
532
|
+
`POST /api/action`, `GET /events` (SSE).
|
|
533
|
+
|
|
534
|
+
### `monitor` — agent observability via agents-observe
|
|
535
|
+
|
|
536
|
+
Checks the [agents-observe](https://github.com/simple10/agents-observe) plugin
|
|
537
|
+
install, pins a stable data dir in `~/.claude/settings.json` (so the DB survives
|
|
538
|
+
plugin upgrades), and prints live server status.
|
|
539
|
+
|
|
540
|
+
```
|
|
541
|
+
aidlc monitor # status check + pin data dir
|
|
542
|
+
aidlc monitor --start # also launch the server if it's down
|
|
543
|
+
aidlc monitor --open # open the dashboard in your browser
|
|
544
|
+
aidlc monitor --json # machine-readable status (no writes)
|
|
545
|
+
aidlc monitor --dry-run # show the settings.json change, don't write
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
When the plugin isn't installed, `--start` offers to **auto-install** it (with
|
|
549
|
+
confirmation) instead of only printing manual steps; `monitor` also
|
|
550
|
+
distinguishes a plugin that is installed-but-failed-to-load from a healthy one.
|
|
551
|
+
`--start` uses Docker when available, otherwise falls back to the plugin's
|
|
552
|
+
**local** runtime (no Docker required) — in local mode the terminal becomes the
|
|
553
|
+
server's log window, and `npm install` is pinned to the public npm registry so
|
|
554
|
+
it never inherits a private registry default. The extension's **Start Monitor**
|
|
555
|
+
button runs `aidlc monitor --start`.
|
|
556
|
+
|
|
557
|
+
### `globals` — built-in workflow agents + skills under `~/.claude/`
|
|
558
|
+
|
|
559
|
+
Built-in workflows (e.g. the SDLC pipeline) ship agent + skill markdown that
|
|
560
|
+
gets installed under `~/.claude/agents` and `~/.claude/skills` so their skill
|
|
561
|
+
paths resolve. `preset apply sdlc` installs them implicitly; this command group
|
|
562
|
+
manages them explicitly — including `uninstall`, which the extension exposes but
|
|
563
|
+
the CLI previously couldn't do.
|
|
564
|
+
|
|
565
|
+
```
|
|
566
|
+
aidlc globals status [--json] # which built-in workflows are installed globally
|
|
567
|
+
aidlc globals install [ids...] # install (default: the standard workflows)
|
|
568
|
+
aidlc globals uninstall [ids...] # remove AIDLC-marked global files (run before removing the extension)
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
`aidlc globals install` also lays down the **artifact annotation tooling** — the
|
|
572
|
+
zero-dependency Markdown→HTML renderer, a vendored [annotron](https://www.npmjs.com/package/annotron)
|
|
573
|
+
(no global install), the per-epic memory tool, and the `/annotate-artifact` +
|
|
574
|
+
`/epic-context` skills — under `~/.claude`. That makes the browser annotation loop
|
|
575
|
+
and epic memory work from a plain terminal + Claude Code, no VS Code required. It
|
|
576
|
+
never edits your `settings.json` (add `Edit(docs/epics/**)` yourself if you want the
|
|
577
|
+
loop to run without per-write confirmation).
|
|
578
|
+
|
|
579
|
+
`uninstall` only removes files AIDLC wrote (marker-guarded) and preserves files
|
|
580
|
+
still needed by other globally-installed workflows.
|
|
581
|
+
|
|
582
|
+
## Recipes
|
|
583
|
+
|
|
584
|
+
### Drive a complete SDLC pipeline end-to-end
|
|
585
|
+
|
|
586
|
+
```sh
|
|
587
|
+
aidlc preset apply sdlc
|
|
588
|
+
aidlc run start sdlc-pipeline --id ABC-123 --context epic=ABC-123
|
|
589
|
+
aidlc run exec ABC-123 --auto-approve # claude works through every phase
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### Manually mark a phase done that you completed outside AIDLC
|
|
593
|
+
|
|
594
|
+
```sh
|
|
595
|
+
aidlc step done <runId> implement --reason "merged via PR #42"
|
|
596
|
+
aidlc run exec <runId> # resumes from the next step
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### Restart a single phase without cascading
|
|
600
|
+
|
|
601
|
+
```sh
|
|
602
|
+
aidlc step reset <runId> review
|
|
603
|
+
aidlc step start <runId> review # → awaiting_work
|
|
604
|
+
aidlc run exec <runId>
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
### One-shot ask, no run state
|
|
608
|
+
|
|
609
|
+
```sh
|
|
610
|
+
aidlc agent run reviewer --message "Review the diff in /tmp/patch.diff"
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### Pipe runs into another tool
|
|
614
|
+
|
|
615
|
+
```sh
|
|
616
|
+
aidlc list --json | jq '.pipelines[].id'
|
|
617
|
+
aidlc status <runId> --json | jq '.steps[] | select(.status=="rejected")'
|
|
618
|
+
aidlc epic list --json | jq '.[] | select(.status=="in_progress") | .id'
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### Live monitor while a long pipeline runs
|
|
622
|
+
|
|
623
|
+
```sh
|
|
624
|
+
# Terminal 1 — kick off the run, then walk away
|
|
625
|
+
aidlc run start sdlc-pipeline --id ABC-123 --context epic=ABC-123
|
|
626
|
+
aidlc run exec ABC-123 --auto-approve
|
|
627
|
+
|
|
628
|
+
# Terminal 2 — live table
|
|
629
|
+
aidlc watch
|
|
630
|
+
|
|
631
|
+
# Terminal 3 — transition log for grep / save
|
|
632
|
+
aidlc tail | tee run-log.txt
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### Open the browser dashboard
|
|
636
|
+
|
|
637
|
+
```sh
|
|
638
|
+
aidlc dashboard
|
|
639
|
+
# then open http://127.0.0.1:8787
|
|
640
|
+
# click any run → approve / reject / rerun directly from the page
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
## Filesystem layout
|
|
644
|
+
|
|
645
|
+
The CLI never holds in-memory state — everything lives in your workspace:
|
|
646
|
+
|
|
647
|
+
```
|
|
648
|
+
my-project/
|
|
649
|
+
├── .aidlc/
|
|
650
|
+
│ ├── workspace.yaml # agents, skills, pipelines (Zod validated)
|
|
651
|
+
│ ├── skills/ # custom skill .md files
|
|
652
|
+
│ │ └── code-reviewer.md
|
|
653
|
+
│ ├── runs/ # one JSON per run
|
|
654
|
+
│ │ └── ABC-123.json # full RunState (steps, status, context)
|
|
655
|
+
│ └── presets/ # saved workspace snapshots
|
|
656
|
+
│ └── my-preset.json
|
|
657
|
+
└── docs/ # produces paths from your pipelines land here
|
|
658
|
+
└── …
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
Runs and presets are local-only — gitignore `.aidlc/runs/` and
|
|
662
|
+
`.aidlc/presets/` if you want, the rest is meant to be committed.
|
|
663
|
+
|
|
664
|
+
## Troubleshooting
|
|
665
|
+
|
|
666
|
+
| Problem | Likely fix |
|
|
667
|
+
|---|---|
|
|
668
|
+
| `aidlc doctor` says "Not authenticated" | Use any Claude Code auth mode: `claude login`, `ANTHROPIC_API_KEY`, AWS Bedrock (`CLAUDE_CODE_USE_BEDROCK=1` + AWS profile/creds), Vertex (`CLAUDE_CODE_USE_VERTEX=1`), or `ANTHROPIC_AUTH_TOKEN`. doctor now detects all of these. |
|
|
669
|
+
| `aidlc run exec` fails with "missing artifacts" | The agent didn't produce the files declared in `pipeline.steps[].produces`. Check the paths or fix the agent's skill. |
|
|
670
|
+
| `aidlc run start` rejects the runId | RunIds must match `^[A-Za-z0-9][A-Za-z0-9._-]*$`. No spaces, no leading dashes. |
|
|
671
|
+
| Pipeline step appears as a string in YAML, but I edited it as an object | Both forms are valid. The CLI writes string form when there's no metadata, object form when there's `human_review` or `produces`. |
|
|
672
|
+
| A phase on `runner: codex` answers without the graph | Its MCP server is per-user and separate from Claude's. Run `aidlc mcp register --runner codex`, then `aidlc mcp status` to confirm. |
|
|
673
|
+
| Custom runner not loading | `runner_path` must be `.js` / `.cjs` / `.mjs` (no TypeScript yet). Run `aidlc doctor` to check the file resolves. |
|
|
674
|
+
|
|
675
|
+
## Credit
|
|
676
|
+
|
|
677
|
+
Built on [`aidlc-io/aidlc`](https://github.com/aidlc-io/aidlc) by
|
|
678
|
+
[hueanmy](https://github.com/hueanmy). If it saves you time,
|
|
679
|
+
[sponsor the original author](https://github.com/sponsors/hueanmy) ❤️.
|
|
680
|
+
|
|
681
|
+
## License
|
|
682
|
+
|
|
683
|
+
MIT — the original copyright line is kept; this fork's changes are added under
|
|
684
|
+
the same terms.
|