worclaude 2.9.1 → 2.9.3

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
@@ -4,6 +4,48 @@ All notable changes to worclaude are documented in this file. Format loosely fol
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.9.3] — 2026-04-29
8
+
9
+ Security tooling refresh shipped as a paired group: a CI-tooling migration from Snyk (whose free-tier scan limit had blocked the v2.9.2 release PR) to a GitHub-native open-source SCA stack (Dependabot + OSV-Scanner), and the cleanup of the inaugural CodeQL scan after enabling the default setup. CodeQL surfaced 5 findings — 2× High "Incomplete multi-character sanitization" on the project-scanner README detector's HTML-stripping helpers, and 3× Medium "Workflow does not contain permissions" on `ci.yml`'s three jobs — all closed in this release. The sanitization fix extracts a `stripUntilStable(text, regex)` helper for the do-while-until-stable pattern; the permissions fix adds a top-level `permissions: contents: read` block matching the rest of the repo's workflows. SECURITY.md's AI-detected typosquat section also refined with the actual chain context: the `claude` npm package is `bcherny/redirect-claude`, an intentional Boris-Cherny-maintained typosquat-warning redirect, not an abandoned package as previously documented.
10
+
11
+ ### Fixed
12
+
13
+ - **CodeQL findings — incomplete multi-character sanitization** (PR #158) — `stripHtmlComments` and `stripHtmlTags` in `src/core/project-scanner/detectors/readme.js` rewritten to delegate to a private `stripUntilStable(text, regex)` helper that applies the regex repeatedly until stable. Closes the two High-severity `js/incomplete-multi-character-sanitization` alerts. Defense-in-depth: verified during plan-mode that no input distinguishes single-pass from looped output for these specific regex patterns; the fix satisfies the static analyzer without behavioral change.
14
+ - **CodeQL findings — missing workflow permissions** (PR #158) — top-level `permissions: contents: read` added to `.github/workflows/ci.yml`. Closes the three Medium-severity `Workflow does not contain permissions` alerts (`test` matrix, `format-check`, `plugin-validate` jobs). Brings ci.yml in line with the rest of the repo's workflows, all of which already declared explicit permissions.
15
+
16
+ ### Changed
17
+
18
+ - **CI scanner stack: Snyk → Dependabot + OSV-Scanner** (PR #157) — Snyk's free-tier monthly scan limit had blocked the v2.9.2 release PR. Replaced with two free, GitHub-native SCA tools: `.github/dependabot.yml` (npm + github-actions ecosystems, weekly Monday 03:00 UTC, minor/patch grouped, `open-pull-requests-limit: 5`) and `.github/workflows/osv-scanner.yml` invoking `google/osv-scanner-action@v2.3.5` as job-level reusable workflows. SARIF upload routes findings to the Security tab. `.snyk` deleted; `SECURITY.md` and `CONTRIBUTING.md` updated to vendor-neutral language.
19
+ - **SECURITY.md typosquat-alert section** (PR #158) — refined to document Socket's chain inference (`worclaude` → `claude` → `@anthropic-ai/claude-code`) with [`bcherny/redirect-claude`](https://github.com/bcherny/redirect-claude) context, replacing the inaccurate "abandoned package" phrasing.
20
+
21
+ ### Docs
22
+
23
+ - **CONTRIBUTING.md** (PR #157) — replaced "Snyk security score" with vendor-neutral "supply-chain trust signal that SCA tools (OSV-Scanner, Socket, Dependabot) and consumers rely on".
24
+
25
+ ## [2.9.2] — 2026-04-28
26
+
27
+ `upstream-check` workflow rebuild: fixes a 5-day silence and migrates to the official client library. Root cause of the silence: the daily workflow committed `.github/upstream-state.json` and pushed to `main`, but `main`'s branch protection (PR-required + 4 required status checks) rejected every push with `GH013`. State never advanced, items were re-evaluated daily, and the `Create issue` step was gated behind state-push success — silent forever. State persistence is now `actions/cache@v4` (key prefix `upstream-state-v3-`); the workflow no longer touches the git tree, `contents: write` permission dropped. Migration to [`@sefaertunc/anthropic-watch-client`](https://www.npmjs.com/package/@sefaertunc/anthropic-watch-client) replaces ~80 lines of hand-rolled fetch/dedup with composite-`uniqueKey` dedup (the `id`-only dedup at `scripts/upstream-precheck.mjs:95` was already silently dropping items where two sources shared an ID — `2.1.114` was the live example), version-gated fetch (`FeedVersionMismatchError`), and typed errors. Claude prompt + `upstream-watcher` agent + `docs/reference/upstream-automation.md` updated for the `community` source category (Reddit, HN, Twitter, GitHub commits — informational only per upstream's contract). Source counts no longer hardcoded — derived from `summary.sourcesChecked`.
28
+
29
+ ### Fixed
30
+
31
+ - **5-day upstream-check silence** (PR follows) — replaces direct-push-to-`main` state persistence with `actions/cache@v4`. Fixes `GH013` rejection that blocked state advance and issue creation since `2026-04-18T09:08:21Z`. `contents: write` permission dropped.
32
+ - **Composite-key dedup bug** in `scripts/upstream-precheck.mjs` (PR follows) — was deduping by `id` alone, silently dropping items where two sources shared an ID. Now uses `@sefaertunc/anthropic-watch-client`'s `filterNew` with the spec'd `${id}|${source}` fallback for legacy state entries.
33
+
34
+ ### Changed
35
+
36
+ - **Migrated upstream fetch to `@sefaertunc/anthropic-watch-client@^1.0.2`** (PR follows) — version-gated feed envelope (`FeedVersionMismatchError`), typed `FeedFetchError` / `FeedMalformedError`, composite `uniqueKey` dedup. Three minor versions overdue per upstream's `WORCLAUDE-INTEGRATION.md` tracking note.
37
+ - **Workflow Claude prompt** (PR follows) — added `community` source category (Reddit, HN, Twitter/X, GitHub commits) treated as informational-only per anthropic-watch's contract; removed hardcoded "16 sources" wording in favor of `summary.sourcesChecked`.
38
+ - **`upstream-watcher` agent prompt** (template + dogfood, byte-identical) — updated to describe client-library usage and the `community` impact-classification row.
39
+
40
+ ### Tests
41
+
42
+ - **`tests/scripts/upstream-precheck.test.js`** (new, 20 cases) — covers happy path, dedup correctness (including the cross-source-same-id regression case), legacy `${id}|unknown` fallback, all four typed-error paths, schema-version refusal, 90-day prune, watchdog-issue-number preservation, and the full output-key contract for downstream workflow steps.
43
+
44
+ ### Docs
45
+
46
+ - **`docs/reference/upstream-automation.md`** — rewrote State File section for cache-based persistence, replaced "Required branch protection" with "Branch protection on `main` — fully compatible", added Community-source policy subsection, added v2.9.2 to version history.
47
+ - **`docs/reference/agents.md`** — `upstream-watcher` description: source count now described as dynamic; switched from "via `curl` (no npm dependencies)" to client-library usage.
48
+
7
49
  ## [2.9.1] — 2026-04-28
8
50
 
9
51
  Security patch clearing three transitive dev-dep advisories surfaced by Socket.dev and `npm audit` (esbuild dev-server CORS, vite path-traversal in optimized-deps, postcss XSS in CSS stringify). All three were dev-only, gated behind running `npm run docs:dev` and visiting a hostile origin in the same session — neither CI nor end-user installs trigger the conditions — but they kept appearing in scanner output and drowning out signal. Resolved via `npm overrides` in `package.json` (esbuild ^0.25.0, vite ^6.4.2, postcss ^8.5.10) which forces vitepress 1.6.4 onto patched transitives despite its declared `vite ^5.4.14` peer range; `npm run docs:build` verified clean. SECURITY.md rewritten: stale "pending upstream fixes" section replaced with "fixed via overrides", new false-positive subsections for Socket's AI-typosquat alert ("Did you mean: claude") and URL-strings alert (template content, not endpoints), supported-version table bumped to 2.9.x.
package/CONTRIBUTING.md CHANGED
@@ -78,7 +78,8 @@ npm provenance (SLSA attestations).
78
78
  4. Verify the "Provenance" badge on `https://www.npmjs.com/package/worclaude`.
79
79
 
80
80
  Do not run `npm publish` from a local machine — manual publishes omit provenance
81
- and weaken the Snyk security score.
81
+ and weaken the supply-chain trust signal that SCA tools (OSV-Scanner, Socket,
82
+ Dependabot) and consumers rely on.
82
83
 
83
84
  ## Reporting Bugs
84
85
 
package/SECURITY.md CHANGED
@@ -22,8 +22,9 @@ If the vulnerability is accepted, a fix will be prioritized and released as a pa
22
22
 
23
23
  ## Supply Chain Scanner Findings
24
24
 
25
- Automated SCA tools (Socket, Snyk, GitHub Dependabot) sometimes surface
26
- alerts that are not real exposures for worclaude. The most common cases:
25
+ Automated SCA tools (Socket, OSV-Scanner, GitHub Dependabot) sometimes
26
+ surface alerts that are not real exposures for worclaude. The most common
27
+ cases:
27
28
 
28
29
  ### Test fixture manifests are not real dependencies
29
30
 
@@ -42,9 +43,10 @@ These fixtures are:
42
43
  dependency lists; it never imports or runs the packages named inside.
43
44
 
44
45
  Worclaude's repo includes `socket.yml` to stop Socket from scanning this
45
- directory, and a `.snyk` policy file with an equivalent `exclude.global`
46
- entry for Snyk Open Source. Other SCA tools may need an equivalent
47
- `ignore` directive.
46
+ directory. The OSV-Scanner workflow scopes itself to the root
47
+ `package-lock.json` (via `--lockfile=`), which inherently skips fixture
48
+ lockfiles without a separate config. Other SCA tools may need an
49
+ equivalent `ignore` directive.
48
50
 
49
51
  ### Real runtime dependencies
50
52
 
@@ -111,11 +113,26 @@ triggers because the package name `worclaude` contains the substring
111
113
  `claude`. The package was published under this name from day one
112
114
  (2026-02), the npm namespace is owned by the original author
113
115
  (`sefaertunc`), and the package is the canonical home for the workflow
114
- described in this README. There is no upstream `claude` workflow
115
- scaffolder being typosquatted — `claude` on npm is an unrelated
116
- abandoned package. Renaming a published, indexed package would break
117
- every existing user's CLI alias and slash-command muscle memory; the
118
- alert is accepted as a permanent false positive.
116
+ described in this README.
117
+
118
+ Socket's chain inference (`worclaude` `claude` `@anthropic-ai/claude-code`)
119
+ produces a false positive at every link:
120
+
121
+ - **`worclaude`** is a workflow scaffolder for Claude Code, not a redirect
122
+ or rename of any other package.
123
+ - **`claude`** on npm is itself an intentional typosquat-warning redirect
124
+ by Boris Cherny ([github.com/bcherny/redirect-claude](https://github.com/bcherny/redirect-claude)),
125
+ deprecated by design — its README points users to `@anthropic-ai/claude-code`.
126
+ Socket flags `claude` as a typosquat of `@anthropic-ai/claude-code`,
127
+ which is exactly the case the redirect was authored to handle.
128
+ - **`@anthropic-ai/claude-code`** is Anthropic's canonical Claude Code
129
+ product — the destination both `worclaude` (as Boris-Cherny-tips-inspired
130
+ workflow tooling per the README's Acknowledgments) and `claude` (as a
131
+ redirect) point readers toward.
132
+
133
+ Renaming a published, indexed package would break every existing user's
134
+ CLI alias and slash-command muscle memory. The alert is accepted as a
135
+ permanent false positive.
119
136
 
120
137
  ### URL-strings supply-chain alert (template content)
121
138
 
@@ -128,3 +145,19 @@ at runtime; the only HTTP code path is `src/utils/npm.js`, which
128
145
  queries the npm registry for the latest published version during
129
146
  `worclaude upgrade` and `worclaude status`. The flagged strings are
130
147
  content, not endpoints.
148
+
149
+ ### CI scanner stack
150
+
151
+ Worclaude's CI runs two free, open-source SCA tools:
152
+
153
+ - **OSV-Scanner** (`.github/workflows/osv-scanner.yml`) — scans
154
+ `package-lock.json` against the [OSV.dev](https://osv.dev) database
155
+ on every PR (fails on vulnerability) and sweeps `main` weekly
156
+ (warn-only). Findings upload as SARIF to the repo's Security tab.
157
+ - **Dependabot** (`.github/dependabot.yml` + Settings → Code security →
158
+ Dependabot security updates) — auto-opens fix PRs when a CVE lands
159
+ affecting a tracked dep, plus weekly version-update PRs grouped by
160
+ minor/patch.
161
+
162
+ Snyk was retired on 2026-04-28 (post-v2.9.2). Both replacements run
163
+ unconditionally — no scan-quota limits.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "worclaude",
3
- "version": "2.9.1",
3
+ "version": "2.9.3",
4
4
  "description": "The Workflow Layer for Claude Code — scaffold agents, commands, skills, hooks, and memory into any project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -64,6 +64,7 @@
64
64
  ],
65
65
  "license": "MIT",
66
66
  "dependencies": {
67
+ "@sefaertunc/anthropic-watch-client": "^1.0.2",
67
68
  "chalk": "^5.4.1",
68
69
  "commander": "^13.1.0",
69
70
  "fs-extra": "^11.3.0",
@@ -10,12 +10,21 @@ const MIN_DESCRIPTION_LENGTH = 20;
10
10
  const MAX_README_BYTES = 512 * 1024;
11
11
  const BADGE_PATTERNS = [/^\s*\[!\[.*?\]\(.*?\)\]\(.*?\)\s*$/, /^\s*!\[.*?\]\(.*?\)\s*$/];
12
12
 
13
+ function stripUntilStable(text, regex) {
14
+ let prev;
15
+ do {
16
+ prev = text;
17
+ text = text.replace(regex, '');
18
+ } while (text !== prev);
19
+ return text;
20
+ }
21
+
13
22
  function stripHtmlComments(text) {
14
- return text.replace(/<!--[\s\S]*?-->/g, '');
23
+ return stripUntilStable(text, /<!--[\s\S]*?-->/g);
15
24
  }
16
25
 
17
26
  function stripHtmlTags(text) {
18
- return text.replace(/<[^>]+>/g, '');
27
+ return stripUntilStable(text, /<[^>]+>/g);
19
28
  }
20
29
 
21
30
  function isSkippable(line) {
@@ -27,24 +27,39 @@ You are read-only. Report findings and recommend actions — do not implement th
27
27
 
28
28
  ## 1. Fetch Upstream Feeds
29
29
 
30
- Feed base: `https://sefaertunc.github.io/anthropic-watch/feeds/`
31
-
32
- Fetch both feeds in parallel to keep the worst-case wait bounded by a single
33
- `--max-time`:
34
-
35
- ```bash
36
- curl -s --max-time 10 https://sefaertunc.github.io/anthropic-watch/feeds/run-report.json &
37
- curl -s --max-time 10 https://sefaertunc.github.io/anthropic-watch/feeds/all.json &
38
- wait
30
+ Use the official client library `@sefaertunc/anthropic-watch-client` (zero
31
+ runtime deps, version-gated, composite-key dedup, typed errors). Add it to the
32
+ project's `package.json` if not already present, then:
33
+
34
+ ```js
35
+ import {
36
+ AnthropicWatchClient,
37
+ FeedFetchError,
38
+ FeedMalformedError,
39
+ FeedVersionMismatchError,
40
+ } from '@sefaertunc/anthropic-watch-client';
41
+
42
+ const client = new AnthropicWatchClient({ timeout: 10_000 });
43
+ const [report, items] = await Promise.all([
44
+ client.fetchRunReport(),
45
+ client.fetchAllItems(),
46
+ ]);
39
47
  ```
40
48
 
41
- If either fetch fails (non-zero exit, empty body, or non-JSON), report
42
- "Could not reach anthropic-watch feeds" and stop — no impact analysis is
43
- possible without the feed data.
49
+ If any fetch throws `FeedFetchError` (network/HTTP), `FeedMalformedError`
50
+ (bad JSON), or `FeedVersionMismatchError` (feed schema bump), report
51
+ "Could not reach anthropic-watch feeds: {error.message}" and stop — no
52
+ impact analysis is possible without the feed data.
53
+
54
+ `report` gives per-source health, `summary.sourcesChecked` (the live source
55
+ count — do not hardcode a number), and `newItemCount` per source. `items`
56
+ gives every item across all sources, sorted newest-first. Each item carries
57
+ `id`, `uniqueKey`, `source`, `sourceCategory`, `sourceName`, `title`, `date`,
58
+ `url`, `snippet`.
44
59
 
45
- `run-report.json` gives per-source health and `newItemCount`. `all.json` gives
46
- the full list of items across all 16 sources, sorted newest-first. Each item
47
- carries `source`, `sourceCategory`, `title`, `date`, `url`, `snippet`.
60
+ The client lib's `filterNew(items, seenSet)` and `uniqueKey(item)` helpers
61
+ handle composite-key dedup with the documented `${id}|${source}` fallback for
62
+ items missing the `uniqueKey` field.
48
63
 
49
64
  ## 2. Read Project Infrastructure
50
65
 
@@ -74,6 +89,7 @@ For each new upstream item, classify it into one of these buckets:
74
89
  | Anthropic API SDK / docs | Relevant **only** if the project imports the SDK directly — skip otherwise |
75
90
  | Engineering blog | New patterns or best practices worth adopting; never blocking |
76
91
  | Status page | Informational only; no action required |
92
+ | `sourceCategory: community` (Reddit, HN, Twitter/X, GitHub commits) | **Informational only — never direct-impact** unless an item explicitly names a project file. Per anthropic-watch's contract, community items are not suitable for autonomous-action triggers. |
77
93
  | Other sources | Classify by content — prefer informational unless it names something the project uses |
78
94
 
79
95
  ## 4. Report Format