Conversation
fix(sdk): restore Timestamp Kysely type for date fields
collectPathsInto only applied `paths` when `baseUrl` was also set, silently dropping alias resolution for tsconfig.json files that omit baseUrl (the standard TS 5.0+ style, resolved relative to the tsconfig directory).
…olution `baseUrl ?? "."` left non-string values (e.g. a boolean) from a malformed tsconfig.json passed straight to path.resolve(), which throws a TypeError. Fall back to "." unless baseUrl is actually a string. Also add a matching resolveSync regression test for the baseUrl- omitted case, and a changeset for the fix.
collectPathsInto resolved a child config's paths against its own directory even when baseUrl was only defined in an extended parent config, and merged inherited paths instead of replacing them the way TypeScript does when a child config defines its own paths. Verified both behaviors against tsc directly before fixing: baseUrl resolves relative to the config file that defines it, and a child's own paths replaces (not merges with) inherited paths. Propagate the effective baseUrl up through the extends recursion so a child without its own baseUrl can still use one inherited from an extended config, and clear previously collected paths before writing a config's own paths.
…exports-v2 feat(runtime): replace flat runtime subpath exports
The CI format check failed on a line oxfmt would have wrapped differently; the local pre-commit hook did not catch it. No logic change.
…verage in ts-hook collectPathsInto called targets.map() unconditionally, which throws a TypeError when a malformed tsconfig defines a paths target that is not an array (e.g. a bare string instead of a string[]). Skip such entries instead of crashing. Also add resolveSync regression tests mirroring the existing resolve tests for the extends inheritance fixes (inherited baseUrl, paths replacement), since both entry points share the same collectPathsInto/loadTsconfigPaths implementation.
…lformed-config coverage in ts-hook collectPathsInto called t.endsWith() on each paths target entry unconditionally, which throws a TypeError when a malformed tsconfig has a non-string entry in a target array (e.g. [123, "./*"]). Filter out non-string entries before mapping. Also add resolveSync tests mirroring the existing resolve tests for the malformed baseUrl/paths cases, matching the PR description's stated coverage.
…ject in ts-hook collectPathsInto cleared previously collected paths whenever compilerOptions.paths was truthy, even when it was malformed (e.g. a boolean). In that case no usable aliases could be collected either, so a valid paths object inherited from an extended config was unintentionally dropped. Only apply the replace-on-own-paths behavior when paths is a non-array object.
When a paths target array normalized to an empty list (all entries were non-string), collectPathsInto still wrote that empty array to the alias. matchTsconfigPaths() returns the first prefix-matching wildcard alias's targets unconditionally, so an empty result short- circuited resolution instead of falling through to a less specific alias with valid targets. Skip writing the alias entirely when its normalized targets are empty.
… in ts-hook TypeScript resolves inherited compilerOptions.paths against the nearest-defined baseUrl in the extends chain, independent of which config level defines paths -- verified directly against tsc: a child overriding only baseUrl (paths inherited) resolves those paths against its own baseUrl, and when no baseUrl is defined anywhere the directory of the config that defines paths is used as the fallback. collectPathsInto previously resolved each config's paths eagerly while still walking the extends chain, using only the baseUrl known at that point, so a baseUrl override at an outer (more child) level was never applied to paths inherited from an extended config. Restructure the walk: resolveEffectiveConfig now walks the chain and returns the raw (unresolved) nearest-defined baseUrl, paths, and the directory that defines those paths, without resolving any target paths. collectPathsInto resolves targets once, after the full chain has been walked, using the final effective baseUrl.
- Strip typeHookExpr/typeValidateExpr in remote snapshot comparison - Add default field comparison to areFieldsDifferent - Fix nested field validators being skipped by early continue - Update orderItem template to use oldRecord fallback in update hook - Bump codemod prereleaseUntil to V2_NEXT_4 - Add sdk-codemod patch to changeset
Use a generic parameter on the issues callback instead of (string & {})
in DottedPaths. The generic <P extends DottedPaths<...>> preserves strict
compile-time checking for invalid field names while maintaining structural
compatibility between concrete and generic TailorDBType instantiations.
fix(cli): resolve tsconfig path aliases without baseUrl in ts-hook
Version Packages (next)
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Bump sdk-codemod to 0.4.0-next.8 and eslint-plugin-sdk to 0.2.0-next.0 so exiting changesets pre mode lands on 0.4.0 / 0.2.0 instead of colliding with 0.3.0-0.3.8 / 0.1.0 already published from main. Reword the v2 baseline changeset for the stable 2.0.0 changelog.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
pnpm only links a package bin whose target file exists at install time, so pointing bin at dist/cli.js left it unlinked on clean checkouts and required stubbing the dist entry before install in erd-schema.yml. Point bin at a committed bin/cli.mjs launcher that imports dist/cli.js, matching the pattern used across major pnpm monorepos, and drop the stub steps.
changesets/action does not support executable files; pnpm sets the bit on the linked bin itself.
This comment has been minimized.
This comment has been minimized.
pnpm chmods a package's bin target +x at install time, so a committed launcher trips the working-tree -x check and dirties checkouts when tracked as 644. Track the launcher as 755 (matching what pnpm enforces) and make the guard inspect committed git object modes, exempting declared workspace bin targets, which changesets/action never commits.
This comment has been minimized.
This comment has been minimized.
The tailor bin (dist/cli/index.mjs) is now a minimal shim that enables Node's on-disk compile cache before dynamically importing the real CLI entry (renamed from index.ts to main.ts), so its full module graph is cached across invocations instead of only the lazily-loaded parts. Hand-rolled via node:module's enableCompileCache since this package is still on politty 0.11.3, which predates politty's own compile-cache helpers.
Upgrade politty to 0.11.5, which ships `politty/compile-cache` and the `politty generate-shim` CLI command. Replace the hand-rolled src/cli/index.mjs shim with a shim generated at build time by `politty generate-shim --entry ./main.mjs --program tailor`, matching the generated content's own reasoning and validation instead of a duplicated, hand-maintained implementation.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
perf(cli): enable Node's on-disk compile cache for the tailor binary
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
`executeScript()'s `arg` option is serialized internally, so a pre-stringified value (`arg: JSON.stringify(x)`, a leftover v1 pattern) double-encodes silently at runtime. A type-level fix was explored first (narrowing `arg` to reject a bare string) but any such constraint is asymmetric with createWorkflowJob's input contract, which allows a top-level string just as legitimately as number/boolean/array/object -- there is no way to distinguish an intentional string arg from an accidental JSON.stringify(x) result by type alone. Add an oxlint rule instead: it flags the exact `arg: JSON.stringify(...)` syntactic pattern (including the multi-argument pretty-print form and values held in a `const` variable) without touching executeScript's type at all, so no legitimate arg shape is ever rejected. Enable it in newly scaffolded projects alongside the existing rules. Also share `resolveValue` (previously local to no-unconditional-permit) via lib/sdk-bindings.js so both rules can follow an identifier through its const initializer.
Now that the plugin has 3 rules, splitting the 350+ line index.test.js by rule keeps each rule's coverage easier to navigate. The shared `lint`/`expectViolation`/`expectClean` helpers move to rules/test-helpers.js; index.test.js keeps only the plugin-level tests (recommended config, scaffolded template alignment). package.json's `files` previously listed the whole `rules`/`lib` directories, which would have silently shipped the new colocated test files (and the test-only helper) to npm consumers. Enumerate the actual source files instead of the directories, so what ships is explicit rather than relying on exclusion patterns.
…onst chains
Address Copilot review feedback:
- test-helpers.js spawned the platform `.bin/oxlint` shim directly,
which is `oxlint.cmd`/`oxlint.ps1` on Windows and would fail with
ENOENT there (the reviews claim that CI already exercises this on
Windows is incorrect -- "Plugin tests (Windows)" runs the unrelated
`packages/sdk` `unit-plugin` project, not this package -- but the
underlying platform gap is real for anyone running these tests on
Windows directly). Resolve the actual `bin/oxlint` script (a plain JS
file with a shebang) from the oxlint package and run it via `node`
instead, which works identically on every platform.
- Both no-execute-script-arg-stringify and no-api-prefix-in-path-pattern
resolved their options object through only one identifier hop, unlike
the arg/pathPattern values they read from it, which already follow a
chain of `const` aliases via resolveValue. Use resolveValue for the
options object too, in both rules, so a transitive alias like
`const base = {...}; const options = base; executeScript(options)`
is caught consistently.
Version Packages (next)
feat(lint): add no-execute-script-arg-stringify rule
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
v2release line (SDK2.0.0-next.xprereleases, published to thenextdist-tag) intomain, so the stable2.0.0ships frommain.v2was a long-lived branch.Pre-merge checklist
Branch sync & CI
origin/mainintov2(currently ~101 commits behind, e.g. chore(e2e): reorganize secure test skill #1794, feat: mirror field optionality in machine user attributes #1800) and resolve conflicts so this PR is mergeable.ci,generate,generate-summary,test-summary,deploy-result) — 77/77 passing as of the ERD bin launcher fix (27580bac9). Note:mainhas since advanced by 2 commits (a Renovate dependency bump, chore(deps): update anthropics/claude-code-action action to v1.0.181 #1864); re-merge before the final merge if this drifts further.Release & versioning
mainstays the 1.x release line as normal (merging its Version Packages PR, currently Version Packages #1878 → 1.84.0, is fine at any time before this PR merges —latestis still legitimately 1.x pre-merge). Themaintenance/v1cutover happens at/after this PR merges: fast-forward/mergemain's pre-merge tip intomaintenance/v1, and from that point on 1.x patches release from there instead. The duplicate1.84.0Version Packages PR onmaintenance/v1(Version Packages #1880, created by activating the release channel ahead of the actual cutover) has been closed — Version Packages #1878 is the sole live 1.x release PR again, so 1.84.0 will ship frommainas normal.changeset-release/v2→v2, currently mergeable) so no release PR is in flight when the merge happens.v1maintenance branch, kept in sync withmain's tip until the real cutover — created asmaintenance/v1@bfad6ccde(2026-07-23), since re-synced tomain@bd0b02e0c(2026-07-24). Needs one more sync tomain's actual pre-merge tip right at/after this PR merges (see the sequencing item above) — this is not a one-time setup, it must trackmainuntil the cutover moment.maintenance/v1(fc4f57d07):release.ymltriggers onmaintenance/v1and publishes with--tag v1,changeset-check.ymlskipschangeset-release/maintenance/v1, and.changeset/config.jsonbaseBranchfollows. The workflow itself is verified working (it opened Version Packages #1880, since closed as a premature duplicate of Version Packages #1878 — see the sequencing item above). The configuration stays in place ready for the real cutover; no further action needed here.pnpm changeset pre exit, which removes.changeset/pre.json) so the first release frommainpublishes the stable2.0.0to thelatestdist-tag. Decide whether to run it onv2right before merging or onmainimmediately after.pnpm codemod:resolve-pending) behaves correctly for the first stable (non-next) release. Verified inresolve-pending-boundaries.ts: a stable2.0.0with pending markers is an explicit no-op (reachesCodemodBoundary()treats pending as reached at the stableuntilboundary), any other stable version with a pending marker fails the release loudly, and no codemod currently usesV2_NEXT_PENDING(usage count 0 inregistry.ts)..changeset/v2-baseline.md— now describes the stable upgrade path (codemod command + migration guide link +v1dist-tag note) instead of thenextprerelease instructions (111518052).@tailor-platform/sdk-plugin-tailordb-erd(now0.1.0-next.2) is ready to leave prerelease — the one known blocker (bin not linking on clean installs) is fixed via the committed launcher; no other open PRs target it. Exits pre mode together with the SDK at0.1.0.main(111518052): bumpedsdk-codemodto0.4.0-next.8andeslint-plugin-sdkto0.2.0-next.0(package.json only —pre.jsonhas noinitialVersions). Dry-run verified:pre exit+changeset versionnow lands on0.4.0/0.2.0(previously0.3.0/0.1.0, colliding with0.3.0–0.3.8/0.1.0already on npm). Also confirmed no collision for the others: sdk/create-sdk exit at2.0.0, tailordb-erd plugin at0.1.0(stable not yet published).CI workflow cleanup (in this PR or immediately after merge)
v2from branch triggers:test.yml,ci.yml,release.yml,pkg-pr-new.yml,erd-schema.yml,lockfile-audit.yml,check-license.yml,template-tests.yml,skills-sync-check.yml,sdk-metrics.yml.branches: [main]filter onsdk-metrics.yml'spull_requesttrigger (removed so it ran for v2-based PRs).changeset-check.yml's skip condition back fromstartsWith(head.ref, 'changeset-release/')to the exactchangeset-release/main(it was broadened for the v2 release branch).link-check.ymlexclusion forexample/resolvers/startWorkflow.ts— the file exists onmainonce this merges.tailor-platform/actions
v1maintenance branch in tailor-platform/actions (maintenance/v1) so the v1.x line can still receive patches.v2branch intomainand publishv2.0.0(released 2026-07-21; thev2major tag tracks it).erd-schema-export/erd-schema-preview/erd-schema-commentinerd-schema.ymlto thev2.0.0release and remove the# pinact:skip-filemarker (also bumpedcheck-licenses).ACTIONS_SHA/ACTIONS_VERSIONinpackages/sdk/src/cli/commands/setup/templates.ts(and the setup workflow templates) tov2.0.0, sotailor setupscaffolds CI that invokes the renamedtailorCLI.TEMPLATE_VERSIONunchanged — pin-only update.tailor setupusers to re-run setup so scaffolded workflows move off the v1 actions.erd-schema.yml— resolved (884d6a08e): the plugin bin now resolves through a committedbin/cli.mjslauncher (the pattern used by vite/vitest/astro/nuxt/changesets), so the bin links on clean installs and both stub steps were removed. Verified with a clean-checkout install (bin links with nodist/present, even under--ignore-scripts).Docs (after the stable publish)
@nextinstall instructions with the stable tag:packages/sdk-plugin-tailordb-erd/README.md,packages/sdk/docs/cli/tailordb.md+tailordb.template.md,packages/sdk/docs/github-actions.md(then runpnpm docs:update).packages/sdk/docs/migration/v2.md(pnpm codemod:docs:update) once all codemod version boundaries are final.Repo housekeeping (after merge)
main(feat(sdk)!: extract seed execution into a CLI plugin package #1807).v2branch and announce that v2 development continues onmain.Notes
main, and the release workflow relies on the consumed-changeset history staying intact.