@amsterdamdatalabs/enact-extensions 0.1.5 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +15 -1
- package/dist/install.js.map +1 -1
- package/dist/internal/agents.d.ts +29 -0
- package/dist/internal/agents.d.ts.map +1 -0
- package/dist/internal/agents.js +83 -0
- package/dist/internal/agents.js.map +1 -0
- package/extensions/enact-context/hooks/hooks.json +20 -0
- package/extensions/enact-core/.agents/plugin.json +39 -0
- package/extensions/enact-core/hooks/hooks.json +14 -0
- package/extensions/enact-factory/.agents/plugin.json +9 -3
- package/extensions/enact-factory/agents/architect.toml +30 -0
- package/extensions/enact-factory/agents/code-reviewer.toml +29 -0
- package/extensions/enact-factory/agents/critic.toml +35 -0
- package/extensions/enact-factory/agents/executor.toml +23 -0
- package/extensions/enact-factory/agents/explore.toml +22 -0
- package/extensions/enact-factory/agents/planner.toml +23 -0
- package/extensions/enact-factory/agents/verifier.toml +29 -0
- package/extensions/enact-factory/skills/ai-slop-cleaner/SKILL.md +52 -0
- package/extensions/enact-factory/skills/azdo-ci-strategy/SKILL.md +262 -0
- package/extensions/enact-factory/skills/azdo-ci-strategy/references/build-failures.md +60 -0
- package/extensions/enact-factory/skills/azdo-ci-strategy/references/cli-reference.md +87 -0
- package/extensions/enact-factory/skills/azdo-ci-strategy/references/policies-and-pipelines.md +132 -0
- package/extensions/enact-factory/skills/azdo-ci-strategy/references/troubleshooting.md +53 -0
- package/extensions/enact-factory/skills/deep-interview/SKILL.md +72 -0
- package/extensions/enact-factory/skills/drive-loop/SKILL.md +259 -0
- package/extensions/enact-factory/skills/drive-loop/references/contract-schema.md +107 -0
- package/extensions/enact-factory/skills/hyperplan/SKILL.md +51 -0
- package/extensions/enact-factory/skills/looplan/SKILL.md +103 -0
- package/extensions/enact-factory/skills/plan/SKILL.md +71 -0
- package/extensions/enact-factory/skills/remove-deadcode/SKILL.md +41 -0
- package/extensions/enact-factory/skills/research/SKILL.md +73 -0
- package/extensions/enact-factory/skills/review/SKILL.md +48 -0
- package/extensions/enact-factory/skills/security-research/SKILL.md +54 -0
- package/extensions/enact-factory/skills/tdd/SKILL.md +56 -0
- package/extensions/enact-factory/skills/trace/SKILL.md +37 -0
- package/extensions/enact-factory/skills/ultraqa/SKILL.md +79 -0
- package/extensions/enact-factory/skills/work-with-workitem/SKILL.md +51 -0
- package/extensions/enact-factory/skills/workitem-triage/SKILL.md +15 -0
- package/extensions/enact-loop/.agents/plugin.json +46 -0
- package/extensions/enact-loop/.mcp.json +1 -0
- package/extensions/enact-loop/hooks/hooks.json +27 -0
- package/extensions/enact-loop/skills/enact-loop/SKILL.md +327 -0
- package/extensions/enact-operator/.agents/plugin.json +0 -1
- package/extensions/enact-operator/hooks/hooks.json +0 -35
- package/extensions/enact-wiki/skills/wiki/SKILL.md +42 -0
- package/extensions/plugin-dev/.agents/plugin.json +4 -6
- package/extensions/plugin-dev/agents/plugin-validator.md +1 -1
- package/extensions/plugin-dev/skills/agent-development/SKILL.md +7 -7
- package/extensions/plugin-dev/{commands/create-plugin.md → skills/create-plugin/SKILL.md} +44 -37
- package/extensions/plugin-dev/skills/plugin-dev-guide/SKILL.md +13 -14
- package/extensions/plugin-dev/skills/skill-development/SKILL.md +0 -2
- package/extensions/plugin-dev/{commands/start.md → skills/start/SKILL.md} +7 -6
- package/package.json +11 -6
- package/scripts/check-hooks.mjs +174 -0
- package/scripts/check-principles.mjs +101 -0
- package/scripts/enact-extensions.mjs +87 -3
- package/scripts/lib/run-validate.mjs +36 -2
- package/scripts/lib/ups-router.mjs +432 -0
- package/spec/enact.json +4 -0
- package/spec/enact.md +5 -2
- package/extensions/cmux/.agents/plugin.json +0 -37
- package/extensions/cmux/skills/cmux/SKILL.md +0 -82
- package/extensions/cmux/skills/cmux/agents/openai.yaml +0 -4
- package/extensions/cmux/skills/cmux/references/handles-and-identify.md +0 -35
- package/extensions/cmux/skills/cmux/references/panes-surfaces.md +0 -37
- package/extensions/cmux/skills/cmux/references/trigger-flash-and-health.md +0 -23
- package/extensions/cmux/skills/cmux/references/windows-workspaces.md +0 -31
- package/extensions/cmux/skills/cmux-vm-monitor/SKILL.md +0 -122
- package/extensions/cmux/skills/cmux-vm-monitor/agents/openai.yaml +0 -4
- package/extensions/cmux/skills/cmux-vm-monitor/references/cmux-commands.md +0 -66
- package/extensions/cmux/skills/cmux-vm-monitor/scripts/codex_vm_monitor.sh +0 -45
- package/extensions/cmux/skills/cmux-workspace/SKILL.md +0 -93
- package/extensions/devops/.agents/plugin.json +0 -36
- package/extensions/devops/skills/azure-devops-cli/SKILL.md +0 -431
- package/extensions/devops/skills/azure-devops-cli/agents/openai.yaml +0 -4
- package/extensions/devops/skills/ci-pipeline-strategy/SKILL.md +0 -217
- package/extensions/devops/skills/ci-pipeline-strategy/agents/openai.yaml +0 -4
- package/extensions/enact-factory/hooks/user-prompt-submit.mjs +0 -67
- package/extensions/enact-operator/commands/doctor.md +0 -39
- package/extensions/enact-operator/commands/setup.md +0 -51
- package/extensions/plugin-dev/.mcp.json +0 -3
- package/extensions/plugin-dev/commands/_archive/create-marketplace.md +0 -427
- package/extensions/plugin-dev/commands/_archive/plugin-dev-guide.md +0 -12
- package/extensions/plugin-dev/hooks/hooks.json +0 -3
- package/extensions/plugin-dev/skills/command-development/SKILL.md +0 -763
- package/extensions/plugin-dev/skills/command-development/examples/plugin-commands.md +0 -612
- package/extensions/plugin-dev/skills/command-development/examples/simple-commands.md +0 -527
- package/extensions/plugin-dev/skills/command-development/references/advanced-workflows.md +0 -762
- package/extensions/plugin-dev/skills/command-development/references/documentation-patterns.md +0 -769
- package/extensions/plugin-dev/skills/command-development/references/frontmatter-reference.md +0 -508
- package/extensions/plugin-dev/skills/command-development/references/interactive-commands.md +0 -966
- package/extensions/plugin-dev/skills/command-development/references/marketplace-considerations.md +0 -943
- package/extensions/plugin-dev/skills/command-development/references/plugin-features-reference.md +0 -637
- package/extensions/plugin-dev/skills/command-development/references/plugin-integration.md +0 -191
- package/extensions/plugin-dev/skills/command-development/references/skill-tool.md +0 -447
- package/extensions/plugin-dev/skills/command-development/references/testing-strategies.md +0 -723
- package/extensions/plugin-dev/skills/command-development/scripts/check-frontmatter.sh +0 -234
- package/extensions/plugin-dev/skills/command-development/scripts/validate-command.sh +0 -160
- /package/extensions/enact-operator/{skills/_variants.md → docs/skill-variants.md} +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name = "planner"
|
|
2
|
+
description = "Structured implementation planner that never writes production code"
|
|
3
|
+
model_reasoning_effort = "medium"
|
|
4
|
+
sandbox_mode = "danger-full-access"
|
|
5
|
+
developer_instructions = """
|
|
6
|
+
You are the Enact Loop planner agent.
|
|
7
|
+
|
|
8
|
+
Role:
|
|
9
|
+
- Turn a goal into a small, reviewable execution plan with clear acceptance criteria.
|
|
10
|
+
- You do not implement code.
|
|
11
|
+
|
|
12
|
+
Rules:
|
|
13
|
+
- Never write production code.
|
|
14
|
+
- Prefer 3 to 6 concrete steps.
|
|
15
|
+
- Include dependencies, risks, and verification expectations.
|
|
16
|
+
- Escalate unresolved product-direction choices instead of guessing.
|
|
17
|
+
|
|
18
|
+
Output contract:
|
|
19
|
+
- plan_summary
|
|
20
|
+
- steps
|
|
21
|
+
- acceptance_criteria
|
|
22
|
+
- risks_and_open_questions
|
|
23
|
+
"""
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name = "verifier"
|
|
2
|
+
description = "Evidence-first verifier for real-surface QA and completion claims — independent grader"
|
|
3
|
+
model_reasoning_effort = "high"
|
|
4
|
+
sandbox_mode = "danger-full-access"
|
|
5
|
+
tools = "Read, Grep, Glob, Bash"
|
|
6
|
+
developer_instructions = """
|
|
7
|
+
You are the Enact Loop verifier agent. You are an INDEPENDENT GRADER.
|
|
8
|
+
|
|
9
|
+
You run on a different model and vendor from the executor. You must reach your own verdict
|
|
10
|
+
independently — do not defer to the executor's self-assessment. Your verdict is recorded by
|
|
11
|
+
`loop_grader_verdict` and is required before the judgment stage can close.
|
|
12
|
+
|
|
13
|
+
Role:
|
|
14
|
+
- Check whether completion claims are supported by fresh evidence.
|
|
15
|
+
- Focus on commands run, outputs observed, and uncovered gaps.
|
|
16
|
+
|
|
17
|
+
Rules:
|
|
18
|
+
- Never edit files.
|
|
19
|
+
- Do not trust prior claims without rerunning or directly reading evidence.
|
|
20
|
+
- Mark each requirement VERIFIED, PARTIAL, or MISSING.
|
|
21
|
+
- Separate missing evidence from failing behavior.
|
|
22
|
+
- Record your GO/NO-GO verdict via loop_grader_verdict — do not self-report on behalf of the executor.
|
|
23
|
+
|
|
24
|
+
Output contract:
|
|
25
|
+
- verdict: PASS, FAIL, or INCOMPLETE
|
|
26
|
+
- evidence: commands and observed results
|
|
27
|
+
- requirement_matrix
|
|
28
|
+
- remaining_gaps
|
|
29
|
+
"""
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ai-slop-cleaner
|
|
3
|
+
description: "Walk the diff for TODO/placeholder/silent-catch noise and replace each with a concrete implementation or remove it entirely."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AI Slop Cleaner
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Removes low-quality AI-generated residue from code produced in a loop session: `// TODO`,
|
|
11
|
+
"for now", "later", silent empty catch blocks, unreachable fallback layers, and placeholder strings.
|
|
12
|
+
Each removal is replaced with a real implementation or an explicit compile-time error — never just
|
|
13
|
+
deleted.
|
|
14
|
+
|
|
15
|
+
## Use When
|
|
16
|
+
|
|
17
|
+
- after an implementation pass before the loop reaches closure
|
|
18
|
+
- before verification stages run
|
|
19
|
+
- when a diff review reveals TODO comments, "for now" strings, or swallowed exceptions
|
|
20
|
+
|
|
21
|
+
## Workflow
|
|
22
|
+
|
|
23
|
+
1. Identify the files changed in the current session (use `git diff --name-only`).
|
|
24
|
+
2. For each changed file, scan for these patterns:
|
|
25
|
+
- `// TODO`, `// FIXME`, `// HACK`, `// XXX`
|
|
26
|
+
- String literals containing "for now", "placeholder", "stub", "later", "not yet implemented"
|
|
27
|
+
- Empty catch blocks or catch blocks that only log without re-throwing or handling
|
|
28
|
+
- Fallback return values that hide real errors (e.g., `return null`, `return []` with no explanation)
|
|
29
|
+
- Dead code gated on `if (false)` or `if (process.env.NEVER)`
|
|
30
|
+
3. For each hit, choose one action:
|
|
31
|
+
- Replace with a real implementation if the intent is clear
|
|
32
|
+
- Replace with an explicit thrown error if the path should never be reached
|
|
33
|
+
- Remove the dead code entirely if it adds no value
|
|
34
|
+
4. After cleanup, re-run the project's doctor/lint check to confirm nothing broken.
|
|
35
|
+
5. Re-run the project's test suite to confirm no regressions.
|
|
36
|
+
6. Run a second grep pass to confirm zero hits remain:
|
|
37
|
+
```
|
|
38
|
+
grep -rE "TODO|FIXME|HACK|for now|placeholder|stub" <changed-files>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## State Contract
|
|
42
|
+
|
|
43
|
+
- Reads: changed files in the working tree
|
|
44
|
+
- Writes: same files (in-place edits only); no new files, no new state in `.enact/loop/`
|
|
45
|
+
|
|
46
|
+
## Final Check
|
|
47
|
+
|
|
48
|
+
- Zero `TODO`, `FIXME`, `HACK`, or placeholder strings in changed files
|
|
49
|
+
- No empty or swallowed catch blocks remain
|
|
50
|
+
- Doctor/lint still passes after cleanup
|
|
51
|
+
- Test suite still passes after cleanup
|
|
52
|
+
- No code was deleted without a replacement or explicit error
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: azdo-ci-strategy
|
|
3
|
+
description: >-
|
|
4
|
+
Azure DevOps CI/CD for enact-os: the branch / PR / release strategy plus the
|
|
5
|
+
az CLI + REST commands to run it. Use when opening or promoting PRs (to
|
|
6
|
+
integration or main), setting branch policies (merge-strategy,
|
|
7
|
+
build-validation), registering pipelines, diagnosing why a pipeline did not
|
|
8
|
+
trigger, or reading build failures. Triggers on "PR to integration", "promote
|
|
9
|
+
to main", "pipeline failing", "branch policy", "az repos", "az pipelines".
|
|
10
|
+
compatibility: >-
|
|
11
|
+
Requires the az CLI (>= 2.30) with the azure-devops extension, an
|
|
12
|
+
authenticated `az login`, and network access to an Azure DevOps organization.
|
|
13
|
+
metadata:
|
|
14
|
+
author: Amsterdam Data Labs
|
|
15
|
+
version: 1.0.0
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Azure DevOps CI/CD Strategy — enact-os
|
|
19
|
+
|
|
20
|
+
The enact-os branch / release strategy and pipeline conventions. The `az` CLI
|
|
21
|
+
and REST command catalogs live in `references/` (see [Reference files](#reference-files))
|
|
22
|
+
and load on demand — this file holds the strategy and the everyday workflow.
|
|
23
|
+
|
|
24
|
+
> **Relationship to the `enact-factory` MCP server.** This is a standalone
|
|
25
|
+
> knowledge skill — it needs only the `az` CLI, no MCP server. When the
|
|
26
|
+
> `enact-factory` MCP *is* available, prefer its tools (`factory_workitem_*`,
|
|
27
|
+
> pipeline governance) for **live board/WorkItem/pipeline state**; use the
|
|
28
|
+
> CLI/REST recipes here for **branch & merge policies, PR creation/promotion,
|
|
29
|
+
> and build-failure diagnosis** — the operations the MCP doesn't cover, or for
|
|
30
|
+
> when it isn't connected. See the sibling `workitem-triage` skill for the
|
|
31
|
+
> read-only WorkItem triage surface.
|
|
32
|
+
|
|
33
|
+
## Branch flow
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
feat/* PR to integration ── PR CI ──► auto-merge to integration
|
|
37
|
+
fix/* PR to integration ── PR CI ──► auto-merge to integration
|
|
38
|
+
integration ── automation creates or updates one PR to main ──► main
|
|
39
|
+
main ── manual approval + CI ──► publish
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- Branch from `integration` (never from `main`). One branch per logical unit,
|
|
43
|
+
kebab-case. Never commit directly to `integration` or `main`.
|
|
44
|
+
- **Create a fresh branch only when no open PR to `integration` is left
|
|
45
|
+
outstanding** for your prior work — let that PR merge (or close it) first. Keep
|
|
46
|
+
one open `integration` PR at a time so the branch → PR → merge cycle stays
|
|
47
|
+
serialized and you never stack new work on a base that's still moving. Check
|
|
48
|
+
before branching:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
az repos pr list --target-branch integration --status active \
|
|
52
|
+
--creator "$(az account show --query user.name -o tsv)" -o table
|
|
53
|
+
```
|
|
54
|
+
- `feat/*` — new functionality, tooling, or docs. `fix/*` — bug/CI/config fixes.
|
|
55
|
+
|
|
56
|
+
## Setup
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
az extension add --name azure-devops # az cli 2.30+
|
|
60
|
+
az login
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For any command surface not spelled out in the references, run `az <group>
|
|
64
|
+
--help` — e.g. `az repos pr --help`, `az pipelines --help`, `az devops --help`.
|
|
65
|
+
The references document only the non-obvious flags, gotchas, and the REST calls
|
|
66
|
+
the CLI can't make; the CLI's own help covers the rest.
|
|
67
|
+
|
|
68
|
+
## Variables
|
|
69
|
+
|
|
70
|
+
Every command and URL in this skill (including the reference files) references
|
|
71
|
+
these. Set them once per shell (or pass `--detect` inside a repo to infer
|
|
72
|
+
org/project from the git remote). Nothing here is tied to one tenant —
|
|
73
|
+
substitute your own org/project:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
ORG_URL="https://dev.azure.com/<your-org>" # e.g. .../amsterdamdatalabs
|
|
77
|
+
PROJECT="<your-project>" # e.g. Enact
|
|
78
|
+
AZDO_RESOURCE="499b84ac-1321-427f-aa17-267ca6975798" # constant AAD app id for AzDO access tokens
|
|
79
|
+
|
|
80
|
+
# Optional: set CLI defaults so --org/--project can be omitted on every command.
|
|
81
|
+
az devops configure --defaults organization="$ORG_URL" project="$PROJECT"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Developer workflow
|
|
85
|
+
|
|
86
|
+
0. Before starting any task: confirm you have no open `integration` PR left from
|
|
87
|
+
prior work, then sync local `integration` and branch from it:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Gate: must return nothing before you branch (let any prior PR merge/close first)
|
|
91
|
+
az repos pr list --target-branch integration --status active \
|
|
92
|
+
--creator "$(az account show --query user.name -o tsv)" -o table
|
|
93
|
+
|
|
94
|
+
git checkout integration
|
|
95
|
+
git pull --ff-only origin integration
|
|
96
|
+
git checkout -b feat/my-branch # or fix/my-branch
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
1. Work on a `feat/*` or `fix/*` branch.
|
|
100
|
+
2. Run local Docker CI before opening a PR. Each package has a wrapper at
|
|
101
|
+
`./scripts/ci-local-<package>.sh` (run from the `enact-os` workspace root):
|
|
102
|
+
|
|
103
|
+
- `ci-local-agent.sh` · `ci-local-context.sh` · `ci-local-eval.sh`
|
|
104
|
+
- `ci-local-factory.sh` · `ci-local-gateway.sh` · `ci-local-observe.sh`
|
|
105
|
+
- `ci-local-operator.sh` · `ci-local-proc-tap.sh` · `ci-local-runtime.sh`
|
|
106
|
+
- `ci-local-voice.sh` · `ci-local-watchdog.sh` · `ci-local-wiki.sh`
|
|
107
|
+
|
|
108
|
+
(Verify the exact set with `ls scripts/ci-local-*.sh` — it grows as packages
|
|
109
|
+
are added.) For `enact-factory` and `enact-wiki`, the Docker wrapper is the
|
|
110
|
+
source of truth for Azure parity; direct host-local Vitest can differ because
|
|
111
|
+
of optional native bindings on non-Linux machines.
|
|
112
|
+
|
|
113
|
+
3. Open a PR targeting **`integration`** only — never directly to `main`. Always
|
|
114
|
+
pass **both** `--auto-complete true` and `--delete-source-branch true` (these
|
|
115
|
+
are NOT inherited by CLI-created PRs — see the auto-complete gotcha in
|
|
116
|
+
`references/cli-reference.md`):
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
az repos pr create \
|
|
120
|
+
--source-branch feat/my-branch \
|
|
121
|
+
--target-branch integration \
|
|
122
|
+
--title "feat: description" \
|
|
123
|
+
--auto-complete true \
|
|
124
|
+
--delete-source-branch true \
|
|
125
|
+
--detect
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
4. CI runs automatically on the PR. When CI passes the PR **auto-merges** into
|
|
129
|
+
`integration`. No reviewer is required on integration.
|
|
130
|
+
5. After each successful merge to `integration`, automation creates or updates
|
|
131
|
+
one open `integration → main` PR.
|
|
132
|
+
6. The `integration → main` PR stays **manual** — owner approval on it is the
|
|
133
|
+
release gate. (Create/update commands: `references/cli-reference.md`.)
|
|
134
|
+
|
|
135
|
+
## CI triggers
|
|
136
|
+
|
|
137
|
+
| Trigger | What runs |
|
|
138
|
+
| ------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
139
|
+
| Push to `feat/*` | Build + test + lint |
|
|
140
|
+
| Push to `fix/*` | **Nothing** — local Docker CI is the gate |
|
|
141
|
+
| PR opened / updated targeting `integration` | Build + test + lint |
|
|
142
|
+
| Push to `integration` (after PR merged) | Build + test + lint |
|
|
143
|
+
| Push to `main` (after PR merged) | Build + test + lint + **Publish** for publishable packages; CI only for internal-only packages |
|
|
144
|
+
|
|
145
|
+
> **⛔ NEVER use `az pipelines run` to manually trigger CI as a substitute for a
|
|
146
|
+
> PR push.** Manual runs do not update PR build status and give false
|
|
147
|
+
> confidence. If CI is not triggering on a PR, push a new commit (even empty):
|
|
148
|
+
>
|
|
149
|
+
> ```bash
|
|
150
|
+
> git commit --allow-empty -m "ci: re-trigger pipeline"
|
|
151
|
+
> git push
|
|
152
|
+
> ```
|
|
153
|
+
>
|
|
154
|
+
> The only permitted use of `az pipelines run` is a deliberate Publish-stage
|
|
155
|
+
> retag/hotfix on `main`, performed explicitly by the repo owner.
|
|
156
|
+
|
|
157
|
+
## Publish gate
|
|
158
|
+
|
|
159
|
+
- Publish only runs on `refs/heads/main`.
|
|
160
|
+
- `main` is branch-protected — direct push blocked; only PR merges allowed.
|
|
161
|
+
- Internal-only packages can omit a publish stage while keeping the same
|
|
162
|
+
`integration` / `main` CI trigger pattern.
|
|
163
|
+
- Merging the `integration → main` PR IS the manual approval for publish.
|
|
164
|
+
- Version bumps are done manually by the repo owner before approving that PR.
|
|
165
|
+
|
|
166
|
+
## Version management
|
|
167
|
+
|
|
168
|
+
- No automated changesets or version bots.
|
|
169
|
+
- Repo owner bumps `package.json` / `Cargo.toml` version manually.
|
|
170
|
+
- Automation opens or updates the `integration → main` PR.
|
|
171
|
+
- Repo owner merges that PR to trigger publish.
|
|
172
|
+
|
|
173
|
+
## Pipeline trigger config (all packages)
|
|
174
|
+
|
|
175
|
+
```yaml
|
|
176
|
+
trigger:
|
|
177
|
+
branches:
|
|
178
|
+
include:
|
|
179
|
+
- integration
|
|
180
|
+
- feat/*
|
|
181
|
+
- main
|
|
182
|
+
|
|
183
|
+
pr:
|
|
184
|
+
branches:
|
|
185
|
+
include:
|
|
186
|
+
- integration
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`feat/*` is included so pushes to feature branches run CI (per the table above);
|
|
190
|
+
`fix/*` is intentionally excluded — local Docker CI is its only gate.
|
|
191
|
+
|
|
192
|
+
Publish stage condition:
|
|
193
|
+
|
|
194
|
+
```yaml
|
|
195
|
+
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Version pins for local CI scripts
|
|
199
|
+
|
|
200
|
+
Tool versions for all `ci-local-*.sh` scripts are pinned in
|
|
201
|
+
`scripts/ci-versions.env`:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
NODE_IMAGE="node:22-bookworm"
|
|
205
|
+
ZIG_VERSION="0.14.0"
|
|
206
|
+
PYTHON_IMAGE="python:3.12-bookworm"
|
|
207
|
+
UV_VERSION="0.11.8" # must match enact-observe/pyproject.toml [tool.uv]
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
When upgrading a tool version: (1) update `scripts/ci-versions.env`, **then**
|
|
211
|
+
(2) update the `variables:` block in the relevant `azure-pipelines.yml` — Azure
|
|
212
|
+
Pipelines does NOT read this file; keep the two in sync manually.
|
|
213
|
+
|
|
214
|
+
## Version-skip pattern
|
|
215
|
+
|
|
216
|
+
All publish steps must handle already-published versions gracefully:
|
|
217
|
+
|
|
218
|
+
- **npm public**: check `npm view <pkg> version`, skip if matches local.
|
|
219
|
+
- **Azure Artifacts**: catch `403|409|already exist|upstream sources`, exit 0.
|
|
220
|
+
- **cargo**: check the Azure Artifacts sparse index or crates.io API, skip if
|
|
221
|
+
the version already exists.
|
|
222
|
+
|
|
223
|
+
## Examples
|
|
224
|
+
|
|
225
|
+
**"Open a PR for my fix branch."**
|
|
226
|
+
→ Run the step-0 gate (no open integration PR), then `az repos pr create` to
|
|
227
|
+
`integration` with `--auto-complete true --delete-source-branch true`.
|
|
228
|
+
→ Result: PR opens, CI runs, and on green it auto-merges — no reviewer needed.
|
|
229
|
+
|
|
230
|
+
**"Promote integration to main."**
|
|
231
|
+
→ Create/update the `integration → main` PR (NO `--auto-complete`,
|
|
232
|
+
`references/cli-reference.md`). → Result: PR awaits the owner's approval; merging
|
|
233
|
+
it triggers the versioned publish.
|
|
234
|
+
|
|
235
|
+
**"Why didn't CI run on my PR?"**
|
|
236
|
+
→ Follow the diagnosis in `references/build-failures.md`: push an empty commit,
|
|
237
|
+
confirm the build-validation policy is enabled, ensure the PR is open and
|
|
238
|
+
targets `integration`. → Result: the pipeline re-queues on the next push event.
|
|
239
|
+
|
|
240
|
+
**"The pipeline is red — what failed?"**
|
|
241
|
+
→ Pull the build timeline via token + curl (`references/build-failures.md`) while
|
|
242
|
+
logs are still live. → Result: a printed list of failed Task/Job/Stage records
|
|
243
|
+
with their first error messages.
|
|
244
|
+
|
|
245
|
+
## Reference files
|
|
246
|
+
|
|
247
|
+
Detailed command catalogs live under `references/` and load on demand. They all
|
|
248
|
+
assume the [Variables](#variables) above are set.
|
|
249
|
+
|
|
250
|
+
- **`references/cli-reference.md`** — az command catalog (PRs, work items,
|
|
251
|
+
pipelines, repos), the full PR workflow, the auto-complete gotcha, common flags.
|
|
252
|
+
- **`references/policies-and-pipelines.md`** — REST recipes for merge-strategy
|
|
253
|
+
and build-validation policies, registering a pipeline, variable-group
|
|
254
|
+
authorization.
|
|
255
|
+
- **`references/build-failures.md`** — pull failing-build timelines/logs via
|
|
256
|
+
token + curl; diagnose why CI did not trigger.
|
|
257
|
+
- **`references/troubleshooting.md`** — `msrestazure` fix, `az repos` vs
|
|
258
|
+
`az devops`, pipeline bootstrap gotchas, first-run checklist.
|
|
259
|
+
|
|
260
|
+
## Canonical doc
|
|
261
|
+
|
|
262
|
+
`enact-docs/05-operations/cross-package/git-branching-strategy.md`
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Reading build failures & diagnosing CI
|
|
2
|
+
|
|
3
|
+
Assumes the **Variables** block from `../SKILL.md` is set (`$ORG_URL`,
|
|
4
|
+
`$PROJECT`, `$AZDO_RESOURCE`).
|
|
5
|
+
|
|
6
|
+
## Reading build failure output
|
|
7
|
+
|
|
8
|
+
AzDO pipeline logs expire quickly (timeline returns HTTP 204 after ~24h). Get
|
|
9
|
+
them while the run is fresh. **`az rest` does NOT work for AzDO URLs** — it
|
|
10
|
+
cannot derive the right AAD scope; use a bearer token + `curl`.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
TOKEN=$(az account get-access-token \
|
|
14
|
+
--resource "$AZDO_RESOURCE" \
|
|
15
|
+
--query accessToken -o tsv)
|
|
16
|
+
|
|
17
|
+
# Failure summary from the build timeline (works while logs are live)
|
|
18
|
+
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
19
|
+
"$ORG_URL/$PROJECT/_apis/build/builds/<buildId>/timeline?api-version=7.1" \
|
|
20
|
+
| python3 -c "
|
|
21
|
+
import sys, json
|
|
22
|
+
d = json.load(sys.stdin)
|
|
23
|
+
failed = [r for r in d.get('records', [])
|
|
24
|
+
if r.get('result') == 'failed' and r.get('type') in ('Task','Job','Stage')]
|
|
25
|
+
for r in sorted(failed, key=lambda x: x.get('order', 0)):
|
|
26
|
+
print(r.get('type'), '|', r.get('name'))
|
|
27
|
+
for i in (r.get('issues') or [])[:3]:
|
|
28
|
+
print(' !', i.get('message', '')[:300])
|
|
29
|
+
"
|
|
30
|
+
|
|
31
|
+
# Logs container URL from a run
|
|
32
|
+
az pipelines runs show --id <run-id> --output json \
|
|
33
|
+
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d['logs']['url'])"
|
|
34
|
+
|
|
35
|
+
# Fetch a specific log entry (<logId> from the logs index)
|
|
36
|
+
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
37
|
+
"$ORG_URL/$PROJECT/_apis/build/builds/<buildId>/logs/<logId>?api-version=7.1"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Timeline returns HTTP 204 (empty) once logs expire — check the AzDO web UI then.
|
|
41
|
+
|
|
42
|
+
## Diagnosing why CI did not trigger on a PR
|
|
43
|
+
|
|
44
|
+
CI should trigger automatically when commits land on a PR source branch. If it
|
|
45
|
+
doesn't, do NOT manually queue a run:
|
|
46
|
+
|
|
47
|
+
1. **Push a new commit** (even empty) to the source branch:
|
|
48
|
+
```bash
|
|
49
|
+
git commit --allow-empty -m "ci: re-trigger pipeline"
|
|
50
|
+
git push
|
|
51
|
+
```
|
|
52
|
+
2. Check the PR's **build-validation policy** is enabled (pipeline registered and
|
|
53
|
+
the policy references the correct pipeline ID — see
|
|
54
|
+
`policies-and-pipelines.md`).
|
|
55
|
+
3. Check the PR is open and targeting `integration`. Closed/draft PRs don't
|
|
56
|
+
trigger CI.
|
|
57
|
+
|
|
58
|
+
For bootstrap PRs introducing `azure-pipelines.yml` for the first time, use
|
|
59
|
+
`git push --force-with-lease` to force a new push event (see
|
|
60
|
+
`troubleshooting.md` → pipeline bootstrap gotchas).
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Azure DevOps CLI reference
|
|
2
|
+
|
|
3
|
+
Command catalog for the enact-os workflow. Assumes the **Variables** block from
|
|
4
|
+
`../SKILL.md` is set (`$ORG_URL`, `$PROJECT`, `$AZDO_RESOURCE`). For anything not
|
|
5
|
+
listed here, run `az <group> --help`.
|
|
6
|
+
|
|
7
|
+
## Most-used commands
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# My PRs
|
|
11
|
+
az repos pr list --creator "$(az account show --query user.name -o tsv)"
|
|
12
|
+
az repos pr list --reviewer "$(az account show --query user.name -o tsv)"
|
|
13
|
+
az repos pr show --id <pr-id>
|
|
14
|
+
az repos pr checkout --id <pr-id>
|
|
15
|
+
|
|
16
|
+
# My work items
|
|
17
|
+
az boards query --wiql "SELECT [System.Id], [System.Title], [System.State] FROM WorkItems WHERE [System.AssignedTo] = @Me AND [System.State] <> 'Closed' ORDER BY [System.ChangedDate] DESC"
|
|
18
|
+
az boards work-item show --id <work-item-id>
|
|
19
|
+
az boards work-item create --title "Task title" --type "Task"
|
|
20
|
+
az boards work-item update --id <id> --state "In Progress"
|
|
21
|
+
|
|
22
|
+
# Pipelines
|
|
23
|
+
az pipelines list
|
|
24
|
+
az pipelines runs list --top 10
|
|
25
|
+
az pipelines runs show --id <run-id>
|
|
26
|
+
|
|
27
|
+
# Repositories
|
|
28
|
+
az repos list
|
|
29
|
+
az repos show --repository <repo-name>
|
|
30
|
+
az repos create --name "new-repo"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Pull request workflow
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Create PR to integration — always auto-complete + delete-source-branch
|
|
37
|
+
az repos pr create \
|
|
38
|
+
--source-branch feat/my-branch \
|
|
39
|
+
--target-branch integration \
|
|
40
|
+
--title "feat: description" \
|
|
41
|
+
--auto-complete true \
|
|
42
|
+
--delete-source-branch true \
|
|
43
|
+
--detect
|
|
44
|
+
# CI passes → PR auto-merges. No reviewer required on integration.
|
|
45
|
+
|
|
46
|
+
# Promotion PR to main (integration→main) — created/updated by automation,
|
|
47
|
+
# merge stays MANUAL. Owner approval on this PR is the release gate.
|
|
48
|
+
az repos pr create \
|
|
49
|
+
--source-branch integration \
|
|
50
|
+
--target-branch main \
|
|
51
|
+
--title "release: promote integration → main" \
|
|
52
|
+
--detect
|
|
53
|
+
# NO --auto-complete ← merge of the main PR is the manual release gate
|
|
54
|
+
# NO --delete-source-branch ← integration is permanent
|
|
55
|
+
|
|
56
|
+
# Enable auto-complete on an existing integration PR (e.g. opened without flags)
|
|
57
|
+
az repos pr update --id <pr-id> --auto-complete true --delete-source-branch true
|
|
58
|
+
|
|
59
|
+
# Reviewers / votes / manual completion
|
|
60
|
+
az repos pr update --id <pr-id> --reviewers user@email.com
|
|
61
|
+
az repos pr set-vote --id <pr-id> --vote 10 # 10 approve · 5 approve-w/-suggestions · -5 wait · -10 reject
|
|
62
|
+
az repos pr update --id <pr-id> --status completed
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Auto-complete gotcha (CLI/REST PRs)
|
|
66
|
+
|
|
67
|
+
The project setting **"Set PRs to auto-complete on creation by default"**
|
|
68
|
+
(Project settings → Repositories → Settings) is enabled, **but it applies only
|
|
69
|
+
to PRs created in the web UI** — PRs created via `az repos pr create` / REST do
|
|
70
|
+
NOT inherit it (verified: a CLI-created PR had auto-complete OFF despite the
|
|
71
|
+
default). So for the CLI workflow, always pass **both** `--auto-complete true`
|
|
72
|
+
and `--delete-source-branch true` explicitly. AzDO has no repo-level policy to
|
|
73
|
+
force-delete branches on merge — enforce it at PR creation. Fix a PR opened
|
|
74
|
+
without the flags after the fact:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
az repos pr update --id <N> --auto-complete true --delete-source-branch true
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Common flags
|
|
81
|
+
|
|
82
|
+
| Flag | Description |
|
|
83
|
+
| ------------------- | --------------------------------------------------- |
|
|
84
|
+
| `--org` | Organization URL (or set via `az devops configure`) |
|
|
85
|
+
| `--project` | Project name (or set via `az devops configure`) |
|
|
86
|
+
| `--detect` | Auto-detect org/project from the git remote |
|
|
87
|
+
| `-o json/table/tsv` | Output format |
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Branch policies, pipelines & variable groups (REST)
|
|
2
|
+
|
|
3
|
+
Assumes the **Variables** block from `../SKILL.md` is set (`$ORG_URL`,
|
|
4
|
+
`$PROJECT`, `$AZDO_RESOURCE`).
|
|
5
|
+
|
|
6
|
+
## Enforcing merge strategy on a branch
|
|
7
|
+
|
|
8
|
+
> **Do NOT use `az repos policy merge-strategy create`** — it warns
|
|
9
|
+
> `This command is from the following extension: azure-devops`. Use the REST API
|
|
10
|
+
> directly (bearer token + curl). Policy type id:
|
|
11
|
+
> `fa4e907d-c16b-4a4c-9dfa-4916e5d171ab`.
|
|
12
|
+
|
|
13
|
+
**integration — squash only** (1 clean commit per PR, linear history):
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
TOKEN=$(az account get-access-token \
|
|
17
|
+
--resource "$AZDO_RESOURCE" --query accessToken -o tsv)
|
|
18
|
+
|
|
19
|
+
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
20
|
+
"$ORG_URL/$PROJECT/_apis/policy/configurations?api-version=7.1" \
|
|
21
|
+
-d '{
|
|
22
|
+
"isEnabled": true, "isBlocking": true,
|
|
23
|
+
"type": {"id": "fa4e907d-c16b-4a4c-9dfa-4916e5d171ab"},
|
|
24
|
+
"settings": {
|
|
25
|
+
"allowSquash": true, "allowNoFastForward": false,
|
|
26
|
+
"allowRebase": false, "allowRebaseMerge": false,
|
|
27
|
+
"scope": [{"repositoryId": "<repo-id>", "refName": "refs/heads/integration", "matchKind": "exact"}]
|
|
28
|
+
}
|
|
29
|
+
}'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**main — basic merge or fast-forward, no squash** (preserves full integration
|
|
33
|
+
history on promotion):
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# POST (new) uses the URL above with these settings; if a policy already exists,
|
|
37
|
+
# PUT to .../policy/configurations/<policy-id>?api-version=7.1 instead.
|
|
38
|
+
curl -s -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
39
|
+
"$ORG_URL/$PROJECT/_apis/policy/configurations/<policy-id>?api-version=7.1" \
|
|
40
|
+
-d '{
|
|
41
|
+
"isEnabled": true, "isBlocking": true,
|
|
42
|
+
"type": {"id": "fa4e907d-c16b-4a4c-9dfa-4916e5d171ab"},
|
|
43
|
+
"settings": {
|
|
44
|
+
"allowSquash": false, "allowNoFastForward": true,
|
|
45
|
+
"allowRebase": true, "allowRebaseMerge": false,
|
|
46
|
+
"scope": [{"repositoryId": "<repo-id>", "refName": "refs/heads/main", "matchKind": "exact"}]
|
|
47
|
+
}
|
|
48
|
+
}'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
POST fails with "rejected by policy" if a merge-strategy policy already exists on
|
|
52
|
+
that branch — use PUT with the existing policy ID. Find existing IDs:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
56
|
+
"$ORG_URL/$PROJECT/_apis/policy/configurations?api-version=7.1" \
|
|
57
|
+
| python3 -c "
|
|
58
|
+
import sys,json
|
|
59
|
+
MERGE_TYPE='fa4e907d-c16b-4a4c-9dfa-4916e5d171ab'
|
|
60
|
+
for p in json.load(sys.stdin).get('value',[]):
|
|
61
|
+
if p.get('type',{}).get('id') == MERGE_TYPE:
|
|
62
|
+
for s in p['settings'].get('scope',[]):
|
|
63
|
+
print(p['id'], s.get('repositoryId'), s.get('refName'))
|
|
64
|
+
"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Register a pipeline
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Run from inside the repo directory — --detect infers org/project/repo
|
|
71
|
+
az pipelines create \
|
|
72
|
+
--name "<package-name> CI" \
|
|
73
|
+
--repository <repo-name> \
|
|
74
|
+
--repository-type tfsgit \
|
|
75
|
+
--branch <default-branch> \
|
|
76
|
+
--yml-path azure-pipelines.yml \
|
|
77
|
+
--skip-first-run \
|
|
78
|
+
--detect
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Build-validation policy (blocking CI gate)
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
az repos policy build create \
|
|
85
|
+
--repository-id <repo-id> \
|
|
86
|
+
--branch integration \
|
|
87
|
+
--build-definition-id <pipeline-id> \
|
|
88
|
+
--queue-on-source-update-only false \
|
|
89
|
+
--manual-queue-only false \
|
|
90
|
+
--valid-duration 0 \
|
|
91
|
+
--blocking true \
|
|
92
|
+
--enabled true \
|
|
93
|
+
--display-name "CI must pass before merge" \
|
|
94
|
+
--detect
|
|
95
|
+
|
|
96
|
+
# List / delete policies for a repo
|
|
97
|
+
az repos policy list --repository-id <repo-id> --detect -o table
|
|
98
|
+
az repos policy delete --id <policy-id> --detect
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Get `--repository-id` via `az repos show --repository <repo-name> --query id -o tsv --detect`.
|
|
102
|
+
Policies for the enact-os packages were created 2026-05-19 with the above.
|
|
103
|
+
|
|
104
|
+
## Variable-group authorization (first run)
|
|
105
|
+
|
|
106
|
+
A pipeline referencing a variable group (e.g. `enact-dev-secrets`) for the first
|
|
107
|
+
time queues but stays `notStarted` until authorized. Two ways:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# UI: open the stuck run and click "Permit" on the variable group.
|
|
111
|
+
az pipelines runs list --pipeline-id <id> --output table
|
|
112
|
+
# $ORG_URL/$PROJECT/_build/results?buildId=<run-id>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# REST (no UI):
|
|
117
|
+
TOKEN=$(az account get-access-token \
|
|
118
|
+
--resource "$AZDO_RESOURCE" --query accessToken -o tsv)
|
|
119
|
+
az pipelines variable-group list --output table # get <groupId>
|
|
120
|
+
|
|
121
|
+
# Authorize specific pipelines:
|
|
122
|
+
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
123
|
+
"$ORG_URL/$PROJECT/_apis/pipelines/pipelinePermissions/variablegroup/<groupId>?api-version=7.1-preview.1" \
|
|
124
|
+
-d '{"pipelines": [{"id": 9, "authorized": true}, {"id": 10, "authorized": true}]}'
|
|
125
|
+
|
|
126
|
+
# …or all pipelines at once:
|
|
127
|
+
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
128
|
+
"$ORG_URL/$PROJECT/_apis/pipelines/pipelinePermissions/variablegroup/<groupId>?api-version=7.1-preview.1" \
|
|
129
|
+
-d '{"allPipelines": {"authorized": true}}'
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The authorization persists for that pipeline permanently.
|