@yagni-app/code 1.0.6 → 1.0.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/README.md +91 -46
- package/dist/claudeCompat.d.ts +59 -0
- package/dist/claudeCompat.js +109 -2
- package/dist/claudePlugins.d.ts +45 -5
- package/dist/claudePlugins.js +129 -21
- package/dist/cli.js +16 -4
- package/dist/doctor.d.ts +21 -8
- package/dist/doctor.js +53 -28
- package/dist/extension/askUserQuestionTool.js +7 -2
- package/dist/extension/condensedTools.d.ts +12 -1
- package/dist/extension/condensedTools.js +17 -9
- package/dist/extension/config.d.ts +6 -0
- package/dist/extension/hooks.d.ts +3 -3
- package/dist/extension/hooks.js +30 -5
- package/dist/extension/index.d.ts +19 -0
- package/dist/extension/index.js +248 -43
- package/dist/extension/mcp/cliConfig.d.ts +1 -1
- package/dist/extension/mcp/cliConfig.js +1 -1
- package/dist/extension/mcp/config.d.ts +24 -2
- package/dist/extension/mcp/config.js +75 -3
- package/dist/extension/mcp/manager.d.ts +3 -1
- package/dist/extension/mcp/manager.js +2 -2
- package/dist/extension/mcp/panel.d.ts +0 -1
- package/dist/extension/mcp/panel.js +13 -3
- package/dist/extension/mcp/startup.js +8 -6
- package/dist/extension/permission/gate.d.ts +101 -2
- package/dist/extension/permission/gate.js +485 -42
- package/dist/extension/permissionRules/bashFileArgs.d.ts +39 -0
- package/dist/extension/permissionRules/bashFileArgs.js +236 -0
- package/dist/extension/permissionRules/engine.d.ts +50 -0
- package/dist/extension/permissionRules/engine.js +238 -0
- package/dist/extension/permissionRules/loadConfig.d.ts +64 -0
- package/dist/extension/permissionRules/loadConfig.js +105 -0
- package/dist/extension/permissionRules/parser.d.ts +38 -0
- package/dist/extension/permissionRules/parser.js +136 -0
- package/dist/extension/permissionRules/pathRules.d.ts +60 -0
- package/dist/extension/permissionRules/pathRules.js +122 -0
- package/dist/extension/permissionRules/shellRules.d.ts +52 -0
- package/dist/extension/permissionRules/shellRules.js +221 -0
- package/dist/extension/pipeline/invocation.d.ts +3 -6
- package/dist/extension/pipeline/invocation.js +3 -6
- package/dist/extension/pipeline/runner.d.ts +0 -1
- package/dist/extension/pipeline/runner.js +6 -14
- package/dist/extension/plugins/inventory.d.ts +88 -0
- package/dist/extension/plugins/inventory.js +144 -0
- package/dist/extension/plugins/panel.d.ts +45 -0
- package/dist/extension/plugins/panel.js +293 -0
- package/dist/extension/sandbox/bash.d.ts +99 -0
- package/dist/extension/sandbox/bash.js +190 -0
- package/dist/extension/sandbox/config.d.ts +115 -0
- package/dist/extension/sandbox/config.js +388 -0
- package/dist/extension/sandbox/manager.d.ts +108 -0
- package/dist/extension/sandbox/manager.js +243 -0
- package/dist/extension/sandbox/panel.d.ts +111 -0
- package/dist/extension/sandbox/panel.js +342 -0
- package/dist/extension/sandbox/session.d.ts +85 -0
- package/dist/extension/sandbox/session.js +829 -0
- package/dist/extension/settingsFiles.d.ts +50 -0
- package/dist/extension/settingsFiles.js +206 -0
- package/dist/extension/telemetry/attrs.d.ts +96 -0
- package/dist/extension/telemetry/attrs.js +149 -0
- package/dist/extension/telemetry/config.d.ts +103 -0
- package/dist/extension/telemetry/config.js +193 -0
- package/dist/extension/telemetry/index.d.ts +7 -0
- package/dist/extension/telemetry/index.js +7 -0
- package/dist/extension/telemetry/probe.d.ts +29 -0
- package/dist/extension/telemetry/probe.js +122 -0
- package/dist/extension/telemetry/register.d.ts +47 -0
- package/dist/extension/telemetry/register.js +207 -0
- package/dist/extension/telemetry/sdk.d.ts +63 -0
- package/dist/extension/telemetry/sdk.js +207 -0
- package/dist/extension/telemetry/tracker.d.ts +131 -0
- package/dist/extension/telemetry/tracker.js +551 -0
- package/dist/extension/vendor/IGNORE-LICENSE-MIT +21 -0
- package/dist/extension/vendor/ignore.d.ts +86 -0
- package/dist/extension/vendor/ignore.js +788 -0
- package/dist/goHeadless.d.ts +1 -1
- package/dist/goHeadless.js +2 -2
- package/dist/launch.d.ts +4 -3
- package/dist/launch.js +7 -4
- package/dist/mcpCommand.d.ts +10 -1
- package/dist/mcpCommand.js +42 -10
- package/dist/otel.d.ts +67 -90
- package/dist/otel.js +152 -195
- package/dist/paths.d.ts +13 -0
- package/dist/paths.js +18 -0
- package/dist/pluginCommand.d.ts +43 -0
- package/dist/pluginCommand.js +499 -0
- package/dist/pluginStore.d.ts +170 -0
- package/dist/pluginStore.js +554 -0
- package/dist/upgrade.js +10 -1
- package/package.json +19 -3
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared settings-file plumbing for the three YAGNI Code settings tiers:
|
|
3
|
+
* user ~/.yagni-code/config.json (always trusted)
|
|
4
|
+
* project .yagni-code/config.json under the cwd (shared, committed)
|
|
5
|
+
* local .yagni-code/config.local.json under cwd (personal, gitignored)
|
|
6
|
+
*
|
|
7
|
+
* Owns the atomic config mutation (promoted from sandbox/session.ts, the
|
|
8
|
+
* single copy now) and the global-gitignore helper (Claude Code
|
|
9
|
+
* addFileGlobRuleToGitignore parity): on the first write to the local file,
|
|
10
|
+
* the LOCAL_GITIGNORE_ENTRY glob lands in the GLOBAL git ignore file so
|
|
11
|
+
* personal settings are never committed. Fail-soft by design — a gitignore
|
|
12
|
+
* failure never fails the settings write.
|
|
13
|
+
*/
|
|
14
|
+
export declare function mutateConfigJson(target: string, mutate: (config: Record<string, unknown>) => void): void;
|
|
15
|
+
/** The project-local settings path for a session cwd. */
|
|
16
|
+
export declare function localConfigPath(cwd: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Mutate the project-local settings file. Every write fire-and-forgets
|
|
19
|
+
* ensureLocalGitignored (Claude parity: the local tier is added to the
|
|
20
|
+
* global git ignore on write, not on session start). The helper is
|
|
21
|
+
* fire-and-forget BY DESIGN — the write's success notice is not gated on
|
|
22
|
+
* two git spawns; when the gitignore step is skipped or fails, the sink
|
|
23
|
+
* warn (gitignore_skipped / gitignore_update_failed) is the designed
|
|
24
|
+
* signal, surfaced via the diagnostics trail.
|
|
25
|
+
*
|
|
26
|
+
* `sinkSource` attributes those sink events to the caller's surface
|
|
27
|
+
* ("permission-rules" for rule saves, "sandbox" for panel/toggle writes) —
|
|
28
|
+
* the diagnostics trail then says which surface's write failed to get
|
|
29
|
+
* ignore-protected, not a blanket permission-rules line for every write.
|
|
30
|
+
*/
|
|
31
|
+
export declare function mutateLocalConfig(cwd: string, mutate: (config: Record<string, unknown>) => void, sinkSource?: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* The global git ignore path git actually reads. Git consults
|
|
34
|
+
* $XDG_CONFIG_HOME/git/ignore (defaulting ~/.config/git/ignore) — honoring
|
|
35
|
+
* XDG is a deliberate divergence from Claude (which hardcodes ~/.config):
|
|
36
|
+
* writing a file git will not read when XDG is set would be a silent no-op.
|
|
37
|
+
*/
|
|
38
|
+
export declare function globalGitignorePath(env?: NodeJS.ProcessEnv): string;
|
|
39
|
+
/**
|
|
40
|
+
* Ensure the LOCAL_GITIGNORE_ENTRY glob (covering config.local.json at any
|
|
41
|
+
* depth) is ignored by the user's GLOBAL git config so local settings are
|
|
42
|
+
* never committed. Skip when:
|
|
43
|
+
* - cwd is not inside a git repo (nothing to protect);
|
|
44
|
+
* - `git check-ignore` already matches (local or global patterns cover it);
|
|
45
|
+
* - the global ignore file already carries the literal entry.
|
|
46
|
+
* Any failure logs one warn sink event and returns — the settings write it
|
|
47
|
+
* accompanies has already succeeded and must not be walked back.
|
|
48
|
+
*/
|
|
49
|
+
export declare function ensureLocalGitignored(cwd: string, env?: NodeJS.ProcessEnv, sinkSource?: string): Promise<void>;
|
|
50
|
+
//# sourceMappingURL=settingsFiles.d.ts.map
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared settings-file plumbing for the three YAGNI Code settings tiers:
|
|
3
|
+
* user ~/.yagni-code/config.json (always trusted)
|
|
4
|
+
* project .yagni-code/config.json under the cwd (shared, committed)
|
|
5
|
+
* local .yagni-code/config.local.json under cwd (personal, gitignored)
|
|
6
|
+
*
|
|
7
|
+
* Owns the atomic config mutation (promoted from sandbox/session.ts, the
|
|
8
|
+
* single copy now) and the global-gitignore helper (Claude Code
|
|
9
|
+
* addFileGlobRuleToGitignore parity): on the first write to the local file,
|
|
10
|
+
* the LOCAL_GITIGNORE_ENTRY glob lands in the GLOBAL git ignore file so
|
|
11
|
+
* personal settings are never committed. Fail-soft by design — a gitignore
|
|
12
|
+
* failure never fails the settings write.
|
|
13
|
+
*/
|
|
14
|
+
import { spawn } from "node:child_process";
|
|
15
|
+
import { randomUUID } from "node:crypto";
|
|
16
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, appendFileSync, writeFileSync, renameSync, chmodSync } from "node:fs";
|
|
17
|
+
import { homedir } from "node:os";
|
|
18
|
+
import { dirname, join } from "node:path";
|
|
19
|
+
import { logEvent } from "./errorSink.js";
|
|
20
|
+
const LOCAL_GITIGNORE_ENTRY = "**/.yagni-code/config.local.json";
|
|
21
|
+
function isPlainRecord(v) {
|
|
22
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Safe config-file mutation shared by every settings writer:
|
|
26
|
+
* - a PARSE FAILURE aborts (never treats a corrupt/half-written file as
|
|
27
|
+
* empty — that would wipe activeProfile/permissions);
|
|
28
|
+
* - the write is ATOMIC (tmp file + rename) so a crash never truncates;
|
|
29
|
+
* - symlinked targets are rejected (a hostile repo's config symlink must
|
|
30
|
+
* not redirect writes to arbitrary paths);
|
|
31
|
+
* - the mutator runs only on a parsed object; a thrown mutator aborts.
|
|
32
|
+
* Throws on any failure — callers decide fail-soft messaging.
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Reject when the target's EXISTING parent directory is a symlink — a
|
|
36
|
+
* hostile repo can commit a symlinked `.yagni-code` DIRECTORY, and every
|
|
37
|
+
* local-settings write would then land outside the repo via the symlinked
|
|
38
|
+
* parent (the final-component lstat guard cannot see this). The parent is
|
|
39
|
+
* the repo-committable component (`.yagni-code` for project/local targets,
|
|
40
|
+
* the state home for user targets); ancestors above it are the user's own
|
|
41
|
+
* filesystem, not repo-controlled. Absent parent is fine — mkdirSync
|
|
42
|
+
* creates it fresh, and mkdir does not follow a symlinked path segment it
|
|
43
|
+
* creates itself. Fail closed.
|
|
44
|
+
*/
|
|
45
|
+
function assertRealParentDir(target) {
|
|
46
|
+
const dir = dirname(target);
|
|
47
|
+
try {
|
|
48
|
+
const st = lstatSync(dir);
|
|
49
|
+
if (!st.isDirectory() || st.isSymbolicLink()) {
|
|
50
|
+
throw new Error(`${dir} is not a real directory (symlinked parent?) — refusing to write through it`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
if (err.code === "ENOENT")
|
|
55
|
+
return; // absent — created fresh below
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function mutateConfigJson(target, mutate) {
|
|
60
|
+
let parsed;
|
|
61
|
+
try {
|
|
62
|
+
parsed = JSON.parse(readFileSync(target, "utf-8"));
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
if (err.code === "ENOENT") {
|
|
66
|
+
parsed = {}; // genuinely fresh file — fine
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw new Error(`config at ${target} is not valid JSON — refusing to rewrite it`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (!isPlainRecord(parsed))
|
|
73
|
+
throw new Error(`config at ${target} is not an object`);
|
|
74
|
+
const config = { ...parsed };
|
|
75
|
+
mutate(config);
|
|
76
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
77
|
+
// Reject symlinked targets: lstat must show a regular file (or absent).
|
|
78
|
+
try {
|
|
79
|
+
const st = lstatSync(target);
|
|
80
|
+
if (!st.isFile())
|
|
81
|
+
throw new Error(`${target} is not a regular file (symlink?) — refusing`);
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
if (err.code !== "ENOENT")
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
87
|
+
// And a symlinked PARENT directory: a committed symlinked .yagni-code
|
|
88
|
+
// dir would redirect the write outside the project — the final-component
|
|
89
|
+
// guard above cannot see it.
|
|
90
|
+
assertRealParentDir(target);
|
|
91
|
+
const tmp = `${target}.yagni-tmp-${process.pid}-${randomUUID().slice(0, 8)}`;
|
|
92
|
+
writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", { mode: 0o600 });
|
|
93
|
+
// chmod: writeFile honors mode only on create — guarantee 0600 even when a
|
|
94
|
+
// same-pid retry reuses an existing tmp file.
|
|
95
|
+
chmodSync(tmp, 0o600);
|
|
96
|
+
renameSync(tmp, target);
|
|
97
|
+
}
|
|
98
|
+
/** The project-local settings path for a session cwd. */
|
|
99
|
+
export function localConfigPath(cwd) {
|
|
100
|
+
return join(cwd, ".yagni-code", "config.local.json");
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Mutate the project-local settings file. Every write fire-and-forgets
|
|
104
|
+
* ensureLocalGitignored (Claude parity: the local tier is added to the
|
|
105
|
+
* global git ignore on write, not on session start). The helper is
|
|
106
|
+
* fire-and-forget BY DESIGN — the write's success notice is not gated on
|
|
107
|
+
* two git spawns; when the gitignore step is skipped or fails, the sink
|
|
108
|
+
* warn (gitignore_skipped / gitignore_update_failed) is the designed
|
|
109
|
+
* signal, surfaced via the diagnostics trail.
|
|
110
|
+
*
|
|
111
|
+
* `sinkSource` attributes those sink events to the caller's surface
|
|
112
|
+
* ("permission-rules" for rule saves, "sandbox" for panel/toggle writes) —
|
|
113
|
+
* the diagnostics trail then says which surface's write failed to get
|
|
114
|
+
* ignore-protected, not a blanket permission-rules line for every write.
|
|
115
|
+
*/
|
|
116
|
+
export function mutateLocalConfig(cwd, mutate, sinkSource = "permission-rules") {
|
|
117
|
+
mutateConfigJson(localConfigPath(cwd), mutate);
|
|
118
|
+
void ensureLocalGitignored(cwd, process.env, sinkSource);
|
|
119
|
+
}
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
// Global-gitignore helper (Claude addFileGlobRuleToGitignore parity)
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
/** Run git <args> in cwd; resolves exit code (never throws). env threads
|
|
124
|
+
* through so the caller's PATH governs git resolution. */
|
|
125
|
+
function git(cwd, args, env) {
|
|
126
|
+
return new Promise((resolve) => {
|
|
127
|
+
try {
|
|
128
|
+
const child = spawn("git", args, { cwd, env, stdio: "ignore" });
|
|
129
|
+
child.on("error", () => resolve(GIT_NOT_INSTALLED));
|
|
130
|
+
child.on("exit", (code) => resolve(code ?? GIT_NOT_INSTALLED));
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
resolve(GIT_NOT_INSTALLED);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const GIT_NOT_INSTALLED = -1;
|
|
138
|
+
/**
|
|
139
|
+
* The global git ignore path git actually reads. Git consults
|
|
140
|
+
* $XDG_CONFIG_HOME/git/ignore (defaulting ~/.config/git/ignore) — honoring
|
|
141
|
+
* XDG is a deliberate divergence from Claude (which hardcodes ~/.config):
|
|
142
|
+
* writing a file git will not read when XDG is set would be a silent no-op.
|
|
143
|
+
*/
|
|
144
|
+
export function globalGitignorePath(env = process.env) {
|
|
145
|
+
const xdg = env.XDG_CONFIG_HOME && env.XDG_CONFIG_HOME.trim() !== "" ? env.XDG_CONFIG_HOME : null;
|
|
146
|
+
return join(xdg ?? join(homedir(), ".config"), "git", "ignore");
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Ensure the LOCAL_GITIGNORE_ENTRY glob (covering config.local.json at any
|
|
150
|
+
* depth) is ignored by the user's GLOBAL git config so local settings are
|
|
151
|
+
* never committed. Skip when:
|
|
152
|
+
* - cwd is not inside a git repo (nothing to protect);
|
|
153
|
+
* - `git check-ignore` already matches (local or global patterns cover it);
|
|
154
|
+
* - the global ignore file already carries the literal entry.
|
|
155
|
+
* Any failure logs one warn sink event and returns — the settings write it
|
|
156
|
+
* accompanies has already succeeded and must not be walked back.
|
|
157
|
+
*/
|
|
158
|
+
export async function ensureLocalGitignored(cwd, env = process.env, sinkSource = "permission-rules") {
|
|
159
|
+
try {
|
|
160
|
+
const inside = await git(cwd, ["rev-parse", "--is-inside-work-tree"], env);
|
|
161
|
+
// -1 = git missing or failed to spawn — protection silently skipped; a
|
|
162
|
+
// warn makes that visible (the file exists un-ignored). 128 = cleanly
|
|
163
|
+
// not a repo — the documented skip, nothing to surface.
|
|
164
|
+
if (inside === GIT_NOT_INSTALLED) {
|
|
165
|
+
logEvent({
|
|
166
|
+
source: sinkSource,
|
|
167
|
+
level: "warn",
|
|
168
|
+
event: "gitignore_skipped",
|
|
169
|
+
fields: { reason: "git-unavailable" },
|
|
170
|
+
});
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
// Not inside a repo (128) or a failed rev-parse: skip, nothing to do.
|
|
174
|
+
if (inside !== 0)
|
|
175
|
+
return;
|
|
176
|
+
// 0 = already ignored by some pattern (project .gitignore or global).
|
|
177
|
+
if ((await git(cwd, ["check-ignore", ".yagni-code/config.local.json"], env)) === 0)
|
|
178
|
+
return;
|
|
179
|
+
const path = globalGitignorePath(env);
|
|
180
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
181
|
+
if (existsSync(path)) {
|
|
182
|
+
const content = readFileSync(path, "utf-8");
|
|
183
|
+
if (content.includes(LOCAL_GITIGNORE_ENTRY))
|
|
184
|
+
return;
|
|
185
|
+
appendFileSync(path, `${content.endsWith("\n") ? "" : "\n"}${LOCAL_GITIGNORE_ENTRY}\n`);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
writeFileSync(path, `${LOCAL_GITIGNORE_ENTRY}\n`, { mode: 0o644 });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
logEvent({
|
|
193
|
+
source: sinkSource,
|
|
194
|
+
level: "warn",
|
|
195
|
+
event: "gitignore_update_failed",
|
|
196
|
+
fields: {
|
|
197
|
+
path: globalGitignorePath(env),
|
|
198
|
+
// The thrown message names the failing operation and the local
|
|
199
|
+
// filesystem path (mkdir/append of the ignore file) — no secret
|
|
200
|
+
// surface, and it makes EACCES-vs-ENOSPC diagnosable.
|
|
201
|
+
error: err instanceof Error ? err.message : String(err),
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=settingsFiles.js.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribute, metric, and event names.
|
|
3
|
+
*
|
|
4
|
+
* Two vocabularies ride on every signal on purpose:
|
|
5
|
+
*
|
|
6
|
+
* - Claude Code's telemetry shape (`session.id`, `input_tokens`,
|
|
7
|
+
* `tool_name`, the `<prefix>.token.usage` counter, the `api_request`
|
|
8
|
+
* event …) so a team's existing Claude Code dashboards swap to YAGNI Code
|
|
9
|
+
* by changing the prefix from `claude_code` to `yagni_code`;
|
|
10
|
+
* - the OpenTelemetry GenAI semantic conventions (`gen_ai.*`) on the LLM
|
|
11
|
+
* and tool spans, which is what vendor LLM-observability products
|
|
12
|
+
* (Datadog LLM Observability, Grafana's GenAI views) key on.
|
|
13
|
+
*
|
|
14
|
+
* Names are literal strings rather than semconv-package imports: the set is
|
|
15
|
+
* small, stable, and part of our documented customer contract.
|
|
16
|
+
*/
|
|
17
|
+
export declare const PREFIX = "yagni_code";
|
|
18
|
+
export declare const ATTR_SESSION_ID = "session.id";
|
|
19
|
+
export declare const ATTR_APP_VERSION = "app.version";
|
|
20
|
+
export declare const ATTR_APP_ENTRYPOINT = "app.entrypoint";
|
|
21
|
+
export declare const ATTR_ORGANIZATION_ID = "organization.id";
|
|
22
|
+
export declare const ATTR_USER_EMAIL = "user.email";
|
|
23
|
+
export declare const ATTR_TERMINAL_TYPE = "terminal.type";
|
|
24
|
+
export declare const ATTR_GEN_AI_OPERATION_NAME = "gen_ai.operation.name";
|
|
25
|
+
export declare const ATTR_GEN_AI_PROVIDER_NAME = "gen_ai.provider.name";
|
|
26
|
+
export declare const ATTR_GEN_AI_SYSTEM = "gen_ai.system";
|
|
27
|
+
export declare const ATTR_GEN_AI_REQUEST_MODEL = "gen_ai.request.model";
|
|
28
|
+
export declare const ATTR_GEN_AI_RESPONSE_MODEL = "gen_ai.response.model";
|
|
29
|
+
export declare const ATTR_GEN_AI_RESPONSE_ID = "gen_ai.response.id";
|
|
30
|
+
export declare const ATTR_GEN_AI_FINISH_REASONS = "gen_ai.response.finish_reasons";
|
|
31
|
+
/**
|
|
32
|
+
* Token usage. The semconv registry says `gen_ai.usage.input_tokens` "SHOULD
|
|
33
|
+
* include all types of input tokens, including cached tokens", and defines the
|
|
34
|
+
* cache counters as subsets of it. pi reports the Anthropic way (non-cached
|
|
35
|
+
* input, cache read, cache write as three disjoint numbers), so the tracker
|
|
36
|
+
* adds them up for the `gen_ai.*` layer. Consumers such as Datadog LLM
|
|
37
|
+
* Observability divide cache_read by input_tokens; feeding them the disjoint
|
|
38
|
+
* number produced cache ratios in the tens of thousands of percent.
|
|
39
|
+
*
|
|
40
|
+
* The flat Claude Code attributes (`input_tokens`, `cache_read_tokens`, …) and
|
|
41
|
+
* the `<prefix>.token.usage` metric deliberately keep Claude Code's disjoint
|
|
42
|
+
* semantics so cross-harness comparisons stay apples to apples.
|
|
43
|
+
*/
|
|
44
|
+
export declare const ATTR_GEN_AI_INPUT_TOKENS = "gen_ai.usage.input_tokens";
|
|
45
|
+
export declare const ATTR_GEN_AI_OUTPUT_TOKENS = "gen_ai.usage.output_tokens";
|
|
46
|
+
export declare const ATTR_GEN_AI_TOTAL_TOKENS = "gen_ai.usage.total_tokens";
|
|
47
|
+
export declare const ATTR_GEN_AI_CACHE_READ_TOKENS = "gen_ai.usage.cache_read.input_tokens";
|
|
48
|
+
export declare const ATTR_GEN_AI_CACHE_WRITE_TOKENS = "gen_ai.usage.cache_write.input_tokens";
|
|
49
|
+
/** Pre-semconv spellings emitted through 1.0.x; kept for one release so
|
|
50
|
+
* dashboards keyed on them keep working. */
|
|
51
|
+
export declare const ATTR_GEN_AI_CACHE_READ_TOKENS_LEGACY = "gen_ai.usage.cache_read_input_tokens";
|
|
52
|
+
export declare const ATTR_GEN_AI_CACHE_CREATION_TOKENS_LEGACY = "gen_ai.usage.cache_creation_input_tokens";
|
|
53
|
+
/** The one cost attribute Datadog's OTLP ingestion documents. Carries the
|
|
54
|
+
* same sell-rate figure as the flat `cost_usd`, so the vendor Cost view
|
|
55
|
+
* populates for the opaque tier id, which no vendor price table knows.
|
|
56
|
+
* Unit is NANODOLLARS (integer), not dollars: Datadog copies the value
|
|
57
|
+
* unscaled into its nanodollar cost metric. */
|
|
58
|
+
export declare const ATTR_GEN_AI_COST_ESTIMATED_TOTAL = "gen_ai.cost.estimated_total";
|
|
59
|
+
export declare const ATTR_GEN_AI_CONVERSATION_ID = "gen_ai.conversation.id";
|
|
60
|
+
export declare const ATTR_GEN_AI_AGENT_NAME = "gen_ai.agent.name";
|
|
61
|
+
export declare const ATTR_GEN_AI_TOOL_NAME = "gen_ai.tool.name";
|
|
62
|
+
export declare const ATTR_GEN_AI_TOOL_CALL_ID = "gen_ai.tool.call.id";
|
|
63
|
+
export declare const ATTR_GEN_AI_TOOL_TYPE = "gen_ai.tool.type";
|
|
64
|
+
export declare const ATTR_ERROR_TYPE = "error.type";
|
|
65
|
+
export declare const ATTR_HTTP_STATUS_CODE = "http.response.status_code";
|
|
66
|
+
/** The provider name every span carries. The backing model is never exposed:
|
|
67
|
+
* `gen_ai.request.model` is the opaque YAGNI tier id. */
|
|
68
|
+
export declare const GEN_AI_PROVIDER = "yagni";
|
|
69
|
+
export declare const SPAN_INTERACTION = "yagni_code.interaction";
|
|
70
|
+
export declare const SPAN_TURN = "yagni_code.turn";
|
|
71
|
+
export declare const SPAN_LLM_REQUEST = "yagni_code.llm_request";
|
|
72
|
+
export declare const SPAN_TOOL = "yagni_code.tool";
|
|
73
|
+
export declare const METRIC_SESSION_COUNT = "yagni_code.session.count";
|
|
74
|
+
export declare const METRIC_LINES_OF_CODE = "yagni_code.lines_of_code.count";
|
|
75
|
+
export declare const METRIC_PULL_REQUEST_COUNT = "yagni_code.pull_request.count";
|
|
76
|
+
export declare const METRIC_COMMIT_COUNT = "yagni_code.commit.count";
|
|
77
|
+
export declare const METRIC_COST_USAGE = "yagni_code.cost.usage";
|
|
78
|
+
export declare const METRIC_TOKEN_USAGE = "yagni_code.token.usage";
|
|
79
|
+
export declare const METRIC_CODE_EDIT_DECISION = "yagni_code.code_edit_tool.decision";
|
|
80
|
+
export declare const METRIC_ACTIVE_TIME = "yagni_code.active_time.total";
|
|
81
|
+
export declare const EVENT_USER_PROMPT = "user_prompt";
|
|
82
|
+
export declare const EVENT_ASSISTANT_RESPONSE = "assistant_response";
|
|
83
|
+
export declare const EVENT_TOOL_RESULT = "tool_result";
|
|
84
|
+
export declare const EVENT_API_REQUEST = "api_request";
|
|
85
|
+
export declare const EVENT_API_ERROR = "api_error";
|
|
86
|
+
export declare const EVENT_TOOL_DECISION = "tool_decision";
|
|
87
|
+
export declare const EVENT_PERMISSION_MODE_CHANGED = "permission_mode_changed";
|
|
88
|
+
/** Claude Code token-type values on `<prefix>.token.usage`. */
|
|
89
|
+
export type TokenType = "input" | "output" | "cacheRead" | "cacheCreation";
|
|
90
|
+
/** Claude Code decision sources on tool_decision / code_edit_tool.decision. */
|
|
91
|
+
export type DecisionSource = "config" | "hook" | "user_permanent" | "user_temporary" | "user_abort" | "user_reject";
|
|
92
|
+
export type Decision = "accept" | "reject";
|
|
93
|
+
export declare function clampString(s: string, max?: number): string;
|
|
94
|
+
/** Language label from a file path's extension (Claude Code's `language` attr). */
|
|
95
|
+
export declare function languageFromPath(path: string | undefined): string | undefined;
|
|
96
|
+
//# sourceMappingURL=attrs.d.ts.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribute, metric, and event names.
|
|
3
|
+
*
|
|
4
|
+
* Two vocabularies ride on every signal on purpose:
|
|
5
|
+
*
|
|
6
|
+
* - Claude Code's telemetry shape (`session.id`, `input_tokens`,
|
|
7
|
+
* `tool_name`, the `<prefix>.token.usage` counter, the `api_request`
|
|
8
|
+
* event …) so a team's existing Claude Code dashboards swap to YAGNI Code
|
|
9
|
+
* by changing the prefix from `claude_code` to `yagni_code`;
|
|
10
|
+
* - the OpenTelemetry GenAI semantic conventions (`gen_ai.*`) on the LLM
|
|
11
|
+
* and tool spans, which is what vendor LLM-observability products
|
|
12
|
+
* (Datadog LLM Observability, Grafana's GenAI views) key on.
|
|
13
|
+
*
|
|
14
|
+
* Names are literal strings rather than semconv-package imports: the set is
|
|
15
|
+
* small, stable, and part of our documented customer contract.
|
|
16
|
+
*/
|
|
17
|
+
export const PREFIX = "yagni_code";
|
|
18
|
+
// ── Resource / standard attributes ──────────────────────────────────────────
|
|
19
|
+
export const ATTR_SESSION_ID = "session.id";
|
|
20
|
+
export const ATTR_APP_VERSION = "app.version";
|
|
21
|
+
export const ATTR_APP_ENTRYPOINT = "app.entrypoint";
|
|
22
|
+
export const ATTR_ORGANIZATION_ID = "organization.id";
|
|
23
|
+
export const ATTR_USER_EMAIL = "user.email";
|
|
24
|
+
export const ATTR_TERMINAL_TYPE = "terminal.type";
|
|
25
|
+
// ── GenAI semantic conventions ──────────────────────────────────────────────
|
|
26
|
+
export const ATTR_GEN_AI_OPERATION_NAME = "gen_ai.operation.name";
|
|
27
|
+
export const ATTR_GEN_AI_PROVIDER_NAME = "gen_ai.provider.name";
|
|
28
|
+
export const ATTR_GEN_AI_SYSTEM = "gen_ai.system";
|
|
29
|
+
export const ATTR_GEN_AI_REQUEST_MODEL = "gen_ai.request.model";
|
|
30
|
+
export const ATTR_GEN_AI_RESPONSE_MODEL = "gen_ai.response.model";
|
|
31
|
+
export const ATTR_GEN_AI_RESPONSE_ID = "gen_ai.response.id";
|
|
32
|
+
export const ATTR_GEN_AI_FINISH_REASONS = "gen_ai.response.finish_reasons";
|
|
33
|
+
/**
|
|
34
|
+
* Token usage. The semconv registry says `gen_ai.usage.input_tokens` "SHOULD
|
|
35
|
+
* include all types of input tokens, including cached tokens", and defines the
|
|
36
|
+
* cache counters as subsets of it. pi reports the Anthropic way (non-cached
|
|
37
|
+
* input, cache read, cache write as three disjoint numbers), so the tracker
|
|
38
|
+
* adds them up for the `gen_ai.*` layer. Consumers such as Datadog LLM
|
|
39
|
+
* Observability divide cache_read by input_tokens; feeding them the disjoint
|
|
40
|
+
* number produced cache ratios in the tens of thousands of percent.
|
|
41
|
+
*
|
|
42
|
+
* The flat Claude Code attributes (`input_tokens`, `cache_read_tokens`, …) and
|
|
43
|
+
* the `<prefix>.token.usage` metric deliberately keep Claude Code's disjoint
|
|
44
|
+
* semantics so cross-harness comparisons stay apples to apples.
|
|
45
|
+
*/
|
|
46
|
+
export const ATTR_GEN_AI_INPUT_TOKENS = "gen_ai.usage.input_tokens";
|
|
47
|
+
export const ATTR_GEN_AI_OUTPUT_TOKENS = "gen_ai.usage.output_tokens";
|
|
48
|
+
export const ATTR_GEN_AI_TOTAL_TOKENS = "gen_ai.usage.total_tokens";
|
|
49
|
+
export const ATTR_GEN_AI_CACHE_READ_TOKENS = "gen_ai.usage.cache_read.input_tokens";
|
|
50
|
+
export const ATTR_GEN_AI_CACHE_WRITE_TOKENS = "gen_ai.usage.cache_write.input_tokens";
|
|
51
|
+
/** Pre-semconv spellings emitted through 1.0.x; kept for one release so
|
|
52
|
+
* dashboards keyed on them keep working. */
|
|
53
|
+
export const ATTR_GEN_AI_CACHE_READ_TOKENS_LEGACY = "gen_ai.usage.cache_read_input_tokens";
|
|
54
|
+
export const ATTR_GEN_AI_CACHE_CREATION_TOKENS_LEGACY = "gen_ai.usage.cache_creation_input_tokens";
|
|
55
|
+
/** The one cost attribute Datadog's OTLP ingestion documents. Carries the
|
|
56
|
+
* same sell-rate figure as the flat `cost_usd`, so the vendor Cost view
|
|
57
|
+
* populates for the opaque tier id, which no vendor price table knows.
|
|
58
|
+
* Unit is NANODOLLARS (integer), not dollars: Datadog copies the value
|
|
59
|
+
* unscaled into its nanodollar cost metric. */
|
|
60
|
+
export const ATTR_GEN_AI_COST_ESTIMATED_TOTAL = "gen_ai.cost.estimated_total";
|
|
61
|
+
export const ATTR_GEN_AI_CONVERSATION_ID = "gen_ai.conversation.id";
|
|
62
|
+
export const ATTR_GEN_AI_AGENT_NAME = "gen_ai.agent.name";
|
|
63
|
+
export const ATTR_GEN_AI_TOOL_NAME = "gen_ai.tool.name";
|
|
64
|
+
export const ATTR_GEN_AI_TOOL_CALL_ID = "gen_ai.tool.call.id";
|
|
65
|
+
export const ATTR_GEN_AI_TOOL_TYPE = "gen_ai.tool.type";
|
|
66
|
+
export const ATTR_ERROR_TYPE = "error.type";
|
|
67
|
+
export const ATTR_HTTP_STATUS_CODE = "http.response.status_code";
|
|
68
|
+
/** The provider name every span carries. The backing model is never exposed:
|
|
69
|
+
* `gen_ai.request.model` is the opaque YAGNI tier id. */
|
|
70
|
+
export const GEN_AI_PROVIDER = "yagni";
|
|
71
|
+
// ── Span names (Claude Code's beta trace tree, prefixed) ────────────────────
|
|
72
|
+
export const SPAN_INTERACTION = `${PREFIX}.interaction`;
|
|
73
|
+
export const SPAN_TURN = `${PREFIX}.turn`;
|
|
74
|
+
export const SPAN_LLM_REQUEST = `${PREFIX}.llm_request`;
|
|
75
|
+
export const SPAN_TOOL = `${PREFIX}.tool`;
|
|
76
|
+
// ── Metric names (Claude Code's eight counters, prefixed) ───────────────────
|
|
77
|
+
export const METRIC_SESSION_COUNT = `${PREFIX}.session.count`;
|
|
78
|
+
export const METRIC_LINES_OF_CODE = `${PREFIX}.lines_of_code.count`;
|
|
79
|
+
export const METRIC_PULL_REQUEST_COUNT = `${PREFIX}.pull_request.count`;
|
|
80
|
+
export const METRIC_COMMIT_COUNT = `${PREFIX}.commit.count`;
|
|
81
|
+
export const METRIC_COST_USAGE = `${PREFIX}.cost.usage`;
|
|
82
|
+
export const METRIC_TOKEN_USAGE = `${PREFIX}.token.usage`;
|
|
83
|
+
export const METRIC_CODE_EDIT_DECISION = `${PREFIX}.code_edit_tool.decision`;
|
|
84
|
+
export const METRIC_ACTIVE_TIME = `${PREFIX}.active_time.total`;
|
|
85
|
+
// ── Event names (Claude Code's log events, prefixed in the body) ────────────
|
|
86
|
+
export const EVENT_USER_PROMPT = "user_prompt";
|
|
87
|
+
export const EVENT_ASSISTANT_RESPONSE = "assistant_response";
|
|
88
|
+
export const EVENT_TOOL_RESULT = "tool_result";
|
|
89
|
+
export const EVENT_API_REQUEST = "api_request";
|
|
90
|
+
export const EVENT_API_ERROR = "api_error";
|
|
91
|
+
export const EVENT_TOOL_DECISION = "tool_decision";
|
|
92
|
+
export const EVENT_PERMISSION_MODE_CHANGED = "permission_mode_changed";
|
|
93
|
+
/** Cap on any string attribute (Claude Code's 60 KB content limit). */
|
|
94
|
+
const MAX_ATTR_BYTES = 60 * 1024;
|
|
95
|
+
export function clampString(s, max = MAX_ATTR_BYTES) {
|
|
96
|
+
if (Buffer.byteLength(s, "utf8") <= max)
|
|
97
|
+
return s;
|
|
98
|
+
let end = max;
|
|
99
|
+
while (end > 0 && Buffer.byteLength(s.slice(0, end), "utf8") > max - 16)
|
|
100
|
+
end -= 64;
|
|
101
|
+
return `${s.slice(0, Math.max(0, end))}…[truncated]`;
|
|
102
|
+
}
|
|
103
|
+
/** Language label from a file path's extension (Claude Code's `language` attr). */
|
|
104
|
+
export function languageFromPath(path) {
|
|
105
|
+
if (!path)
|
|
106
|
+
return undefined;
|
|
107
|
+
const m = /\.([A-Za-z0-9]+)$/.exec(path);
|
|
108
|
+
if (!m)
|
|
109
|
+
return undefined;
|
|
110
|
+
const ext = m[1].toLowerCase();
|
|
111
|
+
const map = {
|
|
112
|
+
ts: "typescript",
|
|
113
|
+
tsx: "typescript",
|
|
114
|
+
mts: "typescript",
|
|
115
|
+
cts: "typescript",
|
|
116
|
+
js: "javascript",
|
|
117
|
+
jsx: "javascript",
|
|
118
|
+
mjs: "javascript",
|
|
119
|
+
cjs: "javascript",
|
|
120
|
+
py: "python",
|
|
121
|
+
rb: "ruby",
|
|
122
|
+
go: "go",
|
|
123
|
+
rs: "rust",
|
|
124
|
+
java: "java",
|
|
125
|
+
kt: "kotlin",
|
|
126
|
+
swift: "swift",
|
|
127
|
+
c: "c",
|
|
128
|
+
h: "c",
|
|
129
|
+
cc: "cpp",
|
|
130
|
+
cpp: "cpp",
|
|
131
|
+
hpp: "cpp",
|
|
132
|
+
cs: "csharp",
|
|
133
|
+
php: "php",
|
|
134
|
+
sh: "shell",
|
|
135
|
+
bash: "shell",
|
|
136
|
+
zsh: "shell",
|
|
137
|
+
sql: "sql",
|
|
138
|
+
md: "markdown",
|
|
139
|
+
json: "json",
|
|
140
|
+
yaml: "yaml",
|
|
141
|
+
yml: "yaml",
|
|
142
|
+
toml: "toml",
|
|
143
|
+
html: "html",
|
|
144
|
+
css: "css",
|
|
145
|
+
scss: "scss",
|
|
146
|
+
};
|
|
147
|
+
return map[ext] ?? ext;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=attrs.js.map
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry export configuration, resolved from the standard OpenTelemetry
|
|
3
|
+
* environment contract (the same variables Claude Code reads), so a machine
|
|
4
|
+
* or workspace already configured for Claude Code lights up YAGNI Code with
|
|
5
|
+
* no translation.
|
|
6
|
+
*
|
|
7
|
+
* Pure: reads an env record, never the network or disk. The launcher decides
|
|
8
|
+
* WHETHER a session exports (see the CLI's otel.ts: env, workspace settings,
|
|
9
|
+
* or a repo's committed config) and sets `YAGNI_OTEL_EXPORT=1` plus the OTLP
|
|
10
|
+
* variables in the child env; this module turns that env into per-signal
|
|
11
|
+
* exporter settings.
|
|
12
|
+
*
|
|
13
|
+
* Endpoint rules follow the OTLP exporter spec:
|
|
14
|
+
* - a per-signal endpoint (`OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`, …) is used
|
|
15
|
+
* verbatim;
|
|
16
|
+
* - the generic `OTEL_EXPORTER_OTLP_ENDPOINT` is a BASE: http transports
|
|
17
|
+
* append `/v1/<signal>`, gRPC uses it as-is;
|
|
18
|
+
* - nothing configured falls back to the local-collector defaults.
|
|
19
|
+
*
|
|
20
|
+
* Content policy is enforced here, not configurable: prompt and response
|
|
21
|
+
* text never export. `OTEL_LOG_USER_PROMPTS` and `OTEL_LOG_TOOL_DETAILS` are
|
|
22
|
+
* deliberately NOT honored — session content leaving the machine is a
|
|
23
|
+
* contract change, not an env knob.
|
|
24
|
+
*/
|
|
25
|
+
export type OtlpProtocol = "grpc" | "http/protobuf" | "http/json";
|
|
26
|
+
export type Signal = "traces" | "metrics" | "logs";
|
|
27
|
+
export declare const SIGNALS: readonly Signal[];
|
|
28
|
+
export interface SignalConfig {
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
protocol: OtlpProtocol;
|
|
31
|
+
/** The fully resolved URL this signal exports to. */
|
|
32
|
+
url: string;
|
|
33
|
+
headers: Record<string, string>;
|
|
34
|
+
/** Batch / periodic export interval in ms. */
|
|
35
|
+
exportIntervalMs: number;
|
|
36
|
+
}
|
|
37
|
+
export interface TelemetryIdentity {
|
|
38
|
+
/** Bound workspace id (YAGNI_WORKSPACE_ID) → `organization.id`. */
|
|
39
|
+
organizationId?: string;
|
|
40
|
+
/**
|
|
41
|
+
* The signed-in user's email → `user.email`. From `YAGNI_USER_EMAIL` when
|
|
42
|
+
* the launcher forwards it; otherwise learned from the /context boot fetch
|
|
43
|
+
* (`TelemetryHandle.setUserEmail`). Gated by `includeAccountId`.
|
|
44
|
+
*/
|
|
45
|
+
userEmail?: string;
|
|
46
|
+
/** Shipping CLI version (YAGNI_CODE_VERSION) → `app.version`. */
|
|
47
|
+
appVersion?: string;
|
|
48
|
+
/** Detected terminal (TERM_PROGRAM / TMUX) → `terminal.type`. */
|
|
49
|
+
terminalType?: string;
|
|
50
|
+
/** `cli` for an interactive launch, `sdk-cli` for a headless /go run. */
|
|
51
|
+
entrypoint: "cli" | "sdk-cli";
|
|
52
|
+
}
|
|
53
|
+
export interface TelemetryConfig {
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
serviceName: string;
|
|
56
|
+
serviceVersion?: string;
|
|
57
|
+
/** OTEL_RESOURCE_ATTRIBUTES, decoded. Applied to the resource and (by
|
|
58
|
+
* default) to every metric and event. */
|
|
59
|
+
resourceAttributes: Record<string, string>;
|
|
60
|
+
traces: SignalConfig;
|
|
61
|
+
metrics: SignalConfig;
|
|
62
|
+
logs: SignalConfig;
|
|
63
|
+
metricsTemporality: "delta" | "cumulative";
|
|
64
|
+
/** Cardinality controls (Claude Code parity). */
|
|
65
|
+
includeSessionId: boolean;
|
|
66
|
+
includeVersion: boolean;
|
|
67
|
+
includeAccountId: boolean;
|
|
68
|
+
includeResourceAttributes: boolean;
|
|
69
|
+
includeEntrypoint: boolean;
|
|
70
|
+
identity: TelemetryIdentity;
|
|
71
|
+
}
|
|
72
|
+
export declare const DEFAULT_SERVICE_NAME = "yagni-code";
|
|
73
|
+
type Env = Record<string, string | undefined>;
|
|
74
|
+
export declare function normalizeProtocol(p: string | undefined): OtlpProtocol | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* Parse a `k=v,k2=v2` list (OTEL_EXPORTER_OTLP_HEADERS / OTEL_RESOURCE_ATTRIBUTES).
|
|
77
|
+
* Values may be percent-encoded per the W3C baggage rules the spec references;
|
|
78
|
+
* a malformed escape keeps the raw value. Splits on the FIRST `=` only so a
|
|
79
|
+
* base64 value's trailing `==` survives.
|
|
80
|
+
*/
|
|
81
|
+
export declare function parseKvList(s: string | undefined): Record<string, string>;
|
|
82
|
+
/**
|
|
83
|
+
* Reduce an endpoint that carries a signal path to its base
|
|
84
|
+
* (`https://otlp.datadoghq.com/v1/traces` → `https://otlp.datadoghq.com`).
|
|
85
|
+
* Pre-parity workspace configs stored the full trace URL; treating it as a
|
|
86
|
+
* base keeps them exporting all three signals without an admin re-save.
|
|
87
|
+
*/
|
|
88
|
+
export declare function stripSignalPath(endpoint: string): string;
|
|
89
|
+
/**
|
|
90
|
+
* Resolve one signal's URL from the env, per the OTLP exporter spec.
|
|
91
|
+
* Exported for the launcher's doctor so its report names the exact URL a
|
|
92
|
+
* session will post to.
|
|
93
|
+
*/
|
|
94
|
+
export declare function resolveSignalUrl(env: Env, signal: Signal, protocol: OtlpProtocol): string;
|
|
95
|
+
/** Personal kill switch, beats every other source (both spellings accepted). */
|
|
96
|
+
export declare function telemetryDisabled(env: Env): boolean;
|
|
97
|
+
/** The launcher's "this session exports" gate. */
|
|
98
|
+
export declare const OTEL_EXPORT_ENV = "YAGNI_OTEL_EXPORT";
|
|
99
|
+
export declare function resolveTelemetryConfig(env?: Env): TelemetryConfig;
|
|
100
|
+
/** Signals this config will actually export (for doctor / status lines). */
|
|
101
|
+
export declare function enabledSignals(config: TelemetryConfig): Signal[];
|
|
102
|
+
export {};
|
|
103
|
+
//# sourceMappingURL=config.d.ts.map
|