@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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leejungkiin/awkit",
3
- "version": "1.7.4",
3
+ "version": "1.7.6",
4
4
  "description": "Antigravity Workflow Kit v1.6 Unified AI agent orchestration system with Mindful Checkpoints.",
5
5
  "main": "bin/awk.js",
6
6
  "private": false,
@@ -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
+ }
@@ -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 && !options.stdio) {
37
- return execSync(`${command} 2>&1 | tail -c 8000`, { ...options, shell: true });
37
+ if (isEligible && !opts.stdio) {
38
+ return execSync(`${command} 2>&1 | tail -c 8000`, { ...opts, shell: true });
38
39
  }
39
- return execSync(command, options);
40
+ return execSync(command, opts);
40
41
  }
41
42
 
42
43
  if (trimmed.startsWith('rtk ')) {