@bunshin-cc/bunshin 0.8.0 → 0.8.1
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/bin.js +62 -41
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1127,6 +1127,23 @@ function scopePath(tree, source) {
|
|
|
1127
1127
|
function inBoundary(section, reader) {
|
|
1128
1128
|
return !isScopeLayer(section.layer) || reader.layers.includes(section.layer);
|
|
1129
1129
|
}
|
|
1130
|
+
function parentScope(tree, layer) {
|
|
1131
|
+
const k = layerKind(layer);
|
|
1132
|
+
if (k === "source") {
|
|
1133
|
+
const g = tree.sources[layerValue(layer)]?.group ?? null;
|
|
1134
|
+
return g && tree.groups.some((x) => x.id === g) ? groupLayer(g) : "org";
|
|
1135
|
+
}
|
|
1136
|
+
if (k === "group") {
|
|
1137
|
+
const g = tree.groups.find((x) => x.id === layerValue(layer));
|
|
1138
|
+
return g?.parent && tree.groups.some((x) => x.id === g.parent) ? groupLayer(g.parent) : "org";
|
|
1139
|
+
}
|
|
1140
|
+
return null;
|
|
1141
|
+
}
|
|
1142
|
+
function ancestorScopes(tree, layer) {
|
|
1143
|
+
const out = [];
|
|
1144
|
+
for (let cur = parentScope(tree, layer); cur && !out.includes(cur); cur = parentScope(tree, cur)) out.push(cur);
|
|
1145
|
+
return out;
|
|
1146
|
+
}
|
|
1130
1147
|
function sourcesIn(tree, layer) {
|
|
1131
1148
|
if (layer === "org") return Object.keys(tree.sources);
|
|
1132
1149
|
if (layerKind(layer) === "source") return [layerValue(layer)];
|
|
@@ -1172,13 +1189,11 @@ function layerValue(layer) {
|
|
|
1172
1189
|
const i = layer.indexOf(":");
|
|
1173
1190
|
return i < 0 ? "" : layer.slice(i + 1);
|
|
1174
1191
|
}
|
|
1192
|
+
function privateLayer(ctx) {
|
|
1193
|
+
return ctx.kind === "robot" ? `robot:${ctx.id}` : `user:${ctx.userId}`;
|
|
1194
|
+
}
|
|
1175
1195
|
function layersFor(ctx) {
|
|
1176
|
-
|
|
1177
|
-
return ["fleet", `arm:${ctx.robot.armModel}`, `mount:${ctx.robot.mount}`, `robot:${ctx.id}`];
|
|
1178
|
-
}
|
|
1179
|
-
const team = ctx.person?.team ?? "";
|
|
1180
|
-
const dept = department(team);
|
|
1181
|
-
return ["org", ...dept ? [`dept:${dept}`] : [], ...team ? [`team:${team}`] : [], `user:${ctx.userId}`];
|
|
1196
|
+
return ["org", privateLayer(ctx)];
|
|
1182
1197
|
}
|
|
1183
1198
|
function isLocalLayer(layer) {
|
|
1184
1199
|
const kind = layerKind(layer);
|
|
@@ -1191,6 +1206,7 @@ function withScope(layers, scope) {
|
|
|
1191
1206
|
return i < 0 ? [...layers, ...path28] : [...layers.slice(0, i), ...path28, ...layers.slice(i)];
|
|
1192
1207
|
}
|
|
1193
1208
|
function readerFor(ctx, ownerClearance, scope) {
|
|
1209
|
+
if (ctx.kind === "robot" && !scope?.source) scope = { ...scope, source: `robot:${ctx.id}` };
|
|
1194
1210
|
const source = scope?.source ? { source: scope.source } : {};
|
|
1195
1211
|
if (ctx.kind === "robot") {
|
|
1196
1212
|
const rank = (c) => c === "private" ? 0 : CLEARANCE_RANK[c];
|
|
@@ -1213,9 +1229,6 @@ function explainSectionAccess(section, reader) {
|
|
|
1213
1229
|
const kind = layerKind(section.layer);
|
|
1214
1230
|
if (kind === "user" && section.layer !== `user:${reader.userId}`) return { allowed: false, reason: "other-user" };
|
|
1215
1231
|
if (kind === "robot" && section.layer !== `robot:${reader.contextId}`) return { allowed: false, reason: "other-robot" };
|
|
1216
|
-
if ((kind === "arm" || kind === "mount") && reader.role === "robot" && !reader.layers.includes(section.layer)) {
|
|
1217
|
-
return { allowed: false, reason: "other-hardware" };
|
|
1218
|
-
}
|
|
1219
1232
|
const access = explainAccess(
|
|
1220
1233
|
{
|
|
1221
1234
|
clearance: section.clearance,
|
|
@@ -1236,42 +1249,25 @@ function scopeAffinity(section, reader) {
|
|
|
1236
1249
|
function baseAffinity(section, reader) {
|
|
1237
1250
|
const kind = layerKind(section.layer);
|
|
1238
1251
|
if (kind === "group" || kind === "source") {
|
|
1239
|
-
|
|
1240
|
-
if (i < 0) return 0.05;
|
|
1252
|
+
if (!reader.layers.includes(section.layer)) return 0.05;
|
|
1241
1253
|
const path28 = reader.layers.filter((l) => {
|
|
1242
1254
|
const k = layerKind(l);
|
|
1243
1255
|
return k === "group" || k === "source";
|
|
1244
1256
|
});
|
|
1245
1257
|
return 0.6 + 0.4 * ((path28.indexOf(section.layer) + 1) / path28.length);
|
|
1246
1258
|
}
|
|
1247
|
-
if (reader.layers.includes(section.layer)
|
|
1248
|
-
|
|
1249
|
-
return 0.5 + 0.5 * (order.indexOf(kind) / Math.max(1, order.length - 1));
|
|
1250
|
-
}
|
|
1251
|
-
if (kind === "team") {
|
|
1252
|
-
const team = layerValue(section.layer);
|
|
1253
|
-
if (department(team) === department(reader.team)) return 0.3;
|
|
1254
|
-
return 0.05;
|
|
1255
|
-
}
|
|
1256
|
-
if (kind === "dept") return 0.1;
|
|
1257
|
-
return 0.2;
|
|
1259
|
+
if (isLocalLayer(section.layer)) return reader.layers.includes(section.layer) ? 1 : 0;
|
|
1260
|
+
return 0.5;
|
|
1258
1261
|
}
|
|
1259
1262
|
function reachesReader(section, reader) {
|
|
1260
|
-
|
|
1261
|
-
const kind = layerKind(section.layer);
|
|
1262
|
-
if (kind === "org" || kind === "dept" || FLEET_LAYER_ORDER.includes(kind)) return canRead(section, reader);
|
|
1263
|
-
if (kind !== "team") return false;
|
|
1264
|
-
return [layerValue(section.layer), ...section.allowedTeams ?? []].some((t) => !!t && orgUnitUnder(reader.team, t));
|
|
1263
|
+
return reader.layers.includes(section.layer) && canRead(section, reader);
|
|
1265
1264
|
}
|
|
1266
|
-
var COMPANY_LAYER_ORDER, FLEET_LAYER_ORDER;
|
|
1267
1265
|
var init_layers = __esm({
|
|
1268
1266
|
"../core/src/v2/layers.ts"() {
|
|
1269
1267
|
"use strict";
|
|
1270
1268
|
init_permissions();
|
|
1271
1269
|
init_text();
|
|
1272
1270
|
init_scopes();
|
|
1273
|
-
COMPANY_LAYER_ORDER = ["org", "dept", "team", "user"];
|
|
1274
|
-
FLEET_LAYER_ORDER = ["fleet", "arm", "mount", "robot"];
|
|
1275
1271
|
}
|
|
1276
1272
|
});
|
|
1277
1273
|
|
|
@@ -1455,6 +1451,9 @@ var init_document = __esm({
|
|
|
1455
1451
|
});
|
|
1456
1452
|
|
|
1457
1453
|
// ../core/src/v2/sections/markdown.ts
|
|
1454
|
+
function repoLayer(repo) {
|
|
1455
|
+
return `source:${repo.includes("/") ? "repo" : "folder"}:${repo}`;
|
|
1456
|
+
}
|
|
1458
1457
|
function repoSectionId(repo, path28, anchor = "") {
|
|
1459
1458
|
return anchor ? `repo:${repo}/${path28}#${anchor}` : `repo:${repo}/${path28}`;
|
|
1460
1459
|
}
|
|
@@ -1487,7 +1486,7 @@ function parseRepoDoc(doc, opts) {
|
|
|
1487
1486
|
id: meta.id ? repoSectionId(doc.repo, doc.path, meta.id) : repoSectionId(doc.repo, doc.path),
|
|
1488
1487
|
orgId: opts.orgId,
|
|
1489
1488
|
kind,
|
|
1490
|
-
layer:
|
|
1489
|
+
layer: opts.layer ?? repoLayer(doc.repo),
|
|
1491
1490
|
title,
|
|
1492
1491
|
body: doc.text,
|
|
1493
1492
|
when,
|
|
@@ -2081,8 +2080,9 @@ var init_engine = __esm({
|
|
|
2081
2080
|
|
|
2082
2081
|
// ../core/src/v2/guidelines.ts
|
|
2083
2082
|
function reflectionGuidelines(sections, reader, opts = {}) {
|
|
2083
|
+
const covering = opts.layer ? /* @__PURE__ */ new Set(["org", opts.layer, ...opts.tree ? ancestorScopes(opts.tree, opts.layer) : []]) : void 0;
|
|
2084
2084
|
const pool = reader ? servable(sections, reader) : sections;
|
|
2085
|
-
return pool.filter((s) => s.delivery === "reflect" && s.status === "active" && (!reader || inBoundary(s, reader))).filter((s) => !
|
|
2085
|
+
return pool.filter((s) => s.delivery === "reflect" && s.status === "active" && (!reader || inBoundary(s, reader))).filter((s) => !covering || covering.has(s.layer)).sort((a, b) => generality(a.layer) - generality(b.layer) || a.id.localeCompare(b.id)).map((s) => ({ id: s.id, title: s.title, layer: s.layer, body: s.body }));
|
|
2086
2086
|
}
|
|
2087
2087
|
function guidelineRules(body) {
|
|
2088
2088
|
const at = body.search(/^## /m);
|
|
@@ -2120,7 +2120,7 @@ var init_guidelines = __esm({
|
|
|
2120
2120
|
init_engine();
|
|
2121
2121
|
init_scopes();
|
|
2122
2122
|
GUIDELINES_ANCHOR = "rules";
|
|
2123
|
-
generality = (l) => ({ org: 0,
|
|
2123
|
+
generality = (l) => ({ org: 0, group: 1, source: 2, robot: 3, user: 3 })[layerKind(l)] ?? 4;
|
|
2124
2124
|
}
|
|
2125
2125
|
});
|
|
2126
2126
|
|
|
@@ -3129,6 +3129,17 @@ var init_generalize = __esm({
|
|
|
3129
3129
|
}
|
|
3130
3130
|
});
|
|
3131
3131
|
|
|
3132
|
+
// ../core/src/v2/adopt.ts
|
|
3133
|
+
var init_adopt = __esm({
|
|
3134
|
+
"../core/src/v2/adopt.ts"() {
|
|
3135
|
+
"use strict";
|
|
3136
|
+
init_text();
|
|
3137
|
+
init_layers();
|
|
3138
|
+
init_scopes();
|
|
3139
|
+
init_sources();
|
|
3140
|
+
}
|
|
3141
|
+
});
|
|
3142
|
+
|
|
3132
3143
|
// ../core/src/v2/index.ts
|
|
3133
3144
|
var init_v2 = __esm({
|
|
3134
3145
|
"../core/src/v2/index.ts"() {
|
|
@@ -3153,6 +3164,7 @@ var init_v2 = __esm({
|
|
|
3153
3164
|
init_sources();
|
|
3154
3165
|
init_scopes();
|
|
3155
3166
|
init_generalize();
|
|
3167
|
+
init_adopt();
|
|
3156
3168
|
}
|
|
3157
3169
|
});
|
|
3158
3170
|
|
|
@@ -3329,7 +3341,8 @@ function indexWorkingTree(v2, config, cwd, opts = {}) {
|
|
|
3329
3341
|
const now = opts.now ?? Date.now();
|
|
3330
3342
|
const cached = v2.readRepoIndex(root);
|
|
3331
3343
|
const ownerTeam = config.ownerTeam || config.orgUnit || "unknown";
|
|
3332
|
-
const
|
|
3344
|
+
const source = sourceFor(root, v2.store.root);
|
|
3345
|
+
const sameRepo = cached && cached.ownerTeam === ownerTeam && cached.format === INDEX_FORMAT;
|
|
3333
3346
|
const repo = sameRepo && cached.repo && !opts.force ? cached.repo : repoName(root);
|
|
3334
3347
|
const fresh = sameRepo && cached.repo === repo && cached.paths && cached.listedAt && now - Date.parse(cached.listedAt) < LIST_TTL_MS && !opts.force;
|
|
3335
3348
|
const paths = fresh ? cached.paths : listDocs(root);
|
|
@@ -3352,11 +3365,12 @@ function indexWorkingTree(v2, config, cwd, opts = {}) {
|
|
|
3352
3365
|
changed = true;
|
|
3353
3366
|
try {
|
|
3354
3367
|
const text2 = fs6.readFileSync(abs, "utf8");
|
|
3355
|
-
files[rel] = { mtimeMs: stat.mtimeMs, size: stat.size, sections: parseRepoDoc({ repo, path: rel, text: text2 }, { orgId: config.orgId, ownerTeam }) };
|
|
3368
|
+
files[rel] = { mtimeMs: stat.mtimeMs, size: stat.size, sections: parseRepoDoc({ repo, path: rel, text: text2 }, { orgId: config.orgId, ownerTeam, layer: source ? sourceLayer(source) : "org" }) };
|
|
3356
3369
|
} catch {
|
|
3357
3370
|
}
|
|
3358
3371
|
}
|
|
3359
3372
|
const index = {
|
|
3373
|
+
format: INDEX_FORMAT,
|
|
3360
3374
|
repo,
|
|
3361
3375
|
ownerTeam,
|
|
3362
3376
|
listedAt: fresh ? cached.listedAt : new Date(now).toISOString(),
|
|
@@ -3397,11 +3411,12 @@ function relativeToRoot(root, file, cwd = root) {
|
|
|
3397
3411
|
}
|
|
3398
3412
|
return null;
|
|
3399
3413
|
}
|
|
3400
|
-
var DOC_NAMES, SKIP_DIRS, LIST_TTL_MS, rootCache, isDoc, deployedSkill;
|
|
3414
|
+
var DOC_NAMES, SKIP_DIRS, LIST_TTL_MS, rootCache, isDoc, deployedSkill, INDEX_FORMAT;
|
|
3401
3415
|
var init_repo = __esm({
|
|
3402
3416
|
"src/v2/repo.ts"() {
|
|
3403
3417
|
"use strict";
|
|
3404
3418
|
init_v22();
|
|
3419
|
+
init_source();
|
|
3405
3420
|
DOC_NAMES = /* @__PURE__ */ new Set(["spec.md", "testing.md", "skill.md"]);
|
|
3406
3421
|
SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".bunshin"]);
|
|
3407
3422
|
LIST_TTL_MS = 6e4;
|
|
@@ -3412,6 +3427,7 @@ var init_repo = __esm({
|
|
|
3412
3427
|
return DOC_NAMES.has(parts[parts.length - 1].toLowerCase());
|
|
3413
3428
|
};
|
|
3414
3429
|
deployedSkill = (root, rel) => /(^|\/)SKILL\.md$/i.test(rel) && fs6.existsSync(path5.join(root, path5.posix.dirname(rel), ".bunshin.json"));
|
|
3430
|
+
INDEX_FORMAT = 2;
|
|
3415
3431
|
}
|
|
3416
3432
|
});
|
|
3417
3433
|
|
|
@@ -4381,6 +4397,11 @@ function childDir(root, name) {
|
|
|
4381
4397
|
const dir = path8.join(root, name);
|
|
4382
4398
|
return path8.dirname(path8.resolve(dir)) === path8.resolve(root) && insideRoot(root, dir) ? dir : null;
|
|
4383
4399
|
}
|
|
4400
|
+
function layerRank(layer, tree) {
|
|
4401
|
+
const kind = layerKind(layer);
|
|
4402
|
+
if (kind === "group") return 1 + (tree ? groupChain(tree, layerValue(layer)).length : 0);
|
|
4403
|
+
return kind === "source" ? 1e3 : kind === "user" || kind === "robot" ? 2e3 : 0;
|
|
4404
|
+
}
|
|
4384
4405
|
function planDeploy(bundle, p, harnesses) {
|
|
4385
4406
|
const active = bundle.sections.filter((s) => s.status === "active" || s.status === "stale");
|
|
4386
4407
|
const byName = /* @__PURE__ */ new Map();
|
|
@@ -4391,7 +4412,7 @@ function planDeploy(bundle, p, harnesses) {
|
|
|
4391
4412
|
continue;
|
|
4392
4413
|
}
|
|
4393
4414
|
const prev = byName.get(s.skill.name);
|
|
4394
|
-
if (!prev || (
|
|
4415
|
+
if (!prev || layerRank(s.layer, bundle.scopes) > layerRank(prev.layer, bundle.scopes)) byName.set(s.skill.name, s);
|
|
4395
4416
|
}
|
|
4396
4417
|
const skills = [...byName.values()].sort((a, b) => a.skill.name.localeCompare(b.skill.name));
|
|
4397
4418
|
const instructions = active.filter((s) => s.delivery === "always" && !s.skill && !s.profileOf).sort((a, b) => (a.packPath ?? a.title).localeCompare(b.packPath ?? b.title));
|
|
@@ -5013,7 +5034,7 @@ ${EXCLUDE_END}
|
|
|
5013
5034
|
} catch {
|
|
5014
5035
|
}
|
|
5015
5036
|
}
|
|
5016
|
-
var settingsFile, orgKey, sha, BLOCK_BEGIN, BLOCK_END, MANIFEST, MAX_FILE, isExecutable, safeJoin, SAFE_NAME, neutralizeMarkers,
|
|
5037
|
+
var settingsFile, orgKey, sha, BLOCK_BEGIN, BLOCK_END, MANIFEST, MAX_FILE, isExecutable, safeJoin, SAFE_NAME, neutralizeMarkers, docMarker, BORN_SLACK_MS, LINK_DIRS, EXCLUDE_BEGIN, EXCLUDE_END;
|
|
5017
5038
|
var init_deploy = __esm({
|
|
5018
5039
|
"src/v2/deploy.ts"() {
|
|
5019
5040
|
"use strict";
|
|
@@ -5038,7 +5059,6 @@ var init_deploy = __esm({
|
|
|
5038
5059
|
safeJoin = containedPath;
|
|
5039
5060
|
SAFE_NAME = /^(?!\.\.?$)[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
5040
5061
|
neutralizeMarkers = (text2) => text2.replace(/<!--(?=\s*bunshin:)/gi, "<!-\u200B-");
|
|
5041
|
-
LAYER_RANK = { org: 0, dept: 1, group: 2, team: 2, source: 3, user: 3, fleet: 0, arm: 1, mount: 2, robot: 3 };
|
|
5042
5062
|
docMarker = (id, version2) => `<!-- bunshin:doc id=${id} v=${version2} -->`;
|
|
5043
5063
|
BORN_SLACK_MS = 2e3;
|
|
5044
5064
|
LINK_DIRS = {
|
|
@@ -6129,7 +6149,8 @@ async function uploadIndex(store, cwd, deadline = Date.now() + 3e4) {
|
|
|
6129
6149
|
}
|
|
6130
6150
|
});
|
|
6131
6151
|
const commit = repoCommit(root);
|
|
6132
|
-
const
|
|
6152
|
+
const source = sourceFor(root, store.root);
|
|
6153
|
+
const res = await v2api(config, "POST", "/sections/index", { repo: index.repo, ...commit ? { commit } : {}, ...source ? { source } : {}, ownerTeam: index.ownerTeam, docs }, { deadline, timeoutMs: 3e4 });
|
|
6133
6154
|
return typeof res.indexed === "number" ? res.indexed : docs.length;
|
|
6134
6155
|
}
|
|
6135
6156
|
var isLocalId, carriesTrace;
|
|
@@ -8030,7 +8051,7 @@ function cmdSuggest(store, args, cwd, out, err) {
|
|
|
8030
8051
|
orgId: config.orgId,
|
|
8031
8052
|
contextId: view.ctx.id,
|
|
8032
8053
|
authorUserId: config.userId,
|
|
8033
|
-
target: known ? { sectionId: known } : {
|
|
8054
|
+
target: known ? { sectionId: known } : { storage: { type: "harness", path: rel, symbol: symbol ?? "" } },
|
|
8034
8055
|
op: { op: "append", text: rationale },
|
|
8035
8056
|
rationale,
|
|
8036
8057
|
evidenceEpisodeIds: sessionId ? [episodeIdFor(view.ctx.id, sessionId)] : [],
|