pumuki 6.3.55 → 6.3.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -85
- package/VERSION +1 -1
- package/core/facts/HeuristicFact.test.ts +28 -0
- package/core/facts/HeuristicFact.ts +11 -0
- package/core/facts/detectors/text/android.test.ts +207 -0
- package/core/facts/detectors/text/android.ts +765 -0
- package/core/facts/detectors/text/ios.test.ts +207 -0
- package/core/facts/detectors/text/ios.ts +848 -0
- package/core/facts/detectors/typescript/index.test.ts +447 -0
- package/core/facts/detectors/typescript/index.ts +1214 -54
- package/core/facts/extractHeuristicFacts.ts +285 -1
- package/core/gate/Finding.test.ts +28 -0
- package/core/gate/Finding.ts +12 -0
- package/core/gate/evaluateRules.ts +22 -0
- package/core/rules/presets/androidRuleSet.test.ts +52 -2
- package/core/rules/presets/androidRuleSet.ts +130 -0
- package/core/rules/presets/iosEnterpriseRuleSet.test.ts +276 -1
- package/core/rules/presets/iosEnterpriseRuleSet.ts +156 -0
- package/core/rules/presets/rulePackVersions.test.ts +2 -2
- package/core/rules/presets/rulePackVersions.ts +2 -2
- package/docs/README.md +44 -15
- package/docs/codex-skills/{windsurf-rules-android.md → android-enterprise-rules.md} +1 -1
- package/docs/codex-skills/{windsurf-rules-backend.md → backend-enterprise-rules.md} +1 -1
- package/docs/codex-skills/{windsurf-rules-frontend.md → frontend-enterprise-rules.md} +1 -1
- package/docs/codex-skills/{windsurf-rules-ios.md → ios-enterprise-rules.md} +1 -1
- package/docs/mcp/{MCP_AGENT_CONTEXT_CONSUMPTION.md → agent-context-consumption.md} +2 -2
- package/docs/mcp/{MCP_SERVERS.md → mcp-servers-overview.md} +2 -2
- package/docs/operations/RELEASE_NOTES.md +28 -4
- package/docs/product/API_REFERENCE.md +2 -2
- package/docs/product/INSTALLATION.md +16 -108
- package/docs/product/USAGE.md +7 -2
- package/docs/rule-packs/engineering-baseline.md +1 -1
- package/docs/rule-packs/ios.md +1 -1
- package/docs/validation/README.md +6 -5
- package/integrations/config/skillsCustomRules.ts +176 -16
- package/integrations/config/skillsEffectiveLock.ts +109 -2
- package/integrations/config/skillsRuleSet.ts +5 -1
- package/integrations/evidence/buildEvidence.ts +55 -0
- package/integrations/evidence/generateEvidence.test.ts +46 -0
- package/integrations/evidence/schema.ts +18 -0
- package/integrations/evidence/writeEvidence.ts +52 -0
- package/integrations/gate/evaluateAiGate.ts +186 -22
- package/integrations/git/findingTraceability.ts +15 -0
- package/integrations/git/gitAtomicity.ts +30 -2
- package/integrations/git/runPlatformGate.ts +56 -3
- package/integrations/sdd/syncDocs.ts +16 -375
- package/integrations/sdd/syncDocsTargets.ts +380 -0
- package/package.json +2 -1
- package/scripts/backlog-action-reasons-lib.ts +18 -22
- package/scripts/backlog-action-reasons-types.ts +25 -0
- package/scripts/backlog-consumer-gh.ts +117 -0
- package/scripts/backlog-consumer-patterns.ts +36 -0
- package/scripts/backlog-consumer-types.ts +7 -0
- package/scripts/backlog-id-issue-map-lib.ts +9 -42
- package/scripts/backlog-id-issue-map-parse.ts +40 -0
- package/scripts/backlog-id-issue-map-types.ts +4 -0
- package/scripts/check-self-worktree-hygiene.ts +94 -0
- package/scripts/check-tracking-single-active.sh +4 -2
- package/scripts/framework-menu-advanced-view-help.ts +39 -0
- package/scripts/framework-menu-advanced-view-lib.ts +6 -63
- package/scripts/framework-menu-advanced-view-status.ts +31 -0
- package/scripts/framework-menu-consumer-preflight-hints.ts +119 -0
- package/scripts/framework-menu-consumer-preflight-lib.ts +14 -247
- package/scripts/framework-menu-consumer-preflight-render.ts +41 -0
- package/scripts/framework-menu-consumer-preflight-run.ts +105 -0
- package/scripts/framework-menu-consumer-preflight-types.ts +40 -0
- package/scripts/framework-menu-consumer-runtime-actions.ts +139 -0
- package/scripts/framework-menu-consumer-runtime-audit.ts +86 -0
- package/scripts/framework-menu-consumer-runtime-lib.ts +46 -223
- package/scripts/framework-menu-consumer-runtime-menu.ts +104 -0
- package/scripts/framework-menu-consumer-runtime-types.ts +52 -0
- package/scripts/framework-menu-evidence-summary-file.ts +42 -0
- package/scripts/framework-menu-evidence-summary-format.ts +49 -0
- package/scripts/framework-menu-evidence-summary-lib.ts +7 -258
- package/scripts/framework-menu-evidence-summary-normalize.ts +87 -0
- package/scripts/framework-menu-evidence-summary-read.ts +60 -0
- package/scripts/framework-menu-evidence-summary-severity.ts +70 -0
- package/scripts/framework-menu-evidence-summary-types.ts +28 -0
- package/scripts/framework-menu-layout-data.ts +52 -0
- package/scripts/framework-menu-layout-lib.ts +8 -116
- package/scripts/framework-menu-layout-resolve.ts +51 -0
- package/scripts/framework-menu-layout-types.ts +16 -0
- package/scripts/framework-menu-legacy-audit-lib.ts +14 -1229
- package/scripts/framework-menu-legacy-audit-markdown-document.ts +31 -0
- package/scripts/framework-menu-legacy-audit-markdown-links.ts +29 -0
- package/scripts/framework-menu-legacy-audit-markdown.ts +19 -0
- package/scripts/framework-menu-legacy-audit-render-panel.ts +249 -0
- package/scripts/framework-menu-legacy-audit-render-report.ts +162 -0
- package/scripts/framework-menu-legacy-audit-render-sections.ts +97 -0
- package/scripts/framework-menu-legacy-audit-render.ts +16 -0
- package/scripts/framework-menu-legacy-audit-summary-metrics.ts +50 -0
- package/scripts/framework-menu-legacy-audit-summary-normalize.ts +195 -0
- package/scripts/framework-menu-legacy-audit-summary-platforms.ts +183 -0
- package/scripts/framework-menu-legacy-audit-summary-ranked.ts +76 -0
- package/scripts/framework-menu-legacy-audit-summary-types.ts +42 -0
- package/scripts/framework-menu-legacy-audit-summary.ts +105 -0
- package/scripts/framework-menu-legacy-audit-types.ts +74 -0
- package/scripts/framework-menu-matrix-canary-evidence.ts +34 -0
- package/scripts/framework-menu-matrix-canary-lib.ts +16 -140
- package/scripts/framework-menu-matrix-canary-scenario.ts +91 -0
- package/scripts/framework-menu-matrix-canary-types.ts +21 -0
- package/scripts/framework-menu-matrix-evidence-diagnosis.ts +46 -0
- package/scripts/framework-menu-matrix-evidence-lib.ts +10 -59
- package/scripts/framework-menu-matrix-evidence-types.ts +18 -0
- package/scripts/framework-menu-rule-coverage-diagnostics-build.ts +122 -0
- package/scripts/framework-menu-rule-coverage-diagnostics-format.ts +46 -0
- package/scripts/framework-menu-rule-coverage-diagnostics-lib.ts +10 -208
- package/scripts/framework-menu-rule-coverage-diagnostics-types.ts +54 -0
- package/scripts/framework-menu-system-notifications-cause.ts +54 -0
- package/scripts/framework-menu-system-notifications-config-choice.ts +35 -0
- package/scripts/framework-menu-system-notifications-config-file.ts +25 -0
- package/scripts/framework-menu-system-notifications-config-state.ts +62 -0
- package/scripts/framework-menu-system-notifications-config-types.ts +8 -0
- package/scripts/framework-menu-system-notifications-config.ts +7 -0
- package/scripts/framework-menu-system-notifications-dispatch.ts +32 -0
- package/scripts/framework-menu-system-notifications-effective-config.ts +18 -0
- package/scripts/framework-menu-system-notifications-event-types.ts +27 -0
- package/scripts/framework-menu-system-notifications-gate.ts +22 -0
- package/scripts/framework-menu-system-notifications-lib.ts +51 -867
- package/scripts/framework-menu-system-notifications-macos-applescript-banner.ts +16 -0
- package/scripts/framework-menu-system-notifications-macos-applescript-dialog.ts +18 -0
- package/scripts/framework-menu-system-notifications-macos-applescript-parse.ts +4 -0
- package/scripts/framework-menu-system-notifications-macos-applescript.ts +38 -0
- package/scripts/framework-menu-system-notifications-macos-banner-delivery-dispatch.ts +15 -0
- package/scripts/framework-menu-system-notifications-macos-banner-delivery-runner.ts +14 -0
- package/scripts/framework-menu-system-notifications-macos-banner-delivery.ts +21 -0
- package/scripts/framework-menu-system-notifications-macos-banner-result.ts +8 -0
- package/scripts/framework-menu-system-notifications-macos-banner-run.ts +6 -0
- package/scripts/framework-menu-system-notifications-macos-banner-script.ts +6 -0
- package/scripts/framework-menu-system-notifications-macos-banner-stage.ts +15 -0
- package/scripts/framework-menu-system-notifications-macos-banner.ts +18 -0
- package/scripts/framework-menu-system-notifications-macos-blocked-dispatch-gate.ts +11 -0
- package/scripts/framework-menu-system-notifications-macos-blocked-dispatch-runner.ts +9 -0
- package/scripts/framework-menu-system-notifications-macos-blocked-dispatch.ts +39 -0
- package/scripts/framework-menu-system-notifications-macos-blocked-stage.ts +30 -0
- package/scripts/framework-menu-system-notifications-macos-dialog-effect.ts +25 -0
- package/scripts/framework-menu-system-notifications-macos-dialog-enabled.ts +20 -0
- package/scripts/framework-menu-system-notifications-macos-dialog-mode-dispatch.ts +50 -0
- package/scripts/framework-menu-system-notifications-macos-dialog-mode-resolve.ts +1 -0
- package/scripts/framework-menu-system-notifications-macos-dialog-mode.ts +21 -0
- package/scripts/framework-menu-system-notifications-macos-dialog-payload.ts +35 -0
- package/scripts/framework-menu-system-notifications-macos-dialog.ts +54 -0
- package/scripts/framework-menu-system-notifications-macos-result.ts +11 -0
- package/scripts/framework-menu-system-notifications-macos-runner-exec.ts +11 -0
- package/scripts/framework-menu-system-notifications-macos-runner-output.ts +29 -0
- package/scripts/framework-menu-system-notifications-macos-runner-parse.ts +7 -0
- package/scripts/framework-menu-system-notifications-macos-runner.ts +3 -0
- package/scripts/framework-menu-system-notifications-macos-swift-args.ts +38 -0
- package/scripts/framework-menu-system-notifications-macos-swift-run.ts +52 -0
- package/scripts/framework-menu-system-notifications-macos-swift-source.ts +246 -0
- package/scripts/framework-menu-system-notifications-macos-swift.ts +6 -0
- package/scripts/framework-menu-system-notifications-macos.ts +48 -0
- package/scripts/framework-menu-system-notifications-payload-types.ts +10 -0
- package/scripts/framework-menu-system-notifications-payloads-audit.ts +31 -0
- package/scripts/framework-menu-system-notifications-payloads-blocked.ts +32 -0
- package/scripts/framework-menu-system-notifications-payloads-context.ts +14 -0
- package/scripts/framework-menu-system-notifications-payloads-events.ts +18 -0
- package/scripts/framework-menu-system-notifications-payloads.ts +55 -0
- package/scripts/framework-menu-system-notifications-remediation.ts +58 -0
- package/scripts/framework-menu-system-notifications-runner-types.ts +20 -0
- package/scripts/framework-menu-system-notifications-text.ts +31 -0
- package/scripts/framework-menu-system-notifications-types.ts +22 -0
- package/scripts/framework-menu-ui-components-lib.ts +14 -220
- package/scripts/framework-menu-ui-components-panel.ts +46 -0
- package/scripts/framework-menu-ui-components-render.ts +58 -0
- package/scripts/framework-menu-ui-components-tokens.ts +105 -0
- package/scripts/framework-menu-ui-components-types.ts +30 -0
- package/scripts/gitflow-cli-commands.ts +145 -0
- package/scripts/gitflow-cli-lib.ts +34 -244
- package/scripts/gitflow-cli-snapshot.ts +97 -0
- package/scripts/gitflow-cli-types.ts +26 -0
- package/scripts/legacy-parity-report-build.ts +96 -0
- package/scripts/legacy-parity-report-lib.ts +11 -406
- package/scripts/legacy-parity-report-markdown.ts +60 -0
- package/scripts/legacy-parity-report-normalize.ts +202 -0
- package/scripts/legacy-parity-report-types.ts +74 -0
- package/scripts/package-manifest-lib.ts +4 -4
- package/scripts/reconcile-consumer-backlog-issues-lib.ts +56 -578
- package/scripts/reconcile-consumer-backlog-issues-parse.ts +197 -0
- package/scripts/reconcile-consumer-backlog-issues-sync.ts +272 -0
- package/scripts/reconcile-consumer-backlog-issues-types.ts +71 -0
- package/scripts/self-worktree-hygiene-lib.ts +202 -0
- package/scripts/sync-codex-skills.sh +4 -4
- package/scripts/watch-consumer-backlog-fleet-lib.ts +131 -0
- package/scripts/watch-consumer-backlog-fleet-tick.ts +10 -82
- package/scripts/watch-consumer-backlog-fleet.ts +10 -77
- package/scripts/watch-consumer-backlog-lib.ts +33 -353
- package/scripts/watch-consumer-backlog-parse.ts +168 -0
- package/scripts/watch-consumer-backlog-types.ts +45 -0
- package/skills.lock.json +758 -758
- package/skills.sources.json +12 -12
- /package/docs/mcp/{MCP_EVIDENCE_CONTEXT_SERVER.md → evidence-context-server.md} +0 -0
- /package/docs/operations/{framework-menu-option-1-walkthrough.md → framework-menu-consumer-walkthrough.md} +0 -0
- /package/docs/operations/{OPERATIONS.md → production-operations-policy.md} +0 -0
- /package/docs/validation/{ast-intelligence-roadmap.md → ast-intelligence-validation-roadmap.md} +0 -0
package/README.md
CHANGED
|
@@ -238,87 +238,18 @@ Legacy parity report (strict comparator):
|
|
|
238
238
|
node --import tsx scripts/build-legacy-parity-report.ts --legacy=<legacy-evidence-path> --enterprise=<enterprise-evidence-path> --out=<output-path>
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
-
## Command
|
|
241
|
+
## Command Paths
|
|
242
242
|
|
|
243
|
-
|
|
243
|
+
Use these docs instead of treating `README.md` as the full command manual:
|
|
244
244
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
### SDD / OpenSpec (Consumer)
|
|
255
|
-
|
|
256
|
-
```bash
|
|
257
|
-
npx --yes pumuki sdd status
|
|
258
|
-
npx --yes pumuki sdd session --open --change=<change-id>
|
|
259
|
-
npx --yes pumuki sdd session --refresh
|
|
260
|
-
npx --yes pumuki sdd session --close
|
|
261
|
-
npx --yes pumuki sdd validate --stage=PRE_COMMIT
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### Loop Runner (Consumer)
|
|
265
|
-
|
|
266
|
-
```bash
|
|
267
|
-
npx --yes pumuki loop run --objective="stabilize gate before commit" --max-attempts=3 --json
|
|
268
|
-
npx --yes pumuki loop status --session=<session-id> --json
|
|
269
|
-
npx --yes pumuki loop stop --session=<session-id> --json
|
|
270
|
-
npx --yes pumuki loop resume --session=<session-id> --json
|
|
271
|
-
npx --yes pumuki loop list --json
|
|
272
|
-
npx --yes pumuki loop export --session=<session-id> --output-json=.audit-reports/loop-session.json
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
### Stage Gates (Consumer)
|
|
276
|
-
|
|
277
|
-
```bash
|
|
278
|
-
npx --yes --package pumuki@latest pumuki-pre-write
|
|
279
|
-
npx --yes --package pumuki@latest pumuki-pre-commit
|
|
280
|
-
npx --yes --package pumuki@latest pumuki-pre-push
|
|
281
|
-
npx --yes --package pumuki@latest pumuki-ci
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### MCP Servers (Optional, Long-Running)
|
|
285
|
-
|
|
286
|
-
```bash
|
|
287
|
-
npx --yes --package pumuki@latest pumuki-mcp-evidence
|
|
288
|
-
npx --yes --package pumuki@latest pumuki-mcp-evidence-stdio
|
|
289
|
-
npx --yes --package pumuki@latest pumuki-mcp-enterprise
|
|
290
|
-
npx --yes --package pumuki@latest pumuki-mcp-enterprise-stdio
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
## Validation and Diagnostics (Framework-Only)
|
|
294
|
-
|
|
295
|
-
These commands are for maintainers and may require additional arguments, external repo context, or authenticated GitHub access.
|
|
296
|
-
|
|
297
|
-
```bash
|
|
298
|
-
npm run validation:consumer-ci-artifacts -- --repo <owner/repo>
|
|
299
|
-
npm run validation:consumer-ci-auth-check -- --repo <owner/repo>
|
|
300
|
-
npm run validation:consumer-workflow-lint -- --repo-path <absolute-path-to-consumer-repo>
|
|
301
|
-
npm run validation:consumer-support-bundle -- --repo <owner/repo>
|
|
302
|
-
npm run validation:consumer-support-ticket-draft
|
|
303
|
-
npm run validation:consumer-startup-unblock-status
|
|
304
|
-
npm run validation:consumer-startup-triage -- --repo <owner/repo> --skip-workflow-lint
|
|
305
|
-
npm run validation:mock-consumer-ab-report
|
|
306
|
-
npm run validation:adapter-readiness
|
|
307
|
-
npm run validation:adapter-session-status
|
|
308
|
-
npm run validation:adapter-real-session-report
|
|
309
|
-
npm run validation:phase5-blockers-readiness
|
|
310
|
-
npm run validation:phase5-execution-closure-status
|
|
311
|
-
npm run validation:phase5-execution-closure -- --repo <owner/repo> --skip-workflow-lint
|
|
312
|
-
npm run validation:phase5-external-handoff
|
|
313
|
-
npm run validation:clean-artifacts
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
Important:
|
|
317
|
-
|
|
318
|
-
- Several validation scripts intentionally return non-zero when verdict is `BLOCKED`, `PENDING`, or `MISSING_INPUTS`.
|
|
319
|
-
- Non-zero in these scripts is often diagnostic output, not a runtime crash.
|
|
320
|
-
- `validation:consumer-support-ticket-draft` expects an existing support bundle generated by `validation:consumer-support-bundle`.
|
|
321
|
-
- If workflow lint is required in your flow, provide `--repo-path` and `--actionlint-bin`; otherwise use `--skip-workflow-lint`.
|
|
245
|
+
- Installation and bootstrap:
|
|
246
|
+
- `docs/product/INSTALLATION.md`
|
|
247
|
+
- Daily usage, gates, menu, lifecycle, SDD and troubleshooting:
|
|
248
|
+
- `docs/product/USAGE.md`
|
|
249
|
+
- Operator-focused short playbook:
|
|
250
|
+
- `PUMUKI.md`
|
|
251
|
+
- Validation runbooks and framework-only diagnostics:
|
|
252
|
+
- `docs/validation/README.md`
|
|
322
253
|
|
|
323
254
|
## Menu Walkthrough and Screenshots
|
|
324
255
|
|
|
@@ -348,13 +279,13 @@ Important:
|
|
|
348
279
|
|
|
349
280
|
Extended annotated walkthrough:
|
|
350
281
|
|
|
351
|
-
- `docs/operations/framework-menu-
|
|
282
|
+
- `docs/operations/framework-menu-consumer-walkthrough.md`
|
|
352
283
|
|
|
353
284
|
## Enterprise Operations Baseline
|
|
354
285
|
|
|
355
286
|
Pumuki production SaaS operation baseline is defined in:
|
|
356
287
|
|
|
357
|
-
- `docs/operations/
|
|
288
|
+
- `docs/operations/production-operations-policy.md`
|
|
358
289
|
|
|
359
290
|
Highlights:
|
|
360
291
|
|
|
@@ -384,11 +315,11 @@ Highlights:
|
|
|
384
315
|
- Configuration: `docs/product/CONFIGURATION.md`
|
|
385
316
|
- Code standards: `docs/governance/CODE_STANDARDS.md`
|
|
386
317
|
- Branch protection: `docs/governance/BRANCH_PROTECTION_GUIDE.md`
|
|
387
|
-
- MCP servers: `docs/mcp/
|
|
388
|
-
- MCP evidence server: `docs/mcp/
|
|
389
|
-
- MCP consumption: `docs/mcp/
|
|
318
|
+
- MCP servers: `docs/mcp/mcp-servers-overview.md`
|
|
319
|
+
- MCP evidence server: `docs/mcp/evidence-context-server.md`
|
|
320
|
+
- MCP consumption: `docs/mcp/agent-context-consumption.md`
|
|
390
321
|
- Evidence schema v2.1: `docs/mcp/ai-evidence-v2.1-contract.md`
|
|
391
|
-
- Operations policy (SLA/SLO): `docs/operations/
|
|
322
|
+
- Operations policy (SLA/SLO): `docs/operations/production-operations-policy.md`
|
|
392
323
|
- Release notes: `docs/operations/RELEASE_NOTES.md`
|
|
393
324
|
- Changelog: `CHANGELOG.md`
|
|
394
325
|
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v6.3.
|
|
1
|
+
v6.3.57
|
|
@@ -32,3 +32,31 @@ test('HeuristicFact permite omitir filePath', () => {
|
|
|
32
32
|
assert.equal(factWithoutPath.filePath, undefined);
|
|
33
33
|
assert.equal(factWithoutPath.severity, 'INFO');
|
|
34
34
|
});
|
|
35
|
+
|
|
36
|
+
test('HeuristicFact conserva metadata semantica opcional del canario iOS', () => {
|
|
37
|
+
const fact: HeuristicFact = {
|
|
38
|
+
kind: 'Heuristic',
|
|
39
|
+
ruleId: 'heuristics.ios.canary-001.presentation-mixed-responsibilities.ast',
|
|
40
|
+
severity: 'CRITICAL',
|
|
41
|
+
code: 'HEURISTICS_IOS_CANARY_001_PRESENTATION_MIXED_RESPONSIBILITIES_AST',
|
|
42
|
+
message: 'Semantic iOS canary triggered.',
|
|
43
|
+
filePath: 'apps/ios/Sources/AppShell/Application/AppShellViewModel.swift',
|
|
44
|
+
lines: [1, 2, 3, 4],
|
|
45
|
+
primary_node: {
|
|
46
|
+
kind: 'class',
|
|
47
|
+
name: 'AppShellViewModel',
|
|
48
|
+
lines: [1],
|
|
49
|
+
},
|
|
50
|
+
related_nodes: [
|
|
51
|
+
{ kind: 'property', name: 'shared singleton', lines: [2] },
|
|
52
|
+
{ kind: 'call', name: 'URLSession.shared', lines: [3] },
|
|
53
|
+
],
|
|
54
|
+
why: 'Mezcla responsabilidades incompatibles.',
|
|
55
|
+
impact: 'Complica tests y cambios.',
|
|
56
|
+
expected_fix: 'Extraer collaborators.',
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
assert.equal(fact.primary_node?.name, 'AppShellViewModel');
|
|
60
|
+
assert.equal(fact.related_nodes?.length, 2);
|
|
61
|
+
assert.equal(fact.expected_fix, 'Extraer collaborators.');
|
|
62
|
+
});
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { Severity } from '../rules/Severity';
|
|
2
2
|
|
|
3
|
+
export type HeuristicNode = {
|
|
4
|
+
kind: 'class' | 'property' | 'call' | 'member';
|
|
5
|
+
name: string;
|
|
6
|
+
lines?: readonly number[];
|
|
7
|
+
};
|
|
8
|
+
|
|
3
9
|
export interface HeuristicFact {
|
|
4
10
|
kind: 'Heuristic';
|
|
5
11
|
ruleId: string;
|
|
@@ -8,4 +14,9 @@ export interface HeuristicFact {
|
|
|
8
14
|
message: string;
|
|
9
15
|
filePath?: string;
|
|
10
16
|
lines?: readonly number[];
|
|
17
|
+
primary_node?: HeuristicNode;
|
|
18
|
+
related_nodes?: readonly HeuristicNode[];
|
|
19
|
+
why?: string;
|
|
20
|
+
impact?: string;
|
|
21
|
+
expected_fix?: string;
|
|
11
22
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import test from 'node:test';
|
|
3
3
|
import {
|
|
4
|
+
findKotlinConcreteDependencyDipMatch,
|
|
5
|
+
findKotlinInterfaceSegregationMatch,
|
|
6
|
+
findKotlinLiskovSubstitutionMatch,
|
|
7
|
+
findKotlinOpenClosedWhenMatch,
|
|
8
|
+
findKotlinPresentationSrpMatch,
|
|
4
9
|
hasKotlinGlobalScopeUsage,
|
|
5
10
|
hasKotlinRunBlockingUsage,
|
|
6
11
|
hasKotlinThreadSleepCall,
|
|
@@ -85,3 +90,205 @@ fun main() {
|
|
|
85
90
|
assert.equal(hasKotlinRunBlockingUsage(commentedSource), false);
|
|
86
91
|
assert.equal(hasKotlinRunBlockingUsage(partialSource), false);
|
|
87
92
|
});
|
|
93
|
+
|
|
94
|
+
test('findKotlinPresentationSrpMatch devuelve payload semantico para SRP-Android en presentation', () => {
|
|
95
|
+
const source = `
|
|
96
|
+
import android.content.SharedPreferences
|
|
97
|
+
import androidx.lifecycle.ViewModel
|
|
98
|
+
import androidx.navigation.NavController
|
|
99
|
+
import okhttp3.OkHttpClient
|
|
100
|
+
import okhttp3.Request
|
|
101
|
+
|
|
102
|
+
class PumukiSrpAndroidCanaryViewModel(
|
|
103
|
+
private val navController: NavController,
|
|
104
|
+
) : ViewModel() {
|
|
105
|
+
fun restoreSessionSnapshot() {}
|
|
106
|
+
|
|
107
|
+
suspend fun fetchRemoteCatalog() {
|
|
108
|
+
val client = OkHttpClient()
|
|
109
|
+
client.newCall(
|
|
110
|
+
Request.Builder()
|
|
111
|
+
.url("https://example.com/catalog.json")
|
|
112
|
+
.build()
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fun cacheLastStore(preferences: SharedPreferences, storeId: String) {
|
|
117
|
+
preferences.edit().putString("last-store-id", storeId).apply()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fun openStoreMap() {
|
|
121
|
+
navController.navigate("store-map")
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
`;
|
|
125
|
+
|
|
126
|
+
const match = findKotlinPresentationSrpMatch(source);
|
|
127
|
+
|
|
128
|
+
assert.ok(match);
|
|
129
|
+
assert.deepEqual(match.primary_node, {
|
|
130
|
+
kind: 'class',
|
|
131
|
+
name: 'PumukiSrpAndroidCanaryViewModel',
|
|
132
|
+
lines: [8],
|
|
133
|
+
});
|
|
134
|
+
assert.deepEqual(match.related_nodes, [
|
|
135
|
+
{ kind: 'member', name: 'session/auth flow', lines: [11] },
|
|
136
|
+
{ kind: 'call', name: 'remote networking', lines: [14] },
|
|
137
|
+
{ kind: 'call', name: 'local persistence', lines: [22] },
|
|
138
|
+
{ kind: 'member', name: 'navigation flow', lines: [27] },
|
|
139
|
+
]);
|
|
140
|
+
assert.match(match.why, /SRP/i);
|
|
141
|
+
assert.match(match.impact, /múltiples razones de cambio/i);
|
|
142
|
+
assert.match(match.expected_fix, /casos de uso|coordinadores/i);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('findKotlinConcreteDependencyDipMatch devuelve payload semantico para DIP-Android en application', () => {
|
|
146
|
+
const source = `
|
|
147
|
+
import android.content.SharedPreferences
|
|
148
|
+
import okhttp3.OkHttpClient
|
|
149
|
+
import okhttp3.Request
|
|
150
|
+
|
|
151
|
+
class PumukiDipAndroidCanaryUseCase(
|
|
152
|
+
private val preferences: SharedPreferences,
|
|
153
|
+
) {
|
|
154
|
+
private val client: OkHttpClient = OkHttpClient()
|
|
155
|
+
|
|
156
|
+
suspend fun execute() {
|
|
157
|
+
val request = Request.Builder()
|
|
158
|
+
.url("https://example.com/catalog.json")
|
|
159
|
+
.build()
|
|
160
|
+
|
|
161
|
+
client.newCall(request)
|
|
162
|
+
preferences.edit().putLong("last-sync", 1L).apply()
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
`;
|
|
166
|
+
|
|
167
|
+
const match = findKotlinConcreteDependencyDipMatch(source);
|
|
168
|
+
|
|
169
|
+
assert.ok(match);
|
|
170
|
+
assert.deepEqual(match.primary_node, {
|
|
171
|
+
kind: 'class',
|
|
172
|
+
name: 'PumukiDipAndroidCanaryUseCase',
|
|
173
|
+
lines: [6],
|
|
174
|
+
});
|
|
175
|
+
assert.deepEqual(match.related_nodes, [
|
|
176
|
+
{ kind: 'property', name: 'concrete dependency: SharedPreferences', lines: [7] },
|
|
177
|
+
{ kind: 'property', name: 'concrete dependency: OkHttpClient', lines: [9] },
|
|
178
|
+
{ kind: 'call', name: 'OkHttpClient()', lines: [9] },
|
|
179
|
+
]);
|
|
180
|
+
assert.match(match.why, /DIP/i);
|
|
181
|
+
assert.match(match.impact, /infraestructura|alto nivel|coste de sustituir/i);
|
|
182
|
+
assert.match(match.expected_fix, /puertos|abstracciones|gateways/i);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('findKotlinOpenClosedWhenMatch devuelve payload semantico para OCP-Android en application', () => {
|
|
186
|
+
const source = `
|
|
187
|
+
enum class PumukiOcpAndroidCanaryChannel {
|
|
188
|
+
GroceryPickup,
|
|
189
|
+
HomeDelivery,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
class PumukiOcpAndroidCanaryUseCase {
|
|
193
|
+
fun resolve(channel: PumukiOcpAndroidCanaryChannel): String {
|
|
194
|
+
return when (channel) {
|
|
195
|
+
PumukiOcpAndroidCanaryChannel.GroceryPickup -> "pickup"
|
|
196
|
+
PumukiOcpAndroidCanaryChannel.HomeDelivery -> "delivery"
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
`;
|
|
201
|
+
|
|
202
|
+
const match = findKotlinOpenClosedWhenMatch(source);
|
|
203
|
+
|
|
204
|
+
assert.ok(match);
|
|
205
|
+
assert.deepEqual(match.primary_node, {
|
|
206
|
+
kind: 'class',
|
|
207
|
+
name: 'PumukiOcpAndroidCanaryUseCase',
|
|
208
|
+
lines: [7],
|
|
209
|
+
});
|
|
210
|
+
assert.deepEqual(match.related_nodes, [
|
|
211
|
+
{ kind: 'member', name: 'discriminator switch: channel', lines: [9] },
|
|
212
|
+
{ kind: 'member', name: 'branch GroceryPickup', lines: [10] },
|
|
213
|
+
{ kind: 'member', name: 'branch HomeDelivery', lines: [11] },
|
|
214
|
+
]);
|
|
215
|
+
assert.match(match.why, /OCP/i);
|
|
216
|
+
assert.match(match.impact, /nuevo caso|modificar/i);
|
|
217
|
+
assert.match(match.expected_fix, /estrategia|interfaz|registry/i);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test('findKotlinInterfaceSegregationMatch devuelve payload semantico para ISP-Android en application', () => {
|
|
221
|
+
const source = `
|
|
222
|
+
interface PumukiIspAndroidCanarySessionPort {
|
|
223
|
+
suspend fun restoreSession()
|
|
224
|
+
suspend fun persistSessionID(id: String)
|
|
225
|
+
suspend fun clearSession()
|
|
226
|
+
suspend fun refreshToken(): String
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
class PumukiIspAndroidCanaryUseCase(
|
|
230
|
+
private val sessionPort: PumukiIspAndroidCanarySessionPort,
|
|
231
|
+
) {
|
|
232
|
+
suspend fun execute() {
|
|
233
|
+
sessionPort.restoreSession()
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
`;
|
|
237
|
+
|
|
238
|
+
const match = findKotlinInterfaceSegregationMatch(source);
|
|
239
|
+
|
|
240
|
+
assert.ok(match);
|
|
241
|
+
assert.deepEqual(match.primary_node, {
|
|
242
|
+
kind: 'class',
|
|
243
|
+
name: 'PumukiIspAndroidCanaryUseCase',
|
|
244
|
+
lines: [9],
|
|
245
|
+
});
|
|
246
|
+
assert.deepEqual(match.related_nodes, [
|
|
247
|
+
{ kind: 'member', name: 'fat interface: PumukiIspAndroidCanarySessionPort', lines: [2] },
|
|
248
|
+
{ kind: 'call', name: 'used member: restoreSession', lines: [13] },
|
|
249
|
+
{ kind: 'member', name: 'unused contract member: persistSessionID', lines: [4] },
|
|
250
|
+
{ kind: 'member', name: 'unused contract member: clearSession', lines: [5] },
|
|
251
|
+
]);
|
|
252
|
+
assert.match(match.why, /ISP/i);
|
|
253
|
+
assert.match(match.impact, /contrato demasiado ancho|cambios ajenos/i);
|
|
254
|
+
assert.match(match.expected_fix, /interfaces pequeñas|puerto mínimo/i);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('findKotlinLiskovSubstitutionMatch devuelve payload semantico para LSP-Android en application', () => {
|
|
258
|
+
const source = `
|
|
259
|
+
interface PumukiLspAndroidCanaryDiscountPolicy {
|
|
260
|
+
fun apply(amount: Double): Double
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
class PumukiLspAndroidCanaryStandardDiscountPolicy : PumukiLspAndroidCanaryDiscountPolicy {
|
|
264
|
+
override fun apply(amount: Double): Double {
|
|
265
|
+
return amount * 0.9
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
class PumukiLspAndroidCanaryPremiumDiscountPolicy : PumukiLspAndroidCanaryDiscountPolicy {
|
|
270
|
+
override fun apply(amount: Double): Double {
|
|
271
|
+
require(amount >= 100.0)
|
|
272
|
+
error("premium-only")
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
`;
|
|
276
|
+
|
|
277
|
+
const match = findKotlinLiskovSubstitutionMatch(source);
|
|
278
|
+
|
|
279
|
+
assert.ok(match);
|
|
280
|
+
assert.deepEqual(match.primary_node, {
|
|
281
|
+
kind: 'class',
|
|
282
|
+
name: 'PumukiLspAndroidCanaryPremiumDiscountPolicy',
|
|
283
|
+
lines: [12],
|
|
284
|
+
});
|
|
285
|
+
assert.deepEqual(match.related_nodes, [
|
|
286
|
+
{ kind: 'member', name: 'base contract: PumukiLspAndroidCanaryDiscountPolicy', lines: [2] },
|
|
287
|
+
{ kind: 'member', name: 'safe substitute: PumukiLspAndroidCanaryStandardDiscountPolicy', lines: [6] },
|
|
288
|
+
{ kind: 'member', name: 'narrowed precondition: apply', lines: [14] },
|
|
289
|
+
{ kind: 'call', name: 'error', lines: [15] },
|
|
290
|
+
]);
|
|
291
|
+
assert.match(match.why, /LSP/i);
|
|
292
|
+
assert.match(match.impact, /sustituci|regresion|crash/i);
|
|
293
|
+
assert.match(match.expected_fix, /contrato base|estrategia|subtipo/i);
|
|
294
|
+
});
|