agent-control-plane 0.4.9 → 0.7.0
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.
- package/README.md +109 -13
- package/npm/bin/agent-control-plane.js +1 -1
- package/package.json +39 -33
- package/tools/bin/debug-session.sh +106 -0
- package/tools/bin/flow-config-lib.sh +13 -3508
- package/tools/bin/flow-execution-lib.sh +243 -0
- package/tools/bin/flow-forge-lib.sh +1770 -0
- package/tools/bin/flow-profile-lib.sh +335 -0
- package/tools/bin/flow-provider-lib.sh +981 -0
- package/tools/bin/flow-runtime-doctor-linux.sh +136 -0
- package/tools/bin/flow-runtime-doctor.sh +5 -1
- package/tools/bin/flow-session-lib.sh +317 -0
- package/tools/bin/install-project-systemd.sh +255 -0
- package/tools/bin/project-runtimectl.sh +45 -0
- package/tools/bin/project-systemd-bootstrap.sh +74 -0
- package/tools/bin/uninstall-project-systemd.sh +87 -0
- package/tools/dashboard/app.js +238 -8
- package/tools/dashboard/issue_queue_state.py +101 -0
- package/tools/dashboard/requirements.txt +3 -0
- package/tools/dashboard/server.py +250 -30
- package/tools/dashboard/styles.css +526 -455
- package/tools/bin/agent-cleanup-worktree +0 -247
- package/tools/bin/agent-github-update-labels +0 -105
- package/tools/bin/agent-init-worktree +0 -216
- package/tools/bin/agent-project-archive-run +0 -52
- package/tools/bin/agent-project-capture-worker +0 -46
- package/tools/bin/agent-project-catch-up-issue-pr-links +0 -118
- package/tools/bin/agent-project-catch-up-merged-prs +0 -195
- package/tools/bin/agent-project-catch-up-scheduled-issue-retries +0 -123
- package/tools/bin/agent-project-cleanup-session +0 -513
- package/tools/bin/agent-project-detached-launch +0 -127
- package/tools/bin/agent-project-heartbeat-loop +0 -1029
- package/tools/bin/agent-project-open-issue-worktree +0 -89
- package/tools/bin/agent-project-open-pr-worktree +0 -80
- package/tools/bin/agent-project-publish-issue-pr +0 -468
- package/tools/bin/agent-project-reconcile-issue-session +0 -1409
- package/tools/bin/agent-project-reconcile-pr-session +0 -1288
- package/tools/bin/agent-project-retry-state +0 -158
- package/tools/bin/agent-project-run-claude-session +0 -805
- package/tools/bin/agent-project-run-codex-resilient +0 -963
- package/tools/bin/agent-project-run-codex-session +0 -435
- package/tools/bin/agent-project-run-kilo-session +0 -369
- package/tools/bin/agent-project-run-ollama-session +0 -658
- package/tools/bin/agent-project-run-openclaw-session +0 -1309
- package/tools/bin/agent-project-run-opencode-session +0 -377
- package/tools/bin/agent-project-run-pi-session +0 -479
- package/tools/bin/agent-project-sync-anchor-repo +0 -139
- package/tools/bin/agent-project-sync-source-repo-main +0 -163
- package/tools/bin/agent-project-worker-status +0 -188
- package/tools/bin/branch-verification-guard.sh +0 -364
- package/tools/bin/capture-worker.sh +0 -18
- package/tools/bin/cleanup-worktree.sh +0 -52
- package/tools/bin/codex-quota +0 -31
- package/tools/bin/create-follow-up-issue.sh +0 -114
- package/tools/bin/dashboard-launchd-bootstrap.sh +0 -50
- package/tools/bin/issue-publish-localization-guard.sh +0 -142
- package/tools/bin/issue-publish-scope-guard.sh +0 -242
- package/tools/bin/issue-requires-local-workspace-install.sh +0 -31
- package/tools/bin/issue-resource-class.sh +0 -12
- package/tools/bin/kick-scheduler.sh +0 -75
- package/tools/bin/label-follow-up-issues.sh +0 -14
- package/tools/bin/new-pr-worktree.sh +0 -50
- package/tools/bin/new-worktree.sh +0 -49
- package/tools/bin/pr-risk.sh +0 -12
- package/tools/bin/prepare-worktree.sh +0 -142
- package/tools/bin/provider-cooldown-state.sh +0 -204
- package/tools/bin/publish-issue-worker.sh +0 -31
- package/tools/bin/reconcile-bootstrap-lib.sh +0 -113
- package/tools/bin/reconcile-issue-worker.sh +0 -34
- package/tools/bin/reconcile-pr-worker.sh +0 -34
- package/tools/bin/record-verification.sh +0 -71
- package/tools/bin/render-flow-config.sh +0 -98
- package/tools/bin/resident-issue-controller-lib.sh +0 -448
- package/tools/bin/retry-state.sh +0 -31
- package/tools/bin/reuse-issue-worktree.sh +0 -121
- package/tools/bin/run-codex-bypass.sh +0 -3
- package/tools/bin/run-codex-safe.sh +0 -3
- package/tools/bin/run-codex-task.sh +0 -280
- package/tools/bin/serve-dashboard.sh +0 -5
- package/tools/bin/start-issue-worker.sh +0 -943
- package/tools/bin/start-pr-fix-worker.sh +0 -528
- package/tools/bin/start-pr-merge-repair-worker.sh +0 -8
- package/tools/bin/start-pr-review-worker.sh +0 -261
- package/tools/bin/start-resident-issue-loop.sh +0 -499
- package/tools/bin/update-github-labels.sh +0 -14
- package/tools/bin/worker-status.sh +0 -19
- package/tools/bin/workflow-catalog.sh +0 -77
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
usage() {
|
|
5
|
-
cat <<'EOF'
|
|
6
|
-
Usage:
|
|
7
|
-
issue-publish-localization-guard.sh --worktree <path> --base-ref <git-ref>
|
|
8
|
-
|
|
9
|
-
Fail fast when an issue branch updates locale resources but still leaves obvious
|
|
10
|
-
hardcoded user-facing strings in the touched UI files.
|
|
11
|
-
EOF
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
worktree=""
|
|
15
|
-
base_ref=""
|
|
16
|
-
|
|
17
|
-
while [[ $# -gt 0 ]]; do
|
|
18
|
-
case "$1" in
|
|
19
|
-
--worktree) worktree="${2:-}"; shift 2 ;;
|
|
20
|
-
--base-ref) base_ref="${2:-}"; shift 2 ;;
|
|
21
|
-
--help|-h) usage; exit 0 ;;
|
|
22
|
-
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
|
|
23
|
-
esac
|
|
24
|
-
done
|
|
25
|
-
|
|
26
|
-
if [[ -z "$worktree" || -z "$base_ref" ]]; then
|
|
27
|
-
usage >&2
|
|
28
|
-
exit 1
|
|
29
|
-
fi
|
|
30
|
-
|
|
31
|
-
if [[ ! -d "$worktree" ]]; then
|
|
32
|
-
echo "missing worktree: $worktree" >&2
|
|
33
|
-
exit 1
|
|
34
|
-
fi
|
|
35
|
-
|
|
36
|
-
changed_files="$(
|
|
37
|
-
git -C "$worktree" diff --name-only --diff-filter=ACMR "${base_ref}...HEAD"
|
|
38
|
-
)"
|
|
39
|
-
|
|
40
|
-
CHANGED_FILES="${changed_files}" WORKTREE="${worktree}" node <<'EOF'
|
|
41
|
-
const fs = require('fs');
|
|
42
|
-
const path = require('path');
|
|
43
|
-
|
|
44
|
-
const changedFiles = String(process.env.CHANGED_FILES || '')
|
|
45
|
-
.split('\n')
|
|
46
|
-
.map((file) => file.trim())
|
|
47
|
-
.filter(Boolean);
|
|
48
|
-
const worktree = String(process.env.WORKTREE || '');
|
|
49
|
-
|
|
50
|
-
const localeFiles = changedFiles.filter((file) =>
|
|
51
|
-
/^packages\/i18n\/src\/resources\/[^/]+\.json$/.test(file),
|
|
52
|
-
);
|
|
53
|
-
if (localeFiles.length === 0) {
|
|
54
|
-
process.stdout.write('LOCALIZATION_GUARD_STATUS=skipped-no-locale-files\n');
|
|
55
|
-
process.exit(0);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const uiFiles = changedFiles.filter((file) =>
|
|
59
|
-
/^(?:apps\/web\/|apps\/mobile\/|packages\/ui\/).+\.[cm]?[jt]sx?$/.test(file),
|
|
60
|
-
);
|
|
61
|
-
if (uiFiles.length === 0) {
|
|
62
|
-
process.stdout.write('LOCALIZATION_GUARD_STATUS=skipped-no-ui-files\n');
|
|
63
|
-
process.exit(0);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const suspiciousPatterns = [
|
|
67
|
-
{
|
|
68
|
-
reason: 'validation_literal',
|
|
69
|
-
test: (line) =>
|
|
70
|
-
/\.(?:min|max|length|email|regex|nonempty)\([^)]*,\s*['"`][^'"`]*[A-Za-z][^'"`]*['"`]/.test(line),
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
reason: 'string_prop',
|
|
74
|
-
test: (line) =>
|
|
75
|
-
/\b(?:title|description|actionLabel|aria-label|placeholder)\s*=\s*['"][^'{"][^'"]*[A-Za-z][^'"]*['"]/.test(
|
|
76
|
-
line,
|
|
77
|
-
),
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
reason: 'object_label_literal',
|
|
81
|
-
test: (line) =>
|
|
82
|
-
/\blabel\s*:\s*['"][A-Za-z][^'"]*['"]/.test(line),
|
|
83
|
-
},
|
|
84
|
-
];
|
|
85
|
-
|
|
86
|
-
const ignoreLine = (line) => {
|
|
87
|
-
const trimmed = line.trim();
|
|
88
|
-
if (!trimmed) return true;
|
|
89
|
-
if (/^\s*\/\//.test(trimmed)) return true;
|
|
90
|
-
if (/\bt\(/.test(trimmed)) return true;
|
|
91
|
-
if (/\buseSafeTranslation\b|\buseTranslation\b|\bi18nKey=/.test(trimmed)) return true;
|
|
92
|
-
if (/^import\s/.test(trimmed)) return true;
|
|
93
|
-
return false;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const findings = [];
|
|
97
|
-
for (const relativeFile of uiFiles) {
|
|
98
|
-
const absoluteFile = path.join(worktree, relativeFile);
|
|
99
|
-
if (!fs.existsSync(absoluteFile)) continue;
|
|
100
|
-
const lines = fs.readFileSync(absoluteFile, 'utf8').split(/\r?\n/);
|
|
101
|
-
lines.forEach((line, index) => {
|
|
102
|
-
if (ignoreLine(line)) return;
|
|
103
|
-
for (const pattern of suspiciousPatterns) {
|
|
104
|
-
if (pattern.test(line)) {
|
|
105
|
-
findings.push({
|
|
106
|
-
file: relativeFile,
|
|
107
|
-
line: index + 1,
|
|
108
|
-
reason: pattern.reason,
|
|
109
|
-
text: line.trim(),
|
|
110
|
-
});
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (findings.length === 0) {
|
|
118
|
-
process.stdout.write('LOCALIZATION_GUARD_STATUS=ok\n');
|
|
119
|
-
process.stdout.write(`LOCALE_RESOURCE_COUNT=${localeFiles.length}\n`);
|
|
120
|
-
process.stdout.write(`UI_FILE_COUNT=${uiFiles.length}\n`);
|
|
121
|
-
process.exit(0);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const lines = [
|
|
125
|
-
'Localization guard blocked branch publication.',
|
|
126
|
-
'',
|
|
127
|
-
'The branch updates locale resources but still leaves obvious hardcoded user-facing strings in touched UI files.',
|
|
128
|
-
'',
|
|
129
|
-
'Why it was blocked:',
|
|
130
|
-
];
|
|
131
|
-
for (const finding of findings.slice(0, 20)) {
|
|
132
|
-
lines.push(`- ${finding.reason}: ${finding.file}:${finding.line} -> ${finding.text}`);
|
|
133
|
-
}
|
|
134
|
-
lines.push(
|
|
135
|
-
'',
|
|
136
|
-
'Required next step:',
|
|
137
|
-
'- move the remaining user-facing literals behind translation keys before publishing this issue branch',
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
process.stderr.write(`${lines.join('\n')}\n`);
|
|
141
|
-
process.exit(44);
|
|
142
|
-
EOF
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
# shellcheck source=/dev/null
|
|
6
|
-
source "${SCRIPT_DIR}/flow-config-lib.sh"
|
|
7
|
-
|
|
8
|
-
usage() {
|
|
9
|
-
cat <<'EOF'
|
|
10
|
-
Usage:
|
|
11
|
-
issue-publish-scope-guard.sh --worktree <path> --base-ref <git-ref> [--issue-id <number>]
|
|
12
|
-
|
|
13
|
-
Fail fast when an issue worker branch is too broad to publish safely as a single
|
|
14
|
-
PR slice.
|
|
15
|
-
EOF
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
worktree=""
|
|
19
|
-
base_ref=""
|
|
20
|
-
issue_id=""
|
|
21
|
-
|
|
22
|
-
while [[ $# -gt 0 ]]; do
|
|
23
|
-
case "$1" in
|
|
24
|
-
--worktree) worktree="${2:-}"; shift 2 ;;
|
|
25
|
-
--base-ref) base_ref="${2:-}"; shift 2 ;;
|
|
26
|
-
--issue-id) issue_id="${2:-}"; shift 2 ;;
|
|
27
|
-
--help|-h) usage; exit 0 ;;
|
|
28
|
-
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
|
|
29
|
-
esac
|
|
30
|
-
done
|
|
31
|
-
|
|
32
|
-
if [[ -z "$worktree" || -z "$base_ref" ]]; then
|
|
33
|
-
usage >&2
|
|
34
|
-
exit 1
|
|
35
|
-
fi
|
|
36
|
-
|
|
37
|
-
if [[ ! -d "$worktree" ]]; then
|
|
38
|
-
echo "missing worktree: $worktree" >&2
|
|
39
|
-
exit 1
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
changed_files="$(
|
|
43
|
-
git -C "$worktree" diff --name-only --diff-filter=ACMR "${base_ref}...HEAD"
|
|
44
|
-
)"
|
|
45
|
-
|
|
46
|
-
issue_title=""
|
|
47
|
-
issue_body=""
|
|
48
|
-
if [[ -n "$issue_id" ]]; then
|
|
49
|
-
CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
|
|
50
|
-
REPO_SLUG="$(flow_resolve_repo_slug "${CONFIG_YAML}")"
|
|
51
|
-
issue_json="$(flow_github_issue_view_json "${REPO_SLUG}" "${issue_id}" 2>/dev/null || true)"
|
|
52
|
-
if [[ -n "$issue_json" ]]; then
|
|
53
|
-
issue_title="$(jq -r '.title // ""' <<<"$issue_json" 2>/dev/null || true)"
|
|
54
|
-
issue_body="$(jq -r '.body // ""' <<<"$issue_json" 2>/dev/null || true)"
|
|
55
|
-
fi
|
|
56
|
-
fi
|
|
57
|
-
|
|
58
|
-
CHANGED_FILES="$changed_files" ISSUE_ID="$issue_id" ISSUE_TITLE="$issue_title" ISSUE_BODY="$issue_body" node <<'EOF'
|
|
59
|
-
const files = String(process.env.CHANGED_FILES || '')
|
|
60
|
-
.split('\n')
|
|
61
|
-
.map((file) => file.trim())
|
|
62
|
-
.filter(Boolean);
|
|
63
|
-
|
|
64
|
-
const issueId = String(process.env.ISSUE_ID || '').trim();
|
|
65
|
-
const issueTitle = String(process.env.ISSUE_TITLE || '').trim();
|
|
66
|
-
const issueBody = String(process.env.ISSUE_BODY || '').trim();
|
|
67
|
-
|
|
68
|
-
const isDoc = (file) =>
|
|
69
|
-
/^openspec\//.test(file) ||
|
|
70
|
-
/^docs\//.test(file) ||
|
|
71
|
-
/^scripts\/README\.md$/.test(file) ||
|
|
72
|
-
/\.md$/i.test(file);
|
|
73
|
-
|
|
74
|
-
const isTest = (file) =>
|
|
75
|
-
/(?:^|\/)__tests__\//.test(file) ||
|
|
76
|
-
/(?:^|\/)e2e\//.test(file) ||
|
|
77
|
-
/\.(?:spec|test)\.[cm]?[jt]sx?$/.test(file);
|
|
78
|
-
|
|
79
|
-
const isLocaleResource = (file) =>
|
|
80
|
-
/^packages\/i18n\/src\/resources\/[^/]+\.json$/.test(file);
|
|
81
|
-
|
|
82
|
-
const isProductNonTest = (file) =>
|
|
83
|
-
!isDoc(file) &&
|
|
84
|
-
!isTest(file) &&
|
|
85
|
-
!isLocaleResource(file) &&
|
|
86
|
-
(/^apps\//.test(file) || /^packages\//.test(file));
|
|
87
|
-
|
|
88
|
-
const isMobileRouteFile = (file) =>
|
|
89
|
-
/^apps\/mobile\/app\/.+\.[cm]?[jt]sx?$/.test(file) &&
|
|
90
|
-
!isTest(file);
|
|
91
|
-
|
|
92
|
-
const mobileSurfaceKey = (file) => {
|
|
93
|
-
const relative = file
|
|
94
|
-
.replace(/^apps\/mobile\/app\//, '')
|
|
95
|
-
.replace(/\.[cm]?[jt]sx?$/, '');
|
|
96
|
-
const segments = relative
|
|
97
|
-
.split('/')
|
|
98
|
-
.filter(Boolean)
|
|
99
|
-
.filter((segment) => !/^\(.+\)$/.test(segment));
|
|
100
|
-
if (segments.length === 0) return relative;
|
|
101
|
-
return segments[0];
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const isAuthCriticalProductFile = (file) =>
|
|
105
|
-
/^apps\/api\/src\/modules\/auth\//.test(file) ||
|
|
106
|
-
file === 'apps/api/src/entities/user.entity.ts' ||
|
|
107
|
-
/^apps\/api\/src\/migrations\/.*(?:Email|Phone|Auth|User).*\.[cm]?[jt]s$/.test(file) ||
|
|
108
|
-
/^apps\/api\/src\/common\/utils\/(?:phone|tenant|email|auth)[^/]*\.[cm]?[jt]s$/.test(file);
|
|
109
|
-
|
|
110
|
-
const isAuthAdjacentProductFile = (file) =>
|
|
111
|
-
isAuthCriticalProductFile(file) ||
|
|
112
|
-
/^apps\/web\/src\/app\/\(auth\)\//.test(file) ||
|
|
113
|
-
/^apps\/api\/src\/modules\/organization\//.test(file);
|
|
114
|
-
|
|
115
|
-
const productNonTestFiles = files.filter(isProductNonTest);
|
|
116
|
-
const mobileProductFiles = productNonTestFiles.filter((file) => /^apps\/mobile\//.test(file));
|
|
117
|
-
const localeResourceFiles = files.filter(isLocaleResource);
|
|
118
|
-
const mobileRouteFiles = productNonTestFiles.filter(isMobileRouteFile);
|
|
119
|
-
const mobileSurfaceKeys = [...new Set(mobileRouteFiles.map(mobileSurfaceKey))];
|
|
120
|
-
const authCriticalTouched = productNonTestFiles.some(isAuthCriticalProductFile);
|
|
121
|
-
const authMixedScopeFiles = authCriticalTouched
|
|
122
|
-
? productNonTestFiles.filter((file) => !isAuthAdjacentProductFile(file))
|
|
123
|
-
: [];
|
|
124
|
-
const openspecChangeFiles = files.filter((file) => /^openspec\/changes\//.test(file));
|
|
125
|
-
const workflowRuleFiles = files.filter((file) =>
|
|
126
|
-
/^(?:AGENTS\.md|openspec\/AGENT_RULES\.md)$/.test(file),
|
|
127
|
-
);
|
|
128
|
-
const docsDeclaredScope =
|
|
129
|
-
/^(?:docs?|documentation)\b/i.test(issueTitle) ||
|
|
130
|
-
/^docs?\(/i.test(issueTitle) ||
|
|
131
|
-
/\b(?:docs?|documentation|openspec)[ -]?only\b/i.test(issueTitle) ||
|
|
132
|
-
/(?:^|\n)\s*(?:scope|mode|type)\s*:\s*(?:docs?|documentation|openspec)(?:[- ]only)?\b/i.test(issueBody) ||
|
|
133
|
-
/(?:^|\n)\s*(?:docs?|documentation|openspec)[ -]?only\b/i.test(issueBody);
|
|
134
|
-
|
|
135
|
-
const reasons = [];
|
|
136
|
-
if (productNonTestFiles.length > 14) {
|
|
137
|
-
reasons.push(`product_non_test_count=${productNonTestFiles.length} exceeds max=14`);
|
|
138
|
-
}
|
|
139
|
-
if (mobileProductFiles.length >= 8) {
|
|
140
|
-
reasons.push(`mobile_product_count=${mobileProductFiles.length} exceeds max=7`);
|
|
141
|
-
}
|
|
142
|
-
if (localeResourceFiles.length > 8 && productNonTestFiles.length >= 6) {
|
|
143
|
-
reasons.push(
|
|
144
|
-
`locale_resource_count=${localeResourceFiles.length} with product_non_test_count=${productNonTestFiles.length} exceeds mixed-scope limit`,
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
if (mobileRouteFiles.length > 3) {
|
|
148
|
-
reasons.push(`mobile_route_file_count=${mobileRouteFiles.length} exceeds max=3`);
|
|
149
|
-
}
|
|
150
|
-
if (mobileSurfaceKeys.length > 2) {
|
|
151
|
-
reasons.push(`mobile_surface_count=${mobileSurfaceKeys.length} exceeds max=2`);
|
|
152
|
-
}
|
|
153
|
-
if (authMixedScopeFiles.length > 0) {
|
|
154
|
-
reasons.push(
|
|
155
|
-
`auth_mixed_scope_count=${authMixedScopeFiles.length} requires a dedicated auth slice before publish`,
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
if (docsDeclaredScope && productNonTestFiles.length > 0) {
|
|
159
|
-
reasons.push(`docs_declared_scope_contains_product_changes=${productNonTestFiles.length}`);
|
|
160
|
-
}
|
|
161
|
-
if (openspecChangeFiles.length > 0 && productNonTestFiles.length > 0) {
|
|
162
|
-
reasons.push(
|
|
163
|
-
`product_and_openspec_change_mix=product:${productNonTestFiles.length},openspec_change:${openspecChangeFiles.length}`,
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
if (workflowRuleFiles.length > 0 && productNonTestFiles.length > 0) {
|
|
167
|
-
reasons.push(
|
|
168
|
-
`workflow_rule_files_mixed_with_product_changes=${workflowRuleFiles.length}`,
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (reasons.length === 0) {
|
|
173
|
-
process.stdout.write('SCOPE_GUARD_STATUS=ok\n');
|
|
174
|
-
process.stdout.write(`PRODUCT_NON_TEST_COUNT=${productNonTestFiles.length}\n`);
|
|
175
|
-
process.stdout.write(`MOBILE_PRODUCT_COUNT=${mobileProductFiles.length}\n`);
|
|
176
|
-
process.stdout.write(`LOCALE_RESOURCE_COUNT=${localeResourceFiles.length}\n`);
|
|
177
|
-
process.stdout.write(`MOBILE_ROUTE_FILE_COUNT=${mobileRouteFiles.length}\n`);
|
|
178
|
-
process.stdout.write(`MOBILE_SURFACE_COUNT=${mobileSurfaceKeys.length}\n`);
|
|
179
|
-
process.stdout.write(`AUTH_MIXED_SCOPE_COUNT=${authMixedScopeFiles.length}\n`);
|
|
180
|
-
process.exit(0);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const lines = [
|
|
184
|
-
`Scope guard blocked issue${issueId ? ` #${issueId}` : ''} from publishing as a single PR.`,
|
|
185
|
-
'',
|
|
186
|
-
'The branch is too broad for the current flow and should be split into a smaller slice before publish.',
|
|
187
|
-
'',
|
|
188
|
-
'Why it was blocked:',
|
|
189
|
-
...reasons.map((reason) => `- ${reason}`),
|
|
190
|
-
];
|
|
191
|
-
|
|
192
|
-
if (productNonTestFiles.length > 0) {
|
|
193
|
-
lines.push('', 'Representative product files:');
|
|
194
|
-
for (const file of productNonTestFiles.slice(0, 12)) {
|
|
195
|
-
lines.push(`- ${file}`);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (localeResourceFiles.length > 0) {
|
|
200
|
-
lines.push('', 'Locale resource files touched:');
|
|
201
|
-
for (const file of localeResourceFiles.slice(0, 12)) {
|
|
202
|
-
lines.push(`- ${file}`);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (openspecChangeFiles.length > 0) {
|
|
207
|
-
lines.push('', 'OpenSpec change files touched:');
|
|
208
|
-
for (const file of openspecChangeFiles.slice(0, 12)) {
|
|
209
|
-
lines.push(`- ${file}`);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (workflowRuleFiles.length > 0) {
|
|
214
|
-
lines.push('', 'Workflow or repo-rule files touched:');
|
|
215
|
-
for (const file of workflowRuleFiles.slice(0, 12)) {
|
|
216
|
-
lines.push(`- ${file}`);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (mobileRouteFiles.length > 0) {
|
|
221
|
-
lines.push('', 'Mobile route files touched:');
|
|
222
|
-
for (const file of mobileRouteFiles.slice(0, 12)) {
|
|
223
|
-
lines.push(`- ${file}`);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (authMixedScopeFiles.length > 0) {
|
|
228
|
-
lines.push('', 'Files that should move to a separate follow-up PR from the auth slice:');
|
|
229
|
-
for (const file of authMixedScopeFiles.slice(0, 12)) {
|
|
230
|
-
lines.push(`- ${file}`);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
lines.push(
|
|
235
|
-
'',
|
|
236
|
-
'Required next step:',
|
|
237
|
-
'- re-run the issue as a narrower slice that stays within one primary product surface, at most two mobile route surfaces, one dedicated auth/security contract change, or one docs/OpenSpec-only branch with no product code',
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
process.stderr.write(`${lines.join('\n')}\n`);
|
|
241
|
-
process.exit(42);
|
|
242
|
-
EOF
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
ISSUE_BODY="${ISSUE_BODY:-${1:-}}"
|
|
5
|
-
|
|
6
|
-
ISSUE_BODY="$ISSUE_BODY" node <<'EOF'
|
|
7
|
-
const body = process.env.ISSUE_BODY || '';
|
|
8
|
-
const scheduled = /^\s*(?:Agent schedule|Schedule|Cadence)\s*:\s*(?:every\s+)?(\d+)\s*([mhd])\s*$/im.test(body);
|
|
9
|
-
|
|
10
|
-
if (!scheduled) {
|
|
11
|
-
process.stdout.write('no\n');
|
|
12
|
-
process.exit(0);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (/^\s*(?:Local workspace install|Worktree local install)\s*:\s*yes\s*$/im.test(body)) {
|
|
16
|
-
process.stdout.write('yes\n');
|
|
17
|
-
process.exit(0);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const installLikePatterns = [
|
|
21
|
-
/(^|\n)\s*\d+\.\s*`(?:pnpm|npm|yarn)\s+(?:install|i|ci|add|remove|rm|up|update|rebuild|dlx)\b/im,
|
|
22
|
-
/(^|\n)\s*\d+\.\s*`pnpm\s+exec\s+pod\s+install\b/im,
|
|
23
|
-
/(^|\n)\s*\d+\.\s*`(?:npx\s+pod-install|expo\s+prebuild|pod\s+install|bundle\s+install)\b/im,
|
|
24
|
-
/`(?:pnpm|npm|yarn)\s+(?:install|i|ci|add|remove|rm|up|update|rebuild|dlx)\b/im,
|
|
25
|
-
/`pnpm\s+exec\s+pod\s+install\b/im,
|
|
26
|
-
/`(?:npx\s+pod-install|expo\s+prebuild|pod\s+install|bundle\s+install)\b/im,
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
const needsLocalInstall = installLikePatterns.some((pattern) => pattern.test(body));
|
|
30
|
-
process.stdout.write(needsLocalInstall ? 'yes\n' : 'no\n');
|
|
31
|
-
EOF
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
# shellcheck source=/dev/null
|
|
6
|
-
source "${SCRIPT_DIR}/flow-shell-lib.sh"
|
|
7
|
-
|
|
8
|
-
ISSUE_ID="${1:?usage: issue-resource-class.sh ISSUE_ID}"
|
|
9
|
-
FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
|
|
10
|
-
ADAPTER_BIN_DIR="${FLOW_SKILL_DIR}/bin"
|
|
11
|
-
|
|
12
|
-
"${ADAPTER_BIN_DIR}/issue-resource-class.sh" "$ISSUE_ID"
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
# shellcheck source=/dev/null
|
|
6
|
-
source "${SCRIPT_DIR}/flow-config-lib.sh"
|
|
7
|
-
|
|
8
|
-
DELAY_SECONDS="${1:-5}"
|
|
9
|
-
WORKSPACE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
10
|
-
FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
|
|
11
|
-
if ! flow_require_explicit_profile_selection "${FLOW_SKILL_DIR}" "kick-scheduler.sh"; then
|
|
12
|
-
exit 64
|
|
13
|
-
fi
|
|
14
|
-
CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
|
|
15
|
-
REPO_SLUG="$(flow_resolve_repo_slug "${CONFIG_YAML}")"
|
|
16
|
-
STATE_ROOT="$(flow_resolve_state_root "${CONFIG_YAML}")"
|
|
17
|
-
BOOTSTRAP_SCRIPT="${ACP_BOOTSTRAP_SCRIPT:-${F_LOSNING_BOOTSTRAP_SCRIPT:-${AGENT_SCHEDULER_BOOTSTRAP_SCRIPT:-$HOME/.agent-runtime/control-plane/workspace/bin/agent-scheduler-launchd.sh}}}"
|
|
18
|
-
FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
|
|
19
|
-
FLOW_SAFE_AUTO_SCRIPT="${ACP_FLOW_HEARTBEAT_SCRIPT:-${F_LOSNING_FLOW_HEARTBEAT_SCRIPT:-${FLOW_SKILL_DIR}/tools/bin/heartbeat-safe-auto.sh}}"
|
|
20
|
-
STATE_DIR="${ACP_SCHEDULER_KICK_STATE_DIR:-${STATE_ROOT}/kick-scheduler}"
|
|
21
|
-
PID_FILE="${STATE_DIR}/pid"
|
|
22
|
-
|
|
23
|
-
mkdir -p "${STATE_DIR}"
|
|
24
|
-
|
|
25
|
-
active_heartbeat_pid() {
|
|
26
|
-
ps -ax -o pid=,command= \
|
|
27
|
-
| while read -r pid command; do
|
|
28
|
-
[[ -n "${pid:-}" ]] || continue
|
|
29
|
-
case "$command" in
|
|
30
|
-
*"${BOOTSTRAP_SCRIPT}"*|*"${WORKSPACE_DIR}/bin/heartbeat-safe-auto.sh"*|*"${FLOW_SAFE_AUTO_SCRIPT}"*|*"agent-project-heartbeat-loop --repo-slug ${REPO_SLUG}"*)
|
|
31
|
-
printf '%s\n' "$pid"
|
|
32
|
-
return 0
|
|
33
|
-
;;
|
|
34
|
-
esac
|
|
35
|
-
done
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if active_pid="$(active_heartbeat_pid)"; [[ -n "$active_pid" ]]; then
|
|
39
|
-
printf 'KICK_STATUS=active-heartbeat\n'
|
|
40
|
-
printf 'PID=%s\n' "$active_pid"
|
|
41
|
-
exit 0
|
|
42
|
-
fi
|
|
43
|
-
|
|
44
|
-
if [[ -f "${PID_FILE}" ]]; then
|
|
45
|
-
existing_pid="$(cat "${PID_FILE}" 2>/dev/null || true)"
|
|
46
|
-
if [[ -n "${existing_pid}" ]] && kill -0 "${existing_pid}" 2>/dev/null; then
|
|
47
|
-
printf 'KICK_STATUS=already-pending\n'
|
|
48
|
-
printf 'PID=%s\n' "${existing_pid}"
|
|
49
|
-
exit 0
|
|
50
|
-
fi
|
|
51
|
-
fi
|
|
52
|
-
|
|
53
|
-
export DELAY_SECONDS BOOTSTRAP_SCRIPT FLOW_SAFE_AUTO_SCRIPT PID_FILE REPO_SLUG
|
|
54
|
-
nohup bash -lc '
|
|
55
|
-
trap '\''rm -f "$PID_FILE"'\'' EXIT
|
|
56
|
-
sleep "$DELAY_SECONDS"
|
|
57
|
-
active_pid="$(ps -ax -o pid=,command= | while read -r pid command; do
|
|
58
|
-
[[ -n "${pid:-}" ]] || continue
|
|
59
|
-
case "$command" in
|
|
60
|
-
*"$BOOTSTRAP_SCRIPT"*|*"$FLOW_SAFE_AUTO_SCRIPT"*|*"agent-project-heartbeat-loop --repo-slug $REPO_SLUG"*)
|
|
61
|
-
printf "%s\n" "$pid"
|
|
62
|
-
break
|
|
63
|
-
;;
|
|
64
|
-
esac
|
|
65
|
-
done)"
|
|
66
|
-
if [[ -n "$active_pid" ]]; then
|
|
67
|
-
exit 0
|
|
68
|
-
fi
|
|
69
|
-
"$BOOTSTRAP_SCRIPT" >/dev/null 2>&1 || true
|
|
70
|
-
' >/dev/null 2>&1 &
|
|
71
|
-
|
|
72
|
-
bg_pid="$!"
|
|
73
|
-
printf '%s\n' "${bg_pid}" >"${PID_FILE}"
|
|
74
|
-
printf 'KICK_STATUS=scheduled\n'
|
|
75
|
-
printf 'PID=%s\n' "${bg_pid}"
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
# shellcheck source=/dev/null
|
|
6
|
-
source "${SCRIPT_DIR}/flow-config-lib.sh"
|
|
7
|
-
|
|
8
|
-
SESSION="${1:?usage: label-follow-up-issues.sh SESSION}"
|
|
9
|
-
CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
|
|
10
|
-
RUNS_ROOT="$(flow_resolve_runs_root "${CONFIG_YAML}")"
|
|
11
|
-
FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
|
|
12
|
-
ADAPTER_BIN_DIR="${FLOW_SKILL_DIR}/bin"
|
|
13
|
-
|
|
14
|
-
ACP_RUNS_ROOT="$RUNS_ROOT" F_LOSNING_RUNS_ROOT="$RUNS_ROOT" "${ADAPTER_BIN_DIR}/label-follow-up-issues.sh" "$SESSION"
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
# shellcheck source=/dev/null
|
|
6
|
-
source "${SCRIPT_DIR}/flow-config-lib.sh"
|
|
7
|
-
|
|
8
|
-
FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
|
|
9
|
-
if ! flow_require_explicit_profile_selection "${FLOW_SKILL_DIR}" "new-pr-worktree.sh"; then
|
|
10
|
-
exit 64
|
|
11
|
-
fi
|
|
12
|
-
FLOW_TOOLS_DIR="${FLOW_SKILL_DIR}/tools/bin"
|
|
13
|
-
flow_export_project_env_aliases
|
|
14
|
-
CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
|
|
15
|
-
AGENT_REPO_ROOT="$(flow_resolve_agent_repo_root "${CONFIG_YAML}")"
|
|
16
|
-
AUTOMATION_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
|
|
17
|
-
WORKTREE_ROOT="$(flow_resolve_worktree_root "${CONFIG_YAML}")"
|
|
18
|
-
RETAINED_REPO_ROOT="$(flow_resolve_retained_repo_root "${CONFIG_YAML}")"
|
|
19
|
-
VSCODE_WORKSPACE_FILE="$(flow_resolve_vscode_workspace_file "${CONFIG_YAML}")"
|
|
20
|
-
PR_WORKTREE_BRANCH_PREFIX="$(flow_resolve_pr_worktree_branch_prefix "${CONFIG_YAML}")"
|
|
21
|
-
|
|
22
|
-
PR_NUMBER="${1:?usage: new-pr-worktree.sh PR_NUMBER HEAD_REF}"
|
|
23
|
-
HEAD_REF="${2:?usage: new-pr-worktree.sh PR_NUMBER HEAD_REF}"
|
|
24
|
-
|
|
25
|
-
ACP_AGENT_REPO_ROOT="$AGENT_REPO_ROOT" \
|
|
26
|
-
F_LOSNING_AGENT_REPO_ROOT="$AGENT_REPO_ROOT" \
|
|
27
|
-
"${SCRIPT_DIR}/sync-agent-repo.sh" >/dev/null
|
|
28
|
-
|
|
29
|
-
export ACP_REPO_ROOT="$AUTOMATION_REPO_ROOT"
|
|
30
|
-
export F_LOSNING_REPO_ROOT="$AUTOMATION_REPO_ROOT"
|
|
31
|
-
|
|
32
|
-
WORKTREE_OUT="$(
|
|
33
|
-
bash "${FLOW_TOOLS_DIR}/agent-project-open-pr-worktree" \
|
|
34
|
-
--repo-root "$AGENT_REPO_ROOT" \
|
|
35
|
-
--worktree-root "$WORKTREE_ROOT" \
|
|
36
|
-
--pr-number "$PR_NUMBER" \
|
|
37
|
-
--head-ref "$HEAD_REF" \
|
|
38
|
-
--local-branch-prefix "$PR_WORKTREE_BRANCH_PREFIX" \
|
|
39
|
-
--prepare-script "${SCRIPT_DIR}/prepare-worktree.sh"
|
|
40
|
-
)"
|
|
41
|
-
|
|
42
|
-
ACP_AGENT_REPO_ROOT="$AGENT_REPO_ROOT" \
|
|
43
|
-
ACP_RETAINED_REPO_ROOT="$RETAINED_REPO_ROOT" \
|
|
44
|
-
ACP_VSCODE_WORKSPACE_FILE="$VSCODE_WORKSPACE_FILE" \
|
|
45
|
-
F_LOSNING_AGENT_REPO_ROOT="$AGENT_REPO_ROOT" \
|
|
46
|
-
F_LOSNING_RETAINED_REPO_ROOT="$RETAINED_REPO_ROOT" \
|
|
47
|
-
F_LOSNING_VSCODE_WORKSPACE_FILE="$VSCODE_WORKSPACE_FILE" \
|
|
48
|
-
"${SCRIPT_DIR}/sync-vscode-workspace.sh" >/dev/null 2>&1 || true
|
|
49
|
-
|
|
50
|
-
printf '%s\n' "$WORKTREE_OUT"
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
# shellcheck source=/dev/null
|
|
6
|
-
source "${SCRIPT_DIR}/flow-config-lib.sh"
|
|
7
|
-
|
|
8
|
-
FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
|
|
9
|
-
if ! flow_require_explicit_profile_selection "${FLOW_SKILL_DIR}" "new-worktree.sh"; then
|
|
10
|
-
exit 64
|
|
11
|
-
fi
|
|
12
|
-
CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
|
|
13
|
-
AGENT_REPO_ROOT="$(flow_resolve_agent_repo_root "${CONFIG_YAML}")"
|
|
14
|
-
AUTOMATION_REPO_ROOT="$(flow_resolve_repo_root "${CONFIG_YAML}")"
|
|
15
|
-
WORKTREE_ROOT="$(flow_resolve_worktree_root "${CONFIG_YAML}")"
|
|
16
|
-
RETAINED_REPO_ROOT="$(flow_resolve_retained_repo_root "${CONFIG_YAML}")"
|
|
17
|
-
VSCODE_WORKSPACE_FILE="$(flow_resolve_vscode_workspace_file "${CONFIG_YAML}")"
|
|
18
|
-
FLOW_TOOLS_DIR="${FLOW_SKILL_DIR}/tools/bin"
|
|
19
|
-
ISSUE_BRANCH_PREFIX="$(flow_resolve_issue_branch_prefix "${CONFIG_YAML}")"
|
|
20
|
-
|
|
21
|
-
ISSUE_ID="${1:?usage: new-worktree.sh ISSUE_ID [SLUG]}"
|
|
22
|
-
SLUG_INPUT="${2:-task}"
|
|
23
|
-
|
|
24
|
-
ACP_AGENT_REPO_ROOT="$AGENT_REPO_ROOT" \
|
|
25
|
-
F_LOSNING_AGENT_REPO_ROOT="$AGENT_REPO_ROOT" \
|
|
26
|
-
"${SCRIPT_DIR}/sync-agent-repo.sh" >/dev/null
|
|
27
|
-
|
|
28
|
-
export ACP_REPO_ROOT="$AUTOMATION_REPO_ROOT"
|
|
29
|
-
export F_LOSNING_REPO_ROOT="$AUTOMATION_REPO_ROOT"
|
|
30
|
-
|
|
31
|
-
WORKTREE_OUT="$(
|
|
32
|
-
bash "${FLOW_TOOLS_DIR}/agent-project-open-issue-worktree" \
|
|
33
|
-
--repo-root "$AGENT_REPO_ROOT" \
|
|
34
|
-
--worktree-root "$WORKTREE_ROOT" \
|
|
35
|
-
--issue-id "$ISSUE_ID" \
|
|
36
|
-
--slug "$SLUG_INPUT" \
|
|
37
|
-
--branch-prefix "$ISSUE_BRANCH_PREFIX" \
|
|
38
|
-
--prepare-script "${SCRIPT_DIR}/prepare-worktree.sh"
|
|
39
|
-
)"
|
|
40
|
-
|
|
41
|
-
ACP_AGENT_REPO_ROOT="$AGENT_REPO_ROOT" \
|
|
42
|
-
ACP_RETAINED_REPO_ROOT="$RETAINED_REPO_ROOT" \
|
|
43
|
-
ACP_VSCODE_WORKSPACE_FILE="$VSCODE_WORKSPACE_FILE" \
|
|
44
|
-
F_LOSNING_AGENT_REPO_ROOT="$AGENT_REPO_ROOT" \
|
|
45
|
-
F_LOSNING_RETAINED_REPO_ROOT="$RETAINED_REPO_ROOT" \
|
|
46
|
-
F_LOSNING_VSCODE_WORKSPACE_FILE="$VSCODE_WORKSPACE_FILE" \
|
|
47
|
-
"${SCRIPT_DIR}/sync-vscode-workspace.sh" >/dev/null 2>&1 || true
|
|
48
|
-
|
|
49
|
-
printf '%s\n' "$WORKTREE_OUT"
|
package/tools/bin/pr-risk.sh
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
-
# shellcheck source=/dev/null
|
|
6
|
-
source "${SCRIPT_DIR}/flow-shell-lib.sh"
|
|
7
|
-
|
|
8
|
-
PR_NUMBER="${1:?usage: pr-risk.sh PR_NUMBER}"
|
|
9
|
-
FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
|
|
10
|
-
ADAPTER_BIN_DIR="${FLOW_SKILL_DIR}/bin"
|
|
11
|
-
|
|
12
|
-
"${ADAPTER_BIN_DIR}/pr-risk.sh" "$PR_NUMBER"
|