learn-cli 0.5.0__tar.gz → 0.5.1__tar.gz
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.
- {learn_cli-0.5.0 → learn_cli-0.5.1}/CHANGELOG.md +9 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/PKG-INFO +1 -1
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/profile/_ledger.py +26 -3
- {learn_cli-0.5.0 → learn_cli-0.5.1}/pyproject.toml +1 -1
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_profile_store.py +17 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/uv.lock +1 -1
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/src/index.js +8 -2
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/test/worker.test.js +44 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/agent-config/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/agent-config/data/backend-fingerprints.yaml +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/agent-config/scripts/show.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/ask-colleague/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/ask-colleague/prompts/explore.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/ask-colleague/prompts/review.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/ask-colleague/prompts/write.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/ask-colleague/scripts/ask-colleague.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/cicd/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/cicd/scripts/_resolve-nick.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/cicd/scripts/portability-lint.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/cicd/scripts/pr-reply.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/cicd/scripts/pr-status.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/cicd/scripts/workflow.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/communicate/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/communicate/scripts/templates/skill-new-brief.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/communicate/scripts/templates/skill-update-brief.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/doc-test-alignment/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/doc-test-alignment/scripts/check.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/pypi-maintainer/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/pypi-maintainer/scripts/switch-source.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/recall/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/recall/scripts/recall.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/remember/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/remember/scripts/remember.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/run-tests/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/sonarclaude/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/sonarclaude/scripts/sonar.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/spec-to-plan/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/think/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/think/scripts/think.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/version-bump/SKILL.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/version-bump/scripts/bump.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills.local.yaml.example +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.devague/current +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.devague/current_plan +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.devague/frames/agentculture-org-learn-is-live-one-learning-hub-in.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.devague/plans/agentculture-org-learn-is-live-one-learning-hub-in.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.flake8 +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.github/workflows/deploy-site.yml +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.github/workflows/publish.yml +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.github/workflows/tests.yml +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.gitignore +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/.markdownlint-cli2.yaml +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/AGENTS.colleague.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/CLAUDE.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/LICENSE +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/README.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/culture.yaml +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/docs/hosting.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/docs/plans/.markdownlint-cli2.yaml +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/docs/plans/2026-07-10-agentculture-org-learn-is-live-one-learning-hub-in.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/docs/skill-sources.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/docs/specs/.markdownlint-cli2.yaml +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/docs/specs/2026-07-10-agentculture-org-learn-is-live-one-learning-hub-in.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/docs/specs/subject-plugin-contract.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/__main__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/auth.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/cli.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/doctor.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/explain.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/learn.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/mcp.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/next_cmd.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/overview.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/progress.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/record.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/site.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/subject.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/subjects.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_commands/whoami.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_errors.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/cli/_output.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/_validate.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/advice.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/doctor.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/error.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/lesson.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/overview.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/practice.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/progress.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/record.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/story.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/story_list.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/contract/schemas/story_read.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/explain/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/explain/catalog.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/front/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/front/_docs.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/front/_driver.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/front/_export.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/motivation/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/motivation/_constants.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/motivation/_decay.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/motivation/_models.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/motivation/_review.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/motivation/_scoring.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/motivation/_state.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/motivation/_streaks.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/motivation/_whatnext.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/profile/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/profile/_api.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/profile/_auth.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/profile/_paths.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/profile/_sync.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/profile/_syncstate.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/subjects/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/subjects/conformance.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/subjects/driver.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/learn/subjects/registry.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/.gitignore +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/.nvmrc +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/README.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/astro.config.mjs +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/package-lock.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/package.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/public/apple-touch-icon.png +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/public/favicon.ico +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/public/favicon.svg +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/scripts/check-export-pages.mjs +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/scripts/check-static-auth.mjs +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/components/Footer.astro +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/components/Header.astro +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/components/LearnerPanelOverview.astro +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/components/LearnerPanelSubject.astro +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/components/Mark.astro +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/components/PageHero.astro +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/content-export/docs/portal.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/content-export/docs/subject-plugin-contract.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/content-export/docs/subjects.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/content-export/meta.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/content-export/stories-culture-guide.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/content-export/stories-french.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/content-export/stories-spanish.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/content-export/subjects.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/data/site.ts +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/layouts/Layout.astro +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/lib/api.ts +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/lib/content.ts +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/pages/[subject]/index.astro +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/pages/[subject]/stories/[id]/index.astro +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/pages/index.astro +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/scripts/learner.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/styles/global.css +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/tsconfig.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/sonar-project.properties +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/conftest.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/e2e/__init__.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/e2e/conftest.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/e2e/test_cli_golden.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/e2e/test_mcp_harness.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/motivation/completed_track_current.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/motivation/completed_track_decayed.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/motivation/cross_subject.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/motivation/single_subject_progression.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/advice.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/doctor.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/error.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/lesson.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/overview.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/practice.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/progress.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/record.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/story.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/story_list.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/payloads/story_read.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/stories/culture-guide-scenario-overloaded-agent.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/stories/french-beginner-le-marche.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/stories/spanish-beginner-la-panaderia.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/subjects/conformant_subject.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/subjects/drifted_subject.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_auth_cli.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_cli.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_cli_faces.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_cli_introspection.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_contract_schemas.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_contract_validator.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_front_app.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_front_driver.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_motivation_decay_review.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_motivation_extras.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_motivation_golden.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_motivation_purity.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_motivation_scoring.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_motivation_streaks.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_motivation_whatnext.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_progress_next_record.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_site_export.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_story_fixtures.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_subject_doctor.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_subject_driver.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_subject_registry.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tests/test_surfaces_agree.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tools/launch-gate/.gitignore +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tools/launch-gate/README.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tools/launch-gate/api-server.mjs +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tools/launch-gate/launch_bar.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tools/launch-gate/package.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tools/launch-gate/report.py +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tools/launch-gate/run.sh +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/tools/launch-gate/walk.mjs +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/.gitignore +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/README.md +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/package.json +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/schema.sql +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/src/auth.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/src/db.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/src/github.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/src/progress.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/src/session.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/src/util.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/src/validate.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/test/helpers.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/test/session.test.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/test/validate.test.js +0 -0
- {learn_cli-0.5.0 → learn_cli-0.5.1}/workers/learn-api/wrangler.toml +0 -0
|
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
Format follows [Keep a Changelog](https://keepachangelog.com/). This project
|
|
6
6
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.5.1] - 2026-07-11
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- API worker: the /learn zone-mount proxy strips Cookie/Authorization before forwarding to the Pages origin (review finding: session leak)
|
|
13
|
+
- API worker: withCors appends to an existing Vary header instead of overwriting it
|
|
14
|
+
- Profile ledger: created 0600 like auth.json (learner data is private)
|
|
15
|
+
- Profile ledger: a malformed ledger line is skipped instead of crashing progress/next/sync
|
|
16
|
+
|
|
8
17
|
## [0.5.0] - 2026-07-11
|
|
9
18
|
|
|
10
19
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: learn-cli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: A CLI, MCP server, and web front for learning — a hosted site where humans and agents learn a subject step by step. Fronts the french-cli and spanish-cli language tutors, and generalizes to other learnable domains such as leading teams of agents. The learn command is the local operator surface and how agents drive it.
|
|
5
5
|
Project-URL: Homepage, https://github.com/agentculture/learn-cli
|
|
6
6
|
Project-URL: Issues, https://github.com/agentculture/learn-cli/issues
|
|
@@ -8,26 +8,44 @@ written to by ``learn record`` (never by a subject CLI directly) and read by
|
|
|
8
8
|
every motivation computation. Append-only by design — nothing here ever
|
|
9
9
|
rewrites or deletes a row, so the sync cursor (:mod:`learn.profile._syncstate`)
|
|
10
10
|
can track "pushed so far" as a simple row count.
|
|
11
|
+
|
|
12
|
+
The ledger is learner data: the file is created ``0600`` (like ``auth.json``),
|
|
13
|
+
and a malformed line — a crash mid-append, a manual edit — is skipped rather
|
|
14
|
+
than crashing every ``progress``/``next``/sync flow. Because the ledger is
|
|
15
|
+
append-only and a malformed line never becomes valid, skipping is stable, so
|
|
16
|
+
the sync cursor's count-of-valid-rows arithmetic stays consistent across runs.
|
|
11
17
|
"""
|
|
12
18
|
|
|
13
19
|
from __future__ import annotations
|
|
14
20
|
|
|
15
21
|
import json
|
|
22
|
+
import os
|
|
16
23
|
from typing import Any
|
|
17
24
|
|
|
18
25
|
from learn.profile._paths import ensure_store_dir, ledger_path
|
|
19
26
|
|
|
27
|
+
#: Learner data is private to the local user, like ``auth.json``.
|
|
28
|
+
_LEDGER_MODE = 0o600
|
|
29
|
+
|
|
20
30
|
|
|
21
31
|
def append_ledger(row: dict[str, Any]) -> None:
|
|
22
32
|
"""Append one row to the local ledger, creating the store dir if needed."""
|
|
23
33
|
ensure_store_dir()
|
|
24
|
-
|
|
34
|
+
path = ledger_path()
|
|
35
|
+
created = not path.exists()
|
|
36
|
+
with path.open("a", encoding="utf-8") as handle:
|
|
25
37
|
handle.write(json.dumps(row, ensure_ascii=False))
|
|
26
38
|
handle.write("\n")
|
|
39
|
+
if created:
|
|
40
|
+
os.chmod(path, _LEDGER_MODE)
|
|
27
41
|
|
|
28
42
|
|
|
29
43
|
def read_ledger() -> list[dict[str, Any]]:
|
|
30
|
-
"""Read every row, in append order. Empty list when
|
|
44
|
+
"""Read every valid row, in append order. Empty list when no ledger exists yet.
|
|
45
|
+
|
|
46
|
+
A line that fails to parse (or parses to a non-object) is skipped — one
|
|
47
|
+
corrupt row must not take down ``progress``/``next``/sync.
|
|
48
|
+
"""
|
|
31
49
|
path = ledger_path()
|
|
32
50
|
if not path.is_file():
|
|
33
51
|
return []
|
|
@@ -37,7 +55,12 @@ def read_ledger() -> list[dict[str, Any]]:
|
|
|
37
55
|
stripped = line.strip()
|
|
38
56
|
if not stripped:
|
|
39
57
|
continue
|
|
40
|
-
|
|
58
|
+
try:
|
|
59
|
+
parsed = json.loads(stripped)
|
|
60
|
+
except json.JSONDecodeError:
|
|
61
|
+
continue
|
|
62
|
+
if isinstance(parsed, dict):
|
|
63
|
+
rows.append(parsed)
|
|
41
64
|
return rows
|
|
42
65
|
|
|
43
66
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "learn-cli"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.1"
|
|
4
4
|
description = "A CLI, MCP server, and web front for learning — a hosted site where humans and agents learn a subject step by step. Fronts the french-cli and spanish-cli language tutors, and generalizes to other learnable domains such as leading teams of agents. The learn command is the local operator surface and how agents drive it."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -72,6 +72,23 @@ def test_read_ledger_skips_blank_lines(profile_home) -> None:
|
|
|
72
72
|
assert len(p.read_ledger()) == 1
|
|
73
73
|
|
|
74
74
|
|
|
75
|
+
def test_ledger_file_is_created_private(profile_home) -> None:
|
|
76
|
+
p.append_ledger({"subject": "french", "item_id": "fr.x", "result": "pass"})
|
|
77
|
+
mode = p.ledger_path().stat().st_mode & 0o777
|
|
78
|
+
assert mode == 0o600
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_read_ledger_skips_malformed_lines(profile_home) -> None:
|
|
82
|
+
p.append_ledger({"subject": "french", "item_id": "fr.a", "result": "pass"})
|
|
83
|
+
with p.ledger_path().open("a", encoding="utf-8") as handle:
|
|
84
|
+
handle.write("{not json\n")
|
|
85
|
+
handle.write("[1, 2, 3]\n")
|
|
86
|
+
p.append_ledger({"subject": "french", "item_id": "fr.b", "result": "partial"})
|
|
87
|
+
rows = p.read_ledger()
|
|
88
|
+
assert [r["item_id"] for r in rows] == ["fr.a", "fr.b"]
|
|
89
|
+
assert p.ledger_count() == 2
|
|
90
|
+
|
|
91
|
+
|
|
75
92
|
# --- auth state ------------------------------------------------------------
|
|
76
93
|
|
|
77
94
|
|
|
@@ -102,7 +102,13 @@ async function proxyToPages(request, env, url) {
|
|
|
102
102
|
requireConfig(env, "PAGES_ORIGIN");
|
|
103
103
|
const origin = env.PAGES_ORIGIN.replace(/\/+$/, "");
|
|
104
104
|
const upstream = origin + url.pathname + url.search;
|
|
105
|
-
|
|
105
|
+
// Never forward credentials to the static origin: the session cookie (and
|
|
106
|
+
// any Authorization header) is for this API only — the Pages origin serves
|
|
107
|
+
// public files and must not see learner sessions.
|
|
108
|
+
const headers = new Headers(request.headers);
|
|
109
|
+
headers.delete("Cookie");
|
|
110
|
+
headers.delete("Authorization");
|
|
111
|
+
return fetch(new Request(upstream, { method: request.method, headers }));
|
|
106
112
|
}
|
|
107
113
|
|
|
108
114
|
// --- public routes ---------------------------------------------------------
|
|
@@ -325,6 +331,6 @@ function withCors(env, request, response) {
|
|
|
325
331
|
headers.set("Access-Control-Allow-Credentials", "true");
|
|
326
332
|
headers.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
327
333
|
headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
328
|
-
headers.
|
|
334
|
+
headers.append("Vary", "Origin");
|
|
329
335
|
return new Response(response.body, { status: response.status, headers });
|
|
330
336
|
}
|
|
@@ -429,3 +429,47 @@ test("POST under the /learn site mount is rejected (read-only proxy)", async ()
|
|
|
429
429
|
const res = await call(env, new Request(`${BASE}/learn/french/`, { method: "POST" }));
|
|
430
430
|
assert.equal(res.status, 405);
|
|
431
431
|
});
|
|
432
|
+
|
|
433
|
+
test("proxy to PAGES_ORIGIN strips Cookie and Authorization headers", async () => {
|
|
434
|
+
let seenHeaders = null;
|
|
435
|
+
const realFetch = globalThis.fetch;
|
|
436
|
+
globalThis.fetch = async (req) => {
|
|
437
|
+
seenHeaders = req.headers;
|
|
438
|
+
return new Response("ok", { status: 200 });
|
|
439
|
+
};
|
|
440
|
+
try {
|
|
441
|
+
const env = makeEnv({ PAGES_ORIGIN: "https://agentculture-learn.pages.dev" });
|
|
442
|
+
const req = new Request(`${BASE}/learn/french/`, {
|
|
443
|
+
headers: { Cookie: "session=supersecret", Authorization: "Bearer tok", Accept: "text/html" },
|
|
444
|
+
});
|
|
445
|
+
const res = await call(env, req);
|
|
446
|
+
assert.equal(res.status, 200);
|
|
447
|
+
assert.equal(seenHeaders.get("Cookie"), null);
|
|
448
|
+
assert.equal(seenHeaders.get("Authorization"), null);
|
|
449
|
+
assert.equal(seenHeaders.get("Accept"), "text/html");
|
|
450
|
+
} finally {
|
|
451
|
+
globalThis.fetch = realFetch;
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
test("withCors appends to an existing Vary header instead of overwriting", async () => {
|
|
456
|
+
let called = 0;
|
|
457
|
+
const realFetch = globalThis.fetch;
|
|
458
|
+
globalThis.fetch = async () => {
|
|
459
|
+
called += 1;
|
|
460
|
+
return new Response("ok", { status: 200, headers: { Vary: "Accept-Encoding" } });
|
|
461
|
+
};
|
|
462
|
+
try {
|
|
463
|
+
const env = makeEnv({
|
|
464
|
+
PAGES_ORIGIN: "https://agentculture-learn.pages.dev",
|
|
465
|
+
CORS_ORIGIN: "https://agentculture.org",
|
|
466
|
+
});
|
|
467
|
+
const res = await call(env, new Request(`${BASE}/learn/french/`, { headers: { Origin: "https://agentculture.org" } }));
|
|
468
|
+
assert.equal(called, 1);
|
|
469
|
+
const vary = res.headers.get("Vary");
|
|
470
|
+
assert.ok(vary.includes("Accept-Encoding"), `Vary lost upstream value: ${vary}`);
|
|
471
|
+
assert.ok(vary.includes("Origin"), `Vary missing Origin: ${vary}`);
|
|
472
|
+
} finally {
|
|
473
|
+
globalThis.fetch = realFetch;
|
|
474
|
+
}
|
|
475
|
+
});
|
|
File without changes
|
{learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/agent-config/data/backend-fingerprints.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learn_cli-0.5.0 → learn_cli-0.5.1}/.claude/skills/communicate/scripts/templates/skill-new-brief.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/content-export/docs/subject-plugin-contract.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learn_cli-0.5.0 → learn_cli-0.5.1}/site-astro/src/content-export/stories-culture-guide.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/motivation/single_subject_progression.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learn_cli-0.5.0 → learn_cli-0.5.1}/tests/fixtures/stories/spanish-beginner-la-panaderia.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|