repterm 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 (97) hide show
  1. package/dist/api/describe.d.ts +18 -0
  2. package/dist/api/describe.d.ts.map +1 -0
  3. package/dist/api/describe.js +33 -0
  4. package/dist/api/describe.js.map +1 -0
  5. package/dist/api/expect.d.ts +43 -0
  6. package/dist/api/expect.d.ts.map +1 -0
  7. package/dist/api/expect.js +167 -0
  8. package/dist/api/expect.js.map +1 -0
  9. package/dist/api/hooks.d.ts +178 -0
  10. package/dist/api/hooks.d.ts.map +1 -0
  11. package/dist/api/hooks.js +231 -0
  12. package/dist/api/hooks.js.map +1 -0
  13. package/dist/api/steps.d.ts +45 -0
  14. package/dist/api/steps.d.ts.map +1 -0
  15. package/dist/api/steps.js +106 -0
  16. package/dist/api/steps.js.map +1 -0
  17. package/dist/api/test.d.ts +101 -0
  18. package/dist/api/test.d.ts.map +1 -0
  19. package/dist/api/test.js +207 -0
  20. package/dist/api/test.js.map +1 -0
  21. package/dist/cli/index.d.ts +7 -0
  22. package/dist/cli/index.d.ts.map +1 -0
  23. package/dist/cli/index.js +203 -0
  24. package/dist/cli/index.js.map +1 -0
  25. package/dist/cli/reporter.d.ts +108 -0
  26. package/dist/cli/reporter.d.ts.map +1 -0
  27. package/dist/cli/reporter.js +368 -0
  28. package/dist/cli/reporter.js.map +1 -0
  29. package/dist/index.d.ts +15 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +24 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/plugin/index.d.ts +47 -0
  34. package/dist/plugin/index.d.ts.map +1 -0
  35. package/dist/plugin/index.js +86 -0
  36. package/dist/plugin/index.js.map +1 -0
  37. package/dist/plugin/withPlugins.d.ts +71 -0
  38. package/dist/plugin/withPlugins.d.ts.map +1 -0
  39. package/dist/plugin/withPlugins.js +101 -0
  40. package/dist/plugin/withPlugins.js.map +1 -0
  41. package/dist/recording/recorder.d.ts +45 -0
  42. package/dist/recording/recorder.d.ts.map +1 -0
  43. package/dist/recording/recorder.js +97 -0
  44. package/dist/recording/recorder.js.map +1 -0
  45. package/dist/runner/artifacts.d.ts +39 -0
  46. package/dist/runner/artifacts.d.ts.map +1 -0
  47. package/dist/runner/artifacts.js +59 -0
  48. package/dist/runner/artifacts.js.map +1 -0
  49. package/dist/runner/config.d.ts +46 -0
  50. package/dist/runner/config.d.ts.map +1 -0
  51. package/dist/runner/config.js +65 -0
  52. package/dist/runner/config.js.map +1 -0
  53. package/dist/runner/filter.d.ts +26 -0
  54. package/dist/runner/filter.d.ts.map +1 -0
  55. package/dist/runner/filter.js +88 -0
  56. package/dist/runner/filter.js.map +1 -0
  57. package/dist/runner/loader.d.ts +32 -0
  58. package/dist/runner/loader.d.ts.map +1 -0
  59. package/dist/runner/loader.js +252 -0
  60. package/dist/runner/loader.js.map +1 -0
  61. package/dist/runner/models.d.ts +261 -0
  62. package/dist/runner/models.d.ts.map +1 -0
  63. package/dist/runner/models.js +5 -0
  64. package/dist/runner/models.js.map +1 -0
  65. package/dist/runner/runner.d.ts +36 -0
  66. package/dist/runner/runner.d.ts.map +1 -0
  67. package/dist/runner/runner.js +216 -0
  68. package/dist/runner/runner.js.map +1 -0
  69. package/dist/runner/scheduler.d.ts +59 -0
  70. package/dist/runner/scheduler.d.ts.map +1 -0
  71. package/dist/runner/scheduler.js +157 -0
  72. package/dist/runner/scheduler.js.map +1 -0
  73. package/dist/runner/worker-runner.d.ts +6 -0
  74. package/dist/runner/worker-runner.d.ts.map +1 -0
  75. package/dist/runner/worker-runner.js +51 -0
  76. package/dist/runner/worker-runner.js.map +1 -0
  77. package/dist/runner/worker.d.ts +54 -0
  78. package/dist/runner/worker.d.ts.map +1 -0
  79. package/dist/runner/worker.js +112 -0
  80. package/dist/runner/worker.js.map +1 -0
  81. package/dist/terminal/session.d.ts +56 -0
  82. package/dist/terminal/session.d.ts.map +1 -0
  83. package/dist/terminal/session.js +126 -0
  84. package/dist/terminal/session.js.map +1 -0
  85. package/dist/terminal/terminal.d.ts +284 -0
  86. package/dist/terminal/terminal.d.ts.map +1 -0
  87. package/dist/terminal/terminal.js +1167 -0
  88. package/dist/terminal/terminal.js.map +1 -0
  89. package/dist/utils/dependencies.d.ts +19 -0
  90. package/dist/utils/dependencies.d.ts.map +1 -0
  91. package/dist/utils/dependencies.js +58 -0
  92. package/dist/utils/dependencies.js.map +1 -0
  93. package/dist/utils/timing.d.ts +55 -0
  94. package/dist/utils/timing.d.ts.map +1 -0
  95. package/dist/utils/timing.js +87 -0
  96. package/dist/utils/timing.js.map +1 -0
  97. package/package.json +43 -0
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Worker process runner for parallel test execution
3
+ * Runs tests in isolated worker processes
4
+ */
5
+ import { fork } from 'child_process';
6
+ import { EventEmitter } from 'events';
7
+ /**
8
+ * Worker process manager
9
+ */
10
+ export class Worker extends EventEmitter {
11
+ process = null;
12
+ config;
13
+ busy = false;
14
+ constructor(config) {
15
+ super();
16
+ this.config = config;
17
+ }
18
+ /**
19
+ * Start the worker process
20
+ */
21
+ start() {
22
+ if (this.process) {
23
+ throw new Error('Worker already started');
24
+ }
25
+ // Fork a new process running the worker script
26
+ this.process = fork(new URL('./worker-runner.js', import.meta.url).pathname, [], {
27
+ stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
28
+ });
29
+ // Handle messages from worker
30
+ this.process.on('message', (message) => {
31
+ this.handleMessage(message);
32
+ });
33
+ // Handle worker exit
34
+ this.process.on('exit', (code) => {
35
+ this.emit('exit', code);
36
+ });
37
+ // Handle worker errors
38
+ this.process.on('error', (error) => {
39
+ this.emit('error', error);
40
+ });
41
+ }
42
+ /**
43
+ * Run a test suite in the worker
44
+ */
45
+ runSuite(suite) {
46
+ if (!this.process) {
47
+ throw new Error('Worker not started');
48
+ }
49
+ if (this.busy) {
50
+ throw new Error('Worker is busy');
51
+ }
52
+ this.busy = true;
53
+ // Send suite to worker
54
+ this.process.send({
55
+ type: 'run',
56
+ data: {
57
+ suite,
58
+ config: this.config.config,
59
+ artifactBaseDir: this.config.artifactBaseDir,
60
+ },
61
+ });
62
+ }
63
+ /**
64
+ * Stop the worker
65
+ */
66
+ stop() {
67
+ if (this.process) {
68
+ this.process.kill();
69
+ this.process = null;
70
+ }
71
+ }
72
+ /**
73
+ * Check if worker is busy
74
+ */
75
+ isBusy() {
76
+ return this.busy;
77
+ }
78
+ /**
79
+ * Get worker ID
80
+ */
81
+ getWorkerId() {
82
+ return this.config.workerId;
83
+ }
84
+ /**
85
+ * Handle message from worker
86
+ */
87
+ handleMessage(message) {
88
+ switch (message.type) {
89
+ case 'ready':
90
+ this.emit('ready');
91
+ break;
92
+ case 'result':
93
+ this.emit('result', message.data);
94
+ break;
95
+ case 'done':
96
+ this.busy = false;
97
+ this.emit('done', message.data);
98
+ break;
99
+ case 'error':
100
+ this.busy = false;
101
+ this.emit('error', message.data);
102
+ break;
103
+ }
104
+ }
105
+ }
106
+ /**
107
+ * Create a worker
108
+ */
109
+ export function createWorker(config) {
110
+ return new Worker(config);
111
+ }
112
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/runner/worker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Terminal session abstraction around bun-pty
3
+ * Provides core PTY operations for terminal interaction
4
+ */
5
+ import { EventEmitter } from 'events';
6
+ export interface SessionConfig {
7
+ cols?: number;
8
+ rows?: number;
9
+ env?: Record<string, string>;
10
+ }
11
+ export interface SessionOptions extends SessionConfig {
12
+ shell?: string;
13
+ args?: string[];
14
+ }
15
+ /**
16
+ * Terminal session wrapper around bun-pty
17
+ */
18
+ export declare class TerminalSession extends EventEmitter {
19
+ private pty;
20
+ private outputBuffer;
21
+ private config;
22
+ constructor(config?: SessionConfig);
23
+ /**
24
+ * Start the terminal session
25
+ */
26
+ start(options?: SessionOptions): void;
27
+ /**
28
+ * Write data to the terminal
29
+ */
30
+ write(data: string): void;
31
+ /**
32
+ * Get the current output buffer
33
+ */
34
+ getOutput(): string;
35
+ /**
36
+ * Clear the output buffer
37
+ */
38
+ clearOutput(): void;
39
+ /**
40
+ * Resize the terminal
41
+ */
42
+ resize(cols: number, rows: number): void;
43
+ /**
44
+ * Kill the terminal process
45
+ */
46
+ kill(signal?: string): void;
47
+ /**
48
+ * Check if the session is active
49
+ */
50
+ isActive(): boolean;
51
+ /**
52
+ * Get the process ID
53
+ */
54
+ getPid(): number | undefined;
55
+ }
56
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/terminal/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAKD;;GAEG;AACH,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,OAAO,CAAC,GAAG,CAAqB;IAChC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,GAAE,aAAkB;IAsBtC;;OAEG;IACH,KAAK,CAAC,OAAO,GAAE,cAAmB,GAAG,IAAI;IA0CzC;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAOzB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,WAAW,IAAI,IAAI;IAInB;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAOxC;;OAEG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAO3B;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,MAAM,IAAI,MAAM,GAAG,SAAS;CAG7B"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Terminal session abstraction around bun-pty
3
+ * Provides core PTY operations for terminal interaction
4
+ */
5
+ import { spawn } from 'bun-pty';
6
+ import { EventEmitter } from 'events';
7
+ const DEFAULT_COLS = 80;
8
+ const DEFAULT_ROWS = 24;
9
+ /**
10
+ * Terminal session wrapper around bun-pty
11
+ */
12
+ export class TerminalSession extends EventEmitter {
13
+ pty = null;
14
+ outputBuffer = '';
15
+ config;
16
+ constructor(config = {}) {
17
+ super();
18
+ // Convert process.env to Record<string, string> by filtering undefined values
19
+ let env = {};
20
+ if (config.env) {
21
+ env = config.env;
22
+ }
23
+ else {
24
+ for (const [key, value] of Object.entries(process.env)) {
25
+ if (value !== undefined) {
26
+ env[key] = value;
27
+ }
28
+ }
29
+ }
30
+ this.config = {
31
+ cols: config.cols ?? DEFAULT_COLS,
32
+ rows: config.rows ?? DEFAULT_ROWS,
33
+ env,
34
+ };
35
+ }
36
+ /**
37
+ * Start the terminal session
38
+ */
39
+ start(options = {}) {
40
+ if (this.pty) {
41
+ throw new Error('Terminal session already started');
42
+ }
43
+ const shell = options.shell ?? process.env.SHELL ?? '/bin/bash';
44
+ const args = options.args ?? [];
45
+ // Merge environment variables, filtering out undefined values
46
+ const mergedEnv = { ...this.config.env, ...options.env };
47
+ const env = {};
48
+ for (const [key, value] of Object.entries(mergedEnv)) {
49
+ if (value !== undefined) {
50
+ env[key] = value;
51
+ }
52
+ }
53
+ // Ensure TERM is set to xterm-256color for proper color support
54
+ if (!env.TERM) {
55
+ env.TERM = 'xterm-256color';
56
+ }
57
+ this.pty = spawn(shell, args, {
58
+ name: 'xterm-256color', // Support 256 colors (like simple-example.js)
59
+ cols: options.cols ?? this.config.cols ?? DEFAULT_COLS,
60
+ rows: options.rows ?? this.config.rows ?? DEFAULT_ROWS,
61
+ cwd: process.cwd(),
62
+ env,
63
+ });
64
+ // Capture output
65
+ this.pty.onData((data) => {
66
+ this.outputBuffer += data;
67
+ this.emit('data', data);
68
+ });
69
+ // Handle exit
70
+ this.pty.onExit(({ exitCode, signal }) => {
71
+ this.emit('exit', { exitCode, signal });
72
+ });
73
+ }
74
+ /**
75
+ * Write data to the terminal
76
+ */
77
+ write(data) {
78
+ if (!this.pty) {
79
+ throw new Error('Terminal session not started');
80
+ }
81
+ this.pty.write(data);
82
+ }
83
+ /**
84
+ * Get the current output buffer
85
+ */
86
+ getOutput() {
87
+ return this.outputBuffer;
88
+ }
89
+ /**
90
+ * Clear the output buffer
91
+ */
92
+ clearOutput() {
93
+ this.outputBuffer = '';
94
+ }
95
+ /**
96
+ * Resize the terminal
97
+ */
98
+ resize(cols, rows) {
99
+ if (!this.pty) {
100
+ throw new Error('Terminal session not started');
101
+ }
102
+ this.pty.resize(cols, rows);
103
+ }
104
+ /**
105
+ * Kill the terminal process
106
+ */
107
+ kill(signal) {
108
+ if (this.pty) {
109
+ this.pty.kill(signal);
110
+ this.pty = null;
111
+ }
112
+ }
113
+ /**
114
+ * Check if the session is active
115
+ */
116
+ isActive() {
117
+ return this.pty !== null;
118
+ }
119
+ /**
120
+ * Get the process ID
121
+ */
122
+ getPid() {
123
+ return this.pty?.pid;
124
+ }
125
+ }
126
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/terminal/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAa,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAatC,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,YAAY;IACvC,GAAG,GAAgB,IAAI,CAAC;IACxB,YAAY,GAAW,EAAE,CAAC;IAC1B,MAAM,CAAgB;IAE9B,YAAY,SAAwB,EAAE;QACpC,KAAK,EAAE,CAAC;QAER,8EAA8E;QAC9E,IAAI,GAAG,GAA2B,EAAE,CAAC;QACrC,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YACf,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBACnB,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,GAAG;YACZ,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,YAAY;YACjC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,YAAY;YACjC,GAAG;SACJ,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAA0B,EAAE;QAChC,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,WAAW,CAAC;QAChE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QAEhC,8DAA8D;QAC9D,MAAM,SAAS,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QACzD,MAAM,GAAG,GAA2B,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACrD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACnB,CAAC;QACH,CAAC;QAED,gEAAgE;QAChE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACd,GAAG,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE;YAC5B,IAAI,EAAE,gBAAgB,EAAG,8CAA8C;YACvE,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,YAAY;YACtD,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,YAAY;YACtD,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,GAAG;SACJ,CAAC,CAAC;QAEH,iBAAiB;QACjB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YACvB,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,cAAc;QACd,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;YACvC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,WAAW;QACT,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAY,EAAE,IAAY;QAC/B,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,MAAe;QAClB,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,284 @@
1
+ /**
2
+ * Terminal API implementation
3
+ * Provides high-level terminal interaction (start/send/wait/snapshot)
4
+ *
5
+ * 执行架构:
6
+ * - 非录制、非交互模式:使用 Bun.spawn,stdout/stderr 分离,exitCode 精确
7
+ * - 录制或交互模式:使用 PTY,支持复杂交互,但 exitCode 不可靠
8
+ */
9
+ import type { TerminalAPI, WaitOptions, RunOptions, PTYProcess, PluginFactory, TerminalWithPlugins, CommandLog } from '../runner/models.js';
10
+ import { TerminalSession } from './session.js';
11
+ import { EventEmitter } from 'events';
12
+ /**
13
+ * 计算 tmux 输出捕获的行范围
14
+ * 纯函数,可独立单元测试
15
+ */
16
+ export declare function calculateOutputRange(beforeCursorY: number, beforeHistorySize: number, afterCursorY: number, afterHistorySize: number, promptLineCount: number): {
17
+ startLine: number;
18
+ endLine: number;
19
+ };
20
+ export interface TerminalConfig {
21
+ cols?: number;
22
+ rows?: number;
23
+ recording?: boolean;
24
+ recordingPath?: string;
25
+ ptyOnly?: boolean;
26
+ tmuxSessionName?: string;
27
+ tmuxPaneId?: string;
28
+ promptLineCount?: number;
29
+ }
30
+ export interface SharedTerminalState {
31
+ paneCount: number;
32
+ currentActivePane?: number;
33
+ paneOutputs: Map<number, string>;
34
+ }
35
+ /**
36
+ * High-level Terminal API for test authoring
37
+ */
38
+ export declare class Terminal extends EventEmitter implements TerminalAPI {
39
+ private session;
40
+ private recording;
41
+ private ptyOnly;
42
+ private recordingPath?;
43
+ private closed;
44
+ private initialized;
45
+ private tmuxSessionName?;
46
+ private tmuxPaneId?;
47
+ private sharedState;
48
+ private paneIndex?;
49
+ private nonInteractiveOutput;
50
+ private commandLogs;
51
+ private pluginFactory?;
52
+ plugins?: Record<string, unknown>;
53
+ private beforeEnterHistorySize;
54
+ private beforeEnterCursorY;
55
+ private commandLineCount;
56
+ private promptLineCount;
57
+ private promptLineCountConfigured;
58
+ private detectedPromptPattern?;
59
+ constructor(config?: TerminalConfig);
60
+ /**
61
+ * Get tmux session name (for multi-terminal coordination)
62
+ */
63
+ getTmuxSessionName(): string | undefined;
64
+ /**
65
+ * Get tmux pane ID (for multi-terminal coordination)
66
+ */
67
+ getTmuxPaneId(): string | undefined;
68
+ /**
69
+ * Get terminal session (for direct access)
70
+ */
71
+ getSession(): TerminalSession;
72
+ /**
73
+ * Get shared state (for factory to update pane count)
74
+ */
75
+ getSharedState(): SharedTerminalState;
76
+ /**
77
+ * Increment pane count (called by factory when creating new panes)
78
+ */
79
+ incrementPaneCount(): void;
80
+ /**
81
+ * Set parent session (for child terminals that share a session)
82
+ */
83
+ setParentSession(session: TerminalSession, sharedState: SharedTerminalState, paneIndex: number): void;
84
+ /**
85
+ * Select the tmux pane that this terminal is bound to
86
+ * Uses arrow key navigation to switch panes without showing pane IDs
87
+ */
88
+ private selectPane;
89
+ /**
90
+ * 执行命令,返回 PTYProcess
91
+ *
92
+ * 执行模式:
93
+ * - 非录制、非交互(默认):使用 Bun.spawn,stdout/stderr 分离,exitCode 精确
94
+ * - 录制或交互:使用 PTY,支持 expect/send,但 exitCode 返回 -1
95
+ *
96
+ * 用法:
97
+ * - 直接 await: 自动调用 wait(),返回 CommandResult
98
+ * - 不 await: 返回 PTYProcess 控制器,可调用 expect/send/wait 等方法
99
+ *
100
+ * @param command - 要执行的命令
101
+ * @param options - 可选配置,包括 interactive: true 启用交互模式
102
+ */
103
+ run(command: string, options?: RunOptions): PTYProcess;
104
+ /**
105
+ * Initialize terminal session (recording or non-recording)
106
+ */
107
+ private initializeSession;
108
+ /**
109
+ * Wait for shell to be ready (detect shell prompt)
110
+ */
111
+ private waitForShellReady;
112
+ /**
113
+ * Wait for tmux to be ready (detect shell prompt)
114
+ */
115
+ private waitForTmuxReady;
116
+ /**
117
+ * Send text to the terminal
118
+ */
119
+ send(text: string): Promise<void>;
120
+ /**
121
+ * Wait for text to appear in terminal output
122
+ * In recording mode with multi-pane, uses tmux capture-pane for isolation
123
+ */
124
+ waitForText(text: string, options?: WaitOptions): Promise<void>;
125
+ /**
126
+ * Get snapshot of current terminal output
127
+ * In recording mode, returns current pane's output (stripped of ANSI)
128
+ */
129
+ snapshot(): Promise<string>;
130
+ /**
131
+ * Get all output (session + non-interactive commands)
132
+ */
133
+ private getAllOutput;
134
+ /**
135
+ * Capture output from current pane using tmux capture-pane
136
+ * Used in recording mode for per-pane output isolation
137
+ */
138
+ private capturePaneOutput;
139
+ /**
140
+ * Execute a tmux command and return its output
141
+ */
142
+ private runTmuxCommand;
143
+ /**
144
+ * Strip ANSI escape sequences from text
145
+ */
146
+ private stripAnsi;
147
+ /**
148
+ * Append output from non-interactive command (internal use)
149
+ */
150
+ appendNonInteractiveOutput(output: string): void;
151
+ /**
152
+ * Record a command execution result for failure diagnostics
153
+ */
154
+ appendCommandLog(log: CommandLog): void;
155
+ /**
156
+ * Get command logs captured during the current test
157
+ */
158
+ getCommandLogs(): CommandLog[];
159
+ /**
160
+ * 设置插件工厂(用于 create() 自动注入插件)
161
+ * @internal 由插件系统调用
162
+ */
163
+ setPluginFactory<TPlugins>(factory: PluginFactory<TPlugins>): void;
164
+ /**
165
+ * Create a new terminal instance (for multi-terminal tests)
166
+ * - Recording mode: splits tmux window (tmux already started via asciinema --command)
167
+ * - Non-recording mode: creates independent terminal
168
+ * - If pluginFactory is set, new terminal will have plugins property
169
+ */
170
+ create<TPlugins = Record<string, unknown>>(): Promise<TerminalWithPlugins<TPlugins>>;
171
+ /**
172
+ * Close the terminal
173
+ */
174
+ close(): Promise<void>;
175
+ /**
176
+ * Clean up tmux session after recording ends
177
+ */
178
+ private cleanupTmuxSession;
179
+ /**
180
+ * Check if terminal is active
181
+ */
182
+ isActive(): boolean;
183
+ /**
184
+ * Check if terminal is in recording mode
185
+ */
186
+ isRecording(): boolean;
187
+ /**
188
+ * 是否使用 PTY 模式(录制或 pty-only)
189
+ * PTY 模式支持交互式命令,但打字效果仅在 recording 模式下启用
190
+ */
191
+ isPtyMode(): boolean;
192
+ /**
193
+ * Get pane index (for tmux commands)
194
+ */
195
+ getPaneIndex(): number | undefined;
196
+ /**
197
+ * Get session output (for non-recording PTY mode)
198
+ */
199
+ getSessionOutput(): string;
200
+ /**
201
+ * Get output length at current moment (for range capture)
202
+ */
203
+ getOutputLength(): number;
204
+ /**
205
+ * Get the state recorded before sending Enter (for output capture)
206
+ */
207
+ getBeforeEnterState(): {
208
+ historySize: number;
209
+ cursorY: number;
210
+ commandLineCount: number;
211
+ };
212
+ /**
213
+ * Record state before sending Enter (internal use)
214
+ * 使用单次 tmux 查询原子获取 history_size 和 cursor_y,避免竞态条件
215
+ */
216
+ private recordBeforeEnterState;
217
+ /**
218
+ * 在录制开始前检测提示符相关信息
219
+ * - 提示符占用的行数
220
+ * - 提示符匹配 pattern
221
+ * 通过创建临时 tmux session 来测量,检测过程不会出现在录制中
222
+ */
223
+ private detectPromptBeforeRecording;
224
+ /**
225
+ * 分析提示符行,生成匹配正则
226
+ */
227
+ private analyzePromptLine;
228
+ /**
229
+ * 获取检测到的提示符行数
230
+ */
231
+ getPromptLineCount(): number;
232
+ /**
233
+ * 获取检测到的提示符匹配 pattern
234
+ */
235
+ getDetectedPromptPattern(): RegExp | undefined;
236
+ /**
237
+ * Type text with human-like delays (for recording mode)
238
+ * @param text - 要打字的文本
239
+ * @param speed - 每字符延迟 (ms),默认 80ms
240
+ * @param variableSpeed - 是否使用变速模式(更自然)
241
+ */
242
+ private typeWithDelay;
243
+ /**
244
+ * 在录制中显示步骤标题
245
+ */
246
+ private displayStepTitle;
247
+ /**
248
+ * Wait for command to complete
249
+ * Uses prompt detection only
250
+ */
251
+ private waitForOutputStable;
252
+ /**
253
+ * Sleep utility
254
+ */
255
+ private sleep;
256
+ /**
257
+ * Wait for output to stabilize (public, for PTYProcessImpl)
258
+ */
259
+ waitForOutputStablePublic(timeout?: number): Promise<void>;
260
+ /**
261
+ * Execute command in PTY (internal, for PTYProcessImpl)
262
+ */
263
+ executeInPty(command: string, options?: {
264
+ typingSpeed?: number;
265
+ pauseBefore?: number;
266
+ showStepTitle?: boolean;
267
+ stepName?: string;
268
+ }): Promise<void>;
269
+ /**
270
+ * 使用 Bracketed Paste Mode 粘贴多行命令
271
+ * 避免 shell 显示续行提示符(如 quote>、pipe heredoc>)
272
+ *
273
+ * Bracketed Paste Mode 使用转义序列包裹粘贴内容:
274
+ * - \x1b[200~ 标记粘贴开始
275
+ * - \x1b[201~ 标记粘贴结束
276
+ * Shell 会将整个内容作为单个输入块处理,不显示续行提示符
277
+ */
278
+ private pasteWithTmux;
279
+ }
280
+ /**
281
+ * Create a new Terminal instance
282
+ */
283
+ export declare function createTerminal(config?: TerminalConfig): Terminal;
284
+ //# sourceMappingURL=terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/terminal/terminal.ts"],"names":[],"mappings":"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"}