@nexus-cortex/server 4.124.31 → 4.124.32
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/.cortex/inventory +390 -0
- package/.cortex/orient +40 -13
- package/package.json +3 -3
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Canonical workspace inventory (CORTEX_INVENTORY=1, dark, 2026-09-29). Vendored by prepack to <pkg>/.cortex/inventory beside the orient
|
|
3
|
+
# scaffold. ONE mechanical, read-only picture of the task workspace that feeds BOTH the action model (orient prints it) and the steering models
|
|
4
|
+
# (the lift planner / EndTurn judge environment report). Evidence (r-orient-deficiencies-2026-09-29, r-steering-input-truncation-2026-09-29):
|
|
5
|
+
# flaky MiMo / TB4.0 / TB2.1 pairs diverge in the first 30 actions on workspace knowledge — the checker or contract not surfaced, a deep or
|
|
6
|
+
# out-of-workdir asset never shown (the lift plan names an asset only when orient showed it: TB4 0/6 vs 4/4), a listed file whose ROLE was not
|
|
7
|
+
# understood (a raw weights blob, a comma-decimal data file, a .dat that is a ZIP), the site-packages copy shadowing the workspace copy, a
|
|
8
|
+
# declared dependency silently missing.
|
|
9
|
+
# RULES: read-only (writes nothing, anywhere); no secrets (the task's own env comes from /proc/1/environ, harness vars and anything named
|
|
10
|
+
# *KEY*/*TOKEN*/*SECRET*/*PASSWORD* are dropped/redacted — transcripts are banked); priority sections are never capped; every capped section
|
|
11
|
+
# ends with "… N more … — <exact command>" so nothing is silently truncated. Always exits 0.
|
|
12
|
+
W="${1:-$(pwd)}"
|
|
13
|
+
cd "$W" 2>/dev/null || { echo "== WORKSPACE INVENTORY: $W (not accessible) =="; exit 0; }
|
|
14
|
+
PY=$(command -v python3 2>/dev/null || command -v python 2>/dev/null)
|
|
15
|
+
if [ -z "$PY" ]; then
|
|
16
|
+
# No interpreter: the shell-only inventory (structure + roles by name + env + services). Still no silent truncation.
|
|
17
|
+
echo "== WORKSPACE INVENTORY: $W (shell-only: no python on this box) =="
|
|
18
|
+
PRUNE='( -name .git -o -name node_modules -o -name __pycache__ -o -name .venv -o -name venv -o -name .cortex -o -name .cache ) -prune -o'
|
|
19
|
+
# shellcheck disable=SC2086
|
|
20
|
+
N=$(find . $PRUNE -type f -print 2>/dev/null | wc -l | tr -d ' ')
|
|
21
|
+
echo "files: $N (excluding .git node_modules __pycache__ venvs .cortex .cache)"
|
|
22
|
+
echo "-- directories (file counts) --"
|
|
23
|
+
# shellcheck disable=SC2086
|
|
24
|
+
find . -maxdepth 3 $PRUNE -type d -print 2>/dev/null | sed 's#^\./##' | grep -v '^\.$' | sort | head -60 | while read -r d; do
|
|
25
|
+
printf ' %s/ (%s)\n' "$d" "$(find "$d" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')"; done
|
|
26
|
+
echo "-- files at depth <= 3 --"
|
|
27
|
+
# shellcheck disable=SC2086
|
|
28
|
+
L=$(find . -maxdepth 3 $PRUNE -type f -print 2>/dev/null | sed 's#^\./##' | sort)
|
|
29
|
+
C=$(printf '%s\n' "$L" | grep -c . )
|
|
30
|
+
printf '%s\n' "$L" | head -150 | sed 's/^/ /'
|
|
31
|
+
[ "$C" -gt 150 ] && echo " … $((C-150)) more files at depth <= 3 not shown — list all: find . -type f -not -path './.git/*'"
|
|
32
|
+
for d in /shared /data /mnt /srv /workspace /input /inputs /output /outputs; do
|
|
33
|
+
[ -d "$d" ] && [ "$d" != "$W" ] && [ -n "$(ls -A "$d" 2>/dev/null)" ] && echo "-- outside the workdir: $d ($(find "$d" -maxdepth 4 -type f 2>/dev/null | head -2000 | wc -l | tr -d ' ') files, first 2000 / depth 4 counted) — list: find $d -type f"
|
|
34
|
+
done
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
exec "$PY" - "$W" <<'PYINV'
|
|
38
|
+
import ast, json, os, re, subprocess, sys
|
|
39
|
+
|
|
40
|
+
W = os.path.abspath(sys.argv[1])
|
|
41
|
+
SKIP_DIRS = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', '.cortex', '.cache', '.pytest_cache', '.mypy_cache', '.tox', '.npm',
|
|
42
|
+
'.gradle', '.m2', 'site-packages', 'dist-packages', '.idea', '.vscode', '.addon-tools'}
|
|
43
|
+
MAX_WALK = 60000
|
|
44
|
+
out = []
|
|
45
|
+
p = out.append
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def rel(x):
|
|
49
|
+
return os.path.relpath(x, W)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def more(n, what, cmd):
|
|
53
|
+
return f' … {n} more {what} not shown — {cmd}'
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ---------------------------------------------------------------- walk (bounded; never follows symlinked dirs)
|
|
57
|
+
files, dirs = [], {}
|
|
58
|
+
walked = 0
|
|
59
|
+
truncated_walk = False
|
|
60
|
+
for dp, dns, fns in os.walk(W, topdown=True, followlinks=False):
|
|
61
|
+
dns[:] = sorted(d for d in dns if d not in SKIP_DIRS and not d.endswith('.egg-info'))
|
|
62
|
+
r = rel(dp)
|
|
63
|
+
dirs[r] = len(fns)
|
|
64
|
+
for f in sorted(fns):
|
|
65
|
+
fp = os.path.join(dp, f)
|
|
66
|
+
try:
|
|
67
|
+
st = os.lstat(fp)
|
|
68
|
+
except OSError:
|
|
69
|
+
continue
|
|
70
|
+
files.append((rel(fp), st.st_size))
|
|
71
|
+
walked += 1
|
|
72
|
+
if walked >= MAX_WALK:
|
|
73
|
+
truncated_walk = True
|
|
74
|
+
break
|
|
75
|
+
if truncated_walk:
|
|
76
|
+
break
|
|
77
|
+
|
|
78
|
+
# ---------------------------------------------------------------- role classification + peeks
|
|
79
|
+
SCRIPT = re.compile(r'\.(py|sh|bash|js|mjs|cjs|ts|tsx|rb|pl|go|rs|c|cc|cpp|h|hpp|java|kt|r|jl|lua|php|swift|scala|m)$', re.I)
|
|
80
|
+
DOC = re.compile(r'\.(md|rst|txt|adoc|pdf|html?|docx?|odt)$', re.I)
|
|
81
|
+
DATA = re.compile(r'\.(csv|tsv|jsonl|ndjson|json|parquet|feather|arrow|npy|npz|pkl|pickle|h5|hdf5|db|sqlite3?|xlsx?|xml|ya?ml|toml|ini|cfg|'
|
|
82
|
+
r'dat|bin|raw|gz|zip|tar|tgz|bz2|xz|7z|fa|fasta|fastq|bam|sam|vcf|bed|gff3?|pdb|cif|wav|mp3|flac|png|jpe?g|gif|bmp|tiff?|svg|'
|
|
83
|
+
r'stl|step|stp|obj|ply|glb|gltf|ckpt|pt|pth|safetensors|onnx|gguf|mat|nc|log|ttf|otf|woff2?)$', re.I)
|
|
84
|
+
CHECKER = re.compile(r'(check|verif|validat|grade|grader|probe|evaluat|eval|scor|judge|assert|audit|regression|smoke|harness|contract_runner|'
|
|
85
|
+
r'run_tests?|run_[a-z0-9_-]+|workflow|diagnos|benchmark|bench)[^/]*\.(py|sh|js|ts|mjs)$', re.I)
|
|
86
|
+
CONTRACT = re.compile(r'(contract|schema|spec|expected|golden|reference|cases|fixture|sample_output|example_output|output_format|interface|'
|
|
87
|
+
r'requirements?_spec|acceptance)[^/]*\.(json|ya?ml|toml|md|txt|csv|jsonl)$|(^|/)(CONTRACT|SPEC|REPAIR_CONTRACT|'
|
|
88
|
+
r'ACCEPTANCE)[^/]*$', re.I)
|
|
89
|
+
TESTF = re.compile(r'(^|/)(tests?|spec|__tests__)/|(^|/)test_[^/]+$|_test\.[a-z]+$|\.test\.[a-z]+$|\.spec\.[a-z]+$', re.I)
|
|
90
|
+
MANIFEST = re.compile(r'(^|/)(requirements[^/]*\.txt|pyproject\.toml|setup\.py|setup\.cfg|Pipfile|environment\.ya?ml|package\.json|Cargo\.toml|'
|
|
91
|
+
r'go\.mod|Gemfile|pom\.xml|build\.gradle|CMakeLists\.txt|Makefile|Dockerfile|docker-compose[^/]*\.ya?ml|tox\.ini|pytest\.ini|'
|
|
92
|
+
r'conftest\.py|\.env\.example)$', re.I)
|
|
93
|
+
VENDOR = re.compile(r'(^|/)(vendor|third_party|external|deps|_offline_deps|offline_deps|runtime_compat|wheels)/', re.I)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def role(path):
|
|
97
|
+
if CHECKER.search(path) and not TESTF.search(path): return 'checker/runner'
|
|
98
|
+
if CONTRACT.search(path): return 'contract/spec'
|
|
99
|
+
if MANIFEST.search(path): return 'manifest/config'
|
|
100
|
+
if TESTF.search(path): return 'test'
|
|
101
|
+
if SCRIPT.search(path): return 'source'
|
|
102
|
+
if DOC.search(path) or re.search(r'(^|/)(README|NOTES|INSTRUCTIONS|TODO|CHANGELOG|LICENSE)[^/]*$', path, re.I): return 'doc'
|
|
103
|
+
if DATA.search(path): return 'data'
|
|
104
|
+
return 'other'
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def head_bytes(path, n=4096):
|
|
108
|
+
try:
|
|
109
|
+
with open(os.path.join(W, path), 'rb') as fh:
|
|
110
|
+
return fh.read(n)
|
|
111
|
+
except OSError:
|
|
112
|
+
return b''
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
MAGIC = [(b'PK\x03\x04', 'zip archive'), (b'\x1f\x8b', 'gzip'), (b'BZh', 'bzip2'), (b'\xfd7zXZ', 'xz'), (b'7z\xbc\xaf', '7z'),
|
|
116
|
+
(b'\x89PNG', 'png image'), (b'\xff\xd8\xff', 'jpeg image'), (b'GIF8', 'gif image'), (b'%PDF', 'pdf'), (b'SQLite format 3', 'sqlite db'),
|
|
117
|
+
(b'\x7fELF', 'ELF binary'), (b'\x93NUMPY', 'numpy array'), (b'\x80\x02', 'pickle'), (b'\x80\x04', 'pickle'), (b'\x80\x05', 'pickle'),
|
|
118
|
+
(b'RIFF', 'riff (wav/avi)'), (b'ustar', 'tar')]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def human(n):
|
|
122
|
+
for u in ('B', 'KB', 'MB', 'GB'):
|
|
123
|
+
if n < 1024 or u == 'GB':
|
|
124
|
+
return f'{n:.0f}{u}' if u == 'B' else f'{n:.1f}{u}'
|
|
125
|
+
n /= 1024
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def peek(path, size, rl):
|
|
129
|
+
b = head_bytes(path)
|
|
130
|
+
if not b:
|
|
131
|
+
return 'empty' if size == 0 else ''
|
|
132
|
+
for sig, name in MAGIC:
|
|
133
|
+
if b.startswith(sig) or (sig == b'ustar' and b[257:262] == b'ustar'):
|
|
134
|
+
ext = os.path.splitext(path)[1].lower()
|
|
135
|
+
expect = {'.zip': 'zip', '.gz': 'gzip', '.png': 'png', '.jpg': 'jpeg', '.jpeg': 'jpeg', '.pdf': 'pdf', '.db': 'sqlite',
|
|
136
|
+
'.sqlite': 'sqlite', '.npy': 'numpy', '.pkl': 'pickle', '.tar': 'tar', '.xz': 'xz', '.bz2': 'bzip2', '.wav': 'riff'}
|
|
137
|
+
mism = ext and ext in expect and expect[ext] not in name
|
|
138
|
+
unexpected = ext and ext not in expect and name not in ('ELF binary',)
|
|
139
|
+
tag = name + (f' (NOTE: content is {name}, not what "{ext}" suggests)' if (mism or unexpected) else '')
|
|
140
|
+
return tag
|
|
141
|
+
try:
|
|
142
|
+
t = b.decode('utf-8')
|
|
143
|
+
except UnicodeDecodeError:
|
|
144
|
+
nz = sum(1 for c in b[:512] if c == 0)
|
|
145
|
+
return f'binary ({nz} NUL bytes in first 512; e.g. raw array / weights / packed data)'
|
|
146
|
+
lines = t.splitlines()
|
|
147
|
+
if rl == 'data' or re.search(r'\.(csv|tsv|dat|txt)$', path, re.I):
|
|
148
|
+
first = next((l for l in lines if l.strip()), '')[:160]
|
|
149
|
+
body = [l for l in lines[:12] if l.strip()][1:6]
|
|
150
|
+
note = ''
|
|
151
|
+
if any(re.search(r'\d,\d', l) and ';' in l for l in body): note = ' (NOTE: ";"-separated with comma decimals, e.g. ' + body[0][:40] + ')'
|
|
152
|
+
elif any(re.match(r'^\s*-?\d+,\d+[\s\t]+-?\d+,\d+', l) for l in body): note = ' (NOTE: comma decimals, e.g. ' + body[0][:40] + ')'
|
|
153
|
+
if path.lower().endswith(('.json',)) or first.lstrip().startswith(('{', '[')):
|
|
154
|
+
try:
|
|
155
|
+
with open(os.path.join(W, path), encoding='utf-8') as fh:
|
|
156
|
+
obj = json.load(fh) if size < 2_000_000 else None
|
|
157
|
+
if isinstance(obj, dict): return 'json object, keys: ' + ', '.join(list(obj)[:14]) + (' …' if len(obj) > 14 else '')
|
|
158
|
+
if isinstance(obj, list): return f'json array[{len(obj)}]' + (', item keys: ' + ', '.join(list(obj[0])[:12]) if obj and isinstance(obj[0], dict) else '')
|
|
159
|
+
except Exception:
|
|
160
|
+
pass
|
|
161
|
+
return f'first line: {first}{note}' if first else 'text'
|
|
162
|
+
if rl in ('source', 'checker/runner', 'test'):
|
|
163
|
+
if path.endswith('.py'):
|
|
164
|
+
try:
|
|
165
|
+
src = open(os.path.join(W, path), encoding='utf-8', errors='replace').read() if size < 2_000_000 else t
|
|
166
|
+
tree = ast.parse(src)
|
|
167
|
+
defs = [n.name for n in tree.body if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef))]
|
|
168
|
+
main = '__main__' in src
|
|
169
|
+
return (('defines: ' + ', '.join(defs[:10]) + (' …' if len(defs) > 10 else '')) if defs else 'no top-level defs') + \
|
|
170
|
+
(' | runnable (__main__)' if main else '') + f' | {src.count(chr(10))} lines'
|
|
171
|
+
except Exception:
|
|
172
|
+
pass
|
|
173
|
+
defs = re.findall(r'^(?:export\s+)?(?:async\s+)?(?:function|class|def|fn|func|interface|struct)\s+([A-Za-z_][\w]*)', t, re.M)
|
|
174
|
+
return ('defines: ' + ', '.join(defs[:10]) if defs else f'{len(lines)}+ lines')
|
|
175
|
+
if rl == 'doc':
|
|
176
|
+
first = next((l.strip('# ').strip() for l in lines if l.strip()), '')
|
|
177
|
+
return f'"{first[:120]}"'
|
|
178
|
+
return ''
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
classified = [(f, s, role(f)) for f, s in files]
|
|
182
|
+
by_role = {}
|
|
183
|
+
for f, s, r in classified:
|
|
184
|
+
by_role.setdefault(r, []).append((f, s))
|
|
185
|
+
|
|
186
|
+
# ---------------------------------------------------------------- header
|
|
187
|
+
p(f'== WORKSPACE INVENTORY: {W} ==')
|
|
188
|
+
p(f'{len(files)} files in {len(dirs)} dirs (excluded: ' + ', '.join(sorted(SKIP_DIRS)[:8]) + ' …)' +
|
|
189
|
+
(f' — WALK STOPPED at {MAX_WALK} files; the rest is not listed — find . -type f | wc -l' if truncated_walk else ''))
|
|
190
|
+
counts = ', '.join(f'{r} {len(v)}' for r, v in sorted(by_role.items(), key=lambda kv: -len(kv[1])))
|
|
191
|
+
p('by role: ' + counts)
|
|
192
|
+
|
|
193
|
+
# ---------------------------------------------------------------- 1. verification + contracts (PRIORITY — never capped)
|
|
194
|
+
chk = by_role.get('checker/runner', []); con = by_role.get('contract/spec', [])
|
|
195
|
+
if chk or con:
|
|
196
|
+
p('-- HOW THIS TASK IS CHECKED (task-shipped checkers/runners and contracts — read these before building) --')
|
|
197
|
+
for f, s in chk:
|
|
198
|
+
src = head_bytes(f, 200_000).decode('utf-8', 'replace')
|
|
199
|
+
usage = next((l.strip() for l in src.splitlines() if re.search(r'usage|^ *Run:|add_argument|sys\.argv|getopts', l, re.I)), '')
|
|
200
|
+
writes = sorted(set(re.findall(r'["\']([\w./-]+\.(?:json|jsonl|csv|txt|md|yaml|yml|html|png))["\']', src)))[:6]
|
|
201
|
+
consts = sorted(set(re.findall(r'["\']?(schema[_-]?version|SCHEMA[_A-Z]*|output_schema[_a-z]*)["\']?\s*[:=]\s*["\']?([\w.:-]+)', src)))[:4]
|
|
202
|
+
line = f' [checker] {f} ({human(s)})'
|
|
203
|
+
if VENDOR.search(f): line += ' — inside a vendored project'
|
|
204
|
+
p(line)
|
|
205
|
+
if usage: p(f' usage: {usage[:160]}')
|
|
206
|
+
if writes: p(' references: ' + ', '.join(writes))
|
|
207
|
+
if consts: p(' constants: ' + ', '.join(f'{a}={b}' for a, b in consts))
|
|
208
|
+
for f, s in con:
|
|
209
|
+
p(f' [contract] {f} ({human(s)}) — {peek(f, s, "data" if not f.lower().endswith(".md") else "doc")}'[:260])
|
|
210
|
+
tests = sorted({os.path.dirname(f) for f, _ in by_role.get('test', []) if os.path.dirname(f)})
|
|
211
|
+
if tests:
|
|
212
|
+
shown = tests[:12]
|
|
213
|
+
p(' test dirs: ' + ', '.join(shown) + (f' (+{len(tests)-12} more — find . -type d -name "test*")' if len(tests) > 12 else ''))
|
|
214
|
+
|
|
215
|
+
# ---------------------------------------------------------------- 2. structure: every dir with counts (capped with marker)
|
|
216
|
+
p('-- STRUCTURE (dir: files directly inside) --')
|
|
217
|
+
dl = sorted(d for d in dirs if d != '.')
|
|
218
|
+
top = [d for d in dl if d.count('/') <= 1]
|
|
219
|
+
for d in top[:60]:
|
|
220
|
+
sub = sum(1 for x in dl if x.startswith(d + '/'))
|
|
221
|
+
p(f' {d}/ ({dirs[d]} files' + (f', {sub} subdirs' if sub else '') + ')')
|
|
222
|
+
if len(top) > 60:
|
|
223
|
+
p(more(len(top) - 60, 'directories at depth <= 2', 'find . -maxdepth 2 -type d'))
|
|
224
|
+
deep = [d for d in dl if d.count('/') > 1]
|
|
225
|
+
if deep:
|
|
226
|
+
p(f' ({len(deep)} deeper directories — find . -mindepth 3 -type d)')
|
|
227
|
+
|
|
228
|
+
# ---------------------------------------------------------------- 3. files by role with a peek (priority roles in full, bulk capped)
|
|
229
|
+
CAPS = {'source': 40, 'doc': 30, 'data': 40, 'manifest/config': 30, 'test': 20, 'other': 20}
|
|
230
|
+
ORDER = ['doc', 'manifest/config', 'source', 'data', 'test', 'other']
|
|
231
|
+
for r in ORDER:
|
|
232
|
+
items = by_role.get(r, [])
|
|
233
|
+
if not items: continue
|
|
234
|
+
# task files before vendored ones; shallow before deep
|
|
235
|
+
items = sorted(items, key=lambda x: (bool(VENDOR.search(x[0])), x[0].count('/'), x[0]))
|
|
236
|
+
cap = CAPS[r]
|
|
237
|
+
p(f'-- {r.upper()} ({len(items)}) --')
|
|
238
|
+
for f, s in items[:cap]:
|
|
239
|
+
pk = peek(f, s, r) if r in ('doc', 'data', 'source', 'other', 'manifest/config') else ''
|
|
240
|
+
p(f' {f} ({human(s)})' + (f' — {pk}' if pk else ''))
|
|
241
|
+
if len(items) > cap:
|
|
242
|
+
vend = sum(1 for f, _ in items[cap:] if VENDOR.search(f))
|
|
243
|
+
p(more(len(items) - cap, f'{r} files' + (f' ({vend} in vendored trees)' if vend else ''),
|
|
244
|
+
f'list: find . -type f | grep -v -e .git/ -e node_modules (role here = {r})'))
|
|
245
|
+
|
|
246
|
+
# ---------------------------------------------------------------- 4. python: which interpreter, which copy of the code runs, missing deps
|
|
247
|
+
def run(cmd, timeout=20):
|
|
248
|
+
try:
|
|
249
|
+
r = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout, cwd=W)
|
|
250
|
+
return (r.stdout or '') + (r.stderr or '')
|
|
251
|
+
except Exception as e:
|
|
252
|
+
return ''
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
p('-- PYTHON --')
|
|
256
|
+
p(f' interpreter: {sys.executable} ({sys.version.split()[0]})' + (f' | VIRTUAL_ENV={os.environ.get("VIRTUAL_ENV")}' if os.environ.get('VIRTUAL_ENV') else ''))
|
|
257
|
+
pkgs = []
|
|
258
|
+
for d in sorted(dirs):
|
|
259
|
+
parts = d.split('/')
|
|
260
|
+
if d == '.' or len(parts) > 4: continue
|
|
261
|
+
if os.path.isfile(os.path.join(W, d, '__init__.py')) and not os.path.isfile(os.path.join(W, os.path.dirname(d) or '.', '__init__.py')):
|
|
262
|
+
pkgs.append(d)
|
|
263
|
+
pkgs = [x for x in pkgs if not TESTF.search(x + '/')][:12]
|
|
264
|
+
for d in pkgs:
|
|
265
|
+
name = os.path.basename(d); parent = os.path.dirname(d) or '.'
|
|
266
|
+
res = run([sys.executable, '-c', f'import {name},os;print(os.path.abspath({name}.__file__))'], 20).strip().splitlines()
|
|
267
|
+
where = res[-1] if res else ''
|
|
268
|
+
ws_copy = os.path.join(W, d)
|
|
269
|
+
if where.startswith(ws_copy):
|
|
270
|
+
p(f' import {name} → the workspace copy ({d}/)')
|
|
271
|
+
elif where.startswith('/'):
|
|
272
|
+
p(f' import {name} → {where} ⚠ NOT the workspace copy ({d}/) — run with PYTHONPATH={os.path.join(W, parent)} to use/test the workspace code')
|
|
273
|
+
else:
|
|
274
|
+
err = next((l for l in res if 'Error' in l), 'fails')
|
|
275
|
+
p(f' import {name} (workspace {d}/) → {err[:120]} from {W}; with PYTHONPATH={os.path.join(W, parent)} it resolves to the workspace copy')
|
|
276
|
+
extra = sorted(d for d in dirs if re.search(r'(^|/)(_?offline_deps|runtime_compat|wheels|vendor_deps)$', d, re.I))[:6]
|
|
277
|
+
if extra:
|
|
278
|
+
p(' dependency dirs shipped with the task: ' + ', '.join(extra) + ' (add to PYTHONPATH / pip install --no-index --find-links as appropriate)')
|
|
279
|
+
# declared vs installed
|
|
280
|
+
declared = []
|
|
281
|
+
for f, _ in by_role.get('manifest/config', []):
|
|
282
|
+
if VENDOR.search(f) and f.count('/') > 2: continue
|
|
283
|
+
b = os.path.basename(f).lower()
|
|
284
|
+
try:
|
|
285
|
+
txt = open(os.path.join(W, f), encoding='utf-8', errors='replace').read()
|
|
286
|
+
except OSError:
|
|
287
|
+
continue
|
|
288
|
+
if b.startswith('requirements') and b.endswith('.txt'):
|
|
289
|
+
declared += [(re.split(r'[<>=!~\[; ]', l.strip())[0], f) for l in txt.splitlines() if l.strip() and not l.strip().startswith(('#', '-'))]
|
|
290
|
+
elif b == 'pyproject.toml':
|
|
291
|
+
m = re.search(r'dependencies\s*=\s*\[(.*?)\]', txt, re.S)
|
|
292
|
+
if m: declared += [(re.split(r'[<>=!~\[; ]', x.strip().strip('"\''))[0], f) for x in m.group(1).split(',') if x.strip().strip('"\'')]
|
|
293
|
+
missing = []
|
|
294
|
+
if declared:
|
|
295
|
+
try:
|
|
296
|
+
from importlib import metadata as md
|
|
297
|
+
have = {re.sub(r'[-_.]+', '-', (d.metadata['Name'] or '').lower()) for d in md.distributions()}
|
|
298
|
+
except Exception:
|
|
299
|
+
have = set()
|
|
300
|
+
for name, src in declared:
|
|
301
|
+
if name and re.sub(r'[-_.]+', '-', name.lower()) not in have:
|
|
302
|
+
missing.append(f'{name} ({src})')
|
|
303
|
+
missing = sorted(set(missing))
|
|
304
|
+
if missing:
|
|
305
|
+
p(' declared but NOT installed: ' + ', '.join(missing[:30]) + (f' … +{len(missing)-30} more' if len(missing) > 30 else ''))
|
|
306
|
+
else:
|
|
307
|
+
p(f' all {len(declared)} declared python dependencies are installed')
|
|
308
|
+
|
|
309
|
+
# ---------------------------------------------------------------- 5. node
|
|
310
|
+
pj = [f for f, _ in by_role.get('manifest/config', []) if os.path.basename(f) == 'package.json' and f.count('/') <= 2 and 'node_modules' not in f]
|
|
311
|
+
for f in pj[:3]:
|
|
312
|
+
try:
|
|
313
|
+
o = json.load(open(os.path.join(W, f)))
|
|
314
|
+
except Exception:
|
|
315
|
+
continue
|
|
316
|
+
deps = list((o.get('dependencies') or {})) + list((o.get('devDependencies') or {}))
|
|
317
|
+
nm = os.path.join(W, os.path.dirname(f), 'node_modules')
|
|
318
|
+
miss = [d for d in deps if not os.path.isdir(os.path.join(nm, d))]
|
|
319
|
+
scripts = list((o.get('scripts') or {}))
|
|
320
|
+
p(f'-- NODE {f}: scripts: ' + (', '.join(scripts[:12]) or 'none') + f' | {len(deps)} deps' +
|
|
321
|
+
(f', NOT installed: {", ".join(miss[:20])}' + (' …' if len(miss) > 20 else '') if miss else (', node_modules present' if os.path.isdir(nm) else ', no node_modules')))
|
|
322
|
+
|
|
323
|
+
# ---------------------------------------------------------------- 6. task environment (from the container's own init env; secrets redacted)
|
|
324
|
+
BOILER = {'PATH', 'HOME', 'HOSTNAME', 'TERM', 'SHLVL', 'PWD', 'OLDPWD', '_', 'LANG', 'LC_ALL', 'DEBIAN_FRONTEND', 'container', 'GPG_KEY',
|
|
325
|
+
'PYTHON_VERSION', 'PYTHON_SHA256', 'PYTHON_PIP_VERSION', 'PYTHON_GET_PIP_URL', 'PYTHON_GET_PIP_SHA256', 'PYTHON_SETUPTOOLS_VERSION',
|
|
326
|
+
'NODE_VERSION', 'YARN_VERSION', 'LS_COLORS', 'SSL_CERT_DIR', 'SSL_CERT_FILE', 'NVIDIA_VISIBLE_DEVICES', 'NVIDIA_DRIVER_CAPABILITIES'}
|
|
327
|
+
HARNESS = re.compile(r'^(CORTEX_|TB2_|MENTORSHIP_|HELPER_|VISION_|NEXUS_|OMNI|ANTHROPIC|OPENAI|DEEPSEEK|XAI|GROQ|GEMINI|GOOGLE_API|MISTRAL|'
|
|
328
|
+
r'TYPESAFE|HF_|HUGGING|MODEL_|DEFAULT_MODEL|MAX_TOOL|TOOL_TIMEOUT|ENABLE_WEBTOOLS|CANON_|NODE_OPTIONS|NPM_|BENCH_|HARBOR)')
|
|
329
|
+
SECRET = re.compile(r'(KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH|COOKIE|SESSION)', re.I)
|
|
330
|
+
env = {}
|
|
331
|
+
try:
|
|
332
|
+
raw = open('/proc/1/environ', 'rb').read().split(b'\0')
|
|
333
|
+
for kv in raw:
|
|
334
|
+
if b'=' in kv:
|
|
335
|
+
k, v = kv.split(b'=', 1); env[k.decode('utf-8', 'replace')] = v.decode('utf-8', 'replace')
|
|
336
|
+
src_note = 'from the container init process'
|
|
337
|
+
except Exception:
|
|
338
|
+
src_note = None
|
|
339
|
+
if src_note is not None:
|
|
340
|
+
keep = []
|
|
341
|
+
for k in sorted(env):
|
|
342
|
+
if k in BOILER or HARNESS.search(k): continue
|
|
343
|
+
v = env[k]
|
|
344
|
+
if SECRET.search(k): v = '<redacted>'
|
|
345
|
+
keep.append(f'{k}={v[:120]}')
|
|
346
|
+
if keep:
|
|
347
|
+
p(f'-- TASK ENVIRONMENT ({src_note}; boilerplate and harness variables omitted, secrets redacted) --')
|
|
348
|
+
for kv in keep[:40]: p(' ' + kv)
|
|
349
|
+
if len(keep) > 40: p(more(len(keep) - 40, 'variables', 'cat /proc/1/environ | tr "\\0" "\\n"'))
|
|
350
|
+
|
|
351
|
+
# ---------------------------------------------------------------- 7. services + paths outside the workdir
|
|
352
|
+
hosts = []
|
|
353
|
+
try:
|
|
354
|
+
for l in open('/etc/hosts'):
|
|
355
|
+
parts = l.split()
|
|
356
|
+
if len(parts) >= 2 and not parts[0].startswith(('#', '127.', '::1', 'fe00', 'ff0')):
|
|
357
|
+
hosts += [h for h in parts[1:] if not re.match(r'^[0-9a-f]{12}$', h) and h not in ('localhost',)]
|
|
358
|
+
except OSError:
|
|
359
|
+
pass
|
|
360
|
+
ports = []
|
|
361
|
+
for f in ('/proc/net/tcp', '/proc/net/tcp6'):
|
|
362
|
+
try:
|
|
363
|
+
for l in open(f).read().splitlines()[1:]:
|
|
364
|
+
x = l.split()
|
|
365
|
+
if len(x) > 3 and x[3] == '0A':
|
|
366
|
+
ports.append(int(x[1].split(':')[1], 16))
|
|
367
|
+
except OSError:
|
|
368
|
+
pass
|
|
369
|
+
urlvars = [f'{k}={env[k][:80]}' for k in sorted(env) if re.search(r'(HOST|PORT|URL|URI|ENDPOINT|ADDR)', k) and not HARNESS.search(k) and not SECRET.search(k)]
|
|
370
|
+
if hosts or ports or urlvars:
|
|
371
|
+
p('-- SERVICES --')
|
|
372
|
+
if hosts: p(' other hosts on this network: ' + ', '.join(sorted(set(hosts))[:20]))
|
|
373
|
+
if ports: p(' listening locally: ' + ', '.join(str(x) for x in sorted(set(ports))[:20]))
|
|
374
|
+
for u in urlvars[:12]: p(' ' + u)
|
|
375
|
+
outside = []
|
|
376
|
+
for d in ('/shared', '/data', '/mnt', '/srv', '/workspace', '/input', '/inputs', '/output', '/outputs', '/reference', '/resources', '/task', '/opt/task'):
|
|
377
|
+
if os.path.isdir(d) and not W.startswith(d) and not d.startswith(W):
|
|
378
|
+
n, capped = 0, False
|
|
379
|
+
try:
|
|
380
|
+
for dp, dns, fs in os.walk(d, followlinks=False): # bounded: a large mount must never stall the inventory
|
|
381
|
+
n += len(fs)
|
|
382
|
+
if n >= 2000 or dp.count('/') - d.count('/') >= 4:
|
|
383
|
+
capped = True; break
|
|
384
|
+
except Exception:
|
|
385
|
+
pass
|
|
386
|
+
if n: outside.append(f'{d} ({n}{"+" if capped else ""} files)')
|
|
387
|
+
if outside:
|
|
388
|
+
p('-- OUTSIDE THE WORKDIR (task data may live here) -- ' + ', '.join(outside) + ' — list: find <dir> -type f | head -100')
|
|
389
|
+
print('\n'.join(out))
|
|
390
|
+
PYINV
|
package/.cortex/orient
CHANGED
|
@@ -5,13 +5,34 @@
|
|
|
5
5
|
# has no .cortex/orient of its own. Deterministic, read-only except for one
|
|
6
6
|
# mechanical .cortex/CORTEX.md render (never overwrites), always exits 0.
|
|
7
7
|
W="$(pwd)"
|
|
8
|
+
# Clean workspace (CORTEX_WORKSPACE_CLEAN=1, dark, 2026-09-29): orient writes nothing into the task's tree. The mechanical CORTEX.md and the
|
|
9
|
+
# baseline go to the harness state dir ($CORTEX_STATE_DIR, else ~/.cortex/projects/<sha1(path)[:12]>, else /tmp/nexus-cortex/<same>, the
|
|
10
|
+
# same order and key as the harness's resolveCortexStateDir). Graders that list the directory or diff the repo (TB2.1 sanitize-git-repo,
|
|
11
|
+
# polyglot listdir == [one file]) see only the model's work. Unset = unchanged.
|
|
12
|
+
CX="$W/.cortex"; CLEAN=0
|
|
13
|
+
case "${CORTEX_WORKSPACE_CLEAN:-0}" in 1|true|TRUE|True|on|ON) CLEAN=1;; esac
|
|
14
|
+
if [ "$CLEAN" = "1" ]; then
|
|
15
|
+
if [ -n "${CORTEX_STATE_DIR:-}" ] && mkdir -p "$CORTEX_STATE_DIR" 2>/dev/null && [ -w "$CORTEX_STATE_DIR" ]; then CX="$CORTEX_STATE_DIR"
|
|
16
|
+
else
|
|
17
|
+
H=$(printf %s "$W" | sha1sum 2>/dev/null | cut -c1-12); [ -n "$H" ] || H=$(printf %s "$W" | cksum | cut -d' ' -f1)
|
|
18
|
+
CX="${HOME:-/tmp}/.cortex/projects/$H"; mkdir -p "$CX" 2>/dev/null && [ -w "$CX" ] || { CX="${TMPDIR:-/tmp}/nexus-cortex/$H"; mkdir -p "$CX" 2>/dev/null; }
|
|
19
|
+
fi
|
|
20
|
+
fi
|
|
21
|
+
# Canonical workspace inventory (CORTEX_INVENTORY=1, dark, 2026-09-29): the full role-labelled inventory (checkers + contracts, every dir,
|
|
22
|
+
# files with a content peek, which copy of the code imports, missing deps, task env, services, data outside the workdir) replaces the
|
|
23
|
+
# workspace map and the v2 verification section; the tooling / git / baseline / setup lines below still print. Unset = unchanged output.
|
|
24
|
+
INV=""; if [ "${CORTEX_INVENTORY:-0}" = "1" ]; then for c in "$(dirname "$0")/inventory" "${CORTEX_ROOT:-/nonexistent}/.cortex/inventory"; do [ -f "$c" ] && { INV="$c"; break; }; done; fi
|
|
25
|
+
if [ -n "$INV" ]; then
|
|
26
|
+
sh "$INV" "$W" 2>/dev/null
|
|
27
|
+
else
|
|
8
28
|
echo "== WORKSPACE MAP: $W =="
|
|
9
29
|
ls -1A "$W" 2>/dev/null | head -40
|
|
30
|
+
fi
|
|
10
31
|
# orient v2 ships DARK (2026-09-27): every v2 section runs only with CORTEX_ORIENT_V2=1; unset = the v1 output byte-for-byte.
|
|
11
32
|
V2="${CORTEX_ORIENT_V2:-0}"
|
|
12
33
|
# orient v2 (2026-09-27, MiMo: the whole library lived under vendor/ and the map showed one level): one more level for the top
|
|
13
34
|
# directories (skipping caches/vendored deps of the toolchain), capped so the map stays small.
|
|
14
|
-
[ "$V2" = "1" ] && for d in $(ls -1A "$W" 2>/dev/null | head -40); do
|
|
35
|
+
[ "$V2" = "1" ] && [ -z "$INV" ] && for d in $(ls -1A "$W" 2>/dev/null | head -40); do
|
|
15
36
|
[ -d "$W/$d" ] || continue
|
|
16
37
|
case "$d" in .git|node_modules|__pycache__|.venv|venv|.cache|.cortex|.addon-tools|dist|build|target) continue;; esac
|
|
17
38
|
n=$(ls -1A "$W/$d" 2>/dev/null | wc -l | tr -d ' ')
|
|
@@ -64,7 +85,7 @@ fi
|
|
|
64
85
|
# protected-file guard (a file outside the task's repair set was modified, usually vendored library code) and the workspaces are not git
|
|
65
86
|
# repos, so nothing could show the agent what it had changed. Record a checksum list ONCE (never overwritten, so a re-run of orient keeps
|
|
66
87
|
# the start state) and ship `.cortex/changed`, which lists modified / added / deleted files against it. POSIX cksum; capped.
|
|
67
|
-
if [ "${CORTEX_ORIENT_BASELINE:-0}" = "1" ]; then
|
|
88
|
+
if [ "${CORTEX_ORIENT_BASELINE:-0}" = "1" ] && [ "$CLEAN" != "1" ]; then
|
|
68
89
|
mkdir -p "$W/.cortex" 2>/dev/null
|
|
69
90
|
cat > "$W/.cortex/changed" 2>/dev/null <<'CHANGED'
|
|
70
91
|
#!/bin/sh
|
|
@@ -85,12 +106,13 @@ CHANGED
|
|
|
85
106
|
fi
|
|
86
107
|
BN=$(wc -l < "$W/.cortex/baseline.cksum" 2>/dev/null | tr -d ' ')
|
|
87
108
|
echo "-- baseline: ${BN:-0} files recorded at start; \`sh .cortex/changed\` lists files you modified/added/deleted. Before finishing, run it and revert every change the task did not require."
|
|
88
|
-
elif [ "${CORTEX_ORIENT_BASELINE:-0}" = "auto" ] && ! { command -v git >/dev/null 2>&1 && git -C "$W" rev-parse --is-inside-work-tree >/dev/null 2>&1; }; then
|
|
109
|
+
elif { [ "${CORTEX_ORIENT_BASELINE:-0}" = "1" ] && [ "$CLEAN" = "1" ]; } || { [ "${CORTEX_ORIENT_BASELINE:-0}" = "auto" ] && ! { command -v git >/dev/null 2>&1 && git -C "$W" rev-parse --is-inside-work-tree >/dev/null 2>&1; }; }; then
|
|
89
110
|
# auto (general work, 2026-09-27): a git repo already has `git status`, so skip it; otherwise keep the baseline OUTSIDE the project
|
|
90
111
|
# (the user's ~/.cortex, else /tmp), keyed by the workspace path, so nothing is written into the tree being worked on.
|
|
91
112
|
KEY=$(printf %s "$W" | cksum | cut -d' ' -f1)
|
|
92
113
|
BD="${HOME:-/tmp}/.cortex/baselines/$KEY"
|
|
93
114
|
mkdir -p "$BD" 2>/dev/null && [ -w "$BD" ] || { BD="${TMPDIR:-/tmp}/cortex-baselines/$KEY"; mkdir -p "$BD" 2>/dev/null; }
|
|
115
|
+
[ "$CLEAN" = "1" ] && { BD="$CX/baseline"; mkdir -p "$BD" 2>/dev/null; }
|
|
94
116
|
{ printf '#!/bin/sh\n# Lists files modified / added / deleted in %s since orient recorded its start state.\nW=%s\nB=%s\n' "$W" "'$W'" "'$BD/baseline.cksum'"
|
|
95
117
|
cat <<'CHANGED'
|
|
96
118
|
cd "$W" || exit 0
|
|
@@ -108,7 +130,11 @@ CHANGED
|
|
|
108
130
|
( cd "$W" && find . \( -path ./.git -o -path ./.cortex -o -name node_modules -o -name __pycache__ -o -name .venv -o -name venv -o -name .cache -o -name .pytest_cache -o -name .mypy_cache \) -prune -o -type f -size -20M -print 2>/dev/null | head -20000 | tr '\n' '\0' | xargs -0 cksum 2>/dev/null > "$BD/baseline.cksum" )
|
|
109
131
|
fi
|
|
110
132
|
BN=$(wc -l < "$BD/baseline.cksum" 2>/dev/null | tr -d ' ')
|
|
133
|
+
if [ "$CLEAN" = "1" ] && [ "${CORTEX_ORIENT_BASELINE:-0}" = "1" ]; then
|
|
134
|
+
echo "-- baseline: ${BN:-0} files recorded at start; \`sh $BD/changed\` lists files you modified/added/deleted. Before finishing, run it and revert every change the task did not require."
|
|
135
|
+
else
|
|
111
136
|
echo "-- baseline: ${BN:-0} files recorded at start (not a git repo); \`sh $BD/changed\` lists files you modified/added/deleted. Before finishing, run it and revert changes to existing files the task did not require."
|
|
137
|
+
fi
|
|
112
138
|
fi
|
|
113
139
|
# Bare-box hint (2026-09-03, operator-simplified): a task container may ship WITHOUT the language, compiler,
|
|
114
140
|
# package or library the objective needs — on purpose (the agent phase is bare; internet is usually allowed).
|
|
@@ -143,7 +169,7 @@ for f in pytest.ini tox.ini setup.cfg pyproject.toml Makefile package.json; do
|
|
|
143
169
|
done
|
|
144
170
|
TD=$(find . -maxdepth 3 -type d \( -name tests -o -name test \) 2>/dev/null | grep -vE "node_modules|/\.|site-packages" | head -4 | tr '\n' ' ')
|
|
145
171
|
fi
|
|
146
|
-
if [ -n "$VE$TC$TD" ]; then
|
|
172
|
+
if [ -n "$VE$TC$TD" ] && [ -z "$INV" ]; then
|
|
147
173
|
echo "== VERIFICATION ENTRY POINTS (build to and verify against these — not a test you invent) =="
|
|
148
174
|
for f in $VE; do
|
|
149
175
|
echo " $f"
|
|
@@ -196,28 +222,29 @@ machine_block() {
|
|
|
196
222
|
ls -1A "$W" 2>/dev/null | head -25 | sed 's/^/- /'
|
|
197
223
|
echo "$MB_END"
|
|
198
224
|
}
|
|
199
|
-
DOC=.cortex/CORTEX.md
|
|
225
|
+
DOC=.cortex/CORTEX.md; CD=.cortex
|
|
226
|
+
[ "$CLEAN" = "1" ] && { DOC="$CX/CORTEX.md"; CD="$CX"; }
|
|
200
227
|
if [ ! -f "$DOC" ]; then
|
|
201
|
-
mkdir -p
|
|
228
|
+
mkdir -p "$CD" 2>/dev/null
|
|
202
229
|
{
|
|
203
230
|
echo "# CORTEX.md (mechanical orient scan — refine with init_cortex_context)"
|
|
204
231
|
echo
|
|
205
232
|
machine_block
|
|
206
|
-
} > "$DOC" 2>/dev/null && echo "(wrote mechanical
|
|
233
|
+
} > "$DOC" 2>/dev/null && echo "(wrote mechanical $DOC)"
|
|
207
234
|
elif grep -q "orient:auto:begin" "$DOC" 2>/dev/null; then
|
|
208
|
-
machine_block >
|
|
209
|
-
awk '/orient:auto:begin/{f=1} f{print} /orient:auto:end/{f=0}' "$DOC" >
|
|
210
|
-
if cmp -s
|
|
211
|
-
rm -f
|
|
235
|
+
machine_block > "$CD"/.orient-fresh-block 2>/dev/null
|
|
236
|
+
awk '/orient:auto:begin/{f=1} f{print} /orient:auto:end/{f=0}' "$DOC" > "$CD"/.orient-cur-block 2>/dev/null
|
|
237
|
+
if cmp -s "$CD"/.orient-cur-block "$CD"/.orient-fresh-block; then
|
|
238
|
+
rm -f "$CD"/.orient-fresh-block "$CD"/.orient-cur-block
|
|
212
239
|
rm -f "$DOC.next" "$DOC.diff"
|
|
213
240
|
echo "(CORTEX.md current)"
|
|
214
241
|
else
|
|
215
|
-
awk -v fresh
|
|
242
|
+
awk -v fresh="$CD/.orient-fresh-block" '
|
|
216
243
|
/orient:auto:begin/ {skip=1; while ((getline line < fresh) > 0) print line; close(fresh); next}
|
|
217
244
|
/orient:auto:end/ {skip=0; next}
|
|
218
245
|
skip!=1 {print}' "$DOC" > "$DOC.next" 2>/dev/null
|
|
219
246
|
diff -u "$DOC" "$DOC.next" > "$DOC.diff" 2>/dev/null
|
|
220
|
-
rm -f
|
|
247
|
+
rm -f "$CD"/.orient-fresh-block "$CD"/.orient-cur-block
|
|
221
248
|
echo "(doctrine refresh staged for curation: machine sections drifted)"
|
|
222
249
|
fi
|
|
223
250
|
fi
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexus-cortex/server",
|
|
3
|
-
"version": "4.124.
|
|
3
|
+
"version": "4.124.32",
|
|
4
4
|
"description": "Thin Express server wrapper for Nexus Cortex core library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"prepack": "node ../../scripts/copy-pkg-cortex-scaffold.mjs"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@nexus-cortex/core": "4.124.
|
|
24
|
-
"@nexus-cortex/executors": "4.124.
|
|
23
|
+
"@nexus-cortex/core": "4.124.32",
|
|
24
|
+
"@nexus-cortex/executors": "4.124.32",
|
|
25
25
|
"chalk": "^5.3.0",
|
|
26
26
|
"cors": "^2.8.5",
|
|
27
27
|
"dotenv": "^16.4.5",
|