Skip to content

Instantly share code, notes, and snippets.

View B4nan's full-sized avatar

Martin Adámek B4nan

View GitHub Profile
@B4nan
B4nan / install-deps.sh
Created August 11, 2026 15:09
Installing deps on SessionStart hook for worktrees
#!/usr/bin/env bash
# SessionStart hook — keep node deps in sync with the lockfile. Covers both the fresh
# worktree (node_modules absent) and the REUSED worktree whose node_modules was installed
# against an older lockfile (real case: apify-sdk-js Aug 2026, June install vs a same-day
# crawlee bump → phantom type errors). NON-BLOCKING: the install is spawned fully detached
# and the hook returns immediately, so session start is never held up.
[ -f package.json ] || exit 0 # only node projects
# Freshness check: a stamp with the lockfile hash is written after each successful install.
@B4nan
B4nan / block-git-stash.sh
Created August 11, 2026 15:06
Blocking git stash hook (for worktrees)
#!/bin/bash
# Block Claude from creating/applying git stashes. The stash stack is shared across all
# worktrees of a repo, so `stash`/`pop`/`apply` can mix up entries between concurrent
# sessions. `list`/`show`/`drop` stay allowed: they are the sanctioned recovery path.
input=$(cat)
cmd=$(printf '%s' "$input" | jq -r '.tool_input.command // empty' 2>/dev/null)
[ -z "$cmd" ] && exit 0
# Every `git stash [subcommand]` occurrence, so chains like `cd x && git stash pop` are caught.
@Entity()
export class Author {
// only `name` will be considered as required for `em.create()`
[OptionalProps]?: 'createdAt' | 'updatedAt';
@PrimaryKey()
id!: number;
@Property({ defaultRaw: 'current_timestamp()' })
const god = em.create(Author, {
name: 'God', // validates required properties
email: 'god@heaven.io',
books: [{
title: 'Bible, part 1',
tags: [{ name: 'old' }, { name: 'bestseller' }],
}],
}, { persist: true }); // we can enable this globally via `persistOnCreate: true`
await em.flush();
const book = {} as Book;
const dto = wrap(book).toObject(); // EntityDTO<Book>
// this is now possible, but with the PK union type, we would need to type cast all the time
const name = dto.author.name;
import { expr } from '@mikro-orm/core';
const res1 = await em.find(Book, {
// the type argument is optional, use it to get autocomplete on the entity properties
[expr<Book>(['price', 'createdAt'])]: { $lte: [100, new Date()] },
});
// will issue query similar to this:
// select `b0`.* from `book` as `b0` where (`b0`.`price`, `b0`.`created_at`) <= (?, ?)
const book = await em.findOneOrFail(Book, 1, { populate: ['author'] });
// update existing book's author's name
wrap(book).assign({
author: {
name: 'New name...',
},
}, { updateByPrimaryKey: false });
const book = await em.findOneOrFail(Book, 1, { populate: ['author'] });
// update existing book's author's name
wrap(book).assign({
author: {
id: book.author.id,
name: 'New name...',
},
});
const res1 = await em.createQueryBuilder(Publisher).insert({
name: 'p1',
type: PublisherType.GLOBAL,
});
// res1 is of type `QueryResult<Publisher>`
console.log(res1.insertId);
const res2 = await em.createQueryBuilder(Publisher)
.select('*')
.where({ name: 'p1' })
@Entity()
export class Book {
@ManyToOne(() => Author, { wrappedReference: true })
author!: IdentifiedReference<Author>;
constructor(authorId: number) {
this.author = Reference.createFromPK(Author, authorId);
}