lingxios 1.0.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.
- package/README.md +54 -0
- package/db/schema.sql +306 -0
- package/dist/src/app/artifacts.d.ts +8 -0
- package/dist/src/app/artifacts.js +114 -0
- package/dist/src/app/artifacts.js.map +1 -0
- package/dist/src/app/doctor.d.ts +22 -0
- package/dist/src/app/doctor.js +44 -0
- package/dist/src/app/doctor.js.map +1 -0
- package/dist/src/app/index.d.ts +123 -0
- package/dist/src/app/index.js +291 -0
- package/dist/src/app/index.js.map +1 -0
- package/dist/src/app/input.d.ts +22 -0
- package/dist/src/app/input.js +60 -0
- package/dist/src/app/input.js.map +1 -0
- package/dist/src/app/recover-wait.d.ts +5 -0
- package/dist/src/app/recover-wait.js +59 -0
- package/dist/src/app/recover-wait.js.map +1 -0
- package/dist/src/app/resources.d.ts +5 -0
- package/dist/src/app/resources.js +9 -0
- package/dist/src/app/resources.js.map +1 -0
- package/dist/src/app/storage.d.ts +2 -0
- package/dist/src/app/storage.js +41 -0
- package/dist/src/app/storage.js.map +1 -0
- package/dist/src/cli/doctor.d.ts +2 -0
- package/dist/src/cli/doctor.js +20 -0
- package/dist/src/cli/doctor.js.map +1 -0
- package/dist/src/cli/eval.d.ts +2 -0
- package/dist/src/cli/eval.js +44 -0
- package/dist/src/cli/eval.js.map +1 -0
- package/dist/src/config.d.ts +22 -0
- package/dist/src/config.js +56 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/context/attachments.d.ts +10 -0
- package/dist/src/context/attachments.js +18 -0
- package/dist/src/context/attachments.js.map +1 -0
- package/dist/src/context/document-text.d.ts +1 -0
- package/dist/src/context/document-text.js +29 -0
- package/dist/src/context/document-text.js.map +1 -0
- package/dist/src/context/document-worker.d.ts +1 -0
- package/dist/src/context/document-worker.js +62 -0
- package/dist/src/context/document-worker.js.map +1 -0
- package/dist/src/context/evidence.d.ts +19 -0
- package/dist/src/context/evidence.js +37 -0
- package/dist/src/context/evidence.js.map +1 -0
- package/dist/src/context/request.d.ts +21 -0
- package/dist/src/context/request.js +32 -0
- package/dist/src/context/request.js.map +1 -0
- package/dist/src/context/research-evidence.d.ts +4 -0
- package/dist/src/context/research-evidence.js +24 -0
- package/dist/src/context/research-evidence.js.map +1 -0
- package/dist/src/context/resource-checks.d.ts +7 -0
- package/dist/src/context/resource-checks.js +15 -0
- package/dist/src/context/resource-checks.js.map +1 -0
- package/dist/src/context/task-contract.d.ts +11 -0
- package/dist/src/context/task-contract.js +23 -0
- package/dist/src/context/task-contract.js.map +1 -0
- package/dist/src/context/text.d.ts +2 -0
- package/dist/src/context/text.js +7 -0
- package/dist/src/context/text.js.map +1 -0
- package/dist/src/control-plane/http-server.d.ts +22 -0
- package/dist/src/control-plane/http-server.js +196 -0
- package/dist/src/control-plane/http-server.js.map +1 -0
- package/dist/src/control-plane/memory-store.d.ts +71 -0
- package/dist/src/control-plane/memory-store.js +389 -0
- package/dist/src/control-plane/memory-store.js.map +1 -0
- package/dist/src/control-plane/pg-store.d.ts +62 -0
- package/dist/src/control-plane/pg-store.js +386 -0
- package/dist/src/control-plane/pg-store.js.map +1 -0
- package/dist/src/control-plane/service.d.ts +52 -0
- package/dist/src/control-plane/service.js +630 -0
- package/dist/src/control-plane/service.js.map +1 -0
- package/dist/src/control-plane/stores.d.ts +184 -0
- package/dist/src/control-plane/stores.js +19 -0
- package/dist/src/control-plane/stores.js.map +1 -0
- package/dist/src/errors.d.ts +66 -0
- package/dist/src/errors.js +102 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/eval/calibration.d.ts +16 -0
- package/dist/src/eval/calibration.js +28 -0
- package/dist/src/eval/calibration.js.map +1 -0
- package/dist/src/eval/index.d.ts +40 -0
- package/dist/src/eval/index.js +40 -0
- package/dist/src/eval/index.js.map +1 -0
- package/dist/src/eval/review.d.ts +20 -0
- package/dist/src/eval/review.js +49 -0
- package/dist/src/eval/review.js.map +1 -0
- package/dist/src/host/http-client.d.ts +48 -0
- package/dist/src/host/http-client.js +127 -0
- package/dist/src/host/http-client.js.map +1 -0
- package/dist/src/host/port.d.ts +26 -0
- package/dist/src/host/port.js +2 -0
- package/dist/src/host/port.js.map +1 -0
- package/dist/src/index.d.ts +17 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/integrations/lingxiloop/actions.d.ts +25 -0
- package/dist/src/integrations/lingxiloop/actions.js +77 -0
- package/dist/src/integrations/lingxiloop/actions.js.map +1 -0
- package/dist/src/integrations/lingxiloop/app.d.ts +167 -0
- package/dist/src/integrations/lingxiloop/app.js +434 -0
- package/dist/src/integrations/lingxiloop/app.js.map +1 -0
- package/dist/src/integrations/lingxiloop/approvals.d.ts +148 -0
- package/dist/src/integrations/lingxiloop/approvals.js +540 -0
- package/dist/src/integrations/lingxiloop/approvals.js.map +1 -0
- package/dist/src/integrations/lingxiloop/attachments.d.ts +8 -0
- package/dist/src/integrations/lingxiloop/attachments.js +38 -0
- package/dist/src/integrations/lingxiloop/attachments.js.map +1 -0
- package/dist/src/integrations/lingxiloop/calendar-approvals.d.ts +21 -0
- package/dist/src/integrations/lingxiloop/calendar-approvals.js +126 -0
- package/dist/src/integrations/lingxiloop/calendar-approvals.js.map +1 -0
- package/dist/src/integrations/lingxiloop/calendar-writes.d.ts +15 -0
- package/dist/src/integrations/lingxiloop/calendar-writes.js +79 -0
- package/dist/src/integrations/lingxiloop/calendar-writes.js.map +1 -0
- package/dist/src/integrations/lingxiloop/calendar.d.ts +19 -0
- package/dist/src/integrations/lingxiloop/calendar.js +43 -0
- package/dist/src/integrations/lingxiloop/calendar.js.map +1 -0
- package/dist/src/integrations/lingxiloop/canvas-events.d.ts +7 -0
- package/dist/src/integrations/lingxiloop/canvas-events.js +53 -0
- package/dist/src/integrations/lingxiloop/canvas-events.js.map +1 -0
- package/dist/src/integrations/lingxiloop/canvas-summary.d.ts +5 -0
- package/dist/src/integrations/lingxiloop/canvas-summary.js +52 -0
- package/dist/src/integrations/lingxiloop/canvas-summary.js.map +1 -0
- package/dist/src/integrations/lingxiloop/canvas-work-report.d.ts +12 -0
- package/dist/src/integrations/lingxiloop/canvas-work-report.js +120 -0
- package/dist/src/integrations/lingxiloop/canvas-work-report.js.map +1 -0
- package/dist/src/integrations/lingxiloop/canvas-work.d.ts +11 -0
- package/dist/src/integrations/lingxiloop/canvas-work.js +306 -0
- package/dist/src/integrations/lingxiloop/canvas-work.js.map +1 -0
- package/dist/src/integrations/lingxiloop/canvas.d.ts +12 -0
- package/dist/src/integrations/lingxiloop/canvas.js +79 -0
- package/dist/src/integrations/lingxiloop/canvas.js.map +1 -0
- package/dist/src/integrations/lingxiloop/chat.d.ts +11 -0
- package/dist/src/integrations/lingxiloop/chat.js +46 -0
- package/dist/src/integrations/lingxiloop/chat.js.map +1 -0
- package/dist/src/integrations/lingxiloop/document-approvals.d.ts +21 -0
- package/dist/src/integrations/lingxiloop/document-approvals.js +75 -0
- package/dist/src/integrations/lingxiloop/document-approvals.js.map +1 -0
- package/dist/src/integrations/lingxiloop/document-content.d.ts +80 -0
- package/dist/src/integrations/lingxiloop/document-content.js +195 -0
- package/dist/src/integrations/lingxiloop/document-content.js.map +1 -0
- package/dist/src/integrations/lingxiloop/document-writes.d.ts +8 -0
- package/dist/src/integrations/lingxiloop/document-writes.js +49 -0
- package/dist/src/integrations/lingxiloop/document-writes.js.map +1 -0
- package/dist/src/integrations/lingxiloop/documents.d.ts +22 -0
- package/dist/src/integrations/lingxiloop/documents.js +38 -0
- package/dist/src/integrations/lingxiloop/documents.js.map +1 -0
- package/dist/src/integrations/lingxiloop/event-outbox.d.ts +5 -0
- package/dist/src/integrations/lingxiloop/event-outbox.js +47 -0
- package/dist/src/integrations/lingxiloop/event-outbox.js.map +1 -0
- package/dist/src/integrations/lingxiloop/index.d.ts +3 -0
- package/dist/src/integrations/lingxiloop/index.js +3 -0
- package/dist/src/integrations/lingxiloop/index.js.map +1 -0
- package/dist/src/integrations/lingxiloop/learning-attempts.d.ts +13 -0
- package/dist/src/integrations/lingxiloop/learning-attempts.js +58 -0
- package/dist/src/integrations/lingxiloop/learning-attempts.js.map +1 -0
- package/dist/src/integrations/lingxiloop/learning-evaluation.d.ts +8 -0
- package/dist/src/integrations/lingxiloop/learning-evaluation.js +64 -0
- package/dist/src/integrations/lingxiloop/learning-evaluation.js.map +1 -0
- package/dist/src/integrations/lingxiloop/learning-evidence.d.ts +7 -0
- package/dist/src/integrations/lingxiloop/learning-evidence.js +88 -0
- package/dist/src/integrations/lingxiloop/learning-evidence.js.map +1 -0
- package/dist/src/integrations/lingxiloop/learning-missions.d.ts +18 -0
- package/dist/src/integrations/lingxiloop/learning-missions.js +95 -0
- package/dist/src/integrations/lingxiloop/learning-missions.js.map +1 -0
- package/dist/src/integrations/lingxiloop/learning.d.ts +22 -0
- package/dist/src/integrations/lingxiloop/learning.js +150 -0
- package/dist/src/integrations/lingxiloop/learning.js.map +1 -0
- package/dist/src/integrations/lingxiloop/memory.d.ts +14 -0
- package/dist/src/integrations/lingxiloop/memory.js +133 -0
- package/dist/src/integrations/lingxiloop/memory.js.map +1 -0
- package/dist/src/integrations/lingxiloop/polls.d.ts +9 -0
- package/dist/src/integrations/lingxiloop/polls.js +47 -0
- package/dist/src/integrations/lingxiloop/polls.js.map +1 -0
- package/dist/src/integrations/lingxiloop/presentations.d.ts +11 -0
- package/dist/src/integrations/lingxiloop/presentations.js +34 -0
- package/dist/src/integrations/lingxiloop/presentations.js.map +1 -0
- package/dist/src/integrations/lingxiloop/questionnaire.d.ts +21 -0
- package/dist/src/integrations/lingxiloop/questionnaire.js +57 -0
- package/dist/src/integrations/lingxiloop/questionnaire.js.map +1 -0
- package/dist/src/integrations/lingxiloop/research.d.ts +19 -0
- package/dist/src/integrations/lingxiloop/research.js +20 -0
- package/dist/src/integrations/lingxiloop/research.js.map +1 -0
- package/dist/src/integrations/lingxiloop/routines.d.ts +91 -0
- package/dist/src/integrations/lingxiloop/routines.js +198 -0
- package/dist/src/integrations/lingxiloop/routines.js.map +1 -0
- package/dist/src/integrations/lingxiloop/service-contracts.d.ts +1045 -0
- package/dist/src/integrations/lingxiloop/service-contracts.js +2 -0
- package/dist/src/integrations/lingxiloop/service-contracts.js.map +1 -0
- package/dist/src/integrations/lingxiloop/teacher-context.d.ts +32 -0
- package/dist/src/integrations/lingxiloop/teacher-context.js +25 -0
- package/dist/src/integrations/lingxiloop/teacher-context.js.map +1 -0
- package/dist/src/integrations/lingxiloop/teacher-digest.d.ts +13 -0
- package/dist/src/integrations/lingxiloop/teacher-digest.js +152 -0
- package/dist/src/integrations/lingxiloop/teacher-digest.js.map +1 -0
- package/dist/src/integrations/lingxiloop/teacher-preview.d.ts +22 -0
- package/dist/src/integrations/lingxiloop/teacher-preview.js +41 -0
- package/dist/src/integrations/lingxiloop/teacher-preview.js.map +1 -0
- package/dist/src/integrations/lingxiloop/teacher.d.ts +24 -0
- package/dist/src/integrations/lingxiloop/teacher.js +224 -0
- package/dist/src/integrations/lingxiloop/teacher.js.map +1 -0
- package/dist/src/kernel/manager.d.ts +52 -0
- package/dist/src/kernel/manager.js +407 -0
- package/dist/src/kernel/manager.js.map +1 -0
- package/dist/src/logging.d.ts +21 -0
- package/dist/src/logging.js +54 -0
- package/dist/src/logging.js.map +1 -0
- package/dist/src/memory/evidence.d.ts +6 -0
- package/dist/src/memory/evidence.js +43 -0
- package/dist/src/memory/evidence.js.map +1 -0
- package/dist/src/memory/processor.d.ts +3 -0
- package/dist/src/memory/processor.js +66 -0
- package/dist/src/memory/processor.js.map +1 -0
- package/dist/src/memory/semantic.d.ts +19 -0
- package/dist/src/memory/semantic.js +93 -0
- package/dist/src/memory/semantic.js.map +1 -0
- package/dist/src/memory/store.d.ts +20 -0
- package/dist/src/memory/store.js +34 -0
- package/dist/src/memory/store.js.map +1 -0
- package/dist/src/memory/synthesis.d.ts +24 -0
- package/dist/src/memory/synthesis.js +138 -0
- package/dist/src/memory/synthesis.js.map +1 -0
- package/dist/src/metrics.d.ts +43 -0
- package/dist/src/metrics.js +130 -0
- package/dist/src/metrics.js.map +1 -0
- package/dist/src/model/driver.d.ts +60 -0
- package/dist/src/model/driver.js +2 -0
- package/dist/src/model/driver.js.map +1 -0
- package/dist/src/model/embeddings.d.ts +24 -0
- package/dist/src/model/embeddings.js +97 -0
- package/dist/src/model/embeddings.js.map +1 -0
- package/dist/src/model/openai.d.ts +45 -0
- package/dist/src/model/openai.js +340 -0
- package/dist/src/model/openai.js.map +1 -0
- package/dist/src/outcome/assessment.d.ts +16 -0
- package/dist/src/outcome/assessment.js +45 -0
- package/dist/src/outcome/assessment.js.map +1 -0
- package/dist/src/outcome/content-check.d.ts +19 -0
- package/dist/src/outcome/content-check.js +44 -0
- package/dist/src/outcome/content-check.js.map +1 -0
- package/dist/src/outcome/envelope.d.ts +34 -0
- package/dist/src/outcome/envelope.js +42 -0
- package/dist/src/outcome/envelope.js.map +1 -0
- package/dist/src/protocol/constants.d.ts +25 -0
- package/dist/src/protocol/constants.js +26 -0
- package/dist/src/protocol/constants.js.map +1 -0
- package/dist/src/protocol/kernel-wire.d.ts +74 -0
- package/dist/src/protocol/kernel-wire.js +2 -0
- package/dist/src/protocol/kernel-wire.js.map +1 -0
- package/dist/src/protocol/outcome.d.ts +16 -0
- package/dist/src/protocol/outcome.js +14 -0
- package/dist/src/protocol/outcome.js.map +1 -0
- package/dist/src/protocol/types.d.ts +266 -0
- package/dist/src/protocol/types.js +19 -0
- package/dist/src/protocol/types.js.map +1 -0
- package/dist/src/research/address.d.ts +2 -0
- package/dist/src/research/address.js +32 -0
- package/dist/src/research/address.js.map +1 -0
- package/dist/src/research/fetch.d.ts +7 -0
- package/dist/src/research/fetch.js +83 -0
- package/dist/src/research/fetch.js.map +1 -0
- package/dist/src/research/index.d.ts +26 -0
- package/dist/src/research/index.js +109 -0
- package/dist/src/research/index.js.map +1 -0
- package/dist/src/runtime/compaction.d.ts +41 -0
- package/dist/src/runtime/compaction.js +86 -0
- package/dist/src/runtime/compaction.js.map +1 -0
- package/dist/src/runtime/corrections.d.ts +20 -0
- package/dist/src/runtime/corrections.js +27 -0
- package/dist/src/runtime/corrections.js.map +1 -0
- package/dist/src/runtime/policy.d.ts +42 -0
- package/dist/src/runtime/policy.js +91 -0
- package/dist/src/runtime/policy.js.map +1 -0
- package/dist/src/runtime/resource-refresh.d.ts +8 -0
- package/dist/src/runtime/resource-refresh.js +37 -0
- package/dist/src/runtime/resource-refresh.js.map +1 -0
- package/dist/src/runtime/runtime.d.ts +51 -0
- package/dist/src/runtime/runtime.js +804 -0
- package/dist/src/runtime/runtime.js.map +1 -0
- package/dist/src/runtime/tool.d.ts +13 -0
- package/dist/src/runtime/tool.js +42 -0
- package/dist/src/runtime/tool.js.map +1 -0
- package/dist/src/ui/index.d.ts +27 -0
- package/dist/src/ui/index.js +54 -0
- package/dist/src/ui/index.js.map +1 -0
- package/dist/src/versions.d.ts +9 -0
- package/dist/src/versions.js +11 -0
- package/dist/src/versions.js.map +1 -0
- package/dist/src/worker/index.d.ts +3 -0
- package/dist/src/worker/index.js +57 -0
- package/dist/src/worker/index.js.map +1 -0
- package/dist/src/worker/main.d.ts +2 -0
- package/dist/src/worker/main.js +9 -0
- package/dist/src/worker/main.js.map +1 -0
- package/dist/src/worker/worker.d.ts +45 -0
- package/dist/src/worker/worker.js +154 -0
- package/dist/src/worker/worker.js.map +1 -0
- package/kernel/runner.py +507 -0
- package/package.json +83 -0
package/kernel/runner.py
ADDED
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
"""Persistent sandboxed Python worker for the LingxiOS Agent OS (protocol 2).
|
|
2
|
+
|
|
3
|
+
One runner process serves one agent session. The transport is newline-delimited
|
|
4
|
+
JSON over stdio; every non-ASCII character is escaped so the protocol is
|
|
5
|
+
locale-independent under ``python -I``.
|
|
6
|
+
|
|
7
|
+
Design invariants:
|
|
8
|
+
|
|
9
|
+
* Product operations are never implemented here. ``host.<namespace>.<method>``
|
|
10
|
+
emits a ``host_call`` and blocks until the matching ``host_result``. The
|
|
11
|
+
parent process owns authorization, approvals, idempotency, and durable state.
|
|
12
|
+
* The capability set is supplied per execution by the manager. Nothing is
|
|
13
|
+
hardcoded; an ungranted namespace or method is not even addressable.
|
|
14
|
+
* The in-process sandbox (audit hooks, socket patching) is defense in depth
|
|
15
|
+
for *accidental* misuse. Authoritative capability enforcement happens in the
|
|
16
|
+
control plane, which validates every action against the durable grant.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import ast
|
|
22
|
+
import base64
|
|
23
|
+
import contextlib
|
|
24
|
+
import hashlib
|
|
25
|
+
import io
|
|
26
|
+
import json
|
|
27
|
+
import mimetypes
|
|
28
|
+
import os
|
|
29
|
+
import pathlib
|
|
30
|
+
import socket
|
|
31
|
+
import sys
|
|
32
|
+
import time
|
|
33
|
+
import traceback
|
|
34
|
+
import types
|
|
35
|
+
import uuid
|
|
36
|
+
from typing import Any
|
|
37
|
+
|
|
38
|
+
KERNEL_PROTOCOL_VERSION = 2
|
|
39
|
+
SDK_MODULE_NAME = "host"
|
|
40
|
+
|
|
41
|
+
MAX_STREAM_CHARS = int(os.environ.get("AGENT_OS_KERNEL_MAX_OUTPUT_CHARS", "8000"))
|
|
42
|
+
MAX_ARTIFACTS = int(os.environ.get("AGENT_OS_KERNEL_MAX_ARTIFACTS", "32"))
|
|
43
|
+
ROOT = pathlib.Path(os.environ["AGENT_OS_KERNEL_HOME"]).resolve()
|
|
44
|
+
HOMES_ROOT = pathlib.Path(os.environ.get("AGENT_OS_HOMES_ROOT", str(ROOT.parent))).resolve()
|
|
45
|
+
ALLOW_NETWORK = os.environ.get("AGENT_OS_KERNEL_ALLOW_NETWORK") == "1"
|
|
46
|
+
ROOT.mkdir(parents=True, exist_ok=True)
|
|
47
|
+
os.chdir(ROOT)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# ---------------------------------------------------------------------------
|
|
51
|
+
# Wire helpers
|
|
52
|
+
# ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
def emit(payload: dict[str, Any]) -> None:
|
|
55
|
+
sys.__stdout__.write(json.dumps(payload, ensure_ascii=True, default=str) + "\n")
|
|
56
|
+
sys.__stdout__.flush()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def read_message() -> dict[str, Any]:
|
|
60
|
+
line = sys.__stdin__.readline()
|
|
61
|
+
if not line:
|
|
62
|
+
raise EOFError()
|
|
63
|
+
value = json.loads(line)
|
|
64
|
+
if not isinstance(value, dict):
|
|
65
|
+
raise ValueError("protocol message must be a JSON object")
|
|
66
|
+
return value
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# ---------------------------------------------------------------------------
|
|
70
|
+
# Sandbox: network, filesystem, and child-process fences
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
def deny_network(*_args: Any, **_kwargs: Any) -> Any:
|
|
74
|
+
raise PermissionError(
|
|
75
|
+
"direct network access is disabled; use a granted host.<namespace> capability"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if not ALLOW_NETWORK:
|
|
80
|
+
socket.create_connection = deny_network # type: ignore[assignment]
|
|
81
|
+
socket.socket.connect = deny_network # type: ignore[assignment]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def is_within(path: pathlib.Path, parent: pathlib.Path) -> bool:
|
|
85
|
+
try:
|
|
86
|
+
path.relative_to(parent)
|
|
87
|
+
return True
|
|
88
|
+
except ValueError:
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def kernel_audit(event: str, args: tuple[Any, ...]) -> None:
|
|
93
|
+
if event == "open" and args and isinstance(args[0], (str, bytes, os.PathLike)):
|
|
94
|
+
path = pathlib.Path(os.fsdecode(args[0])).resolve()
|
|
95
|
+
mode = str(args[1]) if len(args) > 1 else "r"
|
|
96
|
+
if is_within(path, HOMES_ROOT) and not is_within(path, ROOT):
|
|
97
|
+
raise PermissionError("cross-session file access is disabled")
|
|
98
|
+
flags = args[2] if len(args) > 2 and isinstance(args[2], int) else 0
|
|
99
|
+
writing = any(flag in mode for flag in ("w", "a", "x", "+")) or flags & (os.O_WRONLY | os.O_RDWR | os.O_CREAT | os.O_TRUNC | os.O_APPEND)
|
|
100
|
+
if writing and not is_within(path, ROOT):
|
|
101
|
+
raise PermissionError("files may only be written inside this agent home")
|
|
102
|
+
if event in {"os.link", "os.symlink"}:
|
|
103
|
+
raise PermissionError("creating filesystem links is disabled in this kernel")
|
|
104
|
+
mutations = {
|
|
105
|
+
"os.remove": (1, (1,)), "os.rmdir": (1, (1,)), "os.mkdir": (1, (2,)),
|
|
106
|
+
"os.rename": (2, (2, 3)), "os.chmod": (1, (2,)), "os.chown": (1, (3,)),
|
|
107
|
+
"os.utime": (1, (3,)), "os.truncate": (1, ()),
|
|
108
|
+
}
|
|
109
|
+
if event in mutations:
|
|
110
|
+
count, descriptor_indices = mutations[event]
|
|
111
|
+
if any(len(args) > index and args[index] not in (-1, None) for index in descriptor_indices):
|
|
112
|
+
raise PermissionError("descriptor-relative filesystem mutations are disabled")
|
|
113
|
+
for target in args[:count]:
|
|
114
|
+
if not isinstance(target, (str, bytes, os.PathLike)) or not is_within(pathlib.Path(os.fsdecode(target)).resolve(), ROOT):
|
|
115
|
+
raise PermissionError("filesystem mutations must stay inside this agent home")
|
|
116
|
+
if event in {"os.system", "subprocess.Popen"}:
|
|
117
|
+
# A child process would escape the in-process audit fences, so shell
|
|
118
|
+
# effects must go through a typed host capability instead.
|
|
119
|
+
raise PermissionError("direct child processes are disabled in this kernel sandbox")
|
|
120
|
+
if event.startswith("socket.") and not ALLOW_NETWORK:
|
|
121
|
+
raise PermissionError("direct network access is disabled")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
sys.addaudithook(kernel_audit)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# ---------------------------------------------------------------------------
|
|
128
|
+
# Host bridge
|
|
129
|
+
# ---------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
class TurnDeferred(BaseException):
|
|
132
|
+
"""Stop this cell after a host requests a human or delegated wait."""
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class ApprovalPending(RuntimeError):
|
|
136
|
+
"""Raised when a host action suspended into a human approval."""
|
|
137
|
+
|
|
138
|
+
def __init__(self, approval_id: str):
|
|
139
|
+
super().__init__(f"approval pending: {approval_id}")
|
|
140
|
+
self.approval_id = approval_id
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class HostBridge:
|
|
144
|
+
def __init__(self) -> None:
|
|
145
|
+
self.execution_id = ""
|
|
146
|
+
self.run_id = ""
|
|
147
|
+
self.cell_id = ""
|
|
148
|
+
self.call_index = 0
|
|
149
|
+
self.directives: list[dict[str, Any]] = []
|
|
150
|
+
self.capabilities: dict[str, frozenset[str] | None] = {}
|
|
151
|
+
|
|
152
|
+
def begin(self, execution_id: str, context: dict[str, Any]) -> None:
|
|
153
|
+
self.execution_id = execution_id
|
|
154
|
+
self.run_id = str(context.get("runId", ""))
|
|
155
|
+
self.cell_id = str(context.get("cellId", execution_id))
|
|
156
|
+
self.call_index = 0
|
|
157
|
+
self.directives = []
|
|
158
|
+
self.capabilities = {}
|
|
159
|
+
for grant in context.get("capabilities") or []:
|
|
160
|
+
if not isinstance(grant, dict):
|
|
161
|
+
continue
|
|
162
|
+
name = grant.get("name")
|
|
163
|
+
if not isinstance(name, str) or not name.isidentifier() or name.startswith("_"):
|
|
164
|
+
continue
|
|
165
|
+
methods = grant.get("methods")
|
|
166
|
+
allowed: frozenset[str] | None = None
|
|
167
|
+
if isinstance(methods, list):
|
|
168
|
+
allowed = frozenset(m for m in methods if isinstance(m, str) and m.isidentifier())
|
|
169
|
+
self.capabilities[name] = allowed
|
|
170
|
+
|
|
171
|
+
def allows(self, namespace: str, method: str) -> bool:
|
|
172
|
+
if namespace not in self.capabilities or method.startswith("_"):
|
|
173
|
+
return False
|
|
174
|
+
allowed = self.capabilities[namespace]
|
|
175
|
+
return allowed is None or method in allowed
|
|
176
|
+
|
|
177
|
+
def call(self, action: str, args: dict[str, Any]) -> Any:
|
|
178
|
+
if any(directive.get("type") == "defer" for directive in self.directives):
|
|
179
|
+
raise TurnDeferred()
|
|
180
|
+
index = self.call_index
|
|
181
|
+
self.call_index += 1
|
|
182
|
+
request_id = str(uuid.uuid4())
|
|
183
|
+
emit({
|
|
184
|
+
"type": "host_call",
|
|
185
|
+
"id": self.execution_id,
|
|
186
|
+
"requestId": request_id,
|
|
187
|
+
"callIndex": index,
|
|
188
|
+
"action": action,
|
|
189
|
+
"args": args,
|
|
190
|
+
})
|
|
191
|
+
response = read_message()
|
|
192
|
+
if response.get("type") != "host_result" or response.get("requestId") != request_id:
|
|
193
|
+
raise RuntimeError("unexpected host bridge response")
|
|
194
|
+
approval = response.get("approval")
|
|
195
|
+
if isinstance(approval, dict) and approval.get("id"):
|
|
196
|
+
raise ApprovalPending(str(approval["id"]))
|
|
197
|
+
if not response.get("ok"):
|
|
198
|
+
raise RuntimeError(str(response.get("error") or "host action failed"))
|
|
199
|
+
if isinstance(response.get("directive"), dict):
|
|
200
|
+
self.directives.append(response["directive"])
|
|
201
|
+
if response["directive"].get("type") == "defer":
|
|
202
|
+
raise TurnDeferred()
|
|
203
|
+
return response.get("value")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
bridge = HostBridge()
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class _NamespaceModule(types.ModuleType):
|
|
210
|
+
"""`host.<namespace>` — methods resolve lazily against the current grant."""
|
|
211
|
+
|
|
212
|
+
def __init__(self, namespace: str):
|
|
213
|
+
super().__init__(f"{SDK_MODULE_NAME}.{namespace}")
|
|
214
|
+
self._namespace = namespace
|
|
215
|
+
|
|
216
|
+
def __getattr__(self, method: str) -> Any:
|
|
217
|
+
if not bridge.allows(self._namespace, method):
|
|
218
|
+
raise AttributeError(
|
|
219
|
+
f"capability '{self._namespace}.{method}' is not granted to this execution"
|
|
220
|
+
)
|
|
221
|
+
namespace = self._namespace
|
|
222
|
+
|
|
223
|
+
def invoke(**kwargs: Any) -> Any:
|
|
224
|
+
return bridge.call(f"{namespace}.{method}", kwargs)
|
|
225
|
+
|
|
226
|
+
invoke.__name__ = method
|
|
227
|
+
return invoke
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class _SdkModule(types.ModuleType):
|
|
231
|
+
"""`host` — namespaces resolve lazily against the current grant."""
|
|
232
|
+
|
|
233
|
+
def __getattr__(self, namespace: str) -> Any:
|
|
234
|
+
if namespace.startswith("_") or namespace not in bridge.capabilities:
|
|
235
|
+
raise AttributeError(
|
|
236
|
+
f"capability namespace '{namespace}' is not granted to this execution"
|
|
237
|
+
)
|
|
238
|
+
module = _NamespaceModule(namespace)
|
|
239
|
+
sys.modules[module.__name__] = module
|
|
240
|
+
return module
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
sdk = _SdkModule(SDK_MODULE_NAME)
|
|
244
|
+
sdk.__path__ = [] # mark as a package so `import host.files` resolves
|
|
245
|
+
sys.modules[SDK_MODULE_NAME] = sdk
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
# ---------------------------------------------------------------------------
|
|
249
|
+
# Cell execution engines
|
|
250
|
+
# ---------------------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
class CellOutcome:
|
|
253
|
+
def __init__(self, result: Any = None, error: BaseException | None = None):
|
|
254
|
+
self.result = result
|
|
255
|
+
self.error = error
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class BasicEngine:
|
|
259
|
+
"""Fallback engine when IPython is unavailable: exec with expression-result
|
|
260
|
+
semantics (the value of a trailing expression becomes the cell result)."""
|
|
261
|
+
|
|
262
|
+
name = "basic"
|
|
263
|
+
|
|
264
|
+
def __init__(self) -> None:
|
|
265
|
+
self.user_ns: dict[str, Any] = {"__name__": "__main__"}
|
|
266
|
+
|
|
267
|
+
def run_cell(self, code: str) -> CellOutcome:
|
|
268
|
+
try:
|
|
269
|
+
tree = ast.parse(code, mode="exec")
|
|
270
|
+
except SyntaxError as exc:
|
|
271
|
+
return CellOutcome(error=exc)
|
|
272
|
+
trailing_expr: ast.Expression | None = None
|
|
273
|
+
if tree.body and isinstance(tree.body[-1], ast.Expr):
|
|
274
|
+
trailing_expr = ast.Expression(tree.body.pop(-1).value)
|
|
275
|
+
try:
|
|
276
|
+
if tree.body:
|
|
277
|
+
exec(compile(tree, "<cell>", "exec"), self.user_ns) # noqa: S102
|
|
278
|
+
if trailing_expr is not None:
|
|
279
|
+
return CellOutcome(result=eval(compile(trailing_expr, "<cell>", "eval"), self.user_ns)) # noqa: S307
|
|
280
|
+
return CellOutcome()
|
|
281
|
+
except BaseException as exc: # cells may raise non-Exception exits
|
|
282
|
+
return CellOutcome(error=exc)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
class IPythonEngine:
|
|
286
|
+
name = "ipython"
|
|
287
|
+
|
|
288
|
+
def __init__(self, shell: Any):
|
|
289
|
+
self.shell = shell
|
|
290
|
+
self.user_ns = shell.user_ns
|
|
291
|
+
|
|
292
|
+
def run_cell(self, code: str) -> CellOutcome:
|
|
293
|
+
result = self.shell.run_cell(code, store_history=True)
|
|
294
|
+
if result.error_before_exec is not None:
|
|
295
|
+
return CellOutcome(error=result.error_before_exec)
|
|
296
|
+
if result.error_in_exec is not None:
|
|
297
|
+
return CellOutcome(error=result.error_in_exec)
|
|
298
|
+
return CellOutcome(result=result.result)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def create_engine() -> BasicEngine | IPythonEngine:
|
|
302
|
+
try:
|
|
303
|
+
from IPython.core.interactiveshell import InteractiveShell # noqa: PLC0415
|
|
304
|
+
except ImportError:
|
|
305
|
+
return BasicEngine()
|
|
306
|
+
return IPythonEngine(InteractiveShell.instance())
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
engine = create_engine()
|
|
310
|
+
engine.user_ns[SDK_MODULE_NAME] = sdk
|
|
311
|
+
engine.user_ns["ApprovalPending"] = ApprovalPending
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
# ---------------------------------------------------------------------------
|
|
315
|
+
# Result shaping and artifact tracking
|
|
316
|
+
# ---------------------------------------------------------------------------
|
|
317
|
+
|
|
318
|
+
def safe_result(value: Any) -> Any:
|
|
319
|
+
if value is None or isinstance(value, (str, int, float, bool, list, dict)):
|
|
320
|
+
encoded = json.dumps(value, ensure_ascii=False, default=str)
|
|
321
|
+
if len(encoded) <= MAX_STREAM_CHARS:
|
|
322
|
+
return value
|
|
323
|
+
return {"truncated": True, "preview": encoded[: MAX_STREAM_CHARS - 80]}
|
|
324
|
+
if hasattr(value, "_repr_mimebundle_"):
|
|
325
|
+
bundle = value._repr_mimebundle_()
|
|
326
|
+
if isinstance(bundle, tuple):
|
|
327
|
+
bundle = bundle[0]
|
|
328
|
+
if isinstance(bundle, dict):
|
|
329
|
+
encoded = json.dumps(bundle, ensure_ascii=False, default=str)
|
|
330
|
+
if len(encoded) <= MAX_STREAM_CHARS:
|
|
331
|
+
return {"mimeBundle": bundle}
|
|
332
|
+
rich: dict[str, str] = {}
|
|
333
|
+
for method, mime in (
|
|
334
|
+
("_repr_png_", "image/png"),
|
|
335
|
+
("_repr_svg_", "image/svg+xml"),
|
|
336
|
+
("_repr_html_", "text/html"),
|
|
337
|
+
):
|
|
338
|
+
renderer = getattr(value, method, None)
|
|
339
|
+
if not callable(renderer):
|
|
340
|
+
continue
|
|
341
|
+
try:
|
|
342
|
+
rendered = renderer()
|
|
343
|
+
except Exception:
|
|
344
|
+
continue
|
|
345
|
+
if rendered is None:
|
|
346
|
+
continue
|
|
347
|
+
if isinstance(rendered, bytes):
|
|
348
|
+
rendered = base64.b64encode(rendered).decode("ascii")
|
|
349
|
+
rich[mime] = str(rendered)[:MAX_STREAM_CHARS]
|
|
350
|
+
if rich:
|
|
351
|
+
return {"mimeBundle": rich}
|
|
352
|
+
return repr(value)[:MAX_STREAM_CHARS]
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def file_snapshot() -> dict[str, tuple[int, int]]:
|
|
356
|
+
found: dict[str, tuple[int, int]] = {}
|
|
357
|
+
for path in ROOT.rglob("*"):
|
|
358
|
+
try:
|
|
359
|
+
if is_within(path.resolve(), ROOT) and path.is_file() and not path.is_symlink():
|
|
360
|
+
stat = path.stat()
|
|
361
|
+
found[path.relative_to(ROOT).as_posix()] = (stat.st_size, stat.st_mtime_ns)
|
|
362
|
+
except OSError:
|
|
363
|
+
continue
|
|
364
|
+
return found
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
attached_files: set[str] = set()
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def attach_file(path: str) -> None:
|
|
371
|
+
"""Include an existing home file in this cell's checked artifact output."""
|
|
372
|
+
if not isinstance(path, str) or not path or len(path) > 4096:
|
|
373
|
+
raise ValueError('attach_file requires a file path')
|
|
374
|
+
target = (ROOT / path).resolve()
|
|
375
|
+
if not is_within(target, ROOT) or not target.is_file():
|
|
376
|
+
raise ValueError('attached file must exist inside this agent home')
|
|
377
|
+
relative = target.relative_to(ROOT).as_posix()
|
|
378
|
+
if relative not in attached_files and len(attached_files) >= MAX_ARTIFACTS:
|
|
379
|
+
raise ValueError('too many attached files')
|
|
380
|
+
attached_files.add(relative)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
engine.user_ns['attach_file'] = attach_file
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def changed_artifacts(before: dict[str, tuple[int, int]]) -> list[dict[str, Any]]:
|
|
387
|
+
artifacts: list[dict[str, Any]] = []
|
|
388
|
+
current = file_snapshot()
|
|
389
|
+
if attached_files - current.keys():
|
|
390
|
+
raise ValueError('an attached file is no longer available inside this agent home')
|
|
391
|
+
for relative in sorted(current, key=lambda path: path not in attached_files):
|
|
392
|
+
state = current[relative]
|
|
393
|
+
if before.get(relative) == state and relative not in attached_files:
|
|
394
|
+
continue
|
|
395
|
+
path = ROOT / relative
|
|
396
|
+
try:
|
|
397
|
+
if not is_within(path.resolve(), ROOT) or path.is_symlink():
|
|
398
|
+
continue
|
|
399
|
+
digest = hashlib.sha256()
|
|
400
|
+
bytes_read = 0
|
|
401
|
+
with path.open('rb') as stream:
|
|
402
|
+
for chunk in iter(lambda: stream.read(1024 * 1024), b''):
|
|
403
|
+
digest.update(chunk)
|
|
404
|
+
bytes_read += len(chunk)
|
|
405
|
+
final_stat = os.fstat(stream.fileno())
|
|
406
|
+
if bytes_read != state[0] or (final_stat.st_size, final_stat.st_mtime_ns) != state:
|
|
407
|
+
raise OSError('artifact changed while being hashed')
|
|
408
|
+
except OSError:
|
|
409
|
+
if relative in attached_files:
|
|
410
|
+
raise
|
|
411
|
+
continue
|
|
412
|
+
artifacts.append({
|
|
413
|
+
"path": relative,
|
|
414
|
+
"size": state[0],
|
|
415
|
+
"mime": mimetypes.guess_type(relative)[0] or "application/octet-stream",
|
|
416
|
+
"sha256": digest.hexdigest(),
|
|
417
|
+
})
|
|
418
|
+
if len(artifacts) >= MAX_ARTIFACTS:
|
|
419
|
+
break
|
|
420
|
+
return artifacts
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
# ---------------------------------------------------------------------------
|
|
424
|
+
# Main loop
|
|
425
|
+
# ---------------------------------------------------------------------------
|
|
426
|
+
|
|
427
|
+
def execute(message: dict[str, Any]) -> None:
|
|
428
|
+
execution_id = str(message["id"])
|
|
429
|
+
code = str(message["code"])
|
|
430
|
+
bridge.begin(execution_id, message.get("context") or {})
|
|
431
|
+
attached_files.clear()
|
|
432
|
+
stdout = io.StringIO()
|
|
433
|
+
stderr = io.StringIO()
|
|
434
|
+
started = time.monotonic()
|
|
435
|
+
files_before = file_snapshot()
|
|
436
|
+
result_value: Any = None
|
|
437
|
+
error: str | None = None
|
|
438
|
+
approval_id: str | None = None
|
|
439
|
+
try:
|
|
440
|
+
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
441
|
+
outcome = engine.run_cell(code)
|
|
442
|
+
if outcome.error is not None:
|
|
443
|
+
raise outcome.error
|
|
444
|
+
result_value = safe_result(outcome.result)
|
|
445
|
+
except ApprovalPending as pending:
|
|
446
|
+
approval_id = pending.approval_id
|
|
447
|
+
except TurnDeferred:
|
|
448
|
+
pass
|
|
449
|
+
except BaseException as exc:
|
|
450
|
+
error = "".join(traceback.format_exception_only(type(exc), exc)).strip()
|
|
451
|
+
|
|
452
|
+
out = stdout.getvalue()
|
|
453
|
+
err = stderr.getvalue()
|
|
454
|
+
truncated = len(out) + len(err) > MAX_STREAM_CHARS
|
|
455
|
+
if truncated:
|
|
456
|
+
remaining = MAX_STREAM_CHARS
|
|
457
|
+
out = out[:remaining]
|
|
458
|
+
remaining -= len(out)
|
|
459
|
+
err = err[: max(0, remaining)]
|
|
460
|
+
try:
|
|
461
|
+
artifacts = changed_artifacts(files_before)
|
|
462
|
+
except (OSError, ValueError) as exc:
|
|
463
|
+
artifacts = []
|
|
464
|
+
error = str(exc)
|
|
465
|
+
emit({
|
|
466
|
+
"type": "execution_result",
|
|
467
|
+
"id": execution_id,
|
|
468
|
+
"ok": error is None and approval_id is None,
|
|
469
|
+
"stdout": out,
|
|
470
|
+
"stderr": err,
|
|
471
|
+
"result": result_value,
|
|
472
|
+
"error": error,
|
|
473
|
+
"approvalId": approval_id,
|
|
474
|
+
"truncated": truncated,
|
|
475
|
+
"durationMs": round((time.monotonic() - started) * 1000),
|
|
476
|
+
"artifacts": artifacts,
|
|
477
|
+
"directives": bridge.directives,
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def main() -> None:
|
|
482
|
+
emit({
|
|
483
|
+
"type": "ready",
|
|
484
|
+
"protocol": KERNEL_PROTOCOL_VERSION,
|
|
485
|
+
"python": sys.version.split()[0],
|
|
486
|
+
"engine": engine.name,
|
|
487
|
+
"home": str(ROOT),
|
|
488
|
+
})
|
|
489
|
+
while True:
|
|
490
|
+
try:
|
|
491
|
+
message = read_message()
|
|
492
|
+
except EOFError:
|
|
493
|
+
return
|
|
494
|
+
except Exception as exc:
|
|
495
|
+
emit({"type": "protocol_error", "error": str(exc)})
|
|
496
|
+
continue
|
|
497
|
+
message_type = message.get("type")
|
|
498
|
+
if message_type == "shutdown":
|
|
499
|
+
return
|
|
500
|
+
if message_type != "execute":
|
|
501
|
+
emit({"type": "protocol_error", "error": "expected execute"})
|
|
502
|
+
continue
|
|
503
|
+
execute(message)
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
if __name__ == "__main__":
|
|
507
|
+
main()
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lingxios",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "LingxiOS — a purpose-built, production-grade Agent OS: durable work orchestration, sandboxed code-act kernels, and a policy-extensible agent runtime.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/lyyzka/LingxiOS.git"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/src",
|
|
13
|
+
"db/schema.sql",
|
|
14
|
+
"kernel/runner.py"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22.13.0"
|
|
18
|
+
},
|
|
19
|
+
"main": "dist/src/index.js",
|
|
20
|
+
"types": "dist/src/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/src/index.d.ts",
|
|
24
|
+
"import": "./dist/src/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./worker": {
|
|
27
|
+
"types": "./dist/src/worker/index.d.ts",
|
|
28
|
+
"import": "./dist/src/worker/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./eval": {
|
|
31
|
+
"types": "./dist/src/eval/index.d.ts",
|
|
32
|
+
"import": "./dist/src/eval/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./ui": {
|
|
35
|
+
"types": "./dist/src/ui/index.d.ts",
|
|
36
|
+
"import": "./dist/src/ui/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./lingxiloop": {
|
|
39
|
+
"types": "./dist/src/integrations/lingxiloop/index.d.ts",
|
|
40
|
+
"import": "./dist/src/integrations/lingxiloop/index.js"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"bin": {
|
|
44
|
+
"lingxios-worker": "dist/src/worker/main.js",
|
|
45
|
+
"lingxios-eval": "dist/src/cli/eval.js",
|
|
46
|
+
"lingxios-doctor": "dist/src/cli/doctor.js"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "node scripts/build.mjs",
|
|
50
|
+
"prepack": "npm run build",
|
|
51
|
+
"prepublishOnly": "npm run check:release",
|
|
52
|
+
"check:release": "npm test && npm run test:contracts && npm run test:postgres-stores && npm run test:worker-recovery && npm run test:native-calendar && npm run test:native-documents && npm run test:native-document-content && npm run test:native-polls && npm run test:native-presentations && npm run test:native-teacher && npm run test:native-missions && npm run test:native-evidence && npm run test:native-canvas && npm run test:native-canvas-work && npm run test:native-learning",
|
|
53
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
54
|
+
"test": "npm run build && node --test --test-concurrency=1 \"dist/test/**/*.test.js\"",
|
|
55
|
+
"test:only": "node --test --test-concurrency=1 \"dist/test/**/*.test.js\"",
|
|
56
|
+
"eval:live": "npm run build && node scripts/eval-live.mjs",
|
|
57
|
+
"test:contracts": "node scripts/check-lingxiloop-contracts.mjs",
|
|
58
|
+
"test:postgres-stores": "npm run build && node scripts/test-postgres-stores.mjs",
|
|
59
|
+
"test:native-missions": "npm run build && node scripts/test-native-missions.mjs",
|
|
60
|
+
"test:native-learning": "node scripts/test-native-learning.mjs",
|
|
61
|
+
"test:native-evidence": "npm run build && node scripts/test-native-evidence.mjs",
|
|
62
|
+
"test:native-polls": "npm run build && node scripts/test-native-polls.mjs",
|
|
63
|
+
"test:native-presentations": "npm run build && node scripts/test-native-presentations.mjs",
|
|
64
|
+
"worker": "node dist/src/worker/main.js",
|
|
65
|
+
"test:worker-image": "node scripts/test-worker-image.mjs",
|
|
66
|
+
"test:worker-recovery": "npm run build && node scripts/test-worker-recovery.mjs",
|
|
67
|
+
"test:native-teacher": "node scripts/test-native-teacher.mjs",
|
|
68
|
+
"test:native-canvas": "node scripts/test-native-canvas.mjs",
|
|
69
|
+
"test:native-canvas-work": "npm run build && node scripts/test-native-canvas-work.mjs",
|
|
70
|
+
"test:native-documents": "npm run build && node scripts/test-native-documents.mjs",
|
|
71
|
+
"test:native-document-content": "npm run build && node scripts/test-native-document-content.mjs",
|
|
72
|
+
"test:native-calendar": "npm run build && node scripts/test-native-calendar.mjs"
|
|
73
|
+
},
|
|
74
|
+
"devDependencies": {
|
|
75
|
+
"@electric-sql/pglite": "0.5.8",
|
|
76
|
+
"@types/node": "^20.17.0",
|
|
77
|
+
"typescript": "^5.7.0"
|
|
78
|
+
},
|
|
79
|
+
"dependencies": {
|
|
80
|
+
"mammoth": "1.12.2",
|
|
81
|
+
"pdfjs-dist": "6.3.289"
|
|
82
|
+
}
|
|
83
|
+
}
|