* fix(#6867): preserve artifact ownership across compression rotation * docs(changelog): note the #6867 artifacts-panel ownership-guard fix --------- Co-authored-by: nesquena-hermes <nesquena+hermes@gmail.com> Co-authored-by: n <a@n>
60 lines
3.1 KiB
Python
60 lines
3.1 KiB
Python
from pathlib import Path
|
|
|
|
WORKSPACE_JS = Path("static/workspace.js").read_text(encoding="utf-8")
|
|
SESSIONS_JS = Path("static/sessions.js").read_text(encoding="utf-8")
|
|
MESSAGES_JS = Path("static/messages.js").read_text(encoding="utf-8")
|
|
INDEX_HTML = Path("static/index.html").read_text(encoding="utf-8")
|
|
STYLE_CSS = Path("static/style.css").read_text(encoding="utf-8")
|
|
CHANGELOG = Path("CHANGELOG.md").read_text(encoding="utf-8")
|
|
|
|
|
|
def test_workspace_artifacts_tab_collects_session_files_and_previews_them():
|
|
assert 'id="workspaceArtifactsTab"' in INDEX_HTML
|
|
assert 'id="workspaceArtifacts"' in INDEX_HTML
|
|
assert "function collectSessionArtifacts()" in WORKSPACE_JS
|
|
assert "function _artifactCandidatesFromToolCall(tc)" in WORKSPACE_JS
|
|
assert "ARTIFACT_IGNORE_RE" in WORKSPACE_JS
|
|
assert "node_modules" in WORKSPACE_JS and "__pycache__" in WORKSPACE_JS
|
|
assert "function renderSessionArtifacts()" in WORKSPACE_JS
|
|
assert "function scheduleRenderSessionArtifacts()" in WORKSPACE_JS
|
|
assert "function openArtifactPath(path)" in WORKSPACE_JS
|
|
assert "openFile(rel);" in WORKSPACE_JS
|
|
assert "Prose mentions" in WORKSPACE_JS
|
|
assert "/(?:created|wrote|updated|edited|saved|modified)" not in WORKSPACE_JS
|
|
assert "panel.dataset.activeTab = _workspacePanelActiveTab" in WORKSPACE_JS
|
|
assert "projectSessionArtifactsForOwner(sid);" in SESSIONS_JS
|
|
assert "typeof scheduleRenderSessionArtifacts==='function'" in MESSAGES_JS
|
|
assert "S.toolCalls=d.session.tool_calls.map" in MESSAGES_JS
|
|
assert "projectSessionArtifactsForOwner(completedSid);" in MESSAGES_JS
|
|
assert ".workspace-artifact-item" in STYLE_CSS
|
|
|
|
|
|
def test_artifact_snapshot_consumers_route_through_owner():
|
|
assert "function projectSessionArtifactsForOwner(sessionId)" in WORKSPACE_JS
|
|
assert "projectSessionArtifactsForOwner(completedSid);" in MESSAGES_JS
|
|
assert "projectSessionArtifactsForOwner(sid);" in SESSIONS_JS
|
|
assert MESSAGES_JS.count("projectSessionArtifactsForOwner(completedSid);") >= 2
|
|
assert "if(typeof renderSessionArtifacts==='function') renderSessionArtifacts();" not in MESSAGES_JS
|
|
assert "if(typeof renderSessionArtifacts==='function') renderSessionArtifacts();" not in SESSIONS_JS
|
|
|
|
|
|
def test_workspace_artifacts_structured_args_are_mutation_gated():
|
|
"""Read-only tool args with path fields must not appear as changed files."""
|
|
fn_start = WORKSPACE_JS.index("function _artifactCandidatesFromToolCall(tc)")
|
|
fn_end = WORKSPACE_JS.index("function collectSessionArtifacts()", fn_start)
|
|
body = WORKSPACE_JS[fn_start:fn_end]
|
|
|
|
args_gate = body.index("args && typeof args === 'object'")
|
|
mutation_gate = body.rfind("ARTIFACT_MUTATION_TOOLS.has(name)", 0, args_gate)
|
|
|
|
assert mutation_gate >= 0, (
|
|
"structured path/file_path/source/destination extraction must be gated "
|
|
"on ARTIFACT_MUTATION_TOOLS so read_file/list_dir paths do not appear "
|
|
"as created or edited artifacts"
|
|
)
|
|
|
|
|
|
def test_changelog_mentions_workspace_artifacts_tab():
|
|
unreleased = CHANGELOG.split("## [v0.51.103]", 1)[0]
|
|
assert "Artifacts tab" in unreleased
|