@proagentstore/cli 0.4.56 → 0.4.57

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.
@@ -60,6 +60,16 @@ export class HeadlessSession {
60
60
  run = "idle";
61
61
  /** Claude Code's own session id (from the init event) — used to --resume. */
62
62
  claudeSessionId = null;
63
+ /**
64
+ * The cloud's context brief, until the first turn spends it (ADR 0005, #693). Null once
65
+ * delivered, and null from the start when the engine resumed its own conversation.
66
+ *
67
+ * Consumed ONCE, by construction rather than by convention: it is cleared in the same expression
68
+ * that reads it. A brief re-sent on every turn would be the "unbounded brief… a token bill that
69
+ * grows every turn" the ADR names as the cost of owning the conversation, and it would also start
70
+ * contradicting the engine's own memory of the turns since.
71
+ */
72
+ pendingSeed = null;
63
73
  /** "stream-json" for Claude (structured) · "raw" for any other CLI (stdout capture). */
64
74
  mode;
65
75
  cmdBin;
@@ -181,6 +191,17 @@ export class HeadlessSession {
181
191
  get resumedConversation() {
182
192
  return this.mode === "stream-json" && this.claudeSessionId !== null;
183
193
  }
194
+ /**
195
+ * Did this engine come up cold AND with a brief to lead its first turn (ADR 0005, #693)?
196
+ *
197
+ * Read by `/coding/start` so the sentence the user is shown is one this side CONFIRMED. It is
198
+ * armed-not-delivered: the brief goes out with the first `input()`, which may never arrive if
199
+ * the session is closed first. That is why the cloud's wording is "it was given a brief" — true
200
+ * the moment the engine holds one — and never "it has read your history".
201
+ */
202
+ get seededConversation() {
203
+ return this.pendingSeed !== null;
204
+ }
184
205
  constructor(config) {
185
206
  this.config = config;
186
207
  this.engineLabel = `${config.clientType}:${config.id}`;
@@ -188,6 +209,10 @@ export class HeadlessSession {
188
209
  this.claudeSessionId = readState(config.statePath, config.id) ?? (config.resumeFrom ? readState(config.statePath, config.resumeFrom) : null);
189
210
  // Claude is the structured engine; everything else is a raw CLI.
190
211
  this.mode = config.clientType === "claude" ? "stream-json" : "raw";
212
+ // AFTER both lines above, because `resumedConversation` reads them: the brief is the fallback,
213
+ // so an engine that found its own conversation drops it unread rather than being handed a
214
+ // summary of the conversation it is already in.
215
+ this.pendingSeed = this.resumedConversation ? null : config.seed?.trim() || null;
191
216
  const { bin, args } = parseCommand(config.command);
192
217
  // When no explicit command is configured, fall back to THIS engine's default
193
218
  // command (codex/gemini/grok/…) — not a hard-coded "claude", which would drive a
@@ -381,8 +406,17 @@ export class HeadlessSession {
381
406
  input(text, opts = {}) {
382
407
  // The Engine reads the preamble, the pane the short marker; the instruction stays evidence.
383
408
  const sent = authoredTurn(text, opts.author);
409
+ // The brief leads the turn and is spent in the reading (#693). It goes to the ENGINE only:
410
+ // the pane gets the one-line marker below, because the transcript is what the owner and the
411
+ // Pilot re-read through `/coding/capture` and twelve thousand characters of reconstructed
412
+ // history would evict the live output they are looking at — the same budget argument
413
+ // `turn-author.ts` makes for its two-word marker.
414
+ const seed = this.pendingSeed;
415
+ this.pendingSeed = null;
384
416
  if (!this.alive)
385
417
  this.start();
418
+ if (seed)
419
+ this.push("[pags] a context brief from ProAgentStore's record was delivered with this turn — a reconstruction, not the previous conversation");
386
420
  this.push(`\n❯ [${stamp()}] ${authorTag(opts.author)}${text}`); // ❯ — your turn, timestamped
387
421
  this.run = "thinking";
388
422
  const now = Date.now();
@@ -390,16 +424,19 @@ export class HeadlessSession {
390
424
  this.turnStartedAt = now;
391
425
  this.sawOutputSinceInput = false; // arm the persistent-raw idle heuristic for THIS turn
392
426
  try {
427
+ // Brief first, instruction second, and never the other way round: it is background for
428
+ // the request, and an engine that reads the request last acts on the request.
429
+ const withSeed = seed ? `${seed}\n\n${sent}` : sent;
393
430
  if (this.mode === "stream-json") {
394
431
  // `role` stays "user" — the only role this protocol accepts, which is why the
395
432
  // disambiguation rides in the text instead (#505).
396
- const msg = JSON.stringify({ type: "user", message: { role: "user", content: [{ type: "text", text: sent }] } });
433
+ const msg = JSON.stringify({ type: "user", message: { role: "user", content: [{ type: "text", text: withSeed }] } });
397
434
  this.proc?.stdin?.write(`${msg}\n`);
398
435
  }
399
436
  else {
400
437
  // Raw CLI: spawn THIS turn. See `oneShot` — there is no persistent process to
401
438
  // write to, because a non-interactive binary would never have read it.
402
- this.runOneShot(sent);
439
+ this.runOneShot(withSeed);
403
440
  }
404
441
  }
405
442
  catch {
@@ -117,6 +117,7 @@ export class CodingRuntime {
117
117
  env: input.env,
118
118
  statePath: defaultStatePath(this.reposBaseDir),
119
119
  resumeFrom: input.resumeFrom,
120
+ seed: input.seed,
120
121
  ghScope: input.ghScope,
121
122
  bin: input.bin,
122
123
  });
@@ -126,8 +127,12 @@ export class CodingRuntime {
126
127
  // clears its own key on that exit. Reporting after would say "started clean" about a launch
127
128
  // that did carry a conversation, and the transcript (which shows the crash) would disagree.
128
129
  const resumed = session.resumedConversation;
130
+ // Read alongside `resumed`, and BEFORE `start()` for the same reason: a bad `--resume` that
131
+ // kills the process on spawn clears the engine's key, and a seed answer read afterwards would
132
+ // describe a different launch from the one the caller asked about.
133
+ const seeded = session.seededConversation;
129
134
  session.start();
130
- return { ...this.snapshot(input.sessionId), resumed };
135
+ return { ...this.snapshot(input.sessionId), resumed, seeded };
131
136
  }
132
137
  /**
133
138
  * The pane the brain reasons over + the inferred run state.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proagentstore/cli",
3
- "version": "0.4.56",
3
+ "version": "0.4.57",
4
4
  "description": "CLI for creating, publishing, and running ProAgentStore agents",
5
5
  "license": "MIT",
6
6
  "type": "module",