runwork 0.3.0 → 0.4.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/dist/api/client.d.ts +2 -1
- package/dist/api/client.js +4 -0
- package/dist/commands/deploy.js +24 -7
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/dev.js +134 -96
- package/dist/commands/info.d.ts +2 -0
- package/dist/commands/info.js +432 -0
- package/dist/commands/integrations.js +19 -2
- package/dist/commands/logs.js +82 -23
- package/dist/commands/open.js +11 -1
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/index.js +6 -1
- package/dist/logs/tailer.d.ts +1 -0
- package/dist/logs/tailer.js +16 -5
- package/dist/types.d.ts +58 -0
- package/dist/utils/__tests__/output.test.d.ts +1 -0
- package/dist/utils/__tests__/output.test.js +38 -0
- package/dist/utils/output.d.ts +17 -0
- package/dist/utils/output.js +27 -0
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by scripts/embed-types.ts -- do not edit
|
|
2
|
-
export const VERSION = "0.
|
|
2
|
+
export const VERSION = "0.4.0";
|
package/dist/index.js
CHANGED
|
@@ -9,13 +9,17 @@ import { upgradeCommand } from './commands/upgrade.js';
|
|
|
9
9
|
import { logoutCommand } from './commands/logout.js';
|
|
10
10
|
import { integrationsCommand } from './commands/integrations.js';
|
|
11
11
|
import { openCommand } from './commands/open.js';
|
|
12
|
+
import { infoCommand } from './commands/info.js';
|
|
12
13
|
import { handleGitCredentialRequest } from './git/credentials.js';
|
|
13
14
|
import { VERSION } from './generated/version.js';
|
|
14
15
|
const program = new Command();
|
|
15
16
|
program
|
|
16
17
|
.name('runwork')
|
|
17
18
|
.description('Runwork CLI - local development for Runwork apps')
|
|
18
|
-
.version(VERSION)
|
|
19
|
+
.version(VERSION)
|
|
20
|
+
.option('--json', 'Output as JSON (auto-enabled when stdout is not a TTY)');
|
|
21
|
+
// Info first -- it's the agent discovery entry point
|
|
22
|
+
program.addCommand(infoCommand);
|
|
19
23
|
program.addCommand(loginCommand);
|
|
20
24
|
program.addCommand(initCommand);
|
|
21
25
|
program.addCommand(cloneCommand);
|
|
@@ -26,6 +30,7 @@ program.addCommand(upgradeCommand);
|
|
|
26
30
|
program.addCommand(logoutCommand);
|
|
27
31
|
program.addCommand(integrationsCommand);
|
|
28
32
|
program.addCommand(openCommand);
|
|
33
|
+
program.addHelpText('after', '\nFor AI agents: run "runwork info --json" to discover app context and available commands.');
|
|
29
34
|
const credentialHelper = program
|
|
30
35
|
.command('git-credential-helper', { hidden: true })
|
|
31
36
|
.argument('<action>', 'Credential action (get/store/erase)')
|
package/dist/logs/tailer.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ interface TailerOptions {
|
|
|
7
7
|
toFile: boolean;
|
|
8
8
|
intervalMs?: number;
|
|
9
9
|
getFilter?: () => 'all' | 'events' | 'runtime';
|
|
10
|
+
useJson?: boolean;
|
|
10
11
|
}
|
|
11
12
|
export declare function formatLogLine(tag: string, line: string): string;
|
|
12
13
|
export declare function formatRelativeTime(eventTimestamp?: string): string;
|
package/dist/logs/tailer.js
CHANGED
|
@@ -54,7 +54,7 @@ export function startLogTailer(options) {
|
|
|
54
54
|
let seenEventIds = new Set();
|
|
55
55
|
let stopped = false;
|
|
56
56
|
let timer;
|
|
57
|
-
function writeLineFiltered(line, tag) {
|
|
57
|
+
function writeLineFiltered(line, tag, jsonData) {
|
|
58
58
|
// Always write to file (stripped of ANSI codes)
|
|
59
59
|
if (toFile) {
|
|
60
60
|
try {
|
|
@@ -64,9 +64,14 @@ export function startLogTailer(options) {
|
|
|
64
64
|
// Silently ignore file write errors
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
// Filter for terminal
|
|
68
67
|
if (!toTerminal)
|
|
69
68
|
return;
|
|
69
|
+
// JSON mode: emit NDJSON line
|
|
70
|
+
if (options.useJson && jsonData) {
|
|
71
|
+
process.stdout.write(JSON.stringify(jsonData) + '\n');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// Human mode: apply filter and print colored line
|
|
70
75
|
const filter = options.getFilter?.() || 'all';
|
|
71
76
|
if (filter === 'events' && tag !== 'EVENT')
|
|
72
77
|
return;
|
|
@@ -91,7 +96,9 @@ export function startLogTailer(options) {
|
|
|
91
96
|
const newContent = logs.stdout.slice(lastStdoutLength);
|
|
92
97
|
const lines = newContent.split('\n').filter(Boolean);
|
|
93
98
|
for (const line of lines) {
|
|
94
|
-
writeLineFiltered(formatLogLine('RUNTIME', line), 'RUNTIME'
|
|
99
|
+
writeLineFiltered(formatLogLine('RUNTIME', line), 'RUNTIME', {
|
|
100
|
+
event: 'log', type: 'runtime', message: line, timestamp: new Date().toISOString(),
|
|
101
|
+
});
|
|
95
102
|
}
|
|
96
103
|
lastStdoutLength = logs.stdout.length;
|
|
97
104
|
}
|
|
@@ -99,7 +106,9 @@ export function startLogTailer(options) {
|
|
|
99
106
|
const newContent = logs.stderr.slice(lastStderrLength);
|
|
100
107
|
const lines = newContent.split('\n').filter(Boolean);
|
|
101
108
|
for (const line of lines) {
|
|
102
|
-
writeLineFiltered(formatLogLine('ERROR', line), 'ERROR'
|
|
109
|
+
writeLineFiltered(formatLogLine('ERROR', line), 'ERROR', {
|
|
110
|
+
event: 'log', type: 'error', message: line, timestamp: new Date().toISOString(),
|
|
111
|
+
});
|
|
103
112
|
}
|
|
104
113
|
lastStderrLength = logs.stderr.length;
|
|
105
114
|
}
|
|
@@ -135,7 +144,9 @@ export function startLogTailer(options) {
|
|
|
135
144
|
}
|
|
136
145
|
}
|
|
137
146
|
const relTime = gray(formatRelativeTime(event.timestamp));
|
|
138
|
-
writeLineFiltered(` ${relTime} ${yellow('EVENT ')} ${event.type}: ${detail}`, 'EVENT'
|
|
147
|
+
writeLineFiltered(` ${relTime} ${yellow('EVENT ')} ${event.type}: ${detail}`, 'EVENT', {
|
|
148
|
+
event: 'log', type: 'event', eventType: event.type, detail, metadata: event.metadata || {}, timestamp: event.timestamp,
|
|
149
|
+
});
|
|
139
150
|
seenEventIds.add(event.id);
|
|
140
151
|
}
|
|
141
152
|
// Cap the set size to prevent unbounded growth (keep last 200 IDs)
|
package/dist/types.d.ts
CHANGED
|
@@ -26,3 +26,61 @@ export interface WorkspaceInfo {
|
|
|
26
26
|
id: string;
|
|
27
27
|
name: string;
|
|
28
28
|
}
|
|
29
|
+
export interface RegistryEntity {
|
|
30
|
+
entityName: string;
|
|
31
|
+
appId: string;
|
|
32
|
+
appName: string;
|
|
33
|
+
schema?: Record<string, unknown>;
|
|
34
|
+
deploymentMode?: 'preview' | 'production';
|
|
35
|
+
}
|
|
36
|
+
export interface RegistrySchedule {
|
|
37
|
+
name: string;
|
|
38
|
+
appId: string;
|
|
39
|
+
appName: string;
|
|
40
|
+
schedule?: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
deploymentMode?: 'preview' | 'production';
|
|
43
|
+
}
|
|
44
|
+
export interface RegistryWorkflow {
|
|
45
|
+
name: string;
|
|
46
|
+
appId: string;
|
|
47
|
+
appName: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
deploymentMode?: 'preview' | 'production';
|
|
50
|
+
}
|
|
51
|
+
export interface RegistryAgent {
|
|
52
|
+
name: string;
|
|
53
|
+
appId: string;
|
|
54
|
+
appName: string;
|
|
55
|
+
type?: string;
|
|
56
|
+
description?: string;
|
|
57
|
+
deploymentMode?: 'preview' | 'production';
|
|
58
|
+
}
|
|
59
|
+
export interface RegistryEndpoint {
|
|
60
|
+
appId: string;
|
|
61
|
+
appName: string;
|
|
62
|
+
path: string;
|
|
63
|
+
method: string;
|
|
64
|
+
description?: string;
|
|
65
|
+
deploymentMode?: 'preview' | 'production';
|
|
66
|
+
}
|
|
67
|
+
export interface RegistryComponent {
|
|
68
|
+
componentName: string;
|
|
69
|
+
appId: string;
|
|
70
|
+
appName: string;
|
|
71
|
+
deploymentMode?: 'preview' | 'production';
|
|
72
|
+
}
|
|
73
|
+
export interface RegistryFileStorage {
|
|
74
|
+
appId: string;
|
|
75
|
+
appName: string;
|
|
76
|
+
deploymentMode?: 'preview' | 'production';
|
|
77
|
+
}
|
|
78
|
+
export interface WorkspaceAllData {
|
|
79
|
+
entities: RegistryEntity[];
|
|
80
|
+
schedules: RegistrySchedule[];
|
|
81
|
+
workflows: RegistryWorkflow[];
|
|
82
|
+
agents: RegistryAgent[];
|
|
83
|
+
endpoints: RegistryEndpoint[];
|
|
84
|
+
components: RegistryComponent[];
|
|
85
|
+
fileStorages: RegistryFileStorage[];
|
|
86
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { shouldOutputJson, jsonOut, jsonLine } from '../output.js';
|
|
3
|
+
describe('shouldOutputJson', () => {
|
|
4
|
+
it('returns true when json flag is true', () => {
|
|
5
|
+
expect(shouldOutputJson(true)).toBe(true);
|
|
6
|
+
});
|
|
7
|
+
it('returns false when json flag is false (--no-json)', () => {
|
|
8
|
+
expect(shouldOutputJson(false)).toBe(false);
|
|
9
|
+
});
|
|
10
|
+
it('returns false when undefined and stdout is TTY', () => {
|
|
11
|
+
const original = process.stdout.isTTY;
|
|
12
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: true, writable: true });
|
|
13
|
+
expect(shouldOutputJson(undefined)).toBe(false);
|
|
14
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: original, writable: true });
|
|
15
|
+
});
|
|
16
|
+
it('returns true when undefined and stdout is not TTY', () => {
|
|
17
|
+
const original = process.stdout.isTTY;
|
|
18
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: false, writable: true });
|
|
19
|
+
expect(shouldOutputJson(undefined)).toBe(true);
|
|
20
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: original, writable: true });
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('jsonOut', () => {
|
|
24
|
+
it('writes JSON to stdout with newline', () => {
|
|
25
|
+
const spy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
26
|
+
jsonOut({ hello: 'world' });
|
|
27
|
+
expect(spy).toHaveBeenCalledWith('{"hello":"world"}\n');
|
|
28
|
+
spy.mockRestore();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('jsonLine', () => {
|
|
32
|
+
it('writes a single NDJSON line', () => {
|
|
33
|
+
const spy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
34
|
+
jsonLine({ event: 'test', ts: 123 });
|
|
35
|
+
expect(spy).toHaveBeenCalledWith('{"event":"test","ts":123}\n');
|
|
36
|
+
spy.mockRestore();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON output utilities for agent-friendly CLI.
|
|
3
|
+
*
|
|
4
|
+
* When stdout is not a TTY (piped/captured by an agent), output switches
|
|
5
|
+
* to machine-readable JSON automatically. The --json flag forces it.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Determine whether to output JSON based on:
|
|
9
|
+
* 1. Explicit --json flag (true)
|
|
10
|
+
* 2. Explicit --no-json flag (false)
|
|
11
|
+
* 3. Auto-detect: non-TTY stdout means agent/pipe, output JSON
|
|
12
|
+
*/
|
|
13
|
+
export declare function shouldOutputJson(jsonFlag: boolean | undefined): boolean;
|
|
14
|
+
/** Write a single JSON object to stdout (for one-shot commands). */
|
|
15
|
+
export declare function jsonOut(data: unknown): void;
|
|
16
|
+
/** Write one NDJSON line to stdout (for streaming commands). */
|
|
17
|
+
export declare function jsonLine(data: unknown): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON output utilities for agent-friendly CLI.
|
|
3
|
+
*
|
|
4
|
+
* When stdout is not a TTY (piped/captured by an agent), output switches
|
|
5
|
+
* to machine-readable JSON automatically. The --json flag forces it.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Determine whether to output JSON based on:
|
|
9
|
+
* 1. Explicit --json flag (true)
|
|
10
|
+
* 2. Explicit --no-json flag (false)
|
|
11
|
+
* 3. Auto-detect: non-TTY stdout means agent/pipe, output JSON
|
|
12
|
+
*/
|
|
13
|
+
export function shouldOutputJson(jsonFlag) {
|
|
14
|
+
if (jsonFlag === true)
|
|
15
|
+
return true;
|
|
16
|
+
if (jsonFlag === false)
|
|
17
|
+
return false;
|
|
18
|
+
return !process.stdout.isTTY;
|
|
19
|
+
}
|
|
20
|
+
/** Write a single JSON object to stdout (for one-shot commands). */
|
|
21
|
+
export function jsonOut(data) {
|
|
22
|
+
process.stdout.write(JSON.stringify(data) + '\n');
|
|
23
|
+
}
|
|
24
|
+
/** Write one NDJSON line to stdout (for streaming commands). */
|
|
25
|
+
export function jsonLine(data) {
|
|
26
|
+
process.stdout.write(JSON.stringify(data) + '\n');
|
|
27
|
+
}
|
package/package.json
CHANGED