@leejungkiin/awkit 1.7.4 ā 1.7.6
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/README.md +42 -5
- package/bin/awk.js +673 -15
- package/bin/codex-generators.js +2 -1
- package/core/GEMINI.md +6 -2
- package/core/GEMINI.md.bak +4 -0
- package/core/GreetingEngine/index.js +225 -0
- package/core/GreetingEngine/locales/en.json +6 -0
- package/core/GreetingEngine/locales/ja.json +6 -0
- package/core/GreetingEngine/locales/vi.json +6 -0
- package/core/GreetingEngine/test.js +37 -0
- package/core/skill-runtime-manifest.json +1 -0
- package/docs/PRD.md +57 -0
- package/docs/brainstorm_multi_agent_cli.md +211 -0
- package/docs/history/PRD.v1.md +55 -0
- package/docs/history/PRD.v2.md +57 -0
- package/docs/history/implementation_plan.v1.md +49 -45
- package/docs/history/implementation_plan.v2.md +87 -0
- package/docs/history/memoizedfibonacci_spec.v1.md +127 -0
- package/docs/specs/greetingapp_spec.md +97 -0
- package/docs/specs/memoizedfibonacci_spec.md +211 -0
- package/package.json +1 -1
- package/scripts/codex-goal.js +163 -0
- package/scripts/exec-rtk.js +4 -3
- package/scripts/multi-model-pipeline.js +292 -50
- package/scripts/qwen-exec.js +147 -0
- package/skills/claude-planner/SKILL.md +24 -0
- package/skills/codex-conductor/SKILL.md +25 -1
- package/skills/codex-goal/SKILL.md +82 -0
- package/skills/qwen-conductor/SKILL.md +100 -0
- package/workflows/lifecycle/goal.md +86 -0
- package/workflows/multi-agent-pipeline.md +52 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Technical Specification ā MemoizedFibonacci
|
|
2
|
+
|
|
3
|
+
## Revision History
|
|
4
|
+
|
|
5
|
+
| Version | Date | Author | Description |
|
|
6
|
+
| :--- | :--- | :--- | :--- |
|
|
7
|
+
| 1.0 | 2026-06-22 | Antigravity Orchestrator | Initial technical design with Mermaid diagram, class architecture, and caching strategy. |
|
|
8
|
+
| 1.1 | 2026-06-22 | Antigravity Orchestrator | Refined LRU caching mechanism using ES6 Map insertion ordering. Added explicit detail on Async Slicing and Testing Strategy. |
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. System Architecture
|
|
13
|
+
|
|
14
|
+
The `MemoizedFibonacci` feature consists of three primary layers:
|
|
15
|
+
1. **API & Interface Layer:** Exposes synchronous and asynchronous methods to users.
|
|
16
|
+
2. **LRU Cache Layer:** Manages in-memory storage of computed sequences with automatic eviction based on Least Recently Used patterns.
|
|
17
|
+
3. **Computation Engine:** Performs iterative sequence calculations to prevent call stack overflow, handles dynamic upgrading to `BigInt` for large numbers, and schedules asynchronous chunks for heavy inputs.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 2. API Design & Core Interface
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
interface FibonacciConfig {
|
|
25
|
+
maxCacheSize?: number; // Maximum number of entries in the cache (default: 1000)
|
|
26
|
+
useBigInt?: boolean; // Force BigInt computation even for small inputs (default: false)
|
|
27
|
+
asyncThreshold?: number; // Input size to trigger asynchronous execution (default: 50000)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface CacheStats {
|
|
31
|
+
hits: number;
|
|
32
|
+
misses: number;
|
|
33
|
+
size: number;
|
|
34
|
+
evictions: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class MemoizedFibonacci {
|
|
38
|
+
// Built-in ES6 Map maintains insertion order.
|
|
39
|
+
// By deleting and re-inserting a key on access, the most recently used keys move to the end.
|
|
40
|
+
// The first key in map.keys() represents the Least Recently Used (LRU) element.
|
|
41
|
+
private cache: Map<number, number | bigint>;
|
|
42
|
+
private config: Required<FibonacciConfig>;
|
|
43
|
+
private stats: CacheStats;
|
|
44
|
+
|
|
45
|
+
constructor(config?: FibonacciConfig);
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Calculates Fibonacci of n. Automatically picks sync/async mode based on threshold.
|
|
49
|
+
* Returns a Promise resolving to number or bigint.
|
|
50
|
+
*/
|
|
51
|
+
public calculate(n: number): Promise<number | bigint>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Synchronously calculates Fibonacci of n.
|
|
55
|
+
* Throws RangeError if n exceeds asyncThreshold to protect the thread.
|
|
56
|
+
*/
|
|
57
|
+
public calculateSync(n: number): number | bigint;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Checks if the value for n is currently cached.
|
|
61
|
+
*/
|
|
62
|
+
public isCached(n: number): boolean;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Dynamically updates the cache capacity limit. Evicts items if size exceeds new limit.
|
|
66
|
+
*/
|
|
67
|
+
public setMaxCacheSize(size: number): void;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Retrieves cache usage statistics.
|
|
71
|
+
*/
|
|
72
|
+
public getStats(): CacheStats;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Clears all cache entries and resets statistics.
|
|
76
|
+
*/
|
|
77
|
+
public clearCache(): void;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Internal helper implementing iterative computation.
|
|
81
|
+
*/
|
|
82
|
+
private computeIterative(n: number, isBigInt: boolean): number | bigint;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Internal helper performing non-blocking chunked computation.
|
|
86
|
+
*/
|
|
87
|
+
private computeAsyncChunked(n: number, chunkSize: number): Promise<bigint>;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 3. Detailed Logic Flow (Mermaid Diagram)
|
|
94
|
+
|
|
95
|
+
The following diagram illustrates the routing, validation, precision selection, and caching logic:
|
|
96
|
+
|
|
97
|
+
```mermaid
|
|
98
|
+
graph TD
|
|
99
|
+
A[Start: Calculate F(n)] --> B{Validate input n >= 0}
|
|
100
|
+
B -- No --> C[Throw RangeError: Invalid Input]
|
|
101
|
+
B -- Yes --> D{Check Cache for n}
|
|
102
|
+
|
|
103
|
+
D -- Hit (Yes) --> E[Update Map Insertion Order: Delete & Re-insert]
|
|
104
|
+
E --> F[Increment Hit Metric]
|
|
105
|
+
F --> G[Return Cached Value]
|
|
106
|
+
|
|
107
|
+
D -- Miss (No) --> H[Increment Miss Metric]
|
|
108
|
+
H --> I{Check Precision Mode: n > 78 or useBigInt}
|
|
109
|
+
|
|
110
|
+
I -- Standard Number (n <= 78) --> J[Compute iteratively using standard Number]
|
|
111
|
+
I -- BigInt (n > 78) --> K{Is n >= asyncThreshold?}
|
|
112
|
+
|
|
113
|
+
K -- No (Sync BigInt) --> L[Compute iteratively using BigInt]
|
|
114
|
+
K -- Yes (Async BigInt) --> M[Invoke computeAsyncChunked]
|
|
115
|
+
|
|
116
|
+
M --> N[Loop in chunks of size 10,000 using setImmediate]
|
|
117
|
+
N --> O[Yield control back to Event Loop after each chunk]
|
|
118
|
+
|
|
119
|
+
J --> P[Store Result in Cache]
|
|
120
|
+
L --> P
|
|
121
|
+
O --> P
|
|
122
|
+
|
|
123
|
+
P --> Q{Cache Size > maxCacheSize?}
|
|
124
|
+
Q -- Yes --> R[Evict map.keys.next.value oldest entry]
|
|
125
|
+
R --> S[Increment Eviction Metric]
|
|
126
|
+
S --> T[Return Computed Result]
|
|
127
|
+
Q -- No --> T
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 4. Key Implementation Mechanics
|
|
133
|
+
|
|
134
|
+
### 4.1 LRU Eviction Implementation (ES6 Map)
|
|
135
|
+
Instead of managing a separate `lruList` array (which incurs $O(N)$ lookup/splice operations), the implementation relies entirely on the ordered property of JavaScript's `Map`.
|
|
136
|
+
* **Read (Cache Hit):**
|
|
137
|
+
```javascript
|
|
138
|
+
const value = this.cache.get(key);
|
|
139
|
+
this.cache.delete(key);
|
|
140
|
+
this.cache.set(key, value); // Re-inserts at the end of the Map
|
|
141
|
+
```
|
|
142
|
+
* **Write (Cache Miss & Capacity Exceeded):**
|
|
143
|
+
```javascript
|
|
144
|
+
this.cache.set(key, value);
|
|
145
|
+
if (this.cache.size > this.config.maxCacheSize) {
|
|
146
|
+
const oldestKey = this.cache.keys().next().value;
|
|
147
|
+
this.cache.delete(oldestKey); // Deletes the oldest insertion
|
|
148
|
+
this.stats.evictions++;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
This architecture yields highly efficient $O(1)$ operations for both cache lookup and replacement.
|
|
152
|
+
|
|
153
|
+
### 4.2 Precision Safeguards & Double Limits
|
|
154
|
+
- **Standard Float Limits:** Standard numbers in JavaScript lose precision above $F(78)$ ($F(78) = 8944394323791464$, whereas $F(79) = 14472334024559020$ which exceeds `Number.MAX_SAFE_INTEGER`).
|
|
155
|
+
- **Automatic BigInt Upgrade:** If the class configuration is not explicitly set, inputs $n \ge 79$ automatically upgrade execution to `BigInt` mode.
|
|
156
|
+
|
|
157
|
+
### 4.3 Async Slicing / Non-blocking Loop
|
|
158
|
+
For large values of $n$ (e.g. $n \ge 100,000$), calculating Fibonacci in a single synchronous loop blocks the JS single-threaded event loop.
|
|
159
|
+
We employ a chunked calculation pattern:
|
|
160
|
+
```javascript
|
|
161
|
+
private async computeAsyncChunked(n: number, chunkSize: number = 10000): Promise<bigint> {
|
|
162
|
+
let prev = 0n;
|
|
163
|
+
let curr = 1n;
|
|
164
|
+
let i = 2;
|
|
165
|
+
|
|
166
|
+
const runChunk = (): Promise<bigint> => {
|
|
167
|
+
return new Promise((resolve) => {
|
|
168
|
+
setImmediate(() => {
|
|
169
|
+
const target = Math.min(i + chunkSize, n + 1);
|
|
170
|
+
for (; i < target; i++) {
|
|
171
|
+
const next = prev + curr;
|
|
172
|
+
prev = curr;
|
|
173
|
+
curr = next;
|
|
174
|
+
}
|
|
175
|
+
if (i <= n) {
|
|
176
|
+
resolve(runChunk()); // Recursively queue the next chunk
|
|
177
|
+
} else {
|
|
178
|
+
resolve(curr);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
return runChunk();
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 5. Error Handling & Edge Cases
|
|
191
|
+
|
|
192
|
+
| Condition | System Response |
|
|
193
|
+
| :--- | :--- |
|
|
194
|
+
| Negative Input ($n < 0$) | Throws `RangeError: Input must be a non-negative integer.` |
|
|
195
|
+
| Floating point Input (e.g., $n = 3.5$) | Throws `TypeError: Input must be an integer.` |
|
|
196
|
+
| Maximum Guardrail Breach ($n > 1,000,000$) | Throws `RangeError: Calculation size exceeds maximum guardrail of 1,000,000.` |
|
|
197
|
+
| Sync Call beyond Threshold ($n > asyncThreshold$) | Throws `RangeError: Input exceeds asyncThreshold. Use calculate() instead.` |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 6. Testing Strategy
|
|
202
|
+
|
|
203
|
+
### 6.1 Unit Tests
|
|
204
|
+
* **Core Calculations:** Verify $F(0) = 0$, $F(1) = 1$, $F(10) = 55$, and $F(78) = 8944394323791464$.
|
|
205
|
+
* **BigInt Accuracy:** Verify $F(79)$ is correctly calculated as `14472334024559020n` (with tailing `n` specifying bigint).
|
|
206
|
+
* **Caching Performance:** Retrieve $F(50)$ twice. The second call must trigger a cache hit and have a latency under 1 microsecond.
|
|
207
|
+
* **LRU Eviction:** Set cache limit to 3. Populate cache with keys 1, 2, 3. Read key 1 (making it most recently used). Insert key 4. Verify key 2 is evicted.
|
|
208
|
+
|
|
209
|
+
### 6.2 Performance & Memory Benchmarks
|
|
210
|
+
* **Sync vs Async Threshold:** Test the threshold boundary. Verify that calling `calculate(49999)` completes synchronously within milliseconds, and `calculate(50001)` returns a Promise and yields event loop control.
|
|
211
|
+
* **Leak Testing:** Execute calculation loop of random values up to $n = 10,000$ for 100,000 iterations. Verify heap memory remains flat (no leakage outside the bounds of `maxCacheSize`).
|
package/package.json
CHANGED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Codex Goal Conductor - Goal Orchestration Runner for AWKit
|
|
5
|
+
* Pursues high-level development goals autonomously by executing Codex CLI.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { execSync, spawnSync } = require('child_process');
|
|
11
|
+
const os = require('os');
|
|
12
|
+
|
|
13
|
+
const GOALS_DIR = path.join(process.cwd(), 'codex-reports', 'goals');
|
|
14
|
+
const ACTIVE_GOAL_FILE = path.join(GOALS_DIR, 'active_goal.json');
|
|
15
|
+
|
|
16
|
+
const C = {
|
|
17
|
+
reset: '\x1b[0m',
|
|
18
|
+
red: '\x1b[31m',
|
|
19
|
+
green: '\x1b[32m',
|
|
20
|
+
yellow: '\x1b[33m',
|
|
21
|
+
cyan: '\x1b[36m',
|
|
22
|
+
gray: '\x1b[90m',
|
|
23
|
+
bold: '\x1b[1m',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const log = (msg) => console.log(msg);
|
|
27
|
+
const ok = (msg) => log(`${C.green}ā${C.reset} ${msg}`);
|
|
28
|
+
const warn = (msg) => log(`${C.yellow}ā ${C.reset} ${msg}`);
|
|
29
|
+
const err = (msg) => log(`${C.red}ā${C.reset} ${msg}`);
|
|
30
|
+
const info = (msg) => log(`${C.cyan}ā¹${C.reset} ${msg}`);
|
|
31
|
+
|
|
32
|
+
// Parse args
|
|
33
|
+
const args = process.argv.slice(2);
|
|
34
|
+
let prompt = '';
|
|
35
|
+
let checkStatus = false;
|
|
36
|
+
let pauseGoal = false;
|
|
37
|
+
let resumeGoal = false;
|
|
38
|
+
let cancelGoal = false;
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < args.length; i++) {
|
|
41
|
+
if (args[i] === '--prompt' && args[i + 1]) {
|
|
42
|
+
prompt = args[i + 1];
|
|
43
|
+
i++;
|
|
44
|
+
} else if (args[i] === '--status') {
|
|
45
|
+
checkStatus = true;
|
|
46
|
+
} else if (args[i] === '--pause') {
|
|
47
|
+
pauseGoal = true;
|
|
48
|
+
} else if (args[i] === '--resume') {
|
|
49
|
+
resumeGoal = true;
|
|
50
|
+
} else if (args[i] === '--cancel') {
|
|
51
|
+
cancelGoal = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Ensure goals directory exists
|
|
56
|
+
fs.mkdirSync(GOALS_DIR, { recursive: true });
|
|
57
|
+
|
|
58
|
+
function getActiveGoal() {
|
|
59
|
+
if (fs.existsSync(ACTIVE_GOAL_FILE)) {
|
|
60
|
+
try {
|
|
61
|
+
return JSON.parse(fs.readFileSync(ACTIVE_GOAL_FILE, 'utf8'));
|
|
62
|
+
} catch (_) {}
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function saveActiveGoal(state) {
|
|
68
|
+
fs.writeFileSync(ACTIVE_GOAL_FILE, JSON.stringify(state, null, 2) + '\n', 'utf8');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function runGoal(goalPrompt) {
|
|
72
|
+
info(`Setting up Goal Conductor for: "${goalPrompt}"`);
|
|
73
|
+
|
|
74
|
+
// Load codex-goal skill rules
|
|
75
|
+
const skillPath = path.join(__dirname, '..', 'skills', 'codex-goal', 'SKILL.md');
|
|
76
|
+
let skillContent = '';
|
|
77
|
+
if (fs.existsSync(skillPath)) {
|
|
78
|
+
skillContent = fs.readFileSync(skillPath, 'utf8');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const fullPrompt = `${skillContent}\n\n[USER GOAL / OBJECTIVE]\n${goalPrompt}\n\nPlease parse the goal, partition it into steps, and coordinate execution. Call Claude, Qwen, and sub-agents as described in the guidelines.`;
|
|
82
|
+
|
|
83
|
+
const goalId = `goal_${Date.now()}`;
|
|
84
|
+
const state = {
|
|
85
|
+
goalId,
|
|
86
|
+
prompt: goalPrompt,
|
|
87
|
+
status: 'running',
|
|
88
|
+
timestamp: Date.now()
|
|
89
|
+
};
|
|
90
|
+
saveActiveGoal(state);
|
|
91
|
+
|
|
92
|
+
// Set goal_mode = true in current context if running checks
|
|
93
|
+
process.env.goal_mode = 'true';
|
|
94
|
+
|
|
95
|
+
info(`Launching Codex CLI Agent in Goal Orchestration Mode...`);
|
|
96
|
+
try {
|
|
97
|
+
const result = spawnSync('codex', [
|
|
98
|
+
fullPrompt,
|
|
99
|
+
'-s', 'workspace-write',
|
|
100
|
+
'--ask-for-approval', 'untrusted'
|
|
101
|
+
], { stdio: 'inherit' });
|
|
102
|
+
|
|
103
|
+
if (result.status === 0) {
|
|
104
|
+
state.status = 'completed';
|
|
105
|
+
saveActiveGoal(state);
|
|
106
|
+
ok('š Codex Goal Conductor execution finished.');
|
|
107
|
+
} else {
|
|
108
|
+
state.status = 'failed';
|
|
109
|
+
saveActiveGoal(state);
|
|
110
|
+
err('Codex Goal Conductor exited with an error.');
|
|
111
|
+
}
|
|
112
|
+
} catch (e) {
|
|
113
|
+
state.status = 'failed';
|
|
114
|
+
saveActiveGoal(state);
|
|
115
|
+
err('Failed to execute Codex CLI: ' + e.message);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// CLI Command Handling
|
|
120
|
+
if (checkStatus) {
|
|
121
|
+
const state = getActiveGoal();
|
|
122
|
+
if (!state) {
|
|
123
|
+
log('No active goal session tracked.');
|
|
124
|
+
} else {
|
|
125
|
+
log(`\nšÆ Active Goal: "${state.prompt}"`);
|
|
126
|
+
log(`Status: ${state.status === 'running' ? C.cyan : state.status === 'completed' ? C.green : C.red}${state.status.toUpperCase()}${C.reset}`);
|
|
127
|
+
log(`Goal ID: ${state.goalId}`);
|
|
128
|
+
log(`To resume/check the Codex session, run: ${C.green}awkit goal --resume${C.reset}\n`);
|
|
129
|
+
}
|
|
130
|
+
} else if (pauseGoal) {
|
|
131
|
+
log('To pause Codex CLI execution, please press Ctrl+C in the active terminal run window.');
|
|
132
|
+
} else if (resumeGoal) {
|
|
133
|
+
const state = getActiveGoal();
|
|
134
|
+
if (state) {
|
|
135
|
+
info('Resuming last Codex session...');
|
|
136
|
+
try {
|
|
137
|
+
spawnSync('codex', ['resume', '--last'], { stdio: 'inherit' });
|
|
138
|
+
} catch (e) {
|
|
139
|
+
err('Failed to resume Codex session: ' + e.message);
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
warn('No active goal session to resume.');
|
|
143
|
+
}
|
|
144
|
+
} else if (cancelGoal) {
|
|
145
|
+
const state = getActiveGoal();
|
|
146
|
+
if (state) {
|
|
147
|
+
if (fs.existsSync(ACTIVE_GOAL_FILE)) {
|
|
148
|
+
fs.unlinkSync(ACTIVE_GOAL_FILE);
|
|
149
|
+
}
|
|
150
|
+
ok('Goal session cleared locally.');
|
|
151
|
+
} else {
|
|
152
|
+
warn('No active goal session to cancel.');
|
|
153
|
+
}
|
|
154
|
+
} else if (prompt) {
|
|
155
|
+
runGoal(prompt);
|
|
156
|
+
} else {
|
|
157
|
+
log('Usage:');
|
|
158
|
+
log(' node scripts/codex-goal.js --prompt "Goal Description"');
|
|
159
|
+
log(' node scripts/codex-goal.js --status');
|
|
160
|
+
log(' node scripts/codex-goal.js --pause');
|
|
161
|
+
log(' node scripts/codex-goal.js --resume');
|
|
162
|
+
log(' node scripts/codex-goal.js --cancel');
|
|
163
|
+
}
|
package/scripts/exec-rtk.js
CHANGED
|
@@ -24,6 +24,7 @@ function checkRtk() {
|
|
|
24
24
|
* @returns {Buffer|string}
|
|
25
25
|
*/
|
|
26
26
|
function execRtkSync(command, options = {}) {
|
|
27
|
+
const opts = { timeout: 30000, ...options };
|
|
27
28
|
const trimmed = command.trim();
|
|
28
29
|
|
|
29
30
|
// Only compress developer commands known to be verbose
|
|
@@ -33,10 +34,10 @@ function execRtkSync(command, options = {}) {
|
|
|
33
34
|
const isEligible = allEligible.some(prefix => trimmed.startsWith(prefix));
|
|
34
35
|
|
|
35
36
|
if (!checkRtk()) {
|
|
36
|
-
if (isEligible && !
|
|
37
|
-
return execSync(`${command} 2>&1 | tail -c 8000`, { ...
|
|
37
|
+
if (isEligible && !opts.stdio) {
|
|
38
|
+
return execSync(`${command} 2>&1 | tail -c 8000`, { ...opts, shell: true });
|
|
38
39
|
}
|
|
39
|
-
return execSync(command,
|
|
40
|
+
return execSync(command, opts);
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
if (trimmed.startsWith('rtk ')) {
|