-
Notifications
You must be signed in to change notification settings - Fork 3
Release 8.20.97: promote dev changes #305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
* fix: allow markdown docs in any path segment * fix: use configured allowlist for markdown in any path segment * fix: allow markdown by path segment and clean path normalization * fix: guard pm markdown allowlist and inherit parent-path rules * fix: enforce parent-path rules before markdown allow segments
* fix: enforce parent-path rule before markdown segment allowlist * test: cover parent-path markdown allow when setting enabled * fix: run markdown segment allowlist after parent-path guard * feat: add configurable auto commit review reminder
* fix: ensure markdown segment allowlist honors parent gate * docs: add sample ICC configs for main/sub-agent and strict/relaxed * feat: parametrized config deployment and sample icc configs * chore: snapshot current config and tighten main-scope sample agents block * fix: preserve existing icc.config.json unless override provided * chore: rename local config backup and document it * chore: clarify/preserve existing icc.config on ansible reinstall
* fix: apply infra policy checks to full command incl. ssh wrapper * fix: tighten docs fast-path (no heredoc/chaining; only under project docs) * docs: fix duplicate Added header in 8.20.88 changelog * fix: docs fast-path requires path under cwd with segment boundary
* fix: doc fast-path only blocks unquoted substitution * fix: aggressive ALL-CAPS detection handles mixed separators * fix: treat double-quoted substitution as unsafe doc fast-path * fix: respect escaped substitutions in doc fast-path
* fix: allow nested allowlist paths for markdown * chore: dedupe markdown allowlist sequences
* feat: add main-scope dev preset and config-driven bash allowlist * fix: scope config main-scope bash allowlist to main-role
* Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255)
* Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255)
chore: merge origin/main into dev
* feat: allow main scope to inherit agent privileges * docs: clarify main scope agent flag impact
* feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: allow markdown when any path segment is docs (#259) * fix: allow markdown docs in any path segment * fix: use configured allowlist for markdown in any path segment * fix: allow markdown by path segment and clean path normalization * fix: guard pm markdown allowlist and inherit parent-path rules * fix: enforce parent-path rules before markdown allow segments * fix: enforce parent-path before markdown segment allowlist (#261) * fix: enforce parent-path rule before markdown segment allowlist * test: cover parent-path markdown allow when setting enabled * fix: run markdown segment allowlist after parent-path guard * feat: add configurable auto commit review reminder * fix: markdown segment allowlist respects parent-path gate (#262) * fix: ensure markdown segment allowlist honors parent gate * docs: add sample ICC configs for main/sub-agent and strict/relaxed * feat: parametrized config deployment and sample icc configs * chore: snapshot current config and tighten main-scope sample agents block * fix: preserve existing icc.config.json unless override provided * chore: rename local config backup and document it * chore: clarify/preserve existing icc.config on ansible reinstall * fix: enforce infra policy on full command including ssh wrapper (#264) * fix: apply infra policy checks to full command incl. ssh wrapper * fix: tighten docs fast-path (no heredoc/chaining; only under project docs) * docs: fix duplicate Added header in 8.20.88 changelog * fix: docs fast-path requires path under cwd with segment boundary * fix: make doc fast-path allow literal markdown code (#269) * fix: doc fast-path only blocks unquoted substitution * fix: aggressive ALL-CAPS detection handles mixed separators * fix: treat double-quoted substitution as unsafe doc fast-path * fix: respect escaped substitutions in doc fast-path * fix: support nested markdown allowlist segments (#266) * fix: allow nested allowlist paths for markdown * chore: dedupe markdown allowlist sequences * feat: linux main-scope friendly config + guardrail defaults (#272) * feat: add main-scope dev preset and config-driven bash allowlist * fix: scope config main-scope bash allowlist to main-role * fix: doc fast-path & constraint display (#274) * Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255) * chore: sync dev with main (#275) * Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255)
* feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: allow markdown when any path segment is docs (#259) * fix: allow markdown docs in any path segment * fix: use configured allowlist for markdown in any path segment * fix: allow markdown by path segment and clean path normalization * fix: guard pm markdown allowlist and inherit parent-path rules * fix: enforce parent-path rules before markdown allow segments * fix: enforce parent-path before markdown segment allowlist (#261) * fix: enforce parent-path rule before markdown segment allowlist * test: cover parent-path markdown allow when setting enabled * fix: run markdown segment allowlist after parent-path guard * feat: add configurable auto commit review reminder * fix: markdown segment allowlist respects parent-path gate (#262) * fix: ensure markdown segment allowlist honors parent gate * docs: add sample ICC configs for main/sub-agent and strict/relaxed * feat: parametrized config deployment and sample icc configs * chore: snapshot current config and tighten main-scope sample agents block * fix: preserve existing icc.config.json unless override provided * chore: rename local config backup and document it * chore: clarify/preserve existing icc.config on ansible reinstall * fix: enforce infra policy on full command including ssh wrapper (#264) * fix: apply infra policy checks to full command incl. ssh wrapper * fix: tighten docs fast-path (no heredoc/chaining; only under project docs) * docs: fix duplicate Added header in 8.20.88 changelog * fix: docs fast-path requires path under cwd with segment boundary * fix: make doc fast-path allow literal markdown code (#269) * fix: doc fast-path only blocks unquoted substitution * fix: aggressive ALL-CAPS detection handles mixed separators * fix: treat double-quoted substitution as unsafe doc fast-path * fix: respect escaped substitutions in doc fast-path * fix: support nested markdown allowlist segments (#266) * fix: allow nested allowlist paths for markdown * chore: dedupe markdown allowlist sequences * feat: linux main-scope friendly config + guardrail defaults (#272) * feat: add main-scope dev preset and config-driven bash allowlist * fix: scope config main-scope bash allowlist to main-role * fix: doc fast-path & constraint display (#274) * Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255) * chore: sync dev with main (#275) * Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255)
* Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255) * fix: support nested markdown allowlist segments (#266) * fix: allow nested allowlist paths for markdown * chore: dedupe markdown allowlist sequences * feat: linux main-scope friendly config + guardrail defaults (#272) * feat: add main-scope dev preset and config-driven bash allowlist * fix: scope config main-scope bash allowlist to main-role * fix: doc fast-path & constraint display (#274) * Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255) * chore: sync dev with main (#275) * Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255) * feat: main scope agent privilege flag (#278) * feat: allow main scope to inherit agent privileges * docs: clarify main scope agent flag impact * Merge dev into main (v8.20.89) (#273) (#280) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: allow markdown when any path segment is docs (#259) * fix: allow markdown docs in any path segment * fix: use configured allowlist for markdown in any path segment * fix: allow markdown by path segment and clean path normalization * fix: guard pm markdown allowlist and inherit parent-path rules * fix: enforce parent-path rules before markdown allow segments * fix: enforce parent-path before markdown segment allowlist (#261) * fix: enforce parent-path rule before markdown segment allowlist * test: cover parent-path markdown allow when setting enabled * fix: run markdown segment allowlist after parent-path guard * feat: add configurable auto commit review reminder * fix: markdown segment allowlist respects parent-path gate (#262) * fix: ensure markdown segment allowlist honors parent gate * docs: add sample ICC configs for main/sub-agent and strict/relaxed * feat: parametrized config deployment and sample icc configs * chore: snapshot current config and tighten main-scope sample agents block * fix: preserve existing icc.config.json unless override provided * chore: rename local config backup and document it * chore: clarify/preserve existing icc.config on ansible reinstall * fix: enforce infra policy on full command including ssh wrapper (#264) * fix: apply infra policy checks to full command incl. ssh wrapper * fix: tighten docs fast-path (no heredoc/chaining; only under project docs) * docs: fix duplicate Added header in 8.20.88 changelog * fix: docs fast-path requires path under cwd with segment boundary * fix: make doc fast-path allow literal markdown code (#269) * fix: doc fast-path only blocks unquoted substitution * fix: aggressive ALL-CAPS detection handles mixed separators * fix: treat double-quoted substitution as unsafe doc fast-path * fix: respect escaped substitutions in doc fast-path * fix: support nested markdown allowlist segments (#266) * fix: allow nested allowlist paths for markdown * chore: dedupe markdown allowlist sequences * feat: linux main-scope friendly config + guardrail defaults (#272) * feat: add main-scope dev preset and config-driven bash allowlist * fix: scope config main-scope bash allowlist to main-role * fix: doc fast-path & constraint display (#274) * Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255) * chore: sync dev with main (#275) * Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255) * Merge dev into main (v8.20.89) (#273) (#281) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: allow markdown when any path segment is docs (#259) * fix: allow markdown docs in any path segment * fix: use configured allowlist for markdown in any path segment * fix: allow markdown by path segment and clean path normalization * fix: guard pm markdown allowlist and inherit parent-path rules * fix: enforce parent-path rules before markdown allow segments * fix: enforce parent-path before markdown segment allowlist (#261) * fix: enforce parent-path rule before markdown segment allowlist * test: cover parent-path markdown allow when setting enabled * fix: run markdown segment allowlist after parent-path guard * feat: add configurable auto commit review reminder * fix: markdown segment allowlist respects parent-path gate (#262) * fix: ensure markdown segment allowlist honors parent gate * docs: add sample ICC configs for main/sub-agent and strict/relaxed * feat: parametrized config deployment and sample icc configs * chore: snapshot current config and tighten main-scope sample agents block * fix: preserve existing icc.config.json unless override provided * chore: rename local config backup and document it * chore: clarify/preserve existing icc.config on ansible reinstall * fix: enforce infra policy on full command including ssh wrapper (#264) * fix: apply infra policy checks to full command incl. ssh wrapper * fix: tighten docs fast-path (no heredoc/chaining; only under project docs) * docs: fix duplicate Added header in 8.20.88 changelog * fix: docs fast-path requires path under cwd with segment boundary * fix: make doc fast-path allow literal markdown code (#269) * fix: doc fast-path only blocks unquoted substitution * fix: aggressive ALL-CAPS detection handles mixed separators * fix: treat double-quoted substitution as unsafe doc fast-path * fix: respect escaped substitutions in doc fast-path * fix: support nested markdown allowlist segments (#266) * fix: allow nested allowlist paths for markdown * chore: dedupe markdown allowlist sequences * feat: linux main-scope friendly config + guardrail defaults (#272) * feat: add main-scope dev preset and config-driven bash allowlist * fix: scope config main-scope bash allowlist to main-role * fix: doc fast-path & constraint display (#274) * Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255) * chore: sync dev with main (#275) * Release 8.20.89 (dev -> main) (#252) * feat: surface MCP availability hints and gate MCP tools via config * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * Release 8.20.89 (dev -> main) (#253) * feat: surface MCP availability hints and gate MCP tools via config (#246) * fix: allow docs/documentation writes in main scope allowlist (#247) * chore: add config presets and docs allowlist coverage (#248) * docs: streamline README and docs index (#249) * fix: allow docs heredoc writes without infra blocking (#250) * feat: inject best practices & memory guidance; keep exec pattern in all-caps block (#251) * fix: tighten docs heredoc allow to prevent infra bypass (#254) * fix: allow nested docs paths and harden docs write allowlist (#255)
…fastpath-fix infra: harden doc fast-path
Merge dev-workflows into dev (conflicts resolved)
* pm: let allowlisted docs bypass PM tool blacklist * infra: honor parent allowlist in doc fast-path * docs routing: allow docs segment anywhere; enable constraints output in main-scope preset
…ed destructive cmds
…ride infra: env-driven main bypass; marker dir override
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR promotes development changes to main as version 8.20.97, consolidating workflow enforcement improvements, infrastructure protection hardening, and memory directory routing fixes. The primary focus is on allowing free-form notes in memory directories while maintaining structured document routing, and enhancing security through stricter command substitution detection and configurable bypass controls.
Key Changes:
- Enhanced memory directory routing to support both
memory/andmemories/paths while preventing STORY/BUG/EPIC files from being misrouted into these directories - Hardened infrastructure protection with stricter command substitution detection, explicit main-scope agent bypass controls via environment variables, and centralized marker directory management
- Updated test suite to validate memory routing fixes and infrastructure protection enhancements with proper environment variable settings
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/VERSION | Bumped version to 8.20.97 |
| VERSION | Bumped root version to 8.20.97 for consistency |
| CHANGELOG.md | Added changelog entries for versions 8.20.94-8.20.97 documenting all changes |
| src/hooks/lib/directory-enforcement.js | Added support for memories/ directory routing and logic to allow free-form notes in memory directories while blocking STORY/BUG/EPIC files |
| src/hooks/agent-infrastructure-protection.js | Added stricter command substitution detection, main-scope bypass controls, and allowlisted markdown write validation |
| src/hooks/pm-constraints-enforcement.js | Added 'memories' directory to allowlist for consistency with directory enforcement |
| src/hooks/main-scope-enforcement.js | Refactored to use centralized getMarkerDir() function |
| src/hooks/agent-marker.js | Refactored to use centralized getMarkerDir() function |
| src/hooks/context-injection.js | Refactored to use centralized getMarkerDir() function |
| src/hooks/stop.js | Removed auto-review context output to ensure schema compliance and refactored marker directory access |
| src/hooks/subagent-stop.js | Refactored to use centralized getMarkerDir() function |
| src/hooks/user-prompt-submit.js | Refactored to use centralized getMarkerDir() function |
| src/hooks/session-start-dummy.js | Refactored to use centralized getMarkerDir() function and removed trailing whitespace |
| sample-configs/icc.config.main-scope-dev.json | Added auto_commit_review configuration block |
| tests/run-tests.sh | Added CLAUDE_DISABLE_MAIN_INFRA_BYPASS environment variable to ensure test isolation |
| tests/hooks/unit/test-agent-infra-doc-fastpath.js | Added test environment variables and new test case for double-quoted strings with single-quoted substitution |
| tests/hooks/regression/test-known-bugs.js | Updated STORY-007 tests to reflect deployed fix status, removing temporary assertions |
| tests/hooks/integration/test-directory-routing.js | Updated memory directory tests to validate fix and added tests to ensure STORY/BUG files are blocked in memory directories |
Comments suppressed due to low confidence (1)
src/hooks/agent-infrastructure-protection.js:655
- Inconsistent indentation throughout the file: the
function main()declaration at line 25 has incorrect leading spaces, and all subsequent code within the function (constants, helper functions, and main logic) appears to have inconsistent indentation. Lines 25-655 should follow consistent indentation wherefunction main()starts at column 0, and the function body is indented by 2 spaces. Currently lines 25-27 appear to have incorrect leading indentation.
function main() {
// Initialize hook with shared library function
const { log, hookInput } = initializeHook('agent-infrastructure-protection');
const DOC_DIRECTORY_NAMES = new Set([
'docs',
'documentation',
'doc',
'docs-site',
'docs-content',
]);
const MARKDOWN_ALLOWLIST_DIRS = [
getSetting('paths.docs_path', 'docs'),
getSetting('paths.story_path', 'stories'),
getSetting('paths.bug_path', 'bugs'),
getSetting('paths.memory_path', 'memory'),
getSetting('paths.summaries_path', 'summaries'),
'agenttasks'
];
// Strict command substitution detection: ignores anything inside quotes
function hasCommandSubstitution(str) {
let inSingle = false;
let inDouble = false;
for (let i = 0; i < str.length; i++) {
const ch = str[i];
const prev = str[i - 1];
if (!inDouble && ch === "'" && prev !== '\\') {
inSingle = !inSingle;
continue;
}
if (!inSingle && ch === '"' && prev !== '\\') {
inDouble = !inDouble;
continue;
}
if (inSingle) {
continue;
}
if (ch === '$' && prev !== '\\' && str[i + 1] === '(') {
return true;
}
if (ch === '`' && prev !== '\\') {
return true;
}
if ((ch === '>' || ch === '<') && prev !== '\\' && str[i + 1] === '(') {
return true;
}
}
return false;
}
// Looser command substitution detection: allows matches inside double-quotes (but still not single quotes)
function hasCommandSubstitutionLoose(str) {
let inSingle = false;
let inDouble = false;
for (let i = 0; i < str.length; i++) {
const ch = str[i];
const prev = str[i - 1];
if (ch === '"' && prev !== '\\' && !inSingle) {
inDouble = !inDouble;
continue;
}
// Ignore single quotes that appear inside double-quoted strings
if (ch === "'" && prev !== '\\' && !inDouble) {
inSingle = !inSingle;
continue;
}
if (inSingle) {
continue;
}
if (ch === '$' && prev !== '\\' && str[i + 1] === '(') {
return true;
}
if (ch === '`' && prev !== '\\') {
return true;
}
if ((ch === '>' || ch === '<') && prev !== '\\' && str[i + 1] === '(') {
return true;
}
}
return false;
}
function escapeRegex(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
// Return true if `needle` appears in `haystack` outside of quotes
function containsUnquoted(haystack, needle) {
if (!haystack || !needle) return false;
let inSingle = false;
let inDouble = false;
for (let i = 0; i <= haystack.length - needle.length; i++) {
const ch = haystack[i];
if (ch === '\\') { // skip escaped character
i += 1;
continue;
}
if (ch === "'" && !inDouble) {
inSingle = !inSingle;
continue;
}
if (ch === '"' && !inSingle) {
inDouble = !inDouble;
continue;
}
if (!inSingle && !inDouble && haystack.startsWith(needle, i)) {
return true;
}
}
return false;
}
// Match keyword anywhere (quoted or unquoted) using word boundaries
function matchesKeywordAnywhere(str, needle) {
if (!str || !needle) return false;
const re = new RegExp(`\\b${escapeRegex(needle)}\\b`);
return re.test(str);
}
const ALLOW_PARENT_ALLOWLIST_PATHS = getSetting('enforcement.allow_parent_allowlist_paths', false);
function targetsDocumentation(target, cwd) {
const absBase = path.resolve(cwd || process.cwd());
const absTarget = path.resolve(absBase, target);
const underBase = absTarget === absBase || absTarget.startsWith(absBase + path.sep);
if (!underBase && !ALLOW_PARENT_ALLOWLIST_PATHS) {
return false;
}
const segments = absTarget.split(path.sep);
return segments.some((segment) => DOC_DIRECTORY_NAMES.has(segment));
}
function targetsAllowlistedMarkdown(target, cwd) {
const absBase = path.resolve(cwd || process.cwd());
const absTarget = path.resolve(absBase, target);
const underBase = absTarget === absBase || absTarget.startsWith(absBase + path.sep);
if (!underBase && !ALLOW_PARENT_ALLOWLIST_PATHS) {
return false;
}
if (!absTarget.endsWith('.md')) {
return false;
}
const segments = absTarget.split(path.sep);
return segments.some((segment) => MARKDOWN_ALLOWLIST_DIRS.includes(segment));
}
function isAllowlistedMarkdownWrite(cmd, cwd) {
const trimmed = cmd.trim();
if (!trimmed) {
return false;
}
const firstLine = trimmed.split('\n', 1)[0];
if (/[;&|]{1,2}/.test(firstLine)) {
return false;
}
if (hasCommandSubstitutionLoose(firstLine)) {
return false;
}
const redirectMatch = firstLine.match(/^(?:\s*)(cat|printf|tee)\b[^>]*>+\s*([^\s]+)\s*$/i);
if (!redirectMatch) {
return false;
}
const target = redirectMatch[2];
if (!targetsAllowlistedMarkdown(target, cwd)) {
return false;
}
const dashTrim = firstLine.includes('<<-');
const heredocMatch = firstLine.match(/<<-?\s*(?:'([A-Za-z0-9_:-]+)'|"([A-Za-z0-9_:-]+)"|([A-Za-z0-9_:-]+))/);
if (heredocMatch) {
const terminator = heredocMatch[1] || heredocMatch[2] || heredocMatch[3];
const leadingTabs = dashTrim ? '\\t*' : '';
const terminatorRegex = new RegExp(`\\n${leadingTabs}${escapeRegex(terminator)}\\s*$`);
const hasTerminator = terminatorRegex.test(trimmed);
const isQuoted = Boolean(heredocMatch[1] || heredocMatch[2]);
if (!hasTerminator) {
return false;
}
if (!isQuoted) {
const body = trimmed.replace(/^.*?\n/s, '');
if (hasCommandSubstitutionLoose(body)) {
return false;
}
}
return true;
}
return trimmed.indexOf('\n') === -1;
}
function isQuotedHeredoc(cmd) {
const trimmed = cmd.trim();
if (!trimmed) {
return false;
}
const firstLine = trimmed.split('\n', 1)[0];
const heredocMatch = firstLine.match(/<<-?\s*(?:'([A-Za-z0-9_:-]+)'|"([A-Za-z0-9_:-]+)"|([A-Za-z0-9_:-]+))/);
if (!heredocMatch) {
return false;
}
return Boolean(heredocMatch[1] || heredocMatch[2]);
}
function isSingleQuotedHeredoc(cmd) {
const trimmed = cmd.trim();
if (!trimmed) return false;
const firstLine = trimmed.split('\n', 1)[0];
const heredocMatch = firstLine.match(/<<-?\s*'([A-Za-z0-9_:-]+)'/);
return Boolean(heredocMatch);
}
function looksLikeMarkdownWrite(cmd, cwd) {
const trimmed = cmd.trim();
if (!trimmed) return false;
const firstLine = trimmed.split('\n', 1)[0];
const redirectMatch = firstLine.match(/^(?:\s*)(cat|printf|tee)\b[^>]*>+\s*([^\s]+)\s*$/i);
if (!redirectMatch) return false;
const target = redirectMatch[2];
return targetsAllowlistedMarkdown(target, cwd);
}
function isDocumentationWrite(cmd, cwd) {
const trimmed = cmd.trim();
if (!trimmed) {
return false;
}
const firstLine = trimmed.split('\n', 1)[0];
if (/[;&|]{1,2}/.test(firstLine)) {
return false;
}
if (hasCommandSubstitutionLoose(firstLine)) {
return false;
}
const redirectMatch = firstLine.match(/^(?:\s*)(cat|printf|tee)\b[^>]*>+\s*([^\s]+)\s*$/i);
if (!redirectMatch) {
return false;
}
const target = redirectMatch[2];
if (!targetsDocumentation(target, cwd)) {
return false;
}
const dashTrim = firstLine.includes('<<-');
const heredocMatch = firstLine.match(/<<-?\s*(?:'([A-Za-z0-9_:-]+)'|"([A-Za-z0-9_:-]+)"|([A-Za-z0-9_:-]+))/);
if (heredocMatch) {
const terminator = heredocMatch[1] || heredocMatch[2] || heredocMatch[3];
// Require a quoted terminator OR a body with no command substitution
const leadingTabs = dashTrim ? '\\t*' : '';
const terminatorRegex = new RegExp(`\\n${leadingTabs}${escapeRegex(terminator)}\\s*$`);
const hasTerminator = terminatorRegex.test(trimmed);
const isQuoted = Boolean(heredocMatch[1] || heredocMatch[2]);
if (!hasTerminator) {
return false;
}
if (!isQuoted) {
// Unquoted heredoc bodies perform substitution; ensure body is clean
const body = trimmed.replace(/^.*?\n/s, '');
if (hasCommandSubstitutionLoose(body)) {
return false;
}
}
return true;
}
return trimmed.indexOf('\n') === -1;
}
function extractSSHCommand(command) {
// Match SSH command patterns:
// ssh user@host "command"
// ssh -J jump@host user@host "command"
// ssh -i keyfile user@host "command"
// ssh user@host << 'EOF' ... EOF (heredoc)
// ssh user@host << EOF ... EOF (heredoc)
// Pattern 1: Quoted commands
const quotedPatterns = [
/ssh\s+.*?"([^"]+)"/, // ssh ... "command" (double quotes)
/ssh\s+.*?'([^']+)'/, // ssh ... 'command' (single quotes)
];
for (const pattern of quotedPatterns) {
const match = command.match(pattern);
if (match && match[1]) {
return match[1];
}
}
// Pattern 2: Heredoc (extract entire heredoc content)
const heredocPattern = /ssh\s+.*?<<\s*'?EOF'?\s*([\s\S]*?)\s*EOF/;
const heredocMatch = command.match(heredocPattern);
if (heredocMatch && heredocMatch[1]) {
return heredocMatch[1].trim();
}
return command; // Not SSH, return original
}
const standardOutput = {
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "allow"
}
};
try {
// hookInput already parsed earlier for logging
if (!hookInput) {
console.log(JSON.stringify(standardOutput));
process.exit(0);
}
const tool_name = hookInput.tool_name;
// Only check Bash operations
if (tool_name !== 'Bash') {
console.log(JSON.stringify(standardOutput));
process.exit(0);
}
const command = hookInput.tool_input?.command || '';
// Check if infrastructure protection is enabled
const protectionEnabled = PROTECTION_ENABLED;
// If main scope is configured to have agent privileges, bypass infra protection entirely.
const isMainScope =
!hookInput.permission_mode ||
hookInput.permission_mode === 'default' ||
hookInput.permission_mode === 'main';
const mainScopeAgentEnabled =
MAIN_SCOPE_AGENT_ENV === false
? false
: ((MAIN_SCOPE_AGENT_ENV === true) || MAIN_SCOPE_AGENT_PRIV);
if (mainScopeAgentEnabled && isMainScope && !DISABLE_MAIN_INFRA_BYPASS) {
log('Main scope agent privileges enabled - bypassing infrastructure protection');
console.log(JSON.stringify(standardOutput));
process.exit(0);
}
if (!protectionEnabled) {
log('Infrastructure protection disabled - allowing command');
console.log(JSON.stringify(standardOutput));
process.exit(0);
}
log(`Checking command: ${command.substring(0, 100)}...`);
log(`Infrastructure protection: enabled`);
// Extract actual command (handle SSH wrapping)
const actualCommand = extractSSHCommand(command);
log(`Actual command after SSH extraction: ${actualCommand.substring(0, 100)}...`);
// Special-case: allow pure documentation writes to docs*/ directories even if
// the heredoc body contains infra keywords, because only a file write occurs.
if (isDocumentationWrite(command, hookInput.cwd)) {
log('ALLOWED: Documentation write detected (docs*/ directories fast-path)');
console.log(JSON.stringify(standardOutput));
process.exit(0);
}
// If this is a markdown write attempt and contains command substitution, block it
// unless it's an allowlisted markdown heredoc with a quoted terminator (no expansion).
const looksMarkdown = looksLikeMarkdownWrite(command, hookInput.cwd);
const allowlistedMarkdown = looksMarkdown && isAllowlistedMarkdownWrite(command, hookInput.cwd);
const quotedMarkdownHeredoc = looksMarkdown && isQuotedHeredoc(command);
const singleQuotedMarkdownHeredoc = looksMarkdown && isSingleQuotedHeredoc(command);
const rawSubstitution = command.includes('$(') || command.includes('`');
if (looksMarkdown && (hasCommandSubstitutionLoose(command) || rawSubstitution) && !(allowlistedMarkdown && singleQuotedMarkdownHeredoc)) {
log('BLOCKED: Markdown write contains command substitution');
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Command substitution detected inside markdown write"
}
}));
process.exit(0);
}
// Allow markdown writes in allowlisted directories (docs/stories/bugs/memory/summaries/agenttasks)
if (allowlistedMarkdown) {
log('ALLOWED: Markdown write detected in allowlisted directory');
console.log(JSON.stringify(standardOutput));
process.exit(0);
}
// Check for emergency override token
const emergencyOverrideEnabled = EMERGENCY_OVERRIDE_ENABLED;
const emergencyToken = EMERGENCY_TOKEN;
if (emergencyOverrideEnabled && emergencyToken && command.includes(`EMERGENCY_OVERRIDE:${emergencyToken}`)) {
log(`EMERGENCY OVERRIDE ACTIVATED - allowing command with token`);
// Remove token from command before execution
const cleanCommand = command.replace(new RegExp(`EMERGENCY_OVERRIDE:${emergencyToken}\\s*`, 'g'), '');
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "allow",
permissionDecisionReason: "Emergency override token accepted"
}
}));
process.exit(0);
}
// Load configuration-based command lists
const imperativeDestructive = IMPERATIVE_DESTRUCTIVE;
const writeOperations = WRITE_OPERATIONS;
const readOperations = READ_OPERATIONS;
const whitelist = WHITELIST;
const readAllowed = READ_ALLOWED;
const blockingEnabled = BLOCKING_ENABLED;
// Step 1: Check imperative destructive operations (enforce IaC - suggest alternatives)
for (const imperativeCmd of imperativeDestructive) {
// Match both quoted and unquoted occurrences to avoid bypass via wrappers
if (
containsUnquoted(command, imperativeCmd) ||
containsUnquoted(actualCommand, imperativeCmd) ||
matchesKeywordAnywhere(command, imperativeCmd) ||
matchesKeywordAnywhere(actualCommand, imperativeCmd)
) {
if (blockingEnabled) {
log(`IaC-ENFORCEMENT: Imperative destructive command detected: ${imperativeCmd}`);
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "IaC Enforcement - imperative destructive command detected"
},
systemMessage: `🏗️ INFRASTRUCTURE-AS-CODE ENFORCEMENT
Full command: ${command}
Remote command: ${actualCommand}
Blocked command: ${imperativeCmd}
Blocked by: enforcement.infrastructure_protection.imperative_destructive
❌ PROHIBITED APPROACHES:
• Imperative commands (kubectl delete, govc vm.destroy, Remove-VM)
• Shell scripts with infrastructure commands
• Manual SSH operations
• Ad-hoc infrastructure modifications
• One-off fixes without documentation
✅ REQUIRED: REUSABLE INFRASTRUCTURE-AS-CODE
• Ansible Playbooks (playbooks/*.yml) - state management
• Terraform configurations (*.tf) - infrastructure definition
• Helm Charts (charts/*) - Kubernetes applications
• CloudFormation templates (*.yaml) - AWS resources
• Pulumi programs - multi-cloud infrastructure
WHY IaC ONLY:
• Version control - track all changes
• Reusability - apply same config to multiple environments
• Audit trails - who changed what when
• Rollback capability - revert to previous state
• Team visibility - everyone sees infrastructure state
• Documentation - code IS the documentation
• Testing - validate before applying
• Idempotency - same result every time
WORKFLOW:
1. Create reusable playbook/chart/config
2. Test in development environment
3. Commit to version control
4. Apply via IaC tool (ansible-playbook, terraform apply, helm install)
5. Document in repository
To allow imperative commands: Set enforcement.blocking_enabled=false in icc.config.json
Emergency override: EMERGENCY_OVERRIDE:<token> <command>
Configuration: ./icc.config.json or ./.claude/icc.config.json`
}));
process.exit(0);
} else {
log(`[IaC-ENFORCEMENT] Imperative destructive detected but blocking disabled: ${command}`);
// Continue with warning - blocking disabled
}
}
}
// Step 2: Check whitelist (overrides write/read blacklists, but not imperative destructive)
for (const allowedCmd of whitelist) {
if (command.includes(allowedCmd) || actualCommand.includes(allowedCmd)) {
log(`ALLOWED: Command in whitelist: ${allowedCmd}`);
console.log(JSON.stringify(standardOutput));
process.exit(0);
}
}
// Step 3: Check write operations (blocked for agents)
for (const writeCmd of writeOperations) {
if (
containsUnquoted(command, writeCmd) ||
containsUnquoted(actualCommand, writeCmd) ||
matchesKeywordAnywhere(command, writeCmd) ||
matchesKeywordAnywhere(actualCommand, writeCmd)
) {
log(`BLOCKED: Write operation command: ${writeCmd}`);
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Infrastructure write operation blocked for agents"
},
systemMessage: `⚠️ INFRASTRUCTURE MODIFICATION BLOCKED
Full command: ${command}
Remote command: ${actualCommand}
Blocked command: ${writeCmd}
Blocked by: enforcement.infrastructure_protection.write_operations
❌ PROHIBITED:
• Manual infrastructure modifications via SSH
• Shell scripts with kubectl/govc/VM commands
• Direct state changes without IaC
• Ad-hoc fixes and patches
✅ REQUIRED: Create reusable IaC resources
• Ansible Playbooks for configuration management
• Helm Charts for Kubernetes deployments
• Terraform for infrastructure provisioning
• Version-controlled and documented
PRINCIPLE: Infrastructure changes MUST be:
- Repeatable (works in all environments)
- Versionable (committed to git)
- Testable (validated before production)
- Documented (self-documenting code)
To allow this operation:
1. Create reusable playbook/chart/config
2. Add to whitelist: enforcement.infrastructure_protection.whitelist
3. Or disable protection: enforcement.infrastructure_protection.enabled: false
Configuration: ./icc.config.json or ./.claude/icc.config.json`
}));
process.exit(0);
}
}
// Step 4: Check read operations (allowed if read_operations_allowed=true)
for (const readCmd of readOperations) {
if (command.includes(readCmd) || actualCommand.includes(readCmd)) {
if (readAllowed) {
log(`ALLOWED: Read operation: ${readCmd}`);
console.log(JSON.stringify(standardOutput));
process.exit(0);
} else {
log(`BLOCKED: Read operation disabled: ${readCmd}`);
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Infrastructure read operation disabled"
},
systemMessage: `ℹ️ READ OPERATION BLOCKED
Blocked command: ${readCmd}
Full command: ${command}
Blocked by: enforcement.infrastructure_protection.read_operations
Read operations are currently disabled.
To allow read operations:
1. Enable in configuration: enforcement.infrastructure_protection.read_operations_allowed: true
2. Or add to whitelist: enforcement.infrastructure_protection.whitelist
Configuration: ./icc.config.json or ./.claude/icc.config.json`
}));
process.exit(0);
}
}
}
// Allow command
console.log(JSON.stringify(standardOutput));
process.exit(0);
} catch (error) {
log(`Error: ${error.message}`);
console.log(JSON.stringify(standardOutput));
process.exit(0);
}
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const segments = normalizedActual.split(path.sep); | ||
| const isStory = /^STORY-\d+/i.test(basename); | ||
| const isBug = /^BUG-/i.test(basename); | ||
| const isEpic = /^EPIC-/i.test(basename); |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent regex pattern for EPIC detection: line 19 uses /^(STORY|EPIC)-\d+-.*\.md$/ (requiring a suffix after the number), while line 89 uses /^EPIC-/i (no suffix requirement and case-insensitive). This inconsistency could cause isEpic to match files that wouldn't be routed by getCorrectDirectory. Standardize both patterns to match the same format, preferably /^EPIC-\d+/i for consistency.
| getSetting('paths.docs_path', 'docs'), | ||
| getSetting('paths.story_path', 'stories'), | ||
| getSetting('paths.bug_path', 'bugs'), | ||
| getSetting('paths.memory_path', 'memory'), |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing 'memories' directory in MARKDOWN_ALLOWLIST_DIRS: the directory-enforcement.js now supports both 'memory' and 'memories' directories (lines 51-58), and pm-constraints-enforcement.js includes 'memories' in its allowlist (line 1123), but this array only includes 'memory'. Add 'memories' to maintain consistency across all enforcement hooks.
| getSetting('paths.memory_path', 'memory'), | |
| getSetting('paths.memory_path', 'memory'), | |
| 'memories', |
| // unless it's an allowlisted markdown heredoc with a quoted terminator (no expansion). | ||
| const looksMarkdown = looksLikeMarkdownWrite(command, hookInput.cwd); | ||
| const allowlistedMarkdown = looksMarkdown && isAllowlistedMarkdownWrite(command, hookInput.cwd); | ||
| const quotedMarkdownHeredoc = looksMarkdown && isQuotedHeredoc(command); |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable quotedMarkdownHeredoc.
| const quotedMarkdownHeredoc = looksMarkdown && isQuotedHeredoc(command); |
Summary
Testing