mindsystem-cc 4.0.2 → 4.0.4
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 +107 -1
- package/agents/ms-codebase-researcher.md +5 -9
- package/bin/install.js +29 -8
- package/commands/ms/doctor.md +3 -3
- package/package.json +1 -1
- package/scripts/ms-tools.py +56 -8
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ npx mindsystem-cc
|
|
|
19
19
|
|
|
20
20
|
<br>
|
|
21
21
|
|
|
22
|
-
[How it works](#how-it-works) · [Walkthrough](#end-to-end-walkthrough) · [Features](#features) · [Quick start](#quick-start) · [Config](#configuration) · [Commands](#command-reference) · [Troubleshooting](#troubleshooting)
|
|
22
|
+
[How it works](#how-it-works) · [Walkthrough](#end-to-end-walkthrough) · [Features](#features) · [Quick start](#quick-start) · [.planning](#the-planning-directory) · [Config](#configuration) · [Commands](#command-reference) · [Troubleshooting](#troubleshooting)
|
|
23
23
|
|
|
24
24
|
</div>
|
|
25
25
|
|
|
@@ -250,6 +250,15 @@ Requirements you want but haven't shipped yet are tracked in `PROJECT.md` with o
|
|
|
250
250
|
|
|
251
251
|
---
|
|
252
252
|
|
|
253
|
+
## Prerequisites
|
|
254
|
+
|
|
255
|
+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
|
|
256
|
+
- [Node.js](https://nodejs.org/) (for `npx`)
|
|
257
|
+
- [uv](https://docs.astral.sh/uv/) — Python package runner used by CLI scripts (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
|
|
258
|
+
- Python 3.10+ (used by uv for scripts)
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
253
262
|
## Quick start
|
|
254
263
|
|
|
255
264
|
### New project
|
|
@@ -282,6 +291,103 @@ Codebase mapping produces 7 documents covering your stack, conventions, and arch
|
|
|
282
291
|
|
|
283
292
|
---
|
|
284
293
|
|
|
294
|
+
## The .planning directory
|
|
295
|
+
|
|
296
|
+
Every artifact Mindsystem generates lives in `.planning/` — a markdown knowledge base that grows with your project. Commands read from it, execution enriches it, and it all survives `/clear` boundaries and context resets. Here's what a project looks like after a couple of milestones:
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
.planning/
|
|
300
|
+
├── PROJECT.md # Living spec — vision, users, flows, decisions
|
|
301
|
+
├── MILESTONES.md # Registry of completed milestones
|
|
302
|
+
│
|
|
303
|
+
├── STATE.md # Active phase, blockers, recent decisions
|
|
304
|
+
├── MILESTONE-CONTEXT.md # new-milestone → brainstorm that grounds the roadmap
|
|
305
|
+
├── ROADMAP.md # Phase breakdown with goals and success criteria
|
|
306
|
+
├── REQUIREMENTS.md # Checkable REQ-IDs mapped to phases
|
|
307
|
+
│
|
|
308
|
+
├── TECH-DEBT.md # Prioritized debt — TD-IDs, severity tiers
|
|
309
|
+
├── config.json # Subsystems, code review tiers, preferences
|
|
310
|
+
│
|
|
311
|
+
├── knowledge/ # Persists across milestones
|
|
312
|
+
│ ├── auth.md # Patterns, decisions, pitfalls per subsystem
|
|
313
|
+
│ ├── api.md # Enriched after every execute and verify cycle
|
|
314
|
+
│ └── ui.md # Future phases load relevant files automatically
|
|
315
|
+
│
|
|
316
|
+
├── codebase/ # /ms:map-codebase → existing repo analysis
|
|
317
|
+
│ ├── STACK.md # Runtime, frameworks, key dependencies
|
|
318
|
+
│ ├── ARCHITECTURE.md # Modules, layers, data flow patterns
|
|
319
|
+
│ ├── STRUCTURE.md # Directory layout and file organization
|
|
320
|
+
│ ├── CONVENTIONS.md # Naming, style, established patterns
|
|
321
|
+
│ ├── TESTING.md # Test framework, coverage, how to add tests
|
|
322
|
+
│ ├── INTEGRATIONS.md # External services and API connections
|
|
323
|
+
│ └── CONCERNS.md # Known issues, areas requiring care
|
|
324
|
+
│
|
|
325
|
+
├── phases/ # Active milestone work
|
|
326
|
+
│ │
|
|
327
|
+
│ ├── 01-auth-foundation/ # ── Fully executed phase ──
|
|
328
|
+
│ │ ├── CONTEXT.md # discuss-phase → locked intent and decisions
|
|
329
|
+
│ │ ├── DESIGN.md # design-phase → exact tokens, layout, interactions
|
|
330
|
+
│ │ ├── RESEARCH.md # research-phase → library picks, patterns, tradeoffs
|
|
331
|
+
│ │ ├── 01-01-PLAN.md # plan-phase → executable prompt, one per budget slice
|
|
332
|
+
│ │ ├── 01-02-PLAN.md #
|
|
333
|
+
│ │ ├── EXECUTION-ORDER.md # plan-phase → wave grouping and dependencies
|
|
334
|
+
│ │ ├── 01-01-SUMMARY.md # execute-phase → what changed, patterns, learnings
|
|
335
|
+
│ │ ├── 01-02-SUMMARY.md #
|
|
336
|
+
│ │ ├── VERIFICATION.md # execute-phase → goal-backward pass/fail
|
|
337
|
+
│ │ ├── UAT.md # verify-work → manual acceptance test results
|
|
338
|
+
│ │ ├── 01-changes.patch # execute-phase → diff of all code changes
|
|
339
|
+
│ │ ├── 01-uat-fixes.patch # verify-work → diff of fixes applied during testing
|
|
340
|
+
│ │ └── mockups/ # design-phase → HTML/CSS design exploration
|
|
341
|
+
│ │ ├── variant-a.html # self-contained mockup
|
|
342
|
+
│ │ ├── variant-b.html # self-contained mockup
|
|
343
|
+
│ │ └── comparison.html # side-by-side view, opens in browser
|
|
344
|
+
│ │
|
|
345
|
+
│ └── 02-payment-flow/ # ── Phase in progress ──
|
|
346
|
+
│ ├── CONTEXT.md # discussed, not yet planned
|
|
347
|
+
│ └── 02-01-PLAN.md # planned, not yet executed
|
|
348
|
+
│
|
|
349
|
+
├── research/ # /ms:research-project → domain ecosystem
|
|
350
|
+
│ ├── STACK.md # Technology recommendations for this domain
|
|
351
|
+
│ ├── ARCHITECTURE.md # Common system structure patterns
|
|
352
|
+
│ ├── FEATURES.md # Feature landscape in this domain
|
|
353
|
+
│ ├── PITFALLS.md # Mistakes to avoid
|
|
354
|
+
│ └── SUMMARY.md # Synthesized findings with roadmap implications
|
|
355
|
+
│
|
|
356
|
+
├── adhoc/ # /ms:adhoc → out-of-pipeline work
|
|
357
|
+
│ └── 2026-01-15-fix-token/
|
|
358
|
+
│ ├── adhoc-01-SUMMARY.md # Execution results and learnings
|
|
359
|
+
│ └── adhoc-01-changes.patch # Code diff
|
|
360
|
+
│
|
|
361
|
+
├── debug/ # /ms:debug → structured investigations
|
|
362
|
+
│ ├── websocket-reconnect.md # Active investigation — survives /clear
|
|
363
|
+
│ └── resolved/
|
|
364
|
+
│ └── race-condition-login.md # Root cause found, fix documented
|
|
365
|
+
│
|
|
366
|
+
├── todos/ # /ms:add-todo → captured work items
|
|
367
|
+
│ ├── 2026-02-01-rate-limiting.md # Pending — priority, estimate, subsystem
|
|
368
|
+
│ └── done/
|
|
369
|
+
│ └── 2026-01-20-header-fix.md # Completed via /ms:adhoc
|
|
370
|
+
│
|
|
371
|
+
└── milestones/ # /ms:complete-milestone → archived history
|
|
372
|
+
└── mvp/
|
|
373
|
+
├── ROADMAP.md # Historical phase breakdown
|
|
374
|
+
├── REQUIREMENTS.md # Final requirement status
|
|
375
|
+
├── PHASE-SUMMARIES.md # Consolidated execution summaries
|
|
376
|
+
├── MILESTONE-AUDIT.md # Requirements coverage, integration check
|
|
377
|
+
├── CONTEXT.md # Original milestone brainstorm
|
|
378
|
+
├── research/ # Archived domain research
|
|
379
|
+
│ └── ...
|
|
380
|
+
└── phases/ # Archived phase artifacts
|
|
381
|
+
└── 01-foundation/
|
|
382
|
+
├── 01-changes.patch # code diffs retained
|
|
383
|
+
└── mockups/ # design mockups retained
|
|
384
|
+
└── ...
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Everything is plain markdown (plus `config.json` and `.patch` diffs). The entire directory is greppable, diffable, and readable by any team member or AI assistant. Phase 1 starts from scratch. Phase 10 starts with everything the project has learned.
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
285
391
|
## Configuration
|
|
286
392
|
|
|
287
393
|
Mindsystem stores project config in `.planning/config.json`. Run `/ms:config` to change these interactively.
|
|
@@ -37,19 +37,15 @@ Grep/Glob for imports, class names, and file patterns related to the research qu
|
|
|
37
37
|
|
|
38
38
|
Read `.planning/codebase/*.md` if they exist (from `/ms:map-codebase`). Extract relevant conventions, stack info, architecture patterns.
|
|
39
39
|
|
|
40
|
-
## 4.
|
|
41
|
-
|
|
42
|
-
Grep `.planning/LEARNINGS.md` for entries matching phase keywords, subsystem, or tech terms. Extract matched entries verbatim.
|
|
43
|
-
|
|
44
|
-
## 5. Prior Phase Summaries
|
|
40
|
+
## 4. Prior Phase Summaries
|
|
45
41
|
|
|
46
42
|
Scan `.planning/phases/*/SUMMARY.md` frontmatter only (first 25 lines) for `tech-stack`, `patterns-established`, `key-decisions` matching the phase domain. Read full summary only for direct matches.
|
|
47
43
|
|
|
48
|
-
##
|
|
44
|
+
## 5. Debug Resolutions
|
|
49
45
|
|
|
50
46
|
Scan `.planning/debug/resolved/*.md` for root causes related to the phase domain.
|
|
51
47
|
|
|
52
|
-
##
|
|
48
|
+
## 6. Adhoc Summaries
|
|
53
49
|
|
|
54
50
|
Scan `.planning/adhoc/*-SUMMARY.md` learnings arrays for relevant entries.
|
|
55
51
|
|
|
@@ -71,7 +67,7 @@ Return as text (not file). Orchestrator reads this for synthesis.
|
|
|
71
67
|
[Pattern name, files, description — how the project already handles similar work]
|
|
72
68
|
|
|
73
69
|
### Relevant Learnings
|
|
74
|
-
[
|
|
70
|
+
[Debug resolutions, adhoc learnings, summary deviations that match]
|
|
75
71
|
|
|
76
72
|
### Reusable Components
|
|
77
73
|
[Existing code that could be extended or reused for this phase]
|
|
@@ -99,7 +95,7 @@ Return as text (not file). Orchestrator reads this for synthesis.
|
|
|
99
95
|
- [ ] All findings include file:line references
|
|
100
96
|
- [ ] Empty sections explicitly noted
|
|
101
97
|
- [ ] Structured output returned (not written to file)
|
|
102
|
-
- [ ]
|
|
98
|
+
- [ ] Debug resolutions and adhoc summaries scanned for relevant entries
|
|
103
99
|
- [ ] Prior summaries checked (frontmatter only)
|
|
104
100
|
- [ ] Debug resolutions checked
|
|
105
101
|
</success_criteria>
|
package/bin/install.js
CHANGED
|
@@ -420,9 +420,9 @@ function generateWrappers(claudeDir) {
|
|
|
420
420
|
fs.mkdirSync(binDir, { recursive: true });
|
|
421
421
|
|
|
422
422
|
const wrappers = {
|
|
423
|
-
'ms-tools': '#!/usr/bin/env bash\nexec uv run "$(dirname "$0")/../mindsystem/scripts/ms-tools.py" "$@"\n',
|
|
423
|
+
'ms-tools': '#!/usr/bin/env bash\n[ -f "$HOME/.local/bin/env" ] && . "$HOME/.local/bin/env"\nexec uv run "$(dirname "$0")/../mindsystem/scripts/ms-tools.py" "$@"\n',
|
|
424
424
|
'ms-lookup': '#!/usr/bin/env bash\nexec "$(dirname "$0")/../mindsystem/scripts/ms-lookup-wrapper.sh" "$@"\n',
|
|
425
|
-
'ms-compare-mockups': '#!/usr/bin/env bash\nexec uv run "$(dirname "$0")/../mindsystem/scripts/compare_mockups.py" "$@"\n',
|
|
425
|
+
'ms-compare-mockups': '#!/usr/bin/env bash\n[ -f "$HOME/.local/bin/env" ] && . "$HOME/.local/bin/env"\nexec uv run "$(dirname "$0")/../mindsystem/scripts/compare_mockups.py" "$@"\n',
|
|
426
426
|
};
|
|
427
427
|
|
|
428
428
|
for (const [name, content] of Object.entries(wrappers)) {
|
|
@@ -444,11 +444,6 @@ function ensurePathHook(claudeDir, isGlobal, configDir) {
|
|
|
444
444
|
if (!Array.isArray(settings.hooks.SessionStart))
|
|
445
445
|
settings.hooks.SessionStart = [];
|
|
446
446
|
|
|
447
|
-
// Idempotent — skip if already present
|
|
448
|
-
const marker = 'mindsystem/bin';
|
|
449
|
-
if (settings.hooks.SessionStart.some(e => JSON.stringify(e).includes(marker)))
|
|
450
|
-
return;
|
|
451
|
-
|
|
452
447
|
// Build PATH expression
|
|
453
448
|
let binExpr;
|
|
454
449
|
if (isGlobal) {
|
|
@@ -459,6 +454,14 @@ function ensurePathHook(claudeDir, isGlobal, configDir) {
|
|
|
459
454
|
binExpr = '$CLAUDE_PROJECT_DIR/.claude/bin';
|
|
460
455
|
}
|
|
461
456
|
|
|
457
|
+
// Self-healing: remove all existing Mindsystem PATH hooks, then add exactly one.
|
|
458
|
+
// This deduplicates any prior entries AND prevents future duplicates.
|
|
459
|
+
const before = settings.hooks.SessionStart.length;
|
|
460
|
+
settings.hooks.SessionStart = settings.hooks.SessionStart.filter(
|
|
461
|
+
e => !JSON.stringify(e).includes('CLAUDE_ENV_FILE')
|
|
462
|
+
);
|
|
463
|
+
const removed = before - settings.hooks.SessionStart.length;
|
|
464
|
+
|
|
462
465
|
settings.hooks.SessionStart.push({
|
|
463
466
|
matcher: '',
|
|
464
467
|
hooks: [{
|
|
@@ -468,7 +471,11 @@ function ensurePathHook(claudeDir, isGlobal, configDir) {
|
|
|
468
471
|
});
|
|
469
472
|
|
|
470
473
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
471
|
-
|
|
474
|
+
if (removed > 0) {
|
|
475
|
+
console.log(` ${green}✓${reset} Configured PATH hook (cleaned ${removed} duplicate(s))`);
|
|
476
|
+
} else {
|
|
477
|
+
console.log(` ${green}✓${reset} Configured PATH hook`);
|
|
478
|
+
}
|
|
472
479
|
}
|
|
473
480
|
|
|
474
481
|
/**
|
|
@@ -654,6 +661,20 @@ async function install(isGlobal) {
|
|
|
654
661
|
}
|
|
655
662
|
}
|
|
656
663
|
|
|
664
|
+
// Phase 8b: Check uv
|
|
665
|
+
try {
|
|
666
|
+
const { execSync } = require('child_process');
|
|
667
|
+
const uvVersion = execSync('uv --version 2>&1', { encoding: 'utf8' }).trim();
|
|
668
|
+
console.log(` ${green}✓${reset} Found ${uvVersion}`);
|
|
669
|
+
} catch (e) {
|
|
670
|
+
const isWin = process.platform === 'win32';
|
|
671
|
+
const installCmd = isWin
|
|
672
|
+
? 'powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"'
|
|
673
|
+
: 'curl -LsSf https://astral.sh/uv/install.sh | sh';
|
|
674
|
+
console.log(` ${yellow}⚠${reset} uv not found — CLI wrappers (ms-tools, ms-compare-mockups) require it`);
|
|
675
|
+
console.log(` Install: ${cyan}${installCmd}${reset}`);
|
|
676
|
+
}
|
|
677
|
+
|
|
657
678
|
// Phase 9: Cleanup orphaned files
|
|
658
679
|
if (orphans.length > 0) {
|
|
659
680
|
console.log('');
|
package/commands/ms/doctor.md
CHANGED
|
@@ -13,7 +13,7 @@ allowed-tools:
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
<objective>
|
|
16
|
-
Run health checks on project configuration. Detect and fix structural drift across 10 categories: subsystem vocabulary, milestone directory structure, milestone naming convention, phase archival, knowledge files, phase summaries, PLAN cleanup, CLI wrappers, research API keys, and Mindsystem version.
|
|
16
|
+
Run health checks on project configuration. Detect and fix structural drift across 10 categories: subsystem vocabulary, milestone directory structure, milestone naming convention, phase archival, knowledge files, phase summaries, PLAN cleanup, CLI wrappers and environment diagnostics, research API keys, and Mindsystem version.
|
|
17
17
|
|
|
18
18
|
Idempotent.
|
|
19
19
|
</objective>
|
|
@@ -117,7 +117,7 @@ Display results as a markdown table:
|
|
|
117
117
|
| Knowledge files | FAIL | Directory missing |
|
|
118
118
|
| Phase summaries | FAIL | 2 milestones missing summaries |
|
|
119
119
|
| PLAN cleanup | FAIL | 9 leftover PLAN.md files |
|
|
120
|
-
| CLI wrappers | FAIL |
|
|
120
|
+
| CLI wrappers | FAIL | Not resolvable; bin dir not in PATH |
|
|
121
121
|
| Research API Keys | WARN | PERPLEXITY_API_KEY not set |
|
|
122
122
|
| Mindsystem version | WARN | v3.21.0 → v3.22.1 available |
|
|
123
123
|
```
|
|
@@ -143,7 +143,7 @@ If "Review each" → use AskUserQuestion for each failed check with its details
|
|
|
143
143
|
|
|
144
144
|
Apply fixes in dependency order: fix_subsystems → fix_milestone_dirs → fix_milestone_naming → fix_phase_archival → fix_plan_cleanup → fix_knowledge. Skip any fix whose check passed or was skipped by user.
|
|
145
145
|
|
|
146
|
-
Phase summaries are resolved by fix_phase_archival. CLI
|
|
146
|
+
Phase summaries are resolved by fix_phase_archival. CLI wrapper failures have specific fixes: bin dir not in PATH → restart Claude Code session; missing wrappers or bin dir → re-run `npx mindsystem-cc`; uv not found → `curl -LsSf https://astral.sh/uv/install.sh | sh`. WARN checks (Research API Keys, missing uv) are informational — no automated fix, only displayed in the report.
|
|
147
147
|
</step>
|
|
148
148
|
|
|
149
149
|
<step name="apply_fixes">
|
package/package.json
CHANGED
package/scripts/ms-tools.py
CHANGED
|
@@ -761,19 +761,67 @@ def cmd_doctor_scan(args: argparse.Namespace) -> None:
|
|
|
761
761
|
record("PASS", "PLAN Cleanup")
|
|
762
762
|
print()
|
|
763
763
|
|
|
764
|
-
# ---- CHECK 7: CLI Wrappers ----
|
|
764
|
+
# ---- CHECK 7: CLI Wrappers & Environment ----
|
|
765
765
|
print("=== CLI Wrappers ===")
|
|
766
766
|
wrapper_names = ["ms-tools", "ms-lookup", "ms-compare-mockups"]
|
|
767
|
-
|
|
768
|
-
|
|
767
|
+
|
|
768
|
+
# 7a: Check bin directory exists
|
|
769
|
+
global_bin = Path.home() / ".claude" / "bin"
|
|
770
|
+
local_bin = Path(".claude") / "bin"
|
|
771
|
+
bin_dir = global_bin if global_bin.is_dir() else (local_bin if local_bin.is_dir() else None)
|
|
772
|
+
|
|
773
|
+
if bin_dir is None:
|
|
769
774
|
print("Status: FAIL")
|
|
770
|
-
print(
|
|
771
|
-
print("Fix: re-run `npx mindsystem-cc` to
|
|
775
|
+
print("Bin directory not found (~/.claude/bin/ or .claude/bin/)")
|
|
776
|
+
print("Fix: re-run `npx mindsystem-cc` to generate wrappers")
|
|
772
777
|
record("FAIL", "CLI Wrappers")
|
|
773
778
|
else:
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
779
|
+
# 7b: Check wrapper files present
|
|
780
|
+
missing_files = [w for w in wrapper_names if not (bin_dir / w).exists()]
|
|
781
|
+
if missing_files:
|
|
782
|
+
print("Status: FAIL")
|
|
783
|
+
print(f"Wrapper files missing from {bin_dir}: {', '.join(missing_files)}")
|
|
784
|
+
print("Fix: re-run `npx mindsystem-cc` to regenerate wrappers")
|
|
785
|
+
record("FAIL", "CLI Wrappers")
|
|
786
|
+
else:
|
|
787
|
+
# 7c: Check bin dir in PATH
|
|
788
|
+
path_dirs = os.environ.get("PATH", "").split(os.pathsep)
|
|
789
|
+
bin_in_path = str(bin_dir.resolve()) in [os.path.realpath(p) for p in path_dirs]
|
|
790
|
+
|
|
791
|
+
# 7d: Check wrappers resolvable
|
|
792
|
+
missing_wrappers = [w for w in wrapper_names if shutil.which(w) is None]
|
|
793
|
+
|
|
794
|
+
if missing_wrappers:
|
|
795
|
+
print("Status: FAIL")
|
|
796
|
+
print(f"Not resolvable: {', '.join(missing_wrappers)}")
|
|
797
|
+
if not bin_in_path:
|
|
798
|
+
print(f"Cause: {bin_dir} not in PATH")
|
|
799
|
+
print("Fix: restart Claude Code session (PATH hook fires on SessionStart)")
|
|
800
|
+
else:
|
|
801
|
+
print("Fix: re-run `npx mindsystem-cc` to regenerate wrappers and PATH hook")
|
|
802
|
+
record("FAIL", "CLI Wrappers")
|
|
803
|
+
else:
|
|
804
|
+
print(f"All {len(wrapper_names)} CLI wrappers found on PATH")
|
|
805
|
+
|
|
806
|
+
# 7e: Check uv available
|
|
807
|
+
uv_ok = shutil.which("uv") is not None
|
|
808
|
+
# 7f: Check Python available
|
|
809
|
+
py_ok = shutil.which("python3") is not None or shutil.which("python") is not None
|
|
810
|
+
|
|
811
|
+
issues = []
|
|
812
|
+
if not uv_ok:
|
|
813
|
+
issues.append("uv not found — install: `curl -LsSf https://astral.sh/uv/install.sh | sh`")
|
|
814
|
+
if not py_ok:
|
|
815
|
+
issues.append("Python not found — install Python 3.10+")
|
|
816
|
+
|
|
817
|
+
if issues:
|
|
818
|
+
print("Status: WARN")
|
|
819
|
+
for issue in issues:
|
|
820
|
+
print(f" {issue}")
|
|
821
|
+
record("WARN", "CLI Wrappers")
|
|
822
|
+
else:
|
|
823
|
+
print("Status: PASS")
|
|
824
|
+
record("PASS", "CLI Wrappers")
|
|
777
825
|
print()
|
|
778
826
|
|
|
779
827
|
# ---- CHECK 8: Milestone Naming Convention ----
|