@yagni-app/code 1.0.6 → 1.0.7
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 +84 -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/condensedTools.d.ts +12 -1
- package/dist/extension/condensedTools.js +17 -9
- package/dist/extension/index.d.ts +13 -0
- package/dist/extension/index.js +230 -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 +97 -2
- package/dist/extension/permission/gate.js +375 -26
- 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 +53 -0
- package/dist/extension/permissionRules/loadConfig.js +90 -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 +58 -0
- package/dist/extension/permissionRules/pathRules.js +120 -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 +114 -0
- package/dist/extension/sandbox/config.js +366 -0
- package/dist/extension/sandbox/manager.d.ts +98 -0
- package/dist/extension/sandbox/manager.js +216 -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 +775 -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 +99 -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 +40 -0
- package/dist/extension/telemetry/register.js +192 -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/package.json +19 -3
package/dist/goHeadless.d.ts
CHANGED
|
@@ -65,7 +65,7 @@ export declare function buildHeadlessChildEnv(opts: {
|
|
|
65
65
|
workspaceId?: string;
|
|
66
66
|
cliVersion?: string;
|
|
67
67
|
sessionId?: string;
|
|
68
|
-
/** Resolved OTel export config; stage children
|
|
68
|
+
/** Resolved OTel export config; stage children export when present. */
|
|
69
69
|
otel?: OtelLaunchConfig;
|
|
70
70
|
}): NodeJS.ProcessEnv;
|
|
71
71
|
/**
|
package/dist/goHeadless.js
CHANGED
|
@@ -55,8 +55,8 @@ export function buildHeadlessChildEnv(opts) {
|
|
|
55
55
|
PI_CODING_AGENT_DIR: piAgentDir,
|
|
56
56
|
PI_SKIP_VERSION_CHECK: "1",
|
|
57
57
|
PI_TELEMETRY: "0",
|
|
58
|
-
// OTel export:
|
|
59
|
-
//
|
|
58
|
+
// OTel export: the gate plus the OTLP env, inherited by every stage child
|
|
59
|
+
// (see otel.ts for the policy).
|
|
60
60
|
...(opts.otel ? otelChildEnv(opts.otel, opts.baseEnv) : {}),
|
|
61
61
|
};
|
|
62
62
|
}
|
package/dist/launch.d.ts
CHANGED
|
@@ -95,9 +95,10 @@ export interface BuildLaunchOptions {
|
|
|
95
95
|
extraEnv?: Record<string, string>;
|
|
96
96
|
/**
|
|
97
97
|
* Resolved OTel export config (see `otel.ts`). When present, the session
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* byte-for-byte what it was
|
|
98
|
+
* env carries the export gate and the OTLP variables and the bundled
|
|
99
|
+
* extension exports traces, metrics, and log events; absent means no OTLP
|
|
100
|
+
* endpoint is configured and the launch is byte-for-byte what it was
|
|
101
|
+
* before OTel support existed.
|
|
101
102
|
*/
|
|
102
103
|
otel?: OtelLaunchConfig;
|
|
103
104
|
}
|
package/dist/launch.js
CHANGED
|
@@ -9,6 +9,7 @@ import { randomUUID } from "node:crypto";
|
|
|
9
9
|
import { agentDirEnvVar } from "./branding.js";
|
|
10
10
|
import { otelChildEnv } from "./otel.js";
|
|
11
11
|
import { PAD_X_ENV, resolvePadX } from "./padding.js";
|
|
12
|
+
import { resolveCliPath } from "./paths.js";
|
|
12
13
|
import { ENGINEERING_PRACTICE_SECTION, promptEnrichmentDisabled } from "./promptEnrichment.js";
|
|
13
14
|
/**
|
|
14
15
|
* How close to expiry the token can be before launch warns. A coding session
|
|
@@ -76,6 +77,9 @@ export function buildLaunch(creds, passthroughArgs, opts) {
|
|
|
76
77
|
// the launcher read (0600). Absent when the caller can't resolve it.
|
|
77
78
|
...(opts.profilePath ? { YAGNI_PROFILE_PATH: opts.profilePath } : {}),
|
|
78
79
|
...(opts.stateDir ? { YAGNI_CODE_HOME: opts.stateDir } : {}),
|
|
80
|
+
// The launcher's own entry, so the in-session /plugin panel and
|
|
81
|
+
// /reload-plugins can run `yagni plugin …` with the same binary.
|
|
82
|
+
YAGNI_CLI_PATH: resolveCliPath(),
|
|
79
83
|
// Forward the launcher's version so the extension's crash reports carry
|
|
80
84
|
// the shipping version (the bundled extension has no package.json to read).
|
|
81
85
|
...(opts.cliVersion ? { YAGNI_CODE_VERSION: opts.cliVersion } : {}),
|
|
@@ -106,9 +110,9 @@ export function buildLaunch(creds, passthroughArgs, opts) {
|
|
|
106
110
|
// the editor (which the launcher pads by seeding editorPaddingX). The
|
|
107
111
|
// footer can't read pi's settings, so the value crosses over env.
|
|
108
112
|
[PAD_X_ENV]: String(resolvePadX()),
|
|
109
|
-
// OTel export (gated in otel.ts):
|
|
110
|
-
//
|
|
111
|
-
//
|
|
113
|
+
// OTel export (gated in otel.ts): the YAGNI_OTEL_EXPORT gate plus the
|
|
114
|
+
// workspace's OTLP env; the bundled extension does the exporting, and
|
|
115
|
+
// /go stage children and subagents inherit this env so they export too.
|
|
112
116
|
...(opts.otel ? otelChildEnv(opts.otel, opts.baseEnv ?? {}) : {}),
|
|
113
117
|
};
|
|
114
118
|
// Always load our extension. Default the provider to `yagni` unless the user
|
|
@@ -130,7 +134,6 @@ export function buildLaunch(creds, passthroughArgs, opts) {
|
|
|
130
134
|
const argv = [
|
|
131
135
|
"-e",
|
|
132
136
|
opts.extensionPath,
|
|
133
|
-
...(opts.otel ? ["-e", opts.otel.extensionPath] : []),
|
|
134
137
|
...(userChoseProvider ? [] : ["--provider", "yagni"]),
|
|
135
138
|
...(userChoseModel ? [] : ["--model", "advanced"]),
|
|
136
139
|
...(enrichmentOff ? [] : ["--append-system-prompt", ENGINEERING_PRACTICE_SECTION]),
|
package/dist/mcpCommand.d.ts
CHANGED
|
@@ -22,6 +22,12 @@ export interface McpDeps {
|
|
|
22
22
|
stderr?: (text: string) => void;
|
|
23
23
|
/** Test seam: the extension module to import (defaults to the built copy). */
|
|
24
24
|
loadMcpModule?: () => Promise<McpCliModule>;
|
|
25
|
+
/**
|
|
26
|
+
* Test seam: the plugin MCP payload the launcher would hand a session
|
|
27
|
+
* (defaults to running the real, non-interactive discovery). Lets `list`
|
|
28
|
+
* and `get` show plugin-bundled servers outside a session.
|
|
29
|
+
*/
|
|
30
|
+
pluginMcpEnv?: () => Promise<string | undefined>;
|
|
25
31
|
/** Test seam: health probe override (defaults to mod.probeServer). */
|
|
26
32
|
probeServer?: (name: string, config: unknown, opts?: {
|
|
27
33
|
env?: NodeJS.ProcessEnv;
|
|
@@ -73,12 +79,15 @@ export interface McpCliModule {
|
|
|
73
79
|
missingVars: string[];
|
|
74
80
|
};
|
|
75
81
|
}
|
|
82
|
+
export type McpListScope = "user" | "project" | "local" | "plugin";
|
|
76
83
|
export interface McpLoadResult {
|
|
77
84
|
servers: {
|
|
78
85
|
name: string;
|
|
79
|
-
scope:
|
|
86
|
+
scope: McpListScope;
|
|
80
87
|
config: Record<string, unknown>;
|
|
81
88
|
sourcePath: string;
|
|
89
|
+
plugin?: string;
|
|
90
|
+
gated?: boolean;
|
|
82
91
|
}[];
|
|
83
92
|
errors: {
|
|
84
93
|
sourcePath: string;
|
package/dist/mcpCommand.js
CHANGED
|
@@ -18,7 +18,10 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
18
18
|
import { homedir } from "node:os";
|
|
19
19
|
import { join } from "node:path";
|
|
20
20
|
import { fileURLToPath } from "node:url";
|
|
21
|
+
import { CLAUDE_PLUGIN_MCP_ENV, claudeCompatArgs } from "./claudeCompat.js";
|
|
22
|
+
import { agentDir } from "./credentials.js";
|
|
21
23
|
import { DISTRIBUTION } from "./distribution.js";
|
|
24
|
+
import { getActiveProfileName } from "./profiles.js";
|
|
22
25
|
export function resolveMcpConfigPath() {
|
|
23
26
|
const bundled = fileURLToPath(new URL("./extension/mcp/cliConfig.js", import.meta.url));
|
|
24
27
|
if (existsSync(bundled))
|
|
@@ -229,6 +232,25 @@ function describeScopePath(scope, cwd) {
|
|
|
229
232
|
return join(cwd, ".mcp.json");
|
|
230
233
|
return "~/.yagni-code/mcp.json";
|
|
231
234
|
}
|
|
235
|
+
/** The plugin MCP payload for `cwd`, computed the way a launch would (trust respected, never prompting). */
|
|
236
|
+
async function defaultPluginMcpEnv(cwd) {
|
|
237
|
+
try {
|
|
238
|
+
const profile = await getActiveProfileName();
|
|
239
|
+
const compat = await claudeCompatArgs({ cwd, agentDir: agentDir(profile), interactive: false });
|
|
240
|
+
return compat.env[CLAUDE_PLUGIN_MCP_ENV];
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/** `list`/`get` see plugin servers even outside a session: merge the payload into the env they load with. */
|
|
247
|
+
async function envWithPluginMcp(deps, cwd) {
|
|
248
|
+
const base = deps.env ?? process.env;
|
|
249
|
+
if (base[CLAUDE_PLUGIN_MCP_ENV])
|
|
250
|
+
return base;
|
|
251
|
+
const payload = await (deps.pluginMcpEnv ?? defaultPluginMcpEnv)(cwd);
|
|
252
|
+
return payload ? { ...base, [CLAUDE_PLUGIN_MCP_ENV]: payload } : base;
|
|
253
|
+
}
|
|
232
254
|
export async function mcpCommand(args, deps = {}) {
|
|
233
255
|
const stdout = deps.stdout ?? ((t) => process.stdout.write(t));
|
|
234
256
|
const stderr = deps.stderr ?? ((t) => process.stderr.write(t));
|
|
@@ -261,9 +283,9 @@ export async function mcpCommand(args, deps = {}) {
|
|
|
261
283
|
case "remove":
|
|
262
284
|
return mcpRemove(mod, parsed, { cwd, stdout, stderr });
|
|
263
285
|
case "list":
|
|
264
|
-
return mcpList(mod, { cwd, stdout, stderr, env: deps
|
|
286
|
+
return mcpList(mod, { cwd, stdout, stderr, env: await envWithPluginMcp(deps, cwd), probeServer: deps.probeServer });
|
|
265
287
|
case "get":
|
|
266
|
-
return mcpGet(mod, parsed, { cwd, stdout, stderr, env: deps
|
|
288
|
+
return mcpGet(mod, parsed, { cwd, stdout, stderr, env: await envWithPluginMcp(deps, cwd), probeServer: deps.probeServer });
|
|
267
289
|
case "reset-project-choices":
|
|
268
290
|
return mcpResetChoices(mod, { cwd, stdout, stderr });
|
|
269
291
|
case "add-from-claude":
|
|
@@ -548,6 +570,8 @@ async function mcpGet(mod, parsed, io) {
|
|
|
548
570
|
}
|
|
549
571
|
io.stdout(`${name}:\n`);
|
|
550
572
|
io.stdout(` Scope: ${scopeLabel(server.scope)}\n`);
|
|
573
|
+
if (server.plugin)
|
|
574
|
+
io.stdout(` Plugin: ${server.plugin}\n`);
|
|
551
575
|
const config = server.config;
|
|
552
576
|
if (config["type"] === "http" || config["type"] === "sse") {
|
|
553
577
|
io.stdout(` Type: ${config["type"]}\n`);
|
|
@@ -567,14 +591,19 @@ async function mcpGet(mod, parsed, io) {
|
|
|
567
591
|
io.stdout(` Env: ${key}=${value}\n`);
|
|
568
592
|
}
|
|
569
593
|
}
|
|
570
|
-
if (server.scope === "project") {
|
|
594
|
+
if (server.scope === "project" || server.gated) {
|
|
571
595
|
const { state } = mod.readProjectApproval(mod.resolveProjectRoot(io.cwd));
|
|
572
596
|
const decision = mod.decisionFor(state, name);
|
|
573
597
|
io.stdout(` Approved: ${decision === "enabled" ? "yes" : decision === "disabled" ? "no" : "not yet decided"}\n`);
|
|
574
598
|
}
|
|
575
599
|
io.stdout(` Config file: ${server.sourcePath}\n`);
|
|
576
600
|
io.stdout(await healthLine(mod, server, io));
|
|
577
|
-
|
|
601
|
+
if (server.scope === "plugin") {
|
|
602
|
+
io.stdout(`\nThis server is bundled with plugin ${server.plugin}; remove it with: ${DISTRIBUTION.commandName} plugin uninstall "${server.plugin}"\n`);
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
io.stdout(`\nTo remove this server, run: ${DISTRIBUTION.commandName} mcp remove "${name}"\n`);
|
|
606
|
+
}
|
|
578
607
|
return 0;
|
|
579
608
|
}
|
|
580
609
|
function printOAuthDetail(mod, name, config, stdout) {
|
|
@@ -590,7 +619,7 @@ function printOAuthDetail(mod, name, config, stdout) {
|
|
|
590
619
|
async function healthLine(mod, server, io) {
|
|
591
620
|
// Approval gate: an undecided/disabled project server is reported WITHOUT
|
|
592
621
|
// connecting (fail-closed — never spawn an unapproved process).
|
|
593
|
-
if (server.scope === "project") {
|
|
622
|
+
if (server.scope === "project" || server.gated) {
|
|
594
623
|
const { state } = mod.readProjectApproval(mod.resolveProjectRoot(io.cwd));
|
|
595
624
|
const decision = mod.decisionFor(state, server.name);
|
|
596
625
|
if (decision === "disabled")
|
|
@@ -613,17 +642,18 @@ async function mcpList(mod, io) {
|
|
|
613
642
|
return 0;
|
|
614
643
|
}
|
|
615
644
|
const lines = [];
|
|
616
|
-
const byScope = { user: [], project: [], local: [] };
|
|
645
|
+
const byScope = { user: [], project: [], local: [], plugin: [] };
|
|
617
646
|
for (const s of servers)
|
|
618
647
|
(byScope[s.scope] ??= []).push(s);
|
|
619
|
-
|
|
648
|
+
const labels = { local: "Local", project: "Project", user: "User", plugin: "Plugin" };
|
|
649
|
+
for (const scope of ["local", "project", "user", "plugin"]) {
|
|
620
650
|
const group = byScope[scope];
|
|
621
651
|
if (!group?.length)
|
|
622
652
|
continue;
|
|
623
|
-
lines.push(`${scope
|
|
653
|
+
lines.push(`${labels[scope]} servers:`);
|
|
624
654
|
for (const s of group) {
|
|
625
655
|
const status = await listHealthLine(mod, s, io);
|
|
626
|
-
lines.push(` ${s.name} · ${status}`);
|
|
656
|
+
lines.push(` ${s.name}${s.plugin ? ` (${s.plugin})` : ""} · ${status}`);
|
|
627
657
|
}
|
|
628
658
|
}
|
|
629
659
|
for (const err of errors)
|
|
@@ -634,7 +664,7 @@ async function mcpList(mod, io) {
|
|
|
634
664
|
return 0;
|
|
635
665
|
}
|
|
636
666
|
async function listHealthLine(mod, server, io) {
|
|
637
|
-
if (server.scope === "project") {
|
|
667
|
+
if (server.scope === "project" || server.gated) {
|
|
638
668
|
const { state } = mod.readProjectApproval(mod.resolveProjectRoot(io.cwd));
|
|
639
669
|
const decision = mod.decisionFor(state, server.name);
|
|
640
670
|
if (decision === "disabled")
|
|
@@ -654,6 +684,8 @@ function scopeLabel(scope) {
|
|
|
654
684
|
return "Local config (private to you in this project)";
|
|
655
685
|
if (scope === "project")
|
|
656
686
|
return "Project config (shared via .mcp.json)";
|
|
687
|
+
if (scope === "plugin")
|
|
688
|
+
return "Plugin (bundled with an installed plugin)";
|
|
657
689
|
return "User config (available in all your projects)";
|
|
658
690
|
}
|
|
659
691
|
function mcpResetChoices(mod, io) {
|
package/dist/otel.d.ts
CHANGED
|
@@ -1,69 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OTel export
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* OTel export gate (Updater pilot ask, now Claude Code parity): decide
|
|
3
|
+
* whether a launch streams session telemetry — traces, metrics, and log
|
|
4
|
+
* events — to the workspace's own OTLP collector (Datadog, Grafana, an
|
|
5
|
+
* in-house collector), and hand the session the standard OpenTelemetry env
|
|
6
|
+
* it needs. The exporter itself lives in the bundled extension
|
|
7
|
+
* (`pi-extension-yagni/src/telemetry`), so there is nothing extra to load and
|
|
8
|
+
* nothing that can go missing on a customer's `npm install`.
|
|
6
9
|
*
|
|
7
|
-
* Three deliberate policies,
|
|
10
|
+
* Three deliberate policies, enforced here rather than left to defaults:
|
|
8
11
|
*
|
|
9
|
-
* 1. GATED, not always-on.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* 1. GATED, not always-on. Nothing exports unless an OTLP destination is
|
|
13
|
+
* configured: the user's own OTEL_* env, the workspace's admin-set config
|
|
14
|
+
* (fetched fail-soft and cached), or the repo's committed
|
|
15
|
+
* `.pi/settings.json`. The gate result travels to the session as
|
|
16
|
+
* `YAGNI_OTEL_EXPORT=1` plus the OTLP variables; children (/go stages,
|
|
17
|
+
* subagents) inherit the env and export too.
|
|
15
18
|
*
|
|
16
|
-
* 2. METADATA-ONLY,
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* precedence — a repo settings file asking for "full" is overridden, not
|
|
20
|
-
* honored. Session content leaving the machine is a contract change, not a
|
|
21
|
-
* config knob.
|
|
19
|
+
* 2. METADATA-ONLY, in code. Token counts, cost, tier, durations, tool names,
|
|
20
|
+
* and sizes export; prompt, response, and tool content never do. The
|
|
21
|
+
* extension enforces this without a knob — no env var re-enables content.
|
|
22
22
|
*
|
|
23
|
-
* 3. Cost is the customer's SELL rate.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* exported model name is the opaque tier id, never the backing model.
|
|
23
|
+
* 3. Cost is the customer's SELL rate. Usage cost is pi's `usage.cost.total`,
|
|
24
|
+
* computed from the catalog's tier rates (YAG-381), and the exported model
|
|
25
|
+
* name is the opaque tier id, never the backing model.
|
|
27
26
|
*
|
|
28
|
-
* Everything here is fail-soft: telemetry must never block a launch, so
|
|
29
|
-
*
|
|
27
|
+
* Everything here is fail-soft: telemetry must never block a launch, so an
|
|
28
|
+
* unreadable settings file or an offline backend resolves to "disabled" or
|
|
29
|
+
* to last-known config.
|
|
30
30
|
*/
|
|
31
31
|
import { readFileSync } from "node:fs";
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
* subagents: they build their own pi argv inside pi-extension-yagni (which
|
|
35
|
-
* cannot import this package), so the path crosses over env. The extension
|
|
36
|
-
* reads the same literal in `pipeline/runner.ts`.
|
|
37
|
-
*/
|
|
38
|
-
export declare const OTEL_EXTENSION_PATH_ENV = "YAGNI_OTEL_EXTENSION_PATH";
|
|
32
|
+
/** The launcher's "this session exports" gate, read by the bundled extension. */
|
|
33
|
+
export declare const OTEL_EXPORT_ENV = "YAGNI_OTEL_EXPORT";
|
|
39
34
|
/** The service name a collector sees unless the user set their own. */
|
|
40
35
|
export declare const DEFAULT_OTEL_SERVICE_NAME = "yagni-code";
|
|
36
|
+
/** The standard per-signal endpoint variables, generic first (its precedence). */
|
|
37
|
+
declare const ENDPOINT_ENV_VARS: readonly ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT", "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"];
|
|
38
|
+
export type EndpointEnvVar = (typeof ENDPOINT_ENV_VARS)[number];
|
|
41
39
|
export interface OtelLaunchConfig {
|
|
42
|
-
/** Absolute path to pi-otel's extension entry. */
|
|
43
|
-
extensionPath: string;
|
|
44
40
|
/**
|
|
45
|
-
* Where the enablement signal came from. "workspace"
|
|
46
|
-
* protocol/headers/serviceName
|
|
47
|
-
*
|
|
48
|
-
* `OTEL_EXPORTER_OTLP_TRACES_(ENDPOINT|PROTOCOL)` bridge (pi-otel reads only
|
|
49
|
-
* the generic var, so the child env translates); "project-settings" leaves
|
|
50
|
-
* those to whatever the user/repo already configured.
|
|
41
|
+
* Where the enablement signal came from. "workspace" and "project-settings"
|
|
42
|
+
* carry endpoint/protocol/headers/serviceName that the launcher delivers as
|
|
43
|
+
* env; "env" is the user's own setup, passed through untouched.
|
|
51
44
|
*/
|
|
52
45
|
source: "env" | "workspace" | "project-settings";
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
* `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`. Doctor surfaces it so a user who set
|
|
57
|
-
* the per-signal var sees their own var named, not the generic one.
|
|
58
|
-
*/
|
|
59
|
-
envVar?: "OTEL_EXPORTER_OTLP_ENDPOINT" | "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT";
|
|
60
|
-
/** The configured OTLP endpoint (for doctor display; env for workspace source). */
|
|
46
|
+
/** The env var the endpoint came from (env source only; doctor names it). */
|
|
47
|
+
envVar?: EndpointEnvVar;
|
|
48
|
+
/** The configured endpoint: a BASE URL for workspace/project sources. */
|
|
61
49
|
endpoint: string;
|
|
62
|
-
/** OTLP protocol: workspace config, or a per-signal env bridge. */
|
|
63
50
|
protocol?: string;
|
|
64
|
-
/**
|
|
51
|
+
/** Collector headers (workspace / project sources; carries secrets). */
|
|
65
52
|
headers?: Record<string, string>;
|
|
66
|
-
/** Workspace-configured service name (workspace source only). */
|
|
67
53
|
serviceName?: string;
|
|
68
54
|
}
|
|
69
55
|
/**
|
|
@@ -79,51 +65,44 @@ export interface WorkspaceOtelConfig {
|
|
|
79
65
|
headers?: Record<string, string>;
|
|
80
66
|
}
|
|
81
67
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
68
|
+
* Reduce an endpoint that carries a signal path to its base
|
|
69
|
+
* (`https://otlp.datadoghq.com/v1/traces` → `https://otlp.datadoghq.com`).
|
|
70
|
+
* The extension appends `/v1/<signal>` per signal for http transports, so a
|
|
71
|
+
* workspace config saved before logs and metrics existed keeps exporting all
|
|
72
|
+
* three without an admin re-save. Mirrors the extension's own helper.
|
|
73
|
+
*/
|
|
74
|
+
export declare function stripSignalPath(endpoint: string): string;
|
|
75
|
+
/** Personal kill switch: beats every source. Both spellings accepted. */
|
|
76
|
+
export declare function envDisabled(env: NodeJS.ProcessEnv): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Decide whether this launch exports, from the user's env and the repo's
|
|
79
|
+
* settings. Returns undefined when export stays off: no endpoint configured,
|
|
80
|
+
* or a kill switch set.
|
|
85
81
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* over the same way. Logs/metrics per-signal vars are deliberately NOT read:
|
|
92
|
-
* sessions export traces only, and pi-otel's metrics/logs signals are opt-in
|
|
93
|
-
* elsewhere.
|
|
82
|
+
* Any of the standard endpoint variables enables export — the generic
|
|
83
|
+
* `OTEL_EXPORTER_OTLP_ENDPOINT` or a per-signal one — so a machine that
|
|
84
|
+
* carries a Claude Code telemetry env (typically all three per-signal
|
|
85
|
+
* endpoints) lights up with no translation. The extension reads the same
|
|
86
|
+
* variables, per signal, following the OTLP exporter spec.
|
|
94
87
|
*/
|
|
95
88
|
export declare function resolveOtelLaunch(opts: {
|
|
96
89
|
env: NodeJS.ProcessEnv;
|
|
97
90
|
cwd: string;
|
|
98
|
-
/** Injectable
|
|
99
|
-
resolveExtension?: () => string;
|
|
91
|
+
/** Injectable seam for tests. */
|
|
100
92
|
readFile?: typeof readFileSync;
|
|
101
93
|
}): OtelLaunchConfig | undefined;
|
|
102
|
-
/** Absolute path to pi-otel's extension entry (its package main IS the pi
|
|
103
|
-
* extension entry, `dist/index.js`). Resolved ESM-native like `paths.ts` does
|
|
104
|
-
* for pi itself. Throws when the package is missing — callers treat that as
|
|
105
|
-
* "export off", not an error.
|
|
106
|
-
*/
|
|
107
|
-
export declare function resolveOtelExtensionPath(): string;
|
|
108
|
-
/**
|
|
109
|
-
* TCP reachability probe for an OTLP endpoint URL, with scheme-default ports:
|
|
110
|
-
* WHATWG `URL` strips `:443`/`:80` as defaults, so an https endpoint with no
|
|
111
|
-
* port probes 443 (the agentless SaaS shape). Returns false on any parse or
|
|
112
|
-
* connect failure — reachability is advisory, never fatal. Mirrors the probe
|
|
113
|
-
* inside (patched) pi-otel but lives here so `doctor` can use it without
|
|
114
|
-
* importing the extension's SDK graph.
|
|
115
|
-
*/
|
|
116
|
-
export declare function probeOtelEndpoint(endpoint: string, timeoutMs?: number): Promise<boolean>;
|
|
117
94
|
/**
|
|
118
|
-
* The env keys an
|
|
119
|
-
*
|
|
120
|
-
*
|
|
95
|
+
* The env keys an exporting child must carry. `YAGNI_OTEL_EXPORT=1` is the
|
|
96
|
+
* gate the extension reads; the service name only fills in when the user has
|
|
97
|
+
* not chosen their own.
|
|
121
98
|
*
|
|
122
|
-
* A "workspace"-
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
99
|
+
* A "workspace" or "project-settings" config delivers its endpoint (as the
|
|
100
|
+
* generic BASE endpoint — the extension derives the per-signal URLs),
|
|
101
|
+
* protocol, headers, and service name over the standard OTel env vars — but
|
|
102
|
+
* any of those the USER already set in their own environment wins (local
|
|
103
|
+
* env > workspace config), so an engineer can point one session at a
|
|
104
|
+
* scratch collector without an admin change. An "env" config is the user's
|
|
105
|
+
* own setup and passes through untouched.
|
|
127
106
|
*/
|
|
128
107
|
export declare function otelChildEnv(config: OtelLaunchConfig, baseEnv: NodeJS.ProcessEnv): Record<string, string>;
|
|
129
108
|
export interface WorkspaceOtelFetchDeps {
|
|
@@ -154,10 +133,8 @@ export declare function fetchWorkspaceOtel(creds: {
|
|
|
154
133
|
/**
|
|
155
134
|
* Full launch-time resolution, all four sources in precedence order:
|
|
156
135
|
*
|
|
157
|
-
* 1. `PI_OTEL_DISABLED`
|
|
158
|
-
* 2. env `
|
|
159
|
-
* — the user's own setup, untouched (generic wins
|
|
160
|
-
* over per-signal).
|
|
136
|
+
* 1. `PI_OTEL_DISABLED` / `YAGNI_OTEL_DISABLED` — personal kill switch.
|
|
137
|
+
* 2. env `OTEL_EXPORTER_OTLP_*_ENDPOINT` — the user's own setup, untouched.
|
|
161
138
|
* 3. workspace config — admin-set in the web app, fetched/cached.
|
|
162
139
|
* 4. repo `.pi/settings.json` — committed per-repo config.
|
|
163
140
|
*
|
|
@@ -171,9 +148,9 @@ export declare function resolveOtelLaunchWithWorkspace(opts: {
|
|
|
171
148
|
token: string;
|
|
172
149
|
} | null;
|
|
173
150
|
profileName?: string;
|
|
174
|
-
resolveExtension?: () => string;
|
|
175
151
|
readFile?: typeof readFileSync;
|
|
176
152
|
fetchDeps?: WorkspaceOtelFetchDeps;
|
|
177
153
|
fetchWorkspace?: typeof fetchWorkspaceOtel;
|
|
178
154
|
}): Promise<OtelLaunchConfig | undefined>;
|
|
155
|
+
export {};
|
|
179
156
|
//# sourceMappingURL=otel.d.ts.map
|