@hmawla/co-assistant 1.0.1 → 1.0.3
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 +22 -1
- package/dist/cli/index.js +118 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -320,7 +320,10 @@ All configured via `.env` (the setup wizard handles this):
|
|
|
320
320
|
| `co-assistant start -v` | Start with verbose logging |
|
|
321
321
|
| `co-assistant model` | Show current AI model |
|
|
322
322
|
| `co-assistant model <name>` | Switch AI model |
|
|
323
|
-
| `co-assistant plugin list` | List discovered plugins |
|
|
323
|
+
| `co-assistant plugin list` | List discovered plugins in local `plugins/` |
|
|
324
|
+
| `co-assistant plugin available` | List bundled first-party plugins |
|
|
325
|
+
| `co-assistant plugin install <id>` | Install a bundled plugin into `plugins/` |
|
|
326
|
+
| `co-assistant plugin install --all` | Install all bundled plugins |
|
|
324
327
|
| `co-assistant plugin enable <name>` | Enable a plugin |
|
|
325
328
|
| `co-assistant plugin disable <name>` | Disable a plugin |
|
|
326
329
|
| `co-assistant plugin configure <name>` | Set up plugin credentials |
|
|
@@ -385,6 +388,24 @@ Both files are injected as system-level context on every message:
|
|
|
385
388
|
| **Gmail** | Search emails, read email, send email, send reply |
|
|
386
389
|
| **Google Calendar** | List events, create event, update event, delete event |
|
|
387
390
|
|
|
391
|
+
### Install Plugins
|
|
392
|
+
|
|
393
|
+
Co-Assistant ships with first-party plugins (Gmail, Google Calendar). If you installed via npm, they aren't in your working directory yet — install them with:
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
# See what's available
|
|
397
|
+
co-assistant plugin available
|
|
398
|
+
|
|
399
|
+
# Install a specific plugin
|
|
400
|
+
co-assistant plugin install gmail
|
|
401
|
+
|
|
402
|
+
# Install all bundled plugins at once
|
|
403
|
+
co-assistant plugin install --all
|
|
404
|
+
|
|
405
|
+
# Overwrite an existing plugin (e.g. after an update)
|
|
406
|
+
co-assistant plugin install gmail --force
|
|
407
|
+
```
|
|
408
|
+
|
|
388
409
|
### Enable a Plugin
|
|
389
410
|
|
|
390
411
|
```bash
|
package/dist/cli/index.js
CHANGED
|
@@ -27,11 +27,19 @@ function resolveLogLevel() {
|
|
|
27
27
|
const valid = ["fatal", "error", "warn", "info", "debug", "trace", "silent"];
|
|
28
28
|
return envLevel && valid.includes(envLevel) ? envLevel : "info";
|
|
29
29
|
}
|
|
30
|
+
function isPinoPrettyAvailable() {
|
|
31
|
+
try {
|
|
32
|
+
import.meta.resolve("pino-pretty");
|
|
33
|
+
return true;
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
30
38
|
function buildLoggerOptions() {
|
|
31
39
|
const level = resolveLogLevel();
|
|
32
40
|
const isProduction = process.env.NODE_ENV === "production";
|
|
33
41
|
const opts = { level };
|
|
34
|
-
if (!isProduction) {
|
|
42
|
+
if (!isProduction && isPinoPrettyAvailable()) {
|
|
35
43
|
opts.transport = {
|
|
36
44
|
target: "pino-pretty",
|
|
37
45
|
options: {
|
|
@@ -3401,7 +3409,7 @@ ${question}`);
|
|
|
3401
3409
|
}
|
|
3402
3410
|
}
|
|
3403
3411
|
async function promptFilePath(question) {
|
|
3404
|
-
const { existsSync: existsSync9, readFileSync:
|
|
3412
|
+
const { existsSync: existsSync9, readFileSync: readFileSync7 } = await import("fs");
|
|
3405
3413
|
const { resolve } = await import("path");
|
|
3406
3414
|
while (true) {
|
|
3407
3415
|
const raw = await ask(`${question}: `);
|
|
@@ -3415,7 +3423,7 @@ async function promptFilePath(question) {
|
|
|
3415
3423
|
continue;
|
|
3416
3424
|
}
|
|
3417
3425
|
try {
|
|
3418
|
-
return
|
|
3426
|
+
return readFileSync7(filePath, "utf-8");
|
|
3419
3427
|
} catch {
|
|
3420
3428
|
console.log(` \u26A0 Could not read file: ${filePath}`);
|
|
3421
3429
|
}
|
|
@@ -3960,8 +3968,45 @@ Configuring plugin: ${manifest.id}`);
|
|
|
3960
3968
|
}
|
|
3961
3969
|
|
|
3962
3970
|
// src/cli/commands/plugin.ts
|
|
3963
|
-
import {
|
|
3971
|
+
import {
|
|
3972
|
+
existsSync as existsSync7,
|
|
3973
|
+
mkdirSync as mkdirSync4,
|
|
3974
|
+
writeFileSync as writeFileSync5,
|
|
3975
|
+
readdirSync as readdirSync3,
|
|
3976
|
+
readFileSync as readFileSync6,
|
|
3977
|
+
cpSync
|
|
3978
|
+
} from "fs";
|
|
3964
3979
|
import path4 from "path";
|
|
3980
|
+
import { fileURLToPath } from "url";
|
|
3981
|
+
function getPackagePluginsDir() {
|
|
3982
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
3983
|
+
const pkgRoot = path4.resolve(path4.dirname(thisFile), "..", "..", "..");
|
|
3984
|
+
const pluginsDir = path4.join(pkgRoot, "plugins");
|
|
3985
|
+
if (!existsSync7(pluginsDir)) {
|
|
3986
|
+
const altRoot = path4.resolve(path4.dirname(thisFile), "..", "..");
|
|
3987
|
+
const altDir = path4.join(altRoot, "plugins");
|
|
3988
|
+
if (existsSync7(altDir)) return altDir;
|
|
3989
|
+
}
|
|
3990
|
+
return pluginsDir;
|
|
3991
|
+
}
|
|
3992
|
+
function discoverBundledPlugins() {
|
|
3993
|
+
const pkgPluginsDir = getPackagePluginsDir();
|
|
3994
|
+
if (!existsSync7(pkgPluginsDir)) return [];
|
|
3995
|
+
const entries = readdirSync3(pkgPluginsDir, { withFileTypes: true });
|
|
3996
|
+
const results = [];
|
|
3997
|
+
for (const entry of entries) {
|
|
3998
|
+
if (!entry.isDirectory()) continue;
|
|
3999
|
+
const manifestPath = path4.join(pkgPluginsDir, entry.name, "plugin.json");
|
|
4000
|
+
if (!existsSync7(manifestPath)) continue;
|
|
4001
|
+
try {
|
|
4002
|
+
const raw = readFileSync6(manifestPath, "utf-8");
|
|
4003
|
+
const manifest = JSON.parse(raw);
|
|
4004
|
+
results.push({ ...manifest, sourcePath: path4.join(pkgPluginsDir, entry.name) });
|
|
4005
|
+
} catch {
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
return results;
|
|
4009
|
+
}
|
|
3965
4010
|
async function loadRegistry() {
|
|
3966
4011
|
const registry = createPluginRegistry();
|
|
3967
4012
|
const manifests = await registry.discoverPlugins();
|
|
@@ -4179,9 +4224,77 @@ Edit \`tools.ts\` to add or modify the tools this plugin exposes.
|
|
|
4179
4224
|
writeFileSync5(path4.join(pluginDir, "README.md"), readmeContent, "utf-8");
|
|
4180
4225
|
console.log(`\u2713 Plugin '${pluginId}' scaffolded at plugins/${pluginId}/`);
|
|
4181
4226
|
}
|
|
4227
|
+
async function handleAvailable() {
|
|
4228
|
+
const bundled = discoverBundledPlugins();
|
|
4229
|
+
if (bundled.length === 0) {
|
|
4230
|
+
console.log("\n\u{1F4E6} No bundled first-party plugins found.\n");
|
|
4231
|
+
return;
|
|
4232
|
+
}
|
|
4233
|
+
const localPluginsDir = path4.join(process.cwd(), "plugins");
|
|
4234
|
+
console.log("\n\u{1F4E6} Available First-Party Plugins:\n");
|
|
4235
|
+
for (const plugin of bundled) {
|
|
4236
|
+
const localDir = path4.join(localPluginsDir, plugin.id);
|
|
4237
|
+
const installed = existsSync7(path4.join(localDir, "plugin.json"));
|
|
4238
|
+
const status = installed ? "\u2705 Installed" : "\u2B07\uFE0F Not installed";
|
|
4239
|
+
console.log(` ${plugin.id} (v${plugin.version}) \u2014 ${plugin.name}`);
|
|
4240
|
+
console.log(` ${plugin.description}`);
|
|
4241
|
+
console.log(` ${status}
|
|
4242
|
+
`);
|
|
4243
|
+
}
|
|
4244
|
+
console.log(" Install with: co-assistant plugin install <id>");
|
|
4245
|
+
console.log(" Install all: co-assistant plugin install --all\n");
|
|
4246
|
+
}
|
|
4247
|
+
async function handleInstall(pluginId, options) {
|
|
4248
|
+
const bundled = discoverBundledPlugins();
|
|
4249
|
+
if (bundled.length === 0) {
|
|
4250
|
+
console.error("\u2717 No bundled first-party plugins found in the package.");
|
|
4251
|
+
process.exit(1);
|
|
4252
|
+
}
|
|
4253
|
+
let toInstall;
|
|
4254
|
+
if (options.all) {
|
|
4255
|
+
toInstall = bundled;
|
|
4256
|
+
} else if (pluginId) {
|
|
4257
|
+
const match = bundled.find((p) => p.id === pluginId);
|
|
4258
|
+
if (!match) {
|
|
4259
|
+
console.error(`\u2717 Plugin '${pluginId}' is not a bundled first-party plugin.`);
|
|
4260
|
+
console.error(` Available: ${bundled.map((p) => p.id).join(", ")}`);
|
|
4261
|
+
process.exit(1);
|
|
4262
|
+
}
|
|
4263
|
+
toInstall = [match];
|
|
4264
|
+
} else {
|
|
4265
|
+
console.error("\u2717 Specify a plugin ID or use --all to install all plugins.");
|
|
4266
|
+
console.error(` Available: ${bundled.map((p) => p.id).join(", ")}`);
|
|
4267
|
+
process.exit(1);
|
|
4268
|
+
}
|
|
4269
|
+
const localPluginsDir = path4.join(process.cwd(), "plugins");
|
|
4270
|
+
mkdirSync4(localPluginsDir, { recursive: true });
|
|
4271
|
+
let installed = 0;
|
|
4272
|
+
let skipped = 0;
|
|
4273
|
+
for (const plugin of toInstall) {
|
|
4274
|
+
const destDir = path4.join(localPluginsDir, plugin.id);
|
|
4275
|
+
const alreadyExists = existsSync7(path4.join(destDir, "plugin.json"));
|
|
4276
|
+
if (alreadyExists && !options.force) {
|
|
4277
|
+
console.log(` \u23ED ${plugin.id} \u2014 already installed (use --force to overwrite)`);
|
|
4278
|
+
skipped++;
|
|
4279
|
+
continue;
|
|
4280
|
+
}
|
|
4281
|
+
cpSync(plugin.sourcePath, destDir, { recursive: true });
|
|
4282
|
+
console.log(` \u2705 ${plugin.id} \u2014 installed to plugins/${plugin.id}/`);
|
|
4283
|
+
installed++;
|
|
4284
|
+
}
|
|
4285
|
+
console.log(`
|
|
4286
|
+
\u2713 ${installed} installed, ${skipped} skipped`);
|
|
4287
|
+
if (installed > 0) {
|
|
4288
|
+
console.log("\nNext steps:");
|
|
4289
|
+
console.log(" co-assistant plugin configure <id> # Set up credentials");
|
|
4290
|
+
console.log(" co-assistant plugin enable <id> # Enable the plugin\n");
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4182
4293
|
function registerPluginCommand(program2) {
|
|
4183
4294
|
const plugin = program2.command("plugin").description("Manage plugins");
|
|
4184
|
-
plugin.command("list").description("List all
|
|
4295
|
+
plugin.command("list").description("List all plugins in the local plugins/ directory").action(handleList);
|
|
4296
|
+
plugin.command("available").description("List bundled first-party plugins and their install status").action(handleAvailable);
|
|
4297
|
+
plugin.command("install").description("Install a first-party plugin from the package").argument("[id]", "Plugin ID to install (omit with --all)").option("--all", "Install all available first-party plugins").option("--force", "Overwrite existing plugins").action(handleInstall);
|
|
4185
4298
|
plugin.command("enable").description("Enable a plugin").argument("<id>", "Plugin ID to enable").action(handleEnable);
|
|
4186
4299
|
plugin.command("disable").description("Disable a plugin").argument("<id>", "Plugin ID to disable").action(handleDisable);
|
|
4187
4300
|
plugin.command("info").description("Show detailed information about a plugin").argument("<id>", "Plugin ID to inspect").action(handleInfo);
|