wogiflow 1.0.16 → 1.0.17
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/.workflow/templates/claude-md.hbs +99 -0
- package/README.md +1 -77
- package/lib/utils.js +27 -13
- package/package.json +1 -1
- package/scripts/flow +10 -7
- package/scripts/flow-file-ops.js +13 -7
- package/scripts/flow-roadmap.js +1008 -0
- package/scripts/flow-skill-matcher.js +2 -6
- package/scripts/hooks/core/task-gate.js +12 -0
- package/scripts/postinstall.js +48 -34
- package/templates/roadmap.md +80 -0
- package/.workflow/specs/architecture.md.template +0 -24
- package/.workflow/specs/stack.md.template +0 -33
- package/.workflow/specs/testing.md.template +0 -36
- package/scripts/flow-voice-input.js +0 -638
|
@@ -92,6 +92,7 @@ npx flow onboard
|
|
|
92
92
|
| `/wogi-story "title"` | Create story with acceptance criteria |
|
|
93
93
|
| `/wogi-status` | Project overview |
|
|
94
94
|
| `/wogi-health` | Check workflow health |
|
|
95
|
+
| `/wogi-roadmap` | View/manage deferred work |
|
|
95
96
|
|
|
96
97
|
See `.claude/docs/commands.md` for complete command reference.
|
|
97
98
|
|
|
@@ -107,6 +108,7 @@ See `.claude/docs/commands.md` for complete command reference.
|
|
|
107
108
|
| "check health", "workflow health", "is everything ok" | `/wogi-health` |
|
|
108
109
|
| "wrap up", "end session", "that's all" | `/wogi-session-end` |
|
|
109
110
|
| "compact context", "save context", "running low on context" | `/wogi-compact` |
|
|
111
|
+
| "show roadmap", "what's planned", "future work", "deferred items" | `/wogi-roadmap` |
|
|
110
112
|
|
|
111
113
|
**IMPORTANT**: When a user's message matches one of these patterns, immediately invoke the Skill tool with the corresponding command. Do not ask for confirmation.
|
|
112
114
|
|
|
@@ -193,6 +195,7 @@ Check `.claude/skills/[name]/skill.md` for skill-specific guidance.
|
|
|
193
195
|
| Components | `.workflow/state/app-map.md` |
|
|
194
196
|
| Rules | `.workflow/state/decisions.md` |
|
|
195
197
|
| Progress | `.workflow/state/progress.md` |
|
|
198
|
+
| Roadmap | `.workflow/roadmap.md` |
|
|
196
199
|
|
|
197
200
|
## Commit Behavior
|
|
198
201
|
|
|
@@ -226,6 +229,102 @@ Check `config.json → qualityGates` before closing any task:
|
|
|
226
229
|
}
|
|
227
230
|
```
|
|
228
231
|
|
|
232
|
+
## Handling Large Requests (IMPORTANT)
|
|
233
|
+
|
|
234
|
+
When a user requests work that would require:
|
|
235
|
+
- More than 5 distinct tasks or files
|
|
236
|
+
- Multiple logical phases
|
|
237
|
+
- Work that spans beyond a reasonable session
|
|
238
|
+
- A "build me X" request for a substantial system
|
|
239
|
+
|
|
240
|
+
**You MUST:**
|
|
241
|
+
|
|
242
|
+
### Step 1: Acknowledge and Break Down
|
|
243
|
+
Break the request into logical phases. Present it clearly:
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
This is a substantial feature. Let me break it down:
|
|
247
|
+
|
|
248
|
+
**Phase 1 (Implement Now):**
|
|
249
|
+
- [Core foundation tasks]
|
|
250
|
+
|
|
251
|
+
**Phase 2 (Defer to Roadmap):**
|
|
252
|
+
- [Tasks that depend on Phase 1]
|
|
253
|
+
|
|
254
|
+
**Phase 3 (Defer to Roadmap):**
|
|
255
|
+
- [Future enhancements]
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Step 2: Ask User
|
|
259
|
+
```
|
|
260
|
+
Should I:
|
|
261
|
+
1. Implement Phase 1 now and add Phases 2-3 to your roadmap?
|
|
262
|
+
2. Create stories for all phases (you choose when to implement)?
|
|
263
|
+
3. Just implement Phase 1 (forget the rest)?
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Step 3: If User Chooses Option 1 (Recommended)
|
|
267
|
+
1. Create stories for Phase 1
|
|
268
|
+
2. Add remaining phases to `.workflow/roadmap.md` using this format:
|
|
269
|
+
|
|
270
|
+
```markdown
|
|
271
|
+
### [Phase Name]: [Feature]
|
|
272
|
+
|
|
273
|
+
**Status:** Deferred
|
|
274
|
+
**Created:** [TODAY]
|
|
275
|
+
**Depends On:** [Parent phase]
|
|
276
|
+
|
|
277
|
+
**Assumes:**
|
|
278
|
+
- [Key assumptions from current implementation]
|
|
279
|
+
- [Architectural decisions that must remain true]
|
|
280
|
+
|
|
281
|
+
**Key Files:**
|
|
282
|
+
- `path/to/file.ts` - [Why this file matters]
|
|
283
|
+
|
|
284
|
+
**Context When Deferred:**
|
|
285
|
+
[Brief description of current project state]
|
|
286
|
+
|
|
287
|
+
**Implementation Plan:**
|
|
288
|
+
1. [Step 1]
|
|
289
|
+
2. [Step 2]
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
3. Inform user: "Added N items to your roadmap. Run `/wogi-roadmap` to see them."
|
|
293
|
+
|
|
294
|
+
### Before Implementing Roadmap Items
|
|
295
|
+
|
|
296
|
+
When user asks to implement something from the roadmap:
|
|
297
|
+
|
|
298
|
+
1. **Find the item**: Check `.workflow/roadmap.md`
|
|
299
|
+
2. **Validate dependencies**:
|
|
300
|
+
- Is "Depends On" complete?
|
|
301
|
+
- Do "Key Files" still exist?
|
|
302
|
+
- Do "Assumes" still hold true?
|
|
303
|
+
3. **If validation fails**:
|
|
304
|
+
```
|
|
305
|
+
⚠️ This roadmap item may be outdated.
|
|
306
|
+
|
|
307
|
+
Issue: [What changed]
|
|
308
|
+
|
|
309
|
+
Options:
|
|
310
|
+
1. Update this item to match current architecture
|
|
311
|
+
2. Remove this item (no longer relevant)
|
|
312
|
+
3. Proceed anyway (you take responsibility)
|
|
313
|
+
```
|
|
314
|
+
4. **If validation passes**: Proceed with implementation
|
|
315
|
+
|
|
316
|
+
### When Modifying Code That Roadmap Items Depend On
|
|
317
|
+
|
|
318
|
+
If you're about to modify a file listed in any roadmap item's "Key Files":
|
|
319
|
+
|
|
320
|
+
```
|
|
321
|
+
Note: This change may affect roadmap items:
|
|
322
|
+
- [Item 1 name]
|
|
323
|
+
- [Item 2 name]
|
|
324
|
+
|
|
325
|
+
Should I review and update those items after this change?
|
|
326
|
+
```
|
|
327
|
+
|
|
229
328
|
## Context Management
|
|
230
329
|
|
|
231
330
|
Use `/wogi-compact` when:
|
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ A self-improving AI development workflow that learns from your feedback and accu
|
|
|
52
52
|
| [Task Execution](.claude/docs/knowledge-base/02-task-execution/) | The execution pipeline with trade-offs |
|
|
53
53
|
| [Self-Improvement](.claude/docs/knowledge-base/03-self-improvement/) | How WogiFlow learns and improves |
|
|
54
54
|
| [Memory & Context](.claude/docs/knowledge-base/04-memory-context/) | Context management and session persistence |
|
|
55
|
-
| [Development Tools](.claude/docs/knowledge-base/05-development-tools/) | Figma, traces,
|
|
55
|
+
| [Development Tools](.claude/docs/knowledge-base/05-development-tools/) | Figma, traces, MCP integrations |
|
|
56
56
|
| [Safety & Guardrails](.claude/docs/knowledge-base/06-safety-guardrails/) | Protection and recovery systems |
|
|
57
57
|
| [Configuration Reference](.claude/docs/knowledge-base/configuration/all-options.md) | All 200+ configuration options |
|
|
58
58
|
|
|
@@ -119,7 +119,6 @@ Daily commands for working with WogiFlow. Start with `/wogi-ready` to see tasks,
|
|
|
119
119
|
- [Parallel Auto-Detection](#parallel-auto-detection)
|
|
120
120
|
- [Skill Auto-Creation](#skill-auto-creation)
|
|
121
121
|
- [Project-Based Team Sync](#project-based-team-sync)
|
|
122
|
-
- [Voice Input](#voice-input)
|
|
123
122
|
- [Damage Control](#damage-control)
|
|
124
123
|
- [Safety & Verification](#safety--verification)
|
|
125
124
|
- [Execution Traces & Checkpoints](#execution-traces--checkpoints)
|
|
@@ -431,74 +430,6 @@ Sync workflow files at project scope - share decisions, patterns, and knowledge
|
|
|
431
430
|
|
|
432
431
|
---
|
|
433
432
|
|
|
434
|
-
## Voice Input
|
|
435
|
-
Voice-to-transcript support with multiple provider options. Create tasks, stories, and commands using your voice.
|
|
436
|
-
|
|
437
|
-
### How It Works
|
|
438
|
-
|
|
439
|
-
```
|
|
440
|
-
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|
441
|
-
│ Microphone │ ──▶ │ Record │ ──▶ │ Transcribe │
|
|
442
|
-
│ Input │ │ Audio │ │ (Whisper) │
|
|
443
|
-
└─────────────┘ └─────────────┘ └─────────────┘
|
|
444
|
-
│
|
|
445
|
-
▼
|
|
446
|
-
┌──────────┐
|
|
447
|
-
│ Text │
|
|
448
|
-
│ Output │
|
|
449
|
-
└──────────┘
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
### Providers
|
|
453
|
-
|
|
454
|
-
| Provider | API Key | Description |
|
|
455
|
-
|----------|---------|-------------|
|
|
456
|
-
| **Local** | No | Whisper.cpp - works offline |
|
|
457
|
-
| **OpenAI** | Yes | Best accuracy |
|
|
458
|
-
| **Groq** | Yes (free tier) | Fast cloud transcription |
|
|
459
|
-
|
|
460
|
-
### Setup
|
|
461
|
-
|
|
462
|
-
```bash
|
|
463
|
-
./scripts/flow voice-input setup # Interactive setup
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
The setup wizard will:
|
|
467
|
-
1. Ask if you want to enable voice input
|
|
468
|
-
2. Let you choose a provider
|
|
469
|
-
3. Configure API keys (if using cloud)
|
|
470
|
-
|
|
471
|
-
### Configuration
|
|
472
|
-
|
|
473
|
-
```json
|
|
474
|
-
{
|
|
475
|
-
"voice": {
|
|
476
|
-
"enabled": true,
|
|
477
|
-
"provider": "groq",
|
|
478
|
-
"groqApiKey": "gsk_...",
|
|
479
|
-
"defaultDuration": 30
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
### Commands
|
|
485
|
-
|
|
486
|
-
```bash
|
|
487
|
-
./scripts/flow voice-input # Record and transcribe
|
|
488
|
-
./scripts/flow voice-input -d 60 # Record for 60 seconds
|
|
489
|
-
./scripts/flow voice-input -p openai # Use specific provider
|
|
490
|
-
./scripts/flow voice-input --to-story # Create story from voice
|
|
491
|
-
./scripts/flow voice-input status # Show configuration
|
|
492
|
-
./scripts/flow voice-input test # Test with 5-second recording
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
### Requirements
|
|
496
|
-
|
|
497
|
-
- **Recording**: `sox` - install with `brew install sox` (macOS) or `apt install sox` (Linux)
|
|
498
|
-
- **Local Whisper**: `pip install openai-whisper` or download whisper.cpp
|
|
499
|
-
|
|
500
|
-
---
|
|
501
|
-
|
|
502
433
|
## Damage Control
|
|
503
434
|
|
|
504
435
|
Prevents destructive commands from running accidentally. Pattern-based blocking with configurable protection levels.
|
|
@@ -1492,13 +1423,6 @@ flow parallel suggest # Check if suggestion available
|
|
|
1492
1423
|
flow team sync-init # Initialize project sync
|
|
1493
1424
|
flow team project-id # Show/set project ID
|
|
1494
1425
|
|
|
1495
|
-
# Voice Inputflow voice-input setup # Configure voice input
|
|
1496
|
-
flow voice-input # Record and transcribe
|
|
1497
|
-
flow voice-input -d 60 # Record for 60 seconds
|
|
1498
|
-
flow voice-input -p groq # Use specific provider
|
|
1499
|
-
flow voice-input status # Show configuration
|
|
1500
|
-
flow voice-input test # Test recording
|
|
1501
|
-
|
|
1502
1426
|
# Hybrid Mode
|
|
1503
1427
|
flow hybrid enable # Enable with wizard
|
|
1504
1428
|
flow hybrid disable # Disable
|
package/lib/utils.js
CHANGED
|
@@ -37,27 +37,40 @@ function findProjectRoot() {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Safely parse JSON with prototype pollution protection
|
|
40
|
+
* Safely parse JSON content with prototype pollution protection
|
|
41
|
+
*
|
|
42
|
+
* Note: For parsing JSON files, use safeJsonParseFile from flow-file-ops.js
|
|
43
|
+
* or safeReadJson from this module instead.
|
|
44
|
+
*
|
|
41
45
|
* @param {string} content - JSON string to parse
|
|
42
46
|
* @param {*} defaultValue - Default value if parsing fails
|
|
43
47
|
* @returns {Object} Parsed object or default value
|
|
44
48
|
*/
|
|
45
|
-
function
|
|
49
|
+
function safeJsonParseContent(content, defaultValue = null) {
|
|
46
50
|
try {
|
|
51
|
+
// Check for prototype pollution attempts in raw content
|
|
52
|
+
// Covers various quote styles and whitespace variants
|
|
53
|
+
if (/__proto__|constructor\s*["'`:]|prototype\s*["'`:]/i.test(content)) {
|
|
54
|
+
console.warn('[safeJsonParse] Suspicious content detected');
|
|
55
|
+
return defaultValue;
|
|
56
|
+
}
|
|
57
|
+
|
|
47
58
|
const parsed = JSON.parse(content);
|
|
48
59
|
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
// Validate it's an object (not primitive)
|
|
61
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
62
|
+
return parsed; // Allow primitives to pass through
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Additional check: ensure no proto/constructor keys were added
|
|
66
|
+
const keys = Object.getOwnPropertyNames(parsed);
|
|
67
|
+
if (keys.includes('__proto__') || keys.includes('constructor') || keys.includes('prototype')) {
|
|
68
|
+
console.warn('[safeJsonParse] Prototype pollution attempt detected');
|
|
69
|
+
return defaultValue;
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
return parsed;
|
|
60
|
-
} catch (
|
|
73
|
+
} catch (_err) {
|
|
61
74
|
return defaultValue;
|
|
62
75
|
}
|
|
63
76
|
}
|
|
@@ -74,7 +87,7 @@ function safeReadJson(filePath, defaultValue = null) {
|
|
|
74
87
|
return defaultValue;
|
|
75
88
|
}
|
|
76
89
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
77
|
-
return
|
|
90
|
+
return safeJsonParseContent(content, defaultValue);
|
|
78
91
|
} catch (err) {
|
|
79
92
|
return defaultValue;
|
|
80
93
|
}
|
|
@@ -290,7 +303,8 @@ function safeWriteFile(basePath, relativePath, content) {
|
|
|
290
303
|
|
|
291
304
|
module.exports = {
|
|
292
305
|
findProjectRoot,
|
|
293
|
-
|
|
306
|
+
safeJsonParseContent,
|
|
307
|
+
safeJsonParse: safeJsonParseContent, // Backward-compatible alias (deprecated)
|
|
294
308
|
safeReadJson,
|
|
295
309
|
httpsGet,
|
|
296
310
|
copyDir,
|
package/package.json
CHANGED
package/scripts/flow
CHANGED
|
@@ -57,6 +57,13 @@ show_help() {
|
|
|
57
57
|
echo " new-feature <n> Create new feature"
|
|
58
58
|
echo " bug <title> Create bug report"
|
|
59
59
|
echo ""
|
|
60
|
+
echo "Roadmap & Planning:"
|
|
61
|
+
echo " roadmap Show project roadmap"
|
|
62
|
+
echo " roadmap add <title> Add item to roadmap"
|
|
63
|
+
echo " roadmap validate <t> Validate item dependencies"
|
|
64
|
+
echo " roadmap move <t> Move item between phases"
|
|
65
|
+
echo " roadmap list [phase] List items by phase"
|
|
66
|
+
echo ""
|
|
60
67
|
echo "Workflow:"
|
|
61
68
|
echo " morning Morning briefing - where you left off"
|
|
62
69
|
echo " health Check workflow health"
|
|
@@ -283,9 +290,6 @@ show_help() {
|
|
|
283
290
|
echo " confidence stats Show confidence statistics"
|
|
284
291
|
echo ""
|
|
285
292
|
echo "Input & Editing:"
|
|
286
|
-
echo " voice-input Voice-to-transcript input"
|
|
287
|
-
echo " voice-input setup Install/configure voice dependencies"
|
|
288
|
-
echo " voice-input record Record and transcribe audio"
|
|
289
293
|
echo " guided-edit \"task\" Step-by-step guided multi-file editing"
|
|
290
294
|
echo " guided-edit status Show current guided edit session"
|
|
291
295
|
echo ""
|
|
@@ -325,6 +329,9 @@ case "${1:-}" in
|
|
|
325
329
|
story)
|
|
326
330
|
node "$SCRIPT_DIR/flow-story.js" "${@:2}"
|
|
327
331
|
;;
|
|
332
|
+
roadmap)
|
|
333
|
+
node "$SCRIPT_DIR/flow-roadmap.js" "${@:2}"
|
|
334
|
+
;;
|
|
328
335
|
new-feature)
|
|
329
336
|
"$SCRIPT_DIR/flow-new-feature" "${@:2}"
|
|
330
337
|
;;
|
|
@@ -930,9 +937,6 @@ case "${1:-}" in
|
|
|
930
937
|
# Phase 6: Background Sync Daemon
|
|
931
938
|
node "$SCRIPT_DIR/flow-sync-daemon.js" "${@:2}"
|
|
932
939
|
;;
|
|
933
|
-
voice-input|voice)
|
|
934
|
-
node "$SCRIPT_DIR/flow-voice-input.js" "${@:2}"
|
|
935
|
-
;;
|
|
936
940
|
guided-edit)
|
|
937
941
|
node "$SCRIPT_DIR/flow-guided-edit.js" "${@:2}"
|
|
938
942
|
;;
|
|
@@ -965,7 +969,6 @@ case "${1:-}" in
|
|
|
965
969
|
hybrid) echo "Manage hybrid mode. Subcommands: enable, disable, status, execute, test, learning" ;;
|
|
966
970
|
parallel) echo "Manage parallel execution. Subcommands: config, check, enable, disable" ;;
|
|
967
971
|
worktree) echo "Manage worktree isolation. Subcommands: enable, disable, list, cleanup" ;;
|
|
968
|
-
voice-input|voice) echo "Voice-to-transcript input. Subcommands: setup, status, test, record" ;;
|
|
969
972
|
long-input|long-input-process|transcript-digest|digest) echo "Long input processing. Ensures nothing missed from long prompts/transcripts/specs. Subcommands: status, new, check, topics, save-topics" ;;
|
|
970
973
|
guided-edit) echo "Step-by-step guided multi-file editing. Usage: flow guided-edit \"task description\"" ;;
|
|
971
974
|
*) echo "No detailed help for '$2'. Run 'flow help' for all commands." ;;
|
package/scripts/flow-file-ops.js
CHANGED
|
@@ -94,38 +94,42 @@ function writeJson(filePath, data) {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
|
-
* Safely parse JSON with prototype pollution protection
|
|
97
|
+
* Safely read and parse JSON file with prototype pollution protection
|
|
98
98
|
* Use this for user-modifiable files (registry, stats, etc.)
|
|
99
|
+
*
|
|
100
|
+
* Note: For parsing raw JSON content (not files), use safeJsonParseContent
|
|
101
|
+
* from lib/utils.js instead.
|
|
102
|
+
*
|
|
99
103
|
* @param {string} filePath - Path to JSON file
|
|
100
104
|
* @param {*} [defaultValue=null] - Default value if parsing fails
|
|
101
105
|
* @returns {object|null} Parsed JSON or defaultValue on error
|
|
102
106
|
*/
|
|
103
|
-
function
|
|
107
|
+
function safeJsonParseFile(filePath, defaultValue = null) {
|
|
104
108
|
try {
|
|
105
109
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
106
110
|
|
|
107
111
|
// Check for prototype pollution attempts
|
|
108
112
|
if (/__proto__|constructor\s*["'`:]|prototype\s*["'`:]/i.test(content)) {
|
|
109
|
-
console.error(`[
|
|
113
|
+
console.error(`[safeJsonParseFile] Suspicious content detected in ${filePath}`);
|
|
110
114
|
return defaultValue;
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
const parsed = JSON.parse(content);
|
|
114
118
|
|
|
115
119
|
if (typeof parsed !== 'object' || parsed === null) {
|
|
116
|
-
console.error(`[
|
|
120
|
+
console.error(`[safeJsonParseFile] Invalid JSON structure in ${filePath} (expected object)`);
|
|
117
121
|
return defaultValue;
|
|
118
122
|
}
|
|
119
123
|
|
|
120
124
|
const keys = Object.getOwnPropertyNames(parsed);
|
|
121
125
|
if (keys.includes('__proto__') || keys.includes('constructor') || keys.includes('prototype')) {
|
|
122
|
-
console.error(`[
|
|
126
|
+
console.error(`[safeJsonParseFile] Prototype pollution attempt detected in ${filePath}`);
|
|
123
127
|
return defaultValue;
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
return parsed;
|
|
127
131
|
} catch (err) {
|
|
128
|
-
console.error(`[
|
|
132
|
+
console.error(`[safeJsonParseFile] Failed to parse ${filePath}: ${err.message}`);
|
|
129
133
|
return defaultValue;
|
|
130
134
|
}
|
|
131
135
|
}
|
|
@@ -284,7 +288,8 @@ module.exports = {
|
|
|
284
288
|
// JSON operations
|
|
285
289
|
readJson,
|
|
286
290
|
writeJson,
|
|
287
|
-
|
|
291
|
+
safeJsonParseFile,
|
|
292
|
+
safeJsonParse: safeJsonParseFile, // Backward-compatible alias (deprecated)
|
|
288
293
|
validateJson,
|
|
289
294
|
|
|
290
295
|
// Text operations
|
|
@@ -293,6 +298,7 @@ module.exports = {
|
|
|
293
298
|
|
|
294
299
|
// Path validation
|
|
295
300
|
isPathWithinDir,
|
|
301
|
+
isPathWithinProject: isPathWithinDir, // Alias for documentation consistency
|
|
296
302
|
|
|
297
303
|
// Directory operations
|
|
298
304
|
listDirs,
|