@makerx/yoke 0.11.0 → 0.12.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 +1 -1
- package/dist/cli.js +51 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ yoke sync --user # ~/.claude/skills
|
|
|
23
23
|
|
|
24
24
|
- `/pr` raises a PR with a short What/Why/(How) description.
|
|
25
25
|
- `/review [number]` reviews a PR with Claude and Codex, combines their findings and offers to post them. [Configure](src/features/review/README.md#settings).
|
|
26
|
-
- `/review-ci`
|
|
26
|
+
- `/review-ci` makes CI review each PR, adding a workflow or switching the repo's existing LLM review workflow over, and helps set its variable and secret. [Details](src/features/review/README.md#ci).
|
|
27
27
|
|
|
28
28
|
## CLI
|
|
29
29
|
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { Command } from "commander";
|
|
|
7
7
|
// package.json
|
|
8
8
|
var package_default = {
|
|
9
9
|
name: "@makerx/yoke",
|
|
10
|
-
version: "0.
|
|
10
|
+
version: "0.12.0",
|
|
11
11
|
description: "Lean, user-invoked Claude Code skills for MakerX AI-assisted delivery, plus the CLI they call.",
|
|
12
12
|
license: "MIT",
|
|
13
13
|
author: "MakerX",
|
|
@@ -756,11 +756,15 @@ function repoRoot(cwd = process.cwd()) {
|
|
|
756
756
|
throw new ReviewError("Not in a git repository; run `yoke review-ci` from the repo to review.");
|
|
757
757
|
}
|
|
758
758
|
}
|
|
759
|
-
|
|
759
|
+
var editInPlaceMessage = [
|
|
760
|
+
`${callerWorkflowPath} already exists and differs from yoke's version, so it was left as it is.`,
|
|
761
|
+
"Edit it in place to run yoke's review, keeping its provider, models and names. `yoke review-ci --print` shows yoke's version without saving it."
|
|
762
|
+
].join("\n");
|
|
763
|
+
function writeCallerWorkflow(root, content) {
|
|
760
764
|
const path = join3(root, callerWorkflowPath);
|
|
761
765
|
if (existsSync2(path)) {
|
|
762
766
|
if (readFileSync2(path, "utf8") === content) return "unchanged";
|
|
763
|
-
|
|
767
|
+
throw new ReviewError(editInPlaceMessage);
|
|
764
768
|
}
|
|
765
769
|
mkdirSync2(dirname2(path), { recursive: true });
|
|
766
770
|
writeFileSync2(path, content);
|
|
@@ -770,7 +774,7 @@ function entraSetup({ clientId, environment }, repo) {
|
|
|
770
774
|
const credential = federatedCredential(repo, environment);
|
|
771
775
|
return [
|
|
772
776
|
"",
|
|
773
|
-
`Instead of
|
|
777
|
+
`Instead of an API key, the review signs in to Foundry as Entra app ${clientId}. So that the app trusts this repo's review runs, add a federated credential to it with:`,
|
|
774
778
|
` issuer: ${credential.issuer}`,
|
|
775
779
|
` audience: ${credential.audience}`,
|
|
776
780
|
` subject: ${credential.subject}`,
|
|
@@ -780,17 +784,28 @@ function entraSetup({ clientId, environment }, repo) {
|
|
|
780
784
|
...environment ? [`The job runs in the ${environment} environment; create it on the repo if it does not exist.`] : []
|
|
781
785
|
];
|
|
782
786
|
}
|
|
787
|
+
function reportHeading(outcome, workflow) {
|
|
788
|
+
if (outcome === "printed")
|
|
789
|
+
return [`yoke's version of ${callerWorkflowPath}, not saved to the repo:`, "", renderCallerWorkflow(workflow).trimEnd()];
|
|
790
|
+
if (outcome === "unchanged") return [`${callerWorkflowPath} already matches yoke's version; nothing changed.`];
|
|
791
|
+
return [`Added ${callerWorkflowPath}, which reviews each PR opened from this repo.`];
|
|
792
|
+
}
|
|
793
|
+
function variableAndSecretSetup(settings, workflow) {
|
|
794
|
+
const hasSecret = workflowSecrets(workflow).length > 0;
|
|
795
|
+
return [
|
|
796
|
+
hasSecret ? `The review reads the model server's address from the repo variable ${baseUrlVariable} and its API key from the secret ${apiKeySecret}. Set them with:` : `The review reads the model server's address from the repo variable ${baseUrlVariable}. Set it with:`,
|
|
797
|
+
...setupCommands(settings, workflow).map((command) => ` ${command}`),
|
|
798
|
+
...hasSecret ? [`Skip the secret if ${apiKeySecret} is already set for your organisation.`] : []
|
|
799
|
+
];
|
|
800
|
+
}
|
|
783
801
|
function reviewCiReport(outcome, settings, workflow, repo) {
|
|
784
|
-
const action = outcome === "wrote" ? "wrote" : "kept";
|
|
785
|
-
const reads = [`variable ${baseUrlVariable}`, ...workflowSecrets(workflow).map((secret2) => `secret ${secret2}`)];
|
|
786
802
|
return [
|
|
787
|
-
|
|
803
|
+
...reportHeading(outcome, workflow),
|
|
788
804
|
"",
|
|
789
|
-
|
|
790
|
-
...setupCommands(settings, workflow).map((command) => ` ${command}`),
|
|
805
|
+
...variableAndSecretSetup(settings, workflow),
|
|
791
806
|
...workflow.entra ? entraSetup(workflow.entra, repo()) : [],
|
|
792
807
|
"",
|
|
793
|
-
"
|
|
808
|
+
outcome === "printed" ? "Once the repo's review workflow runs this review, commit and push it; each PR opened from this repo then gets a review." : `Commit and push ${callerWorkflowPath}; each PR opened from this repo then gets a review.`
|
|
794
809
|
].join("\n");
|
|
795
810
|
}
|
|
796
811
|
|
|
@@ -2185,23 +2200,38 @@ If \`yoke\` is not found, run \`npm i -g @makerx/yoke\` and retry.
|
|
|
2185
2200
|
// src/features/review/ciSkill.ts
|
|
2186
2201
|
var reviewCiSkill = {
|
|
2187
2202
|
name: "review-ci",
|
|
2188
|
-
description: "Add yoke's adversarial PR review workflow to this repo and set the variable and secret it needs.",
|
|
2203
|
+
description: "Add yoke's adversarial PR review workflow to this repo, or switch its existing LLM review workflow to it, and set the variable and secret it needs.",
|
|
2189
2204
|
disableModelInvocation: true,
|
|
2190
2205
|
userLevel: true,
|
|
2191
2206
|
body: `
|
|
2192
|
-
|
|
2207
|
+
Read \`.github/workflows/\`, recent review runs (\`gh run list\`, \`gh run view --log\`) and \`yoke config list\` before asking anything. Only ask what they don't answer, in plain words about the repo, not flags.
|
|
2193
2208
|
|
|
2194
|
-
|
|
2209
|
+
## Workflow
|
|
2195
2210
|
|
|
2196
|
-
|
|
2197
|
-
- \`REVIEW_CI_BASE_URL\` is a variable, not a secret: confirm the URL with the user and run the printed \`gh variable set\` command.
|
|
2198
|
-
- \`REVIEW_CI_API_KEY\` must never enter this conversation: ask the user to run \`gh secret set REVIEW_CI_API_KEY\` in their own terminal, outside this session, and paste the key at its prompt. With Entra auth there is no API key to set.
|
|
2211
|
+
A workflow is an LLM review if it has a model review PRs, whatever tool it uses.
|
|
2199
2212
|
|
|
2200
|
-
|
|
2213
|
+
- **None:** run \`yoke review-ci $ARGUMENTS\`.
|
|
2214
|
+
- **One, not yoke's:** run \`yoke review-ci $ARGUMENTS --print\` with its provider and models, then edit that file in place to run yoke's review. Keep its name, triggers, provider, models, base URL, variable and secret names.
|
|
2215
|
+
- **Already yoke's** (calls MakerXStudio/yoke's \`review.yml\`, or \`./.github/workflows/review.yml\` in yoke itself): compare with \`--print\` and add only what is missing.
|
|
2201
2216
|
|
|
2202
|
-
|
|
2217
|
+
Never ask whether to overwrite a workflow. If \`review-pr.yml\` exists and differs, edit it in place.
|
|
2203
2218
|
|
|
2204
|
-
If
|
|
2219
|
+
If no workflow or setting names the models, ask which model each reviewer runs. For LiteLLM, offer \`yoke models\`. For Foundry, ask for deployment names.
|
|
2220
|
+
|
|
2221
|
+
For Foundry with Entra, reuse the client and tenant IDs from the existing workflow; ask only if none is there.
|
|
2222
|
+
|
|
2223
|
+
## Variable and secret
|
|
2224
|
+
|
|
2225
|
+
Never ask whether they are set for the organisation, and don't query org settings.
|
|
2226
|
+
|
|
2227
|
+
- \`REVIEW_CI_BASE_URL\` not in \`gh variable list\`: set it on the repo with the base URL from the workflow or the printed command.
|
|
2228
|
+
- \`REVIEW_CI_API_KEY\` not in \`gh secret list\`: tell the user to run \`gh secret set REVIEW_CI_API_KEY\` in their own terminal, and to skip it if the secret is already set for the organisation. Never take the key in this conversation.
|
|
2229
|
+
|
|
2230
|
+
With Entra, check \`az ad app federated-credential list --id <client-id>\` and show the printed create command if the credential is missing.
|
|
2231
|
+
|
|
2232
|
+
Finish with what changed and what's left: commit and push the workflow.
|
|
2233
|
+
|
|
2234
|
+
If \`yoke\` is not found, run \`npm i -g @makerx/yoke\`.
|
|
2205
2235
|
`
|
|
2206
2236
|
};
|
|
2207
2237
|
|
|
@@ -2310,14 +2340,14 @@ addSettingOptions(
|
|
|
2310
2340
|
).option("--provider <provider>", "litellm or foundry; every slot uses it in CI. Default: review.reviewer1.provider, else litellm").option(
|
|
2311
2341
|
"--azure-client-id <id>",
|
|
2312
2342
|
"Entra app (client) ID to sign in to Foundry with GitHub OIDC instead of an API key; needs --provider foundry"
|
|
2313
|
-
).option("--azure-tenant-id <id>", "Entra tenant ID of that app").option("--environment <name>", "GitHub environment the review job runs in, matching the app's federated credential subject").option("--
|
|
2343
|
+
).option("--azure-tenant-id <id>", "Entra tenant ID of that app").option("--environment <name>", "GitHub environment the review job runs in, matching the app's federated credential subject").option("--print", `print the workflow and setup commands without writing ${callerWorkflowPath}`),
|
|
2314
2344
|
ciKeys
|
|
2315
2345
|
).addHelpText("after", settingsHelp).action((options) => {
|
|
2316
2346
|
try {
|
|
2317
2347
|
const settings = resolveSettings(flagSettings(options, ciKeys), process.env, readUserConfig(userConfigPath()));
|
|
2318
2348
|
const workflow = callerWorkflow(settings, options.provider, options);
|
|
2319
2349
|
const root = repoRoot();
|
|
2320
|
-
const outcome = writeCallerWorkflow(root, renderCallerWorkflow(workflow)
|
|
2350
|
+
const outcome = options.print ? "printed" : writeCallerWorkflow(root, renderCallerWorkflow(workflow));
|
|
2321
2351
|
console.log(reviewCiReport(outcome, settings, workflow, () => githubRepo(root)));
|
|
2322
2352
|
} catch (error) {
|
|
2323
2353
|
if (!(error instanceof ReviewError || error instanceof ConfigError)) throw error;
|