pi-harness-runtime 0.10.13 → 0.10.15
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/harness/notification-events.ts +2 -2
- package/package.json +4 -7
- package/packages/auth/src/minimax-browser-auth.js +889 -0
- package/packages/capability-registry/src/types.js +10 -0
- package/packages/checkpoint/src/checkpoint-manager.js +29 -0
- package/packages/clipboard/src/copy-sync.js +169 -0
- package/packages/clipboard/src/gist-relay.js +185 -0
- package/packages/clipboard/src/github-login.js +68 -0
- package/packages/config-capture/src/index.js +268 -0
- package/packages/cookie-sanitizer/src/atomic-write.js +66 -0
- package/packages/cookie-sanitizer/src/detect-format.js +87 -0
- package/packages/cookie-sanitizer/src/index.js +38 -0
- package/packages/cookie-sanitizer/src/infer-provider.js +95 -0
- package/packages/cookie-sanitizer/src/normalize.js +74 -0
- package/packages/cookie-sanitizer/src/parse-json.js +107 -0
- package/packages/cookie-sanitizer/src/parse-netscape.js +98 -0
- package/packages/cookie-sanitizer/src/sync.js +268 -0
- package/packages/cookie-sanitizer/src/types.js +12 -0
- package/packages/cookie-sanitizer/src/watcher.js +147 -0
- package/packages/evaluation-engine/src/engine.js +343 -0
- package/packages/evaluation-engine/src/index.js +7 -0
- package/packages/evaluation-engine/src/types.js +14 -0
- package/packages/event-store/src/types.js +5 -0
- package/packages/experience-replay/src/index.js +6 -0
- package/packages/experience-replay/src/replay.js +228 -0
- package/packages/experience-replay/src/types.js +6 -0
- package/packages/learning-engine/src/engine.js +294 -0
- package/packages/learning-engine/src/index.js +7 -0
- package/packages/learning-engine/src/types.js +63 -0
- package/packages/memory-engine/src/engine.js +507 -0
- package/packages/memory-engine/src/index.js +7 -0
- package/packages/memory-engine/src/types.js +39 -0
- package/packages/model-registry/src/types.js +5 -0
- package/packages/performance-optimizer/src/index.js +6 -0
- package/packages/performance-optimizer/src/optimizer.js +304 -0
- package/packages/performance-optimizer/src/types.js +6 -0
- package/packages/projection-engine/src/types.js +5 -0
- package/packages/providers/src/provider-id.js +112 -0
- package/packages/quota-manager/src/quota-manager.js +259 -0
- package/packages/quota-manager/src/tui-usage-monitor.js +267 -0
- package/packages/todo-bd-sync/src/detector.js +131 -0
- package/packages/todo-bd-sync/src/extension.js +104 -0
- package/packages/todo-bd-sync/src/sync.js +289 -0
- package/packages/todo-bd-sync/src/task-analyzer.js +239 -0
- package/packages/todo-bd-sync/src/types.js +66 -0
- package/packages/token-estimation/src/index.js +114 -0
- package/packages/types/src/agent-worker-types.js +41 -0
- package/packages/types/src/ai-providers.js +66 -0
- package/packages/types/src/runtime-types.js +3 -0
- package/packages/workflow-events/src/types.js +5 -0
- package/packages/write-review/src/blackboard.js +228 -0
- package/packages/write-review/src/gate.js +137 -0
- package/packages/write-review/src/index.js +17 -0
- package/packages/write-review/src/injection.js +141 -0
- package/packages/write-review/src/review.js +153 -0
- package/packages/write-review/src/trigger.js +106 -0
- package/packages/write-review/src/types.js +25 -0
- package/IMPLEMENTATION/RFC-0010/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0010/AI_BRIEF.md +0 -20
- package/IMPLEMENTATION/RFC-0010/FILES.md +0 -11
- package/IMPLEMENTATION/RFC-0010/TASKS.md +0 -10
- package/IMPLEMENTATION/RFC-0010/TESTS.md +0 -6
- package/IMPLEMENTATION/RFC-0011/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0011/AI_BRIEF.md +0 -19
- package/IMPLEMENTATION/RFC-0011/FILES.md +0 -11
- package/IMPLEMENTATION/RFC-0011/TASKS.md +0 -10
- package/IMPLEMENTATION/RFC-0011/TESTS.md +0 -6
- package/IMPLEMENTATION/RFC-0012/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0012/AI_BRIEF.md +0 -18
- package/IMPLEMENTATION/RFC-0012/FILES.md +0 -11
- package/IMPLEMENTATION/RFC-0012/TASKS.md +0 -10
- package/IMPLEMENTATION/RFC-0012/TESTS.md +0 -6
- package/IMPLEMENTATION/RFC-0013/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0013/AI_BRIEF.md +0 -19
- package/IMPLEMENTATION/RFC-0013/FILES.md +0 -11
- package/IMPLEMENTATION/RFC-0013/TASKS.md +0 -10
- package/IMPLEMENTATION/RFC-0013/TESTS.md +0 -6
- package/IMPLEMENTATION/RFC-0014/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0014/AI_BRIEF.md +0 -20
- package/IMPLEMENTATION/RFC-0014/FILES.md +0 -11
- package/IMPLEMENTATION/RFC-0014/TASKS.md +0 -10
- package/IMPLEMENTATION/RFC-0014/TESTS.md +0 -6
- package/IMPLEMENTATION/RFC-0015/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0015/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0015/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0015/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0015/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0016/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0016/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0016/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0016/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0016/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0017/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0017/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0017/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0017/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0017/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0018/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0018/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0018/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0018/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0018/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0019/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0019/AI_BRIEF.md +0 -18
- package/IMPLEMENTATION/RFC-0019/TASKS.md +0 -10
- package/IMPLEMENTATION/RFC-0020/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0020/AI_BRIEF.md +0 -18
- package/IMPLEMENTATION/RFC-0020/TASKS.md +0 -10
- package/IMPLEMENTATION/RFC-0021/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0021/AI_BRIEF.md +0 -18
- package/IMPLEMENTATION/RFC-0021/TASKS.md +0 -10
- package/IMPLEMENTATION/RFC-0022/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0022/AI_BRIEF.md +0 -18
- package/IMPLEMENTATION/RFC-0022/TASKS.md +0 -10
- package/IMPLEMENTATION/RFC-0023/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0023/AI_BRIEF.md +0 -18
- package/IMPLEMENTATION/RFC-0023/TASKS.md +0 -10
- package/IMPLEMENTATION/RFC-0024/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0024/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0025/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0025/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0026/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0026/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0027/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0027/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0028/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0028/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0029/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0029/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0030/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0030/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0031/AI_BRIEF.md +0 -45
- package/IMPLEMENTATION/RFC-0031/TASKS.md +0 -48
- package/IMPLEMENTATION/RFC-0032/AI_BRIEF.md +0 -45
- package/IMPLEMENTATION/RFC-0032/TASKS.md +0 -44
- package/IMPLEMENTATION/RFC-0033/AI_BRIEF.md +0 -46
- package/IMPLEMENTATION/RFC-0033/TASKS.md +0 -49
- package/IMPLEMENTATION/RFC-0034/AI_BRIEF.md +0 -54
- package/IMPLEMENTATION/RFC-0034/TASKS.md +0 -57
- package/IMPLEMENTATION/RFC-0035/AI_BRIEF.md +0 -55
- package/IMPLEMENTATION/RFC-0035/TASKS.md +0 -75
- package/IMPLEMENTATION/RFC-0036/AI_BRIEF.md +0 -62
- package/IMPLEMENTATION/RFC-0036/TASKS.md +0 -60
- package/IMPLEMENTATION/RFC-0037/AI_BRIEF.md +0 -59
- package/IMPLEMENTATION/RFC-0037/TASKS.md +0 -63
- package/IMPLEMENTATION/RFC-0038/AI_BRIEF.md +0 -67
- package/IMPLEMENTATION/RFC-0038/TASKS.md +0 -65
- package/IMPLEMENTATION/RFC-0039/AI_BRIEF.md +0 -68
- package/IMPLEMENTATION/RFC-0039/TASKS.md +0 -74
- package/IMPLEMENTATION/RFC-0040/AI_BRIEF.md +0 -79
- package/IMPLEMENTATION/RFC-0040/TASKS.md +0 -77
- package/IMPLEMENTATION/RFC-0041/ACCEPTANCE_CRITERIA.md +0 -8
- package/IMPLEMENTATION/RFC-0041/AI_BRIEF.md +0 -26
- package/IMPLEMENTATION/RFC-0041/FILES.md +0 -12
- package/IMPLEMENTATION/RFC-0041/TASKS.md +0 -12
- package/IMPLEMENTATION/RFC-0041/TESTS.md +0 -12
- package/IMPLEMENTATION/RFC-0042/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0042/AI_BRIEF.md +0 -5
- package/IMPLEMENTATION/RFC-0042/FILES.md +0 -14
- package/IMPLEMENTATION/RFC-0042/TASKS.md +0 -12
- package/IMPLEMENTATION/RFC-0042/TESTS.md +0 -11
- package/IMPLEMENTATION/RFC-0043/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0043/AI_BRIEF.md +0 -5
- package/IMPLEMENTATION/RFC-0043/FILES.md +0 -14
- package/IMPLEMENTATION/RFC-0043/TASKS.md +0 -12
- package/IMPLEMENTATION/RFC-0043/TESTS.md +0 -10
- package/IMPLEMENTATION/RFC-0044/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0044/AI_BRIEF.md +0 -5
- package/IMPLEMENTATION/RFC-0044/FILES.md +0 -13
- package/IMPLEMENTATION/RFC-0044/TASKS.md +0 -12
- package/IMPLEMENTATION/RFC-0044/TESTS.md +0 -10
- package/IMPLEMENTATION/RFC-0045/ACCEPTANCE_CRITERIA.md +0 -30
- package/IMPLEMENTATION/RFC-0045/AI_BRIEF.md +0 -53
- package/IMPLEMENTATION/RFC-0045/FILES.md +0 -13
- package/IMPLEMENTATION/RFC-0045/TASKS.md +0 -31
- package/IMPLEMENTATION/RFC-0045/TESTS.md +0 -62
- package/IMPLEMENTATION/RFC-0046/ACCEPTANCE_CRITERIA.md +0 -1
- package/IMPLEMENTATION/RFC-0046/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0046/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0046/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0046/TESTS.md +0 -1
- package/IMPLEMENTATION/RFC-0047/ACCEPTANCE_CRITERIA.md +0 -1
- package/IMPLEMENTATION/RFC-0047/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0047/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0047/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0047/TESTS.md +0 -1
- package/IMPLEMENTATION/RFC-0048/ACCEPTANCE_CRITERIA.md +0 -1
- package/IMPLEMENTATION/RFC-0048/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0048/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0048/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0048/TESTS.md +0 -1
- package/IMPLEMENTATION/RFC-0049/ACCEPTANCE_CRITERIA.md +0 -1
- package/IMPLEMENTATION/RFC-0049/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0049/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0049/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0049/TESTS.md +0 -1
- package/IMPLEMENTATION/RFC-0050/ACCEPTANCE_CRITERIA.md +0 -1
- package/IMPLEMENTATION/RFC-0050/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0050/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0050/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0050/TESTS.md +0 -1
- package/IMPLEMENTATION/RFC-0051/ACCEPTANCE_CRITERIA.md +0 -6
- package/IMPLEMENTATION/RFC-0051/AI_BRIEF.md +0 -20
- package/IMPLEMENTATION/RFC-0051/FILES.md +0 -8
- package/IMPLEMENTATION/RFC-0051/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0051/TESTS.md +0 -4
- package/IMPLEMENTATION/RFC-0052/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0052/AI_BRIEF.md +0 -19
- package/IMPLEMENTATION/RFC-0052/FILES.md +0 -8
- package/IMPLEMENTATION/RFC-0052/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0052/TESTS.md +0 -1
- package/IMPLEMENTATION/RFC-0053/ACCEPTANCE_CRITERIA.md +0 -8
- package/IMPLEMENTATION/RFC-0053/AI_BRIEF.md +0 -20
- package/IMPLEMENTATION/RFC-0053/FILES.md +0 -9
- package/IMPLEMENTATION/RFC-0053/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0053/TESTS.md +0 -1
- package/IMPLEMENTATION/RFC-0054/ACCEPTANCE_CRITERIA.md +0 -8
- package/IMPLEMENTATION/RFC-0054/AI_BRIEF.md +0 -19
- package/IMPLEMENTATION/RFC-0054/FILES.md +0 -8
- package/IMPLEMENTATION/RFC-0054/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0054/TESTS.md +0 -1
- package/IMPLEMENTATION/RFC-0055/ACCEPTANCE_CRITERIA.md +0 -8
- package/IMPLEMENTATION/RFC-0055/AI_BRIEF.md +0 -17
- package/IMPLEMENTATION/RFC-0055/FILES.md +0 -9
- package/IMPLEMENTATION/RFC-0055/TASKS.md +0 -3
- package/IMPLEMENTATION/RFC-0055/TESTS.md +0 -1
- package/IMPLEMENTATION/RFC-0056/ACCEPTANCE_CRITERIA.md +0 -6
- package/IMPLEMENTATION/RFC-0056/AI_BRIEF.md +0 -18
- package/IMPLEMENTATION/RFC-0056/FILES.md +0 -9
- package/IMPLEMENTATION/RFC-0056/TASKS.md +0 -9
- package/IMPLEMENTATION/RFC-0056/TESTS.md +0 -7
- package/IMPLEMENTATION/RFC-0057/ACCEPTANCE_CRITERIA.md +0 -5
- package/IMPLEMENTATION/RFC-0057/AI_BRIEF.md +0 -5
- package/IMPLEMENTATION/RFC-0057/FILES.md +0 -11
- package/IMPLEMENTATION/RFC-0057/TASKS.md +0 -9
- package/IMPLEMENTATION/RFC-0057/TESTS.md +0 -7
- package/IMPLEMENTATION/RFC-0058/ACCEPTANCE_CRITERIA.md +0 -6
- package/IMPLEMENTATION/RFC-0058/AI_BRIEF.md +0 -5
- package/IMPLEMENTATION/RFC-0058/FILES.md +0 -11
- package/IMPLEMENTATION/RFC-0058/TASKS.md +0 -9
- package/IMPLEMENTATION/RFC-0058/TESTS.md +0 -7
- package/IMPLEMENTATION/RFC-0059/ACCEPTANCE_CRITERIA.md +0 -6
- package/IMPLEMENTATION/RFC-0059/AI_BRIEF.md +0 -5
- package/IMPLEMENTATION/RFC-0059/FILES.md +0 -11
- package/IMPLEMENTATION/RFC-0059/TASKS.md +0 -9
- package/IMPLEMENTATION/RFC-0059/TESTS.md +0 -7
- package/IMPLEMENTATION/RFC-0060/ACCEPTANCE_CRITERIA.md +0 -7
- package/IMPLEMENTATION/RFC-0060/AI_BRIEF.md +0 -5
- package/IMPLEMENTATION/RFC-0060/FILES.md +0 -14
- package/IMPLEMENTATION/RFC-0060/TASKS.md +0 -12
- package/IMPLEMENTATION/RFC-0060/TESTS.md +0 -10
- package/IMPLEMENTATION/RFC-0061/ACCEPTANCE_CRITERIA.md +0 -1
- package/IMPLEMENTATION/RFC-0061/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0061/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0061/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0061/TESTS.md +0 -2
- package/IMPLEMENTATION/RFC-0062/ACCEPTANCE_CRITERIA.md +0 -1
- package/IMPLEMENTATION/RFC-0062/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0062/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0062/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0062/TESTS.md +0 -2
- package/IMPLEMENTATION/RFC-0063/ACCEPTANCE_CRITERIA.md +0 -1
- package/IMPLEMENTATION/RFC-0063/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0063/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0063/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0063/TESTS.md +0 -2
- package/IMPLEMENTATION/RFC-0064/ACCEPTANCE_CRITERIA.md +0 -1
- package/IMPLEMENTATION/RFC-0064/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0064/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0064/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0064/TESTS.md +0 -2
- package/IMPLEMENTATION/RFC-0065/ACCEPTANCE_CRITERIA.md +0 -1
- package/IMPLEMENTATION/RFC-0065/AI_BRIEF.md +0 -1
- package/IMPLEMENTATION/RFC-0065/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0065/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0065/TESTS.md +0 -2
- package/IMPLEMENTATION/RFC-0066/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0066/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0066/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0066/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0066/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0067/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0067/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0067/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0067/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0067/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0068/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0068/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0068/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0068/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0068/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0069/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0069/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0069/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0069/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0069/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0070/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0070/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0070/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0070/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0070/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0071/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0071/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0071/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0071/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0071/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0072/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0072/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0072/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0072/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0072/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0073/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0073/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0073/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0073/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0073/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0074/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0074/AI_BRIEF.md +0 -17
- package/IMPLEMENTATION/RFC-0074/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0074/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0074/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0075/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0075/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0075/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0075/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0075/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0076/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0076/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0076/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0076/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0076/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0077/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0077/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0077/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0077/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0077/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0078/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0078/AI_BRIEF.md +0 -17
- package/IMPLEMENTATION/RFC-0078/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0078/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0078/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0079/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0079/AI_BRIEF.md +0 -7
- package/IMPLEMENTATION/RFC-0079/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0079/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0079/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0080/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0080/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0080/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0080/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0080/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0081/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0081/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0081/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0081/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0081/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0082/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0082/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0082/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0082/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0082/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0083/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0083/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0083/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0083/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0083/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0084/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0084/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0084/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0084/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0084/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0085/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0085/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0085/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0085/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0085/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0086/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0086/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0086/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0086/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0086/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0087/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0087/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0087/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0087/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0087/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0088/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0088/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0088/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0088/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0088/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0089/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0089/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0089/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0089/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0089/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0090/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0090/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0090/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0090/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0090/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0091/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0091/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0091/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0091/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0091/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0092/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0092/AI_BRIEF.md +0 -20
- package/IMPLEMENTATION/RFC-0092/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0092/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0092/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0093/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0093/AI_BRIEF.md +0 -22
- package/IMPLEMENTATION/RFC-0093/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0093/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0093/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0094/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0094/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0094/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0094/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0094/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0095/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0095/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0095/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0095/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0095/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0096/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0096/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0096/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0096/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0096/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0097/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0097/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0097/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0097/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0097/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0098/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0098/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0098/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0098/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0098/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0099/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0099/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0099/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0099/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0099/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0100/ACCEPTANCE_CRITERIA.md +0 -2
- package/IMPLEMENTATION/RFC-0100/AI_BRIEF.md +0 -2
- package/IMPLEMENTATION/RFC-0100/FILES.md +0 -2
- package/IMPLEMENTATION/RFC-0100/TASKS.md +0 -4
- package/IMPLEMENTATION/RFC-0100/TESTS.md +0 -3
- package/IMPLEMENTATION/RFC-0101/ACCEPTANCE_CRITERIA.md +0 -74
- package/IMPLEMENTATION/RFC-0101/AI_BRIEF.md +0 -80
- package/IMPLEMENTATION/RFC-0101/FILES.md +0 -82
- package/IMPLEMENTATION/RFC-0101/TASKS.md +0 -92
- package/IMPLEMENTATION/RFC-0101/TESTS.md +0 -127
- package/IMPLEMENTATION/RFC-0102/ACCEPTANCE_CRITERIA.md +0 -33
- package/IMPLEMENTATION/RFC-0102/AI_BRIEF.md +0 -34
- package/IMPLEMENTATION/RFC-0102/FILES.md +0 -73
- package/IMPLEMENTATION/RFC-0102/TASKS.md +0 -75
- package/IMPLEMENTATION/RFC-0102/TESTS.md +0 -78
- package/IMPLEMENTATION/RFC-0103/ACCEPTANCE_CRITERIA.md +0 -45
- package/IMPLEMENTATION/RFC-0103/AI_BRIEF.md +0 -46
- package/IMPLEMENTATION/RFC-0103/FILES.md +0 -121
- package/IMPLEMENTATION/RFC-0103/TASKS.md +0 -97
- package/IMPLEMENTATION/RFC-0103/TESTS.md +0 -118
- package/IMPLEMENTATION/RFC-0104/ACCEPTANCE_CRITERIA.md +0 -29
- package/IMPLEMENTATION/RFC-0104/FILES.md +0 -33
- package/IMPLEMENTATION/RFC-0105/ACCEPTANCE_CRITERIA.md +0 -29
- package/IMPLEMENTATION/RFC-0105/FILES.md +0 -41
- package/IMPLEMENTATION/RFC-0106/ACCEPTANCE_CRITERIA.md +0 -29
- package/IMPLEMENTATION/RFC-0106/FILES.md +0 -43
- package/RFC/0001_LOOP_RUNTIME.md +0 -14
- package/RFC/0002_PROVIDER_ADAPTER.md +0 -3
- package/RFC/0003_QUOTA_MANAGER.md +0 -3
- package/RFC/0004_PLAYWRIGHT_ADAPTER.md +0 -3
- package/RFC/0005_GIT_WORKTREE.md +0 -3
- package/RFC/0006_CHECKPOINT_MANAGER.md +0 -56
- package/RFC/0007_SCHEDULER.md +0 -32
- package/RFC/0008_PROVIDER_ROUTER.md +0 -44
- package/RFC/0009_SHARED_CONTEXT.md +0 -32
- package/RFC/0010_CONTEXT_WINDOW_MANAGER.md +0 -50
- package/RFC/0011_SHARED_BLACKBOARD.md +0 -42
- package/RFC/0012_AGENT_HANDOFF_PROTOCOL.md +0 -41
- package/RFC/0013_E2E_TEST_ENGINE.md +0 -42
- package/RFC/0014_PROJECT_DETECTOR_AND_TEST_DATA_ENGINE.md +0 -35
- package/RFC/0015_JOB_STATE_MACHINE.md +0 -45
- package/RFC/0016_TASK_GRAPH.md +0 -31
- package/RFC/0017_MASTER_PLANNER.md +0 -32
- package/RFC/0018_REPAIR_ENGINE.md +0 -36
- package/RFC/0019_AUTO_COMPACT_AND_CONTINUE.md +0 -51
- package/RFC/0020_OUTPUT_TOKEN_LIMIT_HANDLER.md +0 -49
- package/RFC/0021_PARTIAL_RESPONSE_RECOVERY.md +0 -49
- package/RFC/0022_NOTIFICATION_CENTER.md +0 -47
- package/RFC/0023_LOCAL_BROWSER_AGENT.md +0 -67
- package/RFC/0024_LOCAL_RUNTIME_AGENT.md +0 -3
- package/RFC/0025_COMMAND_EXECUTOR.md +0 -3
- package/RFC/0026_WORKSPACE_MANAGER.md +0 -3
- package/RFC/0027_RUNTIME_API.md +0 -3
- package/RFC/0028_POLICY_ENGINE.md +0 -3
- package/RFC/0029_DEEPAGENTS_ADAPTER.md +0 -2
- package/RFC/0030_AGENT_WORKER_INTERFACE.md +0 -2
- package/RFC/0031_PROVIDER_ADAPTER_SDK.md +0 -171
- package/RFC/0032_CHECKPOINT_ENGINE.md +0 -217
- package/RFC/0033_SESSION_MANAGER.md +0 -262
- package/RFC/0034_OBSERVABILITY.md +0 -416
- package/RFC/0035_ROADMAP_V1.md +0 -295
- package/RFC/0036_CODE_REVIEW_ENGINE.md +0 -430
- package/RFC/0037_CODE_GENERATION_PIPELINE.md +0 -504
- package/RFC/0038_FRAMEWORK_DETECTOR.md +0 -466
- package/RFC/0039_TEST_DATA_GENERATOR.md +0 -504
- package/RFC/0040_FRAMEWORK_PLUGIN_SDK.md +0 -543
- package/RFC/0041_PROMPT_COMPILER.md +0 -232
- package/RFC/0042_CONTEXT_COMPILER.md +0 -216
- package/RFC/0043_REQUIREMENT_COMPILER.md +0 -211
- package/RFC/0044_TASK_COMPILER.md +0 -207
- package/RFC/0045_PROJECT_ANALYZER.md +0 -246
- package/RFC/0046_DEPENDENCY_ANALYZER.md +0 -14
- package/RFC/0047_REPOSITORY_KNOWLEDGE_GRAPH.md +0 -14
- package/RFC/0048_CODE_MERGE_ENGINE.md +0 -14
- package/RFC/0049_CONFLICT_RESOLUTION_ENGINE.md +0 -14
- package/RFC/0050_DOCUMENTATION_GENERATOR.md +0 -14
- package/RFC/0051_CAPABILITY_REGISTRY.md +0 -144
- package/RFC/0052_SKILL_REGISTRY.md +0 -167
- package/RFC/0053_MODEL_REGISTRY.md +0 -214
- package/RFC/0054_PROVIDER_ROUTER.md +0 -239
- package/RFC/0055_COST_OPTIMIZER.md +0 -285
- package/RFC/0056_PERFORMANCE_OPTIMIZER.md +0 -118
- package/RFC/0057_EVALUATION_ENGINE.md +0 -116
- package/RFC/0058_LEARNING_ENGINE.md +0 -113
- package/RFC/0059_EXPERIENCE_REPLAY.md +0 -107
- package/RFC/0060_MEMORY_ENGINE_OKF.md +0 -152
- package/RFC/0061_FRAPPE_PLUGIN.md +0 -9
- package/RFC/0062_NEXTJS_PLUGIN.md +0 -9
- package/RFC/0063_REACT_VITE_PLUGIN.md +0 -9
- package/RFC/0064_DJANGO_PLUGIN.md +0 -9
- package/RFC/0065_LARAVEL_PLUGIN.md +0 -9
- package/RFC/0066_GENERIC_WEB_PLUGIN.md +0 -24
- package/RFC/0067_CLI_PLUGIN_SDK.md +0 -101
- package/RFC/0068_MCP_ADAPTER.md +0 -114
- package/RFC/0069_GOOGLE_A2A_ADAPTER.md +0 -139
- package/RFC/0070_OPENAI_CODEX_ADAPTER.md +0 -134
- package/RFC/0071_REQUIREMENT_INTAKE.md +0 -95
- package/RFC/0072_PROJECT_BOOTSTRAP.md +0 -82
- package/RFC/0073_ARCHITECTURE_GENERATOR.md +0 -85
- package/RFC/0074_SPRINT_PLANNER.md +0 -61
- package/RFC/0075_MILESTONE_MANAGER.md +0 -58
- package/RFC/0076_BACKLOG_MANAGER.md +0 -24
- package/RFC/0077_HUMAN_APPROVAL_GATE.md +0 -24
- package/RFC/0078_RELEASE_MANAGER.md +0 -24
- package/RFC/0079_VERSION_MANAGER.md +0 -24
- package/RFC/0080_DEPLOYMENT_PIPELINE.md +0 -24
- package/RFC/0081_MULTI_USER_RUNTIME.md +0 -24
- package/RFC/0082_RBAC.md +0 -24
- package/RFC/0083_AUDIT_TRAIL.md +0 -24
- package/RFC/0084_DASHBOARD.md +0 -24
- package/RFC/0085_ANALYTICS.md +0 -24
- package/RFC/0086_DISTRIBUTED_RUNTIME.md +0 -24
- package/RFC/0087_CLUSTER_MANAGER.md +0 -24
- package/RFC/0088_RUNTIME_FEDERATION.md +0 -24
- package/RFC/0089_HIGH_AVAILABILITY.md +0 -24
- package/RFC/0090_DISASTER_RECOVERY.md +0 -24
- package/RFC/0091_AUTONOMOUS_ARCHITECTURE_REVIEW.md +0 -24
- package/RFC/0092_AUTONOMOUS_REFACTORING.md +0 -24
- package/RFC/0093_AUTONOMOUS_BUG_FIXING.md +0 -24
- package/RFC/0094_AUTONOMOUS_PERFORMANCE_TUNING.md +0 -24
- package/RFC/0095_AUTONOMOUS_SECURITY_REVIEW.md +0 -24
- package/RFC/0096_AUTONOMOUS_COST_OPTIMIZATION.md +0 -24
- package/RFC/0097_AUTONOMOUS_DOCUMENTATION.md +0 -24
- package/RFC/0098_AUTONOMOUS_KNOWLEDGE_MANAGEMENT.md +0 -24
- package/RFC/0099_RUNTIME_EVOLUTION_ENGINE.md +0 -24
- package/RFC/0100_SELF_DEVELOPING_RUNTIME.md +0 -24
- package/RFC/0101_AUTONOMOUS_OPERATIONS_RUNTIME.md +0 -1105
- package/RFC/0102_CONTEXT_ENGINEERING_PIPELINE.md +0 -508
- package/RFC/0103_SESSION_EVENT_RUNTIME_AGENT_COMMUNICATION_LAYER.md +0 -616
- package/RFC/0104_DISTRIBUTED_AGENT_COMMUNICATION.md +0 -143
- package/RFC/0105_DISTRIBUTED_KNOWLEDGE_RETRIEVAL.md +0 -301
- package/RFC/0106_KNOWLEDGE_GRAPH_PROVENANCE.md +0 -368
- package/RFC/README.md +0 -11
- package/packages/event-bus/dist/tsconfig.tsbuildinfo +0 -1
- package/packages/provider-adapter-sdk/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EditThisCookie / Chrome devtools JSON cookie export parser.
|
|
3
|
+
*
|
|
4
|
+
* Browser extension "EditThisCookie" and Chrome devtools both export
|
|
5
|
+
* cookies in this canonical shape (Chrome/Edge/Chromium cookie store):
|
|
6
|
+
*
|
|
7
|
+
* ```json
|
|
8
|
+
* [
|
|
9
|
+
* {
|
|
10
|
+
* "domain": ".minimax.io",
|
|
11
|
+
* "expirationDate": 1760000000.123,
|
|
12
|
+
* "hostOnly": false,
|
|
13
|
+
* "httpOnly": true,
|
|
14
|
+
* "name": "_token",
|
|
15
|
+
* "path": "/",
|
|
16
|
+
* "sameSite": "no_restriction",
|
|
17
|
+
* "secure": true,
|
|
18
|
+
* "session": false,
|
|
19
|
+
* "storeId": "0",
|
|
20
|
+
* "value": "...",
|
|
21
|
+
* "id": 1
|
|
22
|
+
* }
|
|
23
|
+
* ]
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Some tools may export a single object (not an array). Handle both.
|
|
27
|
+
*
|
|
28
|
+
* SEC-001: Cookie VALUES are returned as strings in-memory. Never logged.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Parse EditThisCookie / Chrome devtools JSON export.
|
|
32
|
+
*
|
|
33
|
+
* Accepts:
|
|
34
|
+
* - top-level array of records
|
|
35
|
+
* - top-level single object
|
|
36
|
+
*
|
|
37
|
+
* Skips:
|
|
38
|
+
* - non-object entries
|
|
39
|
+
* - records without non-empty name+value
|
|
40
|
+
*
|
|
41
|
+
* Never throws; returns empty array on parse failure.
|
|
42
|
+
*/
|
|
43
|
+
export function parseEditThisCookieJson(text) {
|
|
44
|
+
if (typeof text !== "string" || text.length === 0)
|
|
45
|
+
return [];
|
|
46
|
+
let data;
|
|
47
|
+
try {
|
|
48
|
+
data = JSON.parse(text);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
const records = [];
|
|
54
|
+
if (Array.isArray(data)) {
|
|
55
|
+
for (const item of data) {
|
|
56
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
57
|
+
records.push(item);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
62
|
+
records.push(data);
|
|
63
|
+
}
|
|
64
|
+
const cookies = [];
|
|
65
|
+
for (const r of records) {
|
|
66
|
+
const name = asString(r.name);
|
|
67
|
+
const value = asString(r.value);
|
|
68
|
+
if (!name || !value)
|
|
69
|
+
continue;
|
|
70
|
+
const expires = asExpires(r.expirationDate, r.session);
|
|
71
|
+
cookies.push({
|
|
72
|
+
name,
|
|
73
|
+
value,
|
|
74
|
+
domain: asString(r.domain) ?? "",
|
|
75
|
+
path: asString(r.path) ?? "/",
|
|
76
|
+
expires,
|
|
77
|
+
secure: asBool(r.secure) ?? false,
|
|
78
|
+
httpOnly: asBool(r.httpOnly) ?? false,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return cookies;
|
|
82
|
+
}
|
|
83
|
+
function asString(v) {
|
|
84
|
+
if (typeof v === "string" && v.length > 0)
|
|
85
|
+
return v;
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
function asBool(v) {
|
|
89
|
+
if (typeof v === "boolean")
|
|
90
|
+
return v;
|
|
91
|
+
if (v === 1 || v === "1" || v === "true" || v === "TRUE")
|
|
92
|
+
return true;
|
|
93
|
+
if (v === 0 || v === "0" || v === "false" || v === "FALSE")
|
|
94
|
+
return false;
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
function asExpires(v, session) {
|
|
98
|
+
if (session === true || session === "true")
|
|
99
|
+
return undefined;
|
|
100
|
+
if (typeof v === "number" && Number.isFinite(v)) {
|
|
101
|
+
// EditThisCookie uses unix-seconds (with millisecond decimals sometimes).
|
|
102
|
+
// If v > 1e12, it's milliseconds — convert.
|
|
103
|
+
const seconds = v > 1e12 ? Math.floor(v / 1000) : Math.floor(v);
|
|
104
|
+
return seconds > 0 ? seconds : undefined;
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Netscape-format cookie file parser.
|
|
3
|
+
*
|
|
4
|
+
* Format reference: https://curl.haxx.se/rfc/cookie_spec.html
|
|
5
|
+
*
|
|
6
|
+
* Each row is tab-separated, 7 columns:
|
|
7
|
+
* domain flag path secure expires name value
|
|
8
|
+
*
|
|
9
|
+
* - Lines starting with `# ` are comments (skipped).
|
|
10
|
+
* - Lines starting with `#HttpOnly_` are HTTP-only cookies
|
|
11
|
+
* (the leading `#HttpOnly_` is stripped, the rest is parsed normally).
|
|
12
|
+
* - Empty lines are skipped.
|
|
13
|
+
* - `expires` is Unix seconds; `0` or unparseable → session cookie.
|
|
14
|
+
* - Lines with fewer than 7 columns are skipped (malformed).
|
|
15
|
+
*
|
|
16
|
+
* SEC-001: Cookie values are returned as strings in-memory. They MUST
|
|
17
|
+
* never be logged. The scrubber in cookie-sanitizer applies value
|
|
18
|
+
* redaction before any path-touching log line.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Parse a Netscape-format cookie string into canonical records.
|
|
22
|
+
*
|
|
23
|
+
* Skips:
|
|
24
|
+
* - blank lines
|
|
25
|
+
* - comments (lines starting with `#` but not `#HttpOnly_`)
|
|
26
|
+
* - malformed rows (< 7 columns)
|
|
27
|
+
*
|
|
28
|
+
* Never throws; returns empty array if input is invalid.
|
|
29
|
+
*/
|
|
30
|
+
export function parseNetscape(text) {
|
|
31
|
+
if (typeof text !== "string" || text.length === 0)
|
|
32
|
+
return [];
|
|
33
|
+
const rows = [];
|
|
34
|
+
const lines = text.split(/\r?\n/);
|
|
35
|
+
for (const raw of lines) {
|
|
36
|
+
if (!raw)
|
|
37
|
+
continue;
|
|
38
|
+
let line = raw;
|
|
39
|
+
let httpOnly = false;
|
|
40
|
+
if (line.startsWith("#HttpOnly_")) {
|
|
41
|
+
httpOnly = true;
|
|
42
|
+
line = line.slice("#HttpOnly_".length);
|
|
43
|
+
}
|
|
44
|
+
else if (line.startsWith("#")) {
|
|
45
|
+
// Plain comment line (Netscape / curl spec).
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const cols = line.split("\t");
|
|
49
|
+
if (cols.length < 7)
|
|
50
|
+
continue;
|
|
51
|
+
const [domain, _flag, cookiePath, secure, expires, name, value] = cols;
|
|
52
|
+
if (!name || !value)
|
|
53
|
+
continue;
|
|
54
|
+
rows.push({
|
|
55
|
+
domain: (domain ?? "").trim(),
|
|
56
|
+
path: (cookiePath ?? "/").trim() || "/",
|
|
57
|
+
secure: (secure ?? "FALSE").toUpperCase() === "TRUE",
|
|
58
|
+
httpOnly,
|
|
59
|
+
expires: parseInt(expires ?? "0", 10) || 0,
|
|
60
|
+
name: name.trim(),
|
|
61
|
+
value, // intentional: keep as-is for in-memory pipeline; never log
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// Map to CanonicalCookie shape.
|
|
65
|
+
return rows.map((r) => ({
|
|
66
|
+
name: r.name,
|
|
67
|
+
value: r.value,
|
|
68
|
+
domain: r.domain,
|
|
69
|
+
path: r.path,
|
|
70
|
+
expires: r.expires === 0 ? undefined : r.expires,
|
|
71
|
+
secure: r.secure,
|
|
72
|
+
httpOnly: r.httpOnly,
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Serialize a list of canonical cookies back to Netscape format.
|
|
77
|
+
* Used by atomic-write.ts to produce the canonical cache.
|
|
78
|
+
*
|
|
79
|
+
* Output uses the canonical column order:
|
|
80
|
+
* domain flag path secure expires name value
|
|
81
|
+
*
|
|
82
|
+
* `flag` is FALSE per curl spec (HttpOnly is encoded as `#HttpOnly_`).
|
|
83
|
+
* Cookie values are NEVER logged during the round-trip.
|
|
84
|
+
*/
|
|
85
|
+
export function serializeNetscape(cookies) {
|
|
86
|
+
const out = ["# Netscape HTTP Cookie File", ""];
|
|
87
|
+
for (const c of cookies) {
|
|
88
|
+
if (!c.name || !c.value)
|
|
89
|
+
continue;
|
|
90
|
+
const domain = c.domain ?? "";
|
|
91
|
+
const path = c.path ?? "/";
|
|
92
|
+
const secure = c.secure ? "TRUE" : "FALSE";
|
|
93
|
+
const expires = c.expires != null ? String(c.expires) : "0";
|
|
94
|
+
const line = [domain, "FALSE", path, secure, expires, c.name, c.value].join("\t");
|
|
95
|
+
out.push(c.httpOnly ? `#HttpOnly_${line}` : line);
|
|
96
|
+
}
|
|
97
|
+
return out.join("\n") + "\n";
|
|
98
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync orchestrator — the heart of the sanitizer.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline (per run):
|
|
5
|
+
* 1. Enumerate files in the drop folder (one level + one sublevel).
|
|
6
|
+
* 2. Read each file. Detect format. Parse.
|
|
7
|
+
* 3. Concatenate cookies from all parsed files.
|
|
8
|
+
* 4. Infer provider from filename + cookies.
|
|
9
|
+
* 5. Normalize (dedupe, expire, domain-match).
|
|
10
|
+
* 6. Serialize to Netscape and write to the canonical cache (atomic).
|
|
11
|
+
*
|
|
12
|
+
* Returns a SyncResult. Never throws — returns structured errors in `result.errors`.
|
|
13
|
+
*
|
|
14
|
+
* Sec-001: Cookie VALUES never appear in any log line. Diagnostics
|
|
15
|
+
* use file basenames and 64-char previews with values redacted.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
import { buildDetectedFile, safePreview } from "./detect-format.js";
|
|
20
|
+
import { parseNetscape, serializeNetscape } from "./parse-netscape.js";
|
|
21
|
+
import { parseEditThisCookieJson } from "./parse-json.js";
|
|
22
|
+
import { normalize } from "./normalize.js";
|
|
23
|
+
import { inferProvider } from "./infer-provider.js";
|
|
24
|
+
import { atomicWriteFileSync, defaultCachePathFor } from "./atomic-write.js";
|
|
25
|
+
/** Max depth for the drop-folder walk (one-level + one subfolder). */
|
|
26
|
+
const MAX_DEPTH = 2;
|
|
27
|
+
/** Max size of a single input file we'll parse (5 MB). */
|
|
28
|
+
const MAX_INPUT_BYTES = 5 * 1024 * 1024;
|
|
29
|
+
/** Default drop-folder location. */
|
|
30
|
+
export const DEFAULT_DROP_DIR = join(process.env.HOME ?? "/tmp", ".pi-harness-runtime", "cookies");
|
|
31
|
+
/**
|
|
32
|
+
* Enumerate readable files inside `dir`, up to MAX_DEPTH.
|
|
33
|
+
* Returns absolute paths. Skips dotfiles, editor temp files.
|
|
34
|
+
*
|
|
35
|
+
* `excludePath` (optional) — absolute path of a file to skip, e.g.
|
|
36
|
+
* the canonical cache file (so we never recursively read it).
|
|
37
|
+
*/
|
|
38
|
+
export function enumerateDropFiles(dir, excludePath) {
|
|
39
|
+
if (!existsSync(dir))
|
|
40
|
+
return [];
|
|
41
|
+
let stat;
|
|
42
|
+
try {
|
|
43
|
+
stat = statSync(dir);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
if (!stat.isDirectory())
|
|
49
|
+
return [];
|
|
50
|
+
const result = [];
|
|
51
|
+
function walk(current, depth) {
|
|
52
|
+
if (depth > MAX_DEPTH)
|
|
53
|
+
return;
|
|
54
|
+
let entries;
|
|
55
|
+
try {
|
|
56
|
+
entries = readdirSync(current);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
for (const name of entries) {
|
|
62
|
+
// Skip dotfiles, editor temp/swap.
|
|
63
|
+
if (name.startsWith("."))
|
|
64
|
+
continue;
|
|
65
|
+
if (name.endsWith("~") || name.endsWith(".swp"))
|
|
66
|
+
continue;
|
|
67
|
+
const full = join(current, name);
|
|
68
|
+
if (excludePath && full === excludePath)
|
|
69
|
+
continue;
|
|
70
|
+
let st;
|
|
71
|
+
try {
|
|
72
|
+
st = statSync(full);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (st.isFile()) {
|
|
78
|
+
result.push(full);
|
|
79
|
+
}
|
|
80
|
+
else if (st.isDirectory() && depth < MAX_DEPTH) {
|
|
81
|
+
walk(full, depth + 1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
walk(dir, 0);
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Read a single input file as text, capped at MAX_INPUT_BYTES.
|
|
90
|
+
* Returns null + a `reason` if the file can't be read.
|
|
91
|
+
*/
|
|
92
|
+
export function readInputFile(filePath) {
|
|
93
|
+
let stat;
|
|
94
|
+
try {
|
|
95
|
+
stat = statSync(filePath);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return { text: "", reason: "file not accessible" };
|
|
99
|
+
}
|
|
100
|
+
if (!stat.isFile())
|
|
101
|
+
return { text: "", reason: "not a regular file" };
|
|
102
|
+
if (stat.size > MAX_INPUT_BYTES) {
|
|
103
|
+
return { text: "", reason: `file too large (${stat.size} bytes)` };
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
return { text: readFileSync(filePath, "utf8") };
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
return {
|
|
110
|
+
text: "",
|
|
111
|
+
reason: `read failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Run the full sync pipeline.
|
|
117
|
+
*
|
|
118
|
+
* Options:
|
|
119
|
+
* - dropDir default: ~/.pi-harness-runtime/cookies/
|
|
120
|
+
* - cachePath default: ~/.config/<provider>-cookies.txt
|
|
121
|
+
* - providerHint override inference (skips filename/domain checks)
|
|
122
|
+
* - dryRun skip the actual file write (still returns would-be result)
|
|
123
|
+
*
|
|
124
|
+
* Returns a SyncResult. Never throws.
|
|
125
|
+
*/
|
|
126
|
+
export function sync(opts = {}) {
|
|
127
|
+
const dropDir = opts.dropDir ?? DEFAULT_DROP_DIR;
|
|
128
|
+
// Ensure the drop directory exists so users don't need to mkdir manually
|
|
129
|
+
if (!existsSync(dropDir))
|
|
130
|
+
mkdirSync(dropDir, { recursive: true });
|
|
131
|
+
const tmpResult = {
|
|
132
|
+
provider: null,
|
|
133
|
+
processedFiles: [],
|
|
134
|
+
skippedFiles: [],
|
|
135
|
+
totalCookies: 0,
|
|
136
|
+
cachePath: "",
|
|
137
|
+
sourceDir: dropDir,
|
|
138
|
+
wrote: false,
|
|
139
|
+
errors: [],
|
|
140
|
+
};
|
|
141
|
+
const files = enumerateDropFiles(dropDir, opts.cachePath);
|
|
142
|
+
if (files.length === 0) {
|
|
143
|
+
// Nothing to do — no error, just nothing. Caller decides whether
|
|
144
|
+
// to surface this to the user.
|
|
145
|
+
return tmpResult;
|
|
146
|
+
}
|
|
147
|
+
const allCookies = [];
|
|
148
|
+
let firstBasename;
|
|
149
|
+
for (const filePath of files) {
|
|
150
|
+
const { text, reason } = readInputFile(filePath);
|
|
151
|
+
if (reason) {
|
|
152
|
+
const det = buildDetectedFile(filePath, "");
|
|
153
|
+
tmpResult.skippedFiles.push({ basename: det.basename, reason });
|
|
154
|
+
tmpResult.errors.push({ basename: det.basename, message: reason });
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const det = buildDetectedFile(filePath, text);
|
|
158
|
+
if (det.format == null) {
|
|
159
|
+
const preview = safePreview(text);
|
|
160
|
+
tmpResult.skippedFiles.push({
|
|
161
|
+
basename: det.basename,
|
|
162
|
+
reason: `unrecognised format (preview: ${preview})`,
|
|
163
|
+
});
|
|
164
|
+
tmpResult.errors.push({
|
|
165
|
+
basename: det.basename,
|
|
166
|
+
message: "unrecognised format",
|
|
167
|
+
});
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
let cookies = [];
|
|
171
|
+
if (det.format === "netscape") {
|
|
172
|
+
cookies = parseNetscape(text);
|
|
173
|
+
}
|
|
174
|
+
else if (det.format === "edit-this-cookie-json") {
|
|
175
|
+
cookies = parseEditThisCookieJson(text);
|
|
176
|
+
}
|
|
177
|
+
if (cookies.length === 0) {
|
|
178
|
+
tmpResult.skippedFiles.push({
|
|
179
|
+
basename: det.basename,
|
|
180
|
+
reason: `${det.format} parsed but yielded 0 cookies`,
|
|
181
|
+
});
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
allCookies.push(...cookies);
|
|
185
|
+
tmpResult.processedFiles.push(det.basename);
|
|
186
|
+
if (!firstBasename)
|
|
187
|
+
firstBasename = det.basename;
|
|
188
|
+
}
|
|
189
|
+
if (allCookies.length === 0) {
|
|
190
|
+
return tmpResult;
|
|
191
|
+
}
|
|
192
|
+
const provider = inferProvider(firstBasename, allCookies, opts.providerHint);
|
|
193
|
+
if (!provider) {
|
|
194
|
+
tmpResult.errors.push({
|
|
195
|
+
basename: firstBasename ?? "<unknown>",
|
|
196
|
+
message: "could not infer provider (no filename/domain match)",
|
|
197
|
+
});
|
|
198
|
+
return tmpResult;
|
|
199
|
+
}
|
|
200
|
+
tmpResult.provider = provider;
|
|
201
|
+
const cachePath = opts.cachePath ?? defaultCachePathFor(provider);
|
|
202
|
+
tmpResult.cachePath = cachePath;
|
|
203
|
+
const normalized = normalize(allCookies, provider);
|
|
204
|
+
tmpResult.totalCookies = normalized.length;
|
|
205
|
+
if (normalized.length === 0) {
|
|
206
|
+
// All cookies were filtered (expired / wrong domain).
|
|
207
|
+
tmpResult.errors.push({
|
|
208
|
+
basename: firstBasename ?? "<unknown>",
|
|
209
|
+
message: "all cookies filtered (expired or wrong-provider domain)",
|
|
210
|
+
});
|
|
211
|
+
return tmpResult;
|
|
212
|
+
}
|
|
213
|
+
if (opts.dryRun) {
|
|
214
|
+
tmpResult.wrote = false;
|
|
215
|
+
return tmpResult;
|
|
216
|
+
}
|
|
217
|
+
const serialized = serializeNetscape(normalized);
|
|
218
|
+
try {
|
|
219
|
+
atomicWriteFileSync(cachePath, serialized);
|
|
220
|
+
tmpResult.wrote = true;
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
tmpResult.errors.push({
|
|
224
|
+
basename: firstBasename ?? "<unknown>",
|
|
225
|
+
message: `atomic write failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
return tmpResult;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Has-any-input check: true if the drop folder has anything readable.
|
|
232
|
+
* Cheap — does a single `readdirSync`; no parsing.
|
|
233
|
+
*/
|
|
234
|
+
export function hasAnyCookieSource(dropDir = DEFAULT_DROP_DIR) {
|
|
235
|
+
return enumerateDropFiles(dropDir).length > 0;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Convenience: cache path for the dominant provider in the drop folder,
|
|
239
|
+
* or null if nothing's there. Used by `footer-status.ts` to ask "should
|
|
240
|
+
* the footer hint point at this provider?"
|
|
241
|
+
*/
|
|
242
|
+
export function inferCachePath(dropDir = DEFAULT_DROP_DIR) {
|
|
243
|
+
const files = enumerateDropFiles(dropDir);
|
|
244
|
+
if (files.length === 0)
|
|
245
|
+
return null;
|
|
246
|
+
let firstBasename;
|
|
247
|
+
const cookies = [];
|
|
248
|
+
for (const fp of files) {
|
|
249
|
+
const { text } = readInputFile(fp);
|
|
250
|
+
if (!text)
|
|
251
|
+
continue;
|
|
252
|
+
const det = buildDetectedFile(fp, text);
|
|
253
|
+
if (!det.format)
|
|
254
|
+
continue;
|
|
255
|
+
if (det.format === "netscape")
|
|
256
|
+
cookies.push(...parseNetscape(text));
|
|
257
|
+
else if (det.format === "edit-this-cookie-json")
|
|
258
|
+
cookies.push(...parseEditThisCookieJson(text));
|
|
259
|
+
if (!firstBasename)
|
|
260
|
+
firstBasename = det.basename;
|
|
261
|
+
}
|
|
262
|
+
const provider = inferProvider(firstBasename, cookies);
|
|
263
|
+
if (!provider)
|
|
264
|
+
return null;
|
|
265
|
+
return defaultCachePathFor(provider);
|
|
266
|
+
}
|
|
267
|
+
export { inferProvider, inferProviderFromFilename, inferProviderFromCookies, } from "./infer-provider.js";
|
|
268
|
+
export { defaultCachePathFor } from "./atomic-write.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie sanitizer types.
|
|
3
|
+
*
|
|
4
|
+
* The data model is intentionally simple and explicit. Cookies flow in
|
|
5
|
+
* from one of two input formats (Netscape, EditThisCookie JSON), are
|
|
6
|
+
* normalised here into a canonical record, and written out as a single
|
|
7
|
+
* standard Netscape file by the writer.
|
|
8
|
+
*
|
|
9
|
+
* Cookie values are NEVER logged anywhere. They live in memory only
|
|
10
|
+
* for the duration of one parse → normalize → write cycle.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live cookie-folder watcher.
|
|
3
|
+
*
|
|
4
|
+
* Wraps chokidar v5 with the project-specific options:
|
|
5
|
+
* - `atomic: 100` — EditThisCookie / browser exporters use atomic write
|
|
6
|
+
* - `awaitWriteFinish` — wait for size to settle before triggering
|
|
7
|
+
* - `ignoreInitial: true` — startup is handled by sync.ts separately
|
|
8
|
+
* - `depth: 2` — one level + one subfolder
|
|
9
|
+
* - editor temp ignored
|
|
10
|
+
*
|
|
11
|
+
* Sec-001: Cookie values are NEVER logged. Diagnostics use only
|
|
12
|
+
* basenames, file paths, and event kinds.
|
|
13
|
+
*/
|
|
14
|
+
import chokidar from "chokidar";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { sync } from "./sync.js";
|
|
17
|
+
const DEFAULT_DEBOUNCE_MS = 250;
|
|
18
|
+
/** Wraps a chokidar watcher for the drop folder. */
|
|
19
|
+
export class CookieWatcher {
|
|
20
|
+
watcher = null;
|
|
21
|
+
debounceMs;
|
|
22
|
+
debounceTimer = null;
|
|
23
|
+
log;
|
|
24
|
+
cfg;
|
|
25
|
+
running = false;
|
|
26
|
+
constructor(config) {
|
|
27
|
+
this.cfg = config;
|
|
28
|
+
this.debounceMs = config.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
29
|
+
this.log = config.logger ?? ((m) => console.log(`[cookie-sanitizer] ${m}`));
|
|
30
|
+
}
|
|
31
|
+
/** Start watching. Idempotent — calling twice is a no-op. */
|
|
32
|
+
start() {
|
|
33
|
+
if (this.running)
|
|
34
|
+
return;
|
|
35
|
+
this.running = true;
|
|
36
|
+
this.watcher = chokidar.watch(this.cfg.dropDir, {
|
|
37
|
+
ignored: (targetPath) => {
|
|
38
|
+
const base = targetPath.split("/").pop() ?? "";
|
|
39
|
+
if (base.startsWith("."))
|
|
40
|
+
return true;
|
|
41
|
+
if (base.endsWith("~") || base.endsWith(".swp"))
|
|
42
|
+
return true;
|
|
43
|
+
if (base.endsWith(".tmp"))
|
|
44
|
+
return true;
|
|
45
|
+
// Exclude the canonical cache file (if specified) so the
|
|
46
|
+
// sanitizer's own write doesn't trigger a re-sync.
|
|
47
|
+
if (this.cfg.syncOptions?.cachePath &&
|
|
48
|
+
targetPath === this.cfg.syncOptions.cachePath) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
},
|
|
53
|
+
ignoreInitial: true,
|
|
54
|
+
persistent: true,
|
|
55
|
+
depth: 2,
|
|
56
|
+
atomic: 100,
|
|
57
|
+
awaitWriteFinish: {
|
|
58
|
+
stabilityThreshold: 200,
|
|
59
|
+
pollInterval: 50,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
this.watcher.on("add", () => this.schedule());
|
|
63
|
+
this.watcher.on("change", () => this.schedule());
|
|
64
|
+
this.watcher.on("unlink", () => this.schedule());
|
|
65
|
+
this.watcher.on("error", (err) => {
|
|
66
|
+
this.log(`watcher error: ${err instanceof Error ? err.message : String(err)}`);
|
|
67
|
+
this.cfg.onEvent({
|
|
68
|
+
kind: "watcher-error",
|
|
69
|
+
message: err instanceof Error ? err.message : String(err),
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
this.log(`watching ${this.cfg.dropDir}`);
|
|
73
|
+
}
|
|
74
|
+
/** Stop watching. Idempotent. */
|
|
75
|
+
async stop() {
|
|
76
|
+
if (!this.running)
|
|
77
|
+
return;
|
|
78
|
+
this.running = false;
|
|
79
|
+
if (this.debounceTimer) {
|
|
80
|
+
clearTimeout(this.debounceTimer);
|
|
81
|
+
this.debounceTimer = null;
|
|
82
|
+
}
|
|
83
|
+
if (this.watcher) {
|
|
84
|
+
await this.watcher.close();
|
|
85
|
+
this.watcher = null;
|
|
86
|
+
}
|
|
87
|
+
this.log("stopped");
|
|
88
|
+
}
|
|
89
|
+
/** Trigger a sync immediately (bypass debounce). */
|
|
90
|
+
triggerNow() {
|
|
91
|
+
if (this.debounceTimer) {
|
|
92
|
+
clearTimeout(this.debounceTimer);
|
|
93
|
+
this.debounceTimer = null;
|
|
94
|
+
}
|
|
95
|
+
this.runSync();
|
|
96
|
+
}
|
|
97
|
+
schedule() {
|
|
98
|
+
if (this.debounceTimer)
|
|
99
|
+
clearTimeout(this.debounceTimer);
|
|
100
|
+
this.debounceTimer = setTimeout(() => {
|
|
101
|
+
this.debounceTimer = null;
|
|
102
|
+
this.runSync();
|
|
103
|
+
}, this.debounceMs);
|
|
104
|
+
}
|
|
105
|
+
runSync() {
|
|
106
|
+
try {
|
|
107
|
+
const result = sync(this.cfg.syncOptions ?? {});
|
|
108
|
+
if (result.errors.length > 0) {
|
|
109
|
+
for (const err of result.errors) {
|
|
110
|
+
this.cfg.onEvent({
|
|
111
|
+
kind: "sync-error",
|
|
112
|
+
message: `${err.basename}: ${err.message}`,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (result.provider && result.wrote) {
|
|
117
|
+
this.cfg.onEvent({
|
|
118
|
+
kind: "sync-ok",
|
|
119
|
+
provider: result.provider,
|
|
120
|
+
cachePath: result.cachePath,
|
|
121
|
+
cookies: result.totalCookies,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
else if (result.processedFiles.length === 0 &&
|
|
125
|
+
result.provider === null) {
|
|
126
|
+
this.cfg.onEvent({
|
|
127
|
+
kind: "sync-skip",
|
|
128
|
+
reason: "no usable cookies found",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
this.cfg.onEvent({
|
|
134
|
+
kind: "sync-error",
|
|
135
|
+
message: e instanceof Error ? e.message : String(e),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** Factory: a watcher that writes to a default no-op logger. */
|
|
141
|
+
export function createWatcher(dropDir, syncOptions, onEvent) {
|
|
142
|
+
return new CookieWatcher({ dropDir, syncOptions, onEvent });
|
|
143
|
+
}
|
|
144
|
+
/** Compute a sensible dropDir for a given HOME override (test seam). */
|
|
145
|
+
export function defaultDropDir(home = process.env.HOME ?? "/tmp") {
|
|
146
|
+
return join(home, ".pi-harness-runtime", "cookies");
|
|
147
|
+
}
|