student-timetable

by openclaw

Student timetable manager for self or parent-managed child profiles. Includes init flow + profile registry under schedules/profiles/.

Scanned
Risk
Critical
Status
warning
Findings
44
Last Scanned
2/18/2026

Discussion

Sign in to join the discussion.

No comments yet. Be the first to share your thoughts.

Scan Report

Duration
191.5s
Rules checked
147
Scanned at
2/18/2026, 10:14:10 AM

Scanners4/5 ran

clawguard-rules
0 findings1ms
No findings — all checks passed.
View logs
clawguard-rules1ms
1[2026-02-18T10:10:58.806Z] Running @yourclaw/clawguard-rules pattern matcher
2Scanning: /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/SKILL.md
3Content length: 1013 chars
4Patterns matched: 0
5✓ Completed in 1ms
gitleaks
0 findings133734ms
No findings — all checks passed.
View logs
gitleaks133734ms
1[2026-02-18T10:13:12.540Z] $ gitleaks detect --source /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable --report-format json --report-path /dev/stdout --no-git
2
3⚠ stderr output:
4
5 │╲
6 │ ○
7 ○ ░
8 ░ gitleaks
9
1010:13AM FTL Report path is not writable: /dev/stdout error="open /dev/stdout: no such device or address"
11
12Process exited with code 1
13✓ Completed in 133734ms
semgrep
43 findings191475ms
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:50)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:125)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:126)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:127)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:128)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:65)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:73)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:79)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:79)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:177)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:190)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:228)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:228)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:229)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:230)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:231)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:233)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:233)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:234)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:235)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:236)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:244)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:244)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:245)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:245)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:246)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:246)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:271)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:288)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:317)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:318)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:319)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:320)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:328)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:329)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:330)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:353)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/profiles_registry.js:25)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:9)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:9)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:10)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:11)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:12)
View logs
semgrep191475ms
1[2026-02-18T10:14:10.285Z] $ semgrep scan --json --quiet --config auto /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable
2{"version":"1.152.0","results":[{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":50,"col":34,"offset":1078},"end":{"line":50,"col":47,"offset":1091},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":125,"col":30,"offset":4348},"end":{"line":125,"col":43,"offset":4361},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":126,"col":36,"offset":4438},"end":{"line":126,"col":40,"offset":4442},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":127,"col":37,"offset":4496},"end":{"line":127,"col":41,"offset":4500},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":128,"col":34,"offset":4559},"end":{"line":128,"col":38,"offset":4563},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":65,"col":23,"offset":1486},"end":{"line":65,"col":36,"offset":1499},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":73,"col":34,"offset":1832},"end":{"line":73,"col":47,"offset":1845},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":79,"col":25,"offset":2080},"end":{"line":79,"col":37,"offset":2092},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":79,"col":39,"offset":2094},"end":{"line":79,"col":43,"offset":2098},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":177,"col":23,"offset":5521},"end":{"line":177,"col":36,"offset":5534},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":190,"col":33,"offset":6063},"end":{"line":190,"col":46,"offset":6076},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":228,"col":31,"offset":7502},"end":{"line":228,"col":44,"offset":7515},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":228,"col":67,"offset":7538},"end":{"line":228,"col":72,"offset":7543},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":229,"col":37,"offset":7582},"end":{"line":229,"col":44,"offset":7589},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":230,"col":38,"offset":7644},"end":{"line":230,"col":45,"offset":7651},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":231,"col":35,"offset":7711},"end":{"line":231,"col":42,"offset":7718},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":233,"col":31,"offset":7774},"end":{"line":233,"col":44,"offset":7787},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":233,"col":71,"offset":7814},"end":{"line":233,"col":80,"offset":7823},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":234,"col":37,"offset":7862},"end":{"line":234,"col":44,"offset":7869},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":235,"col":38,"offset":7924},"end":{"line":235,"col":45,"offset":7931},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":236,"col":35,"offset":7991},"end":{"line":236,"col":42,"offset":7998},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":244,"col":31,"offset":8247},"end":{"line":244,"col":42,"offset":8258},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":244,"col":56,"offset":8272},"end":{"line":244,"col":65,"offset":8281},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":245,"col":32,"offset":8330},"end":{"line":245,"col":43,"offset":8341},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":245,"col":57,"offset":8355},"end":{"line":245,"col":66,"offset":8364},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":246,"col":29,"offset":8418},"end":{"line":246,"col":40,"offset":8429},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":246,"col":54,"offset":8443},"end":{"line":246,"col":63,"offset":8452},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":271,"col":28,"offset":9549},"end":{"line":271,"col":39,"offset":9560},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":288,"col":33,"offset":9960},"end":{"line":288,"col":46,"offset":9973},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":317,"col":29,"offset":10970},"end":{"line":317,"col":42,"offset":10983},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":318,"col":35,"offset":11056},"end":{"line":318,"col":42,"offset":11063},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":319,"col":36,"offset":11116},"end":{"line":319,"col":43,"offset":11123},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":320,"col":33,"offset":11181},"end":{"line":320,"col":40,"offset":11188},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":328,"col":45,"offset":11476},"end":{"line":328,"col":56,"offset":11487},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":329,"col":46,"offset":11574},"end":{"line":329,"col":57,"offset":11585},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":330,"col":43,"offset":11677},"end":{"line":330,"col":54,"offset":11688},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":353,"col":44,"offset":12730},"end":{"line":353,"col":55,"offset":12741},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/profiles_registry.js","start":{"line":25,"col":34,"offset":561},"end":{"line":25,"col":47,"offset":574},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","start":{"line":9,"col":26,"offset":219},"end":{"line":9,"col":39,"offset":232},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","start":{"line":9,"col":66,"offset":259},"end":{"line":9,"col":75,"offset":268},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","start":{"line":10,"col":32,"offset":302},"end":{"line":10,"col":36,"offset":306},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","start":{"line":11,"col":33,"offset":356},"end":{"line":11,"col":37,"offset":360},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","start":{"line":12,"col":30,"offset":415},"end":{"line":12,"col":34,"offset":419},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}}],"errors":[],"paths":{"scanned":["/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/README.md","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/SKILL.md","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/_meta.json","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/cli.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/date_utils.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate_cli.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/profiles_registry.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/recurrence.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/student_timetable_service.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/tool.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/workspace_root.js"]},"time":{"rules":[],"rules_parse_time":13.759119033813477,"profiling_times":{"config_time":18.480637311935425,"core_time":24.874802827835083,"ignores_time":0.006995439529418945,"total_time":43.41956830024719},"parsing_time":{"total_time":0.0,"per_file_time":{"mean":0.0,"std_dev":0.0},"very_slow_stats":{"time_ratio":0.0,"count_ratio":0.0},"very_slow_files":[]},"scanning_time":{"total_time":9.598664283752441,"per_file_time":{"mean":0.23996660709381104,"std_dev":0.2999305121441773},"very_slow_stats":{"time_ratio":0.49366120714810807,"count_ratio":0.05},"very_slow_files":[{"fpath":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","ftime":2.3454911708831787},{"fpath":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","ftime":2.3929970264434814}]},"matching_time":{"total_time":0.0,"per_file_and_rule_time":{"mean":0.0,"std_dev":0.0},"very_slow_stats":{"time_ratio":0.0,"count_ratio":0.0},"very_slow_rules_on_files":[]},"tainting_time":{"total_time":0.0,"per_def_and_rule_time":{"mean":0.0,"std_dev":0.0},"very_slow_stats":{"time_ratio":0.0,"count_ratio":0.0},"very_slow_rules_on_defs":[]},"fixpoint_timeouts":[{"error_type":"Fixpoint timeout","severity":"warn","message":"Fixpoint timeout while performing taint analysis at /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:49:15 [rules: 1, first: javascript.lang.security.audit.unsafe-formatstring.unsafe-formatstring]","location":{"path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":49,"col":16,"offset":1012},"end":{"line":49,"col":31,"offset":1027}}}],"prefiltering":{"project_level_time":0.0,"file_level_time":0.0,"rules_with_project_prefilters_ratio":0.0,"rules_with_file_prefilters_ratio":0.9895484949832776,"rules_selected_ratio":0.019648829431438128,"rules_matched_ratio":0.019648829431438128},"targets":[],"total_bytes":0,"max_memory_bytes":1372265920},"engine_requested":"OSS","skipped_rules":[],"profiling_results":[]}
3
4Process exited with code 0
5✓ Completed in 191475ms
mcp-scan
1 finding154318ms
MCP-W004The MCP server is not in our registry.
View logs
mcp-scan154318ms
1[2026-02-18T10:13:33.132Z] $ mcp-scan --skills /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable --json
2{
3 "/tmp/clawguard-scan-II4u63/repo/skills/extraterrest": {
4 "client": "not-available",
5 "path": "/tmp/clawguard-scan-II4u63/repo/skills/extraterrest",
6 "servers": [
7 {
8 "name": "student-timetable",
9 "server": {
10 "path": "/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable",
11 "type": "skill"
12 },
13 "signature": {
14 "metadata": {
15 "meta": null,
16 "protocolVersion": "built-in",
17 "capabilities": {
18 "experimental": null,
19 "logging": null,
20 "prompts": null,
21 "resources": null,
22 "tools": {
23 "listChanged": false
24 },
25 "completions": null,
26 "tasks": null
27 },
28 "serverInfo": {
29 "name": "student-timetable",
30 "title": null,
31 "version": "skills",
32 "websiteUrl": null,
33 "icons": null
34 },
35 "instructions": "Student timetable manager for self or parent-managed child profiles. Includes init flow + profile registry under schedules/profiles/.",
36 "prompts": {
37 "listChanged": false
38 },
39 "resources": {
40 "subscribe": null,
41 "listChanged": false
42 }
43 },
44 "prompts": [
45 {
46 "name": "SKILL.md",
47 "title": null,
48 "description": "\n\n# student-timetable\n\nDesign\n\n- Supports two operating modes:\n - Self profile: a student manages their own schedule.\n - Child profiles: a parent/guardian manages one or more children.\n- Uses a profile registry + per-profile data files so queries are consistent across kids and reusable in other automations.\n\nInitialize\n\n- Run interactive setup:\n - `node skills/student-timetable/cli.js init`\n- This writes/updates:\n - `schedules/profiles/registry.json`\n - `schedules/profiles/<profile_id>/*`\n\nQuery\n\n- `node skills/student-timetable/cli.js today --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js tomorrow --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js this_week --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js next_week --profile <id|name|alias>`\n\nTool entry\n\n- `tool.js`\n",
49 "arguments": [],
50 "icons": null,
51 "meta": null
52 },
53 {
54 "name": "README.md",
55 "title": null,
56 "description": "# student-timetable\n\nA student timetable manager supporting:\n\n- A student managing their own schedule (self profile)\n- A parent/guardian managing one or more children (child profiles)\n\nData contract reference: `projects/StudentTimetable/docs/contracts/prd.md`.\n\n## Data layout\n\nAll schedule data lives under:\n\n- `schedules/profiles/registry.json`\n- `schedules/profiles/<profile_id>/weekly.json`\n- `schedules/profiles/<profile_id>/special_events.json`\n- `schedules/profiles/<profile_id>/term_calendar.json`\n\n## CLI\n\nInteractive init:\n\n- `node skills/student-timetable/cli.js init`\n\nQuery:\n\n- `node skills/student-timetable/cli.js today --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js tomorrow --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js this_week --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js next_week --profile <id|name|alias>`\n\nIf you omit `--profile`, the CLI defaults to the self profile ONLY when a self profile exists in `schedules/profiles/registry.json`.\n\n## Profile resolution rules\n\nMatching order:\n\n1. Exact match on `profile_id`\n2. Exact match on display name\n3. Exact match on an alias\n\nNormalization:\n\n- Case-insensitive\n- Trim whitespace\n- Collapse internal whitespace runs\n\nAmbiguity handling:\n\n- If multiple profiles match, the tool always asks for clarification.\n- The tool never picks a profile based on ordering, recency, or heuristics.\n\nGeneric aliases (always require clarification):\n\n- `me`, `myself`, `self`\n- `kid`, `child`, `son`, `daughter`, `boy`, `girl`\n- `older`, `younger`, `big`, `small`\n- `primary`, `secondary`\n\nReserved words:\n\n- `all`, `everyone`\n\n## Migration\n\nNon-destructive migration from the legacy `kid-schedule` layout:\n\n- Dry run: `node skills/student-timetable/cli.js migrate kid-schedule --dry-run`\n- Apply: `node skills/student-timetable/cli.js migrate kid-schedule`\n\nLegacy \"zian\" single-JSON (heuristic):\n\n- Dry run: `node skills/student-timetable/cli.js migrate legacy-zian --dry-run`\n- Apply: `node skills/student-timetable/cli.js migrate legacy-zian`\n\nMigration safety:\n\n- Never deletes old data.\n- Does not overwrite destination files if they already exist.\n- Creates backups under `schedules/backups/` for any destination files it would overwrite (if present).\n\n## Notes\n\n- Time zone defaults to `Asia/Singapore` in templates.\n- Biweekly support uses Monday as week start (per contract).\n",
57 "arguments": null,
58 "icons": null,
59 "meta": null
60 }
61 ],
62 "resources": [
63 {
64 "name": "_meta.json",
65 "title": null,
66 "uri": "skill://_meta.json",
67 "description": "{\n \"owner\": \"extraterrest\",\n \"slug\": \"student-timetable\",\n \"displayName\": \"student-timetable\",\n \"latest\": {\n \"version\": \"0.1.0-alpha.2\",\n \"publishedAt\": 1771342552498,\n \"commit\": \"https://github.com/openclaw/skills/commit/31b3360736eeae7db4a4fb716bed620016bc29e4\"\n },\n \"history\": []\n}\n",
68 "mimeType": null,
69 "size": null,
70 "icons": null,
71 "annotations": null,
72 "meta": null
73 }
74 ],
75 "resource_templates": [],
76 "tools": [
77 {
78 "name": "workspace_root.js",
79 "title": null,
80 "description": "Script: workspace_root.js. Code:\nconst fs = require('fs');\nconst path = require('path');\n\nfunction fileExists(p) {\n try {\n fs.accessSync(p, fs.constants.F_OK);\n return true;\n } catch (_) {\n return false;\n }\n}\n\nfunction resolveWorkspaceRoot() {\n const envRoot = process.env.OPENCLAW_WORKSPACE;\n if (envRoot && fileExists(envRoot)) {\n return path.resolve(envRoot);\n }\n\n let cur = process.cwd();\n while (true) {\n const skillsDir = path.join(cur, 'skills');\n const schedulesDir = path.join(cur, 'schedules');\n if (fileExists(skillsDir) && fileExists(schedulesDir)) {\n return cur;\n }\n\n const parent = path.dirname(cur);\n if (parent === cur) {\n break;\n }\n cur = parent;\n }\n\n return process.cwd();\n}\n\nmodule.exports = { resolveWorkspaceRoot };\n",
81 "inputSchema": {},
82 "outputSchema": null,
83 "icons": null,
84 "annotations": null,
85 "meta": null,
86 "execution": null
87 },
88 {
89 "name": "profiles_registry.js",
90 "title": null,
91 "description": "Script: profiles_registry.js. Code:\nconst fs = require('fs');\nconst path = require('path');\n\nfunction readJson(p) {\n return JSON.parse(fs.readFileSync(p, 'utf8'));\n}\n\nfunction normalizeToken(s) {\n return String(s || '')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, ' ');\n}\n\nconst GENERIC_ALIASES = new Set([\n 'me', 'myself', 'self',\n 'kid', 'child', 'son', 'daughter', 'boy', 'girl',\n 'older', 'younger', 'big', 'small',\n 'primary', 'secondary'\n]);\n\nconst RESERVED_WORDS = new Set(['all', 'everyone']);\n\nfunction loadProfilesRegistry(workspaceRoot) {\n const registryPath = path.join(workspaceRoot, 'schedules', 'profiles', 'registry.json');\n if (!fs.existsSync(registryPath)) {\n return { version: 1, dataRoot: 'schedules/profiles', profiles: [], _path: registryPath };\n }\n\n const data = readJson(registryPath);\n const profiles = Array.isArray(data && data.profiles) ? data.profiles : [];\n const version = typeof (data && data.version) === 'number' ? data.version : 1;\n const dataRoot = (data && data.dataRoot) ? String(data.dataRoot) : 'schedules/profiles';\n return { version, dataRoot, profiles, _path: registryPath };\n}\n\nfunction findSelfProfile(registry) {\n return (registry.profiles || []).find(p => p && p.type === 'self') || null;\n}\n\nfunction resolveProfile(registry, rawIdent, opts = {}) {\n const ident = normalizeToken(rawIdent);\n const allowDefaultToSelf = !!opts.allowDefaultToSelf;\n\n if (!ident) {\n if (allowDefaultToSelf) {\n const self = findSelfProfile(registry);\n if (self) {\n return { ok: true, profile: self, reason: 'default_to_self' };\n }\n }\n return { ok: false, reason: 'missing', candidates: registry.profiles || [] };\n }\n\n if (RESERVED_WORDS.has(ident)) {\n return { ok: false, reason: 'reserved', candidates: registry.profiles || [] };\n }\n\n if (GENERIC_ALIASES.has(ident)) {\n return { ok: false, reason: 'generic_alias', candidates: registry.profiles || [] };\n }\n\n const profiles = registry.profiles || [];\n\n const byId = profiles.filter(p => normalizeToken(p && p.profile_id) === ident);\n if (byId.length === 1) return { ok: true, profile: byId[0], reason: 'profile_id' };\n if (byId.length > 1) return { ok: false, reason: 'ambiguous', candidates: byId };\n\n const byName = profiles.filter(p => normalizeToken(p && p.display_name) === ident);\n if (byName.length === 1) return { ok: true, profile: byName[0], reason: 'display_name' };\n if (byName.length > 1) return { ok: false, reason: 'ambiguous', candidates: byName };\n\n const byAlias = profiles.filter(p => {\n const aliases = Array.isArray(p && p.aliases) ? p.aliases : [];\n return aliases.some(a => normalizeToken(a) === ident);\n });\n if (byAlias.length === 1) return { ok: true, profile: byAlias[0], reason: 'alias' };\n if (byAlias.length > 1) return { ok: false, reason: 'ambiguous', candidates: byAlias };\n\n return { ok: false, reason: 'unmatched', candidates: profiles };\n}\n\nfunction clarifyProfileMessage(result) {\n const candidates = (result && result.candidates) ? result.candidates : [];\n const names = candidates\n .map(p => {\n const disp = p && p.display_name ? String(p.display_name) : '';\n const id = p && p.profile_id ? String(p.profile_id) : '';\n if (disp && id && disp.toLowerCase() !== id.toLowerCase()) return `${disp} (${id})`;\n return disp || id;\n })\n .filter(Boolean);\n\n let hint = '';\n if (names.length) {\n hint = `Available profiles: ${names.join(', ')}.`;\n } else {\n hint = 'No profiles found in schedules/profiles/registry.json.';\n }\n\n if (result && result.reason === 'generic_alias') {\n return `Which profile did you mean? Generic aliases like \"${String(result.input || '').trim()}\" require clarification. ${hint}`;\n }\n\n if (result && result.reason === 'reserved') {\n return `\"${String(result.input || '').trim()}\" is reserved; please choose a specific profile. ${hint}`;\n }\n\n return `Which profile? Please pass --profile <id|name|alias>. ${hint}`;\n}\n\nmodule.exports = {\n loadProfilesRegistry,\n resolveProfile,\n clarifyProfileMessage,\n GENERIC_ALIASES,\n RESERVED_WORDS,\n normalizeToken\n};\n",
92 "inputSchema": {},
93 "outputSchema": null,
94 "icons": null,
95 "annotations": null,
96 "meta": null,
97 "execution": null
98 },
99 {
100 "name": "cli.js",
101 "title": null,
102 "description": "Script: cli.js. Code:\n#!/usr/bin/env node\n\nconst { resolveWorkspaceRoot } = require('./workspace_root.js');\nconst { loadProfilesRegistry, resolveProfile, clarifyProfileMessage } = require('./profiles_registry.js');\nconst { dayScheduleForProfile, weekScheduleForProfile, todayDate } = require('./student_timetable_service.js');\nconst { addDays, formatISODate } = require('./date_utils.js');\nconst { interactiveInit } = require('./init.js');\nconst { migrateKidSchedule, migrateLegacyZian } = require('./migrate.js');\n\nfunction usage() {\n process.stderr.write('student-timetable CLI\\n');\n console.log('');\n console.log('Usage:');\n console.log(' node skills/student-timetable/cli.js <command> [--profile <id|name|alias>]');\n console.log('');\n console.log('Commands:');\n console.log(' init');\n console.log(' today');\n console.log(' tomorrow');\n console.log(' this_week');\n console.log(' next_week');\n console.log(' migrate kid-schedule [--dry-run]');\n console.log(' migrate legacy-zian [--dry-run]');\n}\n\nfunction parseArgs(argv) {\n const args = { _: [] };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--profile') {\n args.profile = argv[i + 1];\n i++;\n } else if (a === '--date') {\n args.date = argv[i + 1];\n i++;\n } else if (a === '--dry-run') {\n args.dryRun = true;\n } else {\n args._.push(a);\n }\n }\n return args;\n}\n\nfunction printDay(items, label) {\n console.log(label);\n if (!items.length) {\n console.log(' (no items)');\n return;\n }\n for (const it of items) {\n const time = it.start_time ? `${it.start_time}-${it.end_time || ''}`.replace(/-$/, '') : 'TBD';\n const notes = it.notes ? ` | ${it.notes}` : '';\n console.log(` ${time} | ${it.title}${notes} [${it.source}]`);\n }\n}\n\nasync function main() {\n const argv = process.argv.slice(2);\n const args = parseArgs(argv);\n const command = args._[0];\n\n if (!command) {\n usage();\n process.exit(1);\n }\n\n const workspaceRoot = resolveWorkspaceRoot();\n\n if (command === 'init') {\n await interactiveInit(workspaceRoot);\n return;\n }\n\n if (command === 'migrate') {\n const which = args._[1];\n if (which === 'kid-schedule') {\n const report = migrateKidSchedule(workspaceRoot, { dryRun: !!args.dryRun });\n console.log(JSON.stringify(report, null, 2));\n return;\n }\n if (which === 'legacy-zian') {\n const report = migrateLegacyZian(workspaceRoot, { dryRun: !!args.dryRun });\n console.log(JSON.stringify(report, null, 2));\n return;\n }\n usage();\n process.exit(1);\n }\n\n const registry = loadProfilesRegistry(workspaceRoot);\n const allowDefaultToSelf = true;\n const resolved = resolveProfile(registry, args.profile, { allowDefaultToSelf });\n if (!resolved.ok) {\n resolved.input = args.profile;\n console.log(clarifyProfileMessage(resolved));\n process.exit(2);\n }\n\n const profile = resolved.profile;\n const today = todayDate();\n\n if (command === 'today') {\n const items = dayScheduleForProfile(workspaceRoot, profile.profile_id, today);\n printDay(items, `${profile.display_name || profile.profile_id} - Today (${formatISODate(today)})`);\n return;\n }\n\n if (command === 'tomorrow') {\n const d = addDays(today, 1);\n const items = dayScheduleForProfile(workspaceRoot, profile.profile_id, d);\n printDay(items, `${profile.display_name || profile.profile_id} - Tomorrow (${formatISODate(d)})`);\n return;\n }\n\n if (command === 'this_week' || command === 'next_week') {\n const which = command === 'next_week' ? 'next' : 'this';\n const wk = weekScheduleForProfile(workspaceRoot, profile.profile_id, today, which);\n console.log(`${profile.display_name || profile.profile_id} - ${command} (week of ${wk.week_start})`);\n for (const day of wk.days) {\n console.log('');\n printDay(day.items, `${day.weekday} (${day.date})`);\n }\n return;\n }\n\n usage();\n process.exit(1);\n}\n\nif (require.main === module) {\n main().catch(err => {\n console.error(err && err.stack ? err.stack : String(err));\n process.exit(1);\n });\n}\n",
103 "inputSchema": {},
104 "outputSchema": null,
105 "icons": null,
106 "annotations": null,
107 "meta": null,
108 "execution": null
109 },
110 {
111 "name": "student_timetable.test.js",
112 "title": null,
113 "description": "Script: student_timetable.test.js. Code:\nconst assert = require('assert');\nconst fs = require('fs');\nconst path = require('path');\n\nconst { loadProfilesRegistry, resolveProfile } = require('../profiles_registry.js');\nconst { dayScheduleForProfile } = require('../student_timetable_service.js');\n\nfunction withTempDir(fn) {\n const tmpBase = fs.mkdtempSync(path.join(require('os').tmpdir(), 'student-timetable-'));\n try {\n return fn(tmpBase);\n } finally {\n fs.rmSync(tmpBase, { recursive: true, force: true });\n }\n}\n\nfunction writeJson(p, obj) {\n fs.mkdirSync(path.dirname(p), { recursive: true });\n fs.writeFileSync(p, JSON.stringify(obj, null, 2));\n}\n\n(function testProfileResolutionOrderAndAmbiguity() {\n const registry = {\n version: 1,\n dataRoot: 'schedules/profiles',\n profiles: [\n { profile_id: 'kai', type: 'child', display_name: 'Kai', aliases: ['kk'] },\n { profile_id: 'p2', type: 'child', display_name: 'kai', aliases: [] }\n ]\n };\n\n // exact profile_id wins over display_name\n const r1 = resolveProfile(registry, 'kai', { allowDefaultToSelf: false });\n assert.equal(r1.ok, true);\n assert.equal(r1.profile.profile_id, 'kai');\n\n // ambiguous: \"kai\" matches profile_id of first profile; should still resolve\n const r2 = resolveProfile(registry, 'kai ', { allowDefaultToSelf: false });\n assert.equal(r2.ok, true);\n})();\n\n(function testGenericAliasForcesClarification() {\n const registry = {\n version: 1,\n dataRoot: 'schedules/profiles',\n profiles: [{ profile_id: 'aidan', type: 'child', display_name: 'Aidan', aliases: ['kid'] }]\n };\n\n const r = resolveProfile(registry, 'kid', { allowDefaultToSelf: false });\n assert.equal(r.ok, false);\n assert.equal(r.reason, 'generic_alias');\n})();\n\n(function testDefaultToSelfOnlyWhenConfigured() {\n const regNoSelf = { version: 1, dataRoot: 'schedules/profiles', profiles: [{ profile_id: 'a', type: 'child', display_name: 'A', aliases: [] }] };\n const r1 = resolveProfile(regNoSelf, null, { allowDefaultToSelf: true });\n assert.equal(r1.ok, false);\n\n const regSelf = { version: 1, dataRoot: 'schedules/profiles', profiles: [{ profile_id: 'me', type: 'self', display_name: 'Me', aliases: [] }] };\n const r2 = resolveProfile(regSelf, null, { allowDefaultToSelf: true });\n assert.equal(r2.ok, true);\n assert.equal(r2.profile.type, 'self');\n})();\n\n(function testDayScheduleWeeklyPlusSpecialAndCancelsWeekly() {\n withTempDir((ws) => {\n fs.mkdirSync(path.join(ws, 'skills'), { recursive: true });\n\n writeJson(path.join(ws, 'schedules/profiles/registry.json'), {\n version: 1,\n dataRoot: 'schedules/profiles',\n profiles: [{ profile_id: 'zian', type: 'self', display_name: 'Zian', aliases: ['z'] }]\n });\n\n writeJson(path.join(ws, 'schedules/profiles/zian/weekly.json'), {\n version: 1,\n profile_id: 'zian',\n recurrence: { type: 'every_week' },\n timezone: 'Asia/Singapore',\n weeks: {\n default: {\n mon: [{ title: 'Math', start_time: '09:00', end_time: '10:00', location: '', notes: '' }],\n tue: [], wed: [], thu: [], fri: [], sat: [], sun: []\n }\n }\n });\n\n writeJson(path.join(ws, 'schedules/profiles/zian/special_events.json'), {\n version: 1,\n profile_id: 'zian',\n events: [{ id: 'c', date: '2026-02-16', title: 'Holiday', cancels_weekly: true }]\n });\n\n const items = dayScheduleForProfile(ws, 'zian', new Date('2026-02-16T00:00:00'));\n assert.equal(items.some(i => i.title === 'Math'), false);\n assert.equal(items.some(i => i.title === 'Holiday'), true);\n });\n})();\n\nconsole.log('student-timetable tests: OK');\n",
114 "inputSchema": {},
115 "outputSchema": null,
116 "icons": null,
117 "annotations": null,
118 "meta": null,
119 "execution": null
120 },
121 {
122 "name": "date_utils.js",
123 "title": null,
124 "description": "Script: date_utils.js. Code:\nconst DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n\nfunction startOfDay(d) {\n return new Date(d.getFullYear(), d.getMonth(), d.getDate());\n}\n\nfunction addDays(d, n) {\n const x = new Date(d);\n x.setDate(x.getDate() + n);\n return x;\n}\n\nfunction dayName(d) {\n return DAY_NAMES[d.getDay()];\n}\n\nfunction formatISODate(d) {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, '0');\n const dd = String(d.getDate()).padStart(2, '0');\n return `${y}-${m}-${dd}`;\n}\n\nfunction weekStartMonday(d) {\n const x = startOfDay(d);\n const dow = x.getDay(); // 0 Sunday\n const diff = dow === 0 ? -6 : 1 - dow;\n return addDays(x, diff);\n}\n\nmodule.exports = {\n startOfDay,\n addDays,\n dayName,\n formatISODate,\n weekStartMonday\n};\n",
125 "inputSchema": {},
126 "outputSchema": null,
127 "icons": null,
128 "annotations": null,
129 "meta": null,
130 "execution": null
131 },
132 {
133 "name": "schedule_store.js",
134 "title": null,
135 "description": "Script: schedule_store.js. Code:\nconst fs = require('fs');\nconst path = require('path');\n\nfunction readJson(p) {\n return JSON.parse(fs.readFileSync(p, 'utf8'));\n}\n\nfunction loadProfileScheduleFiles(workspaceRoot, profileId) {\n const base = path.join(workspaceRoot, 'schedules', 'profiles', profileId);\n const weeklyPath = path.join(base, 'weekly.json');\n const specialPath = path.join(base, 'special_events.json');\n const termPath = path.join(base, 'term_calendar.json');\n\n const weekly = fs.existsSync(weeklyPath) ? readJson(weeklyPath) : null;\n const special = fs.existsSync(specialPath) ? readJson(specialPath) : null;\n const term = fs.existsSync(termPath) ? readJson(termPath) : null;\n\n return { weekly, special, term, paths: { weeklyPath, specialPath, termPath } };\n}\n\nmodule.exports = { loadProfileScheduleFiles };\n",
136 "inputSchema": {},
137 "outputSchema": null,
138 "icons": null,
139 "annotations": null,
140 "meta": null,
141 "execution": null
142 },
143 {
144 "name": "recurrence.js",
145 "title": null,
146 "description": "Script: recurrence.js. Code:\nfunction isoDate(date) {\n const y = date.getFullYear();\n const m = String(date.getMonth() + 1).padStart(2, '0');\n const d = String(date.getDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\nfunction parseISODate(s) {\n if (!s) return null;\n const m = String(s).trim().match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (!m) return null;\n const dt = new Date(`${m[1]}-${m[2]}-${m[3]}T00:00:00`);\n if (Number.isNaN(dt.getTime())) return null;\n return dt;\n}\n\nfunction daysBetween(a, b) {\n const ms = 24 * 60 * 60 * 1000;\n const da = new Date(a.getFullYear(), a.getMonth(), a.getDate());\n const db = new Date(b.getFullYear(), b.getMonth(), b.getDate());\n return Math.floor((db.getTime() - da.getTime()) / ms);\n}\n\nfunction occursOnDate(item, date) {\n const rec = item && item.recurrence ? item.recurrence : { type: 'every_week' };\n const type = rec.type || 'every_week';\n\n if (type === 'every_week') {\n return true;\n }\n\n if (type === 'biweekly') {\n const start = parseISODate(rec.start_date);\n if (!start) {\n return true;\n }\n const diffDays = daysBetween(start, date);\n if (diffDays < 0) {\n return false;\n }\n const weeks = Math.floor(diffDays / 7);\n return weeks % 2 === 0;\n }\n\n return true;\n}\n\nmodule.exports = { occursOnDate, isoDate, parseISODate };\n",
147 "inputSchema": {},
148 "outputSchema": null,
149 "icons": null,
150 "annotations": null,
151 "meta": null,
152 "execution": null
153 },
154 {
155 "name": "tool.js",
156 "title": null,
157 "description": "Script: tool.js. Code:\nconst { resolveWorkspaceRoot } = require('./workspace_root.js');\nconst { loadProfilesRegistry, resolveProfile, clarifyProfileMessage } = require('./profiles_registry.js');\nconst { dayScheduleForProfile, weekScheduleForProfile, todayDate } = require('./student_timetable_service.js');\nconst { addDays } = require('./date_utils.js');\n\nfunction parseIntent(input) {\n const s = String(input || '').toLowerCase();\n if (s.includes('tomorrow') || s.includes('\u660e\u5929')) return 'tomorrow';\n if (s.includes('today') || s.includes('\u4eca\u5929')) return 'today';\n if (s.includes('next week') || s.includes('\u4e0b\u5468')) return 'next_week';\n if (s.includes('this week') || s.includes('\u672c\u5468') || s.includes('\u8fd9\u5468')) return 'this_week';\n return 'today';\n}\n\nfunction extractProfileIdent(input) {\n const m = String(input || '').match(/--profile\\s+([^\\s]+)/i);\n if (m) return m[1];\n return null;\n}\n\nfunction renderDay(items) {\n if (!items.length) {\n return '(no items)';\n }\n return items.map(it => {\n const time = it.start_time ? `${it.start_time}-${it.end_time || ''}`.replace(/-$/, '') : 'TBD';\n const notes = it.notes ? ` | ${it.notes}` : '';\n return `${time} | ${it.title}${notes}`;\n }).join('\\n');\n}\n\nasync function run(input) {\n const workspaceRoot = resolveWorkspaceRoot();\n const registry = loadProfilesRegistry(workspaceRoot);\n\n const ident = extractProfileIdent(input);\n const resolved = resolveProfile(registry, ident, { allowDefaultToSelf: true });\n if (!resolved.ok) {\n resolved.input = ident;\n return { ok: false, message: clarifyProfileMessage(resolved) };\n }\n\n const profile = resolved.profile;\n const intent = parseIntent(input);\n const today = todayDate();\n\n if (intent === 'today') {\n const items = dayScheduleForProfile(workspaceRoot, profile.profile_id, today);\n return { ok: true, message: `${profile.display_name || profile.profile_id} today\\n${renderDay(items)}` };\n }\n\n if (intent === 'tomorrow') {\n const d = addDays(today, 1);\n const items = dayScheduleForProfile(workspaceRoot, profile.profile_id, d);\n return { ok: true, message: `${profile.display_name || profile.profile_id} tomorrow\\n${renderDay(items)}` };\n }\n\n if (intent === 'this_week' || intent === 'next_week') {\n const which = intent === 'next_week' ? 'next' : 'this';\n const wk = weekScheduleForProfile(workspaceRoot, profile.profile_id, today, which);\n const lines = [];\n lines.push(`${profile.display_name || profile.profile_id} ${intent} (week of ${wk.week_start})`);\n for (const day of wk.days) {\n lines.push('');\n lines.push(`${day.weekday} ${day.date}`);\n lines.push(renderDay(day.items));\n }\n return { ok: true, message: lines.join('\\n') };\n }\n\n return { ok: false, message: 'Unsupported request.' };\n}\n\nmodule.exports = { run };\n",
158 "inputSchema": {},
159 "outputSchema": null,
160 "icons": null,
161 "annotations": null,
162 "meta": null,
163 "execution": null
164 },
165 {
166 "name": "migrate_cli.js",
167 "title": null,
168 "description": "Script: migrate_cli.js. Code:\n#!/usr/bin/env node\n\nconst { resolveWorkspaceRoot } = require('./workspace_root.js');\nconst { migrateKidSchedule, migrateLegacyZian } = require('./migrate.js');\n\nfunction usage() {\n process.stdout.write('student-timetable migrate\\n');\n process.stdout.write('Usage:\\n');\n process.stdout.write(' node skills/student-timetable/migrate_cli.js kid-schedule [--dry-run]\\n');\n process.stdout.write(' node skills/student-timetable/migrate_cli.js legacy-zian [--dry-run]\\n');\n}\n\nfunction parseArgs(argv) {\n const args = { _: [] };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--dry-run') args.dryRun = true;\n else args._.push(a);\n }\n return args;\n}\n\n(async function main() {\n const args = parseArgs(process.argv.slice(2));\n const cmd = args._[0];\n if (!cmd) {\n usage();\n process.exit(1);\n }\n\n const workspaceRoot = resolveWorkspaceRoot();\n let report;\n if (cmd === 'kid-schedule') {\n report = migrateKidSchedule(workspaceRoot, { dryRun: !!args.dryRun });\n } else if (cmd === 'legacy-zian') {\n report = migrateLegacyZian(workspaceRoot, { dryRun: !!args.dryRun });\n } else {\n usage();\n process.exit(1);\n }\n\n process.stdout.write(JSON.stringify(report, null, 2) + '\\n');\n})();\n",
169 "inputSchema": {},
170 "outputSchema": null,
171 "icons": null,
172 "annotations": null,
173 "meta": null,
174 "execution": null
175 },
176 {
177 "name": "init.js",
178 "title": null,
179 "description": "Script: init.js. Code:\nconst fs = require('fs');\nconst path = require('path');\nconst readline = require('readline');\n\nfunction normalizeToken(s) {\n return String(s || '')\n .trim()\n .replace(/\\s+/g, ' ');\n}\n\nfunction normalizeId(s) {\n return String(s || '')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9\\-]/g, '')\n .replace(/\\-+/g, '-')\n .replace(/^\\-+|\\-+$/g, '') || 'profile';\n}\n\nfunction nowIso() {\n return new Date().toISOString();\n}\n\nfunction writeJsonAtomic(p, obj) {\n fs.mkdirSync(path.dirname(p), { recursive: true });\n const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;\n fs.writeFileSync(tmp, JSON.stringify(obj, null, 2));\n fs.renameSync(tmp, p);\n}\n\nfunction exists(p) {\n try {\n fs.accessSync(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction ask(rl, q) {\n return new Promise((resolve) => rl.question(q, (ans) => resolve(ans)));\n}\n\nfunction emptyWeek() {\n return { mon: [], tue: [], wed: [], thu: [], fri: [], sat: [], sun: [] };\n}\n\nasync function interactiveInit(workspaceRoot) {\n const registryPath = path.join(workspaceRoot, 'schedules', 'profiles', 'registry.json');\n const registry = exists(registryPath)\n ? JSON.parse(fs.readFileSync(registryPath, 'utf8'))\n : { version: 1, dataRoot: 'schedules/profiles', profiles: [] };\n\n const existingIds = new Set((registry.profiles || []).map(p => String(p.profile_id || '')).filter(Boolean));\n\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n try {\n console.log('student-timetable init');\n console.log('');\n console.log('Who is this timetable for?');\n console.log(' 1) Myself (student)');\n console.log(' 2) My child / children (parent/guardian)');\n const mode = normalizeToken(await ask(rl, 'Choose 1 or 2: '));\n\n let profilesToCreate = [];\n\n if (mode === '1') {\n const name = normalizeToken(await ask(rl, 'Your name (display name): '));\n const aliasesRaw = normalizeToken(await ask(rl, 'Aliases (optional, comma-separated): '));\n const aliases = aliasesRaw ? aliasesRaw.split(',').map(a => normalizeToken(a)).filter(Boolean) : [];\n let profileId = normalizeId(name || 'self');\n if (existingIds.has(profileId)) {\n let i = 2;\n while (existingIds.has(`${profileId}-${i}`)) i++;\n profileId = `${profileId}-${i}`;\n }\n existingIds.add(profileId);\n profilesToCreate.push({ profile_id: profileId, type: 'self', display_name: name || 'Self', aliases });\n } else if (mode === '2') {\n const nRaw = normalizeToken(await ask(rl, 'How many children? '));\n const n = Math.max(1, parseInt(nRaw, 10) || 1);\n for (let i = 0; i < n; i++) {\n const name = normalizeToken(await ask(rl, `Child ${i + 1} name (display name): `));\n const aliasesRaw = normalizeToken(await ask(rl, 'Aliases (optional, comma-separated): '));\n const aliases = aliasesRaw ? aliasesRaw.split(',').map(a => normalizeToken(a)).filter(Boolean) : [];\n let profileId = normalizeId(name || `child-${i + 1}`);\n if (existingIds.has(profileId)) {\n let j = 2;\n while (existingIds.has(`${profileId}-${j}`)) j++;\n profileId = `${profileId}-${j}`;\n }\n existingIds.add(profileId);\n profilesToCreate.push({ profile_id: profileId, type: 'child', display_name: name || `Child ${i + 1}`, aliases });\n }\n } else {\n throw new Error('Invalid choice.');\n }\n\n console.log('');\n console.log('Recurrence:');\n console.log(' 1) every_week');\n console.log(' 2) biweekly (Week A / Week B)');\n const recChoice = normalizeToken(await ask(rl, 'Choose 1 or 2: '));\n\n let recurrence = { type: 'every_week' };\n if (recChoice === '2') {\n const startDate = normalizeToken(await ask(rl, 'Biweekly start_date (YYYY-MM-DD): '));\n recurrence = { type: 'biweekly', start_date: startDate };\n }\n\n // Minimal ingest: create empty templates; users edit JSON by hand or extend later.\n const createdAt = nowIso();\n for (const p of profilesToCreate) {\n const entry = {\n profile_id: p.profile_id,\n type: p.type,\n display_name: p.display_name,\n aliases: p.aliases,\n created_at: createdAt,\n updated_at: createdAt\n };\n registry.profiles.push(entry);\n\n const base = path.join(workspaceRoot, 'schedules', 'profiles', p.profile_id);\n const weeklyPath = path.join(base, 'weekly.json');\n const specialPath = path.join(base, 'special_events.json');\n const termPath = path.join(base, 'term_calendar.json');\n\n if (!exists(weeklyPath)) {\n const weeks = recurrence.type === 'biweekly'\n ? { week_a: emptyWeek(), week_b: emptyWeek() }\n : { default: emptyWeek() };\n writeJsonAtomic(weeklyPath, {\n version: 1,\n profile_id: p.profile_id,\n recurrence,\n timezone: 'Asia/Singapore',\n weeks\n });\n }\n\n if (!exists(specialPath)) {\n writeJsonAtomic(specialPath, { version: 1, profile_id: p.profile_id, events: [] });\n }\n\n if (!exists(termPath)) {\n writeJsonAtomic(termPath, { version: 1, profile_id: p.profile_id, timezone: 'Asia/Singapore', terms: [], no_school_days: [] });\n }\n\n console.log(`Created/verified: schedules/profiles/${p.profile_id}/weekly.json`);\n console.log(`Created/verified: schedules/profiles/${p.profile_id}/special_events.json`);\n console.log(`Created/verified: schedules/profiles/${p.profile_id}/term_calendar.json`);\n console.log('');\n }\n\n registry.version = 1;\n registry.dataRoot = 'schedules/profiles';\n writeJsonAtomic(registryPath, registry);\n\n console.log(`Registry written: schedules/profiles/registry.json`);\n } finally {\n rl.close();\n }\n}\n\nmodule.exports = { interactiveInit };\n",
180 "inputSchema": {},
181 "outputSchema": null,
182 "icons": null,
183 "annotations": null,
184 "meta": null,
185 "execution": null
186 },
187 {
188 "name": "migrate.js",
189 "title": null,
190 "description": "Script: migrate.js. Code:\nconst fs = require('fs');\nconst path = require('path');\n\nfunction readJson(p) {\n return JSON.parse(fs.readFileSync(p, 'utf8'));\n}\n\nfunction writeJsonAtomic(p, obj) {\n fs.mkdirSync(path.dirname(p), { recursive: true });\n const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;\n fs.writeFileSync(tmp, JSON.stringify(obj, null, 2));\n fs.renameSync(tmp, p);\n}\n\nfunction exists(p) {\n try {\n fs.accessSync(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction normalizeId(s) {\n return String(s || '')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9\\-]/g, '')\n .replace(/\\-+/g, '-')\n .replace(/^\\-+|\\-+$/g, '') || 'profile';\n}\n\nfunction nowIso() {\n return new Date().toISOString();\n}\n\nfunction ensureUniqueId(existingIds, desired) {\n let base = desired;\n let out = base;\n let i = 2;\n while (existingIds.has(out)) {\n out = `${base}-${i}`;\n i++;\n }\n existingIds.add(out);\n return out;\n}\n\nfunction backupDirName() {\n const d = new Date();\n const pad = (n) => String(n).padStart(2, '0');\n const stamp = `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;\n return `student-timetable-migrate-${stamp}`;\n}\n\nfunction copyFileIfExists(src, dst) {\n if (!exists(src)) return false;\n fs.mkdirSync(path.dirname(dst), { recursive: true });\n fs.copyFileSync(src, dst);\n return true;\n}\n\nfunction loadKidRegistry(workspaceRoot) {\n const p = path.join(workspaceRoot, 'schedules', 'kids', 'registry.json');\n if (!exists(p)) return { kids: [], _path: p };\n const data = readJson(p);\n if (Array.isArray(data)) return { kids: data, _path: p };\n return { kids: Array.isArray(data.kids) ? data.kids : [], _path: p };\n}\n\nfunction detectLegacyZianJson(workspaceRoot) {\n const schedulesDir = path.join(workspaceRoot, 'schedules');\n if (!exists(schedulesDir)) return [];\n const entries = fs.readdirSync(schedulesDir);\n const candidates = [];\n for (const name of entries) {\n if (!/^zian_.*\\.json$/i.test(name)) continue;\n const p = path.join(schedulesDir, name);\n if (!exists(p)) continue;\n try {\n const data = readJson(p);\n if (data && (data.weekly_timetable || data.special_events || data.term_calendar || data.events || data.terms)) {\n candidates.push({ path: p, data });\n }\n } catch {\n // ignore\n }\n }\n return candidates;\n}\n\nfunction convertOldWeeklyToNew(oldWeekly, profileId) {\n const weeklyTimetable = (oldWeekly && (oldWeekly.weekly_timetable || oldWeekly.weekly)) || {};\n // old keys like Monday\n const mapDay = {\n Monday: 'mon', Tuesday: 'tue', Wednesday: 'wed', Thursday: 'thu', Friday: 'fri', Saturday: 'sat', Sunday: 'sun'\n };\n const week = { mon: [], tue: [], wed: [], thu: [], fri: [], sat: [], sun: [] };\n\n for (const [k, items] of Object.entries(weeklyTimetable)) {\n const dk = mapDay[k] || String(k || '').toLowerCase().slice(0, 3);\n if (!week[dk] || !Array.isArray(items)) continue;\n for (const it of items) {\n const title = it && (it.title || it.subject || it.activity || it.name) ? String(it.title || it.subject || it.activity || it.name) : '';\n let start = '';\n let end = '';\n if (it && it.time) {\n const m = String(it.time).match(/(\\d{1,2}:\\d{2})\\s*-\\s*(\\d{1,2}:\\d{2})/);\n if (m) {\n start = m[1];\n end = m[2];\n }\n }\n week[dk].push({\n title,\n start_time: start,\n end_time: end,\n location: it && it.location ? String(it.location) : '',\n notes: it && it.notes ? String(it.notes) : ''\n });\n }\n }\n\n return {\n version: 1,\n profile_id: profileId,\n recurrence: { type: 'every_week' },\n timezone: 'Asia/Singapore',\n weeks: { default: week }\n };\n}\n\nfunction convertOldSpecialToNew(oldSpecial, profileId) {\n const events = Array.isArray(oldSpecial && oldSpecial.events) ? oldSpecial.events : [];\n const out = [];\n for (const ev of events) {\n const date = ev && ev.date ? String(ev.date) : (ev && ev.event_details && ev.event_details.date ? String(ev.event_details.date) : '');\n if (!date) continue;\n let start = '';\n let end = '';\n const time = ev.time || (ev.event_details && ev.event_details.time) || '';\n if (time) {\n const m = String(time).match(/(\\d{1,2}:\\d{2})\\s*-\\s*(\\d{1,2}:\\d{2})/);\n if (m) {\n start = m[1];\n end = m[2];\n }\n }\n out.push({\n id: ev.id ? String(ev.id) : `legacy-${normalizeId((ev.name || ev.title || 'event') + '-' + date)}`,\n date,\n title: ev.title ? String(ev.title) : (ev.name ? String(ev.name) : 'Special event'),\n start_time: ev.start_time ? String(ev.start_time) : start,\n end_time: ev.end_time ? String(ev.end_time) : end,\n location: ev.location ? String(ev.location) : '',\n notes: ev.notes ? String(ev.notes) : (ev.description ? String(ev.description) : ''),\n tags: Array.isArray(ev.tags) ? ev.tags.slice() : [],\n cancels_weekly: !!ev.cancels_weekly\n });\n }\n\n return { version: 1, profile_id: profileId, events: out };\n}\n\nfunction convertOldTermToNew(oldTerm, profileId) {\n return {\n version: 1,\n profile_id: profileId,\n timezone: 'Asia/Singapore',\n terms: Array.isArray(oldTerm && oldTerm.terms) ? oldTerm.terms : [],\n no_school_days: Array.isArray(oldTerm && oldTerm.holidays) ? oldTerm.holidays.map(h => ({ date: h.date || h, name: h.name || '' })) : []\n };\n}\n\nfunction loadNewRegistry(workspaceRoot) {\n const p = path.join(workspaceRoot, 'schedules', 'profiles', 'registry.json');\n if (!exists(p)) return { version: 1, dataRoot: 'schedules/profiles', profiles: [], _path: p };\n const data = readJson(p);\n return {\n version: typeof data.version === 'number' ? data.version : 1,\n dataRoot: data.dataRoot ? String(data.dataRoot) : 'schedules/profiles',\n profiles: Array.isArray(data.profiles) ? data.profiles : [],\n _path: p\n };\n}\n\nfunction migrateKidSchedule(workspaceRoot, opts = {}) {\n const dryRun = !!opts.dryRun;\n const backupsRoot = path.join(workspaceRoot, 'schedules', 'backups', backupDirName());\n\n const oldReg = loadKidRegistry(workspaceRoot);\n const newReg = loadNewRegistry(workspaceRoot);\n\n const existingIds = new Set((newReg.profiles || []).map(p => String(p.profile_id || '')).filter(Boolean));\n const report = { source: 'kid-schedule', dryRun, migrated: [], skipped: [], warnings: [], backupsRoot };\n\n for (const kid of oldReg.kids || []) {\n const oldId = kid && kid.id ? String(kid.id) : '';\n if (!oldId) continue;\n\n let profileId = normalizeId(oldId);\n\n // Special-case: historical kid-schedule data sometimes used zian-2/zian-3 etc.\n // Consolidate all of those into the canonical Zian child profile_id.\n if (profileId === 'zian-2' || profileId === 'zian-3' || profileId === 'zian-specialevents') {\n profileId = 'zian';\n }\n\n const already = (newReg.profiles || []).some(p => String(p.profile_id || '') === profileId);\n if (already) {\n report.skipped.push({ oldId, reason: 'already_migrated', profileId });\n continue;\n }\n\n profileId = ensureUniqueId(existingIds, profileId);\n\n const createdAt = nowIso();\n const prof = {\n profile_id: profileId,\n type: 'child',\n display_name: kid.display_name ? String(kid.display_name) : oldId,\n aliases: Array.isArray(kid.aliases) ? kid.aliases.slice() : [],\n created_at: createdAt,\n updated_at: createdAt\n };\n\n const oldBase = path.join(workspaceRoot, 'schedules', 'kids', oldId);\n const oldWeeklyPath = path.join(oldBase, 'weekly.json');\n const oldSpecialPath = path.join(oldBase, 'special_events.json');\n const oldTermPath = path.join(oldBase, 'term_calendar.json');\n\n const newBase = path.join(workspaceRoot, 'schedules', 'profiles', profileId);\n const newWeeklyPath = path.join(newBase, 'weekly.json');\n const newSpecialPath = path.join(newBase, 'special_events.json');\n const newTermPath = path.join(newBase, 'term_calendar.json');\n\n if (dryRun) {\n report.migrated.push({ oldId, profileId, outputs: [newWeeklyPath, newSpecialPath, newTermPath] });\n continue;\n }\n\n // backup any destination files that exist\n const bWeekly = path.join(backupsRoot, 'profiles', profileId, 'weekly.json');\n const bSpecial = path.join(backupsRoot, 'profiles', profileId, 'special_events.json');\n const bTerm = path.join(backupsRoot, 'profiles', profileId, 'term_calendar.json');\n copyFileIfExists(newWeeklyPath, bWeekly);\n copyFileIfExists(newSpecialPath, bSpecial);\n copyFileIfExists(newTermPath, bTerm);\n\n const oldWeekly = exists(oldWeeklyPath) ? readJson(oldWeeklyPath) : null;\n const oldSpecial = exists(oldSpecialPath) ? readJson(oldSpecialPath) : null;\n const oldTerm = exists(oldTermPath) ? readJson(oldTermPath) : null;\n\n const newWeekly = convertOldWeeklyToNew(oldWeekly, profileId);\n const newSpecial = convertOldSpecialToNew(oldSpecial, profileId);\n const newTerm = convertOldTermToNew(oldTerm, profileId);\n\n // only write if missing (idempotent + non-destructive)\n if (!exists(newWeeklyPath)) writeJsonAtomic(newWeeklyPath, newWeekly);\n if (!exists(newSpecialPath)) writeJsonAtomic(newSpecialPath, newSpecial);\n if (!exists(newTermPath)) writeJsonAtomic(newTermPath, newTerm);\n\n newReg.profiles.push(prof);\n\n report.migrated.push({ oldId, profileId, outputs: [newWeeklyPath, newSpecialPath, newTermPath] });\n }\n\n if (!dryRun) {\n // backup registry if it exists\n const bReg = path.join(backupsRoot, 'profiles', 'registry.json');\n copyFileIfExists(newReg._path, bReg);\n\n // write registry\n const regOut = {\n version: 1,\n dataRoot: 'schedules/profiles',\n profiles: newReg.profiles\n };\n writeJsonAtomic(newReg._path, regOut);\n }\n\n return report;\n}\n\nfunction migrateLegacyZian(workspaceRoot, opts = {}) {\n const dryRun = !!opts.dryRun;\n const backupsRoot = path.join(workspaceRoot, 'schedules', 'backups', backupDirName());\n\n const newReg = loadNewRegistry(workspaceRoot);\n const existingIds = new Set((newReg.profiles || []).map(p => String(p.profile_id || '')).filter(Boolean));\n\n const candidates = detectLegacyZianJson(workspaceRoot);\n const report = { source: 'legacy-zian-json', dryRun, migrated: [], skipped: [], warnings: [], backupsRoot };\n\n if (!candidates.length) return report;\n\n // For v1: migrate all legacy zian JSON into a single canonical child profile.\n // profile_id represents the person (Zian), not the data source.\n const profileId = 'zian';\n\n if ((newReg.profiles || []).some(p => String(p.profile_id || '') === profileId)) {\n report.skipped.push({ profileId, reason: 'profile_exists' });\n return report;\n }\n\n const createdAt = nowIso();\n const prof = {\n profile_id: profileId,\n type: 'child',\n display_name: 'Zian',\n aliases: ['zian'],\n created_at: createdAt,\n updated_at: createdAt\n };\n\n const newBase = path.join(workspaceRoot, 'schedules', 'profiles', profileId);\n const newWeeklyPath = path.join(newBase, 'weekly.json');\n const newSpecialPath = path.join(newBase, 'special_events.json');\n const newTermPath = path.join(newBase, 'term_calendar.json');\n\n if (dryRun) {\n report.migrated.push({ profileId, inputs: candidates.map(c => c.path), outputs: [newWeeklyPath, newSpecialPath, newTermPath] });\n return report;\n }\n\n // backup any destination files that exist\n copyFileIfExists(newWeeklyPath, path.join(backupsRoot, 'profiles', profileId, 'weekly.json'));\n copyFileIfExists(newSpecialPath, path.join(backupsRoot, 'profiles', profileId, 'special_events.json'));\n copyFileIfExists(newTermPath, path.join(backupsRoot, 'profiles', profileId, 'term_calendar.json'));\n\n // best-effort merge: pick first candidate with those keys\n let oldWeekly = null;\n let oldSpecial = null;\n let oldTerm = null;\n for (const c of candidates) {\n const d = c.data;\n if (!oldWeekly && d && d.weekly_timetable) oldWeekly = d;\n if (!oldSpecial && d && (d.special_events || d.events)) oldSpecial = d.special_events ? d.special_events : d;\n if (!oldTerm && d && (d.term_calendar || d.terms)) oldTerm = d.term_calendar ? d.term_calendar : d;\n }\n\n // If destination exists, we still proceed safely:\n // - create backups\n // - overwrite destination so legacy zian content can be migrated even under \"missing-only\" behavior\n writeJsonAtomic(newWeeklyPath, convertOldWeeklyToNew(oldWeekly, profileId));\n writeJsonAtomic(newSpecialPath, convertOldSpecialToNew(oldSpecial, profileId));\n writeJsonAtomic(newTermPath, convertOldTermToNew(oldTerm, profileId));\n\n newReg.profiles.push(prof);\n\n // backup registry if it exists\n copyFileIfExists(newReg._path, path.join(backupsRoot, 'profiles', 'registry.json'));\n writeJsonAtomic(newReg._path, { version: 1, dataRoot: 'schedules/profiles', profiles: newReg.profiles });\n\n report.migrated.push({ profileId, inputs: candidates.map(c => c.path), outputs: [newWeeklyPath, newSpecialPath, newTermPath] });\n report.warnings.push('Legacy zian migration writes to canonical profile_id \"zian\" (child).');\n return report;\n}\n\nmodule.exports = { migrateKidSchedule, migrateLegacyZian };\n",
191 "inputSchema": {},
192 "outputSchema": null,
193 "icons": null,
194 "annotations": null,
195 "meta": null,
196 "execution": null
197 },
198 {
199 "name": "student_timetable_service.js",
200 "title": null,
201 "description": "Script: student_timetable_service.js. Code:\nconst { loadProfileScheduleFiles } = require('./schedule_store.js');\nconst { formatISODate, addDays, weekStartMonday, startOfDay } = require('./date_utils.js');\n\nconst DOW_KEYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];\n\nfunction weekdayKey(date) {\n const js = date.getDay();\n // JS: 0 Sun .. 6 Sat\n if (js === 0) return 'sun';\n if (js === 1) return 'mon';\n if (js === 2) return 'tue';\n if (js === 3) return 'wed';\n if (js === 4) return 'thu';\n if (js === 5) return 'fri';\n return 'sat';\n}\n\nfunction parseHHMM(s) {\n const m = String(s || '').match(/^(\\d{1,2}):(\\d{2})$/);\n if (!m) return null;\n const hh = parseInt(m[1], 10);\n const mm = parseInt(m[2], 10);\n if (hh < 0 || hh > 23 || mm < 0 || mm > 59) return null;\n return hh * 60 + mm;\n}\n\nfunction overlapsRange(aStart, aEnd, bStart, bEnd) {\n if (aStart == null || aEnd == null || bStart == null || bEnd == null) return false;\n return Math.max(aStart, bStart) < Math.min(aEnd, bEnd);\n}\n\nfunction weekIndexForDate(startDateISO, date) {\n const anchor = new Date(`${startDateISO}T00:00:00`);\n const aMon = weekStartMonday(anchor);\n const dMon = weekStartMonday(date);\n const diffMs = dMon.getTime() - aMon.getTime();\n const diffDays = Math.round(diffMs / (24 * 60 * 60 * 1000));\n return Math.floor(diffDays / 7);\n}\n\nfunction normalizeWeeklyEvents(weekly, date) {\n if (!weekly) return [];\n const rec = weekly.recurrence || { type: 'every_week' };\n const type = rec.type || 'every_week';\n const key = weekdayKey(date);\n\n let dayItems = [];\n\n if (type === 'every_week') {\n const w = weekly.weeks && weekly.weeks.default ? weekly.weeks.default : null;\n dayItems = (w && Array.isArray(w[key])) ? w[key] : [];\n } else if (type === 'biweekly') {\n const startDate = rec.start_date;\n if (!startDate) return [];\n const idx = weekIndexForDate(startDate, date);\n const which = (idx % 2 === 0) ? 'week_a' : 'week_b';\n const w = weekly.weeks && weekly.weeks[which] ? weekly.weeks[which] : null;\n dayItems = (w && Array.isArray(w[key])) ? w[key] : [];\n } else {\n return [];\n }\n\n const out = [];\n for (const it of dayItems) {\n out.push({\n date: formatISODate(date),\n weekday: key,\n title: it && it.title ? String(it.title) : '',\n start_time: it && it.start_time ? String(it.start_time) : '',\n end_time: it && it.end_time ? String(it.end_time) : '',\n location: it && it.location ? String(it.location) : '',\n notes: it && it.notes ? String(it.notes) : '',\n source: 'weekly',\n raw: it\n });\n }\n return out;\n}\n\nfunction specialEventsOnDate(special, date) {\n if (!special) return [];\n const target = formatISODate(date);\n const events = Array.isArray(special.events) ? special.events : [];\n const out = [];\n for (const ev of events) {\n if (!ev || String(ev.date || '') !== target) continue;\n out.push({\n date: target,\n weekday: weekdayKey(date),\n id: ev.id ? String(ev.id) : '',\n title: ev.title ? String(ev.title) : 'Special event',\n start_time: ev.start_time ? String(ev.start_time) : '',\n end_time: ev.end_time ? String(ev.end_time) : '',\n location: ev.location ? String(ev.location) : '',\n notes: ev.notes ? String(ev.notes) : '',\n tags: Array.isArray(ev.tags) ? ev.tags.slice() : [],\n cancels_weekly: !!ev.cancels_weekly,\n source: 'special',\n raw: ev\n });\n }\n return out;\n}\n\nfunction applyCancelsWeekly(weeklyItems, specialItems) {\n const cancelers = specialItems.filter(e => e && e.cancels_weekly);\n if (!cancelers.length) return weeklyItems;\n\n // v1: if cancel event has no times, cancel all weekly items for that day.\n const cancelsAllDay = cancelers.some(c => !c.start_time || !c.end_time);\n if (cancelsAllDay) return [];\n\n return weeklyItems.filter(w => {\n const wS = parseHHMM(w.start_time);\n const wE = parseHHMM(w.end_time);\n for (const c of cancelers) {\n const cS = parseHHMM(c.start_time);\n const cE = parseHHMM(c.end_time);\n if (overlapsRange(wS, wE, cS, cE)) return false;\n }\n return true;\n });\n}\n\nfunction sortByTime(items) {\n return items.slice().sort((a, b) => {\n const am = parseHHMM(a.start_time);\n const bm = parseHHMM(b.start_time);\n if (am == null && bm == null) return String(a.title).localeCompare(String(b.title));\n if (am == null) return 1;\n if (bm == null) return -1;\n if (am !== bm) return am - bm;\n return String(a.title).localeCompare(String(b.title));\n });\n}\n\nfunction dayScheduleForProfile(workspaceRoot, profileId, date) {\n const { weekly, special } = loadProfileScheduleFiles(workspaceRoot, profileId);\n const weeklyItems = normalizeWeeklyEvents(weekly, date);\n const specialItems = specialEventsOnDate(special, date);\n const keptWeekly = applyCancelsWeekly(weeklyItems, specialItems);\n return sortByTime(keptWeekly.concat(specialItems));\n}\n\nfunction weekScheduleForProfile(workspaceRoot, profileId, anchorDate, which) {\n const monday = weekStartMonday(anchorDate);\n const start = which === 'next' ? addDays(monday, 7) : monday;\n const days = [];\n for (let i = 0; i < 7; i++) {\n const d = addDays(start, i);\n days.push({ date: formatISODate(d), weekday: weekdayKey(d), items: dayScheduleForProfile(workspaceRoot, profileId, d) });\n }\n return { week_start: formatISODate(start), days };\n}\n\nfunction todayDate() {\n return startOfDay(new Date());\n}\n\nmodule.exports = {\n dayScheduleForProfile,\n weekScheduleForProfile,\n todayDate,\n weekdayKey\n};\n",
202 "inputSchema": {},
203 "outputSchema": null,
204 "icons": null,
205 "annotations": null,
206 "meta": null,
207 "execution": null
208 }
209 ]
210 },
211 "error": null
212 }
213 ],
214 "issues": [
215 {
216 "code": "W004",
217 "message": "The MCP server is not in our registry.",
218 "reference": [
219 0,
220 null
221 ],
222 "extra_data": null
223 }
224 ],
225 "labels": [
226 [
227 {
228 "is_public_sink": 0,
229 "destructive": 0,
230 "untrusted_content": 0,
231 "private_data": 0
232 },
233 {
234 "is_public_sink": 0,
235 "destructive": 0,
236 "untrusted_content": 0,
237 "private_data": 0
238 },
239 {
240 "is_public_sink": 0,
241 "destructive": 0,
242 "untrusted_content": 0,
243 "private_data": 0
244 },
245 {
246 "is_public_sink": 0,
247 "destructive": 0,
248 "untrusted_content": 0,
249 "private_data": 0
250 },
251 {
252 "is_public_sink": 0,
253 "destructive": 0,
254 "untrusted_content": 0,
255 "private_data": 0
256 },
257 {
258 "is_public_sink": 0,
259 "destructive": 0,
260 "untrusted_content": 0,
261 "private_data": 0
262 },
263 {
264 "is_public_sink": 0,
265 "destructive": 0,
266 "untrusted_content": 0,
267 "private_data": 0
268 },
269 {
270 "is_public_sink": 0,
271 "destructive": 0,
272 "untrusted_content": 0,
273 "private_data": 0
274 },
275 {
276 "is_public_sink": 0,
277 "destructive": 0,
278 "untrusted_content": 0,
279 "private_data": 0
280 },
281 {
282 "is_public_sink": 0,
283 "destructive": 0,
284 "untrusted_content": 0,
285 "private_data": 0
286 },
287 {
288 "is_public_sink": 0,
289 "destructive": 0,
290 "untrusted_content": 0,
291 "private_data": 0
292 },
293 {
294 "is_public_sink": 0,
295 "destructive": 0,
296 "untrusted_content": 0,
297 "private_data": 0
298 },
299 {
300 "is_public_sink": 0,
301 "destructive": 0,
302 "untrusted_content": 0,
303 "private_data": 0
304 },
305 {
306 "is_public_sink": 0,
307 "destructive": 0,
308 "untrusted_content": 0,
309 "private_data": 0
310 },
311 {
312 "is_public_sink": 0,
313 "destructive": 0,
314 "untrusted_content": 0,
315 "private_data": 0
316 }
317 ]
318 ],
319 "error": null
320 }
321}
322
323Process exited with code 0
324✓ Completed in 154318ms
npm-audit
No package.json found — skipping npm audit
No package.json found — skipping npm audit
View logs
npm-audit0ms
1No package.json found at /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/package.json
2Skipping npm audit.

Files analyzed

SKILL.mdcli.jsdate_utils.jsinit.jsmigrate.jsmigrate_cli.jsprofiles_registry.jsrecurrence.jsschedule_store.jsstudent_timetable_service.jsstudent_timetable.test.jstool.jsworkspace_root.js

Rules coverage147 patterns

58
prompt injection
15
secrets
53
malware
21
permissions

Security Findings

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:50

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:125

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:126

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:127

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:128

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:65

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:73

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:79

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:79

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:177

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:190

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:228

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:228

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:229

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:230

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:231

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:233

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:233

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:234

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:235

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:236

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:244

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:244

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:245

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:245

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:246

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:246

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:271

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:288

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:317

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:318

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:319

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:320

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:328

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:329

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:330

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:353

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/profiles_registry.js:25

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:9

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:9

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:10

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:11

Mediumjavascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalsemgrepsecurity

Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.

/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:12

LowMCP-W004mcp-scanmcp

The MCP server is not in our registry.

Scan History1 scan

Warning39fe35f
44 findings
0
critical
0
high
43
medium
1
low
0
info

Scanners4/5 ran

clawguard-rules
0 findings1ms
No findings — all checks passed.
View logs
clawguard-rules1ms
1[2026-02-18T10:10:58.806Z] Running @yourclaw/clawguard-rules pattern matcher
2Scanning: /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/SKILL.md
3Content length: 1013 chars
4Patterns matched: 0
5✓ Completed in 1ms
gitleaks
0 findings133734ms
No findings — all checks passed.
View logs
gitleaks133734ms
1[2026-02-18T10:13:12.540Z] $ gitleaks detect --source /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable --report-format json --report-path /dev/stdout --no-git
2
3⚠ stderr output:
4
5 │╲
6 │ ○
7 ○ ░
8 ░ gitleaks
9
1010:13AM FTL Report path is not writable: /dev/stdout error="open /dev/stdout: no such device or address"
11
12Process exited with code 1
13✓ Completed in 133734ms
semgrep
43 findings191475ms
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:50)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:125)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:126)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:127)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:128)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:65)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:73)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:79)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:79)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:177)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:190)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:228)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:228)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:229)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:230)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:231)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:233)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:233)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:234)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:235)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:236)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:244)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:244)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:245)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:245)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:246)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:246)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:271)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:288)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:317)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:318)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:319)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:320)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:328)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:329)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:330)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js:353)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/profiles_registry.js:25)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:9)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:9)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:10)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:11)
javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversalDetected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.(/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js:12)
View logs
semgrep191475ms
1[2026-02-18T10:14:10.285Z] $ semgrep scan --json --quiet --config auto /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable
2{"version":"1.152.0","results":[{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":50,"col":34,"offset":1078},"end":{"line":50,"col":47,"offset":1091},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":125,"col":30,"offset":4348},"end":{"line":125,"col":43,"offset":4361},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":126,"col":36,"offset":4438},"end":{"line":126,"col":40,"offset":4442},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":127,"col":37,"offset":4496},"end":{"line":127,"col":41,"offset":4500},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":128,"col":34,"offset":4559},"end":{"line":128,"col":38,"offset":4563},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":65,"col":23,"offset":1486},"end":{"line":65,"col":36,"offset":1499},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":73,"col":34,"offset":1832},"end":{"line":73,"col":47,"offset":1845},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":79,"col":25,"offset":2080},"end":{"line":79,"col":37,"offset":2092},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":79,"col":39,"offset":2094},"end":{"line":79,"col":43,"offset":2098},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":177,"col":23,"offset":5521},"end":{"line":177,"col":36,"offset":5534},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":190,"col":33,"offset":6063},"end":{"line":190,"col":46,"offset":6076},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":228,"col":31,"offset":7502},"end":{"line":228,"col":44,"offset":7515},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":228,"col":67,"offset":7538},"end":{"line":228,"col":72,"offset":7543},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":229,"col":37,"offset":7582},"end":{"line":229,"col":44,"offset":7589},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":230,"col":38,"offset":7644},"end":{"line":230,"col":45,"offset":7651},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":231,"col":35,"offset":7711},"end":{"line":231,"col":42,"offset":7718},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":233,"col":31,"offset":7774},"end":{"line":233,"col":44,"offset":7787},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":233,"col":71,"offset":7814},"end":{"line":233,"col":80,"offset":7823},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":234,"col":37,"offset":7862},"end":{"line":234,"col":44,"offset":7869},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":235,"col":38,"offset":7924},"end":{"line":235,"col":45,"offset":7931},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":236,"col":35,"offset":7991},"end":{"line":236,"col":42,"offset":7998},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":244,"col":31,"offset":8247},"end":{"line":244,"col":42,"offset":8258},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":244,"col":56,"offset":8272},"end":{"line":244,"col":65,"offset":8281},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":245,"col":32,"offset":8330},"end":{"line":245,"col":43,"offset":8341},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":245,"col":57,"offset":8355},"end":{"line":245,"col":66,"offset":8364},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":246,"col":29,"offset":8418},"end":{"line":246,"col":40,"offset":8429},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":246,"col":54,"offset":8443},"end":{"line":246,"col":63,"offset":8452},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":271,"col":28,"offset":9549},"end":{"line":271,"col":39,"offset":9560},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":288,"col":33,"offset":9960},"end":{"line":288,"col":46,"offset":9973},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":317,"col":29,"offset":10970},"end":{"line":317,"col":42,"offset":10983},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":318,"col":35,"offset":11056},"end":{"line":318,"col":42,"offset":11063},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":319,"col":36,"offset":11116},"end":{"line":319,"col":43,"offset":11123},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":320,"col":33,"offset":11181},"end":{"line":320,"col":40,"offset":11188},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":328,"col":45,"offset":11476},"end":{"line":328,"col":56,"offset":11487},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":329,"col":46,"offset":11574},"end":{"line":329,"col":57,"offset":11585},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":330,"col":43,"offset":11677},"end":{"line":330,"col":54,"offset":11688},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","start":{"line":353,"col":44,"offset":12730},"end":{"line":353,"col":55,"offset":12741},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/profiles_registry.js","start":{"line":25,"col":34,"offset":561},"end":{"line":25,"col":47,"offset":574},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","start":{"line":9,"col":26,"offset":219},"end":{"line":9,"col":39,"offset":232},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","start":{"line":9,"col":66,"offset":259},"end":{"line":9,"col":75,"offset":268},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","start":{"line":10,"col":32,"offset":302},"end":{"line":10,"col":36,"offset":306},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","start":{"line":11,"col":33,"offset":356},"end":{"line":11,"col":37,"offset":360},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}},{"check_id":"javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","start":{"line":12,"col":30,"offset":415},"end":{"line":12,"col":34,"offset":419},"extra":{"message":"Detected possible user input going into a `path.join` or `path.resolve` function. This could possibly lead to a path traversal vulnerability, where the attacker can access arbitrary files stored in the file system. Instead, be sure to sanitize or validate user input first.","metadata":{"owasp":["A05:2017 - Broken Access Control","A01:2021 - Broken Access Control","A01:2025 - Broken Access Control"],"cwe":["CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"],"category":"security","references":["https://owasp.org/www-community/attacks/Path_Traversal"],"technology":["javascript","node.js"],"cwe2022-top25":true,"cwe2021-top25":true,"subcategory":["vuln"],"likelihood":"HIGH","impact":"MEDIUM","confidence":"LOW","license":"Semgrep Rules License v1.0. For more details, visit semgrep.dev/legal/rules-license","vulnerability_class":["Path Traversal"],"source":"https://semgrep.dev/r/javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal","shortlink":"https://sg.run/OPqk"},"severity":"WARNING","fingerprint":"requires login","lines":"requires login","validation_state":"NO_VALIDATOR","engine_kind":"OSS"}}],"errors":[],"paths":{"scanned":["/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/README.md","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/SKILL.md","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/_meta.json","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/cli.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/date_utils.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate_cli.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/profiles_registry.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/recurrence.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/schedule_store.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/student_timetable_service.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/tool.js","/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/workspace_root.js"]},"time":{"rules":[],"rules_parse_time":13.759119033813477,"profiling_times":{"config_time":18.480637311935425,"core_time":24.874802827835083,"ignores_time":0.006995439529418945,"total_time":43.41956830024719},"parsing_time":{"total_time":0.0,"per_file_time":{"mean":0.0,"std_dev":0.0},"very_slow_stats":{"time_ratio":0.0,"count_ratio":0.0},"very_slow_files":[]},"scanning_time":{"total_time":9.598664283752441,"per_file_time":{"mean":0.23996660709381104,"std_dev":0.2999305121441773},"very_slow_stats":{"time_ratio":0.49366120714810807,"count_ratio":0.05},"very_slow_files":[{"fpath":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","ftime":2.3454911708831787},{"fpath":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/migrate.js","ftime":2.3929970264434814}]},"matching_time":{"total_time":0.0,"per_file_and_rule_time":{"mean":0.0,"std_dev":0.0},"very_slow_stats":{"time_ratio":0.0,"count_ratio":0.0},"very_slow_rules_on_files":[]},"tainting_time":{"total_time":0.0,"per_def_and_rule_time":{"mean":0.0,"std_dev":0.0},"very_slow_stats":{"time_ratio":0.0,"count_ratio":0.0},"very_slow_rules_on_defs":[]},"fixpoint_timeouts":[{"error_type":"Fixpoint timeout","severity":"warn","message":"Fixpoint timeout while performing taint analysis at /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js:49:15 [rules: 1, first: javascript.lang.security.audit.unsafe-formatstring.unsafe-formatstring]","location":{"path":"/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/init.js","start":{"line":49,"col":16,"offset":1012},"end":{"line":49,"col":31,"offset":1027}}}],"prefiltering":{"project_level_time":0.0,"file_level_time":0.0,"rules_with_project_prefilters_ratio":0.0,"rules_with_file_prefilters_ratio":0.9895484949832776,"rules_selected_ratio":0.019648829431438128,"rules_matched_ratio":0.019648829431438128},"targets":[],"total_bytes":0,"max_memory_bytes":1372265920},"engine_requested":"OSS","skipped_rules":[],"profiling_results":[]}
3
4Process exited with code 0
5✓ Completed in 191475ms
mcp-scan
1 finding154318ms
MCP-W004The MCP server is not in our registry.
View logs
mcp-scan154318ms
1[2026-02-18T10:13:33.132Z] $ mcp-scan --skills /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable --json
2{
3 "/tmp/clawguard-scan-II4u63/repo/skills/extraterrest": {
4 "client": "not-available",
5 "path": "/tmp/clawguard-scan-II4u63/repo/skills/extraterrest",
6 "servers": [
7 {
8 "name": "student-timetable",
9 "server": {
10 "path": "/tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable",
11 "type": "skill"
12 },
13 "signature": {
14 "metadata": {
15 "meta": null,
16 "protocolVersion": "built-in",
17 "capabilities": {
18 "experimental": null,
19 "logging": null,
20 "prompts": null,
21 "resources": null,
22 "tools": {
23 "listChanged": false
24 },
25 "completions": null,
26 "tasks": null
27 },
28 "serverInfo": {
29 "name": "student-timetable",
30 "title": null,
31 "version": "skills",
32 "websiteUrl": null,
33 "icons": null
34 },
35 "instructions": "Student timetable manager for self or parent-managed child profiles. Includes init flow + profile registry under schedules/profiles/.",
36 "prompts": {
37 "listChanged": false
38 },
39 "resources": {
40 "subscribe": null,
41 "listChanged": false
42 }
43 },
44 "prompts": [
45 {
46 "name": "SKILL.md",
47 "title": null,
48 "description": "\n\n# student-timetable\n\nDesign\n\n- Supports two operating modes:\n - Self profile: a student manages their own schedule.\n - Child profiles: a parent/guardian manages one or more children.\n- Uses a profile registry + per-profile data files so queries are consistent across kids and reusable in other automations.\n\nInitialize\n\n- Run interactive setup:\n - `node skills/student-timetable/cli.js init`\n- This writes/updates:\n - `schedules/profiles/registry.json`\n - `schedules/profiles/<profile_id>/*`\n\nQuery\n\n- `node skills/student-timetable/cli.js today --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js tomorrow --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js this_week --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js next_week --profile <id|name|alias>`\n\nTool entry\n\n- `tool.js`\n",
49 "arguments": [],
50 "icons": null,
51 "meta": null
52 },
53 {
54 "name": "README.md",
55 "title": null,
56 "description": "# student-timetable\n\nA student timetable manager supporting:\n\n- A student managing their own schedule (self profile)\n- A parent/guardian managing one or more children (child profiles)\n\nData contract reference: `projects/StudentTimetable/docs/contracts/prd.md`.\n\n## Data layout\n\nAll schedule data lives under:\n\n- `schedules/profiles/registry.json`\n- `schedules/profiles/<profile_id>/weekly.json`\n- `schedules/profiles/<profile_id>/special_events.json`\n- `schedules/profiles/<profile_id>/term_calendar.json`\n\n## CLI\n\nInteractive init:\n\n- `node skills/student-timetable/cli.js init`\n\nQuery:\n\n- `node skills/student-timetable/cli.js today --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js tomorrow --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js this_week --profile <id|name|alias>`\n- `node skills/student-timetable/cli.js next_week --profile <id|name|alias>`\n\nIf you omit `--profile`, the CLI defaults to the self profile ONLY when a self profile exists in `schedules/profiles/registry.json`.\n\n## Profile resolution rules\n\nMatching order:\n\n1. Exact match on `profile_id`\n2. Exact match on display name\n3. Exact match on an alias\n\nNormalization:\n\n- Case-insensitive\n- Trim whitespace\n- Collapse internal whitespace runs\n\nAmbiguity handling:\n\n- If multiple profiles match, the tool always asks for clarification.\n- The tool never picks a profile based on ordering, recency, or heuristics.\n\nGeneric aliases (always require clarification):\n\n- `me`, `myself`, `self`\n- `kid`, `child`, `son`, `daughter`, `boy`, `girl`\n- `older`, `younger`, `big`, `small`\n- `primary`, `secondary`\n\nReserved words:\n\n- `all`, `everyone`\n\n## Migration\n\nNon-destructive migration from the legacy `kid-schedule` layout:\n\n- Dry run: `node skills/student-timetable/cli.js migrate kid-schedule --dry-run`\n- Apply: `node skills/student-timetable/cli.js migrate kid-schedule`\n\nLegacy \"zian\" single-JSON (heuristic):\n\n- Dry run: `node skills/student-timetable/cli.js migrate legacy-zian --dry-run`\n- Apply: `node skills/student-timetable/cli.js migrate legacy-zian`\n\nMigration safety:\n\n- Never deletes old data.\n- Does not overwrite destination files if they already exist.\n- Creates backups under `schedules/backups/` for any destination files it would overwrite (if present).\n\n## Notes\n\n- Time zone defaults to `Asia/Singapore` in templates.\n- Biweekly support uses Monday as week start (per contract).\n",
57 "arguments": null,
58 "icons": null,
59 "meta": null
60 }
61 ],
62 "resources": [
63 {
64 "name": "_meta.json",
65 "title": null,
66 "uri": "skill://_meta.json",
67 "description": "{\n \"owner\": \"extraterrest\",\n \"slug\": \"student-timetable\",\n \"displayName\": \"student-timetable\",\n \"latest\": {\n \"version\": \"0.1.0-alpha.2\",\n \"publishedAt\": 1771342552498,\n \"commit\": \"https://github.com/openclaw/skills/commit/31b3360736eeae7db4a4fb716bed620016bc29e4\"\n },\n \"history\": []\n}\n",
68 "mimeType": null,
69 "size": null,
70 "icons": null,
71 "annotations": null,
72 "meta": null
73 }
74 ],
75 "resource_templates": [],
76 "tools": [
77 {
78 "name": "workspace_root.js",
79 "title": null,
80 "description": "Script: workspace_root.js. Code:\nconst fs = require('fs');\nconst path = require('path');\n\nfunction fileExists(p) {\n try {\n fs.accessSync(p, fs.constants.F_OK);\n return true;\n } catch (_) {\n return false;\n }\n}\n\nfunction resolveWorkspaceRoot() {\n const envRoot = process.env.OPENCLAW_WORKSPACE;\n if (envRoot && fileExists(envRoot)) {\n return path.resolve(envRoot);\n }\n\n let cur = process.cwd();\n while (true) {\n const skillsDir = path.join(cur, 'skills');\n const schedulesDir = path.join(cur, 'schedules');\n if (fileExists(skillsDir) && fileExists(schedulesDir)) {\n return cur;\n }\n\n const parent = path.dirname(cur);\n if (parent === cur) {\n break;\n }\n cur = parent;\n }\n\n return process.cwd();\n}\n\nmodule.exports = { resolveWorkspaceRoot };\n",
81 "inputSchema": {},
82 "outputSchema": null,
83 "icons": null,
84 "annotations": null,
85 "meta": null,
86 "execution": null
87 },
88 {
89 "name": "profiles_registry.js",
90 "title": null,
91 "description": "Script: profiles_registry.js. Code:\nconst fs = require('fs');\nconst path = require('path');\n\nfunction readJson(p) {\n return JSON.parse(fs.readFileSync(p, 'utf8'));\n}\n\nfunction normalizeToken(s) {\n return String(s || '')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, ' ');\n}\n\nconst GENERIC_ALIASES = new Set([\n 'me', 'myself', 'self',\n 'kid', 'child', 'son', 'daughter', 'boy', 'girl',\n 'older', 'younger', 'big', 'small',\n 'primary', 'secondary'\n]);\n\nconst RESERVED_WORDS = new Set(['all', 'everyone']);\n\nfunction loadProfilesRegistry(workspaceRoot) {\n const registryPath = path.join(workspaceRoot, 'schedules', 'profiles', 'registry.json');\n if (!fs.existsSync(registryPath)) {\n return { version: 1, dataRoot: 'schedules/profiles', profiles: [], _path: registryPath };\n }\n\n const data = readJson(registryPath);\n const profiles = Array.isArray(data && data.profiles) ? data.profiles : [];\n const version = typeof (data && data.version) === 'number' ? data.version : 1;\n const dataRoot = (data && data.dataRoot) ? String(data.dataRoot) : 'schedules/profiles';\n return { version, dataRoot, profiles, _path: registryPath };\n}\n\nfunction findSelfProfile(registry) {\n return (registry.profiles || []).find(p => p && p.type === 'self') || null;\n}\n\nfunction resolveProfile(registry, rawIdent, opts = {}) {\n const ident = normalizeToken(rawIdent);\n const allowDefaultToSelf = !!opts.allowDefaultToSelf;\n\n if (!ident) {\n if (allowDefaultToSelf) {\n const self = findSelfProfile(registry);\n if (self) {\n return { ok: true, profile: self, reason: 'default_to_self' };\n }\n }\n return { ok: false, reason: 'missing', candidates: registry.profiles || [] };\n }\n\n if (RESERVED_WORDS.has(ident)) {\n return { ok: false, reason: 'reserved', candidates: registry.profiles || [] };\n }\n\n if (GENERIC_ALIASES.has(ident)) {\n return { ok: false, reason: 'generic_alias', candidates: registry.profiles || [] };\n }\n\n const profiles = registry.profiles || [];\n\n const byId = profiles.filter(p => normalizeToken(p && p.profile_id) === ident);\n if (byId.length === 1) return { ok: true, profile: byId[0], reason: 'profile_id' };\n if (byId.length > 1) return { ok: false, reason: 'ambiguous', candidates: byId };\n\n const byName = profiles.filter(p => normalizeToken(p && p.display_name) === ident);\n if (byName.length === 1) return { ok: true, profile: byName[0], reason: 'display_name' };\n if (byName.length > 1) return { ok: false, reason: 'ambiguous', candidates: byName };\n\n const byAlias = profiles.filter(p => {\n const aliases = Array.isArray(p && p.aliases) ? p.aliases : [];\n return aliases.some(a => normalizeToken(a) === ident);\n });\n if (byAlias.length === 1) return { ok: true, profile: byAlias[0], reason: 'alias' };\n if (byAlias.length > 1) return { ok: false, reason: 'ambiguous', candidates: byAlias };\n\n return { ok: false, reason: 'unmatched', candidates: profiles };\n}\n\nfunction clarifyProfileMessage(result) {\n const candidates = (result && result.candidates) ? result.candidates : [];\n const names = candidates\n .map(p => {\n const disp = p && p.display_name ? String(p.display_name) : '';\n const id = p && p.profile_id ? String(p.profile_id) : '';\n if (disp && id && disp.toLowerCase() !== id.toLowerCase()) return `${disp} (${id})`;\n return disp || id;\n })\n .filter(Boolean);\n\n let hint = '';\n if (names.length) {\n hint = `Available profiles: ${names.join(', ')}.`;\n } else {\n hint = 'No profiles found in schedules/profiles/registry.json.';\n }\n\n if (result && result.reason === 'generic_alias') {\n return `Which profile did you mean? Generic aliases like \"${String(result.input || '').trim()}\" require clarification. ${hint}`;\n }\n\n if (result && result.reason === 'reserved') {\n return `\"${String(result.input || '').trim()}\" is reserved; please choose a specific profile. ${hint}`;\n }\n\n return `Which profile? Please pass --profile <id|name|alias>. ${hint}`;\n}\n\nmodule.exports = {\n loadProfilesRegistry,\n resolveProfile,\n clarifyProfileMessage,\n GENERIC_ALIASES,\n RESERVED_WORDS,\n normalizeToken\n};\n",
92 "inputSchema": {},
93 "outputSchema": null,
94 "icons": null,
95 "annotations": null,
96 "meta": null,
97 "execution": null
98 },
99 {
100 "name": "cli.js",
101 "title": null,
102 "description": "Script: cli.js. Code:\n#!/usr/bin/env node\n\nconst { resolveWorkspaceRoot } = require('./workspace_root.js');\nconst { loadProfilesRegistry, resolveProfile, clarifyProfileMessage } = require('./profiles_registry.js');\nconst { dayScheduleForProfile, weekScheduleForProfile, todayDate } = require('./student_timetable_service.js');\nconst { addDays, formatISODate } = require('./date_utils.js');\nconst { interactiveInit } = require('./init.js');\nconst { migrateKidSchedule, migrateLegacyZian } = require('./migrate.js');\n\nfunction usage() {\n process.stderr.write('student-timetable CLI\\n');\n console.log('');\n console.log('Usage:');\n console.log(' node skills/student-timetable/cli.js <command> [--profile <id|name|alias>]');\n console.log('');\n console.log('Commands:');\n console.log(' init');\n console.log(' today');\n console.log(' tomorrow');\n console.log(' this_week');\n console.log(' next_week');\n console.log(' migrate kid-schedule [--dry-run]');\n console.log(' migrate legacy-zian [--dry-run]');\n}\n\nfunction parseArgs(argv) {\n const args = { _: [] };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--profile') {\n args.profile = argv[i + 1];\n i++;\n } else if (a === '--date') {\n args.date = argv[i + 1];\n i++;\n } else if (a === '--dry-run') {\n args.dryRun = true;\n } else {\n args._.push(a);\n }\n }\n return args;\n}\n\nfunction printDay(items, label) {\n console.log(label);\n if (!items.length) {\n console.log(' (no items)');\n return;\n }\n for (const it of items) {\n const time = it.start_time ? `${it.start_time}-${it.end_time || ''}`.replace(/-$/, '') : 'TBD';\n const notes = it.notes ? ` | ${it.notes}` : '';\n console.log(` ${time} | ${it.title}${notes} [${it.source}]`);\n }\n}\n\nasync function main() {\n const argv = process.argv.slice(2);\n const args = parseArgs(argv);\n const command = args._[0];\n\n if (!command) {\n usage();\n process.exit(1);\n }\n\n const workspaceRoot = resolveWorkspaceRoot();\n\n if (command === 'init') {\n await interactiveInit(workspaceRoot);\n return;\n }\n\n if (command === 'migrate') {\n const which = args._[1];\n if (which === 'kid-schedule') {\n const report = migrateKidSchedule(workspaceRoot, { dryRun: !!args.dryRun });\n console.log(JSON.stringify(report, null, 2));\n return;\n }\n if (which === 'legacy-zian') {\n const report = migrateLegacyZian(workspaceRoot, { dryRun: !!args.dryRun });\n console.log(JSON.stringify(report, null, 2));\n return;\n }\n usage();\n process.exit(1);\n }\n\n const registry = loadProfilesRegistry(workspaceRoot);\n const allowDefaultToSelf = true;\n const resolved = resolveProfile(registry, args.profile, { allowDefaultToSelf });\n if (!resolved.ok) {\n resolved.input = args.profile;\n console.log(clarifyProfileMessage(resolved));\n process.exit(2);\n }\n\n const profile = resolved.profile;\n const today = todayDate();\n\n if (command === 'today') {\n const items = dayScheduleForProfile(workspaceRoot, profile.profile_id, today);\n printDay(items, `${profile.display_name || profile.profile_id} - Today (${formatISODate(today)})`);\n return;\n }\n\n if (command === 'tomorrow') {\n const d = addDays(today, 1);\n const items = dayScheduleForProfile(workspaceRoot, profile.profile_id, d);\n printDay(items, `${profile.display_name || profile.profile_id} - Tomorrow (${formatISODate(d)})`);\n return;\n }\n\n if (command === 'this_week' || command === 'next_week') {\n const which = command === 'next_week' ? 'next' : 'this';\n const wk = weekScheduleForProfile(workspaceRoot, profile.profile_id, today, which);\n console.log(`${profile.display_name || profile.profile_id} - ${command} (week of ${wk.week_start})`);\n for (const day of wk.days) {\n console.log('');\n printDay(day.items, `${day.weekday} (${day.date})`);\n }\n return;\n }\n\n usage();\n process.exit(1);\n}\n\nif (require.main === module) {\n main().catch(err => {\n console.error(err && err.stack ? err.stack : String(err));\n process.exit(1);\n });\n}\n",
103 "inputSchema": {},
104 "outputSchema": null,
105 "icons": null,
106 "annotations": null,
107 "meta": null,
108 "execution": null
109 },
110 {
111 "name": "student_timetable.test.js",
112 "title": null,
113 "description": "Script: student_timetable.test.js. Code:\nconst assert = require('assert');\nconst fs = require('fs');\nconst path = require('path');\n\nconst { loadProfilesRegistry, resolveProfile } = require('../profiles_registry.js');\nconst { dayScheduleForProfile } = require('../student_timetable_service.js');\n\nfunction withTempDir(fn) {\n const tmpBase = fs.mkdtempSync(path.join(require('os').tmpdir(), 'student-timetable-'));\n try {\n return fn(tmpBase);\n } finally {\n fs.rmSync(tmpBase, { recursive: true, force: true });\n }\n}\n\nfunction writeJson(p, obj) {\n fs.mkdirSync(path.dirname(p), { recursive: true });\n fs.writeFileSync(p, JSON.stringify(obj, null, 2));\n}\n\n(function testProfileResolutionOrderAndAmbiguity() {\n const registry = {\n version: 1,\n dataRoot: 'schedules/profiles',\n profiles: [\n { profile_id: 'kai', type: 'child', display_name: 'Kai', aliases: ['kk'] },\n { profile_id: 'p2', type: 'child', display_name: 'kai', aliases: [] }\n ]\n };\n\n // exact profile_id wins over display_name\n const r1 = resolveProfile(registry, 'kai', { allowDefaultToSelf: false });\n assert.equal(r1.ok, true);\n assert.equal(r1.profile.profile_id, 'kai');\n\n // ambiguous: \"kai\" matches profile_id of first profile; should still resolve\n const r2 = resolveProfile(registry, 'kai ', { allowDefaultToSelf: false });\n assert.equal(r2.ok, true);\n})();\n\n(function testGenericAliasForcesClarification() {\n const registry = {\n version: 1,\n dataRoot: 'schedules/profiles',\n profiles: [{ profile_id: 'aidan', type: 'child', display_name: 'Aidan', aliases: ['kid'] }]\n };\n\n const r = resolveProfile(registry, 'kid', { allowDefaultToSelf: false });\n assert.equal(r.ok, false);\n assert.equal(r.reason, 'generic_alias');\n})();\n\n(function testDefaultToSelfOnlyWhenConfigured() {\n const regNoSelf = { version: 1, dataRoot: 'schedules/profiles', profiles: [{ profile_id: 'a', type: 'child', display_name: 'A', aliases: [] }] };\n const r1 = resolveProfile(regNoSelf, null, { allowDefaultToSelf: true });\n assert.equal(r1.ok, false);\n\n const regSelf = { version: 1, dataRoot: 'schedules/profiles', profiles: [{ profile_id: 'me', type: 'self', display_name: 'Me', aliases: [] }] };\n const r2 = resolveProfile(regSelf, null, { allowDefaultToSelf: true });\n assert.equal(r2.ok, true);\n assert.equal(r2.profile.type, 'self');\n})();\n\n(function testDayScheduleWeeklyPlusSpecialAndCancelsWeekly() {\n withTempDir((ws) => {\n fs.mkdirSync(path.join(ws, 'skills'), { recursive: true });\n\n writeJson(path.join(ws, 'schedules/profiles/registry.json'), {\n version: 1,\n dataRoot: 'schedules/profiles',\n profiles: [{ profile_id: 'zian', type: 'self', display_name: 'Zian', aliases: ['z'] }]\n });\n\n writeJson(path.join(ws, 'schedules/profiles/zian/weekly.json'), {\n version: 1,\n profile_id: 'zian',\n recurrence: { type: 'every_week' },\n timezone: 'Asia/Singapore',\n weeks: {\n default: {\n mon: [{ title: 'Math', start_time: '09:00', end_time: '10:00', location: '', notes: '' }],\n tue: [], wed: [], thu: [], fri: [], sat: [], sun: []\n }\n }\n });\n\n writeJson(path.join(ws, 'schedules/profiles/zian/special_events.json'), {\n version: 1,\n profile_id: 'zian',\n events: [{ id: 'c', date: '2026-02-16', title: 'Holiday', cancels_weekly: true }]\n });\n\n const items = dayScheduleForProfile(ws, 'zian', new Date('2026-02-16T00:00:00'));\n assert.equal(items.some(i => i.title === 'Math'), false);\n assert.equal(items.some(i => i.title === 'Holiday'), true);\n });\n})();\n\nconsole.log('student-timetable tests: OK');\n",
114 "inputSchema": {},
115 "outputSchema": null,
116 "icons": null,
117 "annotations": null,
118 "meta": null,
119 "execution": null
120 },
121 {
122 "name": "date_utils.js",
123 "title": null,
124 "description": "Script: date_utils.js. Code:\nconst DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n\nfunction startOfDay(d) {\n return new Date(d.getFullYear(), d.getMonth(), d.getDate());\n}\n\nfunction addDays(d, n) {\n const x = new Date(d);\n x.setDate(x.getDate() + n);\n return x;\n}\n\nfunction dayName(d) {\n return DAY_NAMES[d.getDay()];\n}\n\nfunction formatISODate(d) {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, '0');\n const dd = String(d.getDate()).padStart(2, '0');\n return `${y}-${m}-${dd}`;\n}\n\nfunction weekStartMonday(d) {\n const x = startOfDay(d);\n const dow = x.getDay(); // 0 Sunday\n const diff = dow === 0 ? -6 : 1 - dow;\n return addDays(x, diff);\n}\n\nmodule.exports = {\n startOfDay,\n addDays,\n dayName,\n formatISODate,\n weekStartMonday\n};\n",
125 "inputSchema": {},
126 "outputSchema": null,
127 "icons": null,
128 "annotations": null,
129 "meta": null,
130 "execution": null
131 },
132 {
133 "name": "schedule_store.js",
134 "title": null,
135 "description": "Script: schedule_store.js. Code:\nconst fs = require('fs');\nconst path = require('path');\n\nfunction readJson(p) {\n return JSON.parse(fs.readFileSync(p, 'utf8'));\n}\n\nfunction loadProfileScheduleFiles(workspaceRoot, profileId) {\n const base = path.join(workspaceRoot, 'schedules', 'profiles', profileId);\n const weeklyPath = path.join(base, 'weekly.json');\n const specialPath = path.join(base, 'special_events.json');\n const termPath = path.join(base, 'term_calendar.json');\n\n const weekly = fs.existsSync(weeklyPath) ? readJson(weeklyPath) : null;\n const special = fs.existsSync(specialPath) ? readJson(specialPath) : null;\n const term = fs.existsSync(termPath) ? readJson(termPath) : null;\n\n return { weekly, special, term, paths: { weeklyPath, specialPath, termPath } };\n}\n\nmodule.exports = { loadProfileScheduleFiles };\n",
136 "inputSchema": {},
137 "outputSchema": null,
138 "icons": null,
139 "annotations": null,
140 "meta": null,
141 "execution": null
142 },
143 {
144 "name": "recurrence.js",
145 "title": null,
146 "description": "Script: recurrence.js. Code:\nfunction isoDate(date) {\n const y = date.getFullYear();\n const m = String(date.getMonth() + 1).padStart(2, '0');\n const d = String(date.getDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\nfunction parseISODate(s) {\n if (!s) return null;\n const m = String(s).trim().match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (!m) return null;\n const dt = new Date(`${m[1]}-${m[2]}-${m[3]}T00:00:00`);\n if (Number.isNaN(dt.getTime())) return null;\n return dt;\n}\n\nfunction daysBetween(a, b) {\n const ms = 24 * 60 * 60 * 1000;\n const da = new Date(a.getFullYear(), a.getMonth(), a.getDate());\n const db = new Date(b.getFullYear(), b.getMonth(), b.getDate());\n return Math.floor((db.getTime() - da.getTime()) / ms);\n}\n\nfunction occursOnDate(item, date) {\n const rec = item && item.recurrence ? item.recurrence : { type: 'every_week' };\n const type = rec.type || 'every_week';\n\n if (type === 'every_week') {\n return true;\n }\n\n if (type === 'biweekly') {\n const start = parseISODate(rec.start_date);\n if (!start) {\n return true;\n }\n const diffDays = daysBetween(start, date);\n if (diffDays < 0) {\n return false;\n }\n const weeks = Math.floor(diffDays / 7);\n return weeks % 2 === 0;\n }\n\n return true;\n}\n\nmodule.exports = { occursOnDate, isoDate, parseISODate };\n",
147 "inputSchema": {},
148 "outputSchema": null,
149 "icons": null,
150 "annotations": null,
151 "meta": null,
152 "execution": null
153 },
154 {
155 "name": "tool.js",
156 "title": null,
157 "description": "Script: tool.js. Code:\nconst { resolveWorkspaceRoot } = require('./workspace_root.js');\nconst { loadProfilesRegistry, resolveProfile, clarifyProfileMessage } = require('./profiles_registry.js');\nconst { dayScheduleForProfile, weekScheduleForProfile, todayDate } = require('./student_timetable_service.js');\nconst { addDays } = require('./date_utils.js');\n\nfunction parseIntent(input) {\n const s = String(input || '').toLowerCase();\n if (s.includes('tomorrow') || s.includes('\u660e\u5929')) return 'tomorrow';\n if (s.includes('today') || s.includes('\u4eca\u5929')) return 'today';\n if (s.includes('next week') || s.includes('\u4e0b\u5468')) return 'next_week';\n if (s.includes('this week') || s.includes('\u672c\u5468') || s.includes('\u8fd9\u5468')) return 'this_week';\n return 'today';\n}\n\nfunction extractProfileIdent(input) {\n const m = String(input || '').match(/--profile\\s+([^\\s]+)/i);\n if (m) return m[1];\n return null;\n}\n\nfunction renderDay(items) {\n if (!items.length) {\n return '(no items)';\n }\n return items.map(it => {\n const time = it.start_time ? `${it.start_time}-${it.end_time || ''}`.replace(/-$/, '') : 'TBD';\n const notes = it.notes ? ` | ${it.notes}` : '';\n return `${time} | ${it.title}${notes}`;\n }).join('\\n');\n}\n\nasync function run(input) {\n const workspaceRoot = resolveWorkspaceRoot();\n const registry = loadProfilesRegistry(workspaceRoot);\n\n const ident = extractProfileIdent(input);\n const resolved = resolveProfile(registry, ident, { allowDefaultToSelf: true });\n if (!resolved.ok) {\n resolved.input = ident;\n return { ok: false, message: clarifyProfileMessage(resolved) };\n }\n\n const profile = resolved.profile;\n const intent = parseIntent(input);\n const today = todayDate();\n\n if (intent === 'today') {\n const items = dayScheduleForProfile(workspaceRoot, profile.profile_id, today);\n return { ok: true, message: `${profile.display_name || profile.profile_id} today\\n${renderDay(items)}` };\n }\n\n if (intent === 'tomorrow') {\n const d = addDays(today, 1);\n const items = dayScheduleForProfile(workspaceRoot, profile.profile_id, d);\n return { ok: true, message: `${profile.display_name || profile.profile_id} tomorrow\\n${renderDay(items)}` };\n }\n\n if (intent === 'this_week' || intent === 'next_week') {\n const which = intent === 'next_week' ? 'next' : 'this';\n const wk = weekScheduleForProfile(workspaceRoot, profile.profile_id, today, which);\n const lines = [];\n lines.push(`${profile.display_name || profile.profile_id} ${intent} (week of ${wk.week_start})`);\n for (const day of wk.days) {\n lines.push('');\n lines.push(`${day.weekday} ${day.date}`);\n lines.push(renderDay(day.items));\n }\n return { ok: true, message: lines.join('\\n') };\n }\n\n return { ok: false, message: 'Unsupported request.' };\n}\n\nmodule.exports = { run };\n",
158 "inputSchema": {},
159 "outputSchema": null,
160 "icons": null,
161 "annotations": null,
162 "meta": null,
163 "execution": null
164 },
165 {
166 "name": "migrate_cli.js",
167 "title": null,
168 "description": "Script: migrate_cli.js. Code:\n#!/usr/bin/env node\n\nconst { resolveWorkspaceRoot } = require('./workspace_root.js');\nconst { migrateKidSchedule, migrateLegacyZian } = require('./migrate.js');\n\nfunction usage() {\n process.stdout.write('student-timetable migrate\\n');\n process.stdout.write('Usage:\\n');\n process.stdout.write(' node skills/student-timetable/migrate_cli.js kid-schedule [--dry-run]\\n');\n process.stdout.write(' node skills/student-timetable/migrate_cli.js legacy-zian [--dry-run]\\n');\n}\n\nfunction parseArgs(argv) {\n const args = { _: [] };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--dry-run') args.dryRun = true;\n else args._.push(a);\n }\n return args;\n}\n\n(async function main() {\n const args = parseArgs(process.argv.slice(2));\n const cmd = args._[0];\n if (!cmd) {\n usage();\n process.exit(1);\n }\n\n const workspaceRoot = resolveWorkspaceRoot();\n let report;\n if (cmd === 'kid-schedule') {\n report = migrateKidSchedule(workspaceRoot, { dryRun: !!args.dryRun });\n } else if (cmd === 'legacy-zian') {\n report = migrateLegacyZian(workspaceRoot, { dryRun: !!args.dryRun });\n } else {\n usage();\n process.exit(1);\n }\n\n process.stdout.write(JSON.stringify(report, null, 2) + '\\n');\n})();\n",
169 "inputSchema": {},
170 "outputSchema": null,
171 "icons": null,
172 "annotations": null,
173 "meta": null,
174 "execution": null
175 },
176 {
177 "name": "init.js",
178 "title": null,
179 "description": "Script: init.js. Code:\nconst fs = require('fs');\nconst path = require('path');\nconst readline = require('readline');\n\nfunction normalizeToken(s) {\n return String(s || '')\n .trim()\n .replace(/\\s+/g, ' ');\n}\n\nfunction normalizeId(s) {\n return String(s || '')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9\\-]/g, '')\n .replace(/\\-+/g, '-')\n .replace(/^\\-+|\\-+$/g, '') || 'profile';\n}\n\nfunction nowIso() {\n return new Date().toISOString();\n}\n\nfunction writeJsonAtomic(p, obj) {\n fs.mkdirSync(path.dirname(p), { recursive: true });\n const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;\n fs.writeFileSync(tmp, JSON.stringify(obj, null, 2));\n fs.renameSync(tmp, p);\n}\n\nfunction exists(p) {\n try {\n fs.accessSync(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction ask(rl, q) {\n return new Promise((resolve) => rl.question(q, (ans) => resolve(ans)));\n}\n\nfunction emptyWeek() {\n return { mon: [], tue: [], wed: [], thu: [], fri: [], sat: [], sun: [] };\n}\n\nasync function interactiveInit(workspaceRoot) {\n const registryPath = path.join(workspaceRoot, 'schedules', 'profiles', 'registry.json');\n const registry = exists(registryPath)\n ? JSON.parse(fs.readFileSync(registryPath, 'utf8'))\n : { version: 1, dataRoot: 'schedules/profiles', profiles: [] };\n\n const existingIds = new Set((registry.profiles || []).map(p => String(p.profile_id || '')).filter(Boolean));\n\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n try {\n console.log('student-timetable init');\n console.log('');\n console.log('Who is this timetable for?');\n console.log(' 1) Myself (student)');\n console.log(' 2) My child / children (parent/guardian)');\n const mode = normalizeToken(await ask(rl, 'Choose 1 or 2: '));\n\n let profilesToCreate = [];\n\n if (mode === '1') {\n const name = normalizeToken(await ask(rl, 'Your name (display name): '));\n const aliasesRaw = normalizeToken(await ask(rl, 'Aliases (optional, comma-separated): '));\n const aliases = aliasesRaw ? aliasesRaw.split(',').map(a => normalizeToken(a)).filter(Boolean) : [];\n let profileId = normalizeId(name || 'self');\n if (existingIds.has(profileId)) {\n let i = 2;\n while (existingIds.has(`${profileId}-${i}`)) i++;\n profileId = `${profileId}-${i}`;\n }\n existingIds.add(profileId);\n profilesToCreate.push({ profile_id: profileId, type: 'self', display_name: name || 'Self', aliases });\n } else if (mode === '2') {\n const nRaw = normalizeToken(await ask(rl, 'How many children? '));\n const n = Math.max(1, parseInt(nRaw, 10) || 1);\n for (let i = 0; i < n; i++) {\n const name = normalizeToken(await ask(rl, `Child ${i + 1} name (display name): `));\n const aliasesRaw = normalizeToken(await ask(rl, 'Aliases (optional, comma-separated): '));\n const aliases = aliasesRaw ? aliasesRaw.split(',').map(a => normalizeToken(a)).filter(Boolean) : [];\n let profileId = normalizeId(name || `child-${i + 1}`);\n if (existingIds.has(profileId)) {\n let j = 2;\n while (existingIds.has(`${profileId}-${j}`)) j++;\n profileId = `${profileId}-${j}`;\n }\n existingIds.add(profileId);\n profilesToCreate.push({ profile_id: profileId, type: 'child', display_name: name || `Child ${i + 1}`, aliases });\n }\n } else {\n throw new Error('Invalid choice.');\n }\n\n console.log('');\n console.log('Recurrence:');\n console.log(' 1) every_week');\n console.log(' 2) biweekly (Week A / Week B)');\n const recChoice = normalizeToken(await ask(rl, 'Choose 1 or 2: '));\n\n let recurrence = { type: 'every_week' };\n if (recChoice === '2') {\n const startDate = normalizeToken(await ask(rl, 'Biweekly start_date (YYYY-MM-DD): '));\n recurrence = { type: 'biweekly', start_date: startDate };\n }\n\n // Minimal ingest: create empty templates; users edit JSON by hand or extend later.\n const createdAt = nowIso();\n for (const p of profilesToCreate) {\n const entry = {\n profile_id: p.profile_id,\n type: p.type,\n display_name: p.display_name,\n aliases: p.aliases,\n created_at: createdAt,\n updated_at: createdAt\n };\n registry.profiles.push(entry);\n\n const base = path.join(workspaceRoot, 'schedules', 'profiles', p.profile_id);\n const weeklyPath = path.join(base, 'weekly.json');\n const specialPath = path.join(base, 'special_events.json');\n const termPath = path.join(base, 'term_calendar.json');\n\n if (!exists(weeklyPath)) {\n const weeks = recurrence.type === 'biweekly'\n ? { week_a: emptyWeek(), week_b: emptyWeek() }\n : { default: emptyWeek() };\n writeJsonAtomic(weeklyPath, {\n version: 1,\n profile_id: p.profile_id,\n recurrence,\n timezone: 'Asia/Singapore',\n weeks\n });\n }\n\n if (!exists(specialPath)) {\n writeJsonAtomic(specialPath, { version: 1, profile_id: p.profile_id, events: [] });\n }\n\n if (!exists(termPath)) {\n writeJsonAtomic(termPath, { version: 1, profile_id: p.profile_id, timezone: 'Asia/Singapore', terms: [], no_school_days: [] });\n }\n\n console.log(`Created/verified: schedules/profiles/${p.profile_id}/weekly.json`);\n console.log(`Created/verified: schedules/profiles/${p.profile_id}/special_events.json`);\n console.log(`Created/verified: schedules/profiles/${p.profile_id}/term_calendar.json`);\n console.log('');\n }\n\n registry.version = 1;\n registry.dataRoot = 'schedules/profiles';\n writeJsonAtomic(registryPath, registry);\n\n console.log(`Registry written: schedules/profiles/registry.json`);\n } finally {\n rl.close();\n }\n}\n\nmodule.exports = { interactiveInit };\n",
180 "inputSchema": {},
181 "outputSchema": null,
182 "icons": null,
183 "annotations": null,
184 "meta": null,
185 "execution": null
186 },
187 {
188 "name": "migrate.js",
189 "title": null,
190 "description": "Script: migrate.js. Code:\nconst fs = require('fs');\nconst path = require('path');\n\nfunction readJson(p) {\n return JSON.parse(fs.readFileSync(p, 'utf8'));\n}\n\nfunction writeJsonAtomic(p, obj) {\n fs.mkdirSync(path.dirname(p), { recursive: true });\n const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;\n fs.writeFileSync(tmp, JSON.stringify(obj, null, 2));\n fs.renameSync(tmp, p);\n}\n\nfunction exists(p) {\n try {\n fs.accessSync(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction normalizeId(s) {\n return String(s || '')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9\\-]/g, '')\n .replace(/\\-+/g, '-')\n .replace(/^\\-+|\\-+$/g, '') || 'profile';\n}\n\nfunction nowIso() {\n return new Date().toISOString();\n}\n\nfunction ensureUniqueId(existingIds, desired) {\n let base = desired;\n let out = base;\n let i = 2;\n while (existingIds.has(out)) {\n out = `${base}-${i}`;\n i++;\n }\n existingIds.add(out);\n return out;\n}\n\nfunction backupDirName() {\n const d = new Date();\n const pad = (n) => String(n).padStart(2, '0');\n const stamp = `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;\n return `student-timetable-migrate-${stamp}`;\n}\n\nfunction copyFileIfExists(src, dst) {\n if (!exists(src)) return false;\n fs.mkdirSync(path.dirname(dst), { recursive: true });\n fs.copyFileSync(src, dst);\n return true;\n}\n\nfunction loadKidRegistry(workspaceRoot) {\n const p = path.join(workspaceRoot, 'schedules', 'kids', 'registry.json');\n if (!exists(p)) return { kids: [], _path: p };\n const data = readJson(p);\n if (Array.isArray(data)) return { kids: data, _path: p };\n return { kids: Array.isArray(data.kids) ? data.kids : [], _path: p };\n}\n\nfunction detectLegacyZianJson(workspaceRoot) {\n const schedulesDir = path.join(workspaceRoot, 'schedules');\n if (!exists(schedulesDir)) return [];\n const entries = fs.readdirSync(schedulesDir);\n const candidates = [];\n for (const name of entries) {\n if (!/^zian_.*\\.json$/i.test(name)) continue;\n const p = path.join(schedulesDir, name);\n if (!exists(p)) continue;\n try {\n const data = readJson(p);\n if (data && (data.weekly_timetable || data.special_events || data.term_calendar || data.events || data.terms)) {\n candidates.push({ path: p, data });\n }\n } catch {\n // ignore\n }\n }\n return candidates;\n}\n\nfunction convertOldWeeklyToNew(oldWeekly, profileId) {\n const weeklyTimetable = (oldWeekly && (oldWeekly.weekly_timetable || oldWeekly.weekly)) || {};\n // old keys like Monday\n const mapDay = {\n Monday: 'mon', Tuesday: 'tue', Wednesday: 'wed', Thursday: 'thu', Friday: 'fri', Saturday: 'sat', Sunday: 'sun'\n };\n const week = { mon: [], tue: [], wed: [], thu: [], fri: [], sat: [], sun: [] };\n\n for (const [k, items] of Object.entries(weeklyTimetable)) {\n const dk = mapDay[k] || String(k || '').toLowerCase().slice(0, 3);\n if (!week[dk] || !Array.isArray(items)) continue;\n for (const it of items) {\n const title = it && (it.title || it.subject || it.activity || it.name) ? String(it.title || it.subject || it.activity || it.name) : '';\n let start = '';\n let end = '';\n if (it && it.time) {\n const m = String(it.time).match(/(\\d{1,2}:\\d{2})\\s*-\\s*(\\d{1,2}:\\d{2})/);\n if (m) {\n start = m[1];\n end = m[2];\n }\n }\n week[dk].push({\n title,\n start_time: start,\n end_time: end,\n location: it && it.location ? String(it.location) : '',\n notes: it && it.notes ? String(it.notes) : ''\n });\n }\n }\n\n return {\n version: 1,\n profile_id: profileId,\n recurrence: { type: 'every_week' },\n timezone: 'Asia/Singapore',\n weeks: { default: week }\n };\n}\n\nfunction convertOldSpecialToNew(oldSpecial, profileId) {\n const events = Array.isArray(oldSpecial && oldSpecial.events) ? oldSpecial.events : [];\n const out = [];\n for (const ev of events) {\n const date = ev && ev.date ? String(ev.date) : (ev && ev.event_details && ev.event_details.date ? String(ev.event_details.date) : '');\n if (!date) continue;\n let start = '';\n let end = '';\n const time = ev.time || (ev.event_details && ev.event_details.time) || '';\n if (time) {\n const m = String(time).match(/(\\d{1,2}:\\d{2})\\s*-\\s*(\\d{1,2}:\\d{2})/);\n if (m) {\n start = m[1];\n end = m[2];\n }\n }\n out.push({\n id: ev.id ? String(ev.id) : `legacy-${normalizeId((ev.name || ev.title || 'event') + '-' + date)}`,\n date,\n title: ev.title ? String(ev.title) : (ev.name ? String(ev.name) : 'Special event'),\n start_time: ev.start_time ? String(ev.start_time) : start,\n end_time: ev.end_time ? String(ev.end_time) : end,\n location: ev.location ? String(ev.location) : '',\n notes: ev.notes ? String(ev.notes) : (ev.description ? String(ev.description) : ''),\n tags: Array.isArray(ev.tags) ? ev.tags.slice() : [],\n cancels_weekly: !!ev.cancels_weekly\n });\n }\n\n return { version: 1, profile_id: profileId, events: out };\n}\n\nfunction convertOldTermToNew(oldTerm, profileId) {\n return {\n version: 1,\n profile_id: profileId,\n timezone: 'Asia/Singapore',\n terms: Array.isArray(oldTerm && oldTerm.terms) ? oldTerm.terms : [],\n no_school_days: Array.isArray(oldTerm && oldTerm.holidays) ? oldTerm.holidays.map(h => ({ date: h.date || h, name: h.name || '' })) : []\n };\n}\n\nfunction loadNewRegistry(workspaceRoot) {\n const p = path.join(workspaceRoot, 'schedules', 'profiles', 'registry.json');\n if (!exists(p)) return { version: 1, dataRoot: 'schedules/profiles', profiles: [], _path: p };\n const data = readJson(p);\n return {\n version: typeof data.version === 'number' ? data.version : 1,\n dataRoot: data.dataRoot ? String(data.dataRoot) : 'schedules/profiles',\n profiles: Array.isArray(data.profiles) ? data.profiles : [],\n _path: p\n };\n}\n\nfunction migrateKidSchedule(workspaceRoot, opts = {}) {\n const dryRun = !!opts.dryRun;\n const backupsRoot = path.join(workspaceRoot, 'schedules', 'backups', backupDirName());\n\n const oldReg = loadKidRegistry(workspaceRoot);\n const newReg = loadNewRegistry(workspaceRoot);\n\n const existingIds = new Set((newReg.profiles || []).map(p => String(p.profile_id || '')).filter(Boolean));\n const report = { source: 'kid-schedule', dryRun, migrated: [], skipped: [], warnings: [], backupsRoot };\n\n for (const kid of oldReg.kids || []) {\n const oldId = kid && kid.id ? String(kid.id) : '';\n if (!oldId) continue;\n\n let profileId = normalizeId(oldId);\n\n // Special-case: historical kid-schedule data sometimes used zian-2/zian-3 etc.\n // Consolidate all of those into the canonical Zian child profile_id.\n if (profileId === 'zian-2' || profileId === 'zian-3' || profileId === 'zian-specialevents') {\n profileId = 'zian';\n }\n\n const already = (newReg.profiles || []).some(p => String(p.profile_id || '') === profileId);\n if (already) {\n report.skipped.push({ oldId, reason: 'already_migrated', profileId });\n continue;\n }\n\n profileId = ensureUniqueId(existingIds, profileId);\n\n const createdAt = nowIso();\n const prof = {\n profile_id: profileId,\n type: 'child',\n display_name: kid.display_name ? String(kid.display_name) : oldId,\n aliases: Array.isArray(kid.aliases) ? kid.aliases.slice() : [],\n created_at: createdAt,\n updated_at: createdAt\n };\n\n const oldBase = path.join(workspaceRoot, 'schedules', 'kids', oldId);\n const oldWeeklyPath = path.join(oldBase, 'weekly.json');\n const oldSpecialPath = path.join(oldBase, 'special_events.json');\n const oldTermPath = path.join(oldBase, 'term_calendar.json');\n\n const newBase = path.join(workspaceRoot, 'schedules', 'profiles', profileId);\n const newWeeklyPath = path.join(newBase, 'weekly.json');\n const newSpecialPath = path.join(newBase, 'special_events.json');\n const newTermPath = path.join(newBase, 'term_calendar.json');\n\n if (dryRun) {\n report.migrated.push({ oldId, profileId, outputs: [newWeeklyPath, newSpecialPath, newTermPath] });\n continue;\n }\n\n // backup any destination files that exist\n const bWeekly = path.join(backupsRoot, 'profiles', profileId, 'weekly.json');\n const bSpecial = path.join(backupsRoot, 'profiles', profileId, 'special_events.json');\n const bTerm = path.join(backupsRoot, 'profiles', profileId, 'term_calendar.json');\n copyFileIfExists(newWeeklyPath, bWeekly);\n copyFileIfExists(newSpecialPath, bSpecial);\n copyFileIfExists(newTermPath, bTerm);\n\n const oldWeekly = exists(oldWeeklyPath) ? readJson(oldWeeklyPath) : null;\n const oldSpecial = exists(oldSpecialPath) ? readJson(oldSpecialPath) : null;\n const oldTerm = exists(oldTermPath) ? readJson(oldTermPath) : null;\n\n const newWeekly = convertOldWeeklyToNew(oldWeekly, profileId);\n const newSpecial = convertOldSpecialToNew(oldSpecial, profileId);\n const newTerm = convertOldTermToNew(oldTerm, profileId);\n\n // only write if missing (idempotent + non-destructive)\n if (!exists(newWeeklyPath)) writeJsonAtomic(newWeeklyPath, newWeekly);\n if (!exists(newSpecialPath)) writeJsonAtomic(newSpecialPath, newSpecial);\n if (!exists(newTermPath)) writeJsonAtomic(newTermPath, newTerm);\n\n newReg.profiles.push(prof);\n\n report.migrated.push({ oldId, profileId, outputs: [newWeeklyPath, newSpecialPath, newTermPath] });\n }\n\n if (!dryRun) {\n // backup registry if it exists\n const bReg = path.join(backupsRoot, 'profiles', 'registry.json');\n copyFileIfExists(newReg._path, bReg);\n\n // write registry\n const regOut = {\n version: 1,\n dataRoot: 'schedules/profiles',\n profiles: newReg.profiles\n };\n writeJsonAtomic(newReg._path, regOut);\n }\n\n return report;\n}\n\nfunction migrateLegacyZian(workspaceRoot, opts = {}) {\n const dryRun = !!opts.dryRun;\n const backupsRoot = path.join(workspaceRoot, 'schedules', 'backups', backupDirName());\n\n const newReg = loadNewRegistry(workspaceRoot);\n const existingIds = new Set((newReg.profiles || []).map(p => String(p.profile_id || '')).filter(Boolean));\n\n const candidates = detectLegacyZianJson(workspaceRoot);\n const report = { source: 'legacy-zian-json', dryRun, migrated: [], skipped: [], warnings: [], backupsRoot };\n\n if (!candidates.length) return report;\n\n // For v1: migrate all legacy zian JSON into a single canonical child profile.\n // profile_id represents the person (Zian), not the data source.\n const profileId = 'zian';\n\n if ((newReg.profiles || []).some(p => String(p.profile_id || '') === profileId)) {\n report.skipped.push({ profileId, reason: 'profile_exists' });\n return report;\n }\n\n const createdAt = nowIso();\n const prof = {\n profile_id: profileId,\n type: 'child',\n display_name: 'Zian',\n aliases: ['zian'],\n created_at: createdAt,\n updated_at: createdAt\n };\n\n const newBase = path.join(workspaceRoot, 'schedules', 'profiles', profileId);\n const newWeeklyPath = path.join(newBase, 'weekly.json');\n const newSpecialPath = path.join(newBase, 'special_events.json');\n const newTermPath = path.join(newBase, 'term_calendar.json');\n\n if (dryRun) {\n report.migrated.push({ profileId, inputs: candidates.map(c => c.path), outputs: [newWeeklyPath, newSpecialPath, newTermPath] });\n return report;\n }\n\n // backup any destination files that exist\n copyFileIfExists(newWeeklyPath, path.join(backupsRoot, 'profiles', profileId, 'weekly.json'));\n copyFileIfExists(newSpecialPath, path.join(backupsRoot, 'profiles', profileId, 'special_events.json'));\n copyFileIfExists(newTermPath, path.join(backupsRoot, 'profiles', profileId, 'term_calendar.json'));\n\n // best-effort merge: pick first candidate with those keys\n let oldWeekly = null;\n let oldSpecial = null;\n let oldTerm = null;\n for (const c of candidates) {\n const d = c.data;\n if (!oldWeekly && d && d.weekly_timetable) oldWeekly = d;\n if (!oldSpecial && d && (d.special_events || d.events)) oldSpecial = d.special_events ? d.special_events : d;\n if (!oldTerm && d && (d.term_calendar || d.terms)) oldTerm = d.term_calendar ? d.term_calendar : d;\n }\n\n // If destination exists, we still proceed safely:\n // - create backups\n // - overwrite destination so legacy zian content can be migrated even under \"missing-only\" behavior\n writeJsonAtomic(newWeeklyPath, convertOldWeeklyToNew(oldWeekly, profileId));\n writeJsonAtomic(newSpecialPath, convertOldSpecialToNew(oldSpecial, profileId));\n writeJsonAtomic(newTermPath, convertOldTermToNew(oldTerm, profileId));\n\n newReg.profiles.push(prof);\n\n // backup registry if it exists\n copyFileIfExists(newReg._path, path.join(backupsRoot, 'profiles', 'registry.json'));\n writeJsonAtomic(newReg._path, { version: 1, dataRoot: 'schedules/profiles', profiles: newReg.profiles });\n\n report.migrated.push({ profileId, inputs: candidates.map(c => c.path), outputs: [newWeeklyPath, newSpecialPath, newTermPath] });\n report.warnings.push('Legacy zian migration writes to canonical profile_id \"zian\" (child).');\n return report;\n}\n\nmodule.exports = { migrateKidSchedule, migrateLegacyZian };\n",
191 "inputSchema": {},
192 "outputSchema": null,
193 "icons": null,
194 "annotations": null,
195 "meta": null,
196 "execution": null
197 },
198 {
199 "name": "student_timetable_service.js",
200 "title": null,
201 "description": "Script: student_timetable_service.js. Code:\nconst { loadProfileScheduleFiles } = require('./schedule_store.js');\nconst { formatISODate, addDays, weekStartMonday, startOfDay } = require('./date_utils.js');\n\nconst DOW_KEYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];\n\nfunction weekdayKey(date) {\n const js = date.getDay();\n // JS: 0 Sun .. 6 Sat\n if (js === 0) return 'sun';\n if (js === 1) return 'mon';\n if (js === 2) return 'tue';\n if (js === 3) return 'wed';\n if (js === 4) return 'thu';\n if (js === 5) return 'fri';\n return 'sat';\n}\n\nfunction parseHHMM(s) {\n const m = String(s || '').match(/^(\\d{1,2}):(\\d{2})$/);\n if (!m) return null;\n const hh = parseInt(m[1], 10);\n const mm = parseInt(m[2], 10);\n if (hh < 0 || hh > 23 || mm < 0 || mm > 59) return null;\n return hh * 60 + mm;\n}\n\nfunction overlapsRange(aStart, aEnd, bStart, bEnd) {\n if (aStart == null || aEnd == null || bStart == null || bEnd == null) return false;\n return Math.max(aStart, bStart) < Math.min(aEnd, bEnd);\n}\n\nfunction weekIndexForDate(startDateISO, date) {\n const anchor = new Date(`${startDateISO}T00:00:00`);\n const aMon = weekStartMonday(anchor);\n const dMon = weekStartMonday(date);\n const diffMs = dMon.getTime() - aMon.getTime();\n const diffDays = Math.round(diffMs / (24 * 60 * 60 * 1000));\n return Math.floor(diffDays / 7);\n}\n\nfunction normalizeWeeklyEvents(weekly, date) {\n if (!weekly) return [];\n const rec = weekly.recurrence || { type: 'every_week' };\n const type = rec.type || 'every_week';\n const key = weekdayKey(date);\n\n let dayItems = [];\n\n if (type === 'every_week') {\n const w = weekly.weeks && weekly.weeks.default ? weekly.weeks.default : null;\n dayItems = (w && Array.isArray(w[key])) ? w[key] : [];\n } else if (type === 'biweekly') {\n const startDate = rec.start_date;\n if (!startDate) return [];\n const idx = weekIndexForDate(startDate, date);\n const which = (idx % 2 === 0) ? 'week_a' : 'week_b';\n const w = weekly.weeks && weekly.weeks[which] ? weekly.weeks[which] : null;\n dayItems = (w && Array.isArray(w[key])) ? w[key] : [];\n } else {\n return [];\n }\n\n const out = [];\n for (const it of dayItems) {\n out.push({\n date: formatISODate(date),\n weekday: key,\n title: it && it.title ? String(it.title) : '',\n start_time: it && it.start_time ? String(it.start_time) : '',\n end_time: it && it.end_time ? String(it.end_time) : '',\n location: it && it.location ? String(it.location) : '',\n notes: it && it.notes ? String(it.notes) : '',\n source: 'weekly',\n raw: it\n });\n }\n return out;\n}\n\nfunction specialEventsOnDate(special, date) {\n if (!special) return [];\n const target = formatISODate(date);\n const events = Array.isArray(special.events) ? special.events : [];\n const out = [];\n for (const ev of events) {\n if (!ev || String(ev.date || '') !== target) continue;\n out.push({\n date: target,\n weekday: weekdayKey(date),\n id: ev.id ? String(ev.id) : '',\n title: ev.title ? String(ev.title) : 'Special event',\n start_time: ev.start_time ? String(ev.start_time) : '',\n end_time: ev.end_time ? String(ev.end_time) : '',\n location: ev.location ? String(ev.location) : '',\n notes: ev.notes ? String(ev.notes) : '',\n tags: Array.isArray(ev.tags) ? ev.tags.slice() : [],\n cancels_weekly: !!ev.cancels_weekly,\n source: 'special',\n raw: ev\n });\n }\n return out;\n}\n\nfunction applyCancelsWeekly(weeklyItems, specialItems) {\n const cancelers = specialItems.filter(e => e && e.cancels_weekly);\n if (!cancelers.length) return weeklyItems;\n\n // v1: if cancel event has no times, cancel all weekly items for that day.\n const cancelsAllDay = cancelers.some(c => !c.start_time || !c.end_time);\n if (cancelsAllDay) return [];\n\n return weeklyItems.filter(w => {\n const wS = parseHHMM(w.start_time);\n const wE = parseHHMM(w.end_time);\n for (const c of cancelers) {\n const cS = parseHHMM(c.start_time);\n const cE = parseHHMM(c.end_time);\n if (overlapsRange(wS, wE, cS, cE)) return false;\n }\n return true;\n });\n}\n\nfunction sortByTime(items) {\n return items.slice().sort((a, b) => {\n const am = parseHHMM(a.start_time);\n const bm = parseHHMM(b.start_time);\n if (am == null && bm == null) return String(a.title).localeCompare(String(b.title));\n if (am == null) return 1;\n if (bm == null) return -1;\n if (am !== bm) return am - bm;\n return String(a.title).localeCompare(String(b.title));\n });\n}\n\nfunction dayScheduleForProfile(workspaceRoot, profileId, date) {\n const { weekly, special } = loadProfileScheduleFiles(workspaceRoot, profileId);\n const weeklyItems = normalizeWeeklyEvents(weekly, date);\n const specialItems = specialEventsOnDate(special, date);\n const keptWeekly = applyCancelsWeekly(weeklyItems, specialItems);\n return sortByTime(keptWeekly.concat(specialItems));\n}\n\nfunction weekScheduleForProfile(workspaceRoot, profileId, anchorDate, which) {\n const monday = weekStartMonday(anchorDate);\n const start = which === 'next' ? addDays(monday, 7) : monday;\n const days = [];\n for (let i = 0; i < 7; i++) {\n const d = addDays(start, i);\n days.push({ date: formatISODate(d), weekday: weekdayKey(d), items: dayScheduleForProfile(workspaceRoot, profileId, d) });\n }\n return { week_start: formatISODate(start), days };\n}\n\nfunction todayDate() {\n return startOfDay(new Date());\n}\n\nmodule.exports = {\n dayScheduleForProfile,\n weekScheduleForProfile,\n todayDate,\n weekdayKey\n};\n",
202 "inputSchema": {},
203 "outputSchema": null,
204 "icons": null,
205 "annotations": null,
206 "meta": null,
207 "execution": null
208 }
209 ]
210 },
211 "error": null
212 }
213 ],
214 "issues": [
215 {
216 "code": "W004",
217 "message": "The MCP server is not in our registry.",
218 "reference": [
219 0,
220 null
221 ],
222 "extra_data": null
223 }
224 ],
225 "labels": [
226 [
227 {
228 "is_public_sink": 0,
229 "destructive": 0,
230 "untrusted_content": 0,
231 "private_data": 0
232 },
233 {
234 "is_public_sink": 0,
235 "destructive": 0,
236 "untrusted_content": 0,
237 "private_data": 0
238 },
239 {
240 "is_public_sink": 0,
241 "destructive": 0,
242 "untrusted_content": 0,
243 "private_data": 0
244 },
245 {
246 "is_public_sink": 0,
247 "destructive": 0,
248 "untrusted_content": 0,
249 "private_data": 0
250 },
251 {
252 "is_public_sink": 0,
253 "destructive": 0,
254 "untrusted_content": 0,
255 "private_data": 0
256 },
257 {
258 "is_public_sink": 0,
259 "destructive": 0,
260 "untrusted_content": 0,
261 "private_data": 0
262 },
263 {
264 "is_public_sink": 0,
265 "destructive": 0,
266 "untrusted_content": 0,
267 "private_data": 0
268 },
269 {
270 "is_public_sink": 0,
271 "destructive": 0,
272 "untrusted_content": 0,
273 "private_data": 0
274 },
275 {
276 "is_public_sink": 0,
277 "destructive": 0,
278 "untrusted_content": 0,
279 "private_data": 0
280 },
281 {
282 "is_public_sink": 0,
283 "destructive": 0,
284 "untrusted_content": 0,
285 "private_data": 0
286 },
287 {
288 "is_public_sink": 0,
289 "destructive": 0,
290 "untrusted_content": 0,
291 "private_data": 0
292 },
293 {
294 "is_public_sink": 0,
295 "destructive": 0,
296 "untrusted_content": 0,
297 "private_data": 0
298 },
299 {
300 "is_public_sink": 0,
301 "destructive": 0,
302 "untrusted_content": 0,
303 "private_data": 0
304 },
305 {
306 "is_public_sink": 0,
307 "destructive": 0,
308 "untrusted_content": 0,
309 "private_data": 0
310 },
311 {
312 "is_public_sink": 0,
313 "destructive": 0,
314 "untrusted_content": 0,
315 "private_data": 0
316 }
317 ]
318 ],
319 "error": null
320 }
321}
322
323Process exited with code 0
324✓ Completed in 154318ms
npm-audit
No package.json found — skipping npm audit
No package.json found — skipping npm audit
View logs
npm-audit0ms
1No package.json found at /tmp/clawguard-scan-II4u63/repo/skills/extraterrest/student-timetable/package.json
2Skipping npm audit.

Scanned: 2/18/2026, 10:14:11 AM