enigma-memory 0.1.18 → 0.1.22

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 (276) hide show
  1. package/README.md +76 -24
  2. package/apps/cli/bin/enigma-desktop.mjs +140 -0
  3. package/apps/cli/bin/enigma-terminal.mjs +78 -0
  4. package/apps/cli/bin/enigma.mjs +1923 -285
  5. package/apps/desktop/electron-main.cjs +217 -0
  6. package/apps/desktop/package.json +12 -0
  7. package/apps/desktop/src/app.js +264 -7
  8. package/apps/desktop/src/index.html +3514 -1373
  9. package/apps/desktop/src/launch-electron.mjs +51 -0
  10. package/apps/desktop/src/server.mjs +2914 -0
  11. package/apps/desktop/src/styles.css +2972 -260
  12. package/apps/desktop/src/zk-browser-prove.mjs +53 -0
  13. package/apps/desktop/src/zk-state.mjs +1789 -0
  14. package/apps/gateway/bin/enigma-gateway.mjs +102 -5
  15. package/apps/gateway/src/server.mjs +271 -8
  16. package/apps/ios/EnigmaCore/Package.swift +12 -0
  17. package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
  18. package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
  19. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
  20. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
  21. package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
  22. package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
  23. package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
  24. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
  25. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
  26. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
  27. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
  28. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
  29. package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
  30. package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
  31. package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
  32. package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
  33. package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
  34. package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
  35. package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
  36. package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
  37. package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
  38. package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
  39. package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
  40. package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
  41. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
  42. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
  43. package/apps/native-host/README.md +19 -8
  44. package/apps/native-host/bin/enigma-native-host.mjs +229 -13
  45. package/apps/relay/bin/enigma-relay.mjs +103 -5
  46. package/apps/relay/src/federation-runtime.mjs +618 -0
  47. package/apps/relay/src/server.mjs +310 -9
  48. package/apps/verifier/bin/enigma-verify.mjs +327 -11
  49. package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
  50. package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
  51. package/cortex-v3/circuits/build/vk_bytes.json +32 -0
  52. package/cortex-v3/proving-assets.json +64 -0
  53. package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
  54. package/cortex-v3/zk/action-transition-vk.json +119 -0
  55. package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
  56. package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
  57. package/cortex-v3/zk/intent-witness.mjs +365 -0
  58. package/cortex-v3/zk/intent-witness.test.mjs +485 -0
  59. package/cortex-v3/zk/proving-assets.mjs +203 -0
  60. package/cortex-v3/zk/sale-witness.mjs +783 -0
  61. package/cortex-v3/zk/sale-witness.test.mjs +784 -0
  62. package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
  63. package/cortex-v3/zk/settlement-evidence.mjs +722 -0
  64. package/cortex-v3/zk/setup-intent.mjs +688 -0
  65. package/cortex-v3/zk/setup-sale.mjs +666 -0
  66. package/cortex-v3/zk/setup.mjs +594 -0
  67. package/cortex-v3/zk/witness.mjs +184 -0
  68. package/cortex-v3/zk/zk-codec.mjs +232 -0
  69. package/cortex-v3/zk/zk-codec.test.mjs +293 -0
  70. package/cortex-v3/zk/zk-settle.mjs +370 -0
  71. package/cortex-v3/zk/zk-tree.mjs +256 -0
  72. package/cortex-v3/zk/zk-tree.test.mjs +419 -0
  73. package/deploy/docker-compose.local-production-simulation.yml +36 -0
  74. package/docs/browser-extension-install.md +8 -6
  75. package/docs/client-connectors.md +15 -11
  76. package/docs/developer-ecosystem.md +15 -13
  77. package/docs/enigma-memory-ready-conformance.md +11 -9
  78. package/docs/install-anywhere.md +61 -28
  79. package/docs/installers-and-desktop.md +8 -7
  80. package/docs/novelty-invention-candidates.md +161 -161
  81. package/docs/proof-network-claim-boundaries.md +320 -318
  82. package/examples/01-quickstart-agent/index.mjs +49 -0
  83. package/examples/01_agent_memory_quickstart.mjs +57 -0
  84. package/examples/02-multi-agent-swarm/index.mjs +57 -0
  85. package/examples/02_cross_model_passport.mjs +64 -0
  86. package/examples/03-langchain-memory/index.mjs +41 -0
  87. package/examples/03_poseidon_commitment_verification.mjs +71 -0
  88. package/examples/04-python-trading-agent/trader.py +49 -0
  89. package/examples/README.md +27 -0
  90. package/examples/ci/github-actions.yml +7 -2
  91. package/package.json +142 -11
  92. package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
  93. package/packages/connectors/src/index.js +196 -4
  94. package/packages/connectors/swarm-router.mjs +168 -0
  95. package/packages/core/src/index.js +248 -1
  96. package/packages/core/src/version.mjs +7 -0
  97. package/packages/dev-tools/package.json +19 -0
  98. package/packages/dev-tools/src/index.js +4 -0
  99. package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
  100. package/packages/dev-tools/src/swarm-simulator.js +101 -0
  101. package/packages/dev-tools/src/vault-inspector.js +114 -0
  102. package/packages/dev-tools/src/vector-benchmark.js +100 -0
  103. package/packages/developer-platform/src/access-credentials.js +341 -0
  104. package/packages/developer-platform/src/http.js +132 -0
  105. package/packages/developer-platform/src/index.js +4 -0
  106. package/packages/developer-platform/src/usage-http.js +60 -0
  107. package/packages/developer-platform/src/usage.js +295 -0
  108. package/packages/enclave-runtime/attestation.mjs +159 -0
  109. package/packages/enclave-runtime/index.mjs +47 -0
  110. package/packages/enclave-runtime/session-manager.mjs +253 -0
  111. package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
  112. package/packages/enigma-reflex/package.json +14 -0
  113. package/packages/enigma-reflex/src/index.js +204 -0
  114. package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
  115. package/packages/enigma-reflex/training/requirements.txt +8 -0
  116. package/packages/enigma-reflex/training/train.py +314 -0
  117. package/packages/enigma-weave/LICENSE +22 -0
  118. package/packages/enigma-weave/UPSTREAM.json +21 -0
  119. package/packages/enigma-weave/package.json +14 -0
  120. package/packages/enigma-weave/src/index.js +286 -0
  121. package/packages/hosted-cloud/src/index.js +80 -5
  122. package/packages/importers/src/index.js +432 -0
  123. package/packages/inference-runtime/src/browser.js +401 -0
  124. package/packages/inference-runtime/src/chat.js +265 -0
  125. package/packages/inference-runtime/src/code.js +407 -0
  126. package/packages/inference-runtime/src/contracts.js +162 -0
  127. package/packages/inference-runtime/src/http.js +232 -0
  128. package/packages/inference-runtime/src/image.js +186 -0
  129. package/packages/inference-runtime/src/index.js +10 -0
  130. package/packages/inference-runtime/src/model-router.js +320 -0
  131. package/packages/inference-runtime/src/platform.js +125 -0
  132. package/packages/inference-runtime/src/privacy.js +400 -0
  133. package/packages/inference-runtime/src/video.js +253 -0
  134. package/packages/mcp-server/README.md +22 -6
  135. package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
  136. package/packages/mcp-server/src/index.js +1418 -105
  137. package/packages/mcp-server/src/oauth.js +561 -0
  138. package/packages/mcp-server/src/private-handoff.js +84 -0
  139. package/packages/mcp-server/src/remote-http.js +273 -0
  140. package/packages/mcp-server/src/remote-policy.js +72 -0
  141. package/packages/mcp-server/swarm-bridge.mjs +361 -0
  142. package/packages/mesh/index.d.ts +283 -0
  143. package/packages/mesh/package.json +23 -0
  144. package/packages/mesh/src/crypto.js +189 -0
  145. package/packages/mesh/src/federation-packets.js +353 -0
  146. package/packages/mesh/src/gossip.js +311 -0
  147. package/packages/mesh/src/index.js +6 -0
  148. package/packages/mesh/src/protocol.js +255 -0
  149. package/packages/mesh/src/router.js +279 -0
  150. package/packages/mesh/src/transport.js +306 -0
  151. package/packages/passport/src/index.js +426 -1
  152. package/packages/private-economy/src/credits-http.js +100 -0
  153. package/packages/private-economy/src/credits.js +447 -0
  154. package/packages/private-economy/src/index.js +5 -0
  155. package/packages/private-economy/src/payments-http.js +120 -0
  156. package/packages/private-economy/src/payments.js +509 -0
  157. package/packages/private-economy/src/x402.js +346 -0
  158. package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
  159. package/packages/rag/index.d.ts +182 -0
  160. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
  161. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
  162. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
  163. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
  164. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
  165. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
  166. package/packages/rag/package.json +27 -0
  167. package/packages/rag/src/blinded-search.js +109 -0
  168. package/packages/rag/src/bm25.js +169 -0
  169. package/packages/rag/src/embeddings.js +459 -0
  170. package/packages/rag/src/hybrid.js +76 -0
  171. package/packages/rag/src/index.js +38 -0
  172. package/packages/rag/src/reranker.js +61 -0
  173. package/packages/rag/src/research.js +107 -0
  174. package/packages/rag/src/vector-store.js +430 -0
  175. package/packages/rag/src/verify-model-artifacts.mjs +4 -0
  176. package/packages/sdk/index.d.ts +760 -0
  177. package/packages/sdk/package.json +33 -0
  178. package/packages/sdk/python/README.md +24 -0
  179. package/packages/sdk/python/enigma_sdk.py +250 -0
  180. package/packages/sdk/python/pyproject.toml +34 -0
  181. package/packages/sdk/python/requirements.txt +1 -0
  182. package/packages/sdk/python/setup.py +20 -0
  183. package/packages/sdk/src/federation/capability-grant.js +389 -0
  184. package/packages/sdk/src/federation/federation-router.js +360 -0
  185. package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
  186. package/packages/sdk/src/federation/index.js +3 -0
  187. package/packages/sdk/src/index.js +1796 -0
  188. package/packages/sdk/src/intelligence/contradiction.js +337 -0
  189. package/packages/sdk/src/intelligence/decision-engine.js +155 -0
  190. package/packages/sdk/src/intelligence/index.js +4 -0
  191. package/packages/sdk/src/intelligence/ontology.js +122 -0
  192. package/packages/sdk/src/intelligence/temporal.js +123 -0
  193. package/packages/sdk/src/market-client.js +142 -0
  194. package/packages/sdk/src/mesh-client.js +110 -0
  195. package/packages/sdk/src/middleware/index.js +3 -0
  196. package/packages/sdk/src/middleware/langchain.js +159 -0
  197. package/packages/sdk/src/middleware/llamaindex.js +101 -0
  198. package/packages/sdk/src/middleware/vercel-ai.js +112 -0
  199. package/packages/sdk/src/rag-client.js +85 -0
  200. package/packages/sdk/src/swarm-orchestrator.js +260 -0
  201. package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
  202. package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
  203. package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
  204. package/packages/snapcompact/index.d.ts +284 -0
  205. package/packages/snapcompact/package.json +25 -0
  206. package/packages/snapcompact/src/index.js +716 -0
  207. package/packages/storage/PACKAGE_CONTRACT.md +1 -1
  208. package/packages/terminal-console/animations.mjs +240 -0
  209. package/packages/terminal-console/auto-anchor.mjs +220 -0
  210. package/packages/terminal-console/banner.mjs +91 -0
  211. package/packages/terminal-console/commands.mjs +459 -0
  212. package/packages/terminal-console/delegation.mjs +152 -0
  213. package/packages/terminal-console/index.mjs +5 -0
  214. package/packages/terminal-console/outbox.mjs +143 -0
  215. package/packages/terminal-console/phantom-bridge.mjs +637 -0
  216. package/packages/terminal-console/repl.mjs +136 -0
  217. package/packages/terminal-console/signer-store.mjs +130 -0
  218. package/packages/terminal-console/solana-rpc.mjs +214 -0
  219. package/packages/terminal-console/solana-transport.mjs +189 -0
  220. package/packages/terminal-tui/dashboard.mjs +214 -0
  221. package/packages/terminal-tui/index.mjs +28 -0
  222. package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
  223. package/packages/terminal-tui/telemetry-hud.mjs +137 -0
  224. package/packages/vault/index.d.ts +449 -0
  225. package/packages/vault/package.json +27 -0
  226. package/packages/vault/src/e2ee.mjs +393 -0
  227. package/packages/vault/src/enclave.js +481 -0
  228. package/packages/vault/src/erasure.js +207 -0
  229. package/packages/vault/src/index.js +1018 -155
  230. package/packages/vault/src/persistence.js +307 -0
  231. package/packages/vault/src/poseidon.js +354 -0
  232. package/packages/vault/src/receipt.js +459 -0
  233. package/scripts/benchmark-optical-context.mjs +166 -0
  234. package/scripts/bootstrap-enigma.mjs +502 -0
  235. package/scripts/build-edge-backend-workers.mjs +20 -5
  236. package/scripts/build-goal-completion-audit.mjs +72 -25
  237. package/scripts/build-hosted-api-key-lifecycle.mjs +26 -8
  238. package/scripts/build-hosted-customer-lifecycle.mjs +20 -3
  239. package/scripts/build-hosted-probe-worker.mjs +19 -4
  240. package/scripts/build-installer-assets.mjs +41 -21
  241. package/scripts/build-operator-evidence-starter.mjs +59 -1
  242. package/scripts/build-production-backend-env-kit.mjs +2 -0
  243. package/scripts/build-production-unblocker.mjs +3 -0
  244. package/scripts/check.mjs +17 -3
  245. package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
  246. package/scripts/install-enigma-local.mjs +18 -5
  247. package/scripts/release-audit.mjs +65 -109
  248. package/scripts/release-provenance.mjs +6 -0
  249. package/scripts/run-backend-readiness-smoke.mjs +112 -10
  250. package/scripts/scan-secrets.mjs +1 -0
  251. package/scripts/simulate-production-env.mjs +7 -2
  252. package/scripts/validate-hosted-backend-live.mjs +112 -1
  253. package/specs/antibody-pack-v1.schema.json +95 -0
  254. package/specs/antigen-envelope-v1.schema.json +81 -0
  255. package/specs/boundary-manifest-v1.schema.json +35 -35
  256. package/specs/capsule-v1.schema.json +55 -55
  257. package/specs/claim-boundary-manifest-v1.schema.json +22 -22
  258. package/specs/claim-ledger-v1.schema.json +291 -0
  259. package/specs/context-passport-v1.schema.json +59 -0
  260. package/specs/deletion-tombstone-v1.schema.json +26 -26
  261. package/specs/evidence-packet-v1.schema.json +177 -0
  262. package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
  263. package/specs/immune-scan-report-v1.schema.json +112 -0
  264. package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
  265. package/specs/memory-atom-v1.schema.json +59 -0
  266. package/specs/memory-event-v1.schema.json +42 -42
  267. package/specs/passport-v1.schema.json +50 -50
  268. package/specs/proof-of-non-use-v1.schema.json +65 -0
  269. package/specs/quarantine-record-v1.schema.json +126 -0
  270. package/specs/receipt-v1.schema.json +61 -61
  271. package/specs/state-checkpoint-v1.schema.json +37 -37
  272. package/specs/trust-bundle-v1.schema.json +56 -56
  273. package/specs/trust-card-v1.schema.json +119 -0
  274. package/docs/proof-network-launch-plan.md +0 -421
  275. package/packages/metering/PACKAGE_CONTRACT.md +0 -20
  276. package/scripts/build-ai-orchestration-plan.mjs +0 -248
@@ -0,0 +1,346 @@
1
+ import EnigmaCore
2
+ import Foundation
3
+ import SwiftUI
4
+
5
+ struct CouncilOpinion: Identifiable, Sendable {
6
+ let id = UUID()
7
+ let model: String
8
+ let answer: String
9
+ let error: String?
10
+ }
11
+
12
+ @MainActor
13
+ final class AppModel: ObservableObject {
14
+ @Published var serverAddress: String
15
+ @Published var oauthIssuer: String
16
+ @Published var oauthClientID: String
17
+ @Published var oauthResource: String
18
+ @Published var isConnected = false
19
+ @Published var isBusy = false
20
+ @Published var errorMessage: String?
21
+ @Published var platform: PlatformResponse?
22
+ @Published var models: [PlatformModel] = []
23
+ @Published var selectedModel = "enigma-auto"
24
+ @Published var privacyMode: PrivacyMode = .smart
25
+ @Published var messages: [EnigmaMessage] = []
26
+ @Published var lastPrivacyReceipt: PrivacyReceipt?
27
+ @Published var imageModels: [PlatformModel] = []
28
+ @Published var videoModels: [PlatformModel] = []
29
+ @Published var councilOpinions: [CouncilOpinion] = []
30
+ @Published var generatedImages: [GeneratedImageAsset] = []
31
+ @Published var creditsVault: CreditsVault?
32
+ @Published var recoveryCodeShownOnce: String?
33
+ @Published var videoJob: VideoJob?
34
+ @Published var videoAsset: VideoAsset?
35
+ @Published var codeOutput = ""
36
+ @Published var codeSession: CodeSession?
37
+ @Published var browserSession: BrowserSession?
38
+ @Published var browserViewerOrigin: String
39
+ @Published var creditPackages: [CreditPackage] = []
40
+ @Published var usage: UsageAggregate?
41
+
42
+ private let broker = CredentialBroker()
43
+ private let privacy = PrivacyMinimizer(semanticTagger: NaturalLanguagePrivacyTagger())
44
+ private let secureStore = SecureStore()
45
+ private var client: EnigmaAPIClient?
46
+
47
+ init(defaults: UserDefaults = .standard) {
48
+ serverAddress = defaults.string(forKey: "enigma.server") ?? ""
49
+ oauthIssuer = defaults.string(forKey: "enigma.oauth.issuer") ?? ""
50
+ oauthClientID = defaults.string(forKey: "enigma.oauth.client") ?? ""
51
+ oauthResource = defaults.string(forKey: "enigma.oauth.resource") ?? ""
52
+ browserViewerOrigin = defaults.string(forKey: "enigma.browser.viewerOrigin") ?? ""
53
+ configureClient()
54
+ Task { await restoreConnection() }
55
+ }
56
+
57
+ var hasServer: Bool { client != nil }
58
+ var displayModel: String { selectedModel == "enigma-auto" ? "Auto" : selectedModel }
59
+
60
+ func configure(server: String, issuer: String, clientID: String, resource: String) {
61
+ serverAddress = server.trimmingCharacters(in: .whitespacesAndNewlines)
62
+ oauthIssuer = issuer.trimmingCharacters(in: .whitespacesAndNewlines)
63
+ oauthClientID = clientID.trimmingCharacters(in: .whitespacesAndNewlines)
64
+ oauthResource = resource.trimmingCharacters(in: .whitespacesAndNewlines)
65
+ let defaults = UserDefaults.standard
66
+ defaults.set(serverAddress, forKey: "enigma.server")
67
+ defaults.set(oauthIssuer, forKey: "enigma.oauth.issuer")
68
+ defaults.set(oauthClientID, forKey: "enigma.oauth.client")
69
+ defaults.set(oauthResource, forKey: "enigma.oauth.resource")
70
+ configureClient()
71
+ }
72
+
73
+ func connectWithOAuth() async {
74
+ guard let issuer = URL(string: oauthIssuer), let resource = URL(string: oauthResource) else {
75
+ errorMessage = "Enter the OAuth issuer and protected resource URL."
76
+ return
77
+ }
78
+ await perform {
79
+ let credential = try await OAuthClient().authorize(
80
+ issuer: issuer,
81
+ clientID: self.oauthClientID.isEmpty ? nil : self.oauthClientID,
82
+ resource: resource
83
+ )
84
+ self.oauthClientID = credential.clientID
85
+ UserDefaults.standard.set(credential.clientID, forKey: "enigma.oauth.client")
86
+ try await self.broker.save(credential)
87
+ self.isConnected = true
88
+ try await self.loadInitialData()
89
+ }
90
+ }
91
+ func setBrowserViewerOrigin(_ value: String) {
92
+ browserViewerOrigin = value.trimmingCharacters(in: .whitespacesAndNewlines)
93
+ UserDefaults.standard.set(browserViewerOrigin, forKey: "enigma.browser.viewerOrigin")
94
+ }
95
+
96
+ func connectWithToken(_ token: String) async {
97
+ let value = token.trimmingCharacters(in: .whitespacesAndNewlines)
98
+ guard !value.isEmpty else { errorMessage = "Paste a direct Enigma token."; return }
99
+ await perform {
100
+ try await self.broker.saveDirectToken(value)
101
+ self.isConnected = true
102
+ try await self.loadInitialData()
103
+ }
104
+ }
105
+
106
+ func disconnect() async {
107
+ do { try await broker.clear() } catch { errorMessage = error.localizedDescription }
108
+ isConnected = false
109
+ platform = nil
110
+ models = []
111
+ clearConversation()
112
+ }
113
+
114
+ func send(_ prompt: String) async {
115
+ let value = prompt.trimmingCharacters(in: .whitespacesAndNewlines)
116
+ guard !value.isEmpty, let client else { return }
117
+ let user = EnigmaMessage(role: .user, content: value)
118
+ messages.append(user)
119
+ isBusy = true
120
+ errorMessage = nil
121
+ let protected = privacy.minimize(messages, mode: privacyMode)
122
+ defer {
123
+ protected.dispose()
124
+ isBusy = false
125
+ }
126
+ do {
127
+ let response = try await client.complete(.init(messages: protected.messages, model: selectedModel, privacyMode: "off"))
128
+ messages.append(.init(role: .assistant, content: protected.restore(response.answer)))
129
+ lastPrivacyReceipt = protected.receipt
130
+ } catch {
131
+ errorMessage = error.localizedDescription
132
+ }
133
+ }
134
+
135
+ func runCouncil(prompt: String, modelIDs: [String]) async {
136
+ let value = prompt.trimmingCharacters(in: .whitespacesAndNewlines)
137
+ let selected = Array(Set(modelIDs.filter { !$0.isEmpty })).prefix(3)
138
+ guard !value.isEmpty, selected.count >= 2, let client else {
139
+ errorMessage = "Choose at least two distinct models."
140
+ return
141
+ }
142
+ isBusy = true
143
+ errorMessage = nil
144
+ councilOpinions = []
145
+ let privacy = self.privacy
146
+ let mode = privacyMode
147
+ councilOpinions = await withTaskGroup(of: CouncilOpinion.self, returning: [CouncilOpinion].self) { group in
148
+ for model in selected {
149
+ group.addTask {
150
+ let session = privacy.minimize([EnigmaMessage(role: .user, content: value)], mode: mode)
151
+ defer { session.dispose() }
152
+ do {
153
+ let response = try await client.complete(.init(messages: session.messages, model: model, privacyMode: "off"))
154
+ return CouncilOpinion(model: model, answer: session.restore(response.answer), error: nil)
155
+ } catch {
156
+ return CouncilOpinion(model: model, answer: "", error: error.localizedDescription)
157
+ }
158
+ }
159
+ }
160
+ var results: [CouncilOpinion] = []
161
+ for await result in group { results.append(result) }
162
+ return results.sorted { $0.model < $1.model }
163
+ }
164
+ isBusy = false
165
+ }
166
+
167
+ func generateImage(prompt: String, model: String) async {
168
+ guard let client else { return }
169
+ let value = prompt.trimmingCharacters(in: .whitespacesAndNewlines)
170
+ guard !value.isEmpty, !model.isEmpty else { errorMessage = "Choose an image model and enter a prompt."; return }
171
+ await perform {
172
+ let session = self.privacy.minimize([EnigmaMessage(role: .user, content: value)], mode: self.privacyMode)
173
+ defer { session.dispose() }
174
+ let response = try await client.generateImage(.init(prompt: session.messages[0].content, model: model))
175
+ self.generatedImages = response.assets
176
+ self.lastPrivacyReceipt = session.receipt
177
+ }
178
+ }
179
+
180
+ func createCreditsVault() async {
181
+ guard let client else { return }
182
+ await perform {
183
+ let session = try await client.createCreditsVault()
184
+ try self.secureStore.setString(session.accessToken, account: "credits-access")
185
+ self.creditsVault = session.vault
186
+ self.recoveryCodeShownOnce = session.recoveryCode
187
+ }
188
+ }
189
+
190
+ func queueVideo(prompt: String, model: String) async {
191
+ guard let client else { return }
192
+ let value = prompt.trimmingCharacters(in: .whitespacesAndNewlines)
193
+ guard !value.isEmpty, !model.isEmpty else { errorMessage = "Choose a video model and enter a prompt."; return }
194
+ await perform {
195
+ let session = self.privacy.minimize([EnigmaMessage(role: .user, content: value)], mode: self.privacyMode)
196
+ defer { session.dispose() }
197
+ self.videoJob = try await client.queueVideo(.init(prompt: session.messages[0].content, model: model))
198
+ self.videoAsset = nil
199
+ self.lastPrivacyReceipt = session.receipt
200
+ for _ in 0..<120 {
201
+ try await Task.sleep(for: .seconds(2))
202
+ guard let id = self.videoJob?.id else { return }
203
+ let result = try await client.retrieveVideo(id: id)
204
+ self.videoJob = result.job
205
+ if result.job.status == "succeeded" {
206
+ self.videoAsset = result.asset
207
+ return
208
+ }
209
+ if ["failed", "cancelled", "expired"].contains(result.job.status) { return }
210
+ }
211
+ throw EnigmaAPIError.server(status: 408, code: "video_poll_timeout", message: "Video generation is still running. Reopen this screen to poll again.")
212
+ }
213
+ }
214
+
215
+ func executeCode(_ source: String) async {
216
+ guard let client else { return }
217
+ await perform {
218
+ let session = try await client.createCodeSession()
219
+ self.codeSession = session
220
+ do {
221
+ try await client.uploadCode(sessionID: session.id, source: source)
222
+ let execution = try await client.executeCode(sessionID: session.id)
223
+ let events = try await client.codeEvents(sessionID: session.id)
224
+ self.codeOutput = events.compactMap { event in
225
+ guard event.type == "command.output", let data = event.data?.data else { return nil }
226
+ return data
227
+ }.joined()
228
+ if self.codeOutput.isEmpty { self.codeOutput = execution.ok ? "Completed without output." : "Execution failed." }
229
+ _ = try await client.burnCodeSession(id: session.id)
230
+ self.codeSession = nil
231
+ } catch {
232
+ do {
233
+ _ = try await client.burnCodeSession(id: session.id)
234
+ self.codeSession = nil
235
+ } catch let cleanupError {
236
+ self.codeOutput = "Cleanup failed. Retry is required before trusting disposal: \(cleanupError.localizedDescription)"
237
+ }
238
+ throw error
239
+ }
240
+ }
241
+ }
242
+
243
+ func startPrivateBrowser() async {
244
+ guard let client else { return }
245
+ await perform {
246
+ let created = try await client.createBrowserSession()
247
+ let connected = try await client.connectBrowserSession(id: created.id)
248
+ guard connected.privacy.privateNetworkBlocked, connected.streamUrl != nil else {
249
+ _ = try? await client.burnBrowserSession(id: created.id)
250
+ throw EnigmaAPIError.server(status: 503, code: "browser_proof_missing", message: "The browser broker did not prove network-level private-address blocking.")
251
+ }
252
+ self.browserSession = connected
253
+ }
254
+ }
255
+
256
+ func navigatePrivateBrowser(_ value: String) async {
257
+ guard let client, let id = browserSession?.id else { return }
258
+ await perform { self.browserSession = try await client.navigateBrowserSession(id: id, url: value) }
259
+ }
260
+
261
+ func burnPrivateBrowser() async {
262
+ guard let client, let id = browserSession?.id else { return }
263
+ await perform {
264
+ _ = try await client.burnBrowserSession(id: id)
265
+ self.browserSession = nil
266
+ }
267
+ }
268
+
269
+ func recoverCreditsVault(_ code: String) async {
270
+ guard let client else { return }
271
+ let value = code.trimmingCharacters(in: .whitespacesAndNewlines)
272
+ guard !value.isEmpty else { errorMessage = "Enter a recovery code."; return }
273
+ await perform {
274
+ let session = try await client.recoverCreditsVault(code: value)
275
+ try self.secureStore.setString(session.accessToken, account: "credits-access")
276
+ self.creditsVault = session.vault
277
+ self.recoveryCodeShownOnce = session.recoveryCode
278
+ }
279
+ }
280
+
281
+ func refreshCredits() async {
282
+ guard let client, let token = try? secureStore.string(account: "credits-access") else { return }
283
+ do { creditsVault = try await client.creditsStatus(accessToken: token) }
284
+ catch {
285
+ try? secureStore.remove(account: "credits-access")
286
+ creditsVault = nil
287
+ }
288
+ }
289
+
290
+ func forgetCreditsSession() {
291
+ try? secureStore.remove(account: "credits-access")
292
+ creditsVault = nil
293
+ recoveryCodeShownOnce = nil
294
+ }
295
+
296
+ func dismissRecoveryCode() { recoveryCodeShownOnce = nil }
297
+
298
+ func refreshUsage() async {
299
+ guard let client else { return }
300
+ do { usage = try await client.usage() }
301
+ catch { errorMessage = error.localizedDescription }
302
+ }
303
+
304
+ func clearConversation() {
305
+ messages.removeAll(keepingCapacity: false)
306
+ lastPrivacyReceipt = nil
307
+ }
308
+
309
+ private func configureClient() {
310
+ guard let url = URL(string: serverAddress) else { client = nil; return }
311
+ let broker = self.broker
312
+ client = try? EnigmaAPIClient(baseURL: url) { try await broker.accessToken() }
313
+ }
314
+
315
+ private func restoreConnection() async {
316
+ guard client != nil else { return }
317
+ do {
318
+ isConnected = try await broker.accessToken() != nil
319
+ if isConnected { try await loadInitialData() }
320
+ } catch {
321
+ errorMessage = error.localizedDescription
322
+ }
323
+ }
324
+
325
+ private func loadInitialData() async throws {
326
+ guard let client else { throw EnigmaAPIError.invalidBaseURL }
327
+ async let platform = client.platform()
328
+ async let models = client.models()
329
+ self.platform = try await platform
330
+ self.models = try await models
331
+ if self.platform?.capabilities.images == true { imageModels = (try? await client.imageModels()) ?? [] }
332
+ if self.platform?.capabilities.videos == true { videoModels = (try? await client.videoModels()) ?? [] }
333
+ if selectedModel != "enigma-auto" && !self.models.contains(where: { $0.id == selectedModel }) { selectedModel = "enigma-auto" }
334
+ creditPackages = (try? await client.creditPackages()) ?? []
335
+ await refreshCredits()
336
+ await refreshUsage()
337
+ }
338
+
339
+ private func perform(_ operation: () async throws -> Void) async {
340
+ isBusy = true
341
+ errorMessage = nil
342
+ defer { isBusy = false }
343
+ do { try await operation() }
344
+ catch { errorMessage = error.localizedDescription }
345
+ }
346
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "colors" : [
3
+ {
4
+ "color" : {
5
+ "color-space" : "srgb",
6
+ "components" : { "alpha" : "1.000", "blue" : "0.110", "green" : "0.300", "red" : "0.940" }
7
+ },
8
+ "idiom" : "universal"
9
+ }
10
+ ],
11
+ "info" : { "author" : "xcode", "version" : 1 }
12
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "images" : [
3
+ {
4
+ "filename" : "EnigmaAppIcon.png",
5
+ "idiom" : "universal",
6
+ "platform" : "ios",
7
+ "size" : "1024x1024"
8
+ }
9
+ ],
10
+ "info" : { "author" : "xcode", "version" : 1 }
11
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "info" : { "author" : "xcode", "version" : 1 }
3
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "colors" : [
3
+ {
4
+ "color" : {
5
+ "color-space" : "srgb",
6
+ "components" : { "alpha" : "1.000", "blue" : "0.949", "green" : "0.969", "red" : "0.976" }
7
+ },
8
+ "idiom" : "universal"
9
+ }
10
+ ],
11
+ "info" : { "author" : "xcode", "version" : 1 }
12
+ }
@@ -0,0 +1,181 @@
1
+ import EnigmaCore
2
+ import SwiftUI
3
+
4
+ struct ChatView: View {
5
+ @EnvironmentObject private var model: AppModel
6
+ @State private var prompt = ""
7
+ @State private var showPrivacyReceipt = false
8
+
9
+ var body: some View {
10
+ ScrollViewReader { proxy in
11
+ ScrollView {
12
+ LazyVStack(spacing: 0) {
13
+ if model.messages.isEmpty { emptyState }
14
+ else {
15
+ ForEach(model.messages) { message in
16
+ MessageRow(message: message)
17
+ .id(message.id)
18
+ }
19
+ }
20
+ }
21
+ .padding(.horizontal, 20)
22
+ .padding(.bottom, 130)
23
+ }
24
+ .scrollDismissesKeyboard(.interactively)
25
+ .onChange(of: model.messages.count) {
26
+ if let last = model.messages.last { withAnimation { proxy.scrollTo(last.id, anchor: .bottom) } }
27
+ }
28
+ }
29
+ .navigationTitle("new chat")
30
+ .navigationBarTitleDisplayMode(.inline)
31
+ .toolbar {
32
+ ToolbarItem(placement: .topBarLeading) {
33
+ HStack(spacing: 7) { EnigmaMark(size: 17); Text("Enigma.").font(.system(.headline, design: .serif)) }
34
+ }
35
+ ToolbarItemGroup(placement: .topBarTrailing) {
36
+ Button { showPrivacyReceipt = true } label: { Image(systemName: "checkmark.shield") }
37
+ .disabled(model.lastPrivacyReceipt == nil)
38
+ Menu {
39
+ Button("Clear local conversation", role: .destructive) { model.clearConversation() }
40
+ } label: { Image(systemName: "ellipsis") }
41
+ }
42
+ }
43
+ .safeAreaInset(edge: .bottom) { composer }
44
+ .sheet(isPresented: $showPrivacyReceipt) { PrivacyReceiptView(receipt: model.lastPrivacyReceipt) }
45
+ .enigmaCanvas()
46
+ }
47
+
48
+ private var emptyState: some View {
49
+ VStack(spacing: 0) {
50
+ Spacer(minLength: 74)
51
+ EnigmaMark(size: 28).padding(.bottom, 18)
52
+ SectionEyebrow(text: "PRIVATE AI WORKSPACE").padding(.bottom, 7)
53
+ Text("What would you like\nto work on?")
54
+ .font(.system(size: 34, weight: .medium, design: .serif))
55
+ .multilineTextAlignment(.center)
56
+ .tracking(-0.8)
57
+ Text("Enigma Auto chooses an explicit route. No training. No silent chat retention.")
58
+ .font(.footnote)
59
+ .foregroundStyle(EnigmaTheme.secondary)
60
+ .multilineTextAlignment(.center)
61
+ .padding(.top, 10)
62
+ .padding(.horizontal, 24)
63
+ VStack(spacing: 8) {
64
+ suggestion("explain e2e encryption →", prompt: "Explain end-to-end encryption and where metadata can still leak.")
65
+ suggestion("tor / i2p / mixnets →", prompt: "Compare Tor, I2P, and mixnets for private agent traffic.")
66
+ suggestion("plan from verified context →", prompt: "Draft an implementation plan grounded only in retrieved Enigma context.")
67
+ }
68
+ .padding(.top, 26)
69
+ VStack(spacing: 3) {
70
+ Text("· Conversation memory stays in this app process.")
71
+ Text("· Context leaves only when you send.")
72
+ Text("· Smart Privacy minimizes identity anchors first.")
73
+ }
74
+ .font(.caption2)
75
+ .foregroundStyle(EnigmaTheme.muted)
76
+ .padding(.top, 18)
77
+ Spacer(minLength: 70)
78
+ }
79
+ .frame(maxWidth: .infinity, minHeight: 520)
80
+ }
81
+
82
+ private func suggestion(_ label: String, prompt value: String) -> some View {
83
+ Button { prompt = value } label: {
84
+ Text(label).font(.footnote).foregroundStyle(EnigmaTheme.secondary)
85
+ .frame(maxWidth: .infinity, alignment: .leading)
86
+ .padding(.horizontal, 14).padding(.vertical, 12)
87
+ .background(.white.opacity(0.74))
88
+ .overlay(RoundedRectangle(cornerRadius: 9).stroke(EnigmaTheme.line))
89
+ }
90
+ .buttonStyle(.plain)
91
+ }
92
+
93
+ private var composer: some View {
94
+ VStack(spacing: 9) {
95
+ HStack(alignment: .bottom, spacing: 10) {
96
+ TextField("Ask anything privately…", text: $prompt, axis: .vertical)
97
+ .lineLimit(1...5)
98
+ .font(EnigmaTheme.body)
99
+ .padding(.horizontal, 12)
100
+ .padding(.vertical, 10)
101
+ Button {
102
+ let outgoing = prompt
103
+ prompt = ""
104
+ Task { await model.send(outgoing) }
105
+ } label: {
106
+ Image(systemName: "arrow.up").font(.headline.weight(.bold)).foregroundStyle(.white)
107
+ .frame(width: 38, height: 38).background(EnigmaTheme.ember).clipShape(Circle())
108
+ }
109
+ .disabled(prompt.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || model.isBusy)
110
+ .padding(5)
111
+ }
112
+ .background(.white)
113
+ .overlay(RoundedRectangle(cornerRadius: 15).stroke(EnigmaTheme.line))
114
+ .clipShape(RoundedRectangle(cornerRadius: 15))
115
+ HStack {
116
+ Menu(model.displayModel) {
117
+ Button("Auto") { model.selectedModel = "enigma-auto" }
118
+ ForEach(model.models) { route in Button(route.id) { model.selectedModel = route.id } }
119
+ }
120
+ Menu("Privacy: \(model.privacyMode.rawValue.capitalized)") {
121
+ ForEach(PrivacyMode.allCases, id: \.self) { mode in Button(mode.rawValue.capitalized) { model.privacyMode = mode } }
122
+ }
123
+ Spacer()
124
+ Text("Local conversation").font(.caption2).foregroundStyle(EnigmaTheme.muted)
125
+ }
126
+ .font(.caption)
127
+ }
128
+ .padding(.horizontal, 14)
129
+ .padding(.top, 8)
130
+ .padding(.bottom, 5)
131
+ .background(.ultraThinMaterial)
132
+ }
133
+ }
134
+
135
+ private struct MessageRow: View {
136
+ let message: EnigmaMessage
137
+
138
+ var body: some View {
139
+ HStack(alignment: .top, spacing: 12) {
140
+ Text(message.role == .user ? "YOU" : "ENIGMA")
141
+ .font(EnigmaTheme.label)
142
+ .foregroundStyle(message.role == .assistant ? EnigmaTheme.ember : EnigmaTheme.muted)
143
+ .frame(width: 54, alignment: .leading)
144
+ Text(message.content)
145
+ .font(EnigmaTheme.body)
146
+ .foregroundStyle(EnigmaTheme.ink)
147
+ .frame(maxWidth: .infinity, alignment: .leading)
148
+ .textSelection(.enabled)
149
+ }
150
+ .padding(.vertical, 18)
151
+ .overlay(alignment: .bottom) { Rectangle().fill(EnigmaTheme.line).frame(height: 0.6) }
152
+ }
153
+ }
154
+
155
+ private struct PrivacyReceiptView: View {
156
+ let receipt: PrivacyReceipt?
157
+ @Environment(\.dismiss) private var dismiss
158
+
159
+ var body: some View {
160
+ NavigationStack {
161
+ List {
162
+ if let receipt {
163
+ Section("Boundary") {
164
+ LabeledContent("Mode", value: receipt.mode.rawValue.capitalized)
165
+ LabeledContent("Input", value: "\(receipt.inputCharacters) characters")
166
+ LabeledContent("Output", value: "\(receipt.outputCharacters) characters")
167
+ LabeledContent("Reference", value: String(receipt.receiptReference.uuidString.prefix(12)) + "…")
168
+ }
169
+ Section("Actions") {
170
+ ForEach(receipt.summary, id: \.self) { item in
171
+ LabeledContent(item.category.rawValue, value: "\(item.action) × \(item.count)")
172
+ }
173
+ }
174
+ Section { Text("Receipt metadata contains no prompt, output, or deterministic prompt hash.") }
175
+ } else { Text("No protected turn yet.") }
176
+ }
177
+ .navigationTitle("Smart Privacy")
178
+ .toolbar { Button("Done") { dismiss() } }
179
+ }
180
+ }
181
+ }
@@ -0,0 +1,78 @@
1
+ import SwiftUI
2
+
3
+ struct CouncilView: View {
4
+ @EnvironmentObject private var model: AppModel
5
+ @State private var prompt = ""
6
+ @State private var seats = ["", "", ""]
7
+
8
+ var body: some View {
9
+ ScrollView {
10
+ VStack(alignment: .leading, spacing: 22) {
11
+ VStack(alignment: .leading, spacing: 8) {
12
+ SectionEyebrow(text: "MULTI-MODEL COUNCIL")
13
+ Text("Independent answers.\nOne shared brief.")
14
+ .font(EnigmaTheme.display)
15
+ .tracking(-0.8)
16
+ Text("Each seat receives the same locally minimized question. Answers remain separate; Enigma does not hide a synthesizer behind the panel.")
17
+ .font(.subheadline)
18
+ .foregroundStyle(EnigmaTheme.secondary)
19
+ }
20
+ VStack(spacing: 0) {
21
+ ForEach(0..<3, id: \.self) { index in
22
+ HStack {
23
+ Text("SEAT 0\(index + 1)").font(EnigmaTheme.label).foregroundStyle(EnigmaTheme.muted)
24
+ Spacer()
25
+ Picker("Seat \(index + 1)", selection: $seats[index]) {
26
+ Text("Choose route").tag("")
27
+ ForEach(model.models) { route in Text(route.id).tag(route.id) }
28
+ }
29
+ .labelsHidden()
30
+ }
31
+ .padding(.vertical, 14)
32
+ if index < 2 { Divider().overlay(EnigmaTheme.line) }
33
+ }
34
+ }
35
+ .enigmaSurface(padding: 16)
36
+
37
+ VStack(alignment: .leading, spacing: 10) {
38
+ Text("BRIEF").font(EnigmaTheme.label).foregroundStyle(EnigmaTheme.muted)
39
+ TextField("Place one question before the council…", text: $prompt, axis: .vertical)
40
+ .lineLimit(4...9)
41
+ .padding(12)
42
+ .background(.white)
43
+ .overlay(RoundedRectangle(cornerRadius: 9).stroke(EnigmaTheme.line))
44
+ Button("Convene council") {
45
+ Task { await model.runCouncil(prompt: prompt, modelIDs: seats) }
46
+ }
47
+ .buttonStyle(PrimaryButtonStyle())
48
+ .disabled(model.isBusy || prompt.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
49
+ }
50
+
51
+ ForEach(model.councilOpinions) { opinion in
52
+ VStack(alignment: .leading, spacing: 10) {
53
+ HStack {
54
+ Text(opinion.model).font(.subheadline.weight(.semibold))
55
+ Spacer()
56
+ Circle().fill(opinion.error == nil ? EnigmaTheme.success : .red).frame(width: 7, height: 7)
57
+ }
58
+ Text(opinion.error ?? opinion.answer)
59
+ .font(EnigmaTheme.body)
60
+ .foregroundStyle(opinion.error == nil ? EnigmaTheme.ink : .red)
61
+ .textSelection(.enabled)
62
+ }
63
+ .enigmaSurface(padding: 16)
64
+ }
65
+ }
66
+ .padding(20)
67
+ .padding(.bottom, 34)
68
+ }
69
+ .navigationTitle("Council")
70
+ .navigationBarTitleDisplayMode(.inline)
71
+ .enigmaCanvas()
72
+ .onAppear {
73
+ if seats.allSatisfy(\.isEmpty) {
74
+ for (index, route) in model.models.prefix(3).enumerated() { seats[index] = route.id }
75
+ }
76
+ }
77
+ }
78
+ }