mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
* add documentation for ai agents * docs: consolidate CLAUDE.md and CONTRIBUTING.md, add style guidelines - Refactor CLAUDE.md to reference CONTRIBUTING.md for build/test/format info - Expand CONTRIBUTING.md with comprehensive build targets, env vars, and testing - Add code style guidelines section with conventional commits - Standardize SDK prettier config to use single quotes (matching web) - Add project-level Claude Code settings to disable co-author attribution * style(sdk): apply prettier with single quotes Run prettier across sdk/base and sdk/package to apply the standardized quote style (single quotes matching web). * docs: add USER.md for per-developer TODO filtering - Add agents/USER.md to .gitignore (contains user identifier) - Document session startup flow in CLAUDE.md: - Create USER.md if missing, prompting for identifier - Filter TODOs by @username tags - Offer relevant TODOs on session start * docs: add i18n documentation task to agent TODOs * docs: document i18n ID patterns in core/ Add agents/i18n-patterns.md covering rust-i18n setup, translation file format, t!() macro usage, key naming conventions, and locale selection. Remove completed TODO item and add reference in CLAUDE.md. * chore: clarify that all builds work on any OS with Docker
100 lines
2.5 KiB
TypeScript
100 lines
2.5 KiB
TypeScript
// a,g,h,A-Z,,,,-
|
|
|
|
export function getRandomCharInSet(charset: string): string {
|
|
const set = stringToCharSet(charset)
|
|
let charIdx = Math.floor(
|
|
(crypto.getRandomValues(new Uint32Array(1))[0] / 2 ** 32) * set.len,
|
|
)
|
|
for (let range of set.ranges) {
|
|
if (range.len > charIdx) {
|
|
return String.fromCharCode(range.start.charCodeAt(0) + charIdx)
|
|
}
|
|
charIdx -= range.len
|
|
}
|
|
throw new Error('unreachable')
|
|
}
|
|
function stringToCharSet(charset: string): CharSet {
|
|
let set: CharSet = { ranges: [], len: 0 }
|
|
let start: string | null = null
|
|
let end: string | null = null
|
|
let in_range = false
|
|
for (let char of charset) {
|
|
switch (char) {
|
|
case ',':
|
|
if (start !== null && end !== null) {
|
|
if (start!.charCodeAt(0) > end!.charCodeAt(0)) {
|
|
throw new Error('start > end of charset')
|
|
}
|
|
const len = end.charCodeAt(0) - start.charCodeAt(0) + 1
|
|
set.ranges.push({
|
|
start,
|
|
end,
|
|
len,
|
|
})
|
|
set.len += len
|
|
start = null
|
|
end = null
|
|
in_range = false
|
|
} else if (start !== null && !in_range) {
|
|
set.len += 1
|
|
set.ranges.push({ start, end: start, len: 1 })
|
|
start = null
|
|
} else if (start !== null && in_range) {
|
|
end = ','
|
|
} else if (start === null && end === null && !in_range) {
|
|
start = ','
|
|
} else {
|
|
throw new Error('unexpected ","')
|
|
}
|
|
break
|
|
case '-':
|
|
if (start === null) {
|
|
start = '-'
|
|
} else if (!in_range) {
|
|
in_range = true
|
|
} else if (in_range && end === null) {
|
|
end = '-'
|
|
} else {
|
|
throw new Error('unexpected "-"')
|
|
}
|
|
break
|
|
default:
|
|
if (start === null) {
|
|
start = char
|
|
} else if (in_range && end === null) {
|
|
end = char
|
|
} else {
|
|
throw new Error(`unexpected "${char}"`)
|
|
}
|
|
}
|
|
}
|
|
if (start !== null && end !== null) {
|
|
if (start!.charCodeAt(0) > end!.charCodeAt(0)) {
|
|
throw new Error('start > end of charset')
|
|
}
|
|
const len = end.charCodeAt(0) - start.charCodeAt(0) + 1
|
|
set.ranges.push({
|
|
start,
|
|
end,
|
|
len,
|
|
})
|
|
set.len += len
|
|
} else if (start !== null) {
|
|
set.len += 1
|
|
set.ranges.push({
|
|
start,
|
|
end: start,
|
|
len: 1,
|
|
})
|
|
}
|
|
return set
|
|
}
|
|
type CharSet = {
|
|
ranges: {
|
|
start: string
|
|
end: string
|
|
len: number
|
|
}[]
|
|
len: number
|
|
}
|