workato-dev-api 1.0.1 → 1.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.
- package/README.md +6 -2
- package/cli.js +16 -8
- package/lib.js +26 -0
- package/package.json +1 -1
- package/test/cli.test.js +138 -0
package/README.md
CHANGED
|
@@ -31,13 +31,16 @@ You can also export it directly in your shell environment.
|
|
|
31
31
|
|
|
32
32
|
## Claude Code setup
|
|
33
33
|
|
|
34
|
-
In a clean working directory, run
|
|
34
|
+
In a clean working directory, run these two commands once before starting Claude Code:
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
|
+
npx workato-dev-api auth YOUR_API_TOKEN
|
|
37
38
|
npx workato-dev-api bootstrap-claude
|
|
38
39
|
```
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
That's it. The first command saves your token to `.env`. The second drops a `CLAUDE.md` into the directory so Claude Code automatically has full context — recipe structure, wiring syntax, data table column names, and project reference IDs.
|
|
42
|
+
|
|
43
|
+
Then just open Claude Code in that directory and start working.
|
|
41
44
|
|
|
42
45
|
## Commands
|
|
43
46
|
|
|
@@ -46,6 +49,7 @@ This writes a `CLAUDE.md` with full context — recipe code structure, wiring sy
|
|
|
46
49
|
| Command | Description |
|
|
47
50
|
|---|---|
|
|
48
51
|
| `workato bootstrap-claude` | Copy `CLAUDE.md` into the current directory |
|
|
52
|
+
| `workato auth <token>` | Save your API token to `.env` in the current directory |
|
|
49
53
|
|
|
50
54
|
### Read
|
|
51
55
|
|
package/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const fs = require('fs');
|
|
5
4
|
const os = require('os');
|
|
6
5
|
const path = require('path');
|
|
7
6
|
const {
|
|
8
7
|
loadEnv,
|
|
8
|
+
cmdBootstrapClaude, cmdAuth,
|
|
9
9
|
cmdGet, cmdListRecipes, cmdListProjects, cmdListFolders,
|
|
10
10
|
cmdListConnections, cmdListDataTables, cmdGetDataTable,
|
|
11
11
|
cmdGetJobs, cmdGetJob,
|
|
@@ -13,12 +13,19 @@ const {
|
|
|
13
13
|
cmdStart, cmdStop, cmdDelete,
|
|
14
14
|
} = require('./lib');
|
|
15
15
|
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
// Setup commands run before env/token setup
|
|
17
|
+
const _setupCmd = process.argv[2];
|
|
18
|
+
if (_setupCmd === 'bootstrap-claude') {
|
|
19
|
+
cmdBootstrapClaude(process.cwd());
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
if (_setupCmd === 'auth') {
|
|
23
|
+
const token = process.argv[3];
|
|
24
|
+
if (!token) {
|
|
25
|
+
console.error('Usage: workato auth <token>');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
cmdAuth(token, process.cwd());
|
|
22
29
|
process.exit(0);
|
|
23
30
|
}
|
|
24
31
|
|
|
@@ -29,7 +36,7 @@ loadEnv(path.join(os.homedir(), '.env'));
|
|
|
29
36
|
loadEnv(path.join(process.cwd(), '.env'));
|
|
30
37
|
|
|
31
38
|
if (!process.env.WORKATO_API_TOKEN) {
|
|
32
|
-
console.error('Error: WORKATO_API_TOKEN not set.\
|
|
39
|
+
console.error('Error: WORKATO_API_TOKEN not set.\nRun: workato auth <your_token>\nOr create a .env file with: WORKATO_API_TOKEN=your_token_here');
|
|
33
40
|
process.exit(1);
|
|
34
41
|
}
|
|
35
42
|
|
|
@@ -61,6 +68,7 @@ workato <command> [options]
|
|
|
61
68
|
|
|
62
69
|
Setup:
|
|
63
70
|
bootstrap-claude Copy CLAUDE.md into the current directory
|
|
71
|
+
auth <token> Save API token to .env in the current directory
|
|
64
72
|
|
|
65
73
|
Read commands:
|
|
66
74
|
get <recipe_id> Fetch recipe code → recipe_<id>_code.json
|
package/lib.js
CHANGED
|
@@ -143,6 +143,30 @@ function apiTriggerConfig() {
|
|
|
143
143
|
];
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
// ── Setup commands ────────────────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
function cmdBootstrapClaude(destDir) {
|
|
149
|
+
const src = path.join(__dirname, 'CLAUDE.md');
|
|
150
|
+
const dest = path.join(destDir ?? process.cwd(), 'CLAUDE.md');
|
|
151
|
+
fs.copyFileSync(src, dest);
|
|
152
|
+
console.log(`CLAUDE.md written to ${dest}`);
|
|
153
|
+
return dest;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function cmdAuth(token, destDir) {
|
|
157
|
+
const envPath = path.join(destDir ?? process.cwd(), '.env');
|
|
158
|
+
let content = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf8') : '';
|
|
159
|
+
const line = `WORKATO_API_TOKEN=${token}`;
|
|
160
|
+
if (/^WORKATO_API_TOKEN=/m.test(content)) {
|
|
161
|
+
content = content.replace(/^WORKATO_API_TOKEN=.*/m, line);
|
|
162
|
+
} else {
|
|
163
|
+
content = content ? content.trimEnd() + '\n' + line + '\n' : line + '\n';
|
|
164
|
+
}
|
|
165
|
+
fs.writeFileSync(envPath, content);
|
|
166
|
+
console.log(`Token saved to ${envPath}`);
|
|
167
|
+
return envPath;
|
|
168
|
+
}
|
|
169
|
+
|
|
146
170
|
// ── Read commands ─────────────────────────────────────────────────────────────
|
|
147
171
|
|
|
148
172
|
async function cmdGet(recipeId) {
|
|
@@ -313,6 +337,8 @@ module.exports = {
|
|
|
313
337
|
// helpers
|
|
314
338
|
findStep, deepMerge, extractCode,
|
|
315
339
|
apiTriggerCode, apiTriggerConfig,
|
|
340
|
+
// setup commands
|
|
341
|
+
cmdBootstrapClaude, cmdAuth,
|
|
316
342
|
// read commands
|
|
317
343
|
cmdGet, cmdListRecipes, cmdListProjects, cmdListFolders,
|
|
318
344
|
cmdListConnections, cmdListDataTables, cmdGetDataTable,
|
package/package.json
CHANGED
package/test/cli.test.js
CHANGED
|
@@ -982,6 +982,144 @@ describe('cmdUpdateStep — deeply nested step', () => {
|
|
|
982
982
|
});
|
|
983
983
|
});
|
|
984
984
|
|
|
985
|
+
// ── cmdBootstrapClaude ────────────────────────────────────────────────────────
|
|
986
|
+
|
|
987
|
+
describe('cmdBootstrapClaude', () => {
|
|
988
|
+
function tmpDir() {
|
|
989
|
+
const d = path.join(os.tmpdir(), `workato-test-${Date.now()}-${Math.random()}`);
|
|
990
|
+
fs.mkdirSync(d, { recursive: true });
|
|
991
|
+
return d;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
test('copies CLAUDE.md into the destination directory', () => {
|
|
995
|
+
const dir = tmpDir();
|
|
996
|
+
try {
|
|
997
|
+
lib.cmdBootstrapClaude(dir);
|
|
998
|
+
assert.ok(fs.existsSync(path.join(dir, 'CLAUDE.md')), 'CLAUDE.md should exist in dest dir');
|
|
999
|
+
} finally {
|
|
1000
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1001
|
+
}
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
test('written file content matches the source CLAUDE.md', () => {
|
|
1005
|
+
const dir = tmpDir();
|
|
1006
|
+
try {
|
|
1007
|
+
lib.cmdBootstrapClaude(dir);
|
|
1008
|
+
const srcPath = path.join(__dirname, '..', 'CLAUDE.md');
|
|
1009
|
+
const src = fs.readFileSync(srcPath, 'utf8');
|
|
1010
|
+
const dest = fs.readFileSync(path.join(dir, 'CLAUDE.md'), 'utf8');
|
|
1011
|
+
assert.equal(dest, src);
|
|
1012
|
+
} finally {
|
|
1013
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
test('returns the destination file path', () => {
|
|
1018
|
+
const dir = tmpDir();
|
|
1019
|
+
try {
|
|
1020
|
+
const result = lib.cmdBootstrapClaude(dir);
|
|
1021
|
+
assert.equal(result, path.join(dir, 'CLAUDE.md'));
|
|
1022
|
+
} finally {
|
|
1023
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
test('overwrites an existing CLAUDE.md', () => {
|
|
1028
|
+
const dir = tmpDir();
|
|
1029
|
+
try {
|
|
1030
|
+
fs.writeFileSync(path.join(dir, 'CLAUDE.md'), 'old content');
|
|
1031
|
+
lib.cmdBootstrapClaude(dir);
|
|
1032
|
+
const content = fs.readFileSync(path.join(dir, 'CLAUDE.md'), 'utf8');
|
|
1033
|
+
assert.notEqual(content, 'old content');
|
|
1034
|
+
} finally {
|
|
1035
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1036
|
+
}
|
|
1037
|
+
});
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
// ── cmdAuth ───────────────────────────────────────────────────────────────────
|
|
1041
|
+
|
|
1042
|
+
describe('cmdAuth', () => {
|
|
1043
|
+
function tmpDir() {
|
|
1044
|
+
const d = path.join(os.tmpdir(), `workato-auth-test-${Date.now()}-${Math.random()}`);
|
|
1045
|
+
fs.mkdirSync(d, { recursive: true });
|
|
1046
|
+
return d;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
test('creates .env with token when file does not exist', () => {
|
|
1050
|
+
const dir = tmpDir();
|
|
1051
|
+
try {
|
|
1052
|
+
lib.cmdAuth('mytoken123', dir);
|
|
1053
|
+
const content = fs.readFileSync(path.join(dir, '.env'), 'utf8');
|
|
1054
|
+
assert.ok(content.includes('WORKATO_API_TOKEN=mytoken123'));
|
|
1055
|
+
} finally {
|
|
1056
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1057
|
+
}
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1060
|
+
test('returns the .env file path', () => {
|
|
1061
|
+
const dir = tmpDir();
|
|
1062
|
+
try {
|
|
1063
|
+
const result = lib.cmdAuth('tok', dir);
|
|
1064
|
+
assert.equal(result, path.join(dir, '.env'));
|
|
1065
|
+
} finally {
|
|
1066
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
test('updates existing WORKATO_API_TOKEN line in .env', () => {
|
|
1071
|
+
const dir = tmpDir();
|
|
1072
|
+
try {
|
|
1073
|
+
fs.writeFileSync(path.join(dir, '.env'), 'WORKATO_API_TOKEN=oldtoken\n');
|
|
1074
|
+
lib.cmdAuth('newtoken', dir);
|
|
1075
|
+
const content = fs.readFileSync(path.join(dir, '.env'), 'utf8');
|
|
1076
|
+
assert.ok(content.includes('WORKATO_API_TOKEN=newtoken'), 'should have new token');
|
|
1077
|
+
assert.ok(!content.includes('oldtoken'), 'should not have old token');
|
|
1078
|
+
assert.equal((content.match(/WORKATO_API_TOKEN=/g) || []).length, 1, 'only one token line');
|
|
1079
|
+
} finally {
|
|
1080
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
test('appends token to .env that has other keys but no WORKATO_API_TOKEN', () => {
|
|
1085
|
+
const dir = tmpDir();
|
|
1086
|
+
try {
|
|
1087
|
+
fs.writeFileSync(path.join(dir, '.env'), 'OTHER_KEY=value\n');
|
|
1088
|
+
lib.cmdAuth('mytoken', dir);
|
|
1089
|
+
const content = fs.readFileSync(path.join(dir, '.env'), 'utf8');
|
|
1090
|
+
assert.ok(content.includes('OTHER_KEY=value'), 'existing key preserved');
|
|
1091
|
+
assert.ok(content.includes('WORKATO_API_TOKEN=mytoken'), 'token appended');
|
|
1092
|
+
} finally {
|
|
1093
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
test('token value containing = is preserved verbatim', () => {
|
|
1098
|
+
const dir = tmpDir();
|
|
1099
|
+
try {
|
|
1100
|
+
lib.cmdAuth('tok==extra==', dir);
|
|
1101
|
+
const content = fs.readFileSync(path.join(dir, '.env'), 'utf8');
|
|
1102
|
+
assert.ok(content.includes('WORKATO_API_TOKEN=tok==extra=='));
|
|
1103
|
+
} finally {
|
|
1104
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
test('preserves other keys in .env when updating token', () => {
|
|
1109
|
+
const dir = tmpDir();
|
|
1110
|
+
try {
|
|
1111
|
+
fs.writeFileSync(path.join(dir, '.env'), 'FOO=bar\nWORKATO_API_TOKEN=old\nBAZ=qux\n');
|
|
1112
|
+
lib.cmdAuth('updated', dir);
|
|
1113
|
+
const content = fs.readFileSync(path.join(dir, '.env'), 'utf8');
|
|
1114
|
+
assert.ok(content.includes('FOO=bar'), 'FOO preserved');
|
|
1115
|
+
assert.ok(content.includes('BAZ=qux'), 'BAZ preserved');
|
|
1116
|
+
assert.ok(content.includes('WORKATO_API_TOKEN=updated'), 'token updated');
|
|
1117
|
+
} finally {
|
|
1118
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1119
|
+
}
|
|
1120
|
+
});
|
|
1121
|
+
});
|
|
1122
|
+
|
|
985
1123
|
// Restore console at end
|
|
986
1124
|
process.on('exit', () => {
|
|
987
1125
|
console.log = origLog;
|