Skip to content

Commit 14b8973

Browse files
committed
Merge origin/main into issue-232
2 parents 15289c3 + 42c20ab commit 14b8973

57 files changed

Lines changed: 3638 additions & 611 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docker-compose.api.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ services:
1010
DOCKER_GIT_PROJECTS_ROOT_VOLUME: ${DOCKER_GIT_PROJECTS_ROOT_VOLUME:-docker-git-projects}
1111
DOCKER_GIT_FEDERATION_PUBLIC_ORIGIN: ${DOCKER_GIT_FEDERATION_PUBLIC_ORIGIN:-}
1212
DOCKER_GIT_FEDERATION_ACTOR: ${DOCKER_GIT_FEDERATION_ACTOR:-docker-git}
13+
DOCKER_GIT_EXCHANGE_TARGETS: ${DOCKER_GIT_EXCHANGE_TARGETS:-}
14+
DOCKER_GIT_EXCHANGE_PROJECT_REPO_URL: ${DOCKER_GIT_EXCHANGE_PROJECT_REPO_URL:-}
15+
DOCKER_GIT_EXCHANGE_AGENT_PROVIDER: ${DOCKER_GIT_EXCHANGE_AGENT_PROVIDER:-codex}
16+
DOCKER_GIT_EXCHANGE_AGENT_COMMAND: ${DOCKER_GIT_EXCHANGE_AGENT_COMMAND:-}
17+
DOCKER_GIT_EXCHANGE_AGENT_TIMEOUT_MS: ${DOCKER_GIT_EXCHANGE_AGENT_TIMEOUT_MS:-3600000}
18+
DOCKER_GIT_OUTBOX_POLLING_INTERVAL_MS: ${DOCKER_GIT_OUTBOX_POLLING_INTERVAL_MS:-5000}
1319
ports:
1420
- "${DOCKER_GIT_API_BIND_HOST:-127.0.0.1}:${DOCKER_GIT_API_PORT:-3334}:${DOCKER_GIT_API_PORT:-3334}"
1521
dns:

docker-compose.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ services:
1313
DOCKER_GIT_PROJECTS_ROOT_VOLUME: ${DOCKER_GIT_PROJECTS_ROOT_VOLUME:-docker-git-projects}
1414
DOCKER_GIT_FEDERATION_PUBLIC_ORIGIN: ${DOCKER_GIT_FEDERATION_PUBLIC_ORIGIN:-}
1515
DOCKER_GIT_FEDERATION_ACTOR: ${DOCKER_GIT_FEDERATION_ACTOR:-docker-git}
16+
DOCKER_GIT_EXCHANGE_TARGETS: ${DOCKER_GIT_EXCHANGE_TARGETS:-}
17+
DOCKER_GIT_EXCHANGE_PROJECT_REPO_URL: ${DOCKER_GIT_EXCHANGE_PROJECT_REPO_URL:-}
18+
DOCKER_GIT_EXCHANGE_AGENT_PROVIDER: ${DOCKER_GIT_EXCHANGE_AGENT_PROVIDER:-codex}
19+
DOCKER_GIT_EXCHANGE_AGENT_COMMAND: ${DOCKER_GIT_EXCHANGE_AGENT_COMMAND:-}
20+
DOCKER_GIT_EXCHANGE_AGENT_TIMEOUT_MS: ${DOCKER_GIT_EXCHANGE_AGENT_TIMEOUT_MS:-3600000}
21+
DOCKER_GIT_OUTBOX_POLLING_INTERVAL_MS: ${DOCKER_GIT_OUTBOX_POLLING_INTERVAL_MS:-5000}
1622
ports:
1723
- "${DOCKER_GIT_API_BIND_HOST:-127.0.0.1}:${DOCKER_GIT_API_PORT:-3334}:${DOCKER_GIT_API_PORT:-3334}"
1824
dns:

packages/api/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ Optional env:
4545
- `DOCKER_GIT_PROJECTS_ROOT_VOLUME` (Docker volume name for controller state, default: `docker-git-projects`)
4646
- `DOCKER_GIT_FEDERATION_PUBLIC_ORIGIN` (optional public ActivityPub origin)
4747
- `DOCKER_GIT_FEDERATION_ACTOR` (default: `docker-git`)
48+
- `DOCKER_GIT_EXCHANGE_TARGETS` (optional comma-separated exchange targets, e.g. `https://exchange.lefine.pro` or `code@exchange.lefine.pro`)
49+
- `DOCKER_GIT_EXCHANGE_PROJECT_REPO_URL` (fallback repo for exchange Tickets without a GitHub URL)
50+
- `DOCKER_GIT_EXCHANGE_AGENT_PROVIDER` (default: `codex`; also supports `claude`, `opencode`, `custom`)
51+
- `DOCKER_GIT_EXCHANGE_AGENT_COMMAND` (optional command template; `{{prompt}}` is replaced with the task prompt)
52+
- `DOCKER_GIT_EXCHANGE_AGENT_TIMEOUT_MS` (default: `3600000`)
53+
- `DOCKER_GIT_OUTBOX_POLLING_INTERVAL_MS` (default: `5000`)
4854

4955
## Endpoints
5056

@@ -56,6 +62,9 @@ Optional env:
5662
- `GET /federation/followers`
5763
- `GET /federation/following`
5864
- `GET /federation/liked`
65+
- `POST /federation/exchange/subscriptions` (discover remote actor, persist metadata, send signed `Follow`)
66+
- `GET /federation/exchange/subscriptions`
67+
- `POST /federation/exchange/poll` (manual remote outbox poll)
5968
- `POST /federation/follows` (create ActivityPub `Follow` subscription)
6069
- `GET /federation/follows`
6170
- `GET /projects`
@@ -77,6 +86,23 @@ Optional env:
7786

7887
## Subscription workflow (ActivityPub Follow + ForgeFed issues)
7988

89+
Exchange targets must be explicit. Use `https://exchange.lefine.pro`, an actor URL, or a handle like `code@exchange.lefine.pro`; the API resolves the code actor document, stores its `inbox/outbox/followers/publicKey`, sends `Follow`, and polls the stored `outbox`.
90+
91+
```bash
92+
./ctl request POST /federation/exchange/subscriptions '{
93+
"domain":"https://social.provercoder.ai",
94+
"target":"https://exchange.lefine.pro",
95+
"projectRepoUrl":"https://github.com/ProverCoderAI/docker-git",
96+
"agentProvider":"codex"
97+
}'
98+
99+
./ctl request POST /federation/exchange/poll '{}'
100+
./ctl request GET /federation/exchange/subscriptions
101+
./ctl request GET /federation/issues
102+
```
103+
104+
When a polled `Create(Ticket)` has no GitHub URL in the Ticket payload, `projectRepoUrl` or `DOCKER_GIT_EXCHANGE_PROJECT_REPO_URL` is required for the automatic docker-git project/agent run.
105+
80106
1. Read actor profile (contains `inbox/outbox/followers/following/liked`):
81107

82108
```bash

packages/api/src/api/contracts.ts

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ export type TerminalSession = {
362362
readonly sshCommand: string
363363
readonly status: TerminalSessionStatus
364364
readonly createdAt: string
365+
readonly attachedClients?: number | undefined
365366
readonly startedAt?: string | undefined
366367
readonly closedAt?: string | undefined
367368
readonly exitCode?: number | undefined
@@ -399,21 +400,46 @@ export type ForgeFedTicket = {
399400
readonly summary: string
400401
readonly content: string
401402
readonly mediaType?: string | undefined
402-
readonly source?: string | undefined
403+
readonly source?: string | ForgeFedTicketSource | undefined
403404
readonly published?: string | undefined
404405
readonly updated?: string | undefined
405406
readonly url?: string | undefined
407+
readonly context?: string | undefined
408+
readonly workType?: string | undefined
409+
readonly attachment?: ReadonlyArray<unknown> | undefined
410+
readonly raw?: unknown | undefined
406411
}
407412

408-
export type FederationIssueStatus = "offered" | "accepted" | "rejected"
413+
export type ForgeFedTicketSource = {
414+
readonly content?: string | undefined
415+
readonly mediaType?: string | undefined
416+
}
417+
418+
export type FederationIssueStatus =
419+
| "offered"
420+
| "accepted"
421+
| "rejected"
422+
| "queued"
423+
| "running"
424+
| "completed"
425+
| "failed"
409426

410427
export type FederationIssueRecord = {
411428
readonly issueId: string
412429
readonly offerId?: string | undefined
430+
readonly activityId?: string | undefined
431+
readonly actor?: string | undefined
413432
readonly tracker?: string | undefined
414433
readonly status: FederationIssueStatus
415434
readonly receivedAt: string
435+
readonly updatedAt?: string | undefined
416436
readonly ticket: ForgeFedTicket
437+
readonly projectId?: string | undefined
438+
readonly agentId?: string | undefined
439+
readonly remoteInbox?: string | undefined
440+
readonly remoteOutbox?: string | undefined
441+
readonly result?: string | undefined
442+
readonly error?: string | undefined
417443
}
418444

419445
export type CreateFollowRequest = {
@@ -437,6 +463,12 @@ export type ActivityPubFollowActivity = {
437463
readonly capability?: string | undefined
438464
}
439465

466+
export type ActivityPubPublicKey = {
467+
readonly id: string
468+
readonly owner: string
469+
readonly publicKeyPem: string
470+
}
471+
440472
export type ActivityPubPerson = {
441473
readonly "@context": "https://www.w3.org/ns/activitystreams"
442474
readonly type: "Person"
@@ -449,10 +481,14 @@ export type ActivityPubPerson = {
449481
readonly followers: string
450482
readonly following: string
451483
readonly liked: string
484+
readonly publicKey?: ActivityPubPublicKey | undefined
485+
readonly endpoints?: {
486+
readonly sharedInbox?: string | undefined
487+
} | undefined
452488
}
453489

454490
export type ActivityPubOrderedCollection = {
455-
readonly "@context": "https://www.w3.org/ns/activitystreams"
491+
readonly "@context": "https://www.w3.org/ns/activitystreams" | ReadonlyArray<string>
456492
readonly type: "OrderedCollection"
457493
readonly id: string
458494
readonly totalItems: number
@@ -465,6 +501,18 @@ export type FollowSubscription = {
465501
readonly actor: string
466502
readonly object: string
467503
readonly inbox?: string | undefined
504+
readonly remoteActor?: string | undefined
505+
readonly remoteInbox?: string | undefined
506+
readonly remoteOutbox?: string | undefined
507+
readonly remoteFollowers?: string | undefined
508+
readonly remoteSharedInbox?: string | undefined
509+
readonly remotePublicKeyId?: string | undefined
510+
readonly remotePublicKeyPem?: string | undefined
511+
readonly subscriptionName?: string | undefined
512+
readonly queue?: string | undefined
513+
readonly projectRepoUrl?: string | undefined
514+
readonly agentProvider?: AgentProvider | undefined
515+
readonly agentCommand?: string | undefined
468516
readonly to: ReadonlyArray<string>
469517
readonly capability?: string | undefined
470518
status: FollowStatus
@@ -487,6 +535,10 @@ export type FederationInboxResult =
487535
readonly kind: "issue.ticket"
488536
readonly issue: FederationIssueRecord
489537
}
538+
| {
539+
readonly kind: "issue.create"
540+
readonly issue: FederationIssueRecord
541+
}
490542
| {
491543
readonly kind: "follow.accept"
492544
readonly subscription: FollowSubscription
@@ -496,6 +548,30 @@ export type FederationInboxResult =
496548
readonly subscription: FollowSubscription
497549
}
498550

551+
export type ExchangeSubscribeRequest = {
552+
readonly target: string
553+
readonly domain?: string | undefined
554+
readonly actor?: string | undefined
555+
readonly inbox?: string | undefined
556+
readonly projectRepoUrl?: string | undefined
557+
readonly agentProvider?: AgentProvider | undefined
558+
readonly agentCommand?: string | undefined
559+
}
560+
561+
export type ExchangePollRequest = {
562+
readonly target?: string | undefined
563+
readonly runTasks?: boolean | undefined
564+
}
565+
566+
export type ExchangePollResult = {
567+
readonly polledAt: string
568+
readonly subscriptions: number
569+
readonly totalItems: number
570+
readonly newItems: number
571+
readonly processedItems: number
572+
readonly failedItems: number
573+
}
574+
499575
export type ApiEventType =
500576
| "snapshot"
501577
| "project.created"

packages/api/src/api/schema.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,21 @@ export const CreateFollowRequestSchema = Schema.Struct({
222222
capability: OptionalString
223223
})
224224

225+
export const ExchangeSubscribeRequestSchema = Schema.Struct({
226+
target: Schema.String,
227+
domain: OptionalString,
228+
actor: OptionalString,
229+
inbox: OptionalString,
230+
projectRepoUrl: OptionalString,
231+
agentProvider: Schema.optional(AgentProviderSchema),
232+
agentCommand: OptionalString
233+
})
234+
235+
export const ExchangePollRequestSchema = Schema.Struct({
236+
target: OptionalString,
237+
runTasks: OptionalBoolean
238+
})
239+
225240
export const AgentSessionSchema = Schema.Struct({
226241
id: Schema.String,
227242
projectId: Schema.String,
@@ -254,6 +269,7 @@ export const TerminalSessionSchema = Schema.Struct({
254269
sshCommand: Schema.String,
255270
status: TerminalSessionStatusSchema,
256271
createdAt: Schema.String,
272+
attachedClients: Schema.optional(Schema.Number),
257273
startedAt: OptionalString,
258274
closedAt: OptionalString,
259275
exitCode: Schema.optional(Schema.Number),

0 commit comments

Comments
 (0)