openkbs 0.0.64 → 0.0.66
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/elastic/README.md +1150 -0
- package/elastic/functions.md +328 -0
- package/elastic/postgres.md +287 -0
- package/elastic/pulse.md +386 -0
- package/elastic/storage.md +291 -0
- package/package.json +1 -1
- package/src/actions.js +76 -92
- package/src/index.js +23 -10
- package/src/utils.js +8 -4
- package/templates/.claude/skills/openkbs/SKILL.md +184 -0
- package/templates/.claude/skills/openkbs/metadata.json +1 -0
- package/templates/.claude/skills/openkbs/reference/backend-sdk.md +428 -0
- package/templates/.claude/skills/openkbs/reference/commands.md +370 -0
- package/templates/.claude/skills/openkbs/reference/elastic-services.md +327 -0
- package/templates/.claude/skills/openkbs/reference/frontend-sdk.md +299 -0
- package/version.json +3 -3
- package/templates/.openkbs/knowledge/metadata.json +0 -3
- package/templates/CLAUDE.md +0 -655
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/app/icon.png +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/app/instructions.txt +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/app/settings.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/scripts/run_job.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/scripts/utils/agent_client.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/actions.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/handler.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/onRequest.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/onRequest.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/onResponse.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Events/onResponse.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Frontend/contentRender.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-copywriter-agent/src/Frontend/contentRender.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/README.md +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/app/instructions.txt +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/app/settings.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Events/actions.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Events/onRequest.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Events/onRequest.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Events/onResponse.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Events/onResponse.json +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Frontend/contentRender.js +0 -0
- /package/templates/{.openkbs/knowledge → .claude/skills/openkbs}/examples/ai-marketing-agent/src/Frontend/contentRender.json +0 -0
package/src/actions.js
CHANGED
|
@@ -611,20 +611,11 @@ async function downloadModifyAction() {
|
|
|
611
611
|
});
|
|
612
612
|
}
|
|
613
613
|
|
|
614
|
-
async function
|
|
614
|
+
async function updateSkillsAction(silent = false) {
|
|
615
615
|
try {
|
|
616
|
-
const
|
|
617
|
-
const metadataPath = path.join(
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
// Check if .openkbs/knowledge directory exists
|
|
621
|
-
if (!fs.existsSync(knowledgeDir)) {
|
|
622
|
-
if (!silent) {
|
|
623
|
-
console.red('Knowledge directory not found. Please ensure you are in an OpenKBS project directory.');
|
|
624
|
-
}
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
|
|
616
|
+
const skillsDir = path.join(process.cwd(), '.claude', 'skills', 'openkbs');
|
|
617
|
+
const metadataPath = path.join(skillsDir, 'metadata.json');
|
|
618
|
+
|
|
628
619
|
// Get local metadata version
|
|
629
620
|
let localVersion = null;
|
|
630
621
|
if (fs.existsSync(metadataPath)) {
|
|
@@ -635,15 +626,14 @@ async function updateKnowledgeAction(silent = false) {
|
|
|
635
626
|
if (!silent) {
|
|
636
627
|
console.red('Error reading local metadata.json:', error.message);
|
|
637
628
|
}
|
|
638
|
-
return;
|
|
639
629
|
}
|
|
640
630
|
}
|
|
641
|
-
|
|
631
|
+
|
|
642
632
|
// Check remote version from S3
|
|
643
633
|
const https = require('https');
|
|
644
634
|
const bucket = 'openkbs-downloads';
|
|
645
|
-
const remoteMetadataKey = 'templates/.openkbs/
|
|
646
|
-
|
|
635
|
+
const remoteMetadataKey = 'templates/.claude/skills/openkbs/metadata.json';
|
|
636
|
+
|
|
647
637
|
let remoteVersion = null;
|
|
648
638
|
try {
|
|
649
639
|
const fileUrl = `https://${bucket}.s3.amazonaws.com/${remoteMetadataKey}`;
|
|
@@ -654,7 +644,7 @@ async function updateKnowledgeAction(silent = false) {
|
|
|
654
644
|
res.on('end', () => resolve(data));
|
|
655
645
|
}).on('error', reject);
|
|
656
646
|
});
|
|
657
|
-
|
|
647
|
+
|
|
658
648
|
const remoteMetadata = JSON.parse(remoteMetadataContent);
|
|
659
649
|
remoteVersion = remoteMetadata.version;
|
|
660
650
|
} catch (error) {
|
|
@@ -663,26 +653,23 @@ async function updateKnowledgeAction(silent = false) {
|
|
|
663
653
|
}
|
|
664
654
|
return;
|
|
665
655
|
}
|
|
666
|
-
|
|
656
|
+
|
|
667
657
|
// Compare versions
|
|
668
658
|
if (localVersion === remoteVersion) {
|
|
669
|
-
console.green('
|
|
659
|
+
console.green('OpenKBS skill is already up to date.');
|
|
670
660
|
return;
|
|
671
661
|
}
|
|
672
|
-
|
|
673
|
-
console.log(`Updating
|
|
674
|
-
|
|
675
|
-
// Download updated
|
|
676
|
-
await
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
console.green('Knowledge base updated successfully!');
|
|
682
|
-
|
|
662
|
+
|
|
663
|
+
console.log(`Updating OpenKBS skill from version ${localVersion || 'not installed'} to ${remoteVersion}...`);
|
|
664
|
+
|
|
665
|
+
// Download updated skill files from S3
|
|
666
|
+
await downloadSkillsFromS3(skillsDir);
|
|
667
|
+
|
|
668
|
+
console.green('OpenKBS skill updated successfully!');
|
|
669
|
+
|
|
683
670
|
} catch (error) {
|
|
684
671
|
if (!silent) {
|
|
685
|
-
console.red('Error updating
|
|
672
|
+
console.red('Error updating skills:', error.message);
|
|
686
673
|
}
|
|
687
674
|
}
|
|
688
675
|
}
|
|
@@ -744,8 +731,8 @@ async function updateCliAction() {
|
|
|
744
731
|
console.red('Error fetching CLI version metadata:', error.message);
|
|
745
732
|
}
|
|
746
733
|
|
|
747
|
-
// Also update
|
|
748
|
-
await
|
|
734
|
+
// Also update skills silently
|
|
735
|
+
await updateSkillsAction(true);
|
|
749
736
|
|
|
750
737
|
} catch (error) {
|
|
751
738
|
console.red('Error updating CLI:', error.message);
|
|
@@ -816,14 +803,17 @@ function compareVersions(version1, version2) {
|
|
|
816
803
|
}
|
|
817
804
|
|
|
818
805
|
|
|
819
|
-
async function
|
|
806
|
+
async function downloadSkillsFromS3(targetDir) {
|
|
820
807
|
const https = require('https');
|
|
821
808
|
const bucket = 'openkbs-downloads';
|
|
822
|
-
const prefix = 'templates/.openkbs/
|
|
809
|
+
const prefix = 'templates/.claude/skills/openkbs/';
|
|
823
810
|
const baseUrl = `https://${bucket}.s3.amazonaws.com`;
|
|
824
|
-
|
|
811
|
+
|
|
825
812
|
try {
|
|
826
|
-
//
|
|
813
|
+
// Ensure directory exists
|
|
814
|
+
await fs.ensureDir(targetDir);
|
|
815
|
+
|
|
816
|
+
// List all objects in skills folder
|
|
827
817
|
const listUrl = `${baseUrl}/?list-type=2&prefix=${prefix}`;
|
|
828
818
|
const listXml = await new Promise((resolve, reject) => {
|
|
829
819
|
https.get(listUrl, (res) => {
|
|
@@ -832,28 +822,28 @@ async function downloadKnowledgeFromS3(targetDir) {
|
|
|
832
822
|
res.on('end', () => resolve(data));
|
|
833
823
|
}).on('error', reject);
|
|
834
824
|
});
|
|
835
|
-
|
|
825
|
+
|
|
836
826
|
// Parse XML to extract object keys
|
|
837
827
|
const keyMatches = listXml.match(/<Key>([^<]+)<\/Key>/g) || [];
|
|
838
828
|
const keys = keyMatches.map(match => match.replace(/<\/?Key>/g, ''));
|
|
839
|
-
|
|
829
|
+
|
|
840
830
|
if (keys.length === 0) {
|
|
841
|
-
console.yellow('No
|
|
831
|
+
console.yellow('No skill files found in remote repository.');
|
|
842
832
|
return;
|
|
843
833
|
}
|
|
844
|
-
|
|
834
|
+
|
|
845
835
|
// Download all files in parallel
|
|
846
836
|
const downloadPromises = keys.map(async (key) => {
|
|
847
837
|
const relativePath = key.substring(prefix.length);
|
|
848
|
-
|
|
838
|
+
|
|
849
839
|
// Skip if it's a directory marker
|
|
850
840
|
if (relativePath.endsWith('/') || relativePath === '') return;
|
|
851
|
-
|
|
841
|
+
|
|
852
842
|
const localPath = path.join(targetDir, relativePath);
|
|
853
|
-
|
|
843
|
+
|
|
854
844
|
// Ensure directory exists
|
|
855
845
|
await fs.ensureDir(path.dirname(localPath));
|
|
856
|
-
|
|
846
|
+
|
|
857
847
|
// Download file
|
|
858
848
|
const fileUrl = `${baseUrl}/${key}`;
|
|
859
849
|
const fileContent = await new Promise((resolve, reject) => {
|
|
@@ -864,49 +854,15 @@ async function downloadKnowledgeFromS3(targetDir) {
|
|
|
864
854
|
}).on('error', reject);
|
|
865
855
|
});
|
|
866
856
|
await fs.writeFile(localPath, fileContent);
|
|
867
|
-
|
|
857
|
+
|
|
868
858
|
console.log(`Downloaded: ${relativePath}`);
|
|
869
859
|
});
|
|
870
|
-
|
|
860
|
+
|
|
871
861
|
await Promise.all(downloadPromises);
|
|
872
|
-
|
|
873
|
-
} catch (error) {
|
|
874
|
-
console.red('Error downloading knowledge files from S3:', error.message);
|
|
875
|
-
throw error;
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
862
|
|
|
879
|
-
async function downloadClaudeMdFromS3(claudeMdPath) {
|
|
880
|
-
const https = require('https');
|
|
881
|
-
const bucket = 'openkbs-downloads';
|
|
882
|
-
const claudeMdKey = 'templates/CLAUDE.md';
|
|
883
|
-
|
|
884
|
-
try {
|
|
885
|
-
// Download CLAUDE.md file from S3
|
|
886
|
-
const fileUrl = `https://${bucket}.s3.amazonaws.com/${claudeMdKey}`;
|
|
887
|
-
const fileContent = await new Promise((resolve, reject) => {
|
|
888
|
-
https.get(fileUrl, (res) => {
|
|
889
|
-
if (res.statusCode === 404) {
|
|
890
|
-
reject(new Error('NoSuchKey'));
|
|
891
|
-
return;
|
|
892
|
-
}
|
|
893
|
-
const chunks = [];
|
|
894
|
-
res.on('data', (chunk) => chunks.push(chunk));
|
|
895
|
-
res.on('end', () => resolve(Buffer.concat(chunks)));
|
|
896
|
-
}).on('error', reject);
|
|
897
|
-
});
|
|
898
|
-
|
|
899
|
-
await fs.writeFile(claudeMdPath, fileContent);
|
|
900
|
-
|
|
901
|
-
console.log('Downloaded: CLAUDE.md');
|
|
902
|
-
|
|
903
863
|
} catch (error) {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
} else {
|
|
907
|
-
console.red('Error downloading CLAUDE.md:', error.message);
|
|
908
|
-
throw error;
|
|
909
|
-
}
|
|
864
|
+
console.red('Error downloading skill files from S3:', error.message);
|
|
865
|
+
throw error;
|
|
910
866
|
}
|
|
911
867
|
}
|
|
912
868
|
|
|
@@ -1935,7 +1891,7 @@ async function siteDeployAction(kbToken, kbId, siteDir, args) {
|
|
|
1935
1891
|
}
|
|
1936
1892
|
|
|
1937
1893
|
console.green(`\nUpload complete! ${uploaded}/${files.length} files uploaded.`);
|
|
1938
|
-
console.log(`Files accessible at: https://files.openkbs.com/${kbId}/`);
|
|
1894
|
+
// console.log(`Files accessible at: https://files.openkbs.com/${kbId}/`);
|
|
1939
1895
|
|
|
1940
1896
|
} catch (error) {
|
|
1941
1897
|
console.red('Upload failed:', error.message);
|
|
@@ -2184,9 +2140,12 @@ async function elasticDeployAction() {
|
|
|
2184
2140
|
if (elasticRes.error) {
|
|
2185
2141
|
console.red('Elastic deploy error:', elasticRes.error);
|
|
2186
2142
|
} else {
|
|
2187
|
-
if (elasticRes.pulse?.enabled) console.green(' ✓ Pulse enabled');
|
|
2188
|
-
if (elasticRes.
|
|
2189
|
-
if (elasticRes.
|
|
2143
|
+
if (elasticRes.pulse?.enabled || elasticRes.pulse?.alreadyEnabled) console.green(' ✓ Pulse enabled');
|
|
2144
|
+
if (elasticRes.pulse?.error) console.yellow(' ⚠ Pulse:', elasticRes.pulse.error);
|
|
2145
|
+
if (elasticRes.postgres?.enabled || elasticRes.postgres?.alreadyEnabled || elasticRes.postgres?.host) console.green(' ✓ Postgres enabled');
|
|
2146
|
+
if (elasticRes.postgres?.error) console.yellow(' ⚠ Postgres:', elasticRes.postgres.error);
|
|
2147
|
+
if (elasticRes.storage?.enabled || elasticRes.storage?.alreadyEnabled || elasticRes.storage?.bucket) console.green(' ✓ Storage enabled');
|
|
2148
|
+
if (elasticRes.storage?.error) console.yellow(' ⚠ Storage:', elasticRes.storage.error);
|
|
2190
2149
|
if (elasticRes.storage?.cloudfront) console.green(' ✓ CloudFront configured');
|
|
2191
2150
|
}
|
|
2192
2151
|
}
|
|
@@ -2277,13 +2236,37 @@ async function elasticDestroyAction() {
|
|
|
2277
2236
|
console.log('\nDisabling Elastic services...');
|
|
2278
2237
|
|
|
2279
2238
|
if (config.elastic.storage) {
|
|
2239
|
+
// First remove CloudFront behavior/origin if configured
|
|
2240
|
+
const cloudfrontPath = typeof config.elastic.storage === 'object'
|
|
2241
|
+
? config.elastic.storage.cloudfront
|
|
2242
|
+
: null;
|
|
2243
|
+
|
|
2244
|
+
if (cloudfrontPath) {
|
|
2245
|
+
try {
|
|
2246
|
+
await makePostRequest(KB_API_URL, {
|
|
2247
|
+
token: kbToken,
|
|
2248
|
+
action: 'setStorageCloudFront',
|
|
2249
|
+
pathPrefix: cloudfrontPath,
|
|
2250
|
+
enable: false
|
|
2251
|
+
});
|
|
2252
|
+
console.green(` ✓ CloudFront behavior removed (/${cloudfrontPath}/*)`);
|
|
2253
|
+
} catch (e) {
|
|
2254
|
+
console.yellow(` ⚠ CloudFront: ${e.message}`);
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
// Then delete storage bucket
|
|
2280
2259
|
try {
|
|
2281
|
-
await makePostRequest(KB_API_URL, {
|
|
2260
|
+
const storageRes = await makePostRequest(KB_API_URL, {
|
|
2282
2261
|
token: kbToken,
|
|
2283
2262
|
action: 'deleteElasticStorage',
|
|
2284
2263
|
force: true
|
|
2285
2264
|
});
|
|
2286
|
-
|
|
2265
|
+
if (storageRes.error) {
|
|
2266
|
+
console.yellow(` ⚠ Storage: ${storageRes.error}`);
|
|
2267
|
+
} else {
|
|
2268
|
+
console.green(' ✓ Storage disabled');
|
|
2269
|
+
}
|
|
2287
2270
|
} catch (e) {
|
|
2288
2271
|
console.yellow(` ⚠ Storage: ${e.message}`);
|
|
2289
2272
|
}
|
|
@@ -2463,7 +2446,7 @@ module.exports = {
|
|
|
2463
2446
|
installFrontendPackageAction,
|
|
2464
2447
|
modifyAction,
|
|
2465
2448
|
downloadModifyAction,
|
|
2466
|
-
|
|
2449
|
+
updateSkillsAction,
|
|
2467
2450
|
updateCliAction,
|
|
2468
2451
|
publishAction,
|
|
2469
2452
|
unpublishAction,
|
|
@@ -2473,5 +2456,6 @@ module.exports = {
|
|
|
2473
2456
|
postgresAction,
|
|
2474
2457
|
pulseAction,
|
|
2475
2458
|
stackAction,
|
|
2476
|
-
elasticDeployAction
|
|
2459
|
+
elasticDeployAction,
|
|
2460
|
+
elasticDestroyAction
|
|
2477
2461
|
};
|
package/src/index.js
CHANGED
|
@@ -13,14 +13,15 @@ const {
|
|
|
13
13
|
deleteFileAction,
|
|
14
14
|
describeAction, deployAction, createByTemplateAction, initByTemplateAction,
|
|
15
15
|
logoutAction, installFrontendPackageAction, modifyAction, downloadModifyAction,
|
|
16
|
-
|
|
16
|
+
updateSkillsAction, updateCliAction, publishAction, unpublishAction,
|
|
17
17
|
fnAction,
|
|
18
18
|
siteAction,
|
|
19
19
|
storageAction,
|
|
20
20
|
postgresAction,
|
|
21
21
|
pulseAction,
|
|
22
22
|
stackAction,
|
|
23
|
-
elasticDeployAction
|
|
23
|
+
elasticDeployAction,
|
|
24
|
+
elasticDestroyAction
|
|
24
25
|
} = require('./actions');
|
|
25
26
|
|
|
26
27
|
|
|
@@ -128,6 +129,19 @@ Reads openkbs.json and deploys:
|
|
|
128
129
|
- Site
|
|
129
130
|
`);
|
|
130
131
|
|
|
132
|
+
program
|
|
133
|
+
.command('destroy')
|
|
134
|
+
.description('Destroy all resources from openkbs.json (DANGEROUS)')
|
|
135
|
+
.action(elasticDestroyAction)
|
|
136
|
+
.addHelpText('after', `
|
|
137
|
+
Examples:
|
|
138
|
+
$ openkbs destroy
|
|
139
|
+
|
|
140
|
+
Reads openkbs.json and deletes:
|
|
141
|
+
- Functions
|
|
142
|
+
- Elastic services (storage, postgres, pulse)
|
|
143
|
+
`);
|
|
144
|
+
|
|
131
145
|
program
|
|
132
146
|
.command('stack <subcommand>')
|
|
133
147
|
.description('Manage stack resources (deploy, destroy, status)')
|
|
@@ -180,25 +194,24 @@ This file will be automatically included when you run the 'openkbs modify' comma
|
|
|
180
194
|
|
|
181
195
|
program
|
|
182
196
|
.command('update [target]')
|
|
183
|
-
.description('Update OpenKBS CLI or
|
|
197
|
+
.description('Update OpenKBS CLI or skills (default: CLI)')
|
|
184
198
|
.action((target) => {
|
|
185
199
|
if (!target) {
|
|
186
200
|
updateCliAction();
|
|
187
|
-
} else if (target === '
|
|
188
|
-
|
|
201
|
+
} else if (target === 'skills') {
|
|
202
|
+
updateSkillsAction();
|
|
189
203
|
} else {
|
|
190
|
-
console.error(`Unknown update target: ${target}.
|
|
204
|
+
console.error(`Unknown update target: ${target}. Supported: skills`);
|
|
191
205
|
process.exit(1);
|
|
192
206
|
}
|
|
193
207
|
})
|
|
194
208
|
.addHelpText('after', `
|
|
195
209
|
Examples:
|
|
196
210
|
$ openkbs update
|
|
197
|
-
|
|
211
|
+
Check for CLI updates and install them.
|
|
198
212
|
|
|
199
|
-
$ openkbs update
|
|
200
|
-
|
|
201
|
-
and update it if necessary.
|
|
213
|
+
$ openkbs update skills
|
|
214
|
+
Update .claude/skills/openkbs/ with latest OpenKBS skill files.
|
|
202
215
|
`);
|
|
203
216
|
|
|
204
217
|
program
|
package/src/utils.js
CHANGED
|
@@ -166,14 +166,18 @@ function makePostRequest(url, data) {
|
|
|
166
166
|
try {
|
|
167
167
|
const parsed = JSON.parse(body);
|
|
168
168
|
if (parsed.error) {
|
|
169
|
-
console.red(parsed.error);
|
|
169
|
+
console.red(`Error: ${parsed.error}`);
|
|
170
170
|
} else if (parsed.message) {
|
|
171
|
-
console.red(parsed.message);
|
|
171
|
+
console.red(`Error: ${parsed.message}`);
|
|
172
172
|
} else {
|
|
173
|
-
|
|
173
|
+
// Show the full response body if no error/message field
|
|
174
|
+
console.red(`Request failed (HTTP ${res.statusCode}):`);
|
|
175
|
+
console.red(JSON.stringify(parsed, null, 2));
|
|
174
176
|
}
|
|
175
177
|
} catch (e) {
|
|
176
|
-
|
|
178
|
+
// Could not parse JSON, show raw body
|
|
179
|
+
console.red(`Request failed (HTTP ${res.statusCode}):`);
|
|
180
|
+
console.red(body || 'No response body');
|
|
177
181
|
}
|
|
178
182
|
|
|
179
183
|
process.exit(1);
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openkbs
|
|
3
|
+
description: OpenKBS AI agent development framework. Use when creating, modifying, or deploying AI agents with backend handlers (onRequest, onResponse, actions.js), frontend components (contentRender.js), or elastic services (functions, postgres, storage, pulse). Trigger keywords: openkbs, kb, agent, handler, contentRender, elastic, memory, scheduled task.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# OpenKBS Development
|
|
7
|
+
|
|
8
|
+
OpenKBS is a framework for building AI-powered applications - from simple agents to full-stack platforms.
|
|
9
|
+
|
|
10
|
+
## Two Usage Modes
|
|
11
|
+
|
|
12
|
+
### 1. Agent-Only Mode
|
|
13
|
+
Build a single conversational AI agent with backend handlers and custom UI.
|
|
14
|
+
```
|
|
15
|
+
openkbs create my-agent
|
|
16
|
+
openkbs push
|
|
17
|
+
```
|
|
18
|
+
Simplest way to get started - just an agent with memory, commands, and custom frontend.
|
|
19
|
+
|
|
20
|
+
### 2. Platform Mode (Full-Stack)
|
|
21
|
+
Build complete SaaS platforms that **include agents** plus additional infrastructure.
|
|
22
|
+
```
|
|
23
|
+
openkbs deploy # Deploy from openkbs.json
|
|
24
|
+
openkbs stack status # View deployed resources
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Platform mode extends agent capabilities with:
|
|
28
|
+
- **Multiple Agents**: Run several agents on one platform (in `agents/` folder)
|
|
29
|
+
- **Elastic Functions**: Serverless Lambda (Node.js, Python, Java)
|
|
30
|
+
- **Elastic Postgres**: Managed PostgreSQL (Neon) for relational data
|
|
31
|
+
- **Elastic Storage**: S3 buckets + CloudFront CDN for files
|
|
32
|
+
- **Elastic Pulse**: Real-time WebSocket pub/sub
|
|
33
|
+
- **Whitelabel**: Custom domains (`example.com`) with static site (`site/` folder)
|
|
34
|
+
|
|
35
|
+
**Architecture Note**: The whitelabel itself is a KB with its own `kbId` (a service agent, not user-facing). This "parent" kbId is used throughout the stack for elastic services. Each agent in `agents/` has its own separate `kbId`. All agents share the platform's elastic services via the parent kbId.
|
|
36
|
+
|
|
37
|
+
## Project Structure
|
|
38
|
+
|
|
39
|
+
### Agent Structure
|
|
40
|
+
```
|
|
41
|
+
my-agent/
|
|
42
|
+
├── app/
|
|
43
|
+
│ ├── settings.json # Agent configuration (model, itemTypes, MCP)
|
|
44
|
+
│ └── instructions.txt # System prompt for LLM
|
|
45
|
+
├── src/
|
|
46
|
+
│ ├── Events/
|
|
47
|
+
│ │ ├── onRequest.js # Pre-process user messages
|
|
48
|
+
│ │ ├── onResponse.js # Parse LLM output, execute commands
|
|
49
|
+
│ │ ├── actions.js # Command implementations
|
|
50
|
+
│ │ ├── onCronjob.js # Scheduled periodic tasks
|
|
51
|
+
│ │ └── onPublicAPIRequest.js # Webhook handler
|
|
52
|
+
│ └── Frontend/
|
|
53
|
+
│ ├── contentRender.js # Custom React UI
|
|
54
|
+
│ └── contentRender.json # Frontend dependencies
|
|
55
|
+
└── openkbs.json # Elastic services config
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Platform Structure
|
|
59
|
+
```
|
|
60
|
+
my-platform/
|
|
61
|
+
├── agents/ # Multiple AI agents
|
|
62
|
+
│ ├── marketing-assistant/ # Each agent has full structure
|
|
63
|
+
│ │ ├── app/
|
|
64
|
+
│ │ │ ├── settings.json
|
|
65
|
+
│ │ │ └── instructions.txt
|
|
66
|
+
│ │ └── src/
|
|
67
|
+
│ │ ├── Events/
|
|
68
|
+
│ │ │ ├── onRequest.js
|
|
69
|
+
│ │ │ ├── onResponse.js
|
|
70
|
+
│ │ │ └── actions.js
|
|
71
|
+
│ │ └── Frontend/
|
|
72
|
+
│ │ └── contentRender.js
|
|
73
|
+
│ └── support-agent/ # Another agent
|
|
74
|
+
│ ├── app/
|
|
75
|
+
│ └── src/
|
|
76
|
+
├── functions/ # Serverless Lambda functions
|
|
77
|
+
│ └── api/
|
|
78
|
+
│ └── index.mjs
|
|
79
|
+
├── site/ # Static site for whitelabel domain
|
|
80
|
+
│ └── index.html
|
|
81
|
+
└── openkbs.json # Elastic services config
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### openkbs.json
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"elastic": {
|
|
88
|
+
"postgres": true,
|
|
89
|
+
"storage": true,
|
|
90
|
+
"pulse": true,
|
|
91
|
+
"functions": {
|
|
92
|
+
"api": { "runtime": "nodejs22.x", "memory": 512 }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Quick Commands
|
|
99
|
+
|
|
100
|
+
### Agent Commands
|
|
101
|
+
```bash
|
|
102
|
+
openkbs create <name> # Create new agent
|
|
103
|
+
openkbs push # Deploy to cloud
|
|
104
|
+
openkbs pull # Download from cloud
|
|
105
|
+
openkbs update skills # Update this skill
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Platform Commands
|
|
109
|
+
```bash
|
|
110
|
+
openkbs deploy # Deploy all elastic services
|
|
111
|
+
openkbs stack status # Show deployed resources
|
|
112
|
+
openkbs destroy # Remove all resources (DANGEROUS)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Elastic Services
|
|
116
|
+
```bash
|
|
117
|
+
openkbs fn list # List Lambda functions
|
|
118
|
+
openkbs fn push api # Deploy function
|
|
119
|
+
openkbs fn logs api # View function logs
|
|
120
|
+
openkbs postgres shell # Connect to Postgres
|
|
121
|
+
openkbs storage ls # List S3 objects
|
|
122
|
+
openkbs pulse status # WebSocket status
|
|
123
|
+
openkbs site push # Deploy static site
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Backend Handler Pattern
|
|
127
|
+
|
|
128
|
+
Commands are XML tags with JSON content that the LLM outputs:
|
|
129
|
+
|
|
130
|
+
```xml
|
|
131
|
+
<commandName>{"param": "value"}</commandName>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The `handler.js` parses these tags, matches regex patterns in `actions.js`, and executes async functions:
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
// actions.js pattern
|
|
138
|
+
[/<googleSearch>([\s\S]*?)<\/googleSearch>/s, async (match) => {
|
|
139
|
+
const data = JSON.parse(match[1].trim());
|
|
140
|
+
const results = await openkbs.googleSearch(data.query);
|
|
141
|
+
return {
|
|
142
|
+
type: 'SEARCH_RESULTS',
|
|
143
|
+
data: results,
|
|
144
|
+
_meta_actions: ["REQUEST_CHAT_MODEL"] // Loop back to LLM
|
|
145
|
+
};
|
|
146
|
+
}]
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Meta Actions
|
|
150
|
+
|
|
151
|
+
Control flow after command execution:
|
|
152
|
+
|
|
153
|
+
- `["REQUEST_CHAT_MODEL"]` - Send result back to LLM for processing
|
|
154
|
+
- `[]` - Display result to user, stop conversation
|
|
155
|
+
|
|
156
|
+
## Memory System
|
|
157
|
+
|
|
158
|
+
Configure in `settings.json`:
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"itemTypes": {
|
|
163
|
+
"memory": {
|
|
164
|
+
"attributes": [
|
|
165
|
+
{ "attrName": "itemId", "attrType": "itemId", "encrypted": false },
|
|
166
|
+
{ "attrName": "body", "attrType": "body", "encrypted": true }
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"options": {
|
|
171
|
+
"priorityItems": [{ "prefix": "memory_", "limit": 100 }]
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Priority items are auto-injected into LLM context.
|
|
177
|
+
|
|
178
|
+
## Additional Resources
|
|
179
|
+
|
|
180
|
+
- For backend SDK methods, see [reference/backend-sdk.md](reference/backend-sdk.md)
|
|
181
|
+
- For frontend React patterns, see [reference/frontend-sdk.md](reference/frontend-sdk.md)
|
|
182
|
+
- For XML command definitions, see [reference/commands.md](reference/commands.md)
|
|
183
|
+
- For elastic services, see [reference/elastic-services.md](reference/elastic-services.md)
|
|
184
|
+
- For complete examples, see [examples/](examples/)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version": "0.1.0"}
|