Files
fidelity-ai-workspace/scripts/aiw/profile.py
david.delagneau 1ad707373a Add daily logs and templates for project fidelity
- Created daily log entries for May 13, 14, 18, 19, 20, and 21, capturing work done, findings, and next steps.
- Established a daily logs index for easy navigation of daily notes.
- Developed templates for daily logs, decisions, meeting notes, people, systems, and work items to standardize documentation.
- Introduced base files for filtering and displaying various types of project knowledge, including daily notes, decisions, people, systems, work items, and workstreams.
- Added maps for current work, fidelity apps, and fidelity domain to enhance project navigation and context.
2026-05-21 12:28:07 -06:00

108 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""Profile path resolution for AI Workspace scripts.
Profiles own their configuration. Reusable scripts should call this module
instead of hardcoding root-level project paths.
"""
from __future__ import annotations
import json
import argparse
from pathlib import Path
from typing import Any
ROOT = Path(__file__).resolve().parents[2]
DEFAULT_WORKSPACE = {
"knowledge_dir": "workspaces/{profile}/project-knowledge",
"inbox_dir": "workspaces/{profile}/inbox",
"index_dir": ".aiw/indexes/{profile}",
}
def workspace_config_path(profile: str, root: Path | None = None) -> Path:
base = root or ROOT
return base / "profiles" / profile / "workspace.json"
def load_workspace_config(profile: str, root: Path | None = None) -> dict[str, Any]:
base = root or ROOT
config = dict(DEFAULT_WORKSPACE)
config["profile"] = profile
path = workspace_config_path(profile, root=base)
if path.is_file():
try:
loaded = json.loads(path.read_text(encoding="utf-8"))
if isinstance(loaded, dict):
config.update(loaded)
except json.JSONDecodeError:
pass
return config
def resolve_path(raw: str | None, *, profile: str, root: Path | None = None, fallback: str) -> Path:
base = root or ROOT
value = (raw or fallback).format(profile=profile)
path = Path(value).expanduser()
return path if path.is_absolute() else base / path
def knowledge_dir(profile: str, root: Path | None = None) -> Path:
config = load_workspace_config(profile, root=root)
return resolve_path(config.get("knowledge_dir"), profile=profile, root=root, fallback="workspaces/{profile}/project-knowledge")
def inbox_dir(profile: str, root: Path | None = None) -> Path:
config = load_workspace_config(profile, root=root)
return resolve_path(config.get("inbox_dir"), profile=profile, root=root, fallback="workspaces/{profile}/inbox")
def index_dir(profile: str, root: Path | None = None) -> Path:
config = load_workspace_config(profile, root=root)
return resolve_path(config.get("index_dir"), profile=profile, root=root, fallback=".aiw/indexes/{profile}")
def relative_to_root(path: Path, root: Path | None = None) -> str:
base = root or ROOT
try:
return str(path.relative_to(base))
except ValueError:
return str(path)
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
subparsers = parser.add_subparsers(dest="command", required=True)
path_parser = subparsers.add_parser("path", help="Print a resolved profile path.")
path_parser.add_argument("kind", choices=["knowledge", "inbox", "index"])
path_parser.add_argument("--profile", default="fidelity")
config_parser = subparsers.add_parser("config", help="Print resolved workspace configuration as JSON.")
config_parser.add_argument("--profile", default="fidelity")
args = parser.parse_args()
if args.command == "path":
if args.kind == "knowledge":
print(knowledge_dir(args.profile))
elif args.kind == "inbox":
print(inbox_dir(args.profile))
else:
print(index_dir(args.profile))
return
config = load_workspace_config(args.profile)
config["resolved"] = {
"knowledge_dir": str(knowledge_dir(args.profile)),
"inbox_dir": str(inbox_dir(args.profile)),
"index_dir": str(index_dir(args.profile)),
}
print(json.dumps(config, ensure_ascii=False, indent=2, sort_keys=True))
if __name__ == "__main__":
main()