@output.ai/core 0.1.8-dev.pr156.05c9aa2 → 0.1.8-dev.pr156.696d4dd
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/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { appendFileSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import {
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
2
|
+
import { join } from 'node:path';
|
|
4
3
|
import buildTraceTree from '../../tools/build_trace_tree.js';
|
|
5
4
|
import { EOL } from 'node:os';
|
|
6
5
|
|
|
7
6
|
const oneWeekInMS = 1000 * 60 * 60 * 24 * 7;
|
|
8
|
-
|
|
9
|
-
const tempDir = join(
|
|
7
|
+
// Use local working directory for temp files, not module-relative path
|
|
8
|
+
const tempDir = join( process.cwd(), 'logs', 'temp', 'traces' );
|
|
10
9
|
|
|
11
10
|
const accumulate = ( { entry, executionContext: { workflowId, startTime } } ) => {
|
|
12
11
|
const path = join( tempDir, `${startTime}_${workflowId}.trace` );
|
|
@@ -28,15 +27,24 @@ export const init = () => {
|
|
|
28
27
|
};
|
|
29
28
|
|
|
30
29
|
/**
|
|
31
|
-
* Get the
|
|
32
|
-
*
|
|
30
|
+
* Get the local file system path for ALL file I/O operations (read/write)
|
|
31
|
+
* Always uses the container's local working directory
|
|
32
|
+
* @param {string} workflowName - The name of the workflow
|
|
33
|
+
* @returns {string} The local filesystem path for file operations
|
|
33
34
|
*/
|
|
34
|
-
const
|
|
35
|
-
return
|
|
35
|
+
const getLocalOutputDir = workflowName => {
|
|
36
|
+
return join( process.cwd(), 'logs', 'runs', workflowName );
|
|
36
37
|
};
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Get the host path for reporting trace file locations to users
|
|
41
|
+
* Uses HOST_TRACE_PATH if set (for Docker), otherwise uses local path
|
|
42
|
+
* @param {string} workflowName - The name of the workflow
|
|
43
|
+
* @returns {string} The path to report to users/API
|
|
44
|
+
*/
|
|
45
|
+
const getReportOutputDir = workflowName => {
|
|
46
|
+
const basePath = process.env.HOST_TRACE_PATH || join( process.cwd(), 'logs' );
|
|
47
|
+
return join( basePath, 'runs', workflowName );
|
|
40
48
|
};
|
|
41
49
|
|
|
42
50
|
const buildOutputFileName = ( { startTime, workflowId } ) => {
|
|
@@ -58,7 +66,8 @@ export const exec = ( { entry, executionContext } ) => {
|
|
|
58
66
|
const { workflowId, workflowName, startTime } = executionContext;
|
|
59
67
|
const content = buildTraceTree( accumulate( { entry, executionContext } ) );
|
|
60
68
|
|
|
61
|
-
|
|
69
|
+
// Always use local path for writing files
|
|
70
|
+
const dir = getLocalOutputDir( workflowName );
|
|
62
71
|
const path = join( dir, buildOutputFileName( { startTime, workflowId } ) );
|
|
63
72
|
|
|
64
73
|
mkdirSync( dir, { recursive: true } );
|
|
@@ -74,5 +83,6 @@ export const exec = ( { entry, executionContext } ) => {
|
|
|
74
83
|
* @returns {string} The absolute path where the trace will be saved
|
|
75
84
|
*/
|
|
76
85
|
export const getDestination = ( { startTime, workflowId, workflowName } ) => {
|
|
77
|
-
|
|
86
|
+
// Use report path for reporting to users/API
|
|
87
|
+
return join( getReportOutputDir( workflowName ), buildOutputFileName( { workflowId, startTime } ) );
|
|
78
88
|
};
|
|
@@ -29,6 +29,7 @@ describe( 'tracing/processors/local', () => {
|
|
|
29
29
|
vi.clearAllMocks();
|
|
30
30
|
store.files.clear();
|
|
31
31
|
process.argv[2] = '/tmp/project';
|
|
32
|
+
delete process.env.HOST_TRACE_PATH; // Clear HOST_TRACE_PATH for clean tests
|
|
32
33
|
} );
|
|
33
34
|
|
|
34
35
|
it( 'init(): creates temp dir and cleans up old files', async () => {
|
|
@@ -39,7 +40,8 @@ describe( 'tracing/processors/local', () => {
|
|
|
39
40
|
|
|
40
41
|
init();
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
// Should create temp dir under process.cwd()/logs, not module-relative
|
|
44
|
+
expect( mkdirSyncMock ).toHaveBeenCalledWith( expect.stringMatching( /logs\/temp\/traces$/ ), { recursive: true } );
|
|
43
45
|
expect( rmSyncMock ).toHaveBeenCalledTimes( 1 );
|
|
44
46
|
} );
|
|
45
47
|
|
|
@@ -78,5 +80,70 @@ describe( 'tracing/processors/local', () => {
|
|
|
78
80
|
expect( destination ).toMatch( /^\/|^[A-Z]:\\/i ); // Starting with / or Windows drive letter
|
|
79
81
|
expect( destination ).toContain( '/logs/runs/test-workflow/2020-01-02-03-04-05-678Z_workflow-id-123.json' );
|
|
80
82
|
} );
|
|
83
|
+
|
|
84
|
+
it( 'exec(): writes to container path regardless of HOST_TRACE_PATH', async () => {
|
|
85
|
+
const { exec, init } = await import( './index.js' );
|
|
86
|
+
|
|
87
|
+
// Set HOST_TRACE_PATH to simulate Docker environment
|
|
88
|
+
process.env.HOST_TRACE_PATH = '/host/path/logs';
|
|
89
|
+
|
|
90
|
+
init();
|
|
91
|
+
|
|
92
|
+
const startTime = Date.parse( '2020-01-02T03:04:05.678Z' );
|
|
93
|
+
const ctx = { executionContext: { workflowId: 'id1', workflowName: 'WF', startTime } };
|
|
94
|
+
|
|
95
|
+
exec( { ...ctx, entry: { name: 'A', phase: 'start', timestamp: startTime } } );
|
|
96
|
+
|
|
97
|
+
expect( writeFileSyncMock ).toHaveBeenCalledTimes( 1 );
|
|
98
|
+
const [ writtenPath ] = writeFileSyncMock.mock.calls.at( -1 );
|
|
99
|
+
|
|
100
|
+
// Should write to process.cwd()/logs, NOT to HOST_TRACE_PATH
|
|
101
|
+
expect( writtenPath ).not.toContain( '/host/path/logs' );
|
|
102
|
+
expect( writtenPath ).toMatch( /logs\/runs\/WF\// );
|
|
103
|
+
} );
|
|
104
|
+
|
|
105
|
+
it( 'getDestination(): returns HOST_TRACE_PATH when set', async () => {
|
|
106
|
+
const { getDestination } = await import( './index.js' );
|
|
107
|
+
|
|
108
|
+
// Set HOST_TRACE_PATH to simulate Docker environment
|
|
109
|
+
process.env.HOST_TRACE_PATH = '/host/path/logs';
|
|
110
|
+
|
|
111
|
+
const startTime = Date.parse( '2020-01-02T03:04:05.678Z' );
|
|
112
|
+
const workflowId = 'workflow-id-123';
|
|
113
|
+
const workflowName = 'test-workflow';
|
|
114
|
+
|
|
115
|
+
const destination = getDestination( { startTime, workflowId, workflowName } );
|
|
116
|
+
|
|
117
|
+
// Should return HOST_TRACE_PATH-based path for reporting
|
|
118
|
+
expect( destination ).toBe( '/host/path/logs/runs/test-workflow/2020-01-02-03-04-05-678Z_workflow-id-123.json' );
|
|
119
|
+
} );
|
|
120
|
+
|
|
121
|
+
it( 'separation of write and report paths works correctly', async () => {
|
|
122
|
+
const { exec, getDestination, init } = await import( './index.js' );
|
|
123
|
+
|
|
124
|
+
// Set HOST_TRACE_PATH to simulate Docker environment
|
|
125
|
+
process.env.HOST_TRACE_PATH = '/Users/ben/project/logs';
|
|
126
|
+
|
|
127
|
+
init();
|
|
128
|
+
|
|
129
|
+
const startTime = Date.parse( '2020-01-02T03:04:05.678Z' );
|
|
130
|
+
const workflowId = 'workflow-id-123';
|
|
131
|
+
const workflowName = 'test-workflow';
|
|
132
|
+
const ctx = { executionContext: { workflowId, workflowName, startTime } };
|
|
133
|
+
|
|
134
|
+
// Execute to write file
|
|
135
|
+
exec( { ...ctx, entry: { name: 'A', phase: 'start', timestamp: startTime } } );
|
|
136
|
+
|
|
137
|
+
// Get destination for reporting
|
|
138
|
+
const destination = getDestination( { startTime, workflowId, workflowName } );
|
|
139
|
+
|
|
140
|
+
// Verify write path is local
|
|
141
|
+
const [ writtenPath ] = writeFileSyncMock.mock.calls.at( -1 );
|
|
142
|
+
expect( writtenPath ).not.toContain( '/Users/ben/project' );
|
|
143
|
+
expect( writtenPath ).toMatch( /logs\/runs\/test-workflow\// );
|
|
144
|
+
|
|
145
|
+
// Verify report path uses HOST_TRACE_PATH
|
|
146
|
+
expect( destination ).toBe( '/Users/ben/project/logs/runs/test-workflow/2020-01-02-03-04-05-678Z_workflow-id-123.json' );
|
|
147
|
+
} );
|
|
81
148
|
} );
|
|
82
149
|
|