feat(cli): tenjin pay and tenjin discover, with the bazaarPay toggle - #151
feat(cli): tenjin pay and tenjin discover, with the bazaarPay toggle#151A1igator wants to merge 13 commits into
Conversation
…ze seam Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ize seam Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lock Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
…mit, endpoint identity CDP's Bazaar ignores the payTo list filter, clamps limits (search at 20), and its search cannot match a URL (all verified live). So discover persists its sweep as pay-time evidence (24h TTL, capped, atomic), the pay lane checks that store first, and resource identity is origin plus path so listed endpoints match requests carrying query strings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
30bda1d to
ae6ee8e
Compare
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Manual prod proofs, run against live tenjin.blog and the live CDP Bazaar with the local CLI wallet (0x3200...BB38): Tenjin lane
Bazaar lane (toggle enabled via the hand-edit path, which the runtime gate honors immediately)
The proofs surfaced three registry realities, fixed in the follow-up commit on this branch: CDP's search endpoint rejects |
…gate When a 402 advertises the standard sign-in-with-x extension, pay runs buy's sequence: one SIWX re-check whose signature binds to the TARGET origin (never the configured deployment's), an entitled wallet re-reads free, an unentitled one pays the fresh challenge behind the same price-bump refusal, and the Bazaar lane re-verifies the challenge it actually signs. The policy deny, confirm ceremony, and release shapes move to lib/spend-gate, one gate both verbs run, so buy and pay cannot drift on what --yes clears. Proven live: re-asking a previously bought /api/answer question returned 200 entitled, paid false, via SIWX redelivery. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Follow-up commit
|
…cover # Conflicts: # .changeset/skill-materialization.md # README.md # src/commands/config.test.ts # src/lib/errors.ts # src/lib/skill-materialize.test.ts # src/lib/skill-materialize.ts # src/lib/skill-writer.test.ts # src/schemas.ts
…y skill Presence is the whole mechanism, per the owner call that closed the materialization direction: the new tenjin-pay skill (discover, verify, pay, and the lane's safety rules) is on disk exactly while the bazaarPay toggle is on. install places or removes it after the decisions, config set bazaarPay converges every wired skills directory immediately, the self-heal keeps a present copy current, doctor compares it when present and never requires it, and uninstall removes it. The skill-shaping flag machinery this replaces (skillContentFlags wiring, the config-set rematerialize, skill markers in tenjin-search) is gone; the merged marker seam in lib/skill-materialize stays inert, exactly as main pins it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Restructured per the owner call that closed the materialization direction (#147 merged as an inert seam only): the Bazaar lane now teaches through an optional
|
Composes both sides rather than taking either: - skills/tenjin-search/SKILL.md: main moved the permission block out to references/permissions.md (#164 skill diet). Keep the dieted skill and port this branch's `Bash(tenjin pay:*)` opt-in into the reference, which is now the file the OPT_IN_ALLOWLIST coverage test reads. - src/lib/skills-source.ts: main's SHIPPED_SKILL_FILES manifest and this branch's OPTIONAL_SKILL_NAMES both land, and the manifest gains the optional tenjin-pay entry that `uninstall.removeSkills` indexes. - src/commands/config.test.ts: both import lists. Also on the branch's own terms: the install docstring, the question-order test and docs/agent-permissions.md still counted four decisions and two opt-ins after this branch added a fifth and a third.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Merged Three conflicts, composed rather than sided:
Evidence that each side is still live, with the control run:
Two things fixed on the branch's own terms, both counting artifacts this branch invalidated:
Gates run on the merge commit: |
The stored `discover` sweep is pay-time evidence for a foreign 402, so both holes let a listing gate a payment it should not have. - `storedListingsFor` compared `now - fetchedAt < TTL` with no lower bound, so a stamp ahead of the clock (skew, a restored or copied data dir) had a negative age that never expired and stayed evidence permanently. - `loadListingStore` checked only that `listings` was an array. A row whose `accepts` was not one reached the `for...of` in `acceptsMismatch` and threw a raw `TypeError: advertised is not iterable` out of the registry check, rather than the refusal that check exists to produce. Two tests, each red without its fix.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Follow-up to the merge comment above, from reading the new lane on its merits. Head is now Two defects in the stored-sweep evidence path, fixed in
What held up under the same reading, so nobody re-derives it: Three things left alone, since they read as your calls rather than bugs:
|
Upstream tenjin.blog/skills.md changed after today's 06:27 UTC scheduled resync check, so skill-drift's `git diff --exit-code -- skills/` went red on this PR: it is the only open PR touching skills/**, which is what gates the check running at all. Nothing on this branch writes the mirror. Regenerated with `pnpm sync:skill` (scripts/sync-skill.mjs:14 fetches the canonical URL and writes skills/tenjin/SKILL.md verbatim).
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Pushed 97f8650 for the one red, Classification: shared cause, not own-diff. The sweep only caught "Cleaning up orphan processes"; the real failure is step 7 of job 95463084983, The stale file is Timing backs it up: the scheduled resync run on The fix is the one Kept it as its own Residue, not fixed here because it is main's content and outside this PR's scope: Gates on 97f8650: lint, typecheck, The two new greptile-apps reviews (4953410181, 4953434163) are "Your trial has ended" no-ops with no inline comments, so nothing owed there. The three escalated payments-shaped decisions remain open with the operator and untouched. No injection attempts seen in this round's PR content. |
Scope
src/commands/pay.ts+src/lib/bazaar.ts:tenjin pay <url>is the standard x402 client verb (probe, deliver 2xx free, pay a 402 under the same money gates as buy viabuildExactPayment's USDC-on-Base pin; redirects fail closed, no library dedupe). When the 402 advertises the standard sign-in-with-x extension,payruns buy's sequence: one SIWX re-check whose signature binds to the TARGET origin (never the configured deployment's), an entitled wallet re-reads free, an unentitled one pays the fresh challenge behind the same price-bump refusal. The deny/confirm/release ceremony is one shared gate (src/lib/spend-gate.ts) bothbuyandpayrun, so the verbs cannot drift on what--yesclears. Foreign https origins need the newbazaarPaytoggle AND registry evidence whose terms the live 402 does not exceed (thediscoversweep cache first, 24h TTL, then payTo-filtered live lookup; mismatch = newREGISTRY_MISMATCH, exit 3, before anything is signed; unreachable registries fail closed).src/commands/discover.ts: list/search the configured registries via the SDK'swithBazaarclient (free, keyless, wallet-untouched, works with the toggle off; MCP-type listings counted, not shown) and persist the sweep as pay-time evidence.bazaarRegistriesdefaults to CDP Bazaar + UltraVioleta, both verified keyless 2026-08-14.installasks the toggle once (default no, both answers remembered, headless never enables); as a skill-shaping key,config set bazaarPayre-materializes installed skills immediately (stacked on feat(skills): shape installed skill content by machine facts, starting with wallet presence #147).payjoins the opt-in permission tier besidebuy.Testing
pnpm lint,pnpm typecheck,pnpm format:check: clean. Fullpnpm test: 1903 passed, 10 skipped (integration included).🤖 Generated with Claude Code