pi-gitnexus-fork 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/.github/workflows/ci.yml +20 -0
  2. package/.gitnexusignore +11 -0
  3. package/.sg-rules/async-function-must-await-or-return.yml +55 -0
  4. package/.sg-rules/catch-must-log-error.yml +78 -0
  5. package/.sg-rules/class-must-implement-or-extend.yml +61 -0
  6. package/.sg-rules/class-property-must-be-readonly.yml +61 -0
  7. package/.sg-rules/error-must-extend-base.yml +56 -0
  8. package/.sg-rules/generic-must-be-constrained.yml +60 -0
  9. package/.sg-rules/import-reexport-risk.yml +9 -0
  10. package/.sg-rules/missing-session-id-in-api.yml +16 -0
  11. package/.sg-rules/no-any-in-generic-args.yml +57 -0
  12. package/.sg-rules/no-await-in-promise-all.yml +28 -0
  13. package/.sg-rules/no-barrel-export.yml +17 -0
  14. package/.sg-rules/no-bq-write-in-module.yml +65 -0
  15. package/.sg-rules/no-console-except-error.yml +27 -0
  16. package/.sg-rules/no-console-in-server.yml +42 -0
  17. package/.sg-rules/no-empty-catch.yml +20 -0
  18. package/.sg-rules/no-empty-function.yml +24 -0
  19. package/.sg-rules/no-eval.yml +28 -0
  20. package/.sg-rules/no-explicit-any.yml +34 -0
  21. package/.sg-rules/no-hardcoded-placeholder-string.yml +23 -0
  22. package/.sg-rules/no-hardcoded-secrets.yml +32 -0
  23. package/.sg-rules/no-innerHTML.yml +22 -0
  24. package/.sg-rules/no-json-parse-without-trycatch.yml +33 -0
  25. package/.sg-rules/no-magic-numbers.yml +25 -0
  26. package/.sg-rules/no-nested-ternary.yml +21 -0
  27. package/.sg-rules/no-non-null-assertion.yml +25 -0
  28. package/.sg-rules/no-stub-implementation.yml +44 -0
  29. package/.sg-rules/no-throw-literal.yml +50 -0
  30. package/.sg-rules/no-todo-comment.yml +24 -0
  31. package/.sg-rules/no-ts-ignore-comment.yml +48 -0
  32. package/.sg-rules/no-type-assertion-in-jsx.yml +23 -0
  33. package/.sg-rules/no-unguarded-trim.yml +24 -0
  34. package/.sg-rules/no-unknown-without-narrowing.yml +76 -0
  35. package/.sg-rules/no-unsafe-bracket-access.yml +58 -0
  36. package/.sg-rules/no-unsafe-type-assertion.yml +45 -0
  37. package/.sg-rules/switch-must-be-exhaustive.yml +62 -0
  38. package/.sg-rules/zod-async-refine-without-abort.yml +62 -0
  39. package/.sg-rules/zod-enum-unsafe-access.yml +59 -0
  40. package/.sg-rules/zod-nested-object-deep-path.yml +70 -0
  41. package/.sg-rules/zod-optional-without-default-in-route.yml +50 -0
  42. package/.sg-rules/zod-parse-not-safe.yml +42 -0
  43. package/.sg-rules/zod-preprocess-without-fallback.yml +58 -0
  44. package/.sg-rules/zod-refine-no-return-undefined.yml +54 -0
  45. package/.sg-rules/zod-transform-without-output-type.yml +52 -0
  46. package/.sg-sha +1 -0
  47. package/.sgignore +4 -0
  48. package/AGENTS.md +1 -0
  49. package/CHANGELOG.md +99 -0
  50. package/LICENSE +21 -0
  51. package/README.md +113 -0
  52. package/biome.json +25 -0
  53. package/coverage/base.css +224 -0
  54. package/coverage/block-navigation.js +87 -0
  55. package/coverage/clover.xml +890 -0
  56. package/coverage/coverage-final.json +12 -0
  57. package/coverage/favicon.png +0 -0
  58. package/coverage/index.html +131 -0
  59. package/coverage/prettify.css +1 -0
  60. package/coverage/prettify.js +2 -0
  61. package/coverage/sort-arrow-sprite.png +0 -0
  62. package/coverage/sorter.js +210 -0
  63. package/coverage/src/augment-remote.ts.html +274 -0
  64. package/coverage/src/gitnexus.ts.html +1363 -0
  65. package/coverage/src/index.html +236 -0
  66. package/coverage/src/index.ts.html +1561 -0
  67. package/coverage/src/mcp-client-factory.ts.html +367 -0
  68. package/coverage/src/mcp-client-stdio.ts.html +736 -0
  69. package/coverage/src/mcp-client.ts.html +568 -0
  70. package/coverage/src/remote-mcp-client.ts.html +709 -0
  71. package/coverage/src/repo-resolver.ts.html +526 -0
  72. package/coverage/src/tools.ts.html +970 -0
  73. package/coverage/src/ui/index.html +131 -0
  74. package/coverage/src/ui/main-menu.ts.html +502 -0
  75. package/coverage/src/ui/settings-menu.ts.html +460 -0
  76. package/dist/augment-remote.d.ts +11 -0
  77. package/dist/augment-remote.js +55 -0
  78. package/dist/gitnexus.d.ts +103 -0
  79. package/dist/gitnexus.js +410 -0
  80. package/dist/index.d.ts +2 -0
  81. package/dist/index.js +479 -0
  82. package/dist/mcp-client-factory.d.ts +19 -0
  83. package/dist/mcp-client-factory.js +78 -0
  84. package/dist/mcp-client-stdio.d.ts +35 -0
  85. package/dist/mcp-client-stdio.js +186 -0
  86. package/dist/mcp-client.d.ts +45 -0
  87. package/dist/mcp-client.js +145 -0
  88. package/dist/remote-mcp-client.d.ts +43 -0
  89. package/dist/remote-mcp-client.js +181 -0
  90. package/dist/repo-resolver.d.ts +47 -0
  91. package/dist/repo-resolver.js +123 -0
  92. package/dist/tools.d.ts +6 -0
  93. package/dist/tools.js +230 -0
  94. package/dist/ui/main-menu.d.ts +33 -0
  95. package/dist/ui/main-menu.js +102 -0
  96. package/dist/ui/settings-menu.d.ts +16 -0
  97. package/dist/ui/settings-menu.js +95 -0
  98. package/docs/design/remote-mcp-backend.md +153 -0
  99. package/media/screenshot.png +0 -0
  100. package/package.json +61 -0
  101. package/sgconfig.yml +4 -0
  102. package/skills/gitnexus-debugging/SKILL.md +84 -0
  103. package/skills/gitnexus-exploring/SKILL.md +73 -0
  104. package/skills/gitnexus-impact-analysis/SKILL.md +93 -0
  105. package/skills/gitnexus-pr-review/SKILL.md +109 -0
  106. package/skills/gitnexus-refactoring/SKILL.md +85 -0
  107. package/src/augment-remote.ts +63 -0
  108. package/src/gitnexus.ts +426 -0
  109. package/src/index.ts +492 -0
  110. package/src/mcp-client-factory.ts +94 -0
  111. package/src/mcp-client-stdio.ts +217 -0
  112. package/src/mcp-client.ts +208 -0
  113. package/src/remote-mcp-client.ts +250 -0
  114. package/src/repo-resolver.ts +147 -0
  115. package/src/tools.ts +295 -0
  116. package/src/ui/main-menu.ts +139 -0
  117. package/src/ui/settings-menu.ts +125 -0
@@ -0,0 +1,42 @@
1
+ # SOURCE: https://getpino.io/#/docs/api?id=logger
2
+ # "Pino is a structured JSON logger. Use it instead of console for production logging.
3
+ # console.log produces unstructured output that's hard to query in log aggregation systems."
4
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-4794/
5
+ # SonarQube S4794: "Using console logging in production code is a security and performance risk."
6
+ # Rationale: This is the server-side companion to no-console-except-error (which is in common/).
7
+ # Server code should ALWAYS use pino (injected via Fastify request.log or a shared logger).
8
+ #
9
+ # REFINED: Only flags console.log, console.debug, console.trace, console.info.
10
+ # console.error and console.warn are legitimate error/warning logging and are NOT flagged.
11
+ id: no-console-in-server
12
+ language: typescript
13
+ message: "console.log/debug/info/trace in server code — use request.log (Fastify pino) or the shared logger instead. Structured logs are required for Cloud Run log aggregation."
14
+ severity: warning
15
+ note: |
16
+ Flags unstructured console output (log, debug, trace, info) in server-side code.
17
+ These produce output without: request ID, timestamp, trace context, or log level.
18
+
19
+ console.error and console.warn are NOT flagged — they are legitimate for error/warning
20
+ logging and produce properly tagged output (stderr with error/warn level markers).
21
+ rule:
22
+ pattern: console.$METHOD($$$)
23
+ constraints:
24
+ METHOD:
25
+ # Only unstructured output methods — NOT error or warn
26
+ regex: '^(log|debug|trace|info)$'
27
+ paths:
28
+ - '**/api/**'
29
+ - '**/server/**'
30
+ - '**/routes/**'
31
+ - '**/src/index.ts'
32
+ - '**/src/app.ts'
33
+ - '**/src/server.ts'
34
+ ignores:
35
+ - '**/*.test.ts'
36
+ - '**/*.spec.ts'
37
+ - '**/test/**'
38
+ - '**/tests/**'
39
+ - '**/__tests__/**'
40
+ - '**/scripts/**'
41
+ - '**/migrations/**'
42
+ - 'test-*.ts'
@@ -0,0 +1,20 @@
1
+ # SOURCE: https://eslint.org/docs/latest/rules/no-empty
2
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-108/
3
+ id: no-empty-catch
4
+ message: Empty catch block silently swallows errors — handle the error or add a comment explaining why it's intentionally ignored
5
+ severity: warning
6
+ language: TypeScript
7
+ note: Mirrors ESLint no-empty and SonarQube S108. Catch blocks with comments are acceptable.
8
+ rule:
9
+ kind: statement_block
10
+ pattern: '{}'
11
+ inside:
12
+ kind: catch_clause
13
+ ignores:
14
+ - '**/*.test.ts'
15
+ - '**/*.spec.ts'
16
+ - '**/test/**'
17
+ - '**/tests/**'
18
+ - '**/__tests__/**'
19
+ - '**/scripts/**'
20
+ - 'test-*.ts'
@@ -0,0 +1,24 @@
1
+ # SOURCE: https://eslint.org/docs/latest/rules/no-empty-function
2
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-1186/
3
+ id: no-empty-function
4
+ message: Empty function body — either implement, add a comment explaining why empty, or throw NotImplementedError
5
+ severity: warning
6
+ language: TypeScript
7
+ note: Mirrors ESLint no-empty-function and SonarQube S1186. Empty functions with comments inside are acceptable.
8
+ rule:
9
+ kind: statement_block
10
+ pattern: '{}'
11
+ inside:
12
+ any:
13
+ - kind: function_declaration
14
+ - kind: function_expression
15
+ - kind: arrow_function
16
+ - kind: method_definition
17
+ ignores:
18
+ - '**/*.test.ts'
19
+ - '**/*.spec.ts'
20
+ - '**/test/**'
21
+ - '**/tests/**'
22
+ - '**/__tests__/**'
23
+ - '**/scripts/**'
24
+ - 'test-*.ts'
@@ -0,0 +1,28 @@
1
+ # SOURCE: https://eslint.org/docs/latest/rules/no-eval
2
+ # ESLint no-eval: "Eliminate eval() and its counterparts."
3
+ # SOURCE: https://rules.sonarsource.com/javascript/RSPEC-1528/
4
+ # SonarQube S1528: "eval" and "new Function" should not be used.
5
+ # SOURCE: https://ast-grep.github.io/catalog/typescript/no-eval.html
6
+ # ast-grep catalog rule for eval detection.
7
+ id: no-eval
8
+ language: TypeScript
9
+ message: "Avoid eval() / new Function() / setTimeout(string) / setInterval(string) — code injection risk"
10
+ severity: error
11
+ note: "Mirrors ESLint no-eval and SonarQube S1528. String arguments to setTimeout/setInterval act as eval."
12
+ rule:
13
+ any:
14
+ - pattern: eval($$$ARGS)
15
+ - pattern: new Function($$$ARGS)
16
+ - pattern: setTimeout($STR, $$$)
17
+ - pattern: setInterval($STR, $$$)
18
+ constraints:
19
+ STR:
20
+ kind: string
21
+ # Only match when first arg is a string literal (not a function reference)
22
+ ignores:
23
+ - '**/*.test.ts'
24
+ - '**/*.spec.ts'
25
+ - '**/test/**'
26
+ - '**/tests/**'
27
+ - '**/__tests__/**'
28
+ - '**/scripts/**'
@@ -0,0 +1,34 @@
1
+ # SOURCE: https://typescript-eslint.io/rules/no-explicit-any/
2
+ # @typescript-eslint/no-explicit-any: "Disallow the any type."
3
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-4328/
4
+ # SonarQube S4328: "ANY type should not be used."
5
+ # SOURCE: https://google.github.io/styleguide/tsguide.html#typescript
6
+ # Google TypeScript Style Guide: "Avoid using any."
7
+ id: no-explicit-any
8
+ language: TypeScript
9
+ message: "Avoid explicit any — use a proper type, generic, or unknown"
10
+ severity: warning
11
+ note: "Mirrors @typescript-eslint/no-explicit-any and SonarQube S4328. any disables all type safety."
12
+ rule:
13
+ any:
14
+ - pattern: $X as any
15
+ - kind: predefined_type
16
+ pattern: any
17
+ inside:
18
+ any:
19
+ - kind: type_annotation
20
+ - kind: type_arguments
21
+ - kind: as_expression
22
+ - kind: tuple_type
23
+ - kind: array_type
24
+ - kind: union_type
25
+ - kind: intersection_type
26
+ ignores:
27
+ - '**/*.test.ts'
28
+ - '**/*.spec.ts'
29
+ - '**/test/**'
30
+ - '**/tests/**'
31
+ - '**/__tests__/**'
32
+ - '**/scripts/**'
33
+ - 'test-*.ts'
34
+ - '**/*.d.ts'
@@ -0,0 +1,23 @@
1
+ # SOURCE: https://eslint.org/docs/latest/rules/no-magic-numbers
2
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-131/ (magic numbers)
3
+ id: no-hardcoded-placeholder-string
4
+ message: Hardcoded placeholder string detected — replace with actual value or configuration
5
+ severity: warning
6
+ language: TypeScript
7
+ note: Detects strings containing placeholder markers like TODO, FIXME, INSERT, REPLACE, STUB, PLACEHOLDER in production code.
8
+ rule:
9
+ any:
10
+ - pattern: '"$VALUE"'
11
+ - pattern: "'$VALUE'"
12
+ constraints:
13
+ VALUE:
14
+ regex: '(?i)^(TODO|FIXME|STUB|PLACEHOLDER|INSERT .+|REPLACE .+|NOT IMPLEMENTED)$'
15
+ ignores:
16
+ - '**/*.test.ts'
17
+ - '**/*.spec.ts'
18
+ - '**/test/**'
19
+ - '**/tests/**'
20
+ - '**/__tests__/**'
21
+ - '**/__mocks__/**'
22
+ - '**/scripts/**'
23
+ - 'test-*.ts'
@@ -0,0 +1,32 @@
1
+ # SOURCE: https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml
2
+ # Gitleaks default config: regex patterns for passwords, API keys, tokens, private keys.
3
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-2068/
4
+ # SonarQube S2068: "Hardcoded credentials should not be used in source code."
5
+ # SOURCE: https://github.com/returntocorp/semgrep-rules/blob/main/javascript/lang/security/no-hardcoded-secrets.yaml
6
+ # Semgrep community rule for hardcoded secret detection.
7
+ id: no-hardcoded-secrets
8
+ language: TypeScript
9
+ message: "Hardcoded credentials detected — use environment variables or secrets manager"
10
+ severity: error
11
+ note: "Mirrors Gitleaks, SonarQube S2068, and Semgrep no-hardcoded-secrets. Catches password/secret/token/credential patterns."
12
+ rule:
13
+ any:
14
+ - pattern: const $KEY = '$VAL'
15
+ - pattern: $OBJ['$KEY'] = '$VAL'
16
+ - pattern: $OBJ.$KEY = '$VAL'
17
+ constraints:
18
+ KEY:
19
+ regex: '(?i)(password|secret|api[_-]?key|token|credential|private[_-]?key|auth[_-]?key|access[_-]?key)'
20
+ VAL:
21
+ regex: '[a-zA-Z0-9+/=_-]{8,}'
22
+ ignores:
23
+ - '**/*.test.ts'
24
+ - '**/*.spec.ts'
25
+ - '**/test/**'
26
+ - '**/tests/**'
27
+ - '**/__tests__/**'
28
+ - '**/__mocks__/**'
29
+ - '**/scripts/**'
30
+ - 'test-*.ts'
31
+ - '**/*.example*'
32
+ - '**/*.md'
@@ -0,0 +1,22 @@
1
+ # SOURCE: https://github.com/mozilla/eslint-plugin-no-unsanitized/blob/master/rules/no-unsanitized-property.md
2
+ # Mozilla eslint-plugin-no-unsanitized: flags innerHTML/outerHTML assignments with unsanitized values.
3
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-2819/
4
+ # SonarQube S2819: "DOM properties should not be misused — innerHTML with untrusted data is XSS."
5
+ # SOURCE: https://websitesecurityscanner.org/alerts/dom-xss-innerhtml/
6
+ # DOM XSS via innerHTML is OWASP A03:2021 Injection.
7
+ id: no-innerHTML
8
+ language: TypeScript
9
+ message: "Avoid .innerHTML / .outerHTML assignment — XSS risk, use textContent or DOM API"
10
+ severity: error
11
+ note: "Mirrors Mozilla no-unsanitized and SonarQube S2819. Direct innerHTML assignment is the #1 DOM XSS vector."
12
+ rule:
13
+ any:
14
+ - pattern: $EL.innerHTML = $VAL
15
+ - pattern: $EL.outerHTML = $VAL
16
+ ignores:
17
+ - '**/*.test.ts'
18
+ - '**/*.spec.ts'
19
+ - '**/test/**'
20
+ - '**/tests/**'
21
+ - '**/__tests__/**'
22
+ - '**/scripts/**'
@@ -0,0 +1,33 @@
1
+ # SOURCE: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
2
+ # "JSON.parse() throws SyntaxError if the string is not valid JSON."
3
+ # SOURCE: https://typescript-eslint.io/rules/no-unsafe-assignment/
4
+ # TypeScript ESLint: unvalidated external data is a security risk.
5
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-4715/
6
+ # SonarQube S4715: "JSON.parse should not be used without error handling."
7
+ #
8
+ # NOTE: framework/bun/safe-json-parse.yml covers this for Bun projects.
9
+ # This rule covers the general TypeScript case (Node.js, Fastify, React).
10
+ id: no-json-parse-without-trycatch
11
+ language: typescript
12
+ message: "JSON.parse without try/catch — throws SyntaxError on malformed input. Wrap in try/catch or use safeParse-style helper"
13
+ severity: warning
14
+ note: |
15
+ JSON.parse() is the only standard JSON parser in JS and it throws on any invalid input.
16
+ In server-side code, malformed JSON from external sources (request bodies, config files,
17
+ external APIs) will crash the handler. Wrap in try/catch with a descriptive error message.
18
+ rule:
19
+ pattern: JSON.parse($ARG)
20
+ not:
21
+ inside:
22
+ kind: try_statement
23
+ has:
24
+ kind: catch_clause
25
+ stopBy: end
26
+ ignores:
27
+ - '**/*.test.ts'
28
+ - '**/*.spec.ts'
29
+ - '**/test/**'
30
+ - '**/tests/**'
31
+ - '**/__tests__/**'
32
+ - '**/scripts/**'
33
+ - 'test-*.ts'
@@ -0,0 +1,25 @@
1
+ # SOURCE: https://eslint.org/docs/latest/rules/no-magic-numbers
2
+ # ESLint no-magic-numbers: "Disallow magic numbers — numbers should be named constants."
3
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-1094/
4
+ # SonarQube S109: "Magic numbers should not be used."
5
+ id: no-magic-numbers
6
+ language: TypeScript
7
+ message: "Magic number detected — extract to a named constant"
8
+ severity: hint
9
+ note: "Mirrors ESLint no-magic-numbers and SonarQube S109. Flags numeric literals > 1 in comparisons."
10
+ rule:
11
+ pattern: $X === $NUM
12
+ constraints:
13
+ NUM:
14
+ regex: '[2-9]'
15
+ ignores:
16
+ - '**/*.test.ts'
17
+ - '**/*.spec.ts'
18
+ - '**/test/**'
19
+ - '**/tests/**'
20
+ - '**/__tests__/**'
21
+ - '**/scripts/**'
22
+ - 'test-*.ts'
23
+ - '**/*.d.ts'
24
+ - '**/const*'
25
+ - '**/constants*'
@@ -0,0 +1,21 @@
1
+ # SOURCE: https://eslint.org/docs/latest/rules/no-nested-ternary
2
+ # ESLint no-nested-ternary: "Disallow nested ternary expressions."
3
+ # SOURCE: https://github.com/airbnb/javascript/blob/master/packages/eslint-config-airbnb-base/rules/style.js
4
+ # Airbnb style guide: "Ternaries should not be nested."
5
+ id: no-nested-ternary
6
+ language: TypeScript
7
+ message: "Avoid nested ternary — extract to a variable or use if/else"
8
+ severity: warning
9
+ note: "Mirrors ESLint no-nested-ternary and Airbnb style guide. Nested ternaries are unreadable."
10
+ rule:
11
+ kind: ternary_expression
12
+ has:
13
+ kind: ternary_expression
14
+ ignores:
15
+ - '**/*.test.ts'
16
+ - '**/*.spec.ts'
17
+ - '**/test/**'
18
+ - '**/tests/**'
19
+ - '**/__tests__/**'
20
+ - '**/scripts/**'
21
+ - 'test-*.ts'
@@ -0,0 +1,25 @@
1
+ # SOURCE: https://typescript-eslint.io/rules/no-non-null-assertion/
2
+ # @typescript-eslint/no-non-null-assertion: "Disallow non-null assertions using the ! postfix operator."
3
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-6557/
4
+ # SonarQube S6557: "Non-null assertions should not be used."
5
+ id: no-non-null-assertion
6
+ language: TypeScript
7
+ message: "Avoid non-null assertion (!) — use proper null checks or optional chaining"
8
+ severity: warning
9
+ note: "Mirrors @typescript-eslint/no-non-null-assertion and SonarQube S6557. The ! operator lies to the compiler."
10
+ rule:
11
+ pattern: $X!
12
+ constraints:
13
+ X:
14
+ not:
15
+ pattern: $Y!
16
+ # We match the postfix ! operator on identifiers and member expressions
17
+ ignores:
18
+ - '**/*.test.ts'
19
+ - '**/*.spec.ts'
20
+ - '**/test/**'
21
+ - '**/tests/**'
22
+ - '**/__tests__/**'
23
+ - '**/scripts/**'
24
+ - 'test-*.ts'
25
+ - '**/*.d.ts'
@@ -0,0 +1,44 @@
1
+ # SOURCE: coding-guard internal — comprehensive stub/placeholder detection
2
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-4658/ (placeholder usage)
3
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-1155/ (empty/placeholder implementations)
4
+ id: no-stub-implementation
5
+ message: "Stub/placeholder/incomplete implementation detected — replace with real code"
6
+ severity: error
7
+ language: TypeScript
8
+ note: |
9
+ Comprehensive anti-evasion stub detector.
10
+
11
+ Keywords: stub, not yet implemented, deferred, work around, monkey patch,
12
+ placeholder, hack, temporary, fixme, wip, todo: implement, not implemented
13
+
14
+ Contexts: throw Error (any subclass), console.log/warn/error/info/debug
15
+
16
+ Evasion resistance:
17
+ - String concatenation: 'st' + 'ub' → caught via per-char gaps in $MSG text
18
+ - Template literals: `stub response` → caught via same regex
19
+ - Different Error types: TypeError/RangeError/etc → $ERR matches any class
20
+
21
+ Note: does NOT match `return` statements to avoid false positives from
22
+ prose/template strings containing incidental keyword matches.
23
+ rule:
24
+ any:
25
+ # ── throw patterns (any Error subclass) ──
26
+ - pattern: throw new $ERR($MSG)
27
+ # ── console patterns ──
28
+ - pattern: console.log($MSG)
29
+ - pattern: console.warn($MSG)
30
+ - pattern: console.error($MSG)
31
+ - pattern: console.info($MSG)
32
+ - pattern: console.debug($MSG)
33
+ constraints:
34
+ MSG:
35
+ regex: '(?i)(s[\W_]{0,5}t[\W_]{0,5}u[\W_]{0,5}b|h[\W_]{0,5}a[\W_]{0,5}c[\W_]{0,5}k|w[\W_]{0,5}i[\W_]{0,5}p|not.{0,15}implement|deferred|work.?-?around|monkey.?-?patch|placeholder|temporary|fixme|todo.{0,20}implement)'
36
+ ignores:
37
+ - '**/*.test.ts'
38
+ - '**/*.spec.ts'
39
+ - '**/test/**'
40
+ - '**/tests/**'
41
+ - '**/__tests__/**'
42
+ - '**/__mocks__/**'
43
+ - '**/scripts/**'
44
+ - '**/fixtures/**'
@@ -0,0 +1,50 @@
1
+ # SOURCE: https://www.typescriptlang.org/docs/handbook/2/functions.html#optional-parameters-in-callbacks
2
+ # "Use explicit return types on methods that return promises to avoid accidentally
3
+ # returning void (floating promises)."
4
+ # SOURCE: https://typescript-book.com/exceptions/dont-throw-use-errors
5
+ # "throw 'string' or throw 42 bypasses Error stack trace capture. Always throw
6
+ # an Error subclass with proper context."
7
+ # SOURCE: https://kentcdodds.com/blog/get-a-catch-block-error-message-with-typescript
8
+ # "throw new Error() captures stack. throw 'message' does not."
9
+ id: no-throw-literal
10
+ language: typescript
11
+ message: "throw with non-Error value — no stack trace captured. Use throw new Error() or throw new AppError() for proper stack traces"
12
+ severity: error
13
+ note: |
14
+ UNSAFE:
15
+ throw 'Something went wrong'
16
+ throw 404
17
+ throw { message: 'failed', code: 'ERR_FAIL' }
18
+ throw response.statusText
19
+
20
+ SAFE:
21
+ throw new Error('Something went wrong')
22
+ throw new AppError('FAILED', 'Something went wrong', 500)
23
+ throw new NotFoundError('User')
24
+ if (err instanceof Error) throw err;
25
+
26
+ WHY: Only `throw new Error()` (or subclass) captures a stack trace. Throwing strings,
27
+ numbers, or plain objects produces errors with no stack trace — you can see the error
28
+ message but have NO idea where it was thrown from. This makes production debugging
29
+ impossible. Rule enforces all throws use Error instances.
30
+ rule:
31
+ any:
32
+ - pattern: throw $LIT
33
+ not:
34
+ any:
35
+ # Safe: throwing Error instances
36
+ - pattern: throw new $ERR($$$ARGS)
37
+ - pattern: throw new $ERR
38
+ # Safe: rethrowing caught error
39
+ - inside:
40
+ kind: catch_clause
41
+ stopBy: end
42
+ pattern: throw $ERR
43
+ ignores:
44
+ - '**/*.test.ts'
45
+ - '**/*.spec.ts'
46
+ - '**/test/**'
47
+ - '**/tests/**'
48
+ - '**/__tests__/**'
49
+ - '**/scripts/**'
50
+ - 'test-*.ts'
@@ -0,0 +1,24 @@
1
+ # SOURCE: https://eslint.org/docs/latest/rules/no-warning-comments
2
+ # Terms: TODO/FIXME/HACK only (mirrors ESLint defaults). Word boundary + location:start.
3
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-1135/
4
+ # isLetterAround() guard — requires delimiter after marker to avoid FP.
5
+ # SOURCE: https://github.com/detekt/detekt/issues/6116
6
+ # Community consensus: require colon after marker (TODO: not just TODO).
7
+ id: no-todo-comment
8
+ message: 'TODO/FIXME/HACK comment found — track in issue tracker instead. ALWAYS callsout to the user WHENEVER encountering these TODO warning'
9
+ severity: warning
10
+ language: TypeScript
11
+ note: "Mirrors ESLint no-warning-comments (terms: TODO/FIXME/HACK, location: start) and SonarQube S1135."
12
+ rule:
13
+ kind: comment
14
+ regex: '(?i)\b(TODO|FIXME|HACK)\s*[::]'
15
+ ignores:
16
+ - '**/*.test.ts'
17
+ - '**/*.spec.ts'
18
+ - '**/*.test-d.ts'
19
+ - '**/test/**'
20
+ - '**/tests/**'
21
+ - '**/__tests__/**'
22
+ - '**/__mocks__/**'
23
+ - '**/scripts/**'
24
+ - 'test-*.ts'
@@ -0,0 +1,48 @@
1
+ # SOURCE: https://typescript-eslint.io/rules/ban-ts-comment/
2
+ # typescript-eslint ban-ts-comment: by default disallows `@ts-ignore` and `@ts-nocheck`
3
+ # while allowing `@ts-expect-error` (with description). Recommended preset.
4
+ # SOURCE: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#-ts-expect-error-comments
5
+ # TypeScript 3.9 introduced `@ts-expect-error` precisely so that the suppression
6
+ # itself raises an error once the underlying issue is fixed — `@ts-ignore` does not.
7
+ # SOURCE: https://rules.sonarsource.com/typescript/RSPEC-6535/
8
+ # SonarQube S6535: "TypeScript directive comments should not be used to silence type errors."
9
+ id: no-ts-ignore-comment
10
+ language: TypeScript
11
+ message: "Replace @ts-ignore / @ts-nocheck with @ts-expect-error — the latter errors out once the underlying issue is fixed"
12
+ severity: warning
13
+ note: |
14
+ Mirrors typescript-eslint ban-ts-comment (recommended preset) and SonarQube S6535.
15
+
16
+ `@ts-ignore` silences the next line forever — even after the type bug is
17
+ fixed, the directive lingers as dead noise (and can hide new bugs).
18
+ `@ts-expect-error` flips the contract: it suppresses the error, but the
19
+ compiler reports an error if the next line type-checks cleanly, so
20
+ obsolete suppressions get flagged the moment they become obsolete.
21
+ `@ts-nocheck` opts an entire file out of type checking and is almost
22
+ never the right answer in a typed codebase.
23
+
24
+ BAD:
25
+ // @ts-ignore
26
+ const value: number = JSON.parse(raw);
27
+
28
+ // @ts-nocheck
29
+ // (silences the entire file)
30
+
31
+ GOOD:
32
+ // @ts-expect-error - upstream types are wrong, see DT#12345
33
+ const value: number = JSON.parse(raw);
34
+
35
+ rule:
36
+ kind: comment
37
+ regex: '@ts-(ignore|nocheck)\b'
38
+ ignores:
39
+ - '**/*.test.ts'
40
+ - '**/*.spec.ts'
41
+ - '**/*.test-d.ts'
42
+ - '**/test/**'
43
+ - '**/tests/**'
44
+ - '**/__tests__/**'
45
+ - '**/__mocks__/**'
46
+ - '**/scripts/**'
47
+ - 'test-*.ts'
48
+ - '**/*.d.ts'
@@ -0,0 +1,23 @@
1
+ # SOURCE: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions
2
+ # TypeScript handbook: "Type assertions are a way to tell TypeScript 'trust me, I know what I'm doing.'
3
+ # The two syntaxes are angle-bracket and as-style, but angle-bracket syntax is NOT valid in JSX/TSX files."
4
+ # SOURCE: https://typescript-eslint.io/rules/consistent-type-assertions/
5
+ # @typescript-eslint/consistent-type-assertions: "Enforce consistent usage of type assertions."
6
+ id: no-type-assertion-in-jsx
7
+ language: typescript
8
+ message: "Angle-bracket type assertion (<Type>expr) conflicts with JSX syntax in TSX — use 'as' syntax instead"
9
+ severity: error
10
+ note: |
11
+ In TSX files, <Type>expr is ambiguous — TypeScript parses it as a JSX element, not a type assertion.
12
+ Use expr as Type instead. This is a hard error in TSX files, not a style preference.
13
+ rule:
14
+ pattern: <$TYPE>$EXPR
15
+ # ast-grep limitation: tree-sitter-typescript may parse this as JSX, not type assertion.
16
+ # If this rule doesn't fire, it's because the parser can't distinguish JSX from angle-bracket assertions.
17
+ # TypeScript itself handles this by banning angle-bracket assertions in TSX — this rule mirrors that.
18
+ ignores:
19
+ - '**/*.test.ts'
20
+ - '**/*.spec.ts'
21
+ - '**/test/**'
22
+ - '**/tests/**'
23
+ - '**/__tests__/**'
@@ -0,0 +1,24 @@
1
+ # SOURCE: coding-guard internal — detects .trim() calls in React render paths
2
+ id: no-unguarded-trim-in-render
3
+ message: "Unguarded .trim() in component — consider (val ?? '').trim() or val?.trim()"
4
+ severity: info
5
+ language: TypeScript
6
+ note: |
7
+ Flags .trim() calls in React component files (.tsx) that lack
8
+ null-safety guards. Use (value ?? '').trim() or value?.trim().
9
+ rule:
10
+ pattern: $OBJ.trim()
11
+ constraints:
12
+ OBJ:
13
+ regex: '^\w+(\.\w+)+$'
14
+ ignores:
15
+ - '**/*.test.ts'
16
+ - '**/*.test.tsx'
17
+ - '**/*.spec.ts'
18
+ - '**/*.spec.tsx'
19
+ - '**/test/**'
20
+ - '**/tests/**'
21
+ - '**/__tests__/**'
22
+ - '**/__mocks__/**'
23
+ - '**/scripts/**'
24
+ - '**/fixtures/**'
@@ -0,0 +1,76 @@
1
+ # SOURCE: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
2
+ # "Type predicates (param is Type) are the TypeScript way to narrow types.
3
+ # typeof checks are for primitives only. instanceof is for classes."
4
+ # SOURCE: https://www.totaltypescript.com/tips/use-type-predicates-to-narrow-types
5
+ # "unknown should be narrowed with type predicates before use."
6
+ # SOURCE: https://typescript-book.com/typeNarrowing
7
+ # "Don't access unknown without narrowing. Use type guards."
8
+ id: no-unknown-without-narrowing
9
+ language: typescript
10
+ message: "Parameter typed as 'unknown' used without type narrowing — use type guard (typeof, instanceof, in) or zod.parse() before accessing"
11
+ severity: warning
12
+ note: |
13
+ UNSAFE:
14
+ function handle(data: unknown) {
15
+ const str = data.toString(); // no narrowing — runtime error if data is null
16
+ }
17
+
18
+ function process(value: unknown) {
19
+ console.log((value as any).name); // bypasses the point of unknown
20
+ }
21
+
22
+ SAFE:
23
+ function handle(data: unknown) {
24
+ if (typeof data === 'string') {
25
+ return data.toUpperCase(); // narrowed to string
26
+ }
27
+ if (typeof data === 'object' && data !== null && 'name' in data) {
28
+ return (data as { name: string }).name; // narrowed
29
+ }
30
+ }
31
+
32
+ function process(value: unknown) {
33
+ const result = schema.safeParse(value); // zod validation
34
+ if (!result.success) throw new ValidationError('...');
35
+ return result.data;
36
+ }
37
+
38
+ WHY: `unknown` forces you to narrow before use — that's its purpose. Accessing unknown
39
+ without narrowing defeats the entire point. Use typeof (primitives), instanceof (classes),
40
+ in operator (objects), or zod.parse() for complex shapes. `as any` on unknown is the
41
+ worst violation — it removes ALL type safety.
42
+ rule:
43
+ pattern: $PARAM.$METHOD($$$ARGS)
44
+ inside:
45
+ any:
46
+ - kind: function_declaration
47
+ - kind: arrow_function
48
+ - kind: function_expression
49
+ not:
50
+ any:
51
+ # Safe: inside a typeof narrowing if block
52
+ - inside:
53
+ pattern: |
54
+ if (typeof $PARAM === $$$TYPE) {
55
+ $$$PRE
56
+ $PARAM.$METHOD($$$ARGS)
57
+ $$$POST
58
+ }
59
+ stopBy: end
60
+ # Safe: inside an instanceof narrowing if block
61
+ - inside:
62
+ pattern: |
63
+ if ($PARAM instanceof $$$TYPE) {
64
+ $$$PRE
65
+ $PARAM.$METHOD($$$ARGS)
66
+ $$$POST
67
+ }
68
+ stopBy: end
69
+ ignores:
70
+ - '**/*.test.ts'
71
+ - '**/*.spec.ts'
72
+ - '**/test/**'
73
+ - '**/tests/**'
74
+ - '**/__tests__/**'
75
+ - '**/scripts/**'
76
+ - 'test-*.ts'