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,140 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var signing_exports = {};
|
|
29
|
+
__export(signing_exports, {
|
|
30
|
+
KEY_KIND: () => KEY_KIND,
|
|
31
|
+
RECORD_NAMESPACE: () => RECORD_NAMESPACE,
|
|
32
|
+
canonicalJson: () => canonicalJson,
|
|
33
|
+
fingerprintOf: () => fingerprintOf,
|
|
34
|
+
keyFileName: () => keyFileName,
|
|
35
|
+
makeDeviceKey: () => makeDeviceKey,
|
|
36
|
+
parseKeyIntroduction: () => parseKeyIntroduction,
|
|
37
|
+
parseSignature: () => parseSignature,
|
|
38
|
+
serializeKeyIntroduction: () => serializeKeyIntroduction,
|
|
39
|
+
shortFingerprint: () => shortFingerprint,
|
|
40
|
+
signWithDevice: () => signWithDevice,
|
|
41
|
+
verifyWithDevice: () => verifyWithDevice
|
|
42
|
+
});
|
|
43
|
+
module.exports = __toCommonJS(signing_exports);
|
|
44
|
+
var import_node_crypto = __toESM(require("node:crypto"));
|
|
45
|
+
var import_yaml = require("yaml");
|
|
46
|
+
const RECORD_NAMESPACE = "codetrellis-task-record";
|
|
47
|
+
const KEY_KIND = "codetrellis-device-key";
|
|
48
|
+
const MAX_KEY_BYTES = 4 * 1024;
|
|
49
|
+
const WRITER = /^[a-f0-9]{8,32}$/;
|
|
50
|
+
const FINGERPRINT = /^SHA256:[A-Za-z0-9+/]{43}$/;
|
|
51
|
+
const EMAIL = /^[^\s<>@]{1,64}@[^\s<>@]{1,255}$/;
|
|
52
|
+
const SSH_SIGNATURE = /^-----BEGIN SSH SIGNATURE-----\n[A-Za-z0-9+/=\n]+-----END SSH SIGNATURE-----$/;
|
|
53
|
+
function canonicalJson(v) {
|
|
54
|
+
const sort = (x) => {
|
|
55
|
+
if (Array.isArray(x)) return x.map(sort);
|
|
56
|
+
if (x && typeof x === "object") {
|
|
57
|
+
return Object.fromEntries(Object.keys(x).sort().map((k) => [k, sort(x[k])]));
|
|
58
|
+
}
|
|
59
|
+
return x;
|
|
60
|
+
};
|
|
61
|
+
return JSON.stringify(sort(v));
|
|
62
|
+
}
|
|
63
|
+
function parseSignature(raw) {
|
|
64
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
65
|
+
const s = raw;
|
|
66
|
+
if (s.how === "device" && typeof s.key === "string" && FINGERPRINT.test(s.key) && typeof s.value === "string" && /^[A-Za-z0-9+/]{86}==$/.test(s.value)) {
|
|
67
|
+
return { how: "device", key: s.key, value: s.value };
|
|
68
|
+
}
|
|
69
|
+
if (s.how === "git" && typeof s.signer === "string" && EMAIL.test(s.signer) && typeof s.value === "string" && SSH_SIGNATURE.test(s.value.trim())) {
|
|
70
|
+
return { how: "git", signer: s.signer, value: s.value.trim() };
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
function fingerprintOf(publicKey) {
|
|
75
|
+
return `SHA256:${import_node_crypto.default.createHash("sha256").update(Buffer.from(publicKey, "base64")).digest("base64").replace(/=+$/, "")}`;
|
|
76
|
+
}
|
|
77
|
+
function makeDeviceKey() {
|
|
78
|
+
const { publicKey, privateKey } = import_node_crypto.default.generateKeyPairSync("ed25519");
|
|
79
|
+
const pub = publicKey.export({ type: "spki", format: "der" }).toString("base64");
|
|
80
|
+
return { publicKey: pub, privateKey: privateKey.export({ type: "pkcs8", format: "der" }).toString("base64"), fingerprint: fingerprintOf(pub) };
|
|
81
|
+
}
|
|
82
|
+
function signWithDevice(key, bytes) {
|
|
83
|
+
const priv = import_node_crypto.default.createPrivateKey({ key: Buffer.from(key.privateKey, "base64"), format: "der", type: "pkcs8" });
|
|
84
|
+
return { how: "device", key: key.fingerprint, value: import_node_crypto.default.sign(null, Buffer.from(bytes, "utf8"), priv).toString("base64") };
|
|
85
|
+
}
|
|
86
|
+
function verifyWithDevice(publicKey, bytes, value) {
|
|
87
|
+
try {
|
|
88
|
+
const pub = import_node_crypto.default.createPublicKey({ key: Buffer.from(publicKey, "base64"), format: "der", type: "spki" });
|
|
89
|
+
if (pub.asymmetricKeyType !== "ed25519") return false;
|
|
90
|
+
return import_node_crypto.default.verify(null, Buffer.from(bytes, "utf8"), pub, Buffer.from(value, "base64"));
|
|
91
|
+
} catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function keyFileName(writer) {
|
|
96
|
+
return `${writer}.yaml`;
|
|
97
|
+
}
|
|
98
|
+
function serializeKeyIntroduction(k) {
|
|
99
|
+
return '# CodeTrellis: this device signs its task-state records with this key.\n# Teammates trust it once, in Settings \u2192 Shared task state, after checking the\n# fingerprint with its owner. Until then its records read "unverified".\n' + (0, import_yaml.stringify)({ kind: KEY_KIND, version: 1, writer: k.writer, name: k.name, publicKey: k.publicKey, fingerprint: k.fingerprint }, { lineWidth: 0 });
|
|
100
|
+
}
|
|
101
|
+
function parseKeyIntroduction(source, fileWriter) {
|
|
102
|
+
if (Buffer.byteLength(source, "utf8") > MAX_KEY_BYTES) return { error: "larger than a key file can be" };
|
|
103
|
+
let raw;
|
|
104
|
+
try {
|
|
105
|
+
raw = (0, import_yaml.parse)(source, { maxAliasCount: 0 });
|
|
106
|
+
} catch {
|
|
107
|
+
return { error: "not YAML" };
|
|
108
|
+
}
|
|
109
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return { error: "not a key file" };
|
|
110
|
+
const r = raw;
|
|
111
|
+
if (r.kind !== KEY_KIND || r.version !== 1) return { error: "not a key file this version reads" };
|
|
112
|
+
if (typeof r.writer !== "string" || !WRITER.test(r.writer) || r.writer !== fileWriter) return { error: "names another device than its file" };
|
|
113
|
+
if (typeof r.publicKey !== "string" || r.publicKey.length > 200) return { error: "no public key" };
|
|
114
|
+
try {
|
|
115
|
+
const pub = import_node_crypto.default.createPublicKey({ key: Buffer.from(r.publicKey, "base64"), format: "der", type: "spki" });
|
|
116
|
+
if (pub.asymmetricKeyType !== "ed25519") return { error: "not an Ed25519 key" };
|
|
117
|
+
} catch {
|
|
118
|
+
return { error: "not a public key" };
|
|
119
|
+
}
|
|
120
|
+
const name = typeof r.name === "string" && r.name.trim() ? r.name.trim().slice(0, 120) : "someone";
|
|
121
|
+
return { key: { writer: r.writer, name, publicKey: r.publicKey, fingerprint: fingerprintOf(r.publicKey) } };
|
|
122
|
+
}
|
|
123
|
+
function shortFingerprint(fp) {
|
|
124
|
+
return fp.slice(0, 7 + 12);
|
|
125
|
+
}
|
|
126
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
127
|
+
0 && (module.exports = {
|
|
128
|
+
KEY_KIND,
|
|
129
|
+
RECORD_NAMESPACE,
|
|
130
|
+
canonicalJson,
|
|
131
|
+
fingerprintOf,
|
|
132
|
+
keyFileName,
|
|
133
|
+
makeDeviceKey,
|
|
134
|
+
parseKeyIntroduction,
|
|
135
|
+
parseSignature,
|
|
136
|
+
serializeKeyIntroduction,
|
|
137
|
+
shortFingerprint,
|
|
138
|
+
signWithDevice,
|
|
139
|
+
verifyWithDevice
|
|
140
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
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 split_signals_exports = {};
|
|
19
|
+
__export(split_signals_exports, {
|
|
20
|
+
stateSplitDrafts: () => stateSplitDrafts
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(split_signals_exports);
|
|
23
|
+
var import_database = require("../database");
|
|
24
|
+
var import_awareness_signals = require("../awareness-signals");
|
|
25
|
+
var import_item_status = require("../../../shared/lib/item-status");
|
|
26
|
+
var import_heads = require("./heads");
|
|
27
|
+
function stateSplitDrafts(projectRoot) {
|
|
28
|
+
const out = [];
|
|
29
|
+
for (const [itemUid, claims] of (0, import_heads.allSplits)()) {
|
|
30
|
+
const row = (0, import_database.getDb)().exec(
|
|
31
|
+
"SELECT i.title, p.project_path FROM plan_items i JOIN plans p ON p.uid = i.plan_uid WHERE i.uid = ?",
|
|
32
|
+
[itemUid]
|
|
33
|
+
)[0]?.values[0];
|
|
34
|
+
if (!row || row[1] !== projectRoot || claims.length === 0) continue;
|
|
35
|
+
const item = { title: String(row[0]) };
|
|
36
|
+
const ws = `task:${itemUid}`;
|
|
37
|
+
const forged = claims.some((c) => c.forged);
|
|
38
|
+
out.push((0, import_awareness_signals.draft)(
|
|
39
|
+
"state-split",
|
|
40
|
+
forged ? "high" : "medium",
|
|
41
|
+
itemUid,
|
|
42
|
+
{ items: [itemUid], labels: { [ws]: item.title }, said: claims.map((c) => ({ name: c.name, status: c.status, ...c.forged ? { forged: true } : {} })) },
|
|
43
|
+
[ws],
|
|
44
|
+
`\u201C${item.title}\u201D: ${(0, import_item_status.atOnceWords)(claims)}.`
|
|
45
|
+
));
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
50
|
+
0 && (module.exports = {
|
|
51
|
+
stateSplitDrafts
|
|
52
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var test_runs_exports = {};
|
|
29
|
+
__export(test_runs_exports, {
|
|
30
|
+
RUNS_DIR: () => RUNS_DIR,
|
|
31
|
+
codeAt: () => codeAt,
|
|
32
|
+
myRunCount: () => myRunCount,
|
|
33
|
+
readTeammateRuns: () => readTeammateRuns,
|
|
34
|
+
writeRunRecord: () => writeRunRecord
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(test_runs_exports);
|
|
37
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
38
|
+
var import_node_path = __toESM(require("node:path"));
|
|
39
|
+
var import_node_child_process = require("node:child_process");
|
|
40
|
+
var import_confined_fs = require("../confined-fs");
|
|
41
|
+
var import_cloud_files = require("../cloud-files");
|
|
42
|
+
var import_grounding = require("../tests/grounding");
|
|
43
|
+
var import_teammate_runs = require("../tests/teammate-runs");
|
|
44
|
+
var import_run_record = require("./run-record");
|
|
45
|
+
var import_trust = require("./trust");
|
|
46
|
+
const RUNS_DIR = import_node_path.default.join(".codetrellis", "runs");
|
|
47
|
+
const FILE = /^([a-f0-9]{8,32})-(\d{1,9})\.yaml$/;
|
|
48
|
+
const MAX_FILES = 2e3;
|
|
49
|
+
const MAX_DIRTY = 500;
|
|
50
|
+
const git = (root, args) => {
|
|
51
|
+
try {
|
|
52
|
+
return (0, import_node_child_process.execFileSync)("git", ["-C", root, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], maxBuffer: 16 * 1024 * 1024 });
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
function filesIn(dir) {
|
|
58
|
+
try {
|
|
59
|
+
return import_node_fs.default.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && FILE.test(e.name)).slice(0, MAX_FILES).map((e) => {
|
|
60
|
+
const m = FILE.exec(e.name);
|
|
61
|
+
return { name: e.name, writer: m[1], counter: Number(m[2]) };
|
|
62
|
+
});
|
|
63
|
+
} catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function codeAt(projectRoot) {
|
|
68
|
+
const commit = git(projectRoot, ["rev-parse", "HEAD"])?.trim() || null;
|
|
69
|
+
if (!commit) return { commit: null, dirty: [] };
|
|
70
|
+
const out = git(projectRoot, ["status", "--porcelain=v1", "-z", "--untracked-files=all"]) ?? "";
|
|
71
|
+
const dirty = [];
|
|
72
|
+
const parts = out.split("\0");
|
|
73
|
+
for (let i = 0; i < parts.length && dirty.length < MAX_DIRTY; i++) {
|
|
74
|
+
const entry = parts[i];
|
|
75
|
+
if (entry.length < 4) continue;
|
|
76
|
+
const file = entry.slice(3);
|
|
77
|
+
if (entry[0] === "R" || entry[0] === "C") i++;
|
|
78
|
+
if (!file.startsWith(".codetrellis/")) dirty.push(file);
|
|
79
|
+
}
|
|
80
|
+
return { commit, dirty };
|
|
81
|
+
}
|
|
82
|
+
function writeRunRecord(where, run) {
|
|
83
|
+
const dir = import_node_path.default.join(where.home, RUNS_DIR);
|
|
84
|
+
const mine = filesIn(dir).filter((f) => f.writer === where.me);
|
|
85
|
+
let counter = Math.max(0, ...mine.map((f) => f.counter)) + 1;
|
|
86
|
+
while (import_node_fs.default.existsSync(import_node_path.default.join(dir, `${where.me}-${counter}.yaml`))) counter++;
|
|
87
|
+
const { commit, dirty } = codeAt(where.projectRoot);
|
|
88
|
+
const record = {
|
|
89
|
+
writer: where.me,
|
|
90
|
+
name: where.name,
|
|
91
|
+
counter,
|
|
92
|
+
at: run.ranAt,
|
|
93
|
+
by: run.by,
|
|
94
|
+
commit,
|
|
95
|
+
dirty,
|
|
96
|
+
report: run.path,
|
|
97
|
+
totals: run.totals,
|
|
98
|
+
files: (0, import_run_record.runFilesOf)(run.cases.map((c) => ({ testFile: (0, import_grounding.testFileOf)(where.projectRoot, c), name: c.name, result: c.result, message: c.message })))
|
|
99
|
+
};
|
|
100
|
+
const signature = (0, import_trust.signRecord)(where.projectRoot, where.home, record, (0, import_run_record.runRecordBytes)(record));
|
|
101
|
+
const file = (0, import_confined_fs.writeFileWithin)(where.home, import_node_path.default.join(dir, `${where.me}-${counter}.yaml`), (0, import_run_record.serializeRunRecord)(record, signature), "test-run record");
|
|
102
|
+
for (const f of mine) {
|
|
103
|
+
try {
|
|
104
|
+
(0, import_confined_fs.removeWithin)(where.home, import_node_path.default.join(dir, f.name), {}, "test-run record");
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return file;
|
|
109
|
+
}
|
|
110
|
+
function readTeammateRuns(projectRoot, home, me) {
|
|
111
|
+
const dir = import_node_path.default.join(home, RUNS_DIR);
|
|
112
|
+
const known = (0, import_teammate_runs.knownRunCounters)(projectRoot);
|
|
113
|
+
const newest = /* @__PURE__ */ new Map();
|
|
114
|
+
for (const f of filesIn(dir)) {
|
|
115
|
+
if (f.writer === me) continue;
|
|
116
|
+
const at = newest.get(f.writer);
|
|
117
|
+
if (!at || f.counter > at.counter) newest.set(f.writer, f);
|
|
118
|
+
}
|
|
119
|
+
let added = 0;
|
|
120
|
+
let ctx = null;
|
|
121
|
+
for (const [writer, f] of newest) {
|
|
122
|
+
if ((known.get(writer) ?? 0) >= f.counter) continue;
|
|
123
|
+
const file = import_node_path.default.join(dir, f.name);
|
|
124
|
+
if ((0, import_cloud_files.isPlaceholder)(file)) continue;
|
|
125
|
+
let text;
|
|
126
|
+
try {
|
|
127
|
+
text = (0, import_confined_fs.readTextWithin)(home, file, "test-run record");
|
|
128
|
+
} catch {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const parsed = (0, import_run_record.parseRunRecord)(text);
|
|
132
|
+
if (!("record" in parsed)) continue;
|
|
133
|
+
const r = parsed.record;
|
|
134
|
+
if (r.writer !== writer || r.counter !== f.counter) continue;
|
|
135
|
+
ctx ??= (0, import_trust.checkContext)(projectRoot);
|
|
136
|
+
const v = (0, import_trust.verifyTaskRecord)(r, parsed.signed, ctx);
|
|
137
|
+
(0, import_teammate_runs.putTeammateRun)(projectRoot, {
|
|
138
|
+
writer,
|
|
139
|
+
counter: r.counter,
|
|
140
|
+
name: v.verified ? v.who : r.name,
|
|
141
|
+
by: r.by,
|
|
142
|
+
commit: r.commit,
|
|
143
|
+
dirty: r.dirty,
|
|
144
|
+
at: r.at,
|
|
145
|
+
report: r.report,
|
|
146
|
+
totals: r.totals,
|
|
147
|
+
files: r.files,
|
|
148
|
+
verdict: v.verified ? { verified: true, how: v.how, who: v.who } : { verified: false, why: v.why }
|
|
149
|
+
});
|
|
150
|
+
added++;
|
|
151
|
+
}
|
|
152
|
+
return added;
|
|
153
|
+
}
|
|
154
|
+
function myRunCount(home, me) {
|
|
155
|
+
return home ? filesIn(import_node_path.default.join(home, RUNS_DIR)).filter((f) => f.writer === me).length : 0;
|
|
156
|
+
}
|
|
157
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
158
|
+
0 && (module.exports = {
|
|
159
|
+
RUNS_DIR,
|
|
160
|
+
codeAt,
|
|
161
|
+
myRunCount,
|
|
162
|
+
readTeammateRuns,
|
|
163
|
+
writeRunRecord
|
|
164
|
+
});
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var trust_exports = {};
|
|
29
|
+
__export(trust_exports, {
|
|
30
|
+
KEYS_DIR: () => KEYS_DIR,
|
|
31
|
+
checkContext: () => checkContext,
|
|
32
|
+
decideKey: () => decideKey,
|
|
33
|
+
deviceKey: () => deviceKey,
|
|
34
|
+
forgetVerdicts: () => forgetVerdicts,
|
|
35
|
+
introduceDeviceKey: () => introduceDeviceKey,
|
|
36
|
+
listTeammateKeys: () => listTeammateKeys,
|
|
37
|
+
readKeyIntroductions: () => readKeyIntroductions,
|
|
38
|
+
signRecord: () => signRecord,
|
|
39
|
+
signingWay: () => signingWay,
|
|
40
|
+
verifyTaskRecord: () => verifyTaskRecord
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(trust_exports);
|
|
43
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
44
|
+
var import_node_path = __toESM(require("node:path"));
|
|
45
|
+
var import_node_crypto = __toESM(require("node:crypto"));
|
|
46
|
+
var import_node_child_process = require("node:child_process");
|
|
47
|
+
var import_database = require("../database");
|
|
48
|
+
var import_persistence = require("../persistence");
|
|
49
|
+
var import_confined_fs = require("../confined-fs");
|
|
50
|
+
var import_signed_approvals = require("../signed-approvals");
|
|
51
|
+
var import_signing = require("./signing");
|
|
52
|
+
var import_cloud_files = require("../cloud-files");
|
|
53
|
+
const KEYS_DIR = import_node_path.default.join(".codetrellis", "keys");
|
|
54
|
+
const MAX_KEY_FILES = 500;
|
|
55
|
+
function deviceKey() {
|
|
56
|
+
const v = (0, import_database.getDb)().exec("SELECT public_key, private_key, fingerprint FROM task_record_device_key WHERE id = 1")[0]?.values[0];
|
|
57
|
+
if (v) return { publicKey: String(v[0]), privateKey: String(v[1]), fingerprint: String(v[2]) };
|
|
58
|
+
const k = (0, import_signing.makeDeviceKey)();
|
|
59
|
+
(0, import_database.getDb)().run(
|
|
60
|
+
"INSERT OR IGNORE INTO task_record_device_key (id, public_key, private_key, fingerprint, created_at) VALUES (1, ?, ?, ?, ?)",
|
|
61
|
+
[k.publicKey, k.privateKey, k.fingerprint, Date.now()]
|
|
62
|
+
);
|
|
63
|
+
(0, import_persistence.markDirty)();
|
|
64
|
+
return deviceKey();
|
|
65
|
+
}
|
|
66
|
+
const gitSigningAllowed = () => process.env.CODETRELLIS_GIT_SIGN_RECORDS !== "0";
|
|
67
|
+
function signingWay(projectRoot) {
|
|
68
|
+
const setup = gitSigningAllowed() ? (0, import_signed_approvals.signingSetup)(projectRoot) : null;
|
|
69
|
+
if (setup?.canSign) {
|
|
70
|
+
return { how: "git", as: setup.signer, says: `Records written here are signed with your git SSH key, as ${setup.signer}. Teammates check them against git's allowed signers, as they do signed commits.` };
|
|
71
|
+
}
|
|
72
|
+
const k = deviceKey();
|
|
73
|
+
return {
|
|
74
|
+
how: "device",
|
|
75
|
+
as: k.fingerprint,
|
|
76
|
+
says: `Records written here are signed with this device's own key (${(0, import_signing.shortFingerprint)(k.fingerprint)}\u2026). Teammates trust it once, in their Settings, after checking that fingerprint with you.`
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function signRecord(projectRoot, home, record, bytes) {
|
|
80
|
+
const setup = gitSigningAllowed() ? (0, import_signed_approvals.signingSetup)(projectRoot) : null;
|
|
81
|
+
if (setup?.canSign) {
|
|
82
|
+
try {
|
|
83
|
+
const value = (0, import_node_child_process.execFileSync)("ssh-keygen", ["-Y", "sign", "-f", setup.keyFile, "-n", import_signing.RECORD_NAMESPACE], {
|
|
84
|
+
input: bytes,
|
|
85
|
+
encoding: "utf-8",
|
|
86
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
87
|
+
timeout: 15e3
|
|
88
|
+
});
|
|
89
|
+
return { how: "git", signer: setup.signer, value: value.trim() };
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.warn("[TaskRecords] git could not sign a record; the device key signs it:", err.message.split("\n")[0]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const key = deviceKey();
|
|
95
|
+
introduceDeviceKey(home, record.writer, record.name, key);
|
|
96
|
+
return (0, import_signing.signWithDevice)(key, bytes);
|
|
97
|
+
}
|
|
98
|
+
function introduceDeviceKey(projectRoot, writer, name, key) {
|
|
99
|
+
const rel = import_node_path.default.join(KEYS_DIR, (0, import_signing.keyFileName)(writer));
|
|
100
|
+
const text = (0, import_signing.serializeKeyIntroduction)({ writer, name, publicKey: key.publicKey, fingerprint: key.fingerprint });
|
|
101
|
+
try {
|
|
102
|
+
if ((0, import_confined_fs.readTextWithin)(projectRoot, rel, "device key") === text) return;
|
|
103
|
+
} catch {
|
|
104
|
+
}
|
|
105
|
+
(0, import_confined_fs.writeFileWithin)(projectRoot, rel, text, "device key");
|
|
106
|
+
}
|
|
107
|
+
function readKeyIntroductions(projectRoot, me) {
|
|
108
|
+
const dir = import_node_path.default.join(projectRoot, KEYS_DIR);
|
|
109
|
+
let names;
|
|
110
|
+
try {
|
|
111
|
+
names = import_node_fs.default.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && /^[a-f0-9]{8,32}\.yaml$/.test(e.name)).map((e) => e.name).slice(0, MAX_KEY_FILES);
|
|
112
|
+
} catch {
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
let added = 0;
|
|
116
|
+
for (const name of names) {
|
|
117
|
+
const writer = name.slice(0, -".yaml".length);
|
|
118
|
+
if (writer === me) continue;
|
|
119
|
+
if ((0, import_cloud_files.isPlaceholder)(import_node_path.default.join(dir, name))) continue;
|
|
120
|
+
let text;
|
|
121
|
+
try {
|
|
122
|
+
text = (0, import_confined_fs.readTextWithin)(projectRoot, import_node_path.default.join(KEYS_DIR, name), "device key");
|
|
123
|
+
} catch {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const parsed = (0, import_signing.parseKeyIntroduction)(text, writer);
|
|
127
|
+
if (!("key" in parsed)) continue;
|
|
128
|
+
const k = parsed.key;
|
|
129
|
+
if ((0, import_database.getDb)().exec("SELECT 1 FROM task_record_keys WHERE writer = ? AND fingerprint = ?", [k.writer, k.fingerprint])[0]?.values[0]) continue;
|
|
130
|
+
(0, import_database.getDb)().run(
|
|
131
|
+
`INSERT INTO task_record_keys (writer, fingerprint, public_key, name, project_root, state, first_seen) VALUES (?, ?, ?, ?, ?, 'new', ?)`,
|
|
132
|
+
[k.writer, k.fingerprint, k.publicKey, k.name, projectRoot, Date.now()]
|
|
133
|
+
);
|
|
134
|
+
added++;
|
|
135
|
+
}
|
|
136
|
+
if (added) (0, import_persistence.markDirty)();
|
|
137
|
+
return added;
|
|
138
|
+
}
|
|
139
|
+
function rowToKey(v, trustedWriters) {
|
|
140
|
+
const writer = String(v[0]);
|
|
141
|
+
const state = String(v[3]);
|
|
142
|
+
return {
|
|
143
|
+
writer,
|
|
144
|
+
name: String(v[1]),
|
|
145
|
+
fingerprint: String(v[2]),
|
|
146
|
+
short: (0, import_signing.shortFingerprint)(String(v[2])),
|
|
147
|
+
state,
|
|
148
|
+
firstSeen: Number(v[4]),
|
|
149
|
+
decidedAt: v[5] == null ? null : Number(v[5]),
|
|
150
|
+
decidedBy: v[6] == null ? null : String(v[6]),
|
|
151
|
+
replaces: state !== "trusted" && trustedWriters.has(writer)
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function listTeammateKeys(roots) {
|
|
155
|
+
const marks = roots.map(() => "?").join(", ");
|
|
156
|
+
const rows = (0, import_database.getDb)().exec(
|
|
157
|
+
`SELECT writer, name, fingerprint, state, first_seen, decided_at, decided_by FROM task_record_keys
|
|
158
|
+
WHERE project_root IN (${marks}) OR writer IN (SELECT writer FROM task_record_keys WHERE project_root IN (${marks}))
|
|
159
|
+
ORDER BY CASE state WHEN 'new' THEN 0 WHEN 'trusted' THEN 1 ELSE 2 END, name, writer`,
|
|
160
|
+
[...roots, ...roots]
|
|
161
|
+
)[0]?.values ?? [];
|
|
162
|
+
const trusted = new Set(rows.filter((r) => r[3] === "trusted").map((r) => String(r[0])));
|
|
163
|
+
return rows.map((r) => rowToKey(r, trusted));
|
|
164
|
+
}
|
|
165
|
+
function decideKey(writer, fingerprint, trust, by) {
|
|
166
|
+
const known = (0, import_database.getDb)().exec("SELECT 1 FROM task_record_keys WHERE writer = ? AND fingerprint = ?", [writer, fingerprint])[0]?.values[0];
|
|
167
|
+
if (!known) return null;
|
|
168
|
+
(0, import_database.getDb)().run(
|
|
169
|
+
"UPDATE task_record_keys SET state = ?, decided_at = ?, decided_by = ? WHERE writer = ? AND fingerprint = ?",
|
|
170
|
+
[trust ? "trusted" : "refused", Date.now(), by, writer, fingerprint]
|
|
171
|
+
);
|
|
172
|
+
(0, import_persistence.markDirty)();
|
|
173
|
+
verdicts.clear();
|
|
174
|
+
const rows = (0, import_database.getDb)().exec(
|
|
175
|
+
"SELECT writer, name, fingerprint, state, first_seen, decided_at, decided_by FROM task_record_keys WHERE writer = ?",
|
|
176
|
+
[writer]
|
|
177
|
+
)[0]?.values ?? [];
|
|
178
|
+
const trusted = new Set(rows.filter((r) => r[3] === "trusted").map((r) => String(r[0])));
|
|
179
|
+
const row = rows.find((r) => r[2] === fingerprint);
|
|
180
|
+
return row ? rowToKey(row, trusted) : null;
|
|
181
|
+
}
|
|
182
|
+
function checkContext(projectRoot) {
|
|
183
|
+
const allowed = (0, import_signed_approvals.signingSetup)(projectRoot).allowedSigners;
|
|
184
|
+
let stamp = "none";
|
|
185
|
+
if (allowed) {
|
|
186
|
+
try {
|
|
187
|
+
const s = import_node_fs.default.statSync(allowed);
|
|
188
|
+
stamp = `${s.mtimeMs}:${s.size}`;
|
|
189
|
+
} catch {
|
|
190
|
+
stamp = "missing";
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return { allowedSigners: allowed, allowedStamp: stamp };
|
|
194
|
+
}
|
|
195
|
+
const verdicts = /* @__PURE__ */ new Map();
|
|
196
|
+
const MAX_VERDICTS = 2e4;
|
|
197
|
+
function verifyTaskRecord(record, signed, ctx) {
|
|
198
|
+
const sig = signed.signature;
|
|
199
|
+
if (!sig) return { verified: false, why: "it is not signed" };
|
|
200
|
+
const key = import_node_crypto.default.createHash("sha256").update(`${record.writer}
|
|
201
|
+
${signed.bytes}
|
|
202
|
+
${JSON.stringify(sig)}
|
|
203
|
+
${ctx.allowedStamp}`).digest("hex");
|
|
204
|
+
const cached = verdicts.get(key);
|
|
205
|
+
if (cached) return cached;
|
|
206
|
+
const verdict = check(record, signed.bytes, sig, ctx);
|
|
207
|
+
if (verdicts.size >= MAX_VERDICTS) verdicts.clear();
|
|
208
|
+
verdicts.set(key, verdict);
|
|
209
|
+
return verdict;
|
|
210
|
+
}
|
|
211
|
+
function check(record, bytes, sig, ctx) {
|
|
212
|
+
if (sig.how === "git") {
|
|
213
|
+
const out = (0, import_signed_approvals.verifyRecord)(bytes, sig.value, sig.signer, ctx.allowedSigners, import_signing.RECORD_NAMESPACE);
|
|
214
|
+
return out.ok ? { verified: true, how: "git", who: sig.signer } : { verified: false, why: out.reason };
|
|
215
|
+
}
|
|
216
|
+
const v = (0, import_database.getDb)().exec(
|
|
217
|
+
"SELECT public_key, name, state FROM task_record_keys WHERE writer = ? AND fingerprint = ?",
|
|
218
|
+
[record.writer, sig.key]
|
|
219
|
+
)[0]?.values[0];
|
|
220
|
+
if (!v) return { verified: false, why: `it is signed with a device key (${(0, import_signing.shortFingerprint)(sig.key)}\u2026) this project has not introduced` };
|
|
221
|
+
const [publicKey, name, state] = [String(v[0]), String(v[1]), String(v[2])];
|
|
222
|
+
if (state === "refused") return { verified: false, why: `it is signed with ${name}'s device key, which you refused` };
|
|
223
|
+
if (state !== "trusted") return { verified: false, why: `it is signed with ${name}'s device key, which you have not trusted yet` };
|
|
224
|
+
if (!(0, import_signing.verifyWithDevice)(publicKey, bytes, sig.value)) return { verified: false, why: `its signature does not match ${name}'s device key: it was changed after it was signed` };
|
|
225
|
+
return { verified: true, how: "device", who: name };
|
|
226
|
+
}
|
|
227
|
+
function forgetVerdicts() {
|
|
228
|
+
verdicts.clear();
|
|
229
|
+
}
|
|
230
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
231
|
+
0 && (module.exports = {
|
|
232
|
+
KEYS_DIR,
|
|
233
|
+
checkContext,
|
|
234
|
+
decideKey,
|
|
235
|
+
deviceKey,
|
|
236
|
+
forgetVerdicts,
|
|
237
|
+
introduceDeviceKey,
|
|
238
|
+
listTeammateKeys,
|
|
239
|
+
readKeyIntroductions,
|
|
240
|
+
signRecord,
|
|
241
|
+
signingWay,
|
|
242
|
+
verifyTaskRecord
|
|
243
|
+
});
|