@botharness/core 1.0.1 → 1.0.2

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/index.d.mts CHANGED
@@ -10832,6 +10832,48 @@ interface MarketplaceClient {
10832
10832
  }>>;
10833
10833
  }
10834
10834
  //#endregion
10835
+ //#region packages/core/src/release/notes.d.ts
10836
+ interface LocalizedText {
10837
+ en: string;
10838
+ zh: string;
10839
+ }
10840
+ interface ReleaseNoteSection {
10841
+ name: string;
10842
+ entries: LocalizedText[];
10843
+ }
10844
+ interface ReleaseNote {
10845
+ version: string;
10846
+ date: string;
10847
+ summary: LocalizedText;
10848
+ sections: ReleaseNoteSection[];
10849
+ }
10850
+ //#endregion
10851
+ //#region packages/core/src/release/service.d.ts
10852
+ interface ReleaseInfo {
10853
+ version: string;
10854
+ releases: ReleaseNote[];
10855
+ }
10856
+ type ReleaseUpdate = {
10857
+ status: 'development';
10858
+ current: string;
10859
+ } | {
10860
+ status: 'unavailable';
10861
+ current: string;
10862
+ } | {
10863
+ status: 'current';
10864
+ current: string;
10865
+ latest: string;
10866
+ } | {
10867
+ status: 'available';
10868
+ current: string;
10869
+ latest: string;
10870
+ releases: ReleaseNote[];
10871
+ };
10872
+ interface ReleaseService {
10873
+ info(since?: string): ReleaseInfo;
10874
+ update(): Promise<ReleaseUpdate>;
10875
+ }
10876
+ //#endregion
10835
10877
  //#region packages/core/src/channels/profile-activity.d.ts
10836
10878
  interface GroupProfileActivityDay {
10837
10879
  day: string;
@@ -11363,6 +11405,8 @@ interface BridgeMethods {
11363
11405
  marketplaceReport(payload: unknown): Promise<BridgeResult<{
11364
11406
  received: true;
11365
11407
  }>>;
11408
+ releaseInfo(payload: unknown): BridgeResult<ReleaseInfo>;
11409
+ releaseUpdate(): Promise<BridgeResult<ReleaseUpdate>>;
11366
11410
  }
11367
11411
  interface BridgeMethodsDeps {
11368
11412
  warn?: (message: string) => void;
@@ -11403,6 +11447,7 @@ interface BridgeMethodsDeps {
11403
11447
  };
11404
11448
  createBotId?: () => string;
11405
11449
  marketplace?: MarketplaceClient;
11450
+ release?: ReleaseService;
11406
11451
  }
11407
11452
  export declare function createBridgeMethods(deps: BridgeMethodsDeps): BridgeMethods;
11408
11453
  //#endregion
@@ -11768,6 +11813,8 @@ export declare class BotharnessBridgeService extends TypertRemoteService {
11768
11813
  }>;
11769
11814
  marketplaceTopics(): Promise<MarketplaceTopic[]>;
11770
11815
  marketplaceDetail(id: string): Promise<MarketplaceDetail>;
11816
+ releaseInfo(since?: string): Promise<ReleaseInfo>;
11817
+ releaseUpdate(): Promise<ReleaseUpdate>;
11771
11818
  }
11772
11819
  export declare function registerBridge(ctx: Context, methods: BridgeMethods): BotharnessBridgeService;
11773
11820
  //#endregion
package/dist/index.mjs CHANGED
@@ -5045,7 +5045,7 @@ const initializer = (inst, issues) => {
5045
5045
  const ZodRealError = /*@__PURE__*/ $constructor("ZodError", initializer, void 0, { Parent: Error });
5046
5046
  //#endregion
5047
5047
  //#region node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/parse.js
5048
- const parse$1 = /* @__PURE__ */ _parse(ZodRealError);
5048
+ const parse$2 = /* @__PURE__ */ _parse(ZodRealError);
5049
5049
  const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError);
5050
5050
  const safeParse = /* @__PURE__ */ _safeParse(ZodRealError);
5051
5051
  const safeParseAsync = /* @__PURE__ */ _safeParseAsync(ZodRealError);
@@ -5177,7 +5177,7 @@ const ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => {
5177
5177
  own(this, "~standard", value);
5178
5178
  },
5179
5179
  parse: function _parse(data, params) {
5180
- return parse$1(this, data, params, { callee: _parse });
5180
+ return parse$2(this, data, params, { callee: _parse });
5181
5181
  },
5182
5182
  parseAsync: async function _parseAsync(data, params) {
5183
5183
  return await parseAsync(this, data, params, { callee: _parseAsync });
@@ -7895,7 +7895,7 @@ function createInboundMessaging(options) {
7895
7895
  const assertCurrent = () => {
7896
7896
  if (!valid(grant(value.id)) || grant(value.id).revision !== value.revision || providers.get(value.providerId) !== entry) throw new MessagingError("source-unavailable");
7897
7897
  };
7898
- const audit = (record) => database.transaction((db) => {
7898
+ const audit = (record) => transaction((db) => {
7899
7899
  assertCurrent();
7900
7900
  const row = db.prepare("SELECT payload_json FROM source_events WHERE source_event_id = ?").get(sourceEventId);
7901
7901
  const payload = JSON.parse(row.payload_json);
@@ -8009,7 +8009,7 @@ function createInboundMessaging(options) {
8009
8009
  });
8010
8010
  result.nextCursor = key;
8011
8011
  }
8012
- database.transaction((db) => {
8012
+ transaction((db) => {
8013
8013
  signal.throwIfAborted();
8014
8014
  assertCurrent();
8015
8015
  for (const event of page.events.slice(cursor?.offset ?? 0, offset)) persistSource(db, value, event);
@@ -21754,6 +21754,15 @@ function parseStringArray(source, key) {
21754
21754
  }
21755
21755
  const parseRoles$1 = (source) => parseStringArray(source, "roles");
21756
21756
  const parseWorkspaces = (source) => parseStringArray(source, "workspaces");
21757
+ function releaseUnavailable() {
21758
+ return {
21759
+ ok: false,
21760
+ error: {
21761
+ code: "release-unavailable",
21762
+ message: "Release information is unavailable"
21763
+ }
21764
+ };
21765
+ }
21757
21766
  function invalidInput(message) {
21758
21767
  return {
21759
21768
  ok: false,
@@ -22597,6 +22606,22 @@ function createBridgeMethods(deps) {
22597
22606
  marketplaceTopics() {
22598
22607
  return marketplaceCall((client) => client.topics());
22599
22608
  },
22609
+ releaseInfo(payload) {
22610
+ if (deps.release === void 0) return releaseUnavailable();
22611
+ const since = asObject(payload)["since"];
22612
+ if (since !== void 0 && typeof since !== "string") return invalidInput("invalid since");
22613
+ return {
22614
+ ok: true,
22615
+ value: deps.release.info(since)
22616
+ };
22617
+ },
22618
+ async releaseUpdate() {
22619
+ if (deps.release === void 0) return releaseUnavailable();
22620
+ return {
22621
+ ok: true,
22622
+ value: await deps.release.update()
22623
+ };
22624
+ },
22600
22625
  marketplaceDetail(payload) {
22601
22626
  const id = asObject(payload)["id"];
22602
22627
  if (typeof id !== "string" || id.trim().length === 0) return Promise.resolve(invalidInput("id is required"));
@@ -25054,6 +25079,12 @@ var BotharnessBridgeService = class extends TypertRemoteService {
25054
25079
  async marketplaceDetail(id) {
25055
25080
  return unwrapAsync(this.methods.marketplaceDetail({ id }));
25056
25081
  }
25082
+ async releaseInfo(since) {
25083
+ return unwrap(this.methods.releaseInfo(since === void 0 ? {} : { since }));
25084
+ }
25085
+ async releaseUpdate() {
25086
+ return unwrapAsync(this.methods.releaseUpdate());
25087
+ }
25057
25088
  };
25058
25089
  markRemoteMethods(BotharnessBridgeService.prototype, [
25059
25090
  "messagingDefaults",
@@ -25178,7 +25209,9 @@ markRemoteMethods(BotharnessBridgeService.prototype, [
25178
25209
  "marketplaceTopics",
25179
25210
  "marketplaceDetail",
25180
25211
  "marketplaceChallenge",
25181
- "marketplaceReport"
25212
+ "marketplaceReport",
25213
+ "releaseInfo",
25214
+ "releaseUpdate"
25182
25215
  ]);
25183
25216
  function registerBridge(ctx, methods) {
25184
25217
  return new BotharnessBridgeService(ctx, methods);
@@ -25206,7 +25239,7 @@ function parseChallenge(value) {
25206
25239
  }
25207
25240
  //#endregion
25208
25241
  //#region packages/core/src/marketplace/client.ts
25209
- const REQUEST_TIMEOUT_MS = 15e3;
25242
+ const REQUEST_TIMEOUT_MS$1 = 15e3;
25210
25243
  function record$2(value) {
25211
25244
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
25212
25245
  }
@@ -25306,7 +25339,7 @@ function parseReceipt(value) {
25306
25339
  function createMarketplaceClient(options) {
25307
25340
  const fetchImpl = options.fetchImpl ?? fetch;
25308
25341
  const baseUrl = options.baseUrl.replace(/\/+$/u, "");
25309
- const timeoutMs = options.timeoutMs ?? REQUEST_TIMEOUT_MS;
25342
+ const timeoutMs = options.timeoutMs ?? REQUEST_TIMEOUT_MS$1;
25310
25343
  const request = async (path, init, parse) => {
25311
25344
  let response;
25312
25345
  try {
@@ -25384,6 +25417,349 @@ function createMarketplaceClient(options) {
25384
25417
  };
25385
25418
  }
25386
25419
  //#endregion
25420
+ //#region scripts/release-ledger.mjs
25421
+ const RELEASE_HEADING = /^## \[([^\]]+)](?: - (\d{4}-\d{2}-\d{2}))?$/;
25422
+ const SECTION_HEADING = /^### (.+)$/;
25423
+ const MARKDOWN_LINK$1 = /\[[^\]]*]\(([^)]+)\)/g;
25424
+ const RELEASE_PROVENANCE = /^- \*\*(Skill version|Verified against DSH|Upstream revision|Skill 版本|核验的 DSH 版本|上游 revision)(?::|:)\*\*\s+(.+)$/;
25425
+ const RELEASE_ARTIFACT_EVIDENCE = /^- \*\*(Release tag|Installable artifact|发布 tag|可安装 artifact)(?::|:)\*\*\s+\[[^\]]+]\((https:\/\/[^)]+)\)$/;
25426
+ const PROVENANCE_KEYS = /* @__PURE__ */ new Map([
25427
+ ["Skill version", "skillVersion"],
25428
+ ["Skill 版本", "skillVersion"],
25429
+ ["Verified against DSH", "verifiedAgainst"],
25430
+ ["核验的 DSH 版本", "verifiedAgainst"],
25431
+ ["Upstream revision", "upstreamSha"],
25432
+ ["上游 revision", "upstreamSha"]
25433
+ ]);
25434
+ const EVIDENCE_KEYS = /* @__PURE__ */ new Map([
25435
+ ["Release tag", "tagUrl"],
25436
+ ["发布 tag", "tagUrl"],
25437
+ ["Installable artifact", "installUrl"],
25438
+ ["可安装 artifact", "installUrl"]
25439
+ ]);
25440
+ function linksIn(text) {
25441
+ return [...text.matchAll(MARKDOWN_LINK$1)].map((match) => match[1]);
25442
+ }
25443
+ function provenanceValue(text) {
25444
+ return text.match(/`([^`]+)`/)?.[1] ?? text.trim();
25445
+ }
25446
+ function parseReleaseLedgerDocument(markdown) {
25447
+ const lines = markdown.replaceAll("\r\n", "\n").split("\n");
25448
+ const releases = [];
25449
+ const unexpectedContent = [];
25450
+ let release;
25451
+ let section;
25452
+ for (const [index, line] of lines.entries()) {
25453
+ const releaseMatch = line.match(RELEASE_HEADING);
25454
+ if (releaseMatch) {
25455
+ release = {
25456
+ identity: releaseMatch[1],
25457
+ date: releaseMatch[2],
25458
+ summary: "",
25459
+ sections: []
25460
+ };
25461
+ releases.push(release);
25462
+ section = void 0;
25463
+ continue;
25464
+ }
25465
+ if (!release) continue;
25466
+ const sectionMatch = line.match(SECTION_HEADING);
25467
+ if (sectionMatch) {
25468
+ section = {
25469
+ name: sectionMatch[1],
25470
+ entries: []
25471
+ };
25472
+ release.sections.push(section);
25473
+ continue;
25474
+ }
25475
+ const provenanceMatch = line.match(RELEASE_PROVENANCE);
25476
+ if (provenanceMatch && !section) {
25477
+ release.provenance ??= {};
25478
+ const key = PROVENANCE_KEYS.get(provenanceMatch[1]);
25479
+ release.provenance[key] = provenanceValue(provenanceMatch[2]);
25480
+ if (key === "upstreamSha") release.provenance.upstreamUrl = linksIn(provenanceMatch[2])[0];
25481
+ continue;
25482
+ }
25483
+ const evidenceMatch = line.match(RELEASE_ARTIFACT_EVIDENCE);
25484
+ if (evidenceMatch && !section) {
25485
+ release.evidence ??= {};
25486
+ release.evidence[EVIDENCE_KEYS.get(evidenceMatch[1])] = evidenceMatch[2];
25487
+ continue;
25488
+ }
25489
+ if (line.startsWith("- ") && section) {
25490
+ const text = line.slice(2);
25491
+ section.entries.push({
25492
+ text,
25493
+ links: linksIn(text)
25494
+ });
25495
+ continue;
25496
+ }
25497
+ if (/^\s{2,}\S/.test(line) && section && section.entries.length > 0) {
25498
+ const entry = section.entries.at(-1);
25499
+ entry.text = `${entry.text} ${line.trim()}`;
25500
+ entry.links = linksIn(entry.text);
25501
+ continue;
25502
+ }
25503
+ if (!release.summary && !section && line.trim()) {
25504
+ release.summary = line.trim();
25505
+ continue;
25506
+ }
25507
+ if (section && line.trim()) unexpectedContent.push({
25508
+ releaseIdentity: release.identity,
25509
+ sectionName: section.name,
25510
+ line: index + 1
25511
+ });
25512
+ }
25513
+ return {
25514
+ releases,
25515
+ unexpectedContent
25516
+ };
25517
+ }
25518
+ function parseReleaseLedger(markdown) {
25519
+ const { releases } = parseReleaseLedgerDocument(markdown);
25520
+ return { releases };
25521
+ }
25522
+ //#endregion
25523
+ //#region packages/core/src/release/version.ts
25524
+ const RELEASE_VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/u;
25525
+ function parse$1(version) {
25526
+ const match = RELEASE_VERSION.exec(version);
25527
+ if (match === null) return void 0;
25528
+ return {
25529
+ core: [
25530
+ Number(match[1]),
25531
+ Number(match[2]),
25532
+ Number(match[3])
25533
+ ],
25534
+ prerelease: match[4] === void 0 ? [] : match[4].split(".")
25535
+ };
25536
+ }
25537
+ function compareIdentifier(left, right) {
25538
+ const leftNumeric = /^\d+$/u.test(left);
25539
+ const rightNumeric = /^\d+$/u.test(right);
25540
+ if (leftNumeric && rightNumeric) return Math.sign(Number(left) - Number(right));
25541
+ if (leftNumeric) return -1;
25542
+ if (rightNumeric) return 1;
25543
+ return left < right ? -1 : left > right ? 1 : 0;
25544
+ }
25545
+ function isReleaseVersion(version) {
25546
+ const parsed = parse$1(version);
25547
+ return parsed !== void 0 && parsed.core.some((part) => part > 0);
25548
+ }
25549
+ function compareVersions(left, right) {
25550
+ const a = parse$1(left);
25551
+ const b = parse$1(right);
25552
+ if (a === void 0 || b === void 0) return 0;
25553
+ for (let index = 0; index < 3; index += 1) {
25554
+ const difference = a.core[index] - b.core[index];
25555
+ if (difference !== 0) return Math.sign(difference);
25556
+ }
25557
+ if (a.prerelease.length === 0 || b.prerelease.length === 0) return Math.sign(b.prerelease.length - a.prerelease.length);
25558
+ const length = Math.max(a.prerelease.length, b.prerelease.length);
25559
+ for (let index = 0; index < length; index += 1) {
25560
+ const left = a.prerelease[index];
25561
+ const right = b.prerelease[index];
25562
+ if (left === void 0) return -1;
25563
+ if (right === void 0) return 1;
25564
+ const order = compareIdentifier(left, right);
25565
+ if (order !== 0) return order;
25566
+ }
25567
+ return 0;
25568
+ }
25569
+ //#endregion
25570
+ //#region packages/core/src/release/notes.ts
25571
+ const RELEASE_REPOSITORY_URL = "https://github.com/BotHarness/BotHarness";
25572
+ const RELEASE_NOTE_SECTION_ORDER = [
25573
+ "Added",
25574
+ "Changed",
25575
+ "Fixed",
25576
+ "Security",
25577
+ "Documentation",
25578
+ "Breaking Changes",
25579
+ "Deprecated",
25580
+ "Removed"
25581
+ ];
25582
+ function sectionRank(name) {
25583
+ const index = RELEASE_NOTE_SECTION_ORDER.indexOf(name);
25584
+ return index === -1 ? RELEASE_NOTE_SECTION_ORDER.length : index;
25585
+ }
25586
+ const MARKDOWN_LINK = /(\[[^\]]*\]\()([^)\s]+)(\))/gu;
25587
+ function absolutizeLedgerLinks(text) {
25588
+ return text.replace(MARKDOWN_LINK, (whole, open, target, close) => {
25589
+ if (/^[a-z][a-z0-9+.-]*:/iu.test(target) || target.startsWith("#")) return whole;
25590
+ const path = target.replace(/^\.?\//u, "");
25591
+ return `${open}${RELEASE_REPOSITORY_URL}/blob/main/${path}${close}`;
25592
+ });
25593
+ }
25594
+ function pairReleaseLedgers(english, chinese) {
25595
+ const translated = new Map(parseReleaseLedger(chinese).releases.map((release) => [release.identity, release]));
25596
+ const notes = [];
25597
+ for (const release of parseReleaseLedger(english).releases) {
25598
+ if (!isReleaseVersion(release.identity) || release.date === void 0) continue;
25599
+ const zh = translated.get(release.identity);
25600
+ notes.push({
25601
+ version: release.identity,
25602
+ date: release.date,
25603
+ summary: {
25604
+ en: absolutizeLedgerLinks(release.summary),
25605
+ zh: absolutizeLedgerLinks(zh?.summary || release.summary)
25606
+ },
25607
+ sections: release.sections.toSorted((left, right) => sectionRank(left.name) - sectionRank(right.name)).map((section) => {
25608
+ const zhEntries = zh?.sections.find((candidate) => candidate.name === section.name)?.entries;
25609
+ return {
25610
+ name: section.name,
25611
+ entries: section.entries.map((entry, index) => ({
25612
+ en: absolutizeLedgerLinks(entry.text),
25613
+ zh: absolutizeLedgerLinks(zhEntries?.[index]?.text ?? entry.text)
25614
+ }))
25615
+ };
25616
+ })
25617
+ });
25618
+ }
25619
+ return notes.sort((left, right) => compareVersions(right.version, left.version));
25620
+ }
25621
+ function selectReleaseNotes(notes, range) {
25622
+ return notes.filter((note) => compareVersions(note.version, range.through) <= 0 && (range.after === void 0 || !isReleaseVersion(range.after) || compareVersions(note.version, range.after) > 0));
25623
+ }
25624
+ //#endregion
25625
+ //#region packages/core/src/release/service.ts
25626
+ const RELEASE_PACKAGE = "deepseekbot";
25627
+ const RELEASE_NOTES_PACKAGE = "@botharness/core";
25628
+ const DEFAULT_RELEASE_REGISTRIES = ["https://registry.npmjs.org", "https://registry.npmmirror.com"];
25629
+ const DEFAULT_RELEASE_NOTE_SOURCES = [(version) => `https://cdn.jsdelivr.net/npm/${RELEASE_NOTES_PACKAGE}@${version}/`, (version) => `https://registry.npmmirror.com/${RELEASE_NOTES_PACKAGE}/${version}/files/`];
25630
+ const CHECK_CACHE_MS = 216e5;
25631
+ const FAILURE_CACHE_MS = 3e5;
25632
+ const REQUEST_TIMEOUT_MS = 8e3;
25633
+ function readFirst(candidates) {
25634
+ for (const candidate of candidates) try {
25635
+ return readFileSync(candidate, "utf8");
25636
+ } catch {
25637
+ continue;
25638
+ }
25639
+ }
25640
+ function installedRelease(moduleUrl) {
25641
+ const ledger = (name) => readFirst([new URL(`../${name}`, moduleUrl), new URL(`../../../${name}`, moduleUrl)]);
25642
+ return {
25643
+ version: () => {
25644
+ const manifest = readFirst([new URL("../package.json", moduleUrl)]);
25645
+ if (manifest === void 0) return "0.0.0";
25646
+ const version = JSON.parse(manifest).version;
25647
+ return typeof version === "string" ? version : "0.0.0";
25648
+ },
25649
+ ledgers: () => {
25650
+ const english = ledger("CHANGELOG.md");
25651
+ if (english === void 0) return void 0;
25652
+ return {
25653
+ english,
25654
+ chinese: ledger("CHANGELOG.zh.md") ?? english
25655
+ };
25656
+ }
25657
+ };
25658
+ }
25659
+ function newestTag(tags, current) {
25660
+ if (typeof tags !== "object" || tags === null) return void 0;
25661
+ const source = tags;
25662
+ return [source["latest"], current.includes("-") ? source["next"] : void 0].filter((value) => typeof value === "string" && isReleaseVersion(value)).sort(compareVersions).at(-1);
25663
+ }
25664
+ function createReleaseService(options) {
25665
+ const fetchImpl = options.fetchImpl ?? fetch;
25666
+ const now = options.now ?? Date.now;
25667
+ const registries = options.registries ?? DEFAULT_RELEASE_REGISTRIES;
25668
+ const noteSources = options.noteSources ?? DEFAULT_RELEASE_NOTE_SOURCES;
25669
+ const timeoutMs = options.timeoutMs ?? REQUEST_TIMEOUT_MS;
25670
+ let notes;
25671
+ let cached;
25672
+ let pending;
25673
+ const installedNotes = () => {
25674
+ if (notes !== void 0) return notes;
25675
+ const ledgers = options.ledgers();
25676
+ notes = ledgers === void 0 ? [] : pairReleaseLedgers(ledgers.english, ledgers.chinese);
25677
+ return notes;
25678
+ };
25679
+ const text = async (url) => {
25680
+ try {
25681
+ const response = await fetchImpl(url, { signal: AbortSignal.timeout(timeoutMs) });
25682
+ return response.ok ? await response.text() : void 0;
25683
+ } catch {
25684
+ return;
25685
+ }
25686
+ };
25687
+ const latestVersion = async (current) => {
25688
+ for (const registry of registries) {
25689
+ const body = await text(`${registry.replace(/\/+$/u, "")}/-/package/${RELEASE_PACKAGE}/dist-tags`);
25690
+ if (body === void 0) continue;
25691
+ try {
25692
+ const latest = newestTag(JSON.parse(body), current);
25693
+ if (latest !== void 0) return latest;
25694
+ } catch {
25695
+ continue;
25696
+ }
25697
+ }
25698
+ };
25699
+ const newerNotes = async (current, latest) => {
25700
+ for (const source of noteSources) {
25701
+ const base = source(latest);
25702
+ const english = await text(`${base}CHANGELOG.md`);
25703
+ if (english === void 0) continue;
25704
+ return selectReleaseNotes(pairReleaseLedgers(english, await text(`${base}CHANGELOG.zh.md`) ?? english), {
25705
+ after: current,
25706
+ through: latest
25707
+ });
25708
+ }
25709
+ return [];
25710
+ };
25711
+ const check = async () => {
25712
+ const current = options.version();
25713
+ if (!isReleaseVersion(current)) return {
25714
+ status: "development",
25715
+ current
25716
+ };
25717
+ const latest = await latestVersion(current);
25718
+ if (latest === void 0) return {
25719
+ status: "unavailable",
25720
+ current
25721
+ };
25722
+ if (compareVersions(latest, current) <= 0) return {
25723
+ status: "current",
25724
+ current,
25725
+ latest
25726
+ };
25727
+ return {
25728
+ status: "available",
25729
+ current,
25730
+ latest,
25731
+ releases: await newerNotes(current, latest)
25732
+ };
25733
+ };
25734
+ return {
25735
+ info(since) {
25736
+ const version = options.version();
25737
+ return {
25738
+ version,
25739
+ releases: !isReleaseVersion(version) ? [] : since === void 0 ? installedNotes().filter((note) => compareVersions(note.version, version) === 0) : selectReleaseNotes(installedNotes(), {
25740
+ after: since,
25741
+ through: version
25742
+ })
25743
+ };
25744
+ },
25745
+ update() {
25746
+ if (cached !== void 0) {
25747
+ if (now() - cached.at < (cached.result.status === "unavailable" ? FAILURE_CACHE_MS : CHECK_CACHE_MS)) return Promise.resolve(cached.result);
25748
+ }
25749
+ pending ??= check().then((result) => {
25750
+ cached = {
25751
+ at: now(),
25752
+ result
25753
+ };
25754
+ return result;
25755
+ }).finally(() => {
25756
+ pending = void 0;
25757
+ });
25758
+ return pending;
25759
+ }
25760
+ };
25761
+ }
25762
+ //#endregion
25387
25763
  //#region packages/core/src/bots/avatar-snapshot.ts
25388
25764
  function deriveAvatarAppearance(value) {
25389
25765
  if (!isAvatarRecipe(value)) return void 0;
@@ -49675,6 +50051,7 @@ function apply(ctx, config) {
49675
50051
  toolRules: core.toolRules,
49676
50052
  assignmentAccess: core.assignmentAccess,
49677
50053
  marketplace: createMarketplaceClient({ baseUrl: config.marketplaceUrl ?? "https://market.botharness.ai" }),
50054
+ release: createReleaseService(installedRelease(import.meta.url)),
49678
50055
  developerMode: { set: (enabled) => developerModeTarget.gate?.set(enabled) },
49679
50056
  computerAccess: { changed: (slug) => {
49680
50057
  (ctx.get("botharnessComputerTools")?.reconcileBot?.(slug))?.catch((error) => {
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@botharness/core",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "BotHarness core: PersonaBot registry, memory, and state",
5
5
  "files": [
6
6
  "dist",
7
7
  "cordis.patch.yml",
8
+ "CHANGELOG.md",
9
+ "CHANGELOG.zh.md",
8
10
  "LICENSE"
9
11
  ],
10
12
  "type": "module",