- Fix incorrect API endpoint paths (removed /api prefix) - Improve TypeScript strict typing with explicit metadata interfaces - Update SKILL.md with clear trigger phrases and examples - Fix README installation path reference - Add clarification about API URL format (no /api suffix needed) - Export new metadata type interfaces
206 lines
5.3 KiB
Bash
Executable File
206 lines
5.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# gantt-api.sh - Helper script for Mosaic Stack Gantt/Project API queries
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
# Configuration from environment
|
|
API_URL="${MOSAIC_API_URL:-http://localhost:3000}"
|
|
WORKSPACE_ID="${MOSAIC_WORKSPACE_ID:-}"
|
|
API_TOKEN="${MOSAIC_API_TOKEN:-}"
|
|
|
|
# Check required environment variables
|
|
if [[ -z "$WORKSPACE_ID" ]]; then
|
|
echo "Error: MOSAIC_WORKSPACE_ID environment variable not set" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "$API_TOKEN" ]]; then
|
|
echo "Error: MOSAIC_API_TOKEN environment variable not set" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Helper function to make API requests
|
|
api_request() {
|
|
local method="$1"
|
|
local endpoint="$2"
|
|
local data="${3:-}"
|
|
|
|
local url="${API_URL}${endpoint}"
|
|
local curl_args=(
|
|
-X "$method"
|
|
-H "Content-Type: application/json"
|
|
-H "X-Workspace-Id: $WORKSPACE_ID"
|
|
-H "Authorization: Bearer $API_TOKEN"
|
|
-s
|
|
)
|
|
|
|
if [[ -n "$data" ]]; then
|
|
curl_args+=(-d "$data")
|
|
fi
|
|
|
|
curl "${curl_args[@]}" "$url"
|
|
}
|
|
|
|
# List all projects
|
|
list_projects() {
|
|
local page="${1:-1}"
|
|
local limit="${2:-50}"
|
|
api_request GET "/projects?page=$page&limit=$limit" | jq .
|
|
}
|
|
|
|
# Get a single project with tasks
|
|
get_project() {
|
|
local project_id="$1"
|
|
api_request GET "/projects/$project_id" | jq .
|
|
}
|
|
|
|
# Get tasks with optional filters
|
|
get_tasks() {
|
|
local project_id="${1:-}"
|
|
local filters=""
|
|
|
|
if [[ -n "$project_id" ]]; then
|
|
filters="projectId=$project_id"
|
|
fi
|
|
|
|
api_request GET "/tasks?$filters" | jq .
|
|
}
|
|
|
|
# Get a single task
|
|
get_task() {
|
|
local task_id="$1"
|
|
api_request GET "/tasks/$task_id" | jq .
|
|
}
|
|
|
|
# Get dependency chain for a task
|
|
get_dependencies() {
|
|
local task_id="$1"
|
|
|
|
# Get the task
|
|
local task_json
|
|
task_json=$(get_task "$task_id")
|
|
|
|
# Extract dependency IDs from metadata
|
|
local dep_ids
|
|
dep_ids=$(echo "$task_json" | jq -r '.metadata.dependencies // [] | .[]')
|
|
|
|
if [[ -z "$dep_ids" ]]; then
|
|
echo "Task has no dependencies"
|
|
return
|
|
fi
|
|
|
|
echo "Dependencies for task: $(echo "$task_json" | jq -r '.title')"
|
|
echo ""
|
|
|
|
# Fetch each dependency
|
|
while IFS= read -r dep_id; do
|
|
if [[ -n "$dep_id" ]]; then
|
|
local dep_task
|
|
dep_task=$(get_task "$dep_id")
|
|
echo "- $(echo "$dep_task" | jq -r '.title') [$(echo "$dep_task" | jq -r '.status')]"
|
|
echo " Due: $(echo "$dep_task" | jq -r '.dueDate // "No due date"')"
|
|
fi
|
|
done <<< "$dep_ids"
|
|
}
|
|
|
|
# Calculate critical path for a project
|
|
critical_path() {
|
|
local project_id="$1"
|
|
|
|
# Get all tasks for the project
|
|
local tasks_json
|
|
tasks_json=$(get_tasks "$project_id")
|
|
|
|
# Use jq to build dependency graph and find longest path
|
|
echo "$tasks_json" | jq -r '
|
|
.data as $tasks |
|
|
|
|
# Build adjacency list
|
|
($tasks | map({
|
|
id: .id,
|
|
title: .title,
|
|
status: .status,
|
|
dueDate: .dueDate,
|
|
dependencies: (.metadata.dependencies // [])
|
|
})) as $nodes |
|
|
|
|
# Find tasks with no dependencies (starting points)
|
|
($nodes | map(select(.dependencies | length == 0))) as $starts |
|
|
|
|
# Display structure
|
|
"Critical Path Analysis\n" +
|
|
"======================\n\n" +
|
|
"Starting tasks (no dependencies):\n" +
|
|
($starts | map("- \(.title) [\(.status)]") | join("\n")) +
|
|
"\n\nAll tasks with dependencies:\n" +
|
|
($nodes | map(
|
|
select(.dependencies | length > 0) |
|
|
"- \(.title) [\(.status)]\n Depends on: \(.dependencies | join(", "))"
|
|
) | join("\n"))
|
|
'
|
|
}
|
|
|
|
# Main command dispatcher
|
|
main() {
|
|
if [[ $# -lt 1 ]]; then
|
|
echo "Usage: $0 <command> [args...]" >&2
|
|
echo "" >&2
|
|
echo "Commands:" >&2
|
|
echo " projects - List all projects" >&2
|
|
echo " project <id> - Get project details" >&2
|
|
echo " tasks [project-id] - Get tasks (optionally filtered by project)" >&2
|
|
echo " task <id> - Get task details" >&2
|
|
echo " dependencies <id> - Get dependency chain for task" >&2
|
|
echo " critical-path <id> - Calculate critical path for project" >&2
|
|
exit 1
|
|
fi
|
|
|
|
local command="$1"
|
|
shift
|
|
|
|
case "$command" in
|
|
projects)
|
|
list_projects "$@"
|
|
;;
|
|
project)
|
|
if [[ $# -lt 1 ]]; then
|
|
echo "Error: project command requires project ID" >&2
|
|
exit 1
|
|
fi
|
|
get_project "$1"
|
|
;;
|
|
tasks)
|
|
get_tasks "$@"
|
|
;;
|
|
task)
|
|
if [[ $# -lt 1 ]]; then
|
|
echo "Error: task command requires task ID" >&2
|
|
exit 1
|
|
fi
|
|
get_task "$1"
|
|
;;
|
|
dependencies)
|
|
if [[ $# -lt 1 ]]; then
|
|
echo "Error: dependencies command requires task ID" >&2
|
|
exit 1
|
|
fi
|
|
get_dependencies "$1"
|
|
;;
|
|
critical-path)
|
|
if [[ $# -lt 1 ]]; then
|
|
echo "Error: critical-path command requires project ID" >&2
|
|
exit 1
|
|
fi
|
|
critical_path "$1"
|
|
;;
|
|
*)
|
|
echo "Error: unknown command '$command'" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|