mirror of
https://github.com/mvanhorn/cli-printing-press.git
synced 2026-09-14 15:38:08 +08:00
main
16 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c6d48489fd |
fix(cli): stop GraphQL false-positives on description prose (#4486)
* fix(cli): stop GraphQL false-positives on description prose Treat authored internal YAML and OpenAPI as those formats even when description text contains "type <word>" or "type Query". Report the structured-spec parse error instead of a GraphQL root-type miss. Closes #4451 Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> * fix(cli): keep GraphQL SDL with name/resources fields Require a YAML scalar name and a nested resources mapping so unindented GraphQL fields named name and resources are not classified as internal YAML. Refs: #4451 Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> * fix(cli): treat flow-style resources as internal YAML Accept resources: { ... } as a YAML mapping so a block-scalar description that happens to contain type Query still parses as internal YAML, not GraphQL. Refs: #4451 Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> * fix(cli): require a YAML key after resources An indented closing brace after GraphQL `resources: [Type]!` no longer counts as an internal-YAML mapping. Flow-style `resources: {payments:` and block `resources:\n payments:` still do. Refs: #4451 Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Trevin Chow <tmchow@users.noreply.github.com> |
||
|
|
4e0e8f845a |
feat(cli): add BLE device-sniff and device-spec CLI generation (#2601)
* feat(cli): add BLE device spec model
* feat(cli): add BLE evidence analyzer
* feat(cli): add BLE device-sniff command
* test(cli): add BLE device-sniff golden
* feat(cli): add BLE replay adapter
* feat(cli): add BLE replay probe
* feat(cli): add live BLE probe adapter
* feat(cli): classify BLE command guidance
* feat(cli): add BLE session mode tiers
* feat(cli): generate minimal BLE device CLI
* feat(cli): generate replay BLE controls
* feat(cli): generate BLE session scaffold
* feat(cli): generate BLE telemetry store
* feat(cli): show BLE device capabilities
* feat(cli): verify BLE device commands safely
* feat(cli): package live BLE probe testing
* feat(cli): integrate BLE device sniff docs
* refactor(cli): simplify BLE device sniff code
* fix(cli): harden BLE probe evidence workflow
* fix(cli): connect BLE inspect after Linux scan
* feat(cli): expose BLE probe in device sniff
* fix(cli): harden BLE probe evidence and live adapter
Code-review fixes for the BLE device-sniff path:
- analyze: degrade gracefully instead of aborting the whole analysis when
evidence omits the optional safety field, has a non-sluggable command
name, or references an undiscovered characteristic
- redact: fix possessive-term replacement order (no more "redacted's"
residue) and apply operator redaction terms to name/display-name fields
- bleprobe: carry redaction terms through scan/inspect/read/subscribe
output so merge can act on them
- ble-probe: cancel live scans/subscriptions on SIGINT/SIGTERM
- live adapter: make service/characteristic discovery context-cancellable
so an unresponsive device no longer hangs, classify
permission/not-found/disconnected errors, pass context errors through
verbatim, and stop holding the notification mutex during hex encoding
- device-sniff: relabel archived evidence so it no longer implies captured
values are scrubbed (only device names are redacted)
- replay adapter: cache device candidates instead of recomputing per call
Adds redact, analyze graceful-degradation, and live-adapter helper tests.
* refactor(cli): make BLE live adapter testable via a driver seam
Split the tinygo-backed live adapter so its lifecycle and concurrency logic
no longer depends on the BLE backend type, turning the largest untested
surface of the BLE probe into ordinary testable Go:
- driver.go: bleDriver / bleDevice / bleService / bleCharacteristic
interfaces
- adapter_live.go: liveAdapter holds a bleDriver and owns all lifecycle
logic (scan duration/drain, context cancellation, service/characteristic
discovery, notification collection, error mapping) with no backend types,
so it compiles and tests on every platform
- driver_tinygo.go: thin tinygo.org/x/bluetooth wrapper -- the only file
importing the backend -- behind the existing build tag
- adapter_live_test.go: stub-driver lifecycle tests that run without
hardware, including under the ble_replay_only build
No behavior change for valid inputs or normal error paths. Malformed-UUID
inputs now route through mapLiveError (wrapped as "unsupported") like other
backend errors instead of being returned raw; no test or workflow depended
on those exact strings.
* chore(cli): gitignore docs/brainstorms/ artifacts
* fix(cli): harden BLE live adapter lifecycle behind the driver seam
- Add bleDriver.NeedsPreScan() so the BlueZ pre-scan path is a seam decision
exercised against the test stub instead of an inline runtime.GOOS check.
- Bound the post-StopScan drain in Scan/ensureDeviceSeen so a backend that
ignores StopScan cannot pin a cancelled command open; keep candidates
collected before a clean backend return.
- Report device-not-found (not a raw context deadline) when a pre-scan ends
without the target in range.
- Add a 30s tinygo ConnectionTimeout and clamp oversized characteristic reads
to the ATT 512-byte max.
- Store backend characteristics by pointer so EnableNotifications' pointer-
receiver bookkeeping survives (disable is no longer a no-op).
- Cancel the root command context on SIGINT/SIGTERM for graceful shutdown of
long-running and hardware-backed subcommands.
- Write device-spec and analysis artifacts 0600 (carry control payloads and
device identity); curtail live scan/subscribe windows under dogfood.
- Document the seam stub-fidelity pattern in docs/PATTERNS.md + solutions/.
* fix(cli): close BLE redaction and analyzer edge cases from review
Redaction completeness (the term an operator asks to scrub must not leak
into the saved-for-sharing artifact):
- Scrub ActionMarker.Label and CommunityReference.CommandName, which are
slugged into device-spec command names and evidence summaries.
- Match redaction terms case-insensitively so 'Owner' also catches
'owner'/'OWNER' in advertised names.
Analyzer / spec robustness:
- Slug the (already-redacted) spec name so an arbitrary advertised device
name can never abort Validate's IsSlug check; DisplayName keeps the prose.
- Honor an explicit session.one_shot_fallback:false for optional mode
instead of unconditionally forcing it true (Validate permits false).
- Stop ReplayAdapter.Scan from filtering in place over its persistent
candidates backing array, which corrupted state on adapter reuse.
- Share one NormalizeUUID (exported from devicespec) instead of duplicating
the helper in the ble package.
All touched packages pass; golden verify is unchanged (29/29).
* refactor(cli): satisfy modernize linter in device spec
- validateEnum uses slices.Contains instead of a manual loop.
- Drop the no-op json omitempty on nested struct fields (Identity,
Capabilities, Session, Payload); encoding/json never omits structs, so
this changes no output. YAML keeps omitempty (yaml.v3 honors it for zero
structs). .golangci.yml enables modernize, so these blocked the push.
* fix(cli): address BLE review feedback
- keep legacy persistent session parsing private
- skip malformed BLE correlation timestamps with report ambiguities
- reuse compiled redaction regexes across evidence fields
Note: pre-existing failure in go test ./... internal/generator govulncheck gate not addressed by this PR.
* feat(cli): add generated BLE session runtime
* fix(cli): skip malformed BLE hex evidence
* fix(cli): annotate read-only BLE device commands
* fix(cli): require confirmation for physical BLE commands
* feat(cli): store generated BLE session summaries
* fix(cli): bump Go floor for govulncheck
* fix(cli): document BLE physical-effect confirmation
* fix(cli): correct BLE alias probe path, redaction claim, and live read clamp
Address code-review findings on the device-sniff BLE branch:
- bluetooth-sniff alias now reports its own command path in probe
doctor/smoke output instead of the nested "device-sniff ble" path.
- device-sniff ble evidence summary states what redaction actually does
(addresses pseudonymized; names only via --redact-term) rather than
claiming device names are always redacted.
- live adapter Read clamps a negative backend byte count so buf[:n]
cannot panic.
- drop an incident-marker comment from a redaction test.
Adds regression tests for the alias doctor binary name and the
negative-count read clamp; updates the device-sniff-ble-sample golden
for the corrected message.
* test(cli): add BLE generated-output proof cases
* fix(cli): report BLE archive name redaction by effective term set
The device-sniff archive note keyed off the raw --redact-term slice, so it
understated redaction when terms arrived from the evidence file and over-claimed
on a blank --redact-term. Key the note on the effective (normalized, non-empty)
merged term set via a shared HasEffectiveRedactionTerms helper.
Bundles review fixes from /ce-code-review:
- redaction-note accuracy + table-driven note-state coverage
- assert the withheld/opaque SKILL.md fallback omits the dry-run/confirm clauses
- document that the typed-const RequiresPhysicalConfirmation method and the
emitted string-literal requiresPhysicalConfirmation gate must stay in sync
* docs(skills): require BLE mapping research gate
* fix(cli): make verify, dogfood, and live-dogfood device-CLI aware
BLE device CLIs (protocol: ble) have no sync data pipeline, no
internal/client HTTP client, no agent-context command, and the device
SKILL template omitted the canonical install block. The HTTP-API-shaped
verifier checks reported false-negative failures even when every command
passed:
- verify "Data Pipeline: sync crashed" -> skip the sync->sql->search
test for device CLIs (dimension satisfied).
- dogfood auth-protocol mismatch (no client.go), sync-generic, and an
agent-context example-discovery crash -> skip the HTTP-only verdict and
issue rules for device CLIs; fall back to a bounded --help command-tree
walk when agent-context is absent.
- live dogfood crashed on the missing agent-context command -> return a
clean "unverified-device" verdict (manual --live testing is the real
gate for device CLIs).
- verify-skill canonical-sections failed -> the device SKILL template now
emits the canonical "Prerequisites: Install the CLI" block via the
shared CanonicalSkillInstallSection helper.
Adds isDeviceCLIDir (delegating to the canonical isDeviceBackedCLIDir).
Device golden SKILL fixtures updated for the new install section.
* feat(cli): emit MCP surface for BLE device CLIs and make scorecard device-aware
Generated BLE device CLIs now ship a stdio MCP server (cmd/<name>-pp-mcp)
that mirrors the Cobra tree via the API-agnostic cobratree walker and exposes
a read-only device-context tool. The MCP binary execs the companion CLI, so it
carries no BLE/CGO dependency and builds anywhere.
Make the scorecard device-aware: HTTP-shaped dimensions (local_cache, vision,
workflows, insight, agent_workflow_readiness, data_pipeline_integrity,
sync_correctness) are marked N/A for device CLIs so they drop from the
denominator instead of scoring a false 0. Add device-specific doctor and
error-handling scorers keyed on BLE reachability and safety remediation.
Single-source the cobratree walker file manifest via cobratreeWalkerTemplateFiles()
across the HTTP and device generators (previously triplicated).
* feat(cli): add novel-command hook to generated device CLIs
Generated device CLIs' root.go now declares a nil-guarded novelCommands
function variable and invokes it after wiring the generated command tree.
Hand-authored commands attach by setting the var from an operator-owned file
(naturally preserved verbatim by regenmerge as a NOVEL file), with no edit to
generated files. The default build is a no-op (nil hook).
This is the extension point for the forthcoming generator-emitted live BLE
control surface, and lets existing device CLIs (e.g. WalkingPad) stop
hand-editing the generated root.go to register their novel commands.
* feat(cli): emit BLE adapter seam into generated device CLIs
Generated device CLIs now carry a device-neutral BLE central seam in
internal/device/: bleBackend/bleLink interfaces (ble.go, always compiled), a
tinygo.org/x/bluetooth live driver behind the ble_live build tag (ble_live.go,
CGO), and a pure-Go stub for the default build (ble_stub.go). The seam addresses
GATT characteristics by UUID, so one connection serves every command and
telemetry stream the device spec declares.
The default build links no BLE stack and stays CGO-free (verify/dogfood/golden
and `go test` remain hardware-free); `go build -tags ble_live ./...` links the
real adapter. tinygo is added to the generated go.mod and retained by `go mod
tidy` via the tag-gated import (the tools.go-style mechanism), so -tags ble_live
resolves without polluting the default build.
This is the plumbing the forthcoming LiveTransport (Phase 3) drives; no command
wires it yet.
* feat(cli): wire live BLE transport, flags, and doctor into device CLIs
Generated device CLIs can now drive real hardware. internal/device/live.go
emits LiveTransport, which implements the existing Transport interface over the
BLE seam: it scans by the spec's ServiceUUIDs (now emitted in spec.go), connects,
and reads telemetry / writes command payloads by characteristic UUID. The same
status and command surface that replays evidence by default actuates the device
under --live.
root.go gains persistent --live/--address/--timeout flags and resolves the
transport at run time (deviceTransport): LiveTransport under --live, replay
otherwise (selection can't happen at construction because persistent flags are
unparsed then). A generated doctor command reports BLE-compiled state, verify/
dogfood env, service UUIDs, and — with --live — device reachability.
Safety carries over: physical-effect confirmation, dry-run preview, and a
verify-mode short-circuit in LiveTransport that returns verify-live-noop before
touching the backend, so --live never dials under PRINTING_PRESS_VERIFY. The
default build stays replay-only and CGO-free; -tags ble_live links the live path.
Tier-1 (fixed-payload writes, readable telemetry) works end to end with no
hand-authoring; notify-based/stateful protocols still need a codec (Phase 5).
* feat(cli): Tier-1 live BLE control with a fake-backend test and scan command
Make the generic live path testable and complete it end to end for fixed-payload
devices:
- internal/device/ble.go gains bleBackendFactory, a var indirection over the
build-tag-selected newBLEBackend, so tests can inject a fake backend.
- internal/device/live_test.go (emitted) exercises the Tier-1 path — command
payload write, dry-run no-write, RSSI-sorted scan — against a fake backend.
No hardware, no build tag, so the printed CLI's own `go test` proves its
generic live transport works in CI.
- A `scan` command discovers nearby devices by service UUID under --live. It is
mcp:hidden (inherently live, non-functional through the replay-only MCP exec).
A fixed-payload device now controls fully with zero hand-authoring: scan/connect,
write captured payloads, read readable telemetry. Notify-based/stateful protocols
still need a codec (Phase 5).
* feat(cli): add Dial/Link connection API and DeviceCodec hook for Tier-2 devices
Enable hand-authored control of stateful/parameterized BLE devices without
reimplementing the BLE stack:
- Export Link (renamed from bleLink) and Dial(ctx, address, timeout) (Link, error).
Hand-authored commands wired through the novelCommands hook open a connection
with Dial and drive it via Link (write/read/subscribe/close) — everything
WalkingPad's client.go did, now generated. Dial refuses under verify
(ErrVerifyMode) as a fail-closed backstop; LiveTransport.withLink uses it.
- Add the DeviceCodec interface (DecodeTelemetry) + a codec hook var. When an
operator registers a codec, the generated status command surfaces decoded
telemetry values; the default (nil) reports raw hex.
The emitted live_test.go now also covers Dial's verify refusal and codec-decoded
status, all against the injected fake backend (no hardware).
This is the Tier-2 enabler: static/readable devices stay zero-hand-authoring;
stateful protocols implement only their codec + novel commands on top of the
generated Dial/Link/codec surface. Parameterized-command spec modeling is left
as future work (operators express it through novel commands today).
* docs(skills): teach generated live BLE control and the Tier-2 codec responsibility
The device-sniff-ble reference now explains the generated CLI's live surface
(replay by default; -tags ble_live + --live to actuate) and the agent's
responsibility per device class: Tier-1 (fixed-payload + readable telemetry)
works with zero hand-authoring; Tier-2 (stateful/parameterized protocols) MUST
get a hand-written codec plus novel commands built on the exported device.Dial /
device.Link / DeviceCodec surface, gated on verify/dogfood, with a codec_test.go
and a -tags ble_live build check before ship. A silently-inert Tier-2 CLI is a
failure, not an acceptable outcome.
* docs(cli): document live BLE build and flags in generated README and SKILL
Generated device README/SKILL now describe the live path: build with
-tags ble_live, actuate with --live (--address/--timeout), the doctor/scan
commands, OS Bluetooth-permission and single-client expectations, and that the
default build is replay-backed. Wording-only template change; no generator
behavior change.
* test(cli): add ble_live compile proof for generated device CLIs
The default generated build never compiles ble_live.go (the tinygo driver), so
TestGeneratedBLEDeviceLiveBuildCompiles builds the generated module with
-tags ble_live. Gated to Linux, where the BLE backend is pure-Go (D-Bus) and
compiles toolchain-free in CI; macOS (CGO/CoreBluetooth) and Windows (WinRT) are
covered manually.
* refactor(cli): dedup live CommandResult construction and tidy service-UUID set
Extract liveResult(command, transport) so LiveTransport.ExecuteCommand's three
return paths share the common CommandResult fields and set only the
distinguishing dry-run/verify fields. Use map[string]struct{} for the
service-UUID dedup set in templateData. No behavior change (emitted device tests
unchanged and passing).
* feat(cli): parameterized device commands via spec params and a codec encode hook
Device specs can now declare typed positional parameters per command
(commands[].parameters: [{name, type}]). The generator emits the parameterized
cobra command — <arg> usage, exact-arg validation, safety gating, dry-run,
verify no-op — and routes the args to the device codec.
DeviceCodec gains EncodeCommand(command, args): with a codec registered, it owns
payload construction (parameterized values, framing, checksums); without one,
fixed-payload commands write their captured bytes and a parameterized command is
a hard error rather than a silent static write. Transport.ExecuteCommand now
takes args (replay ignores them; live encodes via the codec and reports the
bytes actually sent). The emitted live_test.go covers codec encode + the
parameterized-without-codec guard against a fake backend.
This makes Tier-2 control "implement your codec, get a full CLI": operators write
only the encode/decode logic, not the command boilerplate. Stateful choreography
still uses hand-authored commands on Dial/Link.
* docs(skills): document parameterized commands and the EncodeCommand codec hook
Update the device-sniff-ble Tier-2 guidance: implement device.DeviceCodec
(EncodeCommand + DecodeTelemetry), declare parameterized commands in the spec so
the generator emits the command surface, and reserve hand-authored Dial/Link
commands for stateful choreography only.
* fix(cli): score device CLIs on device shape instead of failing them
Six Steinberger scorers keyed off HTTP-CLI structure a BLE device CLI does not
have — separate per-command files, HTTP README sections, endpoint counts, API
response types — so a healthy device CLI scored a false F (output_modes 1,
terminal_ux 0, readme 2, agent_native 3, breadth 0, type_fidelity 0). Add
device-aware variants that grade the same dimensions on the device surface:
commands in root.go, --json/--agent + text output, device README sections, the
MCP server as the agent surface, command+telemetry breadth, and the generated
typed models. type_fidelity credits typed parameters only when a command
declares them, so breadth/fidelity still scale with capability.
A minimal read-only sensor now scores ~66 (B) and a command+telemetry device
~64-70, versus ~23-28 (F) before. The HTTP scorers are unchanged.
* fix(cli): pass parameter names to the generated device command at construction
A parameterized device command rejected its own argument ("accepts 0 arg(s)").
root.go emitted Parameters into the CommandDefinitions var but constructed the
inline CommandDefinition passed to newDeviceCommandCmd without them, so the
command saw zero parameters and built cobra.ExactArgs(0). Pass Parameters in the
AddCommand call too. The generated-output test now builds the CLI and runs the
parameterized command with its positional arg end to end, which the
emission-only assertions missed.
Surfaced by retrofitting the WalkingPad CLI onto the generated surface, where
set-speed <kmh> would not accept its value.
* refactor(cli): tidy device scorers (shared cli-content helper, unrolled fidelity)
scoreDoctorDevice now reads the cli package via deviceCLIContent like the other
device scorers, and scoreTypeFidelityDevice uses an explicit if-chain (matching
the file's other scorers) instead of a []bool loop. No behavior change.
* fix(cli): make generated BLE device control reliable and MCP-honest
Hardware-dogfooding the generated WalkingPad CLI surfaced machine-level issues in the BLE device generator, fixed here and grounded in ph4r05/ph4-walkingpad's reference protocol:
- liveLink.Write now prefers an acknowledged write (write-with-response), falling back to write-without-response only when the characteristic requires it. Fire-and-forget writes were dropped on an immediate Close, silently losing control commands like stop.
- liveBackend.Scan caps its window to the caller deadline and stops on the first matching device, so a long stream deadline no longer starves the connect that follows discovery.
- Status() gains an optional telemetrySnapshot hook: notify-only telemetry (which cannot be GATT-read) captures one notification frame and decodes every field from it, instead of reading back stale/echoed bytes.
- Held-connection devices (session.mode: required) hide their one-shot mutating control commands from MCP. A one-shot tool cannot drive a device that needs a sustained connection, so agents get reads plus the operator's held-connection command rather than a write tool that cannot actuate.
Generated-output tests cover acknowledged-write preference, snapshot decode + error propagation, and session-gated MCP hiding. Golden fixtures updated for generate-device-ble.
* feat(cli): device-spec transport contract and behavioral quirks
Add a first-class operational protocol contract to the device spec so the facts an agent synthesizes from references are captured once and consumed by the machine, rather than rediscovered command-by-command on hardware.
Schema (internal/devicespec): transport: write_mode, command_spacing_ms, connect_ceremony, settle_delays, poll_cadence_ms, teardown, single_client — the quantitative 'how to talk to the device' contract. quirks: cited {category, summary, handling} behavioral facts that do not reduce to a field (init tricks, stale-session gotchas, firmware opcode shifts) — the qualitative half.
Generator consumes it: command_spacing_ms emits a paced liveLink.Write (sleeps the deficit before every write — no hand-authored pacing wrapper); write_mode selects the write path (acknowledged default vs without-response); doctor surfaces the contract and quirks (text + JSON) at runtime.
Skill + docs: the device-sniff-ble research gate becomes a contract-synthesis gate — expand from seeds, extract both halves, do not relearn cited facts, and dogfood to verify the contract rather than discover it.
Generated-output tests cover paced-writer/write_mode/quirks emission; the session golden fixture exercises the paced writer under -tags ble_live. Golden updated for the device cases (doctor now reports the contract).
* feat(cli): device-spec workflows and workflow-fidelity QA gate
Add a workflows: element to the device spec: named, ordered, cited operating
sequences (the proven "spine" for each user goal) that compose the transport:
facts and the capabilities action map. Parsed + validated and surfaced in the
generated doctor (text + JSON) like quirks; it does not drive codegen — it is
the contract the implemented control flow is checked against in the QA
workflow-fidelity pass and confirmed during dogfood.
Also harden the device-sniff-ble research gate: require an explicit external
web-research pass beyond user-provided seeds, a recorded research ledger, and
>=2 independent sources corroborating the contract.
Atomic command/transport facts alone proved insufficient: without the proven
end-to-end sequence written down, a from-scratch implementation rediscovers it
by guessing on hardware. Capturing the spine and diffing the implementation
against it replaces guessing with a checkable contract.
* fix(cli): surface workflow notes and tidy empty-goal output in device doctor
Follow-up polish on the device workflows feature: doctor now emits each
workflow's notes in --json (the field carried the per-workflow gotcha but was
never rendered on its only surface), and the text output drops the dangling
"name: (N steps)" colon when a workflow has no goal. Adds notes/goal test
assertions.
* fix(cli): give device CLIs a version command via a shared template
Device CLIs were generated with no `version` command and no `--version` flag:
the device generator forked its own root template and dropped the version
command the HTTP path emits, so every device CLI failed the `version` quality
gate and could not be published.
Extract the version command into a shared internal/cli/version.go (version.go.tmpl)
emitted by BOTH the HTTP and device generators, replacing the inline copy that
lived only in the HTTP root template. HTTP behavior is unchanged (version still
works, now single-sourced); device CLIs now carry the version subcommand and the
--version flag like every other printed CLI.
This removes a copy-paste divergence the fork introduced — it copied
API-agnostic boilerplate and let it drift. version is the first shared scaffold
file beyond the cliutil/cobratree helpers both generators already share.
* fix(cli): emit AGENTS.md, LICENSE, NOTICE, .goreleaser.yaml for device CLIs
The device generator forked its own file manifest and dropped the four standard
publish artifacts the HTTP generator emits, so every device CLI failed the public
library's publish-completeness gate (same fork-and-drop as the version command).
Share LICENSE/NOTICE/.goreleaser.yaml templates with the device generator
(extending deviceTemplateData with Owner/CompactDescription/ProseName/VisionSet and
adding modulePath + the extracted yamlDoubleQuoted helper to its funcmap), and add a
device-aware AGENTS.md variant (agents_device.md.tmpl) that documents BLE/replay
concepts and the codec/novelCommands customization model instead of HTTP auth/sync.
HTTP output is byte-identical (the yamlDoubleQuoted extraction preserves it).
* fix(cli): exclude downloaded third-party sources from published manuscripts
A research sources/ directory holds reference repos cloned to study a protocol
(common for device CLIs reverse-engineering a wire format). publish package copied
the whole manuscript tree, so those third-party repo copies were on a path to ship
into the public library — a licensing problem and a secret/PII vector. It surfaced
only by luck: a placeholder email in a vendored README tripped the PII scan;
without it a third-party repo would have shipped silently.
- publish: shouldSkipPublishableManuscriptFile prunes any sources/ subtree from
shipped manuscripts (machine backstop), covered by a test.
- device-sniff-ble skill: cite reference repos by URL/commit and clone them to
scratch outside the manuscript tree, never into research/sources/.
- docs/ARTIFACTS.md: manuscripts hold authored synthesis, not third-party inputs.
* fix(cli): address BLE review feedback
* test(cli): refresh BLE skill install goldens
* fix(cli): quote device display names in Go templates
|
||
|
|
feb95d208b | docs(cli): update generated install package name (#1850) | ||
|
|
7c4beddbb6 |
feat(cli): rename generator binary to cli-printing-press (#1722)
* feat(cli): rename generator binary to cli-printing-press * fix(cli): address legacy command review feedback |
||
|
|
89816d49a6 |
feat(cli): press-auth companion for cookie capture + generated CLI integration (#1466)
* feat(cli): scaffold press-auth binary (U1) Adds the press-auth companion CLI surface: a Cobra root command with six subcommand stubs (login, cookies, status, refresh, list, forget), global --json/--quiet/--config flags, and clean usage-error rendering. Subcommand bodies return ErrNotImplemented; U2-U5 fill them in. Tests assert the help surface, flag wiring, missing-arg usage errors, unknown-command handling, and the recovery-path message that cookies emits when state is missing. Anchors chromedp and go-keychain in go.mod via blank imports in deps.go so subsequent units don't re-resolve versions; each blank import is replaced by a real import when its unit lands. * feat(cli): state file + macOS keychain (U2) - AES-GCM encryption of cookie map with per-domain key in macOS Keychain - Atomic file writes at ~/.press-auth/<domain>.json with 0600 mode - Dir mode tightened to 0700 explicitly after MkdirAll - PRESSAUTH_HOME env var for test isolation - keychain_darwin.go (go-keychain) + keychain_other.go stub - 14+ tests: round-trip, wrong-key, modes, atomicity, golden JSON shape, delete, non-darwin Subagent stall during test run was a watchdog timeout (work was complete); orchestrator ran tests and added the explicit Chmod after observing TestSaveFileAndDirModes failure on dirs created by t.TempDir() at 0755. * feat(cli): chromedp launcher + capture loop (U3) * feat(cli): JWT decode + lazy refresh (U4) * feat(cli): generated auth.go prefers press-auth (U6) Inserts a Step 0 in newAuthLoginCmd that shells out to the press-auth companion before falling through to the existing pycookiecheat/cookies/cookie-scoop extraction chain and the browser-use/agent-browser/CDP live-cookie fallback. When press-auth is installed and returns valid cookies, the new path wins and we skip the legacy detection chain entirely. When press-auth is not installed, behavior is identical to before. When press-auth is installed but errored (e.g. user has not run press-auth login yet), the generated CLI surfaces its message and continues with the legacy chain so persistent on-disk cookies can still succeed. Updates the cookie-tool 'not found' error and the live-session failure message to lead with the press-auth install recommendation, leaving the legacy install options as fallback. Adds a tryPressAuth helper in the same file. Only generated CLIs whose Auth.Type is 'cookie' or 'composed' exercise this template; existing golden fixtures use apiKey/oauth2 auth and are unaffected (verify passes clean). * feat(cli): status + list + forget subcommands (U5) * docs(cli): press-auth companion reference + retro (U8) Documents the press-auth companion binary as the canonical cookie capture path for cookie/composed-auth CLIs. - New skill reference at skills/printing-press/references/auth-companion.md covers when to recommend press-auth, the install command, how it fits the generated auth.go flow, debug playbook, and how to scope login_url / login_complete_selector / jwt_carrier_cookie per API. - New retro entry at docs/solutions/logic-errors/auth-login-chrome-broken- 2026-05.md captures the original bug (Chrome holds session cookies in RAM; on-disk extraction misses them; --remote-debugging-port not enabled on daily Chrome) and the press-auth fix. - SKILL.md gets a one-paragraph pointer in the Cookie/composed HTML transport section so the recommendation surfaces during Phase 1.7 / 2. - AGENTS.md Quality Gates gains a single bullet flagging press-auth as the canonical capture path with legacy chain as fallback. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(cli): spec auth_companion fields (U7) * docs(cli): plan for press-auth companion (the 2026-05-12 fix) * fix(cli): satisfy golangci-lint modernize hints + drop unused notImplementedExit * Update internal/pressauth/chrome.go Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update internal/pressauth/login.go Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix(cli): address press-auth review feedback * fix(cli): skip press-auth refresh without endpoint * fix(press-auth): stabilize browser CI cleanup * Update internal/pressauth/state.go Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update chrome.go Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * test(cli): stabilize press-auth capture timeout test under CI cold-start The 500ms timeout was shorter than Chrome's cold-start on a CI runner, so the deadline cancelled the allocator mid-launch and chromedp returned "chrome failed to start" instead of a clean context.DeadlineExceeded, failing the assertion. Give Chrome a realistic launch budget so the deadline fires during the completion wait, and tolerate the launch-race error as the same timeout outcome while keeping the tempdir-cleanup assertion as the load-bearing check. * test(cli): skip press-auth chromedp tests when CI Chrome fails to launch The ubuntu runner's preinstalled Chrome intermittently fails to bring up its DevTools endpoint under load ("websocket url timeout reached") or fails to start at all ("chrome failed to start" with a dbus error). Any of the three capture tests can hit this on any run, which red the PR for an environment condition rather than a Capture regression. Treat those launcher-layer failures as Chrome-unavailable and skip, matching how skipIfNoChrome already handles a missing binary; assertion-level failures and other error strings still fail. * test(cli): give press-auth capture tests room for slow CI Chrome A contended runner can spend 25s+ just launching Chrome, so the capture assertion tests were hitting their own deadline during navigate ("navigate: context deadline exceeded") against an instant in-process server. Widen their budget to 75s and treat a context.DeadlineExceeded as Chrome being too slow in this environment (skip), alongside the existing launch-failure skips. The timeout-cleanup test is unchanged: it wants the deadline. * fix(cli): harden press-auth state load against bad key size and path traversal Addresses Greptile review on the press-auth PR. Load now validates the keychain key size before decrypt (factored into validateKeySize, shared with getOrCreateKey) so a corrupted entry yields an actionable message instead of a cryptic aes.NewCipher error. stateFilePath rejects a domain containing a path separator or ".." and asserts the joined path resolves directly under the state directory, closing the path-traversal gap. --------- Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Trevin Chow <trevin@trevinchow.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> |
||
|
|
aecf495af1 |
fix(cli): harden manifest-gen remote spec loader against hangs and silent truncation (#1699)
* fix(cli): harden manifest-gen remote spec loader against hangs and silent truncation loadSpec in cmd/manifest-gen had two defects when fetching remote specs: 1. No timeout on the HTTP request. http.Get with the default client has no overall request timeout, so a remote host that flushes headers and then blocks on the body would hang manifest-gen indefinitely. 2. Silent truncation. io.LimitReader(body, 50MiB) followed by io.ReadAll returned the first 50 MiB of any oversized response with no error, so the caller could not tell a real 49 MiB spec from a multi-gigabyte stream truncated mid-document. Fix: route the request through http.NewRequestWithContext with a 60s timeout, and read limit+1 bytes so we can return an explicit "spec exceeds N bytes" error when the response is over the limit. The 50 MiB cap is preserved. Adds main_test.go covering happy path, local file, non-200, stalled server (with a short timeout override so the test runs in well under a second), oversized response, and exactly-at-limit response. * fix(cli): eliminate data race in manifest-gen loadSpec tests The previous test helpers `withTimeout` / `withMaxBytes` mutated the package-level `remoteSpecTimeout` and `maxRemoteSpecBytes` vars while the `httptest.Server` handler goroutine read those same vars to size its response. There was no happens-before relationship between the test-goroutine write and the handler-goroutine read, so `go test -race ./cmd/manifest-gen/...` could flag a data race. Refactor `loadSpec` to take its byte limit and timeout as explicit parameters. The single production caller in `main()` passes `maxRemoteSpecBytes` and `remoteSpecTimeout` directly; tests pass their own local values. No package-level state is mutated, so the handler closures close over local vars and the race is gone by construction. Restore the package-level identifiers to `const` since tests no longer override them. Production behavior is unchanged (same 50 MiB limit, same 60s timeout). |
||
|
|
a4b0eb3059 |
fix(cli): anchor openapi loader normalization (#730)
* fix(cli): anchor openapi loader normalization * refactor(cli): simplify openapi parser loading * fix(cli): preserve strict remote ref guard |
||
|
|
4832173d18 | fix(cli): sync module path with v4 release (#677) | ||
|
|
4e1db1e761 |
fix(cli): repair v3 release — version regex, module path, CI gate (#415)
* fix(cli): handle +dirty suffix in pseudo-version detection
Strip semver build metadata before classifying a runtime build-info
version string. Without this, pseudo-versions emitted by Go for builds
off a dirty working tree (e.g. v2.4.1-0.20260430120000-abcdef123456+dirty)
slipped past the pseudo-version regex's `$` anchor, so the leaked
pseudo-version overwrote the hardcoded fallback.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(cli): bump module path to /v3 to match release 3.0.0
Go's Semantic Import Versioning rule requires v2+ modules to embed `/vN`
in the module path and every internal import. release-please bumped
version.go to 3.0.0 in commit
|
||
|
|
5777d267ac |
chore(cli): drop dead manifest_url + manifest_checksum from registry guidance (#364)
Megamcp was the only consumer of these registry.json fields — it used manifest_checksum for cache invalidation and manifest_url to fetch tools-manifest.json over HTTP. With megamcp removed in #363, both fields are dead weight in every published library entry and in the publish skill's instructions. This commit drops them from: - skills/printing-press-publish/SKILL.md — the example schema and the per-field guidance no longer instruct agents to compute or write these values. Also drops the cli-only mcp_ready value from the example since computeMCPReady stopped emitting it after #359. - cmd/manifest-gen/main.go — the "For registry.json:" trailer that printed manifest_checksum guidance is gone. spec_format now prints as a plain "Spec format:" line. The trailing stdout-checksum print (used by scripts that piped into registry generation) is removed. The library repo's existing registry.json entries still carry these fields; a follow-up PR there strips them. Field readers in tools/generate-skills/main.go ignore both, so no consumer breaks during the transition. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
0e1b850854 |
chore(cli)!: remove megamcp aggregate server and Composio plan (#363)
* chore(cli): remove megamcp aggregate server and Composio plan The aggregate "all CLIs in one MCP server" surface no longer earns its place. Per-CLI MCPB bundles serve Claude Desktop install; per-CLI agent-skill packaging serves cross-client install. An aggregate server with dynamic activation, meta-tools, and an auth-format substitution layer added maintenance cost (auth.go has had multiple bugfixes in the changelog) without giving agents anything they can't already do by picking the right printed-CLI skill from descriptions. Pre-launch, no users to migrate. Removes: - internal/megamcp/ (handler, manifest, registry, metatools, activation, auth, security; ~5,000 LOC including tests) - cmd/printing-press-mcp/ (the aggregate binary) - docs/plans/2026-04-19-001-feat-composio-inspired-features-plan.md (forward-looking plan that built on megamcp) - smithery.yaml (described printing-press-mcp; not relevant without it) - printing-press-mcp build/archive blocks from .goreleaser.yaml - Indirect go.mod deps that came from mcp-go: mark3labs/mcp-go, google/jsonschema-go, google/uuid, spf13/cast, yosida95/uritemplate tools-manifest.json stays — auth-doctor and mcp-audit still consume it. The "cli-only" MCP readiness label is now fully dead (megamcp was its only consumer); comments in climanifest.go, mcpb_manifest.go, bundle.go, and mcpb_bundle.go are tightened to drop the stale references. Note: the printing-press-mcp aggregate binary is removed. Replacement paths are per-CLI MCPB bundles (Claude Desktop) and per-CLI /pp-<api> agent skills (cross-client). Pre-launch — no users affected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(cli): collapse computeMCPReady switch redundancy The "full" cases (none, api_key, bearer_token) were unreachable through the explicit case after the default branch already returned "full" for everything not in cookie/composed. Drop the redundant case. Truth table identical across all 8 known auth types (none, api_key, bearer_token, oauth2, cookie, composed, empty, unknown): cookie/composed → "partial" everything else → "full" Pure function, no callers affected. Tests + goldens unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(cli): purge megamcp from active forward-looking plans Fallout from removing internal/megamcp/ in this PR. Two active plans referenced megamcp: - docs/plans/2026-04-19-002-feat-super-cli-run-namespace-plan.md was built explicitly on megamcp parity. The technical approach wrapped internal/megamcp/registry.go and lifted helpers from internal/megamcp/handler.go. With megamcp gone, the plan cannot be implemented as written and would need a clean-sheet rewrite. Deleted; if the run-namespace concept is still desired, write a fresh plan grounded in the per-CLI surface. - docs/plans/2026-04-22-003-feat-mcp-production-readiness-plan.md mentioned megamcp in 7 supporting paragraphs (current-state framing, a "patterns to follow" pointer, an "unchanged invariants" item, source references). The plan itself is about per-CLI MCP improvements and stands without those references — surgical edits only. Other plans that reference megamcp are completed/historical or out-of-scope for this PR; surface them for separate cleanup if needed: - 2026-04-13-002-feat-cloudflare-cli-learnings-plan.md (active) - 2026-04-19-004-feat-auth-doctor-plan.md (active) - 2026-04-17-002-fix-private-library-registry-auth-plan.md (active) - 2026-04-19-003-feat-unified-auth-manager-plan.md (active) - 2026-04-05-001-feat-mcp-readiness-layer-plan.md (active) - docs/brainstorms/2026-04-06-mega-mcp-generic-proxy-requirements.md - docs/plans/2026-04-06-002-feat-mega-mcp-aggregate-server-plan.md (the original megamcp build plan — historical record, leave) - docs/plans/2026-04-06-003-feat-mega-mcp-generic-proxy-plan.md (historical record, leave) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(cli): sweep remaining megamcp references from plan dir Continues the megamcp removal cleanup beyond the two plans handled in the previous commit. Deleted (4 docs — premise gone, no value as forward-looking artifacts): - docs/plans/2026-04-06-002-feat-mega-mcp-aggregate-server-plan.md (the original megamcp build plan) - docs/plans/2026-04-06-003-feat-mega-mcp-generic-proxy-plan.md (the megamcp generic-proxy build plan) - docs/brainstorms/2026-04-06-mega-mcp-generic-proxy-requirements.md (the originating brainstorm) - docs/plans/2026-04-17-002-fix-private-library-registry-auth-plan.md (a fix for megamcp's registry-fetch path; bug doesn't exist now) Status flips (3 docs — work landed or was superseded; refs become historical and accurate to that snapshot): - 2026-04-19-004-feat-auth-doctor-plan.md → completed (auth-doctor is shipped; in AGENTS.md glossary) - 2026-04-05-001-feat-mcp-readiness-layer-plan.md → completed (the MCPReady field, tools-manifest.json, NoAuth flag all shipped and remain in use) - 2026-04-19-003-feat-unified-auth-manager-plan.md → superseded (the auth-doctor plan's overview explicitly notes this one was killed in favor of the lighter diagnostic) Surgical edit (1 doc): - 2026-04-13-002-feat-cloudflare-cli-learnings-plan.md drops "megamcp" from a comma-separated list of subsystems the plan does not touch. After this sweep, all live megamcp references in docs/plans/ live in completed/superseded plans where the references are historical record of what was built at that time. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
1ab789ea58 |
fix(cli): use /v2 module path so go install reports correct version (#298)
* fix(cli): migrate module path to /v2 so go install reports correct version
Tags are at v2.x but go.mod declared the module without a `/v2` suffix,
violating Go's Semantic Import Versioning rule. As a result,
`go install github.com/mvanhorn/cli-printing-press/cmd/printing-press@latest`
silently resolved to a v1-derived pseudo-version (last v1 tag was v1.3.2),
and binaries reported `1.3.3-0.<timestamp>-<hash>` instead of `2.3.6`.
Three fixes that together prevent recurrence:
1. Module path is now `github.com/mvanhorn/cli-printing-press/v2`. All 104
internal imports, the goreleaser ldflags target, and the README install
command are updated to match.
2. The version-from-build-info filter in `internal/version/version.go` now
detects every Go pseudo-version form via the `\d{14}-[0-9a-f]{12}$`
suffix shared by all three forms, not just the narrow `0.0.0-` prefix.
Local `go install` from a checkout always produces a pseudo-version, so
this ensures the binary falls back to the hardcoded Version constant
rather than reporting build-info garbage.
3. New `TestModulePathMatchesMajorVersion` in `internal/cli/release_test.go`
parses the major from `version.Version` and asserts `go.mod`'s path has
the matching `/vN` suffix. The next time release-please proposes v3.0.0,
this test fails until go.mod is also bumped — making the whack-a-mole
self-healing instead of latent.
* fix(skills): point install commands at /v2 module path
The cli commit moved the module to `github.com/mvanhorn/cli-printing-press/v2`.
Skill setup contracts and version-mismatch warnings were still telling
users to `go install` the unsuffixed path, which silently resolves to the
last v1 tag and produces a stale binary.
Updates the four affected SKILL.md files (catalog, publish, score, root
printing-press) so first-time and update flows install the v2-resolved
binary.
|
||
|
|
e041f50e7b |
feat(cli): mega MCP — generic HTTP proxy with activation model (#147)
* feat(cli): generate tools-manifest.json at publish time for mega MCP Add WriteToolsManifest() to the publish pipeline that generates a tools-manifest.json alongside .printing-press.json. The manifest contains pre-computed tool schemas (names, descriptions, parameters with location classification, auth config, base URL, required headers) that the mega MCP server reads at runtime — eliminating the need for runtime OpenAPI spec parsing. Key design decisions: - Sorted map iteration for deterministic JSON (stable checksums) - Explicit param location field (path/query/body) fixing the existing template bug where POST body includes path params - Cookie/composed auth APIs emit only NoAuth endpoints - Uses toSnake() for tool names (matching MCP template convention) - Non-blocking: publish continues if manifest generation fails Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(skills): add manifest_checksum, spec_format, manifest_url to registry schema Extend the registry.json mcp block with three new fields for the mega MCP server: - manifest_checksum: SHA-256 of tools-manifest.json for integrity verification - spec_format: the spec format (openapi3, graphql, internal) - manifest_url: relative path to tools-manifest.json in the library repo The publish skill computes manifest_checksum at publish time and derives manifest_url from the entry's path field. These fields enable the mega MCP to fetch and verify tools manifests from the public library repo. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(cli): mega MCP skeleton — registry fetching, manifest caching, security Create the internal/megamcp/ package and cmd/printing-press-mcp/ entry point for the mega MCP generic HTTP proxy server. Infrastructure: - types.go: re-exports ToolsManifest from pipeline (no duplication), adds RegistryEntry, Registry, APIEntry types - registry.go: FetchRegistry with injectable baseURL for testing - manifest.go: LoadManifests with parallel errgroup loading, checksum verification, temp-then-rename cache writes, PRINTING_PRESS_APIS filter, slugToToolPrefix normalization - security.go: ValidateBaseURL (SSRF protection with DNS resolution), SanitizeText, VerifyChecksum, ValidateSlug, ValidateCachePath Add mcp-go v0.47.0 as direct dependency. Minimal main.go skeleton with MCP server creation and stdio serving. 53 new tests covering registry, manifest, and security packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(cli): mega MCP generic HTTP handler with auth and param routing Add the core HTTP proxying layer for the mega MCP server: handler.go — MakeToolHandler builds MCP tool handlers from manifest data: - Parameter classification: path→URL substitution, query→URL params, body→JSON - Fail-closed auth: blocks unauthenticated calls on non-NoAuth endpoints - Post-assembly URL validation: verifies host matches base_url (SSRF prevention) - Missing path param detection with actionable error messages - RequiredHeaders and per-tool HeaderOverrides - Response body capped at 10MB, credential redaction on 4xx errors - Auth-aware error handling: 401/403→generic hint, 429→surface body auth.go — Auth format string expansion and credential management: - ApplyAuthFormat: {PLACEHOLDER} expansion with semantic aliases ({token}) - BuildAuthHeader/BuildAuthQueryParam: routes auth to header or query - RedactCredentials: scrubs known credential values from error responses 106 tests covering happy paths, auth types, edge cases, and integration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(cli): mega MCP meta-tools and activation model Add the agent-facing discovery and activation layer: metatools.go — 6 meta-tools registered at startup: - library_info: API catalog with auth status (boolean only, no env var names), upgrade availability, activation state - setup_guide: per-API auth instructions with env vars and key URLs - activate_api: dynamically registers API tools via mcp-go AddTool, sends tools/list_changed notification automatically - deactivate_api: removes API tools via DeleteTools - search_tools: keyword search across ALL manifests (activated or not) - about: version, API count, tool count activation.go — ActivationManager for tool lifecycle: - Per-API HTTP clients created at activation time - Idempotent activation (no duplicate tools) - SearchTools with case-insensitive substring matching - Thread-safe via sync.RWMutex Confirmed mcp-go v0.47.0 fully supports dynamic tool add/remove after ServeStdio — no fallback needed. tools/list_changed sent automatically. 50 new tests across activation and meta-tools. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(cli): mega MCP entry point, goreleaser, and marketplace metadata Wire cmd/printing-press-mcp/main.go with the full startup pipeline: registry fetch → manifest loading → activation manager → meta-tools → serve on stdio. Graceful shutdown on SIGINT/SIGTERM. Distribution: - Goreleaser builds both printing-press and printing-press-mcp as separate archives (no bundling confusion) - smithery.yaml at repo root for Smithery marketplace listing - Configurable via PRINTING_PRESS_MCP_BASE_URL and PRINTING_PRESS_MCP_CACHE_DIR env vars Install: go install .../cmd/printing-press-mcp@latest Setup: claude mcp add printing-press -- printing-press-mcp Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cli): address code review feedback — 3 bugs in mega MCP 1. Cached manifests now load on registry fetch failure: LoadManifests distinguishes nil entries (registry failed → scan cache) from empty entries (all filtered out → return empty). Previously, a GitHub outage after a successful first run would boot with zero APIs. 2. Auth failure guidance uses API slug, not display name: MakeToolHandler now takes an apiSlug parameter so setup_guide references like setup_guide("dub") match what the meta-tool expects, instead of setup_guide("Dub") which returns "API not found". 3. ValidateBaseURL wired into manifest loading: both fresh-fetch and cache paths now call ValidateBaseURL before accepting a manifest. Rejects literal private IPs; DNS-based SSRF checks deferred to request-time SafeDialer (prevents DNS rebinding). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cli): add SafeDialer for runtime SSRF protection, validate cached manifests Two fixes from code review: 1. SafeDialer: ValidateBaseURL deferred DNS checks to a runtime dialer that didn't exist. Added safeDialer that resolves hostnames and rejects private/loopback/link-local IPs before connecting. All per-API HTTP clients now use SafeHTTPClient() instead of plain http.Client. This prevents https://localhost and other hostname-based SSRF attacks that passed the format-only ValidateBaseURL check. 2. Cache fallback now validates base URLs: the offline fallback path (loadFromCacheOnly) was loading cached manifests without calling ValidateBaseURL. A tampered or outdated cached manifest with an unsafe base URL would be accepted. Now both the normal path and the cache-only fallback validate base URLs before returning entries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cli): premortem fixes — auth normalization, stubs, truncation, debug tool Four fixes from premortem analysis: 1. Auth format string normalization: WriteToolsManifest now normalizes format strings at publish time so derived placeholders like {token} become {DUB_TOKEN}. Prevents silent auth failures when the mega MCP's runtime expansion doesn't match the generated config's multi-key map. 2. Stub tools at startup: All API tools are now registered as stubs when NewActivationManager is created. Stubs prompt "call activate_api first" instead of making HTTP requests. This lets agents discover tool names via tools/list without activation, fixing the UX issue where agents couldn't find tools they hadn't activated yet. Deactivation re-registers stubs instead of removing tools entirely. 3. Response truncation: 2xx responses larger than 32KB are truncated with a size note before returning to the agent, preventing context window flooding from large API responses (e.g., Steam's 164-endpoint API). 4. debug_api meta-tool: New meta-tool that performs a health check GET to the API's base URL and returns diagnostic info — base URL, auth status, activation state, HTTP status, and response headers. Gives users a way to diagnose failures without guessing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(cli): add manifest-gen tool for backfilling tools manifests Standalone tool that downloads an API spec (OpenAPI, internal YAML, or GraphQL) and generates a tools-manifest.json without running the full printing press pipeline. Prints the SHA-256 checksum for registry.json. Usage: manifest-gen -spec <url-or-path> [-output <dir>] [-format auto|openapi|internal|graphql] Examples: manifest-gen -spec https://api.example.com/openapi.yaml -output ./out manifest-gen -spec ./local-spec.yaml -format internal -output ./out Used to backfill tools manifests for the 6 existing CLIs in the public library repo that were published before tools-manifest.json generation was added to the publish pipeline. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(cli): mega MCP brainstorm, plans, and requirements documents Add the planning artifacts for the mega MCP generic proxy: - Requirements doc from brainstorm session - Original subprocess-based plan (superseded, kept for hybrid mode reference) - Final generic proxy plan with activation model Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
154626ed33 |
fix(cli): write .printing-press.json manifest during generate command (#68)
* fix(cli): write .printing-press.json manifest during generate command The generate command wrote CLIs directly to ~/printing-press/library/ without creating the .printing-press.json manifest. The manifest was only written by PublishWorkingCLI in the fullrun pipeline, which the standalone generate command never calls. This caused publish validate to fail with "missing .printing-press.json" for any skill-generated CLI. Add WriteManifestForGenerate to the pipeline package and call it from both code paths (--spec and --docs) in the generate command. Also suppress redundant "validation failed" stderr when --json mode already contains the structured failure details (Silent field on ExitError). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cli): gofmt struct field alignment in GenerateManifestParams Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
538e65c4ab |
feat(cli): differentiate exit codes by failure type
Agents can now branch on exit code without parsing error text: - 1: user input error (missing/invalid flags) - 2: spec/data error (file not found, parse failure) - 3: generation/pipeline failure (build, quality gate) - 4: unknown/unclassified error (fallback) Adds ExitError type in internal/cli carrying a typed code, with errors.As extraction in main.go. Wraps errors at source in all command RunE functions. Includes guard tests that verify pipeline error messages stay in sync with the string-matched classification. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
454739bd04 |
feat(scaffold): initial project structure with CLI skeleton
Go module, Cobra CLI with generate/version commands, spec parser structs, and generator stub. Compiles and runs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |