better-dsh 0.3.0 → 0.3.1-a

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 (76) hide show
  1. package/README.md +49 -177
  2. package/cordis.patch.yml +5 -36
  3. package/docs/20_specs/kernel-provisioning/spec.md +2 -0
  4. package/docs/adr/0015-independent-bundles-agent-remote.md +40 -0
  5. package/docs/remote-tools.md +56 -0
  6. package/docs/specs/kernel-provisioning/spec.md +12 -40
  7. package/docs/specs/omp-python-repl-port/runtime-guide.md +35 -0
  8. package/docs/specs/omp-python-repl-port/spec.md +68 -0
  9. package/docs/specs/remote-tool-enhancement/spec.md +203 -0
  10. package/dsh-docs/baseline.md +13 -0
  11. package/dsh-docs/subsystems/invariants.md +3 -0
  12. package/dsh-docs/subsystems/invariants.zh.md +3 -0
  13. package/eval-description.md +7 -3
  14. package/lib/LaunchOptions-0Mr6meJc.js +4 -0
  15. package/lib/{LaunchOptions-kGXcZOe0.js → LaunchOptions-iE9M-STS.js} +1 -1
  16. package/lib/{bidi-BalpKaJc.js → bidi-CaQeBZHY.js} +1 -1
  17. package/lib/client/index.js +30 -6
  18. package/lib/failover/index.js +1 -1
  19. package/lib/fs-aware/sandbox-plugin.js +3 -3
  20. package/lib/{index-browser-CysrjMyM.js → index-browser-CJzxT9Vi.js} +4 -4
  21. package/lib/index.d.ts +16 -50
  22. package/lib/index.js +482 -1720
  23. package/lib/kernel-env-x_WkG6Fr.js +76 -0
  24. package/lib/kernel-env.d.ts +5 -69
  25. package/lib/kernel-env.js +2 -2
  26. package/lib/{lsp-server-registry-BXvUTBY7.js → lsp-server-registry-BcdkHROD.js} +1 -1
  27. package/lib/{lsp-server-registry-CH9WNFFt.js → lsp-server-registry-D4VLs1Sm.js} +1 -1
  28. package/lib/{main-BQeFrBM1.js → main-taSMz1KX.js} +1 -1
  29. package/lib/{main-CupOhMp5.js → main-uqGqYYnA.js} +7 -5
  30. package/lib/mobile/plugin.d.ts +1 -1
  31. package/lib/omp-python/DILL-LICENSE +35 -0
  32. package/lib/omp-python/OMP-LICENSE +23 -0
  33. package/lib/omp-python/better_snapshot.py +391 -0
  34. package/lib/omp-python/better_support.py +425 -0
  35. package/lib/omp-python/dill-provenance.json +55 -0
  36. package/lib/omp-python/provenance.json +13 -0
  37. package/lib/omp-python/runner.py +2499 -0
  38. package/lib/omp-python/vendor/dill/__diff.py +234 -0
  39. package/lib/omp-python/vendor/dill/__info__.py +291 -0
  40. package/lib/omp-python/vendor/dill/__init__.py +119 -0
  41. package/lib/omp-python/vendor/dill/_dill.py +2265 -0
  42. package/lib/omp-python/vendor/dill/_objects.py +545 -0
  43. package/lib/omp-python/vendor/dill/_shims.py +193 -0
  44. package/lib/omp-python/vendor/dill/detect.py +287 -0
  45. package/lib/omp-python/vendor/dill/logger.py +285 -0
  46. package/lib/omp-python/vendor/dill/objtypes.py +24 -0
  47. package/lib/omp-python/vendor/dill/pointers.py +122 -0
  48. package/lib/omp-python/vendor/dill/session.py +612 -0
  49. package/lib/omp-python/vendor/dill/settings.py +25 -0
  50. package/lib/omp-python/vendor/dill/source.py +1025 -0
  51. package/lib/omp-python/vendor/dill/temp.py +252 -0
  52. package/lib/{puppeteer-core-CSk2PtSm.js → puppeteer-core-C-4NyOpY.js} +8 -8
  53. package/lib/remote/plugin.d.ts +459 -5
  54. package/lib/remote/plugin.js +2389 -210
  55. package/lib/url-schemes/index.d.ts +11 -11
  56. package/lib/url-schemes/index.js +11 -11
  57. package/lib/web-password.d.ts +8 -8
  58. package/lib/web-password.js +5 -1
  59. package/lib/{web-trust-Dej_RI2B.d.ts → web-trust-C_Y6o8Z2.d.ts} +11 -11
  60. package/lib/web-trust.d.ts +1 -2
  61. package/lib/welcome-notice.d.ts +5 -7
  62. package/lib/welcome-notice.js +9 -48
  63. package/lib/{wrap-T4I0nfPM.js → wrap-0VA0uFx8.js} +1 -1
  64. package/package.json +7 -24
  65. package/scripts/kernel-check.mjs +5 -0
  66. package/lib/LaunchOptions-B874eBu2.js +0 -4
  67. package/lib/bundle-delivery.d.ts +0 -20
  68. package/lib/bundle-delivery.js +0 -209
  69. package/lib/hmr.d.ts +0 -32
  70. package/lib/hmr.js +0 -49
  71. package/lib/kernel-bridge.py +0 -172
  72. package/lib/kernel-env-D8UOWeji.js +0 -195
  73. package/lib/webserver.d.ts +0 -10
  74. package/lib/webserver.js +0 -19
  75. package/scripts/kernel-provision.mjs +0 -35
  76. package/scripts/register-bundle.mjs +0 -80
@@ -0,0 +1,425 @@
1
+ """Better-owned integration around the unchanged OMP runner (see provenance.json)."""
2
+ import ast
3
+ import asyncio
4
+ import builtins
5
+ import contextvars
6
+ import json
7
+ import inspect
8
+ import os
9
+ import signal
10
+ import subprocess
11
+ import time
12
+ import sys
13
+ import threading
14
+ import urllib.request
15
+ import uuid
16
+
17
+ _RUN = contextvars.ContextVar('better_run', default=None)
18
+ _SPECS = contextvars.ContextVar('better_specs', default={})
19
+ _PENDING = {}
20
+ _LOCK = threading.Lock()
21
+ _WRITE_LOCK = threading.Lock()
22
+ _OWNED = {}
23
+ _INJECTED = {}
24
+ _STARTED = False
25
+ _WRITER = None
26
+
27
+
28
+ class HostRejected(Exception):
29
+ pass
30
+
31
+
32
+ def _deliver(reply):
33
+ with _LOCK:
34
+ item = _PENDING.get(reply.get('id'))
35
+ if item is None:
36
+ return
37
+ loop, future, run = item
38
+ if reply.get('run') != run:
39
+ return
40
+ def settle():
41
+ if not future.done():
42
+ if reply.get('ok') is True:
43
+ future.set_result(reply.get('result'))
44
+ else:
45
+ future.set_exception(HostRejected(reply.get('message') or 'host request failed'))
46
+ loop.call_soon_threadsafe(settle)
47
+
48
+
49
+ def _read_replies():
50
+ with os.fdopen(4, 'r', encoding='utf-8') as reader:
51
+ for line in reader:
52
+ try:
53
+ _deliver(json.loads(line))
54
+ except (ValueError, RuntimeError):
55
+ continue
56
+
57
+
58
+ def unsupported_input(*args, **kwargs):
59
+ raise RuntimeError('Interactive stdin is unsupported in Better Python REPL; pass input as a variable or tool argument')
60
+
61
+
62
+ def initialize(ns):
63
+ global _STARTED, _WRITER
64
+ __import__('better_snapshot') # preload pinned dill before user imports
65
+ if not _STARTED:
66
+ _OWNED.update(ns)
67
+ if not os.environ.get('BETTER_CALLBACK_URL'):
68
+ _WRITER = os.fdopen(3, 'w', encoding='utf-8', buffering=1)
69
+ threading.Thread(target=_read_replies, name='better-callback-replies', daemon=True).start()
70
+ _STARTED = True
71
+ # Do not mutate the runner's Python builtins or put internal imports in user globals.
72
+ ns['__builtins__'] = dict(vars(builtins), input=unsupported_input)
73
+ _OWNED['__builtins__'] = ns['__builtins__']
74
+ ns['__omp_with_call_site__'] = with_call_site
75
+
76
+
77
+ async def with_call_site(site_id, action, args):
78
+ """Required runner compiler seam; Better has no speculative read cache."""
79
+ result = action(args)
80
+ return await result if inspect.isawaitable(result) else result
81
+
82
+
83
+ def reset(ns, args):
84
+ """Invoke the native magic, then immediately restore Better capabilities."""
85
+ __import__('better_snapshot').clear()
86
+ sys.modules['__main__'].__dict__['__omp_magic']('reset', args)
87
+ initialize(ns)
88
+ install_bindings(ns, _SPECS.get())
89
+
90
+
91
+ class ResetAdapter(ast.NodeTransformer):
92
+ def visit_Call(self, node):
93
+ node = self.generic_visit(node)
94
+ if (isinstance(node.func, ast.Name) and node.func.id == '__omp_magic'
95
+ and len(node.args) == 2 and isinstance(node.args[0], ast.Constant)
96
+ and node.args[0].value == 'reset'):
97
+ module = ast.Call(func=ast.Name(id='__import__', ctx=ast.Load()),
98
+ args=[ast.Constant('better_support')], keywords=[])
99
+ adapted = ast.Call(func=ast.Attribute(value=module, attr='reset', ctx=ast.Load()),
100
+ args=[ast.Call(func=ast.Name(id='globals', ctx=ast.Load()), args=[], keywords=[]), node.args[1]], keywords=[])
101
+ return ast.copy_location(adapted, node)
102
+ return node
103
+
104
+
105
+ async def host_request(payload):
106
+ run = _RUN.get()
107
+ if run is None:
108
+ raise HostRejected('host callbacks are only available during an active cell')
109
+ request_id = uuid.uuid4().hex
110
+ request = dict(payload, id=request_id, run=run)
111
+ if os.environ.get('BETTER_CALLBACK_URL'):
112
+ def http_call():
113
+ req = urllib.request.Request(os.environ['BETTER_CALLBACK_URL'],
114
+ data=json.dumps(request, allow_nan=False).encode('utf-8'),
115
+ headers={'Authorization': 'Bearer ' + os.environ['BETTER_CALLBACK_TOKEN'], 'Content-Type': 'application/json'})
116
+ # Explicitly bypass consumer proxy settings for the owned loopback endpoint.
117
+ opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
118
+ with opener.open(req, timeout=30) as response:
119
+ return json.load(response)
120
+ reply = await asyncio.to_thread(http_call)
121
+ if reply.get('ok') is not True:
122
+ raise HostRejected(reply.get('message') or 'host request failed')
123
+ return reply.get('result')
124
+ loop = asyncio.get_running_loop()
125
+ future = loop.create_future()
126
+ with _LOCK:
127
+ _PENDING[request_id] = (loop, future, run)
128
+ try:
129
+ with _WRITE_LOCK:
130
+ _WRITER.write(json.dumps(request, allow_nan=False) + '\n')
131
+ _WRITER.flush()
132
+ return await future
133
+ finally:
134
+ with _LOCK:
135
+ _PENDING.pop(request_id, None)
136
+
137
+
138
+ def _error_class(name, member_property):
139
+ def init(self, message, member=None):
140
+ Exception.__init__(self, message)
141
+ if member is not None:
142
+ setattr(self, member_property, member)
143
+ return type(name, (Exception,), {'__init__': init})
144
+
145
+
146
+ def _proxy(ns, global_name, function_name, error_class, flat=False):
147
+ async def invoke(call_args):
148
+ try:
149
+ return await host_request({'type': 'binding.call', 'global': global_name, 'name': function_name, 'args': call_args})
150
+ except HostRejected as rejected:
151
+ cls = ns.get(error_class) if error_class else None
152
+ if cls is None:
153
+ raise
154
+ raise cls(str(rejected), global_name if flat else function_name) from None
155
+ if flat:
156
+ async def callable_binding(args=None, /):
157
+ return await invoke({'args': [] if args is None else [args], 'kwargs': {}})
158
+ callable_binding.__name__ = global_name
159
+ callable_binding.__qualname__ = global_name
160
+ return callable_binding
161
+ async def namespace_binding(*args, **kwargs):
162
+ if kwargs:
163
+ raise TypeError('Better binding calls do not accept keyword arguments')
164
+ return await invoke(args[0] if len(args) == 1 else list(args) if args else None)
165
+ return namespace_binding
166
+
167
+
168
+ def install_bindings(ns, spec):
169
+ for name, value in list(_INJECTED.items()):
170
+ if ns.get(name) is value:
171
+ ns.pop(name, None)
172
+ _INJECTED.clear()
173
+ classes = {}
174
+ for global_name, config in spec.items():
175
+ error = config.get('errorClass')
176
+ error_name = error['name'] if error else None
177
+ if error and error_name not in classes:
178
+ classes[error_name] = _error_class(error_name, error['memberNameProperty'])
179
+ if config.get('callable'):
180
+ value = _proxy(ns, global_name, next(iter(config['functions'])), error_name, flat=True)
181
+ else:
182
+ def holder(global_name=global_name, config=config, error_name=error_name):
183
+ class BindingHolder:
184
+ def __dir__(self):
185
+ return sorted(config['functions'])
186
+ def __getattr__(self, name):
187
+ return _proxy(ns, global_name, name, error_name)
188
+ return BindingHolder()
189
+ value = holder()
190
+ ns[global_name] = value
191
+ _INJECTED[global_name] = value
192
+ ns.update(classes)
193
+ _INJECTED.update(classes)
194
+
195
+
196
+ def complete(value, sentinel, absent=False):
197
+ envelope = {'ok': True}
198
+ if not absent and value is not None:
199
+ try:
200
+ envelope['json'] = json.dumps(value, allow_nan=False)
201
+ except (TypeError, ValueError, OverflowError):
202
+ envelope['json'] = json.dumps(repr(value))
203
+ print(sentinel + json.dumps(envelope))
204
+
205
+
206
+ def _process_tree():
207
+ """Return descendants and birth identities; no subprocess monkeypatching."""
208
+ if os.name != 'posix':
209
+ return {} # Windows limitation is explicit in the delivery report.
210
+ root = os.getpid()
211
+ if os.path.isdir('/proc/self/task'):
212
+ tree = {}
213
+ visited = {root}
214
+ pending = [root]
215
+ while pending:
216
+ parent = pending.pop()
217
+ try:
218
+ tasks = os.listdir('/proc/%d/task' % parent)
219
+ except FileNotFoundError:
220
+ continue
221
+ for task in tasks:
222
+ try:
223
+ with open('/proc/%d/task/%s/children' % (parent, task)) as stream:
224
+ children = stream.read().split()
225
+ except FileNotFoundError:
226
+ continue
227
+ for child in children:
228
+ pid = int(child)
229
+ if pid in visited:
230
+ continue
231
+ visited.add(pid)
232
+ identity = _process_identity(pid)
233
+ if identity is not None:
234
+ tree[pid] = identity[0]
235
+ pending.append(pid)
236
+ return tree
237
+ result = subprocess.run(['ps', '-axo', 'pid=,ppid=,stat=,lstart='],
238
+ capture_output=True, text=True, check=True, timeout=0.03)
239
+ rows = {}
240
+ for line in result.stdout.splitlines():
241
+ parts = line.split(None, 3)
242
+ if len(parts) == 4:
243
+ rows[int(parts[0])] = (int(parts[1]), parts[3])
244
+ if root not in rows:
245
+ raise RuntimeError('cannot inspect Python process tree')
246
+ found = {root}
247
+ changed = True
248
+ while changed:
249
+ changed = False
250
+ for pid, (parent, _) in rows.items():
251
+ if parent in found and pid not in found:
252
+ found.add(pid)
253
+ changed = True
254
+ return {pid: rows[pid][1] for pid in found if pid != root}
255
+
256
+
257
+ def _process_identity(pid):
258
+ if os.path.isdir('/proc/self/task'):
259
+ try:
260
+ with open('/proc/%d/stat' % pid) as stream:
261
+ text = stream.read()
262
+ fields = text[text.rfind(')') + 2:].split()
263
+ return fields[19], fields[0]
264
+ except FileNotFoundError:
265
+ return None
266
+ result = subprocess.run(['ps', '-p', str(pid), '-o', 'stat=,lstart='],
267
+ capture_output=True, text=True, timeout=0.02)
268
+ parts = result.stdout.strip().split(None, 1)
269
+ return (parts[1], parts[0]) if len(parts) == 2 else None
270
+
271
+
272
+ def _cancel_new_children(baseline):
273
+ if baseline is None:
274
+ raise RuntimeError('process tree baseline unavailable')
275
+ # Capture identities before parents exit/reparent; never signal a reused PID.
276
+ current = _process_tree()
277
+ owned = {pid: birth for pid, birth in current.items() if baseline.get(pid) != birth}
278
+ deadline = time.monotonic() + 0.10
279
+ term_until = time.monotonic() + 0.025
280
+ killed = set()
281
+ for pid in reversed(list(owned)):
282
+ identity = _process_identity(pid)
283
+ if identity and identity[0] == owned[pid] and identity[1] != 'Z':
284
+ try:
285
+ os.kill(pid, signal.SIGTERM)
286
+ except ProcessLookupError:
287
+ pass
288
+ while True:
289
+ # Pick up children created by a terminating descendant while its
290
+ # parent is still visible; retain identities after reparenting.
291
+ for pid, birth in _process_tree().items():
292
+ if baseline.get(pid) != birth and pid not in owned:
293
+ owned[pid] = birth
294
+ try:
295
+ os.kill(pid, signal.SIGTERM)
296
+ except ProcessLookupError:
297
+ pass
298
+ # Reap only this cell's direct children; earlier persistent children
299
+ # are left to their owners. Grandchild zombies are no longer executing.
300
+ survivors = []
301
+ for pid, birth in owned.items():
302
+ try:
303
+ os.waitpid(pid, os.WNOHANG)
304
+ except ChildProcessError:
305
+ pass
306
+ identity = _process_identity(pid)
307
+ if identity and identity[0] == birth and not identity[1].startswith('Z'):
308
+ survivors.append(pid)
309
+ if not survivors:
310
+ return
311
+ now = time.monotonic()
312
+ if now >= deadline:
313
+ raise RuntimeError('cancelled descendants did not terminate')
314
+ if now >= term_until:
315
+ for pid in survivors:
316
+ if pid not in killed:
317
+ try:
318
+ os.kill(pid, signal.SIGKILL)
319
+ except ProcessLookupError:
320
+ pass
321
+ killed.add(pid)
322
+ time.sleep(min(0.003, deadline - now))
323
+
324
+
325
+ async def run(ns, source, spec_json, sentinel):
326
+ """Retain OMP transforms/compiler/TLA execution; adapt only typed completion."""
327
+ runner = sys.modules['__main__']
328
+ initialize(ns)
329
+ spec = json.loads(spec_json)
330
+ install_bindings(ns, spec)
331
+ spec_token = _SPECS.set(spec)
332
+ token = _RUN.set(runner._CURRENT_RID.get())
333
+ baseline = None
334
+ interrupted = False
335
+ previous_handler = signal.getsignal(signal.SIGINT)
336
+ def on_interrupt(signum, frame):
337
+ nonlocal interrupted
338
+ interrupted = True
339
+ if callable(previous_handler):
340
+ return previous_handler(signum, frame)
341
+ if previous_handler != signal.SIG_IGN:
342
+ return signal.default_int_handler(signum, frame)
343
+ signal.signal(signal.SIGINT, on_interrupt)
344
+ try:
345
+ try:
346
+ baseline = _process_tree()
347
+ except (OSError, ValueError, subprocess.SubprocessError):
348
+ pass
349
+ transformed = runner.transform_cell(source)
350
+ tree = ResetAdapter().visit(ast.parse(transformed or 'pass', '<cell>', 'exec'))
351
+ # OMP owns compilation and execution. Wrapping its final expression only
352
+ # changes the display boundary to the existing lossless JSON contract.
353
+ if tree.body and isinstance(tree.body[-1], ast.Expr):
354
+ expression = tree.body[-1]
355
+ call = ast.Call(func=ast.Attribute(value=ast.Call(func=ast.Name(id='__import__', ctx=ast.Load()),
356
+ args=[ast.Constant('better_support')], keywords=[]), attr='complete', ctx=ast.Load()),
357
+ args=[expression.value, ast.Constant(sentinel)], keywords=[])
358
+ tree.body[-1] = ast.copy_location(ast.Expr(value=call), expression)
359
+ else:
360
+ tree.body.append(ast.Expr(value=ast.Call(func=ast.Attribute(value=ast.Call(func=ast.Name(id='__import__', ctx=ast.Load()),
361
+ args=[ast.Constant('better_support')], keywords=[]), attr='complete', ctx=ast.Load()),
362
+ args=[ast.Constant(None), ast.Constant(sentinel)], keywords=[ast.keyword(arg='absent', value=ast.Constant(True))])))
363
+ ast.fix_missing_locations(tree)
364
+ await runner._exec_source_async(ast.unparse(tree), ns)
365
+ except KeyboardInterrupt:
366
+ interrupted = True
367
+ raise
368
+ finally:
369
+ if interrupted:
370
+ # User code may catch KeyboardInterrupt itself. Receipt tracking
371
+ # still makes cancellation clean current foreground descendants.
372
+ # The host's confirm SIGINT cannot interrupt cleanup.
373
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
374
+ try:
375
+ _cancel_new_children(baseline)
376
+ except BaseException:
377
+ # Host observes death and sweeps group before queue admission.
378
+ os._exit(130)
379
+ signal.signal(signal.SIGINT, previous_handler)
380
+ _RUN.reset(token)
381
+ _SPECS.reset(spec_token)
382
+ # A detached Python task must not gain admission after its cell ended.
383
+ with _LOCK:
384
+ pending = [item for item in _PENDING.values() if item[2] == runner._CURRENT_RID.get()]
385
+ for loop, future, _ in pending:
386
+ if not future.done():
387
+ future.cancel()
388
+
389
+
390
+ def user_namespace(ns):
391
+ return {name: value for name, value in ns.items()
392
+ if not name.startswith('__omp_') and name not in ('__name__', '__doc__', '__builtins__')
393
+ and not (name in _OWNED and _OWNED[name] is value)
394
+ and not (name in _INJECTED and _INJECTED[name] is value)}
395
+
396
+
397
+ def query(ns, name_json, sentinel):
398
+ user = user_namespace(ns)
399
+ name = json.loads(name_json)
400
+ if name is None:
401
+ reply = {'ok': True, 'kind': 'names', 'names': sorted(user)}
402
+ elif name not in user:
403
+ reply = {'ok': True, 'kind': 'missing'}
404
+ else:
405
+ try:
406
+ reply = {'ok': True, 'kind': 'json', 'text': json.dumps(user[name], allow_nan=False)}
407
+ except (TypeError, ValueError, OverflowError):
408
+ reply = {'ok': True, 'kind': 'repr', 'text': repr(user[name])}
409
+ print(sentinel + json.dumps(reply))
410
+
411
+
412
+ def set_var(ns, name, value_json, sentinel):
413
+ ns[name] = json.loads(value_json)
414
+ print(sentinel + json.dumps({'ok': True}))
415
+
416
+
417
+ def owned_objects():
418
+ return list(_OWNED.values()) + list(_INJECTED.values())
419
+
420
+ def reserved_names():
421
+ return set(_OWNED) | set(_INJECTED)
422
+
423
+
424
+ def injected_names():
425
+ return set(_INJECTED)
@@ -0,0 +1,55 @@
1
+ {
2
+ "version": "0.4.1",
3
+ "artifact": {
4
+ "url": "https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl",
5
+ "sha256": "1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d"
6
+ },
7
+ "adaptations": "None. Runtime Python sources and BSD-3-Clause license copied unchanged from wheel; tests excluded. Better adapter lives in better_snapshot.py.",
8
+ "files": {
9
+ "vendor/dill/__diff.py": {
10
+ "sha256": "ed70aa5887a54d648b8e278e22edd7b6bd6652e8bd6019a5b4fefeb6fb6b1be4"
11
+ },
12
+ "vendor/dill/__info__.py": {
13
+ "sha256": "106836361f383613e762ad49da3e8400f8b105bde9b15c58fb9ac05b3afca6b9"
14
+ },
15
+ "vendor/dill/__init__.py": {
16
+ "sha256": "63cbac9f3a5fb1c949c53e93bd16066ab117916117a6bbf8942d992746c63366"
17
+ },
18
+ "vendor/dill/_dill.py": {
19
+ "sha256": "35d695c86cce6f94b9eda6d83747855dca20a1c1d0ad306452bbbb72ac367f03"
20
+ },
21
+ "vendor/dill/_objects.py": {
22
+ "sha256": "fd773b3aa9d97ac0e62819ad91b92b041303cc7dd3205cbfbed311b5cee5b122"
23
+ },
24
+ "vendor/dill/_shims.py": {
25
+ "sha256": "92421aee6b961c7a7db88b6935f7ea99b8413b830428f21d7b21ce2b1c76545e"
26
+ },
27
+ "vendor/dill/detect.py": {
28
+ "sha256": "55b0b234c68856e762a8cd672e61b04bec975ba33d0a47696e455aac09a726a5"
29
+ },
30
+ "vendor/dill/logger.py": {
31
+ "sha256": "675c2053c05b48011604aa2e71844762b16154baaaa934e2f811dc7ec79b8bcf"
32
+ },
33
+ "vendor/dill/objtypes.py": {
34
+ "sha256": "de10c49d14b4e34995c80de7309a74b1e222030f5269fc5bbaf1b9b45bed85f1"
35
+ },
36
+ "vendor/dill/pointers.py": {
37
+ "sha256": "cde5fc5ea94b0485bdbcbf971ff7abf475169889e56df5a362dbdae7a7939b0c"
38
+ },
39
+ "vendor/dill/session.py": {
40
+ "sha256": "f3c0c914842b03cef7dcff952a46c2ab47759722737244180ab1b170f79229e1"
41
+ },
42
+ "vendor/dill/settings.py": {
43
+ "sha256": "0d1169d900bcc6ca4f67949bdde201e9a6cfa75c0db8136d0848d9f032d8fb1e"
44
+ },
45
+ "vendor/dill/source.py": {
46
+ "sha256": "1ac9987fa6c43cb33dae2bf3d4473b1b613eb44800a1723de428aca9d7101860"
47
+ },
48
+ "vendor/dill/temp.py": {
49
+ "sha256": "785c8c8192094545607518b66b8236b597798371d25059df9b92b72d5d99f779"
50
+ },
51
+ "DILL-LICENSE": {
52
+ "sha256": "f669d63bebf765baaa0b20d8b0c1193296a7e0ea0c22c50a308b74d76ab3939c"
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "upstream": "https://github.com/can1357/oh-my-pi",
3
+ "commit": "fa5ff4a3a977a28b93d025f4cf50f046e019f18c",
4
+ "files": {
5
+ "runner.py": {
6
+ "path": "packages/coding-agent/src/eval/py/runner.py",
7
+ "sha256": "e0e660ca44193735a2de467254b050109bb23028aca71af01b9365b9ab88e974",
8
+ "modified": false
9
+ }
10
+ },
11
+ "license": "OMP-LICENSE",
12
+ "adaptation": "Better-owned better_support.py runs runner.transform_cell and runner._exec_source_async without patching either. It wraps final expression display for lossless JSON, owns bindings, stdlib callback pipes on POSIX and authenticated loopback HTTP on Windows, namespace filtering and unsupported input(). The OMP Agent prelude is neither executed nor shipped. Better supplies the compiler-required __omp_with_call_site__ forwarding helper without speculative caching, restores current bindings/input guard immediately after native reset using its own AST adapter, and uses the default cell filename to avoid synthetic user state. Better tracks per-cell descendant birth identities and SIGINT receipt, cleans new foreground descendants on cancellation with bounded TERM/KILL/reaping, and restores the prior signal handler. Prior persistent children are retained; unproven cleanup retires the runner."
13
+ }