@newrelic/preflight 1.67.3 → 1.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/config.d.ts +75 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +201 -22
- package/dist/config.js.map +1 -1
- package/dist/dashboard/routes/api-handler.d.ts +1 -0
- package/dist/dashboard/routes/api-handler.d.ts.map +1 -1
- package/dist/dashboard/routes/api-handler.js +120 -94
- package/dist/dashboard/routes/api-handler.js.map +1 -1
- package/dist/data/dashboards/ai-coding-assistant-adoption-cost.json +291 -1
- package/dist/data/dashboards/ai-coding-assistant-team-view.json +6 -6
- package/dist/hooks/billed-turn-ledger.d.ts +46 -0
- package/dist/hooks/billed-turn-ledger.d.ts.map +1 -0
- package/dist/hooks/billed-turn-ledger.js +274 -0
- package/dist/hooks/billed-turn-ledger.js.map +1 -0
- package/dist/hooks/collector-script.d.ts.map +1 -1
- package/dist/hooks/collector-script.js +5 -1
- package/dist/hooks/collector-script.js.map +1 -1
- package/dist/hooks/event-processor.d.ts +3 -7
- package/dist/hooks/event-processor.d.ts.map +1 -1
- package/dist/hooks/event-processor.js +21 -7
- package/dist/hooks/event-processor.js.map +1 -1
- package/dist/hooks/parent-transcript-watcher.d.ts +6 -5
- package/dist/hooks/parent-transcript-watcher.d.ts.map +1 -1
- package/dist/hooks/parent-transcript-watcher.js +64 -62
- package/dist/hooks/parent-transcript-watcher.js.map +1 -1
- package/dist/hooks/throttled-warning.d.ts +16 -0
- package/dist/hooks/throttled-warning.d.ts.map +1 -0
- package/dist/hooks/throttled-warning.js +32 -0
- package/dist/hooks/throttled-warning.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +90 -83
- package/dist/index.js.map +1 -1
- package/dist/install/cli.d.ts.map +1 -1
- package/dist/install/cli.js +69 -1
- package/dist/install/cli.js.map +1 -1
- package/dist/install/dashboard-health.js +1 -1
- package/dist/install/dashboard-health.js.map +1 -1
- package/dist/install/diagnostics.d.ts +2 -0
- package/dist/install/diagnostics.d.ts.map +1 -1
- package/dist/install/diagnostics.js +132 -28
- package/dist/install/diagnostics.js.map +1 -1
- package/dist/install/headless-install.d.ts +26 -0
- package/dist/install/headless-install.d.ts.map +1 -1
- package/dist/install/headless-install.js +44 -1
- package/dist/install/headless-install.js.map +1 -1
- package/dist/install/install-helper.d.ts +2 -0
- package/dist/install/install-helper.d.ts.map +1 -1
- package/dist/install/install-helper.js +5 -0
- package/dist/install/install-helper.js.map +1 -1
- package/dist/install/keychain.d.ts +18 -0
- package/dist/install/keychain.d.ts.map +1 -0
- package/dist/install/keychain.js +60 -0
- package/dist/install/keychain.js.map +1 -0
- package/dist/install/kiro-install-helper.d.ts +27 -0
- package/dist/install/kiro-install-helper.d.ts.map +1 -0
- package/dist/install/kiro-install-helper.js +53 -0
- package/dist/install/kiro-install-helper.js.map +1 -0
- package/dist/install/setup-wizard.d.ts +4 -0
- package/dist/install/setup-wizard.d.ts.map +1 -1
- package/dist/install/setup-wizard.js +94 -9
- package/dist/install/setup-wizard.js.map +1 -1
- package/dist/lib/child-env.d.ts +11 -0
- package/dist/lib/child-env.d.ts.map +1 -0
- package/dist/lib/child-env.js +35 -0
- package/dist/lib/child-env.js.map +1 -0
- package/dist/lib/git-remote.d.ts +7 -0
- package/dist/lib/git-remote.d.ts.map +1 -1
- package/dist/lib/git-remote.js +13 -0
- package/dist/lib/git-remote.js.map +1 -1
- package/dist/metrics/cost-tracker-seed.d.ts +16 -0
- package/dist/metrics/cost-tracker-seed.d.ts.map +1 -1
- package/dist/metrics/cost-tracker-seed.js +42 -7
- package/dist/metrics/cost-tracker-seed.js.map +1 -1
- package/dist/metrics/cost-tracker.d.ts +11 -3
- package/dist/metrics/cost-tracker.d.ts.map +1 -1
- package/dist/metrics/cost-tracker.js +4 -1
- package/dist/metrics/cost-tracker.js.map +1 -1
- package/dist/metrics/git-activity-recorder.d.ts +3 -3
- package/dist/metrics/git-activity-recorder.d.ts.map +1 -1
- package/dist/metrics/git-activity-recorder.js +3 -3
- package/dist/metrics/git-activity-recorder.js.map +1 -1
- package/dist/metrics/git-workspace-identity.d.ts +6 -1
- package/dist/metrics/git-workspace-identity.d.ts.map +1 -1
- package/dist/metrics/git-workspace-identity.js +56 -32
- package/dist/metrics/git-workspace-identity.js.map +1 -1
- package/dist/metrics/git-workspace-reporter.d.ts +4 -3
- package/dist/metrics/git-workspace-reporter.d.ts.map +1 -1
- package/dist/metrics/git-workspace-reporter.js +4 -3
- package/dist/metrics/git-workspace-reporter.js.map +1 -1
- package/dist/metrics/pricing-init.d.ts +13 -0
- package/dist/metrics/pricing-init.d.ts.map +1 -0
- package/dist/metrics/pricing-init.js +19 -0
- package/dist/metrics/pricing-init.js.map +1 -0
- package/dist/metrics/skill-activation-tracker.d.ts +27 -0
- package/dist/metrics/skill-activation-tracker.d.ts.map +1 -0
- package/dist/metrics/skill-activation-tracker.js +92 -0
- package/dist/metrics/skill-activation-tracker.js.map +1 -0
- package/dist/metrics/turn-cost-attributor.d.ts +34 -16
- package/dist/metrics/turn-cost-attributor.d.ts.map +1 -1
- package/dist/metrics/turn-cost-attributor.js +95 -60
- package/dist/metrics/turn-cost-attributor.js.map +1 -1
- package/dist/proxy/proxy-manager.d.ts +3 -0
- package/dist/proxy/proxy-manager.d.ts.map +1 -1
- package/dist/proxy/proxy-manager.js +43 -3
- package/dist/proxy/proxy-manager.js.map +1 -1
- package/dist/proxy/types.d.ts +7 -0
- package/dist/proxy/types.d.ts.map +1 -1
- package/dist/proxy/types.js.map +1 -1
- package/dist/proxy/upstream-http.d.ts.map +1 -1
- package/dist/proxy/upstream-http.js +44 -1
- package/dist/proxy/upstream-http.js.map +1 -1
- package/dist/proxy/upstream-stdio.d.ts +0 -1
- package/dist/proxy/upstream-stdio.d.ts.map +1 -1
- package/dist/proxy/upstream-stdio.js +2 -26
- package/dist/proxy/upstream-stdio.js.map +1 -1
- package/dist/redaction-patterns.d.ts.map +1 -1
- package/dist/redaction-patterns.js +1 -0
- package/dist/redaction-patterns.js.map +1 -1
- package/dist/secret-command.d.ts +59 -0
- package/dist/secret-command.d.ts.map +1 -0
- package/dist/secret-command.js +123 -0
- package/dist/secret-command.js.map +1 -0
- package/dist/security/audit-trail.d.ts +7 -1
- package/dist/security/audit-trail.d.ts.map +1 -1
- package/dist/security/audit-trail.js +24 -0
- package/dist/security/audit-trail.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +9 -4
- package/dist/server.js.map +1 -1
- package/dist/shared/pricing-data.d.ts.map +1 -1
- package/dist/shared/pricing-data.js +223 -32
- package/dist/shared/pricing-data.js.map +1 -1
- package/dist/shared/pricing.d.ts +25 -3
- package/dist/shared/pricing.d.ts.map +1 -1
- package/dist/shared/pricing.js +46 -9
- package/dist/shared/pricing.js.map +1 -1
- package/dist/shared/tokens.d.ts +16 -0
- package/dist/shared/tokens.d.ts.map +1 -1
- package/dist/shared/tokens.js +18 -0
- package/dist/shared/tokens.js.map +1 -1
- package/dist/shared/transport/otlp-shared.d.ts.map +1 -1
- package/dist/shared/transport/otlp-shared.js +7 -14
- package/dist/shared/transport/otlp-shared.js.map +1 -1
- package/dist/storage/local-store.d.ts +6 -4
- package/dist/storage/local-store.d.ts.map +1 -1
- package/dist/storage/local-store.js +21 -7
- package/dist/storage/local-store.js.map +1 -1
- package/dist/storage/session-store.d.ts +24 -1
- package/dist/storage/session-store.d.ts.map +1 -1
- package/dist/storage/session-store.js +38 -7
- package/dist/storage/session-store.js.map +1 -1
- package/dist/storage/types.d.ts +13 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js.map +1 -1
- package/dist/tools/cross-session-tools.d.ts +7 -1
- package/dist/tools/cross-session-tools.d.ts.map +1 -1
- package/dist/tools/cross-session-tools.js +47 -14
- package/dist/tools/cross-session-tools.js.map +1 -1
- package/dist/tools/session-stats.d.ts +6 -0
- package/dist/tools/session-stats.d.ts.map +1 -1
- package/dist/tools/session-stats.js +3 -2
- package/dist/tools/session-stats.js.map +1 -1
- package/dist/transport/audit-record-sender.d.ts +20 -0
- package/dist/transport/audit-record-sender.d.ts.map +1 -0
- package/dist/transport/audit-record-sender.js +54 -0
- package/dist/transport/audit-record-sender.js.map +1 -0
- package/dist/transport/nr-ingest.d.ts +7 -0
- package/dist/transport/nr-ingest.d.ts.map +1 -1
- package/dist/transport/nr-ingest.js +64 -27
- package/dist/transport/nr-ingest.js.map +1 -1
- package/dist/transport/tier-types.d.ts +11 -1
- package/dist/transport/tier-types.d.ts.map +1 -1
- package/dist/transport/tier-types.js +28 -6
- package/dist/transport/tier-types.js.map +1 -1
- package/dist/transport/unforwarded-session-monitor.d.ts +12 -6
- package/dist/transport/unforwarded-session-monitor.d.ts.map +1 -1
- package/dist/transport/unforwarded-session-monitor.js +24 -5
- package/dist/transport/unforwarded-session-monitor.js.map +1 -1
- package/dist/web/assets/{index-lvdXUntr.js → index-U9DPZ-Tb.js} +3 -3
- package/dist/web/index.html +1 -1
- package/examples/local-alert-rules.json +28 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { AlertSnapshotCollector } from './alerts/alert-snapshot-collector.js';
|
|
|
9
9
|
import { LocalAlertEngine } from './alerts/local-alert-engine.js';
|
|
10
10
|
import { parseLocalAlertRules } from './alerts/local-alert-rule.js';
|
|
11
11
|
import { OsNotifier } from './alerts/os-notifier.js';
|
|
12
|
-
import { DEFAULT_STORAGE_PATH, loadMcpConfig, redactSensitive } from './config.js';
|
|
12
|
+
import { DEFAULT_STORAGE_PATH, digestWebhookUrlOverride, loadMcpConfig, redactSensitive, } from './config.js';
|
|
13
13
|
import { checkBasicAuthToken } from './dashboard/basic-auth.js';
|
|
14
14
|
import { DashboardServer } from './dashboard/dashboard-server.js';
|
|
15
15
|
import { LiveEventBus } from './dashboard/index.js';
|
|
@@ -21,10 +21,13 @@ import { CopilotUsageWatcher } from './hooks/copilot-usage-watcher.js';
|
|
|
21
21
|
import { HookEventProcessor } from './hooks/index.js';
|
|
22
22
|
import { isPlatformDetectionFellBack } from './hooks/platform-detection-health.js';
|
|
23
23
|
import { ParentTranscriptWatcher } from './hooks/parent-transcript-watcher.js';
|
|
24
|
+
import { BilledTurnLedger, pruneBilledTurns } from './hooks/billed-turn-ledger.js';
|
|
24
25
|
import { isSyntheticSessionId, readJobState, readTranscriptTitle, resolveFromBreadcrumb, resolveFromCwd, resolveFromJobDir, resolveSessionId, resolveSessionName, watchCwdBreadcrumbForCorrection, watchPpidBreadcrumb, } from './hooks/session-resolver.js';
|
|
25
26
|
import { SubagentWatcher } from './hooks/subagent-watcher.js';
|
|
26
27
|
import { WorkflowWatcher } from './hooks/workflow-watcher.js';
|
|
27
28
|
import { migrateStoragePath } from './install/migrate.js';
|
|
29
|
+
import { createHeadlessInstaller } from './install/headless-install.js';
|
|
30
|
+
import { areHooksInstalledAtAnyScope } from './install/install-helper.js';
|
|
28
31
|
import { checkNodeVersion } from './install/node-version-check.js';
|
|
29
32
|
import { localDateKey } from './lib/date.js';
|
|
30
33
|
import { repoNameFromRemote } from './lib/git-remote.js';
|
|
@@ -39,8 +42,7 @@ import { isTokenEventForThisProcess, shouldApplyCostEstimate, } from './metrics/
|
|
|
39
42
|
import { ContextCompositionTracker } from './metrics/context-composition-tracker.js';
|
|
40
43
|
import { ContextTrackerRegistry } from './metrics/context-tracker.js';
|
|
41
44
|
import { ContextWindowTracker } from './metrics/context-window-tracker.js';
|
|
42
|
-
import {
|
|
43
|
-
import { startPricingRefresh } from './metrics/pricing-refresh.js';
|
|
45
|
+
import { initModelPricing } from './metrics/pricing-init.js';
|
|
44
46
|
import { buildCostForecastFromInputs } from './metrics/cost-forecast.js';
|
|
45
47
|
import { CostPerOutcomeAnalyzer } from './metrics/cost-per-outcome.js';
|
|
46
48
|
import { buildCostTrackerSeed } from './metrics/cost-tracker-seed.js';
|
|
@@ -61,6 +63,7 @@ import { QualityProxyTracker } from './metrics/quality-proxy-tracker.js';
|
|
|
61
63
|
import { RecommendationEngine } from './metrics/recommendation-engine.js';
|
|
62
64
|
import { RetryDetector } from './metrics/retry-detector.js';
|
|
63
65
|
import { SessionTracker } from './metrics/session-tracker.js';
|
|
66
|
+
import { SkillActivationTracker } from './metrics/skill-activation-tracker.js';
|
|
64
67
|
import { TaskCompletionTracker } from './metrics/task-completion-tracker.js';
|
|
65
68
|
import { buildTaskDetectorSeed } from './metrics/task-detector-seed.js';
|
|
66
69
|
import { TaskDetector } from './metrics/task-detector.js';
|
|
@@ -70,7 +73,7 @@ import { TrendAnalyzer } from './metrics/trend-analyzer.js';
|
|
|
70
73
|
import { TurnCostAttributor } from './metrics/turn-cost-attributor.js';
|
|
71
74
|
import { TurnTracker } from './metrics/turn-tracker.js';
|
|
72
75
|
import { WorkflowRunTracker } from './metrics/workflow-run-tracker.js';
|
|
73
|
-
import { createDefaultRegistry, GenericMcpAdapter } from './platforms/index.js';
|
|
76
|
+
import { ClaudeCodeAdapter, createDefaultRegistry, GenericMcpAdapter } from './platforms/index.js';
|
|
74
77
|
import { ProxyManager } from './proxy/index.js';
|
|
75
78
|
import { AuditTrailManager } from './security/audit-trail.js';
|
|
76
79
|
import { createServer } from './server.js';
|
|
@@ -86,8 +89,9 @@ import { initMcpTracer } from './tracing/mcp-tracer.js';
|
|
|
86
89
|
import { SessionSpan } from './tracing/session-span.js';
|
|
87
90
|
import { TaskSpanTracker } from './tracing/task-span-tracker.js';
|
|
88
91
|
import { emitToolCallSpan } from './tracing/tool-call-span.js';
|
|
92
|
+
import { nrIngestOptionsFromConfig, sendAuditRecord } from './transport/audit-record-sender.js';
|
|
89
93
|
import { NrIngestManager } from './transport/nr-ingest.js';
|
|
90
|
-
import {
|
|
94
|
+
import { unforwardedSessionsHint, UnforwardedSessionMonitor, detectCloudForwardingGap, } from './transport/unforwarded-session-monitor.js';
|
|
91
95
|
import { HomelabAccumulator, HomelabForwarder } from './homelab/index.js';
|
|
92
96
|
import { VERSION } from './version.js';
|
|
93
97
|
export { loadMcpConfig, redactSensitive } from './config.js';
|
|
@@ -109,9 +113,9 @@ export function maskCredential(key) {
|
|
|
109
113
|
* Helps users troubleshoot configuration issues without requiring
|
|
110
114
|
* manual diagnosis steps.
|
|
111
115
|
*/
|
|
112
|
-
function loadConfigOrDie(options) {
|
|
116
|
+
function loadConfigOrDie(options, loadOptions) {
|
|
113
117
|
try {
|
|
114
|
-
return loadMcpConfig(options);
|
|
118
|
+
return loadMcpConfig(options, loadOptions);
|
|
115
119
|
}
|
|
116
120
|
catch (err) {
|
|
117
121
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -221,8 +225,13 @@ export function runRetentionSweep(deps) {
|
|
|
221
225
|
return;
|
|
222
226
|
const deletedSessionFiles = purgeOldSessions(deps.storagePath, deps.retainSessionsDays);
|
|
223
227
|
const deletedWeeklySummaryFiles = purgeOldWeeklySummaries(deps.storagePath, deps.retainSessionsDays);
|
|
224
|
-
|
|
225
|
-
|
|
228
|
+
const deletedBilledTurnDays = pruneBilledTurns(deps.storagePath, deps.retainSessionsDays, Date.now());
|
|
229
|
+
if (deletedSessionFiles > 0 || deletedWeeklySummaryFiles > 0 || deletedBilledTurnDays > 0) {
|
|
230
|
+
logger.info('Retention purge complete', {
|
|
231
|
+
deletedSessionFiles,
|
|
232
|
+
deletedWeeklySummaryFiles,
|
|
233
|
+
deletedBilledTurnDays,
|
|
234
|
+
});
|
|
226
235
|
}
|
|
227
236
|
}
|
|
228
237
|
/**
|
|
@@ -566,13 +575,6 @@ export function parseArgs(argv) {
|
|
|
566
575
|
validate,
|
|
567
576
|
};
|
|
568
577
|
}
|
|
569
|
-
function initModelPricing(config) {
|
|
570
|
-
applyPricingOverlay(config.customPricingFile);
|
|
571
|
-
void startPricingRefresh({
|
|
572
|
-
enabled: config.pricingRefresh,
|
|
573
|
-
cachePath: resolve(config.storagePath, 'pricing-cache.json'),
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
578
|
async function main() {
|
|
577
579
|
const nodeVersionError = checkNodeVersion();
|
|
578
580
|
if (nodeVersionError) {
|
|
@@ -799,6 +801,21 @@ async function main() {
|
|
|
799
801
|
process.on('SIGTERM', handleSignal);
|
|
800
802
|
if (options.stdio || options.local) {
|
|
801
803
|
let sessionTraceId;
|
|
804
|
+
// Sends the install's audit record at install time: a pending session that
|
|
805
|
+
// never resolves never builds a live ingest manager to send it later.
|
|
806
|
+
const buildHeadlessInstaller = () => createHeadlessInstaller({
|
|
807
|
+
allowHeadlessInstall: config.allowHeadlessInstall,
|
|
808
|
+
getAuditTrail: () => mcpServer?.auditTrailManager,
|
|
809
|
+
onAuditRecord: (record) => {
|
|
810
|
+
sendAuditRecord(record, {
|
|
811
|
+
config: config,
|
|
812
|
+
liveIngest: nrIngest,
|
|
813
|
+
sessionTraceId,
|
|
814
|
+
}).catch((err) => {
|
|
815
|
+
logger.warn('Failed to send the hook install audit event', { error: String(err) });
|
|
816
|
+
});
|
|
817
|
+
},
|
|
818
|
+
});
|
|
802
819
|
// True when the synchronous resolution chain below succeeded ONLY via
|
|
803
820
|
// the cwd fallback — the collision-prone source (shared by every
|
|
804
821
|
// session that ever ran in this directory), unlike the ppid breadcrumb
|
|
@@ -887,9 +904,16 @@ async function main() {
|
|
|
887
904
|
if (!gap)
|
|
888
905
|
throw err;
|
|
889
906
|
process.env.NR_AI_MODE = 'local';
|
|
890
|
-
config = loadConfigOrDie(options);
|
|
907
|
+
config = loadConfigOrDie(options, { ignoreTiers: true });
|
|
891
908
|
unforwardedSessionMonitor = new UnforwardedSessionMonitor({ gap });
|
|
892
|
-
|
|
909
|
+
const problem = gap.reason === 'secret-helper-failed'
|
|
910
|
+
? `could not read ${gap.missingField} from its helper command`
|
|
911
|
+
: `has no ${gap.missingField}`;
|
|
912
|
+
logger.warn(`Cloud export is configured (mode='${gap.requestedMode}') but this --local process ${problem}; sessions it drains will not reach New Relic`, {
|
|
913
|
+
reason: gap.reason,
|
|
914
|
+
requestedMode: gap.requestedMode,
|
|
915
|
+
hint: unforwardedSessionsHint(gap.reason),
|
|
916
|
+
});
|
|
893
917
|
}
|
|
894
918
|
if (!config.enabled) {
|
|
895
919
|
logger.info('Server disabled via config — exiting');
|
|
@@ -921,8 +945,12 @@ async function main() {
|
|
|
921
945
|
// dashboard owner's GC pass can tell which buffer files still have a live
|
|
922
946
|
// owner. Removed in the shutdown handler below. Skipped during the
|
|
923
947
|
// provisional window — the real heartbeat is written after resolution.
|
|
924
|
-
if (options.stdio && !isProvisional)
|
|
925
|
-
localStore.writeHeartbeat()
|
|
948
|
+
if (options.stdio && !isProvisional) {
|
|
949
|
+
localStore.writeHeartbeat(process.pid, process.argv.slice(1), process.cwd(), {
|
|
950
|
+
value: config.companionMode,
|
|
951
|
+
source: config.companionModeSource,
|
|
952
|
+
});
|
|
953
|
+
}
|
|
926
954
|
localStoreForShutdown = localStore;
|
|
927
955
|
// Migrate any pre-existing events from the legacy shared `buffer.jsonl` into
|
|
928
956
|
// per-session files. Idempotent and a no-op on fresh installs.
|
|
@@ -1060,6 +1088,7 @@ async function main() {
|
|
|
1060
1088
|
if (options.stdio)
|
|
1061
1089
|
applyAuthoritativeSessionName(sessionTraceId);
|
|
1062
1090
|
const turnCostAttributor = new TurnCostAttributor({ rateMultiplier });
|
|
1091
|
+
const skillActivationTracker = new SkillActivationTracker();
|
|
1063
1092
|
const turnTracker = new TurnTracker();
|
|
1064
1093
|
const gitEfficiencyTracker = new GitEfficiencyTracker();
|
|
1065
1094
|
const gitWorkspaceReporter = new GitWorkspaceReporter();
|
|
@@ -1703,30 +1732,11 @@ async function main() {
|
|
|
1703
1732
|
// AiMcpToolCall/etc. event is silently dropped — see issue #320.
|
|
1704
1733
|
let warnedMissingIngest = false;
|
|
1705
1734
|
if (config.mode !== 'local' && !isProvisional) {
|
|
1706
|
-
if (!config.licenseKey || !config.accountId) {
|
|
1707
|
-
throw new Error('licenseKey and accountId must be defined. ' +
|
|
1708
|
-
'This should have been caught by config validation. ' +
|
|
1709
|
-
'Check that mode is not "local" or that cloud credentials are configured.');
|
|
1710
|
-
}
|
|
1711
1735
|
nrIngest = new NrIngestManager({
|
|
1712
|
-
|
|
1713
|
-
transportOptions: {
|
|
1714
|
-
accountId: config.accountId,
|
|
1715
|
-
collectorHost: config.collectorHost,
|
|
1716
|
-
},
|
|
1717
|
-
developer: config.developer,
|
|
1718
|
-
appName: config.appName,
|
|
1719
|
-
teamId: config.teamId,
|
|
1720
|
-
projectId: config.projectId,
|
|
1721
|
-
orgId: config.orgId,
|
|
1722
|
-
repoUrl: config.repoUrl,
|
|
1723
|
-
companionMode: config.companionMode,
|
|
1724
|
-
tiers: config.tiers,
|
|
1736
|
+
...nrIngestOptionsFromConfig(config),
|
|
1725
1737
|
sessionTracker,
|
|
1726
1738
|
localStore,
|
|
1727
1739
|
auditTrail,
|
|
1728
|
-
eventHarvestIntervalMs: config.harvestIntervalMs.events,
|
|
1729
|
-
metricHarvestIntervalMs: config.harvestIntervalMs.metrics,
|
|
1730
1740
|
costTracker,
|
|
1731
1741
|
efficiencyScorer,
|
|
1732
1742
|
feedbackCollector,
|
|
@@ -1806,7 +1816,9 @@ async function main() {
|
|
|
1806
1816
|
// record, so audit/security events carry agentId and agentType.
|
|
1807
1817
|
// The watcher's on-demand read is synchronous, which is what keeps it
|
|
1808
1818
|
// ahead of auditTrail.
|
|
1809
|
-
const
|
|
1819
|
+
const attributed = subagentAttribution.attributeAtIntake(incomingRecord, activeSubagentWatcher);
|
|
1820
|
+
const activeSkill = skillActivationTracker.recordToolCall(attributed);
|
|
1821
|
+
const rawRecord = activeSkill ? { ...attributed, activeSkill } : attributed;
|
|
1810
1822
|
if (!config || !sessionTracker || !taskDetector) {
|
|
1811
1823
|
logger.warn('onRecord called before full initialization; skipping');
|
|
1812
1824
|
return;
|
|
@@ -2050,7 +2062,7 @@ async function main() {
|
|
|
2050
2062
|
ownSessionId: sessionTraceId,
|
|
2051
2063
|
});
|
|
2052
2064
|
const closedTurn = turnCostAttributor.recordTokenEvent(tokenEvent);
|
|
2053
|
-
if (
|
|
2065
|
+
if (isOwnEvent)
|
|
2054
2066
|
capturedNrIngest?.ingestTurnCost(closedTurn);
|
|
2055
2067
|
const usage = {
|
|
2056
2068
|
inputTokens: tokenEvent.inputTokens,
|
|
@@ -2300,7 +2312,9 @@ async function main() {
|
|
|
2300
2312
|
});
|
|
2301
2313
|
},
|
|
2302
2314
|
onUserPromptSubmit: (frame) => {
|
|
2303
|
-
|
|
2315
|
+
const slashRun = skillActivationTracker.recordPrompt(frame.sessionId, frame.slashCommand ?? null);
|
|
2316
|
+
if (slashRun)
|
|
2317
|
+
turnCostAttributor.recordSkillRun(frame.sessionId, slashRun);
|
|
2304
2318
|
taskDetector.startTaskIfNone(frame.timestamp);
|
|
2305
2319
|
},
|
|
2306
2320
|
onStop: (frame) => {
|
|
@@ -2455,6 +2469,11 @@ async function main() {
|
|
|
2455
2469
|
// signal for that platform, so it is gated only by its own opt-out, and
|
|
2456
2470
|
// it no-ops cheaply (a single existsSync) when data.db is absent.
|
|
2457
2471
|
const copilotAppUsageWatcherEnabled = process.env['NR_AI_ENABLE_COPILOT_APP_USAGE_WATCHER'] !== '0';
|
|
2472
|
+
// One claimant per process, shared by every watcher that bills turns.
|
|
2473
|
+
const billedTurnLedger = new BilledTurnLedger({
|
|
2474
|
+
storagePath: config.storagePath,
|
|
2475
|
+
retainDays: config.retainSessionsDays,
|
|
2476
|
+
});
|
|
2458
2477
|
// Construct + start the watchers for a given session id. In `--stdio` mode
|
|
2459
2478
|
// the watchers filter discovered transcript dirs by `parentSessionId`; in
|
|
2460
2479
|
// `--local` mode they run unfiltered (parentSessionId: undefined). Shared by
|
|
@@ -2479,6 +2498,7 @@ async function main() {
|
|
|
2479
2498
|
storagePath: config.storagePath,
|
|
2480
2499
|
parentSessionId: isStdioWatcher ? watcherSessionId : undefined,
|
|
2481
2500
|
localStore,
|
|
2501
|
+
ledger: billedTurnLedger,
|
|
2482
2502
|
});
|
|
2483
2503
|
activeParentTranscriptWatcher.start();
|
|
2484
2504
|
logger.info('ParentTranscriptWatcher started', {
|
|
@@ -2656,7 +2676,10 @@ async function main() {
|
|
|
2656
2676
|
// Replace the current LocalStore with one scoped to the real id.
|
|
2657
2677
|
const realLocalStore = new LocalStore(config.storagePath, realId);
|
|
2658
2678
|
realLocalStore.initialize();
|
|
2659
|
-
realLocalStore.writeHeartbeat()
|
|
2679
|
+
realLocalStore.writeHeartbeat(process.pid, process.argv.slice(1), process.cwd(), {
|
|
2680
|
+
value: config.companionMode,
|
|
2681
|
+
source: config.companionModeSource,
|
|
2682
|
+
});
|
|
2660
2683
|
localStoreForShutdown = realLocalStore;
|
|
2661
2684
|
try {
|
|
2662
2685
|
realLocalStore.migrateLegacyBuffer();
|
|
@@ -2688,29 +2711,11 @@ async function main() {
|
|
|
2688
2711
|
});
|
|
2689
2712
|
}
|
|
2690
2713
|
if (config.mode !== 'local') {
|
|
2691
|
-
if (!config.licenseKey || !config.accountId) {
|
|
2692
|
-
throw new Error('licenseKey and accountId must be defined for non-local mode. ' +
|
|
2693
|
-
'This should have been caught by config validation.');
|
|
2694
|
-
}
|
|
2695
2714
|
nrIngest = new NrIngestManager({
|
|
2696
|
-
|
|
2697
|
-
transportOptions: {
|
|
2698
|
-
accountId: config.accountId,
|
|
2699
|
-
collectorHost: config.collectorHost,
|
|
2700
|
-
},
|
|
2701
|
-
developer: config.developer,
|
|
2702
|
-
appName: config.appName,
|
|
2703
|
-
teamId: config.teamId,
|
|
2704
|
-
projectId: config.projectId,
|
|
2705
|
-
orgId: config.orgId,
|
|
2706
|
-
repoUrl: config.repoUrl,
|
|
2707
|
-
companionMode: config.companionMode,
|
|
2708
|
-
tiers: config.tiers,
|
|
2715
|
+
...nrIngestOptionsFromConfig(config),
|
|
2709
2716
|
sessionTracker: sessionTracker,
|
|
2710
2717
|
localStore: realLocalStore,
|
|
2711
2718
|
auditTrail,
|
|
2712
|
-
eventHarvestIntervalMs: config.harvestIntervalMs.events,
|
|
2713
|
-
metricHarvestIntervalMs: config.harvestIntervalMs.metrics,
|
|
2714
2719
|
costTracker,
|
|
2715
2720
|
efficiencyScorer,
|
|
2716
2721
|
feedbackCollector,
|
|
@@ -2737,13 +2742,17 @@ async function main() {
|
|
|
2737
2742
|
accountId: config.accountId ?? null,
|
|
2738
2743
|
licenseKeyMasked: config.licenseKey ? maskCredential(config.licenseKey) : null,
|
|
2739
2744
|
nrApiKeyMasked: config.nrApiKey ? maskCredential(config.nrApiKey) : null,
|
|
2745
|
+
secretSources: config.secretSources,
|
|
2740
2746
|
region: config.collectorHost ?? 'us',
|
|
2741
2747
|
storagePath: config.storagePath,
|
|
2742
2748
|
dashboardUrl: `http://${config.dashboard.host}:${config.dashboard.port}`,
|
|
2743
2749
|
configFilePath,
|
|
2744
2750
|
companionMode: config.companionMode,
|
|
2751
|
+
allowHeadlessInstall: config.allowHeadlessInstall,
|
|
2752
|
+
companionModeSource: config.companionModeSource,
|
|
2745
2753
|
};
|
|
2746
2754
|
registerTools(mcpServer.server, {
|
|
2755
|
+
headlessInstaller: buildHeadlessInstaller(),
|
|
2747
2756
|
sessionTracker: sessionTracker,
|
|
2748
2757
|
costTracker,
|
|
2749
2758
|
budgetTracker,
|
|
@@ -2788,6 +2797,7 @@ async function main() {
|
|
|
2788
2797
|
nrApiKey: config.nrApiKey,
|
|
2789
2798
|
collectorHost: config.collectorHost,
|
|
2790
2799
|
configFilePath,
|
|
2800
|
+
digestWebhookUrlOverride: digestWebhookUrlOverride(config),
|
|
2791
2801
|
configSummary,
|
|
2792
2802
|
});
|
|
2793
2803
|
// The client cached tools/list during the pending window, when only the
|
|
@@ -2899,12 +2909,22 @@ async function main() {
|
|
|
2899
2909
|
accountId: config.accountId ?? null,
|
|
2900
2910
|
licenseKeyMasked: config.licenseKey ? maskCredential(config.licenseKey) : null,
|
|
2901
2911
|
nrApiKeyMasked: config.nrApiKey ? maskCredential(config.nrApiKey) : null,
|
|
2912
|
+
secretSources: config.secretSources,
|
|
2902
2913
|
region: config.collectorHost ?? 'us',
|
|
2903
2914
|
storagePath: config.storagePath,
|
|
2904
2915
|
dashboardUrl: `http://${config.dashboard.host}:${config.dashboard.port}`,
|
|
2905
2916
|
configFilePath: pendingConfigFilePath,
|
|
2906
2917
|
companionMode: config.companionMode,
|
|
2918
|
+
allowHeadlessInstall: config.allowHeadlessInstall,
|
|
2919
|
+
companionModeSource: config.companionModeSource,
|
|
2907
2920
|
},
|
|
2921
|
+
// A Claude Code session with no hooks never resolves, so this is
|
|
2922
|
+
// where the opt-in install has to work. Other stdio clients have no
|
|
2923
|
+
// Claude Code hooks to install or report missing.
|
|
2924
|
+
...(createDefaultRegistry().getActive() instanceof ClaudeCodeAdapter && {
|
|
2925
|
+
hooksInstalledFn: () => areHooksInstalledAtAnyScope(),
|
|
2926
|
+
headlessInstaller: buildHeadlessInstaller(),
|
|
2927
|
+
}),
|
|
2908
2928
|
});
|
|
2909
2929
|
logger.info('Dashboard started early; awaiting session_id resolution (breadcrumb poll)');
|
|
2910
2930
|
sessionResolutionAbort = new AbortController();
|
|
@@ -2963,13 +2983,17 @@ async function main() {
|
|
|
2963
2983
|
accountId: config.accountId ?? null,
|
|
2964
2984
|
licenseKeyMasked: config.licenseKey ? maskCredential(config.licenseKey) : null,
|
|
2965
2985
|
nrApiKeyMasked: config.nrApiKey ? maskCredential(config.nrApiKey) : null,
|
|
2986
|
+
secretSources: config.secretSources,
|
|
2966
2987
|
region: config.collectorHost ?? 'us',
|
|
2967
2988
|
storagePath: config.storagePath,
|
|
2968
2989
|
dashboardUrl: `http://${config.dashboard.host}:${config.dashboard.port}`,
|
|
2969
2990
|
configFilePath,
|
|
2970
2991
|
companionMode: config.companionMode,
|
|
2992
|
+
allowHeadlessInstall: config.allowHeadlessInstall,
|
|
2993
|
+
companionModeSource: config.companionModeSource,
|
|
2971
2994
|
};
|
|
2972
2995
|
registerTools(mcpServer.server, {
|
|
2996
|
+
headlessInstaller: buildHeadlessInstaller(),
|
|
2973
2997
|
sessionTracker,
|
|
2974
2998
|
costTracker,
|
|
2975
2999
|
budgetTracker,
|
|
@@ -3014,6 +3038,7 @@ async function main() {
|
|
|
3014
3038
|
nrApiKey: config.nrApiKey,
|
|
3015
3039
|
collectorHost: config.collectorHost,
|
|
3016
3040
|
configFilePath,
|
|
3041
|
+
digestWebhookUrlOverride: digestWebhookUrlOverride(config),
|
|
3017
3042
|
configSummary,
|
|
3018
3043
|
});
|
|
3019
3044
|
// Harmless if the client hasn't listed yet, and necessary if it listed
|
|
@@ -3069,11 +3094,7 @@ async function main() {
|
|
|
3069
3094
|
// load-time validation), so this mirrors that guard rather than
|
|
3070
3095
|
// re-deriving it.
|
|
3071
3096
|
if (config.mode !== 'local') {
|
|
3072
|
-
|
|
3073
|
-
throw new Error('licenseKey and accountId must be defined. ' +
|
|
3074
|
-
'This should have been caught by config validation. ' +
|
|
3075
|
-
'Check that mode is not "local" or that cloud credentials are configured.');
|
|
3076
|
-
}
|
|
3097
|
+
const configOptions = nrIngestOptionsFromConfig(config);
|
|
3077
3098
|
// Unscoped LocalStore (mirrors --local mode) — proxy mode multiplexes
|
|
3078
3099
|
// many concurrent clients, so there's no single session id to scope a
|
|
3079
3100
|
// buffer file to. Passing it into NrIngestManager gives AuditTrailManager
|
|
@@ -3089,23 +3110,9 @@ async function main() {
|
|
|
3089
3110
|
// to handle a missing tracker.
|
|
3090
3111
|
const apiFailureTracker = new ApiFailureTracker();
|
|
3091
3112
|
nrIngest = new NrIngestManager({
|
|
3092
|
-
|
|
3093
|
-
transportOptions: {
|
|
3094
|
-
accountId: config.accountId,
|
|
3095
|
-
collectorHost: config.collectorHost,
|
|
3096
|
-
},
|
|
3097
|
-
developer: config.developer,
|
|
3098
|
-
appName: config.appName,
|
|
3099
|
-
teamId: config.teamId,
|
|
3100
|
-
projectId: config.projectId,
|
|
3101
|
-
orgId: config.orgId,
|
|
3102
|
-
repoUrl: config.repoUrl,
|
|
3103
|
-
companionMode: config.companionMode,
|
|
3104
|
-
tiers: config.tiers,
|
|
3113
|
+
...configOptions,
|
|
3105
3114
|
sessionTracker: new SessionTracker(sessionTraceId),
|
|
3106
3115
|
localStore: proxyLocalStore,
|
|
3107
|
-
eventHarvestIntervalMs: config.harvestIntervalMs.events,
|
|
3108
|
-
metricHarvestIntervalMs: config.harvestIntervalMs.metrics,
|
|
3109
3116
|
apiFailureTracker,
|
|
3110
3117
|
sessionTraceId,
|
|
3111
3118
|
// Proxy mode has no single coherent session — sessionTracker above is
|