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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openkbs",
3
- "version": "0.0.90",
3
+ "version": "0.0.93",
4
4
  "description": "OpenKBS - Command Line Interface",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
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
- console.log(` ${name} ${region} ${url}`);
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
- response = await makePostRequest(KB_API_URL, {
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, settings.json, and node_modules
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 these files with values from step 1 and openkbs.json:
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` - Elastic services config (region, postgres, storage, pulse)
37
- - `site/` - Static frontend (settings.json links to whitelabel agent)
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 used in `settings.json` files throughout the project. User-facing agents in `agents/` folder each get their own separate `kbId` when pushed.
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
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.1.24"
2
+ "version": "0.1.27"
3
3
  }
@@ -23,7 +23,9 @@ OpenKBS provides managed cloud infrastructure that scales automatically.
23
23
  },
24
24
  "pulse": true,
25
25
  "functions": [
26
- { "name": "hello", "runtime": "nodejs24.x", "memory": 512, "timeout": 30 }
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
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "{{APP_NAME}}",
3
+ "kbId": "{{WHITELABEL_KB_ID}}",
3
4
  "region": "us-east-1",
4
5
  "spa": "/app/index.html",
5
6
  "postgres": true,
package/version.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.90",
3
- "releaseDate": "2026-02-21",
4
- "releaseNotes": "OpenKBS CLI version 0.0.90"
2
+ "version": "0.0.93",
3
+ "releaseDate": "2026-03-03",
4
+ "releaseNotes": "OpenKBS CLI version 0.0.93"
5
5
  }
@@ -1,4 +0,0 @@
1
- {
2
- "kbId": "{{WHITELABEL_KB_ID}}",
3
- "region": "{{REGION}}"
4
- }
@@ -1,4 +0,0 @@
1
- {
2
- "kbId": "{{WHITELABEL_KB_ID}}",
3
- "region": "{{REGION}}"
4
- }