Skip to content

feat(pgpm): init refreshes stale template cache, scaffolds in place, fixes RLS testing docs - #1840

Merged
pyramation merged 2 commits into
mainfrom
feat/pgpm-init-dx
Sep 17, 2026
Merged

pyramation merged 2 commits into
mainfrom
feat/pgpm-init-dx

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

Addresses the constructive side of constructive-io/constructive-planning#2077 (items 1, 3, 5). The pgpm-boilerplates side (CI matrix discovery + template smoke test) is a separate PR.

Stale template cache. genomic's TemplateScaffolder caches a shallow clone (with .git removed) and only re-clones after a 1-day TTL, so a template change never shows up until the entry expires. New refreshTemplateCache() in @pgpmjs/core runs before every inspectTemplate/scaffoldTemplate in pgpm init:

refreshTemplateCache({ templateRepo, branch, toolName, force }): TemplateSourceInfo
// git ls-remote <url> <branch|HEAD>  (15s timeout, memoized per process)
//   sha != <metadata>/<key>.ref.json.sha  ||  force  ||  cache exists w/o sidecar
//     -> CacheManager.clear(key)   (next inspect/scaffold re-clones)
//   ls-remote fails / PGPM_TEMPLATE_OFFLINE set -> { offline: true }, cache kept
  • pgpm init --refresh / --no-cache forces the re-clone.
  • Each scaffold prints the resolved source, e.g. using constructive-io/pgpm-boilerplates@HEAD (abc1234, fetched 2m ago) (describeTemplateSource), with (offline, using cached copy) when the check couldn't reach the remote.
  • Local template paths are untouched.

Nested scaffold dir. pgpm init workspace --name foo run inside an empty directory (or one containing only .git) already named foo now scaffolds in place instead of creating foo/foo (isScaffoldableInPlace). The trailing cd ./… hint is omitted when the target is cwd.

Non-TTY. isNoTtyRequested / detectNoTtyFromProcess also treat process.stdin.isTTY !== true as non-interactive, so piped/CI invocations fail fast on missing required answers instead of hanging on a prompt. Help text notes that non-interactive runs must answer every question via flags.

Docs. pgpm skill testing.md: setContext takes an object (db.setContext({ role: 'authenticated', 'jwt.claims.user_id': 'user-1' })), new "RLS testing" section with the schema/table/sequence grants needed before RLS is reached, and a note that pg/db are separate connections. cli.md: --refresh and pointer to the non-interactive flag table.

Tests: pgpm/core/__tests__/template-refresh.test.ts (bare repo fixture: refresh on new remote commit, no-op when unchanged, force, offline, describe format), in-place workspace init test, tty test.

Link to Devin session: https://app.devin.ai/sessions/dd4055c50bcf4b1e8e604211038aaa82
Open in Devin Desktop: https://app.devin.ai/desktop/session/dd4055c50bcf4b1e8e604211038aaa82?variant=devin
Requested by: @pyramation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@tenki-reviewer

tenki-reviewer Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

Review complete. 🟡 1 medium

💬 Inline comments (1)


This PR enhances pgpm init with template cache refresh/invalidation, offline fallback, and in-place scaffolding. It refactors template-scaffold.ts to add a memoized refreshTemplateCache and describeTemplateSource, and updates the CLI init commands to detect TTY via process.stdin.isTTY and scaffold into the current directory when it matches the module slug and is empty. Docs, tests, and utility helpers are updated to match.

Files Change
pgpm/core/src/core/template-scaffold.ts + template-refresh.test.ts Adds remote-template cache refresh, stale-cache invalidation via remoteSha, offline fallback, and memoized refresh with new tests.
pgpm/cli/src/commands/init/* + utils/tty.ts Wires new refresh flags, improves TTY detection, and adds in-place scaffolding for empty matching directories.
pgpm/cli/__tests__/* + pgpm/skills/references/* Adds init/tty tests and updates CLI/testing reference docs.

Reviewed commit: 8611bf7

@tenki-reviewer tenki-reviewer Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds remote-template cache refresh and in-place scaffolding to the pgpm init command, with TTY detection and template-source cache invalidation improvements.

Key findings

Comment on lines +232 to +242
} catch {
const info = {
repo: url,
branch,
refreshed: false,
offline: true,
local: false,
};
templateRefreshMemo.set(memoKey, info);
return info;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 bug · medium

Folding every ls-remote failure into offline

In refreshTemplateCache the catch around git ls-remote (pgpm/core/src/core/template-scaffold.ts:232) converts every failure — network outage, auth error, missing git, or a nonexistent branch — into offline: true / refreshed: false and returns without clearing the stale clone. Callers like pgpm init then print using <repo> (offline, using cached copy) and scaffold from the old cache.

The explicit offline path is the PGPM_TEMPLATE_OFFLINE branch (lines 210-220); folding every other error into it means a mistyped branch or a transient fetch failure is silently reported as offline, and the result is memoized for the process lifetime, so an explicit --refresh silently serves stale content instead of failing loudly.

📋 Prompt for AI Agents

In pgpm/core/src/core/template-scaffold.ts lines 222-242, the try/catch around execFileSync('git', ['ls-remote', ...]) swallows every failure into an offline: true, refreshed: false result and memoizes it, so a forced --refresh silently serves the stale clone and the process never retries. Change the catch so it only treats a failure as offline when process.env.PGPM_TEMPLATE_OFFLINE is set (that path is already handled at lines 210-220); for any other failure, throw a descriptive error containing the repo/branch and underlying message, and do not memoize a permanent offline result for transient failures. Before returning an offline success, also confirm fs.existsSync(path.join(cm.getReposDir(), key)) so describeTemplateSource does not claim 'using cached copy' when no clone exists.

@pyramation
pyramation merged commit 635a587 into main Sep 17, 2026
20 checks passed
@pyramation
pyramation deleted the feat/pgpm-init-dx branch September 17, 2026 03:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant