* refactor: move Electron app to main directory and enforce ts strict mode * chore: add pre-install plugins * remove duplicated initModel function Signed-off-by: James <james@jan.ai> * chore: correct module path * fix: dynamic import does not work with ts * chore: web should be able to run on target host browser * fix: history panel, should display conversations rather just blank state * chore: init default model * chore: pluggin in ts * fix: pre-pack model management * fix: compiled core should not include plugins * chore: refactor - invoke plugin function * refactor download/delete file Signed-off-by: James <james@jan.ai> * update prebuild lib Signed-off-by: James <james@jan.ai> * chore: yarn workspace * chore: update yarn workspace * chore: yarn workspace with nohoist * fix: llama-cpp-import * chore: fix data-plugin wrong module path * chore: correct build step * chore: - separate inference service (#212) - remove base-plugin Signed-off-by: James <james@jan.ai> Co-authored-by: James <james@jan.ai> * chore: update core plugins * chore: hide installation prompt and fix model load - management plugin * chore: remove legacy files; update readme * fix: refresh page lost the download state Signed-off-by: James <james@jan.ai> * fix: ai prompt not passed to plugin Signed-off-by: James <james@jan.ai> * chore: module import fix for production * chore: auto updater * chore: package is public * chore: fix yarn workspace config * update: model management uses Q4_K_M * chore: fix yarn scripts for publishing * chore: app updater - progress update message * chore: user confirms update action * adding some state for changing page store downloaded model to database Signed-off-by: James <james@jan.ai> * chore: refactor plugins into yarn workspace - a single command to publish all base plugins * chore update readme (#218) Co-authored-by: Hien To <tominhhien97@gmail.com> * change app name and app icon Signed-off-by: James <james@jan.ai> * remove: go-to-nowhere actions * chore: bundle core plugins from root and scan default plugins * fix: app crashes on different field name lookup * chore: css fix * chore: bind download progress to app ui * chore: bind active model * chore: simplify app splash-screen only centered jan icon * feature: system monitoring plugin (#196) * feat: Add function for system monitoring * chore: register plugin functions * chore: move to corresponding directory * chore: bind system monitoring data to UI --------- Co-authored-by: Louis <louis@jan.ai> * chore: add build:plugins step to README * chore: model searching and fix model name * fix: plugin file selected appearance * fix: create new conversation does not work * fix: delete conversation not update state - messages still exist * chore: fix asset path prefix * Add CICD for macos (#221) Co-authored-by: Hien To <tominhhien97@gmail.com> * chore: fix production plugin path * chore: add shell open url in external browser --------- Signed-off-by: James <james@jan.ai> Co-authored-by: James <james@jan.ai> Co-authored-by: NamH <NamNh0122@gmail.com> Co-authored-by: 0xSage <n@pragmatic.vc> Co-authored-by: hiento09 <136591877+hiento09@users.noreply.github.com> Co-authored-by: Hien To <tominhhien97@gmail.com> Co-authored-by: namvuong <22463238+vuonghoainam@users.noreply.github.com>
213 lines
5.6 KiB
JavaScript
213 lines
5.6 KiB
JavaScript
import { init } from "."
|
|
import { join } from 'path'
|
|
import Plugin from "./Plugin"
|
|
import { mkdirSync, writeFileSync, existsSync, readFileSync, rmSync } from "fs"
|
|
|
|
const pluginsDir = './testPlugins'
|
|
const testPluginDir = './testPluginSrc'
|
|
const testPluginName = 'test-plugin'
|
|
const manifest = join(testPluginDir, 'package.json')
|
|
const main = 'index'
|
|
|
|
/** @type Plugin */
|
|
let plugin
|
|
|
|
beforeAll(() => {
|
|
init({
|
|
confirmInstall: () => true,
|
|
pluginsPath: pluginsDir,
|
|
})
|
|
|
|
mkdirSync(testPluginDir)
|
|
|
|
writeFileSync(manifest, JSON.stringify({
|
|
name: testPluginName,
|
|
activationPoints: [],
|
|
main,
|
|
}), 'utf8')
|
|
|
|
plugin = new Plugin(testPluginDir)
|
|
})
|
|
|
|
afterAll(() => {
|
|
rmSync(pluginsDir, { recursive: true })
|
|
rmSync(testPluginDir, { recursive: true })
|
|
})
|
|
|
|
|
|
describe('subscribe', () => {
|
|
let res = false
|
|
it('should register the provided callback', () => {
|
|
plugin.subscribe('test', () => res = true)
|
|
plugin.setActive(true)
|
|
|
|
expect(res).toBeTruthy()
|
|
})
|
|
})
|
|
|
|
describe('unsubscribe', () => {
|
|
it(`should remove the provided callback from the register
|
|
after which it should not be executed anymore when the plugin is updated`, () => {
|
|
let res = false
|
|
plugin.subscribe('test', () => res = true)
|
|
plugin.unsubscribe('test')
|
|
plugin.setActive(true)
|
|
|
|
expect(res).toBeFalsy()
|
|
})
|
|
})
|
|
|
|
describe('install', () => {
|
|
beforeAll(async () => {
|
|
await plugin._install()
|
|
})
|
|
|
|
it('should store all the relevant manifest values on the plugin', async () => {
|
|
expect(plugin).toMatchObject({
|
|
origin: testPluginDir,
|
|
installOptions: {
|
|
version: false,
|
|
fullMetadata: false,
|
|
},
|
|
name: testPluginName,
|
|
url: `plugin://${testPluginName}/${main}`,
|
|
activationPoints: []
|
|
})
|
|
})
|
|
|
|
it('should create a folder for the plugin if it does not yet exist and copy the plugin files to it', () => {
|
|
expect(existsSync(join(pluginsDir, testPluginName))).toBeTruthy()
|
|
})
|
|
|
|
it('should replace the existing plugin files in the plugin folder if it already exist', async () => {
|
|
writeFileSync(manifest, JSON.stringify({
|
|
name: testPluginName,
|
|
activationPoints: [],
|
|
main: 'updated',
|
|
}), 'utf8')
|
|
|
|
await plugin._install()
|
|
|
|
const savedPkg = JSON.parse(readFileSync(join(pluginsDir, testPluginName, 'package.json')))
|
|
|
|
expect(savedPkg.main).toBe('updated')
|
|
})
|
|
|
|
it('should throw an error and the plugin should be set to inactive if no manifest could be found', async () => {
|
|
rmSync(join(testPluginDir, 'package.json'))
|
|
|
|
await expect(() => plugin._install()).rejects.toThrow(/does not contain a valid manifest/)
|
|
})
|
|
|
|
it('should throw an error and the plugin should be set to inactive if plugin does not contain any activation points', async () => {
|
|
writeFileSync(manifest, JSON.stringify({
|
|
name: testPluginName,
|
|
main,
|
|
}), 'utf8')
|
|
|
|
await expect(() => plugin._install()).rejects.toThrow('The plugin does not contain any activation points')
|
|
expect(plugin.active).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('update', () => {
|
|
let updatedPlugin
|
|
let subscription = false
|
|
let beforeUpd
|
|
|
|
beforeAll(async () => {
|
|
writeFileSync(manifest, JSON.stringify({
|
|
name: testPluginName,
|
|
activationPoints: [],
|
|
version: '0.0.1',
|
|
main,
|
|
}), 'utf8')
|
|
|
|
await plugin._install()
|
|
|
|
plugin.subscribe('test', () => subscription = true)
|
|
beforeUpd = Object.assign({}, plugin)
|
|
|
|
await plugin.update()
|
|
})
|
|
|
|
it('should not do anything if no version update is available', () => {
|
|
expect(beforeUpd).toMatchObject(plugin)
|
|
})
|
|
|
|
it('should update the plugin files to the latest version if there is a new version available for the plugin', async () => {
|
|
writeFileSync(manifest, JSON.stringify({
|
|
name: testPluginName,
|
|
activationPoints: [],
|
|
version: '0.0.2',
|
|
main,
|
|
}), 'utf8')
|
|
|
|
await plugin.update()
|
|
|
|
expect(plugin).toMatchObject({
|
|
origin: testPluginDir,
|
|
installOptions: {
|
|
version: false,
|
|
fullMetadata: false,
|
|
},
|
|
name: testPluginName,
|
|
version: '0.0.2',
|
|
url: `plugin://${testPluginName}/${main}`,
|
|
activationPoints: []
|
|
})
|
|
})
|
|
|
|
it('should execute callbacks subscribed to this plugin, providing the plugin as a parameter', () => {
|
|
expect(subscription).toBeTruthy()
|
|
})
|
|
})
|
|
|
|
describe('isUpdateAvailable', () => {
|
|
it('should return false if no new version is available', async () => {
|
|
await expect(plugin.isUpdateAvailable()).resolves.toBe(false)
|
|
})
|
|
|
|
it('should return the latest version number if a new version is available', async () => {
|
|
writeFileSync(manifest, JSON.stringify({
|
|
name: testPluginName,
|
|
activationPoints: [],
|
|
version: '0.0.3',
|
|
main,
|
|
}), 'utf8')
|
|
|
|
await expect(plugin.isUpdateAvailable()).resolves.toBe('0.0.3')
|
|
})
|
|
})
|
|
|
|
describe('setActive', () => {
|
|
it('should set the plugin to be active', () => {
|
|
plugin.setActive(true)
|
|
expect(plugin.active).toBeTruthy()
|
|
})
|
|
|
|
it('should execute callbacks subscribed to this plugin, providing the plugin as a parameter', () => {
|
|
let res = false
|
|
plugin.subscribe('test', () => res = true)
|
|
plugin.setActive(true)
|
|
|
|
expect(res).toBeTruthy()
|
|
})
|
|
})
|
|
|
|
describe('uninstall', () => {
|
|
let subscription = false
|
|
beforeAll(async () => {
|
|
plugin.subscribe('test', () => subscription = true)
|
|
await plugin.uninstall()
|
|
})
|
|
|
|
it('should remove the installed plugin from the plugins folder', () => {
|
|
expect(existsSync(join(pluginsDir, testPluginName))).toBe(false)
|
|
})
|
|
|
|
it('should execute callbacks subscribed to this plugin, providing the plugin as a parameter', () => {
|
|
expect(subscription).toBeTruthy()
|
|
})
|
|
})
|