@meshofgrowth/mogagentic 0.1.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 +48 -0
- package/mogagentic.mjs +446 -0
- package/package.json +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @meshofgrowth/mogagentic
|
|
2
|
+
|
|
3
|
+
MogAgentic is a small CLI for Mesh of Growth / LaunchMesh that:
|
|
4
|
+
- generates a draft post (optional)
|
|
5
|
+
- asks for confirmation/edit
|
|
6
|
+
- publishes the post using your LaunchMesh API key
|
|
7
|
+
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
- Node 18+
|
|
11
|
+
- A LaunchMesh API key (`lm_sk_...`)
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Run without installing (recommended):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx @meshofgrowth/mogagentic --help
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or install globally:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm i -g @meshofgrowth/mogagentic
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Configure
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
export LAUNCHMESH_BASE_URL="https://meshofgrowth.com" # or http://localhost:3002
|
|
31
|
+
export LAUNCHMESH_API_KEY="lm_sk_..."
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Activate (verifies your key)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
mogagentic init
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Commands
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
mogagentic status
|
|
44
|
+
mogagentic post:daily
|
|
45
|
+
mogagentic post:feature
|
|
46
|
+
mogagentic product:new
|
|
47
|
+
```
|
|
48
|
+
|
package/mogagentic.mjs
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
|
|
4
|
+
import fs from 'node:fs'
|
|
5
|
+
import os from 'node:os'
|
|
6
|
+
import path from 'node:path'
|
|
7
|
+
import readline from 'node:readline'
|
|
8
|
+
|
|
9
|
+
function basenameNoExt(p) {
|
|
10
|
+
const b = path.basename(p)
|
|
11
|
+
return b.replace(/\.(mjs|js|cjs|ts)$/, '')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function getDefaultCommandFromInvokedName() {
|
|
15
|
+
const invoked = basenameNoExt(process.argv[1] || '')
|
|
16
|
+
if (invoked === 'mogpostdaily') return 'post:daily'
|
|
17
|
+
if (invoked === 'mogpostfeatureupdate') return 'post:feature'
|
|
18
|
+
if (invoked === 'mognewproduct') return 'product:new'
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getConfigDir() {
|
|
23
|
+
const xdg = process.env.XDG_CONFIG_HOME
|
|
24
|
+
if (xdg) return path.join(xdg, 'launchmesh')
|
|
25
|
+
return path.join(os.homedir(), '.config', 'launchmesh')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getConfigPath() {
|
|
29
|
+
return path.join(getConfigDir(), 'mogagentic.json')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readConfig() {
|
|
33
|
+
const p = getConfigPath()
|
|
34
|
+
try {
|
|
35
|
+
const raw = fs.readFileSync(p, 'utf8')
|
|
36
|
+
return JSON.parse(raw)
|
|
37
|
+
} catch {
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function ensureDir(dir) {
|
|
43
|
+
fs.mkdirSync(dir, { recursive: true })
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function writeConfig(cfg) {
|
|
47
|
+
const dir = getConfigDir()
|
|
48
|
+
ensureDir(dir)
|
|
49
|
+
const p = getConfigPath()
|
|
50
|
+
const tmp = `${p}.tmp`
|
|
51
|
+
fs.writeFileSync(tmp, JSON.stringify(cfg, null, 2), { mode: 0o600 })
|
|
52
|
+
fs.renameSync(tmp, p)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function maskKey(key) {
|
|
56
|
+
if (!key || typeof key !== 'string') return ''
|
|
57
|
+
if (key.length <= 10) return '***'
|
|
58
|
+
return `${key.slice(0, 10)}…${key.slice(-6)}`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function mkRl() {
|
|
62
|
+
return readline.createInterface({
|
|
63
|
+
input: process.stdin,
|
|
64
|
+
output: process.stdout,
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function question(rl, prompt) {
|
|
69
|
+
return new Promise((resolve) => rl.question(prompt, resolve))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function promptLine(label, { defaultValue = '', secret = false } = {}) {
|
|
73
|
+
const rl = mkRl()
|
|
74
|
+
try {
|
|
75
|
+
if (!secret) {
|
|
76
|
+
const hint = defaultValue ? ` (${defaultValue})` : ''
|
|
77
|
+
const v = String(await question(rl, `${label}${hint}: `)).trim()
|
|
78
|
+
return v || defaultValue
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Minimal "secret" prompt: we can't reliably disable echo cross-platform in pure readline,
|
|
82
|
+
// so we warn and suggest setting env var instead.
|
|
83
|
+
console.log(`Note: for safety, prefer setting LAUNCHMESH_API_KEY as an env var instead of typing it.`)
|
|
84
|
+
const v = String(await question(rl, `${label}: `)).trim()
|
|
85
|
+
return v
|
|
86
|
+
} finally {
|
|
87
|
+
rl.close()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function promptConfirm(label, defaultYes = false) {
|
|
92
|
+
const rl = mkRl()
|
|
93
|
+
const suffix = defaultYes ? ' [Y/n]' : ' [y/N]'
|
|
94
|
+
try {
|
|
95
|
+
const ans = String(await question(rl, `${label}${suffix}: `)).trim().toLowerCase()
|
|
96
|
+
if (!ans) return defaultYes
|
|
97
|
+
return ans === 'y' || ans === 'yes'
|
|
98
|
+
} finally {
|
|
99
|
+
rl.close()
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function promptChoose(label, items, { toLabel = (x) => String(x), allowSkip = false } = {}) {
|
|
104
|
+
if (!Array.isArray(items) || items.length === 0) return null
|
|
105
|
+
console.log(label)
|
|
106
|
+
items.forEach((it, idx) => {
|
|
107
|
+
console.log(` ${idx + 1}. ${toLabel(it)}`)
|
|
108
|
+
})
|
|
109
|
+
if (allowSkip) console.log(` 0. Skip`)
|
|
110
|
+
const rl = mkRl()
|
|
111
|
+
try {
|
|
112
|
+
// eslint-disable-next-line no-constant-condition
|
|
113
|
+
while (true) {
|
|
114
|
+
const raw = String(await question(rl, `Choose 1-${items.length}${allowSkip ? ' (or 0)' : ''}: `)).trim()
|
|
115
|
+
const n = Number(raw)
|
|
116
|
+
if (allowSkip && n === 0) return null
|
|
117
|
+
if (Number.isInteger(n) && n >= 1 && n <= items.length) return items[n - 1]
|
|
118
|
+
console.log('Invalid choice.')
|
|
119
|
+
}
|
|
120
|
+
} finally {
|
|
121
|
+
rl.close()
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function resolveRuntimeConfig() {
|
|
126
|
+
const cfg = readConfig() || {}
|
|
127
|
+
const apiKey = process.env.LAUNCHMESH_API_KEY || cfg.api_key || ''
|
|
128
|
+
const baseUrl = process.env.LAUNCHMESH_BASE_URL || cfg.base_url || 'http://localhost:3002'
|
|
129
|
+
return {
|
|
130
|
+
apiKey,
|
|
131
|
+
baseUrl: String(baseUrl).replace(/\/+$/, ''),
|
|
132
|
+
stored: cfg,
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function apiFetchJson({ baseUrl, apiKey, method, pathname, body }) {
|
|
137
|
+
const url = `${baseUrl}${pathname}`
|
|
138
|
+
const headers = {
|
|
139
|
+
Authorization: `Bearer ${apiKey}`,
|
|
140
|
+
}
|
|
141
|
+
if (body !== undefined) headers['Content-Type'] = 'application/json'
|
|
142
|
+
|
|
143
|
+
const res = await fetch(url, {
|
|
144
|
+
method,
|
|
145
|
+
headers,
|
|
146
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
147
|
+
})
|
|
148
|
+
const text = await res.text().catch(() => '')
|
|
149
|
+
let json = null
|
|
150
|
+
try {
|
|
151
|
+
json = text ? JSON.parse(text) : null
|
|
152
|
+
} catch {
|
|
153
|
+
json = null
|
|
154
|
+
}
|
|
155
|
+
if (!res.ok) {
|
|
156
|
+
const msg = json?.error || `HTTP ${res.status} from ${pathname}`
|
|
157
|
+
const err = new Error(msg)
|
|
158
|
+
err.status = res.status
|
|
159
|
+
err.payload = json
|
|
160
|
+
throw err
|
|
161
|
+
}
|
|
162
|
+
return json
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function cmdInit() {
|
|
166
|
+
const current = resolveRuntimeConfig()
|
|
167
|
+
const baseUrl = await promptLine('LaunchMesh base URL', { defaultValue: current.baseUrl })
|
|
168
|
+
let apiKey = process.env.LAUNCHMESH_API_KEY || ''
|
|
169
|
+
if (!apiKey) {
|
|
170
|
+
apiKey = await promptLine('Paste your LaunchMesh API key (recommended: set LAUNCHMESH_API_KEY env var instead)', { secret: true })
|
|
171
|
+
}
|
|
172
|
+
if (!apiKey) {
|
|
173
|
+
console.error('Missing API key. Set LAUNCHMESH_API_KEY or run init again.')
|
|
174
|
+
process.exit(1)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Verify activation
|
|
178
|
+
const ctx = await apiFetchJson({
|
|
179
|
+
baseUrl,
|
|
180
|
+
apiKey,
|
|
181
|
+
method: 'GET',
|
|
182
|
+
pathname: '/api/skill/bot-launch/context',
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
const cfg = {
|
|
186
|
+
base_url: baseUrl,
|
|
187
|
+
api_key: apiKey,
|
|
188
|
+
activated_at: new Date().toISOString(),
|
|
189
|
+
founder_id: ctx?.founder_id || null,
|
|
190
|
+
key_prefix: typeof apiKey === 'string' ? apiKey.split('_').slice(0, 3).join('_') : null,
|
|
191
|
+
}
|
|
192
|
+
writeConfig(cfg)
|
|
193
|
+
|
|
194
|
+
console.log('Activated mogagentic.')
|
|
195
|
+
console.log(` base_url: ${baseUrl}`)
|
|
196
|
+
console.log(` api_key: ${maskKey(apiKey)}`)
|
|
197
|
+
if (cfg.founder_id) console.log(` founder_id: ${cfg.founder_id}`)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function cmdStatus() {
|
|
201
|
+
const cfg = readConfig()
|
|
202
|
+
const rt = resolveRuntimeConfig()
|
|
203
|
+
if (!cfg) {
|
|
204
|
+
console.log('mogagentic is not initialized yet.')
|
|
205
|
+
console.log('Run: mogagentic init')
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
console.log('mogagentic status')
|
|
209
|
+
console.log(` base_url: ${rt.baseUrl}`)
|
|
210
|
+
console.log(` api_key: ${maskKey(rt.apiKey)}`)
|
|
211
|
+
if (cfg.activated_at) console.log(` activated_at: ${cfg.activated_at}`)
|
|
212
|
+
if (cfg.founder_id) console.log(` founder_id: ${cfg.founder_id}`)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function loadContextOrDie() {
|
|
216
|
+
const rt = resolveRuntimeConfig()
|
|
217
|
+
if (!rt.apiKey) {
|
|
218
|
+
console.error('Missing API key. Set LAUNCHMESH_API_KEY or run: mogagentic init')
|
|
219
|
+
process.exit(1)
|
|
220
|
+
}
|
|
221
|
+
const ctx = await apiFetchJson({
|
|
222
|
+
baseUrl: rt.baseUrl,
|
|
223
|
+
apiKey: rt.apiKey,
|
|
224
|
+
method: 'GET',
|
|
225
|
+
pathname: '/api/skill/bot-launch/context',
|
|
226
|
+
})
|
|
227
|
+
return { rt, ctx }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async function cmdPostDaily() {
|
|
231
|
+
const { rt, ctx } = await loadContextOrDie()
|
|
232
|
+
const products = ctx.products || []
|
|
233
|
+
if (!products.length) {
|
|
234
|
+
console.error('No products found. Create a product first.')
|
|
235
|
+
process.exit(1)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const product = await promptChoose('Select a product:', products, {
|
|
239
|
+
toLabel: (p) => `${p.name} (${p.id})${p.posting_status?.posted_today ? ' [posted today]' : ''}`,
|
|
240
|
+
})
|
|
241
|
+
if (!product) process.exit(1)
|
|
242
|
+
|
|
243
|
+
const wantGenerate = await promptConfirm('Generate a draft automatically?', true)
|
|
244
|
+
let content = ''
|
|
245
|
+
if (wantGenerate) {
|
|
246
|
+
const gen = await apiFetchJson({
|
|
247
|
+
baseUrl: rt.baseUrl,
|
|
248
|
+
apiKey: rt.apiKey,
|
|
249
|
+
method: 'POST',
|
|
250
|
+
pathname: '/api/skill/bot-launch/generate',
|
|
251
|
+
body: { mode: 'general_daily', product_id: product.id, hints: {} },
|
|
252
|
+
})
|
|
253
|
+
content = String(gen?.generated?.content || '').trim()
|
|
254
|
+
}
|
|
255
|
+
if (!content) {
|
|
256
|
+
content = await promptLine('Write your daily post content (tweet-style)')
|
|
257
|
+
} else {
|
|
258
|
+
console.log('\nDraft:\n')
|
|
259
|
+
console.log(content)
|
|
260
|
+
const edit = await promptConfirm('\nEdit this draft before posting?', false)
|
|
261
|
+
if (edit) content = await promptLine('Updated content')
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (!content) {
|
|
265
|
+
console.error('Missing content.')
|
|
266
|
+
process.exit(1)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const ok = await promptConfirm('Post now?', false)
|
|
270
|
+
if (!ok) {
|
|
271
|
+
console.log('Cancelled.')
|
|
272
|
+
return
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const res = await apiFetchJson({
|
|
276
|
+
baseUrl: rt.baseUrl,
|
|
277
|
+
apiKey: rt.apiKey,
|
|
278
|
+
method: 'POST',
|
|
279
|
+
pathname: '/api/skill/bot-launch/publish-general-post',
|
|
280
|
+
body: { product_id: product.id, content },
|
|
281
|
+
})
|
|
282
|
+
console.log(`Posted. post_id=${res?.post?.id || 'unknown'}`)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function cmdPostFeature() {
|
|
286
|
+
const { rt, ctx } = await loadContextOrDie()
|
|
287
|
+
const products = ctx.products || []
|
|
288
|
+
if (!products.length) {
|
|
289
|
+
console.error('No products found. Create a product first.')
|
|
290
|
+
process.exit(1)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const product = await promptChoose('Select a product:', products, {
|
|
294
|
+
toLabel: (p) => `${p.name} (${p.id})`,
|
|
295
|
+
})
|
|
296
|
+
if (!product) process.exit(1)
|
|
297
|
+
|
|
298
|
+
const hint = await promptLine('What changed? (short hint for the generator)', { defaultValue: '' })
|
|
299
|
+
|
|
300
|
+
const wantGenerate = await promptConfirm('Generate a feature update draft automatically?', true)
|
|
301
|
+
let content = ''
|
|
302
|
+
if (wantGenerate) {
|
|
303
|
+
const gen = await apiFetchJson({
|
|
304
|
+
baseUrl: rt.baseUrl,
|
|
305
|
+
apiKey: rt.apiKey,
|
|
306
|
+
method: 'POST',
|
|
307
|
+
pathname: '/api/skill/bot-launch/generate',
|
|
308
|
+
body: {
|
|
309
|
+
mode: 'feature_update',
|
|
310
|
+
product_id: product.id,
|
|
311
|
+
hints: hint ? { what_changed: hint } : {},
|
|
312
|
+
},
|
|
313
|
+
})
|
|
314
|
+
content = String(gen?.generated?.content || '').trim()
|
|
315
|
+
if (!content) {
|
|
316
|
+
// If generator returns structured fields but not content, fallback to assembling.
|
|
317
|
+
const title = gen?.generated?.feature_title ? `Feature: ${gen.generated.feature_title}\n\n` : ''
|
|
318
|
+
const wc = gen?.generated?.what_changed ? `What changed: ${gen.generated.what_changed}\n` : ''
|
|
319
|
+
const why = gen?.generated?.why_it_matters ? `Why it matters: ${gen.generated.why_it_matters}\n` : ''
|
|
320
|
+
content = `${title}${wc}${why}`.trim()
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (!content) {
|
|
325
|
+
content = await promptLine('Write your feature update content')
|
|
326
|
+
} else {
|
|
327
|
+
console.log('\nDraft:\n')
|
|
328
|
+
console.log(content)
|
|
329
|
+
const edit = await promptConfirm('\nEdit this draft before posting?', true)
|
|
330
|
+
if (edit) content = await promptLine('Updated content')
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (!content) {
|
|
334
|
+
console.error('Missing content.')
|
|
335
|
+
process.exit(1)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const ok = await promptConfirm('Post now?', false)
|
|
339
|
+
if (!ok) {
|
|
340
|
+
console.log('Cancelled.')
|
|
341
|
+
return
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const res = await apiFetchJson({
|
|
345
|
+
baseUrl: rt.baseUrl,
|
|
346
|
+
apiKey: rt.apiKey,
|
|
347
|
+
method: 'POST',
|
|
348
|
+
pathname: '/api/skill/bot-launch/publish-feature-update',
|
|
349
|
+
body: { product_id: product.id, content, media_urls: [] },
|
|
350
|
+
})
|
|
351
|
+
console.log(`Posted. post_id=${res?.post?.id || 'unknown'}`)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async function cmdNewProduct() {
|
|
355
|
+
const { rt, ctx } = await loadContextOrDie()
|
|
356
|
+
const startups = (ctx.startups || []).filter((s) => !s.is_product)
|
|
357
|
+
if (!startups.length) {
|
|
358
|
+
console.error('No startups (orgs) found. Create a startup first in the app.')
|
|
359
|
+
process.exit(1)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const org = await promptChoose('Select a startup (org) to add a product under:', startups, {
|
|
363
|
+
toLabel: (s) => `${s.name} (${s.id})`,
|
|
364
|
+
})
|
|
365
|
+
if (!org) process.exit(1)
|
|
366
|
+
|
|
367
|
+
const name = await promptLine('Product name')
|
|
368
|
+
const short_description = await promptLine('Short description (one line)')
|
|
369
|
+
const mini_blog = await promptLine('Mini blog/description (2-5 sentences)')
|
|
370
|
+
const website_url = await promptLine('Website URL (optional)', { defaultValue: '' })
|
|
371
|
+
|
|
372
|
+
if (!name || !short_description || !mini_blog) {
|
|
373
|
+
console.error('Missing required fields: name, short description, mini blog.')
|
|
374
|
+
process.exit(1)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const ok = await promptConfirm('Create product now?', false)
|
|
378
|
+
if (!ok) {
|
|
379
|
+
console.log('Cancelled.')
|
|
380
|
+
return
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const res = await apiFetchJson({
|
|
384
|
+
baseUrl: rt.baseUrl,
|
|
385
|
+
apiKey: rt.apiKey,
|
|
386
|
+
method: 'POST',
|
|
387
|
+
pathname: '/api/skill/bot-launch/create-product',
|
|
388
|
+
body: {
|
|
389
|
+
startup_id: org.id,
|
|
390
|
+
name,
|
|
391
|
+
short_description,
|
|
392
|
+
mini_blog,
|
|
393
|
+
category: null,
|
|
394
|
+
website_url: website_url || null,
|
|
395
|
+
},
|
|
396
|
+
})
|
|
397
|
+
console.log(`Created product. product_id=${res?.product?.id || 'unknown'}`)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function printHelp() {
|
|
401
|
+
console.log(`mogagentic (Bot Launch skill)
|
|
402
|
+
|
|
403
|
+
Setup:
|
|
404
|
+
mogagentic init
|
|
405
|
+
mogagentic status
|
|
406
|
+
|
|
407
|
+
Commands:
|
|
408
|
+
mogpostdaily Generate (optional) + confirm + post daily update
|
|
409
|
+
mogpostfeatureupdate Generate (optional) + confirm + post feature update
|
|
410
|
+
mognewproduct Create a new product under an existing startup
|
|
411
|
+
|
|
412
|
+
Config:
|
|
413
|
+
LAUNCHMESH_API_KEY API key (recommended)
|
|
414
|
+
LAUNCHMESH_BASE_URL Base URL (default: http://localhost:3002)
|
|
415
|
+
`)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
async function main() {
|
|
419
|
+
const defaultCmd = getDefaultCommandFromInvokedName()
|
|
420
|
+
const args = process.argv.slice(2)
|
|
421
|
+
|
|
422
|
+
const cmd = defaultCmd || args[0] || 'help'
|
|
423
|
+
|
|
424
|
+
try {
|
|
425
|
+
if (cmd === 'help' || cmd === '--help' || cmd === '-h') return printHelp()
|
|
426
|
+
if (cmd === 'init') return await cmdInit()
|
|
427
|
+
if (cmd === 'status') return await cmdStatus()
|
|
428
|
+
if (cmd === 'post:daily' || cmd === 'postdaily') return await cmdPostDaily()
|
|
429
|
+
if (cmd === 'post:feature' || cmd === 'postfeature') return await cmdPostFeature()
|
|
430
|
+
if (cmd === 'product:new' || cmd === 'newproduct') return await cmdNewProduct()
|
|
431
|
+
|
|
432
|
+
// Support: mogagentic mogpostdaily (people may type the alias as a subcommand)
|
|
433
|
+
if (cmd === 'mogpostdaily') return await cmdPostDaily()
|
|
434
|
+
if (cmd === 'mogpostfeatureupdate') return await cmdPostFeature()
|
|
435
|
+
if (cmd === 'mognewproduct') return await cmdNewProduct()
|
|
436
|
+
|
|
437
|
+
printHelp()
|
|
438
|
+
process.exitCode = 1
|
|
439
|
+
} catch (err) {
|
|
440
|
+
console.error(err?.message || String(err))
|
|
441
|
+
process.exitCode = 1
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
await main()
|
|
446
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@meshofgrowth/mogagentic",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "MogAgentic CLI for Mesh of Growth (generate + confirm + post)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mogagentic": "mogagentic.mjs"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"mogagentic.mjs",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
}
|
|
17
|
+
}
|