busa-cli 0.41.0 → 0.50.0
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/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as runCli, r as pkgVersion, t as checkForUpdate } from "./update-check-
|
|
2
|
+
import { i as runCli, r as pkgVersion, t as checkForUpdate } from "./update-check-Cq2ouWym.js";
|
|
3
3
|
//#region src/cli.ts
|
|
4
4
|
const exitCode = await runCli(process.argv.slice(2));
|
|
5
5
|
const notice = await checkForUpdate("busabase-cli", pkgVersion());
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as render, i as runCli, n as HELP, r as pkgVersion, t as checkForUpdate } from "./update-check-
|
|
1
|
+
import { a as render, i as runCli, n as HELP, r as pkgVersion, t as checkForUpdate } from "./update-check-Cq2ouWym.js";
|
|
2
2
|
import { DEFAULT_BASE_URL, createBusabaseClient, normalizeBaseUrl } from "busabase-sdk";
|
|
3
3
|
export { DEFAULT_BASE_URL, HELP, checkForUpdate, createBusabaseClient, normalizeBaseUrl, pkgVersion, render, runCli };
|
|
@@ -5614,6 +5614,26 @@ const TemplateManifestSchema = z.object({
|
|
|
5614
5614
|
secrets: z.array(TemplateSecretSchema).default([]),
|
|
5615
5615
|
requires: z.object({ airapp: z.boolean().optional() }).default({})
|
|
5616
5616
|
});
|
|
5617
|
+
const TemplateRiskLevelSchema = z.enum([
|
|
5618
|
+
"gated-write",
|
|
5619
|
+
"local-write",
|
|
5620
|
+
"read-only",
|
|
5621
|
+
"sandbox"
|
|
5622
|
+
]);
|
|
5623
|
+
/**
|
|
5624
|
+
* Normalize a declared `risk` string to a known level, or `undefined`.
|
|
5625
|
+
*
|
|
5626
|
+
* Deliberately never throws. The frontmatter field stays a free-form string
|
|
5627
|
+
* (see `SkillBusabaseMetadataSchema` below) so an author's typo or an
|
|
5628
|
+
* already-published package using a since-retired term (`"review-first"`, from
|
|
5629
|
+
* before this enum existed) fails soft — the card shows "undeclared" instead of
|
|
5630
|
+
* guessing, and the package still installs. Only `busabase-cli check` should
|
|
5631
|
+
* ever turn an unrecognized value into something the author sees and fixes.
|
|
5632
|
+
*/
|
|
5633
|
+
const parseTemplateRisk = (raw) => {
|
|
5634
|
+
const result = TemplateRiskLevelSchema.safeParse(raw);
|
|
5635
|
+
return result.success ? result.data : void 0;
|
|
5636
|
+
};
|
|
5617
5637
|
/**
|
|
5618
5638
|
* `metadata.busabase` inside the root `SKILL.md`'s YAML frontmatter.
|
|
5619
5639
|
*
|
|
@@ -5627,6 +5647,12 @@ const SkillBusabaseMetadataSchema = z.object({
|
|
|
5627
5647
|
folderSlug: z.string().optional(),
|
|
5628
5648
|
/** Resource keys the manual talks about; each must exist under `content/`. */
|
|
5629
5649
|
resources: z.array(z.string()).default([]),
|
|
5650
|
+
/**
|
|
5651
|
+
* Free-form on purpose — see `parseTemplateRisk`. Validating this to the enum
|
|
5652
|
+
* here would turn a stranger's typo or a retired term into a hard parse
|
|
5653
|
+
* failure for the whole frontmatter, which is a worse outcome than a card
|
|
5654
|
+
* that cannot show a risk badge.
|
|
5655
|
+
*/
|
|
5630
5656
|
risk: z.string().optional()
|
|
5631
5657
|
});
|
|
5632
5658
|
/**
|
|
@@ -6291,12 +6317,7 @@ z.object({
|
|
|
6291
6317
|
z.object({
|
|
6292
6318
|
parentId: z.string().nullable().optional().describe("Node to start from. Omit or null to start from the space root."),
|
|
6293
6319
|
depth: z.coerce.number().int().min(1).max(5).optional().describe("How many levels beneath the start point to eagerly include (default 2 once either field is set). Capped at 5."),
|
|
6294
|
-
|
|
6295
|
-
* `active` (default) walks the live tree. `archived` returns the flat set of
|
|
6296
|
-
* soft-archived nodes for the Trash view — no `parentId`/`depth` walk, since
|
|
6297
|
-
* archived nodes are shown as a list, not a tree.
|
|
6298
|
-
*/
|
|
6299
|
-
status: z.enum(["active", "archived"]).optional().default("active"),
|
|
6320
|
+
status: z.enum(["active", "archived"]).optional().default("active").describe("`active` walks the live TREE. `archived` returns a FLAT list of soft-archived nodes (the Trash view) with no parent/depth walk — so the response shape you can rely on differs between the two, not just the rows."),
|
|
6300
6321
|
/**
|
|
6301
6322
|
* Narrow to specific node types and return a FLAT list of lightweight node
|
|
6302
6323
|
* summaries (`children: []`) instead of walking the tree. This is what
|
|
@@ -6323,8 +6344,8 @@ z.object({
|
|
|
6323
6344
|
types: z.union([z.array(z.enum(NODE_TYPES)), z.enum(NODE_TYPES)]).transform((value) => Array.isArray(value) ? value : [value]).optional().describe("Return a flat list of lightweight summaries for these node types instead of the tree. Read one node's full detail with GET /nodes/{nodeId}.")
|
|
6324
6345
|
}).optional();
|
|
6325
6346
|
z.object({
|
|
6326
|
-
nodeId: z.string(),
|
|
6327
|
-
potentialAncestorId: z.string()
|
|
6347
|
+
nodeId: z.string().describe("The node walked UPWARDS from — the possible descendant."),
|
|
6348
|
+
potentialAncestorId: z.string().describe("The node looked for on the way up. Answers \"is `nodeId` inside this one?\", not the reverse — swapping the two silently returns the wrong answer rather than an error.")
|
|
6328
6349
|
});
|
|
6329
6350
|
z.object({ isDescendant: z.boolean() });
|
|
6330
6351
|
z.object({
|
|
@@ -6379,8 +6400,8 @@ z.object({
|
|
|
6379
6400
|
agentPrompts: customAgentPromptsSchema.nullable()
|
|
6380
6401
|
});
|
|
6381
6402
|
z.object({
|
|
6382
|
-
query: z.string().min(1),
|
|
6383
|
-
limit: z.coerce.number().int().min(1).max(50).optional().default(20)
|
|
6403
|
+
query: z.string().min(1).describe("Matched against node NAMES only. Use `/api/v1/search` to search content."),
|
|
6404
|
+
limit: z.coerce.number().int().min(1).max(50).optional().default(20).describe("Results to return. Capped at 50 here, unlike most listings' 100.")
|
|
6384
6405
|
});
|
|
6385
6406
|
z.object({
|
|
6386
6407
|
id: z.string(),
|
|
@@ -6571,8 +6592,8 @@ z.object({
|
|
|
6571
6592
|
unreadCount: z.number().int()
|
|
6572
6593
|
});
|
|
6573
6594
|
z.object({
|
|
6574
|
-
page: z.number().int().min(1).optional().default(1),
|
|
6575
|
-
pageSize: z.number().int().min(1).max(100).optional().default(50)
|
|
6595
|
+
page: z.number().int().min(1).optional().default(1).describe("1-indexed, not 0-indexed."),
|
|
6596
|
+
pageSize: z.number().int().min(1).max(100).optional().default(50).describe("Mentions per page. Capped at 100.")
|
|
6576
6597
|
});
|
|
6577
6598
|
z.object({
|
|
6578
6599
|
/** Stamps every unread mention row this caller has on that comment. */
|
|
@@ -6810,8 +6831,8 @@ z.object({
|
|
|
6810
6831
|
reason: z.string().optional()
|
|
6811
6832
|
});
|
|
6812
6833
|
z.object({
|
|
6813
|
-
subjectType: commentSubjectTypeSchema,
|
|
6814
|
-
subjectId: z.string().min(1)
|
|
6834
|
+
subjectType: commentSubjectTypeSchema.describe("What the comment thread hangs off, which decides how `subjectId` is interpreted."),
|
|
6835
|
+
subjectId: z.string().min(1).describe("The subject's id, interpreted according to `subjectType`.")
|
|
6815
6836
|
}).extend({
|
|
6816
6837
|
authorId: z.string().optional().default("local-admin"),
|
|
6817
6838
|
body: z.string().trim().min(1),
|
|
@@ -6822,29 +6843,28 @@ z.object({
|
|
|
6822
6843
|
*/
|
|
6823
6844
|
mentions: z.array(commentMentionInputSchema).optional().default([])
|
|
6824
6845
|
});
|
|
6825
|
-
z.object({ limit: z.coerce.number().int().min(1).max(100).optional().default(50) }).optional().default({ limit: 50 });
|
|
6826
|
-
z.object({ status: z.enum(["active", "archived"]).optional().default("active") });
|
|
6846
|
+
z.object({ limit: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Rows to return, most recent first. Capped at 100; this listing has no cursor.") }).optional().default({ limit: 50 });
|
|
6847
|
+
z.object({ status: z.enum(["active", "archived"]).optional().default("active").describe("`active` (default) or the soft-archived set. Archived rows have the SAME shape as live ones — this is a predicate, not a different resource.") });
|
|
6827
6848
|
z.object({
|
|
6828
|
-
limit: z.coerce.number().int().min(1).max(100).optional().default(50),
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
affectsNodeId: z.string().min(1).optional()
|
|
6849
|
+
limit: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Change requests per page. Capped at 100; ask for the next page with `cursor`."),
|
|
6850
|
+
cursor: z.string().optional().describe("Opaque page cursor: pass back the `nextCursor` from the previous response. Do not construct or parse it."),
|
|
6851
|
+
status: z.array(changeRequestStatusSchema).optional().describe("Keep only these statuses. Omitting it returns every status, not just open ones."),
|
|
6852
|
+
mine: z.boolean().optional().describe("Only change requests CREATED by the acting user — not ones awaiting their review."),
|
|
6853
|
+
affectsNodeId: z.string().min(1).optional().describe("Only change requests whose target, or any of their operations, touches this node — including Base-backed nodes. To ask whether a resource already has an unfinished change request, pass this with `limit: 1` rather than paging the space: an empty result is conclusive.")
|
|
6834
6854
|
}).optional().default({ limit: 50 });
|
|
6835
6855
|
z.object({
|
|
6836
6856
|
changeRequests: z.array(changeRequestSchema),
|
|
6837
6857
|
nextCursor: z.string().nullable()
|
|
6838
6858
|
});
|
|
6839
6859
|
const changeRequestPageInputShape = {
|
|
6840
|
-
page: z.coerce.number().int().min(1).optional().default(1),
|
|
6841
|
-
pageSize: z.coerce.number().int().min(1).max(100).optional().default(50),
|
|
6842
|
-
status: z.array(changeRequestStatusSchema).optional(),
|
|
6843
|
-
mine: z.boolean().optional()
|
|
6860
|
+
page: z.coerce.number().int().min(1).optional().default(1).describe("1-indexed, not 0-indexed."),
|
|
6861
|
+
pageSize: z.coerce.number().int().min(1).max(100).optional().default(50).describe("Change requests per page. Capped at 100."),
|
|
6862
|
+
status: z.array(changeRequestStatusSchema).optional().describe("Keep only these statuses. Omitting it returns every status, not just open ones."),
|
|
6863
|
+
mine: z.boolean().optional().describe("Only change requests CREATED by the acting user — not ones awaiting their review.")
|
|
6844
6864
|
};
|
|
6845
6865
|
z.object({
|
|
6846
6866
|
...changeRequestPageInputShape,
|
|
6847
|
-
affectsNodeId: z.string().min(1).optional()
|
|
6867
|
+
affectsNodeId: z.string().min(1).optional().describe("Only change requests whose target, or any of their operations, touches this node — including Base-backed nodes.")
|
|
6848
6868
|
}).optional().default({
|
|
6849
6869
|
page: 1,
|
|
6850
6870
|
pageSize: 50
|
|
@@ -6876,9 +6896,9 @@ const SEARCH_SOURCES = [
|
|
|
6876
6896
|
"nodes"
|
|
6877
6897
|
];
|
|
6878
6898
|
z.object({
|
|
6879
|
-
query: z.string().default(""),
|
|
6880
|
-
limit: z.coerce.number().int().min(1).max(100).optional().default(20),
|
|
6881
|
-
offset: z.coerce.number().int().min(0).optional().default(0),
|
|
6899
|
+
query: z.string().default("").describe("Full-text query. An empty string matches nothing."),
|
|
6900
|
+
limit: z.coerce.number().int().min(1).max(100).optional().default(20).describe("Results per page. Capped at 100; note the default is 20, not 50."),
|
|
6901
|
+
offset: z.coerce.number().int().min(0).optional().default(0).describe("0-indexed skip count. This endpoint pages by offset, not by cursor."),
|
|
6882
6902
|
/**
|
|
6883
6903
|
* Restrict which content this call searches. Omitted means all three
|
|
6884
6904
|
* (unchanged behavior for every caller before this parameter existed).
|
|
@@ -6888,7 +6908,7 @@ z.object({
|
|
|
6888
6908
|
* (`?sources=records&sources=files`) becomes an array. Accept both shapes
|
|
6889
6909
|
* and normalize to an array.
|
|
6890
6910
|
*/
|
|
6891
|
-
sources: z.union([z.array(z.enum(SEARCH_SOURCES)), z.enum(SEARCH_SOURCES)]).transform((value) => Array.isArray(value) ? value : [value]).optional()
|
|
6911
|
+
sources: z.union([z.array(z.enum(SEARCH_SOURCES)), z.enum(SEARCH_SOURCES)]).transform((value) => Array.isArray(value) ? value : [value]).optional().describe("Restrict which content is searched. Omitting it searches ALL sources. Repeat the parameter to pass several (`?sources=records&sources=files`); a single occurrence is accepted as a bare value.")
|
|
6892
6912
|
});
|
|
6893
6913
|
const authSpaceSchema = z.object({
|
|
6894
6914
|
id: z.string(),
|
|
@@ -7958,6 +7978,8 @@ const validateTemplate = (tree) => {
|
|
|
7958
7978
|
if (skill && skill.name !== tree.manifest.name) errors.push(`Name mismatch: ${PACKAGE_SKILL_ENTRY} declares "${skill.name}" but busabase.json declares "${tree.manifest.name}". They are the same app and must agree.`);
|
|
7959
7979
|
const bases = baseSlugs(tree);
|
|
7960
7980
|
for (const key of busabaseMeta?.resources ?? []) if (!bases.has(key)) errors.push(`${PACKAGE_SKILL_ENTRY} lists resource "${key}", but content/ has no Base with that slug. An agent told about a table that does not exist will write to the wrong one.`);
|
|
7981
|
+
const risk = parseTemplateRisk(busabaseMeta?.risk);
|
|
7982
|
+
if (busabaseMeta?.risk !== void 0 && risk === void 0) warnings.push(`metadata.busabase.risk is "${busabaseMeta.risk}", which is not a recognized level (gated-write, local-write, read-only, sandbox). The Template Center will show it as undeclared.`);
|
|
7961
7983
|
const airapps = airAppSlugs(tree);
|
|
7962
7984
|
const resolved = resolvePrimaryAirApp(template, airapps);
|
|
7963
7985
|
let primaryAirApp;
|
|
@@ -7994,7 +8016,8 @@ const validateTemplate = (tree) => {
|
|
|
7994
8016
|
errors,
|
|
7995
8017
|
warnings,
|
|
7996
8018
|
...primaryAirApp ? { primaryAirApp } : {},
|
|
7997
|
-
...template ? { template } : {}
|
|
8019
|
+
...template ? { template } : {},
|
|
8020
|
+
...risk ? { risk } : {}
|
|
7998
8021
|
};
|
|
7999
8022
|
};
|
|
8000
8023
|
/**
|
|
@@ -10006,25 +10029,6 @@ const assertPlanIsApplicable = (plan, autoMerge) => {
|
|
|
10006
10029
|
//#endregion
|
|
10007
10030
|
//#region ../../packages/busabase-package/src/discover.ts
|
|
10008
10031
|
/**
|
|
10009
|
-
* What is at the end of this URL — one package, one template, or a repository
|
|
10010
|
-
* full of them?
|
|
10011
|
-
*
|
|
10012
|
-
* A user pasting a GitHub URL does not think in terms of "package roots". They
|
|
10013
|
-
* paste the repo they were looking at. Sometimes that repo IS the package;
|
|
10014
|
-
* sometimes it is `busabase/skills`, which holds dozens under `skills/*`. Before
|
|
10015
|
-
* this, the second case was only ever an error message with a list of
|
|
10016
|
-
* subdirectories to paste instead — correct, and a dead end for anyone who did
|
|
10017
|
-
* not want to edit a URL by hand.
|
|
10018
|
-
*
|
|
10019
|
-
* Discovery answers it once for every caller: the CLI turns the result into a
|
|
10020
|
-
* pick-one list, the dashboard's install dialog into a chooser, the Template
|
|
10021
|
-
* Center's index CI into the set of cards to publish. All three must agree on
|
|
10022
|
-
* what counts as a template, which is why the verdict comes from the same
|
|
10023
|
-
* `validateTemplate` they would each otherwise re-implement.
|
|
10024
|
-
*
|
|
10025
|
-
* Spec: `apps/busabase/content/spec/template-center.md` §6.2a.
|
|
10026
|
-
*/
|
|
10027
|
-
/**
|
|
10028
10032
|
* Only one level deep, matching the `skills/<name>/` layout the skills CLI
|
|
10029
10033
|
* already established and the Template Center reads. Walking arbitrarily deep
|
|
10030
10034
|
* would turn one paste into an unbounded scan of a monorepo and surface vendored
|
|
@@ -10074,6 +10078,7 @@ const discoverPackages = (files) => {
|
|
|
10074
10078
|
counts: countTree(tree),
|
|
10075
10079
|
...validation.primaryAirApp ? { primaryAirApp: validation.primaryAirApp } : {},
|
|
10076
10080
|
...tree.manifest.template?.category ? { category: tree.manifest.template.category } : {},
|
|
10081
|
+
...validation.risk ? { risk: validation.risk } : {},
|
|
10077
10082
|
screenshots: tree.manifest.template?.screenshots ?? [],
|
|
10078
10083
|
tags: [.../* @__PURE__ */ new Set([...tree.manifest.tags, ...tree.manifest.template?.tags ?? []])],
|
|
10079
10084
|
agentPrompts: tree.manifest.template?.agentPrompts ?? [],
|
|
@@ -10290,22 +10295,6 @@ const fetchGithubPackageFiles = async (repoUrl, options = {}) => {
|
|
|
10290
10295
|
};
|
|
10291
10296
|
//#endregion
|
|
10292
10297
|
//#region ../../packages/busabase-package/src/index-build.ts
|
|
10293
|
-
/**
|
|
10294
|
-
* Build the Template Center's catalog from a directory of skills.
|
|
10295
|
-
*
|
|
10296
|
-
* The catalog is not hand-maintained. A card that says "6 tables" for a package
|
|
10297
|
-
* that installs five is a trust bug, not a typo — so every field here is read
|
|
10298
|
-
* off the package itself, and whether an entry appears at all is decided by the
|
|
10299
|
-
* SAME `validateTemplate` the installer uses. A skill that would install as a
|
|
10300
|
-
* plain package can never be listed as a template, because one function answers
|
|
10301
|
-
* that question for both.
|
|
10302
|
-
*
|
|
10303
|
-
* Deliberately a plain function over a file map rather than something that
|
|
10304
|
-
* walks a disk: the CLI hands it a checkout, and a future CI job could hand it
|
|
10305
|
-
* a fetched zipball, without either needing its own notion of what counts.
|
|
10306
|
-
*
|
|
10307
|
-
* Spec: `apps/busabase/content/spec/template-center.md` §6.4.
|
|
10308
|
-
*/
|
|
10309
10298
|
/** Bumped when a consumer would misread an older file. */
|
|
10310
10299
|
const TEMPLATE_INDEX_FORMAT = "busabase-template-index@1";
|
|
10311
10300
|
const toEntry = (found, airapps) => ({
|
|
@@ -10313,6 +10302,7 @@ const toEntry = (found, airapps) => ({
|
|
|
10313
10302
|
name: found.name,
|
|
10314
10303
|
description: found.description,
|
|
10315
10304
|
category: found.category ?? "uncategorized",
|
|
10305
|
+
...found.risk ? { risk: found.risk } : {},
|
|
10316
10306
|
tags: found.tags ?? [],
|
|
10317
10307
|
screenshots: found.screenshots,
|
|
10318
10308
|
agentPrompts: found.agentPrompts ?? [],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "busa-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"description": "Command-line client for the Busabase OpenAPI REST API. Talks to a local or remote `busabase server`. Short-name alias for busabase-cli.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/busabase/busabase/tree/main/apps/busabase-cli",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@zip.js/zip.js": "^2.8.20",
|
|
35
35
|
"busabase-package": "workspace:*",
|
|
36
|
-
"busabase-sdk": "0.
|
|
36
|
+
"busabase-sdk": "0.50.0",
|
|
37
37
|
"commander": "^14.0.0",
|
|
38
38
|
"qrcode": "^1.5.4",
|
|
39
39
|
"tar-stream": "^3.1.7",
|