@compforge/harness-toolbox 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +47 -0
  2. package/dist/chunk-0rs1aacd.js +127 -0
  3. package/dist/chunk-1at7zs0z.js +104 -0
  4. package/dist/chunk-1vfwvgkj.js +104 -0
  5. package/dist/chunk-205a4vma.js +85 -0
  6. package/dist/chunk-3dt25p98.js +59 -0
  7. package/dist/chunk-6fnhzhdb.js +103 -0
  8. package/dist/chunk-8nm9f0hh.js +92 -0
  9. package/dist/chunk-ajhdd4hp.js +267 -0
  10. package/dist/chunk-c6z919qb.js +98 -0
  11. package/dist/chunk-djk4kmxb.js +0 -0
  12. package/dist/chunk-hqx7j9xe.js +14 -0
  13. package/dist/chunk-hv2kx47y.js +92 -0
  14. package/dist/chunk-j46x7j7c.js +73 -0
  15. package/dist/chunk-jr9y0ghr.js +157 -0
  16. package/dist/chunk-mkhyty75.js +166 -0
  17. package/dist/chunk-mp88s7r7.js +12 -0
  18. package/dist/chunk-pfar9cm3.js +0 -0
  19. package/dist/chunk-qq77x9ek.js +34 -0
  20. package/dist/chunk-s06hs7a8.js +79 -0
  21. package/dist/chunk-s1sjyem7.js +41 -0
  22. package/dist/chunk-v3hxvnrc.js +47 -0
  23. package/dist/chunk-w3a4p6jm.js +124 -0
  24. package/dist/chunk-xy4g56g4.js +50 -0
  25. package/dist/chunk-ztenxgjv.js +27 -0
  26. package/dist/client-manager.d.ts +14 -0
  27. package/dist/client-manager.js +6 -0
  28. package/dist/client.d.ts +5 -0
  29. package/dist/client.js +0 -0
  30. package/dist/concurrency.d.ts +7 -0
  31. package/dist/concurrency.js +6 -0
  32. package/dist/datasource.d.ts +26 -0
  33. package/dist/datasource.js +10 -0
  34. package/dist/kubernetes/client-node-pod-log.d.ts +31 -0
  35. package/dist/kubernetes/client-node-pod-log.js +425 -0
  36. package/dist/kubernetes/client.d.ts +17 -0
  37. package/dist/kubernetes/client.js +92 -0
  38. package/dist/kubernetes/endpoint.d.ts +4 -0
  39. package/dist/kubernetes/endpoint.js +0 -0
  40. package/dist/kubernetes/executor.d.ts +45 -0
  41. package/dist/kubernetes/executor.js +13 -0
  42. package/dist/kubernetes/log-capture-file.d.ts +12 -0
  43. package/dist/kubernetes/log-capture-file.js +6 -0
  44. package/dist/kubernetes/log-capture-plan.d.ts +29 -0
  45. package/dist/kubernetes/log-capture-plan.js +9 -0
  46. package/dist/kubernetes/log-timestamp.d.ts +2 -0
  47. package/dist/kubernetes/log-timestamp.js +6 -0
  48. package/dist/kubernetes/pod-log-client.d.ts +25 -0
  49. package/dist/kubernetes/pod-log-client.js +12 -0
  50. package/dist/kubernetes/pod-log-datasource.d.ts +17 -0
  51. package/dist/kubernetes/pod-log-datasource.js +31 -0
  52. package/dist/kubernetes/pod-log.d.ts +52 -0
  53. package/dist/kubernetes/pod-log.js +121 -0
  54. package/dist/kubernetes/pod.d.ts +61 -0
  55. package/dist/kubernetes/pod.js +8 -0
  56. package/dist/kubernetes/port-forward.d.ts +42 -0
  57. package/dist/kubernetes/port-forward.js +10 -0
  58. package/dist/kubernetes/service-port-forward.d.ts +29 -0
  59. package/dist/kubernetes/service-port-forward.js +11 -0
  60. package/dist/kubernetes/service.d.ts +31 -0
  61. package/dist/kubernetes/service.js +17 -0
  62. package/dist/mysql/client.d.ts +36 -0
  63. package/dist/mysql/client.js +13 -0
  64. package/dist/mysql/index.d.ts +3 -0
  65. package/dist/mysql/index.js +18 -0
  66. package/dist/mysql/pod.d.ts +7 -0
  67. package/dist/mysql/pod.js +8 -0
  68. package/dist/mysql/target.d.ts +12 -0
  69. package/dist/mysql/target.js +6 -0
  70. package/dist/mysql/types.d.ts +16 -0
  71. package/dist/mysql/types.js +1 -0
  72. package/dist/opensearch/client.d.ts +62 -0
  73. package/dist/opensearch/client.js +12 -0
  74. package/dist/opensearch/endpoint.d.ts +16 -0
  75. package/dist/opensearch/endpoint.js +6 -0
  76. package/dist/opensearch/index.d.ts +3 -0
  77. package/dist/opensearch/index.js +17 -0
  78. package/dist/opensearch/types.d.ts +8 -0
  79. package/dist/opensearch/types.js +1 -0
  80. package/dist/process/index.d.ts +13 -0
  81. package/dist/process/index.js +8 -0
  82. package/dist/redis/client.d.ts +90 -0
  83. package/dist/redis/client.js +14 -0
  84. package/dist/redis/index.d.ts +3 -0
  85. package/dist/redis/index.js +24 -0
  86. package/dist/redis/key-stats.d.ts +27 -0
  87. package/dist/redis/key-stats.js +8 -0
  88. package/dist/redis/topology.d.ts +23 -0
  89. package/dist/redis/topology.js +6 -0
  90. package/dist/transport/index.d.ts +40 -0
  91. package/dist/transport/index.js +12 -0
  92. package/package.json +96 -0
@@ -0,0 +1,92 @@
1
+ import {
2
+ ServicePortForwarder
3
+ } from "../chunk-205a4vma.js";
4
+ import"../chunk-hv2kx47y.js";
5
+ import"../chunk-j46x7j7c.js";
6
+ import"../chunk-6fnhzhdb.js";
7
+ import {
8
+ KubectlExecutor
9
+ } from "../chunk-0rs1aacd.js";
10
+ import"../chunk-ztenxgjv.js";
11
+
12
+ // src/kubernetes/client.ts
13
+ class KubernetesClient {
14
+ kube;
15
+ #controller = new AbortController;
16
+ signal;
17
+ #executors = new Map;
18
+ #forwarders = new Map;
19
+ #operations = new Set;
20
+ #disposal;
21
+ constructor(kube, signal, executor) {
22
+ this.kube = kube;
23
+ this.signal = signal ? AbortSignal.any([signal, this.#controller.signal]) : this.#controller.signal;
24
+ if (executor)
25
+ this.#executors.set(kube.namespace, executor);
26
+ }
27
+ async initialize() {
28
+ this.signal.throwIfAborted();
29
+ }
30
+ #executor(namespace) {
31
+ let executor = this.#executors.get(namespace);
32
+ if (!executor) {
33
+ executor = new KubectlExecutor({ ...this.kube, namespace });
34
+ this.#executors.set(namespace, executor);
35
+ }
36
+ return executor;
37
+ }
38
+ #track(work) {
39
+ this.signal.throwIfAborted();
40
+ const pending = Promise.resolve().then(() => {
41
+ this.signal.throwIfAborted();
42
+ return work();
43
+ });
44
+ this.#operations.add(pending);
45
+ pending.then(() => this.#operations.delete(pending), () => this.#operations.delete(pending));
46
+ return pending;
47
+ }
48
+ #options(options) {
49
+ return { ...options, signal: options?.signal ? AbortSignal.any([this.signal, options.signal]) : this.signal };
50
+ }
51
+ run(namespace, command, options) {
52
+ return this.#track(() => this.#executor(namespace).run(command, this.#options(options)));
53
+ }
54
+ exec(namespace, target, command, options) {
55
+ return this.#track(() => this.#executor(namespace).exec(target, command, this.#options(options)));
56
+ }
57
+ forward(namespace, target) {
58
+ return this.#track(async () => {
59
+ let pending = this.#forwarders.get(namespace);
60
+ if (!pending) {
61
+ pending = ServicePortForwarder.create(this.#executor(namespace), { ...this.kube, namespace });
62
+ this.#forwarders.set(namespace, pending);
63
+ pending.catch(() => {
64
+ if (this.#forwarders.get(namespace) === pending)
65
+ this.#forwarders.delete(namespace);
66
+ });
67
+ }
68
+ const forwarder = await pending;
69
+ this.signal.throwIfAborted();
70
+ return forwarder.forward(target);
71
+ });
72
+ }
73
+ dispose() {
74
+ return this.#disposal ??= (async () => {
75
+ this.#controller.abort(new Error("Kubernetes client disposed"));
76
+ await Promise.allSettled(this.#operations);
77
+ const results = await Promise.allSettled([...this.#forwarders.values()].map(async (pending) => {
78
+ const forwarder = await pending.catch(() => {
79
+ return;
80
+ });
81
+ forwarder?.stop();
82
+ }));
83
+ this.#forwarders.clear();
84
+ const errors = results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
85
+ if (errors.length)
86
+ throw new AggregateError(errors, "Kubernetes client cleanup failed");
87
+ })();
88
+ }
89
+ }
90
+ export {
91
+ KubernetesClient
92
+ };
@@ -0,0 +1,4 @@
1
+ export interface KubernetesEndpoint {
2
+ host: string;
3
+ port: number;
4
+ }
File without changes
@@ -0,0 +1,45 @@
1
+ export interface KubectlOptions {
2
+ /** 省略时不加 -n;跨 namespace 查询由调用方显式选择 */
3
+ namespace?: string;
4
+ kubeconfig?: string;
5
+ context?: string;
6
+ }
7
+ export interface ExecTarget {
8
+ pod: string;
9
+ container?: string;
10
+ }
11
+ export interface RunOptions {
12
+ stdin?: string | Uint8Array;
13
+ timeoutMs?: number;
14
+ signal?: AbortSignal;
15
+ onStdout?: (chunk: string) => void;
16
+ /** 原始 stdout chunk;用于大体量证据直接落盘,避免先拼成一个内存字符串。 */
17
+ onStdoutBytes?: (chunk: Uint8Array) => void;
18
+ onStderr?: (chunk: string) => void;
19
+ /** 默认保留完整 stdout;流式采集可关闭,避免同一份证据同时占用内存和磁盘。 */
20
+ collectStdout?: boolean;
21
+ }
22
+ export interface ExecResult {
23
+ ok: boolean;
24
+ exitCode: number | null;
25
+ stdout: string;
26
+ stderr: string;
27
+ durationMs: number;
28
+ timedOut: boolean;
29
+ /** 完整 argv,原样记录进 evidence manifest,保证采集可复现可审计 */
30
+ command: string[];
31
+ }
32
+ /** 诊断步骤面对的执行接口;测试里用脚本化 mock 替换 KubectlExecutor。 */
33
+ export interface Executor {
34
+ run(sub: string[], opts?: RunOptions): Promise<ExecResult>;
35
+ exec(target: ExecTarget, cmd: string[], opts?: RunOptions): Promise<ExecResult>;
36
+ }
37
+ export declare function buildKubectlArgs(opts: KubectlOptions, sub: string[]): string[];
38
+ export declare function buildExecArgs(opts: KubectlOptions, target: ExecTarget, cmd: string[], interactive: boolean): string[];
39
+ export declare function runArgv(argv: string[], opts?: RunOptions): Promise<ExecResult>;
40
+ export declare class KubectlExecutor implements Executor {
41
+ private readonly opts;
42
+ constructor(opts: KubectlOptions);
43
+ run(sub: string[], opts?: RunOptions): Promise<ExecResult>;
44
+ exec(target: ExecTarget, cmd: string[], opts?: RunOptions): Promise<ExecResult>;
45
+ }
@@ -0,0 +1,13 @@
1
+ import {
2
+ KubectlExecutor,
3
+ buildExecArgs,
4
+ buildKubectlArgs,
5
+ runArgv
6
+ } from "../chunk-0rs1aacd.js";
7
+ import"../chunk-ztenxgjv.js";
8
+ export {
9
+ runArgv,
10
+ buildKubectlArgs,
11
+ buildExecArgs,
12
+ KubectlExecutor
13
+ };
@@ -0,0 +1,12 @@
1
+ /** Append-only raw evidence: readers have independent cursors, memory holds at most one pending block. */
2
+ export declare class LogCaptureFile {
3
+ #private;
4
+ readonly path: string;
5
+ constructor(path: string);
6
+ get size(): number;
7
+ append(line: string): void;
8
+ finish(): void;
9
+ /** Replay existing bytes and follow new bytes in order, including lines not yet flushed to disk. */
10
+ follow(onLine: (line: string) => void): Promise<void>;
11
+ close(): void;
12
+ }
@@ -0,0 +1,6 @@
1
+ import {
2
+ LogCaptureFile
3
+ } from "../chunk-1vfwvgkj.js";
4
+ export {
5
+ LogCaptureFile
6
+ };
@@ -0,0 +1,29 @@
1
+ import { ConcurrencyPool } from "../concurrency";
2
+ import type { KubernetesPodLogAccess, PodLogRequest, PodLogResult } from "./pod-log";
3
+ export interface PodLogCapturePolicy {
4
+ concurrency: number;
5
+ maxBytesPerCapture: number;
6
+ maxTotalBytes: number;
7
+ }
8
+ export interface PodLogCapturePlanItem<T> {
9
+ target: T;
10
+ request: PodLogRequest;
11
+ onStart?: () => void;
12
+ }
13
+ export interface PodLogCapturePlanResult<T> {
14
+ target: T;
15
+ request: PodLogRequest;
16
+ capture: PodLogResult;
17
+ }
18
+ /** A root-owned byte budget. Reservations are made only after obtaining a network slot. */
19
+ export declare class PodLogByteBudget {
20
+ #private;
21
+ constructor(maxBytes: number);
22
+ reserve(maxBytes: number): Promise<number>;
23
+ settle(reserved: number, bytesRead: number): void;
24
+ }
25
+ /**
26
+ * Stern 风格的有界 fan-out:并发完成 transport,但结果严格按计划顺序返回。
27
+ * 每个 worker 启动前预留字节预算,结束后归还未使用部分,避免并发竞争突破总上限。
28
+ */
29
+ export declare function runPodLogCapturePlan<T>(access: KubernetesPodLogAccess, plan: readonly PodLogCapturePlanItem<T>[], policy: PodLogCapturePolicy, pool?: ConcurrencyPool, signal?: AbortSignal, budget?: PodLogByteBudget): Promise<PodLogCapturePlanResult<T>[]>;
@@ -0,0 +1,9 @@
1
+ import {
2
+ PodLogByteBudget,
3
+ runPodLogCapturePlan
4
+ } from "../chunk-8nm9f0hh.js";
5
+ import"../chunk-v3hxvnrc.js";
6
+ export {
7
+ runPodLogCapturePlan,
8
+ PodLogByteBudget
9
+ };
@@ -0,0 +1,2 @@
1
+ /** RFC3339 comparison at container-log precision; Date.parse alone loses sub-millisecond boundaries. */
2
+ export declare function logTimestampNanos(value: string): bigint | undefined;
@@ -0,0 +1,6 @@
1
+ import {
2
+ logTimestampNanos
3
+ } from "../chunk-mp88s7r7.js";
4
+ export {
5
+ logTimestampNanos
6
+ };
@@ -0,0 +1,25 @@
1
+ import type { Client } from "../client";
2
+ import { ConcurrencyPool } from "../concurrency";
3
+ import { PodLogByteBudget, type PodLogCapturePolicy } from "./log-capture-plan";
4
+ import type { KubernetesPodLogAccess, PodLogRequest, PodLogResult } from "./pod-log";
5
+ export interface PodLogSourceScope {
6
+ kubeconfig?: string;
7
+ context?: string;
8
+ namespace: string;
9
+ /** Pod UID and runtime container ID, including the previous instance when selected. */
10
+ instance?: string;
11
+ }
12
+ /**
13
+ * @spec One root execution reads an identical source/window once; each consumer owns its filtering and raw copy.
14
+ * Network capacity and byte reservations apply before transport, never to local replay.
15
+ */
16
+ export declare class PodLogClient implements Client {
17
+ #private;
18
+ private readonly pool;
19
+ private readonly signal;
20
+ private readonly policy;
21
+ constructor(pool: ConcurrencyPool, signal: AbortSignal, policy: PodLogCapturePolicy, budget?: PodLogByteBudget);
22
+ initialize(): Promise<void>;
23
+ capture(access: KubernetesPodLogAccess, scope: PodLogSourceScope, request: PodLogRequest, onReuse?: () => void): Promise<PodLogResult | undefined>;
24
+ dispose(): Promise<void>;
25
+ }
@@ -0,0 +1,12 @@
1
+ import {
2
+ PodLogClient
3
+ } from "../chunk-1at7zs0z.js";
4
+ import"../chunk-8nm9f0hh.js";
5
+ import"../chunk-mp88s7r7.js";
6
+ import"../chunk-1vfwvgkj.js";
7
+ import"../chunk-hqx7j9xe.js";
8
+ import"../chunk-3dt25p98.js";
9
+ import"../chunk-v3hxvnrc.js";
10
+ export {
11
+ PodLogClient
12
+ };
@@ -0,0 +1,17 @@
1
+ import { type DataSource } from "../datasource";
2
+ import type { ConcurrencyPool } from "../concurrency";
3
+ import { PodLogClient } from "./pod-log-client";
4
+ import type { PodLogByteBudget, PodLogCapturePolicy } from "./log-capture-plan";
5
+ /** Target identity is separate from each Pod/container snapshot identity. Limits belong to the root caller. */
6
+ export declare class PodLogDataSource implements DataSource<PodLogClient> {
7
+ private readonly pool;
8
+ private readonly budget;
9
+ private readonly policy;
10
+ readonly key: string;
11
+ constructor(target: {
12
+ kubeconfig?: string;
13
+ context?: string;
14
+ namespace: string;
15
+ }, pool: ConcurrencyPool, budget: PodLogByteBudget, policy: PodLogCapturePolicy);
16
+ createClient(signal: AbortSignal): PodLogClient;
17
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ PodLogClient
3
+ } from "../chunk-1at7zs0z.js";
4
+ import"../chunk-8nm9f0hh.js";
5
+ import"../chunk-mp88s7r7.js";
6
+ import"../chunk-1vfwvgkj.js";
7
+ import {
8
+ dataSourceKey
9
+ } from "../chunk-hqx7j9xe.js";
10
+ import"../chunk-3dt25p98.js";
11
+ import"../chunk-v3hxvnrc.js";
12
+
13
+ // src/kubernetes/pod-log-datasource.ts
14
+ class PodLogDataSource {
15
+ pool;
16
+ budget;
17
+ policy;
18
+ key;
19
+ constructor(target, pool, budget, policy) {
20
+ this.pool = pool;
21
+ this.budget = budget;
22
+ this.policy = policy;
23
+ this.key = dataSourceKey("pod-log", target);
24
+ }
25
+ createClient(signal) {
26
+ return new PodLogClient(this.pool, signal, this.policy, this.budget);
27
+ }
28
+ }
29
+ export {
30
+ PodLogDataSource
31
+ };
@@ -0,0 +1,52 @@
1
+ import type { ExecResult, Executor } from "./executor";
2
+ import { type KubernetesPod } from "./pod";
3
+ export interface ServicePodListResult {
4
+ serviceCapture: ExecResult;
5
+ podCapture: ExecResult;
6
+ byService: Record<string, string[]>;
7
+ pods: KubernetesPod[];
8
+ parseError?: string;
9
+ }
10
+ export interface PodLogRequest {
11
+ pod: string;
12
+ container?: string;
13
+ allContainers?: boolean;
14
+ prefix?: boolean;
15
+ previous?: boolean;
16
+ tail?: number;
17
+ since?: string;
18
+ sinceTime?: string;
19
+ /** Inclusive runtime timestamp boundary, enforced while streaming by the API transport. */
20
+ untilTime?: string;
21
+ /** 单次 Container 日志响应的服务端字节上限。 */
22
+ limitBytes?: number;
23
+ /** 指定后 stdout 原样流式写入该文件,返回值不再在内存中保留 stdout。 */
24
+ rawFilePath?: string;
25
+ onLine?: (line: string) => void;
26
+ /** A streaming sink may own persistence without retaining another copy in stdout. */
27
+ collectStdout?: boolean;
28
+ }
29
+ export type PodLogCaptureStatus = "complete" | "partial" | "unavailable";
30
+ export interface PodLogResult extends ExecResult {
31
+ /** complete=完整读完;partial=保留了部分证据;unavailable=没有取得可用日志。 */
32
+ captureStatus: PodLogCaptureStatus;
33
+ reason?: string;
34
+ bytesRead: number;
35
+ attempts: number;
36
+ /** Replayed from another capture in this root execution; bytesRead only charges the owner. */
37
+ reused?: boolean;
38
+ }
39
+ /** Pod 枚举与日志读取能力;调用方决定采哪个 Pod,infra 决定如何通过 Kubernetes 采。 */
40
+ export interface KubernetesPodLogAccess {
41
+ clientVersion(): Promise<ExecResult>;
42
+ listServicePods(services: readonly string[]): Promise<ServicePodListResult>;
43
+ collectPodLogs(request: PodLogRequest): Promise<PodLogResult>;
44
+ }
45
+ export declare class KubectlPodLogAccess implements KubernetesPodLogAccess {
46
+ private readonly executor;
47
+ private readonly namespace;
48
+ constructor(executor: Executor, namespace: string);
49
+ clientVersion(): Promise<ExecResult>;
50
+ listServicePods(services: readonly string[]): Promise<ServicePodListResult>;
51
+ collectPodLogs(request: PodLogRequest): Promise<PodLogResult>;
52
+ }
@@ -0,0 +1,121 @@
1
+ import {
2
+ findPodsForService,
3
+ parseServices
4
+ } from "../chunk-j46x7j7c.js";
5
+ import {
6
+ parsePods
7
+ } from "../chunk-6fnhzhdb.js";
8
+
9
+ // src/kubernetes/pod-log.ts
10
+ import { closeSync, openSync, writeSync } from "node:fs";
11
+ class KubectlPodLogAccess {
12
+ executor;
13
+ namespace;
14
+ constructor(executor, namespace) {
15
+ this.executor = executor;
16
+ this.namespace = namespace;
17
+ }
18
+ clientVersion() {
19
+ return this.executor.run(["version", "--client"], { timeoutMs: 15000 });
20
+ }
21
+ async listServicePods(services) {
22
+ const [serviceCapture, podCapture] = await Promise.all([
23
+ this.executor.run(["get", "services", "-o", "json"], { timeoutMs: 30000 }),
24
+ this.executor.run(["get", "pods", "-o", "json"], { timeoutMs: 30000 })
25
+ ]);
26
+ const empty = Object.fromEntries(services.map((service) => [service, []]));
27
+ if (!serviceCapture.ok || !podCapture.ok) {
28
+ return { serviceCapture, podCapture, byService: empty, pods: [] };
29
+ }
30
+ try {
31
+ const availableServices = parseServices(serviceCapture.stdout, this.namespace);
32
+ const pods = parsePods(podCapture.stdout, this.namespace);
33
+ return {
34
+ serviceCapture,
35
+ podCapture,
36
+ pods,
37
+ byService: Object.fromEntries(services.map((service) => [
38
+ service,
39
+ findPodsForService(availableServices, pods, service, this.namespace).map((pod) => pod.name)
40
+ ]))
41
+ };
42
+ } catch (err) {
43
+ return {
44
+ serviceCapture,
45
+ podCapture,
46
+ byService: empty,
47
+ pods: [],
48
+ parseError: err instanceof Error ? err.message : String(err)
49
+ };
50
+ }
51
+ }
52
+ async collectPodLogs(request) {
53
+ const args = [
54
+ "logs",
55
+ request.pod,
56
+ "--timestamps=true"
57
+ ];
58
+ if (request.container)
59
+ args.push("-c", request.container);
60
+ if (request.allContainers)
61
+ args.push("--all-containers=true");
62
+ if (request.prefix)
63
+ args.push("--prefix=true");
64
+ if (request.previous)
65
+ args.push("--previous");
66
+ if (request.tail !== undefined)
67
+ args.push(`--tail=${request.tail}`);
68
+ if (request.limitBytes !== undefined)
69
+ args.push(`--limit-bytes=${request.limitBytes}`);
70
+ if (request.sinceTime)
71
+ args.push(`--since-time=${request.sinceTime}`);
72
+ else if (request.since)
73
+ args.push(`--since=${request.since}`);
74
+ if (!request.rawFilePath && !request.onLine && request.collectStdout !== false) {
75
+ const result2 = await this.executor.run(args, { timeoutMs: 60000 });
76
+ const bytesRead2 = Buffer.byteLength(result2.stdout);
77
+ return {
78
+ ...result2,
79
+ captureStatus: result2.ok ? "complete" : bytesRead2 ? "partial" : "unavailable",
80
+ reason: result2.ok ? undefined : result2.stderr.trim() || `exit=${result2.exitCode}`,
81
+ bytesRead: bytesRead2,
82
+ attempts: 1
83
+ };
84
+ }
85
+ const fd = request.rawFilePath ? openSync(request.rawFilePath, "w", 384) : undefined;
86
+ let pending = "";
87
+ let bytesRead = 0;
88
+ const emitLines = (text) => {
89
+ pending += text;
90
+ const lines = pending.split(/\r?\n/);
91
+ pending = lines.pop() ?? "";
92
+ for (const line of lines)
93
+ request.onLine?.(line);
94
+ };
95
+ const result = await this.executor.run(args, {
96
+ timeoutMs: 60000,
97
+ collectStdout: !request.rawFilePath && request.collectStdout !== false,
98
+ onStdoutBytes: (chunk) => {
99
+ bytesRead += chunk.byteLength;
100
+ if (fd !== undefined)
101
+ writeSync(fd, chunk);
102
+ },
103
+ onStdout: request.onLine ? emitLines : undefined
104
+ }).finally(() => {
105
+ if (pending)
106
+ request.onLine?.(pending);
107
+ if (fd !== undefined)
108
+ closeSync(fd);
109
+ });
110
+ return {
111
+ ...result,
112
+ captureStatus: result.ok ? "complete" : bytesRead ? "partial" : "unavailable",
113
+ reason: result.ok ? undefined : result.stderr.trim() || `exit=${result.exitCode}`,
114
+ bytesRead,
115
+ attempts: 1
116
+ };
117
+ }
118
+ }
119
+ export {
120
+ KubectlPodLogAccess
121
+ };
@@ -0,0 +1,61 @@
1
+ import type { KubernetesEndpoint } from "./endpoint";
2
+ export interface KubernetesPod {
3
+ kind: "pod";
4
+ namespace: string;
5
+ name: string;
6
+ uid?: string;
7
+ serviceAccountName: string;
8
+ ip?: string;
9
+ phase: string;
10
+ reason?: string;
11
+ message?: string;
12
+ conditions: KubernetesPodCondition[];
13
+ labels: Record<string, string>;
14
+ containers: KubernetesPodContainer[];
15
+ }
16
+ export interface KubernetesPodCondition {
17
+ type: string;
18
+ status: string;
19
+ reason?: string;
20
+ message?: string;
21
+ lastTransitionTime?: string;
22
+ }
23
+ export type KubernetesContainerState = {
24
+ kind: "waiting";
25
+ reason?: string;
26
+ message?: string;
27
+ } | {
28
+ kind: "running";
29
+ startedAt?: string;
30
+ } | ({
31
+ kind: "terminated";
32
+ } & KubernetesContainerTermination);
33
+ export interface KubernetesContainerTermination {
34
+ exitCode?: number;
35
+ signal?: number;
36
+ reason?: string;
37
+ message?: string;
38
+ startedAt?: string;
39
+ finishedAt?: string;
40
+ containerId?: string;
41
+ }
42
+ export interface KubernetesPodContainer {
43
+ name: string;
44
+ image: string;
45
+ imageId?: string;
46
+ containerId?: string;
47
+ ports?: Array<{
48
+ name?: string;
49
+ containerPort: number;
50
+ }>;
51
+ requests: Record<string, string>;
52
+ limits: Record<string, string>;
53
+ ready?: boolean;
54
+ started?: boolean;
55
+ restartCount: number;
56
+ state?: KubernetesContainerState;
57
+ lastTermination?: KubernetesContainerTermination;
58
+ hasPreviousTerminated: boolean;
59
+ }
60
+ export declare function parsePods(raw: string, defaultNamespace: string): KubernetesPod[];
61
+ export declare function findPod(pods: readonly KubernetesPod[], endpoint: KubernetesEndpoint, defaultNamespace: string): KubernetesPod | undefined;
@@ -0,0 +1,8 @@
1
+ import {
2
+ findPod,
3
+ parsePods
4
+ } from "../chunk-6fnhzhdb.js";
5
+ export {
6
+ parsePods,
7
+ findPod
8
+ };
@@ -0,0 +1,42 @@
1
+ import { type KubectlOptions } from "./executor";
2
+ export interface PortForward {
3
+ target: PortForwardTarget;
4
+ localPort: number;
5
+ /** 完整 argv,进 evidence manifest 供审计复现 */
6
+ command: string[];
7
+ stop(): void;
8
+ }
9
+ export interface PortForwardTarget {
10
+ kind: "service" | "pod";
11
+ name: string;
12
+ }
13
+ export interface PortForwardResult {
14
+ ok: boolean;
15
+ value?: PortForward;
16
+ reason?: string;
17
+ }
18
+ export type StartPortForward = typeof startPortForward;
19
+ /**
20
+ * 起 `kubectl port-forward svc/<service> 0:<remotePort>` 并等待就绪。
21
+ * 本地端口让 kubectl 自选(0:),从 stdout 的 "Forwarding from 127.0.0.1:<port>" 解析,
22
+ * 避免固定端口在运维机上撞占用。调用方负责在采集结束后 stop()。
23
+ */
24
+ export declare function startPortForward(opts: KubectlOptions & {
25
+ service?: string;
26
+ target?: PortForwardTarget;
27
+ remotePort: number;
28
+ timeoutMs?: number;
29
+ }): Promise<PortForwardResult>;
30
+ /** 同一次诊断可能按拓扑建立多个 forward;scope 保证异常路径也能一次性回收。 */
31
+ export declare class PortForwardScope {
32
+ #private;
33
+ private readonly starter;
34
+ constructor(starter?: StartPortForward);
35
+ get active(): readonly PortForward[];
36
+ start(opts: KubectlOptions & {
37
+ target: PortForwardTarget;
38
+ remotePort: number;
39
+ timeoutMs?: number;
40
+ }): Promise<PortForwardResult>;
41
+ stop(): void;
42
+ }
@@ -0,0 +1,10 @@
1
+ import {
2
+ PortForwardScope,
3
+ startPortForward
4
+ } from "../chunk-hv2kx47y.js";
5
+ import"../chunk-0rs1aacd.js";
6
+ import"../chunk-ztenxgjv.js";
7
+ export {
8
+ startPortForward,
9
+ PortForwardScope
10
+ };
@@ -0,0 +1,29 @@
1
+ import type { Executor, KubectlOptions } from "./executor";
2
+ import type { KubernetesEndpoint } from "./endpoint";
3
+ import { type StartPortForward } from "./port-forward";
4
+ export interface ForwardedEndpoint extends KubernetesEndpoint {
5
+ /** TLS 校验仍使用集群内逻辑地址,而不是本地 127.0.0.1。 */
6
+ servername?: string;
7
+ }
8
+ export interface ForwardedServiceTarget extends ForwardedEndpoint {
9
+ pod?: string;
10
+ }
11
+ /**
12
+ * 把集群内 Service/Pod endpoint 映射为本机 endpoint,并缓存同一诊断中的 forward。
13
+ * 它只理解 K8s 网络身份,不理解 Redis/MCP 等调用方协议。
14
+ */
15
+ export declare class ServicePortForwarder {
16
+ #private;
17
+ private readonly opts;
18
+ private readonly services;
19
+ private readonly pods;
20
+ private constructor();
21
+ static create(executor: Executor, opts: KubectlOptions & {
22
+ namespace: string;
23
+ }, starter?: StartPortForward): Promise<ServicePortForwarder>;
24
+ get activeForwards(): readonly import("./port-forward").PortForward[];
25
+ forward(endpoint: KubernetesEndpoint): Promise<ForwardedEndpoint>;
26
+ /** 按 Service selector 把一个逻辑 endpoint 展开为每个 Running Pod 的独立 endpoint。 */
27
+ forwardServiceTargets(endpoint: KubernetesEndpoint): Promise<ForwardedServiceTarget[]>;
28
+ stop(): void;
29
+ }
@@ -0,0 +1,11 @@
1
+ import {
2
+ ServicePortForwarder
3
+ } from "../chunk-205a4vma.js";
4
+ import"../chunk-hv2kx47y.js";
5
+ import"../chunk-j46x7j7c.js";
6
+ import"../chunk-6fnhzhdb.js";
7
+ import"../chunk-0rs1aacd.js";
8
+ import"../chunk-ztenxgjv.js";
9
+ export {
10
+ ServicePortForwarder
11
+ };