openkbs 0.0.90 → 0.0.93
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 +1 -1
- package/src/actions.js +93 -10
- package/templates/.claude/CLAUDE.md +3 -6
- package/templates/.claude/skills/openkbs/SKILL.md +42 -2
- package/templates/.claude/skills/openkbs/metadata.json +1 -1
- package/templates/.claude/skills/openkbs/reference/elastic-services.md +54 -1
- package/templates/platform/openkbs.json +1 -0
- package/version.json +3 -3
- package/templates/platform/functions/settings.json +0 -4
- package/templates/platform/site/settings.json +0 -4
package/package.json
CHANGED
package/src/actions.js
CHANGED
|
@@ -37,11 +37,9 @@ const SERVICES = {
|
|
|
37
37
|
*/
|
|
38
38
|
function findSettings() {
|
|
39
39
|
const paths = [
|
|
40
|
+
path.join(process.cwd(), 'openkbs.json'),
|
|
40
41
|
path.join(process.cwd(), 'settings.json'),
|
|
41
|
-
path.join(process.cwd(), 'app', 'settings.json')
|
|
42
|
-
path.join(process.cwd(), 'functions', 'settings.json'),
|
|
43
|
-
path.join(process.cwd(), 'site', 'settings.json'),
|
|
44
|
-
path.join(process.cwd(), 'openkbs.json')
|
|
42
|
+
path.join(process.cwd(), 'app', 'settings.json')
|
|
45
43
|
];
|
|
46
44
|
|
|
47
45
|
for (const settingsPath of paths) {
|
|
@@ -1137,6 +1135,8 @@ async function fnAction(subCommand, args = []) {
|
|
|
1137
1135
|
return await fnEnvAction(kbToken, args[0], args.slice(1));
|
|
1138
1136
|
case 'invoke':
|
|
1139
1137
|
return await fnInvokeAction(kbToken, args[0], args.slice(1));
|
|
1138
|
+
case 'schedule':
|
|
1139
|
+
return await fnScheduleAction(kbToken, args[0], args.slice(1));
|
|
1140
1140
|
default:
|
|
1141
1141
|
console.log('Usage: openkbs fn <command> [options]');
|
|
1142
1142
|
console.log('');
|
|
@@ -1147,11 +1147,14 @@ async function fnAction(subCommand, args = []) {
|
|
|
1147
1147
|
console.log(' logs <name> View function logs');
|
|
1148
1148
|
console.log(' env <name> [KEY=value] View or set environment variables');
|
|
1149
1149
|
console.log(' invoke <name> [payload] Invoke a function');
|
|
1150
|
+
console.log(' schedule <name> [expr] View/set/enable/disable/remove schedule');
|
|
1150
1151
|
console.log('');
|
|
1151
1152
|
console.log('Options for push:');
|
|
1152
1153
|
console.log(' --region <region> Region (us-east-1, eu-central-1, ap-southeast-1)');
|
|
1153
1154
|
console.log(' --memory <mb> Memory size (128-3008 MB)');
|
|
1154
1155
|
console.log(' --timeout <seconds> Timeout (1-900 seconds)');
|
|
1156
|
+
console.log(' --schedule <expr> Schedule expression (e.g. "rate(1 hour)")');
|
|
1157
|
+
console.log(' --http-access Enable HTTP access for scheduled functions');
|
|
1155
1158
|
}
|
|
1156
1159
|
}
|
|
1157
1160
|
|
|
@@ -1184,8 +1187,9 @@ async function fnListAction(kbToken) {
|
|
|
1184
1187
|
functions.forEach(f => {
|
|
1185
1188
|
const name = f.functionName.padEnd(maxNameLen);
|
|
1186
1189
|
const region = f.region || 'unknown';
|
|
1187
|
-
const url = f.customUrl || f.functionUrl || 'N/A';
|
|
1188
|
-
|
|
1190
|
+
const url = f.customUrl || f.functionUrl || (f.schedule ? '(scheduled)' : 'N/A');
|
|
1191
|
+
const scheduleInfo = f.schedule ? ` [${f.schedule}]` : '';
|
|
1192
|
+
console.log(` ${name} ${region} ${url}${scheduleInfo}`);
|
|
1189
1193
|
});
|
|
1190
1194
|
} catch (error) {
|
|
1191
1195
|
console.red('Error listing functions:', error.message);
|
|
@@ -1203,6 +1207,8 @@ async function fnDeployAction(kbToken, functionName, args) {
|
|
|
1203
1207
|
let timeout = 30;
|
|
1204
1208
|
let runtime = null; // null = use default (nodejs24.x)
|
|
1205
1209
|
let handler = null; // null = use default (index.handler)
|
|
1210
|
+
let schedule = null;
|
|
1211
|
+
let httpAccess = null;
|
|
1206
1212
|
|
|
1207
1213
|
for (let i = 0; i < args.length; i++) {
|
|
1208
1214
|
if (args[i] === '--region' && args[i + 1]) {
|
|
@@ -1215,6 +1221,10 @@ async function fnDeployAction(kbToken, functionName, args) {
|
|
|
1215
1221
|
runtime = args[++i];
|
|
1216
1222
|
} else if (args[i] === '--handler' && args[i + 1]) {
|
|
1217
1223
|
handler = args[++i];
|
|
1224
|
+
} else if (args[i] === '--schedule' && args[i + 1]) {
|
|
1225
|
+
schedule = args[++i];
|
|
1226
|
+
} else if (args[i] === '--http-access') {
|
|
1227
|
+
httpAccess = true;
|
|
1218
1228
|
}
|
|
1219
1229
|
}
|
|
1220
1230
|
|
|
@@ -1275,12 +1285,14 @@ async function fnDeployAction(kbToken, functionName, args) {
|
|
|
1275
1285
|
if (existingFunc) {
|
|
1276
1286
|
// Update existing function
|
|
1277
1287
|
console.log('Updating existing function...');
|
|
1278
|
-
|
|
1288
|
+
const updateParams = {
|
|
1279
1289
|
token: kbToken,
|
|
1280
1290
|
action: 'updateElasticFunction',
|
|
1281
1291
|
functionName,
|
|
1282
1292
|
code
|
|
1283
|
-
}
|
|
1293
|
+
};
|
|
1294
|
+
if (schedule) updateParams.schedule = schedule;
|
|
1295
|
+
response = await makePostRequest(KB_API_URL, updateParams);
|
|
1284
1296
|
} else {
|
|
1285
1297
|
// Create new function
|
|
1286
1298
|
console.log('Creating new function...');
|
|
@@ -1295,6 +1307,8 @@ async function fnDeployAction(kbToken, functionName, args) {
|
|
|
1295
1307
|
};
|
|
1296
1308
|
if (runtime) createParams.runtime = runtime;
|
|
1297
1309
|
if (handler) createParams.handler = handler;
|
|
1310
|
+
if (schedule) createParams.schedule = schedule;
|
|
1311
|
+
if (httpAccess !== null) createParams.httpAccess = httpAccess;
|
|
1298
1312
|
response = await makePostRequest(KB_API_URL, createParams);
|
|
1299
1313
|
}
|
|
1300
1314
|
|
|
@@ -1309,6 +1323,9 @@ async function fnDeployAction(kbToken, functionName, args) {
|
|
|
1309
1323
|
if (response.customUrl) {
|
|
1310
1324
|
console.log(`Custom URL: ${response.customUrl}`);
|
|
1311
1325
|
}
|
|
1326
|
+
if (response.schedule) {
|
|
1327
|
+
console.log(`Schedule: ${response.schedule}`);
|
|
1328
|
+
}
|
|
1312
1329
|
} catch (error) {
|
|
1313
1330
|
console.red('Deploy failed:', error.message);
|
|
1314
1331
|
}
|
|
@@ -1338,6 +1355,71 @@ async function fnDeleteAction(kbToken, functionName) {
|
|
|
1338
1355
|
}
|
|
1339
1356
|
}
|
|
1340
1357
|
|
|
1358
|
+
async function fnScheduleAction(kbToken, functionName, args) {
|
|
1359
|
+
if (!functionName) {
|
|
1360
|
+
return console.red('Function name required. Usage: openkbs fn schedule <name> [expression|enable|disable|remove]');
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
const subCommand = args[0];
|
|
1364
|
+
|
|
1365
|
+
try {
|
|
1366
|
+
if (!subCommand) {
|
|
1367
|
+
// Show current schedule
|
|
1368
|
+
const response = await makePostRequest(KB_API_URL, {
|
|
1369
|
+
token: kbToken,
|
|
1370
|
+
action: 'getElasticFunction',
|
|
1371
|
+
functionName
|
|
1372
|
+
});
|
|
1373
|
+
if (response.error) return console.red('Error:', response.error);
|
|
1374
|
+
if (response.schedule) {
|
|
1375
|
+
console.log(`Schedule: ${response.schedule}`);
|
|
1376
|
+
console.log(`Name: ${response.scheduleName || 'N/A'}`);
|
|
1377
|
+
} else {
|
|
1378
|
+
console.log(`No schedule set for '${functionName}'.`);
|
|
1379
|
+
}
|
|
1380
|
+
} else if (subCommand === 'enable') {
|
|
1381
|
+
const response = await makePostRequest(KB_API_URL, {
|
|
1382
|
+
token: kbToken,
|
|
1383
|
+
action: 'updateElasticFunctionSchedule',
|
|
1384
|
+
functionName,
|
|
1385
|
+
enabled: true
|
|
1386
|
+
});
|
|
1387
|
+
if (response.error) return console.red('Error:', response.error);
|
|
1388
|
+
console.green(`Schedule for '${functionName}' enabled.`);
|
|
1389
|
+
} else if (subCommand === 'disable') {
|
|
1390
|
+
const response = await makePostRequest(KB_API_URL, {
|
|
1391
|
+
token: kbToken,
|
|
1392
|
+
action: 'updateElasticFunctionSchedule',
|
|
1393
|
+
functionName,
|
|
1394
|
+
enabled: false
|
|
1395
|
+
});
|
|
1396
|
+
if (response.error) return console.red('Error:', response.error);
|
|
1397
|
+
console.green(`Schedule for '${functionName}' disabled.`);
|
|
1398
|
+
} else if (subCommand === 'remove') {
|
|
1399
|
+
const response = await makePostRequest(KB_API_URL, {
|
|
1400
|
+
token: kbToken,
|
|
1401
|
+
action: 'updateElasticFunctionSchedule',
|
|
1402
|
+
functionName,
|
|
1403
|
+
schedule: null
|
|
1404
|
+
});
|
|
1405
|
+
if (response.error) return console.red('Error:', response.error);
|
|
1406
|
+
console.green(`Schedule for '${functionName}' removed.`);
|
|
1407
|
+
} else {
|
|
1408
|
+
// Set schedule expression
|
|
1409
|
+
const response = await makePostRequest(KB_API_URL, {
|
|
1410
|
+
token: kbToken,
|
|
1411
|
+
action: 'updateElasticFunctionSchedule',
|
|
1412
|
+
functionName,
|
|
1413
|
+
schedule: subCommand
|
|
1414
|
+
});
|
|
1415
|
+
if (response.error) return console.red('Error:', response.error);
|
|
1416
|
+
console.green(`Schedule for '${functionName}' set to: ${subCommand}`);
|
|
1417
|
+
}
|
|
1418
|
+
} catch (error) {
|
|
1419
|
+
console.red('Schedule operation failed:', error.message);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1341
1423
|
async function fnLogsAction(kbToken, functionName, args) {
|
|
1342
1424
|
if (!functionName) {
|
|
1343
1425
|
return console.red('Function name required. Usage: openkbs fn logs <name>');
|
|
@@ -2068,9 +2150,8 @@ async function siteDeployAction(kbToken, kbId, siteDir, args) {
|
|
|
2068
2150
|
const fullPath = path.join(dir, entry.name);
|
|
2069
2151
|
const relativePath = path.relative(baseDir, fullPath);
|
|
2070
2152
|
|
|
2071
|
-
// Skip hidden files
|
|
2153
|
+
// Skip hidden files and node_modules
|
|
2072
2154
|
if (entry.name.startsWith('.') ||
|
|
2073
|
-
entry.name === 'settings.json' ||
|
|
2074
2155
|
entry.name === 'node_modules') {
|
|
2075
2156
|
continue;
|
|
2076
2157
|
}
|
|
@@ -2480,6 +2561,8 @@ async function elasticDeployAction() {
|
|
|
2480
2561
|
if (fnConfig.timeout) args.push('--timeout', String(fnConfig.timeout));
|
|
2481
2562
|
if (fnConfig.runtime) args.push('--runtime', fnConfig.runtime);
|
|
2482
2563
|
if (fnConfig.handler) args.push('--handler', fnConfig.handler);
|
|
2564
|
+
if (fnConfig.schedule) args.push('--schedule', fnConfig.schedule);
|
|
2565
|
+
if (fnConfig.httpAccess) args.push('--http-access');
|
|
2483
2566
|
|
|
2484
2567
|
console.log(` Deploying ${name}...`);
|
|
2485
2568
|
await fnDeployAction(kbToken, name, args);
|
|
@@ -19,11 +19,8 @@ If auth error, ask user to run `openkbs login` first.
|
|
|
19
19
|
Pick the whitelabel agent kbId from the list.
|
|
20
20
|
|
|
21
21
|
### 2. Configure Settings
|
|
22
|
-
Update
|
|
23
|
-
|
|
24
|
-
**site/settings.json** and **functions/settings.json**:
|
|
22
|
+
Update `openkbs.json`:
|
|
25
23
|
- Replace `{{WHITELABEL_KB_ID}}` with kbId from step 1
|
|
26
|
-
- Replace `{{REGION}}` with region from openkbs.json
|
|
27
24
|
|
|
28
25
|
### 3. Deploy
|
|
29
26
|
```bash
|
|
@@ -33,7 +30,7 @@ openkbs fn push api # API function (optional)
|
|
|
33
30
|
```
|
|
34
31
|
|
|
35
32
|
## Project Structure
|
|
36
|
-
- `openkbs.json` -
|
|
37
|
-
- `site/` - Static frontend
|
|
33
|
+
- `openkbs.json` - Project config (kbId, region, elastic services)
|
|
34
|
+
- `site/` - Static frontend
|
|
38
35
|
- `functions/` - Serverless Lambda functions
|
|
39
36
|
- `agents/` - AI agents (optional, each gets own kbId on push)
|
|
@@ -40,7 +40,7 @@ Platform mode extends agent capabilities with:
|
|
|
40
40
|
- CloudFront distributions
|
|
41
41
|
- SSL certificates
|
|
42
42
|
|
|
43
|
-
This whitelabel `kbId` is
|
|
43
|
+
This whitelabel `kbId` is stored in `openkbs.json` in the project root. User-facing agents in `agents/` folder each get their own separate `kbId` when pushed.
|
|
44
44
|
|
|
45
45
|
## Project Structure
|
|
46
46
|
|
|
@@ -100,7 +100,8 @@ my-platform/
|
|
|
100
100
|
},
|
|
101
101
|
"pulse": true,
|
|
102
102
|
"functions": [
|
|
103
|
-
{ "name": "api", "runtime": "nodejs24.x", "memory": 512, "timeout": 30 }
|
|
103
|
+
{ "name": "api", "runtime": "nodejs24.x", "memory": 512, "timeout": 30 },
|
|
104
|
+
{ "name": "cleanup", "schedule": "rate(1 hour)", "timeout": 900 }
|
|
104
105
|
],
|
|
105
106
|
"site": "./site"
|
|
106
107
|
}
|
|
@@ -127,7 +128,10 @@ openkbs destroy # Remove all resources (DANGEROUS)
|
|
|
127
128
|
```bash
|
|
128
129
|
openkbs fn list # List Lambda functions
|
|
129
130
|
openkbs fn push api # Deploy function
|
|
131
|
+
openkbs fn push cleanup --schedule "rate(1 hour)" # Deploy with schedule
|
|
130
132
|
openkbs fn logs api # View function logs
|
|
133
|
+
openkbs fn schedule cleanup # View schedule
|
|
134
|
+
openkbs fn schedule cleanup disable # Disable schedule
|
|
131
135
|
openkbs postgres shell # Connect to Postgres
|
|
132
136
|
openkbs storage ls # List S3 objects
|
|
133
137
|
openkbs pulse status # WebSocket status
|
|
@@ -246,6 +250,42 @@ Configure in `settings.json`:
|
|
|
246
250
|
|
|
247
251
|
Priority items are auto-injected into LLM context.
|
|
248
252
|
|
|
253
|
+
## Spec Mode
|
|
254
|
+
|
|
255
|
+
When the user is in **Spec Mode**, you act as a Product Manager helping define specifications.
|
|
256
|
+
|
|
257
|
+
### Workflow
|
|
258
|
+
1. Discuss requirements with the user — ask clarifying questions
|
|
259
|
+
2. Explore the codebase to understand the current architecture
|
|
260
|
+
3. Write the specification as a `.md` file in the `spec/` folder
|
|
261
|
+
4. Call `ExitPlanMode` to present the specification for user approval
|
|
262
|
+
5. If rejected or changes requested, revise and re-submit
|
|
263
|
+
|
|
264
|
+
### Spec File Format
|
|
265
|
+
Create files in `spec/` folder with descriptive names (e.g., `spec/user-authentication.md`):
|
|
266
|
+
|
|
267
|
+
- **Goals** — What this feature achieves
|
|
268
|
+
- **Requirements** — Functional requirements (numbered list)
|
|
269
|
+
- **User Stories** — As a [role], I want [action], so that [benefit]
|
|
270
|
+
- **Acceptance Criteria** — Testable conditions for completeness
|
|
271
|
+
- **Constraints** — Technical or business limitations
|
|
272
|
+
- **Out of Scope** — What is explicitly NOT included
|
|
273
|
+
|
|
274
|
+
### Markdown Features
|
|
275
|
+
The spec viewer supports GitHub Flavored Markdown (GFM). Use these for well-structured specs:
|
|
276
|
+
- **Tables** — for requirement matrices, field definitions, API specs
|
|
277
|
+
- **Task lists** — `- [ ]` / `- [x]` for checklists
|
|
278
|
+
- **Strikethrough** — `~~text~~` for deprecated items
|
|
279
|
+
- **Autolinks** — URLs are automatically linked
|
|
280
|
+
- **Headings, lists, bold, italic, code blocks** — all standard markdown
|
|
281
|
+
|
|
282
|
+
### Rules
|
|
283
|
+
- Do NOT write implementation code in spec mode
|
|
284
|
+
- Focus on WHAT to build, not HOW
|
|
285
|
+
- Keep specs concise and actionable
|
|
286
|
+
- One spec file per feature/topic
|
|
287
|
+
- Use tables for structured data (requirements, fields, APIs)
|
|
288
|
+
|
|
249
289
|
## Additional Resources
|
|
250
290
|
|
|
251
291
|
### Reference Documentation
|
|
@@ -23,7 +23,9 @@ OpenKBS provides managed cloud infrastructure that scales automatically.
|
|
|
23
23
|
},
|
|
24
24
|
"pulse": true,
|
|
25
25
|
"functions": [
|
|
26
|
-
{ "name": "
|
|
26
|
+
{ "name": "api", "runtime": "nodejs24.x", "memory": 512, "timeout": 30 },
|
|
27
|
+
{ "name": "cleanup", "runtime": "nodejs24.x", "memory": 256, "timeout": 900, "schedule": "rate(1 hour)" },
|
|
28
|
+
{ "name": "reports", "runtime": "nodejs24.x", "memory": 512, "timeout": 300, "schedule": "cron(0 12 * * ? *)" }
|
|
27
29
|
],
|
|
28
30
|
"site": "./site"
|
|
29
31
|
}
|
|
@@ -66,11 +68,62 @@ export const handler = async (event) => {
|
|
|
66
68
|
```bash
|
|
67
69
|
openkbs fn list # List all functions
|
|
68
70
|
openkbs fn push hello --region us-east-1 # Deploy function
|
|
71
|
+
openkbs fn push hello --schedule "rate(1 hour)" # Deploy with schedule
|
|
72
|
+
openkbs fn push hello --schedule "rate(1 hour)" --http-access # Schedule + HTTP
|
|
69
73
|
openkbs fn delete hello # Delete function
|
|
70
74
|
openkbs fn logs hello # View logs
|
|
71
75
|
openkbs fn env hello # View env vars
|
|
72
76
|
openkbs fn env hello API_KEY=secret # Set env var
|
|
73
77
|
openkbs fn invoke hello '{"test": true}' # Invoke function
|
|
78
|
+
openkbs fn schedule hello # View current schedule
|
|
79
|
+
openkbs fn schedule hello "rate(5 minutes)" # Set schedule
|
|
80
|
+
openkbs fn schedule hello enable # Enable schedule
|
|
81
|
+
openkbs fn schedule hello disable # Disable schedule
|
|
82
|
+
openkbs fn schedule hello remove # Remove schedule
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Scheduled Functions
|
|
86
|
+
|
|
87
|
+
Functions with a `schedule` field are invoked automatically by EventBridge Scheduler. By default, scheduled functions do **not** get HTTP access (no Function URL / CloudFront). Add `"httpAccess": true` to enable both.
|
|
88
|
+
|
|
89
|
+
**Schedule expressions:**
|
|
90
|
+
- `rate(1 hour)`, `rate(5 minutes)`, `rate(1 day)`
|
|
91
|
+
- `cron(0 12 * * ? *)` — daily at 12:00 UTC
|
|
92
|
+
- `cron(0/15 * * * ? *)` — every 15 minutes
|
|
93
|
+
|
|
94
|
+
**openkbs.json example:**
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"functions": [
|
|
98
|
+
{ "name": "api", "runtime": "nodejs24.x", "memory": 512, "timeout": 30 },
|
|
99
|
+
{ "name": "cleanup", "schedule": "rate(1 hour)", "timeout": 900 },
|
|
100
|
+
{ "name": "reports", "schedule": "cron(0 12 * * ? *)", "httpAccess": true }
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Event payload** received by the Lambda handler:
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"source": "openkbs.scheduler",
|
|
109
|
+
"kbId": "abc123",
|
|
110
|
+
"functionName": "cleanup",
|
|
111
|
+
"scheduleExpression": "rate(1 hour)"
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Handler example:**
|
|
116
|
+
```javascript
|
|
117
|
+
export const handler = async (event) => {
|
|
118
|
+
if (event.source === 'openkbs.scheduler') {
|
|
119
|
+
// Invoked by schedule
|
|
120
|
+
console.log(`Running scheduled task: ${event.functionName}`);
|
|
121
|
+
// ... do work ...
|
|
122
|
+
return { statusCode: 200, body: 'OK' };
|
|
123
|
+
}
|
|
124
|
+
// Invoked via HTTP (if httpAccess is enabled)
|
|
125
|
+
return { statusCode: 200, body: JSON.stringify({ message: 'Hello' }) };
|
|
126
|
+
};
|
|
74
127
|
```
|
|
75
128
|
|
|
76
129
|
### Supported Runtimes
|
package/version.json
CHANGED