codetrellis 0.0.0-stage → 0.2.0
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/LICENSE +201 -0
- package/README.md +27 -2
- package/bin/codetrellis.mjs +4 -0
- package/package.json +43 -4
- package/reader/material-reader.mjs +130346 -0
- package/resources/tree-sitter/README.md +150 -0
- package/resources/tree-sitter/tree-sitter-c-sharp.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-go.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-java.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-javascript.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-kotlin.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-php.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-python.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-ruby.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-rust.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-swift.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-tsx.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-typescript.wasm +0 -0
- package/resources/tree-sitter/tree-sitter.wasm +0 -0
- package/src/backend/agent/claude-code-watcher.js +270 -0
- package/src/backend/index.js +8 -0
- package/src/backend/lib/sha256-file.js +39 -0
- package/src/backend/lib/zip-entries.js +98 -0
- package/src/backend/lifecycle.js +102 -0
- package/src/backend/mcp/binding-headers.js +54 -0
- package/src/backend/mcp/client-identity.js +44 -0
- package/src/backend/mcp/connector/command.js +110 -0
- package/src/backend/mcp/connector/core.js +278 -0
- package/src/backend/mcp/connector/files.js +121 -0
- package/src/backend/mcp/connector/hook.js +284 -0
- package/src/backend/mcp/connector/main.js +126 -0
- package/src/backend/mcp/connector/sse-upstream.js +152 -0
- package/src/backend/mcp/helpers.js +43 -0
- package/src/backend/mcp/prompt-builders.js +104 -0
- package/src/backend/mcp/resources.js +197 -0
- package/src/backend/mcp/server.js +813 -0
- package/src/backend/mcp/skill-guide.js +1528 -0
- package/src/backend/mcp/tools/architecture-tools.js +273 -0
- package/src/backend/mcp/tools/audio-tools.js +117 -0
- package/src/backend/mcp/tools/awareness-tools.js +623 -0
- package/src/backend/mcp/tools/budget-tools.js +185 -0
- package/src/backend/mcp/tools/channel-tools.js +205 -0
- package/src/backend/mcp/tools/contribution-tools.js +181 -0
- package/src/backend/mcp/tools/drift-tools.js +252 -0
- package/src/backend/mcp/tools/git-tools.js +316 -0
- package/src/backend/mcp/tools/governance-tools.js +175 -0
- package/src/backend/mcp/tools/graph-tools.js +181 -0
- package/src/backend/mcp/tools/intake-tools.js +244 -0
- package/src/backend/mcp/tools/mobile-tools.js +118 -0
- package/src/backend/mcp/tools/peer-tools.js +330 -0
- package/src/backend/mcp/tools/plan-item-tools.js +1601 -0
- package/src/backend/mcp/tools/plan-tools.js +680 -0
- package/src/backend/mcp/tools/presence-tools.js +185 -0
- package/src/backend/mcp/tools/project-config-tools.js +150 -0
- package/src/backend/mcp/tools/review-tools.js +172 -0
- package/src/backend/mcp/tools/session-tools.js +554 -0
- package/src/backend/mcp/tools/system-docs-tools.js +168 -0
- package/src/backend/mcp/tools/terminal-tools.js +186 -0
- package/src/backend/mcp/tools/test-tools.js +117 -0
- package/src/backend/mcp/tools/ui-tools.js +356 -0
- package/src/backend/mcp/types.js +15 -0
- package/src/backend/middleware/local-auth.js +116 -0
- package/src/backend/server.js +5951 -0
- package/src/backend/services/agent-event-log.js +350 -0
- package/src/backend/services/architecture-rule.js +584 -0
- package/src/backend/services/architecture-rules.js +275 -0
- package/src/backend/services/artefact-content-service.js +181 -0
- package/src/backend/services/artefact-service.js +305 -0
- package/src/backend/services/artefact-watcher.js +167 -0
- package/src/backend/services/ast-parser.js +327 -0
- package/src/backend/services/audio-buffer-service.js +152 -0
- package/src/backend/services/awareness-notices.js +139 -0
- package/src/backend/services/awareness-replies.js +194 -0
- package/src/backend/services/awareness-service.js +344 -0
- package/src/backend/services/awareness-signals.js +267 -0
- package/src/backend/services/baseline-store.js +83 -0
- package/src/backend/services/branch-workstreams.js +341 -0
- package/src/backend/services/breakpoint-service.js +584 -0
- package/src/backend/services/brief-service.js +299 -0
- package/src/backend/services/budget-service.js +528 -0
- package/src/backend/services/callsites/base.js +15 -0
- package/src/backend/services/callsites/csharp.js +148 -0
- package/src/backend/services/callsites/go.js +163 -0
- package/src/backend/services/callsites/index.js +53 -0
- package/src/backend/services/callsites/kotlin.js +123 -0
- package/src/backend/services/callsites/process-env.js +125 -0
- package/src/backend/services/callsites/python.js +91 -0
- package/src/backend/services/callsites/ruby.js +164 -0
- package/src/backend/services/callsites/shared.js +198 -0
- package/src/backend/services/callsites/swift.js +115 -0
- package/src/backend/services/callsites/typescript.js +87 -0
- package/src/backend/services/capability-token.js +108 -0
- package/src/backend/services/change-check.js +156 -0
- package/src/backend/services/channel-dispatcher-service.js +235 -0
- package/src/backend/services/channel-event-file-service.js +125 -0
- package/src/backend/services/channel-event-service.js +297 -0
- package/src/backend/services/check-runs.js +177 -0
- package/src/backend/services/checkout-identity.js +73 -0
- package/src/backend/services/claude-code-parallel.js +221 -0
- package/src/backend/services/claude-desktop-config.js +186 -0
- package/src/backend/services/clock.js +57 -0
- package/src/backend/services/cloud-files.js +191 -0
- package/src/backend/services/coalesce.js +50 -0
- package/src/backend/services/code-breakpoints.js +291 -0
- package/src/backend/services/comment-service.js +168 -0
- package/src/backend/services/commit-attribution.js +134 -0
- package/src/backend/services/commit-edges.js +99 -0
- package/src/backend/services/confined-fs.js +241 -0
- package/src/backend/services/conformity-gate.js +132 -0
- package/src/backend/services/contribution-service.js +409 -0
- package/src/backend/services/coverage-service.js +173 -0
- package/src/backend/services/criteria-service.js +721 -0
- package/src/backend/services/criterion-checks.js +387 -0
- package/src/backend/services/criterion-loop-service.js +411 -0
- package/src/backend/services/cross-system-service.js +231 -0
- package/src/backend/services/database.js +916 -0
- package/src/backend/services/db-schema.js +1358 -0
- package/src/backend/services/deviation-service.js +344 -0
- package/src/backend/services/diff-engine.js +168 -0
- package/src/backend/services/evidence.js +363 -0
- package/src/backend/services/external-intake-service.js +269 -0
- package/src/backend/services/external-pointer-service.js +195 -0
- package/src/backend/services/external-refs-service.js +214 -0
- package/src/backend/services/file-history.js +158 -0
- package/src/backend/services/file-watcher.js +193 -0
- package/src/backend/services/folder-requests.js +118 -0
- package/src/backend/services/freeze-service.js +189 -0
- package/src/backend/services/gemini-cli-hook.js +172 -0
- package/src/backend/services/git-activity-service.js +325 -0
- package/src/backend/services/git-blobs.js +70 -0
- package/src/backend/services/git-branches.js +357 -0
- package/src/backend/services/git-checkout.js +153 -0
- package/src/backend/services/git-commit-service.js +91 -0
- package/src/backend/services/git-env.js +121 -0
- package/src/backend/services/git-identity.js +84 -0
- package/src/backend/services/git-refs.js +386 -0
- package/src/backend/services/git-safety.js +58 -0
- package/src/backend/services/grant-guard.js +67 -0
- package/src/backend/services/html-view-policy.js +135 -0
- package/src/backend/services/human-decision.js +55 -0
- package/src/backend/services/importers.js +159 -0
- package/src/backend/services/intent-service.js +105 -0
- package/src/backend/services/ipc-dispatcher.js +164 -0
- package/src/backend/services/item-git-state.js +208 -0
- package/src/backend/services/line-changes.js +232 -0
- package/src/backend/services/line-history.js +174 -0
- package/src/backend/services/local-api-changes.js +40 -0
- package/src/backend/services/logger.js +217 -0
- package/src/backend/services/material-footprints.js +203 -0
- package/src/backend/services/material-place.js +82 -0
- package/src/backend/services/material-reader/child.js +4 -0
- package/src/backend/services/material-reader/docx-markdown.js +198 -0
- package/src/backend/services/material-reader/fixtures.test-helper.js +169 -0
- package/src/backend/services/material-reader/quote.js +44 -0
- package/src/backend/services/material-reader/read.js +430 -0
- package/src/backend/services/material-reader/reader-host.js +202 -0
- package/src/backend/services/material-signals.js +141 -0
- package/src/backend/services/mcp-capabilities.js +390 -0
- package/src/backend/services/mdns-service.js +304 -0
- package/src/backend/services/mobile-api-server.js +281 -0
- package/src/backend/services/mobile-approvals.js +306 -0
- package/src/backend/services/mobile-awareness.js +180 -0
- package/src/backend/services/mobile-breakpoints.js +115 -0
- package/src/backend/services/mobile-budget.js +98 -0
- package/src/backend/services/mobile-freeze.js +106 -0
- package/src/backend/services/mobile-proposals.js +100 -0
- package/src/backend/services/mobile-rpc-service.js +1289 -0
- package/src/backend/services/mobile-workstreams.js +160 -0
- package/src/backend/services/monorepo-detector.js +131 -0
- package/src/backend/services/other-work.js +45 -0
- package/src/backend/services/pack-seal.js +129 -0
- package/src/backend/services/paired-device-service.js +192 -0
- package/src/backend/services/pairing-server.js +323 -0
- package/src/backend/services/pairing-service.js +200 -0
- package/src/backend/services/pantry-resolution-service.js +166 -0
- package/src/backend/services/parsers/base.js +124 -0
- package/src/backend/services/parsers/csharp.js +224 -0
- package/src/backend/services/parsers/go.js +180 -0
- package/src/backend/services/parsers/index.js +101 -0
- package/src/backend/services/parsers/java.js +103 -0
- package/src/backend/services/parsers/kotlin.js +252 -0
- package/src/backend/services/parsers/php.js +113 -0
- package/src/backend/services/parsers/python.js +189 -0
- package/src/backend/services/parsers/ruby.js +212 -0
- package/src/backend/services/parsers/rust.js +97 -0
- package/src/backend/services/parsers/swift.js +221 -0
- package/src/backend/services/parsers/typescript.js +235 -0
- package/src/backend/services/pattern-scan.js +65 -0
- package/src/backend/services/patterns.js +281 -0
- package/src/backend/services/peer-audit-service.js +123 -0
- package/src/backend/services/peer-auth.js +153 -0
- package/src/backend/services/peer-capabilities.js +209 -0
- package/src/backend/services/peer-connection-service.js +450 -0
- package/src/backend/services/peer-grants.js +33 -0
- package/src/backend/services/persistence.js +116 -0
- package/src/backend/services/personal-sync-service.js +232 -0
- package/src/backend/services/pipeline-approvals.js +72 -0
- package/src/backend/services/pipeline.js +232 -0
- package/src/backend/services/plan-arrivals.js +68 -0
- package/src/backend/services/plan-changes-service.js +273 -0
- package/src/backend/services/plan-conflict-service.js +288 -0
- package/src/backend/services/plan-dependencies.js +91 -0
- package/src/backend/services/plan-doc-guard.js +90 -0
- package/src/backend/services/plan-documents-service.js +275 -0
- package/src/backend/services/plan-event-service.js +154 -0
- package/src/backend/services/plan-file-refs.js +106 -0
- package/src/backend/services/plan-file-service.js +1564 -0
- package/src/backend/services/plan-history-service.js +156 -0
- package/src/backend/services/plan-import-service.js +261 -0
- package/src/backend/services/plan-item-service.js +1223 -0
- package/src/backend/services/plan-migrate-service.js +395 -0
- package/src/backend/services/plan-overlay-service.js +173 -0
- package/src/backend/services/plan-phases-service.js +182 -0
- package/src/backend/services/plan-progress-service.js +134 -0
- package/src/backend/services/plan-review-service.js +262 -0
- package/src/backend/services/plan-service.js +682 -0
- package/src/backend/services/plan-status.js +113 -0
- package/src/backend/services/plan-template-publish-service.js +217 -0
- package/src/backend/services/plan-templates-service.js +242 -0
- package/src/backend/services/plan-templates.js +1164 -0
- package/src/backend/services/planned-overlap-actions.js +200 -0
- package/src/backend/services/plans-home.js +224 -0
- package/src/backend/services/play-forward.js +256 -0
- package/src/backend/services/playback-service.js +117 -0
- package/src/backend/services/power-service.js +167 -0
- package/src/backend/services/power-signals.js +81 -0
- package/src/backend/services/pr-draft-service.js +142 -0
- package/src/backend/services/presence-service.js +122 -0
- package/src/backend/services/pricing.js +60 -0
- package/src/backend/services/project-config-service.js +474 -0
- package/src/backend/services/project-scanner.js +184 -0
- package/src/backend/services/projection-service.js +69 -0
- package/src/backend/services/push-notification-service.js +288 -0
- package/src/backend/services/recent-projects-service.js +204 -0
- package/src/backend/services/record-chain.js +162 -0
- package/src/backend/services/recurrence-rule.js +63 -0
- package/src/backend/services/recurring-agent.js +89 -0
- package/src/backend/services/recurring-scheduler.js +77 -0
- package/src/backend/services/recurring-service.js +276 -0
- package/src/backend/services/reference-service.js +169 -0
- package/src/backend/services/release-public-key.js +30 -0
- package/src/backend/services/release-signature.js +64 -0
- package/src/backend/services/remote-audio-service.js +224 -0
- package/src/backend/services/remote-interaction-service.js +275 -0
- package/src/backend/services/remote-terminal-service.js +324 -0
- package/src/backend/services/rendition/child/main.js +76 -0
- package/src/backend/services/rendition/engine-host.js +249 -0
- package/src/backend/services/rendition/engine-lock.js +39 -0
- package/src/backend/services/rendition/engine-lock.json +14 -0
- package/src/backend/services/rendition/engine-manifest.js +97 -0
- package/src/backend/services/rendition/network-proof.js +73 -0
- package/src/backend/services/rendition/rendition-service.js +175 -0
- package/src/backend/services/replay-frames.js +387 -0
- package/src/backend/services/replay-state.js +201 -0
- package/src/backend/services/resolvers/base.js +108 -0
- package/src/backend/services/resolvers/csharp.js +109 -0
- package/src/backend/services/resolvers/go.js +105 -0
- package/src/backend/services/resolvers/index.js +60 -0
- package/src/backend/services/resolvers/java.js +63 -0
- package/src/backend/services/resolvers/kotlin.js +109 -0
- package/src/backend/services/resolvers/php.js +89 -0
- package/src/backend/services/resolvers/python.js +154 -0
- package/src/backend/services/resolvers/ruby.js +103 -0
- package/src/backend/services/resolvers/rust.js +77 -0
- package/src/backend/services/resolvers/swift.js +98 -0
- package/src/backend/services/resolvers/typescript.js +71 -0
- package/src/backend/services/retention.js +54 -0
- package/src/backend/services/review-architecture.js +236 -0
- package/src/backend/services/review-attest.js +68 -0
- package/src/backend/services/review-bundle.js +226 -0
- package/src/backend/services/review-graduation.js +93 -0
- package/src/backend/services/review-host/bitbucket.js +79 -0
- package/src/backend/services/review-host/detect.js +80 -0
- package/src/backend/services/review-host/github.js +97 -0
- package/src/backend/services/review-host/gitlab.js +77 -0
- package/src/backend/services/review-host/host-state.js +103 -0
- package/src/backend/services/review-host/http.js +58 -0
- package/src/backend/services/review-host/switch.js +120 -0
- package/src/backend/services/review-marks.js +72 -0
- package/src/backend/services/review-notes.js +169 -0
- package/src/backend/services/review-other-work.js +90 -0
- package/src/backend/services/review-queue-service.js +147 -0
- package/src/backend/services/review-risk.js +127 -0
- package/src/backend/services/review-task.js +121 -0
- package/src/backend/services/rule-approvals.js +268 -0
- package/src/backend/services/rule-baseline.js +134 -0
- package/src/backend/services/rule-changes.js +162 -0
- package/src/backend/services/rule-preview.js +47 -0
- package/src/backend/services/rule-proposals.js +104 -0
- package/src/backend/services/rule-scope.js +76 -0
- package/src/backend/services/rulebook.js +286 -0
- package/src/backend/services/rules-at.js +56 -0
- package/src/backend/services/rules-overview.js +88 -0
- package/src/backend/services/schema-reconciler.js +250 -0
- package/src/backend/services/secret-store.js +119 -0
- package/src/backend/services/section-workstreams.js +95 -0
- package/src/backend/services/self-write-tracker.js +75 -0
- package/src/backend/services/sensor-bridge-service.js +285 -0
- package/src/backend/services/session-service.js +192 -0
- package/src/backend/services/settings-service.js +324 -0
- package/src/backend/services/signal-breakpoints.js +172 -0
- package/src/backend/services/signed-approval-record.js +86 -0
- package/src/backend/services/signed-approvals.js +244 -0
- package/src/backend/services/signoff-pack.js +328 -0
- package/src/backend/services/signoff-rows.js +114 -0
- package/src/backend/services/skill-arrival-service.js +138 -0
- package/src/backend/services/skill-model.js +193 -0
- package/src/backend/services/skill-use-service.js +140 -0
- package/src/backend/services/skills-service.js +150 -0
- package/src/backend/services/snapshot-compare-service.js +397 -0
- package/src/backend/services/source-control.js +189 -0
- package/src/backend/services/spec-links-service.js +123 -0
- package/src/backend/services/spec-proposal-withdraw.js +50 -0
- package/src/backend/services/spec-proposals-service.js +470 -0
- package/src/backend/services/sql/embedded.js +95 -0
- package/src/backend/services/sql/index.js +63 -0
- package/src/backend/services/sql/refs.js +357 -0
- package/src/backend/services/sql/schema.js +312 -0
- package/src/backend/services/sql/tokenizer.js +195 -0
- package/src/backend/services/stack-overlaps.js +117 -0
- package/src/backend/services/stack-service.js +225 -0
- package/src/backend/services/state-sync-service.js +384 -0
- package/src/backend/services/stuck-sensor-service.js +200 -0
- package/src/backend/services/system-discovery.js +481 -0
- package/src/backend/services/system-docs-service.js +701 -0
- package/src/backend/services/task-attachments-service.js +340 -0
- package/src/backend/services/task-grounding.js +60 -0
- package/src/backend/services/task-records/check-run-record.js +146 -0
- package/src/backend/services/task-records/check-runs.js +115 -0
- package/src/backend/services/task-records/heads.js +88 -0
- package/src/backend/services/task-records/material-reads.js +225 -0
- package/src/backend/services/task-records/read-record.js +100 -0
- package/src/backend/services/task-records/record.js +173 -0
- package/src/backend/services/task-records/run-record.js +136 -0
- package/src/backend/services/task-records/shared-state.js +548 -0
- package/src/backend/services/task-records/signing.js +140 -0
- package/src/backend/services/task-records/split-signals.js +52 -0
- package/src/backend/services/task-records/test-runs.js +164 -0
- package/src/backend/services/task-records/trust.js +243 -0
- package/src/backend/services/task-rules.js +81 -0
- package/src/backend/services/task-workstreams.js +90 -0
- package/src/backend/services/terminal-history-service.js +266 -0
- package/src/backend/services/terminal-service.js +267 -0
- package/src/backend/services/test-clock.js +53 -0
- package/src/backend/services/tests/grounding.js +266 -0
- package/src/backend/services/tests/junit.js +104 -0
- package/src/backend/services/tests/teammate-runs.js +134 -0
- package/src/backend/services/tests/test-results.js +234 -0
- package/src/backend/services/tree-watcher.js +204 -0
- package/src/backend/services/trellis-service.js +204 -0
- package/src/backend/services/trusted-roots.js +186 -0
- package/src/backend/services/update-download-service.js +342 -0
- package/src/backend/services/update-service.js +266 -0
- package/src/backend/services/watch-ignore.js +76 -0
- package/src/backend/services/webhook-egress.js +206 -0
- package/src/backend/services/webrtc-service.js +413 -0
- package/src/backend/services/work-changes.js +59 -0
- package/src/backend/services/workstream-binding.js +82 -0
- package/src/backend/services/workstream-commits.js +116 -0
- package/src/backend/services/workstream-imports.js +177 -0
- package/src/backend/services/workstream-service.js +335 -0
- package/src/backend/services/workstream-symbols.js +223 -0
- package/src/backend/services/workstream-watch-service.js +391 -0
- package/src/backend/services/worktree-service.js +235 -0
- package/src/cli/agent.js +100 -0
- package/src/cli/args.js +201 -0
- package/src/cli/conformity.js +106 -0
- package/src/cli/desktop.js +91 -0
- package/src/cli/main.js +409 -0
- package/src/cli/pipeline.js +109 -0
- package/src/cli/plan-verbs.js +259 -0
- package/src/cli/review-adapters.js +218 -0
- package/src/cli/review-output.js +93 -0
- package/src/cli/review-post.js +89 -0
- package/src/cli/review-sink.js +183 -0
- package/src/cli/review-skill.js +44 -0
- package/src/cli/review-verify.js +104 -0
- package/src/cli/review.js +386 -0
- package/src/cli/sarif.js +148 -0
- package/src/cli/verbs.js +359 -0
- package/src/shared/build-info.js +39 -0
- package/src/shared/lib/agent-review.js +199 -0
- package/src/shared/lib/agent-turns.js +140 -0
- package/src/shared/lib/awareness-digest.js +120 -0
- package/src/shared/lib/branch-name.js +45 -0
- package/src/shared/lib/breakpoint-words.js +118 -0
- package/src/shared/lib/budget-words.js +56 -0
- package/src/shared/lib/burst.js +69 -0
- package/src/shared/lib/call-entry.js +105 -0
- package/src/shared/lib/check-compare.js +42 -0
- package/src/shared/lib/check-words.js +216 -0
- package/src/shared/lib/csv.js +62 -0
- package/src/shared/lib/folder-entry.js +87 -0
- package/src/shared/lib/freeze-words.js +60 -0
- package/src/shared/lib/fuzzy.js +84 -0
- package/src/shared/lib/git-state-words.js +80 -0
- package/src/shared/lib/grep-entry.js +86 -0
- package/src/shared/lib/grounding-line.js +61 -0
- package/src/shared/lib/import-line.js +71 -0
- package/src/shared/lib/item-status.js +249 -0
- package/src/shared/lib/line-changes.js +53 -0
- package/src/shared/lib/locator.js +71 -0
- package/src/shared/lib/matcher.js +120 -0
- package/src/shared/lib/merge-order.js +65 -0
- package/src/shared/lib/open-findings.js +68 -0
- package/src/shared/lib/other-work.js +108 -0
- package/src/shared/lib/package-entry.js +142 -0
- package/src/shared/lib/plan-vocab.js +40 -0
- package/src/shared/lib/pptx-xml.js +86 -0
- package/src/shared/lib/proposal-words.js +61 -0
- package/src/shared/lib/recurrence.js +183 -0
- package/src/shared/lib/references.js +72 -0
- package/src/shared/lib/rule-pattern.js +56 -0
- package/src/shared/lib/sdp-fingerprint.js +115 -0
- package/src/shared/lib/sdp-minimal.js +123 -0
- package/src/shared/lib/secret-paths.js +34 -0
- package/src/shared/lib/signal-words.js +172 -0
- package/src/shared/lib/signoff.js +56 -0
- package/src/shared/lib/skills-note.js +60 -0
- package/src/shared/lib/spec-sections.js +78 -0
- package/src/shared/lib/symbol-entry.js +60 -0
- package/src/shared/lib/tool-phrasing.js +338 -0
- package/src/shared/lib/turn-gap.js +27 -0
- package/src/shared/lib/workstream-words.js +38 -0
- package/src/shared/lib/xlsx-xml.js +144 -0
- package/src/shared/lib/zip-reader.js +99 -0
- package/src/shared/types/agent.js +27 -0
- package/src/shared/types/architecture-rules.js +30 -0
- package/src/shared/types/ast.js +15 -0
- package/src/shared/types/breakpoint.js +33 -0
- package/src/shared/types/channel.js +41 -0
- package/src/shared/types/criteria.js +15 -0
- package/src/shared/types/graph.js +15 -0
- package/src/shared/types/index.js +53 -0
- package/src/shared/types/peer.js +36 -0
- package/src/shared/types/pipeline.js +15 -0
- package/src/shared/types/plan.js +15 -0
- package/src/shared/types/play-forward.js +15 -0
- package/src/shared/types/power.js +15 -0
- package/src/shared/types/presence.js +15 -0
- package/src/shared/types/project-config.js +35 -0
- package/src/shared/types/project.js +15 -0
- package/src/shared/types/record.js +15 -0
- package/src/shared/types/recurring.js +15 -0
- package/src/shared/types/review.js +15 -0
- package/src/shared/types/settings.js +114 -0
- package/src/shared/types/stack.js +15 -0
- package/src/shared/types/system-doc.js +15 -0
- package/src/shared/types/system.js +15 -0
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var plan_tools_exports = {};
|
|
19
|
+
__export(plan_tools_exports, {
|
|
20
|
+
register: () => register
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(plan_tools_exports);
|
|
23
|
+
var import_zod = require("zod");
|
|
24
|
+
var import_item_git_state = require("../../services/item-git-state");
|
|
25
|
+
var import_plan_status = require("../../services/plan-status");
|
|
26
|
+
var import_plan_arrivals = require("../../services/plan-arrivals");
|
|
27
|
+
var import_helpers = require("../helpers");
|
|
28
|
+
var import_prompt_builders = require("../prompt-builders");
|
|
29
|
+
var import_trusted_roots = require("../../services/trusted-roots");
|
|
30
|
+
var import_stack_service = require("../../services/stack-service");
|
|
31
|
+
var import_play_forward = require("../../services/play-forward");
|
|
32
|
+
var import_recurring_service = require("../../services/recurring-service");
|
|
33
|
+
function register(server, deps) {
|
|
34
|
+
server.registerTool(
|
|
35
|
+
"create_plan",
|
|
36
|
+
{
|
|
37
|
+
description: 'Create a new plan in CodeTrellis. Returns the plan UID. Use add_item or bulk_add_items to populate it with Objects (context pages) and Actions (work items). The new plan is auto-exported to .codetrellis/plans/<slug>/ on disk when the effective default visibility is "shared" (see get_project_config). When "local", it stays DB-only and you can later export it explicitly with export_plan_to_files.',
|
|
38
|
+
inputSchema: {
|
|
39
|
+
title: import_zod.z.string().describe("Brief title of the plan"),
|
|
40
|
+
description: import_zod.z.string().optional().describe("Detailed description of what this plan achieves"),
|
|
41
|
+
project_path: import_zod.z.string().describe("Absolute path to the project this plan is for")
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
async ({ title, description, project_path }) => {
|
|
45
|
+
const plan = deps.planService.createPlan(
|
|
46
|
+
{ title, description: description || "", tasks: [] },
|
|
47
|
+
"agent",
|
|
48
|
+
"mcp",
|
|
49
|
+
project_path
|
|
50
|
+
);
|
|
51
|
+
let exported = false;
|
|
52
|
+
try {
|
|
53
|
+
const visibility = deps.projectConfigService.getEffectiveDefaultVisibility(project_path);
|
|
54
|
+
if (visibility === "shared") {
|
|
55
|
+
deps.planFileService.exportPlan(plan.uid, project_path);
|
|
56
|
+
exported = true;
|
|
57
|
+
}
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.warn(`[create_plan] Auto-export failed for ${plan.uid}:`, err);
|
|
60
|
+
}
|
|
61
|
+
const n = deps.broadcast("plan-created", { plan, exported });
|
|
62
|
+
deps.saveNow(() => deps.exportDatabase());
|
|
63
|
+
return (0, import_helpers.resultWithMeta)({
|
|
64
|
+
uid: plan.uid,
|
|
65
|
+
title: plan.title,
|
|
66
|
+
status: plan.status,
|
|
67
|
+
projectPath: plan.projectPath,
|
|
68
|
+
exported
|
|
69
|
+
}, n);
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
server.registerTool(
|
|
73
|
+
"get_plan",
|
|
74
|
+
{
|
|
75
|
+
description: `Read a plan by its UID. Returns plan metadata, a summary of its items (count by kind, status breakdown), state: every item's state with its source (git or the review host for an item on a branch, "plan" for everything else, with who recorded it) and the plan's progress, what waits on someone, what is under way and its lineage; and git_state: for each item worked on a branch, what git proves (building, pushed, or merged and how), with the commit and source. Where the person turned on a review host for the project, it also says in review (with checks and approvals) or closed, with source github. Use list_items to browse the item tree.`,
|
|
76
|
+
inputSchema: { plan_uid: import_zod.z.string().describe("Plan UID") }
|
|
77
|
+
},
|
|
78
|
+
async ({ plan_uid }) => {
|
|
79
|
+
const plan = deps.planService.getPlan(plan_uid);
|
|
80
|
+
if (!plan) return { content: [{ type: "text", text: "Plan not found" }] };
|
|
81
|
+
const items = deps.planItemService.listItemSummaries(plan_uid);
|
|
82
|
+
const objectCount = items.filter((i) => i.kind === "object").length;
|
|
83
|
+
const actionCount = items.filter((i) => i.kind === "action").length;
|
|
84
|
+
const statusCounts = {};
|
|
85
|
+
for (const i of items) {
|
|
86
|
+
if (i.status) statusCounts[i.status] = (statusCounts[i.status] || 0) + 1;
|
|
87
|
+
}
|
|
88
|
+
return { content: [{ type: "text", text: JSON.stringify({
|
|
89
|
+
uid: plan.uid,
|
|
90
|
+
title: plan.title,
|
|
91
|
+
description: plan.description,
|
|
92
|
+
status: plan.status,
|
|
93
|
+
projectPath: plan.projectPath,
|
|
94
|
+
createdAt: plan.createdAt,
|
|
95
|
+
updatedAt: plan.updatedAt,
|
|
96
|
+
items: { total: items.length, objects: objectCount, actions: actionCount, byStatus: statusCounts },
|
|
97
|
+
// Phase 32 C2.6a — how it reached this machine, when through its files.
|
|
98
|
+
...arrivalFor(plan_uid) ? { arrived_from: arrivalFor(plan_uid) } : {},
|
|
99
|
+
// Phase 32 C2.4 — every item's state with its source, and the plan's status view.
|
|
100
|
+
state: await statusForAgent(plan_uid),
|
|
101
|
+
// Phase 32 C2.1 — what git proves about each item's branch.
|
|
102
|
+
git_state: await gitStateForAgent(plan_uid, items)
|
|
103
|
+
}, null, 2) }] };
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
server.registerTool(
|
|
107
|
+
"update_plan",
|
|
108
|
+
{
|
|
109
|
+
description: `Update a plan (title, description, or status). Creates a new version snapshot. Approving a plan is the person's: set status "review" to ask for it, and they approve it in the window or on the phone. Status "approved" is refused here.`,
|
|
110
|
+
inputSchema: {
|
|
111
|
+
plan_uid: import_zod.z.string(),
|
|
112
|
+
title: import_zod.z.string().optional(),
|
|
113
|
+
description: import_zod.z.string().optional(),
|
|
114
|
+
status: import_zod.z.enum(["draft", "review", "approved", "in_progress", "completed", "archived"]).optional()
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
async ({ plan_uid, title, description, status }, extra) => {
|
|
118
|
+
if (status === "approved") {
|
|
119
|
+
return { content: [{ type: "text", text: `Not changed: approving a plan is the person's. Set status "review" to ask for it; they approve it in the window (Approve on the plan header) or on the phone.` }], isError: true };
|
|
120
|
+
}
|
|
121
|
+
const by = (0, import_helpers.authorFromExtra)(deps, extra);
|
|
122
|
+
deps.planService.updatePlan(plan_uid, { title, description, status }, by.author, by.authorType);
|
|
123
|
+
const n = deps.broadcast("plan-updated", { planUid: plan_uid });
|
|
124
|
+
deps.saveNow(() => deps.exportDatabase());
|
|
125
|
+
return (0, import_helpers.resultWithMeta)({ ok: true, planUid: plan_uid }, n);
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
server.registerTool(
|
|
129
|
+
"list_plans",
|
|
130
|
+
{
|
|
131
|
+
description: "List plans, optionally filtered by project path or status. Returns lightweight summaries with item counts. Use limit/offset for pagination.",
|
|
132
|
+
inputSchema: {
|
|
133
|
+
project_path: import_zod.z.string().optional(),
|
|
134
|
+
status: import_zod.z.string().optional(),
|
|
135
|
+
limit: import_zod.z.number().int().min(1).max(100).optional().describe("Max plans to return (default 20)"),
|
|
136
|
+
offset: import_zod.z.number().int().min(0).optional().describe("Skip this many plans (default 0)")
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
async ({ project_path, status, limit, offset }) => {
|
|
140
|
+
const all = deps.planService.listPlans(project_path, status);
|
|
141
|
+
const start = offset ?? 0;
|
|
142
|
+
const end = start + (limit ?? 20);
|
|
143
|
+
const page = all.slice(start, end);
|
|
144
|
+
const summaries = page.map((p) => ({
|
|
145
|
+
uid: p.uid,
|
|
146
|
+
title: p.title,
|
|
147
|
+
status: p.status,
|
|
148
|
+
projectPath: p.projectPath,
|
|
149
|
+
itemCount: deps.planItemService.listItemSummaries(p.uid).length,
|
|
150
|
+
createdAt: p.createdAt,
|
|
151
|
+
updatedAt: p.updatedAt
|
|
152
|
+
}));
|
|
153
|
+
return { content: [{ type: "text", text: JSON.stringify({
|
|
154
|
+
total: all.length,
|
|
155
|
+
offset: start,
|
|
156
|
+
limit: limit ?? 20,
|
|
157
|
+
plans: summaries
|
|
158
|
+
}, null, 2) }] };
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
server.registerTool(
|
|
162
|
+
"get_stack",
|
|
163
|
+
{
|
|
164
|
+
description: "The stack: every active plan in the project (not completed or archived) and its tasks, in one answer. Each plan is called by its ticket key when it has one, with its progress and how many breakpoint hits wait on a person. Each task says who is on it, the branch it is worked on, and its dependencies, including ones in other plans, with what it waits on in words. Use it to see how plans fit together before picking up work.",
|
|
165
|
+
inputSchema: {
|
|
166
|
+
project_path: import_zod.z.string().optional().describe("An opened project. Omit for the one open in the app.")
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
async ({ project_path }) => {
|
|
170
|
+
const root = project_path ?? (0, import_trusted_roots.getActiveProjectRoot)();
|
|
171
|
+
if (!root) return { isError: true, content: [{ type: "text", text: "No project is open." }] };
|
|
172
|
+
return { content: [{ type: "text", text: JSON.stringify((0, import_stack_service.buildStack)(root), null, 2) }] };
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
server.registerTool(
|
|
176
|
+
"get_play_forward",
|
|
177
|
+
{
|
|
178
|
+
description: 'Play the plans forward: what every active plan in the project says it will change, from its unfinished tasks, and where two plans will meet if they go ahead ("\u25C7 planned overlap: JIRA-142 and JIRA-150 both plan to change src/billing/invoice.ts"), including materials both rely on. The same function, or one plan deleting what another changes, is serious; an overlap whose tasks already wait on one another is sequenced. Nothing here exists yet. Use it before claiming work that a planned overlap names.',
|
|
179
|
+
inputSchema: {
|
|
180
|
+
project_path: import_zod.z.string().optional().describe("An opened project. Omit for the one open in the app.")
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
async ({ project_path }) => {
|
|
184
|
+
const root = project_path ?? (0, import_trusted_roots.getActiveProjectRoot)();
|
|
185
|
+
if (!root) return { isError: true, content: [{ type: "text", text: "No project is open." }] };
|
|
186
|
+
return { content: [{ type: "text", text: JSON.stringify((0, import_play_forward.buildPlayForward)(root), null, 2) }] };
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
server.registerTool(
|
|
190
|
+
"list_recurring",
|
|
191
|
+
{
|
|
192
|
+
description: `The project's recurring playbooks (Phase 32 C4): each rule ("Weekly security review, every Mon 09:00 \xB7 skill: security-review") with its runs by period, \u2713 done, \u25D0 in progress, \u2717 missed, the one due now if it is not started, and the next. Each run is an ordinary plan (planUid). A person makes a playbook recur and starts a run in the app; this only reads.`,
|
|
193
|
+
inputSchema: {
|
|
194
|
+
project_path: import_zod.z.string().optional().describe("An opened project. Omit for the one open in the app.")
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
async ({ project_path }) => {
|
|
198
|
+
const root = project_path ?? (0, import_trusted_roots.getActiveProjectRoot)();
|
|
199
|
+
if (!root) return { isError: true, content: [{ type: "text", text: "No project is open." }] };
|
|
200
|
+
return { content: [{ type: "text", text: JSON.stringify({ series: (0, import_recurring_service.seriesFor)(root) }, null, 2) }] };
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
server.registerTool(
|
|
204
|
+
"request_plan_deletion",
|
|
205
|
+
{
|
|
206
|
+
description: 'Ask the person to delete one or more plans. Opens a confirmation in the CodeTrellis window listing the plans and your reason; they must type the plan name (or "delete N plans") to go ahead. This tool deletes nothing and returns immediately: check list_plans later to see whether they did. Plans outside the projects this app has opened are refused.',
|
|
207
|
+
inputSchema: {
|
|
208
|
+
plan_uids: import_zod.z.array(import_zod.z.string()).min(1).max(50).describe("UIDs of the plans to propose deleting"),
|
|
209
|
+
reason: import_zod.z.string().max(500).describe("One or two sentences the person will read: why these plans should go")
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
async ({ plan_uids, reason }) => {
|
|
213
|
+
const plans = [];
|
|
214
|
+
for (const uid of [...new Set(plan_uids)]) {
|
|
215
|
+
const plan = deps.planService.getPlan(uid);
|
|
216
|
+
if (!plan || plan.status === "archived") {
|
|
217
|
+
return { content: [{ type: "text", text: `No active plan ${uid}` }], isError: true };
|
|
218
|
+
}
|
|
219
|
+
if (!plan.projectPath || !(0, import_trusted_roots.isTrustedProjectRoot)(plan.projectPath)) {
|
|
220
|
+
return {
|
|
221
|
+
content: [{ type: "text", text: `Plan ${uid} belongs to a project that is not open; it can only be deleted from there.` }],
|
|
222
|
+
isError: true
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
plans.push({ uid: plan.uid, title: plan.title, projectPath: plan.projectPath });
|
|
226
|
+
}
|
|
227
|
+
const requestId = `pd-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
228
|
+
const n = deps.broadcast("ui-confirm-plan-deletion", { requestId, plans, reason });
|
|
229
|
+
return (0, import_helpers.resultWithMeta)({
|
|
230
|
+
requested: true,
|
|
231
|
+
requestId,
|
|
232
|
+
plans: plans.map((p) => ({ uid: p.uid, title: p.title })),
|
|
233
|
+
note: n > 0 ? "Asked the person to confirm in the CodeTrellis window. Nothing has been deleted." : "No CodeTrellis window is open to ask. Nothing has been deleted."
|
|
234
|
+
}, n);
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
server.registerTool(
|
|
238
|
+
"export_plan_to_files",
|
|
239
|
+
{
|
|
240
|
+
description: "Round-trip a plan to disk as YAML under `<projectRoot>/.codetrellis/plans/<slug>/`. Exports a nested `items/` tree layout. Idempotent \u2014 re-exporting overwrites the same files. Use this so plans can be committed to git and shared across devices / agents.",
|
|
241
|
+
inputSchema: {
|
|
242
|
+
plan_uid: import_zod.z.string(),
|
|
243
|
+
project_root: import_zod.z.string().describe("Absolute path to the project repo root. The .codetrellis/ directory will be created inside it.")
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
async ({ plan_uid, project_root }) => {
|
|
247
|
+
try {
|
|
248
|
+
const result = deps.planFileService.exportPlan(plan_uid, project_root);
|
|
249
|
+
deps.broadcast("plan-exported", { planUid: plan_uid, planDir: result.planDir, files: result.files.length });
|
|
250
|
+
return {
|
|
251
|
+
content: [{
|
|
252
|
+
type: "text",
|
|
253
|
+
text: JSON.stringify({ planDir: result.planDir, fileCount: result.files.length }, null, 2)
|
|
254
|
+
}]
|
|
255
|
+
};
|
|
256
|
+
} catch (err) {
|
|
257
|
+
return { content: [{ type: "text", text: `Failed: ${err instanceof Error ? err.message : err}` }] };
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
server.registerTool(
|
|
262
|
+
"import_plan_from_files",
|
|
263
|
+
{
|
|
264
|
+
description: "Read a plan directory (`.codetrellis/plans/<slug>/`) from disk and upsert it into the DB. Detects format automatically. UID-based upsert is idempotent. Use after `git pull` to sync external changes.",
|
|
265
|
+
inputSchema: {
|
|
266
|
+
plan_dir: import_zod.z.string().describe("Absolute path to the plan directory (or directly to plan.yaml).")
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
async ({ plan_dir }) => {
|
|
270
|
+
try {
|
|
271
|
+
const result = deps.planFileService.importPlan(plan_dir);
|
|
272
|
+
deps.broadcast("plan-imported", { planUid: result.plan.uid, source: plan_dir });
|
|
273
|
+
if (result.items) {
|
|
274
|
+
for (const item of result.items) {
|
|
275
|
+
deps.broadcast("plan-item-created", { item });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
deps.saveNow(() => deps.exportDatabase());
|
|
279
|
+
return {
|
|
280
|
+
content: [{
|
|
281
|
+
type: "text",
|
|
282
|
+
text: JSON.stringify({
|
|
283
|
+
plan: { uid: result.plan.uid, title: result.plan.title },
|
|
284
|
+
itemCount: result.items?.length ?? 0,
|
|
285
|
+
warnings: result.warnings
|
|
286
|
+
}, null, 2)
|
|
287
|
+
}]
|
|
288
|
+
};
|
|
289
|
+
} catch (err) {
|
|
290
|
+
return { content: [{ type: "text", text: `Failed: ${err instanceof Error ? err.message : err}` }] };
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
server.registerTool(
|
|
295
|
+
"discover_plan_files",
|
|
296
|
+
{
|
|
297
|
+
description: "List every plan directory under `<project_root>/.codetrellis/plans/`. Used to find plans that came in via `git pull` or that another tool authored. Returns absolute paths.",
|
|
298
|
+
inputSchema: { project_root: import_zod.z.string() }
|
|
299
|
+
},
|
|
300
|
+
async ({ project_root }) => {
|
|
301
|
+
const dirs = deps.planFileService.discoverPlanDirs(project_root);
|
|
302
|
+
return { content: [{ type: "text", text: JSON.stringify(dirs, null, 2) }] };
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
server.registerTool(
|
|
306
|
+
"unlink_plan_from_files",
|
|
307
|
+
{
|
|
308
|
+
description: "Remove a plan's on-disk directory under `.codetrellis/plans/<slug>/`. The DB rows survive \u2014 this is the \"Shared \u2192 Local\" toggle. Use this to stop write-through-syncing a plan to the project repo (e.g. for a private brainstorm you don't want committed).",
|
|
309
|
+
inputSchema: {
|
|
310
|
+
plan_uid: import_zod.z.string(),
|
|
311
|
+
project_root: import_zod.z.string()
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
async ({ plan_uid, project_root }) => {
|
|
315
|
+
try {
|
|
316
|
+
const result = deps.planFileService.unlinkPlan(plan_uid, project_root);
|
|
317
|
+
deps.broadcast("plan-unlinked", { planUid: plan_uid });
|
|
318
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
319
|
+
} catch (err) {
|
|
320
|
+
return { content: [{ type: "text", text: `Failed: ${err instanceof Error ? err.message : err}` }] };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
server.registerTool(
|
|
325
|
+
"publish_plan_as_template",
|
|
326
|
+
{
|
|
327
|
+
description: "Snapshot a plan as a reusable template under `<project_root>/.codetrellis/templates/<template_id>/`. Produces a template with a nested items tree. Strips runtime fields (statuses, assignees). The result can be shared via git.",
|
|
328
|
+
inputSchema: {
|
|
329
|
+
plan_uid: import_zod.z.string(),
|
|
330
|
+
project_root: import_zod.z.string(),
|
|
331
|
+
template_id: import_zod.z.string().describe('Lowercase slug, alphanumeric + hyphens (e.g. "company-mass-refactor").'),
|
|
332
|
+
label: import_zod.z.string().optional().describe("Human-readable name shown in the picker. Defaults to the plan title."),
|
|
333
|
+
short_description: import_zod.z.string().optional(),
|
|
334
|
+
long_description: import_zod.z.string().optional(),
|
|
335
|
+
default_title: import_zod.z.string().optional().describe("Default plan title when the template is applied. May contain `{{name}}` etc. for placeholder substitution."),
|
|
336
|
+
default_plan_description: import_zod.z.string().optional()
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
async ({ plan_uid, project_root, template_id, label, short_description, long_description, default_title, default_plan_description }) => {
|
|
340
|
+
try {
|
|
341
|
+
const result = deps.publishPlanAsTemplate({
|
|
342
|
+
planUid: plan_uid,
|
|
343
|
+
projectRoot: project_root,
|
|
344
|
+
templateId: template_id,
|
|
345
|
+
label,
|
|
346
|
+
shortDescription: short_description,
|
|
347
|
+
longDescription: long_description,
|
|
348
|
+
defaultTitle: default_title,
|
|
349
|
+
defaultPlanDescription: default_plan_description
|
|
350
|
+
});
|
|
351
|
+
deps.broadcast("plan-template-published", { templateId: template_id, templateDir: result.templateDir });
|
|
352
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
353
|
+
} catch (err) {
|
|
354
|
+
return { content: [{ type: "text", text: `Failed: ${err instanceof Error ? err.message : err}` }] };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
);
|
|
358
|
+
server.registerTool(
|
|
359
|
+
"list_plan_templates",
|
|
360
|
+
{
|
|
361
|
+
description: "List the available plan templates. Includes built-ins, user-global templates from `~/.codetrellis/templates/`, and project-local templates from `<project_root>/.codetrellis/templates/` when project_root is provided. Each template seeds a full plan tree in one go.",
|
|
362
|
+
inputSchema: {
|
|
363
|
+
project_root: import_zod.z.string().optional().describe("Project root for picking up team-published templates from `.codetrellis/templates/`. Optional \u2014 without it, only built-ins + user-global templates are returned.")
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
async ({ project_root }) => {
|
|
367
|
+
return { content: [{ type: "text", text: JSON.stringify(deps.listTemplates(project_root), null, 2) }] };
|
|
368
|
+
}
|
|
369
|
+
);
|
|
370
|
+
server.registerTool(
|
|
371
|
+
"create_plan_from_template",
|
|
372
|
+
{
|
|
373
|
+
description: "Create a new plan from a template in one call. Use list_plan_templates to pick a template_id. Pass `placeholder_values` for templates with `{{key}}` placeholders.",
|
|
374
|
+
inputSchema: {
|
|
375
|
+
template_id: import_zod.z.string().describe('e.g. "mass-refactor"'),
|
|
376
|
+
project_path: import_zod.z.string(),
|
|
377
|
+
title: import_zod.z.string().optional().describe("Override the template default title"),
|
|
378
|
+
description: import_zod.z.string().optional().describe("Override the template default description"),
|
|
379
|
+
placeholder_values: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional().describe("Values for `{{key}}` placeholders declared by the template (Phase 13 \xA7C). Missing keys fall back to the placeholder default.")
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
async ({ template_id, project_path, title, description, placeholder_values }, extra) => {
|
|
383
|
+
try {
|
|
384
|
+
const result = deps.applyTemplate({
|
|
385
|
+
templateId: template_id,
|
|
386
|
+
projectPath: project_path,
|
|
387
|
+
title,
|
|
388
|
+
description,
|
|
389
|
+
...(0, import_helpers.authorFromExtra)(deps, extra),
|
|
390
|
+
placeholderValues: placeholder_values
|
|
391
|
+
});
|
|
392
|
+
let exported = false;
|
|
393
|
+
try {
|
|
394
|
+
const visibility = deps.projectConfigService.getEffectiveDefaultVisibility(project_path);
|
|
395
|
+
if (visibility === "shared") {
|
|
396
|
+
deps.planFileService.exportPlan(result.plan.uid, project_path);
|
|
397
|
+
exported = true;
|
|
398
|
+
}
|
|
399
|
+
} catch (err) {
|
|
400
|
+
console.warn(`[create_plan_from_template] Auto-export failed for ${result.plan.uid}:`, err);
|
|
401
|
+
}
|
|
402
|
+
deps.broadcast("plan-created", { plan: result.plan, exported });
|
|
403
|
+
if (result.items) {
|
|
404
|
+
for (const item of result.items) deps.broadcast("plan-item-created", { item });
|
|
405
|
+
}
|
|
406
|
+
deps.saveNow(() => deps.exportDatabase());
|
|
407
|
+
return {
|
|
408
|
+
content: [{
|
|
409
|
+
type: "text",
|
|
410
|
+
text: JSON.stringify({
|
|
411
|
+
plan: result.plan,
|
|
412
|
+
itemCount: result.items?.length ?? 0,
|
|
413
|
+
exported,
|
|
414
|
+
hint: "Use list_items(plan_uid) to browse the plan tree."
|
|
415
|
+
}, null, 2)
|
|
416
|
+
}]
|
|
417
|
+
};
|
|
418
|
+
} catch (err) {
|
|
419
|
+
return { content: [{ type: "text", text: `Failed to apply template: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
);
|
|
423
|
+
server.registerTool(
|
|
424
|
+
"import_external",
|
|
425
|
+
{
|
|
426
|
+
description: "Import a plan from external text \u2014 a conversation transcript, markdown notes, GitHub issue body, or any structured text. Extracts action items, file references, and creates a plan with items automatically. Good for turning chat discussions or issue descriptions into actionable CodeTrellis plans.",
|
|
427
|
+
inputSchema: {
|
|
428
|
+
text: import_zod.z.string().describe("The text content to import (markdown, conversation, issue body, etc.)."),
|
|
429
|
+
title: import_zod.z.string().optional().describe("Optional title for the new plan. Auto-generated if omitted."),
|
|
430
|
+
project_path: import_zod.z.string().optional().describe(
|
|
431
|
+
"Absolute path to the project this plan belongs to. Defaults to the project currently open."
|
|
432
|
+
)
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
async ({ text, title, project_path }, extra) => {
|
|
436
|
+
const projectPath = project_path ?? (0, import_trusted_roots.getActiveProjectRoot)();
|
|
437
|
+
if (!projectPath) {
|
|
438
|
+
return { content: [{ type: "text", text: "No project is open: pass project_path, or open the project first." }], isError: true };
|
|
439
|
+
}
|
|
440
|
+
const id = (0, import_helpers.authorFromExtra)(deps, extra);
|
|
441
|
+
try {
|
|
442
|
+
const result = deps.planImportService.importFromConversation({ text, title });
|
|
443
|
+
const plan = deps.planService.createPlan(
|
|
444
|
+
{ title: result.title, description: result.description, tasks: [] },
|
|
445
|
+
id.author,
|
|
446
|
+
id.authorType,
|
|
447
|
+
projectPath
|
|
448
|
+
);
|
|
449
|
+
let itemCount = 0;
|
|
450
|
+
for (const imported of result.items) {
|
|
451
|
+
deps.planItemService.createItem({
|
|
452
|
+
planUid: plan.uid,
|
|
453
|
+
kind: imported.kind,
|
|
454
|
+
title: imported.title,
|
|
455
|
+
body: imported.body,
|
|
456
|
+
fileSpecs: imported.fileSpecs,
|
|
457
|
+
scopePath: imported.scopePath,
|
|
458
|
+
author: id.author,
|
|
459
|
+
authorType: id.authorType
|
|
460
|
+
});
|
|
461
|
+
itemCount++;
|
|
462
|
+
}
|
|
463
|
+
deps.planFileService.exportIfSharedByDefault(plan.uid, projectPath);
|
|
464
|
+
deps.broadcast("plan-imported", { planUid: plan.uid, source: "mcp-import" });
|
|
465
|
+
return {
|
|
466
|
+
content: [{
|
|
467
|
+
type: "text",
|
|
468
|
+
text: `Imported plan "${plan.title}" (${plan.uid}) with ${itemCount} items`
|
|
469
|
+
}]
|
|
470
|
+
};
|
|
471
|
+
} catch (err) {
|
|
472
|
+
return { content: [{ type: "text", text: `Import failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
);
|
|
476
|
+
server.registerTool(
|
|
477
|
+
"copy_plan_as_prompt",
|
|
478
|
+
{
|
|
479
|
+
description: 'Serialise a plan (or a single item) as a markdown prompt suitable for handing off to an AI agent. Returns the formatted prompt text that includes tasks, file targets, constraints, and git context. Equivalent to the "Copy as prompt" handoff button in the UI.',
|
|
480
|
+
inputSchema: {
|
|
481
|
+
plan_uid: import_zod.z.string().describe("UID of the plan to serialise."),
|
|
482
|
+
item_uid: import_zod.z.string().optional().describe("If provided, serialise only this item instead of the full plan.")
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
async ({ plan_uid, item_uid }) => {
|
|
486
|
+
const plan = deps.planService.getPlan(plan_uid);
|
|
487
|
+
if (!plan) {
|
|
488
|
+
return { content: [{ type: "text", text: `Plan ${plan_uid} not found` }], isError: true };
|
|
489
|
+
}
|
|
490
|
+
const items = deps.planItemService.listAllItems(plan_uid);
|
|
491
|
+
if (item_uid) {
|
|
492
|
+
const item = items.find((i) => i.uid === item_uid);
|
|
493
|
+
if (!item) {
|
|
494
|
+
return { content: [{ type: "text", text: `Item ${item_uid} not found in plan ${plan_uid}` }], isError: true };
|
|
495
|
+
}
|
|
496
|
+
const prompt2 = (0, import_prompt_builders.buildItemPrompt)(item, plan);
|
|
497
|
+
return { content: [{ type: "text", text: prompt2 }] };
|
|
498
|
+
}
|
|
499
|
+
const refs = deps.externalRefsService.getExternalRefsByPlan(plan_uid);
|
|
500
|
+
const prompt = (0, import_prompt_builders.buildPlanPrompt)(plan, items, refs);
|
|
501
|
+
return { content: [{ type: "text", text: prompt }] };
|
|
502
|
+
}
|
|
503
|
+
);
|
|
504
|
+
server.registerTool(
|
|
505
|
+
"set_plan_home_repo",
|
|
506
|
+
{
|
|
507
|
+
description: "Set the home repo of a plan to a normalised git origin URL. The home repo is captured automatically at create_plan from the project's git origin \u2014 call this only when you need to override it (e.g. moving a plan between repos, or attaching a previously-orphaned plan). Pass an empty string to clear.",
|
|
508
|
+
inputSchema: {
|
|
509
|
+
plan_uid: import_zod.z.string().describe("UID of the plan to update"),
|
|
510
|
+
home_repo_url: import_zod.z.string().describe("Git origin URL \u2014 will be normalised. Empty string clears.")
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
async ({ plan_uid, home_repo_url }) => {
|
|
514
|
+
const trimmed = home_repo_url.trim();
|
|
515
|
+
deps.planService.setPlanHomeRepo(plan_uid, trimmed === "" ? null : trimmed);
|
|
516
|
+
const plan = deps.planService.getPlan(plan_uid);
|
|
517
|
+
const n = deps.broadcast("plan-updated", { planUid: plan_uid });
|
|
518
|
+
deps.saveNow(() => deps.exportDatabase());
|
|
519
|
+
return (0, import_helpers.resultWithMeta)({ ok: true, planUid: plan_uid, homeRepo: plan?.homeRepo ?? null }, n);
|
|
520
|
+
}
|
|
521
|
+
);
|
|
522
|
+
server.registerTool(
|
|
523
|
+
"add_plan_scope",
|
|
524
|
+
{
|
|
525
|
+
description: "Add a repository (by git origin URL) to a plan's cross-repo scope. When `pointer_project_root` is supplied AND it's a clone of the scoped repo on this machine, a pointer file is written to <pointer_project_root>/.codetrellis/external/<plan-uid>.yaml so developers cloning that repo discover the plan. The pointer caches a snapshot of title/status/summary; it round-trips through git. Returns the updated scope list.",
|
|
526
|
+
inputSchema: {
|
|
527
|
+
plan_uid: import_zod.z.string(),
|
|
528
|
+
repo_url: import_zod.z.string().describe("Git origin URL of the participating repo \u2014 will be normalised"),
|
|
529
|
+
pointer_project_root: import_zod.z.string().optional().describe("Absolute path on this machine where the pointer file should be written. Skip when not locally available."),
|
|
530
|
+
contribution: import_zod.z.string().optional().describe(`Short note describing this repo's contribution to the plan (e.g. "ships the migration").`),
|
|
531
|
+
summary: import_zod.z.string().optional().describe("Short prose summary cached into the pointer; defaults to the plan's description.")
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
async ({ plan_uid, repo_url, pointer_project_root, contribution, summary }) => {
|
|
535
|
+
const plan = deps.planService.getPlan(plan_uid);
|
|
536
|
+
if (!plan) {
|
|
537
|
+
return { content: [{ type: "text", text: `Plan ${plan_uid} not found` }], isError: true };
|
|
538
|
+
}
|
|
539
|
+
const scope = deps.planService.addPlanScope(plan_uid, repo_url);
|
|
540
|
+
let pointerPath = null;
|
|
541
|
+
if (pointer_project_root) {
|
|
542
|
+
try {
|
|
543
|
+
pointerPath = deps.externalPointerService.writePointer({
|
|
544
|
+
planUid: plan_uid,
|
|
545
|
+
projectRoot: pointer_project_root,
|
|
546
|
+
homeRepo: plan.homeRepo ?? "",
|
|
547
|
+
title: plan.title,
|
|
548
|
+
status: plan.status,
|
|
549
|
+
summary: summary ?? plan.description ?? void 0,
|
|
550
|
+
contribution
|
|
551
|
+
});
|
|
552
|
+
} catch (err) {
|
|
553
|
+
console.warn("[add_plan_scope] pointer write failed:", err);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
const n = deps.broadcast("plan-scope-changed", { planUid: plan_uid, scope, added: repo_url, pointerPath });
|
|
557
|
+
deps.saveNow(() => deps.exportDatabase());
|
|
558
|
+
return (0, import_helpers.resultWithMeta)({ ok: true, planUid: plan_uid, scope, pointerPath }, n);
|
|
559
|
+
}
|
|
560
|
+
);
|
|
561
|
+
server.registerTool(
|
|
562
|
+
"remove_plan_scope",
|
|
563
|
+
{
|
|
564
|
+
description: "Remove a repo from a plan's scope. When `pointer_project_root` is supplied, also delete the pointer file at <pointer_project_root>/.codetrellis/external/<plan-uid>.yaml so the scoped repo stops advertising the plan.",
|
|
565
|
+
inputSchema: {
|
|
566
|
+
plan_uid: import_zod.z.string(),
|
|
567
|
+
repo_url: import_zod.z.string(),
|
|
568
|
+
pointer_project_root: import_zod.z.string().optional().describe("Absolute path of the scoped repo on this machine \u2014 pointer is removed when supplied.")
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
async ({ plan_uid, repo_url, pointer_project_root }) => {
|
|
572
|
+
const scope = deps.planService.removePlanScope(plan_uid, repo_url);
|
|
573
|
+
let pointerRemoved = false;
|
|
574
|
+
if (pointer_project_root) {
|
|
575
|
+
pointerRemoved = deps.externalPointerService.removePointer(plan_uid, pointer_project_root);
|
|
576
|
+
}
|
|
577
|
+
const n = deps.broadcast("plan-scope-changed", { planUid: plan_uid, scope, removed: repo_url, pointerRemoved });
|
|
578
|
+
deps.saveNow(() => deps.exportDatabase());
|
|
579
|
+
return (0, import_helpers.resultWithMeta)({ ok: true, planUid: plan_uid, scope, pointerRemoved }, n);
|
|
580
|
+
}
|
|
581
|
+
);
|
|
582
|
+
server.registerTool(
|
|
583
|
+
"list_plan_pointers",
|
|
584
|
+
{
|
|
585
|
+
description: 'List every external plan pointer found under <project_path>/.codetrellis/external/. Each entry is a thin reference to a plan whose home is another repo \u2014 title/status/summary/contribution are cached at the last refresh. Use this to surface "plans from other repos that touch this one" in the UI.',
|
|
586
|
+
inputSchema: {
|
|
587
|
+
project_path: import_zod.z.string().describe("Absolute path to the project root")
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
async ({ project_path }) => {
|
|
591
|
+
const pointers = deps.externalPointerService.discoverPointers(project_path);
|
|
592
|
+
return { content: [{ type: "text", text: JSON.stringify({
|
|
593
|
+
projectPath: project_path,
|
|
594
|
+
count: pointers.length,
|
|
595
|
+
pointers: pointers.map((p) => ({ filePath: p.filePath, ...p.pointer }))
|
|
596
|
+
}, null, 2) }] };
|
|
597
|
+
}
|
|
598
|
+
);
|
|
599
|
+
server.registerTool(
|
|
600
|
+
"list_plans_by_repo",
|
|
601
|
+
{
|
|
602
|
+
description: 'Return every active plan whose home_repo OR scope contains the given git origin URL. Cross-machine safe \u2014 URLs are normalised before matching. Useful for "show me every plan that touches this repo" in cross-repo views.',
|
|
603
|
+
inputSchema: {
|
|
604
|
+
repo_url: import_zod.z.string().describe("Git origin URL \u2014 will be normalised before matching")
|
|
605
|
+
}
|
|
606
|
+
},
|
|
607
|
+
async ({ repo_url }) => {
|
|
608
|
+
const plans = deps.planService.listPlansByRepoUrl(repo_url);
|
|
609
|
+
return { content: [{ type: "text", text: JSON.stringify({
|
|
610
|
+
repoUrl: repo_url,
|
|
611
|
+
count: plans.length,
|
|
612
|
+
plans: plans.map((p) => ({
|
|
613
|
+
uid: p.uid,
|
|
614
|
+
title: p.title,
|
|
615
|
+
status: p.status,
|
|
616
|
+
homeRepo: p.homeRepo,
|
|
617
|
+
scope: p.scope,
|
|
618
|
+
taskCount: p.taskCount,
|
|
619
|
+
completedTaskCount: p.completedTaskCount,
|
|
620
|
+
projectPath: p.projectPath
|
|
621
|
+
}))
|
|
622
|
+
}, null, 2) }] };
|
|
623
|
+
}
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
function arrivalFor(planUid) {
|
|
627
|
+
const a = (0, import_plan_arrivals.getPlanArrival)(planUid);
|
|
628
|
+
return a ? { added_by: a.addedBy, commit: a.commit, says: (0, import_plan_arrivals.arrivalWords)(a) } : null;
|
|
629
|
+
}
|
|
630
|
+
async function statusForAgent(planUid) {
|
|
631
|
+
const s = await (0, import_plan_status.planStatusFresh)(planUid);
|
|
632
|
+
if (!s) return null;
|
|
633
|
+
return {
|
|
634
|
+
progress: s.progress.words,
|
|
635
|
+
waiting: s.waiting.map((w) => ({ item_uid: w.itemUid, title: w.title, says: w.words, source: w.source })),
|
|
636
|
+
in_progress: s.inProgress.map((w) => ({ item_uid: w.itemUid, title: w.title, says: w.words, source: w.source })),
|
|
637
|
+
lineage: s.lineage,
|
|
638
|
+
items: s.items.map((i) => ({
|
|
639
|
+
item_uid: i.itemUid,
|
|
640
|
+
title: i.title,
|
|
641
|
+
kind: i.kind,
|
|
642
|
+
state: i.state,
|
|
643
|
+
says: i.words,
|
|
644
|
+
source: i.source,
|
|
645
|
+
...i.recorded ? { recorded_by: i.recorded.by, recorded_at: i.recorded.at } : {},
|
|
646
|
+
// C3.1: taken from a teammate's record in the project's files, which anyone could have written.
|
|
647
|
+
...i.recorded?.byType === "record" ? { recorded_in: i.recorded.check?.verified ? `the teammate's record, signed with ${i.recorded.check.how === "git" ? "their git key" : "their trusted device key"}` : "the teammate's record, unverified" } : {},
|
|
648
|
+
...i.branch ? { branch: i.branch } : {},
|
|
649
|
+
...i.gitNote ? { git_note: i.gitNote } : {},
|
|
650
|
+
// C3.2: set two ways at once by people who had not seen each other's change; nothing is picked.
|
|
651
|
+
...i.atOnce ? { set_at_once: i.atOnce.words } : {}
|
|
652
|
+
})),
|
|
653
|
+
note: 'Read, never written: source says where each state came from \u2014 git or the review host for an item on a branch, the plan itself ("plan") for everything else.'
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
async function gitStateForAgent(planUid, items) {
|
|
657
|
+
const states = await (0, import_item_git_state.planGitStatesFresh)(planUid);
|
|
658
|
+
if (!states || states.items.length === 0) return { base: states?.base ?? null, items: [], note: "No item is worked on a branch yet (assign_workstream sets one)." };
|
|
659
|
+
const title = new Map(items.map((i) => [i.uid, i.title]));
|
|
660
|
+
return {
|
|
661
|
+
base: states.base,
|
|
662
|
+
items: states.items.map((s) => ({
|
|
663
|
+
item_uid: s.itemUid,
|
|
664
|
+
title: title.get(s.itemUid) ?? null,
|
|
665
|
+
branch: s.branch,
|
|
666
|
+
state: s.state,
|
|
667
|
+
says: s.words,
|
|
668
|
+
...s.how ? { how: s.how } : {},
|
|
669
|
+
commit: s.commit,
|
|
670
|
+
source: s.source,
|
|
671
|
+
...s.review ? { pull_request: s.review } : {},
|
|
672
|
+
...s.hostNote ? { host_note: s.hostNote } : {}
|
|
673
|
+
})),
|
|
674
|
+
note: states.items.some((s) => s.source !== "git" || s.hostNote) ? "From git, and from the review host the person turned on where it says more: source names which." : "From git alone: building, pushed and merged. In review, checks and closed need a review host, which the person turns on in Settings \u2192 Review hosts; none is asked."
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
678
|
+
0 && (module.exports = {
|
|
679
|
+
register
|
|
680
|
+
});
|