next-observer 0.0.0-stage → 0.1.1

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 (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -2
  3. package/dist/agents/cards.d.ts +14 -0
  4. package/dist/agents/cards.js +85 -0
  5. package/dist/agents/cards.js.map +1 -0
  6. package/dist/agents/chat.d.ts +21 -0
  7. package/dist/agents/chat.js +83 -0
  8. package/dist/agents/chat.js.map +1 -0
  9. package/dist/agents/index.d.ts +6 -0
  10. package/dist/agents/index.js +8 -0
  11. package/dist/agents/index.js.map +1 -0
  12. package/dist/agents/investigator.d.ts +50 -0
  13. package/dist/agents/investigator.js +123 -0
  14. package/dist/agents/investigator.js.map +1 -0
  15. package/dist/agents/mock-llm.d.ts +7 -0
  16. package/dist/agents/mock-llm.js +46 -0
  17. package/dist/agents/mock-llm.js.map +1 -0
  18. package/dist/agents/model.d.ts +5 -0
  19. package/dist/agents/model.js +20 -0
  20. package/dist/agents/model.js.map +1 -0
  21. package/dist/agents/specialists.d.ts +20 -0
  22. package/dist/agents/specialists.js +74 -0
  23. package/dist/agents/specialists.js.map +1 -0
  24. package/dist/bin.d.ts +2 -0
  25. package/dist/bin.js +20 -0
  26. package/dist/bin.js.map +1 -0
  27. package/dist/cli.d.ts +29 -0
  28. package/dist/cli.js +231 -0
  29. package/dist/cli.js.map +1 -0
  30. package/dist/collector/chat.d.ts +93 -0
  31. package/dist/collector/chat.js +2 -0
  32. package/dist/collector/chat.js.map +1 -0
  33. package/dist/collector/decode.d.ts +52 -0
  34. package/dist/collector/decode.js +59 -0
  35. package/dist/collector/decode.js.map +1 -0
  36. package/dist/collector/framework.d.ts +7 -0
  37. package/dist/collector/framework.js +9 -0
  38. package/dist/collector/framework.js.map +1 -0
  39. package/dist/collector/index.d.ts +6 -0
  40. package/dist/collector/index.js +5 -0
  41. package/dist/collector/index.js.map +1 -0
  42. package/dist/collector/memory-storage.d.ts +21 -0
  43. package/dist/collector/memory-storage.js +185 -0
  44. package/dist/collector/memory-storage.js.map +1 -0
  45. package/dist/collector/server.d.ts +31 -0
  46. package/dist/collector/server.js +267 -0
  47. package/dist/collector/server.js.map +1 -0
  48. package/dist/collector/static.d.ts +3 -0
  49. package/dist/collector/static.js +43 -0
  50. package/dist/collector/static.js.map +1 -0
  51. package/dist/collector/types.d.ts +116 -0
  52. package/dist/collector/types.js +2 -0
  53. package/dist/collector/types.js.map +1 -0
  54. package/dist/debug/demo.d.ts +4 -0
  55. package/dist/debug/demo.js +90 -0
  56. package/dist/debug/demo.js.map +1 -0
  57. package/dist/debug/detector.d.ts +61 -0
  58. package/dist/debug/detector.js +116 -0
  59. package/dist/debug/detector.js.map +1 -0
  60. package/dist/debug/index.d.ts +3 -0
  61. package/dist/debug/index.js +5 -0
  62. package/dist/debug/index.js.map +1 -0
  63. package/dist/debug/queries.d.ts +207 -0
  64. package/dist/debug/queries.js +242 -0
  65. package/dist/debug/queries.js.map +1 -0
  66. package/dist/ui/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  67. package/dist/ui/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  68. package/dist/ui/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  69. package/dist/ui/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  70. package/dist/ui/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  71. package/dist/ui/assets/index-Y3VIawX_.css +2 -0
  72. package/dist/ui/assets/index-vwPciq9g.js +11 -0
  73. package/dist/ui/index.html +13 -0
  74. package/package.json +72 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/agents/model.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAKvC,MAAM,UAAU,aAAa,CAAC,GAAQ;IACpC,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,IAAI,MAAM,CAAA;IACrC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,IAAI,GAAG,CAAC,CAAA;IAC7G,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAG,GAAQ,OAAO,CAAC,GAAG;IACnD,IAAI,aAAa,CAAC,GAAG,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,OAAO,EAAE,CAAA;IACvD,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,kFAAkF,CAAC,CAAA;QAC1H,OAAO,GAAG,CAAC,YAAY,CAAA,CAAC,8DAA8D;IACxF,CAAC;IACD,uFAAuF;IACvF,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAA;IACrD,OAAO,IAAI,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,oBAAoB,IAAI,MAAM,EAAE,CAAC,CAAA;AACrE,CAAC"}
@@ -0,0 +1,20 @@
1
+ export declare const TOOL_NAMES: readonly ['get_services', 'get_operation_stats', 'compare_versions', 'get_errors', 'search_traces', 'get_trace'];
2
+ export type ToolName = (typeof TOOL_NAMES)[number];
3
+ export interface SpecialistSpec {
4
+ /** snake_case, becomes the tool name the orchestrator calls. */
5
+ name: string;
6
+ /** What this specialist is for — the orchestrator picks specialists by it. */
7
+ description: string;
8
+ /** How the specialist works. Facts-only, own-tools-only and English rules are appended automatically. */
9
+ instruction: string;
10
+ tools: ToolName[];
11
+ }
12
+ /** Validates a specialist; use it in observe.agents.ts for type checking and early, readable errors. */
13
+ export declare function defineSpecialist(spec: SpecialistSpec): SpecialistSpec;
14
+ export declare const BUILT_IN_SPECIALISTS: SpecialistSpec[];
15
+ /** Project specialists replace built-ins with the same name and are appended otherwise. */
16
+ export declare function mergeSpecialists(builtIn: SpecialistSpec[], project: SpecialistSpec[]): SpecialistSpec[];
17
+ export declare const FACTS_ONLY = "Use only facts returned by your tools; if a tool returned nothing relevant, say so \u2014 never guess causes.\nQuote exact numbers, operation names, versions and error messages. Answer in English.";
18
+ export declare const OWN_TOOLS_ONLY = "You can only use the tools listed for you \u2014 never call other agents or tools that are not listed.\nIf you need data your tools cannot give, say what is missing in your answer.";
19
+ export declare function specialistInstruction(spec: SpecialistSpec): string;
20
+ export declare function orchestratorInstruction(specialists: SpecialistSpec[]): string;
@@ -0,0 +1,74 @@
1
+ // Specialists as data: name, description, instruction and which telemetry tools they may use. The built-in three are
2
+ // defaults; a project can replace one (same name) or add its own in observe.agents.ts — the workshop's "write your agent".
3
+ export const TOOL_NAMES = ['get_services', 'get_operation_stats', 'compare_versions', 'get_errors', 'search_traces', 'get_trace'];
4
+ const NAME = /^[a-z][a-z0-9_]{1,40}$/;
5
+ /** Validates a specialist; use it in observe.agents.ts for type checking and early, readable errors. */
6
+ export function defineSpecialist(spec) {
7
+ const where = typeof spec?.name === 'string' ? `specialist "${spec.name}"` : 'specialist';
8
+ if (typeof spec !== 'object' || spec === null)
9
+ throw new Error('a specialist must be an object');
10
+ if (typeof spec.name !== 'string' || !NAME.test(spec.name))
11
+ throw new Error(`${where}: name must be snake_case (a-z, 0-9, _), 2–41 characters`);
12
+ if (spec.name === 'orchestrator')
13
+ throw new Error(`${where}: "orchestrator" is reserved`);
14
+ for (const field of ['description', 'instruction']) {
15
+ if (typeof spec[field] !== 'string' || !spec[field].trim())
16
+ throw new Error(`${where}: ${field} must be a non-empty string`);
17
+ }
18
+ if (!Array.isArray(spec.tools) || spec.tools.length === 0)
19
+ throw new Error(`${where}: tools must list at least one of ${TOOL_NAMES.join(', ')}`);
20
+ const unknown = spec.tools.filter((t) => !TOOL_NAMES.includes(t));
21
+ if (unknown.length)
22
+ throw new Error(`${where}: unknown tools ${unknown.join(', ')} — available: ${TOOL_NAMES.join(', ')}`);
23
+ return { name: spec.name, description: spec.description.trim(), instruction: spec.instruction.trim(), tools: [...new Set(spec.tools)] };
24
+ }
25
+ export const BUILT_IN_SPECIALISTS = [
26
+ {
27
+ name: 'latency_agent',
28
+ description: 'Latency specialist: slow operations, p50/p95/p99, regressions between deployed versions, N+1 patterns.',
29
+ instruction: `You are a latency specialist. Find what is slow and why.
30
+ Check compare_versions for regressions between deployments. For a slow trace, use search_traces then get_trace: high selfMs points at the code file; "repeated" means N+1.
31
+ When asked where time is spent, always open at least one trace with get_trace — aggregates don't show structure.
32
+ Distinguish external dependencies from internal code. Max 3 sentences.`,
33
+ tools: ['get_operation_stats', 'compare_versions', 'search_traces', 'get_trace'],
34
+ },
35
+ {
36
+ name: 'error_agent',
37
+ description: 'Error specialist: failing operations, error rates, exact exception messages, source vs downstream victims.',
38
+ instruction: `You are an error specialist. Report the failing operation, its error rate and the exact exception message.
39
+ Use get_trace on an example trace to separate the source span from its downstream victims and to find the code file. Max 3 sentences.`,
40
+ tools: ['get_errors', 'search_traces', 'get_trace'],
41
+ },
42
+ {
43
+ name: 'traffic_agent',
44
+ description: 'Traffic specialist: which services report data, versions deployed, silent services (no traffic).',
45
+ instruction: `You are a traffic specialist. A service that stopped sending spans is more critical than errors — flag it immediately.
46
+ Report which versions are deployed and whether traffic looks normal. Max 2 sentences.`,
47
+ tools: ['get_services', 'get_operation_stats'],
48
+ },
49
+ ];
50
+ /** Project specialists replace built-ins with the same name and are appended otherwise. */
51
+ export function mergeSpecialists(builtIn, project) {
52
+ const byName = new Map(builtIn.map((s) => [s.name, s]));
53
+ for (const spec of project)
54
+ byName.set(spec.name, spec);
55
+ return [...byName.values()];
56
+ }
57
+ export const FACTS_ONLY = `Use only facts returned by your tools; if a tool returned nothing relevant, say so — never guess causes.
58
+ Quote exact numbers, operation names, versions and error messages. Answer in English.`;
59
+ // Specialists run behind AgentTool with their own tools only; calling another agent from inside one cannot work.
60
+ export const OWN_TOOLS_ONLY = `You can only use the tools listed for you — never call other agents or tools that are not listed.
61
+ If you need data your tools cannot give, say what is missing in your answer.`;
62
+ export function specialistInstruction(spec) {
63
+ return `${spec.instruction}\n${FACTS_ONLY}\n${OWN_TOOLS_ONLY}`;
64
+ }
65
+ export function orchestratorInstruction(specialists) {
66
+ const list = specialists.map((s) => `- ${s.name}: ${s.description}`).join('\n');
67
+ return `You coordinate an investigation of a Next.js app using these specialist agents:
68
+ ${list}
69
+ Pick the specialists whose descriptions fit the question: failures first to the error specialist, slowness to the latency specialist,
70
+ "nothing happens" to the traffic specialist. A broad or unclear question → call all of them. Then write one report for an
71
+ on-call engineer at 3am: priority no-traffic > errors > latency, max 5 sentences, diagnosis only, never suggest automated fixes.
72
+ Treat separate findings as separate problems unless a tool result shows they are connected. ${FACTS_ONLY}`;
73
+ }
74
+ //# sourceMappingURL=specialists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specialists.js","sourceRoot":"","sources":["../../src/agents/specialists.ts"],"names":[],"mappings":"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"}
package/dist/bin.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/bin.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'node:child_process';
3
+ import { run } from './cli.js';
4
+ let stopping = false;
5
+ const shutdownSignal = new Promise((resolve) => {
6
+ for (const signal of ['SIGINT', 'SIGTERM']) {
7
+ process.on(signal, () => {
8
+ // Second Ctrl+C = don't wait for a graceful shutdown.
9
+ if (stopping)
10
+ process.exit(130);
11
+ stopping = true;
12
+ resolve(signal);
13
+ });
14
+ }
15
+ });
16
+ run(process.argv.slice(2), { env: process.env, cwd: process.cwd(), log: (line) => console.log(line), spawn, shutdownSignal }).then((code) => process.exit(code), (error) => {
17
+ console.error(error);
18
+ process.exit(1);
19
+ });
20
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAE9B,IAAI,QAAQ,GAAG,KAAK,CAAA;AACpB,MAAM,cAAc,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;IACrD,KAAK,MAAM,MAAM,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;QACpD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACtB,sDAAsD;YACtD,IAAI,QAAQ;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC/B,QAAQ,GAAG,IAAI,CAAA;YACf,OAAO,CAAC,MAAM,CAAC,CAAA;QACjB,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC,IAAI,CAChI,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAC5B,CAAC,KAAc,EAAE,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CACF,CAAA"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ import type { ChildProcess, SpawnOptions } from 'node:child_process';
2
+ type AgentsModule = typeof import('./agents/index.js');
3
+ export declare const HELP = "Usage:\n next-observer dev [--root <dir>] [--port <n>] [-- <next dev args>]\n Start the collector and `next dev` for the app in <dir> (default: current directory).\n Example: next-observer dev --root apps/web -- -p 3100\n\n next-observer collector [--host <host>] [--port <n>] [--api-key <key>] [--demo]\n Start only the collector (e.g. on a server). Reads OBSERVE_HOST, OBSERVE_PORT, OBSERVE_API_KEY.\n --demo preloads the workshop \"shop\" scenario (a regression in v2, 30% inventory errors, an N+1).\n\nEnvironment: OBSERVE_ROOT, OBSERVE_PORT (default 4318), OBSERVE_HOST (default 127.0.0.1), OBSERVE_API_KEY,\n OBSERVE_AI (mock | real), OBSERVE_DETECTOR (off to disable the anomaly detector)";
4
+ export declare class CliError extends Error {
5
+ }
6
+ export type Env = Record<string, string | undefined>;
7
+ export interface CliArgs {
8
+ command: 'dev' | 'collector' | 'help';
9
+ root: string;
10
+ port: number;
11
+ host: string;
12
+ apiKey?: string;
13
+ demo: boolean;
14
+ nextArgs: string[];
15
+ }
16
+ export declare function parseCliArgs(argv: string[], env: Env, cwd: string): CliArgs;
17
+ export interface CliDeps {
18
+ env: Env;
19
+ cwd: string;
20
+ log: (line: string) => void;
21
+ spawn: (command: string, args: string[], options: SpawnOptions) => ChildProcess;
22
+ /** Resolves when the CLI should stop (SIGINT/SIGTERM in real use). */
23
+ shutdownSignal: Promise<string>;
24
+ /** Loads the agents module; injectable for tests. */
25
+ loadAgents?: () => Promise<AgentsModule>;
26
+ }
27
+ export declare const AGENTS_FILES: string[];
28
+ export declare function run(argv: string[], deps: CliDeps): Promise<number>;
29
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,231 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { parseArgs } from 'node:util';
6
+ import { MemoryStorage, startCollector } from './collector/index.js';
7
+ import { seedDemo } from './debug/demo.js';
8
+ import { AnomalyDetector } from './debug/detector.js';
9
+ export const HELP = `Usage:
10
+ next-observer dev [--root <dir>] [--port <n>] [-- <next dev args>]
11
+ Start the collector and \`next dev\` for the app in <dir> (default: current directory).
12
+ Example: next-observer dev --root apps/web -- -p 3100
13
+
14
+ next-observer collector [--host <host>] [--port <n>] [--api-key <key>] [--demo]
15
+ Start only the collector (e.g. on a server). Reads OBSERVE_HOST, OBSERVE_PORT, OBSERVE_API_KEY.
16
+ --demo preloads the workshop "shop" scenario (a regression in v2, 30% inventory errors, an N+1).
17
+
18
+ Environment: OBSERVE_ROOT, OBSERVE_PORT (default 4318), OBSERVE_HOST (default 127.0.0.1), OBSERVE_API_KEY,
19
+ OBSERVE_AI (mock | real), OBSERVE_DETECTOR (off to disable the anomaly detector)`;
20
+ export class CliError extends Error {
21
+ }
22
+ export function parseCliArgs(argv, env, cwd) {
23
+ const separator = argv.indexOf('--');
24
+ const own = separator === -1 ? argv : argv.slice(0, separator);
25
+ const nextArgs = separator === -1 ? [] : argv.slice(separator + 1);
26
+ let parsed;
27
+ try {
28
+ parsed = parseArgs({
29
+ args: own,
30
+ allowPositionals: true,
31
+ options: {
32
+ root: { type: 'string' },
33
+ port: { type: 'string' },
34
+ host: { type: 'string' },
35
+ 'api-key': { type: 'string' },
36
+ demo: { type: 'boolean' },
37
+ help: { type: 'boolean', short: 'h' },
38
+ },
39
+ });
40
+ }
41
+ catch (error) {
42
+ throw new CliError(error.message);
43
+ }
44
+ const { values, positionals } = parsed;
45
+ const command = values.help || positionals.length === 0 ? 'help' : positionals[0];
46
+ if (command !== 'dev' && command !== 'collector' && command !== 'help')
47
+ throw new CliError(`unknown command "${command}"`);
48
+ const rawPort = values.port ?? env.OBSERVE_PORT ?? '4318';
49
+ const port = Number(rawPort);
50
+ if (!Number.isInteger(port) || port < 0 || port > 65535)
51
+ throw new CliError(`invalid port "${rawPort}"`);
52
+ return {
53
+ command,
54
+ root: resolve(cwd, values.root ?? env.OBSERVE_ROOT ?? '.'),
55
+ port,
56
+ host: values.host ?? env.OBSERVE_HOST ?? '127.0.0.1',
57
+ apiKey: values['api-key'] ?? env.OBSERVE_API_KEY,
58
+ demo: values.demo ?? false,
59
+ nextArgs,
60
+ };
61
+ }
62
+ function resolveNextBin(root) {
63
+ if (!existsSync(join(root, 'package.json')))
64
+ throw new CliError(`no package.json in ${root} — pass --root <app dir>`);
65
+ try {
66
+ const nextPackage = createRequire(join(root, 'package.json')).resolve('next/package.json');
67
+ return join(dirname(nextPackage), 'dist', 'bin', 'next');
68
+ }
69
+ catch {
70
+ throw new CliError(`next is not installed in ${root} — run npm install there first`);
71
+ }
72
+ }
73
+ export const AGENTS_FILES = ['observe.agents.ts', 'observe.agents.mts', 'observe.agents.js', 'observe.agents.mjs'];
74
+ /**
75
+ * The project's own specialists from observe.agents.* in the app root: `export default [defineSpecialist({…})]`.
76
+ * Same name as a built-in replaces it, a new name adds a specialist. Node ≥22.18 runs the .ts file as is (type stripping).
77
+ */
78
+ async function loadProjectSpecialists(root, agents) {
79
+ const found = AGENTS_FILES.filter((name) => existsSync(join(root, name)));
80
+ if (found.length === 0)
81
+ return { specs: [] };
82
+ if (found.length > 1)
83
+ throw new CliError(`found ${found.join(' and ')} in ${root} — keep one`);
84
+ const file = found[0];
85
+ let exported;
86
+ // Next apps rarely have "type": "module", so Node warns that it reparses observe.agents.ts as ESM — noise, not a problem.
87
+ const emitWarning = process.emitWarning;
88
+ process.emitWarning = ((warning, ...rest) => {
89
+ const code = rest[0]?.code;
90
+ if (code === 'MODULE_TYPELESS_PACKAGE_JSON' && String(warning).includes(file))
91
+ return;
92
+ return emitWarning.call(process, warning, ...rest);
93
+ });
94
+ try {
95
+ exported = (await import(pathToFileURL(join(root, file)).href)).default;
96
+ }
97
+ catch (error) {
98
+ const e = error;
99
+ if (e?.code === 'ERR_UNKNOWN_FILE_EXTENSION')
100
+ throw new CliError(`${file}: this Node.js cannot load TypeScript — use Node.js ≥22.18 or rename it to observe.agents.mjs`);
101
+ throw new CliError(`${file}: ${e?.message ?? String(error)}`);
102
+ }
103
+ finally {
104
+ process.emitWarning = emitWarning;
105
+ }
106
+ const list = Array.isArray(exported) ? exported : exported === undefined ? undefined : [exported];
107
+ if (!list)
108
+ throw new CliError(`${file}: export default an array of defineSpecialist({…})`);
109
+ const specs = [];
110
+ for (const item of list) {
111
+ try {
112
+ specs.push(agents.defineSpecialist(item));
113
+ }
114
+ catch (error) {
115
+ throw new CliError(`${file}: ${error.message}`);
116
+ }
117
+ }
118
+ const names = specs.map((s) => s.name);
119
+ const duplicate = names.find((name, i) => names.indexOf(name) !== i);
120
+ if (duplicate)
121
+ throw new CliError(`${file}: specialist "${duplicate}" is defined twice`);
122
+ return { file, specs };
123
+ }
124
+ function agentsLine(builtIn, file, project) {
125
+ const builtInNames = new Set(builtIn.map((s) => s.name));
126
+ const own = project.map((s) => (builtInNames.has(s.name) ? `${s.name} (replaces built-in)` : s.name));
127
+ const kept = builtIn.filter((s) => !project.some((p) => p.name === s.name)).map((s) => s.name);
128
+ return ` agents ${file}: ${own.join(', ')}${kept.length ? `; built-in: ${kept.join(', ')}` : ''}`;
129
+ }
130
+ async function loadChat(storage, root, deps) {
131
+ const agents = await (deps.loadAgents ?? (() => import('./agents/index.js')))();
132
+ const project = await loadProjectSpecialists(root, agents);
133
+ const specialists = agents.mergeSpecialists(agents.BUILT_IN_SPECIALISTS, project.specs);
134
+ try {
135
+ const chat = await agents.createChatHandler({ storage, env: deps.env, specialists });
136
+ const hint = chat.mode === 'mock' ? ' (OBSERVE_AI=real for a real model)' : '';
137
+ const line = ` chat ${chat.mode}${hint}`;
138
+ return { chat, line: project.file ? `${line}\n${agentsLine(agents.BUILT_IN_SPECIALISTS, project.file, project.specs)}` : line };
139
+ }
140
+ catch (error) {
141
+ throw new CliError(error.message);
142
+ }
143
+ }
144
+ async function start(args, deps) {
145
+ const storage = new MemoryStorage();
146
+ if (args.demo)
147
+ await seedDemo(storage);
148
+ const { chat, line: chatLine } = await loadChat(storage, args.root, deps);
149
+ const detector = deps.env.OBSERVE_DETECTOR === 'off' ? undefined : new AnomalyDetector();
150
+ const lines = [chatLine];
151
+ if (detector) {
152
+ const o = detector.options;
153
+ lines.push(` detector errors > ${o.errorRate * 100}%, slow (>${o.slowMs}ms) > ${o.slowRate * 100}%, silence > ${o.noTrafficMs / 1000}s → agents investigate on their own`);
154
+ }
155
+ else
156
+ lines.push(' detector off (OBSERVE_DETECTOR=off)');
157
+ if (args.demo)
158
+ lines.push(' demo "shop" scenario loaded: v1 → v2 regression, inventory errors, catalog N+1');
159
+ const line = lines.join('\n');
160
+ try {
161
+ const collector = await startCollector({ port: args.port, host: args.host, apiKey: args.apiKey, storage, chat, detector });
162
+ return { collector, chatLine: line };
163
+ }
164
+ catch (error) {
165
+ if (error.code === 'EADDRINUSE') {
166
+ throw new CliError(`port ${args.port} is already in use — is another next-observer running? Use --port <n>`);
167
+ }
168
+ throw error;
169
+ }
170
+ }
171
+ function banner(collector, extra = []) {
172
+ return [
173
+ 'next-observer',
174
+ ` ui ${collector.url}`,
175
+ ` collector ${collector.url} (OTLP: /v1/traces, API: /api/traces, /api/operations, /api/services)`,
176
+ ...extra,
177
+ ].join('\n');
178
+ }
179
+ async function runCollector(args, deps) {
180
+ const { collector, chatLine } = await start(args, deps);
181
+ deps.log(banner(collector, [chatLine, ...(args.apiKey ? [' auth x-api-key required'] : [])]));
182
+ await deps.shutdownSignal;
183
+ await collector.close();
184
+ return 0;
185
+ }
186
+ async function runDev(args, deps) {
187
+ const nextBin = resolveNextBin(args.root);
188
+ const { collector, chatLine } = await start(args, deps);
189
+ deps.log(banner(collector, [chatLine, ` app ${['next dev', ...args.nextArgs].join(' ')} in ${args.root}`]));
190
+ const child = deps.spawn(process.execPath, [nextBin, 'dev', ...args.nextArgs], {
191
+ cwd: args.root,
192
+ stdio: 'inherit',
193
+ // Points both register() and the /__observe browser proxy (withObserve) at this collector.
194
+ // Next's global types make NODE_ENV required on ProcessEnv; a plain env map is what spawn really takes.
195
+ env: { ...deps.env, OBSERVE_ENDPOINT: collector.url },
196
+ });
197
+ const exited = new Promise((resolveExit) => {
198
+ child.once('exit', (code) => resolveExit(code ?? 0));
199
+ child.once('error', () => resolveExit(1));
200
+ });
201
+ const first = await Promise.race([exited.then((code) => ({ code })), deps.shutdownSignal.then(() => null)]);
202
+ let code;
203
+ if (first) {
204
+ code = first.code;
205
+ }
206
+ else {
207
+ if (child.exitCode === null)
208
+ child.kill('SIGTERM');
209
+ await exited;
210
+ code = 0;
211
+ }
212
+ await collector.close();
213
+ return code;
214
+ }
215
+ export async function run(argv, deps) {
216
+ try {
217
+ const args = parseCliArgs(argv, deps.env, deps.cwd);
218
+ if (args.command === 'help') {
219
+ deps.log(HELP);
220
+ return 0;
221
+ }
222
+ return await (args.command === 'dev' ? runDev(args, deps) : runCollector(args, deps));
223
+ }
224
+ catch (error) {
225
+ if (!(error instanceof CliError))
226
+ throw error;
227
+ deps.log(`next-observer: ${error.message}\n\n${HELP}`);
228
+ return 1;
229
+ }
230
+ }
231
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import type { Anomaly } from '../debug/detector.js';
2
+ export interface VersionStats {
3
+ version: string;
4
+ count: number;
5
+ p50Ms: number;
6
+ p95Ms: number;
7
+ errorRate: number;
8
+ }
9
+ /**
10
+ * Evidence cards are built by code from tool results — never written by the model — so they can't contain
11
+ * invented facts. The model writes the narrative report; the cards show the proof.
12
+ */
13
+ export type EvidenceCard = {
14
+ kind: 'regression';
15
+ service: string;
16
+ operation: string;
17
+ from: VersionStats;
18
+ to: VersionStats;
19
+ p95Ratio: number | null;
20
+ errorRateDelta: number;
21
+ } | {
22
+ kind: 'errors';
23
+ service: string;
24
+ operation: string;
25
+ errorRate: number | null;
26
+ errors: number;
27
+ message: string;
28
+ traceIds: string[];
29
+ } | {
30
+ kind: 'n-plus-one';
31
+ traceId: string;
32
+ parent: string;
33
+ operation: string;
34
+ count: number;
35
+ totalMs: number;
36
+ } | {
37
+ kind: 'hotspot';
38
+ traceId: string;
39
+ operation: string;
40
+ selfMs: number;
41
+ traceMs: number;
42
+ codeFile: string;
43
+ } | {
44
+ kind: 'silent';
45
+ service: string;
46
+ lastSpanSecondsAgo: number;
47
+ } | {
48
+ kind: 'traces';
49
+ label: string;
50
+ traces: {
51
+ traceId: string;
52
+ root: string;
53
+ durationMs: number;
54
+ errors: number;
55
+ }[];
56
+ };
57
+ export type ChatEvent = {
58
+ type: 'anomaly';
59
+ anomaly: Anomaly;
60
+ } | {
61
+ type: 'status';
62
+ mode: 'mock' | 'real';
63
+ sessionId: string;
64
+ text: string;
65
+ } | {
66
+ type: 'step';
67
+ agent: string;
68
+ tool: string;
69
+ args: Record<string, unknown>;
70
+ } | {
71
+ type: 'card';
72
+ card: EvidenceCard;
73
+ } | {
74
+ type: 'report';
75
+ text: string;
76
+ } | {
77
+ type: 'error';
78
+ message: string;
79
+ };
80
+ export interface ChatRequest {
81
+ question: string;
82
+ /** From a previous `status` event: continue that conversation. Omitted → a new conversation. */
83
+ sessionId?: string;
84
+ }
85
+ /** Runs one chat turn, emitting events as it goes. Resolves when the turn is over. */
86
+ export type ChatHandler = (request: ChatRequest, emit: (event: ChatEvent) => void) => Promise<void>;
87
+ /** Server-pushed (SSE) event: part of a proactive turn started by the detector, not by a question. */
88
+ export interface ProactiveEvent {
89
+ /** Increases by one per event; lets a reconnecting client skip the replayed ones it already has. */
90
+ seq: number;
91
+ turnId: string;
92
+ event: ChatEvent;
93
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/collector/chat.ts"],"names":[],"mappings":""}
@@ -0,0 +1,52 @@
1
+ import type { NormalizedSpan } from './types.js';
2
+ interface OtlpAnyValue {
3
+ stringValue?: string;
4
+ boolValue?: boolean;
5
+ intValue?: string | number;
6
+ doubleValue?: number;
7
+ bytesValue?: string;
8
+ arrayValue?: {
9
+ values?: OtlpAnyValue[];
10
+ };
11
+ kvlistValue?: {
12
+ values?: OtlpKeyValue[];
13
+ };
14
+ }
15
+ interface OtlpKeyValue {
16
+ key: string;
17
+ value?: OtlpAnyValue;
18
+ }
19
+ interface OtlpSpan {
20
+ traceId: string;
21
+ spanId: string;
22
+ parentSpanId?: string;
23
+ name: string;
24
+ kind?: number;
25
+ startTimeUnixNano: string | number;
26
+ endTimeUnixNano: string | number;
27
+ attributes?: OtlpKeyValue[];
28
+ events?: {
29
+ name: string;
30
+ timeUnixNano: string | number;
31
+ attributes?: OtlpKeyValue[];
32
+ }[];
33
+ status?: {
34
+ code?: number;
35
+ message?: string;
36
+ };
37
+ }
38
+ export interface OtlpTraceRequest {
39
+ resourceSpans?: {
40
+ resource?: {
41
+ attributes?: OtlpKeyValue[];
42
+ };
43
+ scopeSpans?: {
44
+ scope?: {
45
+ name?: string;
46
+ };
47
+ spans?: OtlpSpan[];
48
+ }[];
49
+ }[];
50
+ }
51
+ export declare function decodeOtlpJson(request: OtlpTraceRequest): NormalizedSpan[];
52
+ export {};
@@ -0,0 +1,59 @@
1
+ const KINDS = ['unspecified', 'internal', 'server', 'client', 'producer', 'consumer'];
2
+ const STATUSES = ['unset', 'ok', 'error'];
3
+ function value(v) {
4
+ if (!v)
5
+ return null;
6
+ if (v.stringValue !== undefined)
7
+ return v.stringValue;
8
+ if (v.boolValue !== undefined)
9
+ return v.boolValue;
10
+ if (v.intValue !== undefined)
11
+ return Number(v.intValue);
12
+ if (v.doubleValue !== undefined)
13
+ return v.doubleValue;
14
+ if (v.bytesValue !== undefined)
15
+ return v.bytesValue;
16
+ if (v.arrayValue)
17
+ return (v.arrayValue.values ?? []).map(value);
18
+ if (v.kvlistValue)
19
+ return attributes(v.kvlistValue.values);
20
+ return null;
21
+ }
22
+ function attributes(list = []) {
23
+ return Object.fromEntries(list.map((kv) => [kv.key, value(kv.value)]));
24
+ }
25
+ // BigInt keeps nanosecond precision until the final division; Number(ns) would lose it.
26
+ const nanosToMs = (ns) => Number(BigInt(ns) / 1000n) / 1000;
27
+ export function decodeOtlpJson(request) {
28
+ const spans = [];
29
+ for (const rs of request.resourceSpans ?? []) {
30
+ const resource = attributes(rs.resource?.attributes);
31
+ const service = typeof resource['service.name'] === 'string' ? resource['service.name'] : 'unknown';
32
+ const serviceVersion = typeof resource['service.version'] === 'string' ? resource['service.version'] : null;
33
+ for (const ss of rs.scopeSpans ?? []) {
34
+ for (const s of ss.spans ?? []) {
35
+ // Duration is subtracted in nanoseconds: epoch-ms floats (~1.8e12) can't hold sub-µs differences.
36
+ const durationNs = BigInt(s.endTimeUnixNano) - BigInt(s.startTimeUnixNano);
37
+ spans.push({
38
+ traceId: s.traceId,
39
+ spanId: s.spanId,
40
+ parentSpanId: s.parentSpanId || null,
41
+ name: s.name,
42
+ kind: KINDS[s.kind ?? 0] ?? 'unspecified',
43
+ service,
44
+ serviceVersion,
45
+ scope: ss.scope?.name ?? null,
46
+ startTimeMs: nanosToMs(s.startTimeUnixNano),
47
+ durationMs: Number(durationNs) / 1e6,
48
+ status: STATUSES[s.status?.code ?? 0] ?? 'unset',
49
+ statusMessage: s.status?.message || null,
50
+ attributes: attributes(s.attributes),
51
+ resource,
52
+ events: (s.events ?? []).map((e) => ({ name: e.name, timeMs: nanosToMs(e.timeUnixNano), attributes: attributes(e.attributes) })),
53
+ });
54
+ }
55
+ }
56
+ }
57
+ return spans;
58
+ }
59
+ //# sourceMappingURL=decode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode.js","sourceRoot":"","sources":["../../src/collector/decode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { NormalizedSpan } from './types.js';
2
+ /**
3
+ * Next.js internal steps of a request ("executing api route (app) …", "render route (app) …", "start response"): they
4
+ * carry `next.span_type` but are not the request's server span. They repeat the endpoint's and user code's numbers, so
5
+ * agents' aggregates skip them — otherwise one slow call shows up as three problems. Traces keep them for structure.
6
+ */
7
+ export declare function isFrameworkSpan(span: Pick<NormalizedSpan, 'kind' | 'attributes'>): boolean;