diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 201d399..cc9864a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,8 +65,9 @@ jobs: - run: git diff --exit-code schemas/ upstream-scan: - # Dry-run in CI so any drift shows up in the PR. This is not a gate — - # the scheduled upstream-sync workflow proposes fixes. + # Dry-run in CI so any drift surfaces in the PR logs. Not a gate, and not + # automated beyond this — run `/cc sync` by hand to triage the changelog + # and land a bump. runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/upstream-sync.yml b/.github/workflows/upstream-sync.yml deleted file mode 100644 index fb86c26..0000000 --- a/.github/workflows/upstream-sync.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: upstream-sync - -# Daily scan of Claude Code upstream. When `src/upstream/scan.ts --open-pr` -# detects a new npm version of @anthropic-ai/claude-code, it writes an -# updated upstream/claude-code-manifest.json and opens a labeled PR. - -on: - schedule: - # Daily 09:00 UTC. Claude Code usually ships patch releases mid-week; - # daily is tight enough to catch drift within 24h of release. - - cron: "0 9 * * *" - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - scan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - # Need history to push a new branch. - fetch-depth: 0 - - uses: oven-sh/setup-bun@v2 - with: - bun-version: ">=1.1.30" - - run: bun install --frozen-lockfile - - name: Scan upstream (dry-run summary) - run: bun src/upstream/scan.ts - - name: Open PR on drift - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bun src/upstream/scan.ts --open-pr diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c8524c..cad5343 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ All notable changes to cc-settings are documented here. ### Changed +- **Retired the automated upstream-sync cron in favor of manual `/cc sync`.** The daily GitHub Action (`.github/workflows/upstream-sync.yml`) and the `--open-pr` path in `src/upstream/scan.ts` only ever bumped a version number and dumped the drift string into a PR body. The scanner's `diffSets` compares the manifest against cc-settings' *own* zod schema — never upstream — and it never fetched the changelog, so it was structurally blind to new features, settings keys, env vars, hook events, and dedupe opportunities. That triage is the human-reviewed skill's job; the bot's PRs looked actionable but weren't, and raced the manual flow. Removing it also avoids a standing CI credential (making the cron *smarter* would have meant baking an `ANTHROPIC_API_KEY`/OAuth token into repo secrets and burning it unattended on every release). + - **Removed** — `.github/workflows/upstream-sync.yml`; `openSyncPr`/`saveManifest` and the `--open-pr` branch in `src/upstream/scan.ts` (now a pure dry-run detector, no `writeFile`/`runProcessFull` imports); stale "daily GH Action"/"bot owns this file" references in the manifest `description`/`source`, `skills/cc/SKILL.md`, `src/schemas/skill.ts`, and the `.github/workflows/ci.yml` `upstream-scan` comment. + - **Kept** — `bun run upstream:scan` (the dry-run detector) and its non-gating CI job, now the manual way to spot drift before running `/cc sync`. +- **Upstream sync to Claude Code 2.1.161.** Manifest bumped `2.1.160` → `2.1.161`. The release is otherwise all bug fixes / UI / perf with no cc-settings surface; the one tracked addition is `CLAUDE_CODE_TMPDIR` (surfaced by the `EADDRINUSE`/Unix-socket fix), added to the manifest `knownEnvVars` and the `docs/settings-reference.md` env-var table. `OTEL_RESOURCE_ATTRIBUTES` now feeds metric-datapoint labels but is a generic OTEL SDK var outside our CC-specific tracking convention — deliberately skipped. - **Shared team-knowledge migrated from GitHub Project #7 to a markdown repo** (`darkroomengineering/team-knowledge`). The board was structurally hostile to its primary consumers (agents): network-gated GraphQL reads, not greppable offline, and no linter-enforced structure — `gh project item-create` never set the `Kind` field, so every `/share-learning` post landed `kind: None` and was invisible to a Kind-filtered query. The repo is one note per file + a generated `INDEX.md`, mirroring the local auto-memory tier. Decision + roadmap: `docs/plans/knowledge-repo-migration.md` (weighted comparison scored repo 795 vs board 515). - **New** — `src/schemas/knowledge.ts` (zod frontmatter contract: `name`/`kind`/`tags`/`added-by`/`supersedes`), `src/lib/lint-knowledge.ts` + `src/scripts/lint-knowledge.ts` (`bun run lint:knowledge`), `src/scripts/new-note.ts` (`bun run new-note`), `tests/lint-knowledge.test.ts`, emitted `schemas/knowledge.schema.json`. - **Changed** — `/share-learning` now reads `INDEX.md` for dedup and writes notes via `gh api` (was `gh project item-list`/`item-create`); `docs/knowledge-system.md`, the `AGENTS.md` Knowledge Routing section, and assorted docs retargeted; env `KNOWLEDGE_PROJECT_NUMBER` → `KNOWLEDGE_REPO`. diff --git a/docs/settings-reference.md b/docs/settings-reference.md index 1aa1d05..418aad2 100644 --- a/docs/settings-reference.md +++ b/docs/settings-reference.md @@ -83,6 +83,7 @@ Environment variables injected into every Claude Code session. | `CLAUDE_CODE_ENABLE_AUTO_MODE` | `"1"` or unset | Opt in to auto mode on Bedrock, Vertex, and Foundry for Opus 4.7/4.8 (native on the first-party API) (v2.1.158) | | `CLAUDE_CODE_SHELL_PREFIX` | shell prefix string | Custom shell prefix for MCP stdio server launches; overrides the default shell used to spawn stdio MCP processes (v2.1.128) | | `CLAUDE_CODE_SUBAGENT_MODEL` | model shortname (e.g., `sonnet`) | Routes Agent Teams teammate subprocess sessions to a specific model; main session model is unaffected. cc-settings sets `sonnet` (v2.1.147) | +| `CLAUDE_CODE_TMPDIR` | directory path | Overrides the temp directory used for Unix sockets and scratch files; set it shallow to avoid `EADDRINUSE` from over-long socket paths (v2.1.161) | | `OTEL_LOG_TOOL_DETAILS` | `"1"` or unset | Include custom/MCP command names in OTEL tool spans, and `tool_parameters` in `tool_decision` events; values are redacted unless this is set (v2.1.117; `tool_decision` params added v2.1.157) | > **Note on `ultracode` mode (v2.1.154+)**: `/effort ultracode` is a Claude Code session-only mode that sends `xhigh` to the model AND has Claude plan a [dynamic workflow](https://code.claude.com/docs/en/workflows) for each substantive task. It is **not** a valid value for `CLAUDE_CODE_EFFORT_LEVEL`, the `effortLevel` setting, or the `--effort` flag — set it via `/effort ultracode` in-session, or pass `"ultracode": true` through `--settings` or an Agent SDK control request. Disable workflows entirely with `CLAUDE_CODE_DISABLE_WORKFLOWS=1` or `"disableWorkflows": true`. diff --git a/skills/cc/SKILL.md b/skills/cc/SKILL.md index 98a2606..ecdfdd3 100644 --- a/skills/cc/SKILL.md +++ b/skills/cc/SKILL.md @@ -195,8 +195,10 @@ git log. Do not push if anything in Phase 7 is failing. - It does not edit user-installed `~/.claude/settings.json`. cc-settings is the source — users get the changes by re-running `setup.sh`. -- It does not auto-open PRs. The upstream-sync GitHub Action handles - manifest-only bumps; this skill is for the richer human-reviewed sync. +- It does not auto-open PRs, and there is no longer an automated cron. The + daily upstream-sync GitHub Action was retired — it could only bump the + version number, never triage the changelog. `bun run upstream:scan` is the + manual drift detector; this skill is the only sync path. - It does not bump dependencies. That's a separate concern. ### Mental model diff --git a/src/schemas/skill.ts b/src/schemas/skill.ts index e488312..6e7bc4b 100644 --- a/src/schemas/skill.ts +++ b/src/schemas/skill.ts @@ -42,8 +42,8 @@ export const SkillFrontmatter = z // Allow unknown keys — the skills ecosystem is fast-moving and we'd rather // accept an unrecognized field than reject a skill that works in newer CC. - // Contrast with settings.ts which is strict because drift there is the - // whole reason we have an upstream-sync bot. + // Contrast with settings.ts which is strict because drift there is what + // the `bun run upstream:scan` detector exists to catch. }) .passthrough(); diff --git a/src/upstream/scan.ts b/src/upstream/scan.ts index b5f6965..7d6dbf5 100644 --- a/src/upstream/scan.ts +++ b/src/upstream/scan.ts @@ -1,22 +1,20 @@ #!/usr/bin/env bun -// Upstream-sync scanner. Phases: -// dry-run (default): compares the current manifest against -// (a) npm's @anthropic-ai/claude-code latest version -// (b) the zod schema's enumerated keys (our local source of truth) -// and prints a delta. -// --open-pr: write an updated manifest + open a GitHub PR (requires `gh` -// CLI + a token with PR-write scope; used by .github/workflows/upstream-sync.yml). +// Upstream-sync scanner (dry-run detector). Compares the current manifest against +// (a) npm's @anthropic-ai/claude-code latest version +// (b) the zod schema's enumerated keys (our local source of truth) +// and prints the delta. Run it (`bun run upstream:scan`) to find out whether +// Claude Code has shipped a new release. // -// Phase 2 adds the mutation path. It is deliberately low-blast-radius: the -// scanner only updates upstream/claude-code-manifest.json when the live -// npm version differs from the committed one. Schema edits stay human- -// reviewed — the PR body lists the delta and we let the reviewer wire the -// new keys into the zod schemas. - -import { readFile, writeFile } from "node:fs/promises"; +// The scanner never writes. The actual sync — changelog triage +// (ADOPT/DEDUPE/SKIP), schema + doc edits, and the manifest + CHANGELOG bumps — +// is the human-reviewed `/cc sync` skill, run on demand. (There was once a daily +// GH Action that auto-bumped the manifest version, but it could only ever change +// a version number — it never read the changelog — so it was retired in favor of +// the manual skill.) + +import { readFile } from "node:fs/promises"; import { resolve } from "node:path"; import { z } from "zod"; -import { runProcessFull } from "../lib/git.ts"; import { HookEvent } from "../schemas/hooks.ts"; import { Settings } from "../schemas/settings.ts"; @@ -87,61 +85,13 @@ function diffSets(label: string, manifest: string[], live: string[]): string[] { return out; } -async function saveManifest(manifest: Manifest): Promise { - // Preserve the existing on-disk key order as much as we can; stable keys - // keep diffs small when nothing substantive changed. - const content = `${JSON.stringify(manifest, null, 2)}\n`; - await writeFile(MANIFEST, content); -} - -async function openSyncPr(summary: string, body: string, newVersion: string): Promise { - const branch = `upstream-sync/${newVersion}-${Date.now()}`; - await runProcessFull("git", ["config", "user.name", "upstream-sync-bot"]); - await runProcessFull("git", [ - "config", - "user.email", - "upstream-sync-bot@users.noreply.github.com", - ]); - await runProcessFull("git", ["checkout", "-b", branch]); - await runProcessFull("git", ["add", "upstream/claude-code-manifest.json"]); - const commitTitle = `chore(upstream-sync): bump manifest to ${newVersion}`; - const commitRes = await runProcessFull("git", ["commit", "-m", commitTitle]); - if (commitRes.exit !== 0) { - console.error("git commit failed:", commitRes.stderr); - return; - } - const pushRes = await runProcessFull("git", ["push", "-u", "origin", branch]); - if (pushRes.exit !== 0) { - console.error("git push failed:", pushRes.stderr); - return; - } - const prRes = await runProcessFull("gh", [ - "pr", - "create", - "--title", - summary, - "--body", - body, - "--label", - "upstream-sync", - ]); - if (prRes.exit !== 0) { - console.error("gh pr create failed:", prRes.stderr); - return; - } - console.log(`opened PR for ${newVersion}: ${prRes.stdout.trim()}`); -} - async function main() { - const args = process.argv.slice(2); - const openPr = args.includes("--open-pr"); - const manifest = await loadManifest(); const liveSettingsKeys = settingsKeysFromSchema(); const liveHookEvents = hookEventsFromSchema(); const liveVersion = await fetchLatestClaudeCodeVersion(); - console.log(`cc-settings upstream scan (${openPr ? "open-pr" : "dry-run"})`); + console.log("cc-settings upstream scan"); console.log(` manifest version: ${manifest.claudeCodeVersion} (scanned ${manifest.lastScan})`); console.log(` live version: ${liveVersion ?? ""}`); @@ -161,48 +111,7 @@ async function main() { console.log("\ndrift detected:"); for (const line of findings) console.log(line); - - if (!openPr) { - console.log("\nre-run with --open-pr to propose the manifest update as a PR."); - return; - } - - if (!versionDrift) { - // Schema-only drift is interesting but we don't auto-edit schemas; surface - // via CI logs and let a human wire the new keys. - console.log("\nschema-only drift — no manifest update proposed. Review the findings above."); - return; - } - - // Mutate the manifest version + lastScan, keep key lists untouched (schema - // additions are human work). If schema keys drift too, we note them in the - // PR body. - const updated: Manifest = { - ...manifest, - claudeCodeVersion: versionDrift, - lastScan: new Date().toISOString(), - }; - await saveManifest(updated); - - const summary = `chore(upstream-sync): bump claude-code manifest to ${versionDrift}`; - const body = [ - "Automated upstream-sync PR.", - "", - `- manifest: \`${manifest.claudeCodeVersion}\` → \`${versionDrift}\``, - "", - "## Findings", - "", - "```", - findings.join("\n"), - "```", - "", - "If the findings list schema-key drift, wire the new keys into the appropriate", - "zod schemas in `src/schemas/` and push onto this branch.", - "", - "Generated by `src/upstream/scan.ts --open-pr`.", - ].join("\n"); - - await openSyncPr(summary, body, versionDrift); + console.log("\nrun `/cc sync` to triage the changelog and land the bump."); } main().catch((err) => { diff --git a/upstream/claude-code-manifest.json b/upstream/claude-code-manifest.json index 32fbe10..b3827f4 100644 --- a/upstream/claude-code-manifest.json +++ b/upstream/claude-code-manifest.json @@ -1,6 +1,6 @@ { - "lastScan": "2026-06-02T00:00:00.000Z", - "claudeCodeVersion": "2.1.160", + "lastScan": "2026-06-03T00:00:00.000Z", + "claudeCodeVersion": "2.1.161", "knownSettingsKeys": [ "$schema", "agent", @@ -167,6 +167,7 @@ "CLAUDE_CODE_STOP_HOOK_BLOCK_CAP", "CLAUDE_CODE_SUBAGENT_MODEL", "CLAUDE_CODE_SUBPROCESS_ENV_SCRUB", + "CLAUDE_CODE_TMPDIR", "CLAUDE_CODE_USE_POWERSHELL_TOOL", "CLAUDE_EFFORT", "DISABLE_UPDATES", @@ -193,9 +194,9 @@ ], "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://cc-settings.darkroom/upstream/claude-code-manifest.json", - "description": "Snapshot of Claude Code upstream surface area as known to the cc-settings zod schemas. Updated by src/upstream/scan.ts (daily GH Action). Drift triggers a PR that extends the schemas and this manifest atomically. See docs/migration-coexistence.md and ~/Desktop/cc-settings-MIGRATION.md v2.", + "description": "Snapshot of Claude Code upstream surface area as known to the cc-settings zod schemas. Updated by hand via the /cc sync skill; bun run upstream:scan reports drift but never writes. See docs/migration-coexistence.md.", "manifestSchemaVersion": 1, - "source": "manual sync (cc-settings v11.0.1). From 2.1.115 onward, upstream-sync bot owns this file.", + "source": "manual sync via the /cc sync skill (the automated upstream-sync bot was retired June 2026).", "knownPermissionModes": [ "default", "acceptEdits",