octocode-cli 1.2.6 → 1.2.8
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/LICENSE +21 -63
- package/README.md +85 -142
- package/out/octocode-cli.js +7063 -6934
- package/package.json +8 -6
- package/skills/README.md +97 -120
- package/skills/octocode-code-engineer/.claude/settings.local.json +18 -0
- package/skills/octocode-code-engineer/.octocode/rfc/RFC-code-engineer-weakness-fixes.md +255 -0
- package/skills/octocode-code-engineer/.plan/VALIDATED_PLAN.md +223 -0
- package/skills/octocode-code-engineer/README.md +178 -0
- package/skills/octocode-code-engineer/SKILL.md +418 -0
- package/skills/octocode-code-engineer/coverage/architecture.ts.html +7828 -0
- package/skills/octocode-code-engineer/coverage/ast-helpers.ts.html +211 -0
- package/skills/octocode-code-engineer/coverage/ast-search.ts.html +1795 -0
- package/skills/octocode-code-engineer/coverage/base.css +224 -0
- package/skills/octocode-code-engineer/coverage/block-navigation.js +87 -0
- package/skills/octocode-code-engineer/coverage/cache.ts.html +376 -0
- package/skills/octocode-code-engineer/coverage/cli.ts.html +982 -0
- package/skills/octocode-code-engineer/coverage/clover.xml +3217 -0
- package/skills/octocode-code-engineer/coverage/collect-effects.ts.html +664 -0
- package/skills/octocode-code-engineer/coverage/collect-input-sources.ts.html +577 -0
- package/skills/octocode-code-engineer/coverage/collect-performance.ts.html +331 -0
- package/skills/octocode-code-engineer/coverage/collect-prototype-pollution.ts.html +421 -0
- package/skills/octocode-code-engineer/coverage/collect-security.ts.html +604 -0
- package/skills/octocode-code-engineer/coverage/collect-test-profile.ts.html +589 -0
- package/skills/octocode-code-engineer/coverage/coverage-final.json +30 -0
- package/skills/octocode-code-engineer/coverage/dependencies.ts.html +997 -0
- package/skills/octocode-code-engineer/coverage/dependency-summary.ts.html +688 -0
- package/skills/octocode-code-engineer/coverage/discovery.ts.html +322 -0
- package/skills/octocode-code-engineer/coverage/favicon.png +0 -0
- package/skills/octocode-code-engineer/coverage/graph-analytics.ts.html +1510 -0
- package/skills/octocode-code-engineer/coverage/index.html +536 -0
- package/skills/octocode-code-engineer/coverage/index.ts.html +826 -0
- package/skills/octocode-code-engineer/coverage/metrics.ts.html +553 -0
- package/skills/octocode-code-engineer/coverage/pipeline.ts.html +2044 -0
- package/skills/octocode-code-engineer/coverage/prettify.css +1 -0
- package/skills/octocode-code-engineer/coverage/prettify.js +2 -0
- package/skills/octocode-code-engineer/coverage/report-analysis.ts.html +1570 -0
- package/skills/octocode-code-engineer/coverage/report-writer.ts.html +1102 -0
- package/skills/octocode-code-engineer/coverage/security-detectors.ts.html +1747 -0
- package/skills/octocode-code-engineer/coverage/semantic-detectors.ts.html +2152 -0
- package/skills/octocode-code-engineer/coverage/semantic.ts.html +1897 -0
- package/skills/octocode-code-engineer/coverage/sort-arrow-sprite.png +0 -0
- package/skills/octocode-code-engineer/coverage/sorter.js +210 -0
- package/skills/octocode-code-engineer/coverage/summary-md.ts.html +1222 -0
- package/skills/octocode-code-engineer/coverage/test-quality-detectors.ts.html +1039 -0
- package/skills/octocode-code-engineer/coverage/tree-sitter-analyzer.ts.html +955 -0
- package/skills/octocode-code-engineer/coverage/ts-analyzer.ts.html +1213 -0
- package/skills/octocode-code-engineer/coverage/types.ts.html +2473 -0
- package/skills/octocode-code-engineer/coverage/utils.ts.html +820 -0
- package/skills/octocode-code-engineer/eslint.config.mjs +54 -0
- package/skills/octocode-code-engineer/minify-scripts.mjs +32 -0
- package/skills/octocode-code-engineer/package.json +54 -0
- package/skills/octocode-code-engineer/references/agent-ast-reading-rfc.md +95 -0
- package/skills/octocode-code-engineer/references/architecture-techniques.md +121 -0
- package/skills/octocode-code-engineer/references/ast-search.md +210 -0
- package/skills/octocode-code-engineer/references/ast-tree-search.md +151 -0
- package/skills/octocode-code-engineer/references/cli-reference.md +167 -0
- package/skills/octocode-code-engineer/references/concepts.md +107 -0
- package/skills/octocode-code-engineer/references/finding-categories.md +128 -0
- package/skills/octocode-code-engineer/references/improvement-roadmap.md +304 -0
- package/skills/octocode-code-engineer/references/output-files.md +144 -0
- package/skills/octocode-code-engineer/references/playbooks.md +204 -0
- package/skills/octocode-code-engineer/references/present-results.md +136 -0
- package/skills/octocode-code-engineer/references/tool-workflows.md +566 -0
- package/skills/octocode-code-engineer/references/validate-investigate.md +225 -0
- package/skills/octocode-code-engineer/scripts/analysis/dependencies.js +1 -0
- package/skills/octocode-code-engineer/scripts/analysis/dependency-summary.js +1 -0
- package/skills/octocode-code-engineer/scripts/analysis/discovery.js +1 -0
- package/skills/octocode-code-engineer/scripts/analysis/graph-analytics.js +1 -0
- package/skills/octocode-code-engineer/scripts/analysis/semantic.js +1 -0
- package/skills/octocode-code-engineer/scripts/ast/helpers.js +1 -0
- package/skills/octocode-code-engineer/scripts/ast/metrics.js +1 -0
- package/skills/octocode-code-engineer/scripts/ast/search.js +2 -0
- package/skills/octocode-code-engineer/scripts/ast/tree-search.js +2 -0
- package/skills/octocode-code-engineer/scripts/ast/tree-sitter.js +1 -0
- package/skills/octocode-code-engineer/scripts/ast/ts-analyzer.js +1 -0
- package/skills/octocode-code-engineer/scripts/collectors/chains.js +1 -0
- package/skills/octocode-code-engineer/scripts/collectors/effects.js +1 -0
- package/skills/octocode-code-engineer/scripts/collectors/input-sources.js +1 -0
- package/skills/octocode-code-engineer/scripts/collectors/performance.js +1 -0
- package/skills/octocode-code-engineer/scripts/collectors/prototype-pollution.js +1 -0
- package/skills/octocode-code-engineer/scripts/collectors/security.js +1 -0
- package/skills/octocode-code-engineer/scripts/collectors/test-profile.js +1 -0
- package/skills/octocode-code-engineer/scripts/common/is-direct-run.js +1 -0
- package/skills/octocode-code-engineer/scripts/common/utils.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/code-quality.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/cohesion.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/coupling.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/cycle.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/dead-code.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/import-style.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/index.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/security.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/semantic.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/shared.js +1 -0
- package/skills/octocode-code-engineer/scripts/detectors/test-quality.js +1 -0
- package/skills/octocode-code-engineer/scripts/index.js +1 -0
- package/skills/octocode-code-engineer/scripts/pipeline/cache.js +1 -0
- package/skills/octocode-code-engineer/scripts/pipeline/cli.js +1 -0
- package/skills/octocode-code-engineer/scripts/pipeline/main.js +2 -0
- package/skills/octocode-code-engineer/scripts/reporting/analysis.js +1 -0
- package/skills/octocode-code-engineer/scripts/reporting/summary-md.js +1 -0
- package/skills/octocode-code-engineer/scripts/reporting/writer.js +1 -0
- package/skills/octocode-code-engineer/scripts/types/constants.js +1 -0
- package/skills/octocode-code-engineer/scripts/types/index.js +1 -0
- package/skills/octocode-code-engineer/scripts/types/interfaces.js +1 -0
- package/skills/octocode-code-engineer/src/analysis/dependencies.test.ts +545 -0
- package/skills/octocode-code-engineer/src/analysis/dependencies.ts +406 -0
- package/skills/octocode-code-engineer/src/analysis/dependency-summary.test.ts +566 -0
- package/skills/octocode-code-engineer/src/analysis/dependency-summary.ts +257 -0
- package/skills/octocode-code-engineer/src/analysis/discovery.test.ts +420 -0
- package/skills/octocode-code-engineer/src/analysis/discovery.ts +87 -0
- package/skills/octocode-code-engineer/src/analysis/graph-analytics.test.ts +449 -0
- package/skills/octocode-code-engineer/src/analysis/graph-analytics.ts +534 -0
- package/skills/octocode-code-engineer/src/analysis/semantic.test.ts +1533 -0
- package/skills/octocode-code-engineer/src/analysis/semantic.ts +830 -0
- package/skills/octocode-code-engineer/src/ast/helpers.test.ts +185 -0
- package/skills/octocode-code-engineer/src/ast/helpers.ts +62 -0
- package/skills/octocode-code-engineer/src/ast/metrics.test.ts +304 -0
- package/skills/octocode-code-engineer/src/ast/metrics.ts +204 -0
- package/skills/octocode-code-engineer/src/ast/search.test.ts +647 -0
- package/skills/octocode-code-engineer/src/ast/search.ts +648 -0
- package/skills/octocode-code-engineer/src/ast/tree-search.test.ts +199 -0
- package/skills/octocode-code-engineer/src/ast/tree-search.ts +392 -0
- package/skills/octocode-code-engineer/src/ast/tree-sitter.test.ts +407 -0
- package/skills/octocode-code-engineer/src/ast/tree-sitter.ts +402 -0
- package/skills/octocode-code-engineer/src/ast/ts-analyzer.test.ts +1864 -0
- package/skills/octocode-code-engineer/src/ast/ts-analyzer.ts +509 -0
- package/skills/octocode-code-engineer/src/collectors/chains.ts +74 -0
- package/skills/octocode-code-engineer/src/collectors/effects.test.ts +490 -0
- package/skills/octocode-code-engineer/src/collectors/effects.ts +332 -0
- package/skills/octocode-code-engineer/src/collectors/input-sources.test.ts +144 -0
- package/skills/octocode-code-engineer/src/collectors/input-sources.ts +196 -0
- package/skills/octocode-code-engineer/src/collectors/performance.test.ts +82 -0
- package/skills/octocode-code-engineer/src/collectors/performance.ts +141 -0
- package/skills/octocode-code-engineer/src/collectors/prototype-pollution.test.ts +55 -0
- package/skills/octocode-code-engineer/src/collectors/prototype-pollution.ts +162 -0
- package/skills/octocode-code-engineer/src/collectors/security.test.ts +124 -0
- package/skills/octocode-code-engineer/src/collectors/security.ts +309 -0
- package/skills/octocode-code-engineer/src/collectors/test-profile.test.ts +97 -0
- package/skills/octocode-code-engineer/src/collectors/test-profile.ts +269 -0
- package/skills/octocode-code-engineer/src/common/is-direct-run.test.ts +32 -0
- package/skills/octocode-code-engineer/src/common/is-direct-run.ts +13 -0
- package/skills/octocode-code-engineer/src/common/utils.test.ts +463 -0
- package/skills/octocode-code-engineer/src/common/utils.ts +304 -0
- package/skills/octocode-code-engineer/src/detectors/code-quality.ts +966 -0
- package/skills/octocode-code-engineer/src/detectors/cohesion.ts +539 -0
- package/skills/octocode-code-engineer/src/detectors/coupling.ts +323 -0
- package/skills/octocode-code-engineer/src/detectors/cycle.ts +349 -0
- package/skills/octocode-code-engineer/src/detectors/dead-code.ts +320 -0
- package/skills/octocode-code-engineer/src/detectors/import-style.ts +376 -0
- package/skills/octocode-code-engineer/src/detectors/index.test.ts +3061 -0
- package/skills/octocode-code-engineer/src/detectors/index.ts +88 -0
- package/skills/octocode-code-engineer/src/detectors/security.test.ts +882 -0
- package/skills/octocode-code-engineer/src/detectors/security.ts +821 -0
- package/skills/octocode-code-engineer/src/detectors/semantic.ts +758 -0
- package/skills/octocode-code-engineer/src/detectors/shared.ts +49 -0
- package/skills/octocode-code-engineer/src/detectors/test-quality.test.ts +388 -0
- package/skills/octocode-code-engineer/src/detectors/test-quality.ts +367 -0
- package/skills/octocode-code-engineer/src/index.test.ts +4425 -0
- package/skills/octocode-code-engineer/src/index.ts +403 -0
- package/skills/octocode-code-engineer/src/pipeline/cache.test.ts +199 -0
- package/skills/octocode-code-engineer/src/pipeline/cache.ts +130 -0
- package/skills/octocode-code-engineer/src/pipeline/cli.test.ts +493 -0
- package/skills/octocode-code-engineer/src/pipeline/cli.ts +344 -0
- package/skills/octocode-code-engineer/src/pipeline/main.test.ts +174 -0
- package/skills/octocode-code-engineer/src/pipeline/main.ts +1074 -0
- package/skills/octocode-code-engineer/src/pipeline.test.ts +84 -0
- package/skills/octocode-code-engineer/src/reporting/analysis.test.ts +782 -0
- package/skills/octocode-code-engineer/src/reporting/analysis.ts +688 -0
- package/skills/octocode-code-engineer/src/reporting/output-contract.test.ts +463 -0
- package/skills/octocode-code-engineer/src/reporting/summary-md.test.ts +421 -0
- package/skills/octocode-code-engineer/src/reporting/summary-md.ts +714 -0
- package/skills/octocode-code-engineer/src/reporting/writer.ts +430 -0
- package/skills/octocode-code-engineer/src/sanity.test.ts +47 -0
- package/skills/octocode-code-engineer/src/types/constants.ts +248 -0
- package/skills/octocode-code-engineer/src/types/index.ts +80 -0
- package/skills/octocode-code-engineer/src/types/interfaces.ts +682 -0
- package/skills/octocode-code-engineer/tsconfig.json +17 -0
- package/skills/octocode-code-engineer/vitest.config.ts +8 -0
- package/skills/octocode-documentation-writer/README.md +113 -0
- package/skills/octocode-documentation-writer/SKILL.md +886 -0
- package/skills/octocode-documentation-writer/references/agent-discovery-analysis.md +453 -0
- package/skills/octocode-documentation-writer/references/agent-documentation-writer.md +255 -0
- package/skills/octocode-documentation-writer/references/agent-engineer-questions.md +247 -0
- package/skills/octocode-documentation-writer/references/agent-orchestrator.md +370 -0
- package/skills/octocode-documentation-writer/references/agent-qa-validator.md +227 -0
- package/skills/octocode-documentation-writer/references/agent-researcher.md +250 -0
- package/skills/octocode-documentation-writer/schemas/analysis-schema.json +886 -0
- package/skills/octocode-documentation-writer/schemas/discovery-tasks.json +96 -0
- package/skills/octocode-documentation-writer/schemas/documentation-structure.json +373 -0
- package/skills/octocode-documentation-writer/schemas/partial-discovery-schema.json +102 -0
- package/skills/octocode-documentation-writer/schemas/partial-research-schema.json +98 -0
- package/skills/octocode-documentation-writer/schemas/qa-results-schema.json +113 -0
- package/skills/octocode-documentation-writer/schemas/questions-schema.json +228 -0
- package/skills/octocode-documentation-writer/schemas/research-schema.json +104 -0
- package/skills/octocode-documentation-writer/schemas/state-schema.json +222 -0
- package/skills/octocode-documentation-writer/schemas/work-assignments-schema.json +74 -0
- package/skills/octocode-plan/SKILL.md +122 -116
- package/skills/octocode-prompt-optimizer/SKILL.md +617 -0
- package/skills/octocode-pull-request-reviewer/README.md +249 -0
- package/skills/octocode-pull-request-reviewer/SKILL.md +479 -0
- package/skills/octocode-pull-request-reviewer/references/dependency-check.md +74 -0
- package/skills/octocode-pull-request-reviewer/references/domain-reviewers.md +24 -0
- package/skills/octocode-pull-request-reviewer/references/execution-lifecycle.md +441 -0
- package/skills/octocode-pull-request-reviewer/references/flow-analysis-protocol.md +64 -0
- package/skills/octocode-pull-request-reviewer/references/output-template.md +174 -0
- package/skills/octocode-pull-request-reviewer/references/parallel-agent-protocol.md +182 -0
- package/skills/octocode-pull-request-reviewer/references/review-guidelines.md +26 -0
- package/skills/octocode-pull-request-reviewer/references/verification-checklist.md +40 -0
- package/skills/octocode-research/.claude/settings.local.json +46 -0
- package/skills/octocode-research/.octocode/plan/code-review-fixes/plan.md +312 -0
- package/skills/octocode-research/.octocode/plan/code-review-fixes/research.md +212 -0
- package/skills/octocode-research/.octocode/plans/NODE_SERVER_START_PLAN.md +755 -0
- package/skills/octocode-research/.octocode/research/code-review/research.md +371 -0
- package/skills/octocode-research/.octocode/review/IMPROVEMENTS.md +391 -0
- package/skills/octocode-research/.octocode/review/REVIEW_PLAN.md +289 -0
- package/skills/octocode-research/.octocode/review/REVIEW_REPORT.md +356 -0
- package/skills/octocode-research/AGENTS.md +349 -0
- package/skills/octocode-research/README.md +494 -0
- package/skills/octocode-research/SKILL.md +652 -274
- package/skills/octocode-research/docs/API_REFERENCE.md +562 -0
- package/skills/octocode-research/docs/ARCHITECTURE.md +554 -0
- package/skills/octocode-research/docs/FLOWS.md +577 -0
- package/skills/octocode-research/docs/OVERVIEW.md +564 -0
- package/skills/octocode-research/docs/SERVER_FLOWS.md +631 -0
- package/skills/octocode-research/ecosystem.config.cjs +88 -0
- package/skills/octocode-research/eslint.config.mjs +27 -0
- package/skills/octocode-research/package.json +84 -0
- package/skills/octocode-research/references/GUARDRAILS.md +40 -0
- package/skills/octocode-research/references/PARALLEL_AGENT_PROTOCOL.md +178 -0
- package/skills/octocode-research/references/roast-prompt.md +149 -0
- package/skills/octocode-research/scripts/server-init.d.ts +2 -0
- package/skills/octocode-research/scripts/server-init.js +2 -0
- package/skills/octocode-research/scripts/server.d.ts +8 -0
- package/skills/octocode-research/scripts/server.js +445 -0
- package/skills/octocode-research/src/__tests__/integration/circuitBreaker.test.ts +205 -0
- package/skills/octocode-research/src/__tests__/integration/routes.test.ts +374 -0
- package/skills/octocode-research/src/__tests__/unit/circuitBreaker.test.ts +245 -0
- package/skills/octocode-research/src/__tests__/unit/errorHandler.test.ts +183 -0
- package/skills/octocode-research/src/__tests__/unit/httpPreprocess.test.ts +157 -0
- package/skills/octocode-research/src/__tests__/unit/logger.test.ts +143 -0
- package/skills/octocode-research/src/__tests__/unit/queryParser.test.ts +130 -0
- package/skills/octocode-research/src/__tests__/unit/responseBuilder.test.ts +469 -0
- package/skills/octocode-research/src/__tests__/unit/retry.test.ts +205 -0
- package/skills/octocode-research/src/index.ts +186 -0
- package/skills/octocode-research/src/mcpCache.ts +49 -0
- package/skills/octocode-research/src/middleware/errorHandler.ts +65 -0
- package/skills/octocode-research/src/middleware/logger.ts +61 -0
- package/skills/octocode-research/src/middleware/queryParser.ts +115 -0
- package/skills/octocode-research/src/middleware/readiness.ts +17 -0
- package/skills/octocode-research/src/routes/github.ts +197 -0
- package/skills/octocode-research/src/routes/local.ts +175 -0
- package/skills/octocode-research/src/routes/lsp.ts +177 -0
- package/skills/octocode-research/src/routes/package.ts +127 -0
- package/skills/octocode-research/src/routes/prompts.ts +138 -0
- package/skills/octocode-research/src/routes/tools.ts +677 -0
- package/skills/octocode-research/src/server-init.ts +363 -0
- package/skills/octocode-research/src/server.ts +285 -0
- package/skills/octocode-research/src/types/errorGuards.ts +151 -0
- package/skills/octocode-research/src/types/express.d.ts +76 -0
- package/skills/octocode-research/src/types/guards.ts +98 -0
- package/skills/octocode-research/src/types/mcp.ts +119 -0
- package/skills/octocode-research/src/types/responses.ts +199 -0
- package/skills/octocode-research/src/types/toolTypes.ts +33 -0
- package/skills/octocode-research/src/utils/asyncTimeout.ts +116 -0
- package/skills/octocode-research/src/utils/circuitBreaker.ts +492 -0
- package/skills/octocode-research/src/utils/colors.ts +53 -0
- package/skills/octocode-research/src/utils/errorQueue.ts +71 -0
- package/skills/octocode-research/src/utils/logEmoji.ts +103 -0
- package/skills/octocode-research/src/utils/logger.ts +413 -0
- package/skills/octocode-research/src/utils/resilience.ts +169 -0
- package/skills/octocode-research/src/utils/responseBuilder.ts +495 -0
- package/skills/octocode-research/src/utils/responseFactory.ts +100 -0
- package/skills/octocode-research/src/utils/responseParser.ts +272 -0
- package/skills/octocode-research/src/utils/retry.ts +280 -0
- package/skills/octocode-research/src/utils/routeFactory.ts +117 -0
- package/skills/octocode-research/src/utils/url.ts +20 -0
- package/skills/octocode-research/src/validation/httpPreprocess.ts +155 -0
- package/skills/octocode-research/src/validation/index.ts +2 -0
- package/skills/octocode-research/src/validation/schemas.ts +578 -0
- package/skills/octocode-research/src/validation/toolCallSchema.ts +132 -0
- package/skills/octocode-research/tsconfig.json +21 -0
- package/skills/octocode-research/tsdown.config.ts +42 -0
- package/skills/octocode-research/vitest.config.ts +20 -0
- package/skills/octocode-researcher/SKILL.md +461 -0
- package/skills/octocode-researcher/references/fallbacks.md +120 -0
- package/skills/{octocode-local-search → octocode-researcher}/references/tool-reference.md +132 -49
- package/skills/{octocode-local-search → octocode-researcher}/references/workflow-patterns.md +204 -4
- package/skills/octocode-rfc-generator/SKILL.md +223 -0
- package/skills/octocode-rfc-generator/references/rfc-template.md +193 -0
- package/skills/octocode-roast/SKILL.md +63 -21
- package/skills/octocode-implement/SKILL.md +0 -293
- package/skills/octocode-implement/references/execution-phases.md +0 -317
- package/skills/octocode-implement/references/tool-reference.md +0 -403
- package/skills/octocode-implement/references/workflow-patterns.md +0 -385
- package/skills/octocode-local-search/SKILL.md +0 -449
- package/skills/octocode-pr-review/SKILL.md +0 -391
- package/skills/octocode-pr-review/references/domain-reviewers.md +0 -105
- package/skills/octocode-pr-review/references/execution-lifecycle.md +0 -116
- package/skills/octocode-pr-review/references/research-flows.md +0 -75
- package/skills/octocode-research/references/tool-reference.md +0 -304
- package/skills/octocode-research/references/workflow-patterns.md +0 -325
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded queue for fire-and-forget operation errors.
|
|
3
|
+
* Provides visibility into async errors without blocking main flow.
|
|
4
|
+
*
|
|
5
|
+
* @module utils/errorQueue
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
interface QueuedError {
|
|
9
|
+
timestamp: Date;
|
|
10
|
+
error: Error;
|
|
11
|
+
context?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Bounded error queue that stores recent errors from async operations.
|
|
16
|
+
* Prevents unbounded memory growth while maintaining error visibility.
|
|
17
|
+
*/
|
|
18
|
+
class ErrorQueue {
|
|
19
|
+
private errors: QueuedError[] = [];
|
|
20
|
+
private readonly maxSize: number;
|
|
21
|
+
|
|
22
|
+
constructor(maxSize = 100) {
|
|
23
|
+
this.maxSize = maxSize;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Add an error to the queue.
|
|
28
|
+
* If queue is full, oldest error is removed.
|
|
29
|
+
*/
|
|
30
|
+
push(error: unknown, context?: string): void {
|
|
31
|
+
const normalizedError =
|
|
32
|
+
error instanceof Error ? error : new Error(String(error));
|
|
33
|
+
|
|
34
|
+
this.errors.push({
|
|
35
|
+
timestamp: new Date(),
|
|
36
|
+
error: normalizedError,
|
|
37
|
+
context,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Bounded: remove oldest when full
|
|
41
|
+
if (this.errors.length > this.maxSize) {
|
|
42
|
+
this.errors.shift();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get the most recent errors.
|
|
48
|
+
*/
|
|
49
|
+
getRecent(count = 10): QueuedError[] {
|
|
50
|
+
return this.errors.slice(-count);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Clear all errors from the queue.
|
|
55
|
+
*/
|
|
56
|
+
clear(): void {
|
|
57
|
+
this.errors = [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get current queue size.
|
|
62
|
+
*/
|
|
63
|
+
get size(): number {
|
|
64
|
+
return this.errors.length;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Global error queue instance for fire-and-forget operations.
|
|
70
|
+
*/
|
|
71
|
+
export const errorQueue = new ErrorQueue();
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment-aware emoji toggle for log messages.
|
|
3
|
+
*
|
|
4
|
+
* Disables emojis in production or when LOG_NO_EMOJI is set,
|
|
5
|
+
* as they can cause issues with log parsing tools.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/logEmoji
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Configuration
|
|
12
|
+
// =============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Check if emojis should be used in logs.
|
|
16
|
+
* Returns false when:
|
|
17
|
+
* - NODE_ENV is 'production'
|
|
18
|
+
* - LOG_NO_EMOJI env var is truthy ('true', '1', 'yes')
|
|
19
|
+
*/
|
|
20
|
+
export function shouldUseEmoji(): boolean {
|
|
21
|
+
if (process.env.NODE_ENV === 'production') return false;
|
|
22
|
+
const noEmoji = process.env.LOG_NO_EMOJI;
|
|
23
|
+
if (noEmoji === 'true' || noEmoji === '1' || noEmoji === 'yes') return false;
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// Emoji Registry
|
|
29
|
+
// =============================================================================
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Supported emoji keys for logging
|
|
33
|
+
*/
|
|
34
|
+
export type LogEmojiKey =
|
|
35
|
+
| 'server'
|
|
36
|
+
| 'shutdown'
|
|
37
|
+
| 'logs'
|
|
38
|
+
| 'routes'
|
|
39
|
+
| 'success'
|
|
40
|
+
| 'error'
|
|
41
|
+
| 'warning'
|
|
42
|
+
| 'info'
|
|
43
|
+
| 'circuit_open'
|
|
44
|
+
| 'circuit_closed'
|
|
45
|
+
| 'circuit_half_open'
|
|
46
|
+
| 'cleanup'
|
|
47
|
+
| 'reset'
|
|
48
|
+
| 'retry'
|
|
49
|
+
| 'evict';
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Emoji map with fallback text alternatives
|
|
53
|
+
*/
|
|
54
|
+
const EMOJI_MAP: Record<LogEmojiKey, { emoji: string; fallback: string }> = {
|
|
55
|
+
server: { emoji: '🔍', fallback: '[SERVER]' },
|
|
56
|
+
shutdown: { emoji: '🛑', fallback: '[SHUTDOWN]' },
|
|
57
|
+
logs: { emoji: '📁', fallback: '[LOGS]' },
|
|
58
|
+
routes: { emoji: '📋', fallback: '[ROUTES]' },
|
|
59
|
+
success: { emoji: '✅', fallback: '[OK]' },
|
|
60
|
+
error: { emoji: '❌', fallback: '[ERROR]' },
|
|
61
|
+
warning: { emoji: '⚠️', fallback: '[WARN]' },
|
|
62
|
+
info: { emoji: 'ℹ️', fallback: '[INFO]' },
|
|
63
|
+
circuit_open: { emoji: '🔴', fallback: '[OPEN]' },
|
|
64
|
+
circuit_closed: { emoji: '🟢', fallback: '[CLOSED]' },
|
|
65
|
+
circuit_half_open: { emoji: '🟡', fallback: '[HALF-OPEN]' },
|
|
66
|
+
cleanup: { emoji: '🧹', fallback: '[CLEANUP]' },
|
|
67
|
+
reset: { emoji: '🔄', fallback: '[RESET]' },
|
|
68
|
+
retry: { emoji: '⟳', fallback: '[RETRY]' },
|
|
69
|
+
evict: { emoji: '⚠️', fallback: '[EVICT]' },
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// =============================================================================
|
|
73
|
+
// Public API
|
|
74
|
+
// =============================================================================
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get the appropriate emoji or fallback text for a log key.
|
|
78
|
+
*
|
|
79
|
+
* @param key - The emoji key to retrieve
|
|
80
|
+
* @returns Emoji string or fallback text based on environment
|
|
81
|
+
*/
|
|
82
|
+
export function getLogEmoji(key: LogEmojiKey): string {
|
|
83
|
+
const entry = EMOJI_MAP[key];
|
|
84
|
+
return shouldUseEmoji() ? entry.emoji : entry.fallback;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Prefix a message with the appropriate emoji or fallback.
|
|
89
|
+
*
|
|
90
|
+
* @param key - The emoji key to use
|
|
91
|
+
* @param message - The message to prefix
|
|
92
|
+
* @returns Formatted message with emoji/fallback prefix
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* // Development: "🔍 Server running on port 1987"
|
|
97
|
+
* // Production: "[SERVER] Server running on port 1987"
|
|
98
|
+
* console.log(prefixLog('server', 'Server running on port 1987'));
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export function prefixLog(key: LogEmojiKey, message: string): string {
|
|
102
|
+
return `${getLogEmoji(key)} ${message}`;
|
|
103
|
+
}
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { errorLog, warnLog } from './colors.js';
|
|
2
|
+
import { errorQueue } from './errorQueue.js';
|
|
3
|
+
/**
|
|
4
|
+
* Cross-platform logging utility for Octocode Research Server
|
|
5
|
+
*
|
|
6
|
+
* Logs to ~/.octocode/logs/ (or %USERPROFILE%\.octocode\logs on Windows)
|
|
7
|
+
* - errors.log: All errors and warnings
|
|
8
|
+
* - tools.log: Tool invocation data and results
|
|
9
|
+
*
|
|
10
|
+
* PERFORMANCE: Uses async file operations to avoid blocking event loop
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import fs from 'node:fs';
|
|
14
|
+
import { promises as fsAsync } from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import os from 'node:os';
|
|
17
|
+
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Configuration
|
|
20
|
+
// ============================================================================
|
|
21
|
+
|
|
22
|
+
const HOME = os.homedir();
|
|
23
|
+
const OCTOCODE_DIR = process.env.OCTOCODE_HOME || path.join(HOME, '.octocode');
|
|
24
|
+
const LOGS_DIR = path.join(OCTOCODE_DIR, 'logs');
|
|
25
|
+
const ERROR_LOG = path.join(LOGS_DIR, 'errors.log');
|
|
26
|
+
const TOOLS_LOG = path.join(LOGS_DIR, 'tools.log');
|
|
27
|
+
|
|
28
|
+
// Max log file size before rotation (10MB)
|
|
29
|
+
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
30
|
+
|
|
31
|
+
// Max size for JSON.stringify to prevent memory spikes (100KB)
|
|
32
|
+
const MAX_LOG_DATA_SIZE = 100 * 1024;
|
|
33
|
+
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// Directory Initialization (async with sync fallback for startup)
|
|
36
|
+
// ============================================================================
|
|
37
|
+
|
|
38
|
+
let initialized = false;
|
|
39
|
+
let fileLoggingEnabled = true;
|
|
40
|
+
let initPromise: Promise<void> | null = null;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Ensure the logs directory exists (async).
|
|
44
|
+
* Safe to call multiple times (idempotent).
|
|
45
|
+
*/
|
|
46
|
+
async function ensureLogsDirAsync(): Promise<void> {
|
|
47
|
+
if (initialized) return;
|
|
48
|
+
if (initPromise) return initPromise;
|
|
49
|
+
|
|
50
|
+
initPromise = (async () => {
|
|
51
|
+
try {
|
|
52
|
+
await fsAsync.mkdir(OCTOCODE_DIR, { recursive: true, mode: 0o700 });
|
|
53
|
+
await fsAsync.mkdir(LOGS_DIR, { recursive: true, mode: 0o700 });
|
|
54
|
+
initialized = true;
|
|
55
|
+
} catch (err) {
|
|
56
|
+
process.stderr.write(
|
|
57
|
+
`[Logger] Failed to create logs directory: ${err}\n` +
|
|
58
|
+
`Falling back to console-only logging.\n`
|
|
59
|
+
);
|
|
60
|
+
fileLoggingEnabled = false;
|
|
61
|
+
}
|
|
62
|
+
})();
|
|
63
|
+
|
|
64
|
+
return initPromise;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Sync initialization for startup only (blocking but necessary)
|
|
69
|
+
*/
|
|
70
|
+
function ensureLogsDirSync(): void {
|
|
71
|
+
if (initialized) return;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
if (!fs.existsSync(OCTOCODE_DIR)) {
|
|
75
|
+
fs.mkdirSync(OCTOCODE_DIR, { recursive: true, mode: 0o700 });
|
|
76
|
+
}
|
|
77
|
+
if (!fs.existsSync(LOGS_DIR)) {
|
|
78
|
+
fs.mkdirSync(LOGS_DIR, { recursive: true, mode: 0o700 });
|
|
79
|
+
}
|
|
80
|
+
initialized = true;
|
|
81
|
+
} catch (err) {
|
|
82
|
+
process.stderr.write(
|
|
83
|
+
`[Logger] Failed to create logs directory: ${err}\n` +
|
|
84
|
+
`Falling back to console-only logging.\n`
|
|
85
|
+
);
|
|
86
|
+
fileLoggingEnabled = false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// Log Rotation (async)
|
|
92
|
+
// ============================================================================
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Rotate log file if it exceeds max size (async).
|
|
96
|
+
*/
|
|
97
|
+
async function rotateIfNeededAsync(logPath: string): Promise<void> {
|
|
98
|
+
try {
|
|
99
|
+
const stats = await fsAsync.stat(logPath).catch(() => null);
|
|
100
|
+
if (!stats || stats.size < MAX_LOG_SIZE) return;
|
|
101
|
+
|
|
102
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
103
|
+
const ext = path.extname(logPath);
|
|
104
|
+
const base = path.basename(logPath, ext);
|
|
105
|
+
const rotatedPath = path.join(LOGS_DIR, `${base}.${timestamp}${ext}`);
|
|
106
|
+
|
|
107
|
+
await fsAsync.rename(logPath, rotatedPath);
|
|
108
|
+
await cleanupOldLogsAsync(base, ext, 5);
|
|
109
|
+
} catch {
|
|
110
|
+
// Silently fail - logging should never crash the server
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Remove old rotated log files, keeping only the most recent ones (async).
|
|
116
|
+
*/
|
|
117
|
+
async function cleanupOldLogsAsync(baseName: string, ext: string, keep: number): Promise<void> {
|
|
118
|
+
try {
|
|
119
|
+
const files = await fsAsync.readdir(LOGS_DIR);
|
|
120
|
+
const rotatedFiles = files
|
|
121
|
+
.filter((f) => f.startsWith(baseName + '.') && f.endsWith(ext) && f !== baseName + ext)
|
|
122
|
+
.sort()
|
|
123
|
+
.reverse();
|
|
124
|
+
|
|
125
|
+
// Remove files beyond the keep limit
|
|
126
|
+
const toDelete = rotatedFiles.slice(keep);
|
|
127
|
+
await Promise.all(
|
|
128
|
+
toDelete.map((f) => fsAsync.unlink(path.join(LOGS_DIR, f)).catch(err => errorQueue.push(err, 'cleanupOldLogs')))
|
|
129
|
+
);
|
|
130
|
+
} catch {
|
|
131
|
+
// Silently fail
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ============================================================================
|
|
136
|
+
// Log Entry Formatting
|
|
137
|
+
// ============================================================================
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Safely stringify data with size limit to prevent memory spikes.
|
|
141
|
+
* Uses single-pass approach with size tracking to avoid double serialization.
|
|
142
|
+
*/
|
|
143
|
+
function safeStringify(data: unknown): string {
|
|
144
|
+
if (data === undefined) return '';
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
let size = 0;
|
|
148
|
+
let truncated = false;
|
|
149
|
+
const seen = new WeakSet<object>();
|
|
150
|
+
|
|
151
|
+
// Custom replacer that tracks size and detects circular refs
|
|
152
|
+
const replacer = (_key: string, value: unknown): unknown => {
|
|
153
|
+
// Check for circular references
|
|
154
|
+
if (value !== null && typeof value === 'object') {
|
|
155
|
+
if (seen.has(value)) {
|
|
156
|
+
return '[Circular]';
|
|
157
|
+
}
|
|
158
|
+
seen.add(value);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Estimate size contribution (rough but fast)
|
|
162
|
+
const valueStr = typeof value === 'string' ? value : String(value ?? '');
|
|
163
|
+
size += valueStr.length + 10; // +10 for key, quotes, colons, etc.
|
|
164
|
+
|
|
165
|
+
// If we've exceeded limit, mark as truncated and return placeholder
|
|
166
|
+
if (size > MAX_LOG_DATA_SIZE && !truncated) {
|
|
167
|
+
truncated = true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return value;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const result = JSON.stringify(data, replacer, 2);
|
|
174
|
+
|
|
175
|
+
// If truncated during serialization, return truncation notice
|
|
176
|
+
if (truncated) {
|
|
177
|
+
return JSON.stringify({
|
|
178
|
+
_truncated: true,
|
|
179
|
+
_estimatedSize: size,
|
|
180
|
+
_message: 'Data too large for logging',
|
|
181
|
+
}, null, 2);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return result;
|
|
185
|
+
} catch {
|
|
186
|
+
return '[Circular or non-serializable data]';
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Format a log entry with timestamp and level.
|
|
192
|
+
*/
|
|
193
|
+
function formatLogEntry(level: string, message: string, data?: unknown): string {
|
|
194
|
+
const timestamp = new Date().toISOString();
|
|
195
|
+
const dataStr = data !== undefined ? `\n${safeStringify(data)}` : '';
|
|
196
|
+
return `[${timestamp}] [${level}] ${message}${dataStr}\n`;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ============================================================================
|
|
200
|
+
// Core Logging Functions (async with fire-and-forget pattern)
|
|
201
|
+
// ============================================================================
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Write to a log file asynchronously (fire-and-forget).
|
|
205
|
+
* Never blocks the event loop.
|
|
206
|
+
*/
|
|
207
|
+
function writeLogAsync(logPath: string, entry: string): void {
|
|
208
|
+
if (!fileLoggingEnabled) return;
|
|
209
|
+
|
|
210
|
+
// Fire and forget - don't await
|
|
211
|
+
(async () => {
|
|
212
|
+
try {
|
|
213
|
+
await ensureLogsDirAsync();
|
|
214
|
+
await rotateIfNeededAsync(logPath);
|
|
215
|
+
await fsAsync.appendFile(logPath, entry, { encoding: 'utf-8' });
|
|
216
|
+
} catch (err) {
|
|
217
|
+
// Disable file logging on persistent failure
|
|
218
|
+
fileLoggingEnabled = false;
|
|
219
|
+
process.stderr.write(`[Logger] File write failed, disabling: ${err}\n`);
|
|
220
|
+
}
|
|
221
|
+
})();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ============================================================================
|
|
225
|
+
// Public API - Error Logger
|
|
226
|
+
// ============================================================================
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Log an error message (async, non-blocking).
|
|
230
|
+
*/
|
|
231
|
+
export function logError(message: string, error?: Error | unknown): void {
|
|
232
|
+
const errorData =
|
|
233
|
+
error instanceof Error
|
|
234
|
+
? { name: error.name, message: error.message, stack: error.stack }
|
|
235
|
+
: error;
|
|
236
|
+
|
|
237
|
+
const entry = formatLogEntry('ERROR', message, errorData);
|
|
238
|
+
writeLogAsync(ERROR_LOG, entry);
|
|
239
|
+
|
|
240
|
+
// Also write to console for visibility (redact stack in production)
|
|
241
|
+
const consoleError = process.env.NODE_ENV === 'development'
|
|
242
|
+
? error
|
|
243
|
+
: (error instanceof Error ? error.message : String(error || ''));
|
|
244
|
+
// Use %s format specifier to prevent format string injection from user-controlled message
|
|
245
|
+
console.error('%s %o', errorLog('[ERROR] ' + message), consoleError);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Log a warning message (async, non-blocking).
|
|
250
|
+
*/
|
|
251
|
+
export function logWarn(message: string, data?: unknown): void {
|
|
252
|
+
const entry = formatLogEntry('WARN', message, data);
|
|
253
|
+
writeLogAsync(ERROR_LOG, entry);
|
|
254
|
+
// Use %s format specifier to prevent format string injection from user-controlled message
|
|
255
|
+
console.warn('%s', warnLog('[WARN] ' + message));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ============================================================================
|
|
259
|
+
// Public API - Tools Logger
|
|
260
|
+
// ============================================================================
|
|
261
|
+
|
|
262
|
+
export interface ToolLogEntry {
|
|
263
|
+
tool: string;
|
|
264
|
+
route: string;
|
|
265
|
+
method: string;
|
|
266
|
+
params: Record<string, unknown>;
|
|
267
|
+
duration?: number;
|
|
268
|
+
success: boolean;
|
|
269
|
+
error?: string;
|
|
270
|
+
resultSize?: number;
|
|
271
|
+
requestId?: string;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Log a tool invocation (async, non-blocking).
|
|
276
|
+
*/
|
|
277
|
+
export function logToolCall(entry: ToolLogEntry): void {
|
|
278
|
+
const logEntry = formatLogEntry('TOOL', `${entry.method} ${entry.route}`, entry);
|
|
279
|
+
writeLogAsync(TOOLS_LOG, logEntry);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Log a successful tool result.
|
|
284
|
+
*/
|
|
285
|
+
export function logToolSuccess(
|
|
286
|
+
tool: string,
|
|
287
|
+
route: string,
|
|
288
|
+
method: string,
|
|
289
|
+
params: Record<string, unknown>,
|
|
290
|
+
duration: number,
|
|
291
|
+
resultSize: number
|
|
292
|
+
): void {
|
|
293
|
+
logToolCall({
|
|
294
|
+
tool,
|
|
295
|
+
route,
|
|
296
|
+
method,
|
|
297
|
+
params,
|
|
298
|
+
duration,
|
|
299
|
+
success: true,
|
|
300
|
+
resultSize,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Log a failed tool invocation.
|
|
306
|
+
*/
|
|
307
|
+
export function logToolError(
|
|
308
|
+
tool: string,
|
|
309
|
+
route: string,
|
|
310
|
+
method: string,
|
|
311
|
+
params: Record<string, unknown>,
|
|
312
|
+
duration: number,
|
|
313
|
+
error: string
|
|
314
|
+
): void {
|
|
315
|
+
logToolCall({
|
|
316
|
+
tool,
|
|
317
|
+
route,
|
|
318
|
+
method,
|
|
319
|
+
params,
|
|
320
|
+
duration,
|
|
321
|
+
success: false,
|
|
322
|
+
error,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ============================================================================
|
|
327
|
+
// Utility Functions
|
|
328
|
+
// ============================================================================
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Get the path to the logs directory.
|
|
332
|
+
*/
|
|
333
|
+
export function getLogsPath(): string {
|
|
334
|
+
return LOGS_DIR;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Get the path to the errors log file.
|
|
339
|
+
*/
|
|
340
|
+
export function getErrorLogPath(): string {
|
|
341
|
+
return ERROR_LOG;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Get the path to the tools log file.
|
|
346
|
+
*/
|
|
347
|
+
export function getToolsLogPath(): string {
|
|
348
|
+
return TOOLS_LOG;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Initialize logger synchronously (call at startup).
|
|
353
|
+
* After startup, all operations are async.
|
|
354
|
+
*/
|
|
355
|
+
export function initializeLogger(): void {
|
|
356
|
+
ensureLogsDirSync();
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// ============================================================================
|
|
360
|
+
// Express Middleware Integration
|
|
361
|
+
// ============================================================================
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Create a logging middleware that logs tool invocations.
|
|
365
|
+
* Use this to wrap route handlers for automatic logging.
|
|
366
|
+
*/
|
|
367
|
+
export function createToolLogger(toolName: string) {
|
|
368
|
+
return (
|
|
369
|
+
req: { method: string; path: string; query: unknown },
|
|
370
|
+
res: { statusCode: number; on: (event: string, cb: () => void) => void },
|
|
371
|
+
next: () => void
|
|
372
|
+
): void => {
|
|
373
|
+
const start = Date.now();
|
|
374
|
+
|
|
375
|
+
res.on('finish', () => {
|
|
376
|
+
const duration = Date.now() - start;
|
|
377
|
+
const success = res.statusCode < 400;
|
|
378
|
+
|
|
379
|
+
logToolCall({
|
|
380
|
+
tool: toolName,
|
|
381
|
+
route: req.path,
|
|
382
|
+
method: req.method,
|
|
383
|
+
params: req.query as Record<string, unknown>,
|
|
384
|
+
duration,
|
|
385
|
+
success,
|
|
386
|
+
error: success ? undefined : `HTTP ${res.statusCode}`,
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
next();
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// ============================================================================
|
|
395
|
+
// Security Utilities
|
|
396
|
+
// ============================================================================
|
|
397
|
+
|
|
398
|
+
const SENSITIVE_KEYS = ['token', 'key', 'secret', 'password', 'auth', 'credential', 'api_key', 'apikey'];
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Sanitize query parameters by redacting sensitive values.
|
|
402
|
+
* Prevents accidental exposure of secrets in logs.
|
|
403
|
+
*/
|
|
404
|
+
export function sanitizeQueryParams(query: Record<string, unknown>): Record<string, unknown> {
|
|
405
|
+
const sanitized: Record<string, unknown> = {};
|
|
406
|
+
|
|
407
|
+
for (const [key, value] of Object.entries(query)) {
|
|
408
|
+
const isSensitive = SENSITIVE_KEYS.some((s) => key.toLowerCase().includes(s));
|
|
409
|
+
sanitized[key] = isSensitive ? '[REDACTED]' : value;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return sanitized;
|
|
413
|
+
}
|