Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
# Dependencies
node_modules
.turbo

# Build outputs
dist
build
*.tsbuildinfo
.turbo
.turbo-tsconfig.json

# Environment files
.env
.eliza**
.env.local
.env.production
.env.bak

# IDE
.idea
.vscode
.zed
.DS_Store

# Test coverage
coverage
.nyc_output

# Logs
*.log
logs

# Cache
cache
.cache
tokencache

# Temporary files
*.tmp
*.temp
.tmp

# Bundler artifacts
tsup.config.bundled_*.mjs
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,24 @@ const object = await runtime.useModel(ModelType.OBJECT_LARGE, {
- You can pre-download models using `ollama pull modelname`
- Check model availability with `ollama list`

## Publishing (standalone repo)

When developing in a monorepo you keep `@elizaos/core` as `workspace:*`. When publishing from the standalone repo (e.g. after syncing from monorepo), the published package must use a real version so consumers can install.

- **After syncing from monorepo:** run `bun run prepare-publish` to set `@elizaos/core` to the version in `publishCoreVersion` (or set `CORE_VERSION` env). Commit that change so installs work in the standalone repo.
- **Before every publish:** `prepublishOnly` runs automatically and ensures the packed tarball has the correct core version even if `package.json` still has `workspace:*`.
- To change the published core version, update `publishCoreVersion` in `package.json` (or use `CORE_VERSION=1.8.0 bun run prepare-publish`).

### Git hooks (monorepo)

To always **commit** the verified core version and **check out** with `workspace:*` for local dev, install the hooks from the plugin directory (in the monorepo):

```bash
cd packages/plugin-ollama && bun run install-git-hooks
```

- **pre-commit:** Sets `@elizaos/core` to `publishCoreVersion` and stages `package.json`, so every commit has the publishable version.
- **post-checkout:** In a monorepo only, sets `@elizaos/core` back to `workspace:*` after checkout so installs use the local workspace. Not run when this repo is the standalone plugin repo (so installs keep working there).

## License

Expand Down
62 changes: 62 additions & 0 deletions build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bun
import { $ } from "bun";

async function build() {
const totalStart = Date.now();
const pkg = await Bun.file("package.json").json();
const externalDeps = [
...Object.keys(pkg.dependencies ?? {}),
...Object.keys(pkg.peerDependencies ?? {}),
];

// Use the clean script from package.json
if (pkg.scripts?.clean) {
console.log("🧹 Cleaning...");
await $`bun run clean`.quiet();
Comment on lines +12 to +16
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build.ts always runs the package's clean script before building. In this repo the clean script removes node_modules, so running build/dev will delete installed dependencies and can break or severely slow builds. Consider limiting clean to build artifacts (e.g., dist/tsbuildinfo) or make cleaning opt-in via a flag.

Suggested change
// Use the clean script from package.json
if (pkg.scripts?.clean) {
console.log("🧹 Cleaning...");
await $`bun run clean`.quiet();
// Use the clean script from package.json (opt-in via --clean)
const shouldClean = process.argv.includes("--clean");
if (pkg.scripts?.clean && shouldClean) {
console.log("🧹 Cleaning...");
await $`bun run clean`.quiet();
} else if (pkg.scripts?.clean && !shouldClean) {
console.log("ℹ️ Skipping clean step (run with --clean to execute `bun run clean`)");

Copilot uses AI. Check for mistakes.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build script deletes node_modules before tsc needs them

High Severity

build.ts unconditionally runs bun run clean before building. The clean script includes rm -rf node_modules, which deletes all installed dependencies. The subsequent tsc --project tsconfig.build.json step (line 38) requires node_modules to resolve type declarations for imports like @elizaos/core and ai. This causes tsc to fail or produce broken .d.ts files with unresolved types.

Additional Locations (1)
Fix in Cursor Fix in Web

}

const esmStart = Date.now();
console.log("🔨 Building @elizaos/plugin-ollama...");
const esmResult = await Bun.build({
entrypoints: ["src/index.ts"],
outdir: "dist",
target: "node",
format: "esm",
sourcemap: "external",
minify: false,
external: externalDeps,
});
if (!esmResult.success) {
console.error(esmResult.logs);
throw new Error("ESM build failed");
}
console.log(`✅ Build complete in ${((Date.now() - esmStart) / 1000).toFixed(2)}s`);

const dtsStart = Date.now();
if (true) { // Always generate .d.ts
console.log("📝 Generating TypeScript declarations...");
try {
await $`tsc --project tsconfig.build.json`;
console.log(`✅ Declarations generated in ${((Date.now() - dtsStart) / 1000).toFixed(2)}s`);
} catch (error) {
console.warn(`⚠️ TypeScript declaration generation had errors (${((Date.now() - dtsStart) / 1000).toFixed(2)}s)`);
console.warn(" Build will continue - fix type errors when possible");
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The declarations build catches tsc failures and continues. That can produce a JS build with missing/stale/broken .d.ts, which is especially risky for a published package. Consider failing the build on declaration errors (or gating the "continue on error" behavior behind an explicit env var/flag).

Copilot uses AI. Check for mistakes.
} else {
console.log("🔍 Type checking...");
try {
await $`tsc --noEmit --incremental --project tsconfig.build.json`;
console.log(`✅ Type check passed in ${((Date.now() - dtsStart) / 1000).toFixed(2)}s`);
} catch (error) {
console.warn(`⚠️ Type checking had errors (${((Date.now() - dtsStart) / 1000).toFixed(2)}s)`);
console.warn(" Build will continue - fix type errors when possible");
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code: hardcoded if (true) makes else branch unreachable

The if (true) guard was likely left as a placeholder during development. The entire else block (type-check-only path) can never execute, which means it is dead code that will mislead anyone reading the file and is never tested.

Suggested change
if (true) { // Always generate .d.ts
console.log("📝 Generating TypeScript declarations...");
try {
await $`tsc --project tsconfig.build.json`;
console.log(`✅ Declarations generated in ${((Date.now() - dtsStart) / 1000).toFixed(2)}s`);
} catch (error) {
console.warn(`⚠️ TypeScript declaration generation had errors (${((Date.now() - dtsStart) / 1000).toFixed(2)}s)`);
console.warn(" Build will continue - fix type errors when possible");
}
} else {
console.log("🔍 Type checking...");
try {
await $`tsc --noEmit --incremental --project tsconfig.build.json`;
console.log(`✅ Type check passed in ${((Date.now() - dtsStart) / 1000).toFixed(2)}s`);
} catch (error) {
console.warn(`⚠️ Type checking had errors (${((Date.now() - dtsStart) / 1000).toFixed(2)}s)`);
console.warn(" Build will continue - fix type errors when possible");
}
}
// Always generate .d.ts
console.log("📝 Generating TypeScript declarations...");
try {
await $`tsc --project tsconfig.build.json`;
console.log(`✅ Declarations generated in ${((Date.now() - dtsStart) / 1000).toFixed(2)}s`);
} catch (error) {
console.warn(`⚠️ TypeScript declaration generation had errors (${((Date.now() - dtsStart) / 1000).toFixed(2)}s)`);
console.warn(" Build will continue - fix type errors when possible");
}


console.log(`🎉 All builds finished in ${((Date.now() - totalStart) / 1000).toFixed(2)}s`);
}

build().catch((err) => {
console.error("Build failed:", err);
process.exit(1);
});
13 changes: 9 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,27 @@
],
"dependencies": {
"@ai-sdk/ui-utils": "^1.2.8",
"@elizaos/core": "^1.0.0",
"@elizaos/core": "1.7.2",
"ai": "^4.3.9",
"js-tiktoken": "^1.0.18",
"ollama-ai-provider": "^1.2.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tsup listed as a runtime dependency

tsup is a build tool and should be in devDependencies, not dependencies. Keeping it in dependencies causes it to be installed in production environments and inflates the package's install footprint for consumers.

Suggested change
"ollama-ai-provider": "^1.2.0",
"tsup": "8.4.0"

Move the line to devDependencies.

"tsup": "8.4.0"
},
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"build": "bun run build.ts",
"dev": "bun run build.ts --watch",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dev --watch flag is silently ignored

The new dev script passes --watch to build.ts as a CLI argument, but build.ts never reads process.argv or Bun.argv, so the flag has no effect. Running bun run dev will perform a single build and exit — it will not watch for changes as the script name implies.

Either implement watch mode in build.ts (e.g., via Bun.build({ watch: true, … })) or remove the --watch flag until the feature is ready.

Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dev script passes --watch to build.ts, but build.ts never reads argv or enables Bun.build watch mode / tsc watch. As-is, bun run build.ts --watch will do a one-off build, so dev is misleading/broken. Either implement watch handling in build.ts or change the script to a command that actually watches.

Suggested change
"dev": "bun run build.ts --watch",
"dev": "bun --watch run build.ts",

Copilot uses AI. Check for mistakes.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

The dev script's --watch flag is not handled by build.ts.

The dev script passes --watch to build.ts, but build.ts doesn't parse command-line arguments or implement watch mode. The script will run once and exit, not providing the expected continuous rebuild behavior.

Consider either:

  1. Implementing watch mode in build.ts using Bun.argv or a flag parser
  2. Using a different approach for dev mode (e.g., keeping tsup for watch mode)
♻️ Example watch mode implementation
+const watchMode = Bun.argv.includes("--watch");
+
 async function build() {
   // ... existing build logic ...
 }
 
-build().catch((err) => {
-  console.error("Build failed:", err);
-  process.exit(1);
-});
+if (watchMode) {
+  const { watch } = await import("fs");
+  console.log("👀 Watching for changes...");
+  build(); // Initial build
+  watch("src", { recursive: true }, async (event, filename) => {
+    console.log(`\n📝 ${filename} changed, rebuilding...`);
+    await build();
+  });
+} else {
+  build().catch((err) => {
+    console.error("Build failed:", err);
+    process.exit(1);
+  });
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 33 - 34, The dev script passes --watch to build.ts
but build.ts doesn't read CLI flags, so implement watch handling: update
build.ts to parse Bun.argv (or a flag parser) and add a watch mode that runs the
existing build logic repeatedly or hooks into a file watcher; specifically
detect the presence of "--watch" (or "--watch=true") in Bun.argv inside build.ts
and, when present, start a file watcher loop that re-runs the build routine (the
same function currently performing the single build) on file changes, or
alternatively remove the flag from package.json and use a separate watcher
tool—ensure changes reference build.ts and Bun.argv (or the chosen flag parser)
and reuse the existing build function to avoid duplication.

"lint": "prettier --write ./src",
"clean": "rm -rf dist .turbo node_modules .turbo-tsconfig.json tsconfig.tsbuildinfo",
"format": "prettier --write ./src",
"format:check": "prettier --check ./src",
"test": "bun test",
"postinstall": "bun scripts/install-ollama.js"
"postinstall": "bun scripts/install-ollama.js",
"prepare-publish": "bun run scripts/rewrite-core-version.ts",
"restore-workspace": "bun run scripts/rewrite-core-version.ts --restore",
"prepublishOnly": "bun run scripts/rewrite-core-version.ts",
"install-git-hooks": "bun run scripts/install-git-hooks.ts"
},
"publishCoreVersion": "1.7.2",
"publishConfig": {
"access": "public"
},
Expand Down
11 changes: 11 additions & 0 deletions scripts/git-hooks/post-checkout
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Post-checkout: in a monorepo, set @elizaos/core back to workspace:* so dev uses local core.
# Skip when this is the standalone repo (no workspace to link).
set -e
ROOT="$(git rev-parse --show-toplevel)"
if [ -f "$ROOT/packages/plugin-ollama/package.json" ] && grep -q '"publishCoreVersion"' "$ROOT/packages/plugin-ollama/package.json" 2>/dev/null; then
PLUGIN_DIR="$ROOT/packages/plugin-ollama"
(cd "$PLUGIN_DIR" && bun run scripts/rewrite-core-version.ts --restore)
fi
# If repo root has publishCoreVersion (standalone), do not restore — keep committed version for installs.
exit 0
13 changes: 13 additions & 0 deletions scripts/git-hooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Pre-commit: ensure @elizaos/core is the verified version from publishCoreVersion so we commit the publishable state.
set -e
ROOT="$(git rev-parse --show-toplevel)"
if [ -f "$ROOT/packages/plugin-ollama/package.json" ] && grep -q '"publishCoreVersion"' "$ROOT/packages/plugin-ollama/package.json" 2>/dev/null; then
PLUGIN_DIR="$ROOT/packages/plugin-ollama"
else
[ -f "$ROOT/package.json" ] && grep -q '"publishCoreVersion"' "$ROOT/package.json" 2>/dev/null || exit 0
PLUGIN_DIR="$ROOT"
fi
(cd "$PLUGIN_DIR" && bun run scripts/rewrite-core-version.ts)
git add "$PLUGIN_DIR/package.json"
exit 0
28 changes: 28 additions & 0 deletions scripts/install-git-hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bun
/**
* Install git hooks so that:
* - pre-commit: commit with @elizaos/core = publishCoreVersion (verified for publish)
* - post-checkout: in monorepo, restore workspace:* for local dev
*
* Run from plugin dir: bun run scripts/install-git-hooks.ts
* Uses git rev-parse to find .git (works when plugin is in monorepo or standalone).
*/
import { $ } from "bun";
import { mkdir, writeFile } from "fs/promises";
import { join } from "path";

const pluginDir = join(import.meta.dir, "..");
const gitDir = (await $`git -C "${pluginDir}" rev-parse --git-dir`.text()).trim();
const hooksDir = join(pluginDir, gitDir, "hooks");
const hooksSource = join(pluginDir, "scripts", "git-hooks");

await mkdir(hooksDir, { recursive: true });

for (const name of ["pre-commit", "post-checkout"]) {
const src = join(hooksSource, name);
const dest = join(hooksDir, name);
const content = await Bun.file(src).text();
await writeFile(dest, content, { mode: 0o755 });
console.log(`Installed ${name} -> ${dest}`);
}
console.log("Git hooks installed. Pre-commit will use publishCoreVersion; post-checkout will restore workspace:* in monorepo.");
41 changes: 41 additions & 0 deletions scripts/rewrite-core-version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bun
/**
* For standalone publish: replace workspace:* with a real @elizaos/core version
* so installs work outside the monorepo. Run after syncing from monorepo or in
* prepublishOnly. Use --restore to set back to workspace:* (e.g. after publish).
*
* Usage:
* bun run scripts/rewrite-core-version.ts # set to publish version
* bun run scripts/rewrite-core-version.ts --restore # set back to workspace:*
*
* Version: from package.json "publishCoreVersion" or env CORE_VERSION or "1.7.2"
*/

const RESTORE = process.argv.includes("--restore");
const pkgPath = new URL("../package.json", import.meta.url);
const pkg = (await Bun.file(pkgPath).json()) as Record<string, unknown> & {
dependencies?: Record<string, string>;
publishCoreVersion?: string;
};
const coreVersion =
process.env.CORE_VERSION ?? pkg.publishCoreVersion ?? "1.7.2";
const deps = pkg.dependencies ?? {};
const current = deps["@elizaos/core"];
Comment on lines +22 to +23
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Bug: Modifications to deps won't persist if pkg.dependencies is undefined.

If pkg.dependencies is undefined, the nullish coalescing creates a new empty object that isn't connected to pkg. Changes to deps won't be reflected in the written file.

🐛 Proposed fix
-const deps = pkg.dependencies ?? {};
+pkg.dependencies = pkg.dependencies ?? {};
+const deps = pkg.dependencies;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/rewrite-core-version.ts` around lines 22 - 23, The bug is that using
"const deps = pkg.dependencies ?? {}" creates a disconnected object when
pkg.dependencies is undefined so subsequent changes to deps won't be written
back; fix by ensuring pkg.dependencies is initialized on pkg before mutating:
explicitly set pkg.dependencies = pkg.dependencies ?? {} and then use const deps
= pkg.dependencies (or mutate pkg.dependencies directly) so modifications to
deps/current are persisted when writing the package back.


if (RESTORE) {
if (current !== coreVersion) {
console.log(`@elizaos/core is "${current}", not "${coreVersion}", skipping restore`);
process.exit(0);
}
deps["@elizaos/core"] = "workspace:*";
console.log('Set @elizaos/core to "workspace:*"');
} else {
if (current === coreVersion) {
console.log(`@elizaos/core already "${coreVersion}"`);
process.exit(0);
}
deps["@elizaos/core"] = coreVersion;
console.log(`Set @elizaos/core to "${coreVersion}"`);
}

await Bun.write(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
Loading