agent-wire-cli 0.2.1__tar.gz → 0.2.3__tar.gz

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.
Files changed (143) hide show
  1. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/.claude-plugin/marketplace.json +1 -0
  2. agent_wire_cli-0.2.3/.claude-plugin/plugin.json +26 -0
  3. agent_wire_cli-0.2.3/.github/dependabot.yml +28 -0
  4. agent_wire_cli-0.2.3/.github/scripts/mcp_smoke.py +36 -0
  5. agent_wire_cli-0.2.3/.github/workflows/ci.yml +116 -0
  6. agent_wire_cli-0.2.3/.github/workflows/codeql.yml +40 -0
  7. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/.github/workflows/release.yml +13 -6
  8. agent_wire_cli-0.2.3/.github/workflows/security.yml +70 -0
  9. agent_wire_cli-0.2.3/PKG-INFO +694 -0
  10. agent_wire_cli-0.2.3/README.md +664 -0
  11. agent_wire_cli-0.2.3/SECURITY.md +40 -0
  12. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/agents/wire-worker.md +7 -1
  13. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/manifests/cursor_rule.mdc +2 -0
  14. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/manifests/gemini_extension.json +1 -1
  15. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/manifests/hermes_skill.md +3 -1
  16. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/manifests/windsurf_rules.md +2 -0
  17. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/pyproject.toml +5 -3
  18. agent_wire_cli-0.2.3/skills/agent-wire/SKILL.md +45 -0
  19. agent_wire_cli-0.2.3/src/agent_wire/__init__.py +1 -0
  20. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/reddit.py +2 -1
  21. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/rss.py +3 -4
  22. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/search.py +3 -1
  23. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/arxiv_papers.py +7 -2
  24. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/news.py +2 -2
  25. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier3_regional/bilibili.py +4 -1
  26. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/cli.py +51 -2
  27. agent_wire_cli-0.2.3/src/agent_wire/codemode/__init__.py +1 -0
  28. agent_wire_cli-0.2.3/src/agent_wire/codemode/api.py +122 -0
  29. agent_wire_cli-0.2.3/src/agent_wire/codemode/sandbox.py +184 -0
  30. agent_wire_cli-0.2.3/src/agent_wire/engine/errors.py +9 -0
  31. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/engine/http_pool.py +33 -22
  32. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/engine/stealth_browser.py +16 -0
  33. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/engine/waterfall.py +13 -6
  34. agent_wire_cli-0.2.3/src/agent_wire/firewall/ssrf_guard.py +123 -0
  35. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/media/audio_transcriber.py +1 -1
  36. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/research/brief.py +23 -4
  37. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/research/engine.py +26 -1
  38. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/research/watch.py +3 -1
  39. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/server.py +335 -53
  40. agent_wire_cli-0.2.3/src/agent_wire/verify/__init__.py +1 -0
  41. agent_wire_cli-0.2.3/src/agent_wire/verify/citations.py +360 -0
  42. agent_wire_cli-0.2.3/tests/test_citations.py +291 -0
  43. agent_wire_cli-0.2.3/tests/test_codemode.py +201 -0
  44. agent_wire_cli-0.2.3/tests/test_codemode_bench.py +75 -0
  45. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_firewall_outbound.py +1 -1
  46. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_server.py +3 -2
  47. agent_wire_cli-0.2.3/tests/test_ssrf_guard.py +262 -0
  48. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_waterfall_routing.py +10 -1
  49. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/uv.lock +54 -145
  50. agent_wire_cli-0.2.1/.claude-plugin/plugin.json +0 -12
  51. agent_wire_cli-0.2.1/.github/workflows/ci.yml +0 -52
  52. agent_wire_cli-0.2.1/PKG-INFO +0 -258
  53. agent_wire_cli-0.2.1/README.md +0 -230
  54. agent_wire_cli-0.2.1/skills/agent-wire/SKILL.md +0 -26
  55. agent_wire_cli-0.2.1/src/agent_wire/__init__.py +0 -1
  56. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/.gitignore +0 -0
  57. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/.mcp.json +0 -0
  58. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/LICENSE +0 -0
  59. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/assets/agent-wire-banner-light.png +0 -0
  60. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/assets/agent-wire-banner-light.svg +0 -0
  61. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/assets/agent-wire-banner.png +0 -0
  62. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/assets/agent-wire-banner.svg +0 -0
  63. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/assets/agent-wire-logo-transparent.png +0 -0
  64. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/assets/agent-wire-logo-transparent.svg +0 -0
  65. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/assets/agent-wire-logo.png +0 -0
  66. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/assets/agent-wire-logo.svg +0 -0
  67. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/manifests/antigravity_mcp.json +0 -0
  68. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/manifests/codex.toml +0 -0
  69. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/manifests/peridot_local.json +0 -0
  70. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/__main__.py +0 -0
  71. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/auth/__init__.py +0 -0
  72. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/auth/browser_paths.py +0 -0
  73. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/auth/cookie_vault.py +0 -0
  74. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/auth/rate_limiter.py +0 -0
  75. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/cache/__init__.py +0 -0
  76. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/cache/ring_buffer.py +0 -0
  77. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/cache/sqlite_ledger.py +0 -0
  78. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/__init__.py +0 -0
  79. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/base.py +0 -0
  80. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/__init__.py +0 -0
  81. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/github.py +0 -0
  82. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/hackernews.py +0 -0
  83. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/stackoverflow.py +0 -0
  84. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/web.py +0 -0
  85. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/wikipedia.py +0 -0
  86. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/x_twitter.py +0 -0
  87. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier1_global/youtube.py +0 -0
  88. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/__init__.py +0 -0
  89. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/archive_bypass.py +0 -0
  90. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/devto.py +0 -0
  91. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/fediverse.py +0 -0
  92. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/hubs.py +0 -0
  93. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/linkedin.py +0 -0
  94. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/markets.py +0 -0
  95. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/meta_social.py +0 -0
  96. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/polymarket.py +0 -0
  97. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/publishing.py +0 -0
  98. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier2_pro/stocktwits.py +0 -0
  99. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier3_regional/boss_zhipin.py +0 -0
  100. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier3_regional/douyin_tiktok.py +0 -0
  101. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier3_regional/v2ex.py +0 -0
  102. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier3_regional/wechat.py +0 -0
  103. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier3_regional/xiaohongshu.py +0 -0
  104. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier3_regional/xiaoyuzhou.py +0 -0
  105. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier3_regional/xueqiu.py +0 -0
  106. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/channels/tier3_regional/zhihu.py +0 -0
  107. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/compression/__init__.py +0 -0
  108. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/compression/anchor_slicer.py +0 -0
  109. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/compression/bm25_slicer.py +0 -0
  110. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/compression/dam_formatter.py +0 -0
  111. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/compression/url_compactor.py +0 -0
  112. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/config.py +0 -0
  113. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/engine/__init__.py +0 -0
  114. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/engine/challenge.py +0 -0
  115. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/firewall/__init__.py +0 -0
  116. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/firewall/inbound_shield.py +0 -0
  117. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/firewall/outbound_privacy.py +0 -0
  118. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/installers/__init__.py +0 -0
  119. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/installers/client_installer.py +0 -0
  120. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/media/__init__.py +0 -0
  121. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/media/subtitle_cleaner.py +0 -0
  122. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/models.py +0 -0
  123. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/research/__init__.py +0 -0
  124. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/research/briefing.py +0 -0
  125. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/research/cluster.py +0 -0
  126. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/research/library.py +0 -0
  127. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/research/planner.py +0 -0
  128. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/research/scoring.py +0 -0
  129. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/research/store.py +0 -0
  130. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/src/agent_wire/router.py +0 -0
  131. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/conftest.py +0 -0
  132. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_auth.py +0 -0
  133. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_bm25_slicer.py +0 -0
  134. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_channels_new.py +0 -0
  135. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_channels_tier1.py +0 -0
  136. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_channels_tier2_3.py +0 -0
  137. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_compression.py +0 -0
  138. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_config.py +0 -0
  139. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_firewall_inbound.py +0 -0
  140. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_installer.py +0 -0
  141. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_models.py +0 -0
  142. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_research.py +0 -0
  143. {agent_wire_cli-0.2.1 → agent_wire_cli-0.2.3}/tests/test_ring_buffer.py +0 -0
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "agent-wire",
3
+ "description": "Live web and 31-platform access for AI agents from one local MCP server: token-compressed, privacy-firewalled, injection-shielded.",
3
4
  "owner": {
4
5
  "name": "uncoalesced"
5
6
  },
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "agent-wire",
3
+ "version": "0.2.3",
4
+ "description": "Live web and 31-platform access for agents: token-compressed, privacy-firewalled, injection-shielded. Auto-triggers on links and live questions.",
5
+ "author": {
6
+ "name": "uncoalesced"
7
+ },
8
+ "homepage": "https://github.com/uncoalesced/agent-wire",
9
+ "repository": "https://github.com/uncoalesced/agent-wire",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "web",
13
+ "search",
14
+ "reddit",
15
+ "github",
16
+ "youtube",
17
+ "mcp",
18
+ "scraping",
19
+ "research"
20
+ ],
21
+ "icon": "./assets/agent-wire-logo.png",
22
+ "privacyPolicyUrl": "https://github.com/uncoalesced/agent-wire#privacy-policy",
23
+ "documentationUrl": "https://github.com/uncoalesced/agent-wire#readme",
24
+ "supportUrl": "https://github.com/uncoalesced/agent-wire/issues",
25
+ "termsOfServiceUrl": "https://github.com/uncoalesced/agent-wire#terms-of-use"
26
+ }
@@ -0,0 +1,28 @@
1
+ version: 2
2
+ updates:
3
+ # Python dependencies in uv.lock. Security fixes come as separate PRs straight away
4
+ # (Dependabot security updates); this keeps routine upgrades to one weekly batch.
5
+ - package-ecosystem: uv
6
+ directory: /
7
+ target-branch: dev
8
+ schedule:
9
+ interval: weekly
10
+ day: monday
11
+ groups:
12
+ python:
13
+ patterns: ["*"]
14
+ update-types: [minor, patch]
15
+ open-pull-requests-limit: 5
16
+
17
+ # Actions are pinned to commit SHAs; this bumps the SHA and the version comment together.
18
+ - package-ecosystem: github-actions
19
+ directory: /
20
+ target-branch: dev
21
+ schedule:
22
+ interval: weekly
23
+ day: monday
24
+ groups:
25
+ actions:
26
+ patterns: ["*"]
27
+ cooldown:
28
+ default-days: 7
@@ -0,0 +1,36 @@
1
+ """CI smoke test for an installed agent-wire: start the real stdio MCP server and talk to it.
2
+
3
+ No network: lists tools in both modes, runs a Code Mode script that makes no wire calls, and checks
4
+ that a runaway script comes back as an error instead of hanging the server.
5
+ """
6
+
7
+ import asyncio
8
+ import sys
9
+
10
+ from fastmcp import Client
11
+ from fastmcp.client.transports import StdioTransport
12
+
13
+ FULL = {"wire_read", "wire_search", "wire_feed", "wire_me", "wire_research", "wire_cite",
14
+ "wire_run", "wire_status"} # fmt: skip
15
+
16
+
17
+ async def check(args: list[str], expect: set[str]) -> None:
18
+ transport = StdioTransport(sys.executable, ["-m", "agent_wire", *args])
19
+ async with Client(transport) as c:
20
+ names = {t.name for t in await c.list_tools()}
21
+ assert names == expect, f"{args}: tools {sorted(names)}"
22
+ out = await c.call_tool("wire_run", {"code": "return [1 + 1, typeof wire.read]"})
23
+ text = out.content[0].text
24
+ assert text.startswith("[WIRE | code | 0 calls") and '[2,"function"]' in text, text
25
+ hang = (await c.call_tool("wire_run", {"code": "for (;;) await 0"})).content[0].text
26
+ assert hang.startswith("[WIRE | error | code") and "CPU time limit" in hang, hang
27
+ print(f"ok: wire {' '.join(args)} -> {len(names)} tools")
28
+
29
+
30
+ async def main() -> None:
31
+ await asyncio.wait_for(check(["serve"], FULL), 120)
32
+ await asyncio.wait_for(check(["serve", "--code-mode"], {"wire_run", "wire_status"}), 120)
33
+
34
+
35
+ if __name__ == "__main__":
36
+ asyncio.run(main())
@@ -0,0 +1,116 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main, dev]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ci-${{ github.ref }}
13
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
14
+
15
+ jobs:
16
+ lint:
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 10
19
+ steps:
20
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
21
+ with:
22
+ persist-credentials: false
23
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
24
+ - name: Lockfile matches pyproject.toml
25
+ run: uv lock --check
26
+ - name: Install
27
+ run: uv sync --extra dev --locked
28
+ - name: Ruff lint
29
+ run: uv run ruff check src tests .github/scripts
30
+ - name: Ruff format
31
+ run: uv run ruff format --check .
32
+ - name: No temp-dir writes in the package
33
+ run: "! grep -rnE 'tempfile|/tmp' src/"
34
+
35
+ test:
36
+ strategy:
37
+ fail-fast: false
38
+ matrix:
39
+ os: [ubuntu-latest, windows-latest, macos-latest]
40
+ python: ["3.11", "3.14"]
41
+ include:
42
+ - {os: ubuntu-latest, python: "3.12"}
43
+ - {os: ubuntu-latest, python: "3.13"}
44
+ runs-on: ${{ matrix.os }}
45
+ timeout-minutes: 20
46
+ steps:
47
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
48
+ with:
49
+ persist-credentials: false
50
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
51
+ with:
52
+ python-version: ${{ matrix.python }}
53
+ - name: Install
54
+ run: uv sync --extra dev --locked
55
+ - name: Test (offline; network calls are faked)
56
+ run: uv run pytest -q
57
+
58
+ build:
59
+ runs-on: ubuntu-latest
60
+ timeout-minutes: 10
61
+ steps:
62
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
63
+ with:
64
+ persist-credentials: false
65
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
66
+ - name: Build sdist and wheel
67
+ run: uv build
68
+ - name: Package metadata renders on PyPI
69
+ run: uvx twine check --strict dist/*
70
+ - name: Wheel bundles the skill, rules and sandbox, at the pyproject version
71
+ run: |
72
+ python - <<'EOF'
73
+ import glob, re, zipfile
74
+ version = re.search(r'^version = "(.+)"', open("pyproject.toml").read(), re.M)[1]
75
+ whl = glob.glob("dist/*.whl")[0]
76
+ assert f"-{version}-" in whl, (whl, version)
77
+ names = zipfile.ZipFile(whl).namelist()
78
+ for need in ("agent_wire/assets/SKILL.md", "agent_wire/assets/wire-worker.md",
79
+ "agent_wire/research/engine.py", "agent_wire/codemode/sandbox.py",
80
+ "agent_wire/codemode/api.py"):
81
+ assert need in names, need
82
+ print("ok", whl, len(names), "files")
83
+ EOF
84
+
85
+ # Install the built wheel the way users do (no repo, no dev deps) and drive the real MCP server.
86
+ smoke:
87
+ needs: build
88
+ strategy:
89
+ fail-fast: false
90
+ matrix:
91
+ os: [ubuntu-latest, windows-latest, macos-latest]
92
+ python: ["3.11", "3.14"]
93
+ runs-on: ${{ matrix.os }}
94
+ timeout-minutes: 15
95
+ steps:
96
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
97
+ with:
98
+ persist-credentials: false
99
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
100
+ with:
101
+ python-version: ${{ matrix.python }}
102
+ - name: Build wheel
103
+ run: uv build --wheel
104
+ - name: CLI runs from the wheel
105
+ shell: bash
106
+ run: |
107
+ whl=$(ls dist/*.whl)
108
+ uvx --python ${{ matrix.python }} --from "$whl" agent-wire version
109
+ out=$(uvx --python ${{ matrix.python }} --from "$whl" wire run -e "return 6 * 7")
110
+ echo "$out"
111
+ grep -q '^42$' <<<"$out"
112
+ - name: MCP server over stdio (both modes)
113
+ shell: bash
114
+ run: >-
115
+ uv run --isolated --no-project --python ${{ matrix.python }}
116
+ --with "$(ls dist/*.whl)" python .github/scripts/mcp_smoke.py
@@ -0,0 +1,40 @@
1
+ name: codeql
2
+
3
+ on:
4
+ push:
5
+ branches: [main, dev]
6
+ pull_request:
7
+ schedule:
8
+ - cron: "41 5 * * 1"
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ concurrency:
15
+ group: codeql-${{ github.ref }}
16
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
17
+
18
+ jobs:
19
+ analyze:
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ language: [python, actions]
24
+ runs-on: ubuntu-latest
25
+ timeout-minutes: 30
26
+ permissions:
27
+ contents: read
28
+ security-events: write # upload results to the Security tab
29
+ steps:
30
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
31
+ with:
32
+ persist-credentials: false
33
+ - uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
34
+ with:
35
+ languages: ${{ matrix.language }}
36
+ build-mode: none
37
+ queries: security-extended
38
+ - uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
39
+ with:
40
+ category: /language:${{ matrix.language }}
@@ -13,9 +13,14 @@ permissions:
13
13
  jobs:
14
14
  build:
15
15
  runs-on: ubuntu-latest
16
+ timeout-minutes: 20
16
17
  steps:
17
- - uses: actions/checkout@v4
18
- - uses: astral-sh/setup-uv@v6
18
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
19
+ with:
20
+ persist-credentials: false
21
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
22
+ with:
23
+ enable-cache: false # never build a release from a cache another run could have written
19
24
  - name: Tag matches the package version
20
25
  run: |
21
26
  v=$(grep -m1 '^version' pyproject.toml | cut -d'"' -f2)
@@ -23,7 +28,8 @@ jobs:
23
28
  - run: uv sync --extra dev --locked
24
29
  - run: uv run pytest -q
25
30
  - run: uv build
26
- - uses: actions/upload-artifact@v4
31
+ - run: uvx twine check --strict dist/*
32
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
27
33
  with:
28
34
  name: dist
29
35
  path: dist/
@@ -31,12 +37,13 @@ jobs:
31
37
  publish:
32
38
  needs: build
33
39
  runs-on: ubuntu-latest
40
+ timeout-minutes: 10
34
41
  environment: pypi
35
42
  permissions:
36
- id-token: write # PyPI trusted publishing
43
+ id-token: write # PyPI trusted publishing
37
44
  steps:
38
- - uses: actions/download-artifact@v4
45
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
39
46
  with:
40
47
  name: dist
41
48
  path: dist/
42
- - uses: pypa/gh-action-pypi-publish@release/v1
49
+ - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
@@ -0,0 +1,70 @@
1
+ name: security
2
+
3
+ on:
4
+ push:
5
+ branches: [main, dev]
6
+ pull_request:
7
+ schedule:
8
+ - cron: "17 6 * * 1" # Mondays: new advisories land against an unchanged lockfile
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ concurrency:
15
+ group: security-${{ github.ref }}
16
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
17
+
18
+ jobs:
19
+ # Known CVEs in every locked dependency, including the optional extras.
20
+ pip-audit:
21
+ runs-on: ubuntu-latest
22
+ timeout-minutes: 10
23
+ steps:
24
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
25
+ with:
26
+ persist-credentials: false
27
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
28
+ - name: Export the lockfile
29
+ run: uv export --frozen --no-hashes --all-extras --no-emit-project -o requirements-audit.txt
30
+ - name: pip-audit
31
+ run: uvx pip-audit==2.10.1 -r requirements-audit.txt --progress-spinner off --desc
32
+
33
+ # Python security lint: medium severity and up fails the job.
34
+ bandit:
35
+ runs-on: ubuntu-latest
36
+ timeout-minutes: 10
37
+ steps:
38
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
39
+ with:
40
+ persist-credentials: false
41
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
42
+ - name: bandit
43
+ run: uvx bandit==1.9.4 -r src -ll
44
+
45
+ # The workflows themselves: unpinned actions, credential leaks, template injection.
46
+ zizmor:
47
+ runs-on: ubuntu-latest
48
+ timeout-minutes: 10
49
+ steps:
50
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
51
+ with:
52
+ persist-credentials: false
53
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
54
+ - name: zizmor
55
+ run: uvx zizmor==1.31.1 --format plain .github/workflows
56
+ env:
57
+ GH_TOKEN: ${{ github.token }}
58
+
59
+ # Dependencies a pull request adds or upgrades, checked against GitHub's advisory database.
60
+ dependency-review:
61
+ if: github.event_name == 'pull_request'
62
+ runs-on: ubuntu-latest
63
+ timeout-minutes: 10
64
+ steps:
65
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
66
+ with:
67
+ persist-credentials: false
68
+ - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
69
+ with:
70
+ fail-on-severity: moderate