@syntax-syllogism/aloop 0.8.1 → 0.8.3
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/CHANGELOG.md +38 -42
- package/package.json +1 -1
- package/src/adapters.mjs +12 -2
- package/src/pipeline.mjs +5 -1
- package/src/state.mjs +19 -1
- package/src/types.d.ts +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0/).
|
|
7
7
|
|
|
8
|
+
## [0.8.0] - 2026-09-20
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Eval harness for running code across multiple models
|
|
13
|
+
- JSDoc type checking for validation
|
|
14
|
+
- Live TUI renderer for interactive aloop runs
|
|
15
|
+
- aloop init command for project initialization
|
|
16
|
+
- Guided resume capability to repair failing gates
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- TUI renderer now runs even with --yes flag
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- JSDoc type contracts bound to production boundaries
|
|
25
|
+
- Fixed TUI rendering performance with diff-stat caching
|
|
26
|
+
- Resume repair and downstream attestation restored
|
|
27
|
+
|
|
8
28
|
## [0.7.0] - 2026-09-18
|
|
9
29
|
|
|
10
30
|
### Added
|
|
@@ -17,6 +37,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
17
37
|
Gemini has no reasoning-effort flag, so a configured `effort` is ignored for
|
|
18
38
|
it.
|
|
19
39
|
|
|
40
|
+
## [0.6.2] - 2026-09-16
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- Resolve Windows executables to correct on-disk casing
|
|
45
|
+
|
|
20
46
|
## [0.6.0] - 2026-09-14
|
|
21
47
|
|
|
22
48
|
### Added
|
|
@@ -60,6 +86,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
60
86
|
- Handle a failed Windows timeout teardown and isolate POSIX tests from
|
|
61
87
|
Windows CI.
|
|
62
88
|
|
|
89
|
+
## [0.5.2] - 2026-09-13
|
|
90
|
+
|
|
91
|
+
### Changed
|
|
92
|
+
|
|
93
|
+
- Internal maintenance and tooling updates
|
|
94
|
+
|
|
95
|
+
## [0.5.1] - 2026-09-13
|
|
96
|
+
|
|
97
|
+
### Changed
|
|
98
|
+
|
|
99
|
+
- Internal maintenance and tooling updates
|
|
100
|
+
|
|
63
101
|
## [0.5.0] - 2026-09-12
|
|
64
102
|
|
|
65
103
|
### Added
|
|
@@ -82,15 +120,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
82
120
|
- Wiki commit preservation with cron scheduling
|
|
83
121
|
- Output streaming for long-running phases to prevent false hang detection
|
|
84
122
|
|
|
85
|
-
## [Unreleased]
|
|
86
|
-
|
|
87
123
|
---
|
|
88
124
|
|
|
89
125
|
## Pre-extraction history
|
|
90
126
|
|
|
91
127
|
History from before the standalone extraction (changesets format), preserved for reference.
|
|
92
128
|
|
|
93
|
-
|
|
94
129
|
## 0.4.6
|
|
95
130
|
|
|
96
131
|
### Patch Changes
|
|
@@ -194,42 +229,3 @@ History from before the standalone extraction (changesets format), preserved for
|
|
|
194
229
|
rather than assuming `origin` in repos with several remotes.
|
|
195
230
|
- Prompts ship with the package and are overridable per phase from
|
|
196
231
|
`.loop/prompts/` in the consuming project.
|
|
197
|
-
|
|
198
|
-
## [0.8.0] - 2026-09-20
|
|
199
|
-
|
|
200
|
-
### Added
|
|
201
|
-
|
|
202
|
-
- Eval harness for running code across multiple models
|
|
203
|
-
- JSDoc type checking for validation
|
|
204
|
-
- Live TUI renderer for interactive aloop runs
|
|
205
|
-
- aloop init command for project initialization
|
|
206
|
-
- Guided resume capability to repair failing gates
|
|
207
|
-
|
|
208
|
-
### Changed
|
|
209
|
-
|
|
210
|
-
- TUI renderer now runs even with --yes flag
|
|
211
|
-
|
|
212
|
-
### Fixed
|
|
213
|
-
|
|
214
|
-
- JSDoc type contracts bound to production boundaries
|
|
215
|
-
- Fixed TUI rendering performance with diff-stat caching
|
|
216
|
-
- Resume repair and downstream attestation restored
|
|
217
|
-
|
|
218
|
-
## [0.6.2] - 2026-09-16
|
|
219
|
-
|
|
220
|
-
### Fixed
|
|
221
|
-
|
|
222
|
-
- Resolve Windows executables to correct on-disk casing
|
|
223
|
-
|
|
224
|
-
## [0.5.2] - 2026-09-13
|
|
225
|
-
|
|
226
|
-
### Changed
|
|
227
|
-
|
|
228
|
-
- Internal maintenance and tooling updates
|
|
229
|
-
|
|
230
|
-
## [0.5.1] - 2026-09-13
|
|
231
|
-
|
|
232
|
-
### Changed
|
|
233
|
-
|
|
234
|
-
- Internal maintenance and tooling updates
|
|
235
|
-
|
package/package.json
CHANGED
package/src/adapters.mjs
CHANGED
|
@@ -413,16 +413,26 @@ const geminiAdapter = {
|
|
|
413
413
|
// until the process exits, so a multi-minute phase is indistinguishable from
|
|
414
414
|
// a hang. stream-json emits an event per step, which `createRenderer` turns
|
|
415
415
|
// back into readable lines — same reasoning as the claude adapter above.
|
|
416
|
+
//
|
|
417
|
+
// The prompt goes on stdin, not `--prompt`. Gemini's Windows launcher is a
|
|
418
|
+
// `.cmd`/`.ps1` shim, so on Git Bash aloop runs it through `cmd.exe /c`
|
|
419
|
+
// (see command.mjs windowsSpawnSpec). cmd.exe caps the whole command line at
|
|
420
|
+
// ~8191 chars and mangles newlines and metacharacters (`% ! & | < >`), so a
|
|
421
|
+
// real review prompt — work item plus instructions — arrives truncated or
|
|
422
|
+
// garbled and Gemini "ignores" it. stdin is a pipe cmd.exe never parses, so
|
|
423
|
+
// the prompt survives intact. `-p ""` still selects headless mode; Gemini
|
|
424
|
+
// documents `--prompt` as "appended to input on stdin", so an empty flag
|
|
425
|
+
// leaves the stdin prompt as the whole prompt.
|
|
416
426
|
const canWrite = permissionLevel(permissions) === PERMISSIONS.WRITE_WORKTREE || artifactOnly;
|
|
417
427
|
const args = [
|
|
418
|
-
'--prompt',
|
|
428
|
+
'--prompt', '',
|
|
419
429
|
'--approval-mode', canWrite ? 'yolo' : 'plan',
|
|
420
430
|
'--skip-trust',
|
|
421
431
|
'--output-format', 'stream-json',
|
|
422
432
|
];
|
|
423
433
|
if (agent.model) args.push('--model', agent.model);
|
|
424
434
|
for (const dir of addDirs) args.push('--include-directories', dir);
|
|
425
|
-
return { command: 'gemini', args };
|
|
435
|
+
return { command: 'gemini', args, input: prompt };
|
|
426
436
|
},
|
|
427
437
|
createRenderer: () => createJsonlRenderer(renderGeminiEvent),
|
|
428
438
|
};
|
package/src/pipeline.mjs
CHANGED
|
@@ -491,7 +491,7 @@ async function runAgent(phase, ctx, variables) {
|
|
|
491
491
|
// writable. Every other artifact-only phase — pr-description included — gets
|
|
492
492
|
// just its own run directory; it has no business touching the task file repo.
|
|
493
493
|
const artifactOnlyDirs = phase.role === 'verdict' ? ctx.artifactDirs : [ctx.state.dir];
|
|
494
|
-
const { command, args } = adapter.command({
|
|
494
|
+
const { command, args, input } = adapter.command({
|
|
495
495
|
prompt,
|
|
496
496
|
cwd: agentCwd,
|
|
497
497
|
addDirs: worktreeWrite ? ctx.addDirs : [...artifactOnlyDirs, ...(sourceSnapshot ? [sourceSnapshot.path] : [])],
|
|
@@ -539,6 +539,10 @@ async function runAgent(phase, ctx, variables) {
|
|
|
539
539
|
env: execution.env,
|
|
540
540
|
timeoutMs: ctx.config.timeoutMs,
|
|
541
541
|
activeProcessPath: ctx.activeProcessPath,
|
|
542
|
+
// Adapters that carry the prompt on stdin (gemini, to dodge the cmd.exe
|
|
543
|
+
// command-line limit on Windows) return it as `input`; a hermetic wrapper
|
|
544
|
+
// forwards stdin to the sandboxed process unchanged.
|
|
545
|
+
input,
|
|
542
546
|
onOutput: (text, stream) => emit(stream === 'stderr' ? text : renderer.write(text)),
|
|
543
547
|
});
|
|
544
548
|
} catch (error) {
|
package/src/state.mjs
CHANGED
|
@@ -37,6 +37,15 @@ function isActiveProcessAlive(activeProcess) {
|
|
|
37
37
|
return isProcessGroupAlive(activeProcess?.processGroupId) || isProcessAlive(activeProcess?.pid);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
async function pathExists(path) {
|
|
41
|
+
try {
|
|
42
|
+
await access(path);
|
|
43
|
+
return true;
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
async function readActiveProcess(dir) {
|
|
41
50
|
try {
|
|
42
51
|
return JSON.parse(await readFile(join(dir, 'active-command.json'), 'utf8'));
|
|
@@ -238,7 +247,16 @@ export class RunState {
|
|
|
238
247
|
await publishLock(path, lockToken, contents);
|
|
239
248
|
return lockToken;
|
|
240
249
|
} catch (error) {
|
|
241
|
-
|
|
250
|
+
// POSIX rejects a rename onto the existing (non-empty) lock directory
|
|
251
|
+
// with EEXIST/ENOTEMPTY — the signal that the lock is already held.
|
|
252
|
+
// Windows rejects the same rename with EPERM (sometimes EACCES)
|
|
253
|
+
// instead, so without this a `--resume` that finds any prior lock dir
|
|
254
|
+
// crashes with "EPERM: operation not permitted, rename". Treat those as
|
|
255
|
+
// contention too, but only when the lock path is actually present, so a
|
|
256
|
+
// genuine permission failure still surfaces instead of spinning here.
|
|
257
|
+
const contended = ['EEXIST', 'ENOTEMPTY'].includes(error.code)
|
|
258
|
+
|| (['EPERM', 'EACCES'].includes(error.code) && await pathExists(path));
|
|
259
|
+
if (!contended) throw error;
|
|
242
260
|
}
|
|
243
261
|
|
|
244
262
|
let existing;
|
package/src/types.d.ts
CHANGED
|
@@ -70,6 +70,12 @@ export interface AdapterCommandOptions {
|
|
|
70
70
|
export interface AdapterCommand {
|
|
71
71
|
command: string;
|
|
72
72
|
args: string[];
|
|
73
|
+
/**
|
|
74
|
+
* Optional stdin for the command. Adapters use it to carry the prompt off the
|
|
75
|
+
* argument vector (gemini does, to dodge the cmd.exe command-line limit on
|
|
76
|
+
* Windows) rather than passing it as an argv element.
|
|
77
|
+
*/
|
|
78
|
+
input?: string;
|
|
73
79
|
[key: string]: unknown;
|
|
74
80
|
}
|
|
75
81
|
|