@tagma/sdk 0.3.7 → 0.3.9
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 +16 -2
- package/package.json +4 -2
- package/scripts/preinstall.js +38 -0
- package/src/registry.ts +36 -1
- package/src/sdk.ts +1 -0
package/README.md
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
# @tagma/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> ## ⚠️ Bun-only package — do **not** `npm install`
|
|
4
|
+
>
|
|
5
|
+
> ```bash
|
|
6
|
+
> bun add @tagma/sdk
|
|
7
|
+
> ```
|
|
8
|
+
>
|
|
9
|
+
> This package ships TypeScript source (`main: ./src/sdk.ts`) and relies on
|
|
10
|
+
> Bun's native `.ts` loader. `npm` / `yarn` / `pnpm` installs are blocked by a
|
|
11
|
+
> `preinstall` guard and will fail by design. Get Bun at <https://bun.sh>.
|
|
12
|
+
>
|
|
13
|
+
> *(The `npm i @tagma/sdk` line in the npmjs.com sidebar is auto-generated by
|
|
14
|
+
> the npm registry website and cannot be removed — please ignore it and use
|
|
15
|
+
> the command above.)*
|
|
4
16
|
|
|
5
|
-
|
|
17
|
+
A local AI task orchestration SDK for [Bun](https://bun.sh). Define multi-track pipelines in YAML, run AI coding agents (Claude Code, Codex, OpenCode) and shell commands in parallel with dependency resolution, approval gates, and lifecycle hooks.
|
|
6
18
|
|
|
7
19
|
## Install
|
|
8
20
|
|
|
21
|
+
**Requires Bun ≥ 1.3.** Node/npm are not supported.
|
|
22
|
+
|
|
9
23
|
```bash
|
|
10
24
|
bun add @tagma/sdk
|
|
11
25
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tagma/sdk",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,13 +15,15 @@
|
|
|
15
15
|
".": "./src/sdk.ts"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
|
-
"src"
|
|
18
|
+
"src",
|
|
19
|
+
"scripts/preinstall.js"
|
|
19
20
|
],
|
|
20
21
|
"engines": {
|
|
21
22
|
"bun": ">=1.3"
|
|
22
23
|
},
|
|
23
24
|
"packageManager": "bun@1.3.7",
|
|
24
25
|
"scripts": {
|
|
26
|
+
"preinstall": "node scripts/preinstall.js",
|
|
25
27
|
"test": "bun test",
|
|
26
28
|
"release": "bun scripts/release.ts",
|
|
27
29
|
"release:publish": "bun scripts/release.ts --publish"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Preinstall guard — refuses installation under npm / yarn / pnpm.
|
|
2
|
+
// @tagma/sdk ships TypeScript source (main: ./src/sdk.ts) and relies on
|
|
3
|
+
// Bun's native .ts loader, so installing under Node-based managers leaves
|
|
4
|
+
// users with a broken package.
|
|
5
|
+
//
|
|
6
|
+
// Bun detection: we can't rely on process.versions.bun alone, because bun
|
|
7
|
+
// invokes lifecycle scripts via the interpreter named in the script command
|
|
8
|
+
// ("node scripts/preinstall.js" runs under node even when called from bun
|
|
9
|
+
// install). Bun does, however, set npm_config_user_agent to a string that
|
|
10
|
+
// starts with "bun/<version> ...", which is the canonical cross-manager
|
|
11
|
+
// signal. Check both for safety.
|
|
12
|
+
|
|
13
|
+
const ua = process.env.npm_config_user_agent || '';
|
|
14
|
+
if (process.versions.bun || ua.startsWith('bun/') || ua.startsWith('bun ')) {
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const red = (s) => `\x1b[31m${s}\x1b[0m`;
|
|
19
|
+
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
20
|
+
const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
|
|
21
|
+
|
|
22
|
+
process.stderr.write(
|
|
23
|
+
[
|
|
24
|
+
'',
|
|
25
|
+
red(bold(' @tagma/sdk requires Bun (>= 1.3).')),
|
|
26
|
+
'',
|
|
27
|
+
' This package ships TypeScript source and uses Bun\'s native .ts loader.',
|
|
28
|
+
' npm / yarn / pnpm cannot consume it.',
|
|
29
|
+
'',
|
|
30
|
+
' Install with:',
|
|
31
|
+
cyan(' bun add @tagma/sdk'),
|
|
32
|
+
'',
|
|
33
|
+
' Get Bun: https://bun.sh',
|
|
34
|
+
'',
|
|
35
|
+
].join('\n') + '\n',
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
process.exit(1);
|
package/src/registry.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
PluginCategory, DriverPlugin, TriggerPlugin,
|
|
3
|
-
CompletionPlugin, MiddlewarePlugin,
|
|
3
|
+
CompletionPlugin, MiddlewarePlugin, PluginManifest,
|
|
4
4
|
} from './types';
|
|
5
5
|
|
|
6
6
|
type PluginType = DriverPlugin | TriggerPlugin | CompletionPlugin | MiddlewarePlugin;
|
|
@@ -155,6 +155,41 @@ export function isValidPluginName(name: unknown): name is string {
|
|
|
155
155
|
return typeof name === 'string' && PLUGIN_NAME_RE.test(name);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Parse and validate the `tagmaPlugin` field of a `package.json` blob.
|
|
160
|
+
*
|
|
161
|
+
* Returns the strongly-typed manifest if the field is present and
|
|
162
|
+
* well-formed (`category` is one of the four known categories and `type`
|
|
163
|
+
* is a non-empty string). Returns `null` if the field is absent — that
|
|
164
|
+
* is the host's signal that the package is a library, not a plugin.
|
|
165
|
+
*
|
|
166
|
+
* Throws if the field is present but malformed: that's a packaging bug
|
|
167
|
+
* the plugin author should hear about loudly, not a silent skip.
|
|
168
|
+
*
|
|
169
|
+
* Hosts use this during auto-discovery to decide whether to load a
|
|
170
|
+
* package as a plugin without having to dynamically `import()` it.
|
|
171
|
+
*/
|
|
172
|
+
export function readPluginManifest(pkgJson: unknown): PluginManifest | null {
|
|
173
|
+
if (!pkgJson || typeof pkgJson !== 'object') return null;
|
|
174
|
+
const raw = (pkgJson as Record<string, unknown>).tagmaPlugin;
|
|
175
|
+
if (raw === undefined) return null;
|
|
176
|
+
if (!raw || typeof raw !== 'object') {
|
|
177
|
+
throw new Error('tagmaPlugin field must be an object with { category, type }');
|
|
178
|
+
}
|
|
179
|
+
const m = raw as Record<string, unknown>;
|
|
180
|
+
const category = m.category;
|
|
181
|
+
const type = m.type;
|
|
182
|
+
if (typeof category !== 'string' || !VALID_CATEGORIES.has(category as PluginCategory)) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
`tagmaPlugin.category must be one of ${[...VALID_CATEGORIES].join(', ')}, got ${JSON.stringify(category)}`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
if (typeof type !== 'string' || type.length === 0) {
|
|
188
|
+
throw new Error(`tagmaPlugin.type must be a non-empty string, got ${JSON.stringify(type)}`);
|
|
189
|
+
}
|
|
190
|
+
return { category: category as PluginCategory, type };
|
|
191
|
+
}
|
|
192
|
+
|
|
158
193
|
export async function loadPlugins(pluginNames: readonly string[]): Promise<void> {
|
|
159
194
|
for (const name of pluginNames) {
|
|
160
195
|
if (!isValidPluginName(name)) {
|