@synkro-sh/cli 1.1.4 → 1.1.6
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/dist/bootstrap.js +30 -23
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -83,11 +83,18 @@ function writeSettingsAtomic(path, settings) {
|
|
|
83
83
|
writeFileSync(tmpPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
84
84
|
renameSync(tmpPath, path);
|
|
85
85
|
}
|
|
86
|
+
function isSynkroEntry(entry) {
|
|
87
|
+
if (entry?.[SYNKRO_MARKER]) return true;
|
|
88
|
+
const hooks = Array.isArray(entry?.hooks) ? entry.hooks : [];
|
|
89
|
+
return hooks.some(
|
|
90
|
+
(h) => typeof h?.command === "string" && h.command.includes("/.synkro/hooks/")
|
|
91
|
+
);
|
|
92
|
+
}
|
|
86
93
|
function removeSynkroEntries(events, eventName) {
|
|
87
94
|
if (!events) return;
|
|
88
95
|
const arr = events[eventName];
|
|
89
96
|
if (!Array.isArray(arr)) return;
|
|
90
|
-
events[eventName] = arr.filter((entry) => !entry
|
|
97
|
+
events[eventName] = arr.filter((entry) => !isSynkroEntry(entry));
|
|
91
98
|
}
|
|
92
99
|
function installCCHooks(settingsPath, config) {
|
|
93
100
|
const settings = readSettings(settingsPath);
|
|
@@ -118,7 +125,7 @@ function installCCHooks(settingsPath, config) {
|
|
|
118
125
|
{
|
|
119
126
|
type: "command",
|
|
120
127
|
command: config.editPrecheckScriptPath,
|
|
121
|
-
timeout:
|
|
128
|
+
timeout: 15
|
|
122
129
|
}
|
|
123
130
|
],
|
|
124
131
|
[SYNKRO_MARKER]: true
|
|
@@ -801,17 +808,24 @@ if [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v claude >/dev/null 2>&1; t
|
|
|
801
808
|
# ~14s for cold \`claude --print\`. Falls back to direct \`claude --print\`
|
|
802
809
|
# if the daemon binary or primer is missing.
|
|
803
810
|
|
|
804
|
-
#
|
|
805
|
-
#
|
|
806
|
-
#
|
|
807
|
-
#
|
|
808
|
-
#
|
|
809
|
-
#
|
|
810
|
-
# rules
|
|
811
|
+
# Fetch the caller's visible org rules and inject into the grader prompt.
|
|
812
|
+
# On-demand MCP retrieval inside the grader was the cleaner architecture
|
|
813
|
+
# but added 20+ seconds of latency per grade because the model has to
|
|
814
|
+
# call get_guardrails, wait for cosine ranking, then reason. For free-tier
|
|
815
|
+
# local CC inference that's unacceptable. Pre-stuffing the rules costs
|
|
816
|
+
# tokens but keeps grade latency in the 1-3s range. Bounded at 1.5s; on
|
|
817
|
+
# failure proceed with empty rules (degrades to baseline-only judging).
|
|
818
|
+
ORG_RULES=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" \\
|
|
819
|
+
-H "Authorization: Bearer $JWT" \\
|
|
820
|
+
--max-time 1.5 2>/dev/null \\
|
|
821
|
+
| jq -c '[.rules[]? | {rule_id, text, severity, category, mode}]' 2>/dev/null || echo "[]")
|
|
822
|
+
if [ -z "$ORG_RULES" ] || [ "$ORG_RULES" = "null" ]; then ORG_RULES="[]"; fi
|
|
823
|
+
|
|
811
824
|
GRADER_PROMPT_FILE=$(mktemp -t synkro-grade.XXXXXX)
|
|
812
825
|
trap "rm -f \\"$GRADER_PROMPT_FILE\\"" EXIT
|
|
813
826
|
printf 'File: %s\\n' "$FILE_PATH" > "$GRADER_PROMPT_FILE"
|
|
814
|
-
printf 'User intent: %s\\n
|
|
827
|
+
printf 'User intent: %s\\n' "\${USER_INTENT:-none stated}" >> "$GRADER_PROMPT_FILE"
|
|
828
|
+
printf 'Org rules: %s\\n\\n' "$ORG_RULES" >> "$GRADER_PROMPT_FILE"
|
|
815
829
|
printf 'Diff:\\n' >> "$GRADER_PROMPT_FILE"
|
|
816
830
|
printf '%s\\n' "$PROPOSED" >> "$GRADER_PROMPT_FILE"
|
|
817
831
|
|
|
@@ -1632,22 +1646,15 @@ if __name__ == "__main__":
|
|
|
1632
1646
|
EACH GRADING REQUEST INCLUDES:
|
|
1633
1647
|
- File: the path being written
|
|
1634
1648
|
- User intent: what the user told the agent to do
|
|
1649
|
+
- Org rules: a JSON array of this organization's active policies, each with rule_id, text, severity, category. These are the org's primary source of truth \u2014 apply them.
|
|
1635
1650
|
- Diff: the proposed file content
|
|
1636
1651
|
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
- query: a one-sentence summary of WHAT THE DIFF DOES \u2014 describe the file's behavior in plain language. Focus on the action, the data flowing in, and the data flowing out (e.g. "route handler that takes user input and runs a database query", "component that reads a token from disk and includes it in an outbound HTTP request", "function that hashes a password before storing it").
|
|
1641
|
-
- top_k: 8
|
|
1642
|
-
|
|
1643
|
-
The server returns the most semantically-relevant rules (mix of cosine + keyword), each with rule_id, text, severity, category. THESE ARE YOUR PRIMARY SOURCE OF TRUTH for this org. If get_guardrails returns nothing or errors, proceed with baseline-only judging.
|
|
1644
|
-
|
|
1645
|
-
STEP 2: Judge the diff. Priority order:
|
|
1646
|
-
1. ORG RULES first. If the diff matches the prose of any returned rule, flag it \u2014 emit the rule's rule_id verbatim and the rule's severity. Don't second-guess the org's rules: a rule that bans an action class covers ALL forms of that action \u2014 splitting arguments across function calls, wrapping in helpers, or renaming a variable does NOT bypass it. The semantic intent of the rule and the diff is what matters, not the literal substring.
|
|
1647
|
-
2. BASELINE security issues (hardcoded real-looking secrets, eval/exec on user input, SQL string concat with untrusted input, MD5/SHA1 for security-sensitive purposes, unsafe deserialization, command injection, path traversal, missing auth on routes that mutate user/billing data, weak random for tokens, broken JWT verification, CORS misconfig, env-dump logging). Flag these even if no org rule covers them \u2014 they're universally bad. Use a sensible snake_case rule_id like \`no-hardcoded-secrets\`, \`eval-on-user-input\`, \`sql-string-concat\`.
|
|
1652
|
+
JUDGING PRIORITY:
|
|
1653
|
+
1. ORG RULES first. If the diff matches the prose of any rule in the Org rules array, flag it \u2014 emit the rule's rule_id verbatim and the rule's severity. A rule that bans an action class covers ALL forms of that action: splitting arguments across function calls, wrapping in helpers, renaming a variable, using a different invocation pattern \u2014 none of those bypass the rule. Match on semantic intent of the rule's prose, not literal substring.
|
|
1654
|
+
2. BASELINE security issues \u2014 hardcoded real-looking secrets, eval/exec on user input, SQL string concat with untrusted input, MD5/SHA1 for security-sensitive purposes, unsafe deserialization, command injection, path traversal, missing auth on routes that mutate user/billing data, weak random for tokens, broken JWT verification, CORS misconfig, env-dump logging. Flag these even if no org rule covers them \u2014 they're universally bad. Use a sensible snake_case rule_id like \`no-hardcoded-secrets\`, \`eval-on-user-input\`, \`sql-string-concat\`.
|
|
1648
1655
|
3. Stylistic issues, placeholder fixtures, test files (path under /tests/, /__tests__/, *.test.*), and config-only files are NOT security issues \u2014 return ok=true.
|
|
1649
1656
|
|
|
1650
|
-
INDEPENDENCE: Each grade request is INDEPENDENT. Even if you can see prior turns in your context (the daemon reuses one process across grades), treat them as irrelevant. Judge ONLY the current request's File / User intent /
|
|
1657
|
+
INDEPENDENCE: Each grade request is INDEPENDENT. Even if you can see prior turns in your context (the daemon reuses one process across grades), treat them as irrelevant. Judge ONLY the current request's File / User intent / Org rules / Diff. Prior "allows" do NOT authorize the current request \u2014 re-evaluate fresh against the rules in THIS prompt.
|
|
1651
1658
|
|
|
1652
1659
|
OUTPUT RULES \u2014 strictest possible, no exceptions:
|
|
1653
1660
|
|
|
@@ -2083,7 +2090,7 @@ function writeConfigEnv(opts) {
|
|
|
2083
2090
|
`SYNKRO_GATEWAY_URL=${shellQuoteSingle(safeGateway)}`,
|
|
2084
2091
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
2085
2092
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
2086
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.1.
|
|
2093
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.1.6")}`
|
|
2087
2094
|
];
|
|
2088
2095
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
2089
2096
|
if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
|