@valescoagency/runway 0.8.0 → 0.9.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/README.md CHANGED
@@ -156,7 +156,7 @@ sandcastle reads `.sandcastle/.env` per its docs.
156
156
  ## Install
157
157
 
158
158
  ```bash
159
- pnpm install -g @valescoagency/runway # or npm i -g, yarn global add
159
+ pnpm add -g @valescoagency/runway # or npm i -g, yarn global add
160
160
  ```
161
161
 
162
162
  Export runway's own env (in your shell rc, or wherever you keep API keys):
@@ -392,7 +392,7 @@ These are tractable, just not v1.
392
392
 
393
393
  ## Status
394
394
 
395
- 0.8.0 — production-shaped and dogfooded against live Linear queues.
395
+ 0.9.0 — production-shaped and dogfooded against live Linear queues.
396
396
  The end-to-end pipeline (init → run → review → PR) is stable; surface
397
397
  may still shift as the orchestrator's policy and iteration mechanics
398
398
  mature. See [CHANGELOG.md](./CHANGELOG.md) for per-release detail.
package/dist/implement.js CHANGED
@@ -60,6 +60,10 @@ export const runImplementLoop = (issue, deps, branch) => Effect.gen(function* ()
60
60
  // and iteration N+1, since the implementer keeps drifting
61
61
  // toward the same code paths until corrected.
62
62
  priorReviewFeedback: priorFeedback,
63
+ // VA-417: pass the actual base branch so the prompt
64
+ // renders the real name (`main`, `master`, etc.) rather
65
+ // than a hardcoded default.
66
+ baseBranch,
63
67
  }));
64
68
  const sandcastleRunId = `impl-${issue.identifier}-iter-${iter}`;
65
69
  // VA-389: parse the verdict inside the span scope so the
package/dist/linear.js CHANGED
@@ -42,14 +42,20 @@ const WorkflowStateTypeNodeSchema = Schema.Struct({
42
42
  // integration comments can lack an author); we map a missing user to
43
43
  // the empty string so downstream filters can match by name without a
44
44
  // null-guard at every call site.
45
+ //
46
+ // VA-415: `user` can also be *absent from the payload entirely* (vs.
47
+ // present-and-null) on some system / deleted-user comments. The
48
+ // optional + nullable shape below accepts all three forms: missing,
49
+ // null, and full struct. Downstream code already null-coalesces via
50
+ // `comment.user?.name ?? ""`.
45
51
  const CommentNodeSchema = Schema.Struct({
46
52
  id: Schema.String,
47
53
  body: Schema.String,
48
54
  createdAt: Schema.Union(Schema.String, Schema.DateFromSelf),
49
- user: Schema.NullOr(Schema.Struct({
55
+ user: Schema.optional(Schema.NullOr(Schema.Struct({
50
56
  id: Schema.String,
51
57
  name: Schema.String,
52
- })),
58
+ }))),
53
59
  });
54
60
  const ViewerSchema = Schema.Struct({
55
61
  id: Schema.String,
@@ -358,21 +364,44 @@ export function createLinearGateway(config, limiter = null) {
358
364
  message: `Issue ${issueId} has no team`,
359
365
  });
360
366
  }
367
+ // VA-416: Linear labels can be team-scoped OR
368
+ // workspace-scoped (no team association). Earlier code
369
+ // filtered by team only, which silently excluded
370
+ // workspace-scoped labels like the default
371
+ // `ready-for-human`. Query by name alone, then prefer a
372
+ // team-scoped match when one exists so the team-vs-
373
+ // workspace name-collision edge resolves the obvious way.
361
374
  const labels = await client.issueLabels({
362
- filter: {
363
- team: { id: { eq: team.id } },
364
- name: { eq: labelName },
365
- },
375
+ filter: { name: { eq: labelName } },
366
376
  });
367
- const rawLabel = labels.nodes[0];
368
- if (!rawLabel) {
377
+ const decoded = labels.nodes.map((l) => ({
378
+ raw: l,
379
+ decoded: decodeIssueLabelNode(l),
380
+ }));
381
+ const teamScoped = await (async () => {
382
+ for (const { raw, decoded: d } of decoded) {
383
+ const labelTeam = await raw.team;
384
+ if (labelTeam?.id === team.id)
385
+ return d;
386
+ }
387
+ return undefined;
388
+ })();
389
+ const workspaceScoped = await (async () => {
390
+ for (const { raw, decoded: d } of decoded) {
391
+ const labelTeam = await raw.team;
392
+ if (!labelTeam)
393
+ return d;
394
+ }
395
+ return undefined;
396
+ })();
397
+ const label = teamScoped ?? workspaceScoped;
398
+ if (!label) {
369
399
  throw new LinearNotFound({
370
400
  resource: "label",
371
401
  identifier: labelName,
372
- message: `Linear label "${labelName}" not found on team ${team.id}`,
402
+ message: `Linear label "${labelName}" not found at workspace scope or on team ${team.id}`,
373
403
  });
374
404
  }
375
- const label = decodeIssueLabelNode(rawLabel);
376
405
  const existing = await issue.labels();
377
406
  const existingIds = existing.nodes.map((l) => decodeIssueLabelNode(l).id);
378
407
  const labelIds = [...existingIds, label.id];
package/dist/prompts.js CHANGED
@@ -56,6 +56,10 @@ function implementVars(args) {
56
56
  PREVIOUS_ITERATIONS: args.previousIterations,
57
57
  PRIOR_REVIEW_FEEDBACK: args.priorReviewFeedback,
58
58
  POLICY_FORBIDDEN_BULLET: renderForbiddenPathsBullet(args.policy),
59
+ // VA-417: fall back to "main" if the caller didn't pass one, so
60
+ // older test fixtures keep working. Production always passes the
61
+ // resolved base branch from config / orchestrator detection.
62
+ BASE_BRANCH: args.baseBranch ?? "main",
59
63
  };
60
64
  }
61
65
  function reviewVars(args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valescoagency/runway",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Linear-driven orchestrator + scaffolder for coding agents on Sandcastle. `runway init` scaffolds a target repo (sandcastle + varlock + 1Password); `runway run` drains a Linear queue against it; `runway doctor`, `runway upgrade`, `runway upgrade-repo` round out the lifecycle.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -63,7 +63,7 @@
63
63
  "vitest": "^4.1.6"
64
64
  },
65
65
  "engines": {
66
- "node": ">=22"
66
+ "node": ">=24"
67
67
  },
68
68
  "publishConfig": {
69
69
  "access": "public"
@@ -12,8 +12,15 @@ You are an autonomous coding agent working on a single Linear issue.
12
12
 
13
13
  # Repository context
14
14
 
15
- You are operating inside a clean checkout of the target repository on a
16
- fresh branch named `agent/{{ISSUE_IDENTIFIER}}`. Branch off `main`.
15
+ You are operating on the branch `agent/{{ISSUE_IDENTIFIER}}` based off
16
+ `{{BASE_BRANCH}}` (this repo's default branch — usually `main` or
17
+ `master`). The branch is clean on a first attempt. **On a retry it
18
+ may already carry commits from a prior attempt that review rejected**
19
+ — the rejection reasons then appear in the *Review feedback from
20
+ prior attempts* section above. Your job is to produce a final state
21
+ that addresses every blocker in that feedback, replacing the existing
22
+ commits if they would re-introduce a rejected design. Do not treat
23
+ pre-existing commits as authoritative.
17
24
 
18
25
  # What done looks like
19
26
 
@@ -9,7 +9,7 @@
9
9
  # patches AFTER this base, so adopters re-run `runway init --force`
10
10
  # to roll forward.
11
11
 
12
- FROM node:22-bookworm
12
+ FROM node:24-bookworm
13
13
 
14
14
  # Install system dependencies
15
15
  RUN apt-get update && apt-get install -y \
@@ -48,12 +48,12 @@ RUN if ! getent group $AGENT_GID >/dev/null; then \
48
48
  ENV HOME=/home/agent
49
49
  ENV XDG_CACHE_HOME=/home/agent/.cache
50
50
  ENV TURBO_CACHE_DIR=/tmp/turbo-cache
51
- ENV npm_config_cache=/home/agent/.cache/npm
51
+ ENV pnpm_config_cache=/home/agent/.cache/pnpm
52
52
 
53
53
  # Pre-create cache dirs with agent ownership so the first pnpm/turbo
54
54
  # run doesn't have to chown them. Both are inside paths the agent owns
55
55
  # anyway; this just makes them exist.
56
- RUN mkdir -p /home/agent/.cache /home/agent/.cache/npm /tmp/turbo-cache \
56
+ RUN mkdir -p /home/agent/.cache /home/agent/.cache/pnpm /tmp/turbo-cache \
57
57
  && chown -R $AGENT_UID:$AGENT_GID /home/agent/.cache /tmp/turbo-cache
58
58
 
59
59
  # Bake pnpm via corepack at build time so `pnpm` is on PATH inside the
@@ -61,7 +61,7 @@ RUN mkdir -p /home/agent/.cache /home/agent/.cache/npm /tmp/turbo-cache \
61
61
  # can override at runtime via `packageManager` in package.json +
62
62
  # `corepack use`.
63
63
  RUN corepack enable \
64
- && corepack prepare pnpm@10.0.0 --activate
64
+ && corepack prepare pnpm@11.1.1 --activate
65
65
 
66
66
  USER ${AGENT_UID}:${AGENT_GID}
67
67
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  # Install varlock via npm. The official `ghcr.io/dmno-dev/varlock`
6
6
  # image is musl/Alpine — copying its binary into a glibc base
7
- # (node:22-bookworm) produces an ELF that the loader can't resolve
7
+ # (node:24-bookworm) produces an ELF that the loader can't resolve
8
8
  # ("not found" on exec). npm install gets the right binary for the
9
9
  # image's libc.
10
10
  USER root