kelmo 0.1.0__py3-none-any.whl

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 (140) hide show
  1. kelmo/__init__.py +3 -0
  2. kelmo/alerts.py +82 -0
  3. kelmo/archive_adapter.py +1348 -0
  4. kelmo/archive_admin.py +831 -0
  5. kelmo/archive_worker.py +35 -0
  6. kelmo/bootstrap.py +236 -0
  7. kelmo/broker_launcher.py +79 -0
  8. kelmo/budget.py +101 -0
  9. kelmo/cli.py +718 -0
  10. kelmo/client.py +1449 -0
  11. kelmo/config.py +567 -0
  12. kelmo/config_edit.py +68 -0
  13. kelmo/context_binding.py +229 -0
  14. kelmo/contracts.py +565 -0
  15. kelmo/conversation.py +44 -0
  16. kelmo/creation.py +554 -0
  17. kelmo/crew_executor.py +209 -0
  18. kelmo/daemon.py +470 -0
  19. kelmo/doctor.py +469 -0
  20. kelmo/dreaming.py +455 -0
  21. kelmo/dreaming_cli.py +154 -0
  22. kelmo/editor.py +1295 -0
  23. kelmo/embeddings.py +741 -0
  24. kelmo/entry.py +34 -0
  25. kelmo/errors.py +25 -0
  26. kelmo/executor.py +394 -0
  27. kelmo/fact_checks.py +173 -0
  28. kelmo/git_ingress.py +760 -0
  29. kelmo/graph.py +348 -0
  30. kelmo/hot.py +258 -0
  31. kelmo/hub_delivery.py +462 -0
  32. kelmo/hub_embed.py +271 -0
  33. kelmo/initialization.py +39 -0
  34. kelmo/install/__init__.py +0 -0
  35. kelmo/install/file_changes.py +105 -0
  36. kelmo/install/hooks.py +35 -0
  37. kelmo/install/instructions.py +192 -0
  38. kelmo/install/preview.py +128 -0
  39. kelmo/install/providers.py +56 -0
  40. kelmo/install/removal.py +185 -0
  41. kelmo/install/runtime_backup.py +30 -0
  42. kelmo/install/sandbox.py +31 -0
  43. kelmo/install/session_setup.py +110 -0
  44. kelmo/install/setup.py +677 -0
  45. kelmo/install/shared.py +95 -0
  46. kelmo/install/wizard.py +128 -0
  47. kelmo/integration.py +77 -0
  48. kelmo/interface.py +509 -0
  49. kelmo/journal.py +808 -0
  50. kelmo/knowledge_sync.py +88 -0
  51. kelmo/linux_runtime.py +121 -0
  52. kelmo/mcp.py +827 -0
  53. kelmo/mcp_proxy.py +263 -0
  54. kelmo/migration_cli.py +150 -0
  55. kelmo/migration_report.py +65 -0
  56. kelmo/model_selection.py +110 -0
  57. kelmo/model_store.py +248 -0
  58. kelmo/outcomes.py +112 -0
  59. kelmo/project_preview.py +47 -0
  60. kelmo/projects.py +498 -0
  61. kelmo/promotion.py +103 -0
  62. kelmo/publication.py +558 -0
  63. kelmo/quota.py +70 -0
  64. kelmo/resolution.py +395 -0
  65. kelmo/runtime.py +152 -0
  66. kelmo/server.py +2058 -0
  67. kelmo/server_admin.py +204 -0
  68. kelmo/service.py +1162 -0
  69. kelmo/session_control.py +116 -0
  70. kelmo/session_prompts.py +57 -0
  71. kelmo/session_review.py +227 -0
  72. kelmo/session_settings.py +60 -0
  73. kelmo/session_transcripts.py +167 -0
  74. kelmo/session_worker.py +414 -0
  75. kelmo/sessions.py +373 -0
  76. kelmo/snapshot.py +790 -0
  77. kelmo/ssh_gate.py +40 -0
  78. kelmo/state.py +297 -0
  79. kelmo/store/__init__.py +0 -0
  80. kelmo/store/config.py +52 -0
  81. kelmo/store/db.py +234 -0
  82. kelmo/store/doctor.py +162 -0
  83. kelmo/store/errors.py +49 -0
  84. kelmo/store/graph/__init__.py +0 -0
  85. kelmo/store/graph/analysis.py +135 -0
  86. kelmo/store/graph/build.py +353 -0
  87. kelmo/store/graph/index.py +17 -0
  88. kelmo/store/graph/parser.py +228 -0
  89. kelmo/store/graph/query.py +245 -0
  90. kelmo/store/graph/stats.py +22 -0
  91. kelmo/store/memory/__init__.py +0 -0
  92. kelmo/store/memory/backfill.py +224 -0
  93. kelmo/store/memory/chunk.py +500 -0
  94. kelmo/store/memory/delete.py +86 -0
  95. kelmo/store/memory/embed.py +384 -0
  96. kelmo/store/memory/get.py +89 -0
  97. kelmo/store/memory/list.py +131 -0
  98. kelmo/store/memory/reembed.py +163 -0
  99. kelmo/store/memory/search.py +587 -0
  100. kelmo/store/memory/search_log.py +208 -0
  101. kelmo/store/memory/stats.py +98 -0
  102. kelmo/store/memory/store.py +127 -0
  103. kelmo/store/memory/taxonomy.py +24 -0
  104. kelmo/store/memory/update.py +168 -0
  105. kelmo/store/schema.sql +258 -0
  106. kelmo/supersession.py +55 -0
  107. kelmo/telemetry.py +62 -0
  108. kelmo/timings.py +143 -0
  109. kelmo/visibility.py +44 -0
  110. kelmo/wiki/__init__.py +1 -0
  111. kelmo/wiki/context.py +125 -0
  112. kelmo/wiki/directory.py +14 -0
  113. kelmo/wiki/engine.py +2236 -0
  114. kelmo/wiki/file_contract.py +1537 -0
  115. kelmo/wiki/hot_views.py +287 -0
  116. kelmo/wiki/links.py +139 -0
  117. kelmo/wiki/pages.py +935 -0
  118. kelmo/wiki/policy.py +129 -0
  119. kelmo/wiki/prompts/compact.md +17 -0
  120. kelmo/wiki/prompts/conflict.md +13 -0
  121. kelmo/wiki/schemas/wiki-file-contract/3.0/page.schema.json +214 -0
  122. kelmo/wiki/schemas/wiki-file-contract/3.0/records.schema.json +575 -0
  123. kelmo/wiki/schemas/wiki-file-contract/3.0/worker-manifest.schema.json +1484 -0
  124. kelmo/wiki/views.py +173 -0
  125. kelmo-0.1.0.data/data/share/kelmo/bootstrap.py +236 -0
  126. kelmo-0.1.0.data/data/share/kelmo/config.py +567 -0
  127. kelmo-0.1.0.data/data/share/kelmo/entry.py +34 -0
  128. kelmo-0.1.0.data/data/share/kelmo/errors.py +25 -0
  129. kelmo-0.1.0.data/data/share/kelmo/gate.py +50 -0
  130. kelmo-0.1.0.data/data/share/kelmo/hot.py +258 -0
  131. kelmo-0.1.0.data/data/share/kelmo/interface.py +509 -0
  132. kelmo-0.1.0.data/data/share/kelmo/linux_runtime.py +121 -0
  133. kelmo-0.1.0.data/data/share/kelmo/model_store.py +248 -0
  134. kelmo-0.1.0.data/data/share/kelmo/runtime.py +152 -0
  135. kelmo-0.1.0.data/data/share/kelmo/session_settings.py +60 -0
  136. kelmo-0.1.0.data/scripts/kelmo +39 -0
  137. kelmo-0.1.0.dist-info/METADATA +225 -0
  138. kelmo-0.1.0.dist-info/RECORD +140 -0
  139. kelmo-0.1.0.dist-info/WHEEL +4 -0
  140. kelmo-0.1.0.dist-info/licenses/LICENSE +202 -0
kelmo/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """Shared memory service and its public CLI."""
2
+
3
+ __version__ = "0.1.0"
kelmo/alerts.py ADDED
@@ -0,0 +1,82 @@
1
+ """Tell the vault owner when the executor's provider login is lost, once a day while it stays lost, and once
2
+ when the provider answers again.
3
+
4
+ A usage limit needs no one: work waits for the reset by itself. A lost login waits for a person, so it is
5
+ the one wait that alerts. The message goes on stdin to the command named in `[alerts]`; that command owns
6
+ the channel and its secrets, so none of them reach Kelmo. A marker in the state directory holds the outage
7
+ start and the last delivered alert, so a restart neither repeats an alert nor drops one; an undelivered
8
+ alert is tried again on the next lost-login answer.
9
+ """
10
+ import json
11
+ import subprocess
12
+ import sys
13
+ import time
14
+
15
+ REMINDER_SECONDS = 86400
16
+ MARKER = 'login-outage.json'
17
+
18
+
19
+ def _when(epoch):
20
+ return time.strftime('%Y-%m-%d %H:%M UTC', time.gmtime(epoch))
21
+
22
+
23
+ class LoginWatch:
24
+ def __init__(self, marker, argv=None, label='Kelmo', timeout=30):
25
+ self.marker, self.argv, self.label, self.timeout = marker, argv, label, timeout
26
+
27
+ @classmethod
28
+ def for_service(cls, service):
29
+ settings = service.config.alerts or {}
30
+ return cls(service.config.state / MARKER, settings.get('command'), settings.get('label', 'Kelmo'))
31
+
32
+ def saw(self, wait, now=None):
33
+ """Read one checked executor answer: a QuotaWait, or None when the provider answered."""
34
+ now = time.time() if now is None else now
35
+ try:
36
+ if wait is not None and wait.reason == 'login':
37
+ self._lost(now)
38
+ elif self.marker.exists():
39
+ self._back(now)
40
+ except Exception as error: # noqa: BLE001 - Alerting must not turn a wait into a failed attempt.
41
+ print(json.dumps({'alert_delivery': 'failed', 'error': type(error).__name__}), file=sys.stderr, flush=True)
42
+
43
+ def _lost(self, now):
44
+ outage = json.loads(self.marker.read_text(encoding='utf-8')) if self.marker.exists() else None
45
+ if outage is None:
46
+ outage = {'since': now, 'alerted_at': None}
47
+ self._save(outage)
48
+ last = outage['alerted_at']
49
+ if last is not None and now - last < REMINDER_SECONDS:
50
+ return
51
+ text = (f'{self.label}: the executor login is lost since {_when(outage["since"])}. Work waits and is '
52
+ 'tried again every 15 minutes; log in on the executor account.')
53
+ if last is not None:
54
+ text += f' Day {int((now - outage["since"]) // REMINDER_SECONDS) + 1}.'
55
+ if self.send(text):
56
+ self._save({**outage, 'alerted_at': now})
57
+
58
+ def _back(self, now):
59
+ outage = json.loads(self.marker.read_text(encoding='utf-8'))
60
+ # The marker goes first: one recovery message per outage, even if its delivery fails.
61
+ self.marker.unlink()
62
+ hours = round((now - outage['since']) / 3600, 1)
63
+ self.send(f'{self.label}: the executor login works again after {hours} h; waiting work resumes.')
64
+
65
+ def _save(self, outage):
66
+ partial = self.marker.with_name(self.marker.name + '.partial')
67
+ partial.write_text(json.dumps(outage), encoding='utf-8')
68
+ partial.replace(self.marker)
69
+
70
+ def send(self, text):
71
+ """Journal line plus the configured command; True once the command accepts the message."""
72
+ print('kelmo worker: alert: ' + text, file=sys.stderr, flush=True)
73
+ if not self.argv:
74
+ return False
75
+ try:
76
+ done = subprocess.run(self.argv, input=text, text=True, capture_output=True, timeout=self.timeout)
77
+ except (OSError, subprocess.TimeoutExpired) as error:
78
+ print(json.dumps({'alert_delivery': 'failed', 'error': type(error).__name__}), file=sys.stderr, flush=True)
79
+ return False
80
+ if done.returncode != 0:
81
+ print(json.dumps({'alert_delivery': 'failed', 'exit': done.returncode}), file=sys.stderr, flush=True)
82
+ return done.returncode == 0