@senad-d/observme 0.1.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 (111) hide show
  1. package/.env.example +57 -0
  2. package/CHANGELOG.md +52 -0
  3. package/LICENSE +21 -0
  4. package/ObservMe-Production-Docs/00-README.md +79 -0
  5. package/ObservMe-Production-Docs/01-requirements-and-scope.md +207 -0
  6. package/ObservMe-Production-Docs/02-reference-architecture.md +306 -0
  7. package/ObservMe-Production-Docs/03-pi-event-and-session-model.md +266 -0
  8. package/ObservMe-Production-Docs/04-telemetry-semantic-conventions.md +722 -0
  9. package/ObservMe-Production-Docs/05-otel-pipeline-and-collector.md +355 -0
  10. package/ObservMe-Production-Docs/06-security-privacy-redaction.md +294 -0
  11. package/ObservMe-Production-Docs/07-extension-implementation-blueprint.md +447 -0
  12. package/ObservMe-Production-Docs/08-query-grafana-integration.md +276 -0
  13. package/ObservMe-Production-Docs/09-dashboards-alerts-slos.md +640 -0
  14. package/ObservMe-Production-Docs/10-testing-release-operations.md +319 -0
  15. package/ObservMe-Production-Docs/11-deployment-runbooks.md +203 -0
  16. package/ObservMe-Production-Docs/12-configuration-reference.md +337 -0
  17. package/ObservMe-Production-Docs/13-source-notes.md +33 -0
  18. package/ObservMe-Production-Docs/pi-session-format.md +427 -0
  19. package/README.md +356 -0
  20. package/SECURITY.md +45 -0
  21. package/dashboards/observme-agent-node-graphs.json +250 -0
  22. package/dashboards/observme-agents.json +1880 -0
  23. package/dashboards/observme-alerts.yaml +113 -0
  24. package/dashboards/observme-branches-compactions.json +1042 -0
  25. package/dashboards/observme-cost.json +1254 -0
  26. package/dashboards/observme-errors.json +1659 -0
  27. package/dashboards/observme-export-health.json +1802 -0
  28. package/dashboards/observme-latency.json +1494 -0
  29. package/dashboards/observme-llm-conversations.json +730 -0
  30. package/dashboards/observme-logs-llm.json +644 -0
  31. package/dashboards/observme-models.json +933 -0
  32. package/dashboards/observme-overview.json +2129 -0
  33. package/dashboards/observme-slo-health.json +737 -0
  34. package/dashboards/observme-slos.yaml +56 -0
  35. package/dashboards/observme-tools.json +902 -0
  36. package/dashboards/observme-trace-journey.json +1793 -0
  37. package/docs/STRUCTURE.md +49 -0
  38. package/docs/agent-subagent-observability-requirements.md +997 -0
  39. package/docs/compatibility-matrix.md +39 -0
  40. package/docs/configuration-tui-design-standard.md +767 -0
  41. package/docs/configuration.md +38 -0
  42. package/docs/review-validation.md +115 -0
  43. package/docs/validation-flow.md +117 -0
  44. package/examples/collector.yaml +123 -0
  45. package/examples/observme.yaml +131 -0
  46. package/img/demo.gif +0 -0
  47. package/img/icon.svg +47 -0
  48. package/package.json +103 -0
  49. package/src/commands/obs-agents-runtime.ts +150 -0
  50. package/src/commands/obs-agents.ts +491 -0
  51. package/src/commands/obs-args.ts +63 -0
  52. package/src/commands/obs-backfill.ts +1334 -0
  53. package/src/commands/obs-command-support.ts +43 -0
  54. package/src/commands/obs-cost.ts +228 -0
  55. package/src/commands/obs-diagnostics.ts +22 -0
  56. package/src/commands/obs-errors.ts +156 -0
  57. package/src/commands/obs-health.ts +301 -0
  58. package/src/commands/obs-link.ts +90 -0
  59. package/src/commands/obs-logs.ts +194 -0
  60. package/src/commands/obs-loki-summary.ts +184 -0
  61. package/src/commands/obs-session.ts +259 -0
  62. package/src/commands/obs-status.ts +359 -0
  63. package/src/commands/obs-tools.ts +274 -0
  64. package/src/commands/obs-trace.ts +411 -0
  65. package/src/commands/obs.ts +211 -0
  66. package/src/config/bootstrap-project-config.ts +300 -0
  67. package/src/config/defaults.ts +143 -0
  68. package/src/config/load-config.ts +631 -0
  69. package/src/config/project-paths.ts +61 -0
  70. package/src/config/schema.ts +405 -0
  71. package/src/config/validate.ts +456 -0
  72. package/src/constants.ts +4 -0
  73. package/src/diagnostics/sanitize.ts +6 -0
  74. package/src/extension.ts +38 -0
  75. package/src/otel/logs.ts +160 -0
  76. package/src/otel/metrics.ts +165 -0
  77. package/src/otel/otlp-endpoint.ts +10 -0
  78. package/src/otel/sdk.ts +114 -0
  79. package/src/otel/shutdown.ts +102 -0
  80. package/src/otel/traces.ts +166 -0
  81. package/src/pi/agent-lineage.ts +378 -0
  82. package/src/pi/agent-tree-tracker.ts +258 -0
  83. package/src/pi/event-handlers/agent-turn.ts +155 -0
  84. package/src/pi/event-handlers/lifecycle.ts +642 -0
  85. package/src/pi/event-handlers/llm.ts +115 -0
  86. package/src/pi/event-handlers/session-events.ts +159 -0
  87. package/src/pi/event-handlers/tool-bash.ts +275 -0
  88. package/src/pi/handler-internals.ts +2154 -0
  89. package/src/pi/handler-runtime.ts +633 -0
  90. package/src/pi/handler-types.ts +261 -0
  91. package/src/pi/handlers.ts +75 -0
  92. package/src/pi/subagent-spawn.ts +975 -0
  93. package/src/pi/subagent-types.ts +29 -0
  94. package/src/privacy/content-capture.ts +104 -0
  95. package/src/privacy/hash.ts +93 -0
  96. package/src/privacy/redact.ts +619 -0
  97. package/src/privacy/secret-patterns.ts +185 -0
  98. package/src/privacy/truncate.ts +69 -0
  99. package/src/query/grafana-readiness.ts +164 -0
  100. package/src/query/grafana-transport.ts +481 -0
  101. package/src/query/grafana.ts +371 -0
  102. package/src/query/loki.ts +332 -0
  103. package/src/query/prometheus.ts +388 -0
  104. package/src/query/tempo.ts +332 -0
  105. package/src/safety/sensitive-input.ts +208 -0
  106. package/src/semconv/attributes.ts +279 -0
  107. package/src/semconv/metrics.ts +146 -0
  108. package/src/semconv/spans.ts +19 -0
  109. package/src/semconv/values.ts +13 -0
  110. package/src/util/bounded-map.ts +97 -0
  111. package/tsconfig.json +15 -0
package/package.json ADDED
@@ -0,0 +1,103 @@
1
+ {
2
+ "name": "@senad-d/observme",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "ObservMe: a Pi extension that instruments Pi agent sessions and exports OpenTelemetry traces, metrics, and logs to an external observability stack (OTel Collector, Grafana Tempo/Loki/Prometheus).",
6
+ "license": "MIT",
7
+ "author": "Senad Dizdarević <112484166+senad-d@users.noreply.github.com>",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/senad-d/ObservMe.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/senad-d/ObservMe/issues"
14
+ },
15
+ "homepage": "https://github.com/senad-d/ObservMe#readme",
16
+ "keywords": [
17
+ "pi-package",
18
+ "pi-extension",
19
+ "pi-coding-agent",
20
+ "cli",
21
+ "terminal",
22
+ "typescript",
23
+ "coding-agent",
24
+ "observability",
25
+ "opentelemetry"
26
+ ],
27
+ "engines": {
28
+ "node": ">=22.19.0"
29
+ },
30
+ "files": [
31
+ ".env.example",
32
+ "README.md",
33
+ "LICENSE",
34
+ "SECURITY.md",
35
+ "CHANGELOG.md",
36
+ "docs/**/*.md",
37
+ "ObservMe-Production-Docs/**/*.md",
38
+ "dashboards/**/*.json",
39
+ "dashboards/**/*.yaml",
40
+ "examples/**/*.yaml",
41
+ "img/*",
42
+ "src/**/*.ts",
43
+ "tsconfig.json"
44
+ ],
45
+ "scripts": {
46
+ "dev": "pi --no-extensions -e .",
47
+ "typecheck": "tsc --noEmit",
48
+ "typecheck:test": "tsc --project tsconfig.test.json --noEmit",
49
+ "lint": "npm run typecheck && npm run typecheck:test && npm run lint:eslint && npm run format:check && npm run check",
50
+ "lint:eslint": "eslint . --max-warnings=0",
51
+ "lint:fix": "eslint . --fix",
52
+ "format:check": "node scripts/check-format.mjs",
53
+ "test": "node --test test/*.test.mjs test/*.test.ts",
54
+ "test:integration:collector": "node --test test/integration/collector-debug.test.mjs",
55
+ "test:integration:grafana-stack": "node --test test/integration/grafana-stack.test.mjs",
56
+ "test:coverage": "node scripts/test-coverage.mjs",
57
+ "smoke:discover": "node scripts/smoke-observability.mjs",
58
+ "smoke:packaged": "node scripts/smoke-packaged-install.mjs",
59
+ "smoke:handlers": "node scripts/smoke-handler-execution.mjs",
60
+ "smoke:pi-lifecycle": "node scripts/smoke-pi-lifecycle.mjs",
61
+ "smoke:pi-runtime": "node scripts/smoke-pi-runtime.mjs",
62
+ "validate:grafana-obs": "node scripts/validate-grafana-obs-flow.mjs",
63
+ "check": "node --check scripts/check-package-contents.mjs && node --check scripts/test-coverage.mjs && node --check scripts/smoke-observability.mjs && node --check scripts/smoke-packaged-install.mjs && node --check scripts/smoke-handler-execution.mjs && node --check scripts/smoke-pi-lifecycle.mjs && node --check scripts/smoke-pi-runtime.mjs && node --check scripts/validate-grafana-obs-flow.mjs",
64
+ "pack:dry-run": "npm pack --dry-run --json",
65
+ "check:pack": "node scripts/check-package-contents.mjs",
66
+ "validate": "npm run lint && npm run test && npm run check:pack && npm run smoke:packaged && npm run smoke:handlers && npm run smoke:pi-lifecycle && npm run smoke:pi-runtime"
67
+ },
68
+ "pi": {
69
+ "extensions": [
70
+ "./src/extension.ts"
71
+ ],
72
+ "image": "https://raw.githubusercontent.com/senad-d/ObservMe/main/img/demo.gif"
73
+ },
74
+ "peerDependencies": {
75
+ "@earendil-works/pi-ai": "*",
76
+ "@earendil-works/pi-coding-agent": "*",
77
+ "typebox": "*"
78
+ },
79
+ "devDependencies": {
80
+ "@earendil-works/pi-ai": "^0.80.2",
81
+ "@earendil-works/pi-coding-agent": "^0.80.2",
82
+ "@eslint/js": "^10.0.1",
83
+ "@types/node": "^26.1.1",
84
+ "c8": "^11.0.0",
85
+ "eslint": "^10.6.0",
86
+ "globals": "^17.7.0",
87
+ "typebox": "^1.3.6",
88
+ "typescript": "6.0.3",
89
+ "typescript-eslint": "^8.63.0"
90
+ },
91
+ "dependencies": {
92
+ "@opentelemetry/api": "1.9.1",
93
+ "@opentelemetry/api-logs": "0.220.0",
94
+ "@opentelemetry/exporter-logs-otlp-proto": "0.220.0",
95
+ "@opentelemetry/exporter-metrics-otlp-proto": "0.220.0",
96
+ "@opentelemetry/exporter-trace-otlp-proto": "0.220.0",
97
+ "@opentelemetry/resources": "2.9.0",
98
+ "@opentelemetry/sdk-logs": "0.220.0",
99
+ "@opentelemetry/sdk-metrics": "2.9.0",
100
+ "@opentelemetry/sdk-trace-base": "2.9.0",
101
+ "@opentelemetry/sdk-trace-node": "2.9.0"
102
+ }
103
+ }
@@ -0,0 +1,150 @@
1
+ import type { AgentLineageContext } from "../pi/agent-lineage.ts";
2
+ import type { AgentChildStatus, AgentTreeNode, AgentTreeSummary, AgentTreeTracker } from "../pi/agent-tree-tracker.ts";
3
+
4
+ export type ObsAgentWaitJoinKind = "wait" | "join";
5
+
6
+ export interface ObsAgentWaitJoinHint {
7
+ readonly kind: ObsAgentWaitJoinKind;
8
+ readonly id: string;
9
+ readonly active: boolean;
10
+ readonly spawnId?: string;
11
+ readonly childAgentId?: string;
12
+ readonly childStatus?: AgentChildStatus;
13
+ readonly joinStatus?: string;
14
+ readonly reason?: string;
15
+ readonly durationMs?: number;
16
+ }
17
+
18
+ export interface StartObsAgentsRuntimeStateOptions {
19
+ readonly lineage: AgentLineageContext;
20
+ readonly agentTree?: AgentTreeTracker;
21
+ readonly sessionId?: string;
22
+ readonly traceId?: string;
23
+ }
24
+
25
+ export interface UpdateObsAgentsRuntimeTreeOptions {
26
+ readonly sessionId?: string;
27
+ readonly traceId?: string;
28
+ }
29
+
30
+ export interface ObsAgentsRuntimeSnapshot {
31
+ readonly lineage?: AgentLineageContext;
32
+ readonly currentAgent?: AgentTreeNode;
33
+ readonly summary?: AgentTreeSummary;
34
+ readonly children: readonly AgentTreeNode[];
35
+ readonly waitJoinHints: readonly ObsAgentWaitJoinHint[];
36
+ readonly sessionId?: string;
37
+ readonly traceId?: string;
38
+ }
39
+
40
+ interface MutableObsAgentsRuntimeState {
41
+ lineage?: AgentLineageContext;
42
+ currentAgent?: AgentTreeNode;
43
+ summary?: AgentTreeSummary;
44
+ children: AgentTreeNode[];
45
+ waitJoinHints: ObsAgentWaitJoinHint[];
46
+ sessionId?: string;
47
+ traceId?: string;
48
+ }
49
+
50
+ const maxWaitJoinHints = 10;
51
+ const runtimeAgentsState: MutableObsAgentsRuntimeState = createEmptyObsAgentsRuntimeState();
52
+
53
+ export function startObsAgentsRuntimeState(options: StartObsAgentsRuntimeStateOptions): void {
54
+ replaceObsAgentsRuntimeState(createEmptyObsAgentsRuntimeState());
55
+ runtimeAgentsState.lineage = options.lineage;
56
+ runtimeAgentsState.sessionId = normalizeString(options.sessionId);
57
+ runtimeAgentsState.traceId = normalizeString(options.traceId);
58
+ if (options.agentTree) updateObsAgentsRuntimeStateFromTree(options.lineage, options.agentTree, options);
59
+ }
60
+
61
+ export function updateObsAgentsRuntimeStateFromTree(
62
+ lineage: AgentLineageContext,
63
+ agentTree: AgentTreeTracker,
64
+ options: UpdateObsAgentsRuntimeTreeOptions = {},
65
+ ): void {
66
+ runtimeAgentsState.lineage = lineage;
67
+ runtimeAgentsState.currentAgent = agentTree.getAgent(lineage.agentId);
68
+ runtimeAgentsState.summary = agentTree.summarize(lineage.rootAgentId);
69
+ runtimeAgentsState.children = agentTree.getChildren(lineage.agentId);
70
+ updateOptionalRuntimeString("sessionId", options.sessionId);
71
+ updateOptionalRuntimeString("traceId", options.traceId);
72
+ }
73
+
74
+ export function recordObsAgentWaitJoinHint(hint: ObsAgentWaitJoinHint): void {
75
+ const normalized = normalizeObsAgentWaitJoinHint(hint);
76
+ if (!normalized) return;
77
+
78
+ const existingIndex = runtimeAgentsState.waitJoinHints.findIndex(item => item.kind === normalized.kind && item.id === normalized.id);
79
+ if (existingIndex >= 0) {
80
+ runtimeAgentsState.waitJoinHints.splice(existingIndex, 1, normalized);
81
+ } else {
82
+ runtimeAgentsState.waitJoinHints.push(normalized);
83
+ }
84
+
85
+ runtimeAgentsState.waitJoinHints = runtimeAgentsState.waitJoinHints.slice(-maxWaitJoinHints);
86
+ }
87
+
88
+ export function getLocalObsAgentsRuntimeSnapshot(): ObsAgentsRuntimeSnapshot {
89
+ return {
90
+ lineage: runtimeAgentsState.lineage,
91
+ currentAgent: runtimeAgentsState.currentAgent,
92
+ summary: runtimeAgentsState.summary,
93
+ children: [...runtimeAgentsState.children],
94
+ waitJoinHints: [...runtimeAgentsState.waitJoinHints],
95
+ sessionId: runtimeAgentsState.sessionId,
96
+ traceId: runtimeAgentsState.traceId,
97
+ };
98
+ }
99
+
100
+ export function clearObsAgentsRuntimeState(): void {
101
+ replaceObsAgentsRuntimeState(createEmptyObsAgentsRuntimeState());
102
+ }
103
+
104
+ function normalizeObsAgentWaitJoinHint(hint: ObsAgentWaitJoinHint): ObsAgentWaitJoinHint | undefined {
105
+ const id = normalizeString(hint.id);
106
+ if (!id) return undefined;
107
+
108
+ return {
109
+ kind: hint.kind,
110
+ id,
111
+ active: hint.active,
112
+ spawnId: normalizeString(hint.spawnId),
113
+ childAgentId: normalizeString(hint.childAgentId),
114
+ childStatus: hint.childStatus,
115
+ joinStatus: normalizeString(hint.joinStatus),
116
+ reason: normalizeString(hint.reason),
117
+ durationMs: normalizeDurationMs(hint.durationMs),
118
+ };
119
+ }
120
+
121
+ function normalizeDurationMs(value: number | undefined): number | undefined {
122
+ if (value === undefined || !Number.isFinite(value) || value < 0) return undefined;
123
+ return Math.trunc(value);
124
+ }
125
+
126
+ function updateOptionalRuntimeString(key: "sessionId" | "traceId", value: string | undefined): void {
127
+ if (value !== undefined) runtimeAgentsState[key] = normalizeString(value);
128
+ }
129
+
130
+ function replaceObsAgentsRuntimeState(state: MutableObsAgentsRuntimeState): void {
131
+ runtimeAgentsState.lineage = state.lineage;
132
+ runtimeAgentsState.currentAgent = state.currentAgent;
133
+ runtimeAgentsState.summary = state.summary;
134
+ runtimeAgentsState.children = state.children;
135
+ runtimeAgentsState.waitJoinHints = state.waitJoinHints;
136
+ runtimeAgentsState.sessionId = state.sessionId;
137
+ runtimeAgentsState.traceId = state.traceId;
138
+ }
139
+
140
+ function createEmptyObsAgentsRuntimeState(): MutableObsAgentsRuntimeState {
141
+ return {
142
+ children: [],
143
+ waitJoinHints: [],
144
+ };
145
+ }
146
+
147
+ function normalizeString(value: string | undefined): string | undefined {
148
+ const trimmed = value?.trim();
149
+ return trimmed || undefined;
150
+ }