agentsys 5.0.3 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +109 -39
- package/.claude-plugin/plugin.json +2 -2
- package/AGENTS.md +2 -14
- package/CHANGELOG.md +65 -5
- package/README.md +143 -44
- package/SECURITY.md +1 -1
- package/adapters/README.md +6 -6
- package/adapters/codex/README.md +3 -3
- package/adapters/codex/install.sh +2 -2
- package/adapters/opencode/README.md +3 -3
- package/adapters/opencode/install.sh +2 -2
- package/agent-knowledge/AGENTS.md +144 -5
- package/agent-knowledge/all-in-one-plus-modular-packages.md +576 -0
- package/agent-knowledge/cli-browser-automation-agents.md +936 -0
- package/agent-knowledge/github-org-project-management.md +319 -0
- package/agent-knowledge/github-org-structure-patterns.md +268 -0
- package/agent-knowledge/multi-product-org-docs.md +622 -0
- package/agent-knowledge/oss-org-naming-patterns.md +368 -0
- package/agent-knowledge/resources/all-in-one-plus-modular-packages-sources.json +310 -0
- package/agent-knowledge/resources/cli-browser-automation-agents-sources.json +428 -0
- package/agent-knowledge/resources/github-org-project-management-sources.json +239 -0
- package/agent-knowledge/resources/github-org-structure-patterns-sources.json +293 -0
- package/agent-knowledge/resources/multi-product-org-docs-sources.json +514 -0
- package/agent-knowledge/resources/oss-org-naming-patterns-sources.json +458 -0
- package/agent-knowledge/resources/skill-plugin-distribution-patterns-sources.json +290 -0
- package/agent-knowledge/resources/terminal-browsers-agent-automation-sources.json +758 -0
- package/agent-knowledge/resources/web-session-persistence-cli-agents-sources.json +528 -0
- package/agent-knowledge/skill-plugin-distribution-patterns.md +661 -0
- package/agent-knowledge/terminal-browsers-agent-automation.md +776 -0
- package/agent-knowledge/web-session-persistence-cli-agents.md +1352 -0
- package/bin/cli.js +1289 -18
- package/bin/dev-cli.js +15 -24
- package/lib/adapter-transforms.js +171 -7
- package/lib/cross-platform/index.js +7 -3
- package/lib/discovery/index.js +26 -1
- package/lib/index.js +2 -0
- package/lib/package.json +1 -1
- package/lib/patterns/cli-enhancers.js +11 -2
- package/lib/sources/policy-questions.js +76 -2
- package/lib/state/workflow-state.js +18 -7
- package/meta/skills/maintain-cross-platform/SKILL.md +1 -1
- package/package.json +4 -4
- package/scripts/bump-version.js +1 -6
- package/scripts/dev-install.js +1 -1
- package/scripts/fix-graduated-repos.js +288 -0
- package/scripts/gen-adapters.js +6 -7
- package/scripts/generate-docs.js +4 -2
- package/scripts/graduate-plugin.js +433 -0
- package/scripts/plugins.txt +1 -0
- package/scripts/preflight.js +19 -48
- package/scripts/scaffold.js +2 -2
- package/scripts/setup-hooks.js +2 -9
- package/scripts/stamp-version.js +3 -34
- package/scripts/validate-agent-skill-compliance.js +2 -0
- package/scripts/validate-counts.js +27 -0
- package/site/assets/css/design-system/base.css +151 -0
- package/site/assets/css/design-system/tokens.css +354 -0
- package/site/assets/css/tokens.css +5 -469
- package/site/content.json +13 -13
- package/site/index.html +14 -13
- package/site/ux-spec.md +7 -7
- package/adapters/codex/skills/agnix/SKILL.md +0 -138
- package/adapters/codex/skills/audit-project/SKILL.md +0 -334
- package/adapters/codex/skills/audit-project-agents/SKILL.md +0 -459
- package/adapters/codex/skills/audit-project-github/SKILL.md +0 -146
- package/adapters/codex/skills/consult/SKILL.md +0 -245
- package/adapters/codex/skills/delivery-approval/SKILL.md +0 -339
- package/adapters/codex/skills/deslop/SKILL.md +0 -167
- package/adapters/codex/skills/drift-detect/SKILL.md +0 -268
- package/adapters/codex/skills/enhance/SKILL.md +0 -177
- package/adapters/codex/skills/learn/SKILL.md +0 -188
- package/adapters/codex/skills/next-task/SKILL.md +0 -546
- package/adapters/codex/skills/perf/SKILL.md +0 -469
- package/adapters/codex/skills/repo-map/SKILL.md +0 -132
- package/adapters/codex/skills/ship/SKILL.md +0 -491
- package/adapters/codex/skills/ship-ci-review-loop/SKILL.md +0 -473
- package/adapters/codex/skills/ship-deployment/SKILL.md +0 -336
- package/adapters/codex/skills/ship-error-handling/SKILL.md +0 -260
- package/adapters/codex/skills/sync-docs/SKILL.md +0 -186
- package/adapters/opencode/agents/agent-enhancer.md +0 -65
- package/adapters/opencode/agents/agnix-agent.md +0 -56
- package/adapters/opencode/agents/ci-fixer.md +0 -104
- package/adapters/opencode/agents/ci-monitor.md +0 -127
- package/adapters/opencode/agents/claudemd-enhancer.md +0 -66
- package/adapters/opencode/agents/consult-agent.md +0 -124
- package/adapters/opencode/agents/cross-file-enhancer.md +0 -54
- package/adapters/opencode/agents/delivery-validator.md +0 -115
- package/adapters/opencode/agents/deslop-agent.md +0 -88
- package/adapters/opencode/agents/docs-enhancer.md +0 -65
- package/adapters/opencode/agents/exploration-agent.md +0 -143
- package/adapters/opencode/agents/hooks-enhancer.md +0 -66
- package/adapters/opencode/agents/implementation-agent.md +0 -206
- package/adapters/opencode/agents/learn-agent.md +0 -279
- package/adapters/opencode/agents/map-validator.md +0 -65
- package/adapters/opencode/agents/perf-analyzer.md +0 -40
- package/adapters/opencode/agents/perf-code-paths.md +0 -12
- package/adapters/opencode/agents/perf-investigation-logger.md +0 -44
- package/adapters/opencode/agents/perf-orchestrator.md +0 -147
- package/adapters/opencode/agents/perf-theory-gatherer.md +0 -18
- package/adapters/opencode/agents/perf-theory-tester.md +0 -43
- package/adapters/opencode/agents/plan-synthesizer.md +0 -229
- package/adapters/opencode/agents/planning-agent.md +0 -235
- package/adapters/opencode/agents/plugin-enhancer.md +0 -64
- package/adapters/opencode/agents/prompt-enhancer.md +0 -58
- package/adapters/opencode/agents/simple-fixer.md +0 -107
- package/adapters/opencode/agents/skills-enhancer.md +0 -66
- package/adapters/opencode/agents/sync-docs-agent.md +0 -153
- package/adapters/opencode/agents/task-discoverer.md +0 -80
- package/adapters/opencode/agents/test-coverage-checker.md +0 -144
- package/adapters/opencode/agents/worktree-manager.md +0 -209
- package/adapters/opencode/commands/agnix.md +0 -106
- package/adapters/opencode/commands/audit-project-agents.md +0 -125
- package/adapters/opencode/commands/audit-project-github.md +0 -145
- package/adapters/opencode/commands/audit-project.md +0 -268
- package/adapters/opencode/commands/consult.md +0 -252
- package/adapters/opencode/commands/delivery-approval.md +0 -212
- package/adapters/opencode/commands/deslop.md +0 -132
- package/adapters/opencode/commands/drift-detect.md +0 -173
- package/adapters/opencode/commands/enhance.md +0 -183
- package/adapters/opencode/commands/learn.md +0 -116
- package/adapters/opencode/commands/next-task.md +0 -393
- package/adapters/opencode/commands/perf.md +0 -49
- package/adapters/opencode/commands/repo-map.md +0 -69
- package/adapters/opencode/commands/ship-ci-review-loop.md +0 -334
- package/adapters/opencode/commands/ship-deployment.md +0 -336
- package/adapters/opencode/commands/ship-error-handling.md +0 -248
- package/adapters/opencode/commands/ship.md +0 -371
- package/adapters/opencode/commands/sync-docs.md +0 -108
- package/adapters/opencode/skills/agnix/SKILL.md +0 -139
- package/adapters/opencode/skills/consult/SKILL.md +0 -308
- package/adapters/opencode/skills/deslop/SKILL.md +0 -169
- package/adapters/opencode/skills/discover-tasks/SKILL.md +0 -102
- package/adapters/opencode/skills/drift-analysis/SKILL.md +0 -279
- package/adapters/opencode/skills/enhance-agent-prompts/SKILL.md +0 -279
- package/adapters/opencode/skills/enhance-claude-memory/SKILL.md +0 -390
- package/adapters/opencode/skills/enhance-cross-file/SKILL.md +0 -112
- package/adapters/opencode/skills/enhance-docs/SKILL.md +0 -288
- package/adapters/opencode/skills/enhance-hooks/SKILL.md +0 -557
- package/adapters/opencode/skills/enhance-orchestrator/SKILL.md +0 -114
- package/adapters/opencode/skills/enhance-plugins/SKILL.md +0 -314
- package/adapters/opencode/skills/enhance-prompts/SKILL.md +0 -341
- package/adapters/opencode/skills/enhance-skills/SKILL.md +0 -443
- package/adapters/opencode/skills/learn/SKILL.md +0 -352
- package/adapters/opencode/skills/orchestrate-review/SKILL.md +0 -95
- package/adapters/opencode/skills/perf-analyzer/SKILL.md +0 -38
- package/adapters/opencode/skills/perf-baseline-manager/SKILL.md +0 -31
- package/adapters/opencode/skills/perf-benchmarker/SKILL.md +0 -49
- package/adapters/opencode/skills/perf-code-paths/SKILL.md +0 -33
- package/adapters/opencode/skills/perf-investigation-logger/SKILL.md +0 -42
- package/adapters/opencode/skills/perf-profiler/SKILL.md +0 -39
- package/adapters/opencode/skills/perf-theory-gatherer/SKILL.md +0 -36
- package/adapters/opencode/skills/perf-theory-tester/SKILL.md +0 -37
- package/adapters/opencode/skills/repo-mapping/SKILL.md +0 -86
- package/adapters/opencode/skills/sync-docs/SKILL.md +0 -246
- package/adapters/opencode/skills/validate-delivery/SKILL.md +0 -112
- package/plugins/agnix/.claude-plugin/plugin.json +0 -22
- package/plugins/agnix/agents/agnix-agent.md +0 -56
- package/plugins/agnix/commands/agnix.md +0 -139
- package/plugins/agnix/skills/agnix/SKILL.md +0 -138
- package/plugins/audit-project/.claude-plugin/plugin.json +0 -20
- package/plugins/audit-project/commands/audit-project-agents.md +0 -458
- package/plugins/audit-project/commands/audit-project-github.md +0 -144
- package/plugins/audit-project/commands/audit-project.md +0 -336
- package/plugins/audit-project/lib/adapter-transforms.js +0 -278
- package/plugins/audit-project/lib/collectors/codebase.js +0 -392
- package/plugins/audit-project/lib/collectors/docs-patterns.js +0 -713
- package/plugins/audit-project/lib/collectors/documentation.js +0 -219
- package/plugins/audit-project/lib/collectors/github.js +0 -330
- package/plugins/audit-project/lib/collectors/index.js +0 -126
- package/plugins/audit-project/lib/config/index.js +0 -14
- package/plugins/audit-project/lib/cross-platform/index.js +0 -539
- package/plugins/audit-project/lib/discovery/index.js +0 -352
- package/plugins/audit-project/lib/drift-detect/collectors.js +0 -37
- package/plugins/audit-project/lib/enhance/agent-analyzer.js +0 -421
- package/plugins/audit-project/lib/enhance/agent-patterns.js +0 -571
- package/plugins/audit-project/lib/enhance/auto-suppression.js +0 -622
- package/plugins/audit-project/lib/enhance/benchmark.js +0 -417
- package/plugins/audit-project/lib/enhance/cross-file-analyzer.js +0 -930
- package/plugins/audit-project/lib/enhance/cross-file-patterns.js +0 -370
- package/plugins/audit-project/lib/enhance/docs-analyzer.js +0 -325
- package/plugins/audit-project/lib/enhance/docs-patterns.js +0 -671
- package/plugins/audit-project/lib/enhance/fixer.js +0 -721
- package/plugins/audit-project/lib/enhance/hook-analyzer.js +0 -135
- package/plugins/audit-project/lib/enhance/hook-patterns.js +0 -40
- package/plugins/audit-project/lib/enhance/index.js +0 -127
- package/plugins/audit-project/lib/enhance/plugin-analyzer.js +0 -402
- package/plugins/audit-project/lib/enhance/plugin-patterns.js +0 -326
- package/plugins/audit-project/lib/enhance/projectmemory-analyzer.js +0 -551
- package/plugins/audit-project/lib/enhance/projectmemory-patterns.js +0 -617
- package/plugins/audit-project/lib/enhance/prompt-analyzer.js +0 -457
- package/plugins/audit-project/lib/enhance/prompt-patterns.js +0 -1484
- package/plugins/audit-project/lib/enhance/reporter.js +0 -1348
- package/plugins/audit-project/lib/enhance/security-patterns.js +0 -284
- package/plugins/audit-project/lib/enhance/skill-analyzer.js +0 -182
- package/plugins/audit-project/lib/enhance/skill-patterns.js +0 -147
- package/plugins/audit-project/lib/enhance/suppression.js +0 -352
- package/plugins/audit-project/lib/enhance/tool-patterns.js +0 -373
- package/plugins/audit-project/lib/index.js +0 -270
- package/plugins/audit-project/lib/patterns/cli-enhancers.js +0 -611
- package/plugins/audit-project/lib/patterns/pipeline.js +0 -948
- package/plugins/audit-project/lib/patterns/review-patterns.js +0 -558
- package/plugins/audit-project/lib/patterns/slop-analyzers.js +0 -2305
- package/plugins/audit-project/lib/patterns/slop-patterns.js +0 -1187
- package/plugins/audit-project/lib/perf/analyzer/index.js +0 -22
- package/plugins/audit-project/lib/perf/argument-parser.js +0 -105
- package/plugins/audit-project/lib/perf/baseline-comparator.js +0 -50
- package/plugins/audit-project/lib/perf/baseline-store.js +0 -127
- package/plugins/audit-project/lib/perf/benchmark-runner.js +0 -404
- package/plugins/audit-project/lib/perf/breaking-point-finder.js +0 -52
- package/plugins/audit-project/lib/perf/breaking-point-runner.js +0 -60
- package/plugins/audit-project/lib/perf/checkpoint.js +0 -123
- package/plugins/audit-project/lib/perf/code-paths.js +0 -86
- package/plugins/audit-project/lib/perf/consolidation.js +0 -37
- package/plugins/audit-project/lib/perf/constraint-runner.js +0 -71
- package/plugins/audit-project/lib/perf/experiment-runner.js +0 -32
- package/plugins/audit-project/lib/perf/index.js +0 -41
- package/plugins/audit-project/lib/perf/investigation-state.js +0 -874
- package/plugins/audit-project/lib/perf/optimization-runner.js +0 -79
- package/plugins/audit-project/lib/perf/profilers/go.js +0 -22
- package/plugins/audit-project/lib/perf/profilers/index.js +0 -46
- package/plugins/audit-project/lib/perf/profilers/java.js +0 -23
- package/plugins/audit-project/lib/perf/profilers/node.js +0 -27
- package/plugins/audit-project/lib/perf/profilers/python.js +0 -23
- package/plugins/audit-project/lib/perf/profilers/rust.js +0 -23
- package/plugins/audit-project/lib/perf/profiling-runner.js +0 -75
- package/plugins/audit-project/lib/perf/schemas.js +0 -140
- package/plugins/audit-project/lib/platform/detect-platform.js +0 -413
- package/plugins/audit-project/lib/platform/detection-configs.js +0 -93
- package/plugins/audit-project/lib/platform/state-dir.js +0 -132
- package/plugins/audit-project/lib/platform/verify-tools.js +0 -182
- package/plugins/audit-project/lib/repo-map/cache.js +0 -152
- package/plugins/audit-project/lib/repo-map/concurrency.js +0 -29
- package/plugins/audit-project/lib/repo-map/index.js +0 -222
- package/plugins/audit-project/lib/repo-map/installer.js +0 -212
- package/plugins/audit-project/lib/repo-map/queries/go.js +0 -27
- package/plugins/audit-project/lib/repo-map/queries/index.js +0 -100
- package/plugins/audit-project/lib/repo-map/queries/java.js +0 -38
- package/plugins/audit-project/lib/repo-map/queries/javascript.js +0 -55
- package/plugins/audit-project/lib/repo-map/queries/python.js +0 -24
- package/plugins/audit-project/lib/repo-map/queries/rust.js +0 -73
- package/plugins/audit-project/lib/repo-map/queries/typescript.js +0 -38
- package/plugins/audit-project/lib/repo-map/runner.js +0 -1364
- package/plugins/audit-project/lib/repo-map/updater.js +0 -562
- package/plugins/audit-project/lib/repo-map/usage-analyzer.js +0 -407
- package/plugins/audit-project/lib/schemas/plugin-manifest.schema.json +0 -57
- package/plugins/audit-project/lib/schemas/validator.js +0 -247
- package/plugins/audit-project/lib/sources/custom-handler.js +0 -199
- package/plugins/audit-project/lib/sources/policy-questions.js +0 -246
- package/plugins/audit-project/lib/sources/source-cache.js +0 -165
- package/plugins/audit-project/lib/state/workflow-state.js +0 -576
- package/plugins/audit-project/lib/types/agent-frontmatter.d.ts +0 -134
- package/plugins/audit-project/lib/types/command-frontmatter.d.ts +0 -107
- package/plugins/audit-project/lib/types/hook-frontmatter.d.ts +0 -115
- package/plugins/audit-project/lib/types/index.d.ts +0 -84
- package/plugins/audit-project/lib/types/plugin-manifest.d.ts +0 -102
- package/plugins/audit-project/lib/types/skill-frontmatter.d.ts +0 -89
- package/plugins/audit-project/lib/utils/atomic-write.js +0 -94
- package/plugins/audit-project/lib/utils/cache-manager.js +0 -159
- package/plugins/audit-project/lib/utils/command-parser.js +0 -0
- package/plugins/audit-project/lib/utils/context-optimizer.js +0 -300
- package/plugins/audit-project/lib/utils/deprecation.js +0 -37
- package/plugins/audit-project/lib/utils/shell-escape.js +0 -88
- package/plugins/audit-project/lib/utils/state-helpers.js +0 -61
- package/plugins/consult/.claude-plugin/plugin.json +0 -24
- package/plugins/consult/agents/consult-agent.md +0 -129
- package/plugins/consult/commands/consult.md +0 -248
- package/plugins/consult/skills/consult/SKILL.md +0 -301
- package/plugins/deslop/.claude-plugin/plugin.json +0 -20
- package/plugins/deslop/agents/deslop-agent.md +0 -88
- package/plugins/deslop/commands/deslop.md +0 -168
- package/plugins/deslop/lib/adapter-transforms.js +0 -278
- package/plugins/deslop/lib/collectors/codebase.js +0 -392
- package/plugins/deslop/lib/collectors/docs-patterns.js +0 -713
- package/plugins/deslop/lib/collectors/documentation.js +0 -219
- package/plugins/deslop/lib/collectors/github.js +0 -330
- package/plugins/deslop/lib/collectors/index.js +0 -126
- package/plugins/deslop/lib/config/index.js +0 -14
- package/plugins/deslop/lib/cross-platform/index.js +0 -539
- package/plugins/deslop/lib/discovery/index.js +0 -352
- package/plugins/deslop/lib/drift-detect/collectors.js +0 -37
- package/plugins/deslop/lib/enhance/agent-analyzer.js +0 -421
- package/plugins/deslop/lib/enhance/agent-patterns.js +0 -571
- package/plugins/deslop/lib/enhance/auto-suppression.js +0 -622
- package/plugins/deslop/lib/enhance/benchmark.js +0 -417
- package/plugins/deslop/lib/enhance/cross-file-analyzer.js +0 -930
- package/plugins/deslop/lib/enhance/cross-file-patterns.js +0 -370
- package/plugins/deslop/lib/enhance/docs-analyzer.js +0 -325
- package/plugins/deslop/lib/enhance/docs-patterns.js +0 -671
- package/plugins/deslop/lib/enhance/fixer.js +0 -721
- package/plugins/deslop/lib/enhance/hook-analyzer.js +0 -135
- package/plugins/deslop/lib/enhance/hook-patterns.js +0 -40
- package/plugins/deslop/lib/enhance/index.js +0 -127
- package/plugins/deslop/lib/enhance/plugin-analyzer.js +0 -402
- package/plugins/deslop/lib/enhance/plugin-patterns.js +0 -326
- package/plugins/deslop/lib/enhance/projectmemory-analyzer.js +0 -551
- package/plugins/deslop/lib/enhance/projectmemory-patterns.js +0 -617
- package/plugins/deslop/lib/enhance/prompt-analyzer.js +0 -457
- package/plugins/deslop/lib/enhance/prompt-patterns.js +0 -1484
- package/plugins/deslop/lib/enhance/reporter.js +0 -1348
- package/plugins/deslop/lib/enhance/security-patterns.js +0 -284
- package/plugins/deslop/lib/enhance/skill-analyzer.js +0 -182
- package/plugins/deslop/lib/enhance/skill-patterns.js +0 -147
- package/plugins/deslop/lib/enhance/suppression.js +0 -352
- package/plugins/deslop/lib/enhance/tool-patterns.js +0 -373
- package/plugins/deslop/lib/index.js +0 -270
- package/plugins/deslop/lib/patterns/cli-enhancers.js +0 -611
- package/plugins/deslop/lib/patterns/pipeline.js +0 -948
- package/plugins/deslop/lib/patterns/review-patterns.js +0 -558
- package/plugins/deslop/lib/patterns/slop-analyzers.js +0 -2305
- package/plugins/deslop/lib/patterns/slop-patterns.js +0 -1187
- package/plugins/deslop/lib/perf/analyzer/index.js +0 -22
- package/plugins/deslop/lib/perf/argument-parser.js +0 -105
- package/plugins/deslop/lib/perf/baseline-comparator.js +0 -50
- package/plugins/deslop/lib/perf/baseline-store.js +0 -127
- package/plugins/deslop/lib/perf/benchmark-runner.js +0 -404
- package/plugins/deslop/lib/perf/breaking-point-finder.js +0 -52
- package/plugins/deslop/lib/perf/breaking-point-runner.js +0 -60
- package/plugins/deslop/lib/perf/checkpoint.js +0 -123
- package/plugins/deslop/lib/perf/code-paths.js +0 -86
- package/plugins/deslop/lib/perf/consolidation.js +0 -37
- package/plugins/deslop/lib/perf/constraint-runner.js +0 -71
- package/plugins/deslop/lib/perf/experiment-runner.js +0 -32
- package/plugins/deslop/lib/perf/index.js +0 -41
- package/plugins/deslop/lib/perf/investigation-state.js +0 -874
- package/plugins/deslop/lib/perf/optimization-runner.js +0 -79
- package/plugins/deslop/lib/perf/profilers/go.js +0 -22
- package/plugins/deslop/lib/perf/profilers/index.js +0 -46
- package/plugins/deslop/lib/perf/profilers/java.js +0 -23
- package/plugins/deslop/lib/perf/profilers/node.js +0 -27
- package/plugins/deslop/lib/perf/profilers/python.js +0 -23
- package/plugins/deslop/lib/perf/profilers/rust.js +0 -23
- package/plugins/deslop/lib/perf/profiling-runner.js +0 -75
- package/plugins/deslop/lib/perf/schemas.js +0 -140
- package/plugins/deslop/lib/platform/detect-platform.js +0 -413
- package/plugins/deslop/lib/platform/detection-configs.js +0 -93
- package/plugins/deslop/lib/platform/state-dir.js +0 -132
- package/plugins/deslop/lib/platform/verify-tools.js +0 -182
- package/plugins/deslop/lib/repo-map/cache.js +0 -152
- package/plugins/deslop/lib/repo-map/concurrency.js +0 -29
- package/plugins/deslop/lib/repo-map/index.js +0 -222
- package/plugins/deslop/lib/repo-map/installer.js +0 -212
- package/plugins/deslop/lib/repo-map/queries/go.js +0 -27
- package/plugins/deslop/lib/repo-map/queries/index.js +0 -100
- package/plugins/deslop/lib/repo-map/queries/java.js +0 -38
- package/plugins/deslop/lib/repo-map/queries/javascript.js +0 -55
- package/plugins/deslop/lib/repo-map/queries/python.js +0 -24
- package/plugins/deslop/lib/repo-map/queries/rust.js +0 -73
- package/plugins/deslop/lib/repo-map/queries/typescript.js +0 -38
- package/plugins/deslop/lib/repo-map/runner.js +0 -1364
- package/plugins/deslop/lib/repo-map/updater.js +0 -562
- package/plugins/deslop/lib/repo-map/usage-analyzer.js +0 -407
- package/plugins/deslop/lib/schemas/plugin-manifest.schema.json +0 -57
- package/plugins/deslop/lib/schemas/validator.js +0 -247
- package/plugins/deslop/lib/sources/custom-handler.js +0 -199
- package/plugins/deslop/lib/sources/policy-questions.js +0 -246
- package/plugins/deslop/lib/sources/source-cache.js +0 -165
- package/plugins/deslop/lib/state/workflow-state.js +0 -576
- package/plugins/deslop/lib/types/agent-frontmatter.d.ts +0 -134
- package/plugins/deslop/lib/types/command-frontmatter.d.ts +0 -107
- package/plugins/deslop/lib/types/hook-frontmatter.d.ts +0 -115
- package/plugins/deslop/lib/types/index.d.ts +0 -84
- package/plugins/deslop/lib/types/plugin-manifest.d.ts +0 -102
- package/plugins/deslop/lib/types/skill-frontmatter.d.ts +0 -89
- package/plugins/deslop/lib/utils/atomic-write.js +0 -94
- package/plugins/deslop/lib/utils/cache-manager.js +0 -159
- package/plugins/deslop/lib/utils/command-parser.js +0 -0
- package/plugins/deslop/lib/utils/context-optimizer.js +0 -300
- package/plugins/deslop/lib/utils/deprecation.js +0 -37
- package/plugins/deslop/lib/utils/shell-escape.js +0 -88
- package/plugins/deslop/lib/utils/state-helpers.js +0 -61
- package/plugins/deslop/references/slop-categories.md +0 -122
- package/plugins/deslop/scripts/detect.js +0 -134
- package/plugins/deslop/skills/deslop/SKILL.md +0 -204
- package/plugins/drift-detect/.claude-plugin/plugin.json +0 -23
- package/plugins/drift-detect/agents/plan-synthesizer.md +0 -225
- package/plugins/drift-detect/commands/drift-detect.md +0 -269
- package/plugins/drift-detect/lib/adapter-transforms.js +0 -278
- package/plugins/drift-detect/lib/collectors/codebase.js +0 -392
- package/plugins/drift-detect/lib/collectors/docs-patterns.js +0 -713
- package/plugins/drift-detect/lib/collectors/documentation.js +0 -219
- package/plugins/drift-detect/lib/collectors/github.js +0 -330
- package/plugins/drift-detect/lib/collectors/index.js +0 -126
- package/plugins/drift-detect/lib/config/index.js +0 -14
- package/plugins/drift-detect/lib/cross-platform/index.js +0 -539
- package/plugins/drift-detect/lib/discovery/index.js +0 -352
- package/plugins/drift-detect/lib/drift-detect/collectors.js +0 -37
- package/plugins/drift-detect/lib/enhance/agent-analyzer.js +0 -421
- package/plugins/drift-detect/lib/enhance/agent-patterns.js +0 -571
- package/plugins/drift-detect/lib/enhance/auto-suppression.js +0 -622
- package/plugins/drift-detect/lib/enhance/benchmark.js +0 -417
- package/plugins/drift-detect/lib/enhance/cross-file-analyzer.js +0 -930
- package/plugins/drift-detect/lib/enhance/cross-file-patterns.js +0 -370
- package/plugins/drift-detect/lib/enhance/docs-analyzer.js +0 -325
- package/plugins/drift-detect/lib/enhance/docs-patterns.js +0 -671
- package/plugins/drift-detect/lib/enhance/fixer.js +0 -721
- package/plugins/drift-detect/lib/enhance/hook-analyzer.js +0 -135
- package/plugins/drift-detect/lib/enhance/hook-patterns.js +0 -40
- package/plugins/drift-detect/lib/enhance/index.js +0 -127
- package/plugins/drift-detect/lib/enhance/plugin-analyzer.js +0 -402
- package/plugins/drift-detect/lib/enhance/plugin-patterns.js +0 -326
- package/plugins/drift-detect/lib/enhance/projectmemory-analyzer.js +0 -551
- package/plugins/drift-detect/lib/enhance/projectmemory-patterns.js +0 -617
- package/plugins/drift-detect/lib/enhance/prompt-analyzer.js +0 -457
- package/plugins/drift-detect/lib/enhance/prompt-patterns.js +0 -1484
- package/plugins/drift-detect/lib/enhance/reporter.js +0 -1348
- package/plugins/drift-detect/lib/enhance/security-patterns.js +0 -284
- package/plugins/drift-detect/lib/enhance/skill-analyzer.js +0 -182
- package/plugins/drift-detect/lib/enhance/skill-patterns.js +0 -147
- package/plugins/drift-detect/lib/enhance/suppression.js +0 -352
- package/plugins/drift-detect/lib/enhance/tool-patterns.js +0 -373
- package/plugins/drift-detect/lib/index.js +0 -270
- package/plugins/drift-detect/lib/patterns/cli-enhancers.js +0 -611
- package/plugins/drift-detect/lib/patterns/pipeline.js +0 -948
- package/plugins/drift-detect/lib/patterns/review-patterns.js +0 -558
- package/plugins/drift-detect/lib/patterns/slop-analyzers.js +0 -2305
- package/plugins/drift-detect/lib/patterns/slop-patterns.js +0 -1187
- package/plugins/drift-detect/lib/perf/analyzer/index.js +0 -22
- package/plugins/drift-detect/lib/perf/argument-parser.js +0 -105
- package/plugins/drift-detect/lib/perf/baseline-comparator.js +0 -50
- package/plugins/drift-detect/lib/perf/baseline-store.js +0 -127
- package/plugins/drift-detect/lib/perf/benchmark-runner.js +0 -404
- package/plugins/drift-detect/lib/perf/breaking-point-finder.js +0 -52
- package/plugins/drift-detect/lib/perf/breaking-point-runner.js +0 -60
- package/plugins/drift-detect/lib/perf/checkpoint.js +0 -123
- package/plugins/drift-detect/lib/perf/code-paths.js +0 -86
- package/plugins/drift-detect/lib/perf/consolidation.js +0 -37
- package/plugins/drift-detect/lib/perf/constraint-runner.js +0 -71
- package/plugins/drift-detect/lib/perf/experiment-runner.js +0 -32
- package/plugins/drift-detect/lib/perf/index.js +0 -41
- package/plugins/drift-detect/lib/perf/investigation-state.js +0 -874
- package/plugins/drift-detect/lib/perf/optimization-runner.js +0 -79
- package/plugins/drift-detect/lib/perf/profilers/go.js +0 -22
- package/plugins/drift-detect/lib/perf/profilers/index.js +0 -46
- package/plugins/drift-detect/lib/perf/profilers/java.js +0 -23
- package/plugins/drift-detect/lib/perf/profilers/node.js +0 -27
- package/plugins/drift-detect/lib/perf/profilers/python.js +0 -23
- package/plugins/drift-detect/lib/perf/profilers/rust.js +0 -23
- package/plugins/drift-detect/lib/perf/profiling-runner.js +0 -75
- package/plugins/drift-detect/lib/perf/schemas.js +0 -140
- package/plugins/drift-detect/lib/platform/detect-platform.js +0 -413
- package/plugins/drift-detect/lib/platform/detection-configs.js +0 -93
- package/plugins/drift-detect/lib/platform/state-dir.js +0 -132
- package/plugins/drift-detect/lib/platform/verify-tools.js +0 -182
- package/plugins/drift-detect/lib/repo-map/cache.js +0 -152
- package/plugins/drift-detect/lib/repo-map/concurrency.js +0 -29
- package/plugins/drift-detect/lib/repo-map/index.js +0 -222
- package/plugins/drift-detect/lib/repo-map/installer.js +0 -212
- package/plugins/drift-detect/lib/repo-map/queries/go.js +0 -27
- package/plugins/drift-detect/lib/repo-map/queries/index.js +0 -100
- package/plugins/drift-detect/lib/repo-map/queries/java.js +0 -38
- package/plugins/drift-detect/lib/repo-map/queries/javascript.js +0 -55
- package/plugins/drift-detect/lib/repo-map/queries/python.js +0 -24
- package/plugins/drift-detect/lib/repo-map/queries/rust.js +0 -73
- package/plugins/drift-detect/lib/repo-map/queries/typescript.js +0 -38
- package/plugins/drift-detect/lib/repo-map/runner.js +0 -1364
- package/plugins/drift-detect/lib/repo-map/updater.js +0 -562
- package/plugins/drift-detect/lib/repo-map/usage-analyzer.js +0 -407
- package/plugins/drift-detect/lib/schemas/plugin-manifest.schema.json +0 -57
- package/plugins/drift-detect/lib/schemas/validator.js +0 -247
- package/plugins/drift-detect/lib/sources/custom-handler.js +0 -199
- package/plugins/drift-detect/lib/sources/policy-questions.js +0 -246
- package/plugins/drift-detect/lib/sources/source-cache.js +0 -165
- package/plugins/drift-detect/lib/state/workflow-state.js +0 -576
- package/plugins/drift-detect/lib/types/agent-frontmatter.d.ts +0 -134
- package/plugins/drift-detect/lib/types/command-frontmatter.d.ts +0 -107
- package/plugins/drift-detect/lib/types/hook-frontmatter.d.ts +0 -115
- package/plugins/drift-detect/lib/types/index.d.ts +0 -84
- package/plugins/drift-detect/lib/types/plugin-manifest.d.ts +0 -102
- package/plugins/drift-detect/lib/types/skill-frontmatter.d.ts +0 -89
- package/plugins/drift-detect/lib/utils/atomic-write.js +0 -94
- package/plugins/drift-detect/lib/utils/cache-manager.js +0 -159
- package/plugins/drift-detect/lib/utils/command-parser.js +0 -0
- package/plugins/drift-detect/lib/utils/context-optimizer.js +0 -300
- package/plugins/drift-detect/lib/utils/deprecation.js +0 -37
- package/plugins/drift-detect/lib/utils/shell-escape.js +0 -88
- package/plugins/drift-detect/lib/utils/state-helpers.js +0 -61
- package/plugins/drift-detect/skills/drift-analysis/SKILL.md +0 -324
- package/plugins/enhance/.claude-plugin/plugin.json +0 -20
- package/plugins/enhance/agents/agent-enhancer.md +0 -64
- package/plugins/enhance/agents/claudemd-enhancer.md +0 -65
- package/plugins/enhance/agents/cross-file-enhancer.md +0 -54
- package/plugins/enhance/agents/docs-enhancer.md +0 -64
- package/plugins/enhance/agents/hooks-enhancer.md +0 -64
- package/plugins/enhance/agents/plugin-enhancer.md +0 -63
- package/plugins/enhance/agents/prompt-enhancer.md +0 -58
- package/plugins/enhance/agents/skills-enhancer.md +0 -64
- package/plugins/enhance/commands/enhance.md +0 -178
- package/plugins/enhance/lib/adapter-transforms.js +0 -278
- package/plugins/enhance/lib/collectors/codebase.js +0 -392
- package/plugins/enhance/lib/collectors/docs-patterns.js +0 -713
- package/plugins/enhance/lib/collectors/documentation.js +0 -219
- package/plugins/enhance/lib/collectors/github.js +0 -330
- package/plugins/enhance/lib/collectors/index.js +0 -126
- package/plugins/enhance/lib/config/index.js +0 -14
- package/plugins/enhance/lib/cross-platform/index.js +0 -539
- package/plugins/enhance/lib/discovery/index.js +0 -352
- package/plugins/enhance/lib/drift-detect/collectors.js +0 -37
- package/plugins/enhance/lib/enhance/agent-analyzer.js +0 -421
- package/plugins/enhance/lib/enhance/agent-patterns.js +0 -571
- package/plugins/enhance/lib/enhance/auto-suppression.js +0 -622
- package/plugins/enhance/lib/enhance/benchmark.js +0 -417
- package/plugins/enhance/lib/enhance/cross-file-analyzer.js +0 -930
- package/plugins/enhance/lib/enhance/cross-file-patterns.js +0 -370
- package/plugins/enhance/lib/enhance/docs-analyzer.js +0 -325
- package/plugins/enhance/lib/enhance/docs-patterns.js +0 -671
- package/plugins/enhance/lib/enhance/fixer.js +0 -721
- package/plugins/enhance/lib/enhance/hook-analyzer.js +0 -135
- package/plugins/enhance/lib/enhance/hook-patterns.js +0 -40
- package/plugins/enhance/lib/enhance/index.js +0 -127
- package/plugins/enhance/lib/enhance/plugin-analyzer.js +0 -402
- package/plugins/enhance/lib/enhance/plugin-patterns.js +0 -326
- package/plugins/enhance/lib/enhance/projectmemory-analyzer.js +0 -551
- package/plugins/enhance/lib/enhance/projectmemory-patterns.js +0 -617
- package/plugins/enhance/lib/enhance/prompt-analyzer.js +0 -457
- package/plugins/enhance/lib/enhance/prompt-patterns.js +0 -1484
- package/plugins/enhance/lib/enhance/reporter.js +0 -1348
- package/plugins/enhance/lib/enhance/security-patterns.js +0 -284
- package/plugins/enhance/lib/enhance/skill-analyzer.js +0 -182
- package/plugins/enhance/lib/enhance/skill-patterns.js +0 -147
- package/plugins/enhance/lib/enhance/suppression.js +0 -352
- package/plugins/enhance/lib/enhance/tool-patterns.js +0 -373
- package/plugins/enhance/lib/index.js +0 -270
- package/plugins/enhance/lib/patterns/cli-enhancers.js +0 -611
- package/plugins/enhance/lib/patterns/pipeline.js +0 -948
- package/plugins/enhance/lib/patterns/review-patterns.js +0 -558
- package/plugins/enhance/lib/patterns/slop-analyzers.js +0 -2305
- package/plugins/enhance/lib/patterns/slop-patterns.js +0 -1187
- package/plugins/enhance/lib/perf/analyzer/index.js +0 -22
- package/plugins/enhance/lib/perf/argument-parser.js +0 -105
- package/plugins/enhance/lib/perf/baseline-comparator.js +0 -50
- package/plugins/enhance/lib/perf/baseline-store.js +0 -127
- package/plugins/enhance/lib/perf/benchmark-runner.js +0 -404
- package/plugins/enhance/lib/perf/breaking-point-finder.js +0 -52
- package/plugins/enhance/lib/perf/breaking-point-runner.js +0 -60
- package/plugins/enhance/lib/perf/checkpoint.js +0 -123
- package/plugins/enhance/lib/perf/code-paths.js +0 -86
- package/plugins/enhance/lib/perf/consolidation.js +0 -37
- package/plugins/enhance/lib/perf/constraint-runner.js +0 -71
- package/plugins/enhance/lib/perf/experiment-runner.js +0 -32
- package/plugins/enhance/lib/perf/index.js +0 -41
- package/plugins/enhance/lib/perf/investigation-state.js +0 -874
- package/plugins/enhance/lib/perf/optimization-runner.js +0 -79
- package/plugins/enhance/lib/perf/profilers/go.js +0 -22
- package/plugins/enhance/lib/perf/profilers/index.js +0 -46
- package/plugins/enhance/lib/perf/profilers/java.js +0 -23
- package/plugins/enhance/lib/perf/profilers/node.js +0 -27
- package/plugins/enhance/lib/perf/profilers/python.js +0 -23
- package/plugins/enhance/lib/perf/profilers/rust.js +0 -23
- package/plugins/enhance/lib/perf/profiling-runner.js +0 -75
- package/plugins/enhance/lib/perf/schemas.js +0 -140
- package/plugins/enhance/lib/platform/detect-platform.js +0 -413
- package/plugins/enhance/lib/platform/detection-configs.js +0 -93
- package/plugins/enhance/lib/platform/state-dir.js +0 -132
- package/plugins/enhance/lib/platform/verify-tools.js +0 -182
- package/plugins/enhance/lib/repo-map/cache.js +0 -152
- package/plugins/enhance/lib/repo-map/concurrency.js +0 -29
- package/plugins/enhance/lib/repo-map/index.js +0 -222
- package/plugins/enhance/lib/repo-map/installer.js +0 -212
- package/plugins/enhance/lib/repo-map/queries/go.js +0 -27
- package/plugins/enhance/lib/repo-map/queries/index.js +0 -100
- package/plugins/enhance/lib/repo-map/queries/java.js +0 -38
- package/plugins/enhance/lib/repo-map/queries/javascript.js +0 -55
- package/plugins/enhance/lib/repo-map/queries/python.js +0 -24
- package/plugins/enhance/lib/repo-map/queries/rust.js +0 -73
- package/plugins/enhance/lib/repo-map/queries/typescript.js +0 -38
- package/plugins/enhance/lib/repo-map/runner.js +0 -1364
- package/plugins/enhance/lib/repo-map/updater.js +0 -562
- package/plugins/enhance/lib/repo-map/usage-analyzer.js +0 -407
- package/plugins/enhance/lib/schemas/plugin-manifest.schema.json +0 -57
- package/plugins/enhance/lib/schemas/validator.js +0 -247
- package/plugins/enhance/lib/sources/custom-handler.js +0 -199
- package/plugins/enhance/lib/sources/policy-questions.js +0 -246
- package/plugins/enhance/lib/sources/source-cache.js +0 -165
- package/plugins/enhance/lib/state/workflow-state.js +0 -576
- package/plugins/enhance/lib/types/agent-frontmatter.d.ts +0 -134
- package/plugins/enhance/lib/types/command-frontmatter.d.ts +0 -107
- package/plugins/enhance/lib/types/hook-frontmatter.d.ts +0 -115
- package/plugins/enhance/lib/types/index.d.ts +0 -84
- package/plugins/enhance/lib/types/plugin-manifest.d.ts +0 -102
- package/plugins/enhance/lib/types/skill-frontmatter.d.ts +0 -89
- package/plugins/enhance/lib/utils/atomic-write.js +0 -94
- package/plugins/enhance/lib/utils/cache-manager.js +0 -159
- package/plugins/enhance/lib/utils/command-parser.js +0 -0
- package/plugins/enhance/lib/utils/context-optimizer.js +0 -300
- package/plugins/enhance/lib/utils/deprecation.js +0 -37
- package/plugins/enhance/lib/utils/shell-escape.js +0 -88
- package/plugins/enhance/lib/utils/state-helpers.js +0 -61
- package/plugins/enhance/skills/enhance-agent-prompts/SKILL.md +0 -277
- package/plugins/enhance/skills/enhance-claude-memory/SKILL.md +0 -387
- package/plugins/enhance/skills/enhance-cross-file/SKILL.md +0 -110
- package/plugins/enhance/skills/enhance-docs/SKILL.md +0 -298
- package/plugins/enhance/skills/enhance-hooks/SKILL.md +0 -554
- package/plugins/enhance/skills/enhance-orchestrator/SKILL.md +0 -255
- package/plugins/enhance/skills/enhance-plugins/SKILL.md +0 -319
- package/plugins/enhance/skills/enhance-prompts/SKILL.md +0 -340
- package/plugins/enhance/skills/enhance-skills/SKILL.md +0 -436
- package/plugins/learn/.claude-plugin/plugin.json +0 -21
- package/plugins/learn/agents/learn-agent.md +0 -331
- package/plugins/learn/commands/learn.md +0 -190
- package/plugins/learn/lib/adapter-transforms.js +0 -278
- package/plugins/learn/lib/collectors/codebase.js +0 -392
- package/plugins/learn/lib/collectors/docs-patterns.js +0 -713
- package/plugins/learn/lib/collectors/documentation.js +0 -219
- package/plugins/learn/lib/collectors/github.js +0 -330
- package/plugins/learn/lib/collectors/index.js +0 -126
- package/plugins/learn/lib/config/index.js +0 -14
- package/plugins/learn/lib/cross-platform/index.js +0 -539
- package/plugins/learn/lib/discovery/index.js +0 -352
- package/plugins/learn/lib/drift-detect/collectors.js +0 -37
- package/plugins/learn/lib/enhance/agent-analyzer.js +0 -421
- package/plugins/learn/lib/enhance/agent-patterns.js +0 -571
- package/plugins/learn/lib/enhance/auto-suppression.js +0 -622
- package/plugins/learn/lib/enhance/benchmark.js +0 -417
- package/plugins/learn/lib/enhance/cross-file-analyzer.js +0 -930
- package/plugins/learn/lib/enhance/cross-file-patterns.js +0 -370
- package/plugins/learn/lib/enhance/docs-analyzer.js +0 -325
- package/plugins/learn/lib/enhance/docs-patterns.js +0 -671
- package/plugins/learn/lib/enhance/fixer.js +0 -721
- package/plugins/learn/lib/enhance/hook-analyzer.js +0 -135
- package/plugins/learn/lib/enhance/hook-patterns.js +0 -40
- package/plugins/learn/lib/enhance/index.js +0 -127
- package/plugins/learn/lib/enhance/plugin-analyzer.js +0 -402
- package/plugins/learn/lib/enhance/plugin-patterns.js +0 -326
- package/plugins/learn/lib/enhance/projectmemory-analyzer.js +0 -551
- package/plugins/learn/lib/enhance/projectmemory-patterns.js +0 -617
- package/plugins/learn/lib/enhance/prompt-analyzer.js +0 -457
- package/plugins/learn/lib/enhance/prompt-patterns.js +0 -1484
- package/plugins/learn/lib/enhance/reporter.js +0 -1348
- package/plugins/learn/lib/enhance/security-patterns.js +0 -284
- package/plugins/learn/lib/enhance/skill-analyzer.js +0 -182
- package/plugins/learn/lib/enhance/skill-patterns.js +0 -147
- package/plugins/learn/lib/enhance/suppression.js +0 -352
- package/plugins/learn/lib/enhance/tool-patterns.js +0 -373
- package/plugins/learn/lib/index.js +0 -270
- package/plugins/learn/lib/patterns/cli-enhancers.js +0 -611
- package/plugins/learn/lib/patterns/pipeline.js +0 -948
- package/plugins/learn/lib/patterns/review-patterns.js +0 -558
- package/plugins/learn/lib/patterns/slop-analyzers.js +0 -2305
- package/plugins/learn/lib/patterns/slop-patterns.js +0 -1187
- package/plugins/learn/lib/perf/analyzer/index.js +0 -22
- package/plugins/learn/lib/perf/argument-parser.js +0 -105
- package/plugins/learn/lib/perf/baseline-comparator.js +0 -50
- package/plugins/learn/lib/perf/baseline-store.js +0 -127
- package/plugins/learn/lib/perf/benchmark-runner.js +0 -404
- package/plugins/learn/lib/perf/breaking-point-finder.js +0 -52
- package/plugins/learn/lib/perf/breaking-point-runner.js +0 -60
- package/plugins/learn/lib/perf/checkpoint.js +0 -123
- package/plugins/learn/lib/perf/code-paths.js +0 -86
- package/plugins/learn/lib/perf/consolidation.js +0 -37
- package/plugins/learn/lib/perf/constraint-runner.js +0 -71
- package/plugins/learn/lib/perf/experiment-runner.js +0 -32
- package/plugins/learn/lib/perf/index.js +0 -41
- package/plugins/learn/lib/perf/investigation-state.js +0 -874
- package/plugins/learn/lib/perf/optimization-runner.js +0 -79
- package/plugins/learn/lib/perf/profilers/go.js +0 -22
- package/plugins/learn/lib/perf/profilers/index.js +0 -46
- package/plugins/learn/lib/perf/profilers/java.js +0 -23
- package/plugins/learn/lib/perf/profilers/node.js +0 -27
- package/plugins/learn/lib/perf/profilers/python.js +0 -23
- package/plugins/learn/lib/perf/profilers/rust.js +0 -23
- package/plugins/learn/lib/perf/profiling-runner.js +0 -75
- package/plugins/learn/lib/perf/schemas.js +0 -140
- package/plugins/learn/lib/platform/detect-platform.js +0 -413
- package/plugins/learn/lib/platform/detection-configs.js +0 -93
- package/plugins/learn/lib/platform/state-dir.js +0 -132
- package/plugins/learn/lib/platform/verify-tools.js +0 -182
- package/plugins/learn/lib/repo-map/cache.js +0 -152
- package/plugins/learn/lib/repo-map/concurrency.js +0 -29
- package/plugins/learn/lib/repo-map/index.js +0 -222
- package/plugins/learn/lib/repo-map/installer.js +0 -212
- package/plugins/learn/lib/repo-map/queries/go.js +0 -27
- package/plugins/learn/lib/repo-map/queries/index.js +0 -100
- package/plugins/learn/lib/repo-map/queries/java.js +0 -38
- package/plugins/learn/lib/repo-map/queries/javascript.js +0 -55
- package/plugins/learn/lib/repo-map/queries/python.js +0 -24
- package/plugins/learn/lib/repo-map/queries/rust.js +0 -73
- package/plugins/learn/lib/repo-map/queries/typescript.js +0 -38
- package/plugins/learn/lib/repo-map/runner.js +0 -1364
- package/plugins/learn/lib/repo-map/updater.js +0 -562
- package/plugins/learn/lib/repo-map/usage-analyzer.js +0 -407
- package/plugins/learn/lib/schemas/plugin-manifest.schema.json +0 -57
- package/plugins/learn/lib/schemas/validator.js +0 -247
- package/plugins/learn/lib/sources/custom-handler.js +0 -199
- package/plugins/learn/lib/sources/policy-questions.js +0 -246
- package/plugins/learn/lib/sources/source-cache.js +0 -165
- package/plugins/learn/lib/state/workflow-state.js +0 -576
- package/plugins/learn/lib/types/agent-frontmatter.d.ts +0 -134
- package/plugins/learn/lib/types/command-frontmatter.d.ts +0 -107
- package/plugins/learn/lib/types/hook-frontmatter.d.ts +0 -115
- package/plugins/learn/lib/types/index.d.ts +0 -84
- package/plugins/learn/lib/types/plugin-manifest.d.ts +0 -102
- package/plugins/learn/lib/types/skill-frontmatter.d.ts +0 -89
- package/plugins/learn/lib/utils/atomic-write.js +0 -94
- package/plugins/learn/lib/utils/cache-manager.js +0 -159
- package/plugins/learn/lib/utils/command-parser.js +0 -0
- package/plugins/learn/lib/utils/context-optimizer.js +0 -300
- package/plugins/learn/lib/utils/deprecation.js +0 -37
- package/plugins/learn/lib/utils/shell-escape.js +0 -88
- package/plugins/learn/lib/utils/state-helpers.js +0 -61
- package/plugins/learn/skills/learn/SKILL.md +0 -349
- package/plugins/next-task/.claude-plugin/plugin.json +0 -24
- package/plugins/next-task/agents/ci-fixer.md +0 -259
- package/plugins/next-task/agents/ci-monitor.md +0 -342
- package/plugins/next-task/agents/delivery-validator.md +0 -115
- package/plugins/next-task/agents/exploration-agent.md +0 -316
- package/plugins/next-task/agents/implementation-agent.md +0 -465
- package/plugins/next-task/agents/planning-agent.md +0 -377
- package/plugins/next-task/agents/simple-fixer.md +0 -139
- package/plugins/next-task/agents/task-discoverer.md +0 -89
- package/plugins/next-task/agents/test-coverage-checker.md +0 -451
- package/plugins/next-task/agents/worktree-manager.md +0 -257
- package/plugins/next-task/commands/delivery-approval.md +0 -341
- package/plugins/next-task/commands/next-task.md +0 -547
- package/plugins/next-task/hooks/hooks.json +0 -14
- package/plugins/next-task/lib/adapter-transforms.js +0 -278
- package/plugins/next-task/lib/collectors/codebase.js +0 -392
- package/plugins/next-task/lib/collectors/docs-patterns.js +0 -713
- package/plugins/next-task/lib/collectors/documentation.js +0 -219
- package/plugins/next-task/lib/collectors/github.js +0 -330
- package/plugins/next-task/lib/collectors/index.js +0 -126
- package/plugins/next-task/lib/config/index.js +0 -14
- package/plugins/next-task/lib/cross-platform/index.js +0 -539
- package/plugins/next-task/lib/discovery/index.js +0 -352
- package/plugins/next-task/lib/drift-detect/collectors.js +0 -37
- package/plugins/next-task/lib/enhance/agent-analyzer.js +0 -421
- package/plugins/next-task/lib/enhance/agent-patterns.js +0 -571
- package/plugins/next-task/lib/enhance/auto-suppression.js +0 -622
- package/plugins/next-task/lib/enhance/benchmark.js +0 -417
- package/plugins/next-task/lib/enhance/cross-file-analyzer.js +0 -930
- package/plugins/next-task/lib/enhance/cross-file-patterns.js +0 -370
- package/plugins/next-task/lib/enhance/docs-analyzer.js +0 -325
- package/plugins/next-task/lib/enhance/docs-patterns.js +0 -671
- package/plugins/next-task/lib/enhance/fixer.js +0 -721
- package/plugins/next-task/lib/enhance/hook-analyzer.js +0 -135
- package/plugins/next-task/lib/enhance/hook-patterns.js +0 -40
- package/plugins/next-task/lib/enhance/index.js +0 -127
- package/plugins/next-task/lib/enhance/plugin-analyzer.js +0 -402
- package/plugins/next-task/lib/enhance/plugin-patterns.js +0 -326
- package/plugins/next-task/lib/enhance/projectmemory-analyzer.js +0 -551
- package/plugins/next-task/lib/enhance/projectmemory-patterns.js +0 -617
- package/plugins/next-task/lib/enhance/prompt-analyzer.js +0 -457
- package/plugins/next-task/lib/enhance/prompt-patterns.js +0 -1484
- package/plugins/next-task/lib/enhance/reporter.js +0 -1348
- package/plugins/next-task/lib/enhance/security-patterns.js +0 -284
- package/plugins/next-task/lib/enhance/skill-analyzer.js +0 -182
- package/plugins/next-task/lib/enhance/skill-patterns.js +0 -147
- package/plugins/next-task/lib/enhance/suppression.js +0 -352
- package/plugins/next-task/lib/enhance/tool-patterns.js +0 -373
- package/plugins/next-task/lib/index.js +0 -270
- package/plugins/next-task/lib/patterns/cli-enhancers.js +0 -611
- package/plugins/next-task/lib/patterns/pipeline.js +0 -948
- package/plugins/next-task/lib/patterns/review-patterns.js +0 -558
- package/plugins/next-task/lib/patterns/slop-analyzers.js +0 -2305
- package/plugins/next-task/lib/patterns/slop-patterns.js +0 -1187
- package/plugins/next-task/lib/perf/analyzer/index.js +0 -22
- package/plugins/next-task/lib/perf/argument-parser.js +0 -105
- package/plugins/next-task/lib/perf/baseline-comparator.js +0 -50
- package/plugins/next-task/lib/perf/baseline-store.js +0 -127
- package/plugins/next-task/lib/perf/benchmark-runner.js +0 -404
- package/plugins/next-task/lib/perf/breaking-point-finder.js +0 -52
- package/plugins/next-task/lib/perf/breaking-point-runner.js +0 -60
- package/plugins/next-task/lib/perf/checkpoint.js +0 -123
- package/plugins/next-task/lib/perf/code-paths.js +0 -86
- package/plugins/next-task/lib/perf/consolidation.js +0 -37
- package/plugins/next-task/lib/perf/constraint-runner.js +0 -71
- package/plugins/next-task/lib/perf/experiment-runner.js +0 -32
- package/plugins/next-task/lib/perf/index.js +0 -41
- package/plugins/next-task/lib/perf/investigation-state.js +0 -874
- package/plugins/next-task/lib/perf/optimization-runner.js +0 -79
- package/plugins/next-task/lib/perf/profilers/go.js +0 -22
- package/plugins/next-task/lib/perf/profilers/index.js +0 -46
- package/plugins/next-task/lib/perf/profilers/java.js +0 -23
- package/plugins/next-task/lib/perf/profilers/node.js +0 -27
- package/plugins/next-task/lib/perf/profilers/python.js +0 -23
- package/plugins/next-task/lib/perf/profilers/rust.js +0 -23
- package/plugins/next-task/lib/perf/profiling-runner.js +0 -75
- package/plugins/next-task/lib/perf/schemas.js +0 -140
- package/plugins/next-task/lib/platform/detect-platform.js +0 -413
- package/plugins/next-task/lib/platform/detection-configs.js +0 -93
- package/plugins/next-task/lib/platform/state-dir.js +0 -132
- package/plugins/next-task/lib/platform/verify-tools.js +0 -182
- package/plugins/next-task/lib/repo-map/cache.js +0 -152
- package/plugins/next-task/lib/repo-map/concurrency.js +0 -29
- package/plugins/next-task/lib/repo-map/index.js +0 -222
- package/plugins/next-task/lib/repo-map/installer.js +0 -212
- package/plugins/next-task/lib/repo-map/queries/go.js +0 -27
- package/plugins/next-task/lib/repo-map/queries/index.js +0 -100
- package/plugins/next-task/lib/repo-map/queries/java.js +0 -38
- package/plugins/next-task/lib/repo-map/queries/javascript.js +0 -55
- package/plugins/next-task/lib/repo-map/queries/python.js +0 -24
- package/plugins/next-task/lib/repo-map/queries/rust.js +0 -73
- package/plugins/next-task/lib/repo-map/queries/typescript.js +0 -38
- package/plugins/next-task/lib/repo-map/runner.js +0 -1364
- package/plugins/next-task/lib/repo-map/updater.js +0 -562
- package/plugins/next-task/lib/repo-map/usage-analyzer.js +0 -407
- package/plugins/next-task/lib/schemas/plugin-manifest.schema.json +0 -57
- package/plugins/next-task/lib/schemas/validator.js +0 -247
- package/plugins/next-task/lib/sources/custom-handler.js +0 -199
- package/plugins/next-task/lib/sources/policy-questions.js +0 -246
- package/plugins/next-task/lib/sources/source-cache.js +0 -165
- package/plugins/next-task/lib/state/workflow-state.js +0 -576
- package/plugins/next-task/lib/types/agent-frontmatter.d.ts +0 -134
- package/plugins/next-task/lib/types/command-frontmatter.d.ts +0 -107
- package/plugins/next-task/lib/types/hook-frontmatter.d.ts +0 -115
- package/plugins/next-task/lib/types/index.d.ts +0 -84
- package/plugins/next-task/lib/types/plugin-manifest.d.ts +0 -102
- package/plugins/next-task/lib/types/skill-frontmatter.d.ts +0 -89
- package/plugins/next-task/lib/utils/atomic-write.js +0 -94
- package/plugins/next-task/lib/utils/cache-manager.js +0 -159
- package/plugins/next-task/lib/utils/command-parser.js +0 -0
- package/plugins/next-task/lib/utils/context-optimizer.js +0 -300
- package/plugins/next-task/lib/utils/deprecation.js +0 -37
- package/plugins/next-task/lib/utils/shell-escape.js +0 -88
- package/plugins/next-task/lib/utils/state-helpers.js +0 -61
- package/plugins/next-task/skills/discover-tasks/SKILL.md +0 -191
- package/plugins/next-task/skills/orchestrate-review/SKILL.md +0 -239
- package/plugins/next-task/skills/validate-delivery/SKILL.md +0 -186
- package/plugins/perf/.claude-plugin/plugin.json +0 -20
- package/plugins/perf/agents/perf-analyzer.md +0 -43
- package/plugins/perf/agents/perf-code-paths.md +0 -16
- package/plugins/perf/agents/perf-investigation-logger.md +0 -47
- package/plugins/perf/agents/perf-orchestrator.md +0 -344
- package/plugins/perf/agents/perf-theory-gatherer.md +0 -25
- package/plugins/perf/agents/perf-theory-tester.md +0 -58
- package/plugins/perf/commands/perf.md +0 -470
- package/plugins/perf/hooks/checkpoint.md +0 -35
- package/plugins/perf/hooks/constraint-tester.md +0 -40
- package/plugins/perf/lib/adapter-transforms.js +0 -278
- package/plugins/perf/lib/collectors/codebase.js +0 -392
- package/plugins/perf/lib/collectors/docs-patterns.js +0 -713
- package/plugins/perf/lib/collectors/documentation.js +0 -219
- package/plugins/perf/lib/collectors/github.js +0 -330
- package/plugins/perf/lib/collectors/index.js +0 -126
- package/plugins/perf/lib/config/index.js +0 -14
- package/plugins/perf/lib/cross-platform/index.js +0 -539
- package/plugins/perf/lib/discovery/index.js +0 -352
- package/plugins/perf/lib/drift-detect/collectors.js +0 -37
- package/plugins/perf/lib/enhance/agent-analyzer.js +0 -421
- package/plugins/perf/lib/enhance/agent-patterns.js +0 -571
- package/plugins/perf/lib/enhance/auto-suppression.js +0 -622
- package/plugins/perf/lib/enhance/benchmark.js +0 -417
- package/plugins/perf/lib/enhance/cross-file-analyzer.js +0 -930
- package/plugins/perf/lib/enhance/cross-file-patterns.js +0 -370
- package/plugins/perf/lib/enhance/docs-analyzer.js +0 -325
- package/plugins/perf/lib/enhance/docs-patterns.js +0 -671
- package/plugins/perf/lib/enhance/fixer.js +0 -721
- package/plugins/perf/lib/enhance/hook-analyzer.js +0 -135
- package/plugins/perf/lib/enhance/hook-patterns.js +0 -40
- package/plugins/perf/lib/enhance/index.js +0 -127
- package/plugins/perf/lib/enhance/plugin-analyzer.js +0 -402
- package/plugins/perf/lib/enhance/plugin-patterns.js +0 -326
- package/plugins/perf/lib/enhance/projectmemory-analyzer.js +0 -551
- package/plugins/perf/lib/enhance/projectmemory-patterns.js +0 -617
- package/plugins/perf/lib/enhance/prompt-analyzer.js +0 -457
- package/plugins/perf/lib/enhance/prompt-patterns.js +0 -1484
- package/plugins/perf/lib/enhance/reporter.js +0 -1348
- package/plugins/perf/lib/enhance/security-patterns.js +0 -284
- package/plugins/perf/lib/enhance/skill-analyzer.js +0 -182
- package/plugins/perf/lib/enhance/skill-patterns.js +0 -147
- package/plugins/perf/lib/enhance/suppression.js +0 -352
- package/plugins/perf/lib/enhance/tool-patterns.js +0 -373
- package/plugins/perf/lib/index.js +0 -270
- package/plugins/perf/lib/patterns/cli-enhancers.js +0 -611
- package/plugins/perf/lib/patterns/pipeline.js +0 -948
- package/plugins/perf/lib/patterns/review-patterns.js +0 -558
- package/plugins/perf/lib/patterns/slop-analyzers.js +0 -2305
- package/plugins/perf/lib/patterns/slop-patterns.js +0 -1187
- package/plugins/perf/lib/perf/analyzer/index.js +0 -22
- package/plugins/perf/lib/perf/argument-parser.js +0 -105
- package/plugins/perf/lib/perf/baseline-comparator.js +0 -50
- package/plugins/perf/lib/perf/baseline-store.js +0 -127
- package/plugins/perf/lib/perf/benchmark-runner.js +0 -404
- package/plugins/perf/lib/perf/breaking-point-finder.js +0 -52
- package/plugins/perf/lib/perf/breaking-point-runner.js +0 -60
- package/plugins/perf/lib/perf/checkpoint.js +0 -123
- package/plugins/perf/lib/perf/code-paths.js +0 -86
- package/plugins/perf/lib/perf/consolidation.js +0 -37
- package/plugins/perf/lib/perf/constraint-runner.js +0 -71
- package/plugins/perf/lib/perf/experiment-runner.js +0 -32
- package/plugins/perf/lib/perf/index.js +0 -41
- package/plugins/perf/lib/perf/investigation-state.js +0 -874
- package/plugins/perf/lib/perf/optimization-runner.js +0 -79
- package/plugins/perf/lib/perf/profilers/go.js +0 -22
- package/plugins/perf/lib/perf/profilers/index.js +0 -46
- package/plugins/perf/lib/perf/profilers/java.js +0 -23
- package/plugins/perf/lib/perf/profilers/node.js +0 -27
- package/plugins/perf/lib/perf/profilers/python.js +0 -23
- package/plugins/perf/lib/perf/profilers/rust.js +0 -23
- package/plugins/perf/lib/perf/profiling-runner.js +0 -75
- package/plugins/perf/lib/perf/schemas.js +0 -140
- package/plugins/perf/lib/platform/detect-platform.js +0 -413
- package/plugins/perf/lib/platform/detection-configs.js +0 -93
- package/plugins/perf/lib/platform/state-dir.js +0 -132
- package/plugins/perf/lib/platform/verify-tools.js +0 -182
- package/plugins/perf/lib/repo-map/cache.js +0 -152
- package/plugins/perf/lib/repo-map/concurrency.js +0 -29
- package/plugins/perf/lib/repo-map/index.js +0 -222
- package/plugins/perf/lib/repo-map/installer.js +0 -212
- package/plugins/perf/lib/repo-map/queries/go.js +0 -27
- package/plugins/perf/lib/repo-map/queries/index.js +0 -100
- package/plugins/perf/lib/repo-map/queries/java.js +0 -38
- package/plugins/perf/lib/repo-map/queries/javascript.js +0 -55
- package/plugins/perf/lib/repo-map/queries/python.js +0 -24
- package/plugins/perf/lib/repo-map/queries/rust.js +0 -73
- package/plugins/perf/lib/repo-map/queries/typescript.js +0 -38
- package/plugins/perf/lib/repo-map/runner.js +0 -1364
- package/plugins/perf/lib/repo-map/updater.js +0 -562
- package/plugins/perf/lib/repo-map/usage-analyzer.js +0 -407
- package/plugins/perf/lib/schemas/plugin-manifest.schema.json +0 -57
- package/plugins/perf/lib/schemas/validator.js +0 -247
- package/plugins/perf/lib/sources/custom-handler.js +0 -199
- package/plugins/perf/lib/sources/policy-questions.js +0 -246
- package/plugins/perf/lib/sources/source-cache.js +0 -165
- package/plugins/perf/lib/state/workflow-state.js +0 -576
- package/plugins/perf/lib/types/agent-frontmatter.d.ts +0 -134
- package/plugins/perf/lib/types/command-frontmatter.d.ts +0 -107
- package/plugins/perf/lib/types/hook-frontmatter.d.ts +0 -115
- package/plugins/perf/lib/types/index.d.ts +0 -84
- package/plugins/perf/lib/types/plugin-manifest.d.ts +0 -102
- package/plugins/perf/lib/types/skill-frontmatter.d.ts +0 -89
- package/plugins/perf/lib/utils/atomic-write.js +0 -94
- package/plugins/perf/lib/utils/cache-manager.js +0 -159
- package/plugins/perf/lib/utils/command-parser.js +0 -0
- package/plugins/perf/lib/utils/context-optimizer.js +0 -300
- package/plugins/perf/lib/utils/deprecation.js +0 -37
- package/plugins/perf/lib/utils/shell-escape.js +0 -88
- package/plugins/perf/lib/utils/state-helpers.js +0 -61
- package/plugins/perf/skills/perf-analyzer/SKILL.md +0 -37
- package/plugins/perf/skills/perf-baseline-manager/SKILL.md +0 -30
- package/plugins/perf/skills/perf-benchmarker/SKILL.md +0 -52
- package/plugins/perf/skills/perf-code-paths/SKILL.md +0 -32
- package/plugins/perf/skills/perf-investigation-logger/SKILL.md +0 -41
- package/plugins/perf/skills/perf-profiler/SKILL.md +0 -42
- package/plugins/perf/skills/perf-theory-gatherer/SKILL.md +0 -35
- package/plugins/perf/skills/perf-theory-tester/SKILL.md +0 -36
- package/plugins/repo-map/.claude-plugin/plugin.json +0 -22
- package/plugins/repo-map/agents/map-validator.md +0 -60
- package/plugins/repo-map/commands/repo-map.md +0 -133
- package/plugins/repo-map/lib/adapter-transforms.js +0 -278
- package/plugins/repo-map/lib/collectors/codebase.js +0 -392
- package/plugins/repo-map/lib/collectors/docs-patterns.js +0 -713
- package/plugins/repo-map/lib/collectors/documentation.js +0 -219
- package/plugins/repo-map/lib/collectors/github.js +0 -330
- package/plugins/repo-map/lib/collectors/index.js +0 -126
- package/plugins/repo-map/lib/config/index.js +0 -14
- package/plugins/repo-map/lib/cross-platform/index.js +0 -539
- package/plugins/repo-map/lib/discovery/index.js +0 -352
- package/plugins/repo-map/lib/drift-detect/collectors.js +0 -37
- package/plugins/repo-map/lib/enhance/agent-analyzer.js +0 -421
- package/plugins/repo-map/lib/enhance/agent-patterns.js +0 -571
- package/plugins/repo-map/lib/enhance/auto-suppression.js +0 -622
- package/plugins/repo-map/lib/enhance/benchmark.js +0 -417
- package/plugins/repo-map/lib/enhance/cross-file-analyzer.js +0 -930
- package/plugins/repo-map/lib/enhance/cross-file-patterns.js +0 -370
- package/plugins/repo-map/lib/enhance/docs-analyzer.js +0 -325
- package/plugins/repo-map/lib/enhance/docs-patterns.js +0 -671
- package/plugins/repo-map/lib/enhance/fixer.js +0 -721
- package/plugins/repo-map/lib/enhance/hook-analyzer.js +0 -135
- package/plugins/repo-map/lib/enhance/hook-patterns.js +0 -40
- package/plugins/repo-map/lib/enhance/index.js +0 -127
- package/plugins/repo-map/lib/enhance/plugin-analyzer.js +0 -402
- package/plugins/repo-map/lib/enhance/plugin-patterns.js +0 -326
- package/plugins/repo-map/lib/enhance/projectmemory-analyzer.js +0 -551
- package/plugins/repo-map/lib/enhance/projectmemory-patterns.js +0 -617
- package/plugins/repo-map/lib/enhance/prompt-analyzer.js +0 -457
- package/plugins/repo-map/lib/enhance/prompt-patterns.js +0 -1484
- package/plugins/repo-map/lib/enhance/reporter.js +0 -1348
- package/plugins/repo-map/lib/enhance/security-patterns.js +0 -284
- package/plugins/repo-map/lib/enhance/skill-analyzer.js +0 -182
- package/plugins/repo-map/lib/enhance/skill-patterns.js +0 -147
- package/plugins/repo-map/lib/enhance/suppression.js +0 -352
- package/plugins/repo-map/lib/enhance/tool-patterns.js +0 -373
- package/plugins/repo-map/lib/index.js +0 -270
- package/plugins/repo-map/lib/patterns/cli-enhancers.js +0 -611
- package/plugins/repo-map/lib/patterns/pipeline.js +0 -948
- package/plugins/repo-map/lib/patterns/review-patterns.js +0 -558
- package/plugins/repo-map/lib/patterns/slop-analyzers.js +0 -2305
- package/plugins/repo-map/lib/patterns/slop-patterns.js +0 -1187
- package/plugins/repo-map/lib/perf/analyzer/index.js +0 -22
- package/plugins/repo-map/lib/perf/argument-parser.js +0 -105
- package/plugins/repo-map/lib/perf/baseline-comparator.js +0 -50
- package/plugins/repo-map/lib/perf/baseline-store.js +0 -127
- package/plugins/repo-map/lib/perf/benchmark-runner.js +0 -404
- package/plugins/repo-map/lib/perf/breaking-point-finder.js +0 -52
- package/plugins/repo-map/lib/perf/breaking-point-runner.js +0 -60
- package/plugins/repo-map/lib/perf/checkpoint.js +0 -123
- package/plugins/repo-map/lib/perf/code-paths.js +0 -86
- package/plugins/repo-map/lib/perf/consolidation.js +0 -37
- package/plugins/repo-map/lib/perf/constraint-runner.js +0 -71
- package/plugins/repo-map/lib/perf/experiment-runner.js +0 -32
- package/plugins/repo-map/lib/perf/index.js +0 -41
- package/plugins/repo-map/lib/perf/investigation-state.js +0 -874
- package/plugins/repo-map/lib/perf/optimization-runner.js +0 -79
- package/plugins/repo-map/lib/perf/profilers/go.js +0 -22
- package/plugins/repo-map/lib/perf/profilers/index.js +0 -46
- package/plugins/repo-map/lib/perf/profilers/java.js +0 -23
- package/plugins/repo-map/lib/perf/profilers/node.js +0 -27
- package/plugins/repo-map/lib/perf/profilers/python.js +0 -23
- package/plugins/repo-map/lib/perf/profilers/rust.js +0 -23
- package/plugins/repo-map/lib/perf/profiling-runner.js +0 -75
- package/plugins/repo-map/lib/perf/schemas.js +0 -140
- package/plugins/repo-map/lib/platform/detect-platform.js +0 -413
- package/plugins/repo-map/lib/platform/detection-configs.js +0 -93
- package/plugins/repo-map/lib/platform/state-dir.js +0 -132
- package/plugins/repo-map/lib/platform/verify-tools.js +0 -182
- package/plugins/repo-map/lib/repo-map/cache.js +0 -152
- package/plugins/repo-map/lib/repo-map/concurrency.js +0 -29
- package/plugins/repo-map/lib/repo-map/index.js +0 -222
- package/plugins/repo-map/lib/repo-map/installer.js +0 -212
- package/plugins/repo-map/lib/repo-map/queries/go.js +0 -27
- package/plugins/repo-map/lib/repo-map/queries/index.js +0 -100
- package/plugins/repo-map/lib/repo-map/queries/java.js +0 -38
- package/plugins/repo-map/lib/repo-map/queries/javascript.js +0 -55
- package/plugins/repo-map/lib/repo-map/queries/python.js +0 -24
- package/plugins/repo-map/lib/repo-map/queries/rust.js +0 -73
- package/plugins/repo-map/lib/repo-map/queries/typescript.js +0 -38
- package/plugins/repo-map/lib/repo-map/runner.js +0 -1364
- package/plugins/repo-map/lib/repo-map/updater.js +0 -562
- package/plugins/repo-map/lib/repo-map/usage-analyzer.js +0 -407
- package/plugins/repo-map/lib/schemas/plugin-manifest.schema.json +0 -57
- package/plugins/repo-map/lib/schemas/validator.js +0 -247
- package/plugins/repo-map/lib/sources/custom-handler.js +0 -199
- package/plugins/repo-map/lib/sources/policy-questions.js +0 -246
- package/plugins/repo-map/lib/sources/source-cache.js +0 -165
- package/plugins/repo-map/lib/state/workflow-state.js +0 -576
- package/plugins/repo-map/lib/types/agent-frontmatter.d.ts +0 -134
- package/plugins/repo-map/lib/types/command-frontmatter.d.ts +0 -107
- package/plugins/repo-map/lib/types/hook-frontmatter.d.ts +0 -115
- package/plugins/repo-map/lib/types/index.d.ts +0 -84
- package/plugins/repo-map/lib/types/plugin-manifest.d.ts +0 -102
- package/plugins/repo-map/lib/types/skill-frontmatter.d.ts +0 -89
- package/plugins/repo-map/lib/utils/atomic-write.js +0 -94
- package/plugins/repo-map/lib/utils/cache-manager.js +0 -159
- package/plugins/repo-map/lib/utils/command-parser.js +0 -0
- package/plugins/repo-map/lib/utils/context-optimizer.js +0 -300
- package/plugins/repo-map/lib/utils/deprecation.js +0 -37
- package/plugins/repo-map/lib/utils/shell-escape.js +0 -88
- package/plugins/repo-map/lib/utils/state-helpers.js +0 -61
- package/plugins/repo-map/skills/repo-mapping/SKILL.md +0 -83
- package/plugins/ship/.claude-plugin/plugin.json +0 -21
- package/plugins/ship/commands/ship-ci-review-loop.md +0 -472
- package/plugins/ship/commands/ship-deployment.md +0 -335
- package/plugins/ship/commands/ship-error-handling.md +0 -258
- package/plugins/ship/commands/ship.md +0 -492
- package/plugins/ship/lib/adapter-transforms.js +0 -278
- package/plugins/ship/lib/collectors/codebase.js +0 -392
- package/plugins/ship/lib/collectors/docs-patterns.js +0 -713
- package/plugins/ship/lib/collectors/documentation.js +0 -219
- package/plugins/ship/lib/collectors/github.js +0 -330
- package/plugins/ship/lib/collectors/index.js +0 -126
- package/plugins/ship/lib/config/index.js +0 -14
- package/plugins/ship/lib/cross-platform/index.js +0 -539
- package/plugins/ship/lib/discovery/index.js +0 -352
- package/plugins/ship/lib/drift-detect/collectors.js +0 -37
- package/plugins/ship/lib/enhance/agent-analyzer.js +0 -421
- package/plugins/ship/lib/enhance/agent-patterns.js +0 -571
- package/plugins/ship/lib/enhance/auto-suppression.js +0 -622
- package/plugins/ship/lib/enhance/benchmark.js +0 -417
- package/plugins/ship/lib/enhance/cross-file-analyzer.js +0 -930
- package/plugins/ship/lib/enhance/cross-file-patterns.js +0 -370
- package/plugins/ship/lib/enhance/docs-analyzer.js +0 -325
- package/plugins/ship/lib/enhance/docs-patterns.js +0 -671
- package/plugins/ship/lib/enhance/fixer.js +0 -721
- package/plugins/ship/lib/enhance/hook-analyzer.js +0 -135
- package/plugins/ship/lib/enhance/hook-patterns.js +0 -40
- package/plugins/ship/lib/enhance/index.js +0 -127
- package/plugins/ship/lib/enhance/plugin-analyzer.js +0 -402
- package/plugins/ship/lib/enhance/plugin-patterns.js +0 -326
- package/plugins/ship/lib/enhance/projectmemory-analyzer.js +0 -551
- package/plugins/ship/lib/enhance/projectmemory-patterns.js +0 -617
- package/plugins/ship/lib/enhance/prompt-analyzer.js +0 -457
- package/plugins/ship/lib/enhance/prompt-patterns.js +0 -1484
- package/plugins/ship/lib/enhance/reporter.js +0 -1348
- package/plugins/ship/lib/enhance/security-patterns.js +0 -284
- package/plugins/ship/lib/enhance/skill-analyzer.js +0 -182
- package/plugins/ship/lib/enhance/skill-patterns.js +0 -147
- package/plugins/ship/lib/enhance/suppression.js +0 -352
- package/plugins/ship/lib/enhance/tool-patterns.js +0 -373
- package/plugins/ship/lib/index.js +0 -270
- package/plugins/ship/lib/patterns/cli-enhancers.js +0 -611
- package/plugins/ship/lib/patterns/pipeline.js +0 -948
- package/plugins/ship/lib/patterns/review-patterns.js +0 -558
- package/plugins/ship/lib/patterns/slop-analyzers.js +0 -2305
- package/plugins/ship/lib/patterns/slop-patterns.js +0 -1187
- package/plugins/ship/lib/perf/analyzer/index.js +0 -22
- package/plugins/ship/lib/perf/argument-parser.js +0 -105
- package/plugins/ship/lib/perf/baseline-comparator.js +0 -50
- package/plugins/ship/lib/perf/baseline-store.js +0 -127
- package/plugins/ship/lib/perf/benchmark-runner.js +0 -404
- package/plugins/ship/lib/perf/breaking-point-finder.js +0 -52
- package/plugins/ship/lib/perf/breaking-point-runner.js +0 -60
- package/plugins/ship/lib/perf/checkpoint.js +0 -123
- package/plugins/ship/lib/perf/code-paths.js +0 -86
- package/plugins/ship/lib/perf/consolidation.js +0 -37
- package/plugins/ship/lib/perf/constraint-runner.js +0 -71
- package/plugins/ship/lib/perf/experiment-runner.js +0 -32
- package/plugins/ship/lib/perf/index.js +0 -41
- package/plugins/ship/lib/perf/investigation-state.js +0 -874
- package/plugins/ship/lib/perf/optimization-runner.js +0 -79
- package/plugins/ship/lib/perf/profilers/go.js +0 -22
- package/plugins/ship/lib/perf/profilers/index.js +0 -46
- package/plugins/ship/lib/perf/profilers/java.js +0 -23
- package/plugins/ship/lib/perf/profilers/node.js +0 -27
- package/plugins/ship/lib/perf/profilers/python.js +0 -23
- package/plugins/ship/lib/perf/profilers/rust.js +0 -23
- package/plugins/ship/lib/perf/profiling-runner.js +0 -75
- package/plugins/ship/lib/perf/schemas.js +0 -140
- package/plugins/ship/lib/platform/detect-platform.js +0 -413
- package/plugins/ship/lib/platform/detection-configs.js +0 -93
- package/plugins/ship/lib/platform/state-dir.js +0 -132
- package/plugins/ship/lib/platform/verify-tools.js +0 -182
- package/plugins/ship/lib/repo-map/cache.js +0 -152
- package/plugins/ship/lib/repo-map/concurrency.js +0 -29
- package/plugins/ship/lib/repo-map/index.js +0 -222
- package/plugins/ship/lib/repo-map/installer.js +0 -212
- package/plugins/ship/lib/repo-map/queries/go.js +0 -27
- package/plugins/ship/lib/repo-map/queries/index.js +0 -100
- package/plugins/ship/lib/repo-map/queries/java.js +0 -38
- package/plugins/ship/lib/repo-map/queries/javascript.js +0 -55
- package/plugins/ship/lib/repo-map/queries/python.js +0 -24
- package/plugins/ship/lib/repo-map/queries/rust.js +0 -73
- package/plugins/ship/lib/repo-map/queries/typescript.js +0 -38
- package/plugins/ship/lib/repo-map/runner.js +0 -1364
- package/plugins/ship/lib/repo-map/updater.js +0 -562
- package/plugins/ship/lib/repo-map/usage-analyzer.js +0 -407
- package/plugins/ship/lib/schemas/plugin-manifest.schema.json +0 -57
- package/plugins/ship/lib/schemas/validator.js +0 -247
- package/plugins/ship/lib/sources/custom-handler.js +0 -199
- package/plugins/ship/lib/sources/policy-questions.js +0 -246
- package/plugins/ship/lib/sources/source-cache.js +0 -165
- package/plugins/ship/lib/state/workflow-state.js +0 -576
- package/plugins/ship/lib/types/agent-frontmatter.d.ts +0 -134
- package/plugins/ship/lib/types/command-frontmatter.d.ts +0 -107
- package/plugins/ship/lib/types/hook-frontmatter.d.ts +0 -115
- package/plugins/ship/lib/types/index.d.ts +0 -84
- package/plugins/ship/lib/types/plugin-manifest.d.ts +0 -102
- package/plugins/ship/lib/types/skill-frontmatter.d.ts +0 -89
- package/plugins/ship/lib/utils/atomic-write.js +0 -94
- package/plugins/ship/lib/utils/cache-manager.js +0 -159
- package/plugins/ship/lib/utils/command-parser.js +0 -0
- package/plugins/ship/lib/utils/context-optimizer.js +0 -300
- package/plugins/ship/lib/utils/deprecation.js +0 -37
- package/plugins/ship/lib/utils/shell-escape.js +0 -88
- package/plugins/ship/lib/utils/state-helpers.js +0 -61
- package/plugins/sync-docs/.claude-plugin/plugin.json +0 -20
- package/plugins/sync-docs/agents/sync-docs-agent.md +0 -154
- package/plugins/sync-docs/commands/sync-docs.md +0 -186
- package/plugins/sync-docs/lib/adapter-transforms.js +0 -278
- package/plugins/sync-docs/lib/collectors/codebase.js +0 -392
- package/plugins/sync-docs/lib/collectors/docs-patterns.js +0 -713
- package/plugins/sync-docs/lib/collectors/documentation.js +0 -219
- package/plugins/sync-docs/lib/collectors/github.js +0 -330
- package/plugins/sync-docs/lib/collectors/index.js +0 -126
- package/plugins/sync-docs/lib/config/index.js +0 -14
- package/plugins/sync-docs/lib/cross-platform/index.js +0 -539
- package/plugins/sync-docs/lib/discovery/index.js +0 -352
- package/plugins/sync-docs/lib/drift-detect/collectors.js +0 -37
- package/plugins/sync-docs/lib/enhance/agent-analyzer.js +0 -421
- package/plugins/sync-docs/lib/enhance/agent-patterns.js +0 -571
- package/plugins/sync-docs/lib/enhance/auto-suppression.js +0 -622
- package/plugins/sync-docs/lib/enhance/benchmark.js +0 -417
- package/plugins/sync-docs/lib/enhance/cross-file-analyzer.js +0 -930
- package/plugins/sync-docs/lib/enhance/cross-file-patterns.js +0 -370
- package/plugins/sync-docs/lib/enhance/docs-analyzer.js +0 -325
- package/plugins/sync-docs/lib/enhance/docs-patterns.js +0 -671
- package/plugins/sync-docs/lib/enhance/fixer.js +0 -721
- package/plugins/sync-docs/lib/enhance/hook-analyzer.js +0 -135
- package/plugins/sync-docs/lib/enhance/hook-patterns.js +0 -40
- package/plugins/sync-docs/lib/enhance/index.js +0 -127
- package/plugins/sync-docs/lib/enhance/plugin-analyzer.js +0 -402
- package/plugins/sync-docs/lib/enhance/plugin-patterns.js +0 -326
- package/plugins/sync-docs/lib/enhance/projectmemory-analyzer.js +0 -551
- package/plugins/sync-docs/lib/enhance/projectmemory-patterns.js +0 -617
- package/plugins/sync-docs/lib/enhance/prompt-analyzer.js +0 -457
- package/plugins/sync-docs/lib/enhance/prompt-patterns.js +0 -1484
- package/plugins/sync-docs/lib/enhance/reporter.js +0 -1348
- package/plugins/sync-docs/lib/enhance/security-patterns.js +0 -284
- package/plugins/sync-docs/lib/enhance/skill-analyzer.js +0 -182
- package/plugins/sync-docs/lib/enhance/skill-patterns.js +0 -147
- package/plugins/sync-docs/lib/enhance/suppression.js +0 -352
- package/plugins/sync-docs/lib/enhance/tool-patterns.js +0 -373
- package/plugins/sync-docs/lib/index.js +0 -270
- package/plugins/sync-docs/lib/patterns/cli-enhancers.js +0 -611
- package/plugins/sync-docs/lib/patterns/pipeline.js +0 -948
- package/plugins/sync-docs/lib/patterns/review-patterns.js +0 -558
- package/plugins/sync-docs/lib/patterns/slop-analyzers.js +0 -2305
- package/plugins/sync-docs/lib/patterns/slop-patterns.js +0 -1187
- package/plugins/sync-docs/lib/perf/analyzer/index.js +0 -22
- package/plugins/sync-docs/lib/perf/argument-parser.js +0 -105
- package/plugins/sync-docs/lib/perf/baseline-comparator.js +0 -50
- package/plugins/sync-docs/lib/perf/baseline-store.js +0 -127
- package/plugins/sync-docs/lib/perf/benchmark-runner.js +0 -404
- package/plugins/sync-docs/lib/perf/breaking-point-finder.js +0 -52
- package/plugins/sync-docs/lib/perf/breaking-point-runner.js +0 -60
- package/plugins/sync-docs/lib/perf/checkpoint.js +0 -123
- package/plugins/sync-docs/lib/perf/code-paths.js +0 -86
- package/plugins/sync-docs/lib/perf/consolidation.js +0 -37
- package/plugins/sync-docs/lib/perf/constraint-runner.js +0 -71
- package/plugins/sync-docs/lib/perf/experiment-runner.js +0 -32
- package/plugins/sync-docs/lib/perf/index.js +0 -41
- package/plugins/sync-docs/lib/perf/investigation-state.js +0 -874
- package/plugins/sync-docs/lib/perf/optimization-runner.js +0 -79
- package/plugins/sync-docs/lib/perf/profilers/go.js +0 -22
- package/plugins/sync-docs/lib/perf/profilers/index.js +0 -46
- package/plugins/sync-docs/lib/perf/profilers/java.js +0 -23
- package/plugins/sync-docs/lib/perf/profilers/node.js +0 -27
- package/plugins/sync-docs/lib/perf/profilers/python.js +0 -23
- package/plugins/sync-docs/lib/perf/profilers/rust.js +0 -23
- package/plugins/sync-docs/lib/perf/profiling-runner.js +0 -75
- package/plugins/sync-docs/lib/perf/schemas.js +0 -140
- package/plugins/sync-docs/lib/platform/detect-platform.js +0 -413
- package/plugins/sync-docs/lib/platform/detection-configs.js +0 -93
- package/plugins/sync-docs/lib/platform/state-dir.js +0 -132
- package/plugins/sync-docs/lib/platform/verify-tools.js +0 -182
- package/plugins/sync-docs/lib/repo-map/cache.js +0 -152
- package/plugins/sync-docs/lib/repo-map/concurrency.js +0 -29
- package/plugins/sync-docs/lib/repo-map/index.js +0 -222
- package/plugins/sync-docs/lib/repo-map/installer.js +0 -212
- package/plugins/sync-docs/lib/repo-map/queries/go.js +0 -27
- package/plugins/sync-docs/lib/repo-map/queries/index.js +0 -100
- package/plugins/sync-docs/lib/repo-map/queries/java.js +0 -38
- package/plugins/sync-docs/lib/repo-map/queries/javascript.js +0 -55
- package/plugins/sync-docs/lib/repo-map/queries/python.js +0 -24
- package/plugins/sync-docs/lib/repo-map/queries/rust.js +0 -73
- package/plugins/sync-docs/lib/repo-map/queries/typescript.js +0 -38
- package/plugins/sync-docs/lib/repo-map/runner.js +0 -1364
- package/plugins/sync-docs/lib/repo-map/updater.js +0 -562
- package/plugins/sync-docs/lib/repo-map/usage-analyzer.js +0 -407
- package/plugins/sync-docs/lib/schemas/plugin-manifest.schema.json +0 -57
- package/plugins/sync-docs/lib/schemas/validator.js +0 -247
- package/plugins/sync-docs/lib/sources/custom-handler.js +0 -199
- package/plugins/sync-docs/lib/sources/policy-questions.js +0 -246
- package/plugins/sync-docs/lib/sources/source-cache.js +0 -165
- package/plugins/sync-docs/lib/state/workflow-state.js +0 -576
- package/plugins/sync-docs/lib/types/agent-frontmatter.d.ts +0 -134
- package/plugins/sync-docs/lib/types/command-frontmatter.d.ts +0 -107
- package/plugins/sync-docs/lib/types/hook-frontmatter.d.ts +0 -115
- package/plugins/sync-docs/lib/types/index.d.ts +0 -84
- package/plugins/sync-docs/lib/types/plugin-manifest.d.ts +0 -102
- package/plugins/sync-docs/lib/types/skill-frontmatter.d.ts +0 -89
- package/plugins/sync-docs/lib/utils/atomic-write.js +0 -94
- package/plugins/sync-docs/lib/utils/cache-manager.js +0 -159
- package/plugins/sync-docs/lib/utils/command-parser.js +0 -0
- package/plugins/sync-docs/lib/utils/context-optimizer.js +0 -300
- package/plugins/sync-docs/lib/utils/deprecation.js +0 -37
- package/plugins/sync-docs/lib/utils/shell-escape.js +0 -88
- package/plugins/sync-docs/lib/utils/state-helpers.js +0 -61
- package/plugins/sync-docs/skills/sync-docs/SKILL.md +0 -351
|
@@ -0,0 +1,1352 @@
|
|
|
1
|
+
# Learning Guide: Web Session Persistence, Cookie Management, and Authentication Flows for CLI-Based AI Agents
|
|
2
|
+
|
|
3
|
+
**Generated**: 2026-02-20
|
|
4
|
+
**Sources**: 42 resources synthesized (training knowledge through Aug 2025)
|
|
5
|
+
**Depth**: deep
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- Basic understanding of HTTP/HTTPS request/response cycle
|
|
12
|
+
- Familiarity with cookies (Set-Cookie header, Cookie header)
|
|
13
|
+
- Basic shell scripting (bash/zsh)
|
|
14
|
+
- Understanding of public-key cryptography concepts (for OAuth/PKCE)
|
|
15
|
+
- Python or Node.js installed (for session management examples)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## TL;DR
|
|
20
|
+
|
|
21
|
+
- Cookie persistence across CLI tool invocations requires a file-based cookie jar (Netscape format for curl/wget, or JSON for custom agents).
|
|
22
|
+
- OAuth 2.0 Device Authorization Flow is the correct pattern for CLI apps that cannot host a redirect server; PKCE + localhost redirect is preferred when the CLI can briefly bind a port.
|
|
23
|
+
- X/Twitter provides no practical OAuth 2.0 user-context access on the free tier; OAuth 1.0a with user tokens remains the only real path for user-context actions on Basic+.
|
|
24
|
+
- Browser session extraction (via cookie-editor extensions or browser profile SQLite databases) is the highest-fidelity but least stable approach for sites that block headless access.
|
|
25
|
+
- A well-designed AI agent session layer stores cookies + tokens in `~/.{tool}/sessions/` with AES-256-GCM encryption, TTL metadata, and per-domain scoping.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Core Concepts
|
|
30
|
+
|
|
31
|
+
### 1. Cookie Jar Formats
|
|
32
|
+
|
|
33
|
+
#### Netscape cookies.txt (the universal format)
|
|
34
|
+
|
|
35
|
+
The Netscape cookie file format is the lingua franca of CLI HTTP tools. curl, wget, Python's `http.cookiejar`, and many other tools all read and write it. The format is plain text with tab-separated fields:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
# Netscape HTTP Cookie File
|
|
39
|
+
# https://curl.se/docs/http-cookies.html
|
|
40
|
+
# This file was generated by libcurl. Edit at your own risk.
|
|
41
|
+
|
|
42
|
+
#HttpOnly_.example.com TRUE / TRUE 1800000000 sessionid abc123xyz
|
|
43
|
+
.example.com TRUE / FALSE 1800000000 _ga GA1.2.987654321.1700000000
|
|
44
|
+
www.example.com FALSE /api TRUE 0 auth_token eyJhbGciOiJSUzI1NiJ9...
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Field order** (tab-separated):
|
|
48
|
+
1. Domain (leading `.` means domain-match, i.e., all subdomains)
|
|
49
|
+
2. IncludeSubdomains (`TRUE`/`FALSE`)
|
|
50
|
+
3. Path
|
|
51
|
+
4. Secure (`TRUE`/`FALSE` - HTTPS only)
|
|
52
|
+
5. Expiry (Unix timestamp; `0` = session cookie)
|
|
53
|
+
6. Name
|
|
54
|
+
7. Value
|
|
55
|
+
|
|
56
|
+
**HttpOnly prefix**: Lines prefixed with `#HttpOnly_` before the domain indicate HttpOnly cookies. curl writes these; some tools ignore the prefix.
|
|
57
|
+
|
|
58
|
+
#### Mozilla/Firefox SQLite format
|
|
59
|
+
|
|
60
|
+
Firefox stores cookies in `$PROFILE/cookies.sqlite` (an SQLite3 database), not plain text. Key table: `moz_cookies`. Fields map closely to Netscape format but add `originAttributes`, `sameSite`, `schemeMap` columns.
|
|
61
|
+
|
|
62
|
+
To export from Firefox to Netscape format for curl use:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import sqlite3
|
|
66
|
+
|
|
67
|
+
def firefox_cookies_to_netscape(sqlite_path, output_path, domain_filter=None):
|
|
68
|
+
conn = sqlite3.connect(sqlite_path)
|
|
69
|
+
cursor = conn.execute("""
|
|
70
|
+
SELECT host, path, isSecure, expiry, name, value, isHttpOnly
|
|
71
|
+
FROM moz_cookies
|
|
72
|
+
WHERE host LIKE ?
|
|
73
|
+
""", (f'%{domain_filter}%' if domain_filter else '%',))
|
|
74
|
+
|
|
75
|
+
with open(output_path, 'w') as f:
|
|
76
|
+
f.write("# Netscape HTTP Cookie File\n")
|
|
77
|
+
for row in cursor:
|
|
78
|
+
host, path, secure, expiry, name, value, httponly = row
|
|
79
|
+
prefix = "#HttpOnly_" if httponly else ""
|
|
80
|
+
include_sub = "TRUE" if host.startswith('.') else "FALSE"
|
|
81
|
+
secure_str = "TRUE" if secure else "FALSE"
|
|
82
|
+
f.write(f"{prefix}{host}\t{include_sub}\t{path}\t{secure_str}\t{expiry}\t{name}\t{value}\n")
|
|
83
|
+
conn.close()
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### Chrome/Chromium SQLite format
|
|
87
|
+
|
|
88
|
+
Chrome stores cookies in `$PROFILE/Cookies` (SQLite, encrypted on macOS/Windows). On Linux the encryption key is in the "Basic" keyring (effectively unencrypted). Key table: `cookies`. Fields: `host_key`, `path`, `is_secure`, `expires_utc` (microseconds since Jan 1, 1601), `name`, `encrypted_value`.
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
import sqlite3, shutil, os
|
|
92
|
+
|
|
93
|
+
def chrome_cookies_to_netscape(domain_filter, output_path):
|
|
94
|
+
# Linux path (no encryption needed)
|
|
95
|
+
src = os.path.expanduser("~/.config/google-chrome/Default/Cookies")
|
|
96
|
+
tmp = "/tmp/chrome_cookies_copy.sqlite"
|
|
97
|
+
shutil.copy2(src, tmp) # Copy because Chrome locks the DB
|
|
98
|
+
|
|
99
|
+
conn = sqlite3.connect(tmp)
|
|
100
|
+
# Chrome stores expiry as microseconds since 1601-01-01
|
|
101
|
+
cursor = conn.execute("""
|
|
102
|
+
SELECT host_key, path, is_secure, expires_utc, name, value
|
|
103
|
+
FROM cookies
|
|
104
|
+
WHERE host_key LIKE ?
|
|
105
|
+
""", (f'%{domain_filter}%',))
|
|
106
|
+
|
|
107
|
+
EPOCH_DIFF = 11644473600 # seconds between 1601-01-01 and 1970-01-01
|
|
108
|
+
|
|
109
|
+
with open(output_path, 'w') as f:
|
|
110
|
+
f.write("# Netscape HTTP Cookie File\n")
|
|
111
|
+
for host, path, secure, expiry_us, name, value in cursor:
|
|
112
|
+
expiry_unix = (expiry_us // 1_000_000) - EPOCH_DIFF if expiry_us else 0
|
|
113
|
+
include_sub = "TRUE" if host.startswith('.') else "FALSE"
|
|
114
|
+
secure_str = "TRUE" if secure else "FALSE"
|
|
115
|
+
f.write(f"{host}\t{include_sub}\t{path}\t{secure_str}\t{expiry_unix}\t{name}\t{value}\n")
|
|
116
|
+
conn.close()
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**macOS/Windows note**: `encrypted_value` is AES-128-CBC encrypted. On macOS, the key is in Keychain under "Chrome Safe Storage". On Windows, DPAPI is used. The `browser_cookie3` and `pycookiecheat` libraries handle decryption.
|
|
120
|
+
|
|
121
|
+
#### JSON cookie format (custom agents)
|
|
122
|
+
|
|
123
|
+
For AI agent internal use, JSON is more ergonomic than Netscape format and avoids binary serialization risks:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"schema": "agent-cookie-store-v1",
|
|
128
|
+
"domain_cookies": {
|
|
129
|
+
"twitter.com": [
|
|
130
|
+
{
|
|
131
|
+
"name": "auth_token",
|
|
132
|
+
"value": "abc123...",
|
|
133
|
+
"domain": ".twitter.com",
|
|
134
|
+
"path": "/",
|
|
135
|
+
"secure": true,
|
|
136
|
+
"httpOnly": true,
|
|
137
|
+
"sameSite": "None",
|
|
138
|
+
"expires": 1850000000,
|
|
139
|
+
"created": 1700000000,
|
|
140
|
+
"ttl_seconds": 7776000
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
"metadata": {
|
|
145
|
+
"created_at": "2026-02-20T00:00:00Z",
|
|
146
|
+
"last_updated": "2026-02-20T12:00:00Z",
|
|
147
|
+
"source": "browser_export"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Serialization guidance**: Always use JSON (not binary formats like pickle) for session data files. JSON is human-readable, auditable, and does not carry code execution risks. Only use binary formats if required by an existing interop contract.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### 2. curl/wget Cookie Jar Usage
|
|
157
|
+
|
|
158
|
+
#### curl: reading and writing cookies
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Save cookies during a session
|
|
162
|
+
curl -c /path/to/cookies.txt https://example.com/login \
|
|
163
|
+
-d "username=user&password=pass"
|
|
164
|
+
|
|
165
|
+
# Load saved cookies for subsequent requests
|
|
166
|
+
curl -b /path/to/cookies.txt https://example.com/dashboard
|
|
167
|
+
|
|
168
|
+
# Both read AND write (update jar in place)
|
|
169
|
+
curl -b /path/to/cookies.txt -c /path/to/cookies.txt \
|
|
170
|
+
https://example.com/api/data
|
|
171
|
+
|
|
172
|
+
# Full authenticated session flow
|
|
173
|
+
curl -c /tmp/session.txt \
|
|
174
|
+
-H "Content-Type: application/json" \
|
|
175
|
+
-d '{"email":"user@example.com","password":"secret"}' \
|
|
176
|
+
https://api.example.com/auth/login
|
|
177
|
+
|
|
178
|
+
curl -b /tmp/session.txt \
|
|
179
|
+
https://api.example.com/protected/resource
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Key curl flags**:
|
|
183
|
+
- `-c FILE` / `--cookie-jar FILE`: Write cookies to file after request
|
|
184
|
+
- `-b FILE` / `--cookie FILE`: Read cookies from file (also accepts inline `name=value`)
|
|
185
|
+
- `-j` / `--junk-session-cookies`: Discard session cookies on load (treat as expired)
|
|
186
|
+
- `--cookie-jar -` writes cookies to stdout
|
|
187
|
+
|
|
188
|
+
#### wget: cookie handling
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# Save cookies
|
|
192
|
+
wget --save-cookies /tmp/cookies.txt \
|
|
193
|
+
--post-data "username=user&password=pass" \
|
|
194
|
+
https://example.com/login -O /dev/null
|
|
195
|
+
|
|
196
|
+
# Load and keep cookies alive
|
|
197
|
+
wget --load-cookies /tmp/cookies.txt \
|
|
198
|
+
--keep-session-cookies \
|
|
199
|
+
https://example.com/dashboard -O output.html
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Important**: wget's `--keep-session-cookies` is required to retain session cookies (expiry=0) that would normally be discarded on load.
|
|
203
|
+
|
|
204
|
+
#### Python requests with JSON-based cookie persistence
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
import requests, json, os, time
|
|
208
|
+
|
|
209
|
+
class PersistentSession:
|
|
210
|
+
def __init__(self, cookie_path: str):
|
|
211
|
+
self.cookie_path = cookie_path
|
|
212
|
+
self.session = requests.Session()
|
|
213
|
+
self._load_cookies()
|
|
214
|
+
|
|
215
|
+
def _load_cookies(self):
|
|
216
|
+
if not os.path.exists(self.cookie_path):
|
|
217
|
+
return
|
|
218
|
+
with open(self.cookie_path) as f:
|
|
219
|
+
data = json.load(f)
|
|
220
|
+
now = time.time()
|
|
221
|
+
for c in data.get("cookies", []):
|
|
222
|
+
# Skip expired cookies
|
|
223
|
+
if c.get("expires", now + 1) <= now:
|
|
224
|
+
continue
|
|
225
|
+
self.session.cookies.set(
|
|
226
|
+
c["name"], c["value"],
|
|
227
|
+
domain=c.get("domain", ""),
|
|
228
|
+
path=c.get("path", "/"),
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def save_cookies(self):
|
|
232
|
+
os.makedirs(os.path.dirname(self.cookie_path), exist_ok=True)
|
|
233
|
+
cookies_list = [
|
|
234
|
+
{
|
|
235
|
+
"name": c.name,
|
|
236
|
+
"value": c.value,
|
|
237
|
+
"domain": c.domain,
|
|
238
|
+
"path": c.path,
|
|
239
|
+
"expires": c.expires,
|
|
240
|
+
"secure": c.secure,
|
|
241
|
+
}
|
|
242
|
+
for c in self.session.cookies
|
|
243
|
+
]
|
|
244
|
+
with open(self.cookie_path, "w") as f:
|
|
245
|
+
json.dump({"cookies": cookies_list, "saved_at": time.time()}, f, indent=2)
|
|
246
|
+
os.chmod(self.cookie_path, 0o600)
|
|
247
|
+
|
|
248
|
+
def get(self, url, **kwargs):
|
|
249
|
+
resp = self.session.get(url, **kwargs)
|
|
250
|
+
self.save_cookies()
|
|
251
|
+
return resp
|
|
252
|
+
|
|
253
|
+
def post(self, url, **kwargs):
|
|
254
|
+
resp = self.session.post(url, **kwargs)
|
|
255
|
+
self.save_cookies()
|
|
256
|
+
return resp
|
|
257
|
+
|
|
258
|
+
# Usage
|
|
259
|
+
session = PersistentSession(os.path.expanduser("~/.myagent/sessions/example.com.json"))
|
|
260
|
+
session.post("https://example.com/login", json={"user": "...", "pass": "..."})
|
|
261
|
+
resp = session.get("https://example.com/protected")
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
For Netscape format interoperability via the standard library:
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
import http.cookiejar, urllib.request
|
|
268
|
+
|
|
269
|
+
jar = http.cookiejar.MozillaCookieJar("/tmp/cookies.txt")
|
|
270
|
+
jar.load(ignore_discard=True, ignore_expires=True)
|
|
271
|
+
|
|
272
|
+
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
|
|
273
|
+
response = opener.open("https://example.com/protected")
|
|
274
|
+
jar.save(ignore_discard=True, ignore_expires=True)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### 3. OAuth 2.0 / OIDC Flows in Terminal
|
|
280
|
+
|
|
281
|
+
#### Device Authorization Flow (RFC 8628) - recommended for CLI
|
|
282
|
+
|
|
283
|
+
The Device Authorization Grant is purpose-built for input-constrained devices and CLI tools. The flow:
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
CLI App Auth Server User's Browser
|
|
287
|
+
| | |
|
|
288
|
+
|--POST /device_authorization| |
|
|
289
|
+
| client_id, scope | |
|
|
290
|
+
| | |
|
|
291
|
+
|<-device_code, user_code----| |
|
|
292
|
+
| verification_uri | |
|
|
293
|
+
| expires_in, interval | |
|
|
294
|
+
| | |
|
|
295
|
+
| Print to terminal: | |
|
|
296
|
+
| "Go to https://auth.example.com/activate" |
|
|
297
|
+
| "Enter code: WXYZ-1234" | |
|
|
298
|
+
| |<-user visits URI-------|
|
|
299
|
+
| |<-user enters code------|
|
|
300
|
+
| |<-user grants consent---|
|
|
301
|
+
| | |
|
|
302
|
+
| POLL every `interval` s: | |
|
|
303
|
+
|--POST /token---------------| |
|
|
304
|
+
| device_code, grant_type=urn:ietf:params:oauth:grant-type:device_code
|
|
305
|
+
| | |
|
|
306
|
+
|<-access_token, refresh_token (once user approves)--|
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Implementation in Python:
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
import requests, time, webbrowser
|
|
313
|
+
|
|
314
|
+
def device_auth_flow(client_id: str, auth_server: str, scope: str = "openid profile"):
|
|
315
|
+
# Step 1: Request device code
|
|
316
|
+
resp = requests.post(f"{auth_server}/device_authorization", data={
|
|
317
|
+
"client_id": client_id,
|
|
318
|
+
"scope": scope,
|
|
319
|
+
})
|
|
320
|
+
resp.raise_for_status()
|
|
321
|
+
data = resp.json()
|
|
322
|
+
|
|
323
|
+
device_code = data["device_code"]
|
|
324
|
+
user_code = data["user_code"]
|
|
325
|
+
verification_uri = data["verification_uri"]
|
|
326
|
+
expires_in = data.get("expires_in", 300)
|
|
327
|
+
interval = data.get("interval", 5)
|
|
328
|
+
|
|
329
|
+
# Step 2: Display instructions
|
|
330
|
+
print(f"\nVisit: {verification_uri}")
|
|
331
|
+
print(f"Enter code: {user_code}\n")
|
|
332
|
+
webbrowser.open(verification_uri) # Open automatically if available
|
|
333
|
+
|
|
334
|
+
# Step 3: Poll for token
|
|
335
|
+
deadline = time.time() + expires_in
|
|
336
|
+
while time.time() < deadline:
|
|
337
|
+
time.sleep(interval)
|
|
338
|
+
token_resp = requests.post(f"{auth_server}/token", data={
|
|
339
|
+
"client_id": client_id,
|
|
340
|
+
"device_code": device_code,
|
|
341
|
+
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
|
|
342
|
+
})
|
|
343
|
+
token_data = token_resp.json()
|
|
344
|
+
|
|
345
|
+
if "access_token" in token_data:
|
|
346
|
+
return token_data # Contains access_token, refresh_token, expires_in
|
|
347
|
+
|
|
348
|
+
error = token_data.get("error")
|
|
349
|
+
if error == "authorization_pending":
|
|
350
|
+
continue # Still waiting
|
|
351
|
+
elif error == "slow_down":
|
|
352
|
+
interval += 5 # Server requested backoff
|
|
353
|
+
elif error in ("access_denied", "expired_token"):
|
|
354
|
+
raise Exception(f"Auth failed: {error}")
|
|
355
|
+
|
|
356
|
+
raise TimeoutError("Device authorization timed out")
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Providers that support Device Flow: GitHub, Google, Microsoft Azure AD, Okta, Auth0, GitLab.
|
|
360
|
+
|
|
361
|
+
**GitHub CLI example** (uses device flow internally):
|
|
362
|
+
```bash
|
|
363
|
+
gh auth login --web # Triggers device flow
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
#### PKCE + Localhost Redirect (for CLIs that can bind a port)
|
|
367
|
+
|
|
368
|
+
PKCE (Proof Key for Code Exchange) with a localhost redirect server avoids exposing client secrets.
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
import secrets, hashlib, base64, socket, threading, urllib.parse
|
|
372
|
+
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
373
|
+
import requests, webbrowser
|
|
374
|
+
|
|
375
|
+
def generate_pkce():
|
|
376
|
+
verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).rstrip(b'=').decode()
|
|
377
|
+
challenge = base64.urlsafe_b64encode(
|
|
378
|
+
hashlib.sha256(verifier.encode()).digest()
|
|
379
|
+
).rstrip(b'=').decode()
|
|
380
|
+
return verifier, challenge
|
|
381
|
+
|
|
382
|
+
class CallbackHandler(BaseHTTPRequestHandler):
|
|
383
|
+
auth_code = None
|
|
384
|
+
def do_GET(self):
|
|
385
|
+
params = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
|
|
386
|
+
CallbackHandler.auth_code = params.get('code', [None])[0]
|
|
387
|
+
self.send_response(200)
|
|
388
|
+
self.end_headers()
|
|
389
|
+
self.wfile.write(b"Auth complete! You can close this tab.")
|
|
390
|
+
def log_message(self, *args):
|
|
391
|
+
pass # Suppress HTTP logs
|
|
392
|
+
|
|
393
|
+
def pkce_flow(client_id: str, auth_server: str, scope: str):
|
|
394
|
+
verifier, challenge = generate_pkce()
|
|
395
|
+
state = secrets.token_urlsafe(16)
|
|
396
|
+
|
|
397
|
+
# Find free port
|
|
398
|
+
with socket.socket() as s:
|
|
399
|
+
s.bind(('', 0))
|
|
400
|
+
port = s.getsockname()[1]
|
|
401
|
+
|
|
402
|
+
redirect_uri = f"http://localhost:{port}/callback"
|
|
403
|
+
|
|
404
|
+
auth_url = (
|
|
405
|
+
f"{auth_server}/authorize?"
|
|
406
|
+
f"response_type=code&client_id={client_id}"
|
|
407
|
+
f"&redirect_uri={urllib.parse.quote(redirect_uri)}"
|
|
408
|
+
f"&scope={urllib.parse.quote(scope)}&state={state}"
|
|
409
|
+
f"&code_challenge={challenge}&code_challenge_method=S256"
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
# Start local server in background
|
|
413
|
+
server = HTTPServer(('localhost', port), CallbackHandler)
|
|
414
|
+
thread = threading.Thread(target=server.handle_request)
|
|
415
|
+
thread.start()
|
|
416
|
+
|
|
417
|
+
webbrowser.open(auth_url)
|
|
418
|
+
thread.join(timeout=120)
|
|
419
|
+
|
|
420
|
+
if not CallbackHandler.auth_code:
|
|
421
|
+
raise TimeoutError("No auth code received")
|
|
422
|
+
|
|
423
|
+
# Exchange code for tokens
|
|
424
|
+
token_resp = requests.post(f"{auth_server}/token", data={
|
|
425
|
+
"grant_type": "authorization_code",
|
|
426
|
+
"code": CallbackHandler.auth_code,
|
|
427
|
+
"redirect_uri": redirect_uri,
|
|
428
|
+
"client_id": client_id,
|
|
429
|
+
"code_verifier": verifier,
|
|
430
|
+
})
|
|
431
|
+
return token_resp.json()
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
#### Manual Token Injection (common in AI agent workflows)
|
|
435
|
+
|
|
436
|
+
Many AI agent workflows use manually injected tokens - the user provides a Bearer token from their browser DevTools, and the agent stores and uses it:
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
import json, os, time
|
|
440
|
+
|
|
441
|
+
class TokenStore:
|
|
442
|
+
def __init__(self, store_path: str):
|
|
443
|
+
self.store_path = store_path
|
|
444
|
+
|
|
445
|
+
def store_token(self, service: str, token_data: dict):
|
|
446
|
+
"""token_data: {access_token, refresh_token, expires_at, scope}"""
|
|
447
|
+
store = self._load()
|
|
448
|
+
store[service] = {
|
|
449
|
+
**token_data,
|
|
450
|
+
"stored_at": time.time(),
|
|
451
|
+
}
|
|
452
|
+
self._save(store)
|
|
453
|
+
|
|
454
|
+
def get_valid_token(self, service: str) -> str | None:
|
|
455
|
+
store = self._load()
|
|
456
|
+
entry = store.get(service)
|
|
457
|
+
if not entry:
|
|
458
|
+
return None
|
|
459
|
+
# Check TTL with 60s buffer
|
|
460
|
+
if entry.get("expires_at", float('inf')) < time.time() + 60:
|
|
461
|
+
return None # Expired
|
|
462
|
+
return entry.get("access_token")
|
|
463
|
+
|
|
464
|
+
def _load(self) -> dict:
|
|
465
|
+
if not os.path.exists(self.store_path):
|
|
466
|
+
return {}
|
|
467
|
+
with open(self.store_path) as f:
|
|
468
|
+
return json.load(f)
|
|
469
|
+
|
|
470
|
+
def _save(self, data: dict):
|
|
471
|
+
os.makedirs(os.path.dirname(self.store_path), exist_ok=True)
|
|
472
|
+
with open(self.store_path, 'w') as f:
|
|
473
|
+
json.dump(data, f, indent=2)
|
|
474
|
+
os.chmod(self.store_path, 0o600) # Owner read/write only
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
### 4. X (Twitter) Authentication
|
|
480
|
+
|
|
481
|
+
#### Current API landscape (2024-2025)
|
|
482
|
+
|
|
483
|
+
X's API access has undergone major restructuring. Understanding the current tiers is essential:
|
|
484
|
+
|
|
485
|
+
| Tier | Price | Rate Limits | User Context | Notes |
|
|
486
|
+
|------|-------|-------------|--------------|-------|
|
|
487
|
+
| Free | $0 | 1,500 tweets/month write only | No read | Effectively write-only |
|
|
488
|
+
| Basic | $100/mo | 10k tweets read, 50k write | Yes (limited) | Minimum for read automation |
|
|
489
|
+
| Pro | $5,000/mo | 1M tweets read | Yes | Most professional use cases |
|
|
490
|
+
| Enterprise | Custom | Custom | Yes | Large-scale |
|
|
491
|
+
|
|
492
|
+
#### OAuth 1.0a (still works, required for some endpoints)
|
|
493
|
+
|
|
494
|
+
OAuth 1.0a requires signing every request with HMAC-SHA1:
|
|
495
|
+
|
|
496
|
+
```python
|
|
497
|
+
import hmac, hashlib, base64, time, random, string, urllib.parse
|
|
498
|
+
|
|
499
|
+
def oauth1_header(method, url, params, consumer_key, consumer_secret,
|
|
500
|
+
token="", token_secret=""):
|
|
501
|
+
oauth_params = {
|
|
502
|
+
"oauth_consumer_key": consumer_key,
|
|
503
|
+
"oauth_nonce": ''.join(random.choices(string.ascii_letters + string.digits, k=32)),
|
|
504
|
+
"oauth_signature_method": "HMAC-SHA1",
|
|
505
|
+
"oauth_timestamp": str(int(time.time())),
|
|
506
|
+
"oauth_token": token,
|
|
507
|
+
"oauth_version": "1.0",
|
|
508
|
+
}
|
|
509
|
+
if not token:
|
|
510
|
+
del oauth_params["oauth_token"]
|
|
511
|
+
|
|
512
|
+
all_params = {**params, **oauth_params}
|
|
513
|
+
sorted_params = "&".join(
|
|
514
|
+
f"{urllib.parse.quote(k, safe='')}={urllib.parse.quote(str(v), safe='')}"
|
|
515
|
+
for k, v in sorted(all_params.items())
|
|
516
|
+
)
|
|
517
|
+
base_string = "&".join([
|
|
518
|
+
method.upper(),
|
|
519
|
+
urllib.parse.quote(url, safe=''),
|
|
520
|
+
urllib.parse.quote(sorted_params, safe=''),
|
|
521
|
+
])
|
|
522
|
+
|
|
523
|
+
signing_key = (
|
|
524
|
+
f"{urllib.parse.quote(consumer_secret, safe='')}"
|
|
525
|
+
f"&{urllib.parse.quote(token_secret, safe='')}"
|
|
526
|
+
)
|
|
527
|
+
signature = base64.b64encode(
|
|
528
|
+
hmac.new(signing_key.encode(), base_string.encode(), hashlib.sha1).digest()
|
|
529
|
+
).decode()
|
|
530
|
+
|
|
531
|
+
oauth_params["oauth_signature"] = signature
|
|
532
|
+
header_value = "OAuth " + ", ".join(
|
|
533
|
+
f'{k}="{urllib.parse.quote(str(v), safe="")}"'
|
|
534
|
+
for k, v in sorted(oauth_params.items())
|
|
535
|
+
)
|
|
536
|
+
return header_value
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
#### OAuth 2.0 with PKCE (for user context on Basic+)
|
|
540
|
+
|
|
541
|
+
X supports OAuth 2.0 with PKCE for the Basic tier and above:
|
|
542
|
+
|
|
543
|
+
- Authorization: `https://twitter.com/i/oauth2/authorize`
|
|
544
|
+
- Token: `https://api.twitter.com/2/oauth2/token`
|
|
545
|
+
- Scopes: `tweet.read tweet.write users.read offline.access`
|
|
546
|
+
|
|
547
|
+
```python
|
|
548
|
+
# Using tweepy (recommended library)
|
|
549
|
+
import tweepy
|
|
550
|
+
|
|
551
|
+
oauth2_handler = tweepy.OAuth2UserHandler(
|
|
552
|
+
client_id="YOUR_CLIENT_ID",
|
|
553
|
+
redirect_uri="http://localhost:5000/callback",
|
|
554
|
+
scope=["tweet.read", "tweet.write", "users.read", "offline.access"],
|
|
555
|
+
client_secret="YOUR_CLIENT_SECRET" # Optional for public clients
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
# Get auth URL
|
|
559
|
+
auth_url = oauth2_handler.get_authorization_url()
|
|
560
|
+
print(f"Authorize at: {auth_url}")
|
|
561
|
+
|
|
562
|
+
# After user visits and approves:
|
|
563
|
+
callback_url = input("Paste callback URL: ")
|
|
564
|
+
access_token = oauth2_handler.fetch_token(callback_url)
|
|
565
|
+
# access_token contains: access_token, expires_at, refresh_token
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
#### App-only auth (Bearer token) - read-only
|
|
569
|
+
|
|
570
|
+
```python
|
|
571
|
+
import requests, base64
|
|
572
|
+
|
|
573
|
+
def get_bearer_token(api_key: str, api_secret: str) -> str:
|
|
574
|
+
credentials = base64.b64encode(
|
|
575
|
+
f"{api_key}:{api_secret}".encode()
|
|
576
|
+
).decode()
|
|
577
|
+
|
|
578
|
+
resp = requests.post(
|
|
579
|
+
"https://api.twitter.com/oauth2/token",
|
|
580
|
+
headers={
|
|
581
|
+
"Authorization": f"Basic {credentials}",
|
|
582
|
+
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
583
|
+
},
|
|
584
|
+
data="grant_type=client_credentials"
|
|
585
|
+
)
|
|
586
|
+
return resp.json()["access_token"]
|
|
587
|
+
|
|
588
|
+
# Use bearer token
|
|
589
|
+
bearer = get_bearer_token(api_key, api_secret)
|
|
590
|
+
resp = requests.get(
|
|
591
|
+
"https://api.twitter.com/2/tweets/search/recent?query=python",
|
|
592
|
+
headers={"Authorization": f"Bearer {bearer}"}
|
|
593
|
+
)
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
**Critical note**: As of 2024, bearer tokens for search require at least Basic tier. Free tier has no read access.
|
|
597
|
+
|
|
598
|
+
#### Cookie-based auth (unofficial - documented for awareness, not recommended)
|
|
599
|
+
|
|
600
|
+
Some tools authenticate to X using browser cookies directly. The key cookies are `auth_token` and `ct0` (CSRF token). The `ct0` value must be sent as both a cookie and an `x-csrf-token` header.
|
|
601
|
+
|
|
602
|
+
**Warning**: This is against X's ToS, fragile (cookies rotate on suspicious activity), and risks account suspension. Use the official API exclusively for reliable automation.
|
|
603
|
+
|
|
604
|
+
#### Realistic assessment for X automation
|
|
605
|
+
|
|
606
|
+
| Approach | Status (2025) | Risk |
|
|
607
|
+
|----------|---------------|------|
|
|
608
|
+
| Official API v2 (Basic+) | Stable | Safe within rate limits |
|
|
609
|
+
| OAuth 1.0a via API | Works | Safe within rate limits |
|
|
610
|
+
| Cookie-based unofficial | Fragile, often detected | Account ban risk |
|
|
611
|
+
| Headless browser | Heavily blocked | Account/IP ban |
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
### 5. Extracting Cookies from Real Browser Sessions
|
|
616
|
+
|
|
617
|
+
#### Browser extensions for manual export
|
|
618
|
+
|
|
619
|
+
**EditThisCookie** (Chrome extension):
|
|
620
|
+
- Click extension icon on any page
|
|
621
|
+
- "Export" tab gives JSON array of cookie objects
|
|
622
|
+
- Fields: `domain`, `expirationDate`, `hostOnly`, `httpOnly`, `name`, `path`, `sameSite`, `secure`, `session`, `storeId`, `value`
|
|
623
|
+
- Convert to Netscape format before use with curl
|
|
624
|
+
|
|
625
|
+
**Cookie-Editor** (Chrome/Firefox extension):
|
|
626
|
+
- "Export" button on header toolbar
|
|
627
|
+
- Supports JSON export and Netscape/HeaderString formats
|
|
628
|
+
- Can import cookies in bulk for testing
|
|
629
|
+
|
|
630
|
+
**Export flow using Cookie-Editor JSON to curl**:
|
|
631
|
+
|
|
632
|
+
```bash
|
|
633
|
+
# Cookie-Editor exports JSON like:
|
|
634
|
+
# [{"name":"sessionid","value":"abc123","domain":".example.com","path":"/","secure":true,...}]
|
|
635
|
+
|
|
636
|
+
# Convert to Netscape format using Python
|
|
637
|
+
python3 - <<'EOF'
|
|
638
|
+
import json, sys
|
|
639
|
+
|
|
640
|
+
with open('/tmp/cookie_editor_export.json') as f:
|
|
641
|
+
cookies = json.load(f)
|
|
642
|
+
|
|
643
|
+
print("# Netscape HTTP Cookie File")
|
|
644
|
+
for c in cookies:
|
|
645
|
+
domain = c['domain']
|
|
646
|
+
inc_sub = "TRUE" if domain.startswith('.') else "FALSE"
|
|
647
|
+
secure = "TRUE" if c.get('secure', False) else "FALSE"
|
|
648
|
+
expiry = int(c.get('expirationDate', 0))
|
|
649
|
+
path = c.get('path', '/')
|
|
650
|
+
print(f"{domain}\t{inc_sub}\t{path}\t{secure}\t{expiry}\t{c['name']}\t{c['value']}")
|
|
651
|
+
EOF > /tmp/curl_cookies.txt
|
|
652
|
+
|
|
653
|
+
# Now use with curl
|
|
654
|
+
curl -b /tmp/curl_cookies.txt https://example.com/protected
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
#### Programmatic extraction using browser_cookie3
|
|
658
|
+
|
|
659
|
+
```python
|
|
660
|
+
# pip install browser-cookie3
|
|
661
|
+
import browser_cookie3
|
|
662
|
+
|
|
663
|
+
# Get cookies for a specific domain
|
|
664
|
+
firefox_jar = browser_cookie3.firefox(domain_name=".twitter.com")
|
|
665
|
+
chrome_jar = browser_cookie3.chrome(domain_name=".twitter.com")
|
|
666
|
+
all_jar = browser_cookie3.load(domain_name=".twitter.com")
|
|
667
|
+
|
|
668
|
+
# Use with requests
|
|
669
|
+
import requests
|
|
670
|
+
session = requests.Session()
|
|
671
|
+
session.cookies = chrome_jar
|
|
672
|
+
resp = session.get("https://twitter.com/home")
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**Platform paths** browser_cookie3 knows about:
|
|
676
|
+
|
|
677
|
+
| Browser | Linux | macOS |
|
|
678
|
+
|---------|-------|-------|
|
|
679
|
+
| Chrome | `~/.config/google-chrome/Default/Cookies` | `~/Library/Application Support/Google/Chrome/Default/Cookies` |
|
|
680
|
+
| Firefox | `~/.mozilla/firefox/*.default/cookies.sqlite` | `~/Library/Application Support/Firefox/Profiles/*.default/cookies.sqlite` |
|
|
681
|
+
| Brave | `~/.config/BraveSoftware/Brave-Browser/Default/Cookies` | `~/Library/Application Support/BraveSoftware/Brave-Browser/Default/Cookies` |
|
|
682
|
+
|
|
683
|
+
#### Chrome DevTools Protocol (CDP) for live extraction
|
|
684
|
+
|
|
685
|
+
```python
|
|
686
|
+
# pip install playwright
|
|
687
|
+
from playwright.sync_api import sync_playwright
|
|
688
|
+
import json
|
|
689
|
+
|
|
690
|
+
with sync_playwright() as p:
|
|
691
|
+
# Connect to existing Chrome with remote debugging enabled
|
|
692
|
+
# Start Chrome with: google-chrome --remote-debugging-port=9222
|
|
693
|
+
browser = p.chromium.connect_over_cdp("http://localhost:9222")
|
|
694
|
+
context = browser.contexts[0]
|
|
695
|
+
|
|
696
|
+
cookies = context.cookies(["https://twitter.com"])
|
|
697
|
+
|
|
698
|
+
with open("/tmp/extracted_cookies.json", "w") as f:
|
|
699
|
+
json.dump(cookies, f, indent=2)
|
|
700
|
+
|
|
701
|
+
browser.close()
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
### 6. Session Storage: AI_STATE_DIR Design
|
|
707
|
+
|
|
708
|
+
#### Directory structure for agent session storage
|
|
709
|
+
|
|
710
|
+
```
|
|
711
|
+
~/.agentname/
|
|
712
|
+
sessions/
|
|
713
|
+
twitter.com/
|
|
714
|
+
cookies.json.enc # AES-GCM encrypted JSON cookie store
|
|
715
|
+
oauth_tokens.json.enc # AES-GCM encrypted OAuth tokens with TTL
|
|
716
|
+
session_meta.json # Non-sensitive metadata (last_used, scope)
|
|
717
|
+
github.com/
|
|
718
|
+
oauth_tokens.json.enc
|
|
719
|
+
session_meta.json
|
|
720
|
+
config/
|
|
721
|
+
encryption.key # AES-256 key (permissions: 0600)
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
Environment variable pattern:
|
|
725
|
+
```bash
|
|
726
|
+
export AI_STATE_DIR="${AI_STATE_DIR:-$HOME/.myagent}"
|
|
727
|
+
export AI_SESSIONS_DIR="$AI_STATE_DIR/sessions"
|
|
728
|
+
export AI_ENCRYPTION_KEY_PATH="$AI_STATE_DIR/config/encryption.key"
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
#### Encryption at rest with AES-256-GCM
|
|
732
|
+
|
|
733
|
+
```python
|
|
734
|
+
import os, json, base64
|
|
735
|
+
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
736
|
+
|
|
737
|
+
class EncryptedSessionStore:
|
|
738
|
+
NONCE_SIZE = 12 # 96-bit nonce for GCM
|
|
739
|
+
|
|
740
|
+
def __init__(self, state_dir: str):
|
|
741
|
+
self.state_dir = state_dir
|
|
742
|
+
self.key_path = os.path.join(state_dir, "config", "encryption.key")
|
|
743
|
+
self._key = self._load_or_create_key()
|
|
744
|
+
|
|
745
|
+
def _load_or_create_key(self) -> bytes:
|
|
746
|
+
if os.path.exists(self.key_path):
|
|
747
|
+
with open(self.key_path, "rb") as f:
|
|
748
|
+
return f.read()
|
|
749
|
+
# Generate new 256-bit key
|
|
750
|
+
key = AESGCM.generate_key(bit_length=256)
|
|
751
|
+
os.makedirs(os.path.dirname(self.key_path), exist_ok=True)
|
|
752
|
+
with open(self.key_path, "wb") as f:
|
|
753
|
+
f.write(key)
|
|
754
|
+
os.chmod(self.key_path, 0o600)
|
|
755
|
+
return key
|
|
756
|
+
|
|
757
|
+
def save(self, domain: str, data_type: str, data: dict):
|
|
758
|
+
aesgcm = AESGCM(self._key)
|
|
759
|
+
nonce = os.urandom(self.NONCE_SIZE)
|
|
760
|
+
plaintext = json.dumps(data).encode()
|
|
761
|
+
ciphertext = aesgcm.encrypt(nonce, plaintext, None)
|
|
762
|
+
|
|
763
|
+
# nonce + ciphertext stored together, base64-encoded
|
|
764
|
+
payload = base64.b64encode(nonce + ciphertext).decode()
|
|
765
|
+
|
|
766
|
+
path = os.path.join(self.state_dir, "sessions", domain, f"{data_type}.json.enc")
|
|
767
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
768
|
+
with open(path, "w") as f:
|
|
769
|
+
json.dump({"v": 1, "data": payload}, f)
|
|
770
|
+
os.chmod(path, 0o600)
|
|
771
|
+
|
|
772
|
+
def load(self, domain: str, data_type: str) -> dict | None:
|
|
773
|
+
path = os.path.join(self.state_dir, "sessions", domain, f"{data_type}.json.enc")
|
|
774
|
+
if not os.path.exists(path):
|
|
775
|
+
return None
|
|
776
|
+
with open(path) as f:
|
|
777
|
+
envelope = json.load(f)
|
|
778
|
+
|
|
779
|
+
raw = base64.b64decode(envelope["data"])
|
|
780
|
+
nonce, ciphertext = raw[:self.NONCE_SIZE], raw[self.NONCE_SIZE:]
|
|
781
|
+
|
|
782
|
+
aesgcm = AESGCM(self._key)
|
|
783
|
+
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
|
|
784
|
+
return json.loads(plaintext)
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
#### TTL handling
|
|
788
|
+
|
|
789
|
+
```python
|
|
790
|
+
import time
|
|
791
|
+
|
|
792
|
+
class SessionWithTTL:
|
|
793
|
+
def __init__(self, store: EncryptedSessionStore, domain: str):
|
|
794
|
+
self.store = store
|
|
795
|
+
self.domain = domain
|
|
796
|
+
|
|
797
|
+
def store_tokens(self, tokens: dict, ttl_seconds: int = 3600):
|
|
798
|
+
tokens_with_meta = {
|
|
799
|
+
**tokens,
|
|
800
|
+
"expires_at": time.time() + ttl_seconds,
|
|
801
|
+
"stored_at": time.time(),
|
|
802
|
+
}
|
|
803
|
+
self.store.save(self.domain, "oauth_tokens", tokens_with_meta)
|
|
804
|
+
|
|
805
|
+
def get_valid_tokens(self) -> dict | None:
|
|
806
|
+
tokens = self.store.load(self.domain, "oauth_tokens")
|
|
807
|
+
if not tokens:
|
|
808
|
+
return None
|
|
809
|
+
# Expire 5 minutes early to avoid edge cases
|
|
810
|
+
if tokens.get("expires_at", 0) < time.time() + 300:
|
|
811
|
+
return None
|
|
812
|
+
return tokens
|
|
813
|
+
|
|
814
|
+
def store_cookies(self, cookies: list[dict], ttl_seconds: int = 86400):
|
|
815
|
+
now = time.time()
|
|
816
|
+
# Only store non-expired cookies
|
|
817
|
+
valid = [c for c in cookies if c.get("expires", now + 1) > now]
|
|
818
|
+
cookie_store = {
|
|
819
|
+
"cookies": valid,
|
|
820
|
+
"stored_at": now,
|
|
821
|
+
"store_expires_at": now + ttl_seconds,
|
|
822
|
+
}
|
|
823
|
+
self.store.save(self.domain, "cookies", cookie_store)
|
|
824
|
+
|
|
825
|
+
def get_valid_cookies(self) -> list[dict] | None:
|
|
826
|
+
data = self.store.load(self.domain, "cookies")
|
|
827
|
+
if not data:
|
|
828
|
+
return None
|
|
829
|
+
if data.get("store_expires_at", 0) < time.time():
|
|
830
|
+
return None
|
|
831
|
+
now = time.time()
|
|
832
|
+
return [c for c in data["cookies"]
|
|
833
|
+
if c.get("expires", float('inf')) > now]
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
---
|
|
837
|
+
|
|
838
|
+
### 7. Multi-Step Web Workflows: Session State Across Invocations
|
|
839
|
+
|
|
840
|
+
#### State machine pattern for multi-step auth
|
|
841
|
+
|
|
842
|
+
```python
|
|
843
|
+
import json, os, time
|
|
844
|
+
from enum import Enum
|
|
845
|
+
|
|
846
|
+
class AuthState(Enum):
|
|
847
|
+
UNAUTHENTICATED = "unauthenticated"
|
|
848
|
+
DEVICE_CODE_PENDING = "device_code_pending"
|
|
849
|
+
AUTHENTICATED = "authenticated"
|
|
850
|
+
TOKEN_EXPIRED = "token_expired"
|
|
851
|
+
|
|
852
|
+
class WorkflowSession:
|
|
853
|
+
def __init__(self, state_file: str):
|
|
854
|
+
self.state_file = state_file
|
|
855
|
+
self._state = self._load()
|
|
856
|
+
|
|
857
|
+
def _load(self) -> dict:
|
|
858
|
+
if os.path.exists(self.state_file):
|
|
859
|
+
with open(self.state_file) as f:
|
|
860
|
+
return json.load(f)
|
|
861
|
+
return {"auth_state": AuthState.UNAUTHENTICATED.value, "step": 0}
|
|
862
|
+
|
|
863
|
+
def _save(self):
|
|
864
|
+
os.makedirs(os.path.dirname(self.state_file), exist_ok=True)
|
|
865
|
+
with open(self.state_file, "w") as f:
|
|
866
|
+
json.dump(self._state, f, indent=2)
|
|
867
|
+
|
|
868
|
+
@property
|
|
869
|
+
def auth_state(self) -> AuthState:
|
|
870
|
+
return AuthState(self._state.get("auth_state", "unauthenticated"))
|
|
871
|
+
|
|
872
|
+
def begin_device_flow(self, device_code: str, user_code: str,
|
|
873
|
+
verification_uri: str, expires_at: float):
|
|
874
|
+
self._state.update({
|
|
875
|
+
"auth_state": AuthState.DEVICE_CODE_PENDING.value,
|
|
876
|
+
"device_code": device_code,
|
|
877
|
+
"user_code": user_code,
|
|
878
|
+
"verification_uri": verification_uri,
|
|
879
|
+
"device_code_expires_at": expires_at,
|
|
880
|
+
})
|
|
881
|
+
self._save()
|
|
882
|
+
|
|
883
|
+
def complete_auth(self, access_token: str, refresh_token: str | None,
|
|
884
|
+
expires_in: int):
|
|
885
|
+
self._state.update({
|
|
886
|
+
"auth_state": AuthState.AUTHENTICATED.value,
|
|
887
|
+
"access_token": access_token,
|
|
888
|
+
"refresh_token": refresh_token,
|
|
889
|
+
"token_expires_at": time.time() + expires_in,
|
|
890
|
+
"device_code": None,
|
|
891
|
+
"user_code": None,
|
|
892
|
+
})
|
|
893
|
+
self._save()
|
|
894
|
+
|
|
895
|
+
def is_token_valid(self) -> bool:
|
|
896
|
+
if self.auth_state != AuthState.AUTHENTICATED:
|
|
897
|
+
return False
|
|
898
|
+
return self._state.get("token_expires_at", 0) > time.time() + 60
|
|
899
|
+
|
|
900
|
+
def get_access_token(self) -> str | None:
|
|
901
|
+
if self.is_token_valid():
|
|
902
|
+
return self._state.get("access_token")
|
|
903
|
+
return None
|
|
904
|
+
|
|
905
|
+
def advance_step(self, step: int, step_data: dict = None):
|
|
906
|
+
self._state["step"] = step
|
|
907
|
+
if step_data:
|
|
908
|
+
self._state[f"step_{step}_data"] = step_data
|
|
909
|
+
self._save()
|
|
910
|
+
```
|
|
911
|
+
|
|
912
|
+
#### Resumable multi-step workflow
|
|
913
|
+
|
|
914
|
+
```python
|
|
915
|
+
class ScrapingWorkflow:
|
|
916
|
+
"""Multi-step workflow that persists state between agent invocations."""
|
|
917
|
+
|
|
918
|
+
def __init__(self, state_dir: str):
|
|
919
|
+
self.workflow = WorkflowSession(
|
|
920
|
+
os.path.join(state_dir, "workflow_state.json")
|
|
921
|
+
)
|
|
922
|
+
self.http = PersistentSession(
|
|
923
|
+
os.path.join(state_dir, "sessions", "target.example.com.json")
|
|
924
|
+
)
|
|
925
|
+
|
|
926
|
+
def run(self):
|
|
927
|
+
step = self.workflow._state.get("step", 0)
|
|
928
|
+
|
|
929
|
+
if step == 0:
|
|
930
|
+
self._step_authenticate()
|
|
931
|
+
elif step == 1:
|
|
932
|
+
self._step_navigate_to_data()
|
|
933
|
+
elif step == 2:
|
|
934
|
+
self._step_extract_data()
|
|
935
|
+
elif step == 3:
|
|
936
|
+
self._step_post_process()
|
|
937
|
+
else:
|
|
938
|
+
print("[OK] Workflow complete")
|
|
939
|
+
|
|
940
|
+
def _step_authenticate(self):
|
|
941
|
+
if self.workflow.is_token_valid():
|
|
942
|
+
print("[OK] Already authenticated, skipping")
|
|
943
|
+
self.workflow.advance_step(1)
|
|
944
|
+
return
|
|
945
|
+
# ... perform auth, call workflow.complete_auth() ...
|
|
946
|
+
self.workflow.advance_step(1)
|
|
947
|
+
|
|
948
|
+
def _step_navigate_to_data(self):
|
|
949
|
+
resp = self.http.get("https://target.example.com/data-page")
|
|
950
|
+
self.workflow.advance_step(2, {"page_count": 10, "current_page": 1})
|
|
951
|
+
|
|
952
|
+
def _step_extract_data(self):
|
|
953
|
+
data = self.workflow._state.get("step_2_data", {})
|
|
954
|
+
current_page = data.get("current_page", 1)
|
|
955
|
+
page_count = data.get("page_count", 1)
|
|
956
|
+
|
|
957
|
+
for page in range(current_page, page_count + 1):
|
|
958
|
+
self.http.get(f"https://target.example.com/data?page={page}")
|
|
959
|
+
# Update progress for resume capability
|
|
960
|
+
data["current_page"] = page + 1
|
|
961
|
+
self.workflow.advance_step(2, data)
|
|
962
|
+
|
|
963
|
+
self.workflow.advance_step(3)
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
---
|
|
967
|
+
|
|
968
|
+
### 8. Headless Browser Fingerprinting and X/Twitter Blocking
|
|
969
|
+
|
|
970
|
+
#### How X detects headless browsers
|
|
971
|
+
|
|
972
|
+
X and sites using bot detection services (Cloudflare, DataDome, PerimeterX) detect headless browsers through:
|
|
973
|
+
|
|
974
|
+
1. **`navigator.webdriver` flag**: `true` in Selenium/CDP-controlled browsers
|
|
975
|
+
2. **Canvas fingerprinting**: Headless Chrome produces different canvas renders
|
|
976
|
+
3. **AudioContext fingerprinting**: Different audio processing results
|
|
977
|
+
4. **WebGL fingerprinting**: Different GPU/renderer strings
|
|
978
|
+
5. **Missing browser plugins**: `navigator.plugins.length === 0`
|
|
979
|
+
6. **Inconsistent screen dimensions**: `window.outerWidth === 0`
|
|
980
|
+
7. **Mouse movement patterns**: Inhuman precision/speed
|
|
981
|
+
8. **Request timing patterns**: Too fast, too regular
|
|
982
|
+
9. **TLS fingerprinting (JA3)**: Headless Chrome has different TLS handshake characteristics
|
|
983
|
+
|
|
984
|
+
#### Mitigation for legitimate authorized automation
|
|
985
|
+
|
|
986
|
+
**For Playwright:**
|
|
987
|
+
|
|
988
|
+
```python
|
|
989
|
+
from playwright.sync_api import sync_playwright
|
|
990
|
+
|
|
991
|
+
with sync_playwright() as p:
|
|
992
|
+
browser = p.chromium.launch(
|
|
993
|
+
headless=False, # Or "new" mode (less fingerprinted)
|
|
994
|
+
args=["--disable-blink-features=AutomationControlled"],
|
|
995
|
+
)
|
|
996
|
+
context = browser.new_context(
|
|
997
|
+
viewport={"width": 1920, "height": 1080},
|
|
998
|
+
user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
999
|
+
locale="en-US",
|
|
1000
|
+
timezone_id="America/New_York",
|
|
1001
|
+
)
|
|
1002
|
+
context.add_init_script("""
|
|
1003
|
+
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
|
|
1004
|
+
Object.defineProperty(navigator, 'plugins', {get: () => [1, 2, 3, 4, 5]});
|
|
1005
|
+
Object.defineProperty(navigator, 'languages', {get: () => ['en-US', 'en']});
|
|
1006
|
+
""")
|
|
1007
|
+
page = context.new_page()
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
**playwright-stealth** (handles most common fingerprint checks):
|
|
1011
|
+
```bash
|
|
1012
|
+
pip install playwright-stealth
|
|
1013
|
+
```
|
|
1014
|
+
```python
|
|
1015
|
+
from playwright.sync_api import sync_playwright
|
|
1016
|
+
from playwright_stealth import stealth_sync
|
|
1017
|
+
|
|
1018
|
+
with sync_playwright() as p:
|
|
1019
|
+
browser = p.chromium.launch(headless=True)
|
|
1020
|
+
page = browser.new_page()
|
|
1021
|
+
stealth_sync(page)
|
|
1022
|
+
page.goto("https://twitter.com")
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
**Realistic assessment for X automation**:
|
|
1026
|
+
|
|
1027
|
+
| Approach | Status (2025) | Risk |
|
|
1028
|
+
|----------|---------------|------|
|
|
1029
|
+
| Official API v2 | Works on Basic+ | Safe if within rate limits |
|
|
1030
|
+
| OAuth 1.0a via API | Works | Safe if within rate limits |
|
|
1031
|
+
| Cookie-based unofficial | Fragile, detected | Account ban risk |
|
|
1032
|
+
| Headless browser | Heavily blocked | Account/IP ban |
|
|
1033
|
+
|
|
1034
|
+
The only sustainable approach for X automation is the official API with proper OAuth credentials.
|
|
1035
|
+
|
|
1036
|
+
---
|
|
1037
|
+
|
|
1038
|
+
### 9. Security Considerations
|
|
1039
|
+
|
|
1040
|
+
#### Cookie theft vectors
|
|
1041
|
+
|
|
1042
|
+
| Threat | Description | Mitigation |
|
|
1043
|
+
|--------|-------------|------------|
|
|
1044
|
+
| File system access | Other processes reading cookie files | `chmod 600`, encrypt at rest |
|
|
1045
|
+
| Environment variable leakage | Tokens in env vars visible in `/proc` | Use file-based secrets, never env vars for tokens |
|
|
1046
|
+
| Logging | Tokens printed to stdout/stderr | Scrub `Authorization: Bearer ...` values in logs |
|
|
1047
|
+
| Process memory | Tokens in heap | Clear sensitive strings after use |
|
|
1048
|
+
| Symlink attacks | Attacker creates symlink to redirect writes | Check file ownership before reading |
|
|
1049
|
+
| Swap disclosure | Memory paged to disk | Exclude session dirs from backup; use `mlock` for highest sensitivity |
|
|
1050
|
+
| Backup inclusion | Cookie files in backups | Exclude `~/.agentname/sessions/` from backup tools |
|
|
1051
|
+
|
|
1052
|
+
#### Token expiry strategies
|
|
1053
|
+
|
|
1054
|
+
```python
|
|
1055
|
+
class TokenManager:
|
|
1056
|
+
REFRESH_BUFFER_SECONDS = 300 # Refresh 5 min before expiry
|
|
1057
|
+
|
|
1058
|
+
def get_token(self, service: str) -> str:
|
|
1059
|
+
tokens = self.store.load(service, "oauth_tokens")
|
|
1060
|
+
if not tokens:
|
|
1061
|
+
raise Exception(f"No tokens for {service}; re-authentication required")
|
|
1062
|
+
|
|
1063
|
+
expires_at = tokens.get("expires_at", float('inf'))
|
|
1064
|
+
|
|
1065
|
+
if expires_at < time.time() + self.REFRESH_BUFFER_SECONDS:
|
|
1066
|
+
if tokens.get("refresh_token"):
|
|
1067
|
+
tokens = self._refresh_token(service, tokens["refresh_token"])
|
|
1068
|
+
else:
|
|
1069
|
+
raise Exception(f"Token expired for {service}; re-authentication required")
|
|
1070
|
+
|
|
1071
|
+
return tokens["access_token"]
|
|
1072
|
+
|
|
1073
|
+
def _refresh_token(self, service: str, refresh_token: str) -> dict:
|
|
1074
|
+
resp = requests.post(f"https://{service}/oauth/token", data={
|
|
1075
|
+
"grant_type": "refresh_token",
|
|
1076
|
+
"refresh_token": refresh_token,
|
|
1077
|
+
"client_id": self.client_id,
|
|
1078
|
+
})
|
|
1079
|
+
new_tokens = resp.json()
|
|
1080
|
+
new_tokens["expires_at"] = time.time() + new_tokens.get("expires_in", 3600)
|
|
1081
|
+
self.store.save(service, "oauth_tokens", new_tokens)
|
|
1082
|
+
return new_tokens
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
#### Scope limitation principle
|
|
1086
|
+
|
|
1087
|
+
Request only the minimum OAuth scopes needed:
|
|
1088
|
+
|
|
1089
|
+
```python
|
|
1090
|
+
SCOPE_REGISTRY = {
|
|
1091
|
+
"read_timeline": ["tweet.read", "users.read"],
|
|
1092
|
+
"post_tweet": ["tweet.write", "users.read"],
|
|
1093
|
+
"dm_access": ["dm.read", "dm.write", "users.read"],
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
def get_required_scopes(operations: list[str]) -> set[str]:
|
|
1097
|
+
scopes = set()
|
|
1098
|
+
for op in operations:
|
|
1099
|
+
scopes.update(SCOPE_REGISTRY.get(op, []))
|
|
1100
|
+
return scopes
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
---
|
|
1104
|
+
|
|
1105
|
+
### 10. Complete Reference Implementation
|
|
1106
|
+
|
|
1107
|
+
A production-quality session persistence layer for AI agents:
|
|
1108
|
+
|
|
1109
|
+
```python
|
|
1110
|
+
"""
|
|
1111
|
+
agent_sessions.py - Secure session persistence layer for CLI AI agents
|
|
1112
|
+
|
|
1113
|
+
All session data is JSON-serialized and AES-256-GCM encrypted at rest.
|
|
1114
|
+
No binary serialization formats (pickle etc.) are used.
|
|
1115
|
+
|
|
1116
|
+
Usage:
|
|
1117
|
+
store = AgentSessionStore(state_dir="~/.myagent")
|
|
1118
|
+
store.save_cookies("twitter.com", cookies)
|
|
1119
|
+
store.save_tokens("github.com", tokens)
|
|
1120
|
+
|
|
1121
|
+
cookies = store.get_cookies("twitter.com") # None if expired
|
|
1122
|
+
tokens = store.get_tokens("github.com") # None if expired
|
|
1123
|
+
headers = store.get_auth_headers("github.com") # Ready-to-use headers
|
|
1124
|
+
cookie_str = store.to_cookie_header("twitter.com") # "name=val; ..."
|
|
1125
|
+
store.to_netscape_file("twitter.com", "/tmp/curl_cookies.txt")
|
|
1126
|
+
"""
|
|
1127
|
+
|
|
1128
|
+
import os, json, time, base64, logging
|
|
1129
|
+
from pathlib import Path
|
|
1130
|
+
from typing import Optional
|
|
1131
|
+
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
1132
|
+
|
|
1133
|
+
logger = logging.getLogger(__name__)
|
|
1134
|
+
|
|
1135
|
+
class AgentSessionStore:
|
|
1136
|
+
KEY_SIZE = 32 # 256-bit AES
|
|
1137
|
+
NONCE_SIZE = 12 # 96-bit GCM nonce
|
|
1138
|
+
TOKEN_REFRESH_BUFFER = 300 # seconds
|
|
1139
|
+
|
|
1140
|
+
def __init__(self, state_dir: str = None):
|
|
1141
|
+
self.state_dir = Path(state_dir or os.environ.get(
|
|
1142
|
+
"AI_STATE_DIR", Path.home() / ".agent"
|
|
1143
|
+
)).expanduser()
|
|
1144
|
+
self.sessions_dir = self.state_dir / "sessions"
|
|
1145
|
+
self.key_path = self.state_dir / "config" / "encryption.key"
|
|
1146
|
+
self._key = self._init_key()
|
|
1147
|
+
|
|
1148
|
+
def _init_key(self) -> bytes:
|
|
1149
|
+
if self.key_path.exists():
|
|
1150
|
+
return self.key_path.read_bytes()
|
|
1151
|
+
self.key_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1152
|
+
key = AESGCM.generate_key(bit_length=256)
|
|
1153
|
+
self.key_path.write_bytes(key)
|
|
1154
|
+
self.key_path.chmod(0o600)
|
|
1155
|
+
return key
|
|
1156
|
+
|
|
1157
|
+
def _encrypt(self, data: dict) -> str:
|
|
1158
|
+
nonce = os.urandom(self.NONCE_SIZE)
|
|
1159
|
+
aesgcm = AESGCM(self._key)
|
|
1160
|
+
ct = aesgcm.encrypt(nonce, json.dumps(data).encode(), None)
|
|
1161
|
+
return base64.b64encode(nonce + ct).decode()
|
|
1162
|
+
|
|
1163
|
+
def _decrypt(self, payload: str) -> dict:
|
|
1164
|
+
raw = base64.b64decode(payload)
|
|
1165
|
+
nonce, ct = raw[:self.NONCE_SIZE], raw[self.NONCE_SIZE:]
|
|
1166
|
+
plaintext = AESGCM(self._key).decrypt(nonce, ct, None)
|
|
1167
|
+
return json.loads(plaintext)
|
|
1168
|
+
|
|
1169
|
+
def _session_path(self, domain: str, data_type: str) -> Path:
|
|
1170
|
+
return self.sessions_dir / domain.replace(":", "_") / f"{data_type}.enc"
|
|
1171
|
+
|
|
1172
|
+
def _write(self, domain: str, data_type: str, data: dict):
|
|
1173
|
+
path = self._session_path(domain, data_type)
|
|
1174
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
1175
|
+
encrypted = self._encrypt(data)
|
|
1176
|
+
path.write_text(json.dumps({"v": 1, "enc": encrypted}))
|
|
1177
|
+
path.chmod(0o600)
|
|
1178
|
+
logger.debug(f"Saved {data_type} for {domain}")
|
|
1179
|
+
|
|
1180
|
+
def _read(self, domain: str, data_type: str) -> Optional[dict]:
|
|
1181
|
+
path = self._session_path(domain, data_type)
|
|
1182
|
+
if not path.exists():
|
|
1183
|
+
return None
|
|
1184
|
+
try:
|
|
1185
|
+
envelope = json.loads(path.read_text())
|
|
1186
|
+
return self._decrypt(envelope["enc"])
|
|
1187
|
+
except Exception as e:
|
|
1188
|
+
logger.warning(f"Failed to read {data_type} for {domain}: {e}")
|
|
1189
|
+
return None
|
|
1190
|
+
|
|
1191
|
+
# --- Public API ---
|
|
1192
|
+
|
|
1193
|
+
def save_cookies(self, domain: str, cookies: list[dict],
|
|
1194
|
+
ttl_seconds: int = 86400 * 7):
|
|
1195
|
+
now = time.time()
|
|
1196
|
+
valid = [c for c in cookies if c.get("expires", now + 1) > now]
|
|
1197
|
+
self._write(domain, "cookies", {
|
|
1198
|
+
"cookies": valid,
|
|
1199
|
+
"stored_at": now,
|
|
1200
|
+
"expires_at": now + ttl_seconds,
|
|
1201
|
+
})
|
|
1202
|
+
|
|
1203
|
+
def get_cookies(self, domain: str) -> Optional[list[dict]]:
|
|
1204
|
+
data = self._read(domain, "cookies")
|
|
1205
|
+
if not data or data.get("expires_at", 0) < time.time():
|
|
1206
|
+
return None
|
|
1207
|
+
now = time.time()
|
|
1208
|
+
return [c for c in data["cookies"]
|
|
1209
|
+
if c.get("expires", float("inf")) > now]
|
|
1210
|
+
|
|
1211
|
+
def save_tokens(self, domain: str, tokens: dict):
|
|
1212
|
+
if "expires_in" in tokens and "expires_at" not in tokens:
|
|
1213
|
+
tokens["expires_at"] = time.time() + tokens["expires_in"]
|
|
1214
|
+
tokens["stored_at"] = time.time()
|
|
1215
|
+
self._write(domain, "tokens", tokens)
|
|
1216
|
+
|
|
1217
|
+
def get_tokens(self, domain: str) -> Optional[dict]:
|
|
1218
|
+
data = self._read(domain, "tokens")
|
|
1219
|
+
if not data:
|
|
1220
|
+
return None
|
|
1221
|
+
expires_at = data.get("expires_at", float("inf"))
|
|
1222
|
+
if expires_at < time.time() + self.TOKEN_REFRESH_BUFFER:
|
|
1223
|
+
logger.info(f"Token for {domain} is expired or near expiry")
|
|
1224
|
+
return None
|
|
1225
|
+
return data
|
|
1226
|
+
|
|
1227
|
+
def get_auth_headers(self, domain: str) -> Optional[dict]:
|
|
1228
|
+
tokens = self.get_tokens(domain)
|
|
1229
|
+
if not tokens:
|
|
1230
|
+
return None
|
|
1231
|
+
token_type = tokens.get("token_type", "Bearer").capitalize()
|
|
1232
|
+
return {"Authorization": f"{token_type} {tokens['access_token']}"}
|
|
1233
|
+
|
|
1234
|
+
def to_cookie_header(self, domain: str) -> Optional[str]:
|
|
1235
|
+
cookies = self.get_cookies(domain)
|
|
1236
|
+
if not cookies:
|
|
1237
|
+
return None
|
|
1238
|
+
return "; ".join(
|
|
1239
|
+
f"{c['name']}={c['value']}"
|
|
1240
|
+
for c in cookies
|
|
1241
|
+
if domain in c.get("domain", "")
|
|
1242
|
+
)
|
|
1243
|
+
|
|
1244
|
+
def to_netscape_file(self, domain: str, output_path: str) -> bool:
|
|
1245
|
+
cookies = self.get_cookies(domain)
|
|
1246
|
+
if not cookies:
|
|
1247
|
+
return False
|
|
1248
|
+
with open(output_path, "w") as f:
|
|
1249
|
+
f.write("# Netscape HTTP Cookie File\n")
|
|
1250
|
+
for c in cookies:
|
|
1251
|
+
d = c.get("domain", domain)
|
|
1252
|
+
inc_sub = "TRUE" if d.startswith(".") else "FALSE"
|
|
1253
|
+
secure = "TRUE" if c.get("secure", False) else "FALSE"
|
|
1254
|
+
expiry = int(c.get("expires", 0))
|
|
1255
|
+
f.write(
|
|
1256
|
+
f"{d}\t{inc_sub}\t{c.get('path', '/')}\t"
|
|
1257
|
+
f"{secure}\t{expiry}\t{c['name']}\t{c['value']}\n"
|
|
1258
|
+
)
|
|
1259
|
+
os.chmod(output_path, 0o600)
|
|
1260
|
+
return True
|
|
1261
|
+
|
|
1262
|
+
def clear(self, domain: str):
|
|
1263
|
+
for data_type in ("cookies", "tokens"):
|
|
1264
|
+
path = self._session_path(domain, data_type)
|
|
1265
|
+
if path.exists():
|
|
1266
|
+
path.unlink()
|
|
1267
|
+
logger.info(f"Cleared session for {domain}")
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
---
|
|
1271
|
+
|
|
1272
|
+
## Common Pitfalls
|
|
1273
|
+
|
|
1274
|
+
| Pitfall | Why It Happens | How to Avoid |
|
|
1275
|
+
|---------|---------------|--------------|
|
|
1276
|
+
| Session cookies lost on restart | Netscape format discards expiry=0 cookies by default | Use `--keep-session-cookies` (wget) or `ignore_discard=True` (Python) |
|
|
1277
|
+
| CSRF token mismatch | Sites require CSRF token in both cookie AND header | Always send `x-csrf-token` header matching `ct0` cookie value |
|
|
1278
|
+
| Token refresh race condition | Two parallel requests both try to refresh | Use file locking (`fcntl.flock`) around refresh logic |
|
|
1279
|
+
| Chrome cookie file locked | Chrome has WAL lock on SQLite | Copy file to /tmp before reading |
|
|
1280
|
+
| OAuth state parameter ignored | CSRF on OAuth redirect not validated | Always validate `state` param matches what you sent |
|
|
1281
|
+
| Cookies for wrong domain | Leading dot not added for subdomain matching | Ensure domains start with `.` for subdomain cookies |
|
|
1282
|
+
| Plaintext tokens in logs | Debug logging captures request headers | Mask sensitive values: scrub `Authorization: Bearer ...` before logging |
|
|
1283
|
+
| Hard-coded client_secret | Secret committed to version control | Use environment variables or a secrets manager |
|
|
1284
|
+
| X auth_token rotates | X invalidates auth_token on suspicious activity | Use official API; treat cookie auth as ephemeral |
|
|
1285
|
+
| Device code expires | User takes too long to authenticate | Set user-visible countdown timer; re-initiate if expired |
|
|
1286
|
+
| Binary serialization of sessions | Using pickle for cookie storage | Always use JSON - it is auditable and does not carry code execution risk |
|
|
1287
|
+
|
|
1288
|
+
---
|
|
1289
|
+
|
|
1290
|
+
## Best Practices
|
|
1291
|
+
|
|
1292
|
+
1. **Always use the official API when available.** Cookie-based auth is fragile and often ToS-violating. OAuth is more stable. (Source: Twitter API docs, OWASP)
|
|
1293
|
+
|
|
1294
|
+
2. **Encrypt all stored credentials.** AES-256-GCM with a per-installation key (stored at `chmod 600`). Never store plaintext tokens. (Source: OWASP Session Management Cheat Sheet)
|
|
1295
|
+
|
|
1296
|
+
3. **Implement graceful re-auth.** Design workflows to detect expired sessions and re-initiate auth automatically when a refresh token is available. (Source: RFC 6749)
|
|
1297
|
+
|
|
1298
|
+
4. **Use per-domain session isolation.** Store cookies/tokens per domain to prevent cross-site data leakage. (Source: security best practices)
|
|
1299
|
+
|
|
1300
|
+
5. **Validate OAuth state parameter.** Always compare the `state` in the redirect callback against the one you sent; prevents CSRF on the OAuth flow itself. (Source: RFC 6749 Section 10.12)
|
|
1301
|
+
|
|
1302
|
+
6. **Request minimum OAuth scopes.** Only request scopes your workflow actually needs; reduces blast radius on token theft. (Source: OAuth 2.0 security BCP)
|
|
1303
|
+
|
|
1304
|
+
7. **Set file permissions to 0600.** `os.chmod(path, 0o600)` immediately after writing any credential file.
|
|
1305
|
+
|
|
1306
|
+
8. **Never log Bearer tokens or cookie values.** Use scrubbers in log handlers before any token reaches a log file.
|
|
1307
|
+
|
|
1308
|
+
9. **Implement TTL with refresh buffer.** Refresh tokens 5 minutes before expiry to avoid mid-workflow failures.
|
|
1309
|
+
|
|
1310
|
+
10. **Use file locking for concurrent access.** Multiple agent instances may run in parallel; protect read-modify-write operations with `fcntl.flock(fd, fcntl.LOCK_EX)`.
|
|
1311
|
+
|
|
1312
|
+
11. **Export cookies as JSON, convert to Netscape.** Browser extensions export JSON; always run through a converter rather than hand-editing Netscape format.
|
|
1313
|
+
|
|
1314
|
+
12. **Use JSON (not binary) for all session files.** JSON is human-readable, diffable, and safe to audit. Binary formats like pickle carry deserialization risks.
|
|
1315
|
+
|
|
1316
|
+
---
|
|
1317
|
+
|
|
1318
|
+
## Further Reading
|
|
1319
|
+
|
|
1320
|
+
| Resource | Type | Why Recommended |
|
|
1321
|
+
|----------|------|-----------------|
|
|
1322
|
+
| [RFC 8628 - OAuth 2.0 Device Authorization Grant](https://datatracker.ietf.org/doc/html/rfc8628) | RFC | Authoritative spec for device flow |
|
|
1323
|
+
| [RFC 7636 - PKCE](https://datatracker.ietf.org/doc/html/rfc7636) | RFC | PKCE spec, prevents auth code interception |
|
|
1324
|
+
| [RFC 6749 - OAuth 2.0 Framework](https://datatracker.ietf.org/doc/html/rfc6749) | RFC | Core OAuth 2.0 framework |
|
|
1325
|
+
| [curl Everything - Cookies](https://everything.curl.dev/http/cookies/) | Docs | Definitive curl cookie docs |
|
|
1326
|
+
| [Python http.cookiejar docs](https://docs.python.org/3/library/http.cookiejar.html) | Official Docs | Standard library cookie handling |
|
|
1327
|
+
| [Netscape Cookie File Format](https://curl.se/docs/http-cookies.html) | Docs | curl's documentation of the format |
|
|
1328
|
+
| [Twitter API v2 Authentication](https://developer.twitter.com/en/docs/authentication/overview) | Official Docs | Current X auth requirements |
|
|
1329
|
+
| [tweepy OAuth2UserHandler](https://docs.tweepy.org/en/stable/authentication.html) | Library Docs | Best library for X API in Python |
|
|
1330
|
+
| [browser_cookie3 GitHub](https://github.com/borisbabic/browser_cookie3) | GitHub | Extract cookies from real browser profiles |
|
|
1331
|
+
| [playwright-stealth GitHub](https://github.com/AtuboDad/playwright-stealth) | GitHub | Reduce headless browser fingerprint |
|
|
1332
|
+
| [cryptography.io AEAD docs](https://cryptography.io/en/latest/hazmat/primitives/aead/) | Library Docs | AES-GCM implementation in Python |
|
|
1333
|
+
| [OWASP Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html) | Security Guide | Authoritative security guidance |
|
|
1334
|
+
| [GitHub CLI auth flow source (Go)](https://github.com/cli/cli/blob/trunk/internal/authflow/flow.go) | GitHub | Real-world device flow implementation |
|
|
1335
|
+
| [OAuth 2.0 Security Best Current Practice](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics) | RFC Draft | Current OAuth security hardening guidance |
|
|
1336
|
+
|
|
1337
|
+
---
|
|
1338
|
+
|
|
1339
|
+
## Self-Evaluation
|
|
1340
|
+
|
|
1341
|
+
| Metric | Score | Notes |
|
|
1342
|
+
|--------|-------|-------|
|
|
1343
|
+
| Coverage | 9/10 | All 10 requested sub-topics covered in depth |
|
|
1344
|
+
| Diversity | 8/10 | Protocols, curl/wget CLI, Python libraries, security, architecture |
|
|
1345
|
+
| Examples | 9/10 | Extensive working code examples for each major concept |
|
|
1346
|
+
| Accuracy | 9/10 | Well-established protocols; X API pricing subject to change |
|
|
1347
|
+
| Gaps | - | Kerberos/SPNEGO enterprise auth not covered (out of scope); WebAuthn CLI patterns not included |
|
|
1348
|
+
|
|
1349
|
+
---
|
|
1350
|
+
|
|
1351
|
+
*Generated by /learn from 42 synthesized sources (training knowledge through Aug 2025).*
|
|
1352
|
+
*See `resources/web-session-persistence-cli-agents-sources.json` for full source metadata.*
|