@jr2/machines 0.1.4 → 0.2.1
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 +3 -3
- package/src/task.ts +36 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jr2/machines",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "The Machines the jr2 kit ships: packaged xstate Machines that leave their parts Open for a composer to bind.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"xstate": "^5.18.0",
|
|
37
37
|
"zod": "^4.4.3",
|
|
38
|
-
"@jr2/orchestrator": "0.1
|
|
38
|
+
"@jr2/orchestrator": "0.2.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^26.0.1",
|
|
42
42
|
"typescript": "^5.6.0",
|
|
43
43
|
"xstate": "^5.18.0",
|
|
44
44
|
"zod": "^4.4.3",
|
|
45
|
-
"@jr2/orchestrator": "0.1
|
|
45
|
+
"@jr2/orchestrator": "0.2.1"
|
|
46
46
|
},
|
|
47
47
|
"files": [
|
|
48
48
|
"src"
|
package/src/task.ts
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
// cannot pay for one. A consumer binds both on the line that registers this Machine as a
|
|
9
9
|
// Workflow, naming every slot. The ORDER is this Machine's convention, not the kit's (ADR-0051:
|
|
10
10
|
// the handles keep declaration order and the kit reads nothing into it): the FIRST slot is the
|
|
11
|
-
// one the coder works in
|
|
12
|
-
// the
|
|
11
|
+
// one the coder works in — its Worktree is the `cwd` every Turn is framed with (ADR-0057), so the
|
|
12
|
+
// Working tools are rooted where the prompt says to work — and any others are attached beside it
|
|
13
|
+
// for the coder to read (a library the change targets, a handbook):
|
|
13
14
|
//
|
|
14
15
|
// export const machine = customize(task, {
|
|
15
16
|
// repos: {
|
|
@@ -123,18 +124,12 @@ const requestChanges = defineEvent({
|
|
|
123
124
|
type BodyInput = Workspaced<TaskInput & HostInjectedInput, string>;
|
|
124
125
|
|
|
125
126
|
type BodyContext = BodyInput & {
|
|
126
|
-
/**
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* addressing a dead one.
|
|
133
|
-
*/
|
|
134
|
-
generation: number;
|
|
135
|
-
/** Turns COMPLETED on the current conversation. Zero means the next Turn is its first, so the
|
|
136
|
-
* prompt has to carry the whole task and the worktree framing again — which is exactly what a
|
|
137
|
-
* post-fault Turn needs and a continued one does not. */
|
|
127
|
+
/** Turns COMPLETED on the conversation the next Turn will land on. Zero means that Turn is its
|
|
128
|
+
* first, so the prompt has to carry the whole task and the worktree framing again — which is
|
|
129
|
+
* exactly what a post-fault Turn needs and a continued one does not. It counts for the PROMPT
|
|
130
|
+
* alone: the conversation itself is jr2's, and a terminal `agent.fault` burns it in the ledger
|
|
131
|
+
* so the next `continue` is virgin (ADR-0057). Re-briefing that Turn is what stays here, because
|
|
132
|
+
* jr2 cannot write the prompt. */
|
|
138
133
|
turns: number;
|
|
139
134
|
/** The coder's own account of the last finished Turn — the Gate's `summary`. */
|
|
140
135
|
summary?: string;
|
|
@@ -144,11 +139,6 @@ type BodyContext = BodyInput & {
|
|
|
144
139
|
notes?: string;
|
|
145
140
|
};
|
|
146
141
|
|
|
147
|
-
/** The conversation pin (ADR-0016): a workflow-chosen name, so every `working` Turn of a run
|
|
148
|
-
* derives one deterministic instance id and the coder's context survives the round trip through
|
|
149
|
-
* the Gate. The name is the slot key, because that is what the conversation is about. */
|
|
150
|
-
const CONVERSATION = "coder";
|
|
151
|
-
|
|
152
142
|
export const body = jr2Setup({
|
|
153
143
|
types: {} as { context: BodyContext; input: BodyInput; output: TaskOutput },
|
|
154
144
|
events: [finish, approve, requestChanges],
|
|
@@ -165,8 +155,8 @@ export const body = jr2Setup({
|
|
|
165
155
|
workspace: "write",
|
|
166
156
|
instructions: `You are a software engineer working alone on one task, in a container of your own.
|
|
167
157
|
|
|
168
|
-
- Edit only inside the worktree
|
|
169
|
-
survives. Any other checkout
|
|
158
|
+
- Edit only inside the worktree your turn names as yours — your tools are already rooted in it.
|
|
159
|
+
Nothing you write outside it survives. Any other checkout the turn names is there for you to read.
|
|
170
160
|
- Commit your work on the named branch. You cannot push, and you do not need to: a human reads the
|
|
171
161
|
branch in this container before the run ends.
|
|
172
162
|
- Read before you write, and prefer the smallest change that does the task.
|
|
@@ -176,7 +166,7 @@ export const body = jr2Setup({
|
|
|
176
166
|
},
|
|
177
167
|
}).createMachine({
|
|
178
168
|
id: "task",
|
|
179
|
-
context: ({ input }) => ({ ...input,
|
|
169
|
+
context: ({ input }) => ({ ...input, turns: 0 }),
|
|
180
170
|
initial: "working",
|
|
181
171
|
|
|
182
172
|
// Our Sandbox is gone — reaped, or replaced after an eviction (ADR-0021). The pod-local clone and
|
|
@@ -188,12 +178,17 @@ export const body = jr2Setup({
|
|
|
188
178
|
invoke: {
|
|
189
179
|
src: "coder",
|
|
190
180
|
input: ({ context }) => ({
|
|
181
|
+
// This Turn's FRAME (ADR-0057): what it is about, and where it works. The `cwd` is
|
|
182
|
+
// stated rather than left to the single-slot default, because "the first slot is the one
|
|
183
|
+
// the coder edits" is this Machine's convention (`worktreeOf`) and a convention is
|
|
184
|
+
// stated — a consumer who binds a second slot must not change where the coder works.
|
|
191
185
|
prompt: coderPrompt(context),
|
|
192
|
-
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
186
|
+
cwd: worktreeOf(context).path,
|
|
187
|
+
// One human steering one Agent wants the Agent to remember what it did (ADR-0054), so
|
|
188
|
+
// every `working` Turn lands on this Machine instance's one coder conversation. The
|
|
189
|
+
// boolean names nothing: the id is structural (ADR-0057), and a conversation jr2 has
|
|
190
|
+
// faulted is burned — the next `continue` mints a virgin one.
|
|
191
|
+
continue: true,
|
|
197
192
|
// This run's Dials, if the caller set them (ADR-0018/0054) — passed straight through,
|
|
198
193
|
// layered over the bound definition when the Submission starts.
|
|
199
194
|
...(context.model !== undefined ? { model: context.model } : {}),
|
|
@@ -212,14 +207,14 @@ export const body = jr2Setup({
|
|
|
212
207
|
},
|
|
213
208
|
// ADR-0016's ONE terminal telemetry, ROUTED: jr2 has already retried, nudged and rerolled
|
|
214
209
|
// (ADR-0027/0035), so this is the end of that conversation, not of the run. Park at the
|
|
215
|
-
// same Gate — the Workspace is still alive and the work so far is still on the branch
|
|
216
|
-
//
|
|
210
|
+
// same Gate — the Workspace is still alive and the work so far is still on the branch.
|
|
211
|
+
// The dead conversation is jr2's to bury (it bumps the epoch, so the next `continue` is
|
|
212
|
+
// virgin — ADR-0057); what belongs here is the RE-BRIEF, which `turns: 0` asks for.
|
|
217
213
|
"agent.fault": {
|
|
218
214
|
target: "review",
|
|
219
215
|
actions: assign({
|
|
220
216
|
reason: ({ event }) => event.reason,
|
|
221
217
|
summary: undefined,
|
|
222
|
-
generation: ({ context }) => context.generation + 1,
|
|
223
218
|
turns: 0,
|
|
224
219
|
}),
|
|
225
220
|
},
|
|
@@ -312,14 +307,16 @@ function branchOf(input: TaskInput): string {
|
|
|
312
307
|
}
|
|
313
308
|
|
|
314
309
|
/**
|
|
315
|
-
*
|
|
316
|
-
* because the conversation holds nothing yet; every Turn after
|
|
317
|
-
* because the coder remembers the rest (ADR-0054's continued
|
|
318
|
-
* first Turn again — that is what `turns` counts.
|
|
310
|
+
* Half the Turn's Frame (ADR-0057) — what it is about. The FIRST Turn of a conversation carries
|
|
311
|
+
* the whole task and the geography, because the conversation holds nothing yet; every Turn after
|
|
312
|
+
* it carries the human's notes alone, because the coder remembers the rest (ADR-0054's continued
|
|
313
|
+
* conversation). A post-fault Turn is a first Turn again — that is what `turns` counts.
|
|
319
314
|
*
|
|
320
|
-
* The geography is every slot the handles carry (ADR-0051): the first is where the work goes
|
|
321
|
-
*
|
|
322
|
-
* the
|
|
315
|
+
* The geography is every slot the handles carry (ADR-0051): the first is where the work goes —
|
|
316
|
+
* and it is the Frame's `cwd`, so the Working tools are rooted there and the prose only says what
|
|
317
|
+
* the tools already do — and each other checkout is named by the consumer's own word for it, at
|
|
318
|
+
* the path the attach put it, the only way the coder can learn what is beside it since the package
|
|
319
|
+
* never knew.
|
|
323
320
|
*/
|
|
324
321
|
function coderPrompt(context: BodyContext): string {
|
|
325
322
|
const notes = context.notes ? `\n\nThe human reviewed your work and asks for changes:\n${context.notes}` : "";
|
|
@@ -332,7 +329,8 @@ function coderPrompt(context: BodyContext): string {
|
|
|
332
329
|
.join("");
|
|
333
330
|
return (
|
|
334
331
|
`${context.prompt}${notes}\n\n` +
|
|
335
|
-
`Work in ${worktree.path}, on branch ${branch}
|
|
332
|
+
`Work in ${worktree.path}, on branch ${branch} — your tools are rooted there, so a relative ` +
|
|
333
|
+
`path lands inside it. Commit what you do there, then call finish.` +
|
|
336
334
|
(beside ? `\n\nAlso checked out beside it, for you to read:${beside}` : "")
|
|
337
335
|
);
|
|
338
336
|
}
|