codetrellis 0.0.0-stage → 0.3.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 +41 -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/cli-install.js +249 -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/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/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 +275 -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 +209 -0
- package/src/cli/conformity.js +106 -0
- package/src/cli/desktop.js +91 -0
- package/src/cli/main.js +411 -0
- package/src/cli/pipeline.js +109 -0
- package/src/cli/plan-verbs.js +259 -0
- package/src/cli/review-adapters.js +220 -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 +360 -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,324 @@
|
|
|
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 settings_service_exports = {};
|
|
29
|
+
__export(settings_service_exports, {
|
|
30
|
+
SettingsError: () => SettingsError,
|
|
31
|
+
getAuthorKey: () => getAuthorKey,
|
|
32
|
+
getSettings: () => getSettings,
|
|
33
|
+
maybeSeedIdentityFromGit: () => maybeSeedIdentityFromGit,
|
|
34
|
+
mergeWithDefaults: () => mergeWithDefaults,
|
|
35
|
+
readGitIdentity: () => readGitIdentity,
|
|
36
|
+
resetSettingsCache: () => resetSettingsCache,
|
|
37
|
+
settingsPatchProblem: () => settingsPatchProblem,
|
|
38
|
+
updateSettings: () => updateSettings
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(settings_service_exports);
|
|
41
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
42
|
+
var import_node_path = __toESM(require("node:path"));
|
|
43
|
+
var import_node_child_process = require("node:child_process");
|
|
44
|
+
var import_types = require("../../shared/types");
|
|
45
|
+
var import_persistence = require("./persistence");
|
|
46
|
+
var import_peer_capabilities = require("./peer-capabilities");
|
|
47
|
+
let cached = null;
|
|
48
|
+
function getSettingsPath() {
|
|
49
|
+
return import_node_path.default.join((0, import_persistence.getSettingsDir)(), "settings.json");
|
|
50
|
+
}
|
|
51
|
+
function getSettings() {
|
|
52
|
+
if (cached) return cached;
|
|
53
|
+
const filePath = getSettingsPath();
|
|
54
|
+
if (!import_node_fs.default.existsSync(filePath)) {
|
|
55
|
+
cached = { ...import_types.DEFAULT_SETTINGS };
|
|
56
|
+
return cached;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const raw = JSON.parse(import_node_fs.default.readFileSync(filePath, "utf-8"));
|
|
60
|
+
cached = mergeWithDefaults(raw);
|
|
61
|
+
return cached;
|
|
62
|
+
} catch (err) {
|
|
63
|
+
console.warn("[Settings] Failed to read settings.json \u2014 using defaults:", err);
|
|
64
|
+
cached = { ...import_types.DEFAULT_SETTINGS };
|
|
65
|
+
return cached;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function settingsPatchProblem(patch) {
|
|
69
|
+
if (patch === null || typeof patch !== "object" || Array.isArray(patch)) return "settings must be an object";
|
|
70
|
+
const p = patch;
|
|
71
|
+
const section = (name) => {
|
|
72
|
+
const v = p[name];
|
|
73
|
+
if (v === void 0) return null;
|
|
74
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) return `${name} must be an object`;
|
|
75
|
+
return v;
|
|
76
|
+
};
|
|
77
|
+
const checks = [
|
|
78
|
+
["identity.displayName", (v) => typeof v === "string", "text"],
|
|
79
|
+
["identity.email", (v) => typeof v === "string", "text"],
|
|
80
|
+
["mcp.port", (v) => Number.isInteger(v) && v >= 1024 && v <= 65535, "a port from 1024 to 65535"],
|
|
81
|
+
["mcp.autodetectOnCollision", (v) => typeof v === "boolean", "true or false"],
|
|
82
|
+
[
|
|
83
|
+
"mcp.capabilities",
|
|
84
|
+
(v) => Array.isArray(v) && v.every((c) => typeof c === "string" && import_peer_capabilities.ALL_CAPABILITIES.includes(c)),
|
|
85
|
+
`a list of: ${import_peer_capabilities.ALL_CAPABILITIES.join(", ")}`
|
|
86
|
+
],
|
|
87
|
+
["mcp.projectScope", (v) => v === "opened" || v === "anywhere", "opened or anywhere"],
|
|
88
|
+
["mcp.acceptLocalApiChanges", (v) => typeof v === "boolean", "true or false"],
|
|
89
|
+
["plans.defaultVisibility", (v) => v === "shared" || v === "local", "shared or local"],
|
|
90
|
+
["plans.attachmentLocation", (v) => v === "project" || v === "user", "project or user"],
|
|
91
|
+
["data.dataDirOverride", (v) => typeof v === "string", "text"],
|
|
92
|
+
["data.personalSyncPath", (v) => typeof v === "string", "text"],
|
|
93
|
+
["data.personalSyncMode", (v) => ["none", "selective", "full"].includes(v), "none, selective or full"],
|
|
94
|
+
["device.deviceName", (v) => typeof v === "string", "text"],
|
|
95
|
+
["device.advertise", (v) => typeof v === "boolean", "true or false"],
|
|
96
|
+
["device.exposeMobileApi", (v) => typeof v === "boolean", "true or false"],
|
|
97
|
+
["device.shareAudio", (v) => typeof v === "boolean", "true or false"],
|
|
98
|
+
["device.mobileApiPort", (v) => Number.isInteger(v) && v >= 1024 && v <= 65535, "a port from 1024 to 65535"],
|
|
99
|
+
["power.preventLidCloseSleep", (v) => typeof v === "boolean", "true or false"],
|
|
100
|
+
["power.onlyWhenOnAC", (v) => typeof v === "boolean", "true or false"],
|
|
101
|
+
["webhooks.allowedHosts", (v) => Array.isArray(v) && v.every((h) => typeof h === "string"), "a list of host names"],
|
|
102
|
+
["webhooks.allowLoopback", (v) => typeof v === "boolean", "true or false"],
|
|
103
|
+
["updates.autoCheck", (v) => typeof v === "boolean", "true or false"],
|
|
104
|
+
["git.keepRemotesCurrent", (v) => typeof v === "boolean", "true or false"],
|
|
105
|
+
["git.everyMinutes", (v) => import_types.FETCH_INTERVAL_CHOICES.includes(v), `${import_types.FETCH_INTERVAL_CHOICES.join(", ")} minutes`],
|
|
106
|
+
["data.retentionDays", (v) => import_types.RETENTION_CHOICES.includes(v), "14, 30, 90 or 365 days, or null to keep everything"]
|
|
107
|
+
];
|
|
108
|
+
for (const name of ["identity", "mcp", "plans", "data", "device", "power", "webhooks", "updates", "git"]) {
|
|
109
|
+
const sec = section(name);
|
|
110
|
+
if (typeof sec === "string") return sec;
|
|
111
|
+
}
|
|
112
|
+
for (const [dotted, ok, want] of checks) {
|
|
113
|
+
const [sec, key] = dotted.split(".");
|
|
114
|
+
const v = p[sec]?.[key];
|
|
115
|
+
if (v !== void 0 && !ok(v)) return `${dotted} must be ${want}`;
|
|
116
|
+
}
|
|
117
|
+
const triggers = p.power?.triggers;
|
|
118
|
+
if (triggers !== void 0) {
|
|
119
|
+
if (triggers === null || typeof triggers !== "object" || Array.isArray(triggers)) return "power.triggers must be an object";
|
|
120
|
+
for (const k of ["whileMobileConnected", "whileAgentActive", "always"]) {
|
|
121
|
+
if (triggers[k] !== void 0 && typeof triggers[k] !== "boolean") return `power.triggers.${k} must be true or false`;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (p.firstRunComplete !== void 0 && typeof p.firstRunComplete !== "boolean") return "firstRunComplete must be true or false";
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
class SettingsError extends Error {
|
|
128
|
+
}
|
|
129
|
+
function updateSettings(patch) {
|
|
130
|
+
const problem = settingsPatchProblem(patch);
|
|
131
|
+
if (problem) throw new SettingsError(problem);
|
|
132
|
+
const current = getSettings();
|
|
133
|
+
const next = {
|
|
134
|
+
identity: { ...current.identity, ...patch.identity ?? {} },
|
|
135
|
+
mcp: { ...current.mcp, ...patch.mcp ?? {} },
|
|
136
|
+
plans: { ...current.plans, ...patch.plans ?? {} },
|
|
137
|
+
data: { ...current.data, ...patch.data ?? {} },
|
|
138
|
+
device: { ...current.device, ...patch.device ?? {} },
|
|
139
|
+
power: {
|
|
140
|
+
...current.power,
|
|
141
|
+
...patch.power ?? {},
|
|
142
|
+
// triggers is a nested object — preserve unspecified flags
|
|
143
|
+
// instead of letting a partial { triggers: { always: true } }
|
|
144
|
+
// patch wipe whileMobileConnected / whileAgentActive.
|
|
145
|
+
triggers: {
|
|
146
|
+
...current.power.triggers,
|
|
147
|
+
...patch.power?.triggers ?? {}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
webhooks: {
|
|
151
|
+
...current.webhooks,
|
|
152
|
+
...patch.webhooks ?? {},
|
|
153
|
+
// Replace rather than merge: removing a host must actually remove it.
|
|
154
|
+
allowedHosts: Array.isArray(patch.webhooks?.allowedHosts) ? patch.webhooks.allowedHosts : current.webhooks.allowedHosts
|
|
155
|
+
},
|
|
156
|
+
updates: {
|
|
157
|
+
autoCheck: typeof patch.updates?.autoCheck === "boolean" ? patch.updates.autoCheck : current.updates.autoCheck
|
|
158
|
+
},
|
|
159
|
+
git: { ...current.git, ...patch.git ?? {} },
|
|
160
|
+
firstRunComplete: patch.firstRunComplete ?? current.firstRunComplete,
|
|
161
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
162
|
+
};
|
|
163
|
+
if (next.mcp.port < 1024 || next.mcp.port > 65535) {
|
|
164
|
+
next.mcp.port = import_types.DEFAULT_SETTINGS.mcp.port;
|
|
165
|
+
}
|
|
166
|
+
next.webhooks.allowedHosts = [...new Set(
|
|
167
|
+
(next.webhooks.allowedHosts ?? []).filter((h) => typeof h === "string").map((h) => h.trim().toLowerCase()).filter((h) => h.length > 0 && h.length <= 253 && !h.includes("*") && !h.includes("/"))
|
|
168
|
+
)];
|
|
169
|
+
cached = next;
|
|
170
|
+
saveSettings(next);
|
|
171
|
+
return next;
|
|
172
|
+
}
|
|
173
|
+
function readGitIdentity(projectPath) {
|
|
174
|
+
const cwd = projectPath && import_node_fs.default.existsSync(projectPath) ? projectPath : process.cwd();
|
|
175
|
+
const safeRun = (args) => {
|
|
176
|
+
try {
|
|
177
|
+
return (0, import_node_child_process.execSync)(`git config --get ${args}`, {
|
|
178
|
+
cwd,
|
|
179
|
+
encoding: "utf-8",
|
|
180
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
181
|
+
}).trim();
|
|
182
|
+
} catch {
|
|
183
|
+
return "";
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
return {
|
|
187
|
+
name: safeRun("user.name"),
|
|
188
|
+
email: safeRun("user.email")
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function getAuthorKey(role = "human") {
|
|
192
|
+
const { email } = getSettings().identity;
|
|
193
|
+
return email || role;
|
|
194
|
+
}
|
|
195
|
+
function maybeSeedIdentityFromGit(projectPath) {
|
|
196
|
+
const current = getSettings();
|
|
197
|
+
const haveEmail = !!current.identity.email;
|
|
198
|
+
const haveDisplayName = !!current.identity.displayName;
|
|
199
|
+
if (haveEmail && haveDisplayName) return false;
|
|
200
|
+
const gitIdentity = readGitIdentity(projectPath);
|
|
201
|
+
const patch = {};
|
|
202
|
+
if (!haveEmail && gitIdentity.email) {
|
|
203
|
+
patch.identity = { ...patch.identity ?? {}, email: gitIdentity.email };
|
|
204
|
+
}
|
|
205
|
+
if (!haveDisplayName && gitIdentity.name) {
|
|
206
|
+
patch.identity = { ...patch.identity ?? {}, displayName: gitIdentity.name };
|
|
207
|
+
}
|
|
208
|
+
if (!patch.identity) return false;
|
|
209
|
+
updateSettings(patch);
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
function resetSettingsCache() {
|
|
213
|
+
cached = null;
|
|
214
|
+
}
|
|
215
|
+
function saveSettings(settings) {
|
|
216
|
+
const filePath = getSettingsPath();
|
|
217
|
+
try {
|
|
218
|
+
const dir = (0, import_persistence.getSettingsDir)();
|
|
219
|
+
if (!import_node_fs.default.existsSync(dir)) {
|
|
220
|
+
import_node_fs.default.mkdirSync(dir, { recursive: true });
|
|
221
|
+
}
|
|
222
|
+
const tmpPath = `${filePath}.tmp`;
|
|
223
|
+
import_node_fs.default.writeFileSync(tmpPath, JSON.stringify(settings, null, 2));
|
|
224
|
+
import_node_fs.default.renameSync(tmpPath, filePath);
|
|
225
|
+
} catch (err) {
|
|
226
|
+
console.error("[Settings] Failed to save settings.json:", err);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function mergeWithDefaults(raw) {
|
|
230
|
+
if (!raw || typeof raw !== "object") return { ...import_types.DEFAULT_SETTINGS };
|
|
231
|
+
return {
|
|
232
|
+
identity: {
|
|
233
|
+
displayName: typeof raw?.identity?.displayName === "string" ? raw.identity.displayName : import_types.DEFAULT_SETTINGS.identity.displayName,
|
|
234
|
+
email: typeof raw?.identity?.email === "string" ? raw.identity.email : import_types.DEFAULT_SETTINGS.identity.email
|
|
235
|
+
},
|
|
236
|
+
mcp: {
|
|
237
|
+
port: typeof raw?.mcp?.port === "number" ? raw.mcp.port : import_types.DEFAULT_SETTINGS.mcp.port,
|
|
238
|
+
autodetectOnCollision: typeof raw?.mcp?.autodetectOnCollision === "boolean" ? raw.mcp.autodetectOnCollision : import_types.DEFAULT_SETTINGS.mcp.autodetectOnCollision,
|
|
239
|
+
// Phase 30. Validated against the real capability names rather than
|
|
240
|
+
// trusted: this list is what the authorisation gate reads, so a
|
|
241
|
+
// malformed settings file must not be able to widen it. An absent or
|
|
242
|
+
// invalid value leaves it undefined, which the gate reads as
|
|
243
|
+
// DEFAULT_GRANTS — the narrower answer.
|
|
244
|
+
// Spread rather than assigned, so an absent grant list stays ABSENT
|
|
245
|
+
// rather than becoming an explicit `undefined`. The gate reads absent
|
|
246
|
+
// as DEFAULT_GRANTS, and a key that exists with no value is a
|
|
247
|
+
// different thing from a key that was never written.
|
|
248
|
+
...Array.isArray(raw?.mcp?.capabilities) ? {
|
|
249
|
+
capabilities: raw.mcp.capabilities.filter(
|
|
250
|
+
(c) => typeof c === "string" && import_peer_capabilities.ALL_CAPABILITIES.includes(c)
|
|
251
|
+
)
|
|
252
|
+
} : {},
|
|
253
|
+
// An existing settings file predates this field, and the secure value
|
|
254
|
+
// is the default rather than the permissive one — so an upgrade
|
|
255
|
+
// CONFINES path-taking tools rather than leaving them open because
|
|
256
|
+
// nobody had an opinion yet.
|
|
257
|
+
projectScope: raw?.mcp?.projectScope === "anywhere" ? "anywhere" : "opened",
|
|
258
|
+
// Carried item 2b. Only an explicit false turns local API changes off;
|
|
259
|
+
// anything else (absent, malformed) leaves them on, as before.
|
|
260
|
+
...raw?.mcp?.acceptLocalApiChanges === false ? { acceptLocalApiChanges: false } : {}
|
|
261
|
+
},
|
|
262
|
+
plans: {
|
|
263
|
+
defaultVisibility: raw?.plans?.defaultVisibility === "local" ? "local" : import_types.DEFAULT_SETTINGS.plans.defaultVisibility,
|
|
264
|
+
attachmentLocation: raw?.plans?.attachmentLocation === "user" ? "user" : import_types.DEFAULT_SETTINGS.plans.attachmentLocation
|
|
265
|
+
},
|
|
266
|
+
data: {
|
|
267
|
+
dataDirOverride: typeof raw?.data?.dataDirOverride === "string" ? raw.data.dataDirOverride : import_types.DEFAULT_SETTINGS.data.dataDirOverride,
|
|
268
|
+
personalSyncPath: typeof raw?.data?.personalSyncPath === "string" ? raw.data.personalSyncPath : import_types.DEFAULT_SETTINGS.data.personalSyncPath,
|
|
269
|
+
personalSyncMode: ["none", "selective", "full"].includes(raw?.data?.personalSyncMode) ? raw.data.personalSyncMode : import_types.DEFAULT_SETTINGS.data.personalSyncMode,
|
|
270
|
+
retentionDays: import_types.RETENTION_CHOICES.includes(raw?.data?.retentionDays) ? raw.data.retentionDays : import_types.DEFAULT_SETTINGS.data.retentionDays
|
|
271
|
+
},
|
|
272
|
+
device: {
|
|
273
|
+
deviceName: typeof raw?.device?.deviceName === "string" ? raw.device.deviceName : import_types.DEFAULT_SETTINGS.device.deviceName,
|
|
274
|
+
advertise: typeof raw?.device?.advertise === "boolean" ? raw.device.advertise : import_types.DEFAULT_SETTINGS.device.advertise,
|
|
275
|
+
// Deliberately does NOT inherit from `advertise` for existing profiles.
|
|
276
|
+
// Someone who turned advertising on before these were separated was
|
|
277
|
+
// consenting to discovery, not to a 0.0.0.0 listener they were never
|
|
278
|
+
// shown. Defaulting to false makes them opt in explicitly.
|
|
279
|
+
exposeMobileApi: typeof raw?.device?.exposeMobileApi === "boolean" ? raw.device.exposeMobileApi : import_types.DEFAULT_SETTINGS.device.exposeMobileApi,
|
|
280
|
+
shareAudio: typeof raw?.device?.shareAudio === "boolean" ? raw.device.shareAudio : import_types.DEFAULT_SETTINGS.device.shareAudio,
|
|
281
|
+
mobileApiPort: typeof raw?.device?.mobileApiPort === "number" && raw.device.mobileApiPort > 0 ? raw.device.mobileApiPort : import_types.DEFAULT_SETTINGS.device.mobileApiPort
|
|
282
|
+
},
|
|
283
|
+
power: {
|
|
284
|
+
triggers: {
|
|
285
|
+
whileMobileConnected: typeof raw?.power?.triggers?.whileMobileConnected === "boolean" ? raw.power.triggers.whileMobileConnected : import_types.DEFAULT_SETTINGS.power.triggers.whileMobileConnected,
|
|
286
|
+
whileAgentActive: typeof raw?.power?.triggers?.whileAgentActive === "boolean" ? raw.power.triggers.whileAgentActive : import_types.DEFAULT_SETTINGS.power.triggers.whileAgentActive,
|
|
287
|
+
always: typeof raw?.power?.triggers?.always === "boolean" ? raw.power.triggers.always : import_types.DEFAULT_SETTINGS.power.triggers.always
|
|
288
|
+
},
|
|
289
|
+
preventLidCloseSleep: typeof raw?.power?.preventLidCloseSleep === "boolean" ? raw.power.preventLidCloseSleep : import_types.DEFAULT_SETTINGS.power.preventLidCloseSleep,
|
|
290
|
+
onlyWhenOnAC: typeof raw?.power?.onlyWhenOnAC === "boolean" ? raw.power.onlyWhenOnAC : import_types.DEFAULT_SETTINGS.power.onlyWhenOnAC
|
|
291
|
+
},
|
|
292
|
+
webhooks: {
|
|
293
|
+
// Normalised hard, because this list is what stands between a cloned
|
|
294
|
+
// repository and an outbound request from inside the user's network
|
|
295
|
+
// (Phase 19, finding 20). Anything that is not a plain non-empty string
|
|
296
|
+
// is dropped rather than coerced.
|
|
297
|
+
allowedHosts: Array.isArray(raw?.webhooks?.allowedHosts) ? [...new Set(
|
|
298
|
+
raw.webhooks.allowedHosts.filter((h) => typeof h === "string").map((h) => h.trim().toLowerCase()).filter((h) => h.length > 0 && h.length <= 253 && !h.includes("*") && !h.includes("/"))
|
|
299
|
+
)] : [...import_types.DEFAULT_SETTINGS.webhooks.allowedHosts],
|
|
300
|
+
allowLoopback: typeof raw?.webhooks?.allowLoopback === "boolean" ? raw.webhooks.allowLoopback : import_types.DEFAULT_SETTINGS.webhooks.allowLoopback
|
|
301
|
+
},
|
|
302
|
+
updates: {
|
|
303
|
+
autoCheck: typeof raw?.updates?.autoCheck === "boolean" ? raw.updates.autoCheck : import_types.DEFAULT_SETTINGS.updates.autoCheck
|
|
304
|
+
},
|
|
305
|
+
git: {
|
|
306
|
+
keepRemotesCurrent: typeof raw?.git?.keepRemotesCurrent === "boolean" ? raw.git.keepRemotesCurrent : import_types.DEFAULT_SETTINGS.git.keepRemotesCurrent,
|
|
307
|
+
everyMinutes: import_types.FETCH_INTERVAL_CHOICES.includes(raw?.git?.everyMinutes) ? raw.git.everyMinutes : import_types.DEFAULT_SETTINGS.git.everyMinutes
|
|
308
|
+
},
|
|
309
|
+
firstRunComplete: typeof raw?.firstRunComplete === "boolean" ? raw.firstRunComplete : import_types.DEFAULT_SETTINGS.firstRunComplete,
|
|
310
|
+
updatedAt: typeof raw?.updatedAt === "string" ? raw.updatedAt : ""
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
314
|
+
0 && (module.exports = {
|
|
315
|
+
SettingsError,
|
|
316
|
+
getAuthorKey,
|
|
317
|
+
getSettings,
|
|
318
|
+
maybeSeedIdentityFromGit,
|
|
319
|
+
mergeWithDefaults,
|
|
320
|
+
readGitIdentity,
|
|
321
|
+
resetSettingsCache,
|
|
322
|
+
settingsPatchProblem,
|
|
323
|
+
updateSettings
|
|
324
|
+
});
|
|
@@ -0,0 +1,172 @@
|
|
|
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 signal_breakpoints_exports = {};
|
|
19
|
+
__export(signal_breakpoints_exports, {
|
|
20
|
+
SIGNAL_MARKER: () => SIGNAL_MARKER,
|
|
21
|
+
attemptOf: () => attemptOf,
|
|
22
|
+
enforceSignals: () => enforceSignals,
|
|
23
|
+
enforceSignalsForSession: () => enforceSignalsForSession,
|
|
24
|
+
releaseSettled: () => releaseSettled,
|
|
25
|
+
signalHeldResult: () => signalHeldResult,
|
|
26
|
+
signalHeldText: () => signalHeldText,
|
|
27
|
+
signalRules: () => signalRules,
|
|
28
|
+
signalSteerText: () => signalSteerText
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(signal_breakpoints_exports);
|
|
31
|
+
var import_node_crypto = require("node:crypto");
|
|
32
|
+
var import_database = require("./database");
|
|
33
|
+
var import_agent_event_log = require("./agent-event-log");
|
|
34
|
+
var import_session_service = require("./session-service");
|
|
35
|
+
var import_awareness_service = require("./awareness-service");
|
|
36
|
+
var import_breakpoint_service = require("./breakpoint-service");
|
|
37
|
+
var import_push_notification_service = require("./push-notification-service");
|
|
38
|
+
function signalRules(projectRoot) {
|
|
39
|
+
return (0, import_breakpoint_service.rowsOf)(`${import_breakpoint_service.ACTIVE_SELECT} AND b.kind = 'signal' AND b.project_root = ? ORDER BY b.created_at`, [projectRoot]).map(import_breakpoint_service.toBreakpointRow);
|
|
40
|
+
}
|
|
41
|
+
function holding(signals, rule) {
|
|
42
|
+
return signals.filter((s) => s.kind === rule.target && s.severity === "high" && s.state === "open");
|
|
43
|
+
}
|
|
44
|
+
function releaseSettled(projectRoot, signals = (0, import_awareness_service.listSignals)(projectRoot), now = Date.now()) {
|
|
45
|
+
const open = new Set(signals.filter((s) => s.severity === "high" && s.state === "open").map((s) => s.id));
|
|
46
|
+
const waiting = (0, import_breakpoint_service.rowsOf)(
|
|
47
|
+
`${import_breakpoint_service.HIT_SELECT} WHERE b.kind = 'signal' AND b.project_root = ? AND h.answered_at IS NULL AND h.signal_id IS NOT NULL`,
|
|
48
|
+
[projectRoot]
|
|
49
|
+
).map(import_breakpoint_service.toHitRow);
|
|
50
|
+
const released = [];
|
|
51
|
+
for (const hit of waiting) {
|
|
52
|
+
if (hit.signalId && open.has(hit.signalId)) continue;
|
|
53
|
+
const r = (0, import_breakpoint_service.answerHit)({ ref: hit.ref, decision: "continue", note: "The signal was answered in Awareness.", by: "CodeTrellis", byType: "system", now });
|
|
54
|
+
if (r) released.push(r);
|
|
55
|
+
}
|
|
56
|
+
return released;
|
|
57
|
+
}
|
|
58
|
+
function enforceSignals(projectRoot, caller, attempt, now = Date.now(), signalsOf = (root, ws) => (0, import_awareness_service.listSignals)(root, { workstream: ws })) {
|
|
59
|
+
if (!projectRoot || !caller.workstreamRoot) return { kind: "pass" };
|
|
60
|
+
let continued = null;
|
|
61
|
+
try {
|
|
62
|
+
const rules = signalRules(projectRoot);
|
|
63
|
+
if (!rules.length) return { kind: "pass" };
|
|
64
|
+
const mine = signalsOf(projectRoot, caller.workstreamRoot);
|
|
65
|
+
for (const rule of rules) {
|
|
66
|
+
for (const signal of holding(mine, rule)) {
|
|
67
|
+
const latest = (0, import_breakpoint_service.rowsOf)(
|
|
68
|
+
`${import_breakpoint_service.HIT_SELECT} WHERE h.breakpoint_id = ? AND h.signal_id = ? AND h.workstream_root = ? ORDER BY h.hit_at DESC LIMIT 1`,
|
|
69
|
+
[rule.id, signal.id, caller.workstreamRoot]
|
|
70
|
+
).map(import_breakpoint_service.toHitRow)[0];
|
|
71
|
+
if (!latest) {
|
|
72
|
+
const ref = `bp-${(0, import_node_crypto.randomBytes)(5).toString("hex")}`;
|
|
73
|
+
(0, import_database.getDb)().run(
|
|
74
|
+
`INSERT INTO breakpoint_hits (ref, breakpoint_id, tool, action, item_uid, path, breach, signal_id, agent, session_id, workstream_root, hit_at)
|
|
75
|
+
VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?)`,
|
|
76
|
+
[
|
|
77
|
+
ref,
|
|
78
|
+
rule.id,
|
|
79
|
+
attempt.tool,
|
|
80
|
+
attempt.action,
|
|
81
|
+
attempt.itemUid ?? "",
|
|
82
|
+
attempt.path ?? null,
|
|
83
|
+
signal.id,
|
|
84
|
+
caller.agent,
|
|
85
|
+
caller.sessionId,
|
|
86
|
+
caller.workstreamRoot,
|
|
87
|
+
now
|
|
88
|
+
]
|
|
89
|
+
);
|
|
90
|
+
const hit = (0, import_breakpoint_service.getHit)(ref);
|
|
91
|
+
(0, import_agent_event_log.recordBreakpointEvent)("breakpoint_hit", {
|
|
92
|
+
...(0, import_breakpoint_service.hitPayload)(hit),
|
|
93
|
+
breakpointId: rule.id,
|
|
94
|
+
signalKind: signal.kind,
|
|
95
|
+
signalSummary: signal.summary.slice(0, 300)
|
|
96
|
+
}, caller.agent);
|
|
97
|
+
void (0, import_push_notification_service.pushForBreakpoint)(hit).catch(() => {
|
|
98
|
+
});
|
|
99
|
+
return { kind: "paused", hit, signal, fresh: true };
|
|
100
|
+
}
|
|
101
|
+
if (latest.answeredAt === null) return { kind: "paused", hit: latest, signal, fresh: false };
|
|
102
|
+
if (latest.decision === "stop") return { kind: "stop", hit: latest, signal };
|
|
103
|
+
const untold = (0, import_breakpoint_service.rowsOf)("SELECT consumed_at FROM breakpoint_hits WHERE ref = ?", [latest.ref])[0]?.consumed_at === null;
|
|
104
|
+
if (untold) (0, import_database.getDb)().run("UPDATE breakpoint_hits SET consumed_at = ? WHERE ref = ?", [now, latest.ref]);
|
|
105
|
+
continued = { hit: latest, steer: untold ? latest.note : null };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
return { kind: "pass" };
|
|
110
|
+
}
|
|
111
|
+
return continued ? { kind: "continue", ...continued } : { kind: "pass" };
|
|
112
|
+
}
|
|
113
|
+
function attemptOf(tool, args) {
|
|
114
|
+
const call = (0, import_breakpoint_service.guardedCall)(tool, args);
|
|
115
|
+
if (!call) return null;
|
|
116
|
+
return { tool, action: call.actions[0].action, itemUid: call.itemUid };
|
|
117
|
+
}
|
|
118
|
+
function enforceSignalsForSession(projectRoot, sessionId, attempt, now = Date.now()) {
|
|
119
|
+
if (!projectRoot) return { kind: "pass" };
|
|
120
|
+
const session = (0, import_session_service.getActiveSessions)().find((s) => s.sessionId === sessionId);
|
|
121
|
+
if (!session?.workstreamRoot) return { kind: "pass" };
|
|
122
|
+
try {
|
|
123
|
+
releaseSettled(projectRoot);
|
|
124
|
+
} catch {
|
|
125
|
+
}
|
|
126
|
+
return enforceSignals(projectRoot, { agent: session.agentType ?? "mcp-agent", sessionId, workstreamRoot: session.workstreamRoot }, attempt, now);
|
|
127
|
+
}
|
|
128
|
+
const SIGNAL_MARKER = "\u2500\u2500 CodeTrellis breakpoint \u2500\u2500";
|
|
129
|
+
function signalHeldText(result) {
|
|
130
|
+
const h = result.hit;
|
|
131
|
+
const about = result.signal ? `a serious ${result.signal.kind} signal: ${result.signal.summary}` : "a serious signal";
|
|
132
|
+
const rule = h.breakpointNote ? ` Their note on the rule: ${h.breakpointNote}` : "";
|
|
133
|
+
if (result.kind === "stop") {
|
|
134
|
+
return [
|
|
135
|
+
SIGNAL_MARKER,
|
|
136
|
+
`A person answered the breakpoint on ${about} \u2014 stop. Nothing was done.${h.note ? ` Their answer: ${h.note}` : ""}`,
|
|
137
|
+
"Do not go on with work this signal touches while it is open. Tell the person what you will do instead."
|
|
138
|
+
].join("\n");
|
|
139
|
+
}
|
|
140
|
+
return [
|
|
141
|
+
SIGNAL_MARKER,
|
|
142
|
+
`paused: waiting for a decision. Your workstream is named in ${about}. A person asked to be asked before work goes on while a signal like this is open.${rule} Nothing was done.`,
|
|
143
|
+
`Call await_decision with ref "${h.ref}", calling it again while it says it is still waiting (this can take a long time; do not work around it). If they answer continue, make the same call again.`
|
|
144
|
+
].join("\n");
|
|
145
|
+
}
|
|
146
|
+
function signalHeldResult(result) {
|
|
147
|
+
const body = {
|
|
148
|
+
...result.kind === "paused" ? { paused: true, status: "paused: waiting for a decision" } : { stopped: true },
|
|
149
|
+
ref: result.hit.ref,
|
|
150
|
+
signal: result.signal ? { kind: result.signal.kind, summary: result.signal.summary } : null,
|
|
151
|
+
message: signalHeldText(result)
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
content: [{ type: "text", text: JSON.stringify(body, null, 2) }],
|
|
155
|
+
_meta: { summary: result.kind === "paused" ? `Paused at a breakpoint on a serious ${result.signal?.kind ?? ""} signal`.replace(" ", " ") : "Stopped at a signal breakpoint" }
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function signalSteerText(hit) {
|
|
159
|
+
return hit.note ? `A person answered the signal breakpoint (${hit.ref}): continue, with this steer: ${hit.note}` : null;
|
|
160
|
+
}
|
|
161
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
162
|
+
0 && (module.exports = {
|
|
163
|
+
SIGNAL_MARKER,
|
|
164
|
+
attemptOf,
|
|
165
|
+
enforceSignals,
|
|
166
|
+
enforceSignalsForSession,
|
|
167
|
+
releaseSettled,
|
|
168
|
+
signalHeldResult,
|
|
169
|
+
signalHeldText,
|
|
170
|
+
signalRules,
|
|
171
|
+
signalSteerText
|
|
172
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
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 signed_approval_record_exports = {};
|
|
19
|
+
__export(signed_approval_record_exports, {
|
|
20
|
+
NAMESPACE: () => NAMESPACE,
|
|
21
|
+
RECORD_KIND: () => RECORD_KIND,
|
|
22
|
+
canonicalStatement: () => canonicalStatement,
|
|
23
|
+
parseRecord: () => parseRecord,
|
|
24
|
+
recordYaml: () => recordYaml,
|
|
25
|
+
sha256: () => sha256
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(signed_approval_record_exports);
|
|
28
|
+
var import_node_crypto = require("node:crypto");
|
|
29
|
+
var import_yaml = require("yaml");
|
|
30
|
+
const NAMESPACE = "codetrellis-approval";
|
|
31
|
+
const RECORD_KIND = "codetrellis-approval";
|
|
32
|
+
const MAX_RECORD_BYTES = 16 * 1024;
|
|
33
|
+
const UID = /^[A-Za-z0-9-]{8,64}$/;
|
|
34
|
+
const EMAIL = /^[^\s<>@]{1,64}@[^\s<>@]{1,255}$/;
|
|
35
|
+
const SHA256 = /^[0-9a-f]{64}$/;
|
|
36
|
+
const sha256 = (text) => (0, import_node_crypto.createHash)("sha256").update(text, "utf-8").digest("hex");
|
|
37
|
+
function canonicalStatement(s) {
|
|
38
|
+
const sort = (v) => {
|
|
39
|
+
if (Array.isArray(v)) return v.map(sort);
|
|
40
|
+
if (v && typeof v === "object") {
|
|
41
|
+
return Object.fromEntries(Object.keys(v).sort().map((k) => [k, sort(v[k])]));
|
|
42
|
+
}
|
|
43
|
+
return v;
|
|
44
|
+
};
|
|
45
|
+
return JSON.stringify(sort(s));
|
|
46
|
+
}
|
|
47
|
+
function recordYaml(statement, signature) {
|
|
48
|
+
return (0, import_yaml.stringify)({ kind: RECORD_KIND, version: 1, statement: canonicalStatement(statement), signature: signature.trim() });
|
|
49
|
+
}
|
|
50
|
+
function parseRecord(content) {
|
|
51
|
+
if (Buffer.byteLength(content, "utf-8") > MAX_RECORD_BYTES) return { ok: false, reason: "the record is too large" };
|
|
52
|
+
let doc;
|
|
53
|
+
try {
|
|
54
|
+
doc = (0, import_yaml.parse)(content);
|
|
55
|
+
} catch {
|
|
56
|
+
return { ok: false, reason: "the record is not readable YAML" };
|
|
57
|
+
}
|
|
58
|
+
if (!doc || typeof doc !== "object") return { ok: false, reason: "the record is empty" };
|
|
59
|
+
const d = doc;
|
|
60
|
+
if (d.kind !== RECORD_KIND || d.version !== 1) return { ok: false, reason: "not an approval record this version reads" };
|
|
61
|
+
if (typeof d.statement !== "string" || typeof d.signature !== "string") return { ok: false, reason: "the record has no statement or no signature" };
|
|
62
|
+
if (!/^-----BEGIN SSH SIGNATURE-----\n[A-Za-z0-9+/=\n]+-----END SSH SIGNATURE-----\s*$/.test(d.signature.trim() + "\n")) {
|
|
63
|
+
return { ok: false, reason: "the signature is not an SSH signature" };
|
|
64
|
+
}
|
|
65
|
+
let s;
|
|
66
|
+
try {
|
|
67
|
+
s = JSON.parse(d.statement);
|
|
68
|
+
} catch {
|
|
69
|
+
return { ok: false, reason: "the statement is not JSON" };
|
|
70
|
+
}
|
|
71
|
+
const evidence = s.evidence;
|
|
72
|
+
const ok = s && typeof s === "object" && typeof s.uid === "string" && UID.test(s.uid) && typeof s.planUid === "string" && UID.test(s.planUid) && typeof s.itemUid === "string" && UID.test(s.itemUid) && typeof s.criterionUid === "string" && UID.test(s.criterionUid) && typeof s.criterionSha256 === "string" && SHA256.test(s.criterionSha256) && s.decision === "approved" && typeof s.signer === "string" && EMAIL.test(s.signer) && typeof s.at === "string" && !Number.isNaN(Date.parse(s.at)) && !!evidence && typeof evidence === "object" && !Array.isArray(evidence) && Object.entries(evidence).every(([k, v]) => UID.test(k) && (v === null || typeof v === "string" && SHA256.test(v)));
|
|
73
|
+
if (!ok) return { ok: false, reason: "the statement is missing a field or has one it should not" };
|
|
74
|
+
const statement = s;
|
|
75
|
+
if (canonicalStatement(statement) !== d.statement) return { ok: false, reason: "the statement is not in its signed form" };
|
|
76
|
+
return { ok: true, statement, text: d.statement, signature: d.signature.trim() + "\n" };
|
|
77
|
+
}
|
|
78
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
79
|
+
0 && (module.exports = {
|
|
80
|
+
NAMESPACE,
|
|
81
|
+
RECORD_KIND,
|
|
82
|
+
canonicalStatement,
|
|
83
|
+
parseRecord,
|
|
84
|
+
recordYaml,
|
|
85
|
+
sha256
|
|
86
|
+
});
|