Skip to content

fix(orchestration): never spawn visual terminals from test runners - #803

Closed
Pedrovaleriolopez wants to merge 46 commits into
mainfrom
fix/terminal-spawner-no-visual-under-tests
Closed

fix(orchestration): never spawn visual terminals from test runners#803
Pedrovaleriolopez wants to merge 46 commits into
mainfrom
fix/terminal-spawner-no-visual-under-tests

Conversation

@Pedrovaleriolopez

@Pedrovaleriolopez Pedrovaleriolopez commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Problema

As suítes tests/core/terminal-spawner.test.js e tests/core/orchestration/terminal-spawner.test.js chamam o spawnAgent()/spawnInline() REAIS, sem nenhum mock. Em macOS nativo (fora de CI/VS Code/SSH), cada execução de npm test tomava o caminho visual — pm.sh → osascript → Terminal.app — e abria dezenas de janelas reais de Terminal na máquina do usuário (reportado nas instalações do Alan Nicolas e Thiago Finch, agentes rodando npm test como quality gate). Além disso, spawnInline invocava o CLI claude real a partir dos testes (gasto de tokens).

Fix

  • terminal-spawner.jsdetectEnvironment() ganha o tipo TEST: spawn visual só é concedido quando o ambiente é nativo E não há test-runner (JEST_WORKER_ID) E não há opt-out via AIOX_NO_VISUAL=true.
  • pm.sh — mesmo guard em spawn_terminal() (defesa em profundidade para qualquer chamador); AIOX_NO_VISUAL documentada no --help.
  • Testes — stub CLAUDE_CMD=true nos describes que executam o spawner de verdade (nunca mais invocam o claude real); 3 testes de regressão do guard, incluindo "rodando sob jest, supportsVisualTerminal é sempre false".
  • Registry IDS + install-manifest sincronizados (2º commit).

Verificação

  • 77/77 testes passando nas duas suítes (5.3s; o teste que abria as janelas caiu de ~5s de timeout para ~430ms).
  • pm.sh dev test manual com JEST_WORKER_ID=1 e com AIOX_NO_VISUAL=true força Running in inline mode — nenhuma janela.

Mitigação imediata para instalações afetadas (antes do release)

CI=true npm test ou export AIOX_NO_VISUAL=true.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added aiox sdc commands for story lifecycle planning, status, verification, and phase progression.
    • Added aiox wave commands for dependency-aware planning, batch execution, progress tracking, and reporting.
    • Added configurable Synapse pipeline timeouts and session heuristic reinforcement.
    • Added security checks for unsafe paths, prompt injection, SSRF, and prohibited content.
  • Bug Fixes

    • Improved Windows npx installation guidance and test-runner reliability.
  • Documentation

    • Added guidance for SDC workflows, wave execution, story locations, governance, and IDE synchronization.

Introduce .grok/ integration with token-efficient agent profiles,
slash skills, roles, personas, and compact rules. Add regenerable
sync script (npm run sync:skills:grok) so Grok stays aligned with
.source agents under .aiox-core/development/agents/.
Clarify the generator module purpose so entity-registry extraction no
longer picks an unrelated CodeRabbit comment string.
Make Claude subagent governance validate the core aiox-* set instead of
exact directory equality, and guard dev-context-loader cacheHits when
status/shape is incomplete.
CI Install Manifest Validation failed because data/entity-registry.yaml
hash no longer matched install-manifest.yaml after IDS updates.
Escape YAML/TOML scalars, constrain generated write paths under .grok/,
block git push for squad-creator, label markdown fences, and keep the
cacheHits > 0 assertion in dev-context-loader.
Keep install-manifest hash aligned with entity-registry so CI
Install Manifest Validation stays green.
Branch off PR #800 (Grok). Captures P0–P2 waves for SDC skills, runtime
hygiene, orchestration merge, IDE parity, and selective constitution
updates without importing Sinkra product or enterprise IP.

Note: docs/stories is gitignored; force-add for this framework epic only.
MVP cut (A+B), hard A3 merge gates, B0 lean spike, denylist CI story,
deferred D5/E4/F3, semver ship train, tightened A1 ACs. Full finding
resolution table embedded in epic (100% resolved).
…first)

Address architect-first findings: public versionable path (no force-add
gitignored docs/stories), drop stale stories index, ARCH-A slice, A2 as
#797 residual investigation (unref already present), permissions metric
clarified (extend not replace), Wave B–E blocked until per-wave ARCH,
hard ban on workspace/ in OSS, hub XI/XII numbering locked for constitution.
…s/docs

Engine already resolves AIOX_SYNAPSE_PIPELINE_TIMEOUT_MS > core-config
synapse.pipelineTimeoutMs > 100ms default with clamp and timeout warn.
Add unit coverage for precedence/invalid values/soft-fail path and
document knobs in config-override-guide. Closes #798 when merged.
…config

Export resolvePipelineTimeoutMs (env > config > 100ms default, clamp
1-30000), soft-fail remaining layers with console.warn. Config key
synapse.pipelineTimeoutMs. Completes CORE-SU.A1 implementation.
unref() alone still allows post-teardown callbacks. Skip setInterval when
JEST_WORKER_ID is set; keep production timer + unref; gate logs on AIOX_DEBUG;
export disposeConfigCacheTimers. Applies to core and infrastructure copies.
CORE-SU.A2 YOLO.
Extend core/permissions without replacing PermissionMode/OperationGuard.
OSS path deny list excludes product workspace/ trees. Unit tests for
traversal, injection patterns, private/metadata SSRF. Wave A P0.
Add scan for hub/enterprise leakage (workspace product paths, sinkra_*,
mux-adapter, coolify, machine paths). npm run validate:port-denylist;
doctor check port-denylist. Completes Wave A.
Ship OSS lean SDC skill wrappers (validate → develop → review →
apply-qa-fixes → close + full-sdc orchestrator) with tasks as SOT.
Wire grok-skills-sync to copy development/skills → .grok/skills/aiox-*.
Sequence Lock: only close-story sets Done. No product harvest trees.
Add lean SDC/wave engines under .aiox-core/core/sdc with aiox sdc and
aiox wave CLI for plan/next/verify/progress. Upgrade full-sdc skill to
EXECUTE loop; add wave-execute that dispatches full-sdc children via
DAG + file-ownership batches. Grok skills synced; unit tests included.
Close CORE-SU.A1 with hook-runtime synapse config wiring and QA PASS.
Add ARCH-C and wave-run advance/mark/cascade/report CLI. Normalize A2–A4
to Done; package scripts sdc/wave; unit tests for wave-run.
Scan .claude surfaces; fail closed on unreadable paths; doctor wraps
scan errors. Apply lint formatting to sdc/wave-run modules.
Execute CORE-SU-C wave: dispatch-adapter (parallel/sequential pool),
epic-glue + aiox wave from-epic, tests (23). Stories C2–C4 Done;
wave report completed. Skills updated for from-epic flow.
Add install-time hint, doctor windows-npx-install check (17 total),
and docs for cold-cache lock timeout. ARCH-D/E drafts unlock stretch
planning. Wave CORE-SU-F completed via full-sdc.
Remove pm.sh echo-stub: invoke CLAUDE_CMD/claude or fail closed.
Port OSS-safe Articles XI (Squad-First) and XII (Model Governance).
Add ide-sync-contract (D1) and closeout stories for wave-execute.
Official policy: docs/framework/epics/ for versioned framework OSS work;
docs/stories/ remains project L4 (gitignored template). Align AGENTS.md,
CLAUDE.md, story-lifecycle paths, and Grok sync prompts. Gitignore .codex/
until absolute paths / force-push wording are hardened for OSS.
Add npm run diff:framework-3way (peer discovery via env/flags), doctor
advisory framework-3way-diff (18 checks), and ANALYSIS-3WAY-CORRECTIONS
from verified OSS×hub×enterprise facts. Prefer enterprise lean full-sdc
as skill enrichment base; never blind-merge OSS-wins modules.
Cold/warm timeouts, processSessionDigest + debounced reinforce worker,
OSS global-heuristic-hints.yaml, and heuristics unit tests. Does not
replace hook-runtime wholesale. Graceful when MIS absent.
oalanicolas and others added 15 commits July 9, 2026 11:40
Mark epic complete for ship; document optional/deferred backlog as
out-of-release. Gitignore legacy .claude/skills/aios-*/ local noise
before pre-push and CodeRabbit.
Avoid full tree hash in aiox doctor (was timing out CLI tests when
peers exist). Presence-only advisory; full report stays on
npm run diff:framework-3way.
SSRF fe80::/10 + IPv4-mapped delegation; memory-bridge warm only on
success; wave cascade skip origin; SDC safeId/loadJson/plan validation;
npx hint null-env; port-denylist Windows path; gate match anchoring.
Keep feature-branch Grok sync + dual-path story policy; regenerate
entity-registry, install-manifest, and .grok skills after merge.
Avoid lastVerified thrash on no-op processChanges; covers pre-push
noise from IDS hooks.
…orcement

path-guard.js and ssrf-guard.js (CORE-SU.A3) are exported from
permissions/index.js but are not called by OperationGuard.guard() and
are not registered as a PreToolUse hook. No write path or outbound
request is validated by these guards automatically today.

Add the same standalone-library notice prompt-guard.js already carries
so callers don't assume runtime enforcement is active. No logic changed.

Epic: docs/framework/epics/core-super-update/EPIC-CORE-SUPER-UPDATE.md
The terminal-spawner test suites called the REAL spawnAgent()/spawnInline()
with zero mocks. On a native macOS environment each call took the visual
path (pm.sh -> osascript -> Terminal.app), so every `npm test` run burst
open real Terminal windows on user machines (reported by external installs
running agent sessions over this repo), and spawnInline invoked the real
`claude` CLI.

Fixes:
- terminal-spawner.js: detectEnvironment() gains a TEST environment —
  visual spawn is only granted when native AND not under a test runner
  (JEST_WORKER_ID) AND not opted out via AIOX_NO_VISUAL=true.
- pm.sh: same guard in spawn_terminal() (defense in depth for any caller);
  AIOX_NO_VISUAL documented in --help.
- tests: stub CLAUDE_CMD=true so pm.sh never invokes the real agent CLI
  from tests (no token spend, no dependency on claude being installed);
  new regression tests for the TEST guard.

Verified: both suites pass (77/77); pm.sh with JEST_WORKER_ID or
AIOX_NO_VISUAL=true forces inline mode.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
aiox-core Ready Ready Preview, Comment Jul 10, 2026 2:41pm

Request Review

@github-actions github-actions Bot added type: test Test coverage and quality area: core Core framework (.aios-core/core/) area: installer Installer and setup (packages/installer/) area: synapse SYNAPSE context engine area: cli CLI tools (bin/, packages/aios-pro-cli/) area: docs Documentation (docs/) labels Jul 10, 2026
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Walkthrough

This PR adds CLI-driven SDC and wave execution, durable workflow state, phase verification, security guards, doctor checks, configurable Synapse behavior, Windows install guidance, IDE skill synchronization, governance documentation, and related tests and generated metadata.

Changes

SDC and wave execution

Layer / File(s) Summary
CLI and durable orchestration
.aiox-core/cli/..., .aiox-core/core/sdc/..., bin/aiox.js, package.json
Adds aiox sdc and aiox wave commands backed by story parsing, phase state, wave planning, dependency-aware batching, dispatch, reporting, and persisted JSON state.
Security and doctor checks
.aiox-core/core/permissions/*, .aiox-core/core/security/*, .aiox-core/core/doctor/*, scripts/validate-port-denylist.js
Adds path, prompt, SSRF, and port-denylist checks plus Windows npx and framework drift doctor checks.
Synapse and runtime hygiene
.aiox-core/core/synapse/*, .aiox-core/core/config/*, .aiox-core/core/orchestration/*, .aiox-core/scripts/*
Adds configurable pipeline timeouts, MemoryBridge heuristic reinforcement, test-aware cache timers, non-visual execution handling, and registry mutation detection.
Workflow and governance surfaces
.aiox-core/constitution.md, .aiox-core/development/skills/*, .claude/*, .grok/*, docs/framework/*
Adds constitution articles, SDC/wave skill protocols, story-location and IDE-sync contracts, and framework architecture/story documentation.
Validation and generated metadata
tests/*, packages/installer/tests/*, .aiox-core/install-manifest.yaml, .aiox-core/data/entity-registry.yaml
Expands unit/integration coverage and regenerates installation and entity metadata for the added surfaces.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested labels: area: workflows

Suggested reviewers: oalanicolas

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: preventing visual terminal spawning during test runs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/terminal-spawner-no-visual-under-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (21)
.aiox-core/constitution.md-141-147 (1)

141-147: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Specify a language for the portability hierarchy fence.

Use text (or another appropriate identifier) to satisfy Markdown MD040.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/constitution.md around lines 141 - 147, Specify the fenced code
block language as text for the portability hierarchy diagram in the constitution
document, replacing the unlabeled fence while preserving its contents.

Source: Linters/SAST tools

docs/guides/installation-troubleshooting.md-93-97 (1)

93-97: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Specify the language for the error-output fence.

Use an identifier such as text to resolve the reported Markdown MD040 warning.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/guides/installation-troubleshooting.md` around lines 93 - 97, Specify
the `text` language identifier on the fenced error-output block in the
installation troubleshooting guide to resolve the MD040 warning.

Source: Linters/SAST tools

.claude/skills/full-sdc/SKILL.md-20-24 (1)

20-24: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Specify languages for the fenced code blocks.

Add bash or text identifiers to the two fences so Markdown tooling can validate them correctly.

Also applies to: 63-80

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/full-sdc/SKILL.md around lines 20 - 24, Update the fenced
code blocks in the full-sdc documentation, including the examples around the
`/full-sdc` and `aiox sdc plan` commands and the additional affected section, by
adding an appropriate `bash` or `text` language identifier after each opening
fence.

Source: Linters/SAST tools

.aiox-core/core/permissions/prompt-guard.js-163-186 (1)

163-186: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate input in scanInvisibleUnicode() as well.

This function is exported publicly but lacks the explicit string check already used by scan(). Add the same validation and cover it with a regression test so invalid inputs fail with the module’s intentional error message.

Suggested fix
 function scanInvisibleUnicode(input) {
+  if (typeof input !== 'string') {
+    throw new TypeError('prompt-guard: input must be a string');
+  }
   const codePoints = [];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/permissions/prompt-guard.js around lines 163 - 186,
scanInvisibleUnicode() must explicitly reject non-string inputs using the
module’s existing intentional error message. Add the same validation used by
scan() at the start of scanInvisibleUnicode(), then add a regression test
covering invalid input and asserting the expected error message.

Source: Path instructions

.aiox-core/core/security/port-denylist.js-120-123 (1)

120-123: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

normalized is a no-op — separator normalization never happens.

filePath.split(path.sep).join(path.sep) always returns the identical string on any given platform; splitting and rejoining on the same separator does nothing. If the intent was to normalize mixed //\ separators (e.g., Windows paths passed with forward slashes, or vice versa), this doesn't achieve it, and isAllowlisted could silently fail to match on cross-platform input.

As per path instructions for .aiox-core/core/**: "Check for proper input validation on public API methods." isAllowlisted is exported and would benefit from actually normalizing mixed separators.

🐛 Proposed fix
 function isAllowlisted(filePath, allowSubstrings = DEFAULT_ALLOW_PATH_SUBSTRINGS) {
-  const normalized = filePath.split(path.sep).join(path.sep);
+  const normalized = filePath.split(/[/\\]/).join(path.sep);
   return allowSubstrings.some((s) => normalized.includes(s));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/security/port-denylist.js around lines 120 - 123, Fix
isAllowlisted so separator normalization actually handles mixed forward- and
backslash path separators before checking allowlisted substrings. Normalize the
public filePath input consistently across platforms, preserve the existing
allowSubstrings behavior, and add validation for invalid path input as
appropriate.

Source: Path instructions

.aiox-core/core/security/port-denylist.js-192-195 (1)

192-195: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Dead conditional — dotfile/dotdir skip logic is never applied.

The if block's body is empty (just a comment), so this check has no effect on control flow: no continue, no exclusion. Every dot-prefixed entry (aside from names already in SKIP_DIR_NAMES) is still walked and scanned. Either implement the intended skip (with an explicit allowance for .aiox-core/.github) or remove the dead code so the logic isn't misleading.

As per path instructions for .aiox-core/core/**: this is flagged as a "CRITICAL PATH" module requiring thorough review of logic correctness.

🐛 Proposed fix
   for (const entry of entries) {
-    if (entry.name.startsWith('.') && entry.name !== '.aiox-core' && entry.name !== '.github') {
-      // still enter .aiox-core when walking project root via explicit roots
-    }
+    if (entry.name.startsWith('.') && entry.name !== '.aiox-core' && entry.name !== '.github') {
+      continue;
+    }
     const full = path.join(dir, entry.name);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/security/port-denylist.js around lines 192 - 195, Dead
dotfile exclusion logic in the entry-walking loop has no effect. Update the loop
in the port-denylist traversal logic to explicitly skip dot-prefixed entries
while allowing `.aiox-core` and `.github`, using `continue` or equivalent
control flow; alternatively remove the conditional if dotfiles should be
scanned, ensuring the behavior is intentional and consistent with the
surrounding skip rules.

Source: Path instructions

tests/unit/sdc/phase-verify.test.js-19-22 (1)

19-22: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add afterEach to clean up temp directories.

beforeEach creates a new temp directory via fs.mkdtempSync but there is no corresponding afterEach to remove them. The sibling test file tests/unit/sdc/wave-run.test.js in this same PR correctly cleans up with fs.rmSync(cwd, { recursive: true, force: true }). Temp directories will accumulate on every test run.

🧹 Proposed fix
   beforeEach(() => {
     dir = fs.mkdtempSync(path.join(os.tmpdir(), 'sdc-pv-'));
     cwd = dir;
   });
+
+  afterEach(() => {
+    fs.rmSync(dir, { recursive: true, force: true });
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/sdc/phase-verify.test.js` around lines 19 - 22, Add an afterEach
hook in the phase-verify test suite to remove the temporary directory stored in
cwd using fs.rmSync(cwd, { recursive: true, force: true }), matching the cleanup
pattern in wave-run.test.js.
.aiox-core/core/synapse/memory/memory-bridge.js-196-214 (1)

196-214: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Sync throw in fn() leaves timer running + logs a misleading "Timeout" warning.

If fn() throws synchronously, the throw happens before .then/.catch attach, so clearTimeout(timer) is skipped. The stray timer later fires and logs a "Timeout" warning even though the actual failure was a sync throw, not a timeout. Functionally harmless (outer try/catch in getMemoryHints still handles it) but the log is misleading and the timer lingers unnecessarily.

🔧 Proposed fix — defer `fn()` invocation into the promise chain
       Promise.resolve(fn())
+      Promise.resolve()
+        .then(() => fn())
         .then((result) => {
           clearTimeout(timer);
           resolve({ ok: true, value: result });
         })
         .catch((error) => {
           clearTimeout(timer);
           console.warn(`[synapse:memory-bridge] Provider error: ${error.message}`);
           resolve({ ok: false, reason: 'error' });
         });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/synapse/memory/memory-bridge.js around lines 196 - 214,
Update _executeWithTimeout to invoke fn inside the Promise chain, such as by
deferring it through Promise.resolve().then(() => fn()), so synchronous throws
are handled by the existing catch path. Ensure the timer is cleared for this
failure and only genuine elapsed-time cases log the timeout warning.
docs/framework/epics/core-super-update/STORY-CORE-SU.MB-MEMORY-BRIDGE.md-12-27 (1)

12-27: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the completed checklist and File List before marking this story Done.

This framework story has delivery and QA notes, but no [x] completion checklist or File List. Add both so the recorded implementation and verification remain traceable.

As per coding guidelines, framework stories must update story checklists and maintain the story file list.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/framework/epics/core-super-update/STORY-CORE-SU.MB-MEMORY-BRIDGE.md`
around lines 12 - 27, Add a completed [x] checklist covering the delivered
implementation and QA verification, plus a File List identifying all changed or
added artifacts, including the memory-bridge code, reinforcement worker,
heuristic hints, and tests. Update the story document’s completion sections
before marking it Done.

Source: Coding guidelines

.aiox-core/core/sdc/progress.js-80-80 (1)

80-80: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate maxQgIterations instead of using truthiness.

Line 80 silently changes 0 to 3 and accepts negative or non-integer values. Validate the option explicitly and preserve valid zero semantics if zero is supported.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/sdc/progress.js at line 80, Update the initialization of
maxQgIterations in the progress configuration to validate the provided value
explicitly rather than using ||. Preserve 0 when supported, and reject or
default negative, non-integer, and otherwise invalid values; use the existing
initialization or validation symbols nearby to keep behavior consistent.

Source: Path instructions

.aiox-core/core/sdc/progress.js-90-98 (1)

90-98: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Write progress state atomically. .aiox-core/core/sdc/progress.js:105-108 truncates the state file in place, so an interruption can leave invalid JSON and break resume. Write to a temp file and rename it into place.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/sdc/progress.js around lines 90 - 98, Update the
progress-state persistence logic near loadJson and its corresponding write
function to avoid truncating the target file in place: serialize the state to a
temporary file in the same directory, then atomically rename it over the
destination, ensuring cleanup of any temporary file on failure.

Sources: Path instructions, Linters/SAST tools

docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-D.md-34-40 (1)

34-40: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a language tag to the diagram fence.

markdownlint reports MD040 because Line 34 uses an untyped fenced block. Mark it as text so the documentation passes the lint gate.

Proposed fix
-```
+```text
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-D.md` around lines
34 - 40, Add the text language tag to the fenced diagram block containing “IDE
surfaces” and “ARCH-D D1” by changing its opening fence to ```text, while
leaving the diagram content unchanged.

Source: Linters/SAST tools

.aiox-core/cli/commands/wave/index.js-19-41 (1)

19-41: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make resolveStoryPaths handle real globs or fail fast on bad matches. .aiox-core/cli/commands/wave/index.js:19-41** isn’t expanded recursively here, and the regex leaves metacharacters like [, (, and + active. Use a proper glob parser or escape all literals before translating *, and treat zero matches as an error instead of building an empty wave.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/cli/commands/wave/index.js around lines 19 - 41, Update
resolveStoryPaths to correctly expand recursive globs such as ** and escape all
non-wildcard regex metacharacters when translating patterns; use a proper glob
implementation or equivalent safe traversal. Track matches for each wildcard
input and throw a clear error when any pattern or explicit path produces zero
matches, preventing creation of an empty wave.

Source: Linters/SAST tools

.grok/README.md-11-11 (1)

11-11: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use consistent repository-relative skill paths.

The entry prefixes aiox-sdc with skills/, but leaves aiox-full-sdc and atomics unprefixed. In particular, the repository path is .grok/skills/aiox-full-sdc/; document the remaining entries consistently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.grok/README.md at line 11, Update the workflow skills table entry in
README.md to use consistent repository-relative paths, prefixing aiox-full-sdc
and atomics with .grok/skills/ just like aiox-sdc.
.aiox-core/development/tasks/health-check.yaml-14-14 (1)

14-14: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Reconcile the documented doctor-check count.

The task claims 18 checks, but the summary reports 17 and the final module list contains only 17 entries while omitting framework-3way-diff, which is present in governance_map. The displayed status fields also total 16. Add the missing module and derive the summary counts from the actual doctor output, or consistently change all references to the real count.

Also applies to: 70-70, 203-220, 239-239, 254-254, 266-269

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/development/tasks/health-check.yaml at line 14, Reconcile the
doctor-check counts throughout the task: update the documented module list to
include framework-3way-diff from governance_map, and ensure the summary, status
fields, and final module listing consistently reflect the actual aiox doctor
output. Prefer deriving counts from the command output rather than hardcoding
conflicting totals, while preserving consistency across the affected sections.
docs/framework/epics/core-super-update/ROADMAP.md-37-38 (1)

37-38: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a blank line before the completion-boundary table.

markdownlint-cli2 reports MD058 because the table is not surrounded by blank lines.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/framework/epics/core-super-update/ROADMAP.md` around lines 37 - 38, In
the “Out of this release (not open work)” section, add a blank line between the
section text and the completion-boundary table beginning with “| Item |
Disposition |” so the table is surrounded by blank lines and satisfies
markdownlint MD058.

Source: Linters/SAST tools

docs/framework/epics/core-super-update/STORY-CORE-SU.A2-CONFIGCACHE-JEST-RESIDUAL.md-61-76 (1)

61-76: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the second modified ConfigCache path to the story File List.

The decision states that both .aiox-core/core/config/config-cache.js and .aiox-core/infrastructure/scripts/config-cache.js were updated, but the expected File List documents only the first path. Add the infrastructure copy so the story accurately inventories the implementation.

As per coding guidelines, maintain the story file list.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@docs/framework/epics/core-super-update/STORY-CORE-SU.A2-CONFIGCACHE-JEST-RESIDUAL.md`
around lines 61 - 76, Add .aiox-core/infrastructure/scripts/config-cache.js to
the “File List (expected)” section, alongside the existing core config-cache.js
entry, so both modified ConfigCache implementations are documented.

Source: Coding guidelines

docs/framework/epics/core-super-update/STORY-CORE-SU.A1-SYNAPSE-TIMEOUT-CONFIG.md-79-84 (1)

79-84: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Resolve the unchecked DoD item before marking the story Done.

The story is marked Done, but #798 closed with PR link remains unchecked. If this is intentionally deferred until merge, keep the story status consistent with that lifecycle; otherwise update the checklist with the PR link.

As per coding guidelines, story checklists under docs/framework/epics/ must be updated from [ ] to [x].

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@docs/framework/epics/core-super-update/STORY-CORE-SU.A1-SYNAPSE-TIMEOUT-CONFIG.md`
around lines 79 - 84, Update the Definition of Done checklist in
STORY-CORE-SU.A1-SYNAPSE-TIMEOUT-CONFIG.md by resolving the unchecked “#798
closed with PR link” item: add the relevant PR link and mark it [x] if complete,
or change the story status from Done if it is intentionally deferred until
merge.

Source: Coding guidelines

.aiox-core/core/permissions/ssrf-guard.js-156-161 (1)

156-161: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

startsWith prefix match over-blocks addresses that merely start with ::1.

'::1' is already handled exactly at Lines 152-154. Including it in BLOCKED_IPV6_PREFIXES and checking normalized.startsWith(prefix) means any address whose string form happens to start with ::1 (e.g. a deprecated IPv4-compatible form like ::123.4.5.6, or ::1abc::) gets misclassified as "loopback" even though it isn't. This is over-blocking (safe direction) rather than a bypass, but it's still incorrect logic for a documented CIDR-precision guard.

🐛 Proposed fix
 const BLOCKED_IPV6_PREFIXES = [
-  '::1', // loopback exact / start
   'fc', // unique local fc00::/7
   'fd', // unique local fd00::/7
 ];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/permissions/ssrf-guard.js around lines 156 - 161, Fix the
IPv6 prefix matching in the SSRF guard so BLOCKED_IPV6_PREFIXES only matches
complete CIDR prefixes, not arbitrary strings beginning with a prefix such as
::1. Keep the exact ::1 check in the existing normalization logic, remove or
specially handle ::1 in the prefix loop, and ensure prefixes are matched at the
correct hexadecimal boundary while preserving legitimate fc00::/7 and fd00::/8
blocking.
.aiox-core/core/permissions/ssrf-guard.js-87-101 (1)

87-101: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Validate IPv4 octets before ipv4ToInt(). checkIPv4() and the IPv4-mapped paths in checkIPv6()/checkHostname() accept malformed values like 256.0.0.1 and ::ffff:256.0.0.1, then fall through as allowed because the bitwise conversion never rejects out-of-range octets. Add a 0–255 / 4-segment guard before conversion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/permissions/ssrf-guard.js around lines 87 - 101, Validate
IPv4 input as exactly four dot-separated numeric octets, each in the 0–255
range, before calling ipv4ToInt(). Apply this guard in checkIPv4() and the
IPv4-mapped handling paths of checkIPv6() and checkHostname(), rejecting
malformed values such as 256.0.0.1 before CIDR evaluation.

Source: Path instructions

.aiox-core/development/skills/full-sdc/SKILL.md-20-24 (1)

20-24: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Specify languages for the fenced code blocks.

The command example should use bash, and the orchestration pseudocode should use text (or another appropriate language) to satisfy markdownlint MD040.

Also applies to: 63-80

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/development/skills/full-sdc/SKILL.md around lines 20 - 24, Add
explicit language identifiers to all fenced code blocks in the full-SDC
documentation, including bash for command examples and text for orchestration
pseudocode. Update the blocks around the command examples and the additional
section spanning the referenced content to satisfy markdownlint MD040.

Source: Linters/SAST tools

🧹 Nitpick comments (9)
.aiox-core/scripts/reinforce-heuristic.js (1)

20-74: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Script logic is sound; consider concurrent access safeguards.

The read-modify-write cycle on HINTS_PATH has no file locking. If two detached worker instances run concurrently (e.g., from parallel sessions), one update could overwrite the other (TOCTOU/lost update). This is low-risk given the short-lived nature of the script, but a simple advisory lock or atomic write (write to temp file + rename) would harden it.

💡 Optional: atomic write pattern
   if (modified) {
-    fs.writeFileSync(HINTS_PATH, lines.join('\n'), 'utf8');
+    const tmp = HINTS_PATH + '.tmp';
+    fs.writeFileSync(tmp, lines.join('\n'), 'utf8');
+    fs.renameSync(tmp, HINTS_PATH);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/scripts/reinforce-heuristic.js around lines 20 - 74, Protect the
read-modify-write cycle in the main script logic with an advisory lock or atomic
update strategy to prevent concurrent workers from losing increments. Use a lock
around the HINTS_PATH read and write, or write the modified content to a
temporary file in the same directory and atomically rename it over HINTS_PATH,
ensuring cleanup on failure.
docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-B.md (1)

22-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add language identifiers to fenced code blocks.

Static analysis (markdownlint MD040) flags these fences as missing a language spec. Minor doc hygiene fix.

📝 Suggested fix
-```
+```text
 User / IDE slash

and similarly for the second fence at line 73.

Also applies to: 73-73

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-B.md` at line 22,
Add language identifiers to both fenced code blocks in ARCHITECTURE-WAVE-B.md,
including the fences around “User / IDE slash” and the second block near the
referenced location; use ```text for plain-text content so markdownlint MD040
passes.

Source: Linters/SAST tools

.aiox-core/core/sdc/wave-plan.js (1)

91-95: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unreachable dead-code branch.

usedFiles is always empty when the first story in ordered is evaluated (each batch iteration re-initializes usedFiles at line 78), so files.some((f) => usedFiles.has(f)) is always false for ordered[0] — it is always pushed into batch on the first check. batch.length === 0 can therefore never be true, making this fallback dead code.

♻️ Suggested cleanup
-    if (batch.length === 0) {
-      // all conflict — force first
-      const first = ordered[0];
-      batch.push({ ...first, partition: 'sequenced', partition_source: 'forced-serial' });
-    }
-
     batches.push(batch);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/sdc/wave-plan.js around lines 91 - 95, Remove the
unreachable batch.length === 0 fallback branch in the wave-planning logic,
including its forced-serial partition assignment, since the first ordered story
is always added to the batch. Preserve the existing batch initialization and
conflict-checking behavior.
.aiox-core/development/skills/wave-execute/SKILL.md (1)

24-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a language tag to the fenced block.

The invocation block is CLI/shell syntax but has no fence language, which triggers markdownlint MD040. Use bash or text as appropriate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/development/skills/wave-execute/SKILL.md around lines 24 - 30,
Add the appropriate language tag, preferably bash, to the fenced CLI invocation
block containing /wave-execute and aiox wave commands in SKILL.md to satisfy
markdownlint MD040.

Source: Linters/SAST tools

.aiox-core/infrastructure/scripts/framework-3way-diff.js (2)

125-127: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

SHA1 usage is fine here — not a security boundary.

Static analysis flags crypto.createHash('sha1') as a weak hash, but it's used only as a content-change fingerprint for the drift report, not for integrity/authentication. Low-priority; switching to sha256 would be a trivial, low-reward change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/infrastructure/scripts/framework-3way-diff.js around lines 125 -
127, The SHA1 hash in the drift-report fingerprint logic is intentionally
non-security-sensitive and may remain unchanged; no code modification is
required. If addressing the static-analysis warning, update the hash algorithm
in the relevant fingerprint construction to SHA-256 while preserving the
truncated digest behavior.

Source: Linters/SAST tools


74-91: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Flag values aren't validated before use — trailing flag crashes with an unclear error.

If --hub, --enterprise, --oss, or --out is passed as the last CLI argument (no following value), argv[++i] is undefined and path.resolve(undefined) throws a raw TypeError instead of a helpful usage message.

🛡️ Proposed fix
-    if (a === '--oss') args.oss = path.resolve(argv[++i]);
-    else if (a === '--hub') args.hub = path.resolve(argv[++i]);
-    else if (a === '--enterprise') args.enterprise = path.resolve(argv[++i]);
+    if (a === '--oss') {
+      if (argv[i + 1] === undefined) throw new Error(`${a} requires a value`);
+      args.oss = path.resolve(argv[++i]);
+    } else if (a === '--hub') {
+      if (argv[i + 1] === undefined) throw new Error(`${a} requires a value`);
+      args.hub = path.resolve(argv[++i]);
+    } else if (a === '--enterprise') {
+      if (argv[i + 1] === undefined) throw new Error(`${a} requires a value`);
+      args.enterprise = path.resolve(argv[++i]);
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/infrastructure/scripts/framework-3way-diff.js around lines 74 -
91, Validate that each value-taking option has a following argument before
incrementing the index or calling path.resolve. Update the argument parser to
emit a clear usage/error message and exit nonzero when --oss, --hub,
--enterprise, or --out is missing its value, while preserving existing handling
for valid options and flags.
bin/aiox.js (1)

890-946: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated dispatch try/catch — extract a shared helper.

The sdc/wave cases repeat the exact same require→run→catch→exit pattern already used by workers/config/pro. Five near-identical blocks is a DRY smell that will keep growing as more subcommands delegate to .aiox-core/cli/index.js.

♻️ Proposed helper extraction
+async function delegateToCore(label) {
+  try {
+    const { run } = require('../.aiox-core/cli/index.js');
+    await run(process.argv);
+  } catch (error) {
+    console.error(`❌ ${label} command error: ${error.message}`);
+    process.exit(1);
+  }
+}

 switch (command) {
   case 'workers':
-    try {
-      const { run } = require('../.aiox-core/cli/index.js');
-      await run(process.argv);
-    } catch (error) {
-      console.error(`❌ Workers command error: ${error.message}`);
-      process.exit(1);
-    }
+    await delegateToCore('Workers');
     break;
   ...
   case 'sdc':
-    try {
-      const { run } = require('../.aiox-core/cli/index.js');
-      await run(process.argv);
-    } catch (error) {
-      console.error(`❌ SDC command error: ${error.message}`);
-      process.exit(1);
-    }
+    await delegateToCore('SDC');
     break;
   case 'wave':
-    try {
-      const { run } = require('../.aiox-core/cli/index.js');
-      await run(process.argv);
-    } catch (error) {
-      console.error(`❌ Wave command error: ${error.message}`);
-      process.exit(1);
-    }
+    await delegateToCore('Wave');
     break;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/aiox.js` around lines 890 - 946, Extract the repeated CLI delegation
pattern from main into a shared async helper that requires
.aiox-core/cli/index.js, invokes run(process.argv), logs a command-specific
error, and exits with status 1 on failure. Update the workers, config, pro, sdc,
and wave cases to call this helper with their command name, preserving existing
behavior and messages.
docs/npx-install.md (1)

108-143: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate ECOMPROMISED guidance across two sections.

The new "Recommended on Windows" block (lines 112-129) and the new "Troubleshooting → ECOMPROMISED" block (lines 135-143) both document the same cause and largely the same remediation steps. Consider consolidating into a single section (or having one link to the other) to avoid future drift when this guidance is updated.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/npx-install.md` around lines 108 - 143, Consolidate the duplicated
Windows ECOMPROMISED guidance in docs/npx-install.md: retain one authoritative
section containing the cause and remediation steps, and replace the other block
with a concise link or reference to it. Ensure the guidance remains discoverable
from both the Windows recommendations and Troubleshooting sections without
repeating the same commands.
.aiox-core/infrastructure/scripts/validate-claude-integration.js (1)

75-94: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider batching git check-ignore calls; current per-entry spawn is acceptable at current scale.

isGitIgnored spawns a separate git process for every directory entry. For the directories checked here (.claude/commands, .claude/skills, .claude/agent-memory) this is fine given typically small entry counts, but if these directories grow, a single git check-ignore --stdin call passing all candidate paths at once would avoid the per-entry process-spawn overhead. Not blocking — just a forward-looking note.

The static-analysis "zip-slip" hint on line 88 is a false positive: entry.name comes from a real fs.readdirSync directory listing, not from an untrusted archive entry, so there's no path-traversal/extraction risk here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/infrastructure/scripts/validate-claude-integration.js around
lines 75 - 94, Consider optimizing listTopLevelNames by batching candidate paths
into a single git check-ignore --stdin invocation instead of calling
isGitIgnored for every entry; preserve the existing behavior for ignored paths
and entries when projectRoot is absent. The zip-slip static-analysis warning for
entry.name is a false positive and requires no code change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.aiox-core/cli/commands/wave/index.js:
- Around line 4-8: The usage documentation advertises a --glob option that the
plan command does not register. In the plan command definition, add the --glob
option and pass its value through resolveStoryPaths alongside --stories and
--story, or remove the --glob usage entry if glob-based planning is not
supported.
- Around line 170-178: Make the `wave next` action read-only: replace
`sdc.advanceWave(waveId)` with a dedicated lookup that computes or retrieves
`wave` and `nextBatch` without refreshing statuses, auto-marking stories, or
persisting changes. Update the relevant `sdc` helper and the `.action` handler
to preserve the existing display behavior while avoiding state mutation.
- Around line 97-110: Wrap the wave planning logic in the action handler with
try/catch, including the sdc.planWaveFromPaths call and subsequent processing.
On failure, print a clear CLI error message, set process.exitCode to 1, and
return; follow the error-handling pattern used by sibling commands.

In @.aiox-core/core/sdc/epic-glue.js:
- Around line 80-112: Partial parse errors from discoverEpicStories are
discarded when valid stories are also found. Update planWaveFromEpic to always
preserve the errors collection in plan.epicGlue, using an empty array when none
exist, and ensure callers can detect the partial-failure condition; add a
regression test covering mixed valid and malformed STORY files.

In @.aiox-core/core/sdc/index.js:
- Around line 70-85: Serialize the load–update–save workflow in
verifyAndMaybeMark by adding a lock or revision/CAS mechanism around
progress.loadSdcState, progress.markPhase, and progress.saveSdcState. Ensure
concurrent executions cannot update stale state or overwrite each other’s
progress, while preserving the existing initialization and verification
behavior.

In @.aiox-core/core/sdc/phase-verify.js:
- Around line 26-27: verifyPhase currently lets parseStoryFile failures escape
instead of returning a documented VerifyResult. Validate storyPath before
parsing, catch missing, unreadable, and malformed-story errors from
parseStoryFile, and return a structured failure result that includes the
requested phase context; update callers only if exception propagation is
intentionally retained and documented.
- Around line 38-43: Make the status acceptance in the validate phase consistent
with the shared Done integrity gate: update the okStatuses logic in the phase
verification code to remove Done or explicitly support the intended validate
re-entry path in the integrity check, ensuring Done stories do not pass validate
while still being rejected elsewhere.

In @.aiox-core/core/sdc/progress.js:
- Around line 124-125: The saveSdcState function currently permits missing
identifiers, allowing safeId(undefined) to write state under the shared unknown
directory. Validate that both state.storyId and state.waveId are present before
calling saveJson, and reject or throw on invalid state; apply the same
validation to the related save operation around the additional referenced lines.
- Around line 153-174: Update markPhase to prevent premature completion: when
handling passed or skipped statuses, inspect all PHASES rather than only phases
after the supplied phase, and set completed only when no phase remains pending.
Reject or explicitly represent out-of-order transitions where earlier phases are
still pending, while preserving correct currentPhase and running-state behavior.

In @.aiox-core/core/sdc/wave-plan.js:
- Around line 146-153: Sanitize or validate the generated wave identifier before
storing it in the plan returned by planWaveFromPaths(); apply the existing
safeId() behavior to opts.waveId (or reject invalid values) so writeWaveReport()
cannot receive an unsafe wave.waveId and escape the .aiox/waves/ directory,
matching waveStatePath() handling.

In @.aiox-core/scripts/pm.sh:
- Around line 338-342: The context file contents are embedded into the external
CLI prompt without protecting sensitive data. Update the CONTEXT_FILE handling
in the prompt construction logic to redact secrets and PII before appending the
content, or require an explicit opt-in confirmation/warning before transmission;
preserve the existing file validation and size limit.
- Around line 460-468: The command construction in the inline execution path
appends raw PARAMS, allowing parameter metacharacters to alter or inject
commands. Update the relevant command-building logic around full_cmd to preserve
PARAMS as distinct quoted arguments, escaping each positional parameter with the
platform-appropriate shell quoting before appending; apply the same safe
handling across Linux, Windows/WSL, and macOS spawn paths.

In @.claude/skills/coderabbit-review/SKILL.md:
- Line 36: Replace the hardcoded placeholder path in the CodeRabbit invocation
with a configurable repository-root variable or dynamically derive the current
checkout directory, then pass that resolved path to the wsl bash command.

In @.gitignore:
- Around line 379-380: Update the Codex ignore rules in .gitignore so the entire
.codex/ directory is not excluded: replace the broad .codex/ rule with a rule
for local artifacts such as .codex/*, then explicitly unignore .codex/skills/
and .codex/skills/** so the documented skills remain versioned.

---

Minor comments:
In @.aiox-core/cli/commands/wave/index.js:
- Around line 19-41: Update resolveStoryPaths to correctly expand recursive
globs such as ** and escape all non-wildcard regex metacharacters when
translating patterns; use a proper glob implementation or equivalent safe
traversal. Track matches for each wildcard input and throw a clear error when
any pattern or explicit path produces zero matches, preventing creation of an
empty wave.

In @.aiox-core/constitution.md:
- Around line 141-147: Specify the fenced code block language as text for the
portability hierarchy diagram in the constitution document, replacing the
unlabeled fence while preserving its contents.

In @.aiox-core/core/permissions/prompt-guard.js:
- Around line 163-186: scanInvisibleUnicode() must explicitly reject non-string
inputs using the module’s existing intentional error message. Add the same
validation used by scan() at the start of scanInvisibleUnicode(), then add a
regression test covering invalid input and asserting the expected error message.

In @.aiox-core/core/permissions/ssrf-guard.js:
- Around line 156-161: Fix the IPv6 prefix matching in the SSRF guard so
BLOCKED_IPV6_PREFIXES only matches complete CIDR prefixes, not arbitrary strings
beginning with a prefix such as ::1. Keep the exact ::1 check in the existing
normalization logic, remove or specially handle ::1 in the prefix loop, and
ensure prefixes are matched at the correct hexadecimal boundary while preserving
legitimate fc00::/7 and fd00::/8 blocking.
- Around line 87-101: Validate IPv4 input as exactly four dot-separated numeric
octets, each in the 0–255 range, before calling ipv4ToInt(). Apply this guard in
checkIPv4() and the IPv4-mapped handling paths of checkIPv6() and
checkHostname(), rejecting malformed values such as 256.0.0.1 before CIDR
evaluation.

In @.aiox-core/core/sdc/progress.js:
- Line 80: Update the initialization of maxQgIterations in the progress
configuration to validate the provided value explicitly rather than using ||.
Preserve 0 when supported, and reject or default negative, non-integer, and
otherwise invalid values; use the existing initialization or validation symbols
nearby to keep behavior consistent.
- Around line 90-98: Update the progress-state persistence logic near loadJson
and its corresponding write function to avoid truncating the target file in
place: serialize the state to a temporary file in the same directory, then
atomically rename it over the destination, ensuring cleanup of any temporary
file on failure.

In @.aiox-core/core/security/port-denylist.js:
- Around line 120-123: Fix isAllowlisted so separator normalization actually
handles mixed forward- and backslash path separators before checking allowlisted
substrings. Normalize the public filePath input consistently across platforms,
preserve the existing allowSubstrings behavior, and add validation for invalid
path input as appropriate.
- Around line 192-195: Dead dotfile exclusion logic in the entry-walking loop
has no effect. Update the loop in the port-denylist traversal logic to
explicitly skip dot-prefixed entries while allowing `.aiox-core` and `.github`,
using `continue` or equivalent control flow; alternatively remove the
conditional if dotfiles should be scanned, ensuring the behavior is intentional
and consistent with the surrounding skip rules.

In @.aiox-core/core/synapse/memory/memory-bridge.js:
- Around line 196-214: Update _executeWithTimeout to invoke fn inside the
Promise chain, such as by deferring it through Promise.resolve().then(() =>
fn()), so synchronous throws are handled by the existing catch path. Ensure the
timer is cleared for this failure and only genuine elapsed-time cases log the
timeout warning.

In @.aiox-core/development/skills/full-sdc/SKILL.md:
- Around line 20-24: Add explicit language identifiers to all fenced code blocks
in the full-SDC documentation, including bash for command examples and text for
orchestration pseudocode. Update the blocks around the command examples and the
additional section spanning the referenced content to satisfy markdownlint
MD040.

In @.aiox-core/development/tasks/health-check.yaml:
- Line 14: Reconcile the doctor-check counts throughout the task: update the
documented module list to include framework-3way-diff from governance_map, and
ensure the summary, status fields, and final module listing consistently reflect
the actual aiox doctor output. Prefer deriving counts from the command output
rather than hardcoding conflicting totals, while preserving consistency across
the affected sections.

In @.claude/skills/full-sdc/SKILL.md:
- Around line 20-24: Update the fenced code blocks in the full-sdc
documentation, including the examples around the `/full-sdc` and `aiox sdc plan`
commands and the additional affected section, by adding an appropriate `bash` or
`text` language identifier after each opening fence.

In @.grok/README.md:
- Line 11: Update the workflow skills table entry in README.md to use consistent
repository-relative paths, prefixing aiox-full-sdc and atomics with
.grok/skills/ just like aiox-sdc.

In `@docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-D.md`:
- Around line 34-40: Add the text language tag to the fenced diagram block
containing “IDE surfaces” and “ARCH-D D1” by changing its opening fence to
```text, while leaving the diagram content unchanged.

In `@docs/framework/epics/core-super-update/ROADMAP.md`:
- Around line 37-38: In the “Out of this release (not open work)” section, add a
blank line between the section text and the completion-boundary table beginning
with “| Item | Disposition |” so the table is surrounded by blank lines and
satisfies markdownlint MD058.

In
`@docs/framework/epics/core-super-update/STORY-CORE-SU.A1-SYNAPSE-TIMEOUT-CONFIG.md`:
- Around line 79-84: Update the Definition of Done checklist in
STORY-CORE-SU.A1-SYNAPSE-TIMEOUT-CONFIG.md by resolving the unchecked “#798
closed with PR link” item: add the relevant PR link and mark it [x] if complete,
or change the story status from Done if it is intentionally deferred until
merge.

In
`@docs/framework/epics/core-super-update/STORY-CORE-SU.A2-CONFIGCACHE-JEST-RESIDUAL.md`:
- Around line 61-76: Add .aiox-core/infrastructure/scripts/config-cache.js to
the “File List (expected)” section, alongside the existing core config-cache.js
entry, so both modified ConfigCache implementations are documented.

In `@docs/framework/epics/core-super-update/STORY-CORE-SU.MB-MEMORY-BRIDGE.md`:
- Around line 12-27: Add a completed [x] checklist covering the delivered
implementation and QA verification, plus a File List identifying all changed or
added artifacts, including the memory-bridge code, reinforcement worker,
heuristic hints, and tests. Update the story document’s completion sections
before marking it Done.

In `@docs/guides/installation-troubleshooting.md`:
- Around line 93-97: Specify the `text` language identifier on the fenced
error-output block in the installation troubleshooting guide to resolve the
MD040 warning.

In `@tests/unit/sdc/phase-verify.test.js`:
- Around line 19-22: Add an afterEach hook in the phase-verify test suite to
remove the temporary directory stored in cwd using fs.rmSync(cwd, { recursive:
true, force: true }), matching the cleanup pattern in wave-run.test.js.

---

Nitpick comments:
In @.aiox-core/core/sdc/wave-plan.js:
- Around line 91-95: Remove the unreachable batch.length === 0 fallback branch
in the wave-planning logic, including its forced-serial partition assignment,
since the first ordered story is always added to the batch. Preserve the
existing batch initialization and conflict-checking behavior.

In @.aiox-core/development/skills/wave-execute/SKILL.md:
- Around line 24-30: Add the appropriate language tag, preferably bash, to the
fenced CLI invocation block containing /wave-execute and aiox wave commands in
SKILL.md to satisfy markdownlint MD040.

In @.aiox-core/infrastructure/scripts/framework-3way-diff.js:
- Around line 125-127: The SHA1 hash in the drift-report fingerprint logic is
intentionally non-security-sensitive and may remain unchanged; no code
modification is required. If addressing the static-analysis warning, update the
hash algorithm in the relevant fingerprint construction to SHA-256 while
preserving the truncated digest behavior.
- Around line 74-91: Validate that each value-taking option has a following
argument before incrementing the index or calling path.resolve. Update the
argument parser to emit a clear usage/error message and exit nonzero when --oss,
--hub, --enterprise, or --out is missing its value, while preserving existing
handling for valid options and flags.

In @.aiox-core/infrastructure/scripts/validate-claude-integration.js:
- Around line 75-94: Consider optimizing listTopLevelNames by batching candidate
paths into a single git check-ignore --stdin invocation instead of calling
isGitIgnored for every entry; preserve the existing behavior for ignored paths
and entries when projectRoot is absent. The zip-slip static-analysis warning for
entry.name is a false positive and requires no code change.

In @.aiox-core/scripts/reinforce-heuristic.js:
- Around line 20-74: Protect the read-modify-write cycle in the main script
logic with an advisory lock or atomic update strategy to prevent concurrent
workers from losing increments. Use a lock around the HINTS_PATH read and write,
or write the modified content to a temporary file in the same directory and
atomically rename it over HINTS_PATH, ensuring cleanup on failure.

In `@bin/aiox.js`:
- Around line 890-946: Extract the repeated CLI delegation pattern from main
into a shared async helper that requires .aiox-core/cli/index.js, invokes
run(process.argv), logs a command-specific error, and exits with status 1 on
failure. Update the workers, config, pro, sdc, and wave cases to call this
helper with their command name, preserving existing behavior and messages.

In `@docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-B.md`:
- Line 22: Add language identifiers to both fenced code blocks in
ARCHITECTURE-WAVE-B.md, including the fences around “User / IDE slash” and the
second block near the referenced location; use ```text for plain-text content so
markdownlint MD040 passes.

In `@docs/npx-install.md`:
- Around line 108-143: Consolidate the duplicated Windows ECOMPROMISED guidance
in docs/npx-install.md: retain one authoritative section containing the cause
and remediation steps, and replace the other block with a concise link or
reference to it. Ensure the guidance remains discoverable from both the Windows
recommendations and Troubleshooting sections without repeating the same
commands.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5c276cff-49f7-4d49-85c9-c8e514302283

📥 Commits

Reviewing files that changed from the base of the PR and between a139500 and c7b0741.

📒 Files selected for processing (140)
  • .aiox-core/cli/commands/sdc/index.js
  • .aiox-core/cli/commands/wave/index.js
  • .aiox-core/cli/index.js
  • .aiox-core/constitution.md
  • .aiox-core/core-config.yaml
  • .aiox-core/core/config/config-cache.js
  • .aiox-core/core/doctor/checks/framework-3way-diff.js
  • .aiox-core/core/doctor/checks/index.js
  • .aiox-core/core/doctor/checks/port-denylist.js
  • .aiox-core/core/doctor/checks/windows-npx-install.js
  • .aiox-core/core/ids/registry-updater.js
  • .aiox-core/core/install/windows-npx-hint.js
  • .aiox-core/core/orchestration/terminal-spawner.js
  • .aiox-core/core/permissions/__tests__/path-guard.test.js
  • .aiox-core/core/permissions/__tests__/prompt-guard.test.js
  • .aiox-core/core/permissions/__tests__/ssrf-guard.test.js
  • .aiox-core/core/permissions/index.js
  • .aiox-core/core/permissions/path-guard.js
  • .aiox-core/core/permissions/prompt-guard.js
  • .aiox-core/core/permissions/ssrf-guard.js
  • .aiox-core/core/sdc/dispatch-adapter.js
  • .aiox-core/core/sdc/epic-glue.js
  • .aiox-core/core/sdc/index.js
  • .aiox-core/core/sdc/phase-verify.js
  • .aiox-core/core/sdc/progress.js
  • .aiox-core/core/sdc/story-meta.js
  • .aiox-core/core/sdc/wave-plan.js
  • .aiox-core/core/sdc/wave-run.js
  • .aiox-core/core/security/port-denylist.js
  • .aiox-core/core/synapse/engine.js
  • .aiox-core/core/synapse/memory/memory-bridge.js
  • .aiox-core/core/synapse/runtime/hook-runtime.js
  • .aiox-core/data/entity-registry.yaml
  • .aiox-core/development/skills/aiox-commit/SKILL.md
  • .aiox-core/development/skills/apply-qa-fixes/SKILL.md
  • .aiox-core/development/skills/close-story/SKILL.md
  • .aiox-core/development/skills/develop-story/SKILL.md
  • .aiox-core/development/skills/full-sdc/SKILL.md
  • .aiox-core/development/skills/review-story/SKILL.md
  • .aiox-core/development/skills/validate-story-draft/SKILL.md
  • .aiox-core/development/skills/wave-execute/SKILL.md
  • .aiox-core/development/tasks/github-devops-pre-push-quality-gate.md
  • .aiox-core/development/tasks/health-check.yaml
  • .aiox-core/governance/global-heuristic-hints.yaml
  • .aiox-core/infrastructure/scripts/config-cache.js
  • .aiox-core/infrastructure/scripts/framework-3way-diff.js
  • .aiox-core/infrastructure/scripts/grok-skills-sync/index.js
  • .aiox-core/infrastructure/scripts/validate-claude-integration.js
  • .aiox-core/install-manifest.yaml
  • .aiox-core/scripts/pm.sh
  • .aiox-core/scripts/reinforce-heuristic.js
  • .claude/CLAUDE.md
  • .claude/hooks/README.md
  • .claude/rules/story-lifecycle.md
  • .claude/skills/aiox-commit/SKILL.md
  • .claude/skills/apply-qa-fixes/SKILL.md
  • .claude/skills/close-story/SKILL.md
  • .claude/skills/coderabbit-review/SKILL.md
  • .claude/skills/develop-story/SKILL.md
  • .claude/skills/full-sdc/SKILL.md
  • .claude/skills/review-story/SKILL.md
  • .claude/skills/validate-story-draft/SKILL.md
  • .claude/skills/wave-execute/SKILL.md
  • .gitignore
  • .grok/README.md
  • .grok/agents/aiox-analyst.md
  • .grok/agents/aiox-architect.md
  • .grok/agents/aiox-data-engineer.md
  • .grok/agents/aiox-dev.md
  • .grok/agents/aiox-devops.md
  • .grok/agents/aiox-master.md
  • .grok/agents/aiox-pm.md
  • .grok/agents/aiox-po.md
  • .grok/agents/aiox-qa.md
  • .grok/agents/aiox-sm.md
  • .grok/agents/aiox-squad-creator.md
  • .grok/agents/aiox-ux-design-expert.md
  • .grok/personas/aiox-dev.toml
  • .grok/rules/aiox-core.md
  • .grok/skills/aiox-apply-qa-fixes/SKILL.md
  • .grok/skills/aiox-close-story/SKILL.md
  • .grok/skills/aiox-commit/SKILL.md
  • .grok/skills/aiox-develop-story/SKILL.md
  • .grok/skills/aiox-full-sdc/SKILL.md
  • .grok/skills/aiox-review-story/SKILL.md
  • .grok/skills/aiox-sdc/SKILL.md
  • .grok/skills/aiox-validate-story-draft/SKILL.md
  • .grok/skills/aiox-wave-execute/SKILL.md
  • AGENTS.md
  • bin/aiox.js
  • docs/framework/README.md
  • docs/framework/config-override-guide.md
  • docs/framework/epics/core-super-update/ANALYSIS-3WAY-CORRECTIONS.md
  • docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-0.md
  • docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-A.md
  • docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-B.md
  • docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-C.md
  • docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-D.md
  • docs/framework/epics/core-super-update/ARCHITECTURE-WAVE-E.md
  • docs/framework/epics/core-super-update/EPIC-CORE-SUPER-UPDATE.md
  • docs/framework/epics/core-super-update/ROADMAP.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.0-DIFF-HARNESS.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.A1-SYNAPSE-TIMEOUT-CONFIG.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.A2-CONFIGCACHE-JEST-RESIDUAL.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.A3-PERMISSION-GUARDS.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.A4-PORT-DENYLIST.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.C2-DISPATCH-ADAPTER.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.C3-EPIC-GLUE.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.C4-WAVE-C-TESTS.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.D1-IDE-SYNC-CONTRACT.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.E1-CONSTITUTION-XI-XII.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.F1-WINDOWS-ECOMPROMISED.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.MB-MEMORY-BRIDGE.md
  • docs/framework/epics/core-super-update/STORY-CORE-SU.PM-STUB-FIX.md
  • docs/framework/ide-sync-contract.md
  • docs/framework/story-locations.md
  • docs/guides/installation-troubleshooting.md
  • docs/npx-install.md
  • package.json
  • packages/installer/tests/unit/doctor/doctor-checks.test.js
  • packages/installer/tests/unit/doctor/doctor-orchestrator.test.js
  • scripts/validate-port-denylist.js
  • tests/core/config-cache-unref.test.js
  • tests/core/ids/registry-updater.test.js
  • tests/core/orchestration/terminal-spawner.test.js
  • tests/core/terminal-spawner.test.js
  • tests/synapse/engine.test.js
  • tests/synapse/hook-runtime.test.js
  • tests/synapse/memory-bridge-heuristics.test.js
  • tests/unit/framework-3way-diff.test.js
  • tests/unit/install/windows-npx-hint.test.js
  • tests/unit/port-denylist.test.js
  • tests/unit/sdc/dispatch-adapter.test.js
  • tests/unit/sdc/epic-glue.test.js
  • tests/unit/sdc/phase-verify.test.js
  • tests/unit/sdc/story-meta.test.js
  • tests/unit/sdc/wave-c-integration.test.js
  • tests/unit/sdc/wave-plan.test.js
  • tests/unit/sdc/wave-run.test.js
  • tests/unit/validate-claude-integration.test.js

Comment on lines +4 to +8
* Usage:
* aiox wave plan --stories <p1,p2,...> [--wave-id ID] [--mode yolo] [--save]
* aiox wave plan --glob <glob> ...
* aiox wave status <wave-id>
* aiox wave next <wave-id>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Implement or remove the advertised --glob option.

The usage block promises aiox wave plan --glob <glob>, but the plan command registers only --stories and repeatable --story. Commander will reject the documented command. Add the option and route it through resolveStoryPaths, or remove the stale usage entry.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/cli/commands/wave/index.js around lines 4 - 8, The usage
documentation advertises a --glob option that the plan command does not
register. In the plan command definition, add the --glob option and pass its
value through resolveStoryPaths alongside --stories and --story, or remove the
--glob usage entry if glob-based planning is not supported.

Comment on lines +97 to +110
.action((opts) => {
const list = [];
if (opts.stories) list.push(...opts.stories.split(',').map((s) => s.trim()));
if (opts.story) list.push(...opts.story);
if (list.length === 0) {
console.error('Provide --stories a.md,b.md and/or --story path');
process.exitCode = 1;
return;
}
const paths = resolveStoryPaths(list);
const plan = sdc.planWaveFromPaths(paths, {
waveId: opts.waveId,
mode: opts.mode,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== file outline ==\n'
ast-grep outline .aiox-core/cli/commands/wave/index.js --view expanded || true

printf '\n== wave index excerpt ==\n'
nl -ba .aiox-core/cli/commands/wave/index.js | sed -n '1,220p'

printf '\n== sibling command files ==\n'
fd -a 'index.js' .aiox-core/cli/commands | sed 's#^\./##' | sort

printf '\n== search for planWaveFromPaths and try/catch in cli commands ==\n'
rg -n "planWaveFromPaths|try \{|catch \(|process\.exitCode" .aiox-core/cli/commands -g 'index.js' -g '*.js'

Repository: SynkraAI/aiox-core

Length of output: 487


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== wave index excerpt ==\n'
nl -ba .aiox-core/cli/commands/wave/index.js | sed -n '1,220p'

printf '\n== sibling command excerpts ==\n'
for f in $(fd -a 'index.js' .aiox-core/cli/commands | sort); do
  case "$f" in
    *.aiox-core/cli/commands/wave/index.js) continue ;;
  esac
  printf '\n--- %s ---\n' "$f"
  rg -n "try \{|catch \(|process\.exitCode|action\(" "$f" || true
done

printf '\n== planWaveFromPaths definition search ==\n'
rg -n "planWaveFromPaths\s*\(" .aiox-core -g '*.js' -g '*.mjs' -g '*.ts'

Repository: SynkraAI/aiox-core

Length of output: 222


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== wave index =='
nl -ba .aiox-core/cli/commands/wave/index.js | sed -n '1,220p'

echo
echo '== sibling command files with error handling =='
for f in $(fd -a 'index.js' .aiox-core/cli/commands | sort); do
  if [ "$f" = ".aiox-core/cli/commands/wave/index.js" ]; then
    continue
  fi
  echo "--- $f ---"
  rg -n "try \{|catch \(|process\.exitCode|planWaveFromPaths|action\(" "$f" || true
done

echo
echo '== planWaveFromPaths references =='
rg -n "planWaveFromPaths\s*\(" .aiox-core -g '*.js'

Repository: SynkraAI/aiox-core

Length of output: 213


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' .aiox-core/cli/commands/wave/index.js
printf '\n===== sibling cmd grep =====\n'
rg -n "try \{|catch \(|process\.exitCode|planWaveFromPaths|action\(" .aiox-core/cli/commands -g 'index.js'

Repository: SynkraAI/aiox-core

Length of output: 14210


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '== planWaveFromPaths definition ==\n'
rg -n "function planWaveFromPaths|const planWaveFromPaths|planWaveFromPaths\s*=" .aiox-core/core -g '*.js' -g '*.mjs' -g '*.ts' -A40 -B20

printf '\n== wave command boundary handling around plan ==\n'
sed -n '44,130p' .aiox-core/cli/commands/wave/index.js

printf '\n== command entry/global error handling ==\n'
rg -n "uncaughtException|unhandledRejection|process\.on\('uncaughtException'|process\.on\('unhandledRejection'" .aiox-core bin packages -g '*.js' -g '*.mjs' -g '*.ts'

Repository: SynkraAI/aiox-core

Length of output: 8071


Wrap wave planning in a try/catch. sdc.planWaveFromPaths() can throw on invalid story files or parse failures, and this action currently lets that escape without a clean CLI message or exit code. Match the sibling commands by catching the error and setting process.exitCode = 1.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/cli/commands/wave/index.js around lines 97 - 110, Wrap the wave
planning logic in the action handler with try/catch, including the
sdc.planWaveFromPaths call and subsequent processing. On failure, print a clear
CLI error message, set process.exitCode to 1, and return; follow the
error-handling pattern used by sibling commands.

Source: Path instructions

Comment on lines +170 to +178
.action((waveId, opts) => {
let state = sdc.loadWaveState(waveId);
if (!state) {
console.error(`No wave state for ${waveId}`);
process.exitCode = 1;
return;
}
const { wave, nextBatch } = sdc.advanceWave(waveId);
state = wave;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the command file and locate the advanceWave implementation/usages.
printf '\n== file list ==\n'
git ls-files '.aiox-core/cli/commands/wave/index.js' '.aiox-core/**' | sed -n '1,120p'

printf '\n== outline: .aiox-core/cli/commands/wave/index.js ==\n'
ast-grep outline .aiox-core/cli/commands/wave/index.js --view expanded || true

printf '\n== search advanceWave references ==\n'
rg -n "advanceWave\\(" .aiox-core packages bin tests docs -g '!**/node_modules/**' || true

printf '\n== search for loadWaveState/save/update wave state ==\n'
rg -n "loadWaveState|saveWaveState|persist|write.*wave|completed stories|auto-complete|refresh statuses" .aiox-core packages bin tests docs -g '!**/node_modules/**' || true

Repository: SynkraAI/aiox-core

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the cited block and the advanceWave implementation if found.
printf '\n== cited block ==\n'
sed -n '150,205p' .aiox-core/cli/commands/wave/index.js | cat -n

# Try to locate likely implementation files from search results if present.
for f in $(rg -l "advanceWave\\(" .aiox-core packages bin tests docs -g '!**/node_modules/**' || true); do
  printf '\n== outline: %s ==\n' "$f"
  ast-grep outline "$f" --view expanded || true
done

Repository: SynkraAI/aiox-core

Length of output: 3682


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== wave-run advanceWave block ==\n'
sed -n '170,220p' .aiox-core/core/sdc/wave-run.js | cat -n

printf '\n== wave command docs/usages ==\n'
rg -n "wave next|Show first incomplete batch|advanceWave\\(|saveWaveState\\(" .aiox-core/development .aiox-core/cli .aiox-core/core -g '!**/node_modules/**' | sed -n '1,200p'

Repository: SynkraAI/aiox-core

Length of output: 3354


Keep wave next read-only. .aiox-core/cli/commands/wave/index.js:167-178 calls sdc.advanceWave, which refreshes statuses, auto-marks stories, and saves the wave. A command described as “Show” shouldn’t advance persisted state; split out a read-only lookup or rename/document the side effect.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/cli/commands/wave/index.js around lines 170 - 178, Make the `wave
next` action read-only: replace `sdc.advanceWave(waveId)` with a dedicated
lookup that computes or retrieves `wave` and `nextBatch` without refreshing
statuses, auto-marking stories, or persisting changes. Update the relevant `sdc`
helper and the `.action` handler to preserve the existing display behavior while
avoiding state mutation.

Comment on lines +80 to +112
function planWaveFromEpic(opts) {
const { paths, stories, errors } = discoverEpicStories(opts.epicDir, opts);
if (errors.length && paths.length === 0) {
const err = new Error(errors.join('; '));
err.code = 'EPIC_GLUE_EMPTY';
throw err;
}
if (paths.length === 0) {
const err = new Error(
`No stories found under ${opts.epicDir}` +
(opts.filter ? ` (filter ${opts.filter})` : '') +
(opts.skipDone ? ' (skipDone)' : ''),
);
err.code = 'EPIC_GLUE_EMPTY';
throw err;
}

const absPaths = paths.map((p) => path.resolve(opts.cwd || process.cwd(), p));
const plan = planAndSave(absPaths, {
waveId: opts.waveId || `epic-${path.basename(opts.epicDir)}`,
mode: opts.mode || 'interactive',
cwd: opts.cwd,
});
plan.epicGlue = {
epicDir: opts.epicDir,
filter: opts.filter || null,
skipDone: Boolean(opts.skipDone),
discovered: stories.map((s) => s.storyId),
};
const { saveWaveState } = require('./progress');
saveWaveState(plan, opts.cwd);
return plan;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Partial parse errors from discoverEpicStories are silently dropped.

errors is only surfaced when every story fails to parse (Line 82). If a subset of STORY-*.md files is malformed while others parse fine, those errors vanish — never attached to the plan, logged, or returned — so the wave silently proceeds on an incomplete story set with no signal to the caller. Consider always attaching errors to plan.epicGlue (and/or warning) so partial failures aren't invisible. A regression test for the mixed success/failure case would also help guard this.

🛠️ Proposed fix to surface partial parse errors
   plan.epicGlue = {
     epicDir: opts.epicDir,
     filter: opts.filter || null,
     skipDone: Boolean(opts.skipDone),
     discovered: stories.map((s) => s.storyId),
+    errors: errors.length ? errors : undefined,
   };
+  if (errors.length) {
+    // eslint-disable-next-line no-console
+    console.warn(`[epic-glue] Skipped ${errors.length} story file(s) due to parse errors: ${errors.join('; ')}`);
+  }
   const { saveWaveState } = require('./progress');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function planWaveFromEpic(opts) {
const { paths, stories, errors } = discoverEpicStories(opts.epicDir, opts);
if (errors.length && paths.length === 0) {
const err = new Error(errors.join('; '));
err.code = 'EPIC_GLUE_EMPTY';
throw err;
}
if (paths.length === 0) {
const err = new Error(
`No stories found under ${opts.epicDir}` +
(opts.filter ? ` (filter ${opts.filter})` : '') +
(opts.skipDone ? ' (skipDone)' : ''),
);
err.code = 'EPIC_GLUE_EMPTY';
throw err;
}
const absPaths = paths.map((p) => path.resolve(opts.cwd || process.cwd(), p));
const plan = planAndSave(absPaths, {
waveId: opts.waveId || `epic-${path.basename(opts.epicDir)}`,
mode: opts.mode || 'interactive',
cwd: opts.cwd,
});
plan.epicGlue = {
epicDir: opts.epicDir,
filter: opts.filter || null,
skipDone: Boolean(opts.skipDone),
discovered: stories.map((s) => s.storyId),
};
const { saveWaveState } = require('./progress');
saveWaveState(plan, opts.cwd);
return plan;
}
function planWaveFromEpic(opts) {
const { paths, stories, errors } = discoverEpicStories(opts.epicDir, opts);
if (errors.length && paths.length === 0) {
const err = new Error(errors.join('; '));
err.code = 'EPIC_GLUE_EMPTY';
throw err;
}
if (paths.length === 0) {
const err = new Error(
`No stories found under ${opts.epicDir}` +
(opts.filter ? ` (filter ${opts.filter})` : '') +
(opts.skipDone ? ' (skipDone)' : ''),
);
err.code = 'EPIC_GLUE_EMPTY';
throw err;
}
const absPaths = paths.map((p) => path.resolve(opts.cwd || process.cwd(), p));
const plan = planAndSave(absPaths, {
waveId: opts.waveId || `epic-${path.basename(opts.epicDir)}`,
mode: opts.mode || 'interactive',
cwd: opts.cwd,
});
plan.epicGlue = {
epicDir: opts.epicDir,
filter: opts.filter || null,
skipDone: Boolean(opts.skipDone),
discovered: stories.map((s) => s.storyId),
errors: errors.length ? errors : undefined,
};
if (errors.length) {
// eslint-disable-next-line no-console
console.warn(`[epic-glue] Skipped ${errors.length} story file(s) due to parse errors: ${errors.join('; ')}`);
}
const { saveWaveState } = require('./progress');
saveWaveState(plan, opts.cwd);
return plan;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/sdc/epic-glue.js around lines 80 - 112, Partial parse errors
from discoverEpicStories are discarded when valid stories are also found. Update
planWaveFromEpic to always preserve the errors collection in plan.epicGlue,
using an empty array when none exist, and ensure callers can detect the
partial-failure condition; add a regression test covering mixed valid and
malformed STORY files.

Comment on lines +70 to +85
function verifyAndMaybeMark(storyPath, phase, opts = {}) {
const result = phaseVerify.verifyPhase(storyPath, phase, opts);
const meta = storyMeta.parseStoryFile(storyPath);
let state = progress.loadSdcState(meta.storyId, opts.cwd);
if (!state) {
({ state } = initFullSdc(storyPath, opts));
}
if (opts.mark) {
progress.markPhase(
state,
phase,
result.ok ? 'passed' : 'failed',
result.ok ? null : result.failures.join('; '),
);
progress.saveSdcState(state, opts.cwd);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail

printf '\n== file list ==\n'
git ls-files '.aiox-core/core/sdc/index.js' '.aiox-core/core/**' | sed -n '1,120p'

printf '\n== outline index.js ==\n'
ast-grep outline .aiox-core/core/sdc/index.js --view expanded || true

printf '\n== search for relevant helpers ==\n'
rg -n "lock|mutex|atomic|CAS|compare-and-swap|revision|version|saveSdcState|loadSdcState|markPhase|verifyAndMaybeMark" .aiox-core/core -g '!**/node_modules/**'

Repository: SynkraAI/aiox-core

Length of output: 50377


🏁 Script executed:

set -euo pipefail
sed -n '1,180p' .aiox-core/core/sdc/index.js

Repository: SynkraAI/aiox-core

Length of output: 3000


🏁 Script executed:

set -euo pipefail
rg -n "lock|mutex|atomic|CAS|compare-and-swap|revision|version|saveSdcState|loadSdcState|markPhase|verifyAndMaybeMark" .aiox-core/core -g '!**/node_modules/**'

Repository: SynkraAI/aiox-core

Length of output: 50376


🏁 Script executed:

set -euo pipefail

printf '\n== sdc helpers ==\n'
sed -n '1,260p' .aiox-core/core/sdc/progress.js

printf '\n== lock/search within sdc ==\n'
rg -n "proper-lockfile|lockfile|rename|tmp|atomic|fsync|writeFile|appendFile|exclusive|revision|version" .aiox-core/core/sdc

printf '\n== docs mentioning SDC state updates ==\n'
rg -n "SDC|state update|lock|atomic|concurrent|race|single-writer" .aiox-core/core/docs .aiox-core/core/sdc

Repository: SynkraAI/aiox-core

Length of output: 9090


Serialize SDC state updates. The load → markPhase() → save path is non-atomic, so concurrent runs can overwrite each other’s progress or apply updates to stale story metadata. Protect this with a lock or a revision/CAS check around the whole update.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/sdc/index.js around lines 70 - 85, Serialize the
load–update–save workflow in verifyAndMaybeMark by adding a lock or revision/CAS
mechanism around progress.loadSdcState, progress.markPhase, and
progress.saveSdcState. Ensure concurrent executions cannot update stale state or
overwrite each other’s progress, while preserving the existing initialization
and verification behavior.

Source: Path instructions

Comment on lines +146 to +153
const { batches, errors, graph } = planWaveBatches(stories);
const waveId = opts.waveId || `wave-${Date.now()}`;

return {
version: 1,
kind: 'wave-execute',
waveId,
status: errors.length ? 'invalid' : 'planned',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## files\n'
git ls-files '.aiox-core/core/sdc/*' | sed 's#^`#-` #'

printf '\n## wave-plan.js excerpt\n'
nl -ba .aiox-core/core/sdc/wave-plan.js | sed -n '120,180p'

printf '\n## wave-run.js excerpt\n'
nl -ba .aiox-core/core/sdc/wave-run.js | sed -n '1,220p'

printf '\n## search waveId and planWaveFromPaths usages\n'
rg -n "planWaveFromPaths|waveId" .aiox-core/core/sdc .aiox-core/core -g '!**/node_modules/**'

Repository: SynkraAI/aiox-core

Length of output: 516


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## wave-plan.js excerpt\n'
sed -n '120,180p' .aiox-core/core/sdc/wave-plan.js | cat -n

printf '\n## wave-run.js excerpt\n'
sed -n '1,240p' .aiox-core/core/sdc/wave-run.js | cat -n

printf '\n## call sites / usages\n'
rg -n "planWaveFromPaths|writeWaveReport|waveRoot\\(|waveId" .aiox-core -g '!**/node_modules/**'

Repository: SynkraAI/aiox-core

Length of output: 18911


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## progress.js excerpt\n'
sed -n '1,220p' .aiox-core/core/sdc/progress.js | cat -n

printf '\n## wave-run.js report section\n'
sed -n '230,320p' .aiox-core/core/sdc/wave-run.js | cat -n

printf '\n## CLI wave command excerpt\n'
sed -n '1,140p' .aiox-core/cli/commands/wave/index.js | cat -n

Repository: SynkraAI/aiox-core

Length of output: 15589


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## progress.js safeId and wave path helpers\n'
sed -n '1,180p' .aiox-core/core/sdc/progress.js | cat -n

printf '\n## wave-run.js report-writing body\n'
sed -n '235,305p' .aiox-core/core/sdc/wave-run.js | cat -n

printf '\n## CLI wave option parsing\n'
sed -n '1,120p' .aiox-core/cli/commands/wave/index.js | cat -n

Repository: SynkraAI/aiox-core

Length of output: 13771


Sanitize waveId before it reaches report paths
--wave-id flows into planWaveFromPaths() unchanged, and writeWaveReport() later does path.join(waveRoot(cwd), wave.waveId) directly. waveStatePath() already uses safeId(), so report generation should use the same sanitization (or reject invalid ids) to avoid escaping .aiox/waves/.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/core/sdc/wave-plan.js around lines 146 - 153, Sanitize or
validate the generated wave identifier before storing it in the plan returned by
planWaveFromPaths(); apply the existing safeId() behavior to opts.waveId (or
reject invalid values) so writeWaveReport() cannot receive an unsafe wave.waveId
and escape the .aiox/waves/ directory, matching waveStatePath() handling.

Comment thread .aiox-core/scripts/pm.sh
Comment on lines +338 to +342
if [[ -n "$CONTEXT_FILE" && -f "$CONTEXT_FILE" ]]; then
prompt+="Context file: ${CONTEXT_FILE}. "
# shellcheck disable=SC2002
prompt+="Context JSON: $(cat "$CONTEXT_FILE" 2>/dev/null | head -c 8000). "
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the relevant script section
git ls-files '.aiox-core/scripts/pm.sh' '.aiox-core/**' 'docs/**' 'tests/**' | sed -n '1,200p'
echo '---'
wc -l .aiox-core/scripts/pm.sh
echo '---'
sed -n '300,380p' .aiox-core/scripts/pm.sh
echo '---'
rg -n "CONTEXT_FILE|build_agent_prompt|context file|context" .aiox-core/scripts/pm.sh .aiox-core docs tests -S

Repository: SynkraAI/aiox-core

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map script structure first, then inspect only the relevant function range
ast-grep outline .aiox-core/scripts/pm.sh --view expanded || true
echo '---'
sed -n '1,220p' .aiox-core/scripts/pm.sh

Repository: SynkraAI/aiox-core

Length of output: 5584


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find any docs or code explaining how CONTEXT_FILE is used/provided
rg -n "CONTEXT_FILE|context file|context-file|build_agent_prompt|CLAUDE_CMD|Claude CLI|prompt" .aiox-core docs tests -S

Repository: SynkraAI/aiox-core

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the surrounding functions and any user-facing docs for CONTEXT_FILE semantics
sed -n '220,380p' .aiox-core/scripts/pm.sh
echo '---'
rg -n "CONTEXT_FILE|context file|context_file|ctx file|prompt" docs .aiox-core -g '!**/*.min.*' -S

Repository: SynkraAI/aiox-core

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where CONTEXT_FILE is assigned and whether it is user-controlled
rg -n "CONTEXT_FILE\s*=|--context|--context-file|context-file|context file" .aiox-core/scripts/pm.sh -S
echo '---'
sed -n '1,220p' .aiox-core/scripts/pm.sh

Repository: SynkraAI/aiox-core

Length of output: 6061


Raw context-file contents are forwarded to the external CLI. .aiox-core/scripts/pm.sh:338-342 appends up to 8 KiB of CONTEXT_FILE as-is into the prompt. Since --context is only validated as an existing file, any secrets or PII in that JSON will be sent to the configured CLI/service; add redaction or an explicit opt-in warning before embedding it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/scripts/pm.sh around lines 338 - 342, The context file contents
are embedded into the external CLI prompt without protecting sensitive data.
Update the CONTEXT_FILE handling in the prompt construction logic to redact
secrets and PII before appending the content, or require an explicit opt-in
confirmation/warning before transmission; preserve the existing file validation
and size limit.

Comment thread .aiox-core/scripts/pm.sh
Comment on lines +460 to +468
local script_self
script_self="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
local full_cmd="AIOX_INLINE_MODE=true AIOX_OUTPUT_DIR='${OUTPUT_DIR}' "
full_cmd+="AIOX_DEBUG='${DEBUG}' CLAUDE_CMD='${CLAUDE_CMD}' "
full_cmd+="bash '${script_self}' '${AGENT}' '${TASK}'"
[[ -n "$PARAMS" ]] && full_cmd+=" ${PARAMS}"
[[ -n "$CONTEXT_FILE" ]] && full_cmd+=" --context '${CONTEXT_FILE}'"
full_cmd+=" --output '${OUTPUT_FILE}'; "
full_cmd+="rc=\$?; rm -f '${LOCK_FILE}'; exit \$rc"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail

# Inspect the relevant file around the cited lines.
nl -ba .aiox-core/scripts/pm.sh | sed -n '380,520p'

printf '\n--- PARAMS references ---\n'
rg -n '\bPARAMS\b|spawn_linux|spawn_windows|osascript|bash -c|do script' .aiox-core/scripts/pm.sh

printf '\n--- file size ---\n'
wc -l .aiox-core/scripts/pm.sh

Repository: SynkraAI/aiox-core

Length of output: 196


🏁 Script executed:

# If the previous scan is too broad, isolate the definitions and any command-execution helpers.
set -euo pipefail

ast-grep outline .aiox-core/scripts/pm.sh --view expanded || true

printf '\n--- focused snippets ---\n'
for pat in 'spawn_linux' 'spawn_windows' 'osascript' 'bash -c' 'PARAMS=' 'CONTEXT_FILE=' 'full_cmd+='; do
  printf '\n## %s\n' "$pat"
  rg -n -A6 -B6 "$pat" .aiox-core/scripts/pm.sh || true
done

Repository: SynkraAI/aiox-core

Length of output: 6065


🏁 Script executed:

set -euo pipefail
sed -n '220,265p' .aiox-core/scripts/pm.sh

Repository: SynkraAI/aiox-core

Length of output: 1239


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- PARAMS docs/usages ---'
rg -n -A3 -B3 '\bPARAMS\b|quoted string|free-form|task parameters|--context|--output' .aiox-core docs README.md bin packages tests || true

Repository: SynkraAI/aiox-core

Length of output: 50376


🏁 Script executed:

set -euo pipefail

# Read the argument parsing around where PARAMS is populated.
sed -n '110,175p' .aiox-core/scripts/pm.sh

printf '\n--- spawn_macos / spawn_linux / spawn_windows ---\n'
sed -n '230,320p' .aiox-core/scripts/pm.sh

Repository: SynkraAI/aiox-core

Length of output: 4168


🏁 Script executed:

set -euo pipefail

# Probe shell-quoting behavior for the exact construction pattern used here.
python3 - <<'PY'
import shlex, subprocess, textwrap, os, json, tempfile

params = '; echo INJECTED'
cmd = "bash -lc " + shlex.quote(f"echo A {params} B")
print("constructed:", cmd)
out = subprocess.run(cmd, shell=True, capture_output=True, text=True)
print("returncode:", out.returncode)
print("stdout:", out.stdout.strip())
print("stderr:", out.stderr.strip())
PY

Repository: SynkraAI/aiox-core

Length of output: 249


Quote PARAMS before appending it to full_cmd. It is built from positional args and concatenated verbatim into a string that later gets executed by bash -c/Terminal/AppleScript, so metacharacters in a task parameter can inject commands. Escape each argument instead of concatenating raw shell text; this affects Linux, Windows/WSL, and macOS spawn paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.aiox-core/scripts/pm.sh around lines 460 - 468, The command construction in
the inline execution path appends raw PARAMS, allowing parameter metacharacters
to alter or inject commands. Update the relevant command-building logic around
full_cmd to preserve PARAMS as distinct quoted arguments, escaping each
positional parameter with the platform-appropriate shell quoting before
appending; apply the same safe handling across Linux, Windows/WSL, and macOS
spawn paths.


```bash
wsl bash -c 'cd /mnt/c/Users/AllFluence-User/Workspaces/AIOX/SynkraAI/aiox-core && ~/.local/bin/coderabbit {flags}'
wsl bash -c 'cd /mnt/c/path/to/aiox-core && ~/.local/bin/coderabbit {flags}'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Replace the placeholder repository path.

Line 36 will fail because /mnt/c/path/to/aiox-core is not a real repository path. Use a configurable repository-root variable or derive the current checkout path before invoking CodeRabbit.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/coderabbit-review/SKILL.md at line 36, Replace the hardcoded
placeholder path in the CodeRabbit invocation with a configurable
repository-root variable or dynamically derive the current checkout directory,
then pass that resolved path to the wsl bash command.

Comment thread .gitignore
Comment on lines +379 to +380
# Local Codex CLI artifacts (do not version until hardened — absolute paths / force-push wording)
.codex/

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Do not ignore the versioned Codex skills directory.

Ignoring all of .codex/ prevents the documented .codex/skills artifacts from being tracked. Narrow this rule to local artifacts and explicitly allow .codex/skills/**, for example with .codex/*, !.codex/skills/, and !.codex/skills/**.

As per coding guidelines, local-first Codex skills must remain versioned.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.gitignore around lines 379 - 380, Update the Codex ignore rules in
.gitignore so the entire .codex/ directory is not excluded: replace the broad
.codex/ rule with a rule for local artifacts such as .codex/*, then explicitly
unignore .codex/skills/ and .codex/skills/** so the documented skills remain
versioned.

Source: Coding guidelines

@Pedrovaleriolopez

Copy link
Copy Markdown
Contributor Author

Superseded by #802, which contains the same fix (JEST_WORKER_ID/test-runner guard in detectEnvironment() + fail-safe inline degradation in pm.sh) plus the model-budget ceiling gate and shell-safety hardening, with green CI across all platforms. Closing in favor of #802 to avoid conflicting changes to the same 4 files (terminal-spawner.js, pm.sh, and both spawner test suites).

🤖 Generated with Claude Code

@Pedrovaleriolopez
Pedrovaleriolopez deleted the fix/terminal-spawner-no-visual-under-tests branch July 11, 2026 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli CLI tools (bin/, packages/aios-pro-cli/) area: core Core framework (.aios-core/core/) area: docs Documentation (docs/) area: installer Installer and setup (packages/installer/) area: synapse SYNAPSE context engine type: test Test coverage and quality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants