@aicalas/loopy 0.1.0
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 +101 -0
- package/dist/adapters.d.ts +111 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +27 -0
- package/dist/adapters.js.map +1 -0
- package/dist/attention/github.d.ts +57 -0
- package/dist/attention/github.d.ts.map +1 -0
- package/dist/attention/github.js +162 -0
- package/dist/attention/github.js.map +1 -0
- package/dist/authoring/attention-config.d.ts +16 -0
- package/dist/authoring/attention-config.d.ts.map +1 -0
- package/dist/authoring/attention-config.js +19 -0
- package/dist/authoring/attention-config.js.map +1 -0
- package/dist/authoring/channel-config.d.ts +16 -0
- package/dist/authoring/channel-config.d.ts.map +1 -0
- package/dist/authoring/channel-config.js +16 -0
- package/dist/authoring/channel-config.js.map +1 -0
- package/dist/authoring/define.d.ts +13 -0
- package/dist/authoring/define.d.ts.map +1 -0
- package/dist/authoring/define.js +13 -0
- package/dist/authoring/define.js.map +1 -0
- package/dist/authoring/effect-config.d.ts +16 -0
- package/dist/authoring/effect-config.d.ts.map +1 -0
- package/dist/authoring/effect-config.js +17 -0
- package/dist/authoring/effect-config.js.map +1 -0
- package/dist/authoring/harness-config.d.ts +30 -0
- package/dist/authoring/harness-config.d.ts.map +1 -0
- package/dist/authoring/harness-config.js +36 -0
- package/dist/authoring/harness-config.js.map +1 -0
- package/dist/authoring/index.d.ts +10 -0
- package/dist/authoring/index.d.ts.map +1 -0
- package/dist/authoring/index.js +9 -0
- package/dist/authoring/index.js.map +1 -0
- package/dist/authoring/schema.d.ts +9 -0
- package/dist/authoring/schema.d.ts.map +1 -0
- package/dist/authoring/schema.js +28 -0
- package/dist/authoring/schema.js.map +1 -0
- package/dist/authoring/types.d.ts +115 -0
- package/dist/authoring/types.d.ts.map +1 -0
- package/dist/authoring/types.js +2 -0
- package/dist/authoring/types.js.map +1 -0
- package/dist/authoring/watcher-config.d.ts +33 -0
- package/dist/authoring/watcher-config.d.ts.map +1 -0
- package/dist/authoring/watcher-config.js +61 -0
- package/dist/authoring/watcher-config.js.map +1 -0
- package/dist/build/discover.d.ts +34 -0
- package/dist/build/discover.d.ts.map +1 -0
- package/dist/build/discover.js +165 -0
- package/dist/build/discover.js.map +1 -0
- package/dist/build/identity.d.ts +9 -0
- package/dist/build/identity.d.ts.map +1 -0
- package/dist/build/identity.js +0 -0
- package/dist/build/identity.js.map +1 -0
- package/dist/channels/github.d.ts +14 -0
- package/dist/channels/github.d.ts.map +1 -0
- package/dist/channels/github.js +118 -0
- package/dist/channels/github.js.map +1 -0
- package/dist/channels/index.d.ts +2 -0
- package/dist/channels/index.d.ts.map +1 -0
- package/dist/channels/index.js +2 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/cli-help.d.ts +23 -0
- package/dist/cli-help.d.ts.map +1 -0
- package/dist/cli-help.js +186 -0
- package/dist/cli-help.js.map +1 -0
- package/dist/cli.d.ts +37 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +385 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +71 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +426 -0
- package/dist/config.js.map +1 -0
- package/dist/core/calls.d.ts +67 -0
- package/dist/core/calls.d.ts.map +1 -0
- package/dist/core/calls.js +109 -0
- package/dist/core/calls.js.map +1 -0
- package/dist/core/identifiers.d.ts +24 -0
- package/dist/core/identifiers.d.ts.map +1 -0
- package/dist/core/identifiers.js +129 -0
- package/dist/core/identifiers.js.map +1 -0
- package/dist/core/prompt.d.ts +5 -0
- package/dist/core/prompt.d.ts.map +1 -0
- package/dist/core/prompt.js +47 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/reconcile.d.ts +27 -0
- package/dist/core/reconcile.d.ts.map +1 -0
- package/dist/core/reconcile.js +36 -0
- package/dist/core/reconcile.js.map +1 -0
- package/dist/core/wire.d.ts +332 -0
- package/dist/core/wire.d.ts.map +1 -0
- package/dist/core/wire.js +543 -0
- package/dist/core/wire.js.map +1 -0
- package/dist/emitters/github.d.ts +15 -0
- package/dist/emitters/github.d.ts.map +1 -0
- package/dist/emitters/github.js +43 -0
- package/dist/emitters/github.js.map +1 -0
- package/dist/emitters/index.d.ts +2 -0
- package/dist/emitters/index.d.ts.map +1 -0
- package/dist/emitters/index.js +2 -0
- package/dist/emitters/index.js.map +1 -0
- package/dist/git.d.ts +17 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +122 -0
- package/dist/git.js.map +1 -0
- package/dist/github/client.d.ts +53 -0
- package/dist/github/client.d.ts.map +1 -0
- package/dist/github/client.js +169 -0
- package/dist/github/client.js.map +1 -0
- package/dist/github/trigger.d.ts +12 -0
- package/dist/github/trigger.d.ts.map +1 -0
- package/dist/github/trigger.js +21 -0
- package/dist/github/trigger.js.map +1 -0
- package/dist/github/writes.d.ts +4 -0
- package/dist/github/writes.d.ts.map +1 -0
- package/dist/github/writes.js +21 -0
- package/dist/github/writes.js.map +1 -0
- package/dist/harnesses/base.d.ts +41 -0
- package/dist/harnesses/base.d.ts.map +1 -0
- package/dist/harnesses/base.js +182 -0
- package/dist/harnesses/base.js.map +1 -0
- package/dist/harnesses/claude-executable.d.ts +42 -0
- package/dist/harnesses/claude-executable.d.ts.map +1 -0
- package/dist/harnesses/claude-executable.js +138 -0
- package/dist/harnesses/claude-executable.js.map +1 -0
- package/dist/harnesses/claude.d.ts +35 -0
- package/dist/harnesses/claude.d.ts.map +1 -0
- package/dist/harnesses/claude.js +160 -0
- package/dist/harnesses/claude.js.map +1 -0
- package/dist/harnesses/codex.d.ts +40 -0
- package/dist/harnesses/codex.d.ts.map +1 -0
- package/dist/harnesses/codex.js +118 -0
- package/dist/harnesses/codex.js.map +1 -0
- package/dist/harnesses/index.d.ts +2 -0
- package/dist/harnesses/index.d.ts.map +1 -0
- package/dist/harnesses/index.js +2 -0
- package/dist/harnesses/index.js.map +1 -0
- package/dist/harnesses/opencode.d.ts +33 -0
- package/dist/harnesses/opencode.d.ts.map +1 -0
- package/dist/harnesses/opencode.js +203 -0
- package/dist/harnesses/opencode.js.map +1 -0
- package/dist/identifiers.d.ts +26 -0
- package/dist/identifiers.d.ts.map +1 -0
- package/dist/identifiers.js +62 -0
- package/dist/identifiers.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts +10 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +44 -0
- package/dist/log.js.map +1 -0
- package/dist/settings.d.ts +43 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +128 -0
- package/dist/settings.js.map +1 -0
- package/dist/temporal/activities.d.ts +57 -0
- package/dist/temporal/activities.d.ts.map +1 -0
- package/dist/temporal/activities.js +366 -0
- package/dist/temporal/activities.js.map +1 -0
- package/dist/temporal/answers.d.ts +48 -0
- package/dist/temporal/answers.d.ts.map +1 -0
- package/dist/temporal/answers.js +78 -0
- package/dist/temporal/answers.js.map +1 -0
- package/dist/temporal/client.d.ts +13 -0
- package/dist/temporal/client.d.ts.map +1 -0
- package/dist/temporal/client.js +20 -0
- package/dist/temporal/client.js.map +1 -0
- package/dist/temporal/contracts.d.ts +19 -0
- package/dist/temporal/contracts.d.ts.map +1 -0
- package/dist/temporal/contracts.js +22 -0
- package/dist/temporal/contracts.js.map +1 -0
- package/dist/temporal/drain.d.ts +19 -0
- package/dist/temporal/drain.d.ts.map +1 -0
- package/dist/temporal/drain.js +109 -0
- package/dist/temporal/drain.js.map +1 -0
- package/dist/temporal/executions.d.ts +18 -0
- package/dist/temporal/executions.d.ts.map +1 -0
- package/dist/temporal/executions.js +15 -0
- package/dist/temporal/executions.js.map +1 -0
- package/dist/temporal/handle.d.ts +39 -0
- package/dist/temporal/handle.d.ts.map +1 -0
- package/dist/temporal/handle.js +95 -0
- package/dist/temporal/handle.js.map +1 -0
- package/dist/temporal/history.d.ts +75 -0
- package/dist/temporal/history.d.ts.map +1 -0
- package/dist/temporal/history.js +310 -0
- package/dist/temporal/history.js.map +1 -0
- package/dist/temporal/observe.d.ts +85 -0
- package/dist/temporal/observe.d.ts.map +1 -0
- package/dist/temporal/observe.js +110 -0
- package/dist/temporal/observe.js.map +1 -0
- package/dist/temporal/schedules.d.ts +26 -0
- package/dist/temporal/schedules.d.ts.map +1 -0
- package/dist/temporal/schedules.js +200 -0
- package/dist/temporal/schedules.js.map +1 -0
- package/dist/temporal/status.d.ts +63 -0
- package/dist/temporal/status.d.ts.map +1 -0
- package/dist/temporal/status.js +153 -0
- package/dist/temporal/status.js.map +1 -0
- package/dist/temporal/stuck.d.ts +58 -0
- package/dist/temporal/stuck.d.ts.map +1 -0
- package/dist/temporal/stuck.js +53 -0
- package/dist/temporal/stuck.js.map +1 -0
- package/dist/temporal/supervisor.d.ts +11 -0
- package/dist/temporal/supervisor.d.ts.map +1 -0
- package/dist/temporal/supervisor.js +506 -0
- package/dist/temporal/supervisor.js.map +1 -0
- package/dist/temporal/worker.d.ts +21 -0
- package/dist/temporal/worker.d.ts.map +1 -0
- package/dist/temporal/worker.js +82 -0
- package/dist/temporal/worker.js.map +1 -0
- package/dist/temporal/workflow-bundle.js +12742 -0
- package/dist/temporal/workflows.d.ts +9 -0
- package/dist/temporal/workflows.d.ts.map +1 -0
- package/dist/temporal/workflows.js +144 -0
- package/dist/temporal/workflows.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/dist/watchers/base.d.ts +4 -0
- package/dist/watchers/base.d.ts.map +1 -0
- package/dist/watchers/base.js +7 -0
- package/dist/watchers/base.js.map +1 -0
- package/dist/watchers/github/client.d.ts +52 -0
- package/dist/watchers/github/client.d.ts.map +1 -0
- package/dist/watchers/github/client.js +165 -0
- package/dist/watchers/github/client.js.map +1 -0
- package/dist/watchers/github/index.d.ts +19 -0
- package/dist/watchers/github/index.d.ts.map +1 -0
- package/dist/watchers/github/index.js +83 -0
- package/dist/watchers/github/index.js.map +1 -0
- package/dist/watchers/index.d.ts +2 -0
- package/dist/watchers/index.d.ts.map +1 -0
- package/dist/watchers/index.js +2 -0
- package/dist/watchers/index.js.map +1 -0
- package/dist/worker-lock.d.ts +11 -0
- package/dist/worker-lock.d.ts.map +1 -0
- package/dist/worker-lock.js +53 -0
- package/dist/worker-lock.js.map +1 -0
- package/package.json +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 shyam-sadeesh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# loopy
|
|
2
|
+
|
|
3
|
+
Label a GitHub issue or PR, get a coding agent run against it. You write the workflow as a TypeScript function; loopy polls for the trigger, claims the label, provisions a git worktree, runs the agent, validates its structured output, and keeps the whole orchestration durable in Temporal.
|
|
4
|
+
|
|
5
|
+
Design: [`ARCHITECTURE.md`](ARCHITECTURE.md). Operating it: `loopy guide`.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Needs Node.js 24 and `git`.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install --global @aicalas/loopy
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
That installs the `loopy` command on your PATH.
|
|
16
|
+
|
|
17
|
+
Workflows can live in your own project: add loopy there (`pnpm add @aicalas/loopy`) so they can import `@aicalas/loopy/workflow`, and point `project_directory` at it.
|
|
18
|
+
|
|
19
|
+
## Run
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
cp config.example.toml ~/.config/loopy/config.toml # set repository and both task queue names
|
|
23
|
+
export GITHUB_TOKEN=…
|
|
24
|
+
make temporal-dev # or point [temporal] at your own Service
|
|
25
|
+
loopy loop
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`loopy loop` discovers every module under `workflows/`, bundles them, and schedules one poller each. Bundling happens once per process - restart to deploy a workflow edit. `loopy status` shows what each instance is waiting on.
|
|
29
|
+
|
|
30
|
+
## Workflows
|
|
31
|
+
|
|
32
|
+
One file under `workflows/` is one workflow. No spec language, no register step: discovery is registration. Abridged from [`workflows/review.ts`](workflows/review.ts):
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
export default defineWorkflow({
|
|
36
|
+
name: "review",
|
|
37
|
+
watcher: githubPullRequests({
|
|
38
|
+
repository: "owner/repo",
|
|
39
|
+
label: "agent:review",
|
|
40
|
+
onStart: { add: ["agent:reviewing"] },
|
|
41
|
+
}),
|
|
42
|
+
attention: githubAttention({ target: "trigger" }),
|
|
43
|
+
async run(ctx) {
|
|
44
|
+
const reviewer = ctx.agent("reviewer", claude({ model: "claude-opus-4-8", effort: "high" }));
|
|
45
|
+
let outcome = await reviewer.run({
|
|
46
|
+
output: review, // Zod schema: { summary, blockers, done }
|
|
47
|
+
prompt: [promptFile("prompts/review.md"), `Pull request #${ctx.trigger.id}`],
|
|
48
|
+
});
|
|
49
|
+
for (let round = 0; round < 2 && !outcome.done; round += 1) {
|
|
50
|
+
outcome = await reviewer.run({
|
|
51
|
+
output: review,
|
|
52
|
+
prompt: ["Resolve the blockers you reported, then report again.", ...outcome.blockers],
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
await ctx.effect(
|
|
56
|
+
"mark-reviewed",
|
|
57
|
+
githubLabels({
|
|
58
|
+
repository: ctx.trigger.repository,
|
|
59
|
+
issue: triggerIssue(ctx.trigger),
|
|
60
|
+
remove: ["agent:reviewing"],
|
|
61
|
+
add: ["agent:reviewed"],
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
64
|
+
return { summary: outcome.summary };
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Per matching PR, once: claim `agent:review` before `run` starts, review, loop until the agent reports `done`, relabel, return. The agent handle holds one session and one worktree, so later calls resume where the first stopped. `ctx.effect` runs at most once per id. Halts, parks, and stalls go to the attention adapter.
|
|
70
|
+
|
|
71
|
+
## Scheduled workflows
|
|
72
|
+
|
|
73
|
+
A workflow declares exactly one intake: a GitHub `watcher`, or a Temporal `schedule`. Scheduled workflows start directly at their configured cron or interval and may omit `attention`; when they do declare GitHub attention, use a fixed issue rather than `target: "trigger"`.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
export default defineWorkflow({
|
|
77
|
+
name: "nightly-maintenance",
|
|
78
|
+
schedule: { cron: "0 2 * * *", timezone: "UTC" },
|
|
79
|
+
async run(ctx) {
|
|
80
|
+
// ctx.trigger identifies this as source: "schedule".
|
|
81
|
+
return { complete: true };
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`overlap` defaults to `"SKIP"`; `BUFFER_ONE`, `BUFFER_ALL`, `CANCEL_OTHER`, `TERMINATE_OTHER`, and `ALLOW_ALL` are also available. Loopy retains a lightweight control tick for scheduled workflows so status inspection, stuck detection, and `ctx.ask` reply delivery continue to work.
|
|
87
|
+
|
|
88
|
+
## Adapters
|
|
89
|
+
|
|
90
|
+
Factories from `@aicalas/loopy/workflow`. Each takes its own repository, target, and credentials rather than inheriting them, so a workflow can poll one repository and work in another.
|
|
91
|
+
|
|
92
|
+
| Kind | Factories | Role |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| Watcher | `githubIssues`, `githubPullRequests` | Poll a repository for a label; claim each match. |
|
|
95
|
+
| Harness | `claude`, `codex`, `opencode` | The agent behind `ctx.agent(id, harness)`. |
|
|
96
|
+
| Attention | `githubAttention` | Report halted, parked, stuck, and awaiting-answer instances. |
|
|
97
|
+
| Effect | `githubLabels` | Idempotent writes via `ctx.effect(id, effect)`. |
|
|
98
|
+
| Channel | `githubComments` | Where `ctx.ask(id, channel, request)` waits for a human. |
|
|
99
|
+
| Prompt | `promptFile` | A prompt segment read from disk. |
|
|
100
|
+
|
|
101
|
+
`output` takes any Standard JSON Schema validator (Zod 4, Valibot, ArkType) or a literal JSON Schema.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { ZodType } from "zod";
|
|
2
|
+
import type { AttentionEmitResult, AttentionEvent, ChannelPollResult, DeliverQuestionResult, EffectResult, JsonObject, JsonValue, TriggerCandidate } from "./core/wire.js";
|
|
3
|
+
export interface HarnessContext {
|
|
4
|
+
agentId: string;
|
|
5
|
+
prompt: string;
|
|
6
|
+
workspace: string;
|
|
7
|
+
schema: JsonObject;
|
|
8
|
+
/** Continue this provider session instead of starting a new one. */
|
|
9
|
+
resumeSessionId?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface HarnessResult {
|
|
12
|
+
value: JsonValue;
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
usage?: JsonObject;
|
|
15
|
+
}
|
|
16
|
+
export interface Harness {
|
|
17
|
+
run(context: HarnessContext, signal?: AbortSignal): Promise<HarnessResult>;
|
|
18
|
+
}
|
|
19
|
+
export interface HarnessSpec {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly optionsSchema: ZodType;
|
|
22
|
+
create(options: unknown): Harness;
|
|
23
|
+
checkStartup?(): string | undefined | Promise<string | undefined>;
|
|
24
|
+
}
|
|
25
|
+
export interface FetchContext {
|
|
26
|
+
/** The watcher reads its target repository from its own `options`, not from ambient context. */
|
|
27
|
+
options: unknown;
|
|
28
|
+
}
|
|
29
|
+
/** A source-local match; the Activity stamps the registered source and identity digest before persistence. */
|
|
30
|
+
export type WatcherCandidate = Omit<TriggerCandidate, "source" | "digest">;
|
|
31
|
+
export interface WatcherSpec {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly source: string;
|
|
34
|
+
readonly optionsSchema: ZodType;
|
|
35
|
+
fetch(context: FetchContext): Promise<WatcherCandidate[]>;
|
|
36
|
+
checkStartup?(): string | undefined | Promise<string | undefined>;
|
|
37
|
+
}
|
|
38
|
+
export interface EmitterContext {
|
|
39
|
+
/** Every input the emitter needs - repository, target, credential-source, and payload - is declared here. */
|
|
40
|
+
action: unknown;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A failure no retry can fix: the target is gone or the request is invalid as issued. An emitter
|
|
44
|
+
* throws this to fail its Activity Execution non-retryably; any other exception is retried under
|
|
45
|
+
* the Activity's policy, because a human can usually make it succeed.
|
|
46
|
+
*/
|
|
47
|
+
export declare class EmitterPermanentError extends Error {
|
|
48
|
+
}
|
|
49
|
+
export interface EmitterSpec {
|
|
50
|
+
readonly name: string;
|
|
51
|
+
readonly actionSchema: ZodType;
|
|
52
|
+
emit(context: EmitterContext): Promise<EffectResult>;
|
|
53
|
+
checkStartup?(): string | undefined | Promise<string | undefined>;
|
|
54
|
+
}
|
|
55
|
+
export interface AttentionEmitterContext {
|
|
56
|
+
/** The adapter's declared route and credentials; the adapter validates and resolves them. */
|
|
57
|
+
options: unknown;
|
|
58
|
+
trigger: TriggerCandidate;
|
|
59
|
+
event: AttentionEvent;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Surfaces engine-owned attention events - human-actionable workflow states - to an external
|
|
63
|
+
* channel. Separate from `EmitterSpec` because attention emission is operational reporting the
|
|
64
|
+
* engine decides on, not a workflow-authored effect: it takes a normalized event, must be safe to
|
|
65
|
+
* re-emit (`skipped` says the event is already surfaced), and is never addressed by user code.
|
|
66
|
+
*
|
|
67
|
+
* The engine selects the adapter and passes its declaration, trigger, and normalized event once.
|
|
68
|
+
* The adapter owns validation and destination resolution, so the engine never handles an
|
|
69
|
+
* adapter-specific target or relies on paired adapter methods.
|
|
70
|
+
*/
|
|
71
|
+
export interface AttentionEmitterSpec {
|
|
72
|
+
readonly name: string;
|
|
73
|
+
readonly optionsSchema: ZodType;
|
|
74
|
+
emit(context: AttentionEmitterContext): Promise<AttentionEmitResult>;
|
|
75
|
+
checkStartup?(): string | undefined | Promise<string | undefined>;
|
|
76
|
+
}
|
|
77
|
+
export interface ChannelDeliverContext {
|
|
78
|
+
/** The adapter's declared inputs (repository, issue, credentials); the adapter validates them. */
|
|
79
|
+
options: unknown;
|
|
80
|
+
/** Identity of the asking instance and call; the adapter derives its reply token and dedup marker from these. */
|
|
81
|
+
workflowId: string;
|
|
82
|
+
callId: string;
|
|
83
|
+
/** The rendered prompt text; the adapter composes the human-facing question around it. */
|
|
84
|
+
question: string;
|
|
85
|
+
}
|
|
86
|
+
export interface ChannelPollContext {
|
|
87
|
+
/** The adapter-owned correlation `deliver` returned; only the adapter decodes it. */
|
|
88
|
+
correlation: JsonValue;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* One channel a workflow can ask a human over. The adapter owns both outbound operations - `deliver`
|
|
92
|
+
* sends the question and returns opaque correlation, `poll` reads a reply back - so no channel needs
|
|
93
|
+
* an inbound route into loopy. It is configured explicitly (its repository, target, and credentials
|
|
94
|
+
* are its own declared inputs, populated by the author from `ctx`) and reads nothing ambient.
|
|
95
|
+
*/
|
|
96
|
+
export interface ChannelAdapterSpec {
|
|
97
|
+
readonly name: string;
|
|
98
|
+
readonly optionsSchema: ZodType;
|
|
99
|
+
deliver(context: ChannelDeliverContext): Promise<DeliverQuestionResult>;
|
|
100
|
+
poll(context: ChannelPollContext): Promise<ChannelPollResult>;
|
|
101
|
+
checkStartup?(): string | undefined | Promise<string | undefined>;
|
|
102
|
+
}
|
|
103
|
+
export interface AdapterRegistries {
|
|
104
|
+
readonly harnesses: ReadonlyMap<string, HarnessSpec>;
|
|
105
|
+
readonly watchers: ReadonlyMap<string, WatcherSpec>;
|
|
106
|
+
readonly emitters: ReadonlyMap<string, EmitterSpec>;
|
|
107
|
+
readonly attentionEmitters: ReadonlyMap<string, AttentionEmitterSpec>;
|
|
108
|
+
readonly channels: ReadonlyMap<string, ChannelAdapterSpec>;
|
|
109
|
+
}
|
|
110
|
+
export declare function createAdapterRegistries(): AdapterRegistries;
|
|
111
|
+
//# sourceMappingURL=adapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
|
package/dist/adapters.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { gitHubAttentionEmitter } from "./attention/github.js";
|
|
2
|
+
import { gitHubCommentsChannel } from "./channels/index.js";
|
|
3
|
+
import { gitHubLabelsEmitter } from "./emitters/github.js";
|
|
4
|
+
import { claudeHarnessSpec } from "./harnesses/claude.js";
|
|
5
|
+
import { codexHarnessSpec } from "./harnesses/codex.js";
|
|
6
|
+
import { openCodeHarnessSpec } from "./harnesses/opencode.js";
|
|
7
|
+
import { gitHubIssueWatcher, gitHubPullRequestWatcher } from "./watchers/github/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* A failure no retry can fix: the target is gone or the request is invalid as issued. An emitter
|
|
10
|
+
* throws this to fail its Activity Execution non-retryably; any other exception is retried under
|
|
11
|
+
* the Activity's policy, because a human can usually make it succeed.
|
|
12
|
+
*/
|
|
13
|
+
export class EmitterPermanentError extends Error {
|
|
14
|
+
}
|
|
15
|
+
export function createAdapterRegistries() {
|
|
16
|
+
return {
|
|
17
|
+
harnesses: byName([claudeHarnessSpec, codexHarnessSpec, openCodeHarnessSpec]),
|
|
18
|
+
watchers: byName([gitHubPullRequestWatcher, gitHubIssueWatcher]),
|
|
19
|
+
emitters: byName([gitHubLabelsEmitter]),
|
|
20
|
+
attentionEmitters: byName([gitHubAttentionEmitter]),
|
|
21
|
+
channels: byName([gitHubCommentsChannel]),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function byName(values) {
|
|
25
|
+
return new Map(values.map((value) => [value.name, value]));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAW5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAiD1F;;;;GAIG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;CAAG;AAsEnD,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,CAAC,iBAAiB,EAAE,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;QAC7E,QAAQ,EAAE,MAAM,CAAC,CAAC,wBAAwB,EAAE,kBAAkB,CAAC,CAAC;QAChE,QAAQ,EAAE,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC;QACvC,iBAAiB,EAAE,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC;QACnD,QAAQ,EAAE,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC;KAC1C,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAsC,MAAoB;IACvE,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { AttentionEmitterContext, AttentionEmitterSpec } from "../adapters.js";
|
|
3
|
+
import type { AttentionEmitResult, AttentionEvent, AttentionKind, TriggerCandidate } from "../core/wire.js";
|
|
4
|
+
import { GitHubClient } from "../github/client.js";
|
|
5
|
+
/**
|
|
6
|
+
* The kinds this adapter renders an artifact for. `awaiting_answer` is deliberately excluded: the
|
|
7
|
+
* ask's own question comment is the human-facing surface, so no label and no attention comment go on
|
|
8
|
+
* the target. The attention *event* still fires, so an off-GitHub route can still ping on it.
|
|
9
|
+
*/
|
|
10
|
+
type SurfacedAttentionKind = Exclude<AttentionKind, "awaiting_answer">;
|
|
11
|
+
/** The label family this adapter owns when a destination opts into state labels. */
|
|
12
|
+
export declare const ATTENTION_LABELS: Readonly<Record<SurfacedAttentionKind, string>>;
|
|
13
|
+
/**
|
|
14
|
+
* The concrete destination an emit writes to, resolved from the declared route. `labels` is true
|
|
15
|
+
* only when this is the trigger's own surface, which a fixed aggregation sink never is.
|
|
16
|
+
*/
|
|
17
|
+
export interface ResolvedAttentionTarget {
|
|
18
|
+
repository: string;
|
|
19
|
+
issue: number;
|
|
20
|
+
labels: boolean;
|
|
21
|
+
credentials: "env";
|
|
22
|
+
}
|
|
23
|
+
export type GitHubAttentionClientFactory = (repository: string, credentials: "env") => GitHubClient;
|
|
24
|
+
/**
|
|
25
|
+
* The declared route: `trigger` follows the instance's own trigger, `fixed` names an aggregation
|
|
26
|
+
* issue. `labels` applies only to the trigger route, so the union rejects it on the fixed one, and
|
|
27
|
+
* the credential source is declared rather than inherited from the process.
|
|
28
|
+
*/
|
|
29
|
+
export declare const gitHubAttentionOptionsSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
30
|
+
target: z.ZodLiteral<"trigger">;
|
|
31
|
+
labels: z.ZodDefault<z.ZodBoolean>;
|
|
32
|
+
credentials: z.ZodDefault<z.ZodLiteral<"env">>;
|
|
33
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
34
|
+
target: z.ZodLiteral<"fixed">;
|
|
35
|
+
repository: z.ZodString;
|
|
36
|
+
issue: z.ZodNumber;
|
|
37
|
+
credentials: z.ZodDefault<z.ZodLiteral<"env">>;
|
|
38
|
+
}, z.core.$strict>]>;
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the declared route against the instance's trigger: the trigger is passed in explicitly
|
|
41
|
+
* and only its repository and issue number survive into the concrete target, which is all `emit`
|
|
42
|
+
* ever sees.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveGitHubAttentionTarget(options: unknown, trigger: TriggerCandidate): ResolvedAttentionTarget;
|
|
45
|
+
export declare function emitGitHubAttention(context: AttentionEmitterContext, clientFactory?: GitHubAttentionClientFactory): Promise<AttentionEmitResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Deduplication key rendered as an invisible HTML comment: a matching marker on any existing
|
|
48
|
+
* comment means this event is already surfaced. `stuck` is level-triggered - the observer
|
|
49
|
+
* re-reports the same condition every poll tick with a fresh timestamp - so its key drops
|
|
50
|
+
* `occurredAt` and one stuck Run gets one comment. The other kinds are edge-triggered, emitted once
|
|
51
|
+
* per event with a timestamp that is stable across Activity retries, so `occurredAt` stays in the
|
|
52
|
+
* key and each re-park of one call is surfaced as the new event it is.
|
|
53
|
+
*/
|
|
54
|
+
export declare function attentionMarker(event: AttentionEvent): string;
|
|
55
|
+
export declare const gitHubAttentionEmitter: AttentionEmitterSpec;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/attention/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACpF,OAAO,KAAK,EACV,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAA4B,YAAY,EAAsB,MAAM,qBAAqB,CAAC;AAKjG;;;;GAIG;AACH,KAAK,qBAAqB,GAAG,OAAO,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;AAEvE,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAI5E,CAAC;AAuBF;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,KAAK,CAAC;CACpB;AAED,MAAM,MAAM,4BAA4B,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,KAAK,YAAY,CAAC;AAIpG;;;;GAIG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;oBAgBvC,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,gBAAgB,GACxB,uBAAuB,CAsBzB;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,uBAAuB,EAChC,aAAa,GAAE,4BAAmD,GACjE,OAAO,CAAC,mBAAmB,CAAC,CA6B9B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAU7D;AA6BD,eAAO,MAAM,sBAAsB,EAAE,oBAKpC,CAAC"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { authenticationDiagnostic, GitHubClient, REPOSITORY_PATTERN } from "../github/client.js";
|
|
3
|
+
import { triggerNumber } from "../github/trigger.js";
|
|
4
|
+
import { classifyGitHubWriteError, sameLabels } from "../github/writes.js";
|
|
5
|
+
import { sha256 } from "../identifiers.js";
|
|
6
|
+
/** The label family this adapter owns when a destination opts into state labels. */
|
|
7
|
+
export const ATTENTION_LABELS = {
|
|
8
|
+
halted: "loopy:halted",
|
|
9
|
+
awaiting_reconciliation: "loopy:awaiting-reconciliation",
|
|
10
|
+
stuck: "loopy:stuck",
|
|
11
|
+
};
|
|
12
|
+
/** Repository-level label definitions, provisioned on first use rather than expected as setup. */
|
|
13
|
+
const LABEL_STYLES = {
|
|
14
|
+
halted: { color: "b60205", description: "loopy: an expected failure closed this instance" },
|
|
15
|
+
awaiting_reconciliation: {
|
|
16
|
+
color: "fbca04",
|
|
17
|
+
description: "loopy: parked on an ambiguous agent call; operator resolution needed",
|
|
18
|
+
},
|
|
19
|
+
stuck: { color: "d93f0b", description: "loopy: workflow code is failing Workflow Tasks" },
|
|
20
|
+
};
|
|
21
|
+
const KIND_EXPLANATIONS = {
|
|
22
|
+
halted: "An expected operation failure closed this instance and cleanup ran. Read the reason, fix the cause, and start it again from its source trigger.",
|
|
23
|
+
awaiting_reconciliation: "An agent call ended ambiguously (worker loss, heartbeat timeout). The instance is parked and healthy. Retry only once the prior call can no longer mutate external state, or halt to close the instance.",
|
|
24
|
+
stuck: "The workflow code is failing every Workflow Task, so the instance cannot report itself. Fix the workflow code and restart `loopy loop`; the instance resumes against its intact history.",
|
|
25
|
+
};
|
|
26
|
+
const defaultClientFactory = (repository) => GitHubClient.fromEnvironment(repository);
|
|
27
|
+
/**
|
|
28
|
+
* The declared route: `trigger` follows the instance's own trigger, `fixed` names an aggregation
|
|
29
|
+
* issue. `labels` applies only to the trigger route, so the union rejects it on the fixed one, and
|
|
30
|
+
* the credential source is declared rather than inherited from the process.
|
|
31
|
+
*/
|
|
32
|
+
export const gitHubAttentionOptionsSchema = z.union([
|
|
33
|
+
z
|
|
34
|
+
.object({
|
|
35
|
+
target: z.literal("trigger"),
|
|
36
|
+
labels: z.boolean().default(true),
|
|
37
|
+
credentials: z.literal("env").default("env"),
|
|
38
|
+
})
|
|
39
|
+
.strict(),
|
|
40
|
+
z
|
|
41
|
+
.object({
|
|
42
|
+
target: z.literal("fixed"),
|
|
43
|
+
repository: z.string().regex(REPOSITORY_PATTERN),
|
|
44
|
+
issue: z.number().int().positive(),
|
|
45
|
+
credentials: z.literal("env").default("env"),
|
|
46
|
+
})
|
|
47
|
+
.strict(),
|
|
48
|
+
]);
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the declared route against the instance's trigger: the trigger is passed in explicitly
|
|
51
|
+
* and only its repository and issue number survive into the concrete target, which is all `emit`
|
|
52
|
+
* ever sees.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveGitHubAttentionTarget(options, trigger) {
|
|
55
|
+
const parsed = gitHubAttentionOptionsSchema.parse(options);
|
|
56
|
+
if (parsed.target === "fixed") {
|
|
57
|
+
return {
|
|
58
|
+
repository: parsed.repository,
|
|
59
|
+
issue: parsed.issue,
|
|
60
|
+
labels: false,
|
|
61
|
+
credentials: parsed.credentials,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
return {
|
|
66
|
+
repository: trigger.repository,
|
|
67
|
+
issue: triggerNumber(trigger),
|
|
68
|
+
labels: parsed.labels,
|
|
69
|
+
credentials: parsed.credentials,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
// A trigger-following route on a non-GitHub trigger is a deterministic misconfiguration, so it
|
|
74
|
+
// fails the same permanent way a vanished target does rather than retrying identically forever.
|
|
75
|
+
throw classifyGitHubWriteError(error);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export async function emitGitHubAttention(context, clientFactory = defaultClientFactory) {
|
|
79
|
+
const kind = context.event.kind;
|
|
80
|
+
// The ask's question comment is its surface; loopy adds no artifact of its own on the target.
|
|
81
|
+
if (kind === "awaiting_answer")
|
|
82
|
+
return { status: "skipped" };
|
|
83
|
+
const target = resolveGitHubAttentionTarget(context.options, context.trigger);
|
|
84
|
+
try {
|
|
85
|
+
const client = clientFactory(target.repository, target.credentials);
|
|
86
|
+
const marker = attentionMarker(context.event);
|
|
87
|
+
const comments = await client.commentBodies(target.issue);
|
|
88
|
+
if (comments.some((body) => body.includes(marker)))
|
|
89
|
+
return { status: "skipped" };
|
|
90
|
+
if (target.labels) {
|
|
91
|
+
const current = await client.labels(target.issue);
|
|
92
|
+
const desired = new Set(current);
|
|
93
|
+
for (const label of Object.values(ATTENTION_LABELS))
|
|
94
|
+
desired.delete(label);
|
|
95
|
+
const kindLabel = ATTENTION_LABELS[kind];
|
|
96
|
+
desired.add(kindLabel);
|
|
97
|
+
const labels = [...desired].sort();
|
|
98
|
+
if (!sameLabels(current, labels)) {
|
|
99
|
+
// setLabels only attaches labels that already exist in the repository, so provision first.
|
|
100
|
+
const style = LABEL_STYLES[kind];
|
|
101
|
+
await client.ensureLabel(kindLabel, style.color, style.description);
|
|
102
|
+
await client.setLabels(target.issue, labels);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
await client.createComment(target.issue, renderComment(marker, context.event, kind));
|
|
106
|
+
return { status: "emitted" };
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
throw classifyGitHubWriteError(error);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Deduplication key rendered as an invisible HTML comment: a matching marker on any existing
|
|
114
|
+
* comment means this event is already surfaced. `stuck` is level-triggered - the observer
|
|
115
|
+
* re-reports the same condition every poll tick with a fresh timestamp - so its key drops
|
|
116
|
+
* `occurredAt` and one stuck Run gets one comment. The other kinds are edge-triggered, emitted once
|
|
117
|
+
* per event with a timestamp that is stable across Activity retries, so `occurredAt` stays in the
|
|
118
|
+
* key and each re-park of one call is surfaced as the new event it is.
|
|
119
|
+
*/
|
|
120
|
+
export function attentionMarker(event) {
|
|
121
|
+
const occurrence = event.kind === "stuck" ? "" : event.occurredAt;
|
|
122
|
+
const key = [
|
|
123
|
+
event.kind,
|
|
124
|
+
event.workflowId,
|
|
125
|
+
event.runId ?? "",
|
|
126
|
+
event.callAddress ?? "",
|
|
127
|
+
occurrence,
|
|
128
|
+
].join("\0");
|
|
129
|
+
return `<!-- loopy:attention:${sha256(key)} -->`;
|
|
130
|
+
}
|
|
131
|
+
function renderComment(marker, event, kind) {
|
|
132
|
+
const lines = [
|
|
133
|
+
marker,
|
|
134
|
+
`### loopy needs attention: \`${kind}\``,
|
|
135
|
+
"",
|
|
136
|
+
KIND_EXPLANATIONS[kind],
|
|
137
|
+
"",
|
|
138
|
+
`**Workflow:** \`${event.workflowName}\``,
|
|
139
|
+
`**Instance:** \`${event.workflowId}\`${event.runId === undefined ? "" : ` (run \`${event.runId}\`)`}`,
|
|
140
|
+
`**Trigger:** \`${event.triggerRef}\``,
|
|
141
|
+
];
|
|
142
|
+
if (event.callAddress !== undefined)
|
|
143
|
+
lines.push(`**Call:** \`${event.callAddress}\``);
|
|
144
|
+
lines.push("**Reason:**", "```text", event.reason, "```");
|
|
145
|
+
if (event.cleanup !== undefined) {
|
|
146
|
+
lines.push(event.cleanup.status === "completed"
|
|
147
|
+
? `**Cleanup:** completed (${event.cleanup.removed.length} path(s) removed)`
|
|
148
|
+
: `**Cleanup:** failed - ${event.cleanup.reason}`);
|
|
149
|
+
}
|
|
150
|
+
if (event.suggestedCommands.length > 0) {
|
|
151
|
+
lines.push("**Next steps:**", "```bash", ...event.suggestedCommands, "```");
|
|
152
|
+
}
|
|
153
|
+
lines.push("", `<sub>reported at ${event.occurredAt}</sub>`);
|
|
154
|
+
return lines.join("\n");
|
|
155
|
+
}
|
|
156
|
+
export const gitHubAttentionEmitter = {
|
|
157
|
+
name: "github",
|
|
158
|
+
optionsSchema: gitHubAttentionOptionsSchema,
|
|
159
|
+
emit: emitGitHubAttention,
|
|
160
|
+
checkStartup: authenticationDiagnostic,
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/attention/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AttentionDeclaration } from "./types.js";
|
|
2
|
+
export type GitHubAttentionOptions = {
|
|
3
|
+
/** Follow the instance's own trigger: surface on the issue or PR that started it. */
|
|
4
|
+
target: "trigger";
|
|
5
|
+
/** Whether to converge the trigger's attention label; defaults to true. */
|
|
6
|
+
labels?: boolean;
|
|
7
|
+
credentials?: "env";
|
|
8
|
+
} | {
|
|
9
|
+
/** A fixed aggregation issue; comments-only, so unrelated instance states never share a label. */
|
|
10
|
+
repository: string;
|
|
11
|
+
/** GitHub uses the Issues API for both issues and pull requests. */
|
|
12
|
+
issue: number;
|
|
13
|
+
credentials?: "env";
|
|
14
|
+
};
|
|
15
|
+
export declare function githubAttention(options: GitHubAttentionOptions): AttentionDeclaration;
|
|
16
|
+
//# sourceMappingURL=attention-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attention-config.d.ts","sourceRoot":"","sources":["../../src/authoring/attention-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,MAAM,MAAM,sBAAsB,GAC9B;IACE,qFAAqF;IACrF,MAAM,EAAE,SAAS,CAAC;IAClB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,KAAK,CAAC;CACrB,GACD;IACE,kGAAkG;IAClG,UAAU,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;CACrB,CAAC;AAEN,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,oBAAoB,CAiBrF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function githubAttention(options) {
|
|
2
|
+
const credentials = options.credentials ?? "env";
|
|
3
|
+
if ("target" in options) {
|
|
4
|
+
return {
|
|
5
|
+
emitter: "github",
|
|
6
|
+
options: { target: "trigger", labels: options.labels ?? true, credentials },
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
emitter: "github",
|
|
11
|
+
options: {
|
|
12
|
+
target: "fixed",
|
|
13
|
+
repository: options.repository,
|
|
14
|
+
issue: options.issue,
|
|
15
|
+
credentials,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=attention-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attention-config.js","sourceRoot":"","sources":["../../src/authoring/attention-config.ts"],"names":[],"mappings":"AAkBA,MAAM,UAAU,eAAe,CAAC,OAA+B;IAC7D,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,KAAK,CAAC;IACjD,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;QACxB,OAAO;YACL,OAAO,EAAE,QAAQ;YACjB,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI,EAAE,WAAW,EAAE;SAC5E,CAAC;IACJ,CAAC;IACD,OAAO;QACL,OAAO,EAAE,QAAQ;QACjB,OAAO,EAAE;YACP,MAAM,EAAE,OAAO;YACf,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,WAAW;SACZ;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ChannelDeclaration } from "./types.js";
|
|
2
|
+
export interface GitHubCommentsOptions {
|
|
3
|
+
/** The repository whose issue/PR the question is posted on; use `ctx.repository` or a fixed one. */
|
|
4
|
+
repository: string;
|
|
5
|
+
/** The issue or pull-request number to ask on; `triggerIssue(ctx.trigger)` for the trigger's own thread. */
|
|
6
|
+
issue: number;
|
|
7
|
+
/** Credential source; `"env"` is the only one today and the default, declared rather than inherited. */
|
|
8
|
+
credentials?: "env";
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Ask over GitHub issue comments. The port reads nothing ambient - its repository and issue are its
|
|
12
|
+
* own declared inputs, populated by the author from `ctx` (e.g. `issue: triggerIssue(ctx.trigger)`)
|
|
13
|
+
* - so several asks can share one issue and each is bound to its own reply by a run-scoped token.
|
|
14
|
+
*/
|
|
15
|
+
export declare function githubComments(options: GitHubCommentsOptions): ChannelDeclaration;
|
|
16
|
+
//# sourceMappingURL=channel-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-config.d.ts","sourceRoot":"","sources":["../../src/authoring/channel-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,oGAAoG;IACpG,UAAU,EAAE,MAAM,CAAC;IACnB,4GAA4G;IAC5G,KAAK,EAAE,MAAM,CAAC;IACd,wGAAwG;IACxG,WAAW,CAAC,EAAE,KAAK,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,kBAAkB,CASjF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask over GitHub issue comments. The port reads nothing ambient - its repository and issue are its
|
|
3
|
+
* own declared inputs, populated by the author from `ctx` (e.g. `issue: triggerIssue(ctx.trigger)`)
|
|
4
|
+
* - so several asks can share one issue and each is bound to its own reply by a run-scoped token.
|
|
5
|
+
*/
|
|
6
|
+
export function githubComments(options) {
|
|
7
|
+
return {
|
|
8
|
+
channel: "github_comments",
|
|
9
|
+
options: {
|
|
10
|
+
repository: options.repository,
|
|
11
|
+
issue: options.issue,
|
|
12
|
+
credentials: options.credentials ?? "env",
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=channel-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-config.js","sourceRoot":"","sources":["../../src/authoring/channel-config.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,OAAO;QACL,OAAO,EAAE,iBAAiB;QAC1B,OAAO,EAAE;YACP,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,KAAK;SAC1C;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { InstanceResult, JsonValue } from "../core/wire.js";
|
|
2
|
+
import type { WorkflowDefinition } from "./types.js";
|
|
3
|
+
export interface WorkflowFunction {
|
|
4
|
+
(input: unknown): Promise<InstanceResult>;
|
|
5
|
+
readonly definition: WorkflowDefinition<JsonValue>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Wrap a user `run` function as a supervised Temporal Workflow Definition. Discovery reads
|
|
9
|
+
* `definition` under plain Node to synchronize Schedules; the bundled copy is what the isolate
|
|
10
|
+
* executes, so the module must be safe to import twice.
|
|
11
|
+
*/
|
|
12
|
+
export declare function defineWorkflow<R extends JsonValue>(definition: WorkflowDefinition<R>): WorkflowFunction;
|
|
13
|
+
//# sourceMappingURL=define.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/authoring/define.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,gBAAgB;IAC/B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;CACpD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,SAAS,EAChD,UAAU,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAChC,gBAAgB,CAIlB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { assertIdentifier } from "../core/calls.js";
|
|
2
|
+
import { runSupervised } from "../temporal/supervisor.js";
|
|
3
|
+
/**
|
|
4
|
+
* Wrap a user `run` function as a supervised Temporal Workflow Definition. Discovery reads
|
|
5
|
+
* `definition` under plain Node to synchronize Schedules; the bundled copy is what the isolate
|
|
6
|
+
* executes, so the module must be safe to import twice.
|
|
7
|
+
*/
|
|
8
|
+
export function defineWorkflow(definition) {
|
|
9
|
+
assertIdentifier("workflow", definition.name);
|
|
10
|
+
const workflow = (input) => runSupervised(definition, input);
|
|
11
|
+
return Object.assign(workflow, { definition: definition });
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=define.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/authoring/define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAQ1D;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,UAAiC;IAEjC,gBAAgB,CAAC,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,CAAC,KAAc,EAA2B,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC/F,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,UAA2C,EAAE,CAAC,CAAC;AAC9F,CAAC"}
|