chore: import upstream snapshot with attribution
Integ / changes (push) Has been skipped
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
Test (Python) / changes (push) Has been skipped
Test (TypeScript) / changes (push) Has been skipped
CLI exit codes / cli-gate (push) Has been cancelled
Test (Install) / test-install-gate (push) Has been cancelled
Integ / integ-gate (push) Has been cancelled
Test (Python) / test-python-gate (push) Has been cancelled
Test (TypeScript) / test-typescript-gate (push) Has been cancelled
Test (Install) / python-minimal (3.12) (push) Has been cancelled
Test (Install) / python-minimal (3.11) (push) Has been cancelled
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Has been cancelled
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Has been cancelled
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Has been cancelled
Integ / integ (push) Has been cancelled
Integ / integ-database (push) Has been cancelled
Integ / integ-database-ts (push) Has been cancelled
Integ / integ-data (push) Has been cancelled
Integ / integ-ssh (push) Has been cancelled
Integ / integ-ssh-ts (push) Has been cancelled
Test (Python) / audit (push) Has been cancelled
Test (TypeScript) / test (push) Has been cancelled
Test (TypeScript) / python-fs-shim (push) Has been cancelled
CLI exit codes / Python CLI (push) Has been cancelled
CLI exit codes / TypeScript CLI (push) Has been cancelled
CLI exit codes / Cross-language snapshot interop (push) Has been cancelled
Test (Python) / test (push) Has been cancelled
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Integ / integ-ts (push) Has been cancelled
Integ / integ-fuse (push) Has been cancelled
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Has been cancelled
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Has been cancelled
Test (Install) / python-extra (email, mirage.resource.email) (push) Has been cancelled
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Has been cancelled
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Has been cancelled
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Has been cancelled
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Has been cancelled
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Has been cancelled
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Has been cancelled
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Has been cancelled
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Has been cancelled
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Has been cancelled
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Has been cancelled
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Has been cancelled
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Has been cancelled
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Has been cancelled
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Has been cancelled
Test (Install) / ts-minimal (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:30:44 +08:00
commit bcbd1bdb22
5748 changed files with 562488 additions and 0 deletions
@@ -0,0 +1,392 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import asyncio
from functools import partial
from typing import Any, Callable
from mirage.io import IOResult
from mirage.io.stream import async_chain
from mirage.shell.arith import evaluate_arith
from mirage.shell.call_stack import CallStack
from mirage.shell.errors import ArithError
from mirage.shell.job_table import JobTable
from mirage.shell.node_kind import NodeKind, node_kind
from mirage.shell.types import ERREXIT_EXEMPT_TYPES
from mirage.shell.types import NodeType as NT
from mirage.workspace.abort import MirageAbortError
from mirage.workspace.executor.control import (handle_case, handle_for,
handle_if, handle_select,
handle_until, handle_while)
from mirage.workspace.executor.pipes import (handle_connection, handle_pipe,
handle_subshell)
from mirage.workspace.executor.redirect import handle_redirect
from mirage.workspace.expand import (expand_and_classify, expand_node,
expand_redirects)
from mirage.workspace.expand.globs import resolve_globs
from mirage.workspace.expand.node import expand_arith
from mirage.workspace.mount import MountRegistry
from mirage.workspace.mount.namespace import Namespace
from mirage.workspace.node.command_dispatch import execute_command
from mirage.workspace.node.program import execute_program
from mirage.workspace.node.test_expr import expand_test_expr
from mirage.workspace.session import Session
from mirage.workspace.types import ExecutionNode
from mirage.shell.helpers import ( # isort: skip
get_case_items, get_case_word, get_declaration_keyword, get_for_parts,
get_function_body, get_function_name, get_if_branches, get_list_parts,
get_negated_command, get_pipeline_commands, get_redirects,
get_subshell_body, get_text, get_unset_names, get_while_parts)
from mirage.workspace.executor.builtins import ( # isort: skip
handle_export, handle_local, handle_readonly, handle_test, handle_unset)
async def _recurse_reassociated(
recurse: Callable,
dispatch: Callable,
execute_fn: Callable,
registry: MountRegistry,
redirects: list,
right: Any,
node: Any,
session: Session,
stdin: Any = None,
call_stack: CallStack | None = None,
) -> tuple[Any, IOResult, ExecutionNode]:
"""Recurse wrapper for a re-associated trailing redirect.
Executes the list's last command with the hoisted redirects,
expanding targets only at that point (after the left side ran, so
cwd changes apply); every other node recurses normally.
Args:
recurse (Callable): the plain execute_node recursion.
dispatch (Callable): VFS op dispatcher.
execute_fn (Callable): recursive execute (for expansions).
registry (MountRegistry): mount registry.
redirects (list): parsed redirects hoisted off the list.
right (Any): the list's last command node.
node (Any): node being executed by handle_connection.
session (Session): shell session state.
stdin (Any): input stream.
call_stack (CallStack | None): shell call stack.
"""
if node is not right:
return await recurse(node, session, stdin, call_stack)
expanded, pipe_node = await expand_redirects(redirects, session,
execute_fn, registry,
call_stack)
stdout, io, exec_node = await handle_redirect(recurse, dispatch, right,
expanded, session, stdin,
call_stack)
if pipe_node is not None and stdout is not None:
stdout, io2, exec_node2 = await recurse(pipe_node, session, stdout,
call_stack)
io = await io.merge(io2)
exec_node = exec_node2
return stdout, io, exec_node
async def execute_node(
dispatch: Callable,
registry: MountRegistry,
namespace: Namespace,
job_table: JobTable,
execute_fn: Callable,
agent_id: str,
node: Any,
session: Session,
stdin: Any = None,
call_stack: CallStack | None = None,
cancel: asyncio.Event | None = None,
) -> tuple[Any, IOResult, ExecutionNode]:
"""Walk tree-sitter AST and dispatch each node.
Args:
dispatch (Callable): VFS op dispatcher (op, path, **kw).
registry (MountRegistry): mount registry for path resolution.
namespace (Namespace): addressing authority for symlink ops.
job_table (JobTable): background job management.
execute_fn (Callable): recursive execute (for source/eval).
agent_id (str): current agent ID for jobs.
node (Any): tree-sitter node to execute.
session (Session): shell session state.
stdin (Any): input stream.
call_stack (CallStack): shell call stack.
cancel (asyncio.Event | None): event used to abort mid-flight.
"""
if cancel is not None and cancel.is_set():
raise MirageAbortError()
cs = call_stack or CallStack()
recurse = partial(execute_node,
dispatch,
registry,
namespace,
job_table,
execute_fn,
agent_id,
cancel=cancel)
kind = node_kind(node)
if kind == NodeKind.COMMENT:
return None, IOResult(), ExecutionNode(command="", exit_code=0)
# ── program (root / semicolons) ─────────────
if kind == NodeKind.PROGRAM:
return await execute_program(recurse, node, session, stdin, cs,
job_table, agent_id)
# ── command ─────────────────────────────────
if kind == NodeKind.COMMAND:
return await execute_command(recurse,
dispatch,
registry,
namespace,
execute_fn,
node,
session,
stdin,
cs,
job_table,
cancel=cancel)
# ── pipeline ────────────────────────────────
if kind == NodeKind.PIPELINE:
commands, stderr_flags = get_pipeline_commands(node)
return await handle_pipe(recurse, commands, stderr_flags, session,
stdin, cs)
# ── list (&&, ||) ───────────────────────────
if kind == NodeKind.LIST:
left, op, right = get_list_parts(node)
return await handle_connection(recurse, left, op, right, session,
stdin, cs)
# ── redirected statement ────────────────────
if kind == NodeKind.REDIRECT:
command, redirects = get_redirects(node)
if command.type == NT.LIST:
# tree-sitter hoists a trailing redirect over the whole
# &&/|| list; bash binds it to the last command:
# redirected(list(L, op, R), r) == list(L, op, redirected(R, r))
# Re-associate and defer target expansion until R runs, so
# `cd /x && echo hi > f` writes under /x. Compound and
# subshell bodies keep the whole-body redirect (bash group
# semantics).
left, op, right = get_list_parts(command)
wrapped = partial(_recurse_reassociated, recurse, dispatch,
execute_fn, registry, redirects, right)
return await handle_connection(wrapped, left, op, right, session,
stdin, cs)
expanded_redirects, pipe_node = await expand_redirects(
redirects, session, execute_fn, registry, cs)
stdout, io, exec_node = await handle_redirect(recurse, dispatch,
command,
expanded_redirects,
session, stdin, cs)
if pipe_node is not None and stdout is not None:
stdout, io2, exec_node2 = await recurse(pipe_node, session, stdout,
cs)
io = await io.merge(io2)
exec_node = exec_node2
return stdout, io, exec_node
# ── subshell ────────────────────────────────
if kind == NodeKind.SUBSHELL:
body = get_subshell_body(node)
return await handle_subshell(recurse, body, session, stdin, cs)
# ── arithmetic command ((( ... ))) ──────────
if (kind == NodeKind.COMPOUND and node.children
and node.children[0].type == NT.ARITH_OPEN):
text = get_text(node)
expr = await expand_arith(node, session, execute_fn, cs)
try:
value, updates = evaluate_arith(expr, session.env)
except ArithError as exc:
err = f"bash: ((: {expr}: {exc}\n".encode()
return None, IOResult(exit_code=1,
stderr=err), ExecutionNode(command=text,
exit_code=1,
stderr=err)
for name in updates:
if name in session.readonly_vars:
err = f"bash: {name}: readonly variable\n".encode()
return None, IOResult(exit_code=1,
stderr=err), ExecutionNode(command=text,
exit_code=1,
stderr=err)
session.env.update(updates)
code = 0 if value != 0 else 1
return None, IOResult(exit_code=code), ExecutionNode(command=text,
exit_code=code)
# ── compound statement ({ ... }) ───────────
if kind == NodeKind.COMPOUND:
all_stdout: list = []
merged_io = IOResult()
last_exec = ExecutionNode(command="{}", exit_code=0)
for child in node.named_children:
if child.type == NT.COMMENT:
continue
stdout, io, last_exec = await recurse(child, session, stdin, cs)
if stdout is not None:
all_stdout.append(stdout)
merged_io = await merged_io.merge(io)
if (io.exit_code != 0 and session.shell_options.get("errexit")
and child.type not in ERREXIT_EXEMPT_TYPES):
merged_io.exit_code = io.exit_code
break
if len(all_stdout) == 1:
return all_stdout[0], merged_io, last_exec
combined = async_chain(*all_stdout) if all_stdout else None
return combined, merged_io, last_exec
# ── if ──────────────────────────────────────
if kind == NodeKind.IF:
branches, else_body = get_if_branches(node)
return await handle_if(recurse, branches, else_body, session, stdin,
cs)
# ── for / select ────────────────────────────
if kind in (NodeKind.FOR, NodeKind.SELECT):
var, values, body = get_for_parts(node)
classified = await expand_and_classify(values, session, execute_fn,
registry, session.cwd, cs)
# The loop word list is consumed by the shell (WordPolicy.SHELL):
# globs resolve to matches before iteration starts.
classified = await resolve_globs(classified, registry)
if kind == NodeKind.SELECT:
return await handle_select(recurse, var, classified, body, session,
stdin, cs)
return await handle_for(recurse, var, classified, body, session, stdin,
cs)
# ── while / until ───────────────────────────
if kind in (NodeKind.WHILE, NodeKind.UNTIL):
condition, body = get_while_parts(node)
if kind == NodeKind.UNTIL:
return await handle_until(recurse, condition, body, session, stdin,
cs)
return await handle_while(recurse, condition, body, session, stdin, cs)
# ── case ────────────────────────────────────
if kind == NodeKind.CASE:
word_node = get_case_word(node)
word = await expand_node(word_node, session, execute_fn, cs)
items = get_case_items(node)
return await handle_case(recurse, word, items, session, stdin, cs)
# ── function definition ─────────────────────
if kind == NodeKind.FUNCTION_DEF:
name = get_function_name(node)
body = get_function_body(node)
session.functions[name] = body
return None, IOResult(), ExecutionNode(command=f"function {name}",
exit_code=0)
# ── declaration (export/local/declare/readonly) ──
if kind == NodeKind.DECLARATION:
keyword = get_declaration_keyword(node)
assignments = []
flag_chars: set[str] = set()
for child in node.named_children:
if child.type == NT.VARIABLE_ASSIGNMENT:
val_nodes = [
c for c in child.named_children
if c.type != NT.VARIABLE_NAME
]
if val_nodes and val_nodes[0].type == NT.ARRAY:
key = get_text(child).partition("=")[0]
items = [
await expand_node(ac, session, execute_fn, cs)
for ac in val_nodes[0].named_children
]
session.arrays[key] = items
continue
expanded = await expand_node(child, session, execute_fn, cs)
assignments.append(expanded)
elif child.type in (NT.SIMPLE_EXPANSION, NT.EXPANSION,
NT.CONCATENATION, NT.WORD):
expanded = await expand_node(child, session, execute_fn, cs)
if not expanded:
continue
if expanded.startswith("-") and len(expanded) > 1:
flag_chars.update(expanded[1:])
else:
assignments.append(expanded)
if keyword == NT.LOCAL:
return await handle_local(assignments, session)
if keyword == "readonly" or "r" in flag_chars:
return await handle_readonly(assignments, session)
return await handle_export(assignments, session)
# ── unset ───────────────────────────────────
if kind == NodeKind.UNSET:
names = get_unset_names(node)
return await handle_unset(names, session)
# ── test ([ ] or [[ ]]) ─────────────────────
if kind == NodeKind.TEST:
expanded = await expand_test_expr(node, session, execute_fn, cs,
registry)
return await handle_test(dispatch, expanded, session)
# ── negated command ─────────────────────────
if kind == NodeKind.NEGATED:
inner = get_negated_command(node)
stdout, io, exec_node = await recurse(inner, session, stdin, cs)
io = IOResult(
exit_code=0 if io.exit_code != 0 else 1,
stderr=io.stderr,
reads=io.reads,
writes=io.writes,
cache=io.cache,
)
exec_node.exit_code = io.exit_code
return stdout, io, exec_node
# ── variable assignment at top level ────────
if kind == NodeKind.VAR_ASSIGN:
text = get_text(node)
if "=" in text:
key, _, val = text.partition("=")
if key in session.readonly_vars:
err = f"bash: {key}: readonly variable\n".encode()
return None, IOResult(exit_code=1,
stderr=err), ExecutionNode(command=text,
exit_code=1,
stderr=err)
val_nodes = [
c for c in node.named_children if c.type != NT.VARIABLE_NAME
]
if val_nodes and val_nodes[0].type == NT.ARRAY:
items = []
for ac in val_nodes[0].named_children:
items.append(await expand_node(ac, session, execute_fn,
cs))
session.arrays[key] = items
session.env.pop(key, None)
return None, IOResult(), ExecutionNode(command=text,
exit_code=0)
if val_nodes:
val = await expand_node(val_nodes[0], session, execute_fn, cs)
session.env[key] = val
session.arrays.pop(key, None)
return None, IOResult(), ExecutionNode(command=text, exit_code=0)
raise TypeError(f"unsupported tree-sitter node type: {node.type}")