groove-dev 0.27.93 → 0.27.94
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/moe-training/package.json +2 -1
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/api.js +17 -9
- package/node_modules/@groove-dev/daemon/src/process.js +2 -0
- package/node_modules/@groove-dev/gui/dist/assets/{index-VB4_k5Pz.js → index-B3GUKInH.js} +339 -339
- package/node_modules/@groove-dev/gui/dist/assets/{index-Bo6AeNmM.css → index-C1k-GuDg.css} +1 -1
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +2 -0
- package/node_modules/@groove-dev/gui/src/stores/groove.js +14 -10
- package/node_modules/@groove-dev/gui/src/views/agents.jsx +10 -68
- package/node_modules/base64-js/LICENSE +21 -0
- package/node_modules/base64-js/README.md +34 -0
- package/node_modules/base64-js/base64js.min.js +1 -0
- package/node_modules/base64-js/index.d.ts +3 -0
- package/node_modules/base64-js/index.js +150 -0
- package/node_modules/base64-js/package.json +47 -0
- package/node_modules/better-sqlite3/LICENSE +21 -0
- package/node_modules/better-sqlite3/README.md +99 -0
- package/node_modules/better-sqlite3/binding.gyp +38 -0
- package/node_modules/better-sqlite3/deps/common.gypi +68 -0
- package/node_modules/better-sqlite3/deps/copy.js +31 -0
- package/node_modules/better-sqlite3/deps/defines.gypi +41 -0
- package/node_modules/better-sqlite3/deps/download.sh +122 -0
- package/node_modules/better-sqlite3/deps/patches/1208.patch +15 -0
- package/node_modules/better-sqlite3/deps/sqlite3/sqlite3.c +268845 -0
- package/node_modules/better-sqlite3/deps/sqlite3/sqlite3.h +14335 -0
- package/node_modules/better-sqlite3/deps/sqlite3/sqlite3ext.h +739 -0
- package/node_modules/better-sqlite3/deps/sqlite3.gyp +80 -0
- package/node_modules/better-sqlite3/deps/test_extension.c +21 -0
- package/node_modules/better-sqlite3/lib/database.js +90 -0
- package/node_modules/better-sqlite3/lib/index.js +3 -0
- package/node_modules/better-sqlite3/lib/methods/aggregate.js +43 -0
- package/node_modules/better-sqlite3/lib/methods/backup.js +67 -0
- package/node_modules/better-sqlite3/lib/methods/function.js +31 -0
- package/node_modules/better-sqlite3/lib/methods/inspect.js +7 -0
- package/node_modules/better-sqlite3/lib/methods/pragma.js +12 -0
- package/node_modules/better-sqlite3/lib/methods/serialize.js +16 -0
- package/node_modules/better-sqlite3/lib/methods/table.js +189 -0
- package/node_modules/better-sqlite3/lib/methods/transaction.js +78 -0
- package/node_modules/better-sqlite3/lib/methods/wrappers.js +54 -0
- package/node_modules/better-sqlite3/lib/sqlite-error.js +20 -0
- package/node_modules/better-sqlite3/lib/util.js +12 -0
- package/node_modules/better-sqlite3/package.json +59 -0
- package/node_modules/better-sqlite3/src/addon.cpp +47 -0
- package/node_modules/better-sqlite3/src/better_sqlite3.cpp +74 -0
- package/node_modules/better-sqlite3/src/objects/backup.cpp +120 -0
- package/node_modules/better-sqlite3/src/objects/backup.hpp +36 -0
- package/node_modules/better-sqlite3/src/objects/database.cpp +417 -0
- package/node_modules/better-sqlite3/src/objects/database.hpp +103 -0
- package/node_modules/better-sqlite3/src/objects/statement-iterator.cpp +113 -0
- package/node_modules/better-sqlite3/src/objects/statement-iterator.hpp +50 -0
- package/node_modules/better-sqlite3/src/objects/statement.cpp +383 -0
- package/node_modules/better-sqlite3/src/objects/statement.hpp +58 -0
- package/node_modules/better-sqlite3/src/util/bind-map.cpp +73 -0
- package/node_modules/better-sqlite3/src/util/binder.cpp +193 -0
- package/node_modules/better-sqlite3/src/util/constants.cpp +172 -0
- package/node_modules/better-sqlite3/src/util/custom-aggregate.cpp +121 -0
- package/node_modules/better-sqlite3/src/util/custom-function.cpp +59 -0
- package/node_modules/better-sqlite3/src/util/custom-table.cpp +409 -0
- package/node_modules/better-sqlite3/src/util/data-converter.cpp +17 -0
- package/node_modules/better-sqlite3/src/util/data.cpp +194 -0
- package/node_modules/better-sqlite3/src/util/helpers.cpp +109 -0
- package/node_modules/better-sqlite3/src/util/macros.cpp +83 -0
- package/node_modules/better-sqlite3/src/util/query-macros.cpp +71 -0
- package/node_modules/better-sqlite3/src/util/row-builder.cpp +49 -0
- package/node_modules/bindings/LICENSE.md +22 -0
- package/node_modules/bindings/README.md +98 -0
- package/node_modules/bindings/bindings.js +221 -0
- package/node_modules/bindings/package.json +28 -0
- package/node_modules/bl/.travis.yml +17 -0
- package/node_modules/bl/BufferList.js +396 -0
- package/node_modules/bl/LICENSE.md +13 -0
- package/node_modules/bl/README.md +247 -0
- package/node_modules/bl/bl.js +84 -0
- package/node_modules/bl/package.json +37 -0
- package/node_modules/bl/test/convert.js +21 -0
- package/node_modules/bl/test/indexOf.js +492 -0
- package/node_modules/bl/test/isBufferList.js +32 -0
- package/node_modules/bl/test/test.js +869 -0
- package/node_modules/buffer/AUTHORS.md +70 -0
- package/node_modules/buffer/LICENSE +21 -0
- package/node_modules/buffer/README.md +410 -0
- package/node_modules/buffer/index.d.ts +186 -0
- package/node_modules/buffer/index.js +1817 -0
- package/node_modules/buffer/package.json +96 -0
- package/node_modules/decompress-response/index.d.ts +22 -0
- package/node_modules/decompress-response/index.js +58 -0
- package/node_modules/decompress-response/license +9 -0
- package/node_modules/decompress-response/node_modules/mimic-response/index.d.ts +17 -0
- package/node_modules/decompress-response/node_modules/mimic-response/index.js +77 -0
- package/node_modules/decompress-response/node_modules/mimic-response/license +9 -0
- package/node_modules/decompress-response/node_modules/mimic-response/package.json +42 -0
- package/node_modules/decompress-response/node_modules/mimic-response/readme.md +78 -0
- package/node_modules/decompress-response/package.json +56 -0
- package/node_modules/decompress-response/readme.md +48 -0
- package/node_modules/deep-extend/LICENSE +20 -0
- package/node_modules/deep-extend/README.md +91 -0
- package/node_modules/deep-extend/index.js +1 -0
- package/node_modules/deep-extend/lib/deep-extend.js +150 -0
- package/node_modules/deep-extend/package.json +62 -0
- package/node_modules/end-of-stream/LICENSE +21 -0
- package/node_modules/end-of-stream/README.md +54 -0
- package/node_modules/end-of-stream/index.js +96 -0
- package/node_modules/end-of-stream/package.json +37 -0
- package/node_modules/expand-template/.travis.yml +6 -0
- package/node_modules/expand-template/LICENSE +21 -0
- package/node_modules/expand-template/README.md +43 -0
- package/node_modules/expand-template/index.js +26 -0
- package/node_modules/expand-template/package.json +29 -0
- package/node_modules/expand-template/test.js +67 -0
- package/node_modules/file-uri-to-path/.npmignore +1 -0
- package/node_modules/file-uri-to-path/.travis.yml +30 -0
- package/node_modules/file-uri-to-path/History.md +21 -0
- package/node_modules/file-uri-to-path/LICENSE +20 -0
- package/node_modules/file-uri-to-path/README.md +74 -0
- package/node_modules/file-uri-to-path/index.d.ts +2 -0
- package/node_modules/file-uri-to-path/index.js +66 -0
- package/node_modules/file-uri-to-path/package.json +32 -0
- package/node_modules/file-uri-to-path/test/test.js +24 -0
- package/node_modules/file-uri-to-path/test/tests.json +13 -0
- package/node_modules/fs-constants/LICENSE +21 -0
- package/node_modules/fs-constants/README.md +26 -0
- package/node_modules/fs-constants/browser.js +1 -0
- package/node_modules/fs-constants/index.js +1 -0
- package/node_modules/fs-constants/package.json +19 -0
- package/node_modules/github-from-package/.travis.yml +4 -0
- package/node_modules/github-from-package/LICENSE +18 -0
- package/node_modules/github-from-package/example/package.json +8 -0
- package/node_modules/github-from-package/example/url.js +3 -0
- package/node_modules/github-from-package/index.js +17 -0
- package/node_modules/github-from-package/package.json +30 -0
- package/node_modules/github-from-package/readme.markdown +53 -0
- package/node_modules/github-from-package/test/a.json +8 -0
- package/node_modules/github-from-package/test/b.json +5 -0
- package/node_modules/github-from-package/test/c.json +5 -0
- package/node_modules/github-from-package/test/d.json +7 -0
- package/node_modules/github-from-package/test/e.json +5 -0
- package/node_modules/github-from-package/test/url.js +19 -0
- package/node_modules/ieee754/LICENSE +11 -0
- package/node_modules/ieee754/README.md +51 -0
- package/node_modules/ieee754/index.d.ts +10 -0
- package/node_modules/ieee754/index.js +85 -0
- package/node_modules/ieee754/package.json +52 -0
- package/node_modules/ini/LICENSE +15 -0
- package/node_modules/ini/README.md +102 -0
- package/node_modules/ini/ini.js +206 -0
- package/node_modules/ini/package.json +33 -0
- package/node_modules/minimist/.eslintrc +29 -0
- package/node_modules/minimist/.github/FUNDING.yml +12 -0
- package/node_modules/minimist/.nycrc +14 -0
- package/node_modules/minimist/CHANGELOG.md +298 -0
- package/node_modules/minimist/LICENSE +18 -0
- package/node_modules/minimist/README.md +121 -0
- package/node_modules/minimist/example/parse.js +4 -0
- package/node_modules/minimist/index.js +263 -0
- package/node_modules/minimist/package.json +75 -0
- package/node_modules/minimist/test/all_bool.js +34 -0
- package/node_modules/minimist/test/bool.js +177 -0
- package/node_modules/minimist/test/dash.js +43 -0
- package/node_modules/minimist/test/default_bool.js +37 -0
- package/node_modules/minimist/test/dotted.js +24 -0
- package/node_modules/minimist/test/kv_short.js +32 -0
- package/node_modules/minimist/test/long.js +33 -0
- package/node_modules/minimist/test/num.js +38 -0
- package/node_modules/minimist/test/parse.js +209 -0
- package/node_modules/minimist/test/parse_modified.js +11 -0
- package/node_modules/minimist/test/proto.js +64 -0
- package/node_modules/minimist/test/short.js +69 -0
- package/node_modules/minimist/test/stop_early.js +17 -0
- package/node_modules/minimist/test/unknown.js +104 -0
- package/node_modules/minimist/test/whitespace.js +10 -0
- package/node_modules/mkdirp-classic/LICENSE +21 -0
- package/node_modules/mkdirp-classic/README.md +18 -0
- package/node_modules/mkdirp-classic/index.js +98 -0
- package/node_modules/mkdirp-classic/package.json +18 -0
- package/node_modules/moe-training/DEPLOY_CENTRAL_COMMAND.md +413 -0
- package/node_modules/moe-training/client/consent.js +96 -0
- package/node_modules/moe-training/client/envelope-builder.js +56 -0
- package/node_modules/moe-training/client/index.js +10 -0
- package/node_modules/moe-training/client/parsers/claude-code.js +108 -0
- package/node_modules/moe-training/client/parsers/codex.js +80 -0
- package/node_modules/moe-training/client/parsers/gemini.js +80 -0
- package/node_modules/moe-training/client/parsers/grok.js +16 -0
- package/node_modules/moe-training/client/parsers/index.js +20 -0
- package/node_modules/moe-training/client/scrubber.js +128 -0
- package/node_modules/moe-training/client/session-attestation.js +115 -0
- package/node_modules/moe-training/client/step-classifier.js +68 -0
- package/node_modules/moe-training/client/trajectory-capture.js +307 -0
- package/node_modules/moe-training/client/transmission-queue.js +104 -0
- package/node_modules/moe-training/package.json +21 -0
- package/node_modules/moe-training/server/enrichment.js +24 -0
- package/node_modules/moe-training/server/index.js +119 -0
- package/node_modules/moe-training/server/ledger.js +110 -0
- package/node_modules/moe-training/server/routes/ingest.js +96 -0
- package/node_modules/moe-training/server/routes/sessions.js +43 -0
- package/node_modules/moe-training/server/routes/stats.js +31 -0
- package/node_modules/moe-training/server/scoring.js +63 -0
- package/node_modules/moe-training/server/session-registry.js +156 -0
- package/node_modules/moe-training/server/stats.js +129 -0
- package/node_modules/moe-training/server/stitcher.js +69 -0
- package/node_modules/moe-training/server/storage.js +147 -0
- package/node_modules/moe-training/server/verifier.js +102 -0
- package/node_modules/moe-training/shared/constants.js +30 -0
- package/node_modules/moe-training/shared/crypto.js +45 -0
- package/node_modules/moe-training/shared/envelope-schema.js +220 -0
- package/node_modules/moe-training/test/client/consent.test.js +121 -0
- package/node_modules/moe-training/test/client/envelope-builder.test.js +107 -0
- package/node_modules/moe-training/test/client/parsers/claude-code.test.js +119 -0
- package/node_modules/moe-training/test/client/parsers/codex.test.js +83 -0
- package/node_modules/moe-training/test/client/parsers/gemini.test.js +99 -0
- package/node_modules/moe-training/test/client/scrubber.test.js +143 -0
- package/node_modules/moe-training/test/client/session-attestation-security.test.js +95 -0
- package/node_modules/moe-training/test/client/step-classifier.test.js +135 -0
- package/node_modules/moe-training/test/client/transmission-queue.test.js +33 -0
- package/node_modules/moe-training/test/integration/handshake.test.js +260 -0
- package/node_modules/moe-training/test/server/ingest-security.test.js +166 -0
- package/node_modules/moe-training/test/server/ledger.test.js +131 -0
- package/node_modules/moe-training/test/server/scoring.test.js +242 -0
- package/node_modules/moe-training/test/server/session-registry.test.js +125 -0
- package/node_modules/moe-training/test/server/stitcher.test.js +157 -0
- package/node_modules/moe-training/test/server/verifier.test.js +232 -0
- package/node_modules/moe-training/test/shared/crypto.test.js +87 -0
- package/node_modules/moe-training/test/shared/envelope-schema.test.js +351 -0
- package/node_modules/napi-build-utils/.github/workflows/run-npm-tests.yml +31 -0
- package/node_modules/napi-build-utils/LICENSE +21 -0
- package/node_modules/napi-build-utils/README.md +52 -0
- package/node_modules/napi-build-utils/index.js +214 -0
- package/node_modules/napi-build-utils/index.md +0 -0
- package/node_modules/napi-build-utils/package.json +42 -0
- package/node_modules/prebuild-install/CHANGELOG.md +131 -0
- package/node_modules/prebuild-install/CONTRIBUTING.md +6 -0
- package/node_modules/prebuild-install/LICENSE +21 -0
- package/node_modules/prebuild-install/README.md +163 -0
- package/node_modules/prebuild-install/asset.js +44 -0
- package/node_modules/prebuild-install/bin.js +78 -0
- package/node_modules/prebuild-install/download.js +142 -0
- package/node_modules/prebuild-install/error.js +14 -0
- package/node_modules/prebuild-install/help.txt +16 -0
- package/node_modules/prebuild-install/index.js +1 -0
- package/node_modules/prebuild-install/log.js +33 -0
- package/node_modules/prebuild-install/node_modules/node-abi/LICENSE +21 -0
- package/node_modules/prebuild-install/node_modules/node-abi/README.md +54 -0
- package/node_modules/prebuild-install/node_modules/node-abi/abi_registry.json +439 -0
- package/node_modules/prebuild-install/node_modules/node-abi/index.js +179 -0
- package/node_modules/prebuild-install/node_modules/node-abi/package.json +45 -0
- package/node_modules/prebuild-install/node_modules/semver/LICENSE +15 -0
- package/node_modules/prebuild-install/node_modules/semver/README.md +665 -0
- package/node_modules/prebuild-install/node_modules/semver/bin/semver.js +191 -0
- package/node_modules/prebuild-install/node_modules/semver/classes/comparator.js +143 -0
- package/node_modules/prebuild-install/node_modules/semver/classes/index.js +7 -0
- package/node_modules/prebuild-install/node_modules/semver/classes/range.js +557 -0
- package/node_modules/prebuild-install/node_modules/semver/classes/semver.js +333 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/clean.js +8 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/cmp.js +54 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/coerce.js +62 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/compare-build.js +9 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/compare-loose.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/compare.js +7 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/diff.js +60 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/eq.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/gt.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/gte.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/inc.js +21 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/lt.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/lte.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/major.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/minor.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/neq.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/parse.js +18 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/patch.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/prerelease.js +8 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/rcompare.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/rsort.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/satisfies.js +12 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/sort.js +5 -0
- package/node_modules/prebuild-install/node_modules/semver/functions/valid.js +8 -0
- package/node_modules/prebuild-install/node_modules/semver/index.js +91 -0
- package/node_modules/prebuild-install/node_modules/semver/internal/constants.js +37 -0
- package/node_modules/prebuild-install/node_modules/semver/internal/debug.js +11 -0
- package/node_modules/prebuild-install/node_modules/semver/internal/identifiers.js +29 -0
- package/node_modules/prebuild-install/node_modules/semver/internal/lrucache.js +42 -0
- package/node_modules/prebuild-install/node_modules/semver/internal/parse-options.js +17 -0
- package/node_modules/prebuild-install/node_modules/semver/internal/re.js +223 -0
- package/node_modules/prebuild-install/node_modules/semver/package.json +78 -0
- package/node_modules/prebuild-install/node_modules/semver/preload.js +4 -0
- package/node_modules/prebuild-install/node_modules/semver/range.bnf +16 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/gtr.js +6 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/intersects.js +9 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/ltr.js +6 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/max-satisfying.js +27 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/min-satisfying.js +26 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/min-version.js +63 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/outside.js +82 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/simplify.js +49 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/subset.js +249 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/to-comparators.js +10 -0
- package/node_modules/prebuild-install/node_modules/semver/ranges/valid.js +13 -0
- package/node_modules/prebuild-install/package.json +67 -0
- package/node_modules/prebuild-install/proxy.js +35 -0
- package/node_modules/prebuild-install/rc.js +64 -0
- package/node_modules/prebuild-install/util.js +143 -0
- package/node_modules/pump/.github/FUNDING.yml +2 -0
- package/node_modules/pump/.travis.yml +5 -0
- package/node_modules/pump/LICENSE +21 -0
- package/node_modules/pump/README.md +74 -0
- package/node_modules/pump/SECURITY.md +5 -0
- package/node_modules/pump/empty.js +1 -0
- package/node_modules/pump/index.js +86 -0
- package/node_modules/pump/package.json +30 -0
- package/node_modules/pump/test-browser.js +66 -0
- package/node_modules/pump/test-node.js +53 -0
- package/node_modules/rc/LICENSE.APACHE2 +15 -0
- package/node_modules/rc/LICENSE.BSD +26 -0
- package/node_modules/rc/LICENSE.MIT +24 -0
- package/node_modules/rc/README.md +227 -0
- package/node_modules/rc/browser.js +7 -0
- package/node_modules/rc/cli.js +4 -0
- package/node_modules/rc/index.js +53 -0
- package/node_modules/rc/lib/utils.js +104 -0
- package/node_modules/rc/package.json +29 -0
- package/node_modules/rc/test/ini.js +16 -0
- package/node_modules/rc/test/nested-env-vars.js +50 -0
- package/node_modules/rc/test/test.js +59 -0
- package/node_modules/readable-stream/CONTRIBUTING.md +38 -0
- package/node_modules/readable-stream/GOVERNANCE.md +136 -0
- package/node_modules/readable-stream/LICENSE +47 -0
- package/node_modules/readable-stream/README.md +106 -0
- package/node_modules/readable-stream/errors-browser.js +127 -0
- package/node_modules/readable-stream/errors.js +116 -0
- package/node_modules/readable-stream/experimentalWarning.js +17 -0
- package/node_modules/readable-stream/lib/_stream_duplex.js +126 -0
- package/node_modules/readable-stream/lib/_stream_passthrough.js +37 -0
- package/node_modules/readable-stream/lib/_stream_readable.js +1027 -0
- package/node_modules/readable-stream/lib/_stream_transform.js +190 -0
- package/node_modules/readable-stream/lib/_stream_writable.js +641 -0
- package/node_modules/readable-stream/lib/internal/streams/async_iterator.js +180 -0
- package/node_modules/readable-stream/lib/internal/streams/buffer_list.js +183 -0
- package/node_modules/readable-stream/lib/internal/streams/destroy.js +96 -0
- package/node_modules/readable-stream/lib/internal/streams/end-of-stream.js +86 -0
- package/node_modules/readable-stream/lib/internal/streams/from-browser.js +3 -0
- package/node_modules/readable-stream/lib/internal/streams/from.js +52 -0
- package/node_modules/readable-stream/lib/internal/streams/pipeline.js +86 -0
- package/node_modules/readable-stream/lib/internal/streams/state.js +22 -0
- package/node_modules/readable-stream/lib/internal/streams/stream-browser.js +1 -0
- package/node_modules/readable-stream/lib/internal/streams/stream.js +1 -0
- package/node_modules/readable-stream/package.json +68 -0
- package/node_modules/readable-stream/readable-browser.js +9 -0
- package/node_modules/readable-stream/readable.js +16 -0
- package/node_modules/simple-concat/.travis.yml +3 -0
- package/node_modules/simple-concat/LICENSE +20 -0
- package/node_modules/simple-concat/README.md +44 -0
- package/node_modules/simple-concat/index.js +15 -0
- package/node_modules/simple-concat/package.json +47 -0
- package/node_modules/simple-concat/test/basic.js +41 -0
- package/node_modules/simple-get/.github/dependabot.yml +15 -0
- package/node_modules/simple-get/.github/workflows/ci.yml +23 -0
- package/node_modules/simple-get/LICENSE +20 -0
- package/node_modules/simple-get/README.md +333 -0
- package/node_modules/simple-get/index.js +108 -0
- package/node_modules/simple-get/package.json +67 -0
- package/node_modules/string_decoder/LICENSE +48 -0
- package/node_modules/string_decoder/README.md +47 -0
- package/node_modules/string_decoder/lib/string_decoder.js +296 -0
- package/node_modules/string_decoder/package.json +34 -0
- package/node_modules/strip-json-comments/index.js +70 -0
- package/node_modules/strip-json-comments/license +21 -0
- package/node_modules/strip-json-comments/package.json +42 -0
- package/node_modules/strip-json-comments/readme.md +64 -0
- package/node_modules/tar-fs/.travis.yml +6 -0
- package/node_modules/tar-fs/LICENSE +21 -0
- package/node_modules/tar-fs/README.md +165 -0
- package/node_modules/tar-fs/index.js +363 -0
- package/node_modules/tar-fs/node_modules/chownr/LICENSE +15 -0
- package/node_modules/tar-fs/node_modules/chownr/README.md +3 -0
- package/node_modules/tar-fs/node_modules/chownr/chownr.js +167 -0
- package/node_modules/tar-fs/node_modules/chownr/package.json +29 -0
- package/node_modules/tar-fs/package.json +41 -0
- package/node_modules/tar-fs/test/fixtures/a/hello.txt +1 -0
- package/node_modules/tar-fs/test/fixtures/b/a/test.txt +1 -0
- package/node_modules/tar-fs/test/fixtures/d/file1 +0 -0
- package/node_modules/tar-fs/test/fixtures/d/file2 +0 -0
- package/node_modules/tar-fs/test/fixtures/d/sub-dir/file5 +0 -0
- package/node_modules/tar-fs/test/fixtures/d/sub-files/file3 +0 -0
- package/node_modules/tar-fs/test/fixtures/d/sub-files/file4 +0 -0
- package/node_modules/tar-fs/test/fixtures/e/directory/.ignore +0 -0
- package/node_modules/tar-fs/test/fixtures/e/file +0 -0
- package/node_modules/tar-fs/test/fixtures/invalid.tar +0 -0
- package/node_modules/tar-fs/test/index.js +346 -0
- package/node_modules/tar-stream/LICENSE +21 -0
- package/node_modules/tar-stream/README.md +168 -0
- package/node_modules/tar-stream/extract.js +257 -0
- package/node_modules/tar-stream/headers.js +295 -0
- package/node_modules/tar-stream/index.js +2 -0
- package/node_modules/tar-stream/pack.js +255 -0
- package/node_modules/tar-stream/package.json +58 -0
- package/node_modules/tar-stream/sandbox.js +11 -0
- package/node_modules/tunnel-agent/LICENSE +55 -0
- package/node_modules/tunnel-agent/README.md +4 -0
- package/node_modules/tunnel-agent/index.js +244 -0
- package/node_modules/tunnel-agent/package.json +22 -0
- package/node_modules/util-deprecate/History.md +16 -0
- package/node_modules/util-deprecate/LICENSE +24 -0
- package/node_modules/util-deprecate/README.md +53 -0
- package/node_modules/util-deprecate/browser.js +67 -0
- package/node_modules/util-deprecate/node.js +6 -0
- package/node_modules/util-deprecate/package.json +27 -0
- package/node_modules/uuid/CHANGELOG.md +274 -0
- package/node_modules/uuid/CONTRIBUTING.md +18 -0
- package/node_modules/uuid/LICENSE.md +9 -0
- package/node_modules/uuid/README.md +466 -0
- package/node_modules/uuid/dist/bin/uuid +2 -0
- package/node_modules/uuid/dist/commonjs-browser/index.js +79 -0
- package/node_modules/uuid/dist/commonjs-browser/md5.js +223 -0
- package/node_modules/uuid/dist/commonjs-browser/native.js +11 -0
- package/node_modules/uuid/dist/commonjs-browser/nil.js +8 -0
- package/node_modules/uuid/dist/commonjs-browser/parse.js +45 -0
- package/node_modules/uuid/dist/commonjs-browser/regex.js +8 -0
- package/node_modules/uuid/dist/commonjs-browser/rng.js +25 -0
- package/node_modules/uuid/dist/commonjs-browser/sha1.js +104 -0
- package/node_modules/uuid/dist/commonjs-browser/stringify.js +44 -0
- package/node_modules/uuid/dist/commonjs-browser/v1.js +107 -0
- package/node_modules/uuid/dist/commonjs-browser/v3.js +16 -0
- package/node_modules/uuid/dist/commonjs-browser/v35.js +80 -0
- package/node_modules/uuid/dist/commonjs-browser/v4.js +43 -0
- package/node_modules/uuid/dist/commonjs-browser/v5.js +16 -0
- package/node_modules/uuid/dist/commonjs-browser/validate.js +17 -0
- package/node_modules/uuid/dist/commonjs-browser/version.js +21 -0
- package/node_modules/uuid/dist/esm-browser/index.js +9 -0
- package/node_modules/uuid/dist/esm-browser/md5.js +215 -0
- package/node_modules/uuid/dist/esm-browser/native.js +4 -0
- package/node_modules/uuid/dist/esm-browser/nil.js +1 -0
- package/node_modules/uuid/dist/esm-browser/parse.js +35 -0
- package/node_modules/uuid/dist/esm-browser/regex.js +1 -0
- package/node_modules/uuid/dist/esm-browser/rng.js +18 -0
- package/node_modules/uuid/dist/esm-browser/sha1.js +96 -0
- package/node_modules/uuid/dist/esm-browser/stringify.js +33 -0
- package/node_modules/uuid/dist/esm-browser/v1.js +95 -0
- package/node_modules/uuid/dist/esm-browser/v3.js +4 -0
- package/node_modules/uuid/dist/esm-browser/v35.js +66 -0
- package/node_modules/uuid/dist/esm-browser/v4.js +29 -0
- package/node_modules/uuid/dist/esm-browser/v5.js +4 -0
- package/node_modules/uuid/dist/esm-browser/validate.js +7 -0
- package/node_modules/uuid/dist/esm-browser/version.js +11 -0
- package/node_modules/uuid/dist/esm-node/index.js +9 -0
- package/node_modules/uuid/dist/esm-node/md5.js +13 -0
- package/node_modules/uuid/dist/esm-node/native.js +4 -0
- package/node_modules/uuid/dist/esm-node/nil.js +1 -0
- package/node_modules/uuid/dist/esm-node/parse.js +35 -0
- package/node_modules/uuid/dist/esm-node/regex.js +1 -0
- package/node_modules/uuid/dist/esm-node/rng.js +12 -0
- package/node_modules/uuid/dist/esm-node/sha1.js +13 -0
- package/node_modules/uuid/dist/esm-node/stringify.js +33 -0
- package/node_modules/uuid/dist/esm-node/v1.js +95 -0
- package/node_modules/uuid/dist/esm-node/v3.js +4 -0
- package/node_modules/uuid/dist/esm-node/v35.js +66 -0
- package/node_modules/uuid/dist/esm-node/v4.js +29 -0
- package/node_modules/uuid/dist/esm-node/v5.js +4 -0
- package/node_modules/uuid/dist/esm-node/validate.js +7 -0
- package/node_modules/uuid/dist/esm-node/version.js +11 -0
- package/node_modules/uuid/dist/index.js +79 -0
- package/node_modules/uuid/dist/md5-browser.js +223 -0
- package/node_modules/uuid/dist/md5.js +23 -0
- package/node_modules/uuid/dist/native-browser.js +11 -0
- package/node_modules/uuid/dist/native.js +15 -0
- package/node_modules/uuid/dist/nil.js +8 -0
- package/node_modules/uuid/dist/parse.js +45 -0
- package/node_modules/uuid/dist/regex.js +8 -0
- package/node_modules/uuid/dist/rng-browser.js +25 -0
- package/node_modules/uuid/dist/rng.js +24 -0
- package/node_modules/uuid/dist/sha1-browser.js +104 -0
- package/node_modules/uuid/dist/sha1.js +23 -0
- package/node_modules/uuid/dist/stringify.js +44 -0
- package/node_modules/uuid/dist/uuid-bin.js +85 -0
- package/node_modules/uuid/dist/v1.js +107 -0
- package/node_modules/uuid/dist/v3.js +16 -0
- package/node_modules/uuid/dist/v35.js +80 -0
- package/node_modules/uuid/dist/v4.js +43 -0
- package/node_modules/uuid/dist/v5.js +16 -0
- package/node_modules/uuid/dist/validate.js +17 -0
- package/node_modules/uuid/dist/version.js +21 -0
- package/node_modules/uuid/package.json +135 -0
- package/node_modules/uuid/wrapper.mjs +10 -0
- package/package.json +5 -3
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +17 -9
- package/packages/daemon/src/process.js +2 -0
- package/packages/gui/dist/assets/{index-VB4_k5Pz.js → index-B3GUKInH.js} +339 -339
- package/packages/gui/dist/assets/{index-Bo6AeNmM.css → index-C1k-GuDg.css} +1 -1
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/agents/agent-panel.jsx +2 -0
- package/packages/gui/src/stores/groove.js +14 -10
- package/packages/gui/src/views/agents.jsx +10 -68
- package/workspace.png +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
|
+
|
|
3
|
+
import { mkdirSync, appendFileSync, readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
|
|
6
|
+
const QUOTA_BYTES = 50 * 1024 * 1024 * 1024; // 50GB
|
|
7
|
+
const WARN_BYTES = 40 * 1024 * 1024 * 1024; // 40GB
|
|
8
|
+
|
|
9
|
+
export class EnvelopeStorage {
|
|
10
|
+
constructor(basePath = './data/envelopes') {
|
|
11
|
+
this.basePath = basePath;
|
|
12
|
+
if (!existsSync(basePath)) mkdirSync(basePath, { recursive: true, mode: 0o700 });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
checkQuota() {
|
|
16
|
+
const files = this._listFiles();
|
|
17
|
+
let total = 0;
|
|
18
|
+
for (const file of files) {
|
|
19
|
+
try { total += statSync(file).size; } catch { /* skip */ }
|
|
20
|
+
}
|
|
21
|
+
if (total > WARN_BYTES && total <= QUOTA_BYTES) {
|
|
22
|
+
console.warn(`[storage] WARNING: storage at ${(total / (1024 * 1024 * 1024)).toFixed(1)}GB, approaching 50GB quota`);
|
|
23
|
+
}
|
|
24
|
+
return total < QUOTA_BYTES;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
store(envelope) {
|
|
28
|
+
if (!this.checkQuota()) {
|
|
29
|
+
throw new Error('STORAGE_QUOTA_EXCEEDED');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
33
|
+
const filePath = join(this.basePath, `${date}.jsonl`);
|
|
34
|
+
|
|
35
|
+
if (!existsSync(this.basePath)) {
|
|
36
|
+
mkdirSync(this.basePath, { recursive: true, mode: 0o700 });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const line = JSON.stringify(envelope) + '\n';
|
|
40
|
+
appendFileSync(filePath, line, { mode: 0o600 });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getSessionEnvelopes(sessionId) {
|
|
44
|
+
const envelopes = [];
|
|
45
|
+
const files = this._listFiles();
|
|
46
|
+
|
|
47
|
+
for (const file of files) {
|
|
48
|
+
const lines = readFileSync(file, 'utf-8').split('\n').filter(Boolean);
|
|
49
|
+
for (const line of lines) {
|
|
50
|
+
try {
|
|
51
|
+
const env = JSON.parse(line);
|
|
52
|
+
if (env.session_id === sessionId) envelopes.push(env);
|
|
53
|
+
} catch { /* skip malformed lines */ }
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return envelopes.sort((a, b) => (a.chunk_sequence ?? 0) - (b.chunk_sequence ?? 0));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getDateRange(startDate, endDate) {
|
|
61
|
+
const envelopes = [];
|
|
62
|
+
const files = this._listFiles();
|
|
63
|
+
|
|
64
|
+
for (const file of files) {
|
|
65
|
+
const fileName = file.split('/').pop().replace('.jsonl', '');
|
|
66
|
+
if (fileName < startDate || fileName > endDate) continue;
|
|
67
|
+
|
|
68
|
+
const lines = readFileSync(file, 'utf-8').split('\n').filter(Boolean);
|
|
69
|
+
for (const line of lines) {
|
|
70
|
+
try {
|
|
71
|
+
envelopes.push(JSON.parse(line));
|
|
72
|
+
} catch { /* skip */ }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return envelopes;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
getDailyStats(days = 7) {
|
|
80
|
+
const stats = [];
|
|
81
|
+
const files = this._listFiles();
|
|
82
|
+
|
|
83
|
+
const cutoff = new Date();
|
|
84
|
+
cutoff.setDate(cutoff.getDate() - days);
|
|
85
|
+
const cutoffStr = cutoff.toISOString().slice(0, 10);
|
|
86
|
+
|
|
87
|
+
for (const file of files) {
|
|
88
|
+
const date = file.split('/').pop().replace('.jsonl', '');
|
|
89
|
+
if (date < cutoffStr) continue;
|
|
90
|
+
|
|
91
|
+
const lines = readFileSync(file, 'utf-8').split('\n').filter(Boolean);
|
|
92
|
+
let stepCount = 0;
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
try {
|
|
95
|
+
const env = JSON.parse(line);
|
|
96
|
+
stepCount += env.trajectory_log?.length ?? 0;
|
|
97
|
+
} catch { /* skip */ }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
stats.push({ date, envelopeCount: lines.length, stepCount });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return stats.sort((a, b) => a.date.localeCompare(b.date));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
getTotalStats() {
|
|
107
|
+
const files = this._listFiles();
|
|
108
|
+
let totalEnvelopes = 0;
|
|
109
|
+
let totalSteps = 0;
|
|
110
|
+
let storageSizeBytes = 0;
|
|
111
|
+
const contributors = new Set();
|
|
112
|
+
const sessions = new Set();
|
|
113
|
+
|
|
114
|
+
for (const file of files) {
|
|
115
|
+
const stat = statSync(file);
|
|
116
|
+
storageSizeBytes += stat.size;
|
|
117
|
+
|
|
118
|
+
const lines = readFileSync(file, 'utf-8').split('\n').filter(Boolean);
|
|
119
|
+
totalEnvelopes += lines.length;
|
|
120
|
+
|
|
121
|
+
for (const line of lines) {
|
|
122
|
+
try {
|
|
123
|
+
const env = JSON.parse(line);
|
|
124
|
+
totalSteps += env.trajectory_log?.length ?? 0;
|
|
125
|
+
if (env.contributor_id) contributors.add(env.contributor_id);
|
|
126
|
+
if (env.session_id) sessions.add(env.session_id);
|
|
127
|
+
} catch { /* skip */ }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
totalEnvelopes,
|
|
133
|
+
totalSteps,
|
|
134
|
+
storageSizeMb: +(storageSizeBytes / 1_048_576).toFixed(2),
|
|
135
|
+
uniqueContributors: contributors.size,
|
|
136
|
+
uniqueSessions: sessions.size,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
_listFiles() {
|
|
141
|
+
if (!existsSync(this.basePath)) return [];
|
|
142
|
+
return readdirSync(this.basePath)
|
|
143
|
+
.filter(f => f.endsWith('.jsonl'))
|
|
144
|
+
.map(f => join(this.basePath, f))
|
|
145
|
+
.sort();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
|
+
|
|
3
|
+
import { verifyEnvelope } from '../shared/crypto.js';
|
|
4
|
+
|
|
5
|
+
let validateEnvelope;
|
|
6
|
+
try {
|
|
7
|
+
const schema = await import('../shared/envelope-schema.js');
|
|
8
|
+
validateEnvelope = schema.validateEnvelope;
|
|
9
|
+
} catch {
|
|
10
|
+
validateEnvelope = () => ({ valid: true });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class EnvelopeVerifier {
|
|
14
|
+
constructor(sessionRegistry) {
|
|
15
|
+
this.sessionRegistry = sessionRegistry;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
verify(envelope) {
|
|
19
|
+
const sessionId = envelope.session_id;
|
|
20
|
+
if (!sessionId) return { valid: false, reason: 'missing session_id' };
|
|
21
|
+
|
|
22
|
+
const session = this.sessionRegistry.getSession(sessionId);
|
|
23
|
+
if (!session) return { valid: false, reason: 'unknown session_id' };
|
|
24
|
+
if (session.status !== 'active') return { valid: false, reason: 'session is closed' };
|
|
25
|
+
|
|
26
|
+
const attestation = envelope.attestation;
|
|
27
|
+
if (!attestation) return { valid: false, reason: 'missing attestation' };
|
|
28
|
+
|
|
29
|
+
if (!attestation.session_hmac || typeof attestation.session_hmac !== 'string' || attestation.session_hmac.length === 0) {
|
|
30
|
+
return { valid: false, reason: 'empty or missing HMAC' };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// HMAC covers the entire envelope EXCEPT the attestation block
|
|
34
|
+
const envelopeForHmac = { ...envelope };
|
|
35
|
+
delete envelopeForHmac.attestation;
|
|
36
|
+
const envelopeBytes = JSON.stringify(envelopeForHmac);
|
|
37
|
+
|
|
38
|
+
const hmacValid = verifyEnvelope(
|
|
39
|
+
session.shared_secret,
|
|
40
|
+
envelopeBytes,
|
|
41
|
+
attestation.sequence,
|
|
42
|
+
attestation.session_hmac
|
|
43
|
+
);
|
|
44
|
+
if (!hmacValid) return { valid: false, reason: 'HMAC verification failed' };
|
|
45
|
+
|
|
46
|
+
// Atomic sequence check + increment (prevents race conditions)
|
|
47
|
+
const seqResult = this.sessionRegistry.checkAndIncrementSequence(sessionId, attestation.sequence);
|
|
48
|
+
if (!seqResult.valid) {
|
|
49
|
+
return { valid: false, reason: seqResult.reason };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const schemaResult = validateEnvelope(envelope);
|
|
53
|
+
if (!schemaResult.valid) {
|
|
54
|
+
return { valid: false, reason: `schema validation failed: ${schemaResult.reason || schemaResult.errors?.join(', ')}` };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { valid: true };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
verifyClose(envelope) {
|
|
61
|
+
const sessionId = envelope.session_id;
|
|
62
|
+
if (!sessionId) return { valid: false, reason: 'missing session_id' };
|
|
63
|
+
|
|
64
|
+
const session = this.sessionRegistry.getSession(sessionId);
|
|
65
|
+
if (!session) return { valid: false, reason: 'unknown session_id' };
|
|
66
|
+
if (session.status !== 'active') return { valid: false, reason: 'session already closed' };
|
|
67
|
+
|
|
68
|
+
const attestation = envelope.attestation;
|
|
69
|
+
if (!attestation) return { valid: false, reason: 'missing attestation' };
|
|
70
|
+
|
|
71
|
+
if (!attestation.session_hmac || typeof attestation.session_hmac !== 'string' || attestation.session_hmac.length === 0) {
|
|
72
|
+
return { valid: false, reason: 'empty or missing HMAC' };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// HMAC covers the entire envelope EXCEPT the attestation block
|
|
76
|
+
const envelopeForHmac = { ...envelope };
|
|
77
|
+
delete envelopeForHmac.attestation;
|
|
78
|
+
const envelopeBytes = JSON.stringify(envelopeForHmac);
|
|
79
|
+
|
|
80
|
+
const hmacValid = verifyEnvelope(
|
|
81
|
+
session.shared_secret,
|
|
82
|
+
envelopeBytes,
|
|
83
|
+
attestation.sequence,
|
|
84
|
+
attestation.session_hmac
|
|
85
|
+
);
|
|
86
|
+
if (!hmacValid) return { valid: false, reason: 'HMAC verification failed' };
|
|
87
|
+
|
|
88
|
+
// Sequence check for close envelopes too
|
|
89
|
+
const seqResult = this.sessionRegistry.checkAndIncrementSequence(sessionId, attestation.sequence);
|
|
90
|
+
if (!seqResult.valid) {
|
|
91
|
+
return { valid: false, reason: seqResult.reason };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const schemaResult = validateEnvelope(envelope);
|
|
95
|
+
if (!schemaResult.valid) {
|
|
96
|
+
return { valid: false, reason: `schema validation failed: ${schemaResult.reason || schemaResult.errors?.join(', ')}` };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.sessionRegistry.closeSession(sessionId);
|
|
100
|
+
return { valid: true };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
|
+
|
|
3
|
+
export const CURRENT_CONSENT_VERSION = '1.0';
|
|
4
|
+
export const CHUNK_SIZE = 200;
|
|
5
|
+
export const CHUNK_TIMEOUT_MS = 300_000;
|
|
6
|
+
export const MAX_QUEUE_SIZE = 10_000;
|
|
7
|
+
export const OBSERVATION_TRUNCATE_HEAD = 50;
|
|
8
|
+
export const OBSERVATION_TRUNCATE_TAIL = 20;
|
|
9
|
+
export const SUPPORTED_PROVIDERS = ['claude-code', 'codex', 'gemini'];
|
|
10
|
+
|
|
11
|
+
export const MODEL_TIERS = {
|
|
12
|
+
'claude-opus-4-6': 5,
|
|
13
|
+
'claude-opus-4-7': 5,
|
|
14
|
+
'claude-sonnet-4-6': 3,
|
|
15
|
+
'gpt-4.5': 5,
|
|
16
|
+
'o3': 5,
|
|
17
|
+
'o4-mini': 2,
|
|
18
|
+
'gemini-2.5-pro': 3,
|
|
19
|
+
'gemini-2.5-flash': 1.5,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const QUALITY_MULTIPLIERS = {
|
|
23
|
+
correction: 10,
|
|
24
|
+
coordination: 5,
|
|
25
|
+
errorRecovery: 3,
|
|
26
|
+
heavyTask: 2,
|
|
27
|
+
highQuality: 1.5,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const CENTRAL_COMMAND_URL = process.env.GROOVE_CENTRAL_URL || 'https://api.groovedev.ai';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
|
+
|
|
3
|
+
import { createECDH, createHmac, createHash, randomBytes } from 'node:crypto';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
export function generateECDHKeypair() {
|
|
7
|
+
const ecdh = createECDH('prime256v1');
|
|
8
|
+
ecdh.generateKeys();
|
|
9
|
+
return {
|
|
10
|
+
publicKey: ecdh.getPublicKey('base64'),
|
|
11
|
+
privateKey: ecdh.getPrivateKey('base64'),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function deriveSharedSecret(privateKeyB64, otherPublicKeyB64) {
|
|
16
|
+
const ecdh = createECDH('prime256v1');
|
|
17
|
+
ecdh.setPrivateKey(Buffer.from(privateKeyB64, 'base64'));
|
|
18
|
+
const secret = ecdh.computeSecret(Buffer.from(otherPublicKeyB64, 'base64'));
|
|
19
|
+
return secret.toString('base64');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// envelopeBytes MUST contain ALL envelope fields EXCEPT attestation (which holds the HMAC itself).
|
|
23
|
+
// Callers must strip attestation before JSON.stringify to produce envelopeBytes.
|
|
24
|
+
export function signEnvelope(sharedSecretB64, envelopeBytes, sequenceNumber) {
|
|
25
|
+
const key = Buffer.from(sharedSecretB64, 'base64');
|
|
26
|
+
const seqBuf = Buffer.alloc(4);
|
|
27
|
+
seqBuf.writeUInt32BE(sequenceNumber);
|
|
28
|
+
const payload = Buffer.concat([seqBuf, Buffer.from(envelopeBytes)]);
|
|
29
|
+
return createHmac('sha256', key).update(payload).digest('hex');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function verifyEnvelope(sharedSecretB64, envelopeBytes, sequenceNumber, hmac) {
|
|
33
|
+
const expected = signEnvelope(sharedSecretB64, envelopeBytes, sequenceNumber);
|
|
34
|
+
if (expected.length !== hmac.length) return false;
|
|
35
|
+
let diff = 0;
|
|
36
|
+
for (let i = 0; i < expected.length; i++) {
|
|
37
|
+
diff |= expected.charCodeAt(i) ^ hmac.charCodeAt(i);
|
|
38
|
+
}
|
|
39
|
+
return diff === 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function computeAppHash(filePath) {
|
|
43
|
+
const content = readFileSync(filePath);
|
|
44
|
+
return createHash('sha256').update(content).digest('hex');
|
|
45
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
|
+
|
|
3
|
+
import { SUPPORTED_PROVIDERS, MODEL_TIERS } from './constants.js';
|
|
4
|
+
|
|
5
|
+
export const STEP_TYPES = ['thought', 'action', 'observation', 'correction', 'resolution', 'error', 'coordination'];
|
|
6
|
+
|
|
7
|
+
const VALID_MODEL_ENGINES = Object.keys(MODEL_TIERS);
|
|
8
|
+
const VALID_COMPLEXITIES = ['light', 'medium', 'heavy'];
|
|
9
|
+
const VALID_OUTCOME_STATUSES = ['SUCCESS', 'CRASH', 'KILLED'];
|
|
10
|
+
const MAX_STEPS_PER_ENVELOPE = 500;
|
|
11
|
+
const MAX_STEP_CONTENT_LENGTH = 10_000;
|
|
12
|
+
const MAX_TOKEN_COUNT = 100_000;
|
|
13
|
+
const MAX_STEP_NUMBER = 50_000;
|
|
14
|
+
const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
|
|
15
|
+
const ONE_HOUR_MS = 60 * 60 * 1000;
|
|
16
|
+
const HEX_32 = /^[0-9a-f]{32}$/;
|
|
17
|
+
const HEX_64 = /^[0-9a-f]{64}$/;
|
|
18
|
+
const MAX_OUTCOME_NUMERIC = 50_000;
|
|
19
|
+
|
|
20
|
+
export class EnvelopeBuilder {
|
|
21
|
+
constructor() {
|
|
22
|
+
this._steps = [];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
addStep(step) {
|
|
26
|
+
this._steps.push(step);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
build(envelopeId, sessionId, chunkSequence, contributorId, metadata) {
|
|
31
|
+
return {
|
|
32
|
+
envelope_id: envelopeId,
|
|
33
|
+
session_id: sessionId,
|
|
34
|
+
chunk_sequence: chunkSequence,
|
|
35
|
+
contributor_id: contributorId,
|
|
36
|
+
attestation: { session_hmac: '', sequence: 0, app_version_hash: '' },
|
|
37
|
+
metadata,
|
|
38
|
+
trajectory_log: [...this._steps],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static buildSessionClose(envelopeId, sessionId, outcome) {
|
|
43
|
+
return {
|
|
44
|
+
envelope_id: envelopeId,
|
|
45
|
+
session_id: sessionId,
|
|
46
|
+
type: 'SESSION_CLOSE',
|
|
47
|
+
attestation: { session_hmac: '', sequence: 0, app_version_hash: '' },
|
|
48
|
+
outcome,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function validateEnvelope(envelope) {
|
|
54
|
+
const errors = [];
|
|
55
|
+
|
|
56
|
+
if (!envelope) {
|
|
57
|
+
return { valid: false, errors: ['Envelope is null or undefined'] };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (envelope.type === 'SESSION_CLOSE') {
|
|
61
|
+
return validateSessionClose(envelope);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!envelope.session_id || typeof envelope.session_id !== 'string') {
|
|
65
|
+
errors.push('Missing or invalid session_id');
|
|
66
|
+
}
|
|
67
|
+
if (typeof envelope.chunk_sequence !== 'number') {
|
|
68
|
+
errors.push('Missing or invalid chunk_sequence');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// contributor_id: must be 32-char hex (UUID without dashes)
|
|
72
|
+
if (!envelope.contributor_id || typeof envelope.contributor_id !== 'string') {
|
|
73
|
+
errors.push('Missing or invalid contributor_id');
|
|
74
|
+
} else if (!HEX_32.test(envelope.contributor_id)) {
|
|
75
|
+
errors.push('contributor_id must be a 32-character hex string');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Attestation validation
|
|
79
|
+
if (!envelope.attestation || typeof envelope.attestation !== 'object') {
|
|
80
|
+
errors.push('Missing attestation');
|
|
81
|
+
} else {
|
|
82
|
+
if (typeof envelope.attestation.session_hmac !== 'string' || !HEX_64.test(envelope.attestation.session_hmac)) {
|
|
83
|
+
errors.push('attestation.session_hmac must be exactly 64 hex characters');
|
|
84
|
+
}
|
|
85
|
+
if (typeof envelope.attestation.sequence !== 'number' || !Number.isInteger(envelope.attestation.sequence) || envelope.attestation.sequence < 0 || envelope.attestation.sequence > 1_000_000) {
|
|
86
|
+
errors.push('attestation.sequence must be a non-negative integer, max 1000000');
|
|
87
|
+
}
|
|
88
|
+
if (typeof envelope.attestation.app_version_hash !== 'string' || !HEX_64.test(envelope.attestation.app_version_hash)) {
|
|
89
|
+
errors.push('attestation.app_version_hash must be exactly 64 hex characters');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Metadata validation
|
|
94
|
+
if (!envelope.metadata || typeof envelope.metadata !== 'object') {
|
|
95
|
+
errors.push('Missing metadata');
|
|
96
|
+
} else {
|
|
97
|
+
const m = envelope.metadata;
|
|
98
|
+
if (!m.provider || !SUPPORTED_PROVIDERS.includes(m.provider)) {
|
|
99
|
+
errors.push(`metadata.provider must be one of: ${SUPPORTED_PROVIDERS.join(', ')}`);
|
|
100
|
+
}
|
|
101
|
+
if (!m.model_engine || !VALID_MODEL_ENGINES.includes(m.model_engine)) {
|
|
102
|
+
errors.push(`metadata.model_engine must be one of: ${VALID_MODEL_ENGINES.join(', ')}`);
|
|
103
|
+
}
|
|
104
|
+
if (!m.agent_role || typeof m.agent_role !== 'string' || m.agent_role.length > 50) {
|
|
105
|
+
errors.push('metadata.agent_role must be a string, max 50 characters');
|
|
106
|
+
}
|
|
107
|
+
if (!m.agent_id || typeof m.agent_id !== 'string' || m.agent_id.length > 100) {
|
|
108
|
+
errors.push('metadata.agent_id must be a string, max 100 characters');
|
|
109
|
+
}
|
|
110
|
+
if (m.team_size !== undefined && m.team_size !== null) {
|
|
111
|
+
if (!Number.isInteger(m.team_size) || m.team_size < 1 || m.team_size > 50) {
|
|
112
|
+
errors.push('metadata.team_size must be an integer 1-50');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (m.task_complexity !== undefined && m.task_complexity !== null) {
|
|
116
|
+
if (!VALID_COMPLEXITIES.includes(m.task_complexity)) {
|
|
117
|
+
errors.push('metadata.task_complexity must be light, medium, or heavy');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (m.groove_version !== undefined && m.groove_version !== null) {
|
|
121
|
+
if (typeof m.groove_version !== 'string' || m.groove_version.length > 20) {
|
|
122
|
+
errors.push('metadata.groove_version must be a string, max 20 characters');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// session_quality is ignored from client — server derives quality
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Trajectory log validation
|
|
129
|
+
if (!Array.isArray(envelope.trajectory_log)) {
|
|
130
|
+
errors.push('Missing or invalid trajectory_log');
|
|
131
|
+
} else {
|
|
132
|
+
if (envelope.trajectory_log.length > MAX_STEPS_PER_ENVELOPE) {
|
|
133
|
+
errors.push(`trajectory_log exceeds maximum of ${MAX_STEPS_PER_ENVELOPE} steps (got ${envelope.trajectory_log.length})`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const now = Date.now();
|
|
137
|
+
const sevenDaysAgo = now - SEVEN_DAYS_MS;
|
|
138
|
+
const futureLimit = now + ONE_HOUR_MS;
|
|
139
|
+
|
|
140
|
+
for (let i = 0; i < Math.min(envelope.trajectory_log.length, MAX_STEPS_PER_ENVELOPE); i++) {
|
|
141
|
+
const step = envelope.trajectory_log[i];
|
|
142
|
+
if (!STEP_TYPES.includes(step.type)) {
|
|
143
|
+
errors.push(`Invalid step type "${step.type}" at index ${i}`);
|
|
144
|
+
}
|
|
145
|
+
if (typeof step.step !== 'number' || !Number.isInteger(step.step) || step.step < 0 || step.step > MAX_STEP_NUMBER) {
|
|
146
|
+
errors.push(`step.step must be a non-negative integer, max ${MAX_STEP_NUMBER} at index ${i}`);
|
|
147
|
+
}
|
|
148
|
+
if (typeof step.timestamp !== 'number') {
|
|
149
|
+
errors.push(`Missing timestamp at index ${i}`);
|
|
150
|
+
} else {
|
|
151
|
+
const tsMs = step.timestamp < 1e12 ? step.timestamp * 1000 : step.timestamp;
|
|
152
|
+
if (tsMs < sevenDaysAgo || tsMs > futureLimit) {
|
|
153
|
+
errors.push(`Timestamp out of range at index ${i} (must be within last 7 days, max 1 hour in future)`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (step.content !== undefined && typeof step.content === 'string' && step.content.length > MAX_STEP_CONTENT_LENGTH) {
|
|
157
|
+
errors.push(`step.content exceeds ${MAX_STEP_CONTENT_LENGTH} characters at index ${i}`);
|
|
158
|
+
}
|
|
159
|
+
if (step.token_count !== undefined) {
|
|
160
|
+
if (typeof step.token_count !== 'number' || step.token_count < 0 || step.token_count > MAX_TOKEN_COUNT) {
|
|
161
|
+
errors.push(`step.token_count must be 0-${MAX_TOKEN_COUNT} at index ${i}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return { valid: errors.length === 0, errors };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function validateSessionClose(envelope) {
|
|
171
|
+
const errors = [];
|
|
172
|
+
|
|
173
|
+
if (!envelope.session_id || typeof envelope.session_id !== 'string') {
|
|
174
|
+
errors.push('Missing or invalid session_id');
|
|
175
|
+
}
|
|
176
|
+
if (envelope.type !== 'SESSION_CLOSE') {
|
|
177
|
+
errors.push('Invalid type for SESSION_CLOSE envelope');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Attestation validation
|
|
181
|
+
if (!envelope.attestation || typeof envelope.attestation !== 'object') {
|
|
182
|
+
errors.push('Missing attestation');
|
|
183
|
+
} else {
|
|
184
|
+
if (typeof envelope.attestation.session_hmac !== 'string' || !HEX_64.test(envelope.attestation.session_hmac)) {
|
|
185
|
+
errors.push('attestation.session_hmac must be exactly 64 hex characters');
|
|
186
|
+
}
|
|
187
|
+
if (typeof envelope.attestation.sequence !== 'number' || !Number.isInteger(envelope.attestation.sequence) || envelope.attestation.sequence < 0 || envelope.attestation.sequence > 1_000_000) {
|
|
188
|
+
errors.push('attestation.sequence must be a non-negative integer, max 1000000');
|
|
189
|
+
}
|
|
190
|
+
if (typeof envelope.attestation.app_version_hash !== 'string' || !HEX_64.test(envelope.attestation.app_version_hash)) {
|
|
191
|
+
errors.push('attestation.app_version_hash must be exactly 64 hex characters');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Outcome validation
|
|
196
|
+
if (!envelope.outcome || typeof envelope.outcome !== 'object') {
|
|
197
|
+
errors.push('Missing outcome');
|
|
198
|
+
} else {
|
|
199
|
+
if (!VALID_OUTCOME_STATUSES.includes(envelope.outcome.status)) {
|
|
200
|
+
errors.push(`outcome.status must be one of: ${VALID_OUTCOME_STATUSES.join(', ')}`);
|
|
201
|
+
}
|
|
202
|
+
if (typeof envelope.outcome.total_steps !== 'number' || !Number.isInteger(envelope.outcome.total_steps) || envelope.outcome.total_steps < 0 || envelope.outcome.total_steps > MAX_OUTCOME_NUMERIC) {
|
|
203
|
+
errors.push('Missing or invalid outcome.total_steps');
|
|
204
|
+
}
|
|
205
|
+
if (typeof envelope.outcome.total_chunks !== 'number' || !Number.isInteger(envelope.outcome.total_chunks) || envelope.outcome.total_chunks < 0 || envelope.outcome.total_chunks > MAX_OUTCOME_NUMERIC) {
|
|
206
|
+
errors.push('Missing or invalid outcome.total_chunks');
|
|
207
|
+
}
|
|
208
|
+
const numericFields = ['user_interventions', 'total_tokens', 'duration_seconds', 'files_modified', 'errors_encountered', 'errors_recovered', 'coordination_events'];
|
|
209
|
+
for (const field of numericFields) {
|
|
210
|
+
if (envelope.outcome[field] !== undefined) {
|
|
211
|
+
const v = envelope.outcome[field];
|
|
212
|
+
if (typeof v !== 'number' || !Number.isInteger(v) || v < 0 || v > MAX_OUTCOME_NUMERIC) {
|
|
213
|
+
errors.push(`outcome.${field} must be a non-negative integer, max ${MAX_OUTCOME_NUMERIC}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return { valid: errors.length === 0, errors };
|
|
220
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
|
+
|
|
3
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
4
|
+
import assert from 'node:assert/strict';
|
|
5
|
+
import { mkdtempSync, rmSync, existsSync, readFileSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { tmpdir } from 'node:os';
|
|
8
|
+
import { ConsentManager } from '../../client/consent.js';
|
|
9
|
+
|
|
10
|
+
describe('ConsentManager', () => {
|
|
11
|
+
let tmpDir, dbPath, manager;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'consent-test-'));
|
|
15
|
+
dbPath = join(tmpDir, 'consent.db');
|
|
16
|
+
manager = new ConsentManager(dbPath);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
manager.close();
|
|
21
|
+
rmSync(tmpDir, { recursive: true });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('opt in then isOptedIn returns true', () => {
|
|
25
|
+
manager.recordConsent('user1', true, '1.0');
|
|
26
|
+
assert.equal(manager.isOptedIn('user1'), true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('opt out then isOptedIn returns false', () => {
|
|
30
|
+
manager.recordConsent('user1', true, '1.0');
|
|
31
|
+
manager.revokeConsent('user1');
|
|
32
|
+
assert.equal(manager.isOptedIn('user1'), false);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('no consent record returns false', () => {
|
|
36
|
+
assert.equal(manager.isOptedIn('nonexistent'), false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('version mismatch returns false', () => {
|
|
40
|
+
manager.recordConsent('user1', true, '0.9');
|
|
41
|
+
assert.equal(manager.isOptedIn('user1'), false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('getOptedInCount counts correctly', () => {
|
|
45
|
+
manager.recordConsent('user1', true, '1.0');
|
|
46
|
+
manager.recordConsent('user2', true, '1.0');
|
|
47
|
+
manager.recordConsent('user3', false, '1.0');
|
|
48
|
+
assert.equal(manager.getOptedInCount(), 2);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('getConsentHistory returns all records', () => {
|
|
52
|
+
manager.recordConsent('user1', true, '1.0', { source: 'ui' });
|
|
53
|
+
manager.revokeConsent('user1');
|
|
54
|
+
const history = manager.getConsentHistory('user1');
|
|
55
|
+
assert.equal(history.length, 2);
|
|
56
|
+
assert.equal(history[0].opted_in, true);
|
|
57
|
+
assert.deepEqual(history[0].metadata, { source: 'ui' });
|
|
58
|
+
assert.equal(history[1].opted_in, false);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('ConsentManager.getOrCreateUserId', () => {
|
|
63
|
+
let tmpDir, userIdPath;
|
|
64
|
+
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'userid-test-'));
|
|
67
|
+
userIdPath = join(tmpDir, 'user_id');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
afterEach(() => {
|
|
71
|
+
rmSync(tmpDir, { recursive: true });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('creates user_id file and returns id', () => {
|
|
75
|
+
const id = ConsentManager.getOrCreateUserId(userIdPath);
|
|
76
|
+
assert.ok(id.length > 0);
|
|
77
|
+
assert.ok(existsSync(userIdPath));
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('returns same id on second call', () => {
|
|
81
|
+
const id1 = ConsentManager.getOrCreateUserId(userIdPath);
|
|
82
|
+
const id2 = ConsentManager.getOrCreateUserId(userIdPath);
|
|
83
|
+
assert.equal(id1, id2);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('ConsentManager.isCaptureEnabled', () => {
|
|
88
|
+
let tmpDir;
|
|
89
|
+
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'capture-test-'));
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
afterEach(() => {
|
|
95
|
+
rmSync(tmpDir, { recursive: true });
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('returns false when no user_id file exists', () => {
|
|
99
|
+
const result = ConsentManager.isCaptureEnabled(join(tmpDir, 'no_file'), join(tmpDir, 'c.db'));
|
|
100
|
+
assert.equal(result, false);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('returns false when user not opted in', () => {
|
|
104
|
+
const uidPath = join(tmpDir, 'user_id');
|
|
105
|
+
const uid = ConsentManager.getOrCreateUserId(uidPath);
|
|
106
|
+
const dbPath = join(tmpDir, 'consent.db');
|
|
107
|
+
const result = ConsentManager.isCaptureEnabled(uidPath, dbPath);
|
|
108
|
+
assert.equal(result, false);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('returns true when user is opted in', () => {
|
|
112
|
+
const uidPath = join(tmpDir, 'user_id');
|
|
113
|
+
const uid = ConsentManager.getOrCreateUserId(uidPath);
|
|
114
|
+
const dbPath = join(tmpDir, 'consent.db');
|
|
115
|
+
const mgr = new ConsentManager(dbPath);
|
|
116
|
+
mgr.recordConsent(uid, true, '1.0');
|
|
117
|
+
mgr.close();
|
|
118
|
+
const result = ConsentManager.isCaptureEnabled(uidPath, dbPath);
|
|
119
|
+
assert.equal(result, true);
|
|
120
|
+
});
|
|
121
|
+
});
|