79 Commits

Author SHA1 Message Date
przeprogramowani 1ce41e19d2 fix(rules): continue --no-course-rules when markers need repair (#54)
* fix(rules): continue --no-course-rules when markers need repair

Malformed, duplicate, or out-of-order sentinels still fail-close on a
default rules write, but opt-out no longer aborts the whole lesson.
Default get now returns a rules_markers_need_repair envelope instead of
a stack dump.

* chore(release): prepare v1.23.1

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-18 17:21:17 +02:00
przeprogramowani 2f4ebd3b75 docs: wymagania sieciowe dla urządzeń służbowych (allowlist PL+EN) (#53)
* docs: add corporate network allowlist for security/sysadmin teams

Polish sysadmin spec plus a machine-readable host list and a source-scan
test so new CLI destinations cannot land undocumented.

* chore(release): prepare v1.23.1

* docs: rewrite corporate allowlist in sysadmin language (PL+EN)

Plain host/port/protocol tables, matching English document, and an
allowlist test that covers both language files.

* docs: drop localhost from the corporate network allowlist

Public DNS names only; the source scan skips IP literals and
single-label hosts so local-dev URLs stay out of the sysadmin spec.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-18 17:17:28 +02:00
BartoszPawlowicz01 da67b5f7bb feat(tool-profile): add Kiro as a supported tool profile (#51)
Register a `kiro` profile that writes artifacts under `.kiro/` (skills,
prompts, config templates) and co-owns the root `AGENTS.md` for course
rules alongside codex, devin-desktop and generic. Content is delivered in
the generic variant because the delivery API exposes no `kiro` transform
yet.

Auto-detection reports Kiro from `.kiro/.10x-cli-manifest.json`,
`.kiro/steering/`, `.kiro/specs/`, `.kiro/hooks/`, `.kiro/settings/` or a
bare `.kiro/` directory. Every branch is `strong`: the directory name is
Kiro-specific with no plausible false positive, so a Kiro workspace never
loses the `AGENTS.md` confidence tie to codex and `PROFILE_ORDER` needs no
reshuffle. The profile takes its place in the resolution order ahead of
generic.

Extend `--tool` help text for `get` and `sync`, document the new paths,
the `.kiro/config-templates/` staging caveat and the exact limits of
`AGENTS.md` co-ownership (byte-identical rules only, so `kiro` pairs with
generic but reports `incompatible_shared_owner` next to codex or
devin-desktop) in the platform support reference and README, and cover the
profile in the detection, profile, tool-switch, writer and install-contract
test suites — including the divergent-content case that must fail closed.

The bundled `skills/10x-cli-guide/SKILL.md` is deliberately left unchanged:
`helpers install` is create-only and exits 1 on a byte difference, so a
documentation-only edit there would break every existing install.
2026-09-18 11:56:57 +02:00
psmyrdek 9d957e3a10 feat(bench-kit): shallow base repo clone by default, --deep for history
The bootstrap decides the depth (`baseRepoClone.depth`: 1 = HEAD only,
null = full history); this side only executes it. `--deep` on
`bench-kit init` sends `deepClone: true` in the request.

`--depth` is silently ignored for a local path, so a shallow clone goes
through a `file://` URL: that gives up object hardlinking, which is the
point — one commit's objects instead of the whole history. Origin is
re-pointed at the registered remote as before, so `git fetch
--unshallow` in the clone adds the history later.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 09:56:19 +02:00
przeprogramowani 2525f86d88 chore(quality): integrate shared offline CLI gate (#47)
* chore(quality): integrate shared offline CLI gate

* chore(release): prepare v1.22.1

* docs(quality): record complete local gate and source provenance

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-17 10:57:35 +02:00
przeprogramowani 43d6a69088 fix(release): wait for npm metadata before verifying publish (#50)
* fix(release): wait for npm metadata before verifying publish

Direct publish-npm verified immediately after npm accepted 1.22.1,
while registry metadata still lacked dist.tarball. Poll until
integrity exists, then keep the strict pack/gitHead compare. When
the version is already on npm and matches the pack from cli_sha,
skip publish and only complete tag/Release.

* chore(release): prepare v1.22.2

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-16 18:22:01 +02:00
przeprogramowani d21ba2dfbd fix(release): skip unrebased PRs in trusted version preparation (#49)
Master push enumerated every open PR and failed Prepare version when
the PR had not integrated current master. Classify that as a branch
update, write no record, and continue so unrelated open PRs cannot
turn the trusted writer red.

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-16 15:56:28 +02:00
przeprogramowani 95fc5f4394 fix(skills): include idea-check in lesson setup (#48)
* fix(skills): include idea-check in lesson setup

* chore(release): prepare v1.22.1

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-15 17:04:35 +02:00
przeprogramowani a704a86311 feat(cli): install bundled helpers into an explicit project target (#45)
Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 13:24:36 +02:00
przeprogramowani 56484f5856 feat(skills): guide CLI setup, filtered downloads and safe updates (#41)
* feat(skills): guide CLI setup, named downloads and updates

* fix(skills): bound npm inventory checks on cold Windows runners

* fix(skills): align launch guide with 10xCards PRD journey

* fix(tests): make helper checks portable on Windows

* test(helpers): trace Windows npm pack startup

* fix(helpers): allow bounded Windows npm startup time

* fix(helpers): use released lesson-scoped skill filters

Correct setup/guide examples and sync ownership to match CLI 1.21.
Exercise the documented preview/write commands through CAC and the
real partial writer, preserving all three trees and the PRD schema.

Refs: https://github.com/przeprogramowani/10x-cli/pull/41

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-14 10:51:38 +02:00
przeprogramowani 2cc510fe69 fix(release): unblock verified CLI 1.21.0 preparation 2026-09-14 08:21:48 +02:00
przeprogramowani 38dc7066b2 feat(auth): Circle message login (--method circle) 2026-09-14 06:28:48 +02:00
przeprogramowani b2150bae85 fix(release): preserve exact commit evidence through squash and publication 2026-09-13 20:57:09 +02:00
przeprogramowani b0c789af70 feat: enable v4 course selection and protected first-week sync (#38)
* docs(10xdevs4-cli-access): record membership gates and bootstrap context (p1)

Add canonical access plan, accepted decisions and supporting context.
Record phase 1 verification, Toolkit revision and remaining evidence gaps.

* docs(10xdevs4-cli-access): record course access gates and scoped review (p2)

Update canonical Progress, change status, evidence and implementation review.
Record Toolkit revisions, inherited typecheck limitation and phase 3 prerequisites.

* docs(10xdevs4-cli-access): persist reviewed revisions and phase 3 boundary

Record final reviewed Toolkit and CLI context revisions.
Persist Progress attribution and unresolved W04/W05/W08 prerequisites.
Keep phases 3–6, phase 7 and Manual criteria open.

* docs(10xdevs4-cli-access): record squash-safe source prerequisite

Record PR #30, verified gates, permanent-pin lessons and the remaining merge dependency.
Keep phase 3 and all manual rollout criteria pending.

* docs(10xdevs4-cli-access): record source prerequisite review

Record independent review of PR #30 and verified CI evidence.
Keep the master pin and delivery phase completion pending.

* docs(10xdevs4-cli-access): distinguish candidate checks from final master pins

Record passing pre-merge v4 checks and defer workflow suspension.
Keep the final v3 maintenance pin dependent on the resulting master SHA.

* feat: prepare v4 course delivery and protected project sync

Capture the reviewed implementation and manual rehearsal for draft PR review. Master source prerequisites, full clean verification and coordinated Windows CI remain open; production rollout is separate.

* fix: keep paid CI evidence private and converge cumulative sync

* docs: record merged source prerequisite and passing clean gate

* fix: preserve generated API type line endings on Windows

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-13 09:24:16 +02:00
psmyrdek 8a6a32aca1 feat(tool-profiles): replace Windsurf with Devin Desktop 2026-08-20 10:21:18 +02:00
Przemek Smyrdek e1b4b236dc refactor(bench-kit): CLI woła bootstrap kitu — kontrakt v1, logika instancji w template'cie (#37)
Kit zna siebie, CLI zna maszynę użytkownika: init/update klonują
template i wołają .bench-kit/bootstrap/index.mjs z klonu (żądanie JSON
na stdin, odpowiedź w ostatniej linii stdout). Update wykonuje bootstrap
z NOWEJ wersji kitu, więc migracje układu jadą z tagiem. Wchłania
TEMPLATE_ONLY_PATHS (gałąź fix/bench-kit-template-only-paths zbędna).
Minimalna wersja template'u: v0.10.0 (brak bootstrapu → template_incomplete).
Testy zawężone do kontraktu: fake runBootstrap, asercje na żądanie,
render, koperty --json i kody wyjścia.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 10:35:45 +02:00
Przemek Smyrdek d9a822556b feat(bench-kit): init clones the detected base repo into .repos/<name> (#36)
Local working copy for the authoring skills (bench-task, bench-refresh,
bench-wiring): cloned from the surrounding product repo (instant,
offline, full history) with origin pointed at the registered remote.
Gitignored via ensureIgnored so older template tags never commit it;
clone failure degrades to a hint.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 23:25:20 +02:00
Przemek Smyrdek 5d6466ed36 feat(bench-kit): remove TENX_CLI_EXPERIMENTAL gating — init and update generally available (#35)
The bench-kit command is feature-complete (zone-aware update, agent-tool
profiles, safe init defaults shipped in v1.17.0), so the experimental
opt-in has served its purpose. The command now registers unconditionally,
shows up in --help, and is documented in the README; the gating module
and its error envelope (experimental_locked) are removed.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 23:24:25 +02:00
Przemek Smyrdek 155bde9da7 feat(bench-kit): init safe defaults — pin demo task to detected repo, install runner deps, prefer https over SSH (#34)
- init pins placeholder tasks (repo: demo-app + all-zeros commit) to the
  detected base repo and its HEAD; company tasks never touched
- init and update run npm ci in .bench-kit/runner (update's wholesale
  swap deletes node_modules); failure degrades to a hint
- detected SSH remote is probed over https (git ls-remote, no terminal
  prompt) and rewritten when the repo answers publicly

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 19:41:42 +02:00
Przemek Smyrdek 17a504b039 feat(bench-kit): sync shared root files (AGENTS.md) on update (#33)
Template v0.6.0 ships AGENTS.md (agent instructions: skill order and
purpose). init already materializes it with the template root; update
now syncs it with the same proposal semantics as skills — added or
overwritten in the working tree, reviewable via git diff, never
deleting company edits silently.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 22:59:42 +02:00
Przemek Smyrdek 8202734856 feat(bench-kit): zone-aware update + agent-tool profile in init (#31) (#32)
- init resolves the agent tool (--tool flag > manifest on repair >
  interactive pick pre-filled by marker detection > claude-code) and
  materializes template skills under the profile's skill root
  (.claude/skills, .agents/skills, ...); the chosen tool is recorded in
  instance.json so update knows where to propose skill diffs
- update works zone by zone: .bench-kit/ replaced wholesale (staged swap,
  manifest survives version-bumped), workflows and skills synced into the
  working tree as an uncommitted proposal reviewed via git diff, company
  content never touched; clean-worktree gate keeps the proposal reviewable
- template skill source auto-detects the planned .agents/skills migration

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 12:43:40 +02:00
Przemek Smyrdek 47fad2249f feat(bench-kit): install template workflows into .github/workflows (#30)
GitHub only runs workflows from .github/workflows/, so init copies
.bench-kit/workflows/* there; repair mode keeps existing files (the
company may have customized triggers or secrets).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 12:40:49 +02:00
Przemek Smyrdek 846d9b45b3 Fix/lazy yaml import (#29)
* fix: lazy-load yaml so CLI startup stays within budget

The top-level 'yaml' import in bench-kit.ts is pulled in by index.ts,
so every CLI start paid for loading the YAML parser and the binary
smoke test's 50ms startup budget blew on CI (~58ms). Import yaml
dynamically inside registerBaseRepo — the only code path that needs
it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: raise unix startup budget to 60ms

Local measurements show bench-kit added no startup cost (~38ms avg at
pre-bench-kit, merged, and lazy-import refs alike) — the 50ms budget
was simply too tight for shared CI runners, which hover just above it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 21:12:44 +02:00
Przemek Smyrdek 7fbe39eb5e feat: auto-register the surrounding product repo as first base repo (#27)
Running 'bench-kit init' from inside a product repo is the common flow,
so init now detects the git repo containing the invocation cwd (git
rev-parse --show-toplevel + origin remote + HEAD) and replaces the
template's demo-app placeholder in bench.config.yaml with that repo,
editing the YAML document in place so company-zone comments survive.
The detection also lands in instance.json (incl. HEAD as a candidate
pin for the first task). No detection, no origin, or detecting the
instance itself → the placeholder stays. Adds the 'yaml' dependency.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 20:55:12 +02:00
Przemek Smyrdek 3184882f38 feat: add bench-kit command (init + update stub) (#26)
* feat: add bench-kit command (init + update stub)

'10x bench-kit init [dir]' creates a benchmark instance from the
przeprogramowani/10x-bench-kit template: preflight (git required,
container engine advisory), shallow clone at a tag, materialization
without git history, fresh git init + initial commit, and an instance
manifest in .bench-kit/instance.json. Re-running init on an existing
instance repairs missing template files without touching company
content. 'bench-kit update' is a not_implemented stub.

CAC has no nested command groups, so the command follows the auth
precedent: one 'bench-kit <action>' command dispatching internally.
Side effects are injectable (BenchKitDeps) so tests exercise the full
flow against fixture trees without network or real git.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: gate experimental commands behind TENX_CLI_EXPERIMENTAL

New src/lib/experimental.ts exposes experimentalEnabled() and
requireExperimental(), which exits with a stable 'experimental_locked'
envelope (exit 4 FORBIDDEN) unless TENX_CLI_EXPERIMENTAL=1 (or 'true')
is set. bench-kit stays registered so help remains discoverable and the
command never dies silently, but its action is locked before any side
effects. This lets the branch merge to master ahead of the feature
being student-ready.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: hide experimental commands entirely without the opt-in

All-or-nothing per review: registerBenchKitCommand returns early when
TENX_CLI_EXPERIMENTAL is unset, so bench-kit is absent from --help and
behaves like any unknown command instead of appearing half-locked. The
requireExperimental gate stays in the action as defense in depth.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 20:36:43 +02:00
psmyrdek 8006da8efb feat(bench): add '10x bench' live leaderboard from 10xbench.ai
New public command (no auth) that fetches the preprocessed top-10
leaderboard from https://10xbench.ai/api/leaderboard.json and renders
color-coded score bars on stderr, or the standard JSON envelope when
piped. The bench client is deliberately separate from api-client.ts:
its own strict BENCH_BASE_URL allowlist, and non-JSON 200 responses
(the static site's catch-all) surface as bench_unavailable. Colors are
hand-rolled ANSI gated on stderr TTY + NO_COLOR; remote strings are
sanitized before printing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 11:08:43 +02:00
Marcin Czarkowski b000e7bbdf feat(lesson-ref): accept lesson 0 for the m0l0 General Toolkit (#4)
Allow lesson numbers >= 0 so general, non-lesson-bound artifacts can be
fetched via m0l0 (e.g. `10x get m0l0`). Update the parser doc comment
and tests; lesson 0 is now valid, negatives still rejected by the regex.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 10:00:53 +02:00
“mkczarkowski” ec8a2a644d feat(bulk-sync-update): 10x sync command (p3)
- commands/sync.ts: new `10x sync` — enumerate, cheap-skip via catalog digest,
  fetch+apply, actionable report (per-resource remediation), worst-outcome exit
- index.ts: register sync command
- manifest.ts: LessonFilesEntry.catalogContentHash (digest-vs-digest skip), tolerant read
- writer.ts: applyBundle persists catalogContentHash (carried forward on plain get)
- tests/sync-command.test.ts: --all, default/--module, cheap-skip, changed, dry-run,
  conflict+remediation, --force, partial-failure exit 1, locked exclusion, digest round-trip
2026-06-20 11:37:51 +02:00
“mkczarkowski” ca4d0bf247 refactor(bulk-sync-update): planBundle() writer refactor + catalog contentHash type (p2)
- writer.ts: export pure planBundle() + WritePlan types; applyBundle now consumes
  it (shared computeFileAction/planRules) so classification and application can't drift
- api-content.ts: optional contentHash on LessonSummary (always-fetch fallback when absent)
- generated/api-types.ts: regenerated from local API — catalog lesson type carries contentHash
- tests/writer-plan.test.ts: planBundle/applyBundle parity (created/unchanged/clean/conflict)
2026-06-20 11:22:32 +02:00
“mkczarkowski” 2993481628 fix(disable-course-rules): address impl-review F1/F2
F1: updateToolConfig now throws when the merged config has no `tool`
instead of silently persisting an invalid object a later read rejects
wholesale (dropping lang/acknowledgedOrphans).

F2: add command-level course-rules tests — strip-after-apply with
surrounding-content preservation, the human [removed] rules render
line, and the positive --course-rules CAC parse guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:30:43 +02:00
“mkczarkowski” 6fb6ed6890 feat(disable-course-rules): command wiring, resolution & output (p3)
- src/commands/get.ts: register --no-course-rules, add tri-state
  resolveCourseRulesFlag (argv peek), merge-safe persistence via
  updateToolConfig (folds --lang persist, skips under --dry-run),
  explicit --type rules override, output (counts.rules 0 + [removed] line)
- tests/get-command.test.ts: resolver unit + opt-out/override/persist/dry-run
  integration; runGet mirrors process.argv
- README.md, CLAUDE.md: document the flag, persistence & override precedence

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:30:43 +02:00
“mkczarkowski” 29ee156819 feat(disable-course-rules): writer opt-out & strip (p2)
- src/lib/writer.ts: add applyCourseRules?: boolean to ApplyOptions
  (default true); when false, skip writing the course block and strip an
  existing one via removeRulesBlockWithMarkers (rules.action "removed",
  honors dryRun)
- tests/writer.test.ts: opt-out strip / no-op / dry-run / default-idempotent

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:30:43 +02:00
“mkczarkowski” d8fab8c559 feat(disable-course-rules): config schema & merge-safe persistence (p1)
- src/lib/config.ts: add courseRules?: boolean to ToolConfig, drop
  non-boolean courseRules in readToolConfig, add merge-safe
  updateToolConfig(patch) (fixes latent lang/acknowledgedOrphans clobber)
- tests/config.test.ts: courseRules shape validation + updateToolConfig merge
- context/changes/disable-course-rules: change folder (change.md, plan.md, plan-brief.md)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:30:43 +02:00
“mkczarkowski” c37f96f5c3 feat(cumulative-manifest): cumulative writer logic + scoped removal (p2)
Rewrite computeRemovals() for lesson-scoped removal with protected set.
Update manifest building to merge lesson entries, rebuild union files,
and seed from v2/v3-without-lessons manifests. Update existing cleanup
and removal tests for cumulative semantics. Add 8 new behavior tests
covering multi-lesson accumulation, protected-set, upgrade seeding.
Update CLAUDE.md with cumulative manifest documentation.

Files: src/lib/writer.ts, tests/writer.test.ts,
       tests/writer-profiles.test.ts, CLAUDE.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-27 20:54:41 +02:00
“mkczarkowski” 7c80b292f9 feat(cumulative-manifest): manifest schema extension (p1)
Add LessonFilesEntry type, lessons? field on CliManifest, isManifest()
validation for lessons, and buildUnionFiles() helper. Includes frame
brief, plan, and plan-brief for the change.

Files: src/lib/manifest.ts, tests/manifest.test.ts,
       context/changes/cumulative-manifest/{change,frame,plan,plan-brief}.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-27 20:49:19 +02:00
“mkczarkowski” e0b122c8a2 test(user-edit-protection): comprehensive behavior tests (p4)
- Conflict detection: clean update, user edit, matching edit, each resolution
- v2 manifest upgrade: false positive on diff, clean match, v3 upgrade, 3-way after upgrade
- Removal tracking: skill/prompt removals, empty on fresh, dry-run populates
- Hash persistence: stored after apply, preserved on skip, updated on overwrite/save_user
- Non-TTY conflict resolver: always skips without prompting
- Update get-command test types for new counts.removals field

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-27 18:28:52 +02:00
“mkczarkowski” 802ea46a63 feat(user-edit-protection): interactive prompts + output rendering (p3)
- Create conflict-prompt.ts with TTY/non-TTY conflict resolver factory
- Wire createConflictResolver and showUpgradeNotice into get command
- Add v2 manifest upgrade detection before applyBundle
- Render [removed] lines for skill/prompt/config removals
- Render conflict-specific action labels (conflict: overwritten/saved .user/skipped)
- Add removals to JSON output envelope with counts.removals
- Update get-command test for new counts shape

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-27 18:23:59 +02:00
“mkczarkowski” 536ccf6728 feat(user-edit-protection): writer three-way detection + removal tracking (p2)
- Make applyBundle() async with ConflictResolver callback injection
- Three-way conflict detection via stored content hashes in manifest
- Conflict resolutions: overwrite, save-as-.user.<ext>, skip
- Track removals in WriteResult.removals for downstream rendering
- Store per-file contentHashes and promptHashes in v3 manifest
- Update all tests for async applyBundle (writer + writer-profiles)
- Await applyBundle in get.ts command

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-27 18:21:22 +02:00
“mkczarkowski” ed64a987e1 feat(user-edit-protection): manifest v3 schema + contentHash utility (p1)
- Bump MANIFEST_VERSION to 3 with optional contentHashes/promptHashes fields
- Add contentHash() SHA-256 utility in manifest.ts
- isManifest() accepts both v2 and v3 for backward compat
- Update test assertions for v3 manifest version

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-27 18:16:40 +02:00
psmyrdek 2b71e20fac feat(doctor): warn when newer CLI version is on npm
Doctor's version check now queries the npm registry (best-effort, 2s
timeout) and warns with an upgrade hint when the local version is
behind. Lookup failures stay silent so offline runs aren't penalized.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:13:04 +02:00
“mkczarkowski” 3d6aa64040 feat(get): persist --tool choice as user default
When --tool is passed to resolveToolProfile(), save the choice to
config.json so future invocations default to it. Shows a stderr
confirmation on TTY when the default actually changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-17 13:16:34 +02:00
psmyrdek 9bdc69bfa9 test(e2e): query module 0 in list detail test
The shared e2e auth account is only enrolled in module 0 (prework), so
module 1 is locked and now returns lessons: [] after the locked-module
mask. Point the list-detail test at module 0 to match what the account
can actually see.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 16:44:49 +02:00
psmyrdek 4eb70c514c fix(list): hide lesson details for locked modules
The CLI was rendering real lesson titles and "TBD" summaries from
unreleased modules. Now renderModuleDetail returns lessons: [] in JSON
mode and a single "available after unlock" line in human mode when a
module is locked, regardless of what the API returns.

This is a client-side mask; the API still emits the data on the wire.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 16:08:54 +02:00
psmyrdek 95a8d4ec5e test(e2e): stop logging third-party recipients in resend poller
The first-poll diagnostic dumped the 5 most recent emails from the
shared Resend account, including their `to` field, leaking unrelated
customer addresses into CI logs. Replace with a counts-only summary
and drop the recipient from the timeout error message.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:56:54 +02:00
psmyrdek 43710470c9 test(e2e): align list/get fixtures with prework-enabled catalog
list now returns module 0 (prework) first, and the shared test account
is only enrolled in module 0 — switch the get fixtures from m1l1 to
m0l1 and update the list assertion to expect module 0 at index 0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:32:13 +02:00
psmyrdek 8c90cac07f fix(api-client): render API errors with friendly messages
The API ships {error: "<code>"} envelopes (e.g. "course_not_found"); we
were displaying that raw, or worse, "[object Object]" when callers tried
to print the payload. Map the 16 known codes (catalogued from the
delivery API routes) to human strings, prefer the optional `message`
field on auth routes, and fall back to a mentor-facing message for
unknown codes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:23:11 +02:00
psmyrdek f8859d1e28 feat(lesson-ref): allow module 0 for prework
Drop MIN_MODULE from 1 to 0 so parseLessonRef and parseModuleRef accept
m0/m0l1 (the 10xdevs3 prework module). Lesson numbers remain positive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 10:37:21 +02:00
“mkczarkowski” 56560edbdc fix(e2e): gracefully skip tests on auth rate-limit instead of failing
When the backend rate-limits magic-link requests (e.g. from CI re-runs),
tests now skip with a clear message rather than hard-failing the entire
suite. AuthRateLimitedError is caught in beforeAll and sets authSkipped
flag that each test checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-10 16:01:26 +02:00
“mkczarkowski” c34e5f7020 fix(e2e): avoid rate-limit by reusing shared auth singleton
auth-flow.test.ts now uses ensureSharedAuth() (single login per run)
and verifies the resulting auth.json, rather than triggering a
duplicate login that gets rate-limited by the backend.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-10 15:55:37 +02:00
“mkczarkowski” 11bbfc6517 fix(e2e): include stdout in earlyExit error for JSON mode diagnostics
In --json mode the error envelope goes to stdout, not stderr. The
earlyExit handler now reports both streams so CI failures show the
actual API error message.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-10 15:53:00 +02:00