quoxcli 0.0.0-stage → 0.2.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.
Files changed (348) hide show
  1. package/LICENSE +35 -0
  2. package/README.md +142 -2
  3. package/bin/quox.js +292 -0
  4. package/bin/quoxon.js +8 -0
  5. package/lib/api/endpoints/admin.js +125 -0
  6. package/lib/api/endpoints/aee.js +38 -0
  7. package/lib/api/endpoints/agent-attach.js +126 -0
  8. package/lib/api/endpoints/agents.js +56 -0
  9. package/lib/api/endpoints/assistants.js +50 -0
  10. package/lib/api/endpoints/audit.js +14 -0
  11. package/lib/api/endpoints/auth.js +50 -0
  12. package/lib/api/endpoints/awareness.js +34 -0
  13. package/lib/api/endpoints/backup-schedules.js +20 -0
  14. package/lib/api/endpoints/backups.js +86 -0
  15. package/lib/api/endpoints/brain.js +140 -0
  16. package/lib/api/endpoints/budgets.js +62 -0
  17. package/lib/api/endpoints/calendarq.js +71 -0
  18. package/lib/api/endpoints/catalog.js +14 -0
  19. package/lib/api/endpoints/chat.js +54 -0
  20. package/lib/api/endpoints/consent.js +26 -0
  21. package/lib/api/endpoints/contactsq.js +66 -0
  22. package/lib/api/endpoints/conversations.js +32 -0
  23. package/lib/api/endpoints/custom-roles.js +92 -0
  24. package/lib/api/endpoints/divisions.js +56 -0
  25. package/lib/api/endpoints/domains.js +38 -0
  26. package/lib/api/endpoints/engagement.js +231 -0
  27. package/lib/api/endpoints/engine.js +11 -0
  28. package/lib/api/endpoints/entity.js +50 -0
  29. package/lib/api/endpoints/executions.js +32 -0
  30. package/lib/api/endpoints/file.js +20 -0
  31. package/lib/api/endpoints/files.js +26 -0
  32. package/lib/api/endpoints/github.js +21 -0
  33. package/lib/api/endpoints/governance.js +43 -0
  34. package/lib/api/endpoints/hat.js +36 -0
  35. package/lib/api/endpoints/inbox.js +32 -0
  36. package/lib/api/endpoints/inboxq.js +120 -0
  37. package/lib/api/endpoints/index.js +228 -0
  38. package/lib/api/endpoints/invites.js +19 -0
  39. package/lib/api/endpoints/llm-policy.js +43 -0
  40. package/lib/api/endpoints/lucid.js +89 -0
  41. package/lib/api/endpoints/members.js +32 -0
  42. package/lib/api/endpoints/memory.js +75 -0
  43. package/lib/api/endpoints/mfa.js +32 -0
  44. package/lib/api/endpoints/mon.js +178 -0
  45. package/lib/api/endpoints/notesq.js +43 -0
  46. package/lib/api/endpoints/objectives.js +62 -0
  47. package/lib/api/endpoints/orgs.js +38 -0
  48. package/lib/api/endpoints/plugins.js +134 -0
  49. package/lib/api/endpoints/powers.js +75 -0
  50. package/lib/api/endpoints/prompts.js +69 -0
  51. package/lib/api/endpoints/qlarity.js +122 -0
  52. package/lib/api/endpoints/quoxbox.js +55 -0
  53. package/lib/api/endpoints/quoxchat.js +54 -0
  54. package/lib/api/endpoints/quoxflow.js +32 -0
  55. package/lib/api/endpoints/quoxplan.js +114 -0
  56. package/lib/api/endpoints/quoxseo.js +108 -0
  57. package/lib/api/endpoints/reach.js +47 -0
  58. package/lib/api/endpoints/runs.js +38 -0
  59. package/lib/api/endpoints/safety.js +46 -0
  60. package/lib/api/endpoints/scim.js +46 -0
  61. package/lib/api/endpoints/scopes.js +14 -0
  62. package/lib/api/endpoints/security.js +69 -0
  63. package/lib/api/endpoints/setup.js +90 -0
  64. package/lib/api/endpoints/skills.js +180 -0
  65. package/lib/api/endpoints/sso.js +67 -0
  66. package/lib/api/endpoints/tags.js +32 -0
  67. package/lib/api/endpoints/teams.js +56 -0
  68. package/lib/api/endpoints/telephony.js +46 -0
  69. package/lib/api/endpoints/tg.js +56 -0
  70. package/lib/api/endpoints/tools.js +50 -0
  71. package/lib/api/endpoints/traces.js +157 -0
  72. package/lib/api/endpoints/triggers.js +70 -0
  73. package/lib/api/endpoints/user-library.js +41 -0
  74. package/lib/api/endpoints/users.js +20 -0
  75. package/lib/api/endpoints/v1.js +499 -0
  76. package/lib/api/endpoints/vault.js +192 -0
  77. package/lib/api/endpoints/voice.js +22 -0
  78. package/lib/api/endpoints/volt.js +84 -0
  79. package/lib/api/endpoints/ward.js +40 -0
  80. package/lib/api/endpoints/webhooks.js +46 -0
  81. package/lib/api/endpoints/workflows.js +162 -0
  82. package/lib/api/endpoints/x.js +24 -0
  83. package/lib/api/endpoints.js +15 -0
  84. package/lib/commands/admin.js +359 -0
  85. package/lib/commands/aee.js +99 -0
  86. package/lib/commands/agent.js +201 -0
  87. package/lib/commands/agentAttach.js +1440 -0
  88. package/lib/commands/approvals.js +47 -0
  89. package/lib/commands/assistant.js +114 -0
  90. package/lib/commands/auth.js +458 -0
  91. package/lib/commands/awareness.js +88 -0
  92. package/lib/commands/backup.js +373 -0
  93. package/lib/commands/brain.js +994 -0
  94. package/lib/commands/budget.js +241 -0
  95. package/lib/commands/build.js +156 -0
  96. package/lib/commands/calendar.js +216 -0
  97. package/lib/commands/capabilities.js +34 -0
  98. package/lib/commands/chat.js +240 -0
  99. package/lib/commands/claude.js +354 -0
  100. package/lib/commands/config-cmd.js +106 -0
  101. package/lib/commands/consent.js +84 -0
  102. package/lib/commands/contacts.js +967 -0
  103. package/lib/commands/contactsSelftest.js +132 -0
  104. package/lib/commands/conversation.js +74 -0
  105. package/lib/commands/department.js +75 -0
  106. package/lib/commands/dev.js +620 -0
  107. package/lib/commands/devResident.js +314 -0
  108. package/lib/commands/devSupervisor.js +1050 -0
  109. package/lib/commands/discord.js +96 -0
  110. package/lib/commands/doctor.js +181 -0
  111. package/lib/commands/domain.js +114 -0
  112. package/lib/commands/done.js +277 -0
  113. package/lib/commands/engagement.js +586 -0
  114. package/lib/commands/entity.js +119 -0
  115. package/lib/commands/facebook.js +212 -0
  116. package/lib/commands/file.js +128 -0
  117. package/lib/commands/fleet.js +882 -0
  118. package/lib/commands/governance.js +638 -0
  119. package/lib/commands/gripe.js +324 -0
  120. package/lib/commands/hat.js +205 -0
  121. package/lib/commands/helpers.js +79 -0
  122. package/lib/commands/inbox.js +122 -0
  123. package/lib/commands/instagram.js +264 -0
  124. package/lib/commands/integration.js +100 -0
  125. package/lib/commands/inventory.js +115 -0
  126. package/lib/commands/invites.js +45 -0
  127. package/lib/commands/licence.js +280 -0
  128. package/lib/commands/linkedin.js +178 -0
  129. package/lib/commands/llm-policy.js +117 -0
  130. package/lib/commands/llm.js +45 -0
  131. package/lib/commands/lucid.js +591 -0
  132. package/lib/commands/mail.js +531 -0
  133. package/lib/commands/memory.js +284 -0
  134. package/lib/commands/mon.js +514 -0
  135. package/lib/commands/monitoring.js +86 -0
  136. package/lib/commands/motion.js +22 -0
  137. package/lib/commands/notes.js +1246 -0
  138. package/lib/commands/notesBatch.js +160 -0
  139. package/lib/commands/notesBridges.js +56 -0
  140. package/lib/commands/notesLinks.js +60 -0
  141. package/lib/commands/notification.js +57 -0
  142. package/lib/commands/nucleus.js +92 -0
  143. package/lib/commands/objective.js +229 -0
  144. package/lib/commands/onboard.js +328 -0
  145. package/lib/commands/open.js +56 -0
  146. package/lib/commands/org.js +266 -0
  147. package/lib/commands/plan.js +906 -0
  148. package/lib/commands/plugin-doctor.js +1091 -0
  149. package/lib/commands/plugin.js +539 -0
  150. package/lib/commands/policy.js +78 -0
  151. package/lib/commands/powers.js +296 -0
  152. package/lib/commands/prompt.js +350 -0
  153. package/lib/commands/qlarity.js +690 -0
  154. package/lib/commands/quoxbox.js +270 -0
  155. package/lib/commands/quoxchat.js +266 -0
  156. package/lib/commands/quoxseo.js +340 -0
  157. package/lib/commands/reach.js +158 -0
  158. package/lib/commands/role.js +286 -0
  159. package/lib/commands/run.js +132 -0
  160. package/lib/commands/safety.js +107 -0
  161. package/lib/commands/scim.js +88 -0
  162. package/lib/commands/scope.js +58 -0
  163. package/lib/commands/security.js +157 -0
  164. package/lib/commands/service.js +89 -0
  165. package/lib/commands/settings.js +99 -0
  166. package/lib/commands/setup.js +543 -0
  167. package/lib/commands/skillManifest.js +113 -0
  168. package/lib/commands/skillRightsFormat.js +38 -0
  169. package/lib/commands/skills.js +644 -0
  170. package/lib/commands/slot.js +1198 -0
  171. package/lib/commands/sso.js +229 -0
  172. package/lib/commands/status.js +137 -0
  173. package/lib/commands/tag.js +91 -0
  174. package/lib/commands/team.js +140 -0
  175. package/lib/commands/tg.js +240 -0
  176. package/lib/commands/tiktok.js +218 -0
  177. package/lib/commands/tool.js +216 -0
  178. package/lib/commands/trace.js +525 -0
  179. package/lib/commands/trigger.js +128 -0
  180. package/lib/commands/vault.js +1424 -0
  181. package/lib/commands/voice.js +182 -0
  182. package/lib/commands/volt.js +528 -0
  183. package/lib/commands/watch.js +115 -0
  184. package/lib/commands/webhook.js +137 -0
  185. package/lib/commands/workflow.js +503 -0
  186. package/lib/commands/x.js +439 -0
  187. package/lib/core/actingAs.js +136 -0
  188. package/lib/core/aee.js +53 -0
  189. package/lib/core/agentAlias.js +163 -0
  190. package/lib/core/approvalContext.js +61 -0
  191. package/lib/core/auth.js +350 -0
  192. package/lib/core/banner.js +143 -0
  193. package/lib/core/brainPrime.js +90 -0
  194. package/lib/core/callerSource.js +129 -0
  195. package/lib/core/claudeLs.js +94 -0
  196. package/lib/core/client.js +584 -0
  197. package/lib/core/completions.js +163 -0
  198. package/lib/core/config.js +551 -0
  199. package/lib/core/confirm.js +37 -0
  200. package/lib/core/deeplinks.js +76 -0
  201. package/lib/core/doneEngineFetch.js +219 -0
  202. package/lib/core/errors.js +132 -0
  203. package/lib/core/global-flags.js +90 -0
  204. package/lib/core/governedSession.js +402 -0
  205. package/lib/core/lazyCommands.js +119 -0
  206. package/lib/core/liveSessionsReport.js +112 -0
  207. package/lib/core/org-override.js +52 -0
  208. package/lib/core/output.js +239 -0
  209. package/lib/core/prodEnv.js +7 -0
  210. package/lib/core/quoxglyph.js +158 -0
  211. package/lib/core/residentAlarm.js +282 -0
  212. package/lib/core/residentAuth.js +243 -0
  213. package/lib/core/residentPump.js +229 -0
  214. package/lib/core/residentSeed.js +104 -0
  215. package/lib/core/sessionHeartbeat.js +192 -0
  216. package/lib/core/sessionsOverview.js +160 -0
  217. package/lib/core/slotKeeper.js +282 -0
  218. package/lib/core/supervisorEngine.js +864 -0
  219. package/lib/core/systemdInstaller.js +256 -0
  220. package/lib/core/version.js +87 -0
  221. package/lib/core/websiteSession.js +148 -0
  222. package/lib/lucid/LucidIntro.jsx +105 -0
  223. package/lib/lucid/blind.js +71 -0
  224. package/lib/lucid/deck.js +32 -0
  225. package/lib/lucid/fmt.js +139 -0
  226. package/lib/lucid/sitrep.js +173 -0
  227. package/lib/plugins/loader.js +93 -0
  228. package/lib/quoxon/activity.js +104 -0
  229. package/lib/quoxon/api.js +473 -0
  230. package/lib/quoxon/app.js +1262 -0
  231. package/lib/quoxon/capabilities.js +75 -0
  232. package/lib/quoxon/commands.js +154 -0
  233. package/lib/quoxon/connect.js +467 -0
  234. package/lib/quoxon/connectCard.js +28 -0
  235. package/lib/quoxon/context.js +68 -0
  236. package/lib/quoxon/copy.js +33 -0
  237. package/lib/quoxon/demo.fixtures.js +24 -0
  238. package/lib/quoxon/demo.js +35 -0
  239. package/lib/quoxon/egg.js +36 -0
  240. package/lib/quoxon/events.js +458 -0
  241. package/lib/quoxon/gallery.js +223 -0
  242. package/lib/quoxon/indicator.js +193 -0
  243. package/lib/quoxon/intent.js +41 -0
  244. package/lib/quoxon/keys.js +121 -0
  245. package/lib/quoxon/main.js +244 -0
  246. package/lib/quoxon/markdown.js +317 -0
  247. package/lib/quoxon/model.js +205 -0
  248. package/lib/quoxon/motion/clock.js +69 -0
  249. package/lib/quoxon/motion/color.js +35 -0
  250. package/lib/quoxon/motion/frame.js +14 -0
  251. package/lib/quoxon/motion/reveal.js +54 -0
  252. package/lib/quoxon/motion/ring.js +79 -0
  253. package/lib/quoxon/objects/agent.js +61 -0
  254. package/lib/quoxon/objects/crystal.js +100 -0
  255. package/lib/quoxon/objects/fetch.js +170 -0
  256. package/lib/quoxon/objects/index.js +85 -0
  257. package/lib/quoxon/objects/ladder.js +71 -0
  258. package/lib/quoxon/objects/memory.js +44 -0
  259. package/lib/quoxon/objects/model.js +118 -0
  260. package/lib/quoxon/objects/proof.js +110 -0
  261. package/lib/quoxon/objects/skill.js +105 -0
  262. package/lib/quoxon/objects/view.js +76 -0
  263. package/lib/quoxon/objects/workflow.js +119 -0
  264. package/lib/quoxon/observers.js +42 -0
  265. package/lib/quoxon/onboarding/copy.js +235 -0
  266. package/lib/quoxon/onboarding/credential.js +95 -0
  267. package/lib/quoxon/onboarding/detect.js +22 -0
  268. package/lib/quoxon/onboarding/finish.js +119 -0
  269. package/lib/quoxon/onboarding/index.js +67 -0
  270. package/lib/quoxon/onboarding/installRunner.js +225 -0
  271. package/lib/quoxon/onboarding/intent.js +53 -0
  272. package/lib/quoxon/onboarding/journey.js +73 -0
  273. package/lib/quoxon/onboarding/preflight.js +142 -0
  274. package/lib/quoxon/onboarding/runner.js +58 -0
  275. package/lib/quoxon/onboarding/view.js +625 -0
  276. package/lib/quoxon/print.js +94 -0
  277. package/lib/quoxon/qart.js +379 -0
  278. package/lib/quoxon/qglyph.js +143 -0
  279. package/lib/quoxon/qhello.js +58 -0
  280. package/lib/quoxon/qmotion.js +111 -0
  281. package/lib/quoxon/render.js +648 -0
  282. package/lib/quoxon/roster.js +221 -0
  283. package/lib/quoxon/route.js +38 -0
  284. package/lib/quoxon/rules.js +130 -0
  285. package/lib/quoxon/session.js +68 -0
  286. package/lib/quoxon/skills.js +30 -0
  287. package/lib/quoxon/slash/compact.js +90 -0
  288. package/lib/quoxon/slash/ledger.js +83 -0
  289. package/lib/quoxon/slash/listView.js +28 -0
  290. package/lib/quoxon/slash/palette.js +104 -0
  291. package/lib/quoxon/slash/paletteController.js +59 -0
  292. package/lib/quoxon/slash/panels.js +101 -0
  293. package/lib/quoxon/slash/picker.js +38 -0
  294. package/lib/quoxon/slash/restart.js +144 -0
  295. package/lib/quoxon/slash/resume.js +59 -0
  296. package/lib/quoxon/slash/settings.js +50 -0
  297. package/lib/quoxon/sound/index.js +186 -0
  298. package/lib/quoxon/sound/mapping.js +119 -0
  299. package/lib/quoxon/sound/output.js +52 -0
  300. package/lib/quoxon/sound/synth.js +122 -0
  301. package/lib/quoxon/term.js +106 -0
  302. package/lib/quoxon/textBuffer.js +242 -0
  303. package/lib/quoxon/theme.js +253 -0
  304. package/lib/quoxon/transcript.js +150 -0
  305. package/lib/quoxon/web/qface.js +81 -0
  306. package/lib/quoxon/welcome.js +52 -0
  307. package/lib/tui/app.jsx +289 -0
  308. package/lib/tui/components/Breadcrumb.jsx +42 -0
  309. package/lib/tui/components/ChatInput.jsx +68 -0
  310. package/lib/tui/components/Confirm.jsx +32 -0
  311. package/lib/tui/components/DataTable.jsx +270 -0
  312. package/lib/tui/components/DetailPanel.jsx +241 -0
  313. package/lib/tui/components/HelpOverlay.jsx +67 -0
  314. package/lib/tui/components/Layout.jsx +129 -0
  315. package/lib/tui/components/Palette.jsx +141 -0
  316. package/lib/tui/components/SearchInput.jsx +125 -0
  317. package/lib/tui/components/Sparkline.jsx +55 -0
  318. package/lib/tui/components/StatusBar.jsx +133 -0
  319. package/lib/tui/components/Toast.jsx +52 -0
  320. package/lib/tui/hooks/useApi.js +44 -0
  321. package/lib/tui/hooks/useHealth.js +90 -0
  322. package/lib/tui/hooks/usePolledApi.js +86 -0
  323. package/lib/tui/hooks/useTerminalSize.js +46 -0
  324. package/lib/tui/index.js +56 -0
  325. package/lib/tui/intro/Intro.jsx +332 -0
  326. package/lib/tui/jsx-loader.js +32 -0
  327. package/lib/tui/keys.js +87 -0
  328. package/lib/tui/registry.js +49 -0
  329. package/lib/tui/theme.js +103 -0
  330. package/lib/tui/views/AdminView.jsx +398 -0
  331. package/lib/tui/views/AgentView.jsx +204 -0
  332. package/lib/tui/views/BackupView.jsx +225 -0
  333. package/lib/tui/views/BrainView.jsx +223 -0
  334. package/lib/tui/views/ChatView.jsx +468 -0
  335. package/lib/tui/views/FilesView.jsx +218 -0
  336. package/lib/tui/views/FleetView.jsx +234 -0
  337. package/lib/tui/views/GovernanceView.jsx +453 -0
  338. package/lib/tui/views/HealthView.jsx +216 -0
  339. package/lib/tui/views/InboxView.jsx +228 -0
  340. package/lib/tui/views/LucidDeck.jsx +727 -0
  341. package/lib/tui/views/MainMenu.jsx +123 -0
  342. package/lib/tui/views/MemoryView.jsx +377 -0
  343. package/lib/tui/views/ObjectivesView.jsx +230 -0
  344. package/lib/tui/views/OrgView.jsx +229 -0
  345. package/lib/tui/views/ToolView.jsx +221 -0
  346. package/lib/tui/views/VaultView.jsx +422 -0
  347. package/lib/tui/views/WorkflowView.jsx +329 -0
  348. package/package.json +72 -4
@@ -0,0 +1,284 @@
1
+ /**
2
+ * Memory commands: CRUD, search, stats, export, batch
3
+ *
4
+ * FINDING F5 (SEER first-test, QuoxIdentity): `memory search` used to hit
5
+ * the memory service DIRECTLY at :3103 (fragile cert/port, and a different
6
+ * code path from everything else). It now routes through the collector's
7
+ * governed POST /api/v1/tools/execute (tool_name memory_search), matching
8
+ * how nucleus.js and fleet.js already call that endpoint, so the op is
9
+ * org-scoped and audited exactly like every other tool call.
10
+ *
11
+ * `list` and `create` stay on the direct memory-service path: the collector
12
+ * only exposes memory_save/memory_search/memory_update/entity_note as
13
+ * governed tools (services/collector/lib/agentTools.js MEMORY_TOOLS): there
14
+ * is no memory_list tool, and memory_search itself 400s without a non-empty
15
+ * `q` (services/memory/server.js), so it cannot stand in for an unfiltered
16
+ * list. memory_save's type enum (fact/preference/decision/constraint/
17
+ * observation) also does not match `create`'s documented enum (which
18
+ * includes `entity`, not `constraint`), and it has no input for targeting
19
+ * an arbitrary --agent the way the direct endpoint's body.agent_id does.
20
+ * Converting either would be a silent behaviour change, not a port fix, so
21
+ * they were left as-is. See the F5 task report for the full note.
22
+ */
23
+
24
+ import { formatOutput, formatDetail, printSuccess } from '../core/output.js';
25
+ import { resolveEndpoint } from '../api/endpoints.js';
26
+ import { QuoxError } from '../core/errors.js';
27
+ import { resolveOrgId } from './helpers.js';
28
+ import { resolveMyAttach } from './agentAttach.js';
29
+
30
+ // QUOXIDENTITY P9: which agent this session acts as is resolved session-scoped
31
+ // (QUOX_T subtree / QUOX_ATTACH_AGENT override / single-attach fallback), so
32
+ // two sessions on one box no longer collide. See agentAttach.js resolveMyAttach.
33
+ const detectSoleAttachLease = resolveMyAttach;
34
+
35
+ /**
36
+ * Call a governed collector memory tool (POST /api/v1/tools/execute).
37
+ * Lease-aware: when exactly one attach lease is active, the call is made
38
+ * AS that agent (its attach token, no caller org_id override) so the op is
39
+ * witnessed under the agent's own identity and scoped server-side to its
40
+ * namespace (services/collector/lib/memoryToolHandlers.js already scopes
41
+ * memory_search to attachLeaseId's agent_id). Otherwise it runs as the
42
+ * caller's own identity, org-scoped like nucleus.js's tool calls.
43
+ */
44
+ async function callMemoryTool({ client, auth, program }, toolName, input) {
45
+ const ep = resolveEndpoint('v1.tools.execute');
46
+ const body = { tool_name: toolName, input };
47
+ const requestOptions = { service: ep.service, body };
48
+
49
+ const lease = detectSoleAttachLease();
50
+ if (lease) {
51
+ requestOptions.noAuth = true;
52
+ requestOptions.headers = { Authorization: `Bearer ${lease.token}` };
53
+ } else {
54
+ const orgId = resolveOrgId(auth, program);
55
+ if (orgId) body.org_id = orgId;
56
+ }
57
+
58
+ return client.post(ep.path, requestOptions);
59
+ }
60
+
61
+ export function registerMemoryCommands(program, ctx) {
62
+ const { client, auth } = ctx;
63
+
64
+ const memory = program
65
+ .command('memory')
66
+ .description('Manage memories');
67
+
68
+ memory
69
+ .command('list')
70
+ .description('List memories')
71
+ .option('--type <type>', 'filter by type: fact, preference, decision, entity, observation')
72
+ .option('--limit <n>', 'max results', '50')
73
+ .option('--agent <agentId>', 'filter by agent')
74
+ .action(async (options) => {
75
+ auth.requireAuth();
76
+ const query = { limit: options.limit };
77
+ if (options.type) query.type = options.type;
78
+ if (options.agent) query.agent_id = options.agent;
79
+ const data = await client.get(resolveEndpoint('memory.list').path, { service: resolveEndpoint('memory.list').service, query });
80
+ formatOutput({
81
+ columns: ['id', 'type', 'content', 'tags', 'created_at'],
82
+ headers: ['ID', 'Type', 'Content', 'Tags', 'Created'],
83
+ rows: (data.memories || data).map(m => ({
84
+ ...m,
85
+ // fleet #373: the service stores/returns `memory_type`; this table
86
+ // read `type` and so rendered "-" for every row even though
87
+ // `--json` showed the value correctly.
88
+ type: m.memory_type ?? m.type,
89
+ content: (m.content || '').slice(0, 80),
90
+ tags: Array.isArray(m.tags) ? m.tags.join(', ') : m.tags,
91
+ })),
92
+ }, { format: program.opts().output });
93
+ });
94
+
95
+ memory
96
+ .command('get')
97
+ .description('Get memory details')
98
+ .argument('<id>', 'memory ID')
99
+ .action(async (id) => {
100
+ auth.requireAuth();
101
+ const data = await client.get(resolveEndpoint('memory.get', { id }).path, { service: resolveEndpoint('memory.get', { id }).service });
102
+ formatDetail(data.memory || data, { format: program.opts().output });
103
+ });
104
+
105
+ // Codex cycle 4 #10: how beliefs changed, and undoing a wrong correction.
106
+ memory
107
+ .command('timeline')
108
+ .description('Decisions that changed over time (newest change first)')
109
+ .argument('[query]', 'only chains mentioning this text')
110
+ .option('--limit <n>', 'max decisions', '20')
111
+ .action(async (query, options) => {
112
+ auth.requireAuth();
113
+ const ep = resolveEndpoint('memory.timeline');
114
+ const data = await client.get(ep.path, { service: ep.service, query: { q: query || '', limit: options.limit } });
115
+ const decisions = data.decisions || [];
116
+ formatOutput({
117
+ columns: ['id', 'changes', 'last_change', 'now', 'was'],
118
+ headers: ['Current ID', 'Changes', 'Last change', 'Now', 'Was'],
119
+ rows: decisions.map((d) => ({
120
+ id: d.current.id,
121
+ changes: d.changes,
122
+ last_change: d.last_change || '-',
123
+ now: (d.current.content || '').slice(0, 70),
124
+ was: (d.history[d.history.length - 2]?.content || '').slice(0, 70),
125
+ })),
126
+ }, { format: program.opts().output, raw: data });
127
+ });
128
+
129
+ memory
130
+ .command('history')
131
+ .description('Full change history of one belief, oldest first, with reasons')
132
+ .argument('<id>', 'memory ID (any version in the chain)')
133
+ .action(async (id) => {
134
+ auth.requireAuth();
135
+ const ep = resolveEndpoint('memory.history', { id });
136
+ const data = await client.get(ep.path, { service: ep.service });
137
+ formatOutput({
138
+ columns: ['id', 'state', 'created_at', 'content', 'reason'],
139
+ headers: ['ID', 'State', 'Created', 'Content', 'Replaced because'],
140
+ rows: (data.history || []).map((m) => ({
141
+ id: m.id,
142
+ state: m.valid ? 'current' : 'replaced',
143
+ created_at: m.created_at,
144
+ content: (m.content || '').slice(0, 80),
145
+ reason: (m.superseded_reason || '').slice(0, 80),
146
+ })),
147
+ }, { format: program.opts().output, raw: data });
148
+ });
149
+
150
+ memory
151
+ .command('reinstate')
152
+ .description('Undo a wrong correction: make a replaced belief current again')
153
+ .argument('<id>', 'ID of the replaced belief that was right')
154
+ .action(async (id) => {
155
+ auth.requireAuth();
156
+ const ep = resolveEndpoint('memory.reinstate', { id });
157
+ const data = await client.post(ep.path, { service: ep.service, body: {} });
158
+ if (program.opts().output === 'json') { console.log(JSON.stringify(data, null, 2)); return; }
159
+ printSuccess(`Reinstated ${data.reinstated?.id}; retired ${data.retired?.id} (marked disputed, Dream will not re-apply it)`);
160
+ });
161
+
162
+ memory
163
+ .command('create')
164
+ .description('Save a new memory')
165
+ .requiredOption('--type <type>', 'memory type: fact, preference, decision, entity, observation')
166
+ .requiredOption('--content <text>', 'memory content')
167
+ .option('--tags <tags>', 'comma-separated tags')
168
+ .option('--agent <agentId>', 'agent ID')
169
+ .action(async (options) => {
170
+ auth.requireAuth();
171
+ const body = {
172
+ type: options.type,
173
+ content: options.content,
174
+ };
175
+ if (options.tags) body.tags = options.tags.split(',').map(t => t.trim());
176
+ if (options.agent) body.agent_id = options.agent;
177
+ await client.post(resolveEndpoint('memory.create').path, { service: resolveEndpoint('memory.create').service, body });
178
+ printSuccess('Memory saved.');
179
+ });
180
+
181
+ memory
182
+ .command('update')
183
+ .description('Update a memory')
184
+ .argument('<id>', 'memory ID')
185
+ .option('--content <text>', 'new content')
186
+ .option('--tags <tags>', 'new tags (comma-separated)')
187
+ .action(async (id, options) => {
188
+ auth.requireAuth();
189
+ const body = {};
190
+ if (options.content) body.content = options.content;
191
+ if (options.tags) body.tags = options.tags.split(',').map(t => t.trim());
192
+ await client.patch(resolveEndpoint('memory.update', { id }).path, { service: resolveEndpoint('memory.update', { id }).service, body });
193
+ printSuccess('Memory updated.');
194
+ });
195
+
196
+ memory
197
+ .command('delete')
198
+ .description('Delete a memory')
199
+ .argument('<id>', 'memory ID')
200
+ .option('--hard', 'permanently delete (no soft-delete)')
201
+ .action(async (id, options) => {
202
+ auth.requireAuth();
203
+ const query = {};
204
+ if (options.hard) query.hard = 'true';
205
+ await client.delete(resolveEndpoint('memory.delete', { id }).path, { service: resolveEndpoint('memory.delete', { id }).service, query });
206
+ printSuccess('Memory deleted.');
207
+ });
208
+
209
+ // ONE-BRAIN CX6: the user-facing twin of the Cortex memory_forget tool.
210
+ // Same endpoint as `delete`; confirmation is required, like `notes rm`.
211
+ memory
212
+ .command('forget')
213
+ .description('Forget one of your memories (soft delete). Requires --yes. --permanent erases it for good (irreversible).')
214
+ .argument('<id>', 'memory ID')
215
+ .option('--permanent', 'permanently erase the memory (no soft-delete); cannot be undone')
216
+ .option('--yes', 'confirm forgetting')
217
+ .action(async (id, options) => {
218
+ auth.requireAuth();
219
+ if (!options.yes) throw new QuoxError(`Refusing to ${options.permanent ? 'permanently erase' : 'forget'} memory ${id} without --yes.`, 2);
220
+ const ep = resolveEndpoint('memory.delete', { id });
221
+ const query = {};
222
+ if (options.permanent) query.hard = 'true';
223
+ await client.delete(ep.path, { service: ep.service, query });
224
+ printSuccess(options.permanent ? `Permanently erased memory ${id}.` : `Forgot memory ${id}.`);
225
+ });
226
+
227
+ memory
228
+ .command('search')
229
+ .description('Search memories')
230
+ // #620: accept a positional query as shorthand; --query still works and
231
+ // wins if both are given. One of the two is required.
232
+ .argument('[query]', 'search query (shorthand for --query)')
233
+ .option('--query <q>', 'search query')
234
+ .option('--limit <n>', 'max results', '20')
235
+ .option('--type <type>', 'filter by type')
236
+ .action(async (queryArg, options) => {
237
+ auth.requireAuth();
238
+ const query = options.query || queryArg;
239
+ if (!query) {
240
+ throw new Error('A search query is required: `quox memory search "your query"` or --query "your query".');
241
+ }
242
+ // FINDING F5: governed path (POST /api/v1/tools/execute, tool_name
243
+ // memory_search) instead of a direct GET against the memory service.
244
+ // See the file header comment for why list/create stayed direct.
245
+ const input = { query, limit: options.limit };
246
+ if (options.type) input.type_filter = options.type;
247
+ const data = await callMemoryTool({ client, auth, program }, 'memory_search', input);
248
+ formatOutput({
249
+ // The governed memory_search tool's result shape (services/collector
250
+ // /lib/memoryToolHandlers.js memorySearch) has no `rank`/`score`
251
+ // field (it drops the FTS bm25 rank), so this column shows '-'.
252
+ columns: ['id', 'type', 'content', 'rank'],
253
+ headers: ['ID', 'Type', 'Content', 'Score'],
254
+ rows: (data.results || data.memories || []).map(m => ({
255
+ ...m,
256
+ type: m.memory_type ?? m.type, // fleet #373, same as list above
257
+ content: (m.content || '').slice(0, 80),
258
+ rank: typeof m.rank === 'number' ? m.rank.toFixed(2) : (m.rank ?? '-'),
259
+ })),
260
+ }, { format: program.opts().output });
261
+ });
262
+
263
+ memory
264
+ .command('stats')
265
+ .description('Show memory statistics')
266
+ .action(async () => {
267
+ auth.requireAuth();
268
+ const data = await client.get(resolveEndpoint('memory.stats.list').path, { service: resolveEndpoint('memory.stats.list').service });
269
+ formatDetail(data.stats || data, {
270
+ format: program.opts().output,
271
+ title: 'Memory Stats',
272
+ });
273
+ });
274
+
275
+ memory
276
+ .command('export')
277
+ .description('Export all memories')
278
+ .option('--format <fmt>', 'export format', 'json')
279
+ .action(async (options) => {
280
+ auth.requireAuth();
281
+ const data = await client.get(resolveEndpoint('memory.export.list').path, { service: resolveEndpoint('memory.export.list').service, query: { format: options.format } });
282
+ console.log(JSON.stringify(data, null, 2));
283
+ });
284
+ }