@scemoon/cdh 1.0.8 → 1.0.9-beta.2
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/ai-dlc-skill/SKILL.md +106 -0
- package/ai-dlc-skill/architecture/project-structure.md +78 -0
- package/ai-dlc-skill/brownfield/README.md +36 -0
- package/ai-dlc-skill/brownfield/entry.md +45 -0
- package/ai-dlc-skill/brownfield/generate-context.sh +64 -0
- package/ai-dlc-skill/brownfield/scripts/deps.sh +27 -0
- package/ai-dlc-skill/brownfield/scripts/discover.sh +34 -0
- package/ai-dlc-skill/brownfield/scripts/extract-api.sh +45 -0
- package/ai-dlc-skill/components/backend.md +47 -0
- package/ai-dlc-skill/components/desktop.md +63 -0
- package/ai-dlc-skill/components/mya.md +219 -0
- package/ai-dlc-skill/components/native.md +73 -0
- package/ai-dlc-skill/components/tta.md +235 -0
- package/ai-dlc-skill/components/web.md +77 -0
- package/ai-dlc-skill/components/wxa.md +219 -0
- package/ai-dlc-skill/contracts/README.md +25 -0
- package/ai-dlc-skill/core/adaptive-flow.md +107 -0
- package/ai-dlc-skill/core/security.md +29 -0
- package/ai-dlc-skill/core/task-registry.md +153 -0
- package/ai-dlc-skill/cross-tool/README.md +20 -0
- package/ai-dlc-skill/cross-tool/cline/export.sh +38 -0
- package/ai-dlc-skill/cross-tool/copilot/export.sh +41 -0
- package/ai-dlc-skill/cross-tool/cursor/export.sh +53 -0
- package/ai-dlc-skill/cross-tool/onecode/export.sh +27 -0
- package/ai-dlc-skill/cross-tool/opencode/export.sh +38 -0
- package/ai-dlc-skill/phases/debug/entry.md +48 -0
- package/ai-dlc-skill/phases/debug/lifecycle.md +284 -0
- package/ai-dlc-skill/phases/deliver/entry.md +35 -0
- package/ai-dlc-skill/phases/deliver/lifecycle.md +185 -0
- package/ai-dlc-skill/phases/deliver/prompt.md +54 -0
- package/ai-dlc-skill/phases/deliver/rules.md +61 -0
- package/ai-dlc-skill/phases/plan/design_system/accessibility.md +268 -0
- package/ai-dlc-skill/phases/plan/design_system/atomic_design.md +341 -0
- package/ai-dlc-skill/phases/plan/design_system/component_spec.md +398 -0
- package/ai-dlc-skill/phases/plan/design_system/design_tokens.md +190 -0
- package/ai-dlc-skill/phases/plan/design_system/iconography.md +299 -0
- package/ai-dlc-skill/phases/plan/design_system/platform_ui/desktop.md +318 -0
- package/ai-dlc-skill/phases/plan/design_system/platform_ui/mya.md +354 -0
- package/ai-dlc-skill/phases/plan/design_system/platform_ui/native.md +328 -0
- package/ai-dlc-skill/phases/plan/design_system/platform_ui/tta.md +394 -0
- package/ai-dlc-skill/phases/plan/design_system/platform_ui/web.md +287 -0
- package/ai-dlc-skill/phases/plan/design_system/platform_ui/wxa.md +374 -0
- package/ai-dlc-skill/phases/plan/design_system/theme_system.md +318 -0
- package/ai-dlc-skill/phases/plan/entry.md +33 -0
- package/ai-dlc-skill/phases/plan/lifecycle.md +260 -0
- package/ai-dlc-skill/phases/plan/prompt.md +75 -0
- package/ai-dlc-skill/phases/plan/rules.md +60 -0
- package/ai-dlc-skill/phases/understand/entry.md +36 -0
- package/ai-dlc-skill/phases/understand/lifecycle.md +184 -0
- package/ai-dlc-skill/phases/understand/prompt.md +58 -0
- package/ai-dlc-skill/phases/understand/rules.md +49 -0
- package/ai-dlc-skill/phases/verify/config/base_url.md +65 -0
- package/ai-dlc-skill/phases/verify/entry.md +59 -0
- package/ai-dlc-skill/phases/verify/gates/browser_e2e.md +96 -0
- package/ai-dlc-skill/phases/verify/lifecycle.md +217 -0
- package/ai-dlc-skill/phases/verify/prompt.md +73 -0
- package/ai-dlc-skill/phases/verify/rules.md +91 -0
- package/ai-dlc-skill/phases/verify/runners/playwright_local.md +103 -0
- package/ai-dlc-skill/practices/bdd.md +119 -0
- package/ai-dlc-skill/practices/sdd.md +84 -0
- package/ai-dlc-skill/practices/tdd.md +128 -0
- package/ai-dlc-skill/providers/README.md +114 -0
- package/ai-dlc-skill/providers/aliyun/SKILL.md +204 -0
- package/ai-dlc-skill/providers/aliyun/api/rest-api.md +214 -0
- package/ai-dlc-skill/providers/aliyun/api/sdk.md +307 -0
- package/ai-dlc-skill/providers/aliyun/best-practices/database-design.md +363 -0
- package/ai-dlc-skill/providers/aliyun/best-practices/function-design.md +424 -0
- package/ai-dlc-skill/providers/aliyun/best-practices/troubleshooting.md +258 -0
- package/ai-dlc-skill/providers/aliyun/cli/database.md +263 -0
- package/ai-dlc-skill/providers/aliyun/cli/functions.md +263 -0
- package/ai-dlc-skill/providers/aliyun/cli/hosting.md +226 -0
- package/ai-dlc-skill/providers/aliyun/cli/setup.md +235 -0
- package/ai-dlc-skill/providers/aliyun/cli/storage.md +315 -0
- package/ai-dlc-skill/providers/aliyun/deployment.yaml +66 -0
- package/ai-dlc-skill/providers/aliyun/integration/ci-cd.md +288 -0
- package/ai-dlc-skill/providers/aliyun/preview.yaml +84 -0
- package/ai-dlc-skill/providers/aliyun/provider.yaml +160 -0
- package/ai-dlc-skill/providers/aliyun/security/authentication.md +254 -0
- package/ai-dlc-skill/providers/aliyun/services/cdn-hosting.md +220 -0
- package/ai-dlc-skill/providers/aliyun/services/database.md +319 -0
- package/ai-dlc-skill/providers/aliyun/services/function-compute.md +273 -0
- package/ai-dlc-skill/providers/aliyun/services/overview.md +163 -0
- package/ai-dlc-skill/providers/aliyun/services/serverless-app-engine.md +266 -0
- package/ai-dlc-skill/providers/aliyun/services/storage.md +269 -0
- package/ai-dlc-skill/providers/tcb/SKILL.md +208 -0
- package/ai-dlc-skill/providers/tcb/api/rest-api.md +338 -0
- package/ai-dlc-skill/providers/tcb/api/sdk.md +288 -0
- package/ai-dlc-skill/providers/tcb/best-practices/database-design.md +452 -0
- package/ai-dlc-skill/providers/tcb/best-practices/function-design.md +502 -0
- package/ai-dlc-skill/providers/tcb/best-practices/troubleshooting.md +462 -0
- package/ai-dlc-skill/providers/tcb/cli/cls.md +133 -0
- package/ai-dlc-skill/providers/tcb/cli/database.md +230 -0
- package/ai-dlc-skill/providers/tcb/cli/env.md +207 -0
- package/ai-dlc-skill/providers/tcb/cli/functions.md +276 -0
- package/ai-dlc-skill/providers/tcb/cli/hosting.md +219 -0
- package/ai-dlc-skill/providers/tcb/cli/setup.md +218 -0
- package/ai-dlc-skill/providers/tcb/cli/storage.md +233 -0
- package/ai-dlc-skill/providers/tcb/deployment.yaml +111 -0
- package/ai-dlc-skill/providers/tcb/integration/ci-cd.md +309 -0
- package/ai-dlc-skill/providers/tcb/integration/mcp-server.md +371 -0
- package/ai-dlc-skill/providers/tcb/preview.yaml +83 -0
- package/ai-dlc-skill/providers/tcb/provider.yaml +172 -0
- package/ai-dlc-skill/providers/tcb/security/authentication.md +241 -0
- package/ai-dlc-skill/providers/tcb/services/cloud-database.md +299 -0
- package/ai-dlc-skill/providers/tcb/services/cloud-functions.md +265 -0
- package/ai-dlc-skill/providers/tcb/services/cloud-hosting.md +264 -0
- package/ai-dlc-skill/providers/tcb/services/cloud-run.md +285 -0
- package/ai-dlc-skill/providers/tcb/services/cloud-storage.md +245 -0
- package/ai-dlc-skill/providers/tcb/services/overview.md +174 -0
- package/ai-dlc-skill/pybdd/README.md +41 -0
- package/ai-dlc-skill/pybdd/conftest.py +17 -0
- package/ai-dlc-skill/pybdd/example/auth/login.feature +32 -0
- package/ai-dlc-skill/pybdd/pytest.ini +5 -0
- package/ai-dlc-skill/pybdd/steps/.gitkeep +1 -0
- package/ai-dlc-skill/pybdd/steps/test_example_steps.py +65 -0
- package/ai-dlc-skill/requirements.md +140 -0
- package/ai-dlc-skill/skill.yaml +135 -0
- package/ai-dlc-skill/templates/brownfield/context.md +78 -0
- package/ai-dlc-skill/templates/integration/CHANGELOG.md +41 -0
- package/ai-dlc-skill/templates/integration/asyncapi.yaml +43 -0
- package/ai-dlc-skill/templates/integration/contract-diff.md +63 -0
- package/ai-dlc-skill/templates/integration/contract-spec.md +49 -0
- package/ai-dlc-skill/templates/integration/openapi.yaml +18 -0
- package/ai-dlc-skill/templates/integration/runtime-contract.yaml +36 -0
- package/ai-dlc-skill/templates/plan/design.md +49 -0
- package/ai-dlc-skill/templates/plan/task-list.md +32 -0
- package/ai-dlc-skill/templates/project/README.md +126 -0
- package/ai-dlc-skill/templates/project/template.md +119 -0
- package/ai-dlc-skill/templates/understand/feature.feature +30 -0
- package/ai-dlc-skill/templates/understand/intent.md +29 -0
- package/ai-dlc-skill/templates/understand/spec-delta.md +47 -0
- package/ai-dlc-skill/templates/verify/test-unit.py +27 -0
- package/ai-dlc-skill/walkthrough/collect.sh +50 -0
- package/ai-dlc-skill/walkthrough/template.md +54 -0
- package/cdh/__init__.py +0 -0
- package/cdh/__main__.py +4 -0
- package/cdh/__pycache__/__init__.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cli.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cli_logging.cpython-314.pyc +0 -0
- package/cdh/__pycache__/config.cpython-314.pyc +0 -0
- package/cdh/__pycache__/project_loader.cpython-314.pyc +0 -0
- package/cdh/__pycache__/scaffold.cpython-314.pyc +0 -0
- package/cdh/__pycache__/session_store.cpython-314.pyc +0 -0
- package/cdh/cdh_session_aggregator.py +258 -0
- package/cdh/cli.py +3000 -0
- package/cdh/cli_logging.py +45 -0
- package/cdh/config.py +28 -0
- package/cdh/event_loop/__init__.py +7 -0
- package/cdh/event_loop/bus.py +123 -0
- package/cdh/event_loop/events.py +25 -0
- package/cdh/event_loop/runner.py +28 -0
- package/cdh/event_loop/scheduler.py +158 -0
- package/cdh/generators/__init__.py +35 -0
- package/cdh/generators/_runtime.py +176 -0
- package/cdh/generators/ada/MANIFEST.toml +14 -0
- package/cdh/generators/ada/template.ads.tmpl +7 -0
- package/cdh/generators/bash/MANIFEST.toml +14 -0
- package/cdh/generators/bash/template.sh.tmpl +16 -0
- package/cdh/generators/builtin_index.json +590 -0
- package/cdh/generators/c/MANIFEST.toml +14 -0
- package/cdh/generators/c/template.h.tmpl +20 -0
- package/cdh/generators/cli.py +379 -0
- package/cdh/generators/clojure/MANIFEST.toml +14 -0
- package/cdh/generators/clojure/template.clj.tmpl +13 -0
- package/cdh/generators/cobol/MANIFEST.toml +14 -0
- package/cdh/generators/cobol/template.cbl.tmpl +14 -0
- package/cdh/generators/cpp/MANIFEST.toml +14 -0
- package/cdh/generators/cpp/template.hpp.tmpl +32 -0
- package/cdh/generators/crystal/MANIFEST.toml +14 -0
- package/cdh/generators/crystal/template.cr.tmpl +11 -0
- package/cdh/generators/csharp/MANIFEST.toml +23 -0
- package/cdh/generators/csharp/template.cs.tmpl +14 -0
- package/cdh/generators/cython/MANIFEST.toml +14 -0
- package/cdh/generators/cython/template.pyx.tmpl +17 -0
- package/cdh/generators/d/MANIFEST.toml +14 -0
- package/cdh/generators/d/template.d.tmpl +24 -0
- package/cdh/generators/dart/MANIFEST.toml +17 -0
- package/cdh/generators/dart/template.dart.tmpl +27 -0
- package/cdh/generators/elixir/MANIFEST.toml +17 -0
- package/cdh/generators/elixir/template.ex.tmpl +27 -0
- package/cdh/generators/elm/MANIFEST.toml +14 -0
- package/cdh/generators/elm/template.elm.tmpl +20 -0
- package/cdh/generators/erlang/MANIFEST.toml +14 -0
- package/cdh/generators/erlang/template.erl.tmpl +18 -0
- package/cdh/generators/fortran/MANIFEST.toml +14 -0
- package/cdh/generators/fortran/template.f90.tmpl +24 -0
- package/cdh/generators/fsharp/MANIFEST.toml +14 -0
- package/cdh/generators/fsharp/template.fs.tmpl +17 -0
- package/cdh/generators/go/MANIFEST.toml +18 -0
- package/cdh/generators/go/imports.go.tmpl +3 -0
- package/cdh/generators/go/template.go.tmpl +9 -0
- package/cdh/generators/graphql-schema/MANIFEST.toml +18 -0
- package/cdh/generators/graphql-schema/template.graphqls.tmpl +12 -0
- package/cdh/generators/groovy/MANIFEST.toml +14 -0
- package/cdh/generators/groovy/template.groovy.tmpl +28 -0
- package/cdh/generators/hack/MANIFEST.toml +14 -0
- package/cdh/generators/hack/template.hh.tmpl +24 -0
- package/cdh/generators/haskell/MANIFEST.toml +14 -0
- package/cdh/generators/haskell/template.hs.tmpl +20 -0
- package/cdh/generators/haxe/MANIFEST.toml +14 -0
- package/cdh/generators/haxe/template.hx.tmpl +20 -0
- package/cdh/generators/idris/MANIFEST.toml +14 -0
- package/cdh/generators/idris/template.idr.tmpl +22 -0
- package/cdh/generators/java/MANIFEST.toml +18 -0
- package/cdh/generators/java/template.java.tmpl +13 -0
- package/cdh/generators/julia/MANIFEST.toml +14 -0
- package/cdh/generators/julia/template.jl.tmpl +27 -0
- package/cdh/generators/kotlin/MANIFEST.toml +18 -0
- package/cdh/generators/kotlin/template.kt.tmpl +12 -0
- package/cdh/generators/lua/MANIFEST.toml +14 -0
- package/cdh/generators/lua/template.lua.tmpl +27 -0
- package/cdh/generators/matlab/MANIFEST.toml +14 -0
- package/cdh/generators/matlab/template.m.tmpl +26 -0
- package/cdh/generators/nim/MANIFEST.toml +14 -0
- package/cdh/generators/nim/template.nim.tmpl +12 -0
- package/cdh/generators/nix/MANIFEST.toml +14 -0
- package/cdh/generators/nix/template.nix.tmpl +8 -0
- package/cdh/generators/objective-c/MANIFEST.toml +14 -0
- package/cdh/generators/objective-c/template.m.tmpl +31 -0
- package/cdh/generators/ocaml/MANIFEST.toml +14 -0
- package/cdh/generators/ocaml/template.ml.tmpl +13 -0
- package/cdh/generators/pascal/MANIFEST.toml +14 -0
- package/cdh/generators/pascal/template.pas.tmpl +5 -0
- package/cdh/generators/perl/MANIFEST.toml +14 -0
- package/cdh/generators/perl/template.pm.tmpl +27 -0
- package/cdh/generators/php/MANIFEST.toml +17 -0
- package/cdh/generators/php/template.php.tmpl +31 -0
- package/cdh/generators/powershell/MANIFEST.toml +14 -0
- package/cdh/generators/powershell/template.ps1.tmpl +20 -0
- package/cdh/generators/protobuf/MANIFEST.toml +18 -0
- package/cdh/generators/protobuf/template.proto.tmpl +13 -0
- package/cdh/generators/python/MANIFEST.toml +18 -0
- package/cdh/generators/python/template.py.tmpl +12 -0
- package/cdh/generators/r/MANIFEST.toml +14 -0
- package/cdh/generators/r/template.R.tmpl +29 -0
- package/cdh/generators/racket/MANIFEST.toml +14 -0
- package/cdh/generators/racket/template.rkt.tmpl +15 -0
- package/cdh/generators/registry.py +211 -0
- package/cdh/generators/ruby/MANIFEST.toml +17 -0
- package/cdh/generators/ruby/template.rb.tmpl +27 -0
- package/cdh/generators/rust/MANIFEST.toml +18 -0
- package/cdh/generators/rust/template.rs.tmpl +16 -0
- package/cdh/generators/scala/MANIFEST.toml +20 -0
- package/cdh/generators/scala/template.scala.tmpl +13 -0
- package/cdh/generators/scheme/MANIFEST.toml +14 -0
- package/cdh/generators/scheme/template.scm.tmpl +16 -0
- package/cdh/generators/solidity/MANIFEST.toml +14 -0
- package/cdh/generators/solidity/template.sol.tmpl +24 -0
- package/cdh/generators/swift/MANIFEST.toml +18 -0
- package/cdh/generators/swift/template.swift.tmpl +10 -0
- package/cdh/generators/typescript/MANIFEST.toml +18 -0
- package/cdh/generators/typescript/template.ts.tmpl +7 -0
- package/cdh/generators/version.py +214 -0
- package/cdh/generators/zig/MANIFEST.toml +14 -0
- package/cdh/generators/zig/template.zig.tmpl +20 -0
- package/cdh/logging.py +314 -0
- package/cdh/optimizer/__init__.py +7 -0
- package/cdh/optimizer/loop.py +201 -0
- package/cdh/optimizer/mutation.py +85 -0
- package/cdh/optimizer/reward.py +51 -0
- package/cdh/optimizer/tracker.py +118 -0
- package/cdh/project_loader.py +1022 -0
- package/cdh/rules/patterns.yaml +132 -0
- package/cdh/rules/spectral.yaml +301 -0
- package/cdh/scaffold.py +1436 -0
- package/cdh/session_store.py +221 -0
- package/cdh/state_schema.py +127 -0
- package/cdh/tools/__init__.py +57 -0
- package/cdh/tools/cls_search.py +406 -0
- package/cdh/tools/contract_diff.py +644 -0
- package/cdh/tools/deploy_stack.py +590 -0
- package/cdh/tools/generate_shared.py +300 -0
- package/cdh/tools/iac_gen.py +224 -0
- package/cdh/tools/otel_export.py +125 -0
- package/cdh/tools/pattern_detect.py +451 -0
- package/cdh/tools/retrofit_labels.py +505 -0
- package/cdh/trace/__init__.py +101 -0
- package/cdh/trace/__pycache__/__init__.cpython-314.pyc +0 -0
- package/cdh/trace/dashboard/__init__.py +61 -0
- package/cdh/trace/dashboard/api.py +1032 -0
- package/cdh/trace/dashboard/app.html +1321 -0
- package/cdh/trace/dashboard/server.py +310 -0
- package/cdh/trace/otel_exporter.py +462 -0
- package/cdh/trace/otel_tracer.py +281 -0
- package/cdh/tui.py +1084 -0
- package/cdh/validators/__init__.py +16 -0
- package/cdh/validators/__pycache__/__init__.cpython-314.pyc +0 -0
- package/cdh/validators/__pycache__/bdd.cpython-314.pyc +0 -0
- package/cdh/validators/__pycache__/dag.cpython-314.pyc +0 -0
- package/cdh/validators/__pycache__/ears.cpython-314.pyc +0 -0
- package/cdh/validators/__pycache__/fr_namespace.cpython-314.pyc +0 -0
- package/cdh/validators/bdd.py +144 -0
- package/cdh/validators/dag.py +179 -0
- package/cdh/validators/ears.py +452 -0
- package/cdh/validators/fr_namespace.py +143 -0
- package/cdh/validators/spectral.py +475 -0
- package/cdh/verification/__init__.py +3 -0
- package/cdh/verification/aggregation.py +53 -0
- package/cdh/verification/gates/__init__.py +5 -0
- package/cdh/verification/gates/base.py +18 -0
- package/cdh/verification/gates/lint_gate.py +37 -0
- package/cdh/verification/gates/test_gate.py +41 -0
- package/cdh/verification/loop.py +93 -0
- package/cdh/verification/policy.py +24 -0
- package/onecode/__init__.py +1 -0
- package/onecode/__main__.py +4 -0
- package/onecode/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/__pycache__/cli.cpython-314.pyc +0 -0
- package/onecode/__pycache__/commands.cpython-314.pyc +0 -0
- package/onecode/__pycache__/config.cpython-314.pyc +0 -0
- package/onecode/__pycache__/migrate.cpython-314.pyc +0 -0
- package/onecode/agent/__init__.py +0 -0
- package/onecode/agent/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/cdh_loader.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/checkpoint.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/context.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/engine.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/hooks.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/onecode_agent_acp.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/permissions.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/permissions_store.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/project_doc.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/session.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/turn_record.cpython-314.pyc +0 -0
- package/onecode/agent/agents/__init__.py +29 -0
- package/onecode/agent/agents/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/agent/agents/__pycache__/types.cpython-314.pyc +0 -0
- package/onecode/agent/agents/prompts/build-agent.md +50 -0
- package/onecode/agent/agents/prompts/compaction-instructions.md +12 -0
- package/onecode/agent/agents/prompts/explore-agent.md +42 -0
- package/onecode/agent/agents/prompts/plan-agent.md +44 -0
- package/onecode/agent/agents/prompts/plan-gate-hard.md +4 -0
- package/onecode/agent/agents/prompts/plan-gate-soft.md +3 -0
- package/onecode/agent/agents/prompts/solo-agent.md +57 -0
- package/onecode/agent/agents/prompts/subagent-constraints.md +10 -0
- package/onecode/agent/agents/prompts/summary-instructions.md +7 -0
- package/onecode/agent/agents/prompts/title-instructions.md +3 -0
- package/onecode/agent/agents/prompts/tool-descriptions.md +129 -0
- package/onecode/agent/agents/types.py +786 -0
- package/onecode/agent/attachments.py +112 -0
- package/onecode/agent/cdh_loader.py +3 -0
- package/onecode/agent/checkpoint.py +285 -0
- package/onecode/agent/context.py +465 -0
- package/onecode/agent/engine.py +3547 -0
- package/onecode/agent/event_bridge.py +75 -0
- package/onecode/agent/hooks.py +86 -0
- package/onecode/agent/onecode_agent_acp.py +2993 -0
- package/onecode/agent/permissions.py +150 -0
- package/onecode/agent/permissions_store.py +73 -0
- package/onecode/agent/project_doc.py +19 -0
- package/onecode/agent/question_detect.py +230 -0
- package/onecode/agent/session.py +3 -0
- package/onecode/agent/snapshot.py +144 -0
- package/onecode/agent/tools/__init__.py +17 -0
- package/onecode/agent/tools/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/agent_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/apply_patch_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/bash_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/communication_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/config_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/cron_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/errors.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/file_ops.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/file_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/git_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/lsp_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/mcp_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/permission_handler.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/permissions.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/protocol.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/registry.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/sandbox.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/schema_validation.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/skill_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/todo_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/web_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/agent_tools.py +128 -0
- package/onecode/agent/tools/apply_patch_tool.py +138 -0
- package/onecode/agent/tools/bash_tool.py +121 -0
- package/onecode/agent/tools/communication_tools.py +154 -0
- package/onecode/agent/tools/config_tool.py +130 -0
- package/onecode/agent/tools/cron_tools.py +178 -0
- package/onecode/agent/tools/errors.py +17 -0
- package/onecode/agent/tools/file_ops.py +221 -0
- package/onecode/agent/tools/file_tools.py +225 -0
- package/onecode/agent/tools/git_tools.py +88 -0
- package/onecode/agent/tools/lsp_tools.py +404 -0
- package/onecode/agent/tools/mcp_tools.py +211 -0
- package/onecode/agent/tools/permission_handler.py +46 -0
- package/onecode/agent/tools/permissions.py +77 -0
- package/onecode/agent/tools/protocol.py +20 -0
- package/onecode/agent/tools/registry.py +210 -0
- package/onecode/agent/tools/sandbox.py +460 -0
- package/onecode/agent/tools/schema_validation.py +100 -0
- package/onecode/agent/tools/skill_tools.py +52 -0
- package/onecode/agent/tools/todo_tools.py +208 -0
- package/onecode/agent/tools/web_tools.py +530 -0
- package/onecode/agent/turn_record.py +28 -0
- package/onecode/builtin_skills/agent-browser/SKILL.md +212 -0
- package/onecode/builtin_skills/agent-browser/skill.yaml +8 -0
- package/onecode/builtin_skills/cloudbase/SKILL.md +162 -0
- package/onecode/builtin_skills/cloudbase/skill.yaml +7 -0
- package/onecode/builtin_skills/git/SKILL.md +64 -0
- package/onecode/builtin_skills/git/skill.yaml +7 -0
- package/onecode/builtin_skills/shell/SKILL.md +58 -0
- package/onecode/builtin_skills/shell/skill.yaml +8 -0
- package/onecode/builtin_skills/skill-creator/SKILL.md +106 -0
- package/onecode/builtin_skills/skill-creator/skill.yaml +8 -0
- package/onecode/cli.py +1325 -0
- package/onecode/codebase/__init__.py +69 -0
- package/onecode/codebase/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/chunker.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/indexer.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/retriever.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/storage.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/tools.cpython-314.pyc +0 -0
- package/onecode/codebase/chunker.py +125 -0
- package/onecode/codebase/indexer.py +154 -0
- package/onecode/codebase/retriever.py +240 -0
- package/onecode/codebase/storage.py +153 -0
- package/onecode/codebase/tools.py +59 -0
- package/onecode/commands.py +673 -0
- package/onecode/config.py +539 -0
- package/onecode/config_screen.py +486 -0
- package/onecode/cron/__init__.py +3 -0
- package/onecode/lsp/__init__.py +3 -0
- package/onecode/mcp/__init__.py +11 -0
- package/onecode/mcp/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/mcp/__pycache__/client.cpython-314.pyc +0 -0
- package/onecode/mcp/__pycache__/cloudbase.cpython-314.pyc +0 -0
- package/onecode/mcp/__pycache__/config.cpython-314.pyc +0 -0
- package/onecode/mcp/__pycache__/manager.cpython-314.pyc +0 -0
- package/onecode/mcp/__pycache__/oauth.cpython-314.pyc +0 -0
- package/onecode/mcp/client.py +305 -0
- package/onecode/mcp/cloudbase.py +188 -0
- package/onecode/mcp/config.py +363 -0
- package/onecode/mcp/manager.py +603 -0
- package/onecode/mcp/oauth.py +199 -0
- package/onecode/memory/__init__.py +106 -0
- package/onecode/memory/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/backend.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/pyramid.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/recall.cpython-314.pyc +0 -0
- package/onecode/memory/backend.py +179 -0
- package/onecode/memory/pyramid.py +145 -0
- package/onecode/memory/recall.py +322 -0
- package/onecode/migrate.py +122 -0
- package/onecode/models/__init__.py +4 -0
- package/onecode/models/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/errors.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/messages.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/ollama_manager.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/provider.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/registry.cpython-314.pyc +0 -0
- package/onecode/models/errors.py +104 -0
- package/onecode/models/messages.py +750 -0
- package/onecode/models/ollama_manager.py +167 -0
- package/onecode/models/provider.py +730 -0
- package/onecode/models/providers/__init__.py +17 -0
- package/onecode/models/providers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/anthropic_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/deepseek_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/glm_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/minimax_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/minimaxi_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/ollama_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/openai_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/anthropic_provider.py +286 -0
- package/onecode/models/providers/deepseek_provider.py +221 -0
- package/onecode/models/providers/glm_provider.py +219 -0
- package/onecode/models/providers/minimax_provider.py +182 -0
- package/onecode/models/providers/minimaxi_provider.py +426 -0
- package/onecode/models/providers/ollama_provider.py +183 -0
- package/onecode/models/providers/openai_provider.py +234 -0
- package/onecode/models/registry.py +349 -0
- package/onecode/server/__init__.py +3 -0
- package/onecode/server/app.py +251 -0
- package/onecode/skills/__init__.py +11 -0
- package/onecode/skills/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/argument_substitution.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/bootstrap.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/create.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/frontmatter.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/loader.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/model.cpython-314.pyc +0 -0
- package/onecode/skills/argument_substitution.py +38 -0
- package/onecode/skills/bootstrap.py +37 -0
- package/onecode/skills/create.py +56 -0
- package/onecode/skills/frontmatter.py +33 -0
- package/onecode/skills/loader.py +215 -0
- package/onecode/skills/manager.py +75 -0
- package/onecode/skills/model.py +43 -0
- package/onecode/storage/__init__.py +0 -0
- package/onecode/storage/activity.py +63 -0
- package/onecode/storage/project.py +54 -0
- package/onecode/storage/session.py +112 -0
- package/onecode/tasks/__init__.py +26 -0
- package/onecode/tasks/manager.py +232 -0
- package/onecode/tasks/models.py +240 -0
- package/onecode/trace/__init__.py +0 -0
- package/onecode/trace/tracer.py +173 -0
- package/onecode/utils/__init__.py +0 -0
- package/onecode/utils/helpers.py +20 -0
- package/onecode/verification/__init__.py +5 -0
- package/onecode/verification/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/verification/__pycache__/aggregation.cpython-314.pyc +0 -0
- package/onecode/verification/__pycache__/loop.cpython-314.pyc +0 -0
- package/onecode/verification/__pycache__/policy.cpython-314.pyc +0 -0
- package/onecode/verification/aggregation.py +53 -0
- package/onecode/verification/gates/__init__.py +6 -0
- package/onecode/verification/gates/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/verification/gates/__pycache__/base.cpython-314.pyc +0 -0
- package/onecode/verification/gates/__pycache__/lint_gate.cpython-314.pyc +0 -0
- package/onecode/verification/gates/__pycache__/test_gate.cpython-314.pyc +0 -0
- package/onecode/verification/gates/__pycache__/type_gate.cpython-314.pyc +0 -0
- package/onecode/verification/gates/base.py +20 -0
- package/onecode/verification/gates/lint_gate.py +45 -0
- package/onecode/verification/gates/test_gate.py +62 -0
- package/onecode/verification/gates/type_gate.py +46 -0
- package/onecode/verification/loop.py +95 -0
- package/onecode/verification/policy.py +29 -0
- package/package.json +2 -2
- package/pyproject.toml +84 -0
- package/tui/__init__.py +46 -0
- package/tui/__main__.py +4 -0
- package/tui/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tui/__pycache__/_loop.cpython-314.pyc +0 -0
- package/tui/__pycache__/_path_fuzzy_search.cpython-314.pyc +0 -0
- package/tui/__pycache__/_path_match.cpython-314.pyc +0 -0
- package/tui/__pycache__/agent.cpython-314.pyc +0 -0
- package/tui/__pycache__/agent_schema.cpython-314.pyc +0 -0
- package/tui/__pycache__/agents.cpython-314.pyc +0 -0
- package/tui/__pycache__/answer.cpython-314.pyc +0 -0
- package/tui/__pycache__/app.cpython-314.pyc +0 -0
- package/tui/__pycache__/atomic.cpython-314.pyc +0 -0
- package/tui/__pycache__/complete.cpython-314.pyc +0 -0
- package/tui/__pycache__/constants.cpython-314.pyc +0 -0
- package/tui/__pycache__/conversation_markdown.cpython-314.pyc +0 -0
- package/tui/__pycache__/db.cpython-314.pyc +0 -0
- package/tui/__pycache__/dec.cpython-314.pyc +0 -0
- package/tui/__pycache__/directory.cpython-314.pyc +0 -0
- package/tui/__pycache__/directory_watcher.cpython-314.pyc +0 -0
- package/tui/__pycache__/format_path.cpython-314.pyc +0 -0
- package/tui/__pycache__/fuzzy.cpython-314.pyc +0 -0
- package/tui/__pycache__/fuzzy_index.cpython-314.pyc +0 -0
- package/tui/__pycache__/history.cpython-314.pyc +0 -0
- package/tui/__pycache__/jsonrpc.cpython-314.pyc +0 -0
- package/tui/__pycache__/menus.cpython-314.pyc +0 -0
- package/tui/__pycache__/message_log.cpython-314.pyc +0 -0
- package/tui/__pycache__/messages.cpython-314.pyc +0 -0
- package/tui/__pycache__/path_complete.cpython-314.pyc +0 -0
- package/tui/__pycache__/path_filter.cpython-314.pyc +0 -0
- package/tui/__pycache__/paths.cpython-314.pyc +0 -0
- package/tui/__pycache__/pill.cpython-314.pyc +0 -0
- package/tui/__pycache__/platform_commands.cpython-314.pyc +0 -0
- package/tui/__pycache__/protocol.cpython-314.pyc +0 -0
- package/tui/__pycache__/session_tracker.cpython-314.pyc +0 -0
- package/tui/__pycache__/settings.cpython-314.pyc +0 -0
- package/tui/__pycache__/settings_schema.cpython-314.pyc +0 -0
- package/tui/__pycache__/shell.cpython-314.pyc +0 -0
- package/tui/__pycache__/shell_read.cpython-314.pyc +0 -0
- package/tui/__pycache__/slash_command.cpython-314.pyc +0 -0
- package/tui/__pycache__/version.cpython-314.pyc +0 -0
- package/tui/_loop.py +86 -0
- package/tui/_path_fuzzy_search.py +48 -0
- package/tui/_path_match.py +141 -0
- package/tui/about.py +95 -0
- package/tui/acp/__pycache__/agent.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/api.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/encode_tool_call_id.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/event_tap.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/messages.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/prompt.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/protocol.cpython-314.pyc +0 -0
- package/tui/acp/agent.py +1212 -0
- package/tui/acp/api.py +79 -0
- package/tui/acp/encode_tool_call_id.py +12 -0
- package/tui/acp/event_tap.py +107 -0
- package/tui/acp/messages.py +222 -0
- package/tui/acp/prompt.py +53 -0
- package/tui/acp/protocol.py +551 -0
- package/tui/agent.py +70 -0
- package/tui/agent_schema.py +76 -0
- package/tui/agents.py +46 -0
- package/tui/ansi/__init__.py +1 -0
- package/tui/ansi/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_ansi.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_ansi_colors.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_control_codes.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_keys.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_sgr_styles.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_stream_parser.cpython-314.pyc +0 -0
- package/tui/ansi/_ansi.py +1689 -0
- package/tui/ansi/_ansi_colors.py +264 -0
- package/tui/ansi/_control_codes.py +37 -0
- package/tui/ansi/_keys.py +251 -0
- package/tui/ansi/_sgr_styles.py +64 -0
- package/tui/ansi/_stream_parser.py +418 -0
- package/tui/answer.py +12 -0
- package/tui/app.py +1195 -0
- package/tui/atomic.py +37 -0
- package/tui/cli.py +208 -0
- package/tui/code_analyze.py +27 -0
- package/tui/complete.py +38 -0
- package/tui/constants.py +61 -0
- package/tui/conversation_markdown.py +30 -0
- package/tui/danger.py +372 -0
- package/tui/data/agents/ampcode.com.toml +52 -0
- package/tui/data/agents/augmentcode.com.toml +41 -0
- package/tui/data/agents/cdh.cloud-dev-harness.toml +23 -0
- package/tui/data/agents/claude.com.toml +41 -0
- package/tui/data/agents/copilot.github.com.toml +29 -0
- package/tui/data/agents/crowai.dev.toml +36 -0
- package/tui/data/agents/cursor.com.toml +38 -0
- package/tui/data/agents/deepagents.langchain.com +34 -0
- package/tui/data/agents/docker.com.toml +60 -0
- package/tui/data/agents/geminicli.com.toml +28 -0
- package/tui/data/agents/goose.ai.toml +52 -0
- package/tui/data/agents/inference.huggingface.co.toml +41 -0
- package/tui/data/agents/kimi.com.toml +35 -0
- package/tui/data/agents/kiro.dev.toml +43 -0
- package/tui/data/agents/onecode.dev.toml +22 -0
- package/tui/data/agents/openai.com.toml +53 -0
- package/tui/data/agents/openclaw.ai.toml +37 -0
- package/tui/data/agents/opencode.ai.toml +39 -0
- package/tui/data/agents/openhands.dev.toml +46 -0
- package/tui/data/agents/stakpak.dev.toml +62 -0
- package/tui/data/agents/vibe.mistral.ai.toml +31 -0
- package/tui/data/agents/vtcode.dev.toml +63 -0
- package/tui/data/images/frog.png +0 -0
- package/tui/data/sounds/question.wav +0 -0
- package/tui/data/sounds/turn-over.wav +0 -0
- package/tui/db.py +213 -0
- package/tui/dec.py +332 -0
- package/tui/diff_utils.py +131 -0
- package/tui/directory.py +234 -0
- package/tui/directory_suggester.py +93 -0
- package/tui/directory_watcher.py +231 -0
- package/tui/format_path.py +25 -0
- package/tui/fuzzy.py +140 -0
- package/tui/fuzzy_index.py +275 -0
- package/tui/gist.py +33 -0
- package/tui/history.py +138 -0
- package/tui/jsonrpc.py +599 -0
- package/tui/menus.py +14 -0
- package/tui/message_log.py +69 -0
- package/tui/messages.py +144 -0
- package/tui/option_content.py +51 -0
- package/tui/os.py +0 -0
- package/tui/path_complete.py +217 -0
- package/tui/path_filter.py +124 -0
- package/tui/paths.py +87 -0
- package/tui/pill.py +23 -0
- package/tui/platform_commands.py +52 -0
- package/tui/prompt/__pycache__/extract.cpython-314.pyc +0 -0
- package/tui/prompt/__pycache__/resource.cpython-314.pyc +0 -0
- package/tui/prompt/extract.py +19 -0
- package/tui/prompt/resource.py +68 -0
- package/tui/protocol.py +28 -0
- package/tui/screens/__init__.py +0 -0
- package/tui/screens/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/diff_screen.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/main.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/sessions.cpython-314.pyc +0 -0
- package/tui/screens/action_modal.py +94 -0
- package/tui/screens/agent_modal.py +175 -0
- package/tui/screens/command_edit_modal.py +74 -0
- package/tui/screens/diff_explorer_screen.py +419 -0
- package/tui/screens/diff_screen.py +84 -0
- package/tui/screens/ide_screen.py +461 -0
- package/tui/screens/main.py +397 -0
- package/tui/screens/main.tcss +662 -0
- package/tui/screens/permissions.py +404 -0
- package/tui/screens/permissions.tcss +72 -0
- package/tui/screens/projects.tcss +84 -0
- package/tui/screens/projects_app.py +341 -0
- package/tui/screens/projects_screen.py +277 -0
- package/tui/screens/session_resume_modal.py +172 -0
- package/tui/screens/session_resume_modal.tcss +35 -0
- package/tui/screens/sessions.py +171 -0
- package/tui/screens/sessions.tcss +119 -0
- package/tui/screens/settings.py +293 -0
- package/tui/screens/settings.tcss +113 -0
- package/tui/screens/store.py +502 -0
- package/tui/screens/store.tcss +274 -0
- package/tui/screens/tool_content_screen.py +59 -0
- package/tui/screens/trace.py +317 -0
- package/tui/session_tracker.py +123 -0
- package/tui/settings.py +353 -0
- package/tui/settings_schema.py +467 -0
- package/tui/shell.py +304 -0
- package/tui/shell_read.py +42 -0
- package/tui/slash_command.py +34 -0
- package/tui/tui.tcss +246 -0
- package/tui/twitter.py +38 -0
- package/tui/version.py +80 -0
- package/tui/visuals/__init__.py +0 -0
- package/tui/visuals/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tui/visuals/__pycache__/columns.cpython-314.pyc +0 -0
- package/tui/visuals/columns.py +272 -0
- package/tui/widgets/__init__.py +0 -0
- package/tui/widgets/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/agent_response.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/agent_thought.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/aidlc.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/ask_user.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/condensed_path.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/context_stats.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/conversation.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/diff_view.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/flash.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/future_text.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/grid_select.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/highlighted_textarea.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/load_more.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/menu.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/modified_files.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/non_selectable_label.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/note.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/path_search.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/pending_prompts.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/plan.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/project_directory_tree.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/prompt.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/question.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/session_grid_select.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/session_summary.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/session_tabs.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/shell_terminal.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/side_bar.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/slash_complete.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/strike_text.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/terminal.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/throbber.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/tool_call.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/user_input.cpython-314.pyc +0 -0
- package/tui/widgets/acp_content.py +70 -0
- package/tui/widgets/agent_response.py +76 -0
- package/tui/widgets/agent_thought.py +167 -0
- package/tui/widgets/aidlc.py +334 -0
- package/tui/widgets/ask_user.py +604 -0
- package/tui/widgets/command_pane.py +223 -0
- package/tui/widgets/condensed_path.py +115 -0
- package/tui/widgets/context_stats.py +66 -0
- package/tui/widgets/conversation.py +3235 -0
- package/tui/widgets/danger_warning.py +65 -0
- package/tui/widgets/diff_view.py +69 -0
- package/tui/widgets/directory_input.py +8 -0
- package/tui/widgets/edit_field.py +206 -0
- package/tui/widgets/flash.py +81 -0
- package/tui/widgets/future_text.py +126 -0
- package/tui/widgets/grid_select.py +234 -0
- package/tui/widgets/highlighted_textarea.py +183 -0
- package/tui/widgets/load_more.py +24 -0
- package/tui/widgets/mandelbrot.py +294 -0
- package/tui/widgets/markdown_note.py +13 -0
- package/tui/widgets/menu.py +147 -0
- package/tui/widgets/model_status.py +230 -0
- package/tui/widgets/modified_files.py +315 -0
- package/tui/widgets/non_selectable_label.py +5 -0
- package/tui/widgets/note.py +18 -0
- package/tui/widgets/path_search.py +492 -0
- package/tui/widgets/pending_prompts.py +36 -0
- package/tui/widgets/plan.py +285 -0
- package/tui/widgets/project_directory_tree.py +102 -0
- package/tui/widgets/project_grid_select.py +68 -0
- package/tui/widgets/project_summary.py +33 -0
- package/tui/widgets/prompt.py +935 -0
- package/tui/widgets/question.py +360 -0
- package/tui/widgets/session_grid_select.py +230 -0
- package/tui/widgets/session_summary.py +115 -0
- package/tui/widgets/session_tabs.py +194 -0
- package/tui/widgets/shell_result.py +35 -0
- package/tui/widgets/shell_terminal.py +40 -0
- package/tui/widgets/side_bar.py +124 -0
- package/tui/widgets/slash_complete.py +235 -0
- package/tui/widgets/strike_text.py +70 -0
- package/tui/widgets/subagent.py +287 -0
- package/tui/widgets/subagent_screen.py +715 -0
- package/tui/widgets/terminal.py +576 -0
- package/tui/widgets/terminal_tool.py +360 -0
- package/tui/widgets/throbber.py +100 -0
- package/tui/widgets/tool_call.py +432 -0
- package/tui/widgets/user_input.py +23 -0
- package/tui/widgets/version.py +5 -0
- package/tui/widgets/welcome.py +31 -0
package/onecode/cli.py
ADDED
|
@@ -0,0 +1,1325 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import logging
|
|
5
|
+
from logging.handlers import TimedRotatingFileHandler
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from onecode.config import load_config, save_config
|
|
10
|
+
|
|
11
|
+
LOG_DIR = Path.home() / ".onecode" / "logs"
|
|
12
|
+
LOG_FILE = LOG_DIR / "onecode.log"
|
|
13
|
+
LOG_BACKUP_COUNT = 7 # keep 7 days of history
|
|
14
|
+
|
|
15
|
+
_VALID_LOG_LEVELS = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def setup_logging(log_level: str = "INFO") -> logging.Logger:
|
|
19
|
+
"""Configure root logging to write to a daily-rotated ``cdh.log`` file.
|
|
20
|
+
|
|
21
|
+
The active log is always ``~/.cdh/logs/cdh.log``; at midnight it is
|
|
22
|
+
rolled to ``cdh.log.YYYY-MM-DD`` and a fresh file is started. Up to
|
|
23
|
+
:data:`LOG_BACKUP_COUNT` days of history are retained.
|
|
24
|
+
|
|
25
|
+
Returns the root logger so callers can attach additional handlers (e.g.
|
|
26
|
+
a console handler) without re-running ``basicConfig``.
|
|
27
|
+
"""
|
|
28
|
+
LOG_DIR.mkdir(parents=True, exist_ok=True)
|
|
29
|
+
level = log_level.upper()
|
|
30
|
+
if level not in _VALID_LOG_LEVELS:
|
|
31
|
+
level = "INFO"
|
|
32
|
+
numeric_level = getattr(logging, level)
|
|
33
|
+
|
|
34
|
+
handler = TimedRotatingFileHandler(
|
|
35
|
+
LOG_FILE,
|
|
36
|
+
when="midnight",
|
|
37
|
+
interval=1,
|
|
38
|
+
backupCount=LOG_BACKUP_COUNT,
|
|
39
|
+
encoding="utf-8",
|
|
40
|
+
utc=False,
|
|
41
|
+
)
|
|
42
|
+
handler.suffix = "%Y-%m-%d"
|
|
43
|
+
handler.setFormatter(
|
|
44
|
+
logging.Formatter("%(asctime)s [%(name)s] %(levelname)s: %(message)s")
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
root = logging.getLogger()
|
|
48
|
+
root.setLevel(numeric_level)
|
|
49
|
+
# Avoid stacking handlers if setup_logging() is called twice (e.g. by
|
|
50
|
+
# tests importing both the CLI and a sub-process entry point).
|
|
51
|
+
for h in list(root.handlers):
|
|
52
|
+
if isinstance(h, TimedRotatingFileHandler) and getattr(h, "baseFilename", "") == str(LOG_FILE):
|
|
53
|
+
root.removeHandler(h)
|
|
54
|
+
root.addHandler(handler)
|
|
55
|
+
|
|
56
|
+
# Silence chatty third-party loggers; keep the rest at the requested level.
|
|
57
|
+
logging.getLogger("httpx").setLevel(logging.WARNING)
|
|
58
|
+
logging.getLogger("httpcore").setLevel(logging.WARNING)
|
|
59
|
+
# Engine / provider / adapter loggers — leave at the requested level
|
|
60
|
+
# (do NOT cap the entire ``onecode`` namespace at WARNING any more, that
|
|
61
|
+
# was the bug which kept ``cdh.log`` empty).
|
|
62
|
+
return root
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@click.group()
|
|
66
|
+
@click.option(
|
|
67
|
+
"--log-level",
|
|
68
|
+
type=click.Choice(sorted(_VALID_LOG_LEVELS), case_sensitive=False),
|
|
69
|
+
default="INFO",
|
|
70
|
+
show_default=True,
|
|
71
|
+
envvar="CDH_LOG_LEVEL",
|
|
72
|
+
help="Root logger verbosity. Defaults to INFO; daily-rotated to ~/.cdh/logs/cdh.log.",
|
|
73
|
+
)
|
|
74
|
+
def cli(log_level: str):
|
|
75
|
+
"""CDH Agent CLI - Cloud Dev Harness Agent commands."""
|
|
76
|
+
setup_logging(log_level)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@cli.group(invoke_without_command=True)
|
|
80
|
+
def config():
|
|
81
|
+
"""Manage CDH configuration (mode, model, provider, cloud, skill, mcp)."""
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# --- config mode sub-command ---
|
|
86
|
+
|
|
87
|
+
@config.group("mode")
|
|
88
|
+
def config_mode():
|
|
89
|
+
"""Manage default agent mode (build, plan, solo)."""
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@config_mode.command("get")
|
|
94
|
+
def config_mode_get():
|
|
95
|
+
"""Show current mode."""
|
|
96
|
+
cfg = load_config()
|
|
97
|
+
click.echo(f"mode = {cfg.default_mode} (build | plan | solo)")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@config_mode.command("set")
|
|
101
|
+
@click.argument("value", default="build")
|
|
102
|
+
def config_mode_set(value):
|
|
103
|
+
"""Set default agent mode."""
|
|
104
|
+
cfg = load_config()
|
|
105
|
+
cfg.default_mode = value
|
|
106
|
+
save_config(cfg)
|
|
107
|
+
click.echo(f"mode = {value}")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# --- config model sub-command ---
|
|
111
|
+
|
|
112
|
+
@config.group("model")
|
|
113
|
+
def config_model():
|
|
114
|
+
"""Manage default LLM model."""
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@config_model.command("get")
|
|
119
|
+
def config_model_get():
|
|
120
|
+
"""Show current model."""
|
|
121
|
+
cfg = load_config()
|
|
122
|
+
click.echo(f"model = {cfg.default_model}")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@config_model.command("set")
|
|
126
|
+
@click.argument("value")
|
|
127
|
+
def config_model_set(value):
|
|
128
|
+
"""Set default LLM model."""
|
|
129
|
+
cfg = load_config()
|
|
130
|
+
cfg.default_model = value
|
|
131
|
+
save_config(cfg)
|
|
132
|
+
click.echo(f"model = {value}")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# --- config provider sub-command ---
|
|
136
|
+
|
|
137
|
+
@config.group("provider")
|
|
138
|
+
def config_provider():
|
|
139
|
+
"""Manage default LLM provider."""
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@config_provider.command("get")
|
|
144
|
+
def config_provider_get():
|
|
145
|
+
"""Show current provider."""
|
|
146
|
+
cfg = load_config()
|
|
147
|
+
click.echo(f"provider = {cfg.default_provider}")
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@config_provider.command("set")
|
|
151
|
+
@click.argument("value")
|
|
152
|
+
def config_provider_set(value):
|
|
153
|
+
"""Set default LLM provider."""
|
|
154
|
+
cfg = load_config()
|
|
155
|
+
cfg.default_provider = value
|
|
156
|
+
save_config(cfg)
|
|
157
|
+
click.echo(f"provider = {value}")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@config_provider.command("list")
|
|
161
|
+
def config_provider_list():
|
|
162
|
+
"""List registered LLM providers (with the current one marked)."""
|
|
163
|
+
from onecode.models.provider import ProviderRegistry
|
|
164
|
+
from onecode.models.registry import ModelRegistry
|
|
165
|
+
|
|
166
|
+
# Trigger provider/model registration side-effects.
|
|
167
|
+
try:
|
|
168
|
+
from onecode.models import providers as _providers_mod # noqa: F401
|
|
169
|
+
except ImportError:
|
|
170
|
+
pass
|
|
171
|
+
try:
|
|
172
|
+
ModelRegistry.initialize()
|
|
173
|
+
except Exception:
|
|
174
|
+
pass
|
|
175
|
+
|
|
176
|
+
cfg = load_config()
|
|
177
|
+
current = cfg.default_provider
|
|
178
|
+
registered = sorted(ProviderRegistry.list())
|
|
179
|
+
if not registered:
|
|
180
|
+
click.echo("No providers registered.")
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
click.echo(f"Available providers ({len(registered)}):")
|
|
184
|
+
for i, name in enumerate(registered, 1):
|
|
185
|
+
marker = " ← active" if name == current else ""
|
|
186
|
+
try:
|
|
187
|
+
models = ModelRegistry.list_by_provider(name)
|
|
188
|
+
except Exception:
|
|
189
|
+
models = []
|
|
190
|
+
if models:
|
|
191
|
+
model_names = sorted({m.id for m in models})
|
|
192
|
+
shown = ", ".join(model_names[:5])
|
|
193
|
+
if len(model_names) > 5:
|
|
194
|
+
shown += f", … (+{len(model_names) - 5})"
|
|
195
|
+
model_hint = f" models: {shown}"
|
|
196
|
+
else:
|
|
197
|
+
model_hint = " models: (any local)"
|
|
198
|
+
click.echo(f" {i}) {name}{marker}{model_hint}")
|
|
199
|
+
click.echo("")
|
|
200
|
+
click.echo("Switch with: cdh onecode config provider set <name|n>")
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
# --- config log-level sub-command ---
|
|
204
|
+
|
|
205
|
+
@config.group("log-level")
|
|
206
|
+
def config_log_level():
|
|
207
|
+
"""Manage log level."""
|
|
208
|
+
pass
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@config_log_level.command("get")
|
|
212
|
+
def config_log_level_get():
|
|
213
|
+
"""Show current log level."""
|
|
214
|
+
cfg = load_config()
|
|
215
|
+
click.echo(f"log-level = {cfg.log_level} (debug | info | warn | error)")
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@config_log_level.command("set")
|
|
219
|
+
@click.argument("value", default="info")
|
|
220
|
+
def config_log_level_set(value):
|
|
221
|
+
"""Set log level."""
|
|
222
|
+
cfg = load_config()
|
|
223
|
+
cfg.log_level = value
|
|
224
|
+
save_config(cfg)
|
|
225
|
+
click.echo(f"log-level = {value}")
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
# --- config list ---
|
|
229
|
+
|
|
230
|
+
@config.command("list")
|
|
231
|
+
def config_list():
|
|
232
|
+
"""Show full YAML configuration."""
|
|
233
|
+
cfg = load_config()
|
|
234
|
+
import yaml
|
|
235
|
+
from onecode.config import _dataclass_to_dict
|
|
236
|
+
click.echo(yaml.dump(_dataclass_to_dict(cfg), default_flow_style=False))
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@cli.group(invoke_without_command=True)
|
|
240
|
+
def skill():
|
|
241
|
+
"""Manage CDH skills (list, add, remove).
|
|
242
|
+
|
|
243
|
+
\b
|
|
244
|
+
Skills are instruction sets that extend the agent's capabilities.
|
|
245
|
+
Use `cdh skill list` to see available skills.
|
|
246
|
+
"""
|
|
247
|
+
pass
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@skill.command("list")
|
|
251
|
+
def skill_list():
|
|
252
|
+
"""List all skills."""
|
|
253
|
+
from onecode.skills.loader import SkillLoader
|
|
254
|
+
|
|
255
|
+
loader = SkillLoader()
|
|
256
|
+
skills = loader.get_all()
|
|
257
|
+
|
|
258
|
+
if not skills:
|
|
259
|
+
click.echo("No skills found.")
|
|
260
|
+
return
|
|
261
|
+
|
|
262
|
+
click.echo("Skills:")
|
|
263
|
+
for s in skills.values():
|
|
264
|
+
status = "[enabled]" if s.enabled else "[disabled]"
|
|
265
|
+
click.echo(f" {status} {s.name}")
|
|
266
|
+
if s.description:
|
|
267
|
+
click.echo(f" {s.description}")
|
|
268
|
+
click.echo(f"\nTotal: {len(skills)} skill(s)")
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@skill.command("add")
|
|
272
|
+
@click.argument("path", type=click.Path(exists=True, file_okay=True, dir_okay=True, path_type=Path))
|
|
273
|
+
def skill_add(path):
|
|
274
|
+
"""Install a skill from a local path.
|
|
275
|
+
|
|
276
|
+
\b
|
|
277
|
+
The path should contain a skill.yaml and SKILL.md file.
|
|
278
|
+
|
|
279
|
+
\b
|
|
280
|
+
Example:
|
|
281
|
+
cdh skill add /path/to/my-skill
|
|
282
|
+
"""
|
|
283
|
+
from onecode.skills.manager import SkillManager
|
|
284
|
+
|
|
285
|
+
skill_path = Path(path)
|
|
286
|
+
if skill_path.is_file():
|
|
287
|
+
skill_path = skill_path.parent
|
|
288
|
+
|
|
289
|
+
mgr = SkillManager()
|
|
290
|
+
err = mgr.install(skill_path)
|
|
291
|
+
if err:
|
|
292
|
+
click.echo(f"Error: {err}")
|
|
293
|
+
else:
|
|
294
|
+
click.echo(f"Skill installed from {skill_path}")
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
@skill.command("remove")
|
|
298
|
+
@click.argument("name")
|
|
299
|
+
def skill_remove(name):
|
|
300
|
+
"""Remove an installed skill by name."""
|
|
301
|
+
from onecode.skills.manager import SkillManager
|
|
302
|
+
|
|
303
|
+
mgr = SkillManager()
|
|
304
|
+
err = mgr.remove(name)
|
|
305
|
+
if err:
|
|
306
|
+
click.echo(f"Error: {err}")
|
|
307
|
+
else:
|
|
308
|
+
click.echo(f"Skill '{name}' removed.")
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
@skill.command("enable")
|
|
312
|
+
@click.argument("name")
|
|
313
|
+
def skill_enable(name):
|
|
314
|
+
"""Enable a skill by name."""
|
|
315
|
+
_toggle_skill(name, enabled=True)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
@skill.command("disable")
|
|
319
|
+
@click.argument("name")
|
|
320
|
+
def skill_disable(name):
|
|
321
|
+
"""Disable a skill by name."""
|
|
322
|
+
_toggle_skill(name, enabled=False)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
@skill.command("create")
|
|
326
|
+
@click.argument("name")
|
|
327
|
+
@click.option("--description", "-d", default="", help="Skill description")
|
|
328
|
+
def skill_create(name, description):
|
|
329
|
+
"""Create a new skill scaffold.
|
|
330
|
+
|
|
331
|
+
\b
|
|
332
|
+
Creates SKILL.md and skill.yaml in ~/.onecode/skills/<name>/.
|
|
333
|
+
Edit the generated SKILL.md to add your instructions.
|
|
334
|
+
|
|
335
|
+
\b
|
|
336
|
+
Example:
|
|
337
|
+
cdh skill create my-skill -d "My custom skill"
|
|
338
|
+
"""
|
|
339
|
+
from onecode.skills.create import create_skill_scaffold
|
|
340
|
+
from onecode.skills.manager import SkillManager
|
|
341
|
+
from onecode.skills.model import Skill as SkillModel
|
|
342
|
+
|
|
343
|
+
valid, err = SkillModel.validate_name(name)
|
|
344
|
+
if not valid:
|
|
345
|
+
click.echo(f"Error: Invalid skill name: {err}")
|
|
346
|
+
return
|
|
347
|
+
if description:
|
|
348
|
+
valid, err = SkillModel.validate_description(description)
|
|
349
|
+
if not valid:
|
|
350
|
+
click.echo(f"Error: Invalid description: {err}")
|
|
351
|
+
return
|
|
352
|
+
|
|
353
|
+
mgr = SkillManager()
|
|
354
|
+
err = create_skill_scaffold(mgr.skills_dir, name, description or f"A skill for {name}")
|
|
355
|
+
if err:
|
|
356
|
+
click.echo(f"Error: {err}")
|
|
357
|
+
else:
|
|
358
|
+
click.echo(f"Skill '{name}' created at {mgr.skills_dir / name}")
|
|
359
|
+
click.echo(f" Edit {mgr.skills_dir / name / 'SKILL.md'} to add instructions.")
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
@skill.command("search")
|
|
363
|
+
@click.argument("keyword")
|
|
364
|
+
def skill_search(keyword):
|
|
365
|
+
"""Search installed skills by keyword.
|
|
366
|
+
|
|
367
|
+
Matches against name, description, triggers, and phases.
|
|
368
|
+
Case-insensitive.
|
|
369
|
+
|
|
370
|
+
\b
|
|
371
|
+
Example:
|
|
372
|
+
cdh skill search browser
|
|
373
|
+
"""
|
|
374
|
+
from onecode.skills.loader import SkillLoader
|
|
375
|
+
|
|
376
|
+
loader = SkillLoader()
|
|
377
|
+
results = loader.search(keyword)
|
|
378
|
+
|
|
379
|
+
if not results:
|
|
380
|
+
click.echo(f"No skills found matching '{keyword}'.")
|
|
381
|
+
return
|
|
382
|
+
|
|
383
|
+
click.echo(f"Skills matching '{keyword}':")
|
|
384
|
+
for s in results:
|
|
385
|
+
status = "[enabled]" if s.enabled else "[disabled]"
|
|
386
|
+
click.echo(f" {status} {s.name}")
|
|
387
|
+
if s.description:
|
|
388
|
+
click.echo(f" {s.description}")
|
|
389
|
+
click.echo(f"\nTotal: {len(results)} match(es)")
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def _toggle_skill(name: str, enabled: bool):
|
|
393
|
+
import yaml
|
|
394
|
+
from onecode.skills.loader import SkillLoader
|
|
395
|
+
|
|
396
|
+
loader = SkillLoader()
|
|
397
|
+
skill = loader.get(name)
|
|
398
|
+
if not skill or not skill.path:
|
|
399
|
+
click.echo(f"Skill '{name}' not found.")
|
|
400
|
+
return
|
|
401
|
+
|
|
402
|
+
skill_yaml = skill.path / "skill.yaml"
|
|
403
|
+
if not skill_yaml.exists():
|
|
404
|
+
click.echo(f"No skill.yaml found at {skill.path}")
|
|
405
|
+
return
|
|
406
|
+
|
|
407
|
+
data = yaml.safe_load(skill_yaml.read_text()) or {}
|
|
408
|
+
data["enabled"] = enabled
|
|
409
|
+
skill_yaml.write_text(yaml.dump(data, default_flow_style=False))
|
|
410
|
+
loader.invalidate_cache()
|
|
411
|
+
status = "enabled" if enabled else "disabled"
|
|
412
|
+
click.echo(f"Skill '{name}' {status}.")
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
@config.group("skill")
|
|
416
|
+
def config_skill():
|
|
417
|
+
"""Manage CDH skills (alias for cdh skill)."""
|
|
418
|
+
pass
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
@config_skill.command("list")
|
|
422
|
+
def config_skill_list():
|
|
423
|
+
"""List all skills."""
|
|
424
|
+
from onecode.skills.loader import SkillLoader
|
|
425
|
+
|
|
426
|
+
loader = SkillLoader()
|
|
427
|
+
skills = loader.get_all()
|
|
428
|
+
|
|
429
|
+
if not skills:
|
|
430
|
+
click.echo("No skills found.")
|
|
431
|
+
return
|
|
432
|
+
|
|
433
|
+
click.echo("Skills:")
|
|
434
|
+
for s in skills.values():
|
|
435
|
+
status = "[enabled]" if s.enabled else "[disabled]"
|
|
436
|
+
click.echo(f" {status} {s.name}")
|
|
437
|
+
if s.description:
|
|
438
|
+
click.echo(f" {s.description}")
|
|
439
|
+
click.echo(f"\nTotal: {len(skills)} skill(s)")
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
@config_skill.command("add")
|
|
443
|
+
@click.argument("path", type=click.Path(exists=True, file_okay=True, dir_okay=True, path_type=Path))
|
|
444
|
+
def config_skill_add(path):
|
|
445
|
+
"""Install a skill from a local path."""
|
|
446
|
+
from onecode.skills.manager import SkillManager
|
|
447
|
+
|
|
448
|
+
skill_path = Path(path)
|
|
449
|
+
if skill_path.is_file():
|
|
450
|
+
skill_path = skill_path.parent
|
|
451
|
+
|
|
452
|
+
mgr = SkillManager()
|
|
453
|
+
err = mgr.install(skill_path)
|
|
454
|
+
if err:
|
|
455
|
+
click.echo(f"Error: {err}")
|
|
456
|
+
else:
|
|
457
|
+
click.echo(f"Skill installed from {skill_path}")
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
@config_skill.command("remove")
|
|
461
|
+
@click.argument("name")
|
|
462
|
+
def config_skill_remove(name):
|
|
463
|
+
"""Remove an installed skill by name."""
|
|
464
|
+
from onecode.skills.manager import SkillManager
|
|
465
|
+
|
|
466
|
+
mgr = SkillManager()
|
|
467
|
+
err = mgr.remove(name)
|
|
468
|
+
if err:
|
|
469
|
+
click.echo(f"Error: {err}")
|
|
470
|
+
else:
|
|
471
|
+
click.echo(f"Skill '{name}' removed.")
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
@config_skill.command("enable")
|
|
475
|
+
@click.argument("name")
|
|
476
|
+
def config_skill_enable(name):
|
|
477
|
+
"""Enable a skill by name."""
|
|
478
|
+
_toggle_skill(name, enabled=True)
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
@config_skill.command("disable")
|
|
482
|
+
@click.argument("name")
|
|
483
|
+
def config_skill_disable(name):
|
|
484
|
+
"""Disable a skill by name."""
|
|
485
|
+
_toggle_skill(name, enabled=False)
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
@config_skill.command("create")
|
|
489
|
+
@click.argument("name")
|
|
490
|
+
@click.option("--description", "-d", default="", help="Skill description")
|
|
491
|
+
def config_skill_create(name, description):
|
|
492
|
+
"""Create a new skill scaffold (alias for cdh skill create)."""
|
|
493
|
+
from onecode.skills.create import create_skill_scaffold
|
|
494
|
+
from onecode.skills.manager import SkillManager
|
|
495
|
+
from onecode.skills.model import Skill as SkillModel
|
|
496
|
+
|
|
497
|
+
valid, err = SkillModel.validate_name(name)
|
|
498
|
+
if not valid:
|
|
499
|
+
click.echo(f"Error: Invalid skill name: {err}")
|
|
500
|
+
return
|
|
501
|
+
if description:
|
|
502
|
+
valid, err = SkillModel.validate_description(description)
|
|
503
|
+
if not valid:
|
|
504
|
+
click.echo(f"Error: Invalid description: {err}")
|
|
505
|
+
return
|
|
506
|
+
|
|
507
|
+
mgr = SkillManager()
|
|
508
|
+
err = create_skill_scaffold(mgr.skills_dir, name, description or f"A skill for {name}")
|
|
509
|
+
if err:
|
|
510
|
+
click.echo(f"Error: {err}")
|
|
511
|
+
else:
|
|
512
|
+
click.echo(f"Skill '{name}' created at {mgr.skills_dir / name}")
|
|
513
|
+
click.echo(f" Edit {mgr.skills_dir / name / 'SKILL.md'} to add instructions.")
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
@config_skill.command("search")
|
|
517
|
+
@click.argument("keyword")
|
|
518
|
+
def config_skill_search(keyword):
|
|
519
|
+
"""Search installed skills by keyword (alias for cdh skill search)."""
|
|
520
|
+
from onecode.skills.loader import SkillLoader
|
|
521
|
+
|
|
522
|
+
loader = SkillLoader()
|
|
523
|
+
results = loader.search(keyword)
|
|
524
|
+
|
|
525
|
+
if not results:
|
|
526
|
+
click.echo(f"No skills found matching '{keyword}'.")
|
|
527
|
+
return
|
|
528
|
+
|
|
529
|
+
click.echo(f"Skills matching '{keyword}':")
|
|
530
|
+
for s in results:
|
|
531
|
+
status = "[enabled]" if s.enabled else "[disabled]"
|
|
532
|
+
click.echo(f" {status} {s.name}")
|
|
533
|
+
if s.description:
|
|
534
|
+
click.echo(f" {s.description}")
|
|
535
|
+
click.echo(f"\nTotal: {len(results)} match(es)")
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
@cli.group(invoke_without_command=True)
|
|
539
|
+
def mcp():
|
|
540
|
+
"""Manage MCP (Model Context Protocol) servers.
|
|
541
|
+
|
|
542
|
+
\b
|
|
543
|
+
MCP servers expose tools and resources to the agent.
|
|
544
|
+
Use `cdh mcp list` to see configured servers.
|
|
545
|
+
"""
|
|
546
|
+
pass
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
_SECRET_HEADER_HINTS = ("auth", "token", "key", "secret", "password", "cookie")
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
def _is_secret_key(k: str) -> bool:
|
|
553
|
+
kl = k.lower()
|
|
554
|
+
return any(s in kl for s in _SECRET_HEADER_HINTS)
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def _mask_value(v: str) -> str:
|
|
558
|
+
if not v:
|
|
559
|
+
return v
|
|
560
|
+
if len(v) <= 4:
|
|
561
|
+
return "***"
|
|
562
|
+
return v[:2] + "***" + v[-2:]
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
def _format_mcp_servers(servers: list[dict]) -> list[str]:
|
|
566
|
+
lines = []
|
|
567
|
+
if not servers:
|
|
568
|
+
return lines
|
|
569
|
+
for s in servers:
|
|
570
|
+
name = s.get("name", "unknown")
|
|
571
|
+
transport = s.get("transport", "sse")
|
|
572
|
+
enabled = s.get("enabled", True)
|
|
573
|
+
status = "[enabled]" if enabled else "[disabled]"
|
|
574
|
+
if transport == "sse":
|
|
575
|
+
url = s.get("url", "")
|
|
576
|
+
lines.append(f" {status} {name} (SSE)")
|
|
577
|
+
if url:
|
|
578
|
+
lines.append(f" URL: {url}")
|
|
579
|
+
elif transport == "http":
|
|
580
|
+
url = s.get("url", "")
|
|
581
|
+
headers = s.get("headers", {})
|
|
582
|
+
lines.append(f" {status} {name} (HTTP)")
|
|
583
|
+
if url:
|
|
584
|
+
lines.append(f" URL: {url}")
|
|
585
|
+
if headers:
|
|
586
|
+
hdr_str = ", ".join(
|
|
587
|
+
f"{k}={_mask_value(v) if _is_secret_key(k) else v}"
|
|
588
|
+
for k, v in headers.items()
|
|
589
|
+
)
|
|
590
|
+
lines.append(f" Headers: {hdr_str}")
|
|
591
|
+
else:
|
|
592
|
+
cmd = s.get("command", "")
|
|
593
|
+
cmd_args = " ".join(s.get("args", []))
|
|
594
|
+
env = s.get("env", {})
|
|
595
|
+
lines.append(f" {status} {name} (stdio)")
|
|
596
|
+
if cmd:
|
|
597
|
+
lines.append(f" Command: {cmd} {cmd_args}".rstrip())
|
|
598
|
+
if env:
|
|
599
|
+
env_str = ", ".join(f"{k}=***" for k in env)
|
|
600
|
+
lines.append(f" Env: {env_str}")
|
|
601
|
+
return lines
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
def _parse_kv_pairs(raw: Optional[str]) -> dict[str, str]:
|
|
605
|
+
"""Parse comma-separated KEY=VALUE pairs into a dict."""
|
|
606
|
+
result = {}
|
|
607
|
+
if not raw:
|
|
608
|
+
return result
|
|
609
|
+
for pair in raw.split(","):
|
|
610
|
+
pair = pair.strip()
|
|
611
|
+
if not pair:
|
|
612
|
+
continue
|
|
613
|
+
if "=" not in pair:
|
|
614
|
+
continue
|
|
615
|
+
key, _, val = pair.partition("=")
|
|
616
|
+
result[key.strip()] = val.strip()
|
|
617
|
+
return result
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
def _mcp_add_impl(name, url, transport, command, args, env, headers, explicit_url):
|
|
621
|
+
"""Add an MCP server using either the opencode-style or legacy fields."""
|
|
622
|
+
from onecode.mcp.config import MCPServerConfig
|
|
623
|
+
from onecode.mcp.manager import MCPManager
|
|
624
|
+
|
|
625
|
+
mgr = MCPManager()
|
|
626
|
+
if mgr.get_server(name):
|
|
627
|
+
raise click.UsageError(f"MCP server '{name}' already exists")
|
|
628
|
+
|
|
629
|
+
# Normalize transport aliases -> opencode "type"
|
|
630
|
+
transport_norm = (transport or "").lower()
|
|
631
|
+
if transport_norm in ("http", "sse"):
|
|
632
|
+
server_type = "remote"
|
|
633
|
+
elif transport_norm in ("stdio", "local", ""):
|
|
634
|
+
server_type = "local"
|
|
635
|
+
else:
|
|
636
|
+
raise click.UsageError(
|
|
637
|
+
f"unknown transport '{transport}' (use stdio|local|http|sse|remote)"
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
cfg = MCPServerConfig(name=name, type=server_type, enabled=True)
|
|
641
|
+
|
|
642
|
+
if server_type == "local":
|
|
643
|
+
if not command:
|
|
644
|
+
raise click.UsageError("--command required for stdio/local transport")
|
|
645
|
+
if "," in command and not args:
|
|
646
|
+
# Allow `--command npx,-y,pkg` shorthand
|
|
647
|
+
cmd_list = [c.strip() for c in command.split(",") if c.strip()]
|
|
648
|
+
else:
|
|
649
|
+
cmd_list = [command] + ([a.strip() for a in args.split(",")] if args else [])
|
|
650
|
+
cfg.command = cmd_list
|
|
651
|
+
cfg.environment = _parse_kv_pairs(env)
|
|
652
|
+
else:
|
|
653
|
+
final_url = explicit_url or url
|
|
654
|
+
if not final_url:
|
|
655
|
+
raise click.UsageError("--url required for remote transport")
|
|
656
|
+
cfg.url = final_url
|
|
657
|
+
hdrs = _parse_kv_pairs(headers)
|
|
658
|
+
if hdrs:
|
|
659
|
+
cfg.headers = hdrs
|
|
660
|
+
|
|
661
|
+
errs = cfg.validate()
|
|
662
|
+
if errs:
|
|
663
|
+
for e in errs:
|
|
664
|
+
click.echo(f"Error: {e}")
|
|
665
|
+
raise click.UsageError("\n".join(errs))
|
|
666
|
+
|
|
667
|
+
mgr.add_server(name, cfg)
|
|
668
|
+
if server_type == "local":
|
|
669
|
+
click.echo(f"MCP server '{name}' added (local): {' '.join(cfg.command or [])}")
|
|
670
|
+
else:
|
|
671
|
+
click.echo(f"MCP server '{name}' added (remote): {cfg.url}")
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
@mcp.command("list")
|
|
675
|
+
def mcp_list():
|
|
676
|
+
"""List all configured MCP servers."""
|
|
677
|
+
from onecode.mcp.manager import MCPManager
|
|
678
|
+
|
|
679
|
+
mgr = MCPManager()
|
|
680
|
+
servers = mgr.list()
|
|
681
|
+
|
|
682
|
+
if not servers:
|
|
683
|
+
click.echo("No MCP servers configured. Use `cdh mcp add <name> <url>` to add one.")
|
|
684
|
+
return
|
|
685
|
+
|
|
686
|
+
click.echo("Configured MCP servers:")
|
|
687
|
+
for line in _format_mcp_servers(servers):
|
|
688
|
+
click.echo(line)
|
|
689
|
+
click.echo(f"\nTotal: {len(servers)} server(s)")
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
@mcp.command("add")
|
|
693
|
+
@click.argument("name")
|
|
694
|
+
@click.argument("url", required=False, default="")
|
|
695
|
+
@click.option("--type", "transport", default="sse", help="Transport type: sse, stdio, or http")
|
|
696
|
+
@click.option("--command", help="Command for stdio transport")
|
|
697
|
+
@click.option("--args", help="Arguments for stdio transport (comma-separated)")
|
|
698
|
+
@click.option("--env", help="Environment variables for stdio transport (comma-separated KEY=VALUE pairs)")
|
|
699
|
+
@click.option("--headers", help="HTTP headers for http transport (comma-separated Key=Value pairs)")
|
|
700
|
+
@click.option("--url", "explicit_url", help="URL for http/sse transport (alternative to positional argument)")
|
|
701
|
+
def mcp_add(name, url, transport, command, args, env, headers, explicit_url):
|
|
702
|
+
"""Add an MCP server configuration.
|
|
703
|
+
|
|
704
|
+
\b
|
|
705
|
+
For SSE transport (default):
|
|
706
|
+
cdh mcp add my-server https://example.com/mcp
|
|
707
|
+
|
|
708
|
+
\b
|
|
709
|
+
For stdio transport:
|
|
710
|
+
cdh mcp add my-server --type stdio --command npx --args server-name --env KEY=VAL
|
|
711
|
+
|
|
712
|
+
\b
|
|
713
|
+
For HTTP transport:
|
|
714
|
+
cdh mcp add my-server --type http --url https://example.com/mcp --headers Key=Val
|
|
715
|
+
"""
|
|
716
|
+
_mcp_add_impl(name, url, transport, command, args, env, headers, explicit_url)
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
@mcp.command("remove")
|
|
720
|
+
@click.argument("name")
|
|
721
|
+
def mcp_remove(name):
|
|
722
|
+
"""Remove an MCP server configuration."""
|
|
723
|
+
from onecode.mcp.manager import MCPManager
|
|
724
|
+
|
|
725
|
+
mgr = MCPManager()
|
|
726
|
+
err = mgr.remove(name)
|
|
727
|
+
if err:
|
|
728
|
+
click.echo(f"Error: MCP server '{name}' not found")
|
|
729
|
+
else:
|
|
730
|
+
click.echo(f"MCP server '{name}' removed.")
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
@mcp.command("enable")
|
|
734
|
+
@click.argument("name")
|
|
735
|
+
def mcp_enable(name):
|
|
736
|
+
"""Enable an MCP server."""
|
|
737
|
+
from onecode.mcp.manager import MCPManager
|
|
738
|
+
|
|
739
|
+
mgr = MCPManager()
|
|
740
|
+
err = mgr.enable(name, True)
|
|
741
|
+
if err:
|
|
742
|
+
click.echo(f"Error: {err}")
|
|
743
|
+
else:
|
|
744
|
+
click.echo(f"MCP server '{name}' enabled.")
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
@mcp.command("disable")
|
|
748
|
+
@click.argument("name")
|
|
749
|
+
def mcp_disable(name):
|
|
750
|
+
"""Disable an MCP server."""
|
|
751
|
+
from onecode.mcp.manager import MCPManager
|
|
752
|
+
|
|
753
|
+
mgr = MCPManager()
|
|
754
|
+
err = mgr.enable(name, False)
|
|
755
|
+
if err:
|
|
756
|
+
click.echo(f"Error: {err}")
|
|
757
|
+
else:
|
|
758
|
+
click.echo(f"MCP server '{name}' disabled.")
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
@config.group("mcp")
|
|
762
|
+
def config_mcp():
|
|
763
|
+
"""Manage MCP servers (alias for cdh mcp)."""
|
|
764
|
+
pass
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
@config_mcp.command("list")
|
|
768
|
+
def config_mcp_list():
|
|
769
|
+
"""List all configured MCP servers."""
|
|
770
|
+
from onecode.mcp.manager import MCPManager
|
|
771
|
+
|
|
772
|
+
mgr = MCPManager()
|
|
773
|
+
servers = mgr.list()
|
|
774
|
+
|
|
775
|
+
if not servers:
|
|
776
|
+
click.echo("No MCP servers configured. Use `cdh mcp add <name> <url>` to add one.")
|
|
777
|
+
return
|
|
778
|
+
|
|
779
|
+
click.echo("Configured MCP servers:")
|
|
780
|
+
for line in _format_mcp_servers(servers):
|
|
781
|
+
click.echo(line)
|
|
782
|
+
click.echo(f"\nTotal: {len(servers)} server(s)")
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
@config_mcp.command("add")
|
|
786
|
+
@click.argument("name")
|
|
787
|
+
@click.argument("url", required=False, default="")
|
|
788
|
+
@click.option("--type", "transport", default="sse", help="Transport type: sse, stdio, or http")
|
|
789
|
+
@click.option("--command", help="Command for stdio transport")
|
|
790
|
+
@click.option("--args", help="Arguments for stdio transport (comma-separated)")
|
|
791
|
+
@click.option("--env", help="Environment variables for stdio transport (comma-separated KEY=VALUE pairs)")
|
|
792
|
+
@click.option("--headers", help="HTTP headers for http transport (comma-separated Key=Value pairs)")
|
|
793
|
+
@click.option("--url", "explicit_url", help="URL for http/sse transport (alternative to positional argument)")
|
|
794
|
+
def config_mcp_add(name, url, transport, command, args, env, headers, explicit_url):
|
|
795
|
+
"""Add an MCP server configuration."""
|
|
796
|
+
_mcp_add_impl(name, url, transport, command, args, env, headers, explicit_url)
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
@config_mcp.command("remove")
|
|
800
|
+
@click.argument("name")
|
|
801
|
+
def config_mcp_remove(name):
|
|
802
|
+
"""Remove an MCP server configuration."""
|
|
803
|
+
from onecode.mcp.manager import MCPManager
|
|
804
|
+
|
|
805
|
+
mgr = MCPManager()
|
|
806
|
+
err = mgr.remove(name)
|
|
807
|
+
if err:
|
|
808
|
+
click.echo(f"Error: MCP server '{name}' not found")
|
|
809
|
+
else:
|
|
810
|
+
click.echo(f"MCP server '{name}' removed.")
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
@config_mcp.command("enable")
|
|
814
|
+
@click.argument("name")
|
|
815
|
+
def config_mcp_enable(name):
|
|
816
|
+
"""Enable an MCP server."""
|
|
817
|
+
from onecode.mcp.manager import MCPManager
|
|
818
|
+
|
|
819
|
+
mgr = MCPManager()
|
|
820
|
+
err = mgr.enable(name, True)
|
|
821
|
+
if err:
|
|
822
|
+
click.echo(f"Error: {err}")
|
|
823
|
+
else:
|
|
824
|
+
click.echo(f"MCP server '{name}' enabled.")
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
@config_mcp.command("disable")
|
|
828
|
+
@click.argument("name")
|
|
829
|
+
def config_mcp_disable(name):
|
|
830
|
+
"""Disable an MCP server."""
|
|
831
|
+
from onecode.mcp.manager import MCPManager
|
|
832
|
+
|
|
833
|
+
mgr = MCPManager()
|
|
834
|
+
err = mgr.enable(name, False)
|
|
835
|
+
if err:
|
|
836
|
+
click.echo(f"Error: {err}")
|
|
837
|
+
else:
|
|
838
|
+
click.echo(f"MCP server '{name}' disabled.")
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
@mcp.command("auth")
|
|
842
|
+
@click.argument("name")
|
|
843
|
+
def mcp_auth(name):
|
|
844
|
+
"""Authenticate a remote MCP server (OAuth / manual token paste)."""
|
|
845
|
+
from onecode.mcp.manager import MCPManager
|
|
846
|
+
from onecode.mcp.oauth import ManualOAuthFlow, OAuthStore
|
|
847
|
+
|
|
848
|
+
mgr = MCPManager()
|
|
849
|
+
sc = mgr.get_server(name)
|
|
850
|
+
if not sc:
|
|
851
|
+
raise click.UsageError(f"MCP server '{name}' not found")
|
|
852
|
+
if sc.type != "remote":
|
|
853
|
+
raise click.UsageError(
|
|
854
|
+
f"MCP server '{name}' is type=local (stdio). OAuth is for remote servers."
|
|
855
|
+
)
|
|
856
|
+
|
|
857
|
+
oauth_cfg = sc.oauth
|
|
858
|
+
if oauth_cfg is False:
|
|
859
|
+
raise click.UsageError(
|
|
860
|
+
f"OAuth is explicitly disabled for '{name}' (oauth: false in config)."
|
|
861
|
+
)
|
|
862
|
+
|
|
863
|
+
flow = ManualOAuthFlow(oauth_cfg)
|
|
864
|
+
bundle = flow.run(server_name=name)
|
|
865
|
+
if not bundle.access_token:
|
|
866
|
+
click.echo("No token provided; aborting.")
|
|
867
|
+
return
|
|
868
|
+
OAuthStore().save(name, bundle)
|
|
869
|
+
click.echo(f"OAuth token saved for '{name}'.")
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
@mcp.command("logout")
|
|
873
|
+
@click.argument("name")
|
|
874
|
+
def mcp_logout(name):
|
|
875
|
+
"""Remove stored OAuth credentials for a remote MCP server."""
|
|
876
|
+
from onecode.mcp.oauth import OAuthStore
|
|
877
|
+
|
|
878
|
+
if OAuthStore().remove(name):
|
|
879
|
+
click.echo(f"OAuth credentials removed for '{name}'.")
|
|
880
|
+
else:
|
|
881
|
+
click.echo(f"No OAuth credentials stored for '{name}'.")
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
@mcp.command("debug")
|
|
885
|
+
@click.argument("name")
|
|
886
|
+
def mcp_debug(name):
|
|
887
|
+
"""Diagnose an MCP server: presence, auth status, live probe."""
|
|
888
|
+
import asyncio as _asyncio
|
|
889
|
+
|
|
890
|
+
from onecode.mcp.config import resolve_mapping
|
|
891
|
+
from onecode.mcp.manager import MCPManager
|
|
892
|
+
from onecode.mcp.oauth import OAuthStore
|
|
893
|
+
|
|
894
|
+
mgr = MCPManager()
|
|
895
|
+
sc = mgr.get_server(name)
|
|
896
|
+
if not sc:
|
|
897
|
+
click.echo(f"MCP server '{name}' is not configured.")
|
|
898
|
+
return
|
|
899
|
+
|
|
900
|
+
click.echo(f"Type: {sc.type}")
|
|
901
|
+
click.echo(f"Enabled: {sc.enabled}")
|
|
902
|
+
if mgr.is_globally_disabled(name):
|
|
903
|
+
click.echo("Globally: disabled by mcp.disabled in onecode.config.yaml")
|
|
904
|
+
else:
|
|
905
|
+
click.echo("Globally: enabled")
|
|
906
|
+
|
|
907
|
+
if sc.type == "local":
|
|
908
|
+
click.echo(f"Command: {' '.join(sc.command or [])}")
|
|
909
|
+
env = resolve_mapping(sc.environment)
|
|
910
|
+
if env:
|
|
911
|
+
rendered = ", ".join(f"{k}=***" for k in env)
|
|
912
|
+
click.echo(f"Env: {rendered}")
|
|
913
|
+
else:
|
|
914
|
+
click.echo(f"URL: {sc.url}")
|
|
915
|
+
headers = resolve_mapping(sc.headers)
|
|
916
|
+
if headers:
|
|
917
|
+
click.echo("Headers:")
|
|
918
|
+
for k, v in headers.items():
|
|
919
|
+
is_secret = any(s in k.lower() for s in ("auth", "token", "key", "secret"))
|
|
920
|
+
click.echo(f" {k}: ***" if is_secret else f" {k}: {v}")
|
|
921
|
+
|
|
922
|
+
store = OAuthStore()
|
|
923
|
+
bundle = store.get(name)
|
|
924
|
+
if bundle and bundle.access_token:
|
|
925
|
+
if bundle.is_expired():
|
|
926
|
+
click.echo("OAuth: token expired — re-run `cdh mcp auth`")
|
|
927
|
+
else:
|
|
928
|
+
click.echo("OAuth: token present")
|
|
929
|
+
else:
|
|
930
|
+
click.echo("OAuth: none")
|
|
931
|
+
|
|
932
|
+
click.echo("")
|
|
933
|
+
click.echo("Live probe:")
|
|
934
|
+
try:
|
|
935
|
+
ok = _asyncio.run(mgr.connect(name, auto_reconnect=False))
|
|
936
|
+
except Exception as e:
|
|
937
|
+
ok = False
|
|
938
|
+
click.echo(f" connect raised: {e}")
|
|
939
|
+
if ok:
|
|
940
|
+
try:
|
|
941
|
+
tools = _asyncio.run(mgr.list_tools(name))
|
|
942
|
+
click.echo(f" connected; {len(tools)} tool(s) available")
|
|
943
|
+
finally:
|
|
944
|
+
_asyncio.run(mgr.disconnect(name))
|
|
945
|
+
else:
|
|
946
|
+
click.echo(" could not connect (check the env / headers above).")
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
@mcp.command("migrate")
|
|
950
|
+
@click.option("--dry-run", is_flag=True, help="Show what would change without modifying anything")
|
|
951
|
+
def mcp_migrate(dry_run):
|
|
952
|
+
"""Migrate legacy ``mcps.yaml`` to the new ``mcp.json`` format."""
|
|
953
|
+
from onecode.mcp.config import MCPConfigFile
|
|
954
|
+
|
|
955
|
+
cfg = MCPConfigFile()
|
|
956
|
+
if not cfg.legacy_path.exists():
|
|
957
|
+
click.echo(f"No legacy file at {cfg.legacy_path}; nothing to migrate.")
|
|
958
|
+
return
|
|
959
|
+
if cfg.path.exists():
|
|
960
|
+
click.echo(f"{cfg.path} already exists; refusing to overwrite.")
|
|
961
|
+
click.echo("Remove it first if you want to re-migrate.")
|
|
962
|
+
return
|
|
963
|
+
if dry_run:
|
|
964
|
+
servers = cfg._load_legacy()
|
|
965
|
+
click.echo(f"Would migrate {len(servers)} server(s) from {cfg.legacy_path} to {cfg.path}:")
|
|
966
|
+
for n, sc in servers.items():
|
|
967
|
+
click.echo(f" - {n}: type={sc.type}")
|
|
968
|
+
return
|
|
969
|
+
if cfg.migrate_from_legacy():
|
|
970
|
+
click.echo(f"Migrated to {cfg.path}. Legacy file backed up as {cfg.legacy_path}.bak")
|
|
971
|
+
else:
|
|
972
|
+
click.echo("Migration skipped.")
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
@cli.group(invoke_without_command=True)
|
|
976
|
+
def cloudbase():
|
|
977
|
+
"""Manage Tencent CloudBase (TCB) MCP integration.
|
|
978
|
+
|
|
979
|
+
\b
|
|
980
|
+
CloudBase MCP provides structured access to serverless functions,
|
|
981
|
+
database, hosting, and storage via the @cloudbase/cloudbase-mcp package.
|
|
982
|
+
Use `cdh cloudbase init` to configure credentials and enable the MCP server.
|
|
983
|
+
"""
|
|
984
|
+
pass
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
@cloudbase.command("init")
|
|
988
|
+
@click.option("--secret-id", envvar="TENCENTCLOUD_SECRETID", help="Tencent Cloud secret ID")
|
|
989
|
+
@click.option("--secret-key", envvar="TENCENTCLOUD_SECRETKEY", help="Tencent Cloud secret key")
|
|
990
|
+
@click.option("--env-id", envvar="TCB_ENV_ID", help="Default CloudBase environment ID")
|
|
991
|
+
def cloudbase_init(secret_id, secret_key, env_id):
|
|
992
|
+
"""Initialize CloudBase MCP server with credentials.
|
|
993
|
+
|
|
994
|
+
\b
|
|
995
|
+
Writes the opencode-style ``mcp.json`` entry for ``cloudbase`` and
|
|
996
|
+
persists the credentials in ``~/.cloud-harness-tokens.json`` so
|
|
997
|
+
other CDH tools can re-use them.
|
|
998
|
+
|
|
999
|
+
Examples:
|
|
1000
|
+
cdh cloudbase init
|
|
1001
|
+
cdh cloudbase init --secret-id xxx --secret-key xxx
|
|
1002
|
+
"""
|
|
1003
|
+
if not secret_id:
|
|
1004
|
+
secret_id = click.prompt("Tencent Cloud Secret ID", hide_input=False)
|
|
1005
|
+
if not secret_key:
|
|
1006
|
+
secret_key = click.prompt("Tencent Cloud Secret Key", hide_input=True)
|
|
1007
|
+
|
|
1008
|
+
from onecode.mcp.cloudbase import MCP_SERVER_NAME, write_tokens
|
|
1009
|
+
from onecode.mcp.config import MCPServerConfig
|
|
1010
|
+
from onecode.mcp.manager import MCPManager
|
|
1011
|
+
|
|
1012
|
+
mgr = MCPManager()
|
|
1013
|
+
|
|
1014
|
+
env = {
|
|
1015
|
+
"TENCENTCLOUD_SECRETID": secret_id,
|
|
1016
|
+
"TENCENTCLOUD_SECRETKEY": secret_key,
|
|
1017
|
+
}
|
|
1018
|
+
if env_id:
|
|
1019
|
+
env["CLOUDBASE_ENV_ID"] = env_id
|
|
1020
|
+
env["TCB_ENV_ID"] = env_id
|
|
1021
|
+
|
|
1022
|
+
if mgr.get_server(MCP_SERVER_NAME):
|
|
1023
|
+
click.echo("CloudBase MCP server already configured. Updating credentials...")
|
|
1024
|
+
mgr.remove(MCP_SERVER_NAME)
|
|
1025
|
+
|
|
1026
|
+
cfg = MCPServerConfig(
|
|
1027
|
+
name=MCP_SERVER_NAME,
|
|
1028
|
+
type="local",
|
|
1029
|
+
command=["npx", "-y", "@cloudbase/cloudbase-mcp@latest"],
|
|
1030
|
+
environment=env,
|
|
1031
|
+
enabled=True,
|
|
1032
|
+
)
|
|
1033
|
+
mgr.add_server(MCP_SERVER_NAME, cfg)
|
|
1034
|
+
click.echo("CloudBase MCP server configured (local) in mcp.json.")
|
|
1035
|
+
|
|
1036
|
+
try:
|
|
1037
|
+
path = write_tokens(secret_id, secret_key, env_id or "")
|
|
1038
|
+
click.echo(f"Credentials saved to {path}")
|
|
1039
|
+
except OSError as e:
|
|
1040
|
+
click.echo(f"Warning: could not save credentials: {e}", err=True)
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
@cloudbase.command("logout")
|
|
1044
|
+
def cloudbase_logout():
|
|
1045
|
+
"""Remove CloudBase credentials from the tokens file (keeps mcp.json)."""
|
|
1046
|
+
from onecode.mcp.cloudbase import clear_tokens
|
|
1047
|
+
|
|
1048
|
+
if clear_tokens():
|
|
1049
|
+
click.echo("CloudBase credentials removed from tokens file.")
|
|
1050
|
+
else:
|
|
1051
|
+
click.echo("No CloudBase credentials to remove.")
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
@cloudbase.command("status")
|
|
1055
|
+
def cloudbase_status():
|
|
1056
|
+
"""Check CloudBase MCP connection status."""
|
|
1057
|
+
from onecode.mcp.manager import MCPManager
|
|
1058
|
+
mgr = MCPManager()
|
|
1059
|
+
|
|
1060
|
+
cfg = mgr.get("cloudbase")
|
|
1061
|
+
if not cfg:
|
|
1062
|
+
click.echo("CloudBase MCP server is not configured.")
|
|
1063
|
+
click.echo("Run `cdh cloudbase init` to set up.")
|
|
1064
|
+
return
|
|
1065
|
+
|
|
1066
|
+
enabled = cfg.get("enabled", False)
|
|
1067
|
+
transport = cfg.get("transport", "stdio")
|
|
1068
|
+
click.echo(f"CloudBase MCP server: {'[enabled]' if enabled else '[disabled]'} ({transport})")
|
|
1069
|
+
|
|
1070
|
+
if not enabled:
|
|
1071
|
+
return
|
|
1072
|
+
|
|
1073
|
+
connected = mgr.is_connected("cloudbase")
|
|
1074
|
+
if connected:
|
|
1075
|
+
click.echo("Connection: connected")
|
|
1076
|
+
import asyncio
|
|
1077
|
+
tools = asyncio.run(mgr.list_tools("cloudbase"))
|
|
1078
|
+
click.echo(f"Available tools: {len(tools)}")
|
|
1079
|
+
for t in tools[:5]:
|
|
1080
|
+
click.echo(f" - {t.name}: {t.description}")
|
|
1081
|
+
return
|
|
1082
|
+
|
|
1083
|
+
click.echo("No active connection — running a live probe...")
|
|
1084
|
+
|
|
1085
|
+
async def _probe():
|
|
1086
|
+
ok = await mgr.connect("cloudbase", auto_reconnect=False)
|
|
1087
|
+
if not ok:
|
|
1088
|
+
return False, []
|
|
1089
|
+
try:
|
|
1090
|
+
tools = await mgr.list_tools("cloudbase")
|
|
1091
|
+
return True, tools
|
|
1092
|
+
finally:
|
|
1093
|
+
await mgr.disconnect("cloudbase")
|
|
1094
|
+
|
|
1095
|
+
try:
|
|
1096
|
+
import asyncio
|
|
1097
|
+
ok, tools = asyncio.run(_probe())
|
|
1098
|
+
except Exception as e:
|
|
1099
|
+
click.echo(f"Connection: probe failed ({e})")
|
|
1100
|
+
return
|
|
1101
|
+
|
|
1102
|
+
if ok:
|
|
1103
|
+
click.echo(f"Connection: connected (probe) — {len(tools)} tools")
|
|
1104
|
+
for t in tools[:5]:
|
|
1105
|
+
click.echo(f" - {t.name}: {t.description}")
|
|
1106
|
+
else:
|
|
1107
|
+
click.echo("Connection: not connected (probe failed)")
|
|
1108
|
+
click.echo("Hint: run `cdh cloudbase init` to configure credentials.")
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
@cli.group(invoke_without_command=True)
|
|
1112
|
+
def codebase():
|
|
1113
|
+
"""Manage codebase index and search.
|
|
1114
|
+
|
|
1115
|
+
\b
|
|
1116
|
+
The codebase index enables semantic and keyword search over project files.
|
|
1117
|
+
Use `cdh codebase index` to build or update the index, then the agent
|
|
1118
|
+
can automatically retrieve relevant code when answering questions.
|
|
1119
|
+
"""
|
|
1120
|
+
pass
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
@codebase.command("index")
|
|
1124
|
+
@click.option("--force", is_flag=True, help="Rebuild index from scratch")
|
|
1125
|
+
@click.option("--path", default=".", help="Project directory", show_default=True)
|
|
1126
|
+
def codebase_index(force: bool, path: str):
|
|
1127
|
+
"""Index project files for codebase search."""
|
|
1128
|
+
import asyncio
|
|
1129
|
+
from onecode.codebase import CodebaseEngine
|
|
1130
|
+
|
|
1131
|
+
project_dir = Path(path).resolve()
|
|
1132
|
+
if not project_dir.is_dir():
|
|
1133
|
+
click.echo(f"Error: {path} is not a valid directory")
|
|
1134
|
+
return
|
|
1135
|
+
|
|
1136
|
+
cfg = load_config()
|
|
1137
|
+
engine = CodebaseEngine(project_dir, cfg.codebase)
|
|
1138
|
+
result = asyncio.run(engine.ensure_indexed(force=force))
|
|
1139
|
+
|
|
1140
|
+
click.echo(
|
|
1141
|
+
f"Indexed {project_dir.name}: "
|
|
1142
|
+
f"{result.indexed_files} files, "
|
|
1143
|
+
f"{result.total_chunks} chunks"
|
|
1144
|
+
f"{' (forced rebuild)' if force else ''}"
|
|
1145
|
+
)
|
|
1146
|
+
if result.failed_files:
|
|
1147
|
+
click.echo(f" Failed: {result.failed_files}")
|
|
1148
|
+
for err in result.errors[:5]:
|
|
1149
|
+
click.echo(f" {err}")
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
@codebase.command("status")
|
|
1153
|
+
@click.option("--path", default=".", help="Project directory", show_default=True)
|
|
1154
|
+
def codebase_status(path: str):
|
|
1155
|
+
"""Show codebase index status."""
|
|
1156
|
+
from onecode.codebase import CodebaseStorage
|
|
1157
|
+
|
|
1158
|
+
project_dir = Path(path).resolve()
|
|
1159
|
+
if not project_dir.is_dir():
|
|
1160
|
+
click.echo(f"Error: {path} is not a valid directory")
|
|
1161
|
+
return
|
|
1162
|
+
|
|
1163
|
+
storage = CodebaseStorage(project_dir)
|
|
1164
|
+
chunk_count = storage.chunk_count()
|
|
1165
|
+
file_count = storage.file_count()
|
|
1166
|
+
|
|
1167
|
+
click.echo(f"Codebase index for {project_dir.name}:")
|
|
1168
|
+
click.echo(f" Files: {file_count}")
|
|
1169
|
+
click.echo(f" Chunks: {chunk_count}")
|
|
1170
|
+
if chunk_count == 0:
|
|
1171
|
+
click.echo(" (not indexed yet — run `cdh codebase index`)")
|
|
1172
|
+
|
|
1173
|
+
|
|
1174
|
+
@codebase.command("search")
|
|
1175
|
+
@click.argument("query")
|
|
1176
|
+
@click.option("--top-k", default=5, help="Number of results", show_default=True)
|
|
1177
|
+
@click.option("--path", default=".", help="Project directory", show_default=True)
|
|
1178
|
+
def codebase_search(query: str, top_k: int, path: str):
|
|
1179
|
+
"""Search indexed codebase."""
|
|
1180
|
+
import asyncio
|
|
1181
|
+
from onecode.codebase import CodebaseEngine
|
|
1182
|
+
|
|
1183
|
+
project_dir = Path(path).resolve()
|
|
1184
|
+
if not project_dir.is_dir():
|
|
1185
|
+
click.echo(f"Error: {path} is not a valid directory")
|
|
1186
|
+
return
|
|
1187
|
+
|
|
1188
|
+
cfg = load_config()
|
|
1189
|
+
engine = CodebaseEngine(project_dir, cfg.codebase)
|
|
1190
|
+
chunks = asyncio.run(engine.retrieve(query, top_k=top_k))
|
|
1191
|
+
|
|
1192
|
+
if not chunks:
|
|
1193
|
+
click.echo("No results found.")
|
|
1194
|
+
return
|
|
1195
|
+
|
|
1196
|
+
click.echo(f"Top {len(chunks)} results for: {query}\n")
|
|
1197
|
+
for i, c in enumerate(chunks, 1):
|
|
1198
|
+
click.echo(f"[{i}] {c.file_path}:{c.start_line}-{c.end_line}")
|
|
1199
|
+
click.echo("```")
|
|
1200
|
+
click.echo(c.content[:300])
|
|
1201
|
+
if len(c.content) > 300:
|
|
1202
|
+
click.echo("...")
|
|
1203
|
+
click.echo("```")
|
|
1204
|
+
click.echo()
|
|
1205
|
+
|
|
1206
|
+
|
|
1207
|
+
@codebase.command("reindex")
|
|
1208
|
+
@click.option("--path", default=".", help="Project directory", show_default=True)
|
|
1209
|
+
def codebase_reindex(path: str):
|
|
1210
|
+
"""Force rebuild the codebase index (alias for index --force)."""
|
|
1211
|
+
import asyncio
|
|
1212
|
+
from onecode.codebase import CodebaseEngine
|
|
1213
|
+
|
|
1214
|
+
project_dir = Path(path).resolve()
|
|
1215
|
+
if not project_dir.is_dir():
|
|
1216
|
+
click.echo(f"Error: {path} is not a valid directory")
|
|
1217
|
+
return
|
|
1218
|
+
|
|
1219
|
+
cfg = load_config()
|
|
1220
|
+
engine = CodebaseEngine(project_dir, cfg.codebase)
|
|
1221
|
+
result = asyncio.run(engine.ensure_indexed(force=True))
|
|
1222
|
+
|
|
1223
|
+
click.echo(
|
|
1224
|
+
f"Reindexed {project_dir.name}: "
|
|
1225
|
+
f"{result.indexed_files} files, "
|
|
1226
|
+
f"{result.total_chunks} chunks"
|
|
1227
|
+
)
|
|
1228
|
+
|
|
1229
|
+
|
|
1230
|
+
@cli.group()
|
|
1231
|
+
def memory():
|
|
1232
|
+
"""Manage long-term memory.
|
|
1233
|
+
|
|
1234
|
+
\b
|
|
1235
|
+
Memory stores conversation history with BM25 keyword recall.
|
|
1236
|
+
Use `cdh memory status` to view memory usage and `cdh memory clear` to reset.
|
|
1237
|
+
"""
|
|
1238
|
+
pass
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
@memory.command("status")
|
|
1242
|
+
def memory_status():
|
|
1243
|
+
"""Show memory usage statistics."""
|
|
1244
|
+
from onecode.memory.backend import MemoryBackend
|
|
1245
|
+
|
|
1246
|
+
backend = MemoryBackend()
|
|
1247
|
+
counts = backend.count_by_layer()
|
|
1248
|
+
total = sum(counts.values())
|
|
1249
|
+
click.echo(f"Total entries: {total}")
|
|
1250
|
+
for layer, count in counts.items():
|
|
1251
|
+
click.echo(f" {layer}: {count}")
|
|
1252
|
+
if total == 0:
|
|
1253
|
+
click.echo(" (no memories stored yet)")
|
|
1254
|
+
|
|
1255
|
+
|
|
1256
|
+
@memory.command("clear")
|
|
1257
|
+
@click.option("--layer", default=None, help="Layer to clear (default: all layers)")
|
|
1258
|
+
def memory_clear(layer: str):
|
|
1259
|
+
"""Clear memory entries."""
|
|
1260
|
+
from onecode.memory import AgentMemory
|
|
1261
|
+
from onecode.memory.pyramid import MemoryLayer
|
|
1262
|
+
|
|
1263
|
+
am = AgentMemory()
|
|
1264
|
+
if layer:
|
|
1265
|
+
layers_to_clear = [ml for ml in MemoryLayer if ml.value == layer]
|
|
1266
|
+
else:
|
|
1267
|
+
layers_to_clear = list(MemoryLayer)
|
|
1268
|
+
removed = 0
|
|
1269
|
+
for ml in layers_to_clear:
|
|
1270
|
+
entries = am.pyramid.list_by_layer(ml)
|
|
1271
|
+
for e in entries:
|
|
1272
|
+
am.forget(ml, e.id)
|
|
1273
|
+
removed += 1
|
|
1274
|
+
click.echo(f"Cleared {removed} memory entries.")
|
|
1275
|
+
|
|
1276
|
+
|
|
1277
|
+
@memory.command("count")
|
|
1278
|
+
@click.option("--layer", default=None, help="Layer to count (default: all layers)")
|
|
1279
|
+
def memory_count(layer: str):
|
|
1280
|
+
"""Count memory entries."""
|
|
1281
|
+
from onecode.memory.backend import MemoryBackend
|
|
1282
|
+
|
|
1283
|
+
backend = MemoryBackend()
|
|
1284
|
+
counts = backend.count_by_layer()
|
|
1285
|
+
if layer:
|
|
1286
|
+
click.echo(f"Entries in {layer}: {counts.get(layer, 0)}")
|
|
1287
|
+
else:
|
|
1288
|
+
total = sum(counts.values())
|
|
1289
|
+
click.echo(f"Total entries: {total}")
|
|
1290
|
+
for ly, count in sorted(counts.items()):
|
|
1291
|
+
click.echo(f" {ly}: {count}")
|
|
1292
|
+
|
|
1293
|
+
|
|
1294
|
+
@cli.command()
|
|
1295
|
+
@click.argument("command", required=False)
|
|
1296
|
+
@click.option("--list", "list_commands", is_flag=True, help="List all available commands")
|
|
1297
|
+
def help_cmd(command, list_commands):
|
|
1298
|
+
"""Show help for commands."""
|
|
1299
|
+
if list_commands:
|
|
1300
|
+
click.echo("Available commands:")
|
|
1301
|
+
for name, cmd in cli.commands.items():
|
|
1302
|
+
click.echo(f" {name:15} {cmd.help or ''}")
|
|
1303
|
+
elif command:
|
|
1304
|
+
cmd = cli.commands.get(command)
|
|
1305
|
+
if cmd:
|
|
1306
|
+
click.echo(cmd.get_help(click.Context(cmd)))
|
|
1307
|
+
else:
|
|
1308
|
+
click.echo(f"Unknown command: {command}")
|
|
1309
|
+
else:
|
|
1310
|
+
click.echo(cli.get_help(click.Context(cli)))
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
@cli.command()
|
|
1314
|
+
def version():
|
|
1315
|
+
"""Show version info."""
|
|
1316
|
+
from onecode import __version__
|
|
1317
|
+
click.echo(f"onecode {__version__}")
|
|
1318
|
+
|
|
1319
|
+
|
|
1320
|
+
def main():
|
|
1321
|
+
cli()
|
|
1322
|
+
|
|
1323
|
+
|
|
1324
|
+
if __name__ == "__main__":
|
|
1325
|
+
main()
|