aicortexpy 0.2.4__tar.gz → 0.2.6__tar.gz
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.
- {aicortexpy-0.2.4/aicortexpy.egg-info → aicortexpy-0.2.6}/PKG-INFO +1 -1
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/__init__.py +1 -1
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/capabilities.py +1 -1
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/daemon.py +14 -13
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/execenv.py +12 -2
- aicortexpy-0.2.6/aicortexpy/pinned_workdir.py +127 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/runner.py +4 -1
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/runtime_config.py +2 -11
- {aicortexpy-0.2.4 → aicortexpy-0.2.6/aicortexpy.egg-info}/PKG-INFO +1 -1
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/pyproject.toml +1 -1
- aicortexpy-0.2.4/aicortexpy/pinned_workdir.py +0 -60
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/MANIFEST.in +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/README.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortex/__init__.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortex/__main__.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/__main__.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/acp_client.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/acp_conn.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/acp_errors.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/agent_env.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/app_workdir.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/artifact_ws.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/artifacts.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/attachments.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/auto_commit.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/chat_acp_pool.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/cli.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/cli_context.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/client.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/codex_config.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/__init__.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/agent_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/attachment_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/auth_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/autopilot_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/config_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/daemon_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/graph_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/issue_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/label_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/meeting_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/memory_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/project_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/repo_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/runtime_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/setup_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/skill_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/squad_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/update_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/version_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/commands/workspace_cmd.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/config.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/agent-memory/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicorkit-atlassian/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicorkit-graph/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicorkit-outlook/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicorkit-wxmsg/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicortex-basics/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicortex-bridge-cdp/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicortex-cli-ops/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicortex-graph/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/graphify/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/question-form/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/test-report-generator/SKILL.md +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/test-report-generator/scripts/generate_cases.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/test-report-generator/scripts/generate_report.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/design_seed.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/diskusage.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/gc.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/handoff_bundle.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/health.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/id_resolve.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/local_skills.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/models.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/oauth_login.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/openclaw_config.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/output.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/permission.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/platform_client.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/platform_info.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/poisoned.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/process.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/procutil.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/prompt.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/repo.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/sandbox.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/security.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/stream.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/terminal.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/tunnel.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/wakeup.py +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy.egg-info/SOURCES.txt +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy.egg-info/dependency_links.txt +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy.egg-info/entry_points.txt +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy.egg-info/requires.txt +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy.egg-info/top_level.txt +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/scripts/aicortex +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/scripts/aicortex.cmd +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/setup.cfg +0 -0
- {aicortexpy-0.2.4 → aicortexpy-0.2.6}/tests/test_app_workdir.py +0 -0
|
@@ -37,7 +37,7 @@ CAPABILITIES: list[Capability] = [
|
|
|
37
37
|
Capability("repo_cache", "Bare cache + worktree checkout", "repocache/", "done", "per-ws bare + lock + worktree + co-authored hook"),
|
|
38
38
|
Capability("pinned_workdir", "Pinned project workdir", "pinned_workdir.go", "done", "projects/<id> stages"),
|
|
39
39
|
Capability("attachments", "Materialize attachments", "materialize_attachments.go", "done", "_incoming/"),
|
|
40
|
-
Capability("auto_commit", "Auto-commit agent changes", "auto_commit.go", "
|
|
40
|
+
Capability("auto_commit", "Auto-commit agent changes", "auto_commit.go", "skipped", "disabled — user decides when to commit"),
|
|
41
41
|
Capability("artifacts", "Artifacts metadata + WS browse/chunk", "artifact/", "done", "scan metadata + wakeup artifact ops"),
|
|
42
42
|
Capability("agent_claude", "Claude stream-json backend", "claude.go", "done", "stream-json + resume + mcp-config"),
|
|
43
43
|
Capability("agent_codex", "Codex exec backend", "codex.go", "done", "codex exec + CODEX_HOME + semantic inactivity"),
|
|
@@ -16,7 +16,6 @@ from .app_workdir import (
|
|
|
16
16
|
read_app_index_html,
|
|
17
17
|
)
|
|
18
18
|
from .artifacts import report_issue_artifacts
|
|
19
|
-
from .auto_commit import auto_commit_and_push
|
|
20
19
|
from .chat_acp_pool import ChatACPPool
|
|
21
20
|
from .client import APIError, DaemonClient, Task, is_not_found
|
|
22
21
|
from .config import Config, as_register_runtimes, detect_local_timezone
|
|
@@ -308,11 +307,20 @@ class Daemon:
|
|
|
308
307
|
p = Path(prior)
|
|
309
308
|
roots.append(p.parent if p.name == "workdir" else p)
|
|
310
309
|
if task.project_id.strip():
|
|
311
|
-
from .pinned_workdir import
|
|
310
|
+
from .pinned_workdir import pinned_workdir_path, select_local_path
|
|
312
311
|
|
|
313
|
-
local =
|
|
314
|
-
|
|
315
|
-
|
|
312
|
+
local, _explicit = select_local_path(
|
|
313
|
+
task.project_resources, self.cfg.daemon_id
|
|
314
|
+
)
|
|
315
|
+
local_path = Path(local) if local else None
|
|
316
|
+
exists = False
|
|
317
|
+
if local_path is not None:
|
|
318
|
+
try:
|
|
319
|
+
exists = local_path.is_dir()
|
|
320
|
+
except OSError:
|
|
321
|
+
exists = False
|
|
322
|
+
if exists and local_path is not None:
|
|
323
|
+
roots.append(local_path)
|
|
316
324
|
else:
|
|
317
325
|
roots.append(
|
|
318
326
|
pinned_workdir_path(self.cfg.workspaces_root, ws, task.project_id)
|
|
@@ -645,14 +653,7 @@ class Daemon:
|
|
|
645
653
|
if is_poisoned:
|
|
646
654
|
fail_reason = poisoned_reason
|
|
647
655
|
|
|
648
|
-
if result.ok
|
|
649
|
-
# Chat turns should not auto-commit into the user's project worktree.
|
|
650
|
-
try:
|
|
651
|
-
auto_commit_and_push(
|
|
652
|
-
result.work_dir, task.id, str(agent_name)
|
|
653
|
-
)
|
|
654
|
-
except Exception as e:
|
|
655
|
-
log.warning("auto-commit: %s", e)
|
|
656
|
+
if result.ok:
|
|
656
657
|
if task.issue_id:
|
|
657
658
|
try:
|
|
658
659
|
report_issue_artifacts(
|
|
@@ -13,7 +13,11 @@ from .client import Task
|
|
|
13
13
|
from .codex_config import ensure_codex_multi_agent_config, sanitize_copied_codex_config
|
|
14
14
|
from .openclaw_config import prepare_openclaw_config
|
|
15
15
|
from .app_workdir import app_uses_pinned_workdir, prepare_app_workdir
|
|
16
|
-
from .pinned_workdir import
|
|
16
|
+
from .pinned_workdir import (
|
|
17
|
+
narrow_local_path_resources,
|
|
18
|
+
prepare_pinned_workdir,
|
|
19
|
+
project_uses_pinned_workdir,
|
|
20
|
+
)
|
|
17
21
|
from .prompt import build_prompt
|
|
18
22
|
from .runtime_config import (
|
|
19
23
|
inject_runtime_config,
|
|
@@ -51,9 +55,13 @@ def prepare_environment(
|
|
|
51
55
|
workspaces_root: Path,
|
|
52
56
|
task: Task,
|
|
53
57
|
provider: str,
|
|
58
|
+
*,
|
|
59
|
+
daemon_id: str = "",
|
|
54
60
|
) -> Environment:
|
|
55
61
|
ws = task.workspace_id or "default"
|
|
56
62
|
env_updates: dict[str, str] = {}
|
|
63
|
+
# None leaves project resources unchanged. "" means local_path was not used.
|
|
64
|
+
used_local: str | None = None
|
|
57
65
|
|
|
58
66
|
# Priority 0: App edit/run pinned workdir (same layout as Go daemon).
|
|
59
67
|
if app_uses_pinned_workdir(task):
|
|
@@ -67,7 +75,7 @@ def prepare_environment(
|
|
|
67
75
|
task.app_mode,
|
|
68
76
|
)
|
|
69
77
|
elif project_uses_pinned_workdir(task):
|
|
70
|
-
work_dir = prepare_pinned_workdir(workspaces_root, task)
|
|
78
|
+
work_dir, used_local = prepare_pinned_workdir(workspaces_root, task, daemon_id)
|
|
71
79
|
root_dir = work_dir
|
|
72
80
|
pinned = True
|
|
73
81
|
else:
|
|
@@ -94,6 +102,8 @@ def prepare_environment(
|
|
|
94
102
|
|
|
95
103
|
agent = task.agent or {}
|
|
96
104
|
ctx = task_context_from_task(task)
|
|
105
|
+
if used_local is not None:
|
|
106
|
+
ctx.project_resources = narrow_local_path_resources(ctx.project_resources, used_local)
|
|
97
107
|
runtime_brief = inject_runtime_config(work_dir, provider, ctx)
|
|
98
108
|
write_project_sidecar(work_dir, ctx)
|
|
99
109
|
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""Shared project workdir layout."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from .client import Task
|
|
11
|
+
|
|
12
|
+
log = logging.getLogger("aicortexpy.pinned")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def project_uses_pinned_workdir(task: Task) -> bool:
|
|
16
|
+
return bool(task.project_id.strip())
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _local_path_payload(resources: list[dict[str, Any]]) -> tuple[str, dict[str, str]] | None:
|
|
20
|
+
for r in resources:
|
|
21
|
+
rtype = str(r.get("resource_type") or r.get("type") or "")
|
|
22
|
+
if rtype != "local_path":
|
|
23
|
+
continue
|
|
24
|
+
ref = r.get("resource_ref")
|
|
25
|
+
if ref is None:
|
|
26
|
+
ref = r.get("ref") or {}
|
|
27
|
+
if isinstance(ref, str):
|
|
28
|
+
try:
|
|
29
|
+
ref = json.loads(ref)
|
|
30
|
+
except json.JSONDecodeError:
|
|
31
|
+
return "", {}
|
|
32
|
+
if not isinstance(ref, dict):
|
|
33
|
+
return "", {}
|
|
34
|
+
path = str(ref.get("path") or "").strip()
|
|
35
|
+
by_daemon: dict[str, str] = {}
|
|
36
|
+
raw = ref.get("by_daemon") or {}
|
|
37
|
+
if isinstance(raw, dict):
|
|
38
|
+
for key, value in raw.items():
|
|
39
|
+
daemon_id = str(key).strip()
|
|
40
|
+
directory = str(value).strip() if value is not None else ""
|
|
41
|
+
if daemon_id and directory:
|
|
42
|
+
by_daemon[daemon_id] = directory
|
|
43
|
+
return path, by_daemon
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def select_local_path(resources: list[dict[str, Any]], daemon_id: str) -> tuple[str, bool]:
|
|
48
|
+
"""Return (path, explicit). explicit is true when by_daemon names this daemon.
|
|
49
|
+
|
|
50
|
+
Other daemons use the default path, so each machine does not need a row.
|
|
51
|
+
"""
|
|
52
|
+
parsed = _local_path_payload(resources)
|
|
53
|
+
if parsed is None:
|
|
54
|
+
return "", False
|
|
55
|
+
path, by_daemon = parsed
|
|
56
|
+
daemon_id = (daemon_id or "").strip()
|
|
57
|
+
if daemon_id and by_daemon.get(daemon_id):
|
|
58
|
+
return by_daemon[daemon_id], True
|
|
59
|
+
return path, False
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def extract_local_path(resources: list[dict[str, Any]]) -> str:
|
|
63
|
+
path, _explicit = select_local_path(resources, "")
|
|
64
|
+
return path
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def narrow_local_path_resources(resources: list[dict[str, Any]], used_path: str) -> list[dict[str, Any]]:
|
|
68
|
+
"""Keep a single local_path ref of {path: used_path}. Drop it when unused."""
|
|
69
|
+
used_path = (used_path or "").strip()
|
|
70
|
+
out: list[dict[str, Any]] = []
|
|
71
|
+
kept = False
|
|
72
|
+
for r in resources:
|
|
73
|
+
rtype = str(r.get("resource_type") or r.get("type") or "")
|
|
74
|
+
if rtype != "local_path":
|
|
75
|
+
out.append(r)
|
|
76
|
+
continue
|
|
77
|
+
if not used_path or kept:
|
|
78
|
+
continue
|
|
79
|
+
copied = dict(r)
|
|
80
|
+
copied["resource_ref"] = {"path": used_path}
|
|
81
|
+
out.append(copied)
|
|
82
|
+
kept = True
|
|
83
|
+
return out
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def pinned_workdir_path(workspaces_root: Path, workspace_id: str, project_id: str) -> Path:
|
|
87
|
+
return workspaces_root / workspace_id / "projects" / project_id
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def ensure_project_layout(root: Path) -> None:
|
|
91
|
+
"""Create the project workdir itself. Do not add stage subdirectories."""
|
|
92
|
+
root.mkdir(parents=True, exist_ok=True)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _dir_exists(path: Path) -> bool:
|
|
96
|
+
try:
|
|
97
|
+
return path.is_dir()
|
|
98
|
+
except OSError:
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def prepare_pinned_workdir(
|
|
103
|
+
workspaces_root: Path,
|
|
104
|
+
task: Task,
|
|
105
|
+
daemon_id: str = "",
|
|
106
|
+
) -> tuple[Path, str]:
|
|
107
|
+
"""Return (workdir, used_local_path). used_local_path is empty on fallback."""
|
|
108
|
+
local, explicit = select_local_path(task.project_resources, daemon_id)
|
|
109
|
+
if local:
|
|
110
|
+
root = Path(local)
|
|
111
|
+
if _dir_exists(root):
|
|
112
|
+
ensure_project_layout(root)
|
|
113
|
+
log.info("using local_path project workdir %s explicit=%s", root, explicit)
|
|
114
|
+
return root, local
|
|
115
|
+
if explicit or not project_uses_pinned_workdir(task):
|
|
116
|
+
raise RuntimeError(
|
|
117
|
+
f"project local_path: working directory {local!r} is not accessible"
|
|
118
|
+
)
|
|
119
|
+
log.warning(
|
|
120
|
+
"default local_path %s is not on this machine; using the daemon project directory",
|
|
121
|
+
local,
|
|
122
|
+
)
|
|
123
|
+
root = pinned_workdir_path(
|
|
124
|
+
workspaces_root, task.workspace_id or "default", task.project_id
|
|
125
|
+
)
|
|
126
|
+
ensure_project_layout(root)
|
|
127
|
+
return root, ""
|
|
@@ -300,7 +300,10 @@ def run_agent(
|
|
|
300
300
|
) -> RunResult:
|
|
301
301
|
from .security import default_security_policy
|
|
302
302
|
|
|
303
|
-
|
|
303
|
+
daemon_id = cfg.daemon_id if cfg is not None else ""
|
|
304
|
+
env_info: Environment = prepare_environment(
|
|
305
|
+
workspaces_root, task, provider, daemon_id=daemon_id
|
|
306
|
+
)
|
|
304
307
|
work_dir = env_info.work_dir
|
|
305
308
|
policy = security_policy or default_security_policy()
|
|
306
309
|
roots = [str(work_dir)]
|
|
@@ -272,6 +272,7 @@ def _format_project_resource(r: dict[str, Any]) -> str:
|
|
|
272
272
|
if hint:
|
|
273
273
|
out += f" (default branch: `{hint}`)"
|
|
274
274
|
elif rtype == "local_path":
|
|
275
|
+
# by_daemon is resolved before this runs; only this machine's path is shown.
|
|
275
276
|
out = f"**Local path**: `{ref.get('path') or ''}`"
|
|
276
277
|
else:
|
|
277
278
|
out = f"**{rtype}**: `{json.dumps(ref, ensure_ascii=False)}`"
|
|
@@ -322,15 +323,6 @@ def _project_context_section(ctx: TaskContextForEnv) -> str:
|
|
|
322
323
|
parts.append(f"This {scope} belongs to **{ctx.project_title}**.\n\n")
|
|
323
324
|
if ctx.project_id:
|
|
324
325
|
parts.append(f"Project working directory (logical): `/workspace/{ctx.project_id}/`\n\n")
|
|
325
|
-
parts.append(
|
|
326
|
-
"Use this shared layout:\n\n"
|
|
327
|
-
"- `docs/` — project materials\n"
|
|
328
|
-
"- `design/` — design HTML and static mockups\n"
|
|
329
|
-
"- `app/` — application / development code\n"
|
|
330
|
-
"- `test/` — tests, fixtures, and reports\n"
|
|
331
|
-
"- `release/` — build artifacts and release notes\n\n"
|
|
332
|
-
"Write only in the directory that matches the current task.\n\n"
|
|
333
|
-
)
|
|
334
326
|
if ctx.project_resources:
|
|
335
327
|
parts.append("Project resources (also at `.aicortex/project/resources.json`):\n\n")
|
|
336
328
|
for r in ctx.project_resources:
|
|
@@ -574,8 +566,7 @@ def _design_studio_runtime(provider: str, ctx: TaskContextForEnv) -> str:
|
|
|
574
566
|
parts.append(f"This design session belongs to **{ctx.project_title}**.\n\n")
|
|
575
567
|
if ctx.project_id:
|
|
576
568
|
parts.append(
|
|
577
|
-
f"Project working directory (logical): `/workspace/{ctx.project_id}/`\n"
|
|
578
|
-
"Write design HTML under `design/`.\n\n"
|
|
569
|
+
f"Project working directory (logical): `/workspace/{ctx.project_id}/`\n\n"
|
|
579
570
|
)
|
|
580
571
|
if ctx.project_resources:
|
|
581
572
|
parts.append("Project resources (tokens/branding only):\n\n")
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
# PyPI + import + console script entry for full Go CLI replacement.
|
|
7
7
|
name = "aicortexpy"
|
|
8
|
-
version = "0.2.
|
|
8
|
+
version = "0.2.6"
|
|
9
9
|
description = "AICortex Python CLI and local agent runtime daemon (Go CLI compatible)"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
license = { text = "Apache-2.0" }
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"""Shared project workdir layout."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
import logging
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Any
|
|
9
|
-
|
|
10
|
-
from .client import Task
|
|
11
|
-
|
|
12
|
-
log = logging.getLogger("aicortexpy.pinned")
|
|
13
|
-
|
|
14
|
-
STAGE_DIRS = ("docs", "design", "app", "test", "release")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def project_uses_pinned_workdir(task: Task) -> bool:
|
|
18
|
-
return bool(task.project_id.strip())
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def extract_local_path(resources: list[dict[str, Any]]) -> str:
|
|
22
|
-
for r in resources:
|
|
23
|
-
if r.get("resource_type") != "local_path":
|
|
24
|
-
continue
|
|
25
|
-
ref = r.get("resource_ref")
|
|
26
|
-
if isinstance(ref, str):
|
|
27
|
-
try:
|
|
28
|
-
ref = json.loads(ref)
|
|
29
|
-
except json.JSONDecodeError:
|
|
30
|
-
continue
|
|
31
|
-
if isinstance(ref, dict) and ref.get("path"):
|
|
32
|
-
return str(ref["path"])
|
|
33
|
-
return ""
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def pinned_workdir_path(workspaces_root: Path, workspace_id: str, project_id: str) -> Path:
|
|
37
|
-
return workspaces_root / workspace_id / "projects" / project_id
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def ensure_project_layout(root: Path) -> None:
|
|
41
|
-
root.mkdir(parents=True, exist_ok=True)
|
|
42
|
-
for name in STAGE_DIRS:
|
|
43
|
-
(root / name).mkdir(parents=True, exist_ok=True)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def prepare_pinned_workdir(
|
|
47
|
-
workspaces_root: Path,
|
|
48
|
-
task: Task,
|
|
49
|
-
) -> Path:
|
|
50
|
-
local = extract_local_path(task.project_resources)
|
|
51
|
-
if local:
|
|
52
|
-
root = Path(local)
|
|
53
|
-
ensure_project_layout(root)
|
|
54
|
-
log.info("using local_path project workdir %s", root)
|
|
55
|
-
return root
|
|
56
|
-
root = pinned_workdir_path(
|
|
57
|
-
workspaces_root, task.workspace_id or "default", task.project_id
|
|
58
|
-
)
|
|
59
|
-
ensure_project_layout(root)
|
|
60
|
-
return root
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicorkit-atlassian/SKILL.md
RENAMED
|
File without changes
|
{aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicorkit-graph/SKILL.md
RENAMED
|
File without changes
|
{aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicorkit-outlook/SKILL.md
RENAMED
|
File without changes
|
{aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicorkit-wxmsg/SKILL.md
RENAMED
|
File without changes
|
{aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicortex-basics/SKILL.md
RENAMED
|
File without changes
|
{aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicortex-bridge-cdp/SKILL.md
RENAMED
|
File without changes
|
{aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicortex-cli-ops/SKILL.md
RENAMED
|
File without changes
|
{aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/aicortex-graph/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aicortexpy-0.2.4 → aicortexpy-0.2.6}/aicortexpy/data/default_skills/test-report-generator/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|