Rename content_hash to cid in CLI

Update CLI argument names and help text:
- Change argument names from content_hash to cid
- Update user-facing messages to use CID terminology
- Update README examples with CID syntax

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-12 08:04:07 +00:00
parent c0414a9e0d
commit 6c1735e6b4
2 changed files with 62 additions and 62 deletions

106
artdag.py
View File

@@ -308,7 +308,7 @@ def run(recipe, input_hash, name, wait):
if status["status"] == "completed":
click.echo(f"Completed!")
click.echo(f"Output: {status['output_hash']}")
click.echo(f"Output: {status['output_cid']}")
else:
click.echo(f"Failed: {status.get('error', 'Unknown error')}")
@@ -327,7 +327,7 @@ def list_runs(limit):
click.echo("-" * 80)
for run in runs[:limit]:
output = run.get("output_hash", "")[:16] + "..." if run.get("output_hash") else "-"
output = run.get("output_cid", "")[:16] + "..." if run.get("output_cid") else "-"
click.echo(f"{run['run_id']} {run['status']:<10} {run['recipe']:<10} {output}")
@@ -353,8 +353,8 @@ def status(run_id):
if run.get("completed_at"):
click.echo(f"Completed: {run['completed_at']}")
if run.get("output_hash"):
click.echo(f"Output Hash: {run['output_hash']}")
if run.get("output_cid"):
click.echo(f"Output Hash: {run['output_cid']}")
if run.get("error"):
click.echo(f"Error: {run['error']}")
@@ -411,12 +411,12 @@ def delete_run(run_id, force):
@cli.command("delete-cache")
@click.argument("content_hash")
@click.argument("cid")
@click.option("--force", "-f", is_flag=True, help="Skip confirmation")
def delete_cache(content_hash, force):
def delete_cache(cid, force):
"""Delete a cached item. Requires login.
CONTENT_HASH: The content hash to delete
CID: The content identifier (IPFS CID) to delete
"""
token_data = load_token()
if not token_data.get("access_token"):
@@ -424,14 +424,14 @@ def delete_cache(content_hash, force):
sys.exit(1)
if not force:
click.echo(f"Content hash: {content_hash}")
click.echo(f"CID: {cid}")
if not click.confirm("Delete this cached item?"):
click.echo("Cancelled.")
return
try:
headers = {"Authorization": f"Bearer {token_data['access_token']}"}
resp = requests.delete(f"{get_server()}/cache/{content_hash}", headers=headers)
resp = requests.delete(f"{get_server()}/cache/{cid}", headers=headers)
if resp.status_code == 400:
click.echo(f"Cannot delete: {resp.json().get('detail', 'Unknown error')}", err=True)
sys.exit(1)
@@ -439,14 +439,14 @@ def delete_cache(content_hash, force):
click.echo("Access denied", err=True)
sys.exit(1)
if resp.status_code == 404:
click.echo(f"Content not found: {content_hash}", err=True)
click.echo(f"Content not found: {cid}", err=True)
sys.exit(1)
resp.raise_for_status()
except requests.RequestException as e:
click.echo(f"Failed to delete cache item: {e}", err=True)
sys.exit(1)
click.echo(f"Deleted: {content_hash}")
click.echo(f"Deleted: {cid}")
@cli.command()
@@ -465,14 +465,14 @@ def cache(limit):
@cli.command()
@click.argument("content_hash")
@click.argument("cid")
@click.option("--output", "-o", type=click.Path(), help="Save to file (use - for stdout)")
def view(content_hash, output):
def view(cid, output):
"""View or download cached content.
Use -o - to pipe to stdout, e.g.: artdag view <hash> -o - | mpv -
Use -o - to pipe to stdout, e.g.: artdag view <cid> -o - | mpv -
"""
url = f"{get_server()}/cache/{content_hash}"
url = f"{get_server()}/cache/{cid}"
try:
if output == "-":
@@ -495,14 +495,14 @@ def view(content_hash, output):
resp.raise_for_status()
size = resp.headers.get("content-length", "unknown")
content_type = resp.headers.get("content-type", "unknown")
click.echo(f"Hash: {content_hash}")
click.echo(f"CID: {cid}")
click.echo(f"Size: {size} bytes")
click.echo(f"Type: {content_type}")
click.echo(f"URL: {url}")
resp.close()
except requests.HTTPError as e:
if e.response.status_code == 404:
click.echo(f"Not found: {content_hash}", err=True)
click.echo(f"Not found: {cid}", err=True)
else:
raise
@@ -513,7 +513,7 @@ def import_file(filepath):
"""Import a local file to cache (local server only)."""
path = str(Path(filepath).resolve())
result = api_post("/cache/import", params={"path": path})
click.echo(f"Imported: {result['content_hash']}")
click.echo(f"Imported: {result['cid']}")
@cli.command()
@@ -588,14 +588,14 @@ def publish(run_id, output_name):
result = resp.json()
click.echo(f"Published to L2!")
click.echo(f"Asset: {result['asset']['name']}")
click.echo(f"Hash: {result['asset']['content_hash']}")
click.echo(f"CID: {result['asset']['cid']}")
click.echo(f"Activity: {result['activity']['activity_id']}")
# ============ Metadata Commands ============
@cli.command()
@click.argument("content_hash")
@click.argument("cid")
@click.option("--origin", type=click.Choice(["self", "external"]), help="Set origin type")
@click.option("--origin-url", help="Set external origin URL")
@click.option("--origin-note", help="Note about the origin")
@@ -607,7 +607,7 @@ def publish(run_id, output_name):
@click.option("--publish", "publish_name", help="Publish to L2 with given asset name")
@click.option("--publish-type", default="image", help="Asset type for publishing (image, video)")
@click.option("--republish", is_flag=True, help="Re-sync with L2 after metadata changes")
def meta(content_hash, origin, origin_url, origin_note, description, tags, folder, add_collection, remove_collection, publish_name, publish_type, republish):
def meta(cid, origin, origin_url, origin_note, description, tags, folder, add_collection, remove_collection, publish_name, publish_type, republish):
"""View or update metadata for a cached item.
With no options, displays current metadata.
@@ -627,7 +627,7 @@ def meta(content_hash, origin, origin_url, origin_note, description, tags, folde
if publish_name:
try:
resp = requests.post(
f"{get_server()}/cache/{content_hash}/publish",
f"{get_server()}/cache/{cid}/publish",
json={"asset_name": publish_name, "asset_type": publish_type},
headers=headers
)
@@ -635,7 +635,7 @@ def meta(content_hash, origin, origin_url, origin_note, description, tags, folde
click.echo(f"Error: {resp.json().get('detail', 'Bad request')}", err=True)
sys.exit(1)
if resp.status_code == 404:
click.echo(f"Content not found: {content_hash}", err=True)
click.echo(f"Content not found: {cid}", err=True)
sys.exit(1)
resp.raise_for_status()
result = resp.json()
@@ -651,14 +651,14 @@ def meta(content_hash, origin, origin_url, origin_note, description, tags, folde
if republish:
try:
resp = requests.patch(
f"{get_server()}/cache/{content_hash}/republish",
f"{get_server()}/cache/{cid}/republish",
headers=headers
)
if resp.status_code == 400:
click.echo(f"Error: {resp.json().get('detail', 'Bad request')}", err=True)
sys.exit(1)
if resp.status_code == 404:
click.echo(f"Content not found: {content_hash}", err=True)
click.echo(f"Content not found: {cid}", err=True)
sys.exit(1)
resp.raise_for_status()
result = resp.json()
@@ -675,9 +675,9 @@ def meta(content_hash, origin, origin_url, origin_note, description, tags, folde
if not has_updates:
# GET metadata
try:
resp = requests.get(f"{get_server()}/cache/{content_hash}/meta", headers=headers)
resp = requests.get(f"{get_server()}/cache/{cid}/meta", headers=headers)
if resp.status_code == 404:
click.echo(f"Content not found: {content_hash}", err=True)
click.echo(f"Content not found: {cid}", err=True)
sys.exit(1)
if resp.status_code == 403:
click.echo("Access denied", err=True)
@@ -688,7 +688,7 @@ def meta(content_hash, origin, origin_url, origin_note, description, tags, folde
click.echo(f"Failed to get metadata: {e}", err=True)
sys.exit(1)
click.echo(f"Content Hash: {content_hash}")
click.echo(f"Content Hash: {cid}")
click.echo(f"Uploader: {meta.get('uploader', 'unknown')}")
click.echo(f"Uploaded: {meta.get('uploaded_at', 'unknown')}")
if meta.get("origin"):
@@ -715,7 +715,7 @@ def meta(content_hash, origin, origin_url, origin_note, description, tags, folde
if origin or origin_url or origin_note:
# Get current origin first
try:
resp = requests.get(f"{get_server()}/cache/{content_hash}/meta", headers=headers)
resp = requests.get(f"{get_server()}/cache/{cid}/meta", headers=headers)
resp.raise_for_status()
current = resp.json()
current_origin = current.get("origin", {})
@@ -740,7 +740,7 @@ def meta(content_hash, origin, origin_url, origin_note, description, tags, folde
if add_collection or remove_collection:
# Get current collections
try:
resp = requests.get(f"{get_server()}/cache/{content_hash}/meta", headers=headers)
resp = requests.get(f"{get_server()}/cache/{cid}/meta", headers=headers)
resp.raise_for_status()
current = resp.json()
collections = set(current.get("collections", []))
@@ -756,12 +756,12 @@ def meta(content_hash, origin, origin_url, origin_note, description, tags, folde
# PATCH metadata
try:
resp = requests.patch(
f"{get_server()}/cache/{content_hash}/meta",
f"{get_server()}/cache/{cid}/meta",
json=update,
headers=headers
)
if resp.status_code == 404:
click.echo(f"Content not found: {content_hash}", err=True)
click.echo(f"Content not found: {cid}", err=True)
sys.exit(1)
if resp.status_code == 400:
click.echo(f"Error: {resp.json().get('detail', 'Bad request')}", err=True)
@@ -1088,7 +1088,7 @@ def list_effects(limit):
for effect in effects:
meta = effect.get("meta", {})
click.echo(f" {meta.get('name', 'unknown')} v{meta.get('version', '?')}")
click.echo(f" Hash: {effect['content_hash'][:32]}...")
click.echo(f" Hash: {effect['cid'][:32]}...")
click.echo(f" Temporal: {meta.get('temporal', False)}")
if meta.get('params'):
click.echo(f" Params: {', '.join(p['name'] for p in meta['params'])}")
@@ -1155,12 +1155,12 @@ def show_recipe(recipe_id):
if recipe.get("fixed_inputs"):
click.echo("\nFixed Inputs:")
for inp in recipe["fixed_inputs"]:
click.echo(f" - {inp['asset']}: {inp['content_hash'][:16]}...")
click.echo(f" - {inp['asset']}: {inp['cid'][:16]}...")
@cli.command("run-recipe")
@click.argument("recipe_id")
@click.option("--input", "-i", "inputs", multiple=True, help="Input as node_id:content_hash")
@click.option("--input", "-i", "inputs", multiple=True, help="Input as node_id:cid")
@click.option("--wait", "-w", is_flag=True, help="Wait for completion")
def run_recipe(recipe_id, inputs, wait):
"""Run a recipe with variable inputs. Requires login.
@@ -1178,10 +1178,10 @@ def run_recipe(recipe_id, inputs, wait):
input_dict = {}
for inp in inputs:
if ":" not in inp:
click.echo(f"Invalid input format: {inp} (expected node_id:content_hash)", err=True)
click.echo(f"Invalid input format: {inp} (expected node_id:cid)", err=True)
sys.exit(1)
node_id, content_hash = inp.split(":", 1)
input_dict[node_id] = content_hash
node_id, cid = inp.split(":", 1)
input_dict[node_id] = cid
# Run
try:
@@ -1225,7 +1225,7 @@ def run_recipe(recipe_id, inputs, wait):
continue
if run["status"] == "completed":
click.echo(f"Completed! Output: {run.get('output_hash', 'N/A')}")
click.echo(f"Completed! Output: {run.get('output_cid', 'N/A')}")
break
elif run["status"] == "failed":
click.echo(f"Failed: {run.get('error', 'Unknown error')}", err=True)
@@ -1272,7 +1272,7 @@ def delete_recipe(recipe_id, force):
@cli.command("plan")
@click.argument("recipe_file", type=click.Path(exists=True))
@click.option("--input", "-i", "inputs", multiple=True, help="Input as name:content_hash")
@click.option("--input", "-i", "inputs", multiple=True, help="Input as name:cid")
@click.option("--features", "-f", multiple=True, help="Features to extract (default: beats, energy)")
@click.option("--output", "-o", type=click.Path(), help="Save plan JSON to file")
def generate_plan(recipe_file, inputs, features, output):
@@ -1297,10 +1297,10 @@ def generate_plan(recipe_file, inputs, features, output):
input_hashes = {}
for inp in inputs:
if ":" not in inp:
click.echo(f"Invalid input format: {inp} (expected name:content_hash)", err=True)
click.echo(f"Invalid input format: {inp} (expected name:cid)", err=True)
sys.exit(1)
name, content_hash = inp.split(":", 1)
input_hashes[name] = content_hash
name, cid = inp.split(":", 1)
input_hashes[name] = cid
# Build request
request_data = {
@@ -1401,7 +1401,7 @@ def execute_plan(plan_file, wait):
@cli.command("run-v2")
@click.argument("recipe_file", type=click.Path(exists=True))
@click.option("--input", "-i", "inputs", multiple=True, help="Input as name:content_hash")
@click.option("--input", "-i", "inputs", multiple=True, help="Input as name:cid")
@click.option("--features", "-f", multiple=True, help="Features to extract (default: beats, energy)")
@click.option("--wait", "-w", is_flag=True, help="Wait for completion")
def run_recipe_v2(recipe_file, inputs, features, wait):
@@ -1433,10 +1433,10 @@ def run_recipe_v2(recipe_file, inputs, features, wait):
input_hashes = {}
for inp in inputs:
if ":" not in inp:
click.echo(f"Invalid input format: {inp} (expected name:content_hash)", err=True)
click.echo(f"Invalid input format: {inp} (expected name:cid)", err=True)
sys.exit(1)
name, content_hash = inp.split(":", 1)
input_hashes[name] = content_hash
name, cid = inp.split(":", 1)
input_hashes[name] = cid
# Build request
request_data = {
@@ -1473,8 +1473,8 @@ def run_recipe_v2(recipe_file, inputs, features, wait):
click.echo(f"Run ID: {run_id}")
click.echo(f"Status: {result['status']}")
if result.get("output_hash"):
click.echo(f"Output: {result['output_hash']}")
if result.get("output_cid"):
click.echo(f"Output: {result['output_cid']}")
if result.get("output_ipfs_cid"):
click.echo(f"IPFS CID: {result['output_ipfs_cid']}")
return
@@ -1505,8 +1505,8 @@ def _wait_for_v2_run(token_data: dict, run_id: str):
if status == "completed":
click.echo(f"\nCompleted!")
if run.get("output_hash"):
click.echo(f"Output: {run['output_hash']}")
if run.get("output_cid"):
click.echo(f"Output: {run['output_cid']}")
if run.get("output_ipfs_cid"):
click.echo(f"IPFS CID: {run['output_ipfs_cid']}")
if run.get("cached"):
@@ -1555,8 +1555,8 @@ def run_status_v2(run_id):
click.echo(f"Recipe: {run['recipe']}")
if run.get("plan_id"):
click.echo(f"Plan ID: {run['plan_id'][:16]}...")
if run.get("output_hash"):
click.echo(f"Output: {run['output_hash']}")
if run.get("output_cid"):
click.echo(f"Output: {run['output_cid']}")
if run.get("output_ipfs_cid"):
click.echo(f"IPFS CID: {run['output_ipfs_cid']}")
if run.get("cached") is not None: