@meffecta/agent 1.0.13 → 1.0.15

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.
@@ -52,5 +52,5 @@ REGION=europe-west1
52
52
  # SCALING=scale-to-zero
53
53
  # CPU=2
54
54
  # MEMORY=4Gi
55
- # MAX_INSTANCES=1 # >1 breaks the serial run queue — raise only with reason
55
+ # MAX_INSTANCES=1 # the run pool is per process>1 breaks it, so raise only with reason
56
56
  # REQUEST_TIMEOUT=3600 # seconds one held request may last; the ceiling on a single run
package/engine.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "engineTag": "1.0.13",
3
- "builtFrom": "2c7075fd557116ad9692c5bb1780d60a1559aa01"
2
+ "engineTag": "1.0.15",
3
+ "builtFrom": "6b2db5d04d06db2612112659dd526e6f23a3e8c3"
4
4
  }
package/lib/commands.js CHANGED
@@ -730,7 +730,7 @@ export const GROUPS = [
730
730
  "Provision GCP: registry, buckets, service account, run queue, service shell",
731
731
  script("setup-infrastructure.sh"),
732
732
  ],
733
- ["set-secret", "AGENT_API_SECRET --random, CLAUDE_CODE_OAUTH_TOKEN, GITHUB_TOKEN", script("set-secret.sh")],
733
+ ["set-secret", "AGENT_API_SECRET --random, ANTHROPIC_API_KEY, GITHUB_TOKEN", script("set-secret.sh")],
734
734
  ["set-env", "GIT_REPO_URL — the one setting the service will not boot without", script("set-env.sh")],
735
735
  ["deploy", "Roll out an engine image and assert the runtime shape", script("deploy.sh")],
736
736
  [
package/lib/doctor.js CHANGED
@@ -216,7 +216,29 @@ export async function doctor() {
216
216
  "meffecta-agent set-secret AGENT_API_SECRET (paste the same value, deploy, then delete the old one)",
217
217
  );
218
218
  }
219
- for (const name of [apiSecretName, "CLAUDE_CODE_OAUTH_TOKEN", "GITHUB_TOKEN"]) {
219
+ // Either variable pays for runs, and the API key wins when both are set. Naming the one
220
+ // in effect matters more than naming a missing variable: a deployment that switched to a
221
+ // Console key and left the old token behind is still billing the key, not the subscription.
222
+ const claudeAuth = env.ANTHROPIC_API_KEY ? "ANTHROPIC_API_KEY" : "CLAUDE_CODE_OAUTH_TOKEN";
223
+ if (!env.ANTHROPIC_API_KEY && !env.CLAUDE_CODE_OAUTH_TOKEN) {
224
+ r.fail(
225
+ "No way to pay for runs",
226
+ "The engine needs ANTHROPIC_API_KEY (a Claude Console key — what a product or service should use) or CLAUDE_CODE_OAUTH_TOKEN (billed to a personal subscription).",
227
+ "meffecta-agent set-secret ANTHROPIC_API_KEY",
228
+ );
229
+ } else {
230
+ r.ok("Claude credential", `runs bill to ${claudeAuth}`);
231
+ if (env.ANTHROPIC_API_KEY && env.CLAUDE_CODE_OAUTH_TOKEN) {
232
+ r.warn(
233
+ "Both Claude credentials are set",
234
+ "ANTHROPIC_API_KEY outranks CLAUDE_CODE_OAUTH_TOKEN, so the subscription token is unused.",
235
+ // Both are secret-backed, so --remove-env-vars (what `set-env --unset` does) will not
236
+ // touch them. Removing one is --remove-secrets, which the CLI has no command for.
237
+ `Drop whichever you did not mean to bill: gcloud run services update ${d.SERVICE} --region=${d.REGION} --remove-secrets CLAUDE_CODE_OAUTH_TOKEN`,
238
+ );
239
+ }
240
+ }
241
+ for (const name of [apiSecretName, claudeAuth, "GITHUB_TOKEN"]) {
220
242
  const ref = env[name]?.valueFrom?.secretKeyRef?.name;
221
243
  if (!env[name]) {
222
244
  r.fail(`${name} not set`, "Required by the engine.", `meffecta-agent set-secret ${name}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meffecta/agent",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Set up and operate a Meffecta Agent deployment — a self-hosted Claude Code job runner.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- # Step 1 of IMPLEMENTATION.md: create the GCP project this deployment will live in.
4
+ # Step 1 of the set-up (https://agent.meffecta.com/install): create the GCP project this
5
+ # deployment will live in.
5
6
  #
6
7
  # Give the agent a project of its own, separate from any product project it will read:
7
8
  # its service account gets project-wide secret access, and the mail tokens stored here
package/scripts/deploy.sh CHANGED
@@ -32,9 +32,9 @@ set -euo pipefail
32
32
  # and is left alone.
33
33
  #
34
34
  # Usage:
35
- # scripts/deploy.sh # the newest published engine (--tag latest)
36
- # scripts/deploy.sh --tag sha-556ca72 # a specific build, e.g. to roll back
37
- # scripts/deploy.sh --image europe-west1-docker.pkg.dev/PROJECT/REPO/agent:sha-556ca72
35
+ # scripts/deploy.sh # the newest release (--tag latest)
36
+ # scripts/deploy.sh --tag 1.0.13 # a specific version, e.g. to roll back
37
+ # scripts/deploy.sh --image europe-west1-docker.pkg.dev/PROJECT/REPO/agent:1.0.13
38
38
  # scripts/deploy.sh --dry-run # print the target, image and shape; change nothing
39
39
  # scripts/deploy.sh --no-scheduler # roll out without re-syncing the triggers
40
40
  #
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- # Step 2 of IMPLEMENTATION.md: link a billing account to the project.
4
+ # Step 2 of the set-up (https://agent.meffecta.com/install): link a billing account.
5
5
  #
6
6
  # Nothing else works without this — provisioning starts by enabling APIs, which fails on
7
7
  # an unbilled project, and the failure does not mention billing.
@@ -2,7 +2,7 @@
2
2
  set -euo pipefail
3
3
 
4
4
  # One-time GCP provisioning for a deployment of the agent. Idempotent — safe to re-run.
5
- # See IMPLEMENTATION.md for the whole set-up, of which this is step 6.
5
+ # See https://agent.meffecta.com/install for the whole set-up, of which this is step 5.
6
6
  #
7
7
  # Give the agent a GCP project of its OWN, separate from any product project it reads:
8
8
  # this project's service account holds project-wide secret access, and the mail refresh
@@ -325,7 +325,8 @@ echo " Next, from this directory:"
325
325
  echo ""
326
326
  echo " $(cmd set-env) GIT_REPO_URL=https://github.com/<owner>/<content-repo>.git"
327
327
  echo " $(cmd set-secret) AGENT_API_SECRET --random"
328
- echo " $(cmd set-secret) CLAUDE_CODE_OAUTH_TOKEN # from: claude setup-token"
328
+ echo " $(cmd set-secret) ANTHROPIC_API_KEY # a Claude Console key — for a service"
329
+ echo " ...or CLAUDE_CODE_OAUTH_TOKEN # from: claude setup-token — individual use"
329
330
  echo " $(cmd set-secret) GITHUB_TOKEN # must be able to clone the repo above"
330
331
  echo " $(cmd deploy) # rolls out the engine, then creates its triggers"
331
332
  if has_cli; then
@@ -23,7 +23,7 @@ set -euo pipefail
23
23
  # That is this script's job, done by hand once. Afterwards:
24
24
  #
25
25
  # scripts/update-tooling.sh # match the newest published engine
26
- # scripts/update-tooling.sh --tag sha-558a144 # match a specific one, e.g. what you run
26
+ # scripts/update-tooling.sh --tag 1.0.13 # match a specific one, e.g. what you run
27
27
  # scripts/update-tooling.sh --dry-run # show what would change, touch nothing
28
28
  #
29
29
  # Needs docker, and is the only thing here that does: the files are lifted out of the
@@ -163,6 +163,24 @@ async function checkAhrefs() {
163
163
  : fail("AHREFS_API_KEY", `domain-rating-free → ${status}`);
164
164
  }
165
165
 
166
+ async function checkMevisio() {
167
+ if (!env.MEVISIO_HOST || !env.MEVISIO_EMAIL || !env.MEVISIO_PASSWORD) {
168
+ return skip("MEVISIO", "unset");
169
+ }
170
+ // A real login, because that is the only thing that proves these three agree — the platform
171
+ // hands an ANONYMOUS session to anyone who asks, and /gateway/api/context answers 200 with
172
+ // the account filled in and no user at all. Checking the host alone would report a pass.
173
+ const { status, json } = await http(`https://${env.MEVISIO_HOST}/identity/api/login`, {
174
+ method: "POST",
175
+ headers: { "content-type": "application/json" },
176
+ body: JSON.stringify({ email: env.MEVISIO_EMAIL, password: env.MEVISIO_PASSWORD }),
177
+ });
178
+ if (status !== 200 || !json?.ok) {
179
+ return fail("MEVISIO", `login → ${status}${json?.error ? ` ${json.error}` : ""}`);
180
+ }
181
+ ok("MEVISIO", `${env.MEVISIO_EMAIL} @ ${env.MEVISIO_HOST}`);
182
+ }
183
+
166
184
  async function checkAgentmail() {
167
185
  if (!env.AGENTMAIL_API_KEY) {
168
186
  return skip("AGENTMAIL_API_KEY", "unset");
@@ -601,7 +619,13 @@ async function checkDeploymentsContext() {
601
619
  * These are also the ones a shipped script CAN test properly, because they are the
602
620
  * engine's own and mean the same thing in every deployment.
603
621
  */
604
- const ESSENTIAL = new Set(["AGENT_API_SECRET", "CLAUDE_CODE_OAUTH_TOKEN", "GITHUB_TOKEN", "GIT_REPO_URL"]);
622
+ const ESSENTIAL = new Set([
623
+ "AGENT_API_SECRET",
624
+ "ANTHROPIC_API_KEY",
625
+ "CLAUDE_CODE_OAUTH_TOKEN",
626
+ "GITHUB_TOKEN",
627
+ "GIT_REPO_URL",
628
+ ]);
605
629
 
606
630
  /**
607
631
  * Inside a run, three of the four are proven by the fact that this output exists at all —
@@ -627,12 +651,20 @@ function checkPresence() {
627
651
  // started it, which is exactly right, and means "unset" here would be a lie: the run
628
652
  // doing the reporting is itself the proof it is set. AGENT_SPAWN_TOKEN is how we know we
629
653
  // are inside a run; the engine sets that one, so `claude` has no reason to strip it.
630
- if (env.CLAUDE_CODE_OAUTH_TOKEN) {
631
- ok("CLAUDE_CODE_OAUTH_TOKEN", "present (not remotely testable)");
654
+ //
655
+ // Either variable pays for runs, and the API key wins when both are set — so report which
656
+ // one is actually in play rather than just that something is.
657
+ if (env.ANTHROPIC_API_KEY) {
658
+ ok("ANTHROPIC_API_KEY", "present — runs bill to this Console key (not remotely testable)");
659
+ if (env.CLAUDE_CODE_OAUTH_TOKEN) {
660
+ ok("CLAUDE_CODE_OAUTH_TOKEN", "present but unused — the API key outranks it");
661
+ }
662
+ } else if (env.CLAUDE_CODE_OAUTH_TOKEN) {
663
+ ok("CLAUDE_CODE_OAUTH_TOKEN", "present — runs bill to this subscription (not remotely testable)");
632
664
  } else if (env.AGENT_SPAWN_TOKEN) {
633
- ok("CLAUDE_CODE_OAUTH_TOKEN", "in use by this very run — a run cannot read it, by design");
665
+ ok("Claude credential", "in use by this very run — a run cannot read it, by design");
634
666
  } else {
635
- skip("CLAUDE_CODE_OAUTH_TOKEN", "unset");
667
+ skip("Claude credential", "neither ANTHROPIC_API_KEY nor CLAUDE_CODE_OAUTH_TOKEN is set");
636
668
  }
637
669
  // Either name satisfies the engine; say which one is actually in play.
638
670
  if (env.AGENT_API_SECRET) {
@@ -666,6 +698,7 @@ const CHECKS = [
666
698
  ["AHREFS_API_KEY", checkAhrefs],
667
699
  ["SERPER_API_KEY", checkSerper],
668
700
  ["AGENTMAIL_API_KEY", checkAgentmail],
701
+ ["MEVISIO", checkMevisio],
669
702
  ["HUBSPOT_TOKEN", checkHubspot],
670
703
  ["KLEER_API_TOKEN", checkKleer],
671
704
  ["CLOUDFLARE", checkCloudflare],