Something went wrong. Try again.
A collaborative coding-agent orchestrator for atproto radl.app
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071import type { AgentRecord, ArtifactRecord, ArtifactRequestRecord, MessageRecord, StrongRef,} from './generated/records.js'
type ExactlyOne<L extends string, R extends string> = | (Record<L, StrongRef> & Partial<Record<R, never>>) | (Record<R, StrongRef> & Partial<Record<L, never>>)
export type ScopedArtifactRequest = ArtifactRequestRecord & ExactlyOne<'goal', 'project'>export type ScopedArtifact = ArtifactRecord & ExactlyOne<'goal', 'project'>export type AnchoredMessage = MessageRecord & ExactlyOne<'goal', 'artifact'>
/** * One `join` per space per repo, by construction: the record key is derived from the space's own * address rather than minted. * * A join is the only record a client writes without the human asking for it — the UI writes one the * first time a member opens a space — so attempting it twice has to be safe. With a derived key the * second attempt collides at the PDS (`RecordAlreadyExists`) instead of leaving a repo holding two * identical bookmarks that every reader then has to dedupe. * * Both halves are already key-safe in practice: a `did:plc:` tail is base32 and a space's rkey is a * TID. A `did:web:` tail can carry characters a record key may not (a percent-encoded port), so * anything outside the permitted set becomes `-`. Two spaces cannot collide through that flattening — * the key ends with the space's own rkey, which is unique in the repo that minted it, so the DID half * only ever has to separate spaces whose rkeys already match. * * It lives here rather than beside the command that writes it because the fixture derives it too, and * two spellings of one key is how a fixture comes to disagree with the code it stands in for. */export const joinRkey = (spaceDid: string, spaceRkey: string): string => `join-${spaceDid.slice(spaceDid.lastIndexOf(':') + 1).replace(/[^a-zA-Z0-9.~_-]/g, '-')}-${spaceRkey}`
/** * What a profile accepts IN ONE SPACE — the single reading of an agent record's capabilities, shared * by the assignee picker, the daemon's coverage advisories and every test, so there is one rule and * not three spellings of it (design §11). * * The rule is OVERRIDE, not intersection: a `scopes` entry naming this space replaces the top-level * `artifactTypes` outright, and an entry with an empty list is a valid statement — "this profile does * nothing here" — rather than a missing one. Entries naming other spaces are inert; a record with no * entry for this space falls back to the top-level list, which is what every record written before * scoping existed does, so an unscoped agent behaves exactly as it always has. * * The fold never rewrites a signed value, so `index.agents` keeps carrying raw records and consumers * resolve through here instead. First entry wins if a record somehow names one space twice: the * resolution has to be a pure function of the record, and "the first one" is the only tie-break that * needs no ordering nobody guaranteed. */export function agentTypesFor(record: AgentRecord, spaceUri: string): string[] { const scope = record.scopes?.find((entry) => entry.space === spaceUri) return [...(scope ? scope.artifactTypes : record.artifactTypes)]}
/** * The collection a tangled issue is a record in, and the `goal.source.kind` that names one. * * A goal imported from an issue carries the pointer so the space can tell which issues it has already * taken up; it never carries the issue's live text, and nothing mechanical follows the pointer. The * kind is a free-form string in the lexicon, like `closeGoal.disposition`, so a newer writer can name * a forge this build has never heard of without older readers rejecting the record. */export const TANGLED_ISSUE_COLLECTION = 'sh.tangled.repo.issue'export const GOAL_SOURCE_TANGLED_ISSUE = 'tangled-issue'
export * from './generated/records.js'