cueloop 0.1.0-alpha.37 → 0.1.0-alpha.39
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/package.json +5 -5
- package/src/actions-command.ts +40 -0
- package/src/main.ts +5 -0
- package/src/session-commands.ts +41 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cueloop",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.39",
|
|
4
4
|
"description": "Terminal review surface for coding agents: annotate plans and diffs, return a verdict, send structured feedback back",
|
|
5
5
|
"homepage": "https://github.com/mmurakaru/cueloop#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@cueloop/adapters": "0.1.0-alpha.
|
|
31
|
-
"@cueloop/client": "0.1.0-alpha.
|
|
32
|
-
"@cueloop/daemon": "0.1.0-alpha.
|
|
33
|
-
"@cueloop/schema": "0.1.0-alpha.
|
|
30
|
+
"@cueloop/adapters": "0.1.0-alpha.39",
|
|
31
|
+
"@cueloop/client": "0.1.0-alpha.39",
|
|
32
|
+
"@cueloop/daemon": "0.1.0-alpha.39",
|
|
33
|
+
"@cueloop/schema": "0.1.0-alpha.39"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
36
|
"bun": ">=1.3.0"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cueloop actions list [--session <id>]` - print the quick-action vocabulary
|
|
3
|
+
* (the same presets a human picks in the marker popover) so a review-side agent
|
|
4
|
+
* can reference one by name or index via `session annotate --action`. With
|
|
5
|
+
* `--session`, the vocabulary comes from that session's repo (matching what
|
|
6
|
+
* `--action` will resolve); otherwise from the caller's cwd. JSON on stdout.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { loadConfig } from "@cueloop/client/config";
|
|
10
|
+
import { DaemonClient } from "@cueloop/daemon/client";
|
|
11
|
+
import { parseArgs, stringFlag } from "./args";
|
|
12
|
+
|
|
13
|
+
export async function actionsCommand(argv: string[]): Promise<number> {
|
|
14
|
+
const { positional, flags } = parseArgs(argv);
|
|
15
|
+
const verb = positional[0] ?? "list";
|
|
16
|
+
if (verb !== "list") {
|
|
17
|
+
console.error("usage: cueloop actions list [--session <id>]");
|
|
18
|
+
return 2;
|
|
19
|
+
}
|
|
20
|
+
const repoRoot = await repoRootForSession(stringFlag(flags, "session"));
|
|
21
|
+
const actions = loadConfig({ repoRoot }).actions;
|
|
22
|
+
const numbered = actions.map((action, index) => ({
|
|
23
|
+
index: index + 1,
|
|
24
|
+
prompt: action.prompt,
|
|
25
|
+
metadata: action.metadata,
|
|
26
|
+
}));
|
|
27
|
+
console.log(JSON.stringify(numbered, null, 2));
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The repo the given session lives in, or the caller's cwd when no session is named. */
|
|
32
|
+
async function repoRootForSession(sessionId: string | undefined): Promise<string> {
|
|
33
|
+
if (sessionId === undefined) return process.cwd();
|
|
34
|
+
const client = await DaemonClient.connect({ autostart: true });
|
|
35
|
+
try {
|
|
36
|
+
return (await client.sessionGet(sessionId)).workspace.repoRoot;
|
|
37
|
+
} finally {
|
|
38
|
+
client.close();
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/main.ts
CHANGED
|
@@ -89,6 +89,10 @@ async function main(): Promise<number> {
|
|
|
89
89
|
const { wakeCommand } = await import("./wake-command");
|
|
90
90
|
return wakeCommand(argv.slice(1));
|
|
91
91
|
}
|
|
92
|
+
case "actions": {
|
|
93
|
+
const { actionsCommand } = await import("./actions-command");
|
|
94
|
+
return actionsCommand(argv.slice(1));
|
|
95
|
+
}
|
|
92
96
|
case "review":
|
|
93
97
|
return reviewEntry(argv.slice(1));
|
|
94
98
|
case "review-post": {
|
|
@@ -254,6 +258,7 @@ function printHelp(): void {
|
|
|
254
258
|
"",
|
|
255
259
|
"scripting:",
|
|
256
260
|
" cueloop session <verb> [flags] script the daemon (create|get|list|wait|annotate|resolve|submit-revision)",
|
|
261
|
+
" cueloop actions list list the quick-action vocabulary (for annotate --action)",
|
|
257
262
|
" cueloop wake <id> [--harness codex --thread <id>] resume the agent with the verdict (spawn detached)",
|
|
258
263
|
" cueloop review-post <id> <pr> post a resolved session's verdict back to the PR",
|
|
259
264
|
" cueloop daemon run the daemon in the foreground",
|
package/src/session-commands.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { newAnnotationId, type ArtifactType, type VerdictKind } from "@cueloop/s
|
|
|
8
8
|
import { DaemonClient } from "@cueloop/daemon/client";
|
|
9
9
|
import { openHerdrPaneForReview } from "@cueloop/daemon/herdr-pane";
|
|
10
10
|
import { openReview, verdictResponse, type ReviewNote } from "@cueloop/daemon/review";
|
|
11
|
+
import { loadConfig, quickActionBody, resolveQuickAction } from "@cueloop/client/config";
|
|
11
12
|
import { parseArgs, stringFlag } from "./args";
|
|
12
13
|
|
|
13
14
|
async function readStdin(): Promise<string> {
|
|
@@ -42,10 +43,8 @@ export async function sessionCommand(argv: string[]): Promise<number> {
|
|
|
42
43
|
title: stringFlag(flags, "title"),
|
|
43
44
|
notes,
|
|
44
45
|
});
|
|
45
|
-
// herdr auto-open:
|
|
46
|
-
|
|
47
|
-
// herdr; a broken binary never blocks the create.
|
|
48
|
-
openHerdrPaneForReview(review.session);
|
|
46
|
+
// herdr auto-open: render the review in a tab (no-op outside herdr).
|
|
47
|
+
await openHerdrPaneForReview(review.session, client);
|
|
49
48
|
out(review.session);
|
|
50
49
|
return 0;
|
|
51
50
|
}
|
|
@@ -72,19 +71,25 @@ export async function sessionCommand(argv: string[]): Promise<number> {
|
|
|
72
71
|
}
|
|
73
72
|
case "annotate": {
|
|
74
73
|
const id = required(positional[1], "session id");
|
|
75
|
-
const body = stringFlag(flags, "body") ?? "";
|
|
76
74
|
const quote = required(stringFlag(flags, "quote"), "--quote");
|
|
75
|
+
const author = stringFlag(flags, "author");
|
|
76
|
+
const body = await annotateBody(flags, client, id);
|
|
77
77
|
out(
|
|
78
|
-
await client.sessionAnnotate(
|
|
79
|
-
id
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
await client.sessionAnnotate(
|
|
79
|
+
id,
|
|
80
|
+
{
|
|
81
|
+
id: stringFlag(flags, "annotation-id") ?? newAnnotationId(),
|
|
82
|
+
kind: stringFlag(flags, "kind") ?? "comment",
|
|
83
|
+
anchor: {
|
|
84
|
+
quote,
|
|
85
|
+
prefix: stringFlag(flags, "prefix") ?? "",
|
|
86
|
+
suffix: stringFlag(flags, "suffix") ?? "",
|
|
87
|
+
},
|
|
88
|
+
body,
|
|
89
|
+
...(author ? { author } : {}),
|
|
85
90
|
},
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
stringFlag(flags, "author-name"),
|
|
92
|
+
),
|
|
88
93
|
);
|
|
89
94
|
return 0;
|
|
90
95
|
}
|
|
@@ -121,3 +126,25 @@ function required<T>(value: T | undefined, description: string): T {
|
|
|
121
126
|
if (value === undefined) throw new Error(`missing ${description}`);
|
|
122
127
|
return value;
|
|
123
128
|
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The annotation body: an explicit `--body`, else the `--action <index|name>`
|
|
132
|
+
* quick-action expanded through the shared vocabulary. The vocabulary is loaded
|
|
133
|
+
* from the reviewed session's own repo, not the caller's cwd, so an agent
|
|
134
|
+
* annotating from elsewhere still sees that session's actions.
|
|
135
|
+
*/
|
|
136
|
+
async function annotateBody(
|
|
137
|
+
flags: Record<string, string | boolean>,
|
|
138
|
+
client: DaemonClient,
|
|
139
|
+
id: string,
|
|
140
|
+
): Promise<string> {
|
|
141
|
+
const explicit = stringFlag(flags, "body");
|
|
142
|
+
if (explicit !== undefined) return explicit;
|
|
143
|
+
const actionRef = stringFlag(flags, "action");
|
|
144
|
+
if (actionRef === undefined) return "";
|
|
145
|
+
const session = await client.sessionGet(id);
|
|
146
|
+
const actions = loadConfig({ repoRoot: session.workspace.repoRoot }).actions;
|
|
147
|
+
const action = resolveQuickAction(actions, actionRef);
|
|
148
|
+
if (!action) throw new Error(`no quick action ${actionRef} - see: cueloop actions list`);
|
|
149
|
+
return quickActionBody(action);
|
|
150
|
+
}
|