@prism-d1/cli 1.0.44 → 1.0.46

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.
@@ -0,0 +1,17 @@
1
+ # PRISM D1 Velocity — GitLab CI/CD Pipeline
2
+ #
3
+ # Copy this file to .gitlab-ci.yml in your repo root.
4
+ # Individual workflow files should be placed in .prism/gitlab-workflows/
5
+ #
6
+ # Required setup:
7
+ # 1. Run: prism-cli bootstrapper setup-gitlab-oidc
8
+ # 2. Add CI/CD variable PRISM_METRICS_ROLE_ARN with the output role ARN
9
+ # 3. Copy gitlab-workflows/*.yml to .prism/gitlab-workflows/ in your repo
10
+ # 4. (Optional) Set GITLAB_OIDC_AUDIENCE if not using gitlab.aws.dev
11
+ # 5. (Optional) Create a pipeline schedule for prism-dora-weekly (Monday 09:00 UTC)
12
+
13
+ include:
14
+ - local: '.prism/gitlab-workflows/prism-ai-metrics.yml'
15
+ - local: '.prism/gitlab-workflows/prism-dora-weekly.yml'
16
+ - local: '.prism/gitlab-workflows/prism-agent-eval.yml'
17
+ - local: '.prism/gitlab-workflows/prism-eval-gate.yml'
@@ -0,0 +1,132 @@
1
+ # prism-agent-eval.yml — Evaluate agent outputs on MRs that modify agent code.
2
+ #
3
+ # Include this file in your .gitlab-ci.yml:
4
+ # include:
5
+ # - local: '.prism/gitlab-workflows/prism-agent-eval.yml'
6
+ #
7
+ # Required setup:
8
+ # - CI/CD variable PRISM_METRICS_ROLE_ARN (IAM role with bedrock:InvokeModel + events:PutEvents)
9
+ # - CI/CD variable AWS_REGION (default: us-west-2)
10
+ # - .prism/config.json committed to the repo
11
+ # - .prism/eval-harness/ installed (run: prism-cli bootstrapper install-eval-harness)
12
+ # - (Optional) Agent entry point supports --mock flag for dry-run execution
13
+
14
+ prism-agent-eval:
15
+ stage: test
16
+ image: python:3.12-slim
17
+ id_tokens:
18
+ GITLAB_OIDC_TOKEN:
19
+ aud: https://gitlab.aws.dev
20
+ rules:
21
+ - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
22
+ changes:
23
+ - agent/**
24
+ - agents/**
25
+ - mcp-servers/**
26
+ - "**/*agent*.py"
27
+ - "**/*agent*.ts"
28
+ variables:
29
+ AWS_DEFAULT_REGION: ${AWS_REGION:-us-west-2}
30
+ before_script:
31
+ - apt-get update -qq && apt-get install -y -qq jq bc git curl unzip
32
+ - curl -s "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip
33
+ - unzip -q /tmp/awscliv2.zip -d /tmp && /tmp/aws/install
34
+ - pip install --quiet strands-agents strands-agents-tools requests
35
+ - git fetch --unshallow || true
36
+ - |
37
+ # Assume AWS role via GitLab OIDC
38
+ if [[ -n "${PRISM_METRICS_ROLE_ARN}" && -n "${GITLAB_OIDC_TOKEN}" ]]; then
39
+ CREDS=$(aws sts assume-role-with-web-identity \
40
+ --role-arn "${PRISM_METRICS_ROLE_ARN}" \
41
+ --role-session-name "gitlab-ci-${CI_JOB_ID}" \
42
+ --web-identity-token "${GITLAB_OIDC_TOKEN}" \
43
+ --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
44
+ --output text)
45
+ export AWS_ACCESS_KEY_ID=$(echo "${CREDS}" | awk '{print $1}')
46
+ export AWS_SECRET_ACCESS_KEY=$(echo "${CREDS}" | awk '{print $2}')
47
+ export AWS_SESSION_TOKEN=$(echo "${CREDS}" | awk '{print $3}')
48
+ fi
49
+ script:
50
+ - |
51
+ TEAM_ID=$(jq -r '.team_id // "no_team"' .prism/config.json 2>/dev/null || echo "no_team")
52
+ BASE_SHA="${CI_MERGE_REQUEST_DIFF_BASE_SHA}"
53
+ HEAD_SHA="${CI_COMMIT_SHA}"
54
+
55
+ # Identify agent changes
56
+ AGENT_FILES=$(git diff --name-only "${BASE_SHA}..${HEAD_SHA}" \
57
+ | grep -E '(^agent/|^agents/|^mcp-servers/|agent.*\.(py|ts)$)' || true)
58
+
59
+ if [[ -z "${AGENT_FILES}" ]]; then
60
+ echo "No agent-related files changed. Skipping."
61
+ exit 0
62
+ fi
63
+
64
+ FILE_COUNT=$(echo "${AGENT_FILES}" | wc -l | tr -d ' ')
65
+ echo "Found ${FILE_COUNT} changed agent files."
66
+
67
+ # Run agent in mock mode
68
+ AGENT_ENTRY=""
69
+ for CANDIDATE in agent/main.py agents/main.py agent.py; do
70
+ [[ -f "${CANDIDATE}" ]] && AGENT_ENTRY="${CANDIDATE}" && break
71
+ done
72
+
73
+ MOCK_RAN="false"
74
+ if [[ -n "${AGENT_ENTRY}" ]]; then
75
+ echo "Running agent in mock mode: ${AGENT_ENTRY}"
76
+ MOCK_RAN="true"
77
+ set +e
78
+ python "${AGENT_ENTRY}" --mock > /tmp/agent-output.json 2>/tmp/agent-stderr.log
79
+ AGENT_EXIT=$?
80
+ set -e
81
+ else
82
+ echo "{}" > /tmp/agent-output.json
83
+ AGENT_EXIT=0
84
+ fi
85
+
86
+ # Evaluate
87
+ chmod +x .prism/eval-harness/run-eval.sh
88
+ RUBRIC=".prism/eval-harness/rubrics/agent-quality.json"
89
+
90
+ if [[ -s /tmp/agent-output.json ]]; then
91
+ EVAL_TARGET="/tmp/agent-output.json"
92
+ else
93
+ EVAL_TARGET=$(echo "${AGENT_FILES}" | head -1)
94
+ fi
95
+
96
+ set +e
97
+ OUTPUT=$(./.prism/eval-harness/run-eval.sh "${RUBRIC}" "${EVAL_TARGET}" 2>&1)
98
+ set -e
99
+
100
+ SCORE=$(echo "${OUTPUT}" | grep '^Score:' | awk '{print $2}' || echo "0")
101
+ RESULT=$(echo "${OUTPUT}" | grep '^Result:' | awk '{print $2}' || echo "UNKNOWN")
102
+
103
+ echo "Agent eval: score=${SCORE} result=${RESULT}"
104
+
105
+ # Post MR note
106
+ if [[ -n "${GITLAB_TOKEN:-${CI_JOB_TOKEN}}" ]]; then
107
+ EMOJI=$([[ "${RESULT}" == "PASS" ]] && echo "✅" || echo "❌")
108
+ NOTE="## ${EMOJI} PRISM Agent Eval — ${RESULT}\n\n**Score**: ${SCORE} | **Agent Files**: ${FILE_COUNT} | **Mock**: ${MOCK_RAN} (exit ${AGENT_EXIT})"
109
+ curl -s --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN:-${CI_JOB_TOKEN}}" \
110
+ --form "body=${NOTE}" \
111
+ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/notes" > /dev/null
112
+ fi
113
+
114
+ # Emit event
115
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
116
+ EVAL_EVENT=$(jq -n \
117
+ --arg team_id "${TEAM_ID}" --arg repo "${CI_PROJECT_PATH}" --arg timestamp "${TIMESTAMP}" \
118
+ --argjson score "${SCORE:-0}" --arg result "${RESULT}" --argjson file_count "${FILE_COUNT}" \
119
+ --arg mr_iid "${CI_MERGE_REQUEST_IID}" --arg mock_ran "${MOCK_RAN}" \
120
+ '{team_id:$team_id, repo:$repo, timestamp:$timestamp, prism_level:3,
121
+ metric:{name:"agent_eval_score",value:$score,unit:"score"},
122
+ ai_context:{tool:"bedrock-eval",model:"anthropic.claude-sonnet-4-20250514",origin:"ai-generated"},
123
+ ai_dora:{eval_gate_pass_rate:(if $result == "PASS" then 1.0 else 0.0 end)},
124
+ agent_eval:{file_count:$file_count, result:$result, mock_ran:($mock_ran == "true"),
125
+ mr_iid:($mr_iid | tonumber), rubric:"agent-quality"}}')
126
+
127
+ aws events put-events --region "${AWS_DEFAULT_REGION}" \
128
+ --entries "[{\"Source\":\"prism.d1.velocity\",\"DetailType\":\"prism.d1.agent.eval\",
129
+ \"EventBusName\":\"prism-d1-metrics\",
130
+ \"Detail\":$(echo "${EVAL_EVENT}" | jq -c '.' | jq -Rs '.')}]"
131
+
132
+ [[ "${RESULT}" == "FAIL" ]] && exit 1 || exit 0
@@ -0,0 +1,141 @@
1
+ # prism-ai-metrics.yml — Emit AI-assisted development metrics on MR merge.
2
+ #
3
+ # Include this file in your .gitlab-ci.yml:
4
+ # include:
5
+ # - local: '.prism/gitlab-workflows/prism-ai-metrics.yml'
6
+ #
7
+ # Required setup:
8
+ # - CI/CD variable PRISM_METRICS_ROLE_ARN (IAM role ARN with events:PutEvents)
9
+ # - CI/CD variable AWS_REGION (default: us-west-2)
10
+ # - .prism/config.json committed to the repo
11
+ # - AWS credentials configured via OIDC or CI/CD variables
12
+
13
+ prism-ai-metrics:
14
+ stage: .post
15
+ image:
16
+ name: amazon/aws-cli:latest
17
+ entrypoint: [""]
18
+ id_tokens:
19
+ GITLAB_OIDC_TOKEN:
20
+ aud: https://gitlab.aws.dev
21
+ rules:
22
+ - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_STATE == "merged"'
23
+ - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"'
24
+ variables:
25
+ AWS_DEFAULT_REGION: ${AWS_REGION:-us-west-2}
26
+ before_script:
27
+ - yum install -y -q jq bc git
28
+ - git fetch --unshallow || true
29
+ - |
30
+ # Assume AWS role via GitLab OIDC
31
+ if [[ -n "${PRISM_METRICS_ROLE_ARN}" && -n "${GITLAB_OIDC_TOKEN}" ]]; then
32
+ CREDS=$(aws sts assume-role-with-web-identity \
33
+ --role-arn "${PRISM_METRICS_ROLE_ARN}" \
34
+ --role-session-name "gitlab-ci-${CI_JOB_ID}" \
35
+ --web-identity-token "${GITLAB_OIDC_TOKEN}" \
36
+ --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
37
+ --output text)
38
+ export AWS_ACCESS_KEY_ID=$(echo "${CREDS}" | awk '{print $1}')
39
+ export AWS_SECRET_ACCESS_KEY=$(echo "${CREDS}" | awk '{print $2}')
40
+ export AWS_SESSION_TOKEN=$(echo "${CREDS}" | awk '{print $3}')
41
+ fi
42
+ script:
43
+ - |
44
+ # Read team ID
45
+ TEAM_ID=$(jq -r '.team_id // "no_team"' .prism/config.json 2>/dev/null || echo "no_team")
46
+
47
+ # Determine commit range
48
+ if [[ -n "${CI_MERGE_REQUEST_DIFF_BASE_SHA}" ]]; then
49
+ BASE_SHA="${CI_MERGE_REQUEST_DIFF_BASE_SHA}"
50
+ HEAD_SHA="${CI_COMMIT_SHA}"
51
+ else
52
+ BASE_SHA=$(git rev-parse HEAD~1 2>/dev/null || git rev-parse HEAD)
53
+ HEAD_SHA="${CI_COMMIT_SHA}"
54
+ fi
55
+
56
+ TOTAL_COMMITS=$(git rev-list --count "${BASE_SHA}..${HEAD_SHA}" 2>/dev/null || echo "1")
57
+
58
+ # Count AI origin per-commit
59
+ AI_GENERATED=0; AI_ASSISTED=0; HUMAN_ONLY=0
60
+ TOTAL_INPUT_TOKENS=0; TOTAL_OUTPUT_TOKENS=0; TOTAL_COST="0"
61
+
62
+ for SHA in $(git rev-list "${BASE_SHA}..${HEAD_SHA}" 2>/dev/null || echo "${HEAD_SHA}"); do
63
+ MSG=$(git log -1 --format='%B' "${SHA}")
64
+ echo "${MSG}" | grep -q '^AI-Origin: ai-generated' && AI_GENERATED=$((AI_GENERATED + 1))
65
+ echo "${MSG}" | grep -q '^AI-Origin: ai-assisted' && AI_ASSISTED=$((AI_ASSISTED + 1))
66
+ echo "${MSG}" | grep -q '^AI-Origin: human' && HUMAN_ONLY=$((HUMAN_ONLY + 1))
67
+
68
+ INPUT_T=$(echo "${MSG}" | grep -oP '(?<=^AI-Input-Tokens: )\d+' || echo "0")
69
+ OUTPUT_T=$(echo "${MSG}" | grep -oP '(?<=^AI-Output-Tokens: )\d+' || echo "0")
70
+ COST_T=$(echo "${MSG}" | grep -oP '(?<=^AI-Cost: )[0-9.]+' || echo "0")
71
+ [[ ${INPUT_T} -gt 1000000 ]] && INPUT_T=0
72
+ [[ ${OUTPUT_T} -gt 1000000 ]] && OUTPUT_T=0
73
+ TOTAL_INPUT_TOKENS=$((TOTAL_INPUT_TOKENS + INPUT_T))
74
+ TOTAL_OUTPUT_TOKENS=$((TOTAL_OUTPUT_TOKENS + OUTPUT_T))
75
+ TOTAL_COST=$(echo "${TOTAL_COST} + ${COST_T}" | bc -l)
76
+ done
77
+
78
+ AI_COMMITS=$((AI_GENERATED + AI_ASSISTED))
79
+ [[ "${TOTAL_COMMITS}" -gt 0 ]] && AI_RATIO=$(echo "scale=4; ${AI_COMMITS} / ${TOTAL_COMMITS}" | bc -l | sed 's/^\./0./') || AI_RATIO="0"
80
+
81
+ # Calculate lead time (MR created to merged)
82
+ LEAD_TIME_SECONDS=0
83
+ if [[ -n "${CI_MERGE_REQUEST_CREATED_AT}" ]]; then
84
+ CREATED_TS=$(date -d "${CI_MERGE_REQUEST_CREATED_AT}" +%s 2>/dev/null || echo "0")
85
+ MERGED_TS=$(date +%s)
86
+ LEAD_TIME_SECONDS=$((MERGED_TS - CREATED_TS))
87
+ fi
88
+
89
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
90
+
91
+ PR_EVENT=$(jq -n \
92
+ --arg team_id "${TEAM_ID}" \
93
+ --arg repo "${CI_PROJECT_PATH}" \
94
+ --arg timestamp "${TIMESTAMP}" \
95
+ --argjson ai_ratio "${AI_RATIO}" \
96
+ --argjson total_commits "${TOTAL_COMMITS}" \
97
+ --argjson ai_commits "${AI_COMMITS}" \
98
+ --argjson ai_generated "${AI_GENERATED}" \
99
+ --argjson ai_assisted "${AI_ASSISTED}" \
100
+ --argjson lead_time_seconds "${LEAD_TIME_SECONDS}" \
101
+ --arg mr_iid "${CI_MERGE_REQUEST_IID:-0}" \
102
+ --arg mr_author "${GITLAB_USER_LOGIN}" \
103
+ --argjson total_input_tokens "${TOTAL_INPUT_TOKENS}" \
104
+ --argjson total_output_tokens "${TOTAL_OUTPUT_TOKENS}" \
105
+ --arg total_cost "${TOTAL_COST}" \
106
+ '{
107
+ team_id: $team_id, repo: $repo, timestamp: $timestamp, prism_level: 2,
108
+ metric: {name: "ai_to_merge_ratio", value: $ai_ratio, unit: "ratio"},
109
+ ai_context: {tool: "gitlab-ci", model: "n/a",
110
+ origin: (if $ai_ratio > 0 then "ai-assisted" else "human" end)},
111
+ dora: {deployment_frequency: 1, lead_time_seconds: $lead_time_seconds},
112
+ ai_dora: {ai_to_merge_ratio: $ai_ratio, total_commits: $total_commits,
113
+ ai_commits: $ai_commits, ai_generated_commits: $ai_generated,
114
+ ai_assisted_commits: $ai_assisted,
115
+ total_input_tokens: $total_input_tokens,
116
+ total_output_tokens: $total_output_tokens,
117
+ total_cost_usd: (if $total_cost != "0" and $total_cost != "" then ($total_cost | tonumber) else 0 end)},
118
+ mr: {iid: ($mr_iid | tonumber), author: $mr_author}
119
+ }')
120
+
121
+ aws events put-events --region "${AWS_DEFAULT_REGION}" \
122
+ --entries "[{
123
+ \"Source\": \"prism.d1.velocity\",
124
+ \"DetailType\": \"prism.d1.pr\",
125
+ \"EventBusName\": \"prism-d1-metrics\",
126
+ \"Detail\": $(echo "${PR_EVENT}" | jq -c '.' | jq -Rs '.')
127
+ }]"
128
+
129
+ # Also emit deploy event
130
+ DEPLOY_EVENT=$(jq -n --arg team_id "${TEAM_ID}" --arg repo "${CI_PROJECT_PATH}" --arg timestamp "${TIMESTAMP}" \
131
+ '{team_id: $team_id, repo: $repo, timestamp: $timestamp, prism_level: 2,
132
+ metric: {name: "deployment", value: 1, unit: "count"},
133
+ dora: {deployment_frequency: 1}}')
134
+
135
+ aws events put-events --region "${AWS_DEFAULT_REGION}" \
136
+ --entries "[{
137
+ \"Source\": \"prism.d1.velocity\",
138
+ \"DetailType\": \"prism.d1.deploy\",
139
+ \"EventBusName\": \"prism-d1-metrics\",
140
+ \"Detail\": $(echo "${DEPLOY_EVENT}" | jq -c '.' | jq -Rs '.')
141
+ }]"
@@ -0,0 +1,168 @@
1
+ # prism-dora-weekly.yml — Weekly DORA + AI-DORA metrics assessment.
2
+ #
3
+ # Include this file in your .gitlab-ci.yml:
4
+ # include:
5
+ # - local: '.prism/gitlab-workflows/prism-dora-weekly.yml'
6
+ #
7
+ # Required setup:
8
+ # - CI/CD variable PRISM_METRICS_ROLE_ARN (IAM role with events:PutEvents + cloudwatch:PutMetricData)
9
+ # - CI/CD variable AWS_REGION (default: us-west-2)
10
+ # - .prism/config.json committed to the repo
11
+ # - Pipeline schedule configured: weekly on Monday at 09:00 UTC
12
+
13
+ prism-dora-weekly:
14
+ stage: .post
15
+ image:
16
+ name: amazon/aws-cli:latest
17
+ entrypoint: [""]
18
+ id_tokens:
19
+ GITLAB_OIDC_TOKEN:
20
+ aud: https://gitlab.aws.dev
21
+ rules:
22
+ - if: '$CI_PIPELINE_SOURCE == "schedule"'
23
+ - if: '$CI_PIPELINE_SOURCE == "web"'
24
+ when: manual
25
+ variables:
26
+ AWS_DEFAULT_REGION: ${AWS_REGION:-us-west-2}
27
+ before_script:
28
+ - yum install -y -q jq bc git curl
29
+ - git fetch --unshallow || true
30
+ - |
31
+ # Assume AWS role via GitLab OIDC
32
+ if [[ -n "${PRISM_METRICS_ROLE_ARN}" && -n "${GITLAB_OIDC_TOKEN}" ]]; then
33
+ CREDS=$(aws sts assume-role-with-web-identity \
34
+ --role-arn "${PRISM_METRICS_ROLE_ARN}" \
35
+ --role-session-name "gitlab-ci-${CI_JOB_ID}" \
36
+ --web-identity-token "${GITLAB_OIDC_TOKEN}" \
37
+ --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
38
+ --output text)
39
+ export AWS_ACCESS_KEY_ID=$(echo "${CREDS}" | awk '{print $1}')
40
+ export AWS_SECRET_ACCESS_KEY=$(echo "${CREDS}" | awk '{print $2}')
41
+ export AWS_SESSION_TOKEN=$(echo "${CREDS}" | awk '{print $3}')
42
+ fi
43
+ script:
44
+ - |
45
+ TEAM_ID=$(jq -r '.team_id // "no_team"' .prism/config.json 2>/dev/null || echo "no_team")
46
+ SINCE_DATE=$(date -u -d '7 days ago' +"%Y-%m-%d")
47
+ REPO="${CI_PROJECT_PATH}"
48
+ NAMESPACE="PRISM/D1/Velocity"
49
+
50
+ # ---------------------------------------------------------------
51
+ # 1. Deployment Frequency — merged MRs to default branch (past 7 days)
52
+ # ---------------------------------------------------------------
53
+ SINCE_ISO=$(date -u -d '7 days ago' +"%Y-%m-%dT%H:%M:%SZ")
54
+ MERGED_MRS=$(curl -s --header "PRIVATE-TOKEN: ${GITLAB_TOKEN:-${CI_JOB_TOKEN}}" \
55
+ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests?state=merged&updated_after=${SINCE_ISO}&per_page=100" 2>/dev/null || echo "[]")
56
+ DEPLOY_COUNT=$(echo "${MERGED_MRS}" | jq 'length')
57
+ DEPLOY_FREQUENCY=$(echo "scale=2; ${DEPLOY_COUNT} / 7" | bc -l | sed 's/^\./0./')
58
+
59
+ # ---------------------------------------------------------------
60
+ # 2. Lead Time — avg time from MR open to merge
61
+ # ---------------------------------------------------------------
62
+ AVG_LEAD_TIME_HOURS=$(echo "${MERGED_MRS}" | jq '
63
+ if length == 0 then 0
64
+ else [.[] | select(.merged_at != null and .created_at != null) |
65
+ ((.merged_at | sub("\\.[0-9]+Z$"; "Z") | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime) -
66
+ (.created_at | sub("\\.[0-9]+Z$"; "Z") | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime)) / 3600
67
+ ] | if length > 0 then add / length | . * 100 | round / 100 else 0 end
68
+ end')
69
+
70
+ # ---------------------------------------------------------------
71
+ # 3. Change Failure Rate — MRs with "revert|hotfix|rollback" in title
72
+ # ---------------------------------------------------------------
73
+ FAILURE_MRS=$(echo "${MERGED_MRS}" | jq '[.[] | select(.title // "" | test("revert|hotfix|rollback"; "i"))] | length')
74
+ [[ "${DEPLOY_COUNT}" -gt 0 ]] && CHANGE_FAILURE_RATE=$(echo "scale=4; ${FAILURE_MRS} / ${DEPLOY_COUNT}" | bc -l | sed 's/^\./0./') || CHANGE_FAILURE_RATE="0"
75
+
76
+ # ---------------------------------------------------------------
77
+ # 4. MTTR — avg time for hotfix/revert MRs
78
+ # ---------------------------------------------------------------
79
+ MTTR_HOURS=$(echo "${MERGED_MRS}" | jq '
80
+ [.[] | select(.title // "" | test("revert|hotfix|rollback"; "i")) |
81
+ select(.merged_at != null and .created_at != null) |
82
+ ((.merged_at | sub("\\.[0-9]+Z$"; "Z") | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime) -
83
+ (.created_at | sub("\\.[0-9]+Z$"; "Z") | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime)) / 3600
84
+ ] | if length > 0 then add / length | . * 100 | round / 100 else 0 end')
85
+
86
+ # ---------------------------------------------------------------
87
+ # 5. AI-DORA metrics from commit trailers
88
+ # ---------------------------------------------------------------
89
+ TOTAL_COMMITS=$(git log --since="${SINCE_DATE}" --oneline "${CI_DEFAULT_BRANCH}" 2>/dev/null | wc -l | tr -d ' ')
90
+ AI_GENERATED=0; AI_ASSISTED=0; HUMAN_ONLY=0; SPEC_REFS=0
91
+ CLAUDE_CODE_COUNT=0; KIRO_COUNT=0; Q_DEV_COUNT=0
92
+
93
+ for SHA in $(git log --since="${SINCE_DATE}" --format='%H' "${CI_DEFAULT_BRANCH}" 2>/dev/null); do
94
+ MSG=$(git log -1 --format='%B' "${SHA}")
95
+ echo "${MSG}" | grep -q '^AI-Origin: ai-generated' && AI_GENERATED=$((AI_GENERATED + 1))
96
+ echo "${MSG}" | grep -q '^AI-Origin: ai-assisted' && AI_ASSISTED=$((AI_ASSISTED + 1))
97
+ echo "${MSG}" | grep -q '^AI-Origin: human' && HUMAN_ONLY=$((HUMAN_ONLY + 1))
98
+ echo "${MSG}" | grep -q '^Spec-Ref:' && SPEC_REFS=$((SPEC_REFS + 1))
99
+ TOOL=$(echo "${MSG}" | grep -oP '(?<=^AI-Tool: ).+' || true)
100
+ case "${TOOL}" in
101
+ *claude-code*) CLAUDE_CODE_COUNT=$((CLAUDE_CODE_COUNT + 1)) ;;
102
+ *kiro*) KIRO_COUNT=$((KIRO_COUNT + 1)) ;;
103
+ *q-developer*) Q_DEV_COUNT=$((Q_DEV_COUNT + 1)) ;;
104
+ esac
105
+ done
106
+
107
+ UNTAGGED=$((TOTAL_COMMITS - AI_GENERATED - AI_ASSISTED - HUMAN_ONLY))
108
+ [[ "${UNTAGGED}" -lt 0 ]] && UNTAGGED=0
109
+ AI_TOTAL=$((AI_GENERATED + AI_ASSISTED))
110
+ [[ "${TOTAL_COMMITS}" -gt 0 ]] && AI_ADOPTION_RATE=$(echo "scale=4; ${AI_TOTAL} / ${TOTAL_COMMITS}" | bc -l | sed 's/^\./0./') || AI_ADOPTION_RATE="0"
111
+ [[ "${TOTAL_COMMITS}" -gt 0 ]] && SPEC_COVERAGE=$(echo "scale=4; ${SPEC_REFS} / ${TOTAL_COMMITS}" | bc -l | sed 's/^\./0./') || SPEC_COVERAGE="0"
112
+
113
+ # ---------------------------------------------------------------
114
+ # Emit assessment event
115
+ # ---------------------------------------------------------------
116
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
117
+
118
+ ASSESSMENT_EVENT=$(jq -n \
119
+ --arg team_id "${TEAM_ID}" --arg repo "${REPO}" --arg timestamp "${TIMESTAMP}" \
120
+ --argjson deploy_count "${DEPLOY_COUNT}" --argjson deploy_frequency "${DEPLOY_FREQUENCY}" \
121
+ --argjson avg_lead_time_hours "${AVG_LEAD_TIME_HOURS}" \
122
+ --argjson change_failure_rate "${CHANGE_FAILURE_RATE}" --argjson mttr_hours "${MTTR_HOURS}" \
123
+ --argjson total_commits "${TOTAL_COMMITS}" --argjson ai_generated "${AI_GENERATED}" \
124
+ --argjson ai_assisted "${AI_ASSISTED}" --argjson human_only "${HUMAN_ONLY}" \
125
+ --argjson untagged "${UNTAGGED}" --argjson ai_adoption_rate "${AI_ADOPTION_RATE}" \
126
+ --argjson spec_coverage "${SPEC_COVERAGE}" \
127
+ --argjson claude_code "${CLAUDE_CODE_COUNT}" --argjson kiro "${KIRO_COUNT}" --argjson q_dev "${Q_DEV_COUNT}" \
128
+ '{team_id:$team_id, repo:$repo, timestamp:$timestamp, prism_level:2,
129
+ metric:{name:"weekly_assessment",value:1,unit:"assessment"},
130
+ dora:{deployment_frequency:$deploy_frequency, deployments:$deploy_count,
131
+ lead_time_hours:$avg_lead_time_hours, change_failure_rate:$change_failure_rate,
132
+ mttr_hours:$mttr_hours},
133
+ ai_dora:{ai_adoption_rate:$ai_adoption_rate, ai_to_merge_ratio:$ai_adoption_rate,
134
+ total_commits:$total_commits, ai_generated_commits:$ai_generated,
135
+ ai_assisted_commits:$ai_assisted, human_commits:$human_only,
136
+ untagged_commits:$untagged, spec_coverage:$spec_coverage,
137
+ tool_breakdown:{claude_code:$claude_code, kiro:$kiro, q_developer:$q_dev}}}')
138
+
139
+ aws events put-events --region "${AWS_DEFAULT_REGION}" \
140
+ --entries "[{\"Source\":\"prism.d1.velocity\",\"DetailType\":\"prism.d1.assessment\",
141
+ \"EventBusName\":\"prism-d1-metrics\",
142
+ \"Detail\":$(echo "${ASSESSMENT_EVENT}" | jq -c '.' | jq -Rs '.')}]"
143
+
144
+ # Emit CloudWatch metrics
145
+ for METRIC_DATA in \
146
+ "AIAdoptionRate:${AI_ADOPTION_RATE}:Percent" \
147
+ "SpecCoverage:${SPEC_COVERAGE}:Percent" \
148
+ "ClaudeCodeCommits:${CLAUDE_CODE_COUNT}:Count" \
149
+ "KiroCommits:${KIRO_COUNT}:Count" \
150
+ "QDeveloperCommits:${Q_DEV_COUNT}:Count" \
151
+ "UntaggedCommits:${UNTAGGED}:Count"; do
152
+ METRIC_NAME="${METRIC_DATA%%:*}"; REST="${METRIC_DATA#*:}"
153
+ METRIC_VALUE="${REST%%:*}"; METRIC_UNIT="${REST#*:}"
154
+ aws cloudwatch put-metric-data --region "${AWS_DEFAULT_REGION}" --namespace "${NAMESPACE}" \
155
+ --metric-data "[{\"MetricName\":\"${METRIC_NAME}\",\"Value\":${METRIC_VALUE},
156
+ \"Unit\":\"${METRIC_UNIT}\",\"Timestamp\":\"${TIMESTAMP}\",
157
+ \"Dimensions\":[{\"Name\":\"TeamId\",\"Value\":\"${TEAM_ID}\"},{\"Name\":\"Repository\",\"Value\":\"${REPO}\"}]}]"
158
+ done
159
+
160
+ echo "=== DORA Metrics ==="
161
+ echo "Deployment Frequency: ${DEPLOY_FREQUENCY}/day"
162
+ echo "Lead Time: ${AVG_LEAD_TIME_HOURS} hours"
163
+ echo "Change Failure Rate: ${CHANGE_FAILURE_RATE}"
164
+ echo "MTTR: ${MTTR_HOURS} hours"
165
+ echo "=== AI-DORA Metrics ==="
166
+ echo "AI Adoption Rate: ${AI_ADOPTION_RATE}"
167
+ echo "Spec Coverage: ${SPEC_COVERAGE}"
168
+ echo "Total Commits: ${TOTAL_COMMITS}"
@@ -0,0 +1,141 @@
1
+ # prism-eval-gate.yml — Evaluate AI-generated code quality on MRs.
2
+ #
3
+ # Include this file in your .gitlab-ci.yml:
4
+ # include:
5
+ # - local: '.prism/gitlab-workflows/prism-eval-gate.yml'
6
+ #
7
+ # Required setup:
8
+ # - CI/CD variable PRISM_METRICS_ROLE_ARN (IAM role with bedrock:InvokeModel + events:PutEvents)
9
+ # - CI/CD variable AWS_REGION (default: us-west-2)
10
+ # - .prism/eval-harness/ directory in your repo (run: prism-cli bootstrapper install-eval-harness)
11
+ # - At least one rubric JSON in .prism/eval-harness/rubrics/
12
+
13
+ prism-eval-gate:
14
+ stage: test
15
+ image:
16
+ name: amazon/aws-cli:latest
17
+ entrypoint: [""]
18
+ id_tokens:
19
+ GITLAB_OIDC_TOKEN:
20
+ aud: https://gitlab.aws.dev
21
+ rules:
22
+ - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
23
+ variables:
24
+ AWS_DEFAULT_REGION: ${AWS_REGION:-us-west-2}
25
+ before_script:
26
+ - yum install -y -q jq bc git curl
27
+ - git fetch --unshallow || true
28
+ - |
29
+ # Assume AWS role via GitLab OIDC
30
+ if [[ -n "${PRISM_METRICS_ROLE_ARN}" && -n "${GITLAB_OIDC_TOKEN}" ]]; then
31
+ CREDS=$(aws sts assume-role-with-web-identity \
32
+ --role-arn "${PRISM_METRICS_ROLE_ARN}" \
33
+ --role-session-name "gitlab-ci-${CI_JOB_ID}" \
34
+ --web-identity-token "${GITLAB_OIDC_TOKEN}" \
35
+ --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
36
+ --output text)
37
+ export AWS_ACCESS_KEY_ID=$(echo "${CREDS}" | awk '{print $1}')
38
+ export AWS_SECRET_ACCESS_KEY=$(echo "${CREDS}" | awk '{print $2}')
39
+ export AWS_SESSION_TOKEN=$(echo "${CREDS}" | awk '{print $3}')
40
+ fi
41
+ script:
42
+ - |
43
+ TEAM_ID=$(jq -r '.team_id // "no_team"' .prism/config.json 2>/dev/null || echo "no_team")
44
+ BASE_SHA="${CI_MERGE_REQUEST_DIFF_BASE_SHA}"
45
+ HEAD_SHA="${CI_COMMIT_SHA}"
46
+
47
+ # Identify AI-generated commits
48
+ AI_SHAS=""
49
+ for SHA in $(git rev-list "${BASE_SHA}..${HEAD_SHA}" 2>/dev/null); do
50
+ if git log -1 --format='%B' "${SHA}" | grep -q 'AI-Origin: ai-generated\|AI-Origin: ai-assisted'; then
51
+ AI_SHAS="${AI_SHAS} ${SHA}"
52
+ fi
53
+ done
54
+ AI_SHAS=$(echo "${AI_SHAS}" | xargs)
55
+
56
+ if [[ -z "${AI_SHAS}" ]]; then
57
+ echo "No AI-generated code detected. Skipping eval gate."
58
+ # Post skip note
59
+ curl -s --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN:-${CI_JOB_TOKEN}}" \
60
+ --form "body=✅ **PRISM Eval Gate** — No AI-generated code detected. Skipped." \
61
+ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/notes" > /dev/null 2>&1 || true
62
+ exit 0
63
+ fi
64
+
65
+ # Collect changed source files from AI commits
66
+ CHANGED_FILES=""
67
+ for SHA in ${AI_SHAS}; do
68
+ FILES=$(git diff-tree --no-commit-id --name-only -r "${SHA}" \
69
+ | grep -E '\.(ts|js|py|go|java|rs|tsx|jsx)$' | grep -v '\.test\.\|\.spec\.' || true)
70
+ CHANGED_FILES="${CHANGED_FILES}\n${FILES}"
71
+ done
72
+ echo -e "${CHANGED_FILES}" | sort -u | grep -v '^$' > /tmp/ai-changed-files.txt || true
73
+ FILE_COUNT=$(wc -l < /tmp/ai-changed-files.txt | tr -d ' ')
74
+
75
+ # Run evaluations
76
+ chmod +x .prism/eval-harness/run-eval.sh
77
+ PASS_COUNT=0; FAIL_COUNT=0; TOTAL_SCORE=0; TOTAL_HALLUCINATIONS=0; RESULTS=""
78
+
79
+ while IFS= read -r FILE; do
80
+ [[ -z "${FILE}" || ! -f "${FILE}" ]] && continue
81
+
82
+ # Auto-select rubric
83
+ if echo "${FILE}" | grep -qiE '(agent|assistant|orchestrat|workflow|chain)'; then
84
+ RUBRIC=".prism/eval-harness/rubrics/agent-quality.json"
85
+ elif echo "${FILE}" | grep -qiE '(auth|security|guard|policy|iam|permission|crypto)'; then
86
+ RUBRIC=".prism/eval-harness/rubrics/security-compliance.json"
87
+ elif echo "${FILE}" | grep -qiE '(api|handler|route|controller)'; then
88
+ RUBRIC=".prism/eval-harness/rubrics/api-response-quality.json"
89
+ else
90
+ RUBRIC=".prism/eval-harness/rubrics/code-quality.json"
91
+ fi
92
+ [[ -f "${RUBRIC}" ]] || RUBRIC=$(ls .prism/eval-harness/rubrics/*.json 2>/dev/null | head -1)
93
+ [[ -f "${RUBRIC}" ]] || { echo "No rubrics found"; exit 1; }
94
+
95
+ set +e
96
+ OUTPUT=$(./.prism/eval-harness/run-eval.sh "${RUBRIC}" "${FILE}" 2>&1)
97
+ set -e
98
+
99
+ SCORE=$(echo "${OUTPUT}" | grep '^Score:' | awk '{print $2}' || echo "0")
100
+ RESULT=$(echo "${OUTPUT}" | grep '^Result:' | awk '{print $2}' || echo "UNKNOWN")
101
+ HALLUC=$(echo "${OUTPUT}" | grep '^Hallucinations:' | awk '{print $2}' || echo "0")
102
+
103
+ TOTAL_SCORE=$(echo "${TOTAL_SCORE} + ${SCORE}" | bc -l)
104
+ TOTAL_HALLUCINATIONS=$((TOTAL_HALLUCINATIONS + HALLUC))
105
+
106
+ [[ "${RESULT}" == "SKIP" ]] && continue
107
+ [[ "${RESULT}" == "PASS" ]] && PASS_COUNT=$((PASS_COUNT + 1)) || FAIL_COUNT=$((FAIL_COUNT + 1))
108
+ RESULTS="${RESULTS}\n| \`${FILE}\` | $(basename "${RUBRIC}" .json) | ${SCORE} | ${RESULT} |"
109
+ done < /tmp/ai-changed-files.txt
110
+
111
+ TOTAL_FILES=$((PASS_COUNT + FAIL_COUNT))
112
+ [[ "${TOTAL_FILES}" -gt 0 ]] && AVG_SCORE=$(echo "scale=4; ${TOTAL_SCORE} / ${TOTAL_FILES}" | bc -l) || AVG_SCORE="0"
113
+ [[ "${FAIL_COUNT}" -gt 0 ]] && OVERALL="FAIL" || OVERALL="PASS"
114
+
115
+ # Post MR note
116
+ EMOJI=$([[ "${OVERALL}" == "PASS" ]] && echo "✅" || echo "❌")
117
+ NOTE="## ${EMOJI} PRISM Eval Gate — ${OVERALL}\n\n**Score**: ${AVG_SCORE} | **Files**: ${TOTAL_FILES} | **Pass**: ${PASS_COUNT} | **Fail**: ${FAIL_COUNT} | **Hallucinations**: ${TOTAL_HALLUCINATIONS}\n\n| File | Rubric | Score | Result |\n|---|---|---|---|\n$(echo -e "${RESULTS}")\n\n> Threshold: 0.82 | Model: claude-sonnet-4-20250514"
118
+ curl -s --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN:-${CI_JOB_TOKEN}}" \
119
+ --form "body=${NOTE}" \
120
+ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/notes" > /dev/null 2>&1 || true
121
+
122
+ # Emit event
123
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
124
+ EVAL_EVENT=$(jq -n \
125
+ --arg team_id "${TEAM_ID}" --arg repo "${CI_PROJECT_PATH}" --arg timestamp "${TIMESTAMP}" \
126
+ --argjson score "${AVG_SCORE}" --arg result "${OVERALL}" \
127
+ --argjson total_files "${TOTAL_FILES}" --argjson pass_count "${PASS_COUNT}" \
128
+ --argjson fail_count "${FAIL_COUNT}" --argjson hallucinations "${TOTAL_HALLUCINATIONS}" \
129
+ --arg mr_iid "${CI_MERGE_REQUEST_IID}" \
130
+ '{team_id:$team_id, repo:$repo, timestamp:$timestamp, prism_level:2,
131
+ metric:{name:"eval_score",value:$score,unit:"score"},
132
+ ai_context:{tool:"bedrock-eval",model:"anthropic.claude-sonnet-4-20250514",origin:"ai-generated"},
133
+ eval:{total_files:$total_files, pass_count:$pass_count, fail_count:$fail_count,
134
+ result:$result, mr_iid:($mr_iid | tonumber), hallucinations_caught:$hallucinations}}')
135
+
136
+ aws events put-events --region "${AWS_DEFAULT_REGION}" \
137
+ --entries "[{\"Source\":\"prism.d1.velocity\",\"DetailType\":\"prism.d1.eval\",
138
+ \"EventBusName\":\"prism-d1-metrics\",
139
+ \"Detail\":$(echo "${EVAL_EVENT}" | jq -c '.' | jq -Rs '.')}]"
140
+
141
+ [[ "${OVERALL}" == "FAIL" ]] && exit 1 || exit 0
@@ -0,0 +1,14 @@
1
+ declare const _default: {
2
+ description: string;
3
+ options: {
4
+ flags: string;
5
+ description: string;
6
+ default: string;
7
+ }[];
8
+ action(opts: {
9
+ gitlabUrl?: string;
10
+ outputDir: string;
11
+ }): Promise<void>;
12
+ };
13
+ export default _default;
14
+ //# sourceMappingURL=install-gitlab-workflows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-gitlab-workflows.d.ts","sourceRoot":"","sources":["../../../../src/commands/bootstrapper/install-gitlab-workflows.ts"],"names":[],"mappings":";;;;;;;iBAsBqB;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;;AAN9D,wBA2CE"}
@@ -0,0 +1,53 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { createInterface } from 'node:readline';
4
+ import { getAssetPath } from '../../utils/root.js';
5
+ function prompt(question, defaultValue) {
6
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
7
+ const suffix = defaultValue ? ` [${defaultValue}]` : '';
8
+ return new Promise((resolve) => {
9
+ rl.question(`${question}${suffix}: `, (answer) => {
10
+ rl.close();
11
+ resolve(answer.trim() || defaultValue || '');
12
+ });
13
+ });
14
+ }
15
+ export default {
16
+ description: 'Install GitLab CI workflow templates into the current repo',
17
+ options: [
18
+ { flags: '--gitlab-url <url>', description: 'GitLab instance URL for OIDC audience', default: 'https://gitlab.aws.dev' },
19
+ { flags: '--output-dir <dir>', description: 'Output directory', default: '.prism/gitlab-workflows' },
20
+ ],
21
+ async action(opts) {
22
+ const gitlabUrl = opts.gitlabUrl || await prompt('GitLab instance URL', 'https://gitlab.aws.dev');
23
+ const outputDir = opts.outputDir;
24
+ console.log(`\n📦 Installing GitLab CI workflows`);
25
+ console.log(` Audience: ${gitlabUrl}`);
26
+ console.log(` Output: ${outputDir}/\n`);
27
+ mkdirSync(outputDir, { recursive: true });
28
+ const assetDir = getAssetPath(import.meta.url, 'gitlab-workflows/.gitlab-ci.yml').replace('/.gitlab-ci.yml', '');
29
+ const files = readdirSync(assetDir).filter(f => f.endsWith('.yml'));
30
+ for (const file of files) {
31
+ let content = readFileSync(join(assetDir, file), 'utf-8');
32
+ // Template the audience
33
+ content = content.replace(/aud: https:\/\/gitlab\.aws\.dev/g, `aud: ${gitlabUrl}`);
34
+ writeFileSync(join(outputDir, file), content);
35
+ console.log(` ✓ ${file}`);
36
+ }
37
+ // Update .gitlab-ci.yml include paths
38
+ const ciFile = join(outputDir, '.gitlab-ci.yml');
39
+ if (existsSync(ciFile)) {
40
+ let ci = readFileSync(ciFile, 'utf-8');
41
+ ci = ci.replace(/\.prism\/gitlab-workflows/g, outputDir);
42
+ writeFileSync(ciFile, ci);
43
+ }
44
+ console.log(`\n✅ Installed ${files.length} workflow files to ${outputDir}/`);
45
+ console.log(`\nNext steps:`);
46
+ console.log(` 1. Copy ${outputDir}/.gitlab-ci.yml to your repo root`);
47
+ console.log(` 2. Run: prism-cli bootstrapper setup-gitlab-oidc`);
48
+ console.log(` 3. Add CI/CD variable PRISM_METRICS_ROLE_ARN in GitLab`);
49
+ console.log(` 4. (Optional) Create pipeline schedule for weekly DORA assessment`);
50
+ console.log('');
51
+ },
52
+ };
53
+ //# sourceMappingURL=install-gitlab-workflows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-gitlab-workflows.js","sourceRoot":"","sources":["../../../../src/commands/bootstrapper/install-gitlab-workflows.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prism-d1/cli",
3
- "version": "1.0.44",
3
+ "version": "1.0.46",
4
4
  "description": "PRISM D1 Velocity CLI — AI development lifecycle assessment tool",
5
5
  "author": "andklee",
6
6
  "engines": {
@@ -22,7 +22,7 @@
22
22
  "access": "public"
23
23
  },
24
24
  "scripts": {
25
- "build": "npx tsc && mkdir -p dist/assets/infra && cp -r ../bootstrapper/metric-hooks ../bootstrapper/eval-harness ../bootstrapper/github-workflows dist/assets/ && cp -r ../infra/bin ../infra/lib ../infra/package.json ../infra/tsconfig.json ../infra/cdk.json dist/assets/infra/",
25
+ "build": "npx tsc && mkdir -p dist/assets/infra && cp -r ../bootstrapper/metric-hooks ../bootstrapper/eval-harness ../bootstrapper/github-workflows ../bootstrapper/gitlab-workflows dist/assets/ && cp -r ../infra/bin ../infra/lib ../infra/package.json ../infra/tsconfig.json ../infra/cdk.json dist/assets/infra/",
26
26
  "prepublishOnly": "npm run build",
27
27
  "start": "tsx bin/prism-cli.ts",
28
28
  "dev": "tsx bin/prism-cli.ts"