opencode-courier 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +677 -0
- package/dist/cleanup.d.ts +59 -0
- package/dist/cleanup.js +98 -0
- package/dist/courier.d.ts +97 -0
- package/dist/courier.js +143 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +422 -0
- package/dist/later.d.ts +40 -0
- package/dist/later.js +85 -0
- package/dist/question.d.ts +138 -0
- package/dist/question.js +620 -0
- package/dist/relay.d.ts +76 -0
- package/dist/relay.js +118 -0
- package/dist/roster.d.ts +51 -0
- package/dist/roster.js +83 -0
- package/dist/storage.d.ts +6 -0
- package/dist/storage.js +12 -0
- package/dist/watch.d.ts +69 -0
- package/dist/watch.js +167 -0
- package/dist/webhook.d.ts +103 -0
- package/dist/webhook.js +396 -0
- package/package.json +46 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
|
+
import type { Plugin as EffectPlugin } from "@opencode-ai/plugin/effect";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import { type RosterStorage } from "./roster.js";
|
|
5
|
+
type Context = Plugin.Context;
|
|
6
|
+
/** OpenCode's own question tool, which the relay wraps. */
|
|
7
|
+
export declare const QUESTION_TOOL = "question";
|
|
8
|
+
/** At most this many questions are kept in storage; the oldest go first. */
|
|
9
|
+
export declare const MAX_STORED = 100;
|
|
10
|
+
/** One question of OpenCode's question tool, as the asking model wrote it. */
|
|
11
|
+
export interface Prompt {
|
|
12
|
+
readonly question: string;
|
|
13
|
+
readonly header: string;
|
|
14
|
+
readonly options: ReadonlyArray<{
|
|
15
|
+
readonly label: string;
|
|
16
|
+
readonly description: string;
|
|
17
|
+
}>;
|
|
18
|
+
readonly multiple?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** The answers to a question call, as the question tool returns them: one list per question. */
|
|
21
|
+
export type Answers = string[][];
|
|
22
|
+
/** A question a spawned session asked with its question tool, stored until it is answered. */
|
|
23
|
+
export interface Asked {
|
|
24
|
+
readonly requestID: string;
|
|
25
|
+
readonly sessionID: string;
|
|
26
|
+
/** The session told, at the top of the sessions started with courier_spawn; it alone answers. */
|
|
27
|
+
readonly top: string;
|
|
28
|
+
readonly title: string;
|
|
29
|
+
/** The session that started the asking one, when that is not the top session itself. */
|
|
30
|
+
readonly startedBy?: string;
|
|
31
|
+
readonly questions: ReadonlyArray<Prompt>;
|
|
32
|
+
readonly askedAt: number;
|
|
33
|
+
}
|
|
34
|
+
/** How a question was settled without the top session: in the asking session, or not at all. */
|
|
35
|
+
export type Elsewhere = {
|
|
36
|
+
readonly by: "child";
|
|
37
|
+
readonly answers: Answers;
|
|
38
|
+
} | {
|
|
39
|
+
readonly by: "dismissed";
|
|
40
|
+
} | {
|
|
41
|
+
readonly by: "failed";
|
|
42
|
+
readonly error: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Timings, changed by the tests: how long a question cut off by a closing location waits before an
|
|
46
|
+
* instance still loaded tells its top session, how long an answer waits for another one to it that
|
|
47
|
+
* is still being passed on, and how long what follows a call's end waits for the notice of the
|
|
48
|
+
* question to go out.
|
|
49
|
+
*/
|
|
50
|
+
export declare const timing: {
|
|
51
|
+
closingGraceMs: number;
|
|
52
|
+
passingWaitMs: number;
|
|
53
|
+
relayWaitMs: number;
|
|
54
|
+
};
|
|
55
|
+
export interface QuestionPorts {
|
|
56
|
+
readonly storage: RosterStorage;
|
|
57
|
+
readonly session: Pick<Context["session"], "synthetic">;
|
|
58
|
+
readonly now: () => number;
|
|
59
|
+
readonly newID: () => string;
|
|
60
|
+
readonly log: (message: string) => void;
|
|
61
|
+
}
|
|
62
|
+
/** Whether a request id is a question's rather than a permission request's. */
|
|
63
|
+
export declare const isQuestion: (requestID: string) => boolean;
|
|
64
|
+
/** What OpenCode's question tool tells the asking model once it has the answers. */
|
|
65
|
+
export declare function answeredText(questions: ReadonlyArray<Prompt>, answers: ReadonlyArray<ReadonlyArray<string>>): string;
|
|
66
|
+
declare const CUT_OFF: {
|
|
67
|
+
stopped: string;
|
|
68
|
+
restarted: string;
|
|
69
|
+
};
|
|
70
|
+
/** What the top session is told about a question, when it is asked or after its call was cut off. */
|
|
71
|
+
export declare function questionNotice(asked: Asked, cutOff?: keyof typeof CUT_OFF): string;
|
|
72
|
+
/** What the top session is told about a question settled without it. */
|
|
73
|
+
export declare function settledNotice(asked: Asked, how: Elsewhere): string;
|
|
74
|
+
export interface QuestionAnswerInput {
|
|
75
|
+
readonly sessionID: string;
|
|
76
|
+
readonly requestID: string;
|
|
77
|
+
/** One entry per question: a label or the text the person gave, or a list of them. */
|
|
78
|
+
readonly answers: ReadonlyArray<string | ReadonlyArray<string>>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Answers a question of a session started, directly or through others, from the caller, which must
|
|
82
|
+
* be the session at the top, as for permission requests. `answered` is false when it no longer waits.
|
|
83
|
+
*/
|
|
84
|
+
export declare function answerQuestion(ports: QuestionPorts, callerID: string, input: QuestionAnswerInput): Promise<{
|
|
85
|
+
sessionID: string;
|
|
86
|
+
requestID: string;
|
|
87
|
+
answered: boolean;
|
|
88
|
+
by?: undefined;
|
|
89
|
+
answers?: undefined;
|
|
90
|
+
} | {
|
|
91
|
+
sessionID: string;
|
|
92
|
+
requestID: string;
|
|
93
|
+
answered: boolean;
|
|
94
|
+
by: "message" | "result";
|
|
95
|
+
answers: Answers;
|
|
96
|
+
}>;
|
|
97
|
+
/** The questions a session waits on, for courier_status; `stopped` when its call was cut off. */
|
|
98
|
+
export declare function pendingQuestions(storage: RosterStorage, sessionID: string): Promise<{
|
|
99
|
+
type: "question";
|
|
100
|
+
requestID: string;
|
|
101
|
+
questions: Prompt[];
|
|
102
|
+
stopped?: true;
|
|
103
|
+
}[]>;
|
|
104
|
+
/**
|
|
105
|
+
* On loading: drops stored questions that are too old, whose session is no longer on a roster, or
|
|
106
|
+
* beyond the newest `MAX_STORED`, and tells the top session about the rest, which a restart cut off.
|
|
107
|
+
*/
|
|
108
|
+
export declare function noticeCutOff(ports: QuestionPorts): Promise<void>;
|
|
109
|
+
/** A plugin instance whose ports the relay may use, until the returned function is called. */
|
|
110
|
+
export declare function joinRelay(ports: QuestionPorts): () => undefined;
|
|
111
|
+
/** Called for OpenCode's `form.created`: a question call's form is shown, so its question can be relayed. */
|
|
112
|
+
export declare function formShown(event: {
|
|
113
|
+
readonly data: {
|
|
114
|
+
readonly form: {
|
|
115
|
+
readonly sessionID: string;
|
|
116
|
+
readonly metadata?: unknown;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
}): void;
|
|
120
|
+
/**
|
|
121
|
+
* Called when an event stream may have missed forms being shown: every call still waiting for its
|
|
122
|
+
* form is taken as shown. One still waiting for its permission check is relayed early, which is the
|
|
123
|
+
* lesser harm.
|
|
124
|
+
*/
|
|
125
|
+
export declare function formsMayHaveBeenMissed(): void;
|
|
126
|
+
/**
|
|
127
|
+
* Called when an instance starts following OpenCode's events. Every instance is sent every event,
|
|
128
|
+
* so a form shown is missed only while none follows them; then the calls waiting are released, and
|
|
129
|
+
* true is returned, for the caller to release them again on its first event, once it is connected.
|
|
130
|
+
*/
|
|
131
|
+
export declare function eventsFollowed(): boolean;
|
|
132
|
+
/** Called when an instance's event stream ended or broke. */
|
|
133
|
+
export declare function eventsLeft(): void;
|
|
134
|
+
/** Wraps OpenCode's question tool for the relay. A tool by that id that is missing is left alone. */
|
|
135
|
+
export declare function relayQuestions(host: Pick<EffectPlugin.Context, "tool">, ports: () => QuestionPorts | undefined): Effect.Effect<import("@opencode-ai/plugin/effect/registration").Registration, never, import("effect/Scope").Scope>;
|
|
136
|
+
/** For tests: forgets every question this process knows. */
|
|
137
|
+
export declare function forgetQuestions(): void;
|
|
138
|
+
export {};
|