Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 2 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,6 @@ Trigger manually: **Actions tab → select workflow → Run workflow**. The Dail

---

## Automate locally (macOS crontab)

```bash
crontab -e
```
```
PATH=/Users/yourname/.nvm/versions/node/v22.14.0/bin:/opt/homebrew/bin:/usr/bin:/bin
TZ=Australia/Sydney
0 17 * * * /opt/homebrew/bin/pnpm --prefix /path/to/project cleanup >> /path/to/project/data/cron.log 2>&1
```
> Mac must be awake at 5pm — GitHub Actions is more reliable for unattended runs.

---

## Commands

| Command | What it does |
Expand All @@ -103,7 +89,6 @@ TZ=Australia/Sydney
| `pnpm news` | Scrape, curate, send via Telegram — alias for `--job=news` |
| `pnpm jobs` | List every registered job with its cron schedule |
| `pnpm run dev --job=<name>` | Run any registered job by name |
| `pnpm dev` | Long-running daemon (node-cron) |
| `pnpm seed-mock` | Seed expired mock users into company DB |
| `pnpm test` | Run the unit test suite (`node:test` via `tsx`) |
| `pnpm tsc` | TypeScript type check |
Expand All @@ -124,7 +109,7 @@ src/
│ ├── curator-graph.test.ts # Unit tests for the curator retry graph
│ └── *.agent.ts # One focused agent per task
├── tools/ # DynamicStructuredTool implementations
├── jobs/ # registry.ts (add jobs here) + scheduler.ts
├── jobs/registry.ts # Job definitions + CLI dispatch (add jobs here)
├── storage/ # PostgreSQL queries (own-db + company-db)
├── schemas/index.ts # Zod schemas + shared types (TrendingRepo, CuratedRepo, ...)
└── index.ts # Entry point + CLI flags
Expand All @@ -139,7 +124,7 @@ src/
|---|---|
| `kpi` | Daily GitHub activity records |
| `diary` | AI-generated daily KPI reports |
| `cleanup_log` | Company DB cleanup history |
| `cleanup_log` | Company DB cleanup history (Functionality no longer supported) |
| `github_trending` | Trending repos with summaries, tags, sent status |

---
Expand Down
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,11 @@
"@octokit/rest": "^22.0.1",
"dotenv": "^17.3.1",
"langchain": "^1.2.37",
"node-cron": "^4.2.1",
"pg": "^8.20.0",
"zod": "^4.3.6"
},
"devDependencies": {
"@types/node": "^25.5.0",
"@types/node-cron": "^3.0.11",
"@types/pg": "^8.20.0",
"prettier": "^3.8.1",
"ts-node": "^10.9.2",
Expand Down
17 changes: 0 additions & 17 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/agent/curator-graph.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { runCuratorGraph } from './curator.graph.ts'
import { TrendingRepo } from '../tools/trending-scrape.tool.ts'
import { TrendingRepo } from '../schemas/index.ts'

const sampleRepos: TrendingRepo[] = [
{ name: 'foo/bar', url: 'https://github.com/foo/bar', description: 'test repo', language: 'typescript', stars: 100, todayStars: 5 },
Expand Down
6 changes: 3 additions & 3 deletions src/agent/curator.graph.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { StateGraph, StateSchema, START, END } from '@langchain/langgraph'
import { z } from 'zod'
import { TrendingRepoSchema, type CuratedRepo } from '../schemas/index.js'
import { TrendingRepoOutputSchema, type CuratedRepo } from '../schemas/index.js'

import { parseJson } from './utils.ts'
import { TrendingRepo } from '../tools/trending-scrape.tool.ts'
import { TrendingRepo } from '../schemas/index.ts'

const CuratedRepoOutputSchema = z.object({ repos: z.array(TrendingRepoSchema) })
const CuratedRepoOutputSchema = z.object({ repos: z.array(TrendingRepoOutputSchema) })

export type CurateFn = (repos: TrendingRepo[], feedback?: string) => Promise<string>
export type CuratorResult = { curated: CuratedRepo[] | null; error: string | null }
Expand Down
6 changes: 3 additions & 3 deletions src/agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { manualKpiAgent } from './manual-kpi.agent.js'
import { diaryAgent } from './diary.agent.js'
import { trendingCuratorAgent } from './news-curator.agent.js'
import { trendingTelegramAgent } from './news-telegram.agent.js'
import { trendingScrapeTool, type TrendingRepo } from '../tools/trending-scrape.tool.js'
import { trendingScrapeTool } from '../tools/trending-scrape.tool.js'
import { saveKpiRecord, saveTrendingRepos, getRecentRepoNames } from '../storage/own-db.js'
import { sectionLogger } from '../utils/logger.js'
import { notifyError, parseJson, toolOutput } from './utils.ts'
import { AgentResult, CuratedRepo } from '../schemas/index.ts'
import { AgentResult, CuratedRepo, TrendingRepo } from '../schemas/index.ts'
import { runCuratorGraph } from './curator.graph.ts'

export class WorkCoordinator {
Expand Down Expand Up @@ -315,5 +315,5 @@ export class WorkCoordinator {
}
}

// ── Named exports for backwards compatibility with index.ts and scheduler.ts ───
// ── Named exports for backwards compatibility with index.ts and registry.ts ───
export const { runCleanup, runDailyJobs, runNewsAgent } = WorkCoordinator
7 changes: 5 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'dotenv/config'
import { initDb } from './storage/own-db.js'
import { startScheduler } from './jobs/scheduler.js'
import { jobs, findJobByCliArg } from './jobs/registry.js'

function printJobs(): void {
Expand Down Expand Up @@ -38,7 +37,11 @@ async function main(): Promise<void> {
process.exit(0)
}

startScheduler()
// No recognized args — scheduling is handled by GitHub Actions, not an
// in-process daemon. Point the user at the actual options instead.
console.log('No job specified. Use --job=<name> to run one, or --list-jobs to see all.\n')
printJobs()
process.exit(0)
}

main().catch((err) => {
Expand Down
5 changes: 3 additions & 2 deletions src/jobs/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { DEFAULT_CRONJOB_TIME, DEFAULT_CRONJOB_TIMEZONE, NEWS_CRON_TIME } from '
*
* - `name` stable identifier — used by CLI (`--job=<name>`) and logs
* - `description` one-line human-readable summary shown by `--list-jobs`
* - `schedule` cron expression for the in-process scheduler. Omit for
* interactive/manual-only jobs that are never auto-scheduled
* - `schedule` cron expression, shown by `--list-jobs` — informational only;
* the actual schedule lives in .github/workflows/*.yml. Omit
* for interactive/manual-only jobs that are never scheduled
* - `timezone` IANA timezone name (defaults to DEFAULT_CRONJOB_TIMEZONE)
* - `run` the actual pipeline — hand-written, not generalized
*/
Expand Down
33 changes: 0 additions & 33 deletions src/jobs/scheduler.ts

This file was deleted.

16 changes: 12 additions & 4 deletions src/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const CleanupResultSchema = z.object({
})

// --- GitHub Trending ---
export const TrendingRepoSchema = z.object({
export const TrendingRepoOutputSchema = z.object({
repo_name: z.string(),
url: z.string(),
description: z.string(),
Expand All @@ -72,22 +72,30 @@ export const TrendingRepoSchema = z.object({
tags: z.array(z.string()),
})

export const TrendingRepoLogSchema = TrendingRepoSchema.extend({
export const TrendingRepoLogSchema = TrendingRepoOutputSchema.extend({
sent: z.boolean(),
created_at: z.string(),
updated_at: z.string(),
})

// TypeScript types inferred from schemas
export interface TrendingRepo {
name: string // e.g. "owner/repo"
url: string
description: string
language: string
stars: number
todayStars: number
}

export type GitHubDigest = z.infer<typeof GitHubDigestSchema>
export type GithubKpiInput = z.infer<typeof GithubKpiInputSchema>
export type ManualKpiInput = z.infer<typeof ManualKpiInputSchema>
export type KpiRecord = z.infer<typeof KpiRecordSchema>
export type DiaryEntry = z.infer<typeof DiaryEntrySchema>
export type CleanupResult = z.infer<typeof CleanupResultSchema>
export type TrendingRepo = z.infer<typeof TrendingRepoSchema>
export type TrendingRepoLog = z.infer<typeof TrendingRepoLogSchema>

export type CuratedRepo = z.infer<typeof TrendingRepoSchema>
export type CuratedRepo = z.infer<typeof TrendingRepoOutputSchema>

export type AgentResult = { messages: Array<{ _getType?: () => string; content: unknown }> }
10 changes: 1 addition & 9 deletions src/tools/trending-scrape.tool.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import { DynamicStructuredTool } from '@langchain/core/tools'
import { z } from 'zod'

export interface TrendingRepo {
name: string // e.g. "owner/repo"
url: string
description: string
language: string
stars: number
todayStars: number
}
import { TrendingRepo } from '../schemas/index.ts'

function parseTrendingHtml(html: string): TrendingRepo[] {
const repos: TrendingRepo[] = []
Expand Down
Loading