coding-agent-skills 0.2.16 → 0.2.17

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 CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  All notable changes follow [Semantic Versioning](docs/versioning/README.md).
4
4
 
5
+ ## [0.2.17] - 2026-07-04
6
+
7
+ ### Changed
8
+
9
+ - `repo-map` now supports generic safe discovery when no `.coding-agent` project declaration exists.
10
+ - JSON output now reports `adapterPresent: false`, `mode: generic-safe-discovery`, reduced confidence, `changedState: false`, no target-project commands, and no secret-file reads for no-adapter repo-map runs.
11
+ - Invalid or unsafe project adapters still fail closed instead of falling back silently.
12
+ - Usage, adapter, and release documentation now clarify that adapters are optional hints, not mandatory requirements.
13
+
5
14
  ## [0.2.16] - 2026-07-03
6
15
 
7
16
  ### Added
package/README.md CHANGED
@@ -60,7 +60,8 @@ Every skill emits the evidence-pack contract. A command being attempted is never
60
60
  - Run `node scripts/validate-adapters.mjs <adapter-root>` for a disposable external root.
61
61
  - Review [project-owned installation and pinning](docs/adapters/project-installation.md).
62
62
  - Run `node scripts/validate-project-adapters.mjs <project-root>` for a declared project root.
63
- - Render adapter-aware `repo-map` orientation with
63
+ - Render repo-map orientation with optional adapter hints and generic safe
64
+ discovery when no adapter is present:
64
65
  `node scripts/render-adapter-repo-map.mjs <project-root>`.
65
66
  - Render a static route-trace report with
66
67
  `node scripts/render-route-trace.mjs <project-root>`.
@@ -118,6 +119,12 @@ OpenClaw should remain the owner of memory, routing, permissions, scheduling, us
118
119
  interaction, and workflow state. `coding-agent-skills` is a safe callable evidence
119
120
  producer, not an orchestrator.
120
121
 
122
+ Adapters are optional hints, not a prerequisite for safe orientation. `repo-map`
123
+ falls back to `generic-safe-discovery` when no `.coding-agent` declaration exists,
124
+ marks `adapterPresent: false`, reduces confidence, and still refuses target project
125
+ builds, tests, runtime checks, deploys, migrations, package installs, and secret-file
126
+ reads.
127
+
121
128
  ## Autonomous Maintainer Loop
122
129
 
123
130
  The local maintainer loop reads Git tags, `ROADMAP.md`, `CHANGELOG.md`, and
@@ -42,8 +42,8 @@ const commandMetadata = {
42
42
  skillId: "repo-map",
43
43
  mode: "audit-only",
44
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.",
45
+ label: "Review reported repo boundaries",
46
+ reason: "Use the reported docs, safe paths, ignored paths, adapter status, confidence, and evidence requirements before choosing another action.",
47
47
  requiresApproval: false,
48
48
  },
49
49
  },
@@ -35,6 +35,12 @@ ignored paths, required evidence, package-manager hints, repository bounds, and
35
35
  Git branch state. It does not read target project file contents, run project tests or
36
36
  builds, install packages, perform runtime checks, deploy, migrate, or read `.env` files.
37
37
 
38
+ Adapters are optional hints, not mandatory gates. If no `.coding-agent` declaration is
39
+ present, `repo-map` falls back to `generic-safe-discovery`, reports `adapterPresent: false`,
40
+ uses reduced confidence, applies built-in ignored paths, and still refuses target project
41
+ builds, tests, runtime checks, deployments, migrations, package installs, and secret-file
42
+ reads. Invalid or weakening adapters still fail closed.
43
+
38
44
  This is agent context for safer repository understanding. It is not target-application
39
45
  product behavior.
40
46
 
@@ -109,6 +109,12 @@ The renderer is metadata-only. It does not read target project file contents, ru
109
109
  project tests, run builds, install packages, perform runtime checks, deploy, migrate, read
110
110
  `.env` files, or modify project state.
111
111
 
112
+ Project adapters are optional hints. If no project declaration exists, `repo-map` still
113
+ runs a bounded `generic-safe-discovery` report with `adapterPresent: false`, reduced
114
+ confidence, built-in ignored paths, and explicit no-secret/no-build/no-runtime safety
115
+ warnings. A declared adapter that is invalid, unsafe, or incompatible remains a hard
116
+ failure.
117
+
112
118
  A project-owned adapter can also enable read-only `route-trace` context:
113
119
 
114
120
  ```bash
@@ -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.16`.
10
+ - Package version: `0.2.17`.
11
11
  - CLI bin: `coding-agent-skills` mapped to `bin/coding-agent-skills`.
12
12
  - Module type: `module`.
13
13
  - Dependencies: none.
@@ -41,16 +41,18 @@ Select the least-privileged skill that matches the request:
41
41
 
42
42
  Every skill emits an evidence pack. Read `status`, skipped checks, failures, confidence, and changed state before relying on a completion claim.
43
43
 
44
- When a project owns a compatible adapter, render read-only adapter-aware `repo-map` context
45
- with:
44
+ Render read-only `repo-map` context with:
46
45
 
47
46
  ```bash
48
47
  node scripts/render-adapter-repo-map.mjs <project-root>
49
48
  ```
50
49
 
51
- This validates the project adapter first, then reports adapter-declared documentation
52
- precedence, safe read paths, ignored paths, and required evidence. It is not a build,
53
- test, runtime, deployment, migration, package-install, or secret-reading flow.
50
+ When a project owns a compatible adapter, this validates the adapter first and reports
51
+ adapter-declared documentation precedence, safe read paths, ignored paths, and required
52
+ evidence. When no `.coding-agent` declaration exists, adapters remain optional: `repo-map`
53
+ uses `generic-safe-discovery`, reports `adapterPresent: false`, reduces confidence, and
54
+ still refuses builds, tests, runtime checks, deployments, migrations, package installs, and
55
+ secret-file reads.
54
56
 
55
57
  See [examples](../../examples/README.md) for safe concrete inputs and outputs.
56
58
 
@@ -85,8 +87,8 @@ npx coding-agent-skills validate-pack
85
87
  ```
86
88
 
87
89
  These commands wrap the same validated scripts shipped in the repository. `repo-map`
88
- validates the project adapter first, then renders adapter-declared documentation
89
- precedence, safe read paths, ignored paths, and required evidence.
90
+ uses adapter metadata when present and valid; otherwise it falls back to generic safe
91
+ discovery with reduced confidence and clear adapter-absence warnings.
90
92
  `route-trace` validates a project adapter when present, uses adapter-declared safe paths
91
93
  when enabled, and statically reports verified route files, inferred route declarations,
92
94
  skipped items, and not-verified runtime-dependent route classes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coding-agent-skills",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "Evidence-first, read-only coding-agent skills and project adapter tooling.",
5
5
  "type": "module",
6
6
  "private": false,
@@ -30,6 +30,87 @@ const REFUSED_BEHAVIOR = [
30
30
  "no project writes",
31
31
  ];
32
32
 
33
+ const GENERIC_IGNORED_PATHS = [
34
+ ".git",
35
+ ".env",
36
+ ".env.*",
37
+ ".next",
38
+ ".nuxt",
39
+ ".output",
40
+ ".turbo",
41
+ ".cache",
42
+ "node_modules",
43
+ "dist",
44
+ "build",
45
+ "coverage",
46
+ "validation-output",
47
+ "supabase/.temp",
48
+ "secrets",
49
+ "tokens",
50
+ "credentials",
51
+ "private",
52
+ ];
53
+
54
+ const GENERIC_DOCUMENTATION_PRECEDENCE = [
55
+ "README.md",
56
+ "docs/README.md",
57
+ "docs/kb/README.md",
58
+ "AGENTS.md",
59
+ "CLAUDE.md",
60
+ "RUNBOOK.md",
61
+ "CONTRIBUTING.md",
62
+ ];
63
+
64
+ const GENERIC_SAFE_READ_PATHS = [
65
+ "README.md",
66
+ "docs",
67
+ "app",
68
+ "apps",
69
+ "src",
70
+ "lib",
71
+ "pages",
72
+ "components",
73
+ "server",
74
+ "api",
75
+ "routes",
76
+ "services",
77
+ "packages",
78
+ "schemas",
79
+ "scripts",
80
+ "tests",
81
+ "package.json",
82
+ "tsconfig.json",
83
+ "vite.config.ts",
84
+ "vite.config.js",
85
+ "next.config.ts",
86
+ "next.config.js",
87
+ ];
88
+
89
+ const GENERIC_ROOT_MARKERS = [
90
+ "README.md",
91
+ "package.json",
92
+ "pnpm-lock.yaml",
93
+ "package-lock.json",
94
+ "yarn.lock",
95
+ "bun.lockb",
96
+ "tsconfig.json",
97
+ "vite.config.ts",
98
+ "vite.config.js",
99
+ "next.config.ts",
100
+ "next.config.js",
101
+ "pyproject.toml",
102
+ "Cargo.toml",
103
+ "go.mod",
104
+ ];
105
+
106
+ const PACKAGE_MANAGER_MARKERS = [
107
+ ["pnpm-lock.yaml", "pnpm"],
108
+ ["package-lock.json", "npm"],
109
+ ["yarn.lock", "yarn"],
110
+ ["bun.lockb", "bun"],
111
+ ["package.json", "npm-compatible"],
112
+ ];
113
+
33
114
  function inside(root, candidate) {
34
115
  const relative = path.relative(root, candidate);
35
116
  return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
@@ -90,6 +171,28 @@ function describeApprovedPath(projectRoot, relativePath) {
90
171
  };
91
172
  }
92
173
 
174
+ function existingPathRecords(projectRoot, candidates) {
175
+ return candidates
176
+ .map((relativePath) => describeApprovedPath(projectRoot, relativePath))
177
+ .filter((record) => record.status === "present");
178
+ }
179
+
180
+ function genericRootMarkers(projectRoot) {
181
+ return GENERIC_ROOT_MARKERS
182
+ .map((relativePath) => describeApprovedPath(projectRoot, relativePath))
183
+ .filter((record) => record.status === "present")
184
+ .map((record) => ({
185
+ kind: record.type,
186
+ path: record.path,
187
+ }));
188
+ }
189
+
190
+ function genericPackageManagers(projectRoot) {
191
+ return PACKAGE_MANAGER_MARKERS
192
+ .filter(([relativePath]) => describeApprovedPath(projectRoot, relativePath).status === "present")
193
+ .map(([, manager]) => manager);
194
+ }
195
+
93
196
  function gitSummary(projectRoot) {
94
197
  const summary = {
95
198
  root: null,
@@ -174,30 +277,92 @@ function loadRepoMapAdapters(loaded) {
174
277
 
175
278
  export function buildAdapterRepoMapReport(projectRootInput, options = {}) {
176
279
  const coreRoot = path.resolve(options.coreRoot ?? DEFAULT_CORE_ROOT);
177
- const validation = validateProjectAdapters(projectRootInput, { coreRoot });
178
- if (!validation.ok) {
280
+ const loaded = readProjectAdapterDeclaration(projectRootInput);
281
+ if (!loaded.ok) {
282
+ if (loaded.codes.length === 1 && loaded.codes[0] === "missing-project-declaration") {
283
+ const projectRoot = fs.realpathSync(path.resolve(projectRootInput));
284
+ const git = gitSummary(projectRoot);
285
+ return {
286
+ ok: true,
287
+ status: "complete",
288
+ coreVersion: PILOT_VERSION,
289
+ projectRoot,
290
+ declarationPath: "not present",
291
+ adapterRoot: "not present",
292
+ projectId: "not declared",
293
+ adapterIds: [],
294
+ manifestPaths: [],
295
+ enabledSkills: ["repo-map"],
296
+ adapter: {
297
+ present: false,
298
+ enabled: false,
299
+ mode: "generic-safe-discovery",
300
+ codes: ["missing-project-declaration"],
301
+ },
302
+ adapterPresent: false,
303
+ mode: "generic-safe-discovery",
304
+ confidence: "reduced",
305
+ rootMarkers: genericRootMarkers(projectRoot),
306
+ maximumDepth: 2,
307
+ scope: "generic-project-root",
308
+ requireApprovalOutsideScope: true,
309
+ documentationPrecedence: existingPathRecords(projectRoot, GENERIC_DOCUMENTATION_PRECEDENCE),
310
+ safeReadPaths: existingPathRecords(projectRoot, GENERIC_SAFE_READ_PATHS),
311
+ ignoredPaths: GENERIC_IGNORED_PATHS,
312
+ requiredEvidence: [
313
+ "repository root markers",
314
+ "bounded generic file/directory inventory",
315
+ "adapter absence evidence",
316
+ ],
317
+ packageManagers: unique(genericPackageManagers(projectRoot)),
318
+ git,
319
+ warnings: unique([
320
+ ...git.warnings,
321
+ "adapterPresent: false",
322
+ "mode: generic-safe-discovery",
323
+ "reduced confidence; adapter-provided project intent is unavailable",
324
+ "no project adapter declaration found; repo-map used generic bounded discovery",
325
+ "no target project build, test, runtime, deployment, migration, package, or secret-reading command was performed",
326
+ "no secrets read",
327
+ ]),
328
+ refusedBehavior: REFUSED_BEHAVIOR,
329
+ validation: {
330
+ ok: false,
331
+ status: "failed",
332
+ acceptedAdapters: 0,
333
+ acceptedSkills: [],
334
+ codes: ["missing-project-declaration"],
335
+ },
336
+ };
337
+ }
179
338
  return {
180
339
  ok: false,
181
340
  status: "failed",
182
- codes: validation.codes,
183
- validation,
341
+ codes: loaded.codes,
342
+ validation: {
343
+ ok: false,
344
+ status: "failed",
345
+ acceptedAdapters: 0,
346
+ acceptedSkills: [],
347
+ codes: loaded.codes,
348
+ },
184
349
  };
185
350
  }
186
- if (!validation.acceptedSkills.includes("repo-map")) {
351
+
352
+ const validation = validateProjectAdapters(loaded.projectRoot, { coreRoot });
353
+ if (!validation.ok) {
187
354
  return {
188
355
  ok: false,
189
356
  status: "failed",
190
- codes: ["repo-map-not-enabled"],
357
+ codes: validation.codes,
191
358
  validation,
192
359
  };
193
360
  }
194
-
195
- const loaded = readProjectAdapterDeclaration(projectRootInput);
196
- if (!loaded.ok) {
361
+ if (!validation.acceptedSkills.includes("repo-map")) {
197
362
  return {
198
363
  ok: false,
199
364
  status: "failed",
200
- codes: loaded.codes,
365
+ codes: ["repo-map-not-enabled"],
201
366
  validation,
202
367
  };
203
368
  }
@@ -246,6 +411,15 @@ export function buildAdapterRepoMapReport(projectRootInput, options = {}) {
246
411
  adapterIds: adapters.map((adapter) => adapter.manifest.adapterId).sort(),
247
412
  manifestPaths: adapters.map((adapter) => adapter.manifestPath).sort(),
248
413
  enabledSkills: ["repo-map"],
414
+ adapter: {
415
+ present: true,
416
+ enabled: true,
417
+ mode: "adapter-limited",
418
+ codes: [],
419
+ },
420
+ adapterPresent: true,
421
+ mode: "adapter-limited",
422
+ confidence: "adapter-declared",
249
423
  rootMarkers,
250
424
  maximumDepth,
251
425
  scope: "declared-project-root",
@@ -294,10 +468,16 @@ export function renderAdapterRepoMapReport(report) {
294
468
  `Project root: ${redactSensitiveText(report.projectRoot)}`,
295
469
  `Declaration: ${report.declarationPath}`,
296
470
  `Adapter root: ${report.adapterRoot}`,
297
- `Adapter IDs: ${report.adapterIds.join(", ")}`,
298
- `Adapter manifests: ${report.manifestPaths.join(", ")}`,
471
+ `Adapter IDs: ${report.adapterIds.length ? report.adapterIds.join(", ") : "none"}`,
472
+ `Adapter manifests: ${report.manifestPaths.length ? report.manifestPaths.join(", ") : "none"}`,
299
473
  `Enabled skills: ${report.enabledSkills.join(", ")}`,
300
474
  "",
475
+ "## Adapter Scope",
476
+ `- Adapter present: ${report.adapterPresent ? "yes" : "no"}`,
477
+ `- Repo-map enabled: ${report.adapter?.enabled ? "yes" : "generic fallback"}`,
478
+ `- Mode: ${report.mode}`,
479
+ `- Confidence: ${report.confidence}`,
480
+ "",
301
481
  "## Git State",
302
482
  `- Git root: ${redactSensitiveText(report.git.root ?? "not detected")}`,
303
483
  `- Branch state: ${redactSensitiveText(report.git.branchState ?? "not detected")}`,
@@ -334,6 +514,8 @@ export function renderAdapterRepoMapReport(report) {
334
514
  ...formatList("Refused Behavior", report.refusedBehavior),
335
515
  "",
336
516
  "No target project build, test, runtime, deployment, migration, package installation, or secret-file read was performed.",
517
+ "No project commands beyond safe repository metadata inspection were performed.",
518
+ "No secrets were read.",
337
519
  ];
338
520
 
339
521
  return lines.join("\n");
@@ -221,7 +221,7 @@ function snapshotAbsoluteDirectory(directory) {
221
221
  return digest.digest("hex");
222
222
  }
223
223
 
224
- function assertOpenClawJsonContract(value, command, packageVersion = "0.2.16") {
224
+ function assertOpenClawJsonContract(value, command, packageVersion = "0.2.17") {
225
225
  assert.equal(value.tool, "coding-agent-skills");
226
226
  assert.equal(value.command, command);
227
227
  assert.equal(value.packageVersion, packageVersion);
@@ -378,6 +378,10 @@ test("local CLI maps approved commands to existing safe scripts", () => {
378
378
  ["repo-map", path.join(fixtureRoot, "project-adapter-installation", "valid-exact-pin")],
379
379
  /# Adapter-Aware Repo Map/,
380
380
  ],
381
+ [
382
+ ["repo-map", path.join(fixtureRoot, "sample-repo")],
383
+ /generic-safe-discovery/,
384
+ ],
381
385
  [
382
386
  ["route-trace", path.join(fixtureRoot, "route-trace", "static-project")],
383
387
  /# Route Trace Report/,
@@ -443,6 +447,7 @@ test("local CLI emits OpenClaw-compatible JSON for public commands", () => {
443
447
  path.join(fixtureRoot, "project-adapter-installation", "valid-exact-pin"),
444
448
  ],
445
449
  ["repo-map", path.join(fixtureRoot, "project-adapter-installation", "valid-exact-pin")],
450
+ ["repo-map", path.join(fixtureRoot, "sample-repo")],
446
451
  ["route-trace", path.join(fixtureRoot, "route-trace", "static-project")],
447
452
  ["env-audit", path.join(fixtureRoot, "env-audit", "static-project")],
448
453
  ["secret-audit", path.join(fixtureRoot, "secret-audit", "static-project")],
@@ -488,7 +493,7 @@ test("local CLI emits OpenClaw-compatible JSON for public commands", () => {
488
493
  test("npm package metadata is public-ready and dependency-free", () => {
489
494
  const packageJson = readJson("package.json");
490
495
  assert.equal(packageJson.name, "coding-agent-skills");
491
- assert.equal(packageJson.version, "0.2.16");
496
+ assert.equal(packageJson.version, "0.2.17");
492
497
  assert.equal(
493
498
  packageJson.description,
494
499
  "Evidence-first, read-only coding-agent skills and project adapter tooling.",
@@ -1769,6 +1774,42 @@ test("adapter-aware repo-map consumes validated project adapter metadata", () =>
1769
1774
  assert.match(rendered, /No target project build, test, runtime, deployment/);
1770
1775
  });
1771
1776
 
1777
+ test("repo-map supports generic safe discovery without a project adapter", () => {
1778
+ const report = buildAdapterRepoMapReport(
1779
+ path.join(root, "tests", "fixtures", "sample-repo"),
1780
+ { coreRoot: root },
1781
+ );
1782
+
1783
+ assert.equal(report.ok, true, report.codes?.join(","));
1784
+ assert.equal(report.adapter.present, false);
1785
+ assert.equal(report.adapter.enabled, false);
1786
+ assert.equal(report.mode, "generic-safe-discovery");
1787
+ assert.equal(report.confidence, "reduced");
1788
+ assert.equal(report.adapterPresent, false);
1789
+ assert.ok(report.validation.codes.includes("missing-project-declaration"));
1790
+ assert.ok(report.warnings.includes("adapterPresent: false"));
1791
+ assert.ok(report.warnings.includes("mode: generic-safe-discovery"));
1792
+ assert.ok(report.warnings.includes("no secrets read"));
1793
+ assert.ok(report.ignoredPaths.includes(".env"));
1794
+ assert.ok(report.ignoredPaths.includes(".env.*"));
1795
+ assert.ok(
1796
+ report.documentationPrecedence.some((record) => record.path === "README.md"),
1797
+ );
1798
+
1799
+ const rendered = renderAdapterRepoMapReport(report);
1800
+ assert.match(rendered, /Adapter present: no/);
1801
+ assert.match(rendered, /Mode: generic-safe-discovery/);
1802
+ assert.match(rendered, /Confidence: reduced/);
1803
+ assert.match(rendered, /No secrets were read/);
1804
+
1805
+ const cli = adapterRepoMapCliResult(path.join(root, "tests", "fixtures", "sample-repo"), {
1806
+ coreRoot: root,
1807
+ });
1808
+ assert.equal(cli.exitCode, 0);
1809
+ assert.equal(cli.stream, "stdout");
1810
+ assert.match(cli.lines.join("\n"), /generic-safe-discovery/);
1811
+ });
1812
+
1772
1813
  test("adapter-aware repo-map fails closed without repo-map compatibility", () => {
1773
1814
  const fixtureRoot = path.join(
1774
1815
  root,
@@ -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.16") {
691
- failures.push("package.json version must be 0.2.16 for public package validation");
690
+ if (packageJson.version !== "0.2.17") {
691
+ failures.push("package.json version must be 0.2.17 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) {