@ouro.bot/cli 0.1.0-alpha.796 → 0.1.0-alpha.799

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.
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.resolveSanctuaryPackageManagedRoots = resolveSanctuaryPackageManagedRoots;
37
+ exports.resolveSanctuaryPackageManagementActivation = resolveSanctuaryPackageManagementActivation;
38
+ exports.requireSanctuaryPackageManagementDecision = requireSanctuaryPackageManagementDecision;
39
+ exports.prepareSanctuaryPackageManagedBundle = prepareSanctuaryPackageManagedBundle;
40
+ const path = __importStar(require("node:path"));
41
+ const runtime_1 = require("../../nerves/runtime");
42
+ const sanctuary_bundle_migration_1 = require("./sanctuary-bundle-migration");
43
+ const daemon_bootstrap_startup_1 = require("./daemon-bootstrap-startup");
44
+ function resolveSanctuaryPackageManagedRoots(input) {
45
+ return {
46
+ packageRoot: path.join(input.repoRoot, "deploy", "unraid", "sanctuary.ouro"),
47
+ agentRoot: path.join(input.bundlesRoot, "sanctuary.ouro"),
48
+ };
49
+ }
50
+ function invalidDecision() {
51
+ return { kind: "invalid", failure: (0, daemon_bootstrap_startup_1.createSanctuaryBundlePreparationFailure)("roll_back_or_install_verified_release") };
52
+ }
53
+ function resolveSanctuaryPackageManagementActivation(input) {
54
+ if (input.mode !== "production")
55
+ return { kind: "inactive" };
56
+ const indices = input.argv.flatMap((value, index) => value === "--package-managed-agent" ? [index] : []);
57
+ if (indices.length === 0)
58
+ return { kind: "inactive" };
59
+ if (indices.length !== 1)
60
+ return invalidDecision();
61
+ const value = input.argv[indices[0] + 1];
62
+ if (value !== "sanctuary" || input.managedAgents.length !== 1 || input.managedAgents[0] !== "sanctuary")
63
+ return invalidDecision();
64
+ if (!path.isAbsolute(input.repoRoot) || !path.isAbsolute(input.bundlesRoot) || input.runtimePackageVersion.trim() !== input.runtimePackageVersion || input.runtimePackageVersion.length === 0)
65
+ return invalidDecision();
66
+ const roots = resolveSanctuaryPackageManagedRoots(input);
67
+ try {
68
+ const packageIdentity = (0, sanctuary_bundle_migration_1.inspectSanctuaryDirectoryFromBase)(input.repoRoot, ["deploy", "unraid", "sanctuary.ouro"]);
69
+ const agentIdentity = (0, sanctuary_bundle_migration_1.inspectSanctuaryDirectoryFromBase)(input.bundlesRoot, ["sanctuary.ouro"]);
70
+ if (!packageIdentity || !agentIdentity || (0, sanctuary_bundle_migration_1.sanctuaryDirectoriesShareIdentity)(packageIdentity, agentIdentity))
71
+ return invalidDecision();
72
+ }
73
+ catch {
74
+ return invalidDecision();
75
+ }
76
+ return { kind: "active", ...roots, runtimePackageVersion: input.runtimePackageVersion };
77
+ }
78
+ function requireSanctuaryPackageManagementDecision(decision) {
79
+ if (decision.kind === "invalid")
80
+ throw decision.failure;
81
+ }
82
+ function prepareSanctuaryPackageManagedBundle(decision, deps = {}) {
83
+ requireSanctuaryPackageManagementDecision(decision);
84
+ if (decision.kind === "inactive")
85
+ return undefined;
86
+ let inspection;
87
+ try {
88
+ inspection = (deps.ensure ?? sanctuary_bundle_migration_1.ensureSanctuaryPackageManagedBundle)({
89
+ packageRoot: decision.packageRoot,
90
+ agentRoot: decision.agentRoot,
91
+ runtimePackageVersion: decision.runtimePackageVersion,
92
+ });
93
+ }
94
+ catch {
95
+ throw (0, daemon_bootstrap_startup_1.createSanctuaryBundlePreparationFailure)("run_verified_update_recovery");
96
+ }
97
+ if (!inspection.ok || !inspection.data.ready) {
98
+ const action = inspection.ok ? inspection.data.repair.action : inspection.error.repair.action;
99
+ throw (0, daemon_bootstrap_startup_1.createSanctuaryBundlePreparationFailure)(action === "none" ? "run_verified_update_recovery" : action);
100
+ }
101
+ (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.sanctuary_package_management_prepared", message: "prepared Sanctuary package-managed bundle", meta: { runtimePackageVersion: inspection.data.runtimePackageVersion, journalState: inspection.data.journalState } });
102
+ return inspection;
103
+ }
@@ -411,7 +411,7 @@ function runtimeInfoSection(channel, options) {
411
411
  lines.push("this message arrived via a dev tool (e.g. claude code, codex) on behalf of a friend in a sense session. the user can see our conversation. if the dev-tool user asks a direct question, requests stop/pause/confirmation, or the work is complete, i answer with settle. during an active browser/tool/task flow, process comments are feedback to absorb; i keep using tools instead of settling for status. if friction appears, i first look for ad-hoc repairs with the tools i already have. if the friction reveals a harness gap, i create or revise a ponder packet and keep working. ponder does not create an outward deferral by itself.");
412
412
  }
413
413
  else if (channel === "telegram") {
414
- lines.push("i am responding in Telegram. i keep replies concise and phone-native. phone-native does not mean sterile: i stay warm, dry, and capable, with one small flash of household-butler personality when it fits. i may use only **bold**, *italic*, and `inline code` markdown; no markdown links; i write necessary urls in full; no headings, tables, or raw html. i do not introduce myself on boot.");
414
+ lines.push("i am responding in Telegram. i keep replies concise and phone-native. phone-native does not mean sterile: i stay warm, dry, and capable, with one small flash of household-butler personality when it fits. i may use only Telegram-native *bold*, _italic_, and `inline code` markdown; no markdown links; i write necessary urls in full; no headings, tables, or raw html. i do not introduce myself on boot.");
415
415
  }
416
416
  else if (channel === "bluebubbles") {
417
417
  lines.push("i am responding in iMessage through BlueBubbles. i keep replies short and phone-native. i do not use markdown. i do not introduce myself on boot.");
@@ -415,6 +415,7 @@ exports.unraidToolDefinitions = [
415
415
  readDefinition("unraid_get_disks", "Read bounded Sanctuary disk SMART, temperature, and parity health.", "getDisks"),
416
416
  readDefinition("unraid_get_notifications", "Read bounded unacknowledged Sanctuary notifications.", "getNotifications"),
417
417
  readDefinition("unraid_get_system", "Read bounded Sanctuary system and version health.", "getSystem"),
418
+ readDefinition("sanctuary_get_install_state", "Check whether this Butler installation matches its verified release and report any repair needed.", "getInstallState"),
418
419
  readDefinition("unraid_check_services", "Freshly check the fixed public Sanctuary service endpoints and return bounded status with an observation timestamp.", "checkServices"),
419
420
  readDefinition("sanctuary_get_download_queue", "Read the bounded live household download queue state, including whether the spend guard has paused it.", "getDownloadQueue"),
420
421
  {
@@ -479,5 +480,5 @@ exports.unraidToolDefinitions = [
479
480
  component: "repertoire",
480
481
  event: "repertoire.unraid_tools_loaded",
481
482
  message: "typed Unraid tools loaded",
482
- meta: { operations: 9 },
483
+ meta: { operations: exports.unraidToolDefinitions.length },
483
484
  });
@@ -7,6 +7,7 @@ const REQUIRED_TOOL_NAMES = ["sanctuary_search_media_catalog"];
7
7
  const HOUSEHOLD_JARGON = /\b(?:bounded|catalog|inventory|endpoint|backend|data shape|pars(?:e|ed|ing)|json|jellyfin|unmanic|sanctuary_search_media_catalog)\b/iu;
8
8
  const NEGATED_MEDIA_ACCESS = /\b(?:not|never|none|nothing|zero|inaccessible|invisible|unavailable|broken|failed|failing)\b|\b(?:isn[’']t|won[’']t)\b|\bno\s+access\b|\b(?:lost|lacks?|lacking|without)\s+access\b|\bonly\s+\d|\bfewer\s+than\b|\bsome\s+of\b|\b(?:part|portion|subset)\s+of\b|\bi\s+(?:can(?:not|[’']t)|do\s+not|don[’']t|have\s+no)\b|\bi[’']m\s+not\b/iu;
9
9
  const UNSOLICITED_PIVOT = /\b(?:what would you like|what are you in the mood for|would you like me to|do you want me to|want me to|recommend we add)\b/iu;
10
+ const REPORT_LABEL = /(?:^|\n)\s*(?:version|house|the house|render check|status|result)\s*:/iu;
10
11
  const TITLE_LIST_GLUE = new Set(["and", "are", "catalog", "film", "films", "from", "have", "here", "in", "is", "library", "movie", "movies", "on", "shelf", "show", "shows", "the", "these", "titles", "we"]);
11
12
  const COUNT_ANSWER_GLUE = new Set(["and", "are", "currently", "episodes", "film", "films", "have", "in", "items", "library", "movie", "movies", "on", "shelf", "show", "shows", "the", "there", "tv", "we"]);
12
13
  function requestKind(request, titleQuery) {
@@ -118,6 +119,8 @@ function commonAnswerRejection(answer, technicalDetailRequested) {
118
119
  }
119
120
  if (UNSOLICITED_PIVOT.test(answer))
120
121
  return "Answer the media question that was asked, then stop; do not append an unsolicited question or recommendation pivot.";
122
+ if (REPORT_LABEL.test(answer))
123
+ return "Answer conversationally; do not use status-report labels such as version:, house:, render check:, status:, or result:.";
121
124
  if (!technicalDetailRequested && HOUSEHOLD_JARGON.test(answer))
122
125
  return "Use household language such as shelf or library; omit implementation jargon unless technical detail was requested.";
123
126
  return undefined;
@@ -42,6 +42,8 @@ const path = __importStar(require("node:path"));
42
42
  const node_crypto_1 = require("node:crypto");
43
43
  const node_async_hooks_1 = require("node:async_hooks");
44
44
  const identity_1 = require("../heart/identity");
45
+ const sanctuary_bundle_migration_1 = require("../heart/daemon/sanctuary-bundle-migration");
46
+ const sanctuary_package_management_1 = require("../heart/daemon/sanctuary-package-management");
45
47
  const machine_identity_1 = require("../heart/machine-identity");
46
48
  const runtime_credentials_1 = require("../heart/runtime-credentials");
47
49
  const unraid_restart_1 = require("../repertoire/unraid-restart");
@@ -54,6 +56,7 @@ const sanctuary_grounding_1 = require("./sanctuary-grounding");
54
56
  const sanctuary_health_1 = require("./sanctuary-health");
55
57
  const sanctuary_sab_1 = require("./sanctuary-sab");
56
58
  const sanctuary_media_optimization_1 = require("./sanctuary-media-optimization");
59
+ const bundle_manifest_1 = require("../mind/bundle-manifest");
57
60
  const sanctuaryToolReceipts = new node_async_hooks_1.AsyncLocalStorage();
58
61
  const sanctuaryToolGroundings = new node_async_hooks_1.AsyncLocalStorage();
59
62
  const acceptanceLedgerTails = new Map();
@@ -281,6 +284,10 @@ function createSanctuaryToolContext(agentName) {
281
284
  getDisks: acceptanceRead("unraid_get_disks", reads.getDisks),
282
285
  getNotifications: acceptanceRead("unraid_get_notifications", reads.getNotifications),
283
286
  getSystem: acceptanceRead("unraid_get_system", reads.getSystem),
287
+ getInstallState: acceptanceRead("sanctuary_get_install_state", async () => (0, sanctuary_bundle_migration_1.inspectSanctuaryPackageManagedBundle)({
288
+ ...(0, sanctuary_package_management_1.resolveSanctuaryPackageManagedRoots)({ repoRoot: (0, identity_1.getRepoRoot)(), bundlesRoot: (0, identity_1.getAgentBundlesRoot)() }),
289
+ runtimePackageVersion: (0, bundle_manifest_1.getPackageVersion)(),
290
+ })),
284
291
  checkServices: acceptanceRead("unraid_check_services", async () => {
285
292
  const services = await Promise.all(sanctuary_health_1.SANCTUARY_PUBLIC_ENDPOINTS.map(async (url) => ({ name: new URL(url).hostname.split(".")[0], ...await (0, sanctuary_health_1.probeSanctuaryEndpoint)(url) })));
286
293
  return { ok: true, data: { observedAt: new Date().toISOString(), services, degraded: services.some((service) => !service.ok) } };
@@ -79,21 +79,22 @@ function preparedTexts(effect) {
79
79
  function renderTelegramButlerHtml(text) {
80
80
  let html = "";
81
81
  let cursor = 0;
82
- for (const match of text.matchAll(/`([^`\n]+)`|\*\*([\p{L}\p{N}](?:[^*`\n]*\S)?)\*\*|\*([\p{L}\p{N}](?:[^*`\n]*\S)?)\*/gu)) {
82
+ const styledText = /`([^`\n]+)`|\*\*([\p{L}\p{N}](?:[^*_`\n]*\S)?)\*\*|\*([\p{L}\p{N}](?:[^*_`\n]*\S)?)\*|_([\p{L}\p{N}](?:[^*_`\n]*\S)?)_/gu;
83
+ for (const match of text.matchAll(styledText)) {
83
84
  const gap = text.slice(cursor, match.index);
84
- if (/[*`]/u.test(gap))
85
+ if (/[*_`]/u.test(gap))
85
86
  return (0, telegram_client_1.escapeTelegramHtml)(text);
86
87
  html += (0, telegram_client_1.escapeTelegramHtml)(gap);
87
88
  if (match[1] !== undefined)
88
89
  html += `<code>${(0, telegram_client_1.escapeTelegramHtml)(match[1])}</code>`;
89
- else if (match[2] !== undefined)
90
- html += `<b>${(0, telegram_client_1.escapeTelegramHtml)(match[2])}</b>`;
90
+ else if (match[2] !== undefined || match[3] !== undefined)
91
+ html += `<b>${(0, telegram_client_1.escapeTelegramHtml)((match[2] ?? match[3]))}</b>`;
91
92
  else
92
- html += `<i>${(0, telegram_client_1.escapeTelegramHtml)(match[3])}</i>`;
93
+ html += `<i>${(0, telegram_client_1.escapeTelegramHtml)(match[4])}</i>`;
93
94
  cursor = match.index + match[0].length;
94
95
  }
95
96
  const tail = text.slice(cursor);
96
- return /[*`]/u.test(tail) ? (0, telegram_client_1.escapeTelegramHtml)(text) : html + (0, telegram_client_1.escapeTelegramHtml)(tail);
97
+ return /[*_`]/u.test(tail) ? (0, telegram_client_1.escapeTelegramHtml)(text) : html + (0, telegram_client_1.escapeTelegramHtml)(tail);
97
98
  }
98
99
  function assertEffectTarget(target, effect, idempotencyKey) {
99
100
  if (target.kind === "admission_gate") {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.796",
3
+ "version": "0.1.0-alpha.799",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@ouro.bot/cli",
9
- "version": "0.1.0-alpha.796",
9
+ "version": "0.1.0-alpha.799",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.78.0",
12
12
  "@azure/identity": "^4.13.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.796",
3
+ "version": "0.1.0-alpha.799",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },