/** * `clustly publish` (design §2 step 9; build-plan slice 4.1) — turn the workspace's * `clustly.yaml` listing block into a marketplace listing. Missing fields are prompted and * WRITTEN BACK into the block (the next publish is idempotent, and the answers are the * builder's committed word). The listing id is remembered per workspace in ~/.clustly/config: * a later publish UPDATES the same listing (price/copy edits), never mints a duplicate; a * server-side 404 self-heals by forgetting the stale id and creating fresh. */ import { type CliApiDeps } from "./api-client"; import type { DeclaredField } from "./envelope"; import { type ClustlyManifest, type ListingBlock } from "./manifest"; /** This domain speaks to the API through the shared client (R5). */ export type PublishDeps = CliApiDeps; /** Terminal interaction the command glue injects (readline-backed; scripted in tests). */ export interface PublishIO { say(message: string): void; /** Plain text prompt; Enter returns `fallback` (may be ""). */ ask(question: string, fallback: string): Promise; confirm(question: string): Promise; } export declare const MICRO_PER_USDC = 1000000; /** * The deliverable kinds a listing may declare, in prompt order (commonest last-mile first). * * A structural copy of the server's `OUTPUT_KINDS` — the sdk ↔ server boundary cannot share an * import, so `manifest-pin.test.ts` pins the two lists equal, the same way it already pins the * DeliverableManifest kind union. Drift fails that test rather than shipping a CLI that offers a * kind the marketplace rejects. */ export declare const LISTING_OUTPUT_KINDS: readonly ["markdown", "file", "pdf", "image", "video"]; export interface PublishResult { listingId: string; status: string; created: boolean; /** Parked because this agent has not yet completed its conformance order — an unpaid job the * platform issues so no buyer is the first to run the handler. Absent from older servers. */ pendingConformance?: boolean; } /** * Fill the listing block: existing values pass through; gaps are prompted (interactive) or * refused (--ci — the committed block is the consent). Returns the completed block or the * first missing field's name. */ export declare function completeListing(manifest: ClustlyManifest, io: PublishIO, ci: boolean): Promise<{ listing: Required> & ListingBlock; } | { missing: string; }>; /** Persist the completed block back into clustly.yaml (prompted answers become committed). */ export declare function writeListingBlock(workspacePath: string, manifest: ClustlyManifest, listing: ListingBlock): ClustlyManifest; /** Create-or-update the workspace's listing. `live` = publish active; false = draft. */ export declare function publishListing(deps: PublishDeps, input: { workspacePath: string; agentId: string; listing: ListingBlock & { title: string; description: string; price: number; }; live: boolean; /** §5c publish-ahead: park as draft carrying the auto-activate intent — the server * records it and the activation crank flips the listing live on DEPLOYED. */ activateOnDeploy?: boolean; /** 1:N disambiguation (2026-08-28): "new" force-creates an offer alongside the existing * ones; a listing id targets exactly that one (a miss is an ERROR, never a silent * create). Absent = the legacy remembered-id ladder. */ target?: "new" | { listingId: string; }; /** The manifest's declared request fields, if any (2026-08-28). Sent ALWAYS, including * empty: `clustly.yaml` is the truth, so deleting the block must clear the listing's form * rather than leave a stale question the agent no longer reads. */ inputs?: DeclaredField[]; }): Promise; /** The consent copy. Honest wording is load-bearing: the NFT lives on a public chain we * do not control — "not deletable by us" is the truth; "PERMANENT" overstates what the * builder can reason about and understates who holds the power (they can burn it after * claiming custody, phase 5). */ export declare const IDENTITY_CONSENT_PROMPT: string; export type IdentityConsentDecision = { mode: "flag"; consent: boolean; } | { mode: "prompt"; } /** Neither flag in a non-interactive run: never guess a consent (D4). */ | { mode: "skip"; }; export declare function decideIdentityConsent(input: { ci: boolean; isTTY: boolean; publicIdentity: boolean | undefined; }): IdentityConsentDecision; /** Record (or withdraw) the standing consent server-side — the agent row is the one * truth the activation crank reads; the CLI never mints anything itself (LLD 2.5). */ export declare function setIdentityConsent(deps: PublishDeps, agentId: string, consent: boolean): Promise; /** Stable per agent + title, so a repeated publish of the same offer replays, a different offer creates. */ export declare function listingIdempotencyKey(agentId: string, title: string): string; /** A positive decimal, nothing else: `12,50` (→ 12 under parseFloat) and `5 usd` are refused on a money field. */ export declare function parsePrice(raw: string): number | null;