agent-bios 0.18.0 → 0.19.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/DEPENDENCIES.md +236 -80
- package/INSTALL.md +112 -0
- package/README.md +184 -524
- package/claude/CLAUDE.md +1 -1
- package/claude/guides/cli-multi-model-workflow.md +1 -1
- package/claude/guides/learning-flow.md +23 -12
- package/claude/guides/session-distill-workflow.md +22 -12
- package/codex/AGENTS.md +1 -1
- package/codex/guides/cli-multi-model-workflow.md +1 -1
- package/codex/guides/learning-flow.md +23 -12
- package/codex/guides/session-distill-workflow.md +22 -12
- package/compose/app_bridge/SKILL.md +75 -0
- package/compose/app_bridge/agents/openai.yaml +2 -0
- package/compose/app_bridge/scripts/bridge.py +76 -0
- package/compose/bootstrap/SKILL.md +12 -1
- package/compose/corpus.py +31 -9
- package/compose/corpus_app.py +456 -0
- package/compose/corpus_import.py +529 -0
- package/compose/corpus_install.py +196 -18
- package/compose/corpus_session.py +27 -0
- package/compose/corpus_setup.py +674 -0
- package/compose/corpus_setup_cli.py +582 -0
- package/compose/corpus_setup_i18n.py +318 -0
- package/compose/corpus_setup_ui.py +633 -0
- package/compose/corpus_store.py +167 -29
- package/compose/corpus_transaction.py +43 -10
- package/compose/corpus_ui_runtime.py +278 -0
- package/compose/setup/START.md +147 -0
- package/compose/ui_runtime/linkify_it_py-2.2.0-py3-none-any.whl +0 -0
- package/compose/ui_runtime/manifest.json +238 -0
- package/compose/ui_runtime/markdown_it_py-4.2.0-py3-none-any.whl +0 -0
- package/compose/ui_runtime/mdit_py_plugins-0.6.1-py3-none-any.whl +0 -0
- package/compose/ui_runtime/mdurl-0.1.2-py3-none-any.whl +0 -0
- package/compose/ui_runtime/platformdirs-4.11.8-py3-none-any.whl +0 -0
- package/compose/ui_runtime/pygments-2.21.0-py3-none-any.whl +0 -0
- package/compose/ui_runtime/rich-15.0.0-py3-none-any.whl +0 -0
- package/compose/ui_runtime/textual-8.2.8-py3-none-any.whl +0 -0
- package/compose/ui_runtime/typing_extensions-4.16.0-py3-none-any.whl +0 -0
- package/docs/advanced-launch.md +131 -0
- package/docs/assets/corpus-studio.svg +227 -0
- package/docs/corpus.md +117 -0
- package/docs/recovery.md +201 -0
- package/docs/session-model.md +120 -0
- package/docs/setup.md +190 -0
- package/docs/understand.md +40 -0
- package/install.sh +75 -46
- package/launch/agent-launch.py +91 -47
- package/launch/provision-venv.sh +44 -13
- package/learn/collect-learning.py +14 -5
- package/learn/learning.schema.json +2 -2
- package/package.json +14 -2
- package/provenance.json +1 -1
- package/wrappers/claude-run.sh +10 -13
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"""Load the shipped pure-Python UI wheels offline into one process-owned directory."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import atexit
|
|
5
|
+
from email.parser import BytesParser
|
|
6
|
+
import hashlib
|
|
7
|
+
import importlib
|
|
8
|
+
import io
|
|
9
|
+
import json
|
|
10
|
+
from pathlib import Path, PurePosixPath
|
|
11
|
+
import re
|
|
12
|
+
import stat
|
|
13
|
+
import sys
|
|
14
|
+
import tempfile
|
|
15
|
+
import threading
|
|
16
|
+
from typing import Any
|
|
17
|
+
import zipfile
|
|
18
|
+
import zlib
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
SCHEMA_VERSION = 1
|
|
22
|
+
MAX_ARCHIVE_BYTES = 32 * 1024 * 1024
|
|
23
|
+
MAX_EXPANDED_BYTES = 128 * 1024 * 1024
|
|
24
|
+
_LOCK = threading.RLock()
|
|
25
|
+
_ACTIVE: tuple[str, tempfile.TemporaryDirectory[str]] | None = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class UiRuntimeError(RuntimeError):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _canonical(value: Any) -> bytes:
|
|
33
|
+
return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _bundle_id(manifest: dict[str, Any]) -> str:
|
|
37
|
+
return hashlib.sha256(_canonical({key: value for key, value in manifest.items() if key != "bundle_id"})).hexdigest()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _normalized_name(name: str) -> str:
|
|
41
|
+
return re.sub(r"[-_.]+", "-", name).lower()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _members(archive: zipfile.ZipFile) -> list[zipfile.ZipInfo]:
|
|
45
|
+
result = []
|
|
46
|
+
seen = set()
|
|
47
|
+
expanded = 0
|
|
48
|
+
for info in archive.infolist():
|
|
49
|
+
raw = info.filename.rstrip("/")
|
|
50
|
+
path = PurePosixPath(raw)
|
|
51
|
+
if not raw or path.is_absolute() or "\\" in raw or path.as_posix() != raw \
|
|
52
|
+
or any(part in {".", ".."} for part in path.parts) \
|
|
53
|
+
or any(ord(character) < 32 or ord(character) == 127 for character in raw):
|
|
54
|
+
raise UiRuntimeError(f"unsafe UI wheel member: {info.filename!r}")
|
|
55
|
+
if raw in seen:
|
|
56
|
+
raise UiRuntimeError(f"duplicate UI wheel member: {raw}")
|
|
57
|
+
seen.add(raw)
|
|
58
|
+
mode = info.external_attr >> 16
|
|
59
|
+
if stat.S_ISLNK(mode) or (stat.S_IFMT(mode) not in {0, stat.S_IFREG, stat.S_IFDIR}):
|
|
60
|
+
raise UiRuntimeError(f"non-regular UI wheel member: {raw}")
|
|
61
|
+
if info.is_dir():
|
|
62
|
+
continue
|
|
63
|
+
if info.flag_bits & 1:
|
|
64
|
+
raise UiRuntimeError(f"encrypted UI wheel member: {raw}")
|
|
65
|
+
if path.suffix.lower() in {".so", ".pyd", ".dll", ".dylib", ".pth", ".pyc"} \
|
|
66
|
+
or path.parts[0].endswith(".data"):
|
|
67
|
+
raise UiRuntimeError(f"UI wheel requires unsupported installation behavior: {raw}")
|
|
68
|
+
expanded += info.file_size
|
|
69
|
+
if expanded > MAX_EXPANDED_BYTES:
|
|
70
|
+
raise UiRuntimeError("UI wheel exceeds the extraction size limit")
|
|
71
|
+
result.append(info)
|
|
72
|
+
if not result:
|
|
73
|
+
raise UiRuntimeError("UI wheel has no files")
|
|
74
|
+
return result
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def wheel_metadata(filename: str, data: bytes) -> dict[str, Any]:
|
|
78
|
+
"""Read wheel metadata and licensing without importing its Python code."""
|
|
79
|
+
if Path(filename).name != filename or not re.fullmatch(r"[A-Za-z0-9_.!+-]+-py[0-9.]+-none-any\.whl", filename):
|
|
80
|
+
raise UiRuntimeError(f"UI runtime requires a pure Python universal wheel: {filename}")
|
|
81
|
+
if not data or len(data) > MAX_ARCHIVE_BYTES:
|
|
82
|
+
raise UiRuntimeError(f"invalid UI wheel size: {filename}")
|
|
83
|
+
try:
|
|
84
|
+
with zipfile.ZipFile(io.BytesIO(data)) as archive:
|
|
85
|
+
members = _members(archive)
|
|
86
|
+
names = {member.filename for member in members}
|
|
87
|
+
metadata_paths = [name for name in names if name.endswith(".dist-info/METADATA")]
|
|
88
|
+
if len(metadata_paths) != 1:
|
|
89
|
+
raise UiRuntimeError(f"UI wheel needs exactly one distribution metadata file: {filename}")
|
|
90
|
+
metadata_path = metadata_paths[0]
|
|
91
|
+
info_root = metadata_path.rsplit("/", 1)[0]
|
|
92
|
+
wheel_path = info_root + "/WHEEL"
|
|
93
|
+
if wheel_path not in names:
|
|
94
|
+
raise UiRuntimeError(f"UI wheel lacks WHEEL metadata: {filename}")
|
|
95
|
+
metadata = BytesParser().parsebytes(archive.read(metadata_path))
|
|
96
|
+
wheel = BytesParser().parsebytes(archive.read(wheel_path))
|
|
97
|
+
tags = wheel.get_all("Tag", [])
|
|
98
|
+
if wheel.get("Root-Is-Purelib", "").lower() != "true" or not tags \
|
|
99
|
+
or any(not re.fullmatch(r"py[0-9.]+-none-any", tag) for tag in tags):
|
|
100
|
+
raise UiRuntimeError(f"UI wheel is not pure Python: {filename}")
|
|
101
|
+
license_files = sorted(name for name in names if name.startswith(info_root + "/") and (
|
|
102
|
+
"/licenses/" in name.lower() or PurePosixPath(name).name.lower().startswith(("license", "licence", "copying"))))
|
|
103
|
+
if not license_files or any(not archive.read(name).strip() for name in license_files):
|
|
104
|
+
raise UiRuntimeError(f"UI wheel lacks an upstream license: {filename}")
|
|
105
|
+
modules = set()
|
|
106
|
+
for name in names:
|
|
107
|
+
parts = PurePosixPath(name).parts
|
|
108
|
+
if parts[0].endswith(".dist-info"):
|
|
109
|
+
continue
|
|
110
|
+
root = parts[0][:-3] if len(parts) == 1 and parts[0].endswith(".py") else parts[0]
|
|
111
|
+
if re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", root):
|
|
112
|
+
modules.add(root)
|
|
113
|
+
name, version = metadata.get("Name"), metadata.get("Version")
|
|
114
|
+
if not isinstance(name, str) or not re.fullmatch(r"[A-Za-z0-9_.-]+", name) \
|
|
115
|
+
or not isinstance(version, str) or not re.fullmatch(r"[A-Za-z0-9_.!+]+", version) or not modules:
|
|
116
|
+
raise UiRuntimeError(f"invalid UI distribution metadata: {filename}")
|
|
117
|
+
return {"name": _normalized_name(name), "version": version, "filename": filename,
|
|
118
|
+
"sha256": hashlib.sha256(data).hexdigest(), "size_bytes": len(data),
|
|
119
|
+
"expanded_bytes": sum(member.file_size for member in members),
|
|
120
|
+
"modules": sorted(modules), "license_files": license_files,
|
|
121
|
+
"requires_python": metadata.get("Requires-Python", ""),
|
|
122
|
+
"requires_dist": metadata.get_all("Requires-Dist", [])}
|
|
123
|
+
except (zipfile.BadZipFile, KeyError, OSError, UnicodeError, RuntimeError, ValueError, EOFError, zlib.error) as exc:
|
|
124
|
+
if isinstance(exc, UiRuntimeError):
|
|
125
|
+
raise
|
|
126
|
+
raise UiRuntimeError(f"cannot read UI wheel {filename}: {exc}") from exc
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _read_bundle(repo: Path) -> tuple[dict[str, Any], list[tuple[dict[str, Any], bytes]]]:
|
|
130
|
+
bundle = Path(repo) / "compose/ui_runtime"
|
|
131
|
+
manifest_path = bundle / "manifest.json"
|
|
132
|
+
if bundle.is_symlink() or manifest_path.is_symlink() or not manifest_path.is_file():
|
|
133
|
+
raise UiRuntimeError("bundled UI runtime manifest is missing or unsafe; reinstall the agent-bios package")
|
|
134
|
+
try:
|
|
135
|
+
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
|
136
|
+
except (OSError, ValueError) as exc:
|
|
137
|
+
raise UiRuntimeError(f"cannot read UI runtime manifest: {exc}") from exc
|
|
138
|
+
if not isinstance(manifest, dict) or manifest.get("schema_version") != SCHEMA_VERSION \
|
|
139
|
+
or manifest.get("python_requirement") != ">=3.11" or manifest.get("source") != "pypi":
|
|
140
|
+
raise UiRuntimeError("unsupported UI runtime manifest")
|
|
141
|
+
if manifest.get("bundle_id") != _bundle_id(manifest):
|
|
142
|
+
raise UiRuntimeError("UI runtime manifest fingerprint mismatch")
|
|
143
|
+
requirements = manifest.get("root_requirement")
|
|
144
|
+
rows = manifest.get("packages")
|
|
145
|
+
if not isinstance(requirements, str) or not re.fullmatch(r"textual==[0-9][A-Za-z0-9_.!+]*", requirements) \
|
|
146
|
+
or not isinstance(rows, list) or not rows:
|
|
147
|
+
raise UiRuntimeError("UI runtime manifest has no valid package inventory")
|
|
148
|
+
supplied = set()
|
|
149
|
+
filenames = set()
|
|
150
|
+
modules = set()
|
|
151
|
+
files = set()
|
|
152
|
+
expanded = 0
|
|
153
|
+
archives = []
|
|
154
|
+
for row in rows:
|
|
155
|
+
if not isinstance(row, dict) or not isinstance(row.get("filename"), str):
|
|
156
|
+
raise UiRuntimeError("UI runtime manifest has an invalid package row")
|
|
157
|
+
filename = row["filename"]
|
|
158
|
+
if Path(filename).name != filename or filename in filenames:
|
|
159
|
+
raise UiRuntimeError(f"invalid or duplicate UI wheel name: {filename}")
|
|
160
|
+
path = bundle / filename
|
|
161
|
+
if path.is_symlink() or not path.is_file():
|
|
162
|
+
raise UiRuntimeError(f"bundled UI wheel missing or unsafe: {filename}")
|
|
163
|
+
if path.stat().st_size != row.get("size_bytes") or path.stat().st_size > MAX_ARCHIVE_BYTES:
|
|
164
|
+
raise UiRuntimeError(f"UI wheel size mismatch: {filename}")
|
|
165
|
+
data = path.read_bytes()
|
|
166
|
+
if hashlib.sha256(data).hexdigest() != row.get("sha256"):
|
|
167
|
+
raise UiRuntimeError(f"UI wheel SHA256 mismatch: {filename}")
|
|
168
|
+
actual = wheel_metadata(filename, data)
|
|
169
|
+
if actual != row:
|
|
170
|
+
raise UiRuntimeError(f"UI wheel metadata differs from its manifest: {filename}")
|
|
171
|
+
if row["name"] in supplied or modules.intersection(row["modules"]):
|
|
172
|
+
raise UiRuntimeError(f"UI distributions overlap: {filename}")
|
|
173
|
+
supplied.add(row["name"])
|
|
174
|
+
filenames.add(filename)
|
|
175
|
+
modules.update(row["modules"])
|
|
176
|
+
with zipfile.ZipFile(io.BytesIO(data)) as archive:
|
|
177
|
+
names = {member.filename for member in _members(archive)}
|
|
178
|
+
if files.intersection(names):
|
|
179
|
+
raise UiRuntimeError(f"UI wheel paths overlap: {filename}")
|
|
180
|
+
files.update(names)
|
|
181
|
+
expanded += row["expanded_bytes"]
|
|
182
|
+
if expanded > MAX_EXPANDED_BYTES:
|
|
183
|
+
raise UiRuntimeError("UI runtime exceeds the extraction size limit")
|
|
184
|
+
archives.append((row, data))
|
|
185
|
+
if {path.name for path in bundle.iterdir() if path.name != "manifest.json"} != filenames:
|
|
186
|
+
raise UiRuntimeError("UI runtime directory differs from its exact wheel inventory")
|
|
187
|
+
if not any(f"{row['name']}=={row['version']}" == requirements for row in rows):
|
|
188
|
+
raise UiRuntimeError("UI runtime root Textual requirement is not present")
|
|
189
|
+
return manifest, archives
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def runtime_inventory(repo: Path) -> dict[str, Any]:
|
|
193
|
+
"""Report bundled hashes, purity, and licenses without extraction or UI imports."""
|
|
194
|
+
try:
|
|
195
|
+
manifest, _archives = _read_bundle(repo)
|
|
196
|
+
except (UiRuntimeError, OSError) as exc:
|
|
197
|
+
return {"schema_version": SCHEMA_VERSION, "status": "unavailable", "issues": [str(exc)], "packages": []}
|
|
198
|
+
return {**manifest, "status": "available", "issues": [],
|
|
199
|
+
"package_count": len(manifest["packages"]),
|
|
200
|
+
"size_bytes": sum(row["size_bytes"] for row in manifest["packages"]),
|
|
201
|
+
"expanded_bytes": sum(row["expanded_bytes"] for row in manifest["packages"]),
|
|
202
|
+
"license_file_count": sum(len(row["license_files"]) for row in manifest["packages"]),
|
|
203
|
+
"pure_python": True}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _preloaded_modules(modules: set[str], active: Path | None) -> list[str]:
|
|
207
|
+
conflicts = []
|
|
208
|
+
for name, module in tuple(sys.modules.items()):
|
|
209
|
+
if name.split(".", 1)[0] not in modules:
|
|
210
|
+
continue
|
|
211
|
+
filename = getattr(module, "__file__", None)
|
|
212
|
+
if active is not None and isinstance(filename, str):
|
|
213
|
+
try:
|
|
214
|
+
Path(filename).resolve().relative_to(active)
|
|
215
|
+
continue
|
|
216
|
+
except (ValueError, OSError):
|
|
217
|
+
pass
|
|
218
|
+
conflicts.append(name)
|
|
219
|
+
return sorted(conflicts)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _cleanup_runtime() -> None:
|
|
223
|
+
global _ACTIVE
|
|
224
|
+
if _ACTIVE is not None:
|
|
225
|
+
_bundle, temporary = _ACTIVE
|
|
226
|
+
sys.path[:] = [entry for entry in sys.path if entry != temporary.name]
|
|
227
|
+
temporary.cleanup()
|
|
228
|
+
_ACTIVE = None
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def release_ui_runtime() -> None:
|
|
232
|
+
"""Release owned files immediately before process handoff; UI reuse needs a fresh process."""
|
|
233
|
+
with _LOCK:
|
|
234
|
+
_cleanup_runtime()
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def activate_ui_runtime(repo: Path) -> Path:
|
|
238
|
+
"""Activate only verified shipped modules; imports must follow this call."""
|
|
239
|
+
global _ACTIVE
|
|
240
|
+
if sys.version_info < (3, 11):
|
|
241
|
+
raise UiRuntimeError("the bundled UI runtime requires Python 3.11 or newer")
|
|
242
|
+
with _LOCK:
|
|
243
|
+
manifest, archives = _read_bundle(repo)
|
|
244
|
+
if _ACTIVE is not None and _ACTIVE[0] != manifest["bundle_id"]:
|
|
245
|
+
raise UiRuntimeError("another UI bundle is active; start a fresh process for this agent-bios package")
|
|
246
|
+
active = Path(_ACTIVE[1].name).resolve() if _ACTIVE is not None else None
|
|
247
|
+
names = {name for row, _data in archives for name in row["modules"]}
|
|
248
|
+
conflicts = _preloaded_modules(names, active)
|
|
249
|
+
if conflicts:
|
|
250
|
+
raise UiRuntimeError("UI dependencies were imported before bundled activation: " + ", ".join(conflicts[:8])
|
|
251
|
+
+ "; start a fresh process and activate the bundle before importing UI modules")
|
|
252
|
+
if active is not None:
|
|
253
|
+
if not active.is_dir():
|
|
254
|
+
raise UiRuntimeError("the active UI runtime directory is missing; start a fresh process")
|
|
255
|
+
return active
|
|
256
|
+
parent = Path(tempfile.gettempdir()).resolve()
|
|
257
|
+
home = Path.home().resolve()
|
|
258
|
+
if parent == home or home in parent.parents:
|
|
259
|
+
parent = Path("/tmp").resolve()
|
|
260
|
+
temporary = tempfile.TemporaryDirectory(prefix="agent-bios-ui-", dir=parent)
|
|
261
|
+
target = Path(temporary.name)
|
|
262
|
+
try:
|
|
263
|
+
for _row, data in archives:
|
|
264
|
+
with zipfile.ZipFile(io.BytesIO(data)) as archive:
|
|
265
|
+
for member in _members(archive):
|
|
266
|
+
path = target.joinpath(*PurePosixPath(member.filename).parts)
|
|
267
|
+
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
|
|
268
|
+
with path.open("xb") as output:
|
|
269
|
+
output.write(archive.read(member))
|
|
270
|
+
path.chmod(0o600)
|
|
271
|
+
sys.path.insert(0, str(target))
|
|
272
|
+
importlib.invalidate_caches()
|
|
273
|
+
_ACTIVE = (manifest["bundle_id"], temporary)
|
|
274
|
+
atexit.register(_cleanup_runtime)
|
|
275
|
+
return target
|
|
276
|
+
except BaseException:
|
|
277
|
+
temporary.cleanup()
|
|
278
|
+
raise
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Set up agent-bios through conversation
|
|
2
|
+
|
|
3
|
+
This guide uses the same installation controller as the terminal wizard. The
|
|
4
|
+
conversation collects choices and presents effects; `setup` validates and executes
|
|
5
|
+
them. It needs local command and file access on the intended machine, Bash, and
|
|
6
|
+
Python 3.11 or newer. Codex CLI, an additional model login, and Textual are not
|
|
7
|
+
requirements for this route.
|
|
8
|
+
|
|
9
|
+
## Start without an installed skill
|
|
10
|
+
|
|
11
|
+
The user can request installation using the public repository link. Follow the
|
|
12
|
+
repository's root `INSTALL.md` to obtain and verify the source, select the language
|
|
13
|
+
and run `setup start`. The agent resolves paths; the user does not need a checkout,
|
|
14
|
+
an installed skill or a long installation prompt. An explicitly selected trusted
|
|
15
|
+
local source remains valid. Preserve the acquisition's exact revision and location
|
|
16
|
+
for the review and any resume. If the selected public revision lacks conversation
|
|
17
|
+
setup, report that limitation instead of invoking an older installation route.
|
|
18
|
+
|
|
19
|
+
## Choose the entrypoint and language
|
|
20
|
+
|
|
21
|
+
For an already registered app bridge, run `python3 "$BRIDGE" setup start`, where
|
|
22
|
+
`BRIDGE` is the absolute helper path beside the loaded skill. Read the returned
|
|
23
|
+
`guide_path`. For an acquired source, use the verified `setup_argv` from its start
|
|
24
|
+
response. Keep using that entrypoint and the reported private roots throughout
|
|
25
|
+
the review. Shell variables from one app tool call do not persist to the next;
|
|
26
|
+
pass absolute arguments or set the variable in the same call.
|
|
27
|
+
|
|
28
|
+
`start` returns language choices, a suggested language and execution context without
|
|
29
|
+
probing dependencies or creating private setup state. Confirm English, 한국어 or
|
|
30
|
+
日本語, honoring an explicit language already chosen by the user, before `inspect`.
|
|
31
|
+
Use the selected language for questions and explanations; retain identifiers,
|
|
32
|
+
paths, versions, raw diagnostics and command arguments exactly. Use a native
|
|
33
|
+
question control when the current host exposes one for this interaction, or ask
|
|
34
|
+
ordinary concise questions. The conversation does not require custom widgets.
|
|
35
|
+
|
|
36
|
+
The commands below use `agent-bios` as shorthand for that verified entrypoint. In
|
|
37
|
+
an app bridge call, replace `agent-bios setup` with `python3 "$BRIDGE" setup`.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
agent-bios setup inspect --language ko
|
|
41
|
+
agent-bios setup discover --project-root /absolute/project
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Collect and review the choices
|
|
45
|
+
|
|
46
|
+
Use `inspect`'s `default_plan`, inventory and choices. Present all dependency
|
|
47
|
+
capabilities with readiness, purpose and installation destination. Only returned
|
|
48
|
+
installation recipes are selectable; do not create shell recipes from model
|
|
49
|
+
memory. A dependency's presence does not authorize installing another one.
|
|
50
|
+
|
|
51
|
+
Collect the six plan fields without asking the user to author JSON:
|
|
52
|
+
|
|
53
|
+
- `selection_mode` and `targets`: keep saved policy, no active corpus, all available
|
|
54
|
+
corpus, or specific returned package/domain/item targets. Start from the returned
|
|
55
|
+
default. No active corpus retains private library assets but delivers no corpus.
|
|
56
|
+
- `dependencies`: chosen installable inventory IDs; an empty list installs none.
|
|
57
|
+
- `app_bridge`: explicit registration choice; registration enables discovery only.
|
|
58
|
+
- `project_roots` and `import_paths`: absolute project folders and explicitly
|
|
59
|
+
selected files from discovery. Capture is independent of corpus selection.
|
|
60
|
+
|
|
61
|
+
Keep saved policy uses `selection_mode: null` and `targets: null`. No active corpus
|
|
62
|
+
uses `"none"` and `[]`. Explicit choices use `"selected"` and their target list;
|
|
63
|
+
all available corpus uses `"selected"` and `["all"]`.
|
|
64
|
+
|
|
65
|
+
Discovery checks known global instruction locations and the specified project
|
|
66
|
+
roots. Show detected sources before selecting them. Capture preserves originals
|
|
67
|
+
and prepares private evidence for later model review; it is not an automatically
|
|
68
|
+
optimized personal corpus. Read the import procedure only when the user requests
|
|
69
|
+
that subsequent review.
|
|
70
|
+
|
|
71
|
+
Save choices to a new caller-owned artifact. Run `plan` and save its complete
|
|
72
|
+
stdout bytes to another new caller-owned artifact:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
agent-bios setup plan --language ko --input /absolute/choices.json > /absolute/review.json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The returned review envelope contains `review_id`, `context`, `language`,
|
|
79
|
+
`preview` and `summary`. Keep the entire envelope; do not reconstruct it from the
|
|
80
|
+
summary, copy only `preview`, change its IDs, or accept truncated output. Show the
|
|
81
|
+
concrete private paths, selected dependency commands/destinations, corpus policy,
|
|
82
|
+
app discovery change and selected capture sources. Keep the exact artifact
|
|
83
|
+
available for inspection. Preparing these caller-owned files is separate from
|
|
84
|
+
applying installation effects.
|
|
85
|
+
|
|
86
|
+
Apply the saved envelope only when its concrete choices are authorized. Existing
|
|
87
|
+
authorization for those exact choices does not require another confirmation.
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
agent-bios setup apply --input /absolute/review.json --review-id REVIEW_ID --yes
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The engine checks the reviewed context, source bytes, private state and package
|
|
94
|
+
before its effects. If the review is stale, show a fresh plan and explain the
|
|
95
|
+
changed effects; do not bypass checks. Report completed dependencies, private
|
|
96
|
+
installation, bridge registration and pending import separately. A partial failure
|
|
97
|
+
or cancellation does not roll back completed external package installations.
|
|
98
|
+
|
|
99
|
+
## Continue or resume
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
agent-bios setup status --review-id REVIEW_ID
|
|
103
|
+
agent-bios setup resume --review-id REVIEW_ID
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
These commands do not execute the remaining installation. `status` reports the
|
|
107
|
+
recorded attempt in `receipt`, `result` and `state`; a past `complete` result does
|
|
108
|
+
not establish the current runtime's health. Inspect `handoff` for current readiness
|
|
109
|
+
and any `needs_action`. Package verification, full runtime verification and helper
|
|
110
|
+
verification are independent observations; one does not prove the others.
|
|
111
|
+
`replayed: true` means the existing attempt was returned without executing it again.
|
|
112
|
+
If `handoff.verification` is `"deferred"`, its readiness fields are null: they are
|
|
113
|
+
unverified, not false. Status can return recorded progress while setup holds the
|
|
114
|
+
private-state lock. Follow `needs_action` and retry status when that operation has
|
|
115
|
+
settled; require checked readiness before using a handoff to continue.
|
|
116
|
+
|
|
117
|
+
`resume` adds `remaining_plan`, `review` and `needs_action`. When `review` is
|
|
118
|
+
non-null, save that entire nested review object to a new caller-owned JSON artifact
|
|
119
|
+
using deterministic JSON extraction. Do not pass the enclosing status response or
|
|
120
|
+
`remaining_plan` to Apply. Preserve every review field, including `continuation`,
|
|
121
|
+
and use the nested review's own `review_id`. Review its remaining effects before
|
|
122
|
+
applying within the user's authorization. If `review` is null, inspect the stated
|
|
123
|
+
reason; unknown prior effects are not permission to replay package installation.
|
|
124
|
+
When `resumed_from` is present, the response has followed a receipt's `continued_by`
|
|
125
|
+
link to an existing continuation. Report the returned child `review_id` rather than
|
|
126
|
+
assuming the original ID is current.
|
|
127
|
+
|
|
128
|
+
After an explicit app registration succeeds, use `handoff.helper_argv` only when
|
|
129
|
+
`helper_usable` is true, appending `setup` and the desired operation.
|
|
130
|
+
`helper_verified` confirms helper bytes, while `helper_usable` also requires a
|
|
131
|
+
verified package and no pending work blocking it. Otherwise inspect `needs_action`
|
|
132
|
+
and current readiness before continuing. A usable helper can continue in this task
|
|
133
|
+
even if native skill discovery has not refreshed. Without a
|
|
134
|
+
verified helper, a verified runtime's `setup_argv` already includes `setup`;
|
|
135
|
+
`cli_argv` does not. Supply the returned `environment` with each call. These arrays
|
|
136
|
+
are command arguments, not shell snippets. Finish applying an existing review
|
|
137
|
+
through its reviewed entrypoint/context; changing entrypoints requires a fresh
|
|
138
|
+
review. Status and subsequent setup can use the verified handoff.
|
|
139
|
+
Do not create a duplicate personal skill or edit host discovery settings to force
|
|
140
|
+
refresh. Once discovered, `$agent-bios` is the ordinary entrypoint. Registration
|
|
141
|
+
on disk is not proof of discovery or corpus loading.
|
|
142
|
+
|
|
143
|
+
If capture completed, report its actual capture ID and returned next action. Its
|
|
144
|
+
semantic review, proposed consumption placement and revision-checked import are
|
|
145
|
+
separate from installation. Setup enables no hooks, native agent registration,
|
|
146
|
+
permissions or edits to global/project instruction files. Each app task requires
|
|
147
|
+
its own explicit corpus use; neither setup nor opening the app performs it.
|
|
Binary file
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"source": "pypi",
|
|
4
|
+
"python_requirement": ">=3.11",
|
|
5
|
+
"root_requirement": "textual==8.2.8",
|
|
6
|
+
"packages": [
|
|
7
|
+
{
|
|
8
|
+
"name": "linkify-it-py",
|
|
9
|
+
"version": "2.2.0",
|
|
10
|
+
"filename": "linkify_it_py-2.2.0-py3-none-any.whl",
|
|
11
|
+
"sha256": "3adc40eb5af300b2605fcfdb968c24e1d780a90f1f2221af7c15e5111e94d443",
|
|
12
|
+
"size_bytes": 21971,
|
|
13
|
+
"expanded_bytes": 66766,
|
|
14
|
+
"modules": [
|
|
15
|
+
"linkify_it"
|
|
16
|
+
],
|
|
17
|
+
"license_files": [
|
|
18
|
+
"linkify_it_py-2.2.0.dist-info/licenses/LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"requires_python": ">=3.10",
|
|
21
|
+
"requires_dist": [
|
|
22
|
+
"pytest; extra == \"test\"",
|
|
23
|
+
"coverage; extra == \"test\"",
|
|
24
|
+
"pytest-cov; extra == \"test\"",
|
|
25
|
+
"pytest-timeout; extra == \"test\"",
|
|
26
|
+
"pre-commit; extra == \"dev\"",
|
|
27
|
+
"isort; extra == \"dev\"",
|
|
28
|
+
"flake8; extra == \"dev\"",
|
|
29
|
+
"black; extra == \"dev\"",
|
|
30
|
+
"pyproject-flake8; extra == \"dev\"",
|
|
31
|
+
"pytest; extra == \"benchmark\"",
|
|
32
|
+
"pytest-benchmark; extra == \"benchmark\"",
|
|
33
|
+
"sphinx; extra == \"doc\"",
|
|
34
|
+
"sphinx_book_theme; extra == \"doc\"",
|
|
35
|
+
"myst-parser; extra == \"doc\""
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "markdown-it-py",
|
|
40
|
+
"version": "4.2.0",
|
|
41
|
+
"filename": "markdown_it_py-4.2.0-py3-none-any.whl",
|
|
42
|
+
"sha256": "9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a",
|
|
43
|
+
"size_bytes": 91687,
|
|
44
|
+
"expanded_bytes": 244684,
|
|
45
|
+
"modules": [
|
|
46
|
+
"markdown_it"
|
|
47
|
+
],
|
|
48
|
+
"license_files": [
|
|
49
|
+
"markdown_it_py-4.2.0.dist-info/licenses/LICENSE",
|
|
50
|
+
"markdown_it_py-4.2.0.dist-info/licenses/LICENSE.markdown-it"
|
|
51
|
+
],
|
|
52
|
+
"requires_python": ">=3.10",
|
|
53
|
+
"requires_dist": [
|
|
54
|
+
"mdurl~=0.1",
|
|
55
|
+
"psutil ; extra == \"benchmarking\"",
|
|
56
|
+
"pytest ; extra == \"benchmarking\"",
|
|
57
|
+
"pytest-benchmark ; extra == \"benchmarking\"",
|
|
58
|
+
"commonmark~=0.9 ; extra == \"compare\"",
|
|
59
|
+
"markdown~=3.4 ; extra == \"compare\"",
|
|
60
|
+
"mistletoe~=1.0 ; extra == \"compare\"",
|
|
61
|
+
"mistune~=3.0 ; extra == \"compare\"",
|
|
62
|
+
"panflute~=2.3 ; extra == \"compare\"",
|
|
63
|
+
"markdown-it-pyrs ; extra == \"compare\"",
|
|
64
|
+
"linkify-it-py>=1,<3 ; extra == \"linkify\"",
|
|
65
|
+
"mdit-py-plugins>=0.5.0 ; extra == \"plugins\"",
|
|
66
|
+
"gprof2dot ; extra == \"profiling\"",
|
|
67
|
+
"mdit-py-plugins>=0.5.0 ; extra == \"rtd\"",
|
|
68
|
+
"myst-parser ; extra == \"rtd\"",
|
|
69
|
+
"pyyaml ; extra == \"rtd\"",
|
|
70
|
+
"sphinx ; extra == \"rtd\"",
|
|
71
|
+
"sphinx-copybutton ; extra == \"rtd\"",
|
|
72
|
+
"sphinx-design ; extra == \"rtd\"",
|
|
73
|
+
"sphinx-book-theme~=1.0 ; extra == \"rtd\"",
|
|
74
|
+
"jupyter_sphinx ; extra == \"rtd\"",
|
|
75
|
+
"ipykernel ; extra == \"rtd\"",
|
|
76
|
+
"coverage ; extra == \"testing\"",
|
|
77
|
+
"pytest ; extra == \"testing\"",
|
|
78
|
+
"pytest-cov ; extra == \"testing\"",
|
|
79
|
+
"pytest-regressions ; extra == \"testing\"",
|
|
80
|
+
"pytest-timeout ; extra == \"testing\"",
|
|
81
|
+
"requests ; extra == \"testing\""
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "mdit-py-plugins",
|
|
86
|
+
"version": "0.6.1",
|
|
87
|
+
"filename": "mdit_py_plugins-0.6.1-py3-none-any.whl",
|
|
88
|
+
"sha256": "214c82fb2ac524472ab6a5bcab1de80f73b50443e187f401bfd77efbc7c6481d",
|
|
89
|
+
"size_bytes": 66663,
|
|
90
|
+
"expanded_bytes": 172036,
|
|
91
|
+
"modules": [
|
|
92
|
+
"mdit_py_plugins"
|
|
93
|
+
],
|
|
94
|
+
"license_files": [
|
|
95
|
+
"mdit_py_plugins-0.6.1.dist-info/licenses/LICENSE"
|
|
96
|
+
],
|
|
97
|
+
"requires_python": ">=3.10",
|
|
98
|
+
"requires_dist": [
|
|
99
|
+
"markdown-it-py>=2.0.0,<5.0.0",
|
|
100
|
+
"pre-commit ; extra == \"code-style\"",
|
|
101
|
+
"myst-parser ; extra == \"rtd\"",
|
|
102
|
+
"sphinx-book-theme ; extra == \"rtd\"",
|
|
103
|
+
"coverage ; extra == \"testing\"",
|
|
104
|
+
"pytest ; extra == \"testing\"",
|
|
105
|
+
"pytest-cov ; extra == \"testing\"",
|
|
106
|
+
"pytest-regressions ; extra == \"testing\"",
|
|
107
|
+
"pytest-timeout ; extra == \"testing\""
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "mdurl",
|
|
112
|
+
"version": "0.1.2",
|
|
113
|
+
"filename": "mdurl-0.1.2-py3-none-any.whl",
|
|
114
|
+
"sha256": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8",
|
|
115
|
+
"size_bytes": 9979,
|
|
116
|
+
"expanded_bytes": 23308,
|
|
117
|
+
"modules": [
|
|
118
|
+
"mdurl"
|
|
119
|
+
],
|
|
120
|
+
"license_files": [
|
|
121
|
+
"mdurl-0.1.2.dist-info/LICENSE"
|
|
122
|
+
],
|
|
123
|
+
"requires_python": ">=3.7",
|
|
124
|
+
"requires_dist": []
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"name": "platformdirs",
|
|
128
|
+
"version": "4.11.8",
|
|
129
|
+
"filename": "platformdirs-4.11.8-py3-none-any.whl",
|
|
130
|
+
"sha256": "52f2f181bbfde907966932cc8312d967d02976422d66d537ea16092b8e291081",
|
|
131
|
+
"size_bytes": 24027,
|
|
132
|
+
"expanded_bytes": 129535,
|
|
133
|
+
"modules": [
|
|
134
|
+
"platformdirs"
|
|
135
|
+
],
|
|
136
|
+
"license_files": [
|
|
137
|
+
"platformdirs-4.11.8.dist-info/licenses/LICENSE"
|
|
138
|
+
],
|
|
139
|
+
"requires_python": ">=3.10",
|
|
140
|
+
"requires_dist": []
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"name": "pygments",
|
|
144
|
+
"version": "2.21.0",
|
|
145
|
+
"filename": "pygments-2.21.0-py3-none-any.whl",
|
|
146
|
+
"sha256": "2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9",
|
|
147
|
+
"size_bytes": 1250147,
|
|
148
|
+
"expanded_bytes": 4621166,
|
|
149
|
+
"modules": [
|
|
150
|
+
"pygments"
|
|
151
|
+
],
|
|
152
|
+
"license_files": [
|
|
153
|
+
"pygments-2.21.0.dist-info/licenses/AUTHORS",
|
|
154
|
+
"pygments-2.21.0.dist-info/licenses/LICENSE"
|
|
155
|
+
],
|
|
156
|
+
"requires_python": ">=3.9",
|
|
157
|
+
"requires_dist": [
|
|
158
|
+
"colorama>=0.4.6; extra == 'windows-terminal'"
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"name": "rich",
|
|
163
|
+
"version": "15.0.0",
|
|
164
|
+
"filename": "rich-15.0.0-py3-none-any.whl",
|
|
165
|
+
"sha256": "33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb",
|
|
166
|
+
"size_bytes": 310654,
|
|
167
|
+
"expanded_bytes": 1245816,
|
|
168
|
+
"modules": [
|
|
169
|
+
"rich"
|
|
170
|
+
],
|
|
171
|
+
"license_files": [
|
|
172
|
+
"rich-15.0.0.dist-info/licenses/LICENSE"
|
|
173
|
+
],
|
|
174
|
+
"requires_python": ">=3.9.0",
|
|
175
|
+
"requires_dist": [
|
|
176
|
+
"ipywidgets (>=7.5.1,<9) ; extra == \"jupyter\"",
|
|
177
|
+
"markdown-it-py (>=2.2.0)",
|
|
178
|
+
"pygments (>=2.13.0,<3.0.0)"
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"name": "textual",
|
|
183
|
+
"version": "8.2.8",
|
|
184
|
+
"filename": "textual-8.2.8-py3-none-any.whl",
|
|
185
|
+
"sha256": "267375fd402dc8d981457212efa71f0e3365fd17bba144ba9bb3ed7563cb374a",
|
|
186
|
+
"size_bytes": 731418,
|
|
187
|
+
"expanded_bytes": 2827661,
|
|
188
|
+
"modules": [
|
|
189
|
+
"textual"
|
|
190
|
+
],
|
|
191
|
+
"license_files": [
|
|
192
|
+
"textual-8.2.8.dist-info/licenses/LICENSE"
|
|
193
|
+
],
|
|
194
|
+
"requires_python": ">=3.9,<4.0",
|
|
195
|
+
"requires_dist": [
|
|
196
|
+
"markdown-it-py[linkify] (>=2.1.0)",
|
|
197
|
+
"mdit-py-plugins",
|
|
198
|
+
"platformdirs (>=3.6.0,<5)",
|
|
199
|
+
"pygments (>=2.19.2,<3.0.0)",
|
|
200
|
+
"rich (>=14.2.0)",
|
|
201
|
+
"tree-sitter (>=0.25.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
202
|
+
"tree-sitter-bash (>=0.23.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
203
|
+
"tree-sitter-css (>=0.23.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
204
|
+
"tree-sitter-go (>=0.23.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
205
|
+
"tree-sitter-html (>=0.23.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
206
|
+
"tree-sitter-java (>=0.23.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
207
|
+
"tree-sitter-javascript (>=0.23.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
208
|
+
"tree-sitter-json (>=0.24.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
209
|
+
"tree-sitter-markdown (>=0.3.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
210
|
+
"tree-sitter-python (>=0.23.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
211
|
+
"tree-sitter-regex (>=0.24.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
212
|
+
"tree-sitter-rust (>=0.23.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
213
|
+
"tree-sitter-sql (>=0.3.11) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
214
|
+
"tree-sitter-toml (>=0.6.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
215
|
+
"tree-sitter-xml (>=0.7.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
216
|
+
"tree-sitter-yaml (>=0.6.0) ; (python_version >= \"3.10\") and (extra == \"syntax\")",
|
|
217
|
+
"typing-extensions (>=4.4.0,<5.0.0)"
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"name": "typing-extensions",
|
|
222
|
+
"version": "4.16.0",
|
|
223
|
+
"filename": "typing_extensions-4.16.0-py3-none-any.whl",
|
|
224
|
+
"sha256": "481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8",
|
|
225
|
+
"size_bytes": 45571,
|
|
226
|
+
"expanded_bytes": 182767,
|
|
227
|
+
"modules": [
|
|
228
|
+
"typing_extensions"
|
|
229
|
+
],
|
|
230
|
+
"license_files": [
|
|
231
|
+
"typing_extensions-4.16.0.dist-info/licenses/LICENSE"
|
|
232
|
+
],
|
|
233
|
+
"requires_python": ">=3.9",
|
|
234
|
+
"requires_dist": []
|
|
235
|
+
}
|
|
236
|
+
],
|
|
237
|
+
"bundle_id": "f86c64655f21c67f45a1b43cf5ea16da5f4b6957a5ce0b8b222e8e8f8d2c1194"
|
|
238
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|