@meffecta/agent 1.0.11 → 1.0.13
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/deployment.env.example +1 -1
- package/engine.json +2 -2
- package/lib/commands.js +5 -0
- package/lib/create-job.js +1 -1
- package/lib/integrations.js +9 -4
- package/lib/resources.js +3 -0
- package/package.json +1 -1
- package/scripts/lib/deployment.sh +1 -1
- package/scripts/setup-infrastructure.sh +7 -0
- package/scripts/verify-credentials.mjs +20 -0
package/deployment.env.example
CHANGED
|
@@ -32,7 +32,7 @@ REGION=europe-west1
|
|
|
32
32
|
# several Google accounts and want this deployment pinned to one.
|
|
33
33
|
# ACCOUNT=you@example.com
|
|
34
34
|
|
|
35
|
-
# Optional. The
|
|
35
|
+
# Optional. The zone every job's `cron:` is read in. Defaults to UTC.
|
|
36
36
|
# TIMEZONE=Europe/Stockholm
|
|
37
37
|
|
|
38
38
|
# Optional. The runtime shape asserted on every rollout, so the deployed service
|
package/engine.json
CHANGED
package/lib/commands.js
CHANGED
|
@@ -217,6 +217,11 @@ async function status() {
|
|
|
217
217
|
}
|
|
218
218
|
console.log(` revision ${svc.status?.latestReadyRevisionName ?? "?"}`);
|
|
219
219
|
console.log(` image ${container.image}`);
|
|
220
|
+
// The address you paste into someone else's console. GA4, Search Console and Google Ads
|
|
221
|
+
// authenticate as this rather than with a token, so granting the agent a property means
|
|
222
|
+
// inviting this email — and it is read from the service rather than assembled from the
|
|
223
|
+
// project name, so it is what the agent actually runs as.
|
|
224
|
+
console.log(` acts as ${tpl.spec.serviceAccountName ?? "(the project's default compute account)"}`);
|
|
220
225
|
console.log(
|
|
221
226
|
` shape min ${ann["autoscaling.knative.dev/minScale"] ?? "0"}, max ${
|
|
222
227
|
ann["autoscaling.knative.dev/maxScale"] ?? "?"
|
package/lib/create-job.js
CHANGED
|
@@ -230,7 +230,7 @@ export async function createJob(args) {
|
|
|
230
230
|
.map((f) => f.replace(/\.md$/, ""))
|
|
231
231
|
: [];
|
|
232
232
|
|
|
233
|
-
const timezone = d.TIMEZONE ?? "
|
|
233
|
+
const timezone = d.TIMEZONE ?? "UTC";
|
|
234
234
|
console.error(`Asking ${d.SERVICE} to write it — it can see your jobs, worlds and skills. This takes a minute.`);
|
|
235
235
|
const params = new URLSearchParams({ prompt: buildPrompt(description, { timezone, existing }) });
|
|
236
236
|
if (flags.model) {
|
package/lib/integrations.js
CHANGED
|
@@ -63,8 +63,8 @@ const INTEGRATIONS = {
|
|
|
63
63
|
gives: "query-google-marketing — traffic, the queries that bring it, campaign spend",
|
|
64
64
|
needs: [
|
|
65
65
|
"No token at all: these authenticate as the runtime service account, which means",
|
|
66
|
-
"inviting it rather than minting anything. `meffecta-agent status` prints
|
|
67
|
-
"
|
|
66
|
+
"inviting it rather than minting anything. `meffecta-agent status` prints the exact",
|
|
67
|
+
"address to invite, on its `acts as` line.",
|
|
68
68
|
"",
|
|
69
69
|
"Invite it as a Viewer on each property you want read: the GA4 property (Admin →",
|
|
70
70
|
"Property access management), the Search Console property (Settings → Users and",
|
|
@@ -199,7 +199,8 @@ const INTEGRATIONS = {
|
|
|
199
199
|
needs: [
|
|
200
200
|
"A mailbox the agent can read. Either a Workspace mailbox via domain-wide delegation",
|
|
201
201
|
"(keyless, Cloud Run only), or any Gmail account you have already connected — see",
|
|
202
|
-
"`meffecta-agent connect gmail` first if you have not.",
|
|
202
|
+
"`meffecta-agent connect gmail` first if you have not. An AgentMail inbox needs none",
|
|
203
|
+
"of that: set AGENTMAIL_API_KEY and skip to the frontmatter below.",
|
|
203
204
|
],
|
|
204
205
|
steps: [
|
|
205
206
|
[
|
|
@@ -213,11 +214,15 @@ const INTEGRATIONS = {
|
|
|
213
214
|
more: [
|
|
214
215
|
"Then, in the job's frontmatter:",
|
|
215
216
|
"",
|
|
216
|
-
" inbox: crm@yourdomain.com",
|
|
217
|
+
" inbox: gmail:crm@yourdomain.com",
|
|
217
218
|
" allowFrom: you@yourdomain.com, @yourdomain.com",
|
|
218
219
|
"",
|
|
219
220
|
"and `deploy` to register it — both fields are read when the service boots.",
|
|
220
221
|
"",
|
|
222
|
+
"The system is required: `gmail:<address>`, or `agentmail:<address>` for an inbox the",
|
|
223
|
+
"agent owns. A bare address is refused rather than guessed at, because an address",
|
|
224
|
+
"polled against the wrong system finds nothing for ever and looks healthy doing it.",
|
|
225
|
+
"",
|
|
221
226
|
"allowFrom is required and enforced in code: mail from anyone not listed is dropped",
|
|
222
227
|
"before the run starts, so it never reaches the model. Leave it out and the job",
|
|
223
228
|
"refuses every message — an omission is not read as consent.",
|
package/lib/resources.js
CHANGED
|
@@ -210,6 +210,9 @@ export async function resources() {
|
|
|
210
210
|
const note = explain[name] ?? `${display || "no description"} — not part of the agent set-up`;
|
|
211
211
|
row(email === runtimeSa ? "✔" : explain[name] ? "✔" : "·", name, note, saWidth);
|
|
212
212
|
}
|
|
213
|
+
console.log(` ${runtimeSa}`);
|
|
214
|
+
console.log(" is the address to invite on a GA4 property, Search Console or Google Ads —");
|
|
215
|
+
console.log(" those grant access to a login rather than to a token.");
|
|
213
216
|
const held = (roles ?? "").split("\n").filter(Boolean);
|
|
214
217
|
if (held.length) {
|
|
215
218
|
console.log(` agent-runtime may, across the whole project: ${held.map((r) => leaf(r)).join(", ")}`);
|
package/package.json
CHANGED
|
@@ -70,7 +70,7 @@ resolve_deployment() {
|
|
|
70
70
|
# configure by editing a committed file.
|
|
71
71
|
GHCR_IMAGE="${GHCR_IMAGE:-ghcr.io/meffecta/agent}"
|
|
72
72
|
GHCR_PATH="${GHCR_IMAGE#*/}" # ghcr.io/meffecta/agent → meffecta/agent
|
|
73
|
-
TIMEZONE="${TIMEZONE:-
|
|
73
|
+
TIMEZONE="${TIMEZONE:-UTC}"
|
|
74
74
|
|
|
75
75
|
# The runtime shape, asserted by deploy.sh on every rollout so the deployed service
|
|
76
76
|
# matches this file rather than whatever was last done by hand in the console. Defaults
|
|
@@ -314,6 +314,13 @@ echo " the agent acts as, a bucket for its memory, a write-once bucket for the
|
|
|
314
314
|
echo " trail, the queue that carries work back to the service, and the service itself —"
|
|
315
315
|
echo " empty, waiting for an engine."
|
|
316
316
|
echo ""
|
|
317
|
+
# The one address an operator has to type into someone else's console. Google Analytics,
|
|
318
|
+
# Search Console and Google Ads grant access to a login rather than to a token, so this is
|
|
319
|
+
# what gets invited. Printed on every run, not only the one that created it.
|
|
320
|
+
echo " The agent acts as:"
|
|
321
|
+
echo " ${RUNTIME_SA}"
|
|
322
|
+
echo " Invite that on a GA4 property, Search Console or Google Ads to let it read them."
|
|
323
|
+
echo ""
|
|
317
324
|
echo " Next, from this directory:"
|
|
318
325
|
echo ""
|
|
319
326
|
echo " $(cmd set-env) GIT_REPO_URL=https://github.com/<owner>/<content-repo>.git"
|
|
@@ -163,6 +163,25 @@ async function checkAhrefs() {
|
|
|
163
163
|
: fail("AHREFS_API_KEY", `domain-rating-free → ${status}`);
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
+
async function checkAgentmail() {
|
|
167
|
+
if (!env.AGENTMAIL_API_KEY) {
|
|
168
|
+
return skip("AGENTMAIL_API_KEY", "unset");
|
|
169
|
+
}
|
|
170
|
+
// The cheapest call there is, and the one that answers what actually matters about this
|
|
171
|
+
// key: a key scoped to a single inbox is indistinguishable from an account-wide one until
|
|
172
|
+
// something asks, and a job pointed at another inbox would fail with a puzzling 404.
|
|
173
|
+
const { status, json } = await http("https://api.agentmail.to/v0/auth/me", {
|
|
174
|
+
headers: { Authorization: `Bearer ${env.AGENTMAIL_API_KEY}` },
|
|
175
|
+
});
|
|
176
|
+
if (status !== 200) {
|
|
177
|
+
return fail("AGENTMAIL_API_KEY", `auth/me → ${status}`);
|
|
178
|
+
}
|
|
179
|
+
ok(
|
|
180
|
+
"AGENTMAIL_API_KEY",
|
|
181
|
+
json?.scope_type === "inbox" ? `scoped to ${json.inbox_id}` : `${json?.scope_type ?? "?"}-wide scope`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
166
185
|
async function checkSerper() {
|
|
167
186
|
if (!env.SERPER_API_KEY) {
|
|
168
187
|
return skip("SERPER_API_KEY", "unset");
|
|
@@ -646,6 +665,7 @@ const CHECKS = [
|
|
|
646
665
|
["POSTHOG", checkPosthog],
|
|
647
666
|
["AHREFS_API_KEY", checkAhrefs],
|
|
648
667
|
["SERPER_API_KEY", checkSerper],
|
|
668
|
+
["AGENTMAIL_API_KEY", checkAgentmail],
|
|
649
669
|
["HUBSPOT_TOKEN", checkHubspot],
|
|
650
670
|
["KLEER_API_TOKEN", checkKleer],
|
|
651
671
|
["CLOUDFLARE", checkCloudflare],
|