oh-my-codex 0.18.16 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/crates/omx-sparkshell/tests/execution.rs +8 -1
- package/dist/agents/__tests__/definitions.test.js +5 -5
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +18 -14
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/definitions.d.ts +2 -2
- package/dist/agents/definitions.d.ts.map +1 -1
- package/dist/agents/definitions.js +4 -4
- package/dist/agents/definitions.js.map +1 -1
- package/dist/agents/native-config.d.ts +1 -0
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +18 -16
- package/dist/agents/native-config.js.map +1 -1
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +17 -4
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/autopilot/__tests__/planner-routing.test.js +2 -2
- package/dist/autopilot/__tests__/planner-routing.test.js.map +1 -1
- package/dist/autopilot/fsm.d.ts +1 -1
- package/dist/autopilot/fsm.d.ts.map +1 -1
- package/dist/autopilot/fsm.js +1 -1
- package/dist/autopilot/fsm.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js +78 -3
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +30 -5
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +2 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +96 -8
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +135 -1
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +2 -4
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js +14 -0
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +8 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/resume.test.js +229 -1
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +46 -0
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +37 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +21 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/version.test.js +13 -1
- package/dist/cli/__tests__/version.test.js.map +1 -1
- package/dist/cli/auth.d.ts +1 -1
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +49 -9
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/index.d.ts +25 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +233 -32
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +22 -1
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +4 -0
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +3 -1
- package/dist/cli/setup.js.map +1 -1
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +7 -0
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +12 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +267 -7
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +143 -30
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +121 -0
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +110 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +1 -1
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/reconcile.d.ts +3 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +281 -151
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +4 -2
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +44 -12
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +1 -4
- package/dist/hud/tmux.js.map +1 -1
- package/dist/hud/types.d.ts +5 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js.map +1 -1
- package/dist/leader/__tests__/contract.test.d.ts +2 -0
- package/dist/leader/__tests__/contract.test.d.ts.map +1 -0
- package/dist/leader/__tests__/contract.test.js +75 -0
- package/dist/leader/__tests__/contract.test.js.map +1 -0
- package/dist/leader/contract.d.ts +26 -0
- package/dist/leader/contract.d.ts.map +1 -0
- package/dist/leader/contract.js +97 -0
- package/dist/leader/contract.js.map +1 -0
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +22 -7
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/dispatcher.test.js +16 -0
- package/dist/notifications/__tests__/dispatcher.test.js.map +1 -1
- package/dist/notifications/__tests__/profiles.test.js +87 -0
- package/dist/notifications/__tests__/profiles.test.js.map +1 -1
- package/dist/notifications/config.d.ts +1 -0
- package/dist/notifications/config.d.ts.map +1 -1
- package/dist/notifications/config.js +60 -22
- package/dist/notifications/config.js.map +1 -1
- package/dist/notifications/dispatcher.d.ts.map +1 -1
- package/dist/notifications/dispatcher.js +6 -16
- package/dist/notifications/dispatcher.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +2 -0
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/stages/ultragoal.d.ts.map +1 -1
- package/dist/pipeline/stages/ultragoal.js +6 -1
- package/dist/pipeline/stages/ultragoal.js.map +1 -1
- package/dist/question/__tests__/renderer.test.js +58 -4
- package/dist/question/__tests__/renderer.test.js.map +1 -1
- package/dist/question/renderer.d.ts +1 -1
- package/dist/question/renderer.d.ts.map +1 -1
- package/dist/question/renderer.js +73 -5
- package/dist/question/renderer.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +202 -0
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/runtime.d.ts +7 -0
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +63 -4
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +8484 -4560
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +4387 -190
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +1137 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/planning-gate.test.js +410 -0
- package/dist/state/__tests__/planning-gate.test.js.map +1 -1
- package/dist/state/operations.d.ts +10 -0
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +242 -8
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +4 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +5 -3
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +642 -1
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/__tests__/tracker.test.js +248 -1
- package/dist/subagents/__tests__/tracker.test.js.map +1 -1
- package/dist/subagents/tracker.d.ts +60 -0
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +225 -1
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +72 -4
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +44 -2
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +127 -8
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +89 -0
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/model-contract.d.ts +3 -0
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +42 -5
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/runtime.d.ts +2 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +21 -11
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +13 -11
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/tmux-session.d.ts +1 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +63 -13
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +7 -0
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +5 -0
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/utils/__tests__/agents-model-table.test.js +2 -2
- package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +19 -7
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +16 -0
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +23 -0
- package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +3 -2
- package/skills/code-review/SKILL.md +16 -0
- package/skills/ecomode/references/agent-tiers.md +1 -1
- package/skills/ultragoal/SKILL.md +23 -0
- package/skills/ultrawork/references/agent-tiers.md +3 -2
- package/src/scripts/__tests__/codex-native-hook.test.ts +14014 -9097
- package/src/scripts/codex-native-hook.ts +4459 -199
|
@@ -7,13 +7,654 @@ const DENIED_BASH_PATTERNS = [
|
|
|
7
7
|
/\bgh\s+pr\s+create\b/,
|
|
8
8
|
/\bgh\s+pr\s+merge\b/,
|
|
9
9
|
];
|
|
10
|
+
function escapeRegExp(value) {
|
|
11
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
12
|
+
}
|
|
13
|
+
function normalizeProtectedArtifactPath(path) {
|
|
14
|
+
return path.replace(/^\.\//, '');
|
|
15
|
+
}
|
|
16
|
+
function normalizeShellPath(path) {
|
|
17
|
+
return path
|
|
18
|
+
.replace(/\\/g, '/')
|
|
19
|
+
.replace(/^\.\//, '')
|
|
20
|
+
.replace(/\/\.\//g, '/')
|
|
21
|
+
.replace(/\/+/g, '/');
|
|
22
|
+
}
|
|
23
|
+
function joinShellPath(cwd, path) {
|
|
24
|
+
if (!cwd || cwd === '.')
|
|
25
|
+
return normalizeShellPath(path);
|
|
26
|
+
if (path.startsWith('/'))
|
|
27
|
+
return normalizeShellPath(path);
|
|
28
|
+
return normalizeShellPath(`${cwd}/${path}`);
|
|
29
|
+
}
|
|
30
|
+
function sameShellPath(candidate, target) {
|
|
31
|
+
return normalizeShellPath(candidate) === normalizeShellPath(target);
|
|
32
|
+
}
|
|
33
|
+
function shellCommandBasename(commandName) {
|
|
34
|
+
const normalized = normalizeShellPath(commandName);
|
|
35
|
+
return normalized.slice(normalized.lastIndexOf('/') + 1);
|
|
36
|
+
}
|
|
37
|
+
function shellWords(statement) {
|
|
38
|
+
const words = [];
|
|
39
|
+
let current = '';
|
|
40
|
+
let quote = null;
|
|
41
|
+
let escaped = false;
|
|
42
|
+
for (const char of statement) {
|
|
43
|
+
if (escaped) {
|
|
44
|
+
current += char;
|
|
45
|
+
escaped = false;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (char === '\\' && quote !== 'single') {
|
|
49
|
+
escaped = true;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (char === "'" && quote !== 'double') {
|
|
53
|
+
quote = quote === 'single' ? null : 'single';
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (char === '"' && quote !== 'single') {
|
|
57
|
+
quote = quote === 'double' ? null : 'double';
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (/\s/.test(char) && !quote) {
|
|
61
|
+
if (current) {
|
|
62
|
+
words.push(current);
|
|
63
|
+
current = '';
|
|
64
|
+
}
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
current += char;
|
|
68
|
+
}
|
|
69
|
+
if (current)
|
|
70
|
+
words.push(current);
|
|
71
|
+
return words;
|
|
72
|
+
}
|
|
73
|
+
function shellStatementRecords(command) {
|
|
74
|
+
const statements = [];
|
|
75
|
+
let current = '';
|
|
76
|
+
let quote = null;
|
|
77
|
+
let escaped = false;
|
|
78
|
+
let subshellDepth = 0;
|
|
79
|
+
let statementSubshellDepth = 0;
|
|
80
|
+
let closesSubshells = 0;
|
|
81
|
+
const pushStatement = () => {
|
|
82
|
+
const statement = current.trim();
|
|
83
|
+
if (statement) {
|
|
84
|
+
statements.push({
|
|
85
|
+
text: statement,
|
|
86
|
+
subshellDepth: statementSubshellDepth,
|
|
87
|
+
closesSubshells,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
current = '';
|
|
91
|
+
statementSubshellDepth = subshellDepth;
|
|
92
|
+
closesSubshells = 0;
|
|
93
|
+
};
|
|
94
|
+
for (let index = 0; index < command.length; index += 1) {
|
|
95
|
+
const char = command[index];
|
|
96
|
+
const next = command[index + 1];
|
|
97
|
+
if (escaped) {
|
|
98
|
+
current += char;
|
|
99
|
+
escaped = false;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (char === '\\' && quote !== 'single') {
|
|
103
|
+
current += char;
|
|
104
|
+
escaped = true;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (char === "'" && quote !== 'double') {
|
|
108
|
+
current += char;
|
|
109
|
+
quote = quote === 'single' ? null : 'single';
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (char === '"' && quote !== 'single') {
|
|
113
|
+
current += char;
|
|
114
|
+
quote = quote === 'double' ? null : 'double';
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (!quote && char === '(' && !current.trim()) {
|
|
118
|
+
subshellDepth += 1;
|
|
119
|
+
statementSubshellDepth = subshellDepth;
|
|
120
|
+
current += char;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
current += char;
|
|
124
|
+
if (!quote && char === ')' && subshellDepth > 0) {
|
|
125
|
+
subshellDepth -= 1;
|
|
126
|
+
closesSubshells += 1;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (!quote && (char === '\n' || char === ';' || (char === '&' && next === '&') || (char === '|' && next === '|'))) {
|
|
130
|
+
current = current.slice(0, -1);
|
|
131
|
+
pushStatement();
|
|
132
|
+
if ((char === '&' && next === '&') || (char === '|' && next === '|'))
|
|
133
|
+
index += 1;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
pushStatement();
|
|
138
|
+
return statements;
|
|
139
|
+
}
|
|
140
|
+
function shellStatements(command) {
|
|
141
|
+
return shellStatementRecords(command).map((statement) => statement.text);
|
|
142
|
+
}
|
|
143
|
+
function isShellName(name) {
|
|
144
|
+
return /^(?:sh|bash|dash|zsh|ksh|fish)$/.test(name);
|
|
145
|
+
}
|
|
146
|
+
function isScriptInterpreterName(name) {
|
|
147
|
+
return /^(?:python[0-9.]?|python3(?:\.[0-9]+)?|node|nodejs|ruby|perl|php|lua|deno|bun|tsx|go|npx|npm|pnpm|yarn)$/.test(name);
|
|
148
|
+
}
|
|
149
|
+
function isProtectedArtifactPath(path) {
|
|
150
|
+
return /^(?:\.\/)?\.omx\/(?:context|specs|tmp)\/[^"'\s;|&<>]+$/.test(path);
|
|
151
|
+
}
|
|
152
|
+
function resolveCommandOperand(cwd, operand) {
|
|
153
|
+
return joinShellPath(cwd, operand.replace(/^\.\//, ''));
|
|
154
|
+
}
|
|
155
|
+
function isPythonRuntimeOptionWithSeparateValue(word) {
|
|
156
|
+
return word === '-W' || word === '-X' || word === '--check-hash-based-pycs';
|
|
157
|
+
}
|
|
158
|
+
function runtimeLoadOptionOperandMatches(word, args, index, cwd, targetPath) {
|
|
159
|
+
if (word === '-r' || word === '--require' || word === '--import' || word === '--loader' || word === '--experimental-loader') {
|
|
160
|
+
const operand = args[index + 1];
|
|
161
|
+
return Boolean(operand && sameShellPath(resolveCommandOperand(cwd, operand), targetPath));
|
|
162
|
+
}
|
|
163
|
+
for (const prefix of ['--require=', '--import=', '--loader=', '--experimental-loader=']) {
|
|
164
|
+
if (word.startsWith(prefix))
|
|
165
|
+
return sameShellPath(resolveCommandOperand(cwd, word.slice(prefix.length)), targetPath);
|
|
166
|
+
}
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
function stdinRedirectOperandMatches(args, cwd, targetPath) {
|
|
170
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
171
|
+
const word = args[index];
|
|
172
|
+
if (word === '<') {
|
|
173
|
+
const operand = args[index + 1];
|
|
174
|
+
if (operand && sameShellPath(resolveCommandOperand(cwd, operand), targetPath))
|
|
175
|
+
return true;
|
|
176
|
+
index += 1;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (/^\d*<[^<&].+/.test(word)) {
|
|
180
|
+
const operand = word.replace(/^\d*</, '');
|
|
181
|
+
if (sameShellPath(resolveCommandOperand(cwd, operand), targetPath))
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
function shellScriptOperand(args, cwd, targetPath) {
|
|
188
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
189
|
+
const word = args[index];
|
|
190
|
+
if (word === '--') {
|
|
191
|
+
const operand = args[index + 1];
|
|
192
|
+
return Boolean(operand && sameShellPath(resolveCommandOperand(cwd, operand), targetPath));
|
|
193
|
+
}
|
|
194
|
+
if (word === '-c' || word === '--command') {
|
|
195
|
+
const inlineCommand = args[index + 1];
|
|
196
|
+
return Boolean(inlineCommand && hasTokenizedExecutionOfPath(inlineCommand, targetPath, cwd));
|
|
197
|
+
}
|
|
198
|
+
if (/^-[A-Za-z]*c[A-Za-z]*$/.test(word)) {
|
|
199
|
+
const inlineCommand = args[index + 1];
|
|
200
|
+
return Boolean(inlineCommand && hasTokenizedExecutionOfPath(inlineCommand, targetPath, cwd));
|
|
201
|
+
}
|
|
202
|
+
if (word === '--init-file' || word === '--rcfile') {
|
|
203
|
+
const operand = args[index + 1];
|
|
204
|
+
if (operand && sameShellPath(resolveCommandOperand(cwd, operand), targetPath))
|
|
205
|
+
return true;
|
|
206
|
+
index += 1;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (word.startsWith('--init-file=') || word.startsWith('--rcfile=')) {
|
|
210
|
+
if (sameShellPath(resolveCommandOperand(cwd, word.slice(word.indexOf('=') + 1)), targetPath))
|
|
211
|
+
return true;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (word === '-o' || word === '+o' || word === '-O' || word === '+O') {
|
|
215
|
+
index += 1;
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (word.startsWith('-') || word.startsWith('+'))
|
|
219
|
+
continue;
|
|
220
|
+
return sameShellPath(resolveCommandOperand(cwd, word), targetPath);
|
|
221
|
+
}
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
function scriptInterpreterOperand(args, cwd, targetPath, commandName) {
|
|
225
|
+
let sawGoRun = false;
|
|
226
|
+
let sawPackageRunner = commandName === 'npx';
|
|
227
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
228
|
+
const word = args[index];
|
|
229
|
+
if (!word || word === '--')
|
|
230
|
+
continue;
|
|
231
|
+
if (/^python/.test(commandName)) {
|
|
232
|
+
if (word === '-c' || word === '-m')
|
|
233
|
+
return false;
|
|
234
|
+
if (isPythonRuntimeOptionWithSeparateValue(word)) {
|
|
235
|
+
index += 1;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if (word.startsWith('-W') || word.startsWith('-X'))
|
|
239
|
+
continue;
|
|
240
|
+
if (word.startsWith('-'))
|
|
241
|
+
continue;
|
|
242
|
+
return sameShellPath(resolveCommandOperand(cwd, word), targetPath);
|
|
243
|
+
}
|
|
244
|
+
if (commandName === 'node' || commandName === 'nodejs' || commandName === 'bun' || commandName === 'tsx') {
|
|
245
|
+
if (word === '-e' || word === '--eval' || word === '-p' || word === '--print')
|
|
246
|
+
return false;
|
|
247
|
+
if (runtimeLoadOptionOperandMatches(word, args, index, cwd, targetPath))
|
|
248
|
+
return true;
|
|
249
|
+
if (word === '-r' || word === '--require' || word === '--import' || word === '--loader' || word === '--experimental-loader' || word === '--tsconfig' || word === '-C') {
|
|
250
|
+
index += 1;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (word.startsWith('--require=') || word.startsWith('--import=') || word.startsWith('--loader=') || word.startsWith('--experimental-loader='))
|
|
254
|
+
continue;
|
|
255
|
+
if (word.startsWith('--eval=') || word.startsWith('--print='))
|
|
256
|
+
return false;
|
|
257
|
+
if (commandName === 'tsx' && word === 'watch')
|
|
258
|
+
continue;
|
|
259
|
+
if (word.startsWith('-'))
|
|
260
|
+
continue;
|
|
261
|
+
return sameShellPath(resolveCommandOperand(cwd, word), targetPath);
|
|
262
|
+
}
|
|
263
|
+
if (commandName === 'deno') {
|
|
264
|
+
if (word === 'eval' || word === 'repl')
|
|
265
|
+
return false;
|
|
266
|
+
if (word === 'run')
|
|
267
|
+
continue;
|
|
268
|
+
if (word.startsWith('-'))
|
|
269
|
+
continue;
|
|
270
|
+
return sameShellPath(resolveCommandOperand(cwd, word), targetPath);
|
|
271
|
+
}
|
|
272
|
+
if (commandName === 'go') {
|
|
273
|
+
if (!sawGoRun) {
|
|
274
|
+
if (word === 'run') {
|
|
275
|
+
sawGoRun = true;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
if (word.startsWith('-'))
|
|
281
|
+
continue;
|
|
282
|
+
return sameShellPath(resolveCommandOperand(cwd, word), targetPath);
|
|
283
|
+
}
|
|
284
|
+
if (commandName === 'npm' || commandName === 'pnpm' || commandName === 'yarn' || commandName === 'npx') {
|
|
285
|
+
if (!sawPackageRunner) {
|
|
286
|
+
if (word === 'exec' || word === 'x' || word === 'dlx') {
|
|
287
|
+
sawPackageRunner = true;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
if (word.startsWith('-'))
|
|
293
|
+
continue;
|
|
294
|
+
if (word === 'tsx' || word === 'node' || word === 'bun' || word === 'deno')
|
|
295
|
+
continue;
|
|
296
|
+
return sameShellPath(resolveCommandOperand(cwd, word), targetPath);
|
|
297
|
+
}
|
|
298
|
+
if (word === '-e' || word.startsWith('-e'))
|
|
299
|
+
return false;
|
|
300
|
+
if (word.startsWith('-'))
|
|
301
|
+
continue;
|
|
302
|
+
return sameShellPath(resolveCommandOperand(cwd, word), targetPath);
|
|
303
|
+
}
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
function shellExecutionMatches(words, cwd, targetPath) {
|
|
307
|
+
if (words.length === 0)
|
|
308
|
+
return false;
|
|
309
|
+
const rawCommandName = words[0];
|
|
310
|
+
const commandName = shellCommandBasename(rawCommandName);
|
|
311
|
+
if (commandName === 'source' || commandName === '.') {
|
|
312
|
+
const operand = words[1];
|
|
313
|
+
return Boolean(operand && sameShellPath(resolveCommandOperand(cwd, operand), targetPath));
|
|
314
|
+
}
|
|
315
|
+
if (isShellName(commandName)) {
|
|
316
|
+
return stdinRedirectOperandMatches(words.slice(1), cwd, targetPath)
|
|
317
|
+
|| shellScriptOperand(words.slice(1), cwd, targetPath);
|
|
318
|
+
}
|
|
319
|
+
if (isScriptInterpreterName(commandName)) {
|
|
320
|
+
return stdinRedirectOperandMatches(words.slice(1), cwd, targetPath)
|
|
321
|
+
|| scriptInterpreterOperand(words.slice(1), cwd, targetPath, commandName);
|
|
322
|
+
}
|
|
323
|
+
if (rawCommandName.startsWith('./') || rawCommandName.includes('/')) {
|
|
324
|
+
return sameShellPath(resolveCommandOperand(cwd, rawCommandName), targetPath);
|
|
325
|
+
}
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
function findDirectWrapperOperandIndex(words, startIndex) {
|
|
329
|
+
for (let index = startIndex; index < words.length; index += 1) {
|
|
330
|
+
const word = words[index];
|
|
331
|
+
if (!word || word === '--' || /^[A-Za-z_][A-Za-z0-9_]*=.*/.test(word))
|
|
332
|
+
continue;
|
|
333
|
+
if (word.startsWith('-'))
|
|
334
|
+
continue;
|
|
335
|
+
return index;
|
|
336
|
+
}
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
function findTimeWrapperOperandIndex(words, startIndex) {
|
|
340
|
+
for (let index = startIndex; index < words.length; index += 1) {
|
|
341
|
+
const word = words[index];
|
|
342
|
+
if (!word || word === '--' || /^[A-Za-z_][A-Za-z0-9_]*=.*/.test(word))
|
|
343
|
+
continue;
|
|
344
|
+
if (word === '-f' || word === '--format' || word === '-o' || word === '--output') {
|
|
345
|
+
index += 1;
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (word.startsWith('--format=') || word.startsWith('--output='))
|
|
349
|
+
continue;
|
|
350
|
+
if (word.startsWith('-'))
|
|
351
|
+
continue;
|
|
352
|
+
return index;
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
function findTimeoutWrapperOperandIndex(words, startIndex) {
|
|
357
|
+
let sawDuration = false;
|
|
358
|
+
for (let index = startIndex; index < words.length; index += 1) {
|
|
359
|
+
const word = words[index];
|
|
360
|
+
if (!word || word === '--' || /^[A-Za-z_][A-Za-z0-9_]*=.*/.test(word))
|
|
361
|
+
continue;
|
|
362
|
+
if (word === '-k' || word === '--kill-after' || word === '-s' || word === '--signal') {
|
|
363
|
+
index += 1;
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
if (word.startsWith('--kill-after=') || word.startsWith('--signal='))
|
|
367
|
+
continue;
|
|
368
|
+
if (word.startsWith('-'))
|
|
369
|
+
continue;
|
|
370
|
+
if (!sawDuration) {
|
|
371
|
+
sawDuration = true;
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
return index;
|
|
375
|
+
}
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
function unwrapExecutionCommand(words, cwd) {
|
|
379
|
+
let currentWords = words;
|
|
380
|
+
let currentCwd = cwd;
|
|
381
|
+
for (let unwrapCount = 0; unwrapCount < 8; unwrapCount += 1) {
|
|
382
|
+
const commandName = shellCommandBasename(currentWords[0] ?? '');
|
|
383
|
+
if (commandName === 'env') {
|
|
384
|
+
const unwrapped = unwrapEnvCommand(currentWords, currentCwd);
|
|
385
|
+
if (unwrapped.words === currentWords)
|
|
386
|
+
return unwrapped;
|
|
387
|
+
currentWords = unwrapped.words;
|
|
388
|
+
currentCwd = unwrapped.cwd;
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
const operandIndex = commandName === 'command' || commandName === 'nohup' || commandName === 'setsid'
|
|
392
|
+
? findDirectWrapperOperandIndex(currentWords, 1)
|
|
393
|
+
: commandName === 'time'
|
|
394
|
+
? findTimeWrapperOperandIndex(currentWords, 1)
|
|
395
|
+
: commandName === 'timeout' || commandName === 'gtimeout'
|
|
396
|
+
? findTimeoutWrapperOperandIndex(currentWords, 1)
|
|
397
|
+
: null;
|
|
398
|
+
if (operandIndex === null)
|
|
399
|
+
return { words: currentWords, cwd: currentCwd };
|
|
400
|
+
currentWords = currentWords.slice(operandIndex);
|
|
401
|
+
}
|
|
402
|
+
return { words: currentWords, cwd: currentCwd };
|
|
403
|
+
}
|
|
404
|
+
function unwrapCdCommandWords(words) {
|
|
405
|
+
let currentWords = words;
|
|
406
|
+
for (let unwrapCount = 0; unwrapCount < 4; unwrapCount += 1) {
|
|
407
|
+
const commandName = shellCommandBasename(currentWords[0] ?? '');
|
|
408
|
+
if (commandName === 'command') {
|
|
409
|
+
const operandIndex = findDirectWrapperOperandIndex(currentWords, 1);
|
|
410
|
+
if (operandIndex === null)
|
|
411
|
+
return currentWords;
|
|
412
|
+
currentWords = currentWords.slice(operandIndex);
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
if (commandName === 'builtin') {
|
|
416
|
+
currentWords = currentWords.slice(1);
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
return currentWords;
|
|
420
|
+
}
|
|
421
|
+
return currentWords;
|
|
422
|
+
}
|
|
423
|
+
function cdOperand(words) {
|
|
424
|
+
if (words[0] !== 'cd')
|
|
425
|
+
return null;
|
|
426
|
+
for (let index = 1; index < words.length; index += 1) {
|
|
427
|
+
const word = words[index];
|
|
428
|
+
if (word === '--')
|
|
429
|
+
continue;
|
|
430
|
+
if (/^-[LP]+$/.test(word))
|
|
431
|
+
continue;
|
|
432
|
+
return word;
|
|
433
|
+
}
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
function cdTransitionTarget(words, cwd) {
|
|
437
|
+
const operand = cdOperand(unwrapCdCommandWords(words));
|
|
438
|
+
return operand ? resolveCommandOperand(cwd, operand) : null;
|
|
439
|
+
}
|
|
440
|
+
function unwrapEnvCommand(words, cwd) {
|
|
441
|
+
if (shellCommandBasename(words[0] ?? '') !== 'env')
|
|
442
|
+
return { words, cwd };
|
|
443
|
+
let index = 1;
|
|
444
|
+
let envCwd = cwd;
|
|
445
|
+
while (index < words.length) {
|
|
446
|
+
const word = words[index];
|
|
447
|
+
if (word === '--') {
|
|
448
|
+
index += 1;
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
if (word === '-C' || word === '--chdir') {
|
|
452
|
+
const next = words[index + 1];
|
|
453
|
+
if (!next)
|
|
454
|
+
return { words: [], cwd: envCwd };
|
|
455
|
+
envCwd = resolveCommandOperand(envCwd, next);
|
|
456
|
+
index += 2;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if (word.startsWith('-C') && word.length > 2) {
|
|
460
|
+
envCwd = resolveCommandOperand(envCwd, word.slice(2));
|
|
461
|
+
index += 1;
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
if (word.startsWith('--chdir=')) {
|
|
465
|
+
envCwd = resolveCommandOperand(envCwd, word.slice('--chdir='.length));
|
|
466
|
+
index += 1;
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
if (word.startsWith('-')) {
|
|
470
|
+
index += 1;
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*=.*/.test(word)) {
|
|
474
|
+
index += 1;
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
return { words: words.slice(index), cwd: envCwd };
|
|
480
|
+
}
|
|
481
|
+
function groupedShellWords(statement) {
|
|
482
|
+
const words = shellWords(statement);
|
|
483
|
+
while (words.length > 0) {
|
|
484
|
+
const first = words[0];
|
|
485
|
+
if (first === '{') {
|
|
486
|
+
words.shift();
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
const stripped = first.replace(/^\(+/, '');
|
|
490
|
+
if (stripped !== first) {
|
|
491
|
+
if (stripped)
|
|
492
|
+
words[0] = stripped;
|
|
493
|
+
else
|
|
494
|
+
words.shift();
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
while (words.length > 0) {
|
|
500
|
+
const lastIndex = words.length - 1;
|
|
501
|
+
const last = words[lastIndex];
|
|
502
|
+
if (last === '}') {
|
|
503
|
+
words.pop();
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
const stripped = last.replace(/[)}]+$/, '');
|
|
507
|
+
if (stripped !== last) {
|
|
508
|
+
if (stripped)
|
|
509
|
+
words[lastIndex] = stripped;
|
|
510
|
+
else
|
|
511
|
+
words.pop();
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
return words;
|
|
517
|
+
}
|
|
518
|
+
function scopedCwd(cwds, depth, initialCwd) {
|
|
519
|
+
if (cwds.has(depth))
|
|
520
|
+
return cwds.get(depth);
|
|
521
|
+
if (depth <= 0)
|
|
522
|
+
return initialCwd;
|
|
523
|
+
return scopedCwd(cwds, depth - 1, initialCwd);
|
|
524
|
+
}
|
|
525
|
+
function hasTokenizedExecutionOfPath(command, path, initialCwd = '') {
|
|
526
|
+
const targetPath = normalizeShellPath(path);
|
|
527
|
+
const cwds = new Map([[0, initialCwd]]);
|
|
528
|
+
for (const statement of shellStatementRecords(command)) {
|
|
529
|
+
const cwd = scopedCwd(cwds, statement.subshellDepth, initialCwd);
|
|
530
|
+
const words = groupedShellWords(statement.text);
|
|
531
|
+
if (words.length > 0) {
|
|
532
|
+
const cdTarget = cdTransitionTarget(words, cwd);
|
|
533
|
+
if (cdTarget) {
|
|
534
|
+
cwds.set(statement.subshellDepth, cdTarget);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
const unwrapped = unwrapExecutionCommand(words, cwd);
|
|
538
|
+
if (shellExecutionMatches(unwrapped.words, unwrapped.cwd, targetPath))
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (statement.closesSubshells > 0) {
|
|
543
|
+
for (let depth = statement.subshellDepth; depth > statement.subshellDepth - statement.closesSubshells; depth -= 1) {
|
|
544
|
+
cwds.delete(depth);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
function isPlanningTmpShellPath(path) {
|
|
551
|
+
const normalized = normalizeShellPath(path);
|
|
552
|
+
return normalized === '.omx/tmp' || normalized.startsWith('.omx/tmp/');
|
|
553
|
+
}
|
|
554
|
+
function stdinRedirectsPlanningTmp(args, cwd) {
|
|
555
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
556
|
+
const word = args[index];
|
|
557
|
+
if (word === '<') {
|
|
558
|
+
const operand = args[index + 1];
|
|
559
|
+
if (operand && isPlanningTmpShellPath(resolveCommandOperand(cwd, operand)))
|
|
560
|
+
return true;
|
|
561
|
+
index += 1;
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
if (/^\d*<[^<&].+/.test(word)) {
|
|
565
|
+
const operand = word.replace(/^\d*</, '');
|
|
566
|
+
if (isPlanningTmpShellPath(resolveCommandOperand(cwd, operand)))
|
|
567
|
+
return true;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
function commandStdinRedirectsPlanningTmpIntoInterpreter(command, initialCwd = '') {
|
|
573
|
+
const cwds = new Map([[0, initialCwd]]);
|
|
574
|
+
for (const statement of shellStatementRecords(command)) {
|
|
575
|
+
const cwd = scopedCwd(cwds, statement.subshellDepth, initialCwd);
|
|
576
|
+
const words = groupedShellWords(statement.text);
|
|
577
|
+
if (words.length > 0) {
|
|
578
|
+
const cdTarget = cdTransitionTarget(words, cwd);
|
|
579
|
+
if (cdTarget) {
|
|
580
|
+
cwds.set(statement.subshellDepth, cdTarget);
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
const unwrapped = unwrapExecutionCommand(words, cwd);
|
|
584
|
+
const commandName = shellCommandBasename(unwrapped.words[0] ?? '');
|
|
585
|
+
if ((isShellName(commandName) || isScriptInterpreterName(commandName))
|
|
586
|
+
&& stdinRedirectsPlanningTmp(unwrapped.words.slice(1), unwrapped.cwd))
|
|
587
|
+
return true;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
if (statement.closesSubshells > 0) {
|
|
591
|
+
for (let depth = statement.subshellDepth; depth > statement.subshellDepth - statement.closesSubshells; depth -= 1) {
|
|
592
|
+
cwds.delete(depth);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
function collectProtectedArtifactWritePaths(command) {
|
|
599
|
+
const paths = new Set();
|
|
600
|
+
const protectedPath = String.raw `(["']?)((?:\.\/)?\.omx\/(?:context|specs|plans|tmp)\/[^"'\s;|&<>]+)\1`;
|
|
601
|
+
const redirectPattern = new RegExp(String.raw `(?:^|[^<])>>?\s*${protectedPath}`, 'g');
|
|
602
|
+
for (const match of command.matchAll(redirectPattern)) {
|
|
603
|
+
const path = match[2]?.trim();
|
|
604
|
+
if (path)
|
|
605
|
+
paths.add(normalizeProtectedArtifactPath(path));
|
|
606
|
+
}
|
|
607
|
+
const pythonPathWritePattern = /\bpython3?\b[\s\S]{0,520}\bPath\s*\(\s*(["'])((?:\.\/)?\.omx\/(?:context|specs|plans|tmp)\/[^"']+)\1\s*\)\s*\.\s*(?:write_text|write_bytes)\s*\(/g;
|
|
608
|
+
for (const match of command.matchAll(pythonPathWritePattern)) {
|
|
609
|
+
const path = match[2]?.trim();
|
|
610
|
+
if (path)
|
|
611
|
+
paths.add(normalizeProtectedArtifactPath(path));
|
|
612
|
+
}
|
|
613
|
+
for (const statement of shellStatements(command)) {
|
|
614
|
+
const words = shellWords(statement);
|
|
615
|
+
const teeIndex = words.findIndex((word) => word === 'tee');
|
|
616
|
+
if (teeIndex === -1)
|
|
617
|
+
continue;
|
|
618
|
+
for (let index = teeIndex + 1; index < words.length; index += 1) {
|
|
619
|
+
const word = words[index];
|
|
620
|
+
if (word === '--')
|
|
621
|
+
continue;
|
|
622
|
+
if (word.startsWith('-'))
|
|
623
|
+
continue;
|
|
624
|
+
if (isProtectedArtifactPath(word))
|
|
625
|
+
paths.add(normalizeProtectedArtifactPath(word));
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return paths;
|
|
629
|
+
}
|
|
630
|
+
function executesOrSourcesPath(command, path) {
|
|
631
|
+
const escapedPath = escapeRegExp(path);
|
|
632
|
+
const optionalDotSlashPath = String.raw `(?:\.\/)?${escapedPath}`;
|
|
633
|
+
const quotedPath = String.raw `["']${optionalDotSlashPath}["']|${optionalDotSlashPath}`;
|
|
634
|
+
const shellExecPattern = new RegExp(String.raw `(?:^|[\s;&|()])(?:sh|bash|dash|zsh|ksh|fish)\s+(?:-[^\s]+\s+)*(${quotedPath})(?:$|[\s;&|)])`);
|
|
635
|
+
const sourcePattern = new RegExp(String.raw `(?:^|[\s;&|()])(?:source|\.)\s+(${quotedPath})(?:$|[\s;&|)])`);
|
|
636
|
+
const directExecPattern = new RegExp(String.raw `(?:^|[;&|()\n])\s*(?:\.\/)?${escapedPath}(?:$|[\s;&|)])`);
|
|
637
|
+
return shellExecPattern.test(command)
|
|
638
|
+
|| sourcePattern.test(command)
|
|
639
|
+
|| directExecPattern.test(command)
|
|
640
|
+
|| hasTokenizedExecutionOfPath(command, path);
|
|
641
|
+
}
|
|
642
|
+
function hasSameCommandProtectedArtifactExecution(command) {
|
|
643
|
+
for (const path of collectProtectedArtifactWritePaths(command)) {
|
|
644
|
+
if (executesOrSourcesPath(command, path))
|
|
645
|
+
return true;
|
|
646
|
+
}
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
10
649
|
export const PLANNING_GATE_BYPASS_TTL_MS = 10 * 60 * 1000;
|
|
11
650
|
export const BYPASS_PLANNING_GATE_PHRASE = 'bypass planning gate';
|
|
12
651
|
export function isImplementationToolCall(input) {
|
|
13
652
|
if (IMPLEMENTATION_TOOLS.has(input.tool_name))
|
|
14
653
|
return true;
|
|
15
654
|
if (input.tool_name === 'Bash' && typeof input.tool_input === 'string') {
|
|
16
|
-
return DENIED_BASH_PATTERNS.some((pattern) => pattern.test(input.tool_input))
|
|
655
|
+
return DENIED_BASH_PATTERNS.some((pattern) => pattern.test(input.tool_input))
|
|
656
|
+
|| commandStdinRedirectsPlanningTmpIntoInterpreter(input.tool_input)
|
|
657
|
+
|| hasSameCommandProtectedArtifactExecution(input.tool_input);
|
|
17
658
|
}
|
|
18
659
|
return false;
|
|
19
660
|
}
|