Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
day: 'friday'
time: '16:00'
timezone: 'Etc/UTC'
assignees:
- 'vreshch'
open-pull-requests-limit: 10
groups:
all-npm:
patterns:
- '*'

- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
day: 'friday'
time: '16:00'
timezone: 'Etc/UTC'
assignees:
- 'vreshch'
open-pull-requests-limit: 5
groups:
all-actions:
patterns:
- '*'
47 changes: 47 additions & 0 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: PR Validation

on:
pull_request:
branches: [master]
types: [opened, synchronize, reopened]

concurrency:
group: pr-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read

jobs:
validate:
name: Validate
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Type check
run: npm run type-check

- name: Lint
run: npm run lint

- name: Format check
run: npm run format:check

- name: Test with coverage
run: npm run test:coverage

- name: Build
run: npm run build
79 changes: 79 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Publish Package

# Publishes @agentage/observability to npm. Manual (workflow_dispatch) or on a release
# commit to master; never on an ordinary push. Requires an NPM_TOKEN repo secret.

on:
push:
branches: [master]
paths:
- 'package.json'
workflow_dispatch:

permissions:
contents: write
id-token: write

env:
NODE_VERSION: '22'

jobs:
release-gate:
name: Release gate
runs-on: ubuntu-latest
outputs:
is-release: ${{ steps.check.outputs.is-release }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 5
- id: check
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "is-release=true" >> "$GITHUB_OUTPUT"; exit 0
fi
MSG=$(git log -1 --pretty=%s)
if echo "$MSG" | grep -qE "(^Release v|^chore: prepare release|^chore\(release\))"; then
echo "is-release=true" >> "$GITHUB_OUTPUT"
else
echo "is-release=false" >> "$GITHUB_OUTPUT"
echo "Not a release commit - skipping publish."
fi

publish:
name: Publish to npm
needs: [release-gate]
if: needs.release-gate.outputs.is-release == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- name: Skip if version already on npm
id: ver
run: |
name=$(node -p "require('./package.json').name")
version=$(node -p "require('./package.json').version")
if npm view "${name}@${version}" version >/dev/null 2>&1; then
echo "publish=false" >> "$GITHUB_OUTPUT"
echo "${name}@${version} already published."
else
echo "publish=true" >> "$GITHUB_OUTPUT"
fi
echo "tag=v${version}" >> "$GITHUB_OUTPUT"
- if: steps.ver.outputs.publish == 'true'
run: npm run verify
- if: steps.ver.outputs.publish == 'true'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public --provenance
- if: steps.ver.outputs.publish == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "${{ steps.ver.outputs.tag }}" -m "Release ${{ steps.ver.outputs.tag }}"
git push origin "${{ steps.ver.outputs.tag }}"
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
coverage/
*.tsbuildinfo
.DS_Store
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
dist
coverage
package-lock.json
*.snap
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 100,
"tabWidth": 2
}
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ The shared observability kit for agentage services. One package, three things:
HTTP/Express/fetch for pure-ESM services and Next.js standalone servers.
- **Logs** - a pino preset: JSON to stdout with a standard shape (`service`,
`level`, `msg`, `err`), plus `trace_id`/`span_id` injected from the active
span so every log line links to its trace in SigNoz.
span so every log line links to its trace in SigNoz. `stream: 'stderr'` for
stdio MCP servers (stdout there is the JSON-RPC channel).
- **Errors** - `captureError(log, err, ctx)`: one call writes the structured
error log AND flags the active span (recordException + ERROR status).

Expand Down
54 changes: 54 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import prettierPlugin from 'eslint-plugin-prettier';
import prettierConfig from 'eslint-config-prettier';

export default [
{
ignores: ['dist/**', 'coverage/**', 'node_modules/**'],
},
{
files: ['src/**/*.ts', 'test/**/*.ts'],
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 2024,
sourceType: 'module',
project: './tsconfig.json',
},
},
plugins: {
'@typescript-eslint': typescriptEslint,
prettier: prettierPlugin,
},
rules: {
...prettierConfig.rules,
'prettier/prettier': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/consistent-type-imports': [
'error',
{ prefer: 'type-imports', fixStyle: 'inline-type-imports' },
],
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
],
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'interface',
format: ['PascalCase'],
custom: { regex: '^[A-Z]', match: true },
},
{
selector: 'typeAlias',
format: ['PascalCase'],
},
],
'prefer-const': 'error',
'prefer-arrow-callback': 'error',
'arrow-body-style': ['error', 'as-needed'],
'no-var': 'error',
},
},
];
Loading