@tiens.nguyen/gonext-local-worker 1.0.234 → 1.0.235

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.
@@ -1926,20 +1926,31 @@ _WS_ACTIVE: str = ""
1926
1926
 
1927
1927
 
1928
1928
  def _rag_read_allowed(path: str) -> str:
1929
- """Resolve `path` and ensure it stays within a safe root (worker cwd, temp dir,
1930
- ~/.gonext, or a registered workspace) — so the agent's file tools can't read
1931
- arbitrary files like ~/.ssh. Relative paths anchor to the terminal workspace (where
1932
- downloads/unzips land), NOT the worker's process cwd (the home dir), because the
1933
- model routinely passes bare names like "tools-hook" or "tools-hook/README.md"."""
1929
+ """Resolve `path` and ensure it stays within a safe root (temp dir, ~/.gonext, the
1930
+ active terminal folder, or a registered workspace) — so the agent's file tools can't
1931
+ read arbitrary files like ~/.ssh. Relative paths anchor to the terminal workspace
1932
+ (where downloads/unzips land), because the model routinely passes bare names like
1933
+ "tools-hook" or "tools-hook/README.md".
1934
+
1935
+ NOTE: the worker's PROCESS CWD is deliberately NOT an allowed root (bug #70). The
1936
+ daemon is often launched from ~/Projects (the PARENT of every workspace), so trusting
1937
+ os.getcwd() let `grep_repo(path="/Users/joseph/Projects")` read EVERY project on disk
1938
+ — including other repos' secrets. Reads are confined to the registered/active
1939
+ workspaces + ~/.gonext + the temp dir. Fail-closed: no workspace ⇒ no repo reads."""
1934
1940
  import os
1935
1941
  import tempfile
1936
1942
  expanded = os.path.expanduser((path or "").strip())
1937
1943
  if not os.path.isabs(expanded):
1938
- base = _WS_ACTIVE or (_WS_ROOTS[0]["path"] if _WS_ROOTS else os.getcwd())
1944
+ # Anchor a relative path to the active workspace (NOT the worker cwd — see above).
1945
+ base = _WS_ACTIVE or (_WS_ROOTS[0]["path"] if _WS_ROOTS else None)
1946
+ if base is None:
1947
+ raise ValueError(
1948
+ "No workspace is active — register a folder with `gonext-local-worker "
1949
+ "workspace add <path>` before reading files."
1950
+ )
1939
1951
  expanded = os.path.join(base, expanded)
1940
1952
  rp = os.path.realpath(expanded)
1941
1953
  roots = [
1942
- os.path.realpath(os.getcwd()),
1943
1954
  os.path.realpath(tempfile.gettempdir()),
1944
1955
  os.path.realpath(os.path.join(os.path.expanduser("~"), ".gonext")),
1945
1956
  ] + [w["path"] for w in _WS_ROOTS]
@@ -1950,8 +1961,8 @@ def _rag_read_allowed(path: str) -> str:
1950
1961
  if any(rp == r or rp.startswith(r + os.sep) for r in roots):
1951
1962
  return rp
1952
1963
  raise ValueError(
1953
- "Path is outside the allowed working directories (download/unzip outputs "
1954
- "or a registered workspace)."
1964
+ f"Path '{path}' is outside your registered workspace(s). The agent can only read "
1965
+ "inside a folder you registered (or download/unzip outputs), not the whole disk."
1955
1966
  )
1956
1967
 
1957
1968
 
@@ -3040,6 +3051,9 @@ def run_agent_chat(cfg):
3040
3051
  f" CURRENT folder — the terminal is open HERE; default ALL create/edit/run/"
3041
3052
  f"download operations to THIS folder unless the user EXPLICITLY names another "
3042
3053
  f"workspace: {_active_label}\n"
3054
+ " Ignore any OTHER folder paths that appear only in EARLIER messages (a previous "
3055
+ "task, a cancelled turn) — they are stale. Do NOT grep/list/read across parent "
3056
+ "directories or unrelated projects; work in the CURRENT folder above.\n"
3043
3057
  if _active_label else ""
3044
3058
  )
3045
3059
  # Upfront, ZERO-COST (no tool call, no model round-trip) top-level listing — so the
@@ -5196,8 +5210,17 @@ def run_agent_chat(cfg):
5196
5210
  # even during a total coding-model outage, instead of trusting a plain-chat
5197
5211
  # model's guess that "there's no code or project" (seen live — false: the
5198
5212
  # workspace had real content the whole time, the model just never reached it).
5213
+ # ONLY the current/active folder — never dump the full list of every registered
5214
+ # workspace here. That list (t1..t23) used to get persisted into the answer/history
5215
+ # and then confused the next turn into free-roaming other projects (bug #70).
5199
5216
  if _WS_AVAILABLE:
5200
- note += f"\n\n(Your registered workspace:\n{_workspace_overview(_WS_ROOTS)})"
5217
+ import os as _os
5218
+ _ov_path = _WS_ACTIVE or (_WS_ROOTS[0]["path"] if _WS_ROOTS else "")
5219
+ _ov = next((w for w in _WS_ROOTS if w["path"] == _ov_path), None)
5220
+ if _ov is None and _ov_path:
5221
+ _ov = {"name": _os.path.basename(_ov_path), "path": _ov_path}
5222
+ if _ov:
5223
+ note += f"\n\n(Current folder {_ov['name']}:\n{_workspace_overview([_ov])})"
5201
5224
  _emit({"type": "final", "text": note})
5202
5225
 
5203
5226
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gonext-local-worker",
3
- "version": "1.0.234",
3
+ "version": "1.0.235",
4
4
  "description": "Polls GoNext cloud API for async local LLM jobs and runs them against Ollama/OpenAI-compatible servers on this Mac",
5
5
  "type": "module",
6
6
  "license": "MIT",