@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syntax-syllogism/aloop",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "Syntax & Syllogism agentic loop runner.",
5
5
  "type": "module",
6
6
  "exports": {
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', 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
- if (!['EEXIST', 'ENOTEMPTY'].includes(error.code)) throw error;
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