Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定 - #31

Merged
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements
Aug 20, 2026
Merged

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定#31
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#28 ・设计依据见 #27

fix(plan-mode):plan mode 一定退得出去

原来裸 /plan 在 planning 态只 notify 一句「已激活」,ready 态的选择菜单也只有 continue / implement / fresh —— 没有任何「关闭」入口,不知道 /plan off 这个确切写法的人就出不去了。

  • PLAN_READY_ACTIONS 增加 off: "Turn plan mode off"
  • /plan(planning 态)改为弹菜单:Continue planning / Finalize now / Turn plan mode off;非 UI 会话保持原有提示
  • ready 态的 block 文案补上 /plan off 出口

feat(footer):单条 status 空间够就内联

  • 状态文案缩短:plan mode · read-onlyplan modeplan mode · readyplan ready
  • renderFooter()只有一条 status 且能塞进第一行剩余空隙时并入该行,否则维持独占行。多条 status(后台任务 + 子代理等)行为完全不变

feat(plan-mode):bash 门禁从「语法」改为「副作用」

原来靠语法黑名单一票否决:任何引号、|*$~ 都拒,程序只认 git/gh。结果 rg -l "pattern" --glob '*.ts' 这种纯只读命令跑不了,只读调研在没有 rg/fd 工具的宿主会话里直接无解。对照 Claude Code 与 Codex,两者都允许带引号参数,按命令效果分类。

  • 新增小型 tokenizer:引号内按字面量处理;$、反引号、\ 一律拒(无论是否在引号内);未加引号的元字符与 glob 仍拒;未配对引号拒;词首 ~ 拒但 HEAD~3 保留
  • 加引号的 glob 放行--glob '*.ts' 由程序自己解析,shell 不展开),未加引号仍拒并在报错里告诉怎么改
  • 程序白名单扩到 rg fd ls wc head tail,各自配 flag 允许表,沿用原有准入标准(只塑形输出,不能命名要执行的程序 / 要写的文件 / 不能永久阻塞):排除 rg --pre/--pre-glob/-zfd -x/-Xtail -f
  • git/gh 的子命令与 flag 表完全不变,包括「子命令必须紧跟程序名」;短 flag 聚合(ls -la)只对新增的只读程序开放
  • 全部拒绝文案改为可行动:说清拒绝了哪一部分 + 怎么写才能过

保留原有架构:fail-closed 允许列表、flag 级逃逸分析、子代理靠 harness 收窄工具。未做#28 里标为可选):管道与 &&/; 分段放行、tree-sitter 解析。

验证

  • bun run test:719 + 29 全绿(基线 713 + 29)
  • bun run check 退出 0(仅剩 file-search/src/binaries.ts 的既存 lint warning)
  • 额外用 26 条策略断言脚本交叉验证,确认 git checkout .git pushgit -Cgit log -sprg foo | headrg $(whoami) 等仍被拒

Allow quoted literal arguments and a narrow set of read-only search and inspection tools.\nKeep shell expansion, composition, unsafe flags, and unknown effects fail-closed so plan mode cannot mutate before approval.
The first pass added cluster handling twice: once inside scanArguments and
once in a separate scanShortFlagClusters pass. The scanArguments branch was
not gated by program, so it silently widened git and gh too. Collapse both
into one opt-in parameter that only the file-inspection programs pass.
The leaner default layout from #26 leaves room for a single status to inline
at width 80, so the old lines.length >= 2 assertion encoded placement rather
than the property it meant to protect: the status must stay visible.
@tt-a1i
tt-a1iforce-pushed the plan-mode-improvements branch from 2735b01 to 6f6e2b8CompareAugust 20, 2026 14:15
@tt-a1i
tt-a1i merged commit 1f49756 into mainAug 20, 2026
4 checks passed
@tt-a1i
tt-a1i deleted the plan-mode-improvements branch August 20, 2026 14:27
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plan Mode 三项改进:指示器内联、必定可退出、bash 门禁改按副作用判定

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定 - #31

Merged
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements
Aug 20, 2026
Merged

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定#31
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#28 ・设计依据见 #27

fix(plan-mode):plan mode 一定退得出去

原来裸 /plan 在 planning 态只 notify 一句「已激活」,ready 态的选择菜单也只有 continue / implement / fresh —— 没有任何「关闭」入口,不知道 /plan off 这个确切写法的人就出不去了。

  • PLAN_READY_ACTIONS 增加 off: "Turn plan mode off"
  • /plan(planning 态)改为弹菜单:Continue planning / Finalize now / Turn plan mode off;非 UI 会话保持原有提示
  • ready 态的 block 文案补上 /plan off 出口

feat(footer):单条 status 空间够就内联

  • 状态文案缩短:plan mode · read-onlyplan modeplan mode · readyplan ready
  • renderFooter()只有一条 status 且能塞进第一行剩余空隙时并入该行,否则维持独占行。多条 status(后台任务 + 子代理等)行为完全不变

feat(plan-mode):bash 门禁从「语法」改为「副作用」

原来靠语法黑名单一票否决:任何引号、|*$~ 都拒,程序只认 git/gh。结果 rg -l "pattern" --glob '*.ts' 这种纯只读命令跑不了,只读调研在没有 rg/fd 工具的宿主会话里直接无解。对照 Claude Code 与 Codex,两者都允许带引号参数,按命令效果分类。

  • 新增小型 tokenizer:引号内按字面量处理;$、反引号、\ 一律拒(无论是否在引号内);未加引号的元字符与 glob 仍拒;未配对引号拒;词首 ~ 拒但 HEAD~3 保留
  • 加引号的 glob 放行--glob '*.ts' 由程序自己解析,shell 不展开),未加引号仍拒并在报错里告诉怎么改
  • 程序白名单扩到 rg fd ls wc head tail,各自配 flag 允许表,沿用原有准入标准(只塑形输出,不能命名要执行的程序 / 要写的文件 / 不能永久阻塞):排除 rg --pre/--pre-glob/-zfd -x/-Xtail -f
  • git/gh 的子命令与 flag 表完全不变,包括「子命令必须紧跟程序名」;短 flag 聚合(ls -la)只对新增的只读程序开放
  • 全部拒绝文案改为可行动:说清拒绝了哪一部分 + 怎么写才能过

保留原有架构:fail-closed 允许列表、flag 级逃逸分析、子代理靠 harness 收窄工具。未做#28 里标为可选):管道与 &&/; 分段放行、tree-sitter 解析。

验证

  • bun run test:719 + 29 全绿(基线 713 + 29)
  • bun run check 退出 0(仅剩 file-search/src/binaries.ts 的既存 lint warning)
  • 额外用 26 条策略断言脚本交叉验证,确认 git checkout .git pushgit -Cgit log -sprg foo | headrg $(whoami) 等仍被拒

Allow quoted literal arguments and a narrow set of read-only search and inspection tools.\nKeep shell expansion, composition, unsafe flags, and unknown effects fail-closed so plan mode cannot mutate before approval.
The first pass added cluster handling twice: once inside scanArguments and
once in a separate scanShortFlagClusters pass. The scanArguments branch was
not gated by program, so it silently widened git and gh too. Collapse both
into one opt-in parameter that only the file-inspection programs pass.
The leaner default layout from #26 leaves room for a single status to inline
at width 80, so the old lines.length >= 2 assertion encoded placement rather
than the property it meant to protect: the status must stay visible.
@tt-a1i
tt-a1iforce-pushed the plan-mode-improvements branch from 2735b01 to 6f6e2b8CompareAugust 20, 2026 14:15
@tt-a1i
tt-a1i merged commit 1f49756 into mainAug 20, 2026
4 checks passed
@tt-a1i
tt-a1i deleted the plan-mode-improvements branch August 20, 2026 14:27
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plan Mode 三项改进:指示器内联、必定可退出、bash 门禁改按副作用判定

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定 - #31

Merged
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements
Aug 20, 2026
Merged

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定#31
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#28 ・设计依据见 #27

fix(plan-mode):plan mode 一定退得出去

原来裸 /plan 在 planning 态只 notify 一句「已激活」,ready 态的选择菜单也只有 continue / implement / fresh —— 没有任何「关闭」入口,不知道 /plan off 这个确切写法的人就出不去了。

  • PLAN_READY_ACTIONS 增加 off: "Turn plan mode off"
  • /plan(planning 态)改为弹菜单:Continue planning / Finalize now / Turn plan mode off;非 UI 会话保持原有提示
  • ready 态的 block 文案补上 /plan off 出口

feat(footer):单条 status 空间够就内联

  • 状态文案缩短:plan mode · read-onlyplan modeplan mode · readyplan ready
  • renderFooter()只有一条 status 且能塞进第一行剩余空隙时并入该行,否则维持独占行。多条 status(后台任务 + 子代理等)行为完全不变

feat(plan-mode):bash 门禁从「语法」改为「副作用」

原来靠语法黑名单一票否决:任何引号、|*$~ 都拒,程序只认 git/gh。结果 rg -l "pattern" --glob '*.ts' 这种纯只读命令跑不了,只读调研在没有 rg/fd 工具的宿主会话里直接无解。对照 Claude Code 与 Codex,两者都允许带引号参数,按命令效果分类。

  • 新增小型 tokenizer:引号内按字面量处理;$、反引号、\ 一律拒(无论是否在引号内);未加引号的元字符与 glob 仍拒;未配对引号拒;词首 ~ 拒但 HEAD~3 保留
  • 加引号的 glob 放行--glob '*.ts' 由程序自己解析,shell 不展开),未加引号仍拒并在报错里告诉怎么改
  • 程序白名单扩到 rg fd ls wc head tail,各自配 flag 允许表,沿用原有准入标准(只塑形输出,不能命名要执行的程序 / 要写的文件 / 不能永久阻塞):排除 rg --pre/--pre-glob/-zfd -x/-Xtail -f
  • git/gh 的子命令与 flag 表完全不变,包括「子命令必须紧跟程序名」;短 flag 聚合(ls -la)只对新增的只读程序开放
  • 全部拒绝文案改为可行动:说清拒绝了哪一部分 + 怎么写才能过

保留原有架构:fail-closed 允许列表、flag 级逃逸分析、子代理靠 harness 收窄工具。未做#28 里标为可选):管道与 &&/; 分段放行、tree-sitter 解析。

验证

  • bun run test:719 + 29 全绿(基线 713 + 29)
  • bun run check 退出 0(仅剩 file-search/src/binaries.ts 的既存 lint warning)
  • 额外用 26 条策略断言脚本交叉验证,确认 git checkout .git pushgit -Cgit log -sprg foo | headrg $(whoami) 等仍被拒

Allow quoted literal arguments and a narrow set of read-only search and inspection tools.\nKeep shell expansion, composition, unsafe flags, and unknown effects fail-closed so plan mode cannot mutate before approval.
The first pass added cluster handling twice: once inside scanArguments and
once in a separate scanShortFlagClusters pass. The scanArguments branch was
not gated by program, so it silently widened git and gh too. Collapse both
into one opt-in parameter that only the file-inspection programs pass.
The leaner default layout from #26 leaves room for a single status to inline
at width 80, so the old lines.length >= 2 assertion encoded placement rather
than the property it meant to protect: the status must stay visible.
@tt-a1i
tt-a1iforce-pushed the plan-mode-improvements branch from 2735b01 to 6f6e2b8CompareAugust 20, 2026 14:15
@tt-a1i
tt-a1i merged commit 1f49756 into mainAug 20, 2026
4 checks passed
@tt-a1i
tt-a1i deleted the plan-mode-improvements branch August 20, 2026 14:27
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plan Mode 三项改进:指示器内联、必定可退出、bash 门禁改按副作用判定

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定 - #31

Merged
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements
Aug 20, 2026
Merged

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定#31
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#28 ・设计依据见 #27

fix(plan-mode):plan mode 一定退得出去

原来裸 /plan 在 planning 态只 notify 一句「已激活」,ready 态的选择菜单也只有 continue / implement / fresh —— 没有任何「关闭」入口,不知道 /plan off 这个确切写法的人就出不去了。

  • PLAN_READY_ACTIONS 增加 off: "Turn plan mode off"
  • /plan(planning 态)改为弹菜单:Continue planning / Finalize now / Turn plan mode off;非 UI 会话保持原有提示
  • ready 态的 block 文案补上 /plan off 出口

feat(footer):单条 status 空间够就内联

  • 状态文案缩短:plan mode · read-onlyplan modeplan mode · readyplan ready
  • renderFooter()只有一条 status 且能塞进第一行剩余空隙时并入该行,否则维持独占行。多条 status(后台任务 + 子代理等)行为完全不变

feat(plan-mode):bash 门禁从「语法」改为「副作用」

原来靠语法黑名单一票否决:任何引号、|*$~ 都拒,程序只认 git/gh。结果 rg -l "pattern" --glob '*.ts' 这种纯只读命令跑不了,只读调研在没有 rg/fd 工具的宿主会话里直接无解。对照 Claude Code 与 Codex,两者都允许带引号参数,按命令效果分类。

  • 新增小型 tokenizer:引号内按字面量处理;$、反引号、\ 一律拒(无论是否在引号内);未加引号的元字符与 glob 仍拒;未配对引号拒;词首 ~ 拒但 HEAD~3 保留
  • 加引号的 glob 放行--glob '*.ts' 由程序自己解析,shell 不展开),未加引号仍拒并在报错里告诉怎么改
  • 程序白名单扩到 rg fd ls wc head tail,各自配 flag 允许表,沿用原有准入标准(只塑形输出,不能命名要执行的程序 / 要写的文件 / 不能永久阻塞):排除 rg --pre/--pre-glob/-zfd -x/-Xtail -f
  • git/gh 的子命令与 flag 表完全不变,包括「子命令必须紧跟程序名」;短 flag 聚合(ls -la)只对新增的只读程序开放
  • 全部拒绝文案改为可行动:说清拒绝了哪一部分 + 怎么写才能过

保留原有架构:fail-closed 允许列表、flag 级逃逸分析、子代理靠 harness 收窄工具。未做#28 里标为可选):管道与 &&/; 分段放行、tree-sitter 解析。

验证

  • bun run test:719 + 29 全绿(基线 713 + 29)
  • bun run check 退出 0(仅剩 file-search/src/binaries.ts 的既存 lint warning)
  • 额外用 26 条策略断言脚本交叉验证,确认 git checkout .git pushgit -Cgit log -sprg foo | headrg $(whoami) 等仍被拒

Allow quoted literal arguments and a narrow set of read-only search and inspection tools.\nKeep shell expansion, composition, unsafe flags, and unknown effects fail-closed so plan mode cannot mutate before approval.
The first pass added cluster handling twice: once inside scanArguments and
once in a separate scanShortFlagClusters pass. The scanArguments branch was
not gated by program, so it silently widened git and gh too. Collapse both
into one opt-in parameter that only the file-inspection programs pass.
The leaner default layout from #26 leaves room for a single status to inline
at width 80, so the old lines.length >= 2 assertion encoded placement rather
than the property it meant to protect: the status must stay visible.
@tt-a1i
tt-a1iforce-pushed the plan-mode-improvements branch from 2735b01 to 6f6e2b8CompareAugust 20, 2026 14:15
@tt-a1i
tt-a1i merged commit 1f49756 into mainAug 20, 2026
4 checks passed
@tt-a1i
tt-a1i deleted the plan-mode-improvements branch August 20, 2026 14:27
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plan Mode 三项改进:指示器内联、必定可退出、bash 门禁改按副作用判定

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定 - #31

Merged
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements
Aug 20, 2026
Merged

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定#31
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#28 ・设计依据见 #27

fix(plan-mode):plan mode 一定退得出去

原来裸 /plan 在 planning 态只 notify 一句「已激活」,ready 态的选择菜单也只有 continue / implement / fresh —— 没有任何「关闭」入口,不知道 /plan off 这个确切写法的人就出不去了。

  • PLAN_READY_ACTIONS 增加 off: "Turn plan mode off"
  • /plan(planning 态)改为弹菜单:Continue planning / Finalize now / Turn plan mode off;非 UI 会话保持原有提示
  • ready 态的 block 文案补上 /plan off 出口

feat(footer):单条 status 空间够就内联

  • 状态文案缩短:plan mode · read-onlyplan modeplan mode · readyplan ready
  • renderFooter()只有一条 status 且能塞进第一行剩余空隙时并入该行,否则维持独占行。多条 status(后台任务 + 子代理等)行为完全不变

feat(plan-mode):bash 门禁从「语法」改为「副作用」

原来靠语法黑名单一票否决:任何引号、|*$~ 都拒,程序只认 git/gh。结果 rg -l "pattern" --glob '*.ts' 这种纯只读命令跑不了,只读调研在没有 rg/fd 工具的宿主会话里直接无解。对照 Claude Code 与 Codex,两者都允许带引号参数,按命令效果分类。

  • 新增小型 tokenizer:引号内按字面量处理;$、反引号、\ 一律拒(无论是否在引号内);未加引号的元字符与 glob 仍拒;未配对引号拒;词首 ~ 拒但 HEAD~3 保留
  • 加引号的 glob 放行--glob '*.ts' 由程序自己解析,shell 不展开),未加引号仍拒并在报错里告诉怎么改
  • 程序白名单扩到 rg fd ls wc head tail,各自配 flag 允许表,沿用原有准入标准(只塑形输出,不能命名要执行的程序 / 要写的文件 / 不能永久阻塞):排除 rg --pre/--pre-glob/-zfd -x/-Xtail -f
  • git/gh 的子命令与 flag 表完全不变,包括「子命令必须紧跟程序名」;短 flag 聚合(ls -la)只对新增的只读程序开放
  • 全部拒绝文案改为可行动:说清拒绝了哪一部分 + 怎么写才能过

保留原有架构:fail-closed 允许列表、flag 级逃逸分析、子代理靠 harness 收窄工具。未做#28 里标为可选):管道与 &&/; 分段放行、tree-sitter 解析。

验证

  • bun run test:719 + 29 全绿(基线 713 + 29)
  • bun run check 退出 0(仅剩 file-search/src/binaries.ts 的既存 lint warning)
  • 额外用 26 条策略断言脚本交叉验证,确认 git checkout .git pushgit -Cgit log -sprg foo | headrg $(whoami) 等仍被拒

Allow quoted literal arguments and a narrow set of read-only search and inspection tools.\nKeep shell expansion, composition, unsafe flags, and unknown effects fail-closed so plan mode cannot mutate before approval.
The first pass added cluster handling twice: once inside scanArguments and
once in a separate scanShortFlagClusters pass. The scanArguments branch was
not gated by program, so it silently widened git and gh too. Collapse both
into one opt-in parameter that only the file-inspection programs pass.
The leaner default layout from #26 leaves room for a single status to inline
at width 80, so the old lines.length >= 2 assertion encoded placement rather
than the property it meant to protect: the status must stay visible.
@tt-a1i
tt-a1iforce-pushed the plan-mode-improvements branch from 2735b01 to 6f6e2b8CompareAugust 20, 2026 14:15
@tt-a1i
tt-a1i merged commit 1f49756 into mainAug 20, 2026
4 checks passed
@tt-a1i
tt-a1i deleted the plan-mode-improvements branch August 20, 2026 14:27
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plan Mode 三项改进:指示器内联、必定可退出、bash 门禁改按副作用判定

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定 - #31

Merged
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements
Aug 20, 2026
Merged

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定#31
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#28 ・设计依据见 #27

fix(plan-mode):plan mode 一定退得出去

原来裸 /plan 在 planning 态只 notify 一句「已激活」,ready 态的选择菜单也只有 continue / implement / fresh —— 没有任何「关闭」入口,不知道 /plan off 这个确切写法的人就出不去了。

  • PLAN_READY_ACTIONS 增加 off: "Turn plan mode off"
  • /plan(planning 态)改为弹菜单:Continue planning / Finalize now / Turn plan mode off;非 UI 会话保持原有提示
  • ready 态的 block 文案补上 /plan off 出口

feat(footer):单条 status 空间够就内联

  • 状态文案缩短:plan mode · read-onlyplan modeplan mode · readyplan ready
  • renderFooter()只有一条 status 且能塞进第一行剩余空隙时并入该行,否则维持独占行。多条 status(后台任务 + 子代理等)行为完全不变

feat(plan-mode):bash 门禁从「语法」改为「副作用」

原来靠语法黑名单一票否决:任何引号、|*$~ 都拒,程序只认 git/gh。结果 rg -l "pattern" --glob '*.ts' 这种纯只读命令跑不了,只读调研在没有 rg/fd 工具的宿主会话里直接无解。对照 Claude Code 与 Codex,两者都允许带引号参数,按命令效果分类。

  • 新增小型 tokenizer:引号内按字面量处理;$、反引号、\ 一律拒(无论是否在引号内);未加引号的元字符与 glob 仍拒;未配对引号拒;词首 ~ 拒但 HEAD~3 保留
  • 加引号的 glob 放行--glob '*.ts' 由程序自己解析,shell 不展开),未加引号仍拒并在报错里告诉怎么改
  • 程序白名单扩到 rg fd ls wc head tail,各自配 flag 允许表,沿用原有准入标准(只塑形输出,不能命名要执行的程序 / 要写的文件 / 不能永久阻塞):排除 rg --pre/--pre-glob/-zfd -x/-Xtail -f
  • git/gh 的子命令与 flag 表完全不变,包括「子命令必须紧跟程序名」;短 flag 聚合(ls -la)只对新增的只读程序开放
  • 全部拒绝文案改为可行动:说清拒绝了哪一部分 + 怎么写才能过

保留原有架构:fail-closed 允许列表、flag 级逃逸分析、子代理靠 harness 收窄工具。未做#28 里标为可选):管道与 &&/; 分段放行、tree-sitter 解析。

验证

  • bun run test:719 + 29 全绿(基线 713 + 29)
  • bun run check 退出 0(仅剩 file-search/src/binaries.ts 的既存 lint warning)
  • 额外用 26 条策略断言脚本交叉验证,确认 git checkout .git pushgit -Cgit log -sprg foo | headrg $(whoami) 等仍被拒

Allow quoted literal arguments and a narrow set of read-only search and inspection tools.\nKeep shell expansion, composition, unsafe flags, and unknown effects fail-closed so plan mode cannot mutate before approval.
The first pass added cluster handling twice: once inside scanArguments and
once in a separate scanShortFlagClusters pass. The scanArguments branch was
not gated by program, so it silently widened git and gh too. Collapse both
into one opt-in parameter that only the file-inspection programs pass.
The leaner default layout from #26 leaves room for a single status to inline
at width 80, so the old lines.length >= 2 assertion encoded placement rather
than the property it meant to protect: the status must stay visible.
@tt-a1i
tt-a1iforce-pushed the plan-mode-improvements branch from 2735b01 to 6f6e2b8CompareAugust 20, 2026 14:15
@tt-a1i
tt-a1i merged commit 1f49756 into mainAug 20, 2026
4 checks passed
@tt-a1i
tt-a1i deleted the plan-mode-improvements branch August 20, 2026 14:27
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plan Mode 三项改进:指示器内联、必定可退出、bash 门禁改按副作用判定

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定 - #31

Merged
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements
Aug 20, 2026
Merged

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定#31
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#28 ・设计依据见 #27

fix(plan-mode):plan mode 一定退得出去

原来裸 /plan 在 planning 态只 notify 一句「已激活」,ready 态的选择菜单也只有 continue / implement / fresh —— 没有任何「关闭」入口,不知道 /plan off 这个确切写法的人就出不去了。

  • PLAN_READY_ACTIONS 增加 off: "Turn plan mode off"
  • /plan(planning 态)改为弹菜单:Continue planning / Finalize now / Turn plan mode off;非 UI 会话保持原有提示
  • ready 态的 block 文案补上 /plan off 出口

feat(footer):单条 status 空间够就内联

  • 状态文案缩短:plan mode · read-onlyplan modeplan mode · readyplan ready
  • renderFooter()只有一条 status 且能塞进第一行剩余空隙时并入该行,否则维持独占行。多条 status(后台任务 + 子代理等)行为完全不变

feat(plan-mode):bash 门禁从「语法」改为「副作用」

原来靠语法黑名单一票否决:任何引号、|*$~ 都拒,程序只认 git/gh。结果 rg -l "pattern" --glob '*.ts' 这种纯只读命令跑不了,只读调研在没有 rg/fd 工具的宿主会话里直接无解。对照 Claude Code 与 Codex,两者都允许带引号参数,按命令效果分类。

  • 新增小型 tokenizer:引号内按字面量处理;$、反引号、\ 一律拒(无论是否在引号内);未加引号的元字符与 glob 仍拒;未配对引号拒;词首 ~ 拒但 HEAD~3 保留
  • 加引号的 glob 放行--glob '*.ts' 由程序自己解析,shell 不展开),未加引号仍拒并在报错里告诉怎么改
  • 程序白名单扩到 rg fd ls wc head tail,各自配 flag 允许表,沿用原有准入标准(只塑形输出,不能命名要执行的程序 / 要写的文件 / 不能永久阻塞):排除 rg --pre/--pre-glob/-zfd -x/-Xtail -f
  • git/gh 的子命令与 flag 表完全不变,包括「子命令必须紧跟程序名」;短 flag 聚合(ls -la)只对新增的只读程序开放
  • 全部拒绝文案改为可行动:说清拒绝了哪一部分 + 怎么写才能过

保留原有架构:fail-closed 允许列表、flag 级逃逸分析、子代理靠 harness 收窄工具。未做#28 里标为可选):管道与 &&/; 分段放行、tree-sitter 解析。

验证

  • bun run test:719 + 29 全绿(基线 713 + 29)
  • bun run check 退出 0(仅剩 file-search/src/binaries.ts 的既存 lint warning)
  • 额外用 26 条策略断言脚本交叉验证,确认 git checkout .git pushgit -Cgit log -sprg foo | headrg $(whoami) 等仍被拒

Allow quoted literal arguments and a narrow set of read-only search and inspection tools.\nKeep shell expansion, composition, unsafe flags, and unknown effects fail-closed so plan mode cannot mutate before approval.
The first pass added cluster handling twice: once inside scanArguments and
once in a separate scanShortFlagClusters pass. The scanArguments branch was
not gated by program, so it silently widened git and gh too. Collapse both
into one opt-in parameter that only the file-inspection programs pass.
The leaner default layout from #26 leaves room for a single status to inline
at width 80, so the old lines.length >= 2 assertion encoded placement rather
than the property it meant to protect: the status must stay visible.
@tt-a1i
tt-a1iforce-pushed the plan-mode-improvements branch from 2735b01 to 6f6e2b8CompareAugust 20, 2026 14:15
@tt-a1i
tt-a1i merged commit 1f49756 into mainAug 20, 2026
4 checks passed
@tt-a1i
tt-a1i deleted the plan-mode-improvements branch August 20, 2026 14:27
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plan Mode 三项改进:指示器内联、必定可退出、bash 门禁改按副作用判定

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定 - #31

Merged
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements
Aug 20, 2026
Merged

Plan Mode 三项改进:指示器内联、必定可退出、bash 按副作用判定#31
tt-a1i merged 5 commits into
mainfrom
plan-mode-improvements

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#28 ・设计依据见 #27

fix(plan-mode):plan mode 一定退得出去

原来裸 /plan 在 planning 态只 notify 一句「已激活」,ready 态的选择菜单也只有 continue / implement / fresh —— 没有任何「关闭」入口,不知道 /plan off 这个确切写法的人就出不去了。

  • PLAN_READY_ACTIONS 增加 off: "Turn plan mode off"
  • /plan(planning 态)改为弹菜单:Continue planning / Finalize now / Turn plan mode off;非 UI 会话保持原有提示
  • ready 态的 block 文案补上 /plan off 出口

feat(footer):单条 status 空间够就内联

  • 状态文案缩短:plan mode · read-onlyplan modeplan mode · readyplan ready
  • renderFooter()只有一条 status 且能塞进第一行剩余空隙时并入该行,否则维持独占行。多条 status(后台任务 + 子代理等)行为完全不变

feat(plan-mode):bash 门禁从「语法」改为「副作用」

原来靠语法黑名单一票否决:任何引号、|*$~ 都拒,程序只认 git/gh。结果 rg -l "pattern" --glob '*.ts' 这种纯只读命令跑不了,只读调研在没有 rg/fd 工具的宿主会话里直接无解。对照 Claude Code 与 Codex,两者都允许带引号参数,按命令效果分类。

  • 新增小型 tokenizer:引号内按字面量处理;$、反引号、\ 一律拒(无论是否在引号内);未加引号的元字符与 glob 仍拒;未配对引号拒;词首 ~ 拒但 HEAD~3 保留
  • 加引号的 glob 放行--glob '*.ts' 由程序自己解析,shell 不展开),未加引号仍拒并在报错里告诉怎么改
  • 程序白名单扩到 rg fd ls wc head tail,各自配 flag 允许表,沿用原有准入标准(只塑形输出,不能命名要执行的程序 / 要写的文件 / 不能永久阻塞):排除 rg --pre/--pre-glob/-zfd -x/-Xtail -f
  • git/gh 的子命令与 flag 表完全不变,包括「子命令必须紧跟程序名」;短 flag 聚合(ls -la)只对新增的只读程序开放
  • 全部拒绝文案改为可行动:说清拒绝了哪一部分 + 怎么写才能过

保留原有架构:fail-closed 允许列表、flag 级逃逸分析、子代理靠 harness 收窄工具。未做#28 里标为可选):管道与 &&/; 分段放行、tree-sitter 解析。

验证

  • bun run test:719 + 29 全绿(基线 713 + 29)
  • bun run check 退出 0(仅剩 file-search/src/binaries.ts 的既存 lint warning)
  • 额外用 26 条策略断言脚本交叉验证,确认 git checkout .git pushgit -Cgit log -sprg foo | headrg $(whoami) 等仍被拒

Allow quoted literal arguments and a narrow set of read-only search and inspection tools.\nKeep shell expansion, composition, unsafe flags, and unknown effects fail-closed so plan mode cannot mutate before approval.
The first pass added cluster handling twice: once inside scanArguments and
once in a separate scanShortFlagClusters pass. The scanArguments branch was
not gated by program, so it silently widened git and gh too. Collapse both
into one opt-in parameter that only the file-inspection programs pass.
The leaner default layout from #26 leaves room for a single status to inline
at width 80, so the old lines.length >= 2 assertion encoded placement rather
than the property it meant to protect: the status must stay visible.
@tt-a1i
tt-a1iforce-pushed the plan-mode-improvements branch from 2735b01 to 6f6e2b8CompareAugust 20, 2026 14:15
@tt-a1i
tt-a1i merged commit 1f49756 into mainAug 20, 2026
4 checks passed
@tt-a1i
tt-a1i deleted the plan-mode-improvements branch August 20, 2026 14:27
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plan Mode 三项改进:指示器内联、必定可退出、bash 门禁改按副作用判定

1 participant

@tt-a1i