@ouro.bot/cli 0.1.0-alpha.8 → 0.1.0-alpha.80

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.
Files changed (127) hide show
  1. package/AdoptionSpecialist.ouro/agent.json +70 -9
  2. package/AdoptionSpecialist.ouro/psyche/SOUL.md +5 -2
  3. package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
  4. package/README.md +147 -205
  5. package/assets/ouroboros.png +0 -0
  6. package/changelog.json +462 -0
  7. package/dist/heart/active-work.js +218 -0
  8. package/dist/heart/bridges/manager.js +358 -0
  9. package/dist/heart/bridges/state-machine.js +135 -0
  10. package/dist/heart/bridges/store.js +123 -0
  11. package/dist/heart/commitments.js +89 -0
  12. package/dist/heart/config.js +68 -23
  13. package/dist/heart/core.js +452 -93
  14. package/dist/heart/cross-chat-delivery.js +146 -0
  15. package/dist/heart/daemon/agent-discovery.js +81 -0
  16. package/dist/heart/daemon/auth-flow.js +430 -0
  17. package/dist/heart/daemon/daemon-cli.js +1746 -247
  18. package/dist/heart/daemon/daemon-entry.js +55 -6
  19. package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
  20. package/dist/heart/daemon/daemon.js +216 -10
  21. package/dist/heart/daemon/hatch-animation.js +10 -3
  22. package/dist/heart/daemon/hatch-flow.js +7 -82
  23. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  24. package/dist/heart/daemon/launchd.js +159 -0
  25. package/dist/heart/daemon/log-tailer.js +4 -3
  26. package/dist/heart/daemon/message-router.js +17 -8
  27. package/dist/heart/daemon/ouro-bot-entry.js +0 -0
  28. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  29. package/dist/heart/daemon/ouro-entry.js +0 -0
  30. package/dist/heart/daemon/ouro-path-installer.js +260 -0
  31. package/dist/heart/daemon/ouro-uti.js +11 -2
  32. package/dist/heart/daemon/ouro-version-manager.js +164 -0
  33. package/dist/heart/daemon/process-manager.js +14 -1
  34. package/dist/heart/daemon/run-hooks.js +37 -0
  35. package/dist/heart/daemon/runtime-logging.js +58 -15
  36. package/dist/heart/daemon/runtime-metadata.js +219 -0
  37. package/dist/heart/daemon/runtime-mode.js +67 -0
  38. package/dist/heart/daemon/sense-manager.js +307 -0
  39. package/dist/heart/daemon/skill-management-installer.js +94 -0
  40. package/dist/heart/daemon/socket-client.js +202 -0
  41. package/dist/heart/daemon/specialist-orchestrator.js +53 -84
  42. package/dist/heart/daemon/specialist-prompt.js +63 -11
  43. package/dist/heart/daemon/specialist-tools.js +211 -60
  44. package/dist/heart/daemon/staged-restart.js +114 -0
  45. package/dist/heart/daemon/thoughts.js +507 -0
  46. package/dist/heart/daemon/update-checker.js +111 -0
  47. package/dist/heart/daemon/update-hooks.js +138 -0
  48. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  49. package/dist/heart/delegation.js +62 -0
  50. package/dist/heart/identity.js +126 -21
  51. package/dist/heart/kicks.js +1 -19
  52. package/dist/heart/model-capabilities.js +48 -0
  53. package/dist/heart/obligations.js +141 -0
  54. package/dist/heart/progress-story.js +42 -0
  55. package/dist/heart/providers/anthropic.js +74 -9
  56. package/dist/heart/providers/azure.js +86 -7
  57. package/dist/heart/providers/github-copilot.js +149 -0
  58. package/dist/heart/providers/minimax.js +4 -0
  59. package/dist/heart/providers/openai-codex.js +12 -3
  60. package/dist/heart/safe-workspace.js +228 -0
  61. package/dist/heart/sense-truth.js +61 -0
  62. package/dist/heart/session-activity.js +169 -0
  63. package/dist/heart/session-recall.js +116 -0
  64. package/dist/heart/streaming.js +100 -22
  65. package/dist/heart/target-resolution.js +123 -0
  66. package/dist/heart/turn-coordinator.js +28 -0
  67. package/dist/mind/associative-recall.js +14 -2
  68. package/dist/mind/bundle-manifest.js +70 -0
  69. package/dist/mind/context.js +27 -11
  70. package/dist/mind/first-impressions.js +16 -2
  71. package/dist/mind/friends/channel.js +35 -0
  72. package/dist/mind/friends/group-context.js +144 -0
  73. package/dist/mind/friends/store-file.js +19 -0
  74. package/dist/mind/friends/trust-explanation.js +74 -0
  75. package/dist/mind/friends/types.js +8 -0
  76. package/dist/mind/memory.js +27 -26
  77. package/dist/mind/pending.js +76 -9
  78. package/dist/mind/phrases.js +1 -0
  79. package/dist/mind/prompt.js +445 -77
  80. package/dist/mind/token-estimate.js +8 -12
  81. package/dist/nerves/cli-logging.js +15 -2
  82. package/dist/nerves/coverage/run-artifacts.js +1 -1
  83. package/dist/nerves/index.js +12 -0
  84. package/dist/repertoire/ado-client.js +4 -2
  85. package/dist/repertoire/coding/feedback.js +134 -0
  86. package/dist/repertoire/coding/index.js +4 -1
  87. package/dist/repertoire/coding/manager.js +62 -4
  88. package/dist/repertoire/coding/spawner.js +3 -3
  89. package/dist/repertoire/coding/tools.js +41 -2
  90. package/dist/repertoire/data/ado-endpoints.json +188 -0
  91. package/dist/repertoire/guardrails.js +290 -0
  92. package/dist/repertoire/mcp-client.js +254 -0
  93. package/dist/repertoire/mcp-manager.js +195 -0
  94. package/dist/repertoire/skills.js +3 -26
  95. package/dist/repertoire/tasks/board.js +12 -0
  96. package/dist/repertoire/tasks/index.js +23 -9
  97. package/dist/repertoire/tasks/transitions.js +1 -2
  98. package/dist/repertoire/tools-base.js +686 -251
  99. package/dist/repertoire/tools-bluebubbles.js +93 -0
  100. package/dist/repertoire/tools-teams.js +58 -25
  101. package/dist/repertoire/tools.js +95 -53
  102. package/dist/senses/bluebubbles-client.js +210 -5
  103. package/dist/senses/bluebubbles-entry.js +2 -0
  104. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  105. package/dist/senses/bluebubbles-media.js +339 -0
  106. package/dist/senses/bluebubbles-model.js +12 -4
  107. package/dist/senses/bluebubbles-mutation-log.js +45 -5
  108. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  109. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  110. package/dist/senses/bluebubbles.js +894 -45
  111. package/dist/senses/cli-layout.js +187 -0
  112. package/dist/senses/cli.js +405 -156
  113. package/dist/senses/continuity.js +94 -0
  114. package/dist/senses/debug-activity.js +154 -0
  115. package/dist/senses/inner-dialog-worker.js +47 -18
  116. package/dist/senses/inner-dialog.js +377 -83
  117. package/dist/senses/pipeline.js +307 -0
  118. package/dist/senses/teams.js +573 -129
  119. package/dist/senses/trust-gate.js +112 -2
  120. package/package.json +14 -3
  121. package/subagents/README.md +4 -70
  122. package/dist/heart/daemon/specialist-session.js +0 -142
  123. package/dist/heart/daemon/subagent-installer.js +0 -125
  124. package/dist/inner-worker-entry.js +0 -4
  125. package/subagents/work-doer.md +0 -233
  126. package/subagents/work-merger.md +0 -624
  127. package/subagents/work-planner.md +0 -373
@@ -9,6 +9,7 @@ const config_1 = require("../config");
9
9
  const identity_1 = require("../identity");
10
10
  const runtime_1 = require("../../nerves/runtime");
11
11
  const streaming_1 = require("../streaming");
12
+ const model_capabilities_1 = require("../model-capabilities");
12
13
  const OPENAI_CODEX_AUTH_FAILURE_MARKERS = [
13
14
  "authentication failed",
14
15
  "unauthorized",
@@ -27,11 +28,11 @@ function getOpenAICodexOAuthInstructions() {
27
28
  const agentName = getOpenAICodexAgentNameForGuidance();
28
29
  return [
29
30
  "Fix:",
30
- ` 1. Run \`npm run auth:openai-codex -- --agent ${agentName}\``,
31
- " (or run `codex login` and set the OAuth token manually)",
31
+ ` 1. Run \`ouro auth --agent ${agentName}\``,
32
32
  ` 2. Open ${getOpenAICodexSecretsPathForGuidance()}`,
33
33
  " 3. Confirm providers.openai-codex.oauthAccessToken is set",
34
34
  " 4. This provider uses chatgpt.com/backend-api/codex/responses (not api.openai.com/responses).",
35
+ " 5. After reauth, retry the failed ouro command or reconnect this session.",
35
36
  ].join("\n");
36
37
  }
37
38
  function getOpenAICodexReauthGuidance(reason) {
@@ -106,6 +107,12 @@ function createOpenAICodexProviderRuntime() {
106
107
  if (!chatgptAccountId) {
107
108
  throw new Error(getOpenAICodexReauthGuidance("OpenAI Codex OAuth access token is missing a chatgpt_account_id claim required for chatgpt.com/backend-api/codex."));
108
109
  }
110
+ const modelCaps = (0, model_capabilities_1.getModelCapabilities)(codexConfig.model);
111
+ const capabilities = new Set();
112
+ if (modelCaps.reasoningEffort)
113
+ capabilities.add("reasoning-effort");
114
+ if (modelCaps.phase)
115
+ capabilities.add("phase-annotation");
109
116
  const client = new openai_1.default({
110
117
  apiKey: token,
111
118
  baseURL: OPENAI_CODEX_BACKEND_BASE_URL,
@@ -123,6 +130,8 @@ function createOpenAICodexProviderRuntime() {
123
130
  id: "openai-codex",
124
131
  model: codexConfig.model,
125
132
  client,
133
+ capabilities,
134
+ supportedReasoningEfforts: modelCaps.reasoningEffort,
126
135
  resetTurnState(messages) {
127
136
  const { instructions, input } = (0, streaming_1.toResponsesInput)(messages);
128
137
  nativeInput = input;
@@ -141,7 +150,7 @@ function createOpenAICodexProviderRuntime() {
141
150
  input: nativeInput,
142
151
  instructions: nativeInstructions,
143
152
  tools: (0, streaming_1.toResponsesTools)(request.activeTools),
144
- reasoning: { effort: "medium", summary: "detailed" },
153
+ reasoning: { effort: request.reasoningEffort ?? "medium", summary: "detailed" },
145
154
  stream: true,
146
155
  store: false,
147
156
  include: ["reasoning.encrypted_content"],
@@ -0,0 +1,228 @@
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.resetSafeWorkspaceSelection = resetSafeWorkspaceSelection;
37
+ exports.getActiveSafeWorkspaceSelection = getActiveSafeWorkspaceSelection;
38
+ exports.ensureSafeRepoWorkspace = ensureSafeRepoWorkspace;
39
+ exports.resolveSafeRepoPath = resolveSafeRepoPath;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const child_process_1 = require("child_process");
43
+ const identity_1 = require("./identity");
44
+ const runtime_1 = require("../nerves/runtime");
45
+ let activeSelection = null;
46
+ let cleanupHookRegistered = false;
47
+ function defaultNow() {
48
+ return Date.now();
49
+ }
50
+ function resolveAgentName(explicit) {
51
+ if (explicit && explicit.trim().length > 0)
52
+ return explicit.trim();
53
+ try {
54
+ return (0, identity_1.getAgentName)();
55
+ }
56
+ catch {
57
+ return "slugger";
58
+ }
59
+ }
60
+ function runGit(cwd, args, spawnSync) {
61
+ return spawnSync("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
62
+ }
63
+ function readStdout(result) {
64
+ return (result.stdout ?? Buffer.from("")).toString("utf-8").trim();
65
+ }
66
+ function readStderr(result) {
67
+ return (result.stderr ?? Buffer.from("")).toString("utf-8").trim();
68
+ }
69
+ function assertGitOk(result, action) {
70
+ if (result.error) {
71
+ throw result.error;
72
+ }
73
+ if (result.status !== 0) {
74
+ const detail = readStderr(result) || readStdout(result) || `exit ${result.status ?? "unknown"}`;
75
+ throw new Error(`${action} failed: ${detail}`);
76
+ }
77
+ return readStdout(result);
78
+ }
79
+ function isGitClone(repoRoot, spawnSync) {
80
+ const result = runGit(repoRoot, ["rev-parse", "--is-inside-work-tree"], spawnSync);
81
+ return result.status === 0 && readStdout(result) === "true";
82
+ }
83
+ function readCurrentBranch(repoRoot, spawnSync) {
84
+ return assertGitOk(runGit(repoRoot, ["rev-parse", "--abbrev-ref", "HEAD"], spawnSync), "git branch read");
85
+ }
86
+ function ensureFetchedOrigin(repoRoot, spawnSync) {
87
+ assertGitOk(runGit(repoRoot, ["fetch", "origin"], spawnSync), "git fetch origin");
88
+ }
89
+ function ensureMainFastForward(repoRoot, spawnSync) {
90
+ assertGitOk(runGit(repoRoot, ["pull", "--ff-only", "origin", "main"], spawnSync), "git pull --ff-only origin main");
91
+ }
92
+ function createDedicatedWorktree(repoRoot, workspaceRoot, branchSuffix, existsSync, mkdirSync, rmSync, spawnSync) {
93
+ mkdirSync(path.dirname(workspaceRoot), { recursive: true });
94
+ const branchName = `slugger/${branchSuffix}`;
95
+ if (existsSync(workspaceRoot)) {
96
+ rmSync(workspaceRoot, { recursive: true, force: true });
97
+ }
98
+ assertGitOk(runGit(repoRoot, ["worktree", "add", "-B", branchName, workspaceRoot, "origin/main"], spawnSync), "git worktree add");
99
+ return { workspaceRoot, created: true };
100
+ }
101
+ function createScratchClone(workspaceRoot, cloneUrl, existsSync, mkdirSync, rmSync, spawnSync) {
102
+ mkdirSync(path.dirname(workspaceRoot), { recursive: true });
103
+ if (existsSync(workspaceRoot)) {
104
+ rmSync(workspaceRoot, { recursive: true, force: true });
105
+ }
106
+ const result = spawnSync("git", ["clone", "--depth", "1", "--branch", "main", cloneUrl, workspaceRoot], {
107
+ stdio: ["ignore", "pipe", "pipe"],
108
+ });
109
+ assertGitOk(result, "git clone");
110
+ return { workspaceRoot, created: true };
111
+ }
112
+ function registerCleanupHook(options) {
113
+ if (cleanupHookRegistered)
114
+ return;
115
+ cleanupHookRegistered = true;
116
+ process.on("exit", () => {
117
+ if (!activeSelection?.cleanupAfterMerge)
118
+ return;
119
+ try {
120
+ options.rmSync(activeSelection.workspaceRoot, { recursive: true, force: true });
121
+ }
122
+ catch {
123
+ // best effort
124
+ }
125
+ });
126
+ }
127
+ function resetSafeWorkspaceSelection(options = {}) {
128
+ activeSelection = null;
129
+ if (!options.keepCleanupHookRegistered) {
130
+ cleanupHookRegistered = false;
131
+ }
132
+ }
133
+ function getActiveSafeWorkspaceSelection() {
134
+ return activeSelection;
135
+ }
136
+ function ensureSafeRepoWorkspace(options = {}) {
137
+ if (activeSelection) {
138
+ return activeSelection;
139
+ }
140
+ const repoRoot = options.repoRoot ?? (0, identity_1.getRepoRoot)();
141
+ const agentName = resolveAgentName(options.agentName);
142
+ const canonicalRepoUrl = options.canonicalRepoUrl ?? identity_1.HARNESS_CANONICAL_REPO_URL;
143
+ const workspaceBase = options.workspaceRoot ?? (0, identity_1.getAgentRepoWorkspacesRoot)(agentName);
144
+ const spawnSync = options.spawnSync ?? child_process_1.spawnSync;
145
+ const existsSync = options.existsSync ?? fs.existsSync;
146
+ const mkdirSync = options.mkdirSync ?? fs.mkdirSync;
147
+ const rmSync = options.rmSync ?? fs.rmSync;
148
+ const now = options.now ?? defaultNow;
149
+ const stamp = String(now());
150
+ registerCleanupHook({ rmSync });
151
+ let selection;
152
+ if (isGitClone(repoRoot, spawnSync)) {
153
+ const branch = readCurrentBranch(repoRoot, spawnSync);
154
+ ensureFetchedOrigin(repoRoot, spawnSync);
155
+ if (branch === "main") {
156
+ ensureMainFastForward(repoRoot, spawnSync);
157
+ const worktreeRoot = path.join(workspaceBase, `ouroboros-main-${stamp}`);
158
+ const created = createDedicatedWorktree(repoRoot, worktreeRoot, `safe-workspace-${stamp}`, existsSync, mkdirSync, rmSync, spawnSync);
159
+ selection = {
160
+ runtimeKind: "clone-main",
161
+ repoRoot,
162
+ workspaceRoot: created.workspaceRoot,
163
+ sourceBranch: branch,
164
+ sourceCloneUrl: canonicalRepoUrl,
165
+ cleanupAfterMerge: false,
166
+ created: created.created,
167
+ note: `running from clone on main; fast-forwarded and created dedicated worktree ${created.workspaceRoot}`,
168
+ };
169
+ }
170
+ else {
171
+ const worktreeRoot = path.join(workspaceBase, `ouroboros-origin-main-${stamp}`);
172
+ const created = createDedicatedWorktree(repoRoot, worktreeRoot, `safe-workspace-${stamp}`, existsSync, mkdirSync, rmSync, spawnSync);
173
+ selection = {
174
+ runtimeKind: "clone-non-main",
175
+ repoRoot,
176
+ workspaceRoot: created.workspaceRoot,
177
+ sourceBranch: branch,
178
+ sourceCloneUrl: canonicalRepoUrl,
179
+ cleanupAfterMerge: false,
180
+ created: created.created,
181
+ note: `running from branch ${branch}; defaulted new work from origin/main in dedicated worktree ${created.workspaceRoot}`,
182
+ };
183
+ }
184
+ }
185
+ else {
186
+ const scratchRoot = path.join(workspaceBase, `ouroboros-scratch-${stamp}`);
187
+ const created = createScratchClone(scratchRoot, canonicalRepoUrl, existsSync, mkdirSync, rmSync, spawnSync);
188
+ selection = {
189
+ runtimeKind: "installed-runtime",
190
+ repoRoot,
191
+ workspaceRoot: created.workspaceRoot,
192
+ sourceBranch: null,
193
+ sourceCloneUrl: canonicalRepoUrl,
194
+ cleanupAfterMerge: true,
195
+ created: created.created,
196
+ note: `running from installed runtime/wrapper; created scratch clone ${created.workspaceRoot} from ${canonicalRepoUrl}`,
197
+ };
198
+ }
199
+ activeSelection = selection;
200
+ (0, runtime_1.emitNervesEvent)({
201
+ component: "workspace",
202
+ event: "workspace.safe_repo_acquired",
203
+ message: "acquired safe repo workspace before local edits",
204
+ meta: {
205
+ runtimeKind: selection.runtimeKind,
206
+ repoRoot: selection.repoRoot,
207
+ workspaceRoot: selection.workspaceRoot,
208
+ sourceBranch: selection.sourceBranch,
209
+ sourceCloneUrl: selection.sourceCloneUrl,
210
+ cleanupAfterMerge: selection.cleanupAfterMerge,
211
+ },
212
+ });
213
+ return selection;
214
+ }
215
+ function resolveSafeRepoPath(options) {
216
+ const requestedPath = path.resolve(options.requestedPath);
217
+ const repoRoot = path.resolve(options.repoRoot ?? (0, identity_1.getRepoRoot)());
218
+ if (activeSelection && requestedPath.startsWith(activeSelection.workspaceRoot + path.sep)) {
219
+ return { selection: activeSelection, resolvedPath: requestedPath };
220
+ }
221
+ if (requestedPath !== repoRoot && !requestedPath.startsWith(repoRoot + path.sep)) {
222
+ return { selection: activeSelection, resolvedPath: requestedPath };
223
+ }
224
+ const selection = ensureSafeRepoWorkspace(options);
225
+ const relativePath = requestedPath === repoRoot ? "" : path.relative(repoRoot, requestedPath);
226
+ const resolvedPath = relativePath ? path.join(selection.workspaceRoot, relativePath) : selection.workspaceRoot;
227
+ return { selection, resolvedPath };
228
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSenseInventory = getSenseInventory;
4
+ const runtime_1 = require("../nerves/runtime");
5
+ const identity_1 = require("./identity");
6
+ const SENSES = [
7
+ { sense: "cli", label: "CLI", daemonManaged: false },
8
+ { sense: "teams", label: "Teams", daemonManaged: true },
9
+ { sense: "bluebubbles", label: "BlueBubbles", daemonManaged: true },
10
+ ];
11
+ function configuredSenses(senses) {
12
+ return senses ?? {
13
+ cli: { ...identity_1.DEFAULT_AGENT_SENSES.cli },
14
+ teams: { ...identity_1.DEFAULT_AGENT_SENSES.teams },
15
+ bluebubbles: { ...identity_1.DEFAULT_AGENT_SENSES.bluebubbles },
16
+ };
17
+ }
18
+ function resolveStatus(enabled, daemonManaged, runtimeInfo) {
19
+ if (!enabled) {
20
+ return "disabled";
21
+ }
22
+ if (!daemonManaged) {
23
+ return "interactive";
24
+ }
25
+ if (runtimeInfo?.runtime === "error") {
26
+ return "error";
27
+ }
28
+ if (runtimeInfo?.runtime === "running") {
29
+ return "running";
30
+ }
31
+ if (runtimeInfo?.configured === false) {
32
+ return "needs_config";
33
+ }
34
+ return "ready";
35
+ }
36
+ function getSenseInventory(agent, runtime = {}) {
37
+ const senses = configuredSenses(agent.senses);
38
+ const inventory = SENSES.map(({ sense, label, daemonManaged }) => {
39
+ const enabled = senses[sense].enabled;
40
+ return {
41
+ sense,
42
+ label,
43
+ enabled,
44
+ daemonManaged,
45
+ status: resolveStatus(enabled, daemonManaged, runtime[sense]),
46
+ };
47
+ });
48
+ (0, runtime_1.emitNervesEvent)({
49
+ component: "channels",
50
+ event: "channel.sense_inventory_built",
51
+ message: "built sense inventory",
52
+ meta: {
53
+ senses: inventory.map((entry) => ({
54
+ sense: entry.sense,
55
+ enabled: entry.enabled,
56
+ status: entry.status,
57
+ })),
58
+ },
59
+ });
60
+ return inventory;
61
+ }
@@ -0,0 +1,169 @@
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.listSessionActivity = listSessionActivity;
37
+ exports.findFreshestFriendSession = findFreshestFriendSession;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const runtime_1 = require("../nerves/runtime");
41
+ const DEFAULT_ACTIVE_THRESHOLD_MS = 24 * 60 * 60 * 1000;
42
+ function activityPriority(source) {
43
+ return source === "friend-facing" ? 0 : 1;
44
+ }
45
+ function resolveFriendName(friendId, friendsDir, agentName) {
46
+ if (friendId === "self")
47
+ return agentName;
48
+ try {
49
+ const raw = fs.readFileSync(path.join(friendsDir, `${friendId}.json`), "utf-8");
50
+ const parsed = JSON.parse(raw);
51
+ return parsed.name ?? friendId;
52
+ }
53
+ catch {
54
+ return friendId;
55
+ }
56
+ }
57
+ function parseFriendActivity(sessionPath) {
58
+ let mtimeMs;
59
+ try {
60
+ mtimeMs = fs.statSync(sessionPath).mtimeMs;
61
+ }
62
+ catch {
63
+ return null;
64
+ }
65
+ try {
66
+ const raw = fs.readFileSync(sessionPath, "utf-8");
67
+ const parsed = JSON.parse(raw);
68
+ const explicit = parsed?.state?.lastFriendActivityAt;
69
+ if (typeof explicit === "string") {
70
+ const parsedMs = Date.parse(explicit);
71
+ if (Number.isFinite(parsedMs)) {
72
+ return {
73
+ lastActivityMs: parsedMs,
74
+ lastActivityAt: new Date(parsedMs).toISOString(),
75
+ activitySource: "friend-facing",
76
+ };
77
+ }
78
+ }
79
+ }
80
+ catch {
81
+ // fall back to file mtime below
82
+ }
83
+ return {
84
+ lastActivityMs: mtimeMs,
85
+ lastActivityAt: new Date(mtimeMs).toISOString(),
86
+ activitySource: "mtime-fallback",
87
+ };
88
+ }
89
+ function listSessionActivity(query) {
90
+ const { sessionsDir, friendsDir, agentName, activeThresholdMs = DEFAULT_ACTIVE_THRESHOLD_MS, currentSession = null, } = query;
91
+ (0, runtime_1.emitNervesEvent)({
92
+ component: "daemon",
93
+ event: "daemon.session_activity_scan",
94
+ message: "scanning session activity",
95
+ meta: {
96
+ sessionsDir,
97
+ currentSession: currentSession ? `${currentSession.friendId}/${currentSession.channel}/${currentSession.key}` : null,
98
+ },
99
+ });
100
+ if (!fs.existsSync(sessionsDir))
101
+ return [];
102
+ const now = Date.now();
103
+ const results = [];
104
+ let friendDirs;
105
+ try {
106
+ friendDirs = fs.readdirSync(sessionsDir);
107
+ }
108
+ catch {
109
+ return [];
110
+ }
111
+ for (const friendId of friendDirs) {
112
+ const friendPath = path.join(sessionsDir, friendId);
113
+ let channels;
114
+ try {
115
+ channels = fs.readdirSync(friendPath);
116
+ }
117
+ catch {
118
+ continue;
119
+ }
120
+ for (const channel of channels) {
121
+ const channelPath = path.join(friendPath, channel);
122
+ let keys;
123
+ try {
124
+ keys = fs.readdirSync(channelPath);
125
+ }
126
+ catch {
127
+ continue;
128
+ }
129
+ for (const keyFile of keys) {
130
+ if (!keyFile.endsWith(".json"))
131
+ continue;
132
+ const key = keyFile.replace(/\.json$/, "");
133
+ if (currentSession && friendId === currentSession.friendId && channel === currentSession.channel && key === currentSession.key) {
134
+ continue;
135
+ }
136
+ const sessionPath = path.join(channelPath, keyFile);
137
+ const activity = parseFriendActivity(sessionPath);
138
+ if (!activity)
139
+ continue;
140
+ if (now - activity.lastActivityMs > activeThresholdMs)
141
+ continue;
142
+ results.push({
143
+ friendId,
144
+ friendName: resolveFriendName(friendId, friendsDir, agentName),
145
+ channel,
146
+ key,
147
+ sessionPath,
148
+ lastActivityAt: activity.lastActivityAt,
149
+ lastActivityMs: activity.lastActivityMs,
150
+ activitySource: activity.activitySource,
151
+ });
152
+ }
153
+ }
154
+ }
155
+ return results.sort((a, b) => {
156
+ const sourceDiff = activityPriority(a.activitySource) - activityPriority(b.activitySource);
157
+ if (sourceDiff !== 0)
158
+ return sourceDiff;
159
+ return b.lastActivityMs - a.lastActivityMs;
160
+ });
161
+ }
162
+ function findFreshestFriendSession(query) {
163
+ const { activeOnly = false, activeThresholdMs = DEFAULT_ACTIVE_THRESHOLD_MS, ...rest } = query;
164
+ const currentSession = rest.currentSession ?? null;
165
+ const all = activeOnly
166
+ ? listSessionActivity({ ...rest, activeThresholdMs, currentSession })
167
+ : listSessionActivity({ ...rest, activeThresholdMs: Number.MAX_SAFE_INTEGER, currentSession });
168
+ return all.find((entry) => entry.friendId === query.friendId) ?? null;
169
+ }
@@ -0,0 +1,116 @@
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.recallSession = recallSession;
37
+ const fs = __importStar(require("fs"));
38
+ const runtime_1 = require("../nerves/runtime");
39
+ function normalizeContent(content) {
40
+ if (typeof content === "string")
41
+ return content;
42
+ if (!Array.isArray(content))
43
+ return "";
44
+ return content
45
+ .map((part) => (part && typeof part === "object" && "type" in part && part.type === "text" && "text" in part
46
+ ? String(part.text ?? "")
47
+ : ""))
48
+ .filter((text) => text.length > 0)
49
+ .join("");
50
+ }
51
+ function buildSummaryInstruction(friendId, channel, trustLevel) {
52
+ if (friendId === "self" && channel === "inner") {
53
+ return "summarize this session transcript fully and transparently. this is my own inner dialog — include all details, decisions, and reasoning.";
54
+ }
55
+ return `summarize this session transcript. the person asking has trust level: ${trustLevel}. family=full transparency, friend=share work and general topics but protect other people's identities, acquaintance=very guarded minimal disclosure.`;
56
+ }
57
+ function clip(text, limit = 160) {
58
+ const compact = text.replace(/\s+/g, " ").trim();
59
+ return compact.length > limit ? compact.slice(0, limit - 1) + "…" : compact;
60
+ }
61
+ function buildSnapshot(summary, tailMessages) {
62
+ const lines = [`recent focus: ${clip(summary, 240)}`];
63
+ const latestUser = [...tailMessages].reverse().find((message) => message.role === "user")?.content;
64
+ const latestAssistant = [...tailMessages].reverse().find((message) => message.role === "assistant")?.content;
65
+ if (latestUser) {
66
+ lines.push(`latest user: ${clip(latestUser)}`);
67
+ }
68
+ if (latestAssistant) {
69
+ lines.push(`latest assistant: ${clip(latestAssistant)}`);
70
+ }
71
+ return lines.join("\n");
72
+ }
73
+ async function recallSession(options) {
74
+ (0, runtime_1.emitNervesEvent)({
75
+ component: "daemon",
76
+ event: "daemon.session_recall",
77
+ message: "recalling session transcript tail",
78
+ meta: {
79
+ friendId: options.friendId,
80
+ channel: options.channel,
81
+ key: options.key,
82
+ messageCount: options.messageCount,
83
+ },
84
+ });
85
+ let raw;
86
+ try {
87
+ raw = fs.readFileSync(options.sessionPath, "utf-8");
88
+ }
89
+ catch {
90
+ return { kind: "missing" };
91
+ }
92
+ const parsed = JSON.parse(raw);
93
+ const tailMessages = (parsed.messages ?? [])
94
+ .map((message) => ({
95
+ role: typeof message.role === "string" ? message.role : "",
96
+ content: normalizeContent(message.content),
97
+ }))
98
+ .filter((message) => message.role !== "system" && message.content.length > 0)
99
+ .slice(-options.messageCount);
100
+ if (tailMessages.length === 0) {
101
+ return { kind: "empty" };
102
+ }
103
+ const transcript = tailMessages
104
+ .map((message) => `[${message.role}] ${message.content}`)
105
+ .join("\n");
106
+ const summary = options.summarize
107
+ ? await options.summarize(transcript, buildSummaryInstruction(options.friendId, options.channel, options.trustLevel ?? "family"))
108
+ : transcript;
109
+ return {
110
+ kind: "ok",
111
+ transcript,
112
+ summary,
113
+ snapshot: buildSnapshot(summary, tailMessages),
114
+ tailMessages,
115
+ };
116
+ }