@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,6 +1,6 @@
1
1
  {
2
2
  "name": "@output.ai/core",
3
- "version": "0.1.8-dev.pr156.05c9aa2",
3
+ "version": "0.1.8-dev.pr156.696d4dd",
4
4
  "description": "The core module of the output framework",
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,12 +1,11 @@
1
1
  import { appendFileSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
2
- import { dirname, join } from 'node:path';
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
- const __dirname = dirname( fileURLToPath( import.meta.url ) );
9
- const tempDir = join( __dirname, 'temp', 'traces' );
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 base path for trace file storage
32
- * @returns {string} The base path where traces should be written
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 getBasePath = () => {
35
- return process.env.HOST_TRACE_PATH || join( process.cwd(), 'logs' );
35
+ const getLocalOutputDir = workflowName => {
36
+ return join( process.cwd(), 'logs', 'runs', workflowName );
36
37
  };
37
38
 
38
- const getOutputDir = workflowName => {
39
- return join( getBasePath(), 'runs', workflowName );
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
- const dir = getOutputDir( workflowName );
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
- return join( getOutputDir( workflowName ), buildOutputFileName( { workflowId, startTime } ) );
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
- expect( mkdirSyncMock ).toHaveBeenCalledWith( expect.stringMatching( /temp\/traces$/ ), { recursive: true } );
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