autark-cli 0.2.0 → 0.3.1
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/autark.mjs +38 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# autark-cli
|
|
2
2
|
|
|
3
|
-
CLI for [autark](https://autark.
|
|
3
|
+
CLI for [autark](https://autark.sh) — hypothesis-driven product runbooks.
|
|
4
4
|
|
|
5
5
|
A product has hypotheses. Each hypothesis has runs. Each run logs actions (emails sent, posts made, replies received). The dashboard shows it all.
|
|
6
6
|
|
package/autark.mjs
CHANGED
|
@@ -22,11 +22,42 @@ const CREDS_PATH = process.env.AUTARK_CREDENTIALS || path.join(AUTARK_HOME, 'cre
|
|
|
22
22
|
// loop, so they need to be initialized at module-load time before the
|
|
23
23
|
// main().catch() call below.
|
|
24
24
|
const RAW_RUNTIME_BASE = process.env.AUTARK_RUNTIME_RAW_BASE
|
|
25
|
-
|| 'https://autark.
|
|
25
|
+
|| 'https://autark.sh/runtime'
|
|
26
26
|
const SKILL_NAMES = ['autark', 'plumcake', 'chrome-relay', 'email', 'outreach', 'email-finder']
|
|
27
27
|
const ECOSYSTEM_CLIS = ['autark-cli', 'plumcake-cli', 'chrome-relay']
|
|
28
28
|
const PROGRAM_FILES = ['start.md', 'double-down.md', 'check.md', 'followup.md']
|
|
29
29
|
|
|
30
|
+
// ============================================================ address reject
|
|
31
|
+
// Two address shapes are bad enough to refuse at the CLI boundary, regardless
|
|
32
|
+
// of what the agent prompted: RFC 2606 reserved domains (test@example.com — pure
|
|
33
|
+
// bounce, hurts SES rep) and role-accounts (sales@, info@, hello@ — almost never
|
|
34
|
+
// reach a human, waste of a thread). Reject mode is hard — surfaces an error so
|
|
35
|
+
// the operator sees and the agent picks a different target. Lives up here, not
|
|
36
|
+
// next to mailSend, because mailSend gets invoked via main() synchronously and
|
|
37
|
+
// would TDZ on the Sets if they were declared after main()'s call site.
|
|
38
|
+
const RFC2606_DOMAINS = new Set(['example.com', 'example.net', 'example.org', 'example', 'test', 'invalid', 'localhost'])
|
|
39
|
+
const PLACEHOLDER_USERS = new Set(['test', 'foo', 'bar', 'x', 'y', 'sample', 'placeholder'])
|
|
40
|
+
const ROLE_ACCOUNT_USERS = new Set([
|
|
41
|
+
'sales', 'info', 'hello', 'team', 'contact', 'support', 'press', 'marketing',
|
|
42
|
+
'admin', 'billing', 'careers', 'jobs', 'webmaster', 'postmaster', 'help',
|
|
43
|
+
'office', 'media', 'partners', 'enquiries', 'inquiries', 'general',
|
|
44
|
+
'noreply', 'no-reply', 'donotreply', 'do-not-reply',
|
|
45
|
+
])
|
|
46
|
+
|
|
47
|
+
function rejectUnsendableAddress(addresses) {
|
|
48
|
+
for (const raw of addresses || []) {
|
|
49
|
+
const addr = String(raw || '').trim().toLowerCase()
|
|
50
|
+
if (!addr) continue
|
|
51
|
+
const [user, domain] = addr.split('@')
|
|
52
|
+
if (!user || !domain) throw new Error(`malformed address: ${raw}`)
|
|
53
|
+
if (RFC2606_DOMAINS.has(domain)) throw new Error(`refusing to send to RFC2606 reserved domain: ${raw}`)
|
|
54
|
+
if (PLACEHOLDER_USERS.has(user)) throw new Error(`refusing to send to placeholder address: ${raw}`)
|
|
55
|
+
if (ROLE_ACCOUNT_USERS.has(user)) {
|
|
56
|
+
throw new Error(`refusing to send to role-account: ${raw}. Find a named person, or skip this target — role accounts almost never reply.`)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
30
61
|
const args = process.argv.slice(2)
|
|
31
62
|
main()
|
|
32
63
|
.then(() => maybeNudge())
|
|
@@ -805,6 +836,10 @@ function deliverabilityUsage() {
|
|
|
805
836
|
bounces don't tank your domain rep.`)
|
|
806
837
|
}
|
|
807
838
|
|
|
839
|
+
// rejectUnsendableAddress is defined near the top of the file (before main()
|
|
840
|
+
// runs) so the const Sets it depends on are out of TDZ when mailSend invokes
|
|
841
|
+
// it. See block tagged "address reject" up top.
|
|
842
|
+
|
|
808
843
|
// ============================================================ mail
|
|
809
844
|
|
|
810
845
|
async function mail(command, rest) {
|
|
@@ -853,6 +888,7 @@ async function mailSend(rest) {
|
|
|
853
888
|
const opts = parseArgs(rest)
|
|
854
889
|
const creds = requireAgentmailCredentials()
|
|
855
890
|
const to = listOpt(opts.to, '--to')
|
|
891
|
+
rejectUnsendableAddress(to)
|
|
856
892
|
const subject = opts.subject || ''
|
|
857
893
|
const body = mailBody(opts, { to, subject })
|
|
858
894
|
const result = await agentmailRequest('POST', `/inboxes/${encodeURIComponent(creds.inboxId)}/messages/send`, body)
|
|
@@ -1084,7 +1120,7 @@ function printProductContext(r) {
|
|
|
1084
1120
|
console.log(`# ${r.product.slug} — ${r.product.name}\n`)
|
|
1085
1121
|
if (r.product.tagline) console.log(`> ${r.product.tagline}\n`)
|
|
1086
1122
|
console.log(`## Brief\n`)
|
|
1087
|
-
console.log(r.product.brief?.trim() || '(no brief set — owner can add one at https://autark.
|
|
1123
|
+
console.log(r.product.brief?.trim() || '(no brief set — owner can add one at https://autark.sh)')
|
|
1088
1124
|
if (!r.hypotheses?.length) {
|
|
1089
1125
|
console.log(`\n## Hypotheses\n\n(none yet — create one with: autark hypothesis create --product-id <product_id> --md @hyp.md)`)
|
|
1090
1126
|
} else {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autark-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "CLI for autark
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "CLI for autark \u2014 hypothesis-driven product runbooks. Track products, hypotheses, runs, and actions from the terminal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"autark.mjs",
|
|
12
12
|
"README.md"
|
|
13
13
|
],
|
|
14
|
-
"homepage": "https://autark.
|
|
14
|
+
"homepage": "https://autark.sh",
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
17
17
|
"url": "git+https://github.com/kiluazen/autark.git"
|