fix(orchestration): never spawn visual terminals from test runners - #803
fix(orchestration): never spawn visual terminals from test runners#803Pedrovaleriolopez wants to merge 46 commits into
Conversation
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.
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>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughThis 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. ChangesSDC and wave execution
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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 winSpecify 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 winSpecify the language for the error-output fence.
Use an identifier such as
textto 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 winSpecify languages for the fenced code blocks.
Add
bashortextidentifiers 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 winValidate 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
normalizedis 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, andisAllowlistedcould 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."isAllowlistedis 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 winDead conditional — dotfile/dotdir skip logic is never applied.
The
ifblock's body is empty (just a comment), so this check has no effect on control flow: nocontinue, no exclusion. Every dot-prefixed entry (aside from names already inSKIP_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 winAdd
afterEachto clean up temp directories.
beforeEachcreates a new temp directory viafs.mkdtempSyncbut there is no correspondingafterEachto remove them. The sibling test filetests/unit/sdc/wave-run.test.jsin this same PR correctly cleans up withfs.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 winSync throw in
fn()leaves timer running + logs a misleading "Timeout" warning.If
fn()throws synchronously, the throw happens before.then/.catchattach, soclearTimeout(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 ingetMemoryHintsstill 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 winAdd 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 winValidate
maxQgIterationsinstead of using truthiness.Line 80 silently changes
0to3and 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 winWrite progress state atomically.
.aiox-core/core/sdc/progress.js:105-108truncates 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 winAdd a language tag to the diagram fence.
markdownlintreports MD040 because Line 34 uses an untyped fenced block. Mark it astextso 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 winMake
resolveStoryPathshandle 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 winUse consistent repository-relative skill paths.
The entry prefixes
aiox-sdcwithskills/, but leavesaiox-full-sdcandatomicsunprefixed. 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 winReconcile 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 ingovernance_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 winAdd a blank line before the completion-boundary table.
markdownlint-cli2reports 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 winAdd the second modified ConfigCache path to the story File List.
The decision states that both
.aiox-core/core/config/config-cache.jsand.aiox-core/infrastructure/scripts/config-cache.jswere 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 winResolve the unchecked DoD item before marking the story Done.
The story is marked
Done, but#798 closed with PR linkremains 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
startsWithprefix match over-blocks addresses that merely start with::1.
'::1'is already handled exactly at Lines 152-154. Including it inBLOCKED_IPV6_PREFIXESand checkingnormalized.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 winValidate IPv4 octets before
ipv4ToInt().checkIPv4()and the IPv4-mapped paths incheckIPv6()/checkHostname()accept malformed values like256.0.0.1and::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 winSpecify languages for the fenced code blocks.
The command example should use
bash, and the orchestration pseudocode should usetext(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 valueScript logic is sound; consider concurrent access safeguards.
The read-modify-write cycle on
HINTS_PATHhas 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 winAdd 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 slashand 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 valueUnreachable dead-code branch.
usedFilesis always empty when the first story inorderedis evaluated (each batch iteration re-initializesusedFilesat line 78), sofiles.some((f) => usedFiles.has(f))is alwaysfalseforordered[0]— it is always pushed intobatchon the first check.batch.length === 0can 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 winAdd a language tag to the fenced block.
The invocation block is CLI/shell syntax but has no fence language, which triggers markdownlint MD040. Use
bashortextas 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 valueSHA1 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 winFlag values aren't validated before use — trailing flag crashes with an unclear error.
If
--hub,--enterprise,--oss, or--outis passed as the last CLI argument (no following value),argv[++i]isundefinedandpath.resolve(undefined)throws a rawTypeErrorinstead 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 winDuplicated dispatch try/catch — extract a shared helper.
The
sdc/wavecases repeat the exact same require→run→catch→exit pattern already used byworkers/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 winDuplicate 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 valueConsider batching
git check-ignorecalls; current per-entry spawn is acceptable at current scale.
isGitIgnoredspawns a separategitprocess 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 singlegit check-ignore --stdincall 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.namecomes from a realfs.readdirSyncdirectory 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
📒 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.mdAGENTS.mdbin/aiox.jsdocs/framework/README.mddocs/framework/config-override-guide.mddocs/framework/epics/core-super-update/ANALYSIS-3WAY-CORRECTIONS.mddocs/framework/epics/core-super-update/ARCHITECTURE-WAVE-0.mddocs/framework/epics/core-super-update/ARCHITECTURE-WAVE-A.mddocs/framework/epics/core-super-update/ARCHITECTURE-WAVE-B.mddocs/framework/epics/core-super-update/ARCHITECTURE-WAVE-C.mddocs/framework/epics/core-super-update/ARCHITECTURE-WAVE-D.mddocs/framework/epics/core-super-update/ARCHITECTURE-WAVE-E.mddocs/framework/epics/core-super-update/EPIC-CORE-SUPER-UPDATE.mddocs/framework/epics/core-super-update/ROADMAP.mddocs/framework/epics/core-super-update/STORY-CORE-SU.0-DIFF-HARNESS.mddocs/framework/epics/core-super-update/STORY-CORE-SU.A1-SYNAPSE-TIMEOUT-CONFIG.mddocs/framework/epics/core-super-update/STORY-CORE-SU.A2-CONFIGCACHE-JEST-RESIDUAL.mddocs/framework/epics/core-super-update/STORY-CORE-SU.A3-PERMISSION-GUARDS.mddocs/framework/epics/core-super-update/STORY-CORE-SU.A4-PORT-DENYLIST.mddocs/framework/epics/core-super-update/STORY-CORE-SU.C2-DISPATCH-ADAPTER.mddocs/framework/epics/core-super-update/STORY-CORE-SU.C3-EPIC-GLUE.mddocs/framework/epics/core-super-update/STORY-CORE-SU.C4-WAVE-C-TESTS.mddocs/framework/epics/core-super-update/STORY-CORE-SU.D1-IDE-SYNC-CONTRACT.mddocs/framework/epics/core-super-update/STORY-CORE-SU.E1-CONSTITUTION-XI-XII.mddocs/framework/epics/core-super-update/STORY-CORE-SU.F1-WINDOWS-ECOMPROMISED.mddocs/framework/epics/core-super-update/STORY-CORE-SU.MB-MEMORY-BRIDGE.mddocs/framework/epics/core-super-update/STORY-CORE-SU.PM-STUB-FIX.mddocs/framework/ide-sync-contract.mddocs/framework/story-locations.mddocs/guides/installation-troubleshooting.mddocs/npx-install.mdpackage.jsonpackages/installer/tests/unit/doctor/doctor-checks.test.jspackages/installer/tests/unit/doctor/doctor-orchestrator.test.jsscripts/validate-port-denylist.jstests/core/config-cache-unref.test.jstests/core/ids/registry-updater.test.jstests/core/orchestration/terminal-spawner.test.jstests/core/terminal-spawner.test.jstests/synapse/engine.test.jstests/synapse/hook-runtime.test.jstests/synapse/memory-bridge-heuristics.test.jstests/unit/framework-3way-diff.test.jstests/unit/install/windows-npx-hint.test.jstests/unit/port-denylist.test.jstests/unit/sdc/dispatch-adapter.test.jstests/unit/sdc/epic-glue.test.jstests/unit/sdc/phase-verify.test.jstests/unit/sdc/story-meta.test.jstests/unit/sdc/wave-c-integration.test.jstests/unit/sdc/wave-plan.test.jstests/unit/sdc/wave-run.test.jstests/unit/validate-claude-integration.test.js
| * 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> |
There was a problem hiding this comment.
🎯 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.
| .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, | ||
| }); |
There was a problem hiding this comment.
🩺 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
| .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; |
There was a problem hiding this comment.
🗄️ 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/**' || trueRepository: 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
doneRepository: 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.
| 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; | ||
| } |
There was a problem hiding this comment.
🎯 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.
| 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.
| 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); | ||
| } |
There was a problem hiding this comment.
🗄️ 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.jsRepository: 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/sdcRepository: 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
| 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', |
There was a problem hiding this comment.
🔒 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 -nRepository: 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 -nRepository: 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.
| 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 |
There was a problem hiding this comment.
🔒 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 -SRepository: 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.shRepository: 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 -SRepository: 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.*' -SRepository: 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.shRepository: 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.
| 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" |
There was a problem hiding this comment.
🔒 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.shRepository: 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
doneRepository: SynkraAI/aiox-core
Length of output: 6065
🏁 Script executed:
set -euo pipefail
sed -n '220,265p' .aiox-core/scripts/pm.shRepository: 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 || trueRepository: 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.shRepository: 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())
PYRepository: 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}' |
There was a problem hiding this comment.
🎯 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.
| # Local Codex CLI artifacts (do not version until hardened — absolute paths / force-push wording) | ||
| .codex/ |
There was a problem hiding this comment.
📐 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
|
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 |
Problema
As suítes
tests/core/terminal-spawner.test.jsetests/core/orchestration/terminal-spawner.test.jschamam ospawnAgent()/spawnInline()REAIS, sem nenhum mock. Em macOS nativo (fora de CI/VS Code/SSH), cada execução denpm testtomava 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 rodandonpm testcomo quality gate). Além disso,spawnInlineinvocava o CLIclaudereal a partir dos testes (gasto de tokens).Fix
terminal-spawner.js—detectEnvironment()ganha o tipoTEST: spawn visual só é concedido quando o ambiente é nativo E não há test-runner (JEST_WORKER_ID) E não há opt-out viaAIOX_NO_VISUAL=true.pm.sh— mesmo guard emspawn_terminal()(defesa em profundidade para qualquer chamador);AIOX_NO_VISUALdocumentada no--help.CLAUDE_CMD=truenos describes que executam o spawner de verdade (nunca mais invocam oclaudereal); 3 testes de regressão do guard, incluindo "rodando sob jest,supportsVisualTerminalé semprefalse".Verificação
pm.sh dev testmanual comJEST_WORKER_ID=1e comAIOX_NO_VISUAL=trueforçaRunning in inline mode— nenhuma janela.Mitigação imediata para instalações afetadas (antes do release)
CI=true npm testouexport AIOX_NO_VISUAL=true.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
aiox sdccommands for story lifecycle planning, status, verification, and phase progression.aiox wavecommands for dependency-aware planning, batch execution, progress tracking, and reporting.Bug Fixes
npxinstallation guidance and test-runner reliability.Documentation