specrails-desktop 2.42.2 → 2.43.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/docs/ci-cd.md +1 -1
- package/docs/codex.md +2 -2
- package/docs/customizing.md +1 -1
- package/docs/gemini.md +3 -3
- package/docs/getting-started.md +1 -1
- package/docs/internals/interactive-jobs.md +53 -0
- package/package.json +1 -1
- package/server/dist/core-package.js +7 -4
- package/server/dist/loop-executors.js +14 -1
package/docs/ci-cd.md
CHANGED
|
@@ -42,7 +42,7 @@ The macOS job retains `artifacts/chromium-signing/` as the `chromium-signing-mac
|
|
|
42
42
|
## Credentials and external requirements
|
|
43
43
|
|
|
44
44
|
- `RELEASE_PAT` must be authorized for release-please's pull requests and releases. It also permits tag pushes to trigger publication workflows; events created with the repository's ordinary `GITHUB_TOKEN` generally do not trigger another workflow.
|
|
45
|
-
- `NPM_TOKEN` must authenticate an account with publishing permission for `specrails-desktop
|
|
45
|
+
- Publication uses one of two credentials. When the `NPM_TOKEN` secret is set, it must authenticate an account with publishing permission for `specrails-desktop` (npm now requires such tokens to be granular with *bypass 2FA*, and they expire within 90 days); the workflow checks authentication and gives an explicit error before publishing. When the secret is empty, the job publishes through npm **trusted publishing**: it installs npm 11, removes the empty token line that `setup-node` writes, and lets npm exchange the job's OIDC identity (`id-token: write`) for a short-lived publish grant. That path only works once the package's *Trusted publisher* on npmjs.com names this repository (`fjpulidop/specrails-desktop`) and workflow file (`npm-publish.yml`, no environment); registry configuration is never changed from here. Provenance does **not** grant publishing permission in either mode. An npm `E404` during publication is npm's answer to an unauthorized publish and does not identify which token or permission failed; an `E403` mentioning two-factor authentication means the stored token lacks *bypass 2FA*. [npm publishing and provenance](https://docs.github.com/en/actions/tutorials/publish-packages/publish-nodejs-packages).
|
|
46
46
|
- Existing Apple signing/notarization and Tauri updater signing secrets remain required. Installer build steps retain their platform-specific checks.
|
|
47
47
|
- Hostinger credentials must support **explicit FTPS**, a valid TLS certificate, uploads and `RNFR`/`RNTO` in the release directory. There is no plaintext FTP fallback. A failed transfer or rename fails the workflow before old files are removed. [FTP action protocol and security options](https://github.com/SamKirkland/FTP-Deploy-Action/blob/v4.3.6/action.yml).
|
|
48
48
|
|
package/docs/codex.md
CHANGED
|
@@ -46,9 +46,9 @@ binary isn't on `PATH`; it shows install commands if you click "More info".
|
|
|
46
46
|
The first provider you select becomes the project default.
|
|
47
47
|
4. Submit. The app writes `.specrails/install-config.yaml` (with
|
|
48
48
|
`provider: codex` and `tier: quick` as YAML keys) and spawns
|
|
49
|
-
`npx --yes --prefer-online specrails-core@^
|
|
49
|
+
`npx --yes --prefer-online specrails-core@^5.1.0 init --yes --from-config <file>`
|
|
50
50
|
— the provider and tier live in the YAML, not as CLI flags. (The app
|
|
51
|
-
pins `specrails-core@^
|
|
51
|
+
pins `specrails-core@^5.1.0`; that floor is the version that ships the
|
|
52
52
|
current provider targets, including Kimi and the Codex skill set.) The install
|
|
53
53
|
produces:
|
|
54
54
|
- `.codex/config.toml` — model, reasoning effort, sandbox mode, and
|
package/docs/customizing.md
CHANGED
|
@@ -148,7 +148,7 @@ Most settings live in the UI. A few app-level switches are env-only because they
|
|
|
148
148
|
|
|
149
149
|
| Variable | Effect |
|
|
150
150
|
|----------|--------|
|
|
151
|
-
| `SPECRAILS_CORE_BIN` | Override the `specrails-core` binary (default: `npx --yes --prefer-online specrails-core@^
|
|
151
|
+
| `SPECRAILS_CORE_BIN` | Override the `specrails-core` binary (default: `npx --yes --prefer-online specrails-core@^5.1.0` — the 5.1.0 floor is the release that quotes the command path in its Windows shell runner, so OpenSpec init works from an install directory with spaces; it is also the version bundled with the app) |
|
|
152
152
|
| `SPECRAILS_TECH_URL` | Override the specrails-tech proxy base URL |
|
|
153
153
|
| `SPECRAILS_AGENTS_SECTION=false` | Hide the Agents section from every project |
|
|
154
154
|
| `SPECRAILS_PLUGINS_SECTION=false` | Hide the Integrations section from every project |
|
package/docs/gemini.md
CHANGED
|
@@ -24,11 +24,11 @@ Specrails supports **four AI providers**: Anthropic's
|
|
|
24
24
|
|---|---|---|
|
|
25
25
|
| `gemini` CLI ≥ 0.11.0 | Earlier versions lack `--output-format stream-json` + headless `--resume`, which the app relies on | `npm i -g @google/gemini-cli` · check with `gemini --version` |
|
|
26
26
|
| A Gemini API key | The app spawns Gemini headlessly, so it needs non-interactive auth | Set `GEMINI_API_KEY` to a paid Gemini Developer API key from [Google AI Studio](https://aistudio.google.com/apikey) |
|
|
27
|
-
| `specrails-core` ≥ 4.8.0 in the project | 4.8.0 ships the Gemini provider target (`.gemini/` commands + agents) that the rails pipeline needs | The current Add-Project install flow uses `specrails-core@^
|
|
27
|
+
| `specrails-core` ≥ 4.8.0 in the project | 4.8.0 ships the Gemini provider target (`.gemini/` commands + agents) that the rails pipeline needs | The current Add-Project install flow uses `specrails-core@^5.1.0` automatically |
|
|
28
28
|
| `git`, `node`, `npm`, `npx` | Same as Claude — needed for `specrails-core init` | Use your usual installer |
|
|
29
29
|
|
|
30
30
|
> **Two different minimums.** The `gemini` **binary** floor is **0.11.0**.
|
|
31
|
-
> The current Desktop `specrails-core` **package** floor is **
|
|
31
|
+
> The current Desktop `specrails-core` **package** floor is **5.1.0** (a
|
|
32
32
|
> single shared version for all providers, including Kimi). They are separate
|
|
33
33
|
> things — the binary on your
|
|
34
34
|
> machine vs. the artifacts installed into the project.
|
|
@@ -52,7 +52,7 @@ the Gemini provider checkbox with a "not found" hint when the binary isn't on
|
|
|
52
52
|
project](#running-multiple-providers-in-one-project)). The first provider
|
|
53
53
|
you select becomes the project default.
|
|
54
54
|
4. Submit. The app writes `.specrails/install-config.yaml` and spawns
|
|
55
|
-
`npx --yes --prefer-online specrails-core@^
|
|
55
|
+
`npx --yes --prefer-online specrails-core@^5.1.0 init --yes --from-config <file>`.
|
|
56
56
|
The install produces the `.gemini/` artifacts (commands + `sr-*` agents),
|
|
57
57
|
plus a `GEMINI.md` instructions file.
|
|
58
58
|
|
package/docs/getting-started.md
CHANGED
|
@@ -61,7 +61,7 @@ specrails-desktop list # verify
|
|
|
61
61
|
The setup wizard runs automatically. Three steps:
|
|
62
62
|
|
|
63
63
|
1. **Configure** — choose which agents to install (the baseline trio `sr-architect`, `sr-developer`, `sr-reviewer` is always selected; optional agents like Test Writer or Security Reviewer are opt-in). Pick a model preset (Balanced / Budget / Max) and optionally override the model per agent.
|
|
64
|
-
2. **Install** — the app runs the installer (`npx --yes --prefer-online specrails-core@^
|
|
64
|
+
2. **Install** — the app runs the installer (`npx --yes --prefer-online specrails-core@^5.1.0 init --yes --from-config <config>`) non-interactively and streams the output live. The version is pinned to the core release the app ships with — it never silently jumps to a new major.
|
|
65
65
|
3. **Done** — a summary tells you how many agents and commands landed. Click **Continue to project**.
|
|
66
66
|
|
|
67
67
|
That's the whole onboarding. No tier picker, no second wizard. You can manage agents and their per-agent models later from the **Agents** page (Profiles tab).
|
|
@@ -314,3 +314,56 @@ delivery row — stranded uncommitted work. Loops disabled ⇒ the legacy QueueM
|
|
|
314
314
|
unchanged. Relatedly, the agent-chat operator prompt gained the ask-confirmation-once
|
|
315
315
|
turn-discipline rule (`server/agent-operator-prompt.ts`): a confirmation question is asked
|
|
316
316
|
exactly once and ends the reply — the answer arrives as the next user message.
|
|
317
|
+
|
|
318
|
+
## Decider starved by its own tool budget (2026-09-07)
|
|
319
|
+
|
|
320
|
+
A two-repo `factory:implement` run (pipeline run `47b9a423`) finished its work, and the
|
|
321
|
+
verify step answered `VERIFICATION: PASS` with a freshly re-run receipt across both
|
|
322
|
+
repositories. The loop continued anyway. The Decider step's log line was the tell:
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
Decision: continue — error_max_turns: Reached maximum number of turns (1)
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
That is not a verdict. The Decider never emitted one — it died before answering, and the
|
|
329
|
+
executor's fail-open default did the rest.
|
|
330
|
+
|
|
331
|
+
- **The starvation.** `runDecider` spawned with `maxTurns: 1` *and* `toolPolicy:
|
|
332
|
+
'read-only'`, which on claude is `--tools Read,Grep,Glob` **plus `--permission-mode plan
|
|
333
|
+
--safe-mode`**. One tool call — a repo read, or plan mode's own exit call — consumes the
|
|
334
|
+
single allowed turn, so the run ends `error_max_turns` **before** the JSON verdict is
|
|
335
|
+
produced. Nothing about it is intermittent: a Decider that touches any tool can never
|
|
336
|
+
answer. The step burned 2 turns and ~$0.09 to say nothing.
|
|
337
|
+
- **Reproduced across loops and tiers.** A `SDD Quick (OpenSpec)` run on claude/**sonnet**
|
|
338
|
+
showed the identical signature — every Decider step `2 turns`, ~7 s, `Decision: continue
|
|
339
|
+
— error_max_turns`. Its verify step reported `VERIFICATION: PASS` twice, and the loop
|
|
340
|
+
still cycled `opsx:ff → opsx:apply → opsx:verify` for two full iterations (the fix steps
|
|
341
|
+
correctly finding nothing to do and saying so) until the user cancelled it. So the bug is
|
|
342
|
+
not model-, tier- or loop-specific: it is every Decider on claude.
|
|
343
|
+
- **Why it became a `continue`.** A failed Decider invocation is deliberately forced to
|
|
344
|
+
`{ continue: true, parsed: false }` — a streamed verdict from an interrupted run is not
|
|
345
|
+
an authoritative completion gate, and `maxIterations`/`timeout` are the hard stop. Sound
|
|
346
|
+
in isolation, but combined with the starvation above it meant *every* such run silently
|
|
347
|
+
discarded a real STOP and paid for another iteration: here a fix step that invented work
|
|
348
|
+
(tautological cascade tests, a mutation probe, a wrong conclusion, then a full revert)
|
|
349
|
+
plus a second full re-verification, for no change to the delivered candidate.
|
|
350
|
+
- **The fix.** The Decider judges from the prompt it is GIVEN (goal + spec + iteration
|
|
351
|
+
history) and must answer with one JSON object, so it needs no tools at all.
|
|
352
|
+
`runDecider` now picks the tightest boundary the CLI enforces via
|
|
353
|
+
`pureOutputToolPolicy(adapter)`: `'none'` on claude (`--tools __none__`, no approval
|
|
354
|
+
bypass needed), `'read-only'` on codex/gemini — byte-identical there, since neither has
|
|
355
|
+
a native no-tools mode. The null case is unreachable: `LoopRunManager.run` already
|
|
356
|
+
rejects a decider-bearing graph whose provider cannot enforce `read-only` natively
|
|
357
|
+
(kimi), before allocating or persisting the run. `'none'` also drops the plan-mode flags
|
|
358
|
+
(the adapter attaches them only to `read-only`), removing the second way the single turn
|
|
359
|
+
could be consumed. This aligns the Decider with the repo's other single-turn spawns —
|
|
360
|
+
`file-summary-generator.ts` and both `contract-refine-runner.ts` invocations already
|
|
361
|
+
resolve a pure-output policy rather than hardcoding `read-only`; the Decider was the last
|
|
362
|
+
one left with tools it could not afford to use.
|
|
363
|
+
- **Deliberately NOT changed:** the fail-open `continue` on a genuinely failed Decider
|
|
364
|
+
(timeout, spawn failure, non-zero exit, provider limit). The starvation was the bug; the
|
|
365
|
+
default is the safety net, and with tools gone it stops firing on every healthy run.
|
|
366
|
+
- **Adjacent, still open:** the verify step re-ran the full cross-repository suite each
|
|
367
|
+
iteration because the Core receipt is invalidated per session (*"Verification environment
|
|
368
|
+
changed: ./mvnw / npm"*) even when the candidate hash is identical. That is a receipt
|
|
369
|
+
env-hash question in specrails-core, not a desktop one.
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CORE_PACKAGE_SPEC = void 0;
|
|
4
|
-
/** Online fallback selects the supported Core 5 lifecycle.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
4
|
+
/** Online fallback selects the supported Core 5 lifecycle; 5.1.0 is the floor
|
|
5
|
+
* because it quotes the command path in its Windows shell runner (OpenSpec init
|
|
6
|
+
* from an install directory with spaces). The desktop bundles the same version.
|
|
7
|
+
* Bundled Core 4 remains readable for installed apps; the runtime resolver
|
|
8
|
+
* selects the newest usable compatible package and never downgrades a newer
|
|
9
|
+
* activated framework. */
|
|
10
|
+
exports.CORE_PACKAGE_SPEC = 'specrails-core@^5.1.0';
|
|
@@ -488,7 +488,20 @@ function createLoopExecutors(opts = {}) {
|
|
|
488
488
|
const decEnv = aiStepEnv(baseEnv, repoDir, executionManifest);
|
|
489
489
|
// spec-gen is a one-shot, system-prompted invocation (workspace-write on
|
|
490
490
|
// codex, not full-access) — appropriate for a read-only judgment.
|
|
491
|
-
|
|
491
|
+
//
|
|
492
|
+
// The Decider judges the goal from the prompt it is GIVEN (goal + spec +
|
|
493
|
+
// iteration history) and must answer with a single JSON object, so it
|
|
494
|
+
// needs no tools. Granting them was actively harmful on claude: with
|
|
495
|
+
// `--max-turns 1`, one Read/Grep call consumes the whole turn budget and
|
|
496
|
+
// the run ends `error_max_turns` BEFORE the verdict is emitted. A failed
|
|
497
|
+
// Decider invocation is forced to `continue` below, so every such run
|
|
498
|
+
// silently discarded a real STOP verdict and burned another iteration.
|
|
499
|
+
// `pureOutputToolPolicy` picks the tightest boundary the CLI enforces:
|
|
500
|
+
// 'none' on claude, 'read-only' on codex/gemini (byte-identical to the
|
|
501
|
+
// previous behaviour there). The null case is unreachable — `run()`
|
|
502
|
+
// rejects a decider graph whose provider cannot enforce 'read-only'.
|
|
503
|
+
const toolPolicy = (0, runtime_1.pureOutputToolPolicy)(adapter) ?? 'read-only';
|
|
504
|
+
const buildOpts = { prompt: userPrompt, systemPrompt, model, maxTurns: 1, reasoning_effort: effort, toolPolicy, ...(executionManifest ? { extraArgs: aiStepExtraArgs(adapter, cwd, repoDir, executionManifest) } : {}) };
|
|
492
505
|
const wallStartedAt = Date.now();
|
|
493
506
|
const res = await (0, spawn_lifecycle_1.runAiCliInvocation)({
|
|
494
507
|
adapter,
|