245 Commits

Author SHA1 Message Date
7946099f72
f(ai): add WithFormat to change format without changing Generate signature 2026-08-17 17:28:11 -06:00
4e60fc6597
f(ai): add WithModel to change model on-the-fly 2026-08-17 17:28:11 -06:00
a84cf639ed
f(ai): fix interface / add type guard 2026-08-17 17:28:11 -06:00
613cdfa312
feat(ai): add Ollama and OpenAI helpers 2026-08-17 17:28:11 -06:00
1f2e264712
feat: add cmd/smbtest for debugging smb connection issues 2026-08-17 17:28:11 -06:00
89281ece5a
ref(cmd/monorelease): fix tag and version output, start flagset 2026-08-17 17:28:11 -06:00
e315659aec
WIP: feat(cmd/monorelease): fix versioning 2026-08-17 17:28:11 -06:00
90d519cc3a
WIP: feat(cmd/monorelease): better table 2026-08-17 17:28:11 -06:00
039e56cd25
WIP: feat(cmd/monorelease): show table 2026-08-17 17:28:11 -06:00
232b12372e
WIP: feat(cmd/monorelease): show bins 2026-08-17 17:28:11 -06:00
bd04c811e3
WIP: feat: add cmd/monorelease for checking version info 2026-08-17 17:28:11 -06:00
f7d30e4dcf
feat: add tools/gitver for monorepo versioning 2026-08-17 17:28:11 -06:00
d80c4ffab8
feat: add ./scripts/concat-for-context.sh to reduce total file count 2026-08-17 17:28:11 -06:00
27e3b05a10
doc: add PROMPT.md for Ai context 2026-08-17 17:28:11 -06:00
6dbe89ff02
feat: add cmd/api-example as server boilerplate 2026-08-17 17:28:11 -06:00
e178c86945
f: cmd/cli-example 2026-08-17 17:28:11 -06:00
2c99785ec3
feat: add cmd/cli-example for reference, and Ai context 2026-08-17 17:28:11 -06:00
5f2d7a9c9a
fix(sqlmigrate): address high-severity review findings
- Collect: replace WalkDir with ReadDir to avoid subdirectory recursion
  and the risk of duplicate filenames silently overwriting each other
- shmigrate: check scanner.Err() after reading migrations log
- shmigrate: shell-quote all paths in generated scripts to prevent
  shell injection via migration filenames
- shmigrate: wrap errors with ErrQueryApplied sentinel for consistency
  with DB backends
- mustInit: remove stale err check that could never fire
- mustInit: fix swapped error messages (read vs create)
2026-08-17 17:28:11 -06:00
484b6bc11a
fix(io/transform/gsheet2csv): use safe defaults for http client io/transform/gsheet2csv/v1.0.6 2026-08-17 17:25:45 -06:00
c66c4a8de4
ref!(https): rewrite with latest best practices, for publish https/v0.9.0 2026-08-17 15:15:09 -06:00
71671b7852
fix(sql-migrate): add missing period 'basename+".up.sql"' 2026-07-07 16:40:37 -06:00
bc3fb945af
chore(sql-migrate): lint 2026-07-07 16:30:13 -06:00
3e2b055c88
fix(sql-migrate): strip id\t prefix when parsing migrations.log
parseAndFixupBatches treated every line as a migration name, but the
new log format uses id\tname (tab-separated). This caused fixupMigration
to look for non-existent files like '05aba66a\t2026-06-03-003000_team-create.up.sql'.

Align with shmigrate.Applied() which already handles both formats.
cmd/sql-migrate/v2.2.5
2026-06-04 22:08:22 -06:00
a408dc890b
feat(sync/dataset): generic hot-swap refresh with atomic.Pointer
Coordinates a Set of Fetchers (each producing a typed dataset) so a
running server can swap to fresh data without locks on the read path.
Readers go through atomic.Pointer; Load/Close are mutex-serialized so
concurrent reloads can't race. Add and AddInitial register fetchers
before the first Load.
sync/dataset/v0.5.0
2026-05-26 22:46:04 -06:00
584061744b
feat(geoip-update): CLI for downloading GeoLite2 databases via conditional HTTP GET
- Downloads all editions listed in a GeoIP.conf
  - Flags: -config, -dir, -fresh-days, -base-url (override
    DownloadBase for custom mirror/proxy), -V/--version, -help
  - Version output shows name, version, commit, date, copyright and
    license (populated via ldflags at build time)
  - Uses Basic auth with split credential encoding for readability
  - ETag/Last-Modified caching via httpcache
net/geoip/v0.5.0 ‎net/geoip/v0.5.0
2026-05-26 22:04:22 -06:00
2f33b5e430
feat(net/geoip): MaxMind GeoLite2 reader with auto-update
Add a Go package for reading MaxMind GeoLite2 City and ASN databases.

  - ParseConf: parses geoipupdate-style config files (AccountID,
    LicenseKey, EditionIDs, DatabaseDirectory)
  - Databases: holds open City + ASN readers; Open() loads both
    editions from a directory, extracting .mmdb from tar.gz in memory
    without writing to disk
  - FindTarGz: resolves cache paths, preferring *_LATEST.tar.gz
  - Lookup: returns city, region, country, ASN, and AS org for an IP
  - DownloadBase constant, TarGzName helper, DefaultConfPaths and
    DefaultCacheDir conveniences

Integration tests verify download and conditional-get freshness.
2026-05-26 22:04:17 -06:00
ecba24973b
chore: add LOCAL.md and agents/ to .gitignore 2026-05-26 21:59:57 -06:00
04b8bb406d
feat(net/httpcache): ETag/Last-Modified HTTP cache
Conditional GET cache for periodic data sources. Persists ETag and
Last-Modified to a .meta sidecar so 304s survive process restarts.
Two independent rate-limit gates (MaxAge file-mtime, MinInterval
in-memory). Body cap via MaxBytes defends against fill-disk from a
hostile upstream or redirect target. Authorization (and any
caller-supplied) headers stripped on every redirect hop. Userinfo
in URL is redacted from error messages.
net/httpcache/v0.5.0
2026-05-26 01:27:20 -06:00
dddfdd392c
feat(net/ipgate): IP allowlist/blocklist via PrefixSet and DomainSet
PrefixSet: git-backed CIDR files via gitshallow, refreshed every 47 min.
DomainSet: takes pre-parsed (staticPrefixes, domains []string); resolves
hostnames every 5 min, retaining stale IPs on failure. Both use
atomic-swapped ipcohort.Cohort for lock-free reads.

ParseDomainSet(RecordReader) parses rows into prefixes and hostnames;
caller constructs the record reader (e.g. csv.Reader with delimiter,
comment char). RecordReader interface is satisfied by *csv.Reader.

commaify uses plain string concat (integers max ~7 groups).
net/ipgate/v0.5.2
2026-05-22 12:23:35 -04:00
d472c00ef1
feat(net/dnsresolver): parallel DNS resolver with fallback servers
Resolves A, CNAME chain, and SRV records via miekg/dns. Queries all
configured servers in parallel and returns the first success. Falls
back to OpenDNS/Cloudflare/Quad9 when /etc/resolv.conf is absent or empty.
net/dnsresolver/v0.5.0
2026-05-22 11:16:22 -04:00
1db21be047
fix(gitshallow): depth-3 windowed fetch with low-memory GC
- Default depth changed from 1 to 3: enough overlap for delta
  compression even if the remote pushes 2 commits between fetches
- Keep --depth on fetch (not just clone) so shallow stays windowed
- GCInterval default changed: 0 now means every fetch (was disabled)
- GC sequence: reflog expire → prune → gc --prune=now
  Expire makes old shallow entries' objects unreachable, prune removes
  them cheaply (5MB RSS), then gc delta-compresses what remains (~10MB)
- Only GC when HEAD actually changed (skip no-op fetches)
- Dropped GCAggressive (no benefit in shallow clones)
net/gitshallow/v0.9.1
2026-05-11 23:45:10 -06:00
1dacbdd8f7
feat(net/gitshallow): incremental shallow git-repo mirroring
Periodically-updated shallow clone for repos used as a data source.
One Fetch verb (clone-or-pull-or-skip) drives both the Fetcher
interface and per-File handles. MaxAge gates on FETCH_HEAD mtime so
short-lived CLI invocations don't hammer the remote across process
restarts; an in-memory 1s debounce coalesces concurrent Fetches.
Hardens git invocations against argument injection: validates
branch/ref shape, rejects URLs starting with '-', and uses '--'
separators before positional args. Userinfo in URL is redacted from
error output (both args echo and git's own messages).
net/gitshallow/cmd/git-shallow-sync/v0.9.0 net/gitshallow/v0.9.0
2026-05-02 16:15:54 -06:00
bea4c3de0a
feat(net/ipcohort): IP block/allow cohort filter
IPv4 host + CIDR membership testing backed by sorted /32 binary search
and a linear scan of CIDR ranges. CSV/text loader with bounded reads
(maxBytes is required so callers pick a limit appropriate to their
input source — 1 KB allowlists through 100+ MB threat feeds). Returns
errors for unparseable IPs so callers can decide fail-open vs
fail-closed; partial cohorts are returned alongside parse errors.
net/ipcohort/cmd/ipcohort-contains/v0.9.0 net/ipcohort/v0.9.0
2026-05-02 15:41:38 -06:00
c2f5dbeeca
doc(skills): pgmigrate clarificaton 2026-04-19 19:25:52 -06:00
65432d7c29
database/sqlmigrate/pgmigrate: add Schema field for qualified _migrations table
Add Schema string field to Migrator. When set, Applied() constructs a
schema-qualified table name via pgx.Identifier.Sanitize() rather than
the bare "_migrations". New() signature is unchanged.

Usage:
    runner := pgmigrate.New(conn)
    runner.Schema = "authz"
database/sqlmigrate/pgmigrate/v1.0.5
2026-04-17 03:53:32 -06:00
17bbc881a9
database/sqlmigrate: allow optional schema prefix in INSERT INTO _migrations
Update idFromInsert regex to match schema-qualified table references
such as INSERT INTO authz._migrations, in addition to the existing
unqualified INSERT INTO _migrations form.
database/sqlmigrate/v1.0.3
2026-04-17 02:30:41 -06:00
02fef67e53
fix(auth/csvauth): ID() returns Name only, not Name~hashID for tokens
Principal identity is the subject (who), not the credential instance
(which token). The hashID suffix was an internal cache fingerprint that
leaked into the public ID. Callers that need to distinguish individual
token instances must use a separate mechanism.

TSV serialization in ToRecord() still writes Name~hashID when hashID is
set so the credential file round-trips correctly.
auth/csvauth/v1.2.9
2026-04-13 22:57:21 -06:00
fbb4a14620
chore(git): ignore worktrees and vim swap files 2026-04-13 17:14:08 -06:00
4abac2a0df
feat(auth/xhubsig): X-Hub-Signature HMAC webhook verification + HTTP middleware
Verify X-Hub-Signature-256 (and SHA-1) webhook signatures. Middleware
buffers and re-exposes the body for downstream handlers. Errors honor
Accept header: TSV default (text/plain for browsers), JSON, CSV, or
Markdown — three fields (error, description, hint) with pseudocode hints.
auth/xhubsig/v0.9.0
2026-04-13 17:04:45 -06:00
aebef71a95
test(sqlmigrate): add ordering, end-to-end, rollback, and dialect-specific tests
Across all four backends:

- TestAppliedOrdering: insert rows out of order, verify Applied()
  returns them sorted by name. Guards against the ORDER BY clause
  being dropped or the query returning rows in arbitrary order.
- TestEndToEndCycle: Collect → Up → Applied → Down → Applied via
  the sqlmigrate orchestrator with real migration files. Catches
  wiring bugs between Migrator and orchestrator that the in-package
  mockMigrator tests cannot.
- TestDMLRollback: multi-statement DML migration where the last
  statement fails, verifies earlier INSERTs are rolled back. MySQL
  note: DML-only because MySQL implicitly commits DDL.

Dialect-specific:

- mymigrate TestMultiStatementsRequired: strip multiStatements=true
  from the DSN, verify ExecUp fails with a clear error mentioning
  multiStatements (rather than silently running only the first
  statement of a multi-statement migration).
- litemigrate TestForeignKeyEnforcement: verifies FK constraints
  are enforced when the DSN includes _pragma=foreign_keys(1).

Test fixture fix: cleanup closures now use context.Background()
instead of the test context. t.Context() is canceled before
t.Cleanup runs, so DB cleanup silently failed. Previously the
_migrations cleanup appeared to work because the next test's
connect() re-ran DROP TABLE at setup, but domain tables (test_*)
leaked across runs. New tests also pre-clean at setup for
self-healing after interrupted runs.
database/sqlmigrate/pgmigrate/v1.0.4 database/sqlmigrate/litemigrate/v1.0.4 database/sqlmigrate/msmigrate/v1.0.4 database/sqlmigrate/mymigrate/v1.0.4
2026-04-10 01:07:58 -06:00
28af8f49b8
test(mymigrate): use single-schema test fixture for hosted MariaDB
Hosted MariaDB users (e.g. todo_test_*) typically have access to a single
database/schema and cannot CREATE/DROP DATABASE. Drop the per-test database
isolation pattern in favour of dropping _migrations directly on entry and
exit, matching msmigrate's approach. Tests must not run concurrently
against the same DSN.
2026-04-10 00:25:29 -06:00
3402b60bc6
fix(sqlmigrate): defensive table-missing check at rows.Err() across backends
Apply the same lazy-error pattern fix to all backends, plus regression
tests that catch the bug.

pgmigrate is the confirmed-broken case (pgx/v5's Conn.Query is lazy and
surfaces 42P01 at rows.Err() once the prepared statement cache is primed).
The defensive check at rows.Err() is also added to mymigrate and msmigrate
in case their drivers exhibit similar behavior in some configurations.

litemigrate is refactored to probe sqlite_master with errors.Is(sql.ErrNoRows)
instead of string-matching the error message — SQLite returns the generic
SQLITE_ERROR code for "no such table" so a typed-error approach isn't
possible at the driver layer; the probe lets us use idiomatic errors.Is.

Tests:
- litemigrate: in-memory SQLite, runs on every go test (no infra)
- pgmigrate:   PG_TEST_URL env-gated; verified against real Postgres,
               TestAppliedAfterDropTable reproduces the agent's exact error
               message ("reading rows: ... 42P01") without the fix
- mymigrate:   MYSQL_TEST_DSN env-gated
- msmigrate:   MSSQL_TEST_URL env-gated; verified against real SQL Server

Each backend has four cases: missing table, populated table, empty table,
and table-dropped-after-cache-primed (the lazy-error scenario).
2026-04-10 00:15:06 -06:00
e11b228765
fix(pgmigrate): handle 42P01 surfaced lazily at rows.Err()
pgx/v5's Conn.Query is lazy — when the queried table doesn't exist,
the 42P01 error doesn't surface at Query() time, it surfaces at
rows.Err() after the iteration loop. The original code only checked
for 42P01 at the Query() site, so first-run migrations against an
empty database failed with:

    reading rows: ERROR: relation "_migrations" does not exist (SQLSTATE 42P01)

Apply the typed-error check at both sites via a shared helper.
2026-04-10 00:01:55 -06:00
0c1eb1f125
feat(skills): add sqlmigrate skill index and per-database skills
Index skill (use-sqlmigrate) plus focused skills for CLI usage, Go
library integration, and per-database conventions (PostgreSQL,
MySQL/MariaDB, SQLite, SQL Server).
2026-04-09 17:08:32 -06:00
5b3a4be3c2
fix(sql-migrate): remove local replace directives from go.mod
Replace directives pointing to local paths prevent `go install` from
working. Use published module versions (sqlmigrate v1.0.2, shmigrate
v1.0.2) so users can install with:

    go install github.com/therootcompany/golib/cmd/sql-migrate/v2@latest
cmd/sql-migrate/v2.2.4
2026-04-09 16:51:56 -06:00
dda4491c94
chore: golint fixes across all modules
Run scripts/golint: goimports, go fix, go vet, go mod tidy.
2026-04-09 14:23:33 -06:00
2256b12223
feat(sql-migrate): add sqlite and sqlcmd --sql-command aliases
- Use full flag names in command defaults (--no-align, --tuples-only, etc.)
- Add sqlite/sqlite3/lite alias for SQLite
- Add sqlcmd/mssql/sqlserver alias for SQL Server (go-sqlcmd, TDS 8.0)
- Add SQL Server help text with SQLCMD env vars and TLS docs
- Add sqlite and sqlcmd SELECT expressions for id+name migration log
2026-04-09 13:26:40 -06:00
86ff126df0 chore(litemigrate): add go.sum database/sqlmigrate/mymigrate/v1.0.3 database/sqlmigrate/litemigrate/v1.0.3 database/sqlmigrate/msmigrate/v1.0.3 database/sqlmigrate/pgmigrate/v1.0.3 2026-04-09 10:56:47 -06:00
67ad7a9fa2 fix(litemigrate,mymigrate,msmigrate): take *sql.Conn instead of *sql.DB
Same issue as pgmigrate: *sql.DB is a connection pool, so each call
may land on a different connection. Migrations need a pinned connection
for session state (SET search_path, temp tables, etc.) to persist
across sequential calls. *sql.Conn (from db.Conn(ctx)) pins one
underlying connection for its lifetime.
2026-04-09 10:56:47 -06:00
d5d1df060f fix(pgmigrate): take *pgx.Conn instead of *pgxpool.Pool
Migrations run sequentially on a single connection — a pool adds
unnecessary complexity and forces callers to create one. This also
drops the puddle/v2 and x/sync transitive dependencies.
2026-04-09 10:56:47 -06:00