starforge-kernel 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.
- starforge/__init__.py +86 -0
- starforge/core/__init__.py +0 -0
- starforge/core/checkpoints.py +178 -0
- starforge/core/figures.py +119 -0
- starforge/core/previews.py +109 -0
- starforge/core/provenance.py +192 -0
- starforge/core/runner.py +293 -0
- starforge/core/serializers.py +141 -0
- starforge/core/spec.py +126 -0
- starforge/index/__init__.py +9 -0
- starforge/index/scanner.py +487 -0
- starforge/kernel/__init__.py +0 -0
- starforge/kernel/__main__.py +3 -0
- starforge/kernel/server.py +351 -0
- starforge/kernel/worker.py +66 -0
- starforge/mcp.py +283 -0
- starforge_kernel-0.1.0.dist-info/METADATA +76 -0
- starforge_kernel-0.1.0.dist-info/RECORD +20 -0
- starforge_kernel-0.1.0.dist-info/WHEEL +5 -0
- starforge_kernel-0.1.0.dist-info/top_level.txt +1 -0
starforge/mcp.py
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"""*Forge MCP server — agents author and run pipelines in the workspace.
|
|
2
|
+
|
|
3
|
+
Run over stdio: python -m starforge.mcp [workspace]
|
|
4
|
+
|
|
5
|
+
Tools wrap the same core engine the VS Code extension uses, file-based and
|
|
6
|
+
stateless: pipelines are the `.forge` JSON documents under
|
|
7
|
+
``.forge/pipelines/``, blocks come from the static AST index, and runs
|
|
8
|
+
execute in the standard per-run worker subprocess. The `mcp` dependency is
|
|
9
|
+
optional — ``pip install starforge-kernel[mcp]``.
|
|
10
|
+
|
|
11
|
+
The plain functions below are the implementation; FastMCP registration is a
|
|
12
|
+
thin veneer so everything stays unit-testable without an MCP client.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import os
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
import subprocess
|
|
21
|
+
import sys
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
from starforge.core.checkpoints import CheckpointStore
|
|
25
|
+
from starforge.core.provenance import compute_states, env_fingerprint
|
|
26
|
+
from starforge.core.spec import PipelineDoc
|
|
27
|
+
from starforge.index import scan_workspace
|
|
28
|
+
from starforge.kernel.server import BUILTIN_PALETTE
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _workspace(path: str) -> Path:
|
|
32
|
+
workspace = Path(path).resolve()
|
|
33
|
+
if not workspace.is_dir():
|
|
34
|
+
raise ValueError(f"workspace '{path}' is not a directory")
|
|
35
|
+
return workspace
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _pipeline_path(workspace: Path, name: str) -> Path:
|
|
39
|
+
candidate = (workspace / name).resolve()
|
|
40
|
+
if candidate.suffix != ".forge":
|
|
41
|
+
candidate = candidate.with_suffix(".forge")
|
|
42
|
+
if workspace not in candidate.parents and candidate != workspace:
|
|
43
|
+
raise ValueError("pipeline path escapes the workspace")
|
|
44
|
+
return candidate
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def list_blocks(workspace: str = ".") -> list[dict[str, Any]]:
|
|
48
|
+
"""Every block available in the workspace: builtins plus discovered
|
|
49
|
+
@block functions, with params/outputs/annotations/docstrings."""
|
|
50
|
+
ws = _workspace(workspace)
|
|
51
|
+
index, _ = scan_workspace(ws)
|
|
52
|
+
return list(BUILTIN_PALETTE) + [b.to_dict() for b in sorted(index.blocks.values(), key=lambda b: b.block_id)]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def list_pipelines(workspace: str = ".") -> list[str]:
|
|
56
|
+
"""Workspace-relative paths of saved pipelines."""
|
|
57
|
+
ws = _workspace(workspace)
|
|
58
|
+
root = ws / ".forge" / "pipelines"
|
|
59
|
+
if not root.is_dir():
|
|
60
|
+
return []
|
|
61
|
+
return sorted(p.relative_to(ws).as_posix() for p in root.glob("*.forge"))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def read_pipeline(workspace: str, path: str) -> dict[str, Any]:
|
|
65
|
+
"""The pipeline document (nodes, edges, comments) as JSON."""
|
|
66
|
+
ws = _workspace(workspace)
|
|
67
|
+
return PipelineDoc.load(_pipeline_path(ws, path)).to_dict()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def write_pipeline(workspace: str, path: str, doc: dict[str, Any]) -> dict[str, Any]:
|
|
71
|
+
"""Validate and save a pipeline document; returns its node states so the
|
|
72
|
+
caller immediately sees problems and staleness."""
|
|
73
|
+
ws = _workspace(workspace)
|
|
74
|
+
pipeline = PipelineDoc.from_dict(doc) # validates the schema
|
|
75
|
+
target = _pipeline_path(ws, path)
|
|
76
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
77
|
+
pipeline.save(target)
|
|
78
|
+
return pipeline_state(workspace, path)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def pipeline_state(workspace: str, path: str) -> dict[str, Any]:
|
|
82
|
+
"""Per-node history hash, staleness, and problems for a saved pipeline."""
|
|
83
|
+
ws = _workspace(workspace)
|
|
84
|
+
doc = PipelineDoc.load(_pipeline_path(ws, path))
|
|
85
|
+
index, _ = scan_workspace(ws)
|
|
86
|
+
store = CheckpointStore(ws)
|
|
87
|
+
states = compute_states(doc, index, env_fingerprint(ws), store.exists)
|
|
88
|
+
return {
|
|
89
|
+
"path": _pipeline_path(ws, path).relative_to(ws).as_posix(),
|
|
90
|
+
"nodes": {nid: state.to_dict() for nid, state in states.items()},
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def run_pipeline(workspace: str, path: str, target: str | None = None, timeout_seconds: float = 600) -> dict[str, Any]:
|
|
95
|
+
"""Run a saved pipeline (optionally only up to `target` node) in the
|
|
96
|
+
standard worker subprocess; blocks until done. Returns the event stream
|
|
97
|
+
summary and terminal status."""
|
|
98
|
+
ws = _workspace(workspace)
|
|
99
|
+
doc = PipelineDoc.load(_pipeline_path(ws, path))
|
|
100
|
+
index, _ = scan_workspace(ws)
|
|
101
|
+
store = CheckpointStore(ws)
|
|
102
|
+
store.ensure_layout()
|
|
103
|
+
states = compute_states(doc, index, env_fingerprint(ws), store.exists)
|
|
104
|
+
blocks = {
|
|
105
|
+
b.block_id: {
|
|
106
|
+
"module": b.module,
|
|
107
|
+
"qualname": b.qualname,
|
|
108
|
+
"label": b.label,
|
|
109
|
+
"outputs": b.outputs,
|
|
110
|
+
"source_hash": b.source_hash,
|
|
111
|
+
"optional_params": [p.name for p in b.params if p.optional and not p.has_default],
|
|
112
|
+
}
|
|
113
|
+
for b in index.blocks.values()
|
|
114
|
+
}
|
|
115
|
+
spec = {
|
|
116
|
+
"workspace": str(ws),
|
|
117
|
+
"doc": doc.to_dict(),
|
|
118
|
+
"blocks": blocks,
|
|
119
|
+
"states": {nid: s.to_dict() for nid, s in states.items()},
|
|
120
|
+
"pickle_enabled": False,
|
|
121
|
+
"target": target,
|
|
122
|
+
}
|
|
123
|
+
runs_dir = ws / ".forge" / "cache" / "runs"
|
|
124
|
+
runs_dir.mkdir(parents=True, exist_ok=True)
|
|
125
|
+
spec_path = runs_dir / "mcp_run.json"
|
|
126
|
+
spec_path.write_text(json.dumps(spec, default=repr), encoding="utf-8")
|
|
127
|
+
|
|
128
|
+
env = dict(os.environ)
|
|
129
|
+
package_root = str(Path(__file__).resolve().parent.parent)
|
|
130
|
+
env["PYTHONPATH"] = package_root + os.pathsep + env.get("PYTHONPATH", "")
|
|
131
|
+
try:
|
|
132
|
+
result = subprocess.run(
|
|
133
|
+
[sys.executable, "-m", "starforge.kernel.worker", str(spec_path)],
|
|
134
|
+
cwd=str(ws),
|
|
135
|
+
env=env,
|
|
136
|
+
stdin=subprocess.DEVNULL,
|
|
137
|
+
capture_output=True,
|
|
138
|
+
timeout=timeout_seconds,
|
|
139
|
+
)
|
|
140
|
+
finally:
|
|
141
|
+
spec_path.unlink(missing_ok=True)
|
|
142
|
+
|
|
143
|
+
events = []
|
|
144
|
+
for line in result.stdout.decode("utf-8", errors="replace").splitlines():
|
|
145
|
+
try:
|
|
146
|
+
events.append(json.loads(line))
|
|
147
|
+
except json.JSONDecodeError:
|
|
148
|
+
continue
|
|
149
|
+
status = next(
|
|
150
|
+
(e.get("status") for e in reversed(events) if e.get("event") == "run_finished"), "failed"
|
|
151
|
+
)
|
|
152
|
+
summary = {
|
|
153
|
+
"completed": [e["node"] for e in events if e.get("event") == "node_completed"],
|
|
154
|
+
"skipped": [e["node"] for e in events if e.get("event") == "node_skipped"],
|
|
155
|
+
"blocked": [e["node"] for e in events if e.get("event") == "node_blocked"],
|
|
156
|
+
"failed": {
|
|
157
|
+
e["node"]: e.get("traceback", "").strip().splitlines()[-1:]
|
|
158
|
+
for e in events
|
|
159
|
+
if e.get("event") == "node_failed"
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
return {"status": status, **summary, "states": pipeline_state(workspace, path)["nodes"]}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def inspect_node(workspace: str, path: str, node_id: str) -> dict[str, Any]:
|
|
166
|
+
"""Checkpoint provenance for one node: outputs with previews, figures,
|
|
167
|
+
timing — or its staleness/problems when no checkpoint exists."""
|
|
168
|
+
ws = _workspace(workspace)
|
|
169
|
+
state = pipeline_state(workspace, path)["nodes"].get(node_id)
|
|
170
|
+
if state is None:
|
|
171
|
+
raise ValueError(f"node '{node_id}' not found in {path}")
|
|
172
|
+
store = CheckpointStore(ws)
|
|
173
|
+
history_hash = state.get("history_hash")
|
|
174
|
+
if not history_hash or not store.exists(history_hash):
|
|
175
|
+
return {"node": node_id, "state": state, "checkpoint": None}
|
|
176
|
+
return {"node": node_id, "state": state, "checkpoint": store.read_provenance(history_hash)}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
TOOL_NAMES = (
|
|
180
|
+
"starforge_list_blocks",
|
|
181
|
+
"starforge_list_pipelines",
|
|
182
|
+
"starforge_read_pipeline",
|
|
183
|
+
"starforge_write_pipeline",
|
|
184
|
+
"starforge_pipeline_state",
|
|
185
|
+
"starforge_run_pipeline",
|
|
186
|
+
"starforge_inspect_node",
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def main() -> None:
|
|
191
|
+
if any(arg in ("-h", "--help") for arg in sys.argv[1:]):
|
|
192
|
+
print(__doc__)
|
|
193
|
+
return
|
|
194
|
+
try:
|
|
195
|
+
from mcp.server.fastmcp import FastMCP
|
|
196
|
+
except ImportError as exc: # pragma: no cover
|
|
197
|
+
raise SystemExit(
|
|
198
|
+
"The *Forge MCP server needs the 'mcp' package: pip install starforge-kernel[mcp]"
|
|
199
|
+
) from exc
|
|
200
|
+
|
|
201
|
+
default_workspace = sys.argv[1] if len(sys.argv) > 1 else "."
|
|
202
|
+
|
|
203
|
+
# stdout is the MCP protocol channel; everything human goes to stderr.
|
|
204
|
+
# Without this banner, running the server by hand looks like a hang.
|
|
205
|
+
print(
|
|
206
|
+
"\n".join(
|
|
207
|
+
[
|
|
208
|
+
"*Forge MCP server",
|
|
209
|
+
f" workspace : {Path(default_workspace).resolve()}",
|
|
210
|
+
" transport : stdio — waiting for an MCP client to connect on stdin.",
|
|
211
|
+
" (Silence is normal: agents launch this server themselves;",
|
|
212
|
+
" you rarely need to run it manually.)",
|
|
213
|
+
f" tools : {', '.join(TOOL_NAMES)}",
|
|
214
|
+
"",
|
|
215
|
+
"To register with agents, run \"*Forge: Set Up MCP for Agents\" in VS Code,",
|
|
216
|
+
"or add to your agent's MCP config:",
|
|
217
|
+
' { "command": "python", "args": ["-m", "starforge.mcp"] } (cwd = your repo)',
|
|
218
|
+
"",
|
|
219
|
+
"Ctrl+C to exit.",
|
|
220
|
+
]
|
|
221
|
+
),
|
|
222
|
+
file=sys.stderr,
|
|
223
|
+
flush=True,
|
|
224
|
+
)
|
|
225
|
+
server = FastMCP(
|
|
226
|
+
"starforge",
|
|
227
|
+
instructions=(
|
|
228
|
+
"Author and run *Forge pipelines in this workspace. Blocks are @block-decorated "
|
|
229
|
+
"functions in the repo (see list_blocks for ids/params/outputs). Pipelines are "
|
|
230
|
+
".forge JSON documents (read one for the schema). write_pipeline validates and "
|
|
231
|
+
"returns per-node staleness; run_pipeline executes only stale nodes and returns "
|
|
232
|
+
"results; inspect_node shows output previews from checkpoints. Edges target "
|
|
233
|
+
"parameter NAMES; params left unwired use literals from the doc or signature "
|
|
234
|
+
f"defaults. Default workspace: {Path(default_workspace).resolve()}"
|
|
235
|
+
),
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
def _ws(workspace: str | None) -> str:
|
|
239
|
+
return workspace or default_workspace
|
|
240
|
+
|
|
241
|
+
@server.tool()
|
|
242
|
+
def starforge_list_blocks(workspace: str | None = None) -> list[dict[str, Any]]:
|
|
243
|
+
"""List every available block with params, outputs, types, and docs."""
|
|
244
|
+
return list_blocks(_ws(workspace))
|
|
245
|
+
|
|
246
|
+
@server.tool()
|
|
247
|
+
def starforge_list_pipelines(workspace: str | None = None) -> list[str]:
|
|
248
|
+
"""List saved .forge pipelines in the workspace."""
|
|
249
|
+
return list_pipelines(_ws(workspace))
|
|
250
|
+
|
|
251
|
+
@server.tool()
|
|
252
|
+
def starforge_read_pipeline(path: str, workspace: str | None = None) -> dict[str, Any]:
|
|
253
|
+
"""Read a pipeline document (nodes, edges, comments)."""
|
|
254
|
+
return read_pipeline(_ws(workspace), path)
|
|
255
|
+
|
|
256
|
+
@server.tool()
|
|
257
|
+
def starforge_write_pipeline(path: str, doc: dict[str, Any], workspace: str | None = None) -> dict[str, Any]:
|
|
258
|
+
"""Validate and save a pipeline document; returns per-node states (problems, staleness)."""
|
|
259
|
+
return write_pipeline(_ws(workspace), path, doc)
|
|
260
|
+
|
|
261
|
+
@server.tool()
|
|
262
|
+
def starforge_pipeline_state(path: str, workspace: str | None = None) -> dict[str, Any]:
|
|
263
|
+
"""Per-node staleness and problems without running anything."""
|
|
264
|
+
return pipeline_state(_ws(workspace), path)
|
|
265
|
+
|
|
266
|
+
@server.tool()
|
|
267
|
+
def starforge_run_pipeline(
|
|
268
|
+
path: str, target: str | None = None, workspace: str | None = None
|
|
269
|
+
) -> dict[str, Any]:
|
|
270
|
+
"""Run a saved pipeline (stale nodes only; `target` limits to one node's
|
|
271
|
+
ancestor cone). Blocks until the run finishes."""
|
|
272
|
+
return run_pipeline(_ws(workspace), path, target=target)
|
|
273
|
+
|
|
274
|
+
@server.tool()
|
|
275
|
+
def starforge_inspect_node(path: str, node_id: str, workspace: str | None = None) -> dict[str, Any]:
|
|
276
|
+
"""Checkpoint provenance for a node: output previews, figures, timing."""
|
|
277
|
+
return inspect_node(_ws(workspace), path, node_id)
|
|
278
|
+
|
|
279
|
+
server.run()
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
if __name__ == "__main__":
|
|
283
|
+
main()
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: starforge-kernel
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: *Forge — pipeline canvas, checkpointing, and stale/hydrate execution for the repo you already have open
|
|
5
|
+
Author: Jonathan Potter
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/Jonpot/forge
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
12
|
+
Requires-Dist: pandas>=2.0; extra == "dev"
|
|
13
|
+
Requires-Dist: pyarrow>=15.0; extra == "dev"
|
|
14
|
+
Requires-Dist: numpy>=1.26; extra == "dev"
|
|
15
|
+
Provides-Extra: mcp
|
|
16
|
+
Requires-Dist: mcp>=1.8; extra == "mcp"
|
|
17
|
+
|
|
18
|
+
# *Forge (`starforge`)
|
|
19
|
+
|
|
20
|
+
Forge's canvas — checkpointing, provenance, stale/hydrate execution — as a VS Code
|
|
21
|
+
extension over the repo you already have open. Blocks are ordinary Python functions
|
|
22
|
+
tagged with `@block`. See [DESIGN.md](DESIGN.md) for the full design.
|
|
23
|
+
|
|
24
|
+
## Try it (M0)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# 1. Install the kernel + decorator into the venv your target repo uses
|
|
28
|
+
pip install -e <forge-repo>/starforge
|
|
29
|
+
|
|
30
|
+
# 2. Build the extension
|
|
31
|
+
cd <forge-repo>/starforge/vscode
|
|
32
|
+
npm install && npm run build
|
|
33
|
+
|
|
34
|
+
# 3. Open starforge/vscode in VS Code and press F5 (extension dev host).
|
|
35
|
+
# In the dev-host window, open any Python repo.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
In your repo:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
# analysis/blocks.py
|
|
42
|
+
import matplotlib.pyplot as plt
|
|
43
|
+
from starforge import block
|
|
44
|
+
|
|
45
|
+
@block(category="IO")
|
|
46
|
+
def make_numbers(n: int = 5) -> dict:
|
|
47
|
+
return {"values": list(range(1, n + 1))}
|
|
48
|
+
|
|
49
|
+
@block
|
|
50
|
+
def scale(data: dict, factor: float = 2.0) -> dict:
|
|
51
|
+
return {"values": [v * factor for v in data["values"]]}
|
|
52
|
+
|
|
53
|
+
@block
|
|
54
|
+
def plot(data: dict) -> dict:
|
|
55
|
+
plt.plot(data["values"])
|
|
56
|
+
plt.show() # rendered inline on the canvas node
|
|
57
|
+
return data
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Save, run **“*Forge: New Pipeline”**, drag the blocks from the palette, wire
|
|
61
|
+
`output → data`, hit **▶ Run**. Run again — instant, everything reused. Edit
|
|
62
|
+
`scale`, watch it (and only it) go stale.
|
|
63
|
+
|
|
64
|
+
## Layout
|
|
65
|
+
|
|
66
|
+
| Path | What |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `src/starforge/__init__.py` | the `@block` decorator — zero-dep, the only thing user code touches |
|
|
69
|
+
| `src/starforge/index/` | static AST indexer (discovery, import graph, incremental cache) |
|
|
70
|
+
| `src/starforge/core/` | doc schema, history hashing, serializers, checkpoint store, runner |
|
|
71
|
+
| `src/starforge/kernel/` | stdio JSON-RPC kernel + per-run worker subprocess |
|
|
72
|
+
| `vscode/` | the extension (TS host + React Flow webview) |
|
|
73
|
+
| `tests/` | headless M0 proof — `python -m pytest starforge/tests` |
|
|
74
|
+
|
|
75
|
+
State lives in the target repo under `.forge/` — `pipelines/` is committable,
|
|
76
|
+
`checkpoints/` and `cache/` are auto-gitignored.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
starforge/__init__.py,sha256=yRj7cwyn-dsRhmGX7J3I6WkfWvN1MeE6ei9LoGIsaag,2982
|
|
2
|
+
starforge/mcp.py,sha256=T55eHXZ5rLuBBsnDJ-VK90_mStKsIA78_Lr_O5GviFU,11297
|
|
3
|
+
starforge/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
starforge/core/checkpoints.py,sha256=ElIp21DkvK_VAdpP_ORhgatPKdMYDpMGv2mqQycARlk,7212
|
|
5
|
+
starforge/core/figures.py,sha256=EAreO6qG93LXBn2S1w6ALxRYmDaullhAOd92CAQmSD8,4156
|
|
6
|
+
starforge/core/previews.py,sha256=A7zud4-MiEx3ewdwsGQ_lI_8_5RJg9G0AwBXSaeBPhE,4096
|
|
7
|
+
starforge/core/provenance.py,sha256=DioES9Vd9663rRxQUv1r4FUFk3-4KSl2xJaW9J0q2TE,7362
|
|
8
|
+
starforge/core/runner.py,sha256=bWVRPN0tKbXA9BS58GGAz7fj6UiLYszvThfN88QVK8k,11322
|
|
9
|
+
starforge/core/serializers.py,sha256=f1e3rT6AQDAA7IKVxlxppxSW0IopuifOO7ElKOYD6cQ,4847
|
|
10
|
+
starforge/core/spec.py,sha256=8QAU7nIE3i05ut0iAuln9w_0NQDGHEWZ0x_dfDeSyTw,3873
|
|
11
|
+
starforge/index/__init__.py,sha256=4uZiK1x-5yO-wQBoCB_i1lurm605ungYPWv3Na6TY6U,214
|
|
12
|
+
starforge/index/scanner.py,sha256=2Hll4LmzVt3kgW3nfGb_PHbae7Qv9mkcVYxBpPWLvU8,18203
|
|
13
|
+
starforge/kernel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
starforge/kernel/__main__.py,sha256=dKkjWoNHUSl5SvOEIwIdgP0oU40PPUfWrc4tWXNK5fc,49
|
|
15
|
+
starforge/kernel/server.py,sha256=3KKrnsTELGZFzdUCI--n1G4ZYD8Ksh8p7IVoaY42qiM,14276
|
|
16
|
+
starforge/kernel/worker.py,sha256=1uTyZET-h8hQVm7UN3H5eHpz3JcYFSlUv3TUtsfHm-8,2228
|
|
17
|
+
starforge_kernel-0.1.0.dist-info/METADATA,sha256=F3MWhjrvpGU_CpfY_UZPGwO0olftzGQdcRYTfV-alNc,2650
|
|
18
|
+
starforge_kernel-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
19
|
+
starforge_kernel-0.1.0.dist-info/top_level.txt,sha256=lV8j4pGR6UxAx7zmzqeV7_WmUxjqcjHvZSkMhOiBC4A,10
|
|
20
|
+
starforge_kernel-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
starforge
|