coding-agent-skills 0.2.15 → 0.2.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +26 -0
- package/ROADMAP.md +3 -0
- package/bin/coding-agent-skills +333 -2
- package/docs/release/README.md +12 -9
- package/docs/release/npm-package.md +21 -1
- package/docs/testing/README.md +8 -0
- package/docs/usage/README.md +44 -0
- package/package.json +1 -1
- package/runs/skill-runs.md +17 -0
- package/scripts/test-pack.mjs +92 -1
- package/scripts/validate-pack.mjs +2 -2
- package/work-ledger.md +21 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes follow [Semantic Versioning](docs/versioning/README.md).
|
|
4
4
|
|
|
5
|
+
## [0.2.16] - 2026-07-03
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Optional `--json` output for every public `coding-agent-skills` CLI command.
|
|
10
|
+
- OpenClaw-compatible structured result fields for command identity, skill id, package
|
|
11
|
+
version, status, findings, warnings, skipped checks, refused behavior, safety summary,
|
|
12
|
+
`recommendedNextAction`, and exit-code meaning.
|
|
13
|
+
- Release tests that validate the JSON contract across the public CLI surface and confirm
|
|
14
|
+
redaction of local home paths and secret-like values.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- The public wrapper now preserves default human-readable output while offering sanitized
|
|
19
|
+
machine-readable results for orchestrator callers.
|
|
20
|
+
- Usage, release, testing, roadmap, ledger, and run-log docs now describe the exit-code
|
|
21
|
+
contract and OpenClaw integration boundary.
|
|
22
|
+
- Stale v0.2.15 ledger and run-log entries now reflect that the deployment-preflight
|
|
23
|
+
release was published, smoke-tested, and released.
|
|
24
|
+
|
|
5
25
|
## [0.2.15] - 2026-07-03
|
|
6
26
|
|
|
7
27
|
### Added
|
package/README.md
CHANGED
|
@@ -52,6 +52,9 @@ Every skill emits the evidence-pack contract. A command being attempted is never
|
|
|
52
52
|
- Review static migration and schema evidence with `coding-agent-skills migration-review <project-root>`.
|
|
53
53
|
- Prepare local Git handoff evidence with `coding-agent-skills github-handoff <project-root>`.
|
|
54
54
|
- Map static deployment readiness evidence with `coding-agent-skills deployment-preflight <project-root>`.
|
|
55
|
+
- Add `--json` to any public CLI command when an OpenClaw-style orchestrator
|
|
56
|
+
needs a sanitized machine-readable result with `success`, `status`,
|
|
57
|
+
`recommendedNextAction`, safety flags, and exit-code meaning.
|
|
55
58
|
- Validate project adapters against [the formal adapter schema](schemas/project-adapter.schema.json).
|
|
56
59
|
- Review [external adapter discovery](docs/adapters/discovery.md).
|
|
57
60
|
- Run `node scripts/validate-adapters.mjs <adapter-root>` for a disposable external root.
|
|
@@ -92,6 +95,29 @@ Every skill emits the evidence-pack contract. A command being attempted is never
|
|
|
92
95
|
Governance lives in [CONTRIBUTING.md](CONTRIBUTING.md), [ROADMAP.md](ROADMAP.md), and the [release policy](docs/release/README.md).
|
|
93
96
|
The [harness guide](docs/testing/README.md) explains trigger, command, mutation, privacy, adapter, and completion checks.
|
|
94
97
|
|
|
98
|
+
## Orchestrator Output
|
|
99
|
+
|
|
100
|
+
The default CLI output remains human-readable. OpenClaw-style callers can request a
|
|
101
|
+
structured result with `--json`:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
coding-agent-skills repo-map /path/to/project --json
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
JSON output is read-only and sanitized. It includes command identity, package version,
|
|
108
|
+
skill id, status, findings, warnings, skipped checks, refused behavior, safety flags,
|
|
109
|
+
and `recommendedNextAction`. Exit codes follow the public contract:
|
|
110
|
+
|
|
111
|
+
- `0`: handled execution path, including complete, partial, blocked, or controlled audit results
|
|
112
|
+
- `2`: usage error
|
|
113
|
+
- `3`: safety refusal
|
|
114
|
+
- `4`: missing required input or file
|
|
115
|
+
- `5`: unexpected internal or runtime failure
|
|
116
|
+
|
|
117
|
+
OpenClaw should remain the owner of memory, routing, permissions, scheduling, user
|
|
118
|
+
interaction, and workflow state. `coding-agent-skills` is a safe callable evidence
|
|
119
|
+
producer, not an orchestrator.
|
|
120
|
+
|
|
95
121
|
## Autonomous Maintainer Loop
|
|
96
122
|
|
|
97
123
|
The local maintainer loop reads Git tags, `ROADMAP.md`, `CHANGELOG.md`, and
|
package/ROADMAP.md
CHANGED
|
@@ -42,6 +42,8 @@ execution constraints remain unchanged.
|
|
|
42
42
|
evidence before separately approved GitHub work.
|
|
43
43
|
- `v0.2.15`: audit-only `deployment-preflight` skill and CLI renderer for static
|
|
44
44
|
deployment readiness evidence before separately approved deployment work.
|
|
45
|
+
- `v0.2.16`: OpenClaw-compatible optional `--json` output and documented exit-code
|
|
46
|
+
semantics for every public CLI command.
|
|
45
47
|
|
|
46
48
|
The next milestone is recorded in [work-ledger.md](work-ledger.md). The
|
|
47
49
|
[maintainer loop](RUNBOOK.md) may select and evidence that milestone, but it must stop
|
|
@@ -89,6 +91,7 @@ Next safe milestone options:
|
|
|
89
91
|
| `migration-review-skill` | General with platform adapters | Audit-only | Implemented in `v0.2.13` |
|
|
90
92
|
| `github-handoff-skill` | General | Audit-only | Implemented in `v0.2.14` |
|
|
91
93
|
| `deployment-preflight-skill` | General | Audit-only | Implemented in `v0.2.15` |
|
|
94
|
+
| `orchestrator-json-output-contract` | General tooling | Read-only CLI contract | Implemented in `v0.2.16` |
|
|
92
95
|
| `cloudflare-preflight-skill` | Platform-specific | Audit-only | Builder-mode approved; later in wave |
|
|
93
96
|
| `cloudflare-deploy-skill` | Platform-specific | Action-capable | Blocked on approval model |
|
|
94
97
|
| `supabase-rls-audit-skill` | Platform-specific | Audit-only | Builder-mode approved; later in wave |
|
package/bin/coding-agent-skills
CHANGED
|
@@ -1,9 +1,125 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
|
+
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
|
|
7
|
+
import { externalAdapterCliResult } from "../scripts/lib/adapter-discovery.mjs";
|
|
8
|
+
import { adapterRepoMapCliResult } from "../scripts/lib/adapter-repo-map.mjs";
|
|
9
|
+
import { apiContractAuditCliResult } from "../scripts/lib/api-contract-audit.mjs";
|
|
10
|
+
import { deploymentPreflightCliResult } from "../scripts/lib/deployment-preflight.mjs";
|
|
11
|
+
import { envAuditCliResult } from "../scripts/lib/env-audit.mjs";
|
|
12
|
+
import { githubHandoffCliResult } from "../scripts/lib/github-handoff.mjs";
|
|
13
|
+
import { migrationReviewCliResult } from "../scripts/lib/migration-review.mjs";
|
|
14
|
+
import { redactSensitiveText } from "../scripts/lib/pack-rules.mjs";
|
|
15
|
+
import { projectAdapterCliResult } from "../scripts/lib/project-adapter-installation.mjs";
|
|
16
|
+
import { routeTraceCliResult } from "../scripts/lib/route-trace.mjs";
|
|
17
|
+
import { secretAuditCliResult } from "../scripts/lib/secret-audit.mjs";
|
|
18
|
+
|
|
6
19
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
20
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(repoRoot, "package.json"), "utf8"));
|
|
21
|
+
|
|
22
|
+
const commandMetadata = {
|
|
23
|
+
"validate-pack": {
|
|
24
|
+
skillId: "pack-validation",
|
|
25
|
+
mode: "validation",
|
|
26
|
+
next: {
|
|
27
|
+
label: "Select a read-only audit command",
|
|
28
|
+
reason: "The package is structurally valid; choose the narrowest command for the target task.",
|
|
29
|
+
requiresApproval: false,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
"validate-project": {
|
|
33
|
+
skillId: "project-adapter-validation",
|
|
34
|
+
mode: "validation",
|
|
35
|
+
next: {
|
|
36
|
+
label: "Run an adapter-aware read-only report",
|
|
37
|
+
reason: "The project adapter declaration is valid; use a scoped report command next.",
|
|
38
|
+
requiresApproval: false,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
"repo-map": {
|
|
42
|
+
skillId: "repo-map",
|
|
43
|
+
mode: "audit-only",
|
|
44
|
+
next: {
|
|
45
|
+
label: "Review adapter-declared repo boundaries",
|
|
46
|
+
reason: "Use the reported docs, safe paths, ignored paths, and evidence requirements before choosing another action.",
|
|
47
|
+
requiresApproval: false,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
"route-trace": {
|
|
51
|
+
skillId: "route-trace",
|
|
52
|
+
mode: "audit-only",
|
|
53
|
+
next: {
|
|
54
|
+
label: "Review static route findings",
|
|
55
|
+
reason: "Inspect verified and inferred route surfaces before approving code or runtime work.",
|
|
56
|
+
requiresApproval: false,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
"env-audit": {
|
|
60
|
+
skillId: "env-audit",
|
|
61
|
+
mode: "audit-only",
|
|
62
|
+
next: {
|
|
63
|
+
label: "Review variable-name inventory",
|
|
64
|
+
reason: "Use value-free environment names to plan documentation or configuration review without reading secrets.",
|
|
65
|
+
requiresApproval: false,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
"secret-audit": {
|
|
69
|
+
skillId: "secret-audit",
|
|
70
|
+
mode: "audit-only",
|
|
71
|
+
next: {
|
|
72
|
+
label: "Review redacted secret-risk findings",
|
|
73
|
+
reason: "Any remediation, credential rotation, or repository mutation needs separate approval.",
|
|
74
|
+
requiresApproval: true,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
"api-contract-audit": {
|
|
78
|
+
skillId: "api-contract-audit",
|
|
79
|
+
mode: "audit-only",
|
|
80
|
+
next: {
|
|
81
|
+
label: "Review static API contract surfaces",
|
|
82
|
+
reason: "Use contract, endpoint, client, and schema evidence before editing API code.",
|
|
83
|
+
requiresApproval: false,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
"migration-review": {
|
|
87
|
+
skillId: "migration-review",
|
|
88
|
+
mode: "audit-only",
|
|
89
|
+
next: {
|
|
90
|
+
label: "Review migration evidence",
|
|
91
|
+
reason: "Database access, migration edits, generation, or execution require separate approval.",
|
|
92
|
+
requiresApproval: true,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
"github-handoff": {
|
|
96
|
+
skillId: "github-handoff",
|
|
97
|
+
mode: "audit-only",
|
|
98
|
+
next: {
|
|
99
|
+
label: "Request explicit GitHub handoff approval",
|
|
100
|
+
reason: "Commit, push, tag, pull request, or API mutation work is outside this read-only report.",
|
|
101
|
+
requiresApproval: true,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
"deployment-preflight": {
|
|
105
|
+
skillId: "deployment-preflight",
|
|
106
|
+
mode: "audit-only",
|
|
107
|
+
next: {
|
|
108
|
+
label: "Request explicit deployment approval",
|
|
109
|
+
reason: "Deployment, provider API, provider CLI, build, runtime, or migration work is outside this read-only report.",
|
|
110
|
+
requiresApproval: true,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
"validate-adapters": {
|
|
114
|
+
skillId: "external-adapter-validation",
|
|
115
|
+
mode: "validation",
|
|
116
|
+
next: {
|
|
117
|
+
label: "Use accepted adapters only as narrowing metadata",
|
|
118
|
+
reason: "Adapters may narrow safe context but must not grant new powers or weaken shared restrictions.",
|
|
119
|
+
requiresApproval: false,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
7
123
|
|
|
8
124
|
const commands = {
|
|
9
125
|
"validate-pack": {
|
|
@@ -73,6 +189,29 @@ const commands = {
|
|
|
73
189
|
},
|
|
74
190
|
};
|
|
75
191
|
|
|
192
|
+
const jsonHandlers = {
|
|
193
|
+
"validate-project": ([projectRoot]) => projectAdapterCliResult(projectRoot, { coreRoot: repoRoot }),
|
|
194
|
+
"repo-map": ([projectRoot]) => adapterRepoMapCliResult(projectRoot, { coreRoot: repoRoot }),
|
|
195
|
+
"route-trace": ([projectRoot]) => routeTraceCliResult(projectRoot, { coreRoot: repoRoot }),
|
|
196
|
+
"env-audit": ([projectRoot]) => envAuditCliResult(projectRoot, { coreRoot: repoRoot }),
|
|
197
|
+
"secret-audit": ([projectRoot]) => secretAuditCliResult(projectRoot, { coreRoot: repoRoot }),
|
|
198
|
+
"api-contract-audit": ([projectRoot]) => apiContractAuditCliResult(projectRoot, { coreRoot: repoRoot }),
|
|
199
|
+
"migration-review": ([projectRoot]) => migrationReviewCliResult(projectRoot, { coreRoot: repoRoot }),
|
|
200
|
+
"github-handoff": ([projectRoot]) => githubHandoffCliResult(projectRoot, { coreRoot: repoRoot }),
|
|
201
|
+
"deployment-preflight": ([projectRoot]) => deploymentPreflightCliResult(projectRoot, { coreRoot: repoRoot }),
|
|
202
|
+
"validate-adapters": ([adapterRoot]) => externalAdapterCliResult(adapterRoot, { coreRoot: repoRoot }),
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
function stripJsonFlag(args) {
|
|
206
|
+
let json = false;
|
|
207
|
+
const rest = [];
|
|
208
|
+
for (const arg of args) {
|
|
209
|
+
if (arg === "--json") json = true;
|
|
210
|
+
else rest.push(arg);
|
|
211
|
+
}
|
|
212
|
+
return { json, args: rest };
|
|
213
|
+
}
|
|
214
|
+
|
|
76
215
|
function usage(exitCode = 0) {
|
|
77
216
|
const lines = [
|
|
78
217
|
"usage: coding-agent-skills <command> [args]",
|
|
@@ -97,7 +236,192 @@ function usage(exitCode = 0) {
|
|
|
97
236
|
process.exitCode = exitCode;
|
|
98
237
|
}
|
|
99
238
|
|
|
100
|
-
|
|
239
|
+
function sanitizedLines(text) {
|
|
240
|
+
return redactSensitiveText(text)
|
|
241
|
+
.split(/\r?\n/)
|
|
242
|
+
.map((line) => line.trimEnd())
|
|
243
|
+
.filter((line) => line.length > 0);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function sectionLines(lines, heading) {
|
|
247
|
+
const result = [];
|
|
248
|
+
let active = false;
|
|
249
|
+
for (const line of lines) {
|
|
250
|
+
if (line === `## ${heading}`) {
|
|
251
|
+
active = true;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (active && line.startsWith("## ")) break;
|
|
255
|
+
if (active && line.trim()) result.push(line.replace(/^- /, ""));
|
|
256
|
+
}
|
|
257
|
+
return result.filter((line) => line !== "none" && line !== "none found");
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function detectedStatus(lines, exitCode) {
|
|
261
|
+
for (const line of lines) {
|
|
262
|
+
const match = /^Status:\s*([a-z-]+)/i.exec(line);
|
|
263
|
+
if (match) return match[1].toLowerCase();
|
|
264
|
+
}
|
|
265
|
+
if (exitCode === 0) return "complete";
|
|
266
|
+
if (exitCode === 2) return "failed";
|
|
267
|
+
return "failed";
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function exitCodeMeaning(exitCode) {
|
|
271
|
+
if (exitCode === 0) return "handled";
|
|
272
|
+
if (exitCode === 2) return "usage-error";
|
|
273
|
+
if (exitCode === 3) return "safety-refusal";
|
|
274
|
+
if (exitCode === 4) return "missing-required-input";
|
|
275
|
+
return "unexpected-internal-or-runtime-failure";
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function adapterSummary(lines) {
|
|
279
|
+
const adapter = {};
|
|
280
|
+
const adapterLines = [
|
|
281
|
+
...sectionLines(lines, "Adapter Scope"),
|
|
282
|
+
...sectionLines(lines, "Adapter Bounds"),
|
|
283
|
+
];
|
|
284
|
+
for (const line of adapterLines) {
|
|
285
|
+
const match = /^([^:]+):\s*(.*)$/.exec(line);
|
|
286
|
+
if (!match) continue;
|
|
287
|
+
const key = match[1]
|
|
288
|
+
.trim()
|
|
289
|
+
.replace(/[^a-zA-Z0-9]+([a-zA-Z0-9])/g, (_, char) => char.toUpperCase())
|
|
290
|
+
.replace(/^[A-Z]/, (char) => char.toLowerCase());
|
|
291
|
+
adapter[key] = match[2].trim();
|
|
292
|
+
}
|
|
293
|
+
return adapter;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function summaryLines(lines) {
|
|
297
|
+
return lines
|
|
298
|
+
.filter((line) => line.trim().length > 0)
|
|
299
|
+
.filter((line) => !line.startsWith("#"))
|
|
300
|
+
.filter((line) => !line.startsWith("## "))
|
|
301
|
+
.filter((line) => !line.startsWith("- "))
|
|
302
|
+
.slice(0, 12);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function findingLines(lines) {
|
|
306
|
+
const ignoredSections = new Set([
|
|
307
|
+
"Git State",
|
|
308
|
+
"Adapter Scope",
|
|
309
|
+
"Adapter Bounds",
|
|
310
|
+
"Scope Paths",
|
|
311
|
+
"Ignored Paths",
|
|
312
|
+
"Summary",
|
|
313
|
+
"Skipped",
|
|
314
|
+
"Not Verified",
|
|
315
|
+
"Warnings",
|
|
316
|
+
"Refused Behavior",
|
|
317
|
+
]);
|
|
318
|
+
const findings = [];
|
|
319
|
+
let current = null;
|
|
320
|
+
for (const line of lines) {
|
|
321
|
+
if (line.startsWith("## ")) {
|
|
322
|
+
current = line.replace(/^## /, "");
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (!current || ignoredSections.has(current)) continue;
|
|
326
|
+
if (line.startsWith("- ") && !line.includes("none found")) findings.push(line.slice(2));
|
|
327
|
+
}
|
|
328
|
+
return findings.slice(0, 100);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function normalizeOutcome(outcome) {
|
|
332
|
+
if (Array.isArray(outcome.lines)) {
|
|
333
|
+
return {
|
|
334
|
+
exitCode: outcome.exitCode ?? 5,
|
|
335
|
+
lines: outcome.lines
|
|
336
|
+
.map((line) => redactSensitiveText(line))
|
|
337
|
+
.filter((line) => line.trim().length > 0),
|
|
338
|
+
report: outcome.report ?? outcome.result ?? null,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return {
|
|
343
|
+
exitCode: outcome.status ?? 5,
|
|
344
|
+
lines: [
|
|
345
|
+
...sanitizedLines(outcome.stdout ?? ""),
|
|
346
|
+
...sanitizedLines(outcome.stderr ?? ""),
|
|
347
|
+
],
|
|
348
|
+
report: null,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function buildJsonResult(commandName, args, outcome) {
|
|
353
|
+
const normalized = normalizeOutcome(outcome);
|
|
354
|
+
const lines = normalized.lines;
|
|
355
|
+
const metadata = commandMetadata[commandName] ?? {
|
|
356
|
+
skillId: commandName,
|
|
357
|
+
mode: "unknown",
|
|
358
|
+
next: null,
|
|
359
|
+
};
|
|
360
|
+
const status = normalized.report?.status ?? detectedStatus(lines, normalized.exitCode);
|
|
361
|
+
const summary = summaryLines(lines);
|
|
362
|
+
const warnings = [
|
|
363
|
+
...(Array.isArray(normalized.report?.warnings)
|
|
364
|
+
? normalized.report.warnings.map((line) => redactSensitiveText(line))
|
|
365
|
+
: []),
|
|
366
|
+
...sectionLines(lines, "Warnings"),
|
|
367
|
+
...lines.filter((line) => /\bwarning\b/i.test(line) && !line.startsWith("## ")),
|
|
368
|
+
];
|
|
369
|
+
|
|
370
|
+
return {
|
|
371
|
+
success: normalized.exitCode === 0,
|
|
372
|
+
status,
|
|
373
|
+
tool: "coding-agent-skills",
|
|
374
|
+
command: commandName,
|
|
375
|
+
skillId: metadata.skillId,
|
|
376
|
+
packageVersion: packageJson.version,
|
|
377
|
+
mode: metadata.mode,
|
|
378
|
+
changedState: false,
|
|
379
|
+
summary: summary.length > 0
|
|
380
|
+
? summary
|
|
381
|
+
: [
|
|
382
|
+
normalized.exitCode === 0
|
|
383
|
+
? `${commandName} completed successfully`
|
|
384
|
+
: `${commandName} did not complete successfully`,
|
|
385
|
+
],
|
|
386
|
+
findings: Array.isArray(normalized.report?.findings)
|
|
387
|
+
? normalized.report.findings.map((finding) => redactSensitiveText(JSON.stringify(finding)))
|
|
388
|
+
: findingLines(lines),
|
|
389
|
+
warnings: [...new Set(warnings)],
|
|
390
|
+
risks: Array.isArray(normalized.report?.riskIndicators)
|
|
391
|
+
? normalized.report.riskIndicators.map((risk) => redactSensitiveText(JSON.stringify(risk)))
|
|
392
|
+
: sectionLines(lines, "Risk Indicators"),
|
|
393
|
+
skipped: Array.isArray(normalized.report?.skipped)
|
|
394
|
+
? normalized.report.skipped.map((item) => redactSensitiveText(JSON.stringify(item)))
|
|
395
|
+
: sectionLines(lines, "Skipped"),
|
|
396
|
+
notVerified: Array.isArray(normalized.report?.notVerified)
|
|
397
|
+
? normalized.report.notVerified.map((item) => redactSensitiveText(String(item)))
|
|
398
|
+
: sectionLines(lines, "Not Verified"),
|
|
399
|
+
refusedBehavior: Array.isArray(normalized.report?.refusedBehavior)
|
|
400
|
+
? normalized.report.refusedBehavior.map((item) => redactSensitiveText(String(item)))
|
|
401
|
+
: sectionLines(lines, "Refused Behavior"),
|
|
402
|
+
adapter: adapterSummary(lines),
|
|
403
|
+
recommendedNextAction: metadata.next,
|
|
404
|
+
safety: {
|
|
405
|
+
readOnly: true,
|
|
406
|
+
secretsRead: false,
|
|
407
|
+
targetCommandsRun: false,
|
|
408
|
+
mutationsPerformed: false,
|
|
409
|
+
},
|
|
410
|
+
exitCode: normalized.exitCode,
|
|
411
|
+
exitCodeMeaning: exitCodeMeaning(normalized.exitCode),
|
|
412
|
+
invocation: {
|
|
413
|
+
args: args.map((arg) => redactSensitiveText(arg)),
|
|
414
|
+
outputFormat: "json",
|
|
415
|
+
},
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function printJson(value) {
|
|
420
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const { json, args: rawArgs } = stripJsonFlag(process.argv.slice(2));
|
|
424
|
+
const [commandName, ...args] = rawArgs;
|
|
101
425
|
if (!commandName || commandName === "help" || commandName === "--help" || commandName === "-h") {
|
|
102
426
|
usage(commandName ? 0 : 2);
|
|
103
427
|
} else if (!Object.hasOwn(commands, commandName)) {
|
|
@@ -108,6 +432,10 @@ if (!commandName || commandName === "help" || commandName === "--help" || comman
|
|
|
108
432
|
if ((command.requiredArgs ?? 0) !== args.length) {
|
|
109
433
|
process.stderr.write(`usage: ${command.usage}\n`);
|
|
110
434
|
process.exitCode = 2;
|
|
435
|
+
} else if (json && jsonHandlers[commandName]) {
|
|
436
|
+
const outcome = jsonHandlers[commandName](args);
|
|
437
|
+
printJson(buildJsonResult(commandName, args, outcome));
|
|
438
|
+
process.exitCode = outcome.exitCode ?? 5;
|
|
111
439
|
} else {
|
|
112
440
|
const result = spawnSync(
|
|
113
441
|
process.execPath,
|
|
@@ -115,10 +443,13 @@ if (!commandName || commandName === "help" || commandName === "--help" || comman
|
|
|
115
443
|
{
|
|
116
444
|
cwd: repoRoot,
|
|
117
445
|
encoding: "utf8",
|
|
118
|
-
stdio: "inherit",
|
|
446
|
+
stdio: json ? "pipe" : "inherit",
|
|
119
447
|
shell: false,
|
|
120
448
|
},
|
|
121
449
|
);
|
|
450
|
+
if (json) {
|
|
451
|
+
printJson(buildJsonResult(commandName, args, result));
|
|
452
|
+
}
|
|
122
453
|
process.exitCode = result.status ?? 1;
|
|
123
454
|
}
|
|
124
455
|
}
|
package/docs/release/README.md
CHANGED
|
@@ -19,20 +19,23 @@
|
|
|
19
19
|
13. Inspect tarball contents for local-only files, credentials, `.env` files, dependency
|
|
20
20
|
folders, generated output, and unrelated repositories.
|
|
21
21
|
14. Install the tarball into a temporary npm prefix and smoke-test the installed CLI.
|
|
22
|
-
15. Smoke-test
|
|
22
|
+
15. Smoke-test human-readable and `--json` output for public commands touched by the
|
|
23
|
+
release. JSON output must include safety flags, `recommendedNextAction`, and
|
|
24
|
+
`exitCodeMeaning` without secrets or `.env` contents.
|
|
25
|
+
16. Smoke-test any new CLI command such as `coding-agent-skills route-trace`,
|
|
23
26
|
`coding-agent-skills env-audit`, `coding-agent-skills secret-audit`,
|
|
24
27
|
`coding-agent-skills api-contract-audit`, `coding-agent-skills migration-review`,
|
|
25
28
|
`coding-agent-skills github-handoff`, or `coding-agent-skills deployment-preflight`
|
|
26
29
|
against synthetic fixtures only unless a real project read-only smoke is explicitly
|
|
27
30
|
approved.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
17. Review changelog, ledger, run evidence, and versioning impact.
|
|
32
|
+
18. Commit with approved identity.
|
|
33
|
+
19. Push `main` using credential-free remotes.
|
|
34
|
+
20. Confirm a clean synchronized worktree.
|
|
35
|
+
21. Create and push the annotated version tag.
|
|
36
|
+
22. Publish with `npm publish --access public --registry=https://registry.npmjs.org/`.
|
|
37
|
+
23. Install the published package into a temporary prefix and smoke-test the installed CLI.
|
|
38
|
+
24. Create the GitHub Release for the pushed tag.
|
|
36
39
|
|
|
37
40
|
Deployments, migrations, runtime mutation, platform actions, and target-project builds or
|
|
38
41
|
tests remain outside this release process unless separately approved.
|
|
@@ -7,7 +7,7 @@ safety model.
|
|
|
7
7
|
## Current Package Shape
|
|
8
8
|
|
|
9
9
|
- Package name: `coding-agent-skills`.
|
|
10
|
-
- Package version: `0.2.
|
|
10
|
+
- Package version: `0.2.16`.
|
|
11
11
|
- CLI bin: `coding-agent-skills` mapped to `bin/coding-agent-skills`.
|
|
12
12
|
- Module type: `module`.
|
|
13
13
|
- Dependencies: none.
|
|
@@ -37,6 +37,18 @@ coding-agent-skills deployment-preflight /path/to/project
|
|
|
37
37
|
coding-agent-skills validate-adapters /path/to/adapter-root
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
Each public command also supports optional machine-readable output:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
coding-agent-skills repo-map /path/to/project --json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The JSON contract is intended for OpenClaw-style orchestrators that already own memory,
|
|
47
|
+
routing, approvals, scheduling, and workflow state. It includes `success`, `status`,
|
|
48
|
+
`command`, `skillId`, `packageVersion`, sanitized findings and warnings, safety flags,
|
|
49
|
+
`recommendedNextAction`, and `exitCodeMeaning`. The default human-readable output is
|
|
50
|
+
unchanged.
|
|
51
|
+
|
|
40
52
|
The package can also be executed without a repo-local install:
|
|
41
53
|
|
|
42
54
|
```bash
|
|
@@ -112,3 +124,11 @@ already permits a bounded local validation action. The installed `repo-map`,
|
|
|
112
124
|
|
|
113
125
|
Project adapters narrow context for safer repository understanding; they do not weaken
|
|
114
126
|
shared restrictions or authorize additional command families.
|
|
127
|
+
|
|
128
|
+
## Exit Codes
|
|
129
|
+
|
|
130
|
+
- `0`: handled execution path, including complete, partial, blocked, or controlled audit result
|
|
131
|
+
- `2`: usage error
|
|
132
|
+
- `3`: safety refusal
|
|
133
|
+
- `4`: missing required input or file
|
|
134
|
+
- `5`: unexpected internal or runtime failure
|
package/docs/testing/README.md
CHANGED
|
@@ -126,6 +126,14 @@ compatibility, schema drift, restriction weakening, evidence removal, failure su
|
|
|
126
126
|
completion override, mode escalation, `.env` avoidance, traversal, symlinks, and mutation
|
|
127
127
|
snapshots. Chain summaries use ordinal revision labels rather than directory names.
|
|
128
128
|
|
|
129
|
+
## OpenClaw-Compatible CLI JSON
|
|
130
|
+
|
|
131
|
+
Public CLI tests exercise `--json` for every exposed command. The contract must remain
|
|
132
|
+
valid JSON, preserve default human-readable output, include safety flags and
|
|
133
|
+
`recommendedNextAction`, use handled exit semantics for successful/partial audit results,
|
|
134
|
+
redact local home paths, and avoid token, private-key, authorization-header, or `.env`
|
|
135
|
+
contents.
|
|
136
|
+
|
|
129
137
|
## Evidence Bundles
|
|
130
138
|
|
|
131
139
|
Disposable evidence bundles cover valid replay, hash mismatch, missing entries,
|
package/docs/usage/README.md
CHANGED
|
@@ -117,6 +117,50 @@ The installed CLI does not run target project builds or tests, perform runtime c
|
|
|
117
117
|
deploy, migrate, mutate services or processes, or read `.env` files. Project adapters
|
|
118
118
|
narrow context; they do not grant additional power or weaken shared restrictions.
|
|
119
119
|
|
|
120
|
+
## Machine-Readable Output
|
|
121
|
+
|
|
122
|
+
Every public CLI command accepts optional `--json` for OpenClaw-style tool callers:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
coding-agent-skills repo-map /path/to/project --json
|
|
126
|
+
coding-agent-skills validate-pack --json
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The default human-readable output is unchanged. JSON output is sanitized and includes:
|
|
130
|
+
|
|
131
|
+
- `success`
|
|
132
|
+
- `status`
|
|
133
|
+
- `tool`
|
|
134
|
+
- `command`
|
|
135
|
+
- `skillId`
|
|
136
|
+
- `packageVersion`
|
|
137
|
+
- `mode`
|
|
138
|
+
- `changedState`
|
|
139
|
+
- `summary`
|
|
140
|
+
- `findings`
|
|
141
|
+
- `warnings`
|
|
142
|
+
- `risks`
|
|
143
|
+
- `skipped`
|
|
144
|
+
- `notVerified`
|
|
145
|
+
- `refusedBehavior`
|
|
146
|
+
- `adapter`
|
|
147
|
+
- `recommendedNextAction`
|
|
148
|
+
- `safety`
|
|
149
|
+
- `exitCode`
|
|
150
|
+
- `exitCodeMeaning`
|
|
151
|
+
|
|
152
|
+
Exit-code semantics:
|
|
153
|
+
|
|
154
|
+
- `0`: handled execution path, including complete, partial, blocked, or controlled audit result
|
|
155
|
+
- `2`: usage error
|
|
156
|
+
- `3`: safety refusal
|
|
157
|
+
- `4`: missing required input or file
|
|
158
|
+
- `5`: unexpected internal or runtime failure
|
|
159
|
+
|
|
160
|
+
OpenClaw or another orchestrator should own memory, routing, permissions, scheduling,
|
|
161
|
+
chat/user interaction, and workflow state. This package remains a read-only external tool
|
|
162
|
+
and evidence producer.
|
|
163
|
+
|
|
120
164
|
## Local Command Surface
|
|
121
165
|
|
|
122
166
|
From the shared skill repository root, the same wrapper can be used directly:
|
package/package.json
CHANGED
package/runs/skill-runs.md
CHANGED
|
@@ -277,6 +277,23 @@ This file records bounded maintainer-loop runs. Entries must not contain secrets
|
|
|
277
277
|
API calls, no provider CLI execution, no package installs, no builds, no tests, no
|
|
278
278
|
runtime checks, no service mutation, no deployments, no migrations, and no target-project
|
|
279
279
|
mutation.
|
|
280
|
+
- Validation commands: full source validation, package dry-run, tarball smoke, registry
|
|
281
|
+
install smoke, npm exec, and GitHub Release verification.
|
|
282
|
+
- Result: passed; `v0.2.15` was committed, pushed, tagged, published to npm, smoke-tested
|
|
283
|
+
from the registry, and released on GitHub.
|
|
284
|
+
- Commit/tag/push status: complete.
|
|
285
|
+
|
|
286
|
+
## implementation-v0.2.16-openclaw-json-output
|
|
287
|
+
|
|
288
|
+
- Run ID: `implementation-v0.2.16-openclaw-json-output`
|
|
289
|
+
- Repository: `/home/oneclickwebsitedesignfactory/coding-agent-skills`
|
|
290
|
+
- Command used: `bounded approval for OpenClaw-compatible JSON output and exit-code contract`
|
|
291
|
+
- Files changed: CLI wrapper, release tests, usage/release/testing docs, changelog,
|
|
292
|
+
roadmap, work ledger, run log, and package metadata.
|
|
293
|
+
- Safety boundary: read-only machine-readable output only; no `.env` reads, no OpenClaw
|
|
294
|
+
modification, no OpenClaw plugin code, no cron or memory integration, no real project
|
|
295
|
+
repository mutation, no target-project builds/tests/runtime checks, no deployments, no
|
|
296
|
+
migrations, and no dependency changes.
|
|
280
297
|
- Validation commands: pending final release validation matrix.
|
|
281
298
|
- Result: pass pending final publication evidence.
|
|
282
299
|
- Commit/tag/push status: pending approved release workflow.
|
package/scripts/test-pack.mjs
CHANGED
|
@@ -221,6 +221,39 @@ function snapshotAbsoluteDirectory(directory) {
|
|
|
221
221
|
return digest.digest("hex");
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
function assertOpenClawJsonContract(value, command, packageVersion = "0.2.16") {
|
|
225
|
+
assert.equal(value.tool, "coding-agent-skills");
|
|
226
|
+
assert.equal(value.command, command);
|
|
227
|
+
assert.equal(value.packageVersion, packageVersion);
|
|
228
|
+
assert.equal(value.success, true);
|
|
229
|
+
assert.match(value.status, /^(complete|partial|blocked|failed|empty)$/);
|
|
230
|
+
assert.equal(value.changedState, false);
|
|
231
|
+
assert.equal(value.safety?.readOnly, true);
|
|
232
|
+
assert.equal(value.safety?.secretsRead, false);
|
|
233
|
+
assert.equal(value.safety?.targetCommandsRun, false);
|
|
234
|
+
assert.equal(value.safety?.mutationsPerformed, false);
|
|
235
|
+
assert.equal(value.exitCode, 0);
|
|
236
|
+
assert.equal(value.exitCodeMeaning, "handled");
|
|
237
|
+
assert.ok(value.recommendedNextAction);
|
|
238
|
+
assert.equal(typeof value.recommendedNextAction.label, "string");
|
|
239
|
+
assert.equal(typeof value.recommendedNextAction.reason, "string");
|
|
240
|
+
assert.equal(typeof value.recommendedNextAction.requiresApproval, "boolean");
|
|
241
|
+
for (const key of [
|
|
242
|
+
"summary",
|
|
243
|
+
"findings",
|
|
244
|
+
"warnings",
|
|
245
|
+
"risks",
|
|
246
|
+
"skipped",
|
|
247
|
+
"notVerified",
|
|
248
|
+
"refusedBehavior",
|
|
249
|
+
]) {
|
|
250
|
+
assert.ok(Array.isArray(value[key]), `${command}.${key} must be an array`);
|
|
251
|
+
}
|
|
252
|
+
const encoded = JSON.stringify(value);
|
|
253
|
+
assert.doesNotMatch(encoded, /github_pat_|ghp_|Authorization:\s*Bearer|BEGIN .*PRIVATE KEY/i);
|
|
254
|
+
assert.doesNotMatch(encoded, /\/home\/oneclickwebsitedesignfactory\//);
|
|
255
|
+
}
|
|
256
|
+
|
|
224
257
|
const manifestSchema = readJson("schemas/skill-manifest.schema.json");
|
|
225
258
|
const policySchema = readJson("schemas/command-policy.schema.json");
|
|
226
259
|
const adapterSchema = readJson("schemas/project-adapter.schema.json");
|
|
@@ -394,10 +427,68 @@ test("local CLI maps approved commands to existing safe scripts", () => {
|
|
|
394
427
|
assert.match(unknown.stderr, /unknown command: deploy/);
|
|
395
428
|
});
|
|
396
429
|
|
|
430
|
+
test("local CLI emits OpenClaw-compatible JSON for public commands", () => {
|
|
431
|
+
const cliPath = path.join(root, "bin", "coding-agent-skills");
|
|
432
|
+
const fixtureRoot = path.join(root, "tests", "fixtures");
|
|
433
|
+
const githubHandoffFixture = createGitFixture(
|
|
434
|
+
path.join("tests", "fixtures", "github-handoff", "static-project"),
|
|
435
|
+
);
|
|
436
|
+
fs.appendFileSync(path.join(githubHandoffFixture, "README.md"), "\nLocal handoff change.\n");
|
|
437
|
+
|
|
438
|
+
const commands = [
|
|
439
|
+
["validate-pack"],
|
|
440
|
+
["validate-adapters", path.join(fixtureRoot, "external-adapters", "valid-basic")],
|
|
441
|
+
[
|
|
442
|
+
"validate-project",
|
|
443
|
+
path.join(fixtureRoot, "project-adapter-installation", "valid-exact-pin"),
|
|
444
|
+
],
|
|
445
|
+
["repo-map", path.join(fixtureRoot, "project-adapter-installation", "valid-exact-pin")],
|
|
446
|
+
["route-trace", path.join(fixtureRoot, "route-trace", "static-project")],
|
|
447
|
+
["env-audit", path.join(fixtureRoot, "env-audit", "static-project")],
|
|
448
|
+
["secret-audit", path.join(fixtureRoot, "secret-audit", "static-project")],
|
|
449
|
+
["api-contract-audit", path.join(fixtureRoot, "api-contract-audit", "static-project")],
|
|
450
|
+
["migration-review", path.join(fixtureRoot, "migration-review", "static-project")],
|
|
451
|
+
["github-handoff", githubHandoffFixture],
|
|
452
|
+
["deployment-preflight", path.join(fixtureRoot, "deployment-preflight", "static-project")],
|
|
453
|
+
];
|
|
454
|
+
|
|
455
|
+
for (const args of commands) {
|
|
456
|
+
const result = spawnSync(cliPath, [...args, "--json"], {
|
|
457
|
+
cwd: root,
|
|
458
|
+
encoding: "utf8",
|
|
459
|
+
stdio: "pipe",
|
|
460
|
+
});
|
|
461
|
+
assert.equal(result.status, 0, `${args.join(" ")}\n${result.stderr}`);
|
|
462
|
+
assert.equal(result.stderr, "");
|
|
463
|
+
const parsed = JSON.parse(result.stdout);
|
|
464
|
+
assertOpenClawJsonContract(parsed, args[0]);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const partial = spawnSync(
|
|
468
|
+
cliPath,
|
|
469
|
+
[
|
|
470
|
+
"deployment-preflight",
|
|
471
|
+
path.join(fixtureRoot, "project-adapter-installation", "valid-exact-pin"),
|
|
472
|
+
"--json",
|
|
473
|
+
],
|
|
474
|
+
{
|
|
475
|
+
cwd: root,
|
|
476
|
+
encoding: "utf8",
|
|
477
|
+
stdio: "pipe",
|
|
478
|
+
},
|
|
479
|
+
);
|
|
480
|
+
assert.equal(partial.status, 0);
|
|
481
|
+
const parsedPartial = JSON.parse(partial.stdout);
|
|
482
|
+
assertOpenClawJsonContract(parsedPartial, "deployment-preflight");
|
|
483
|
+
assert.equal(parsedPartial.status, "partial");
|
|
484
|
+
assert.ok(parsedPartial.skipped.length > 0);
|
|
485
|
+
assert.ok(parsedPartial.refusedBehavior.includes("no deployments"));
|
|
486
|
+
});
|
|
487
|
+
|
|
397
488
|
test("npm package metadata is public-ready and dependency-free", () => {
|
|
398
489
|
const packageJson = readJson("package.json");
|
|
399
490
|
assert.equal(packageJson.name, "coding-agent-skills");
|
|
400
|
-
assert.equal(packageJson.version, "0.2.
|
|
491
|
+
assert.equal(packageJson.version, "0.2.16");
|
|
401
492
|
assert.equal(
|
|
402
493
|
packageJson.description,
|
|
403
494
|
"Evidence-first, read-only coding-agent skills and project adapter tooling.",
|
|
@@ -687,8 +687,8 @@ if (packageJson) {
|
|
|
687
687
|
if (packageJson.name !== "coding-agent-skills") {
|
|
688
688
|
failures.push("package.json has unexpected package name");
|
|
689
689
|
}
|
|
690
|
-
if (packageJson.version !== "0.2.
|
|
691
|
-
failures.push("package.json version must be 0.2.
|
|
690
|
+
if (packageJson.version !== "0.2.16") {
|
|
691
|
+
failures.push("package.json version must be 0.2.16 for public package validation");
|
|
692
692
|
}
|
|
693
693
|
if (packageJson.type !== "module") failures.push("package.json must preserve ESM mode");
|
|
694
694
|
if (packageJson.private !== false) {
|
package/work-ledger.md
CHANGED
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
- First external project-owned adapter adoption completed for `/home/oneclickwebsitedesignfactory/tax-lien-platform` at candidate commit `c548b1a6cbb3455a70b89d0e301e22435bfccac9`.
|
|
11
11
|
- The adopted adapter is `repo-map` only, docs/metadata-only, and contains no commands, runtime checks, build/test/package behavior, platform/deployment behavior, or secret-aware behavior.
|
|
12
12
|
- The shared repository does not contain real adapter manifests; real project adapters remain owned by their project repositories.
|
|
13
|
-
- Public npm package release `v0.2.
|
|
13
|
+
- Public npm package release `v0.2.16` exposes the dependency-free
|
|
14
14
|
`coding-agent-skills` CLI under MIT license.
|
|
15
|
+
- `v0.2.16` adds optional OpenClaw-compatible `--json` output and documented
|
|
16
|
+
exit-code semantics for every public CLI command.
|
|
15
17
|
- `route-trace` is implemented as an audit-only static route tracing skill.
|
|
16
18
|
- `env-audit` is implemented as an audit-only value-free environment variable name mapping
|
|
17
19
|
skill.
|
|
@@ -28,14 +30,14 @@
|
|
|
28
30
|
|
|
29
31
|
## Last Completed Version
|
|
30
32
|
|
|
31
|
-
`v0.2.
|
|
33
|
+
`v0.2.16`
|
|
32
34
|
|
|
33
35
|
## Current Recommended Milestone
|
|
34
36
|
|
|
35
|
-
The
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
`cloudflare-preflight-skill`.
|
|
37
|
+
The OpenClaw-compatible JSON output contract is the current release milestone. After
|
|
38
|
+
`v0.2.16` is published and verified, continue the remaining read-only skill wave one
|
|
39
|
+
release at a time unless a real safety, validation, publication, or authentication
|
|
40
|
+
boundary appears. The next approved wave item remains `cloudflare-preflight-skill`.
|
|
39
41
|
|
|
40
42
|
## Allowed Next Actions
|
|
41
43
|
|
|
@@ -122,9 +124,20 @@ No autonomous maintainer-loop run has been recorded yet.
|
|
|
122
124
|
- Implemented milestone: `deployment-preflight` audit-only static deployment readiness
|
|
123
125
|
evidence skill and CLI command.
|
|
124
126
|
- Required permission: `builder-mode-skill-implementation`
|
|
125
|
-
- Validation result:
|
|
127
|
+
- Validation result: passed; `v0.2.15` commit, tag, npm publication, registry smoke,
|
|
128
|
+
npm exec, and GitHub Release completed
|
|
129
|
+
- Next recommended milestone: implement the OpenClaw-compatible JSON output and exit-code
|
|
130
|
+
contract before continuing to `cloudflare-preflight-skill`.
|
|
131
|
+
|
|
132
|
+
### 2026-07-03T15:00:00Z
|
|
133
|
+
|
|
134
|
+
- Latest tag observed: `v0.2.15`
|
|
135
|
+
- Implemented milestone: OpenClaw-compatible optional `--json` output and documented
|
|
136
|
+
exit-code semantics for every public CLI command.
|
|
137
|
+
- Required permission: `orchestrator-output-contract`
|
|
138
|
+
- Validation result: pass pending final release validation matrix
|
|
126
139
|
- Next recommended milestone: continue builder-mode wave with `cloudflare-preflight-skill`
|
|
127
|
-
after `v0.2.
|
|
140
|
+
after `v0.2.16` publication completes.
|
|
128
141
|
|
|
129
142
|
### 2026-07-03T12:00:00Z
|
|
130
143
|
|