@take-out/scripts 0.0.93 → 0.0.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,61 +1,56 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- /**
4
- * @description Update changelog.mdx with recent git commits using Claude Code
5
- *
6
- * outputs a prompt for claude code to investigate commits and update changelog
7
- * run: bun tko update-changelog
8
- */
3
+ import { cmd } from './cmd'
9
4
 
10
- import { execSync } from 'node:child_process'
11
- import { existsSync, readFileSync } from 'node:fs'
12
- import { join } from 'node:path'
5
+ await cmd`update changelog with recent git commits`.run(async ({ path }) => {
6
+ const { execSync } = await import('node:child_process')
7
+ const { existsSync, readFileSync } = await import('node:fs')
13
8
 
14
- const CHANGELOG_PATH = join(process.cwd(), 'src/features/site/docs/changelog.mdx')
9
+ const CHANGELOG_PATH = path.join(process.cwd(), 'src/features/site/docs/changelog.mdx')
15
10
 
16
- function getLastSha(): string | null {
17
- if (!existsSync(CHANGELOG_PATH)) return null
11
+ function getLastSha(): string | null {
12
+ if (!existsSync(CHANGELOG_PATH)) return null
18
13
 
19
- try {
20
- const content = readFileSync(CHANGELOG_PATH, 'utf-8')
21
- const match = content.match(/\{\/\* last updated: ([a-f0-9]+) \*\/\}/)
22
- return match?.[1] || null
23
- } catch {
24
- return null
14
+ try {
15
+ const content = readFileSync(CHANGELOG_PATH, 'utf-8')
16
+ const match = content.match(/\{\/\* last updated: ([a-f0-9]+) \*\/\}/)
17
+ return match?.[1] || null
18
+ } catch {
19
+ return null
20
+ }
25
21
  }
26
- }
27
22
 
28
- function getLatestSha(): string {
29
- return execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim()
30
- }
23
+ function getLatestSha(): string {
24
+ return execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim()
25
+ }
31
26
 
32
- function getCommitCount(fromSha: string, toSha: string): number {
33
- try {
34
- const result = execSync(`git rev-list --count ${fromSha}..${toSha} --no-merges`, {
35
- encoding: 'utf-8',
36
- })
37
- return parseInt(result.trim(), 10)
38
- } catch {
39
- return 0
27
+ function getCommitCount(fromSha: string, toSha: string): number {
28
+ try {
29
+ const result = execSync(`git rev-list --count ${fromSha}..${toSha} --no-merges`, {
30
+ encoding: 'utf-8',
31
+ })
32
+ return parseInt(result.trim(), 10)
33
+ } catch {
34
+ return 0
35
+ }
40
36
  }
41
- }
42
37
 
43
- const lastSha = getLastSha()
44
- const latestSha = getLatestSha()
38
+ const lastSha = getLastSha()
39
+ const latestSha = getLatestSha()
45
40
 
46
- if (!lastSha) {
47
- console.info(`no last sha found in changelog, defaulting to 4 weeks ago`)
48
- }
41
+ if (!lastSha) {
42
+ console.info(`no last sha found in changelog, defaulting to 4 weeks ago`)
43
+ }
49
44
 
50
- const fromRef = lastSha || '$(git log --since="4 weeks ago" --format="%H" | tail -1)'
51
- const commitCount = lastSha ? getCommitCount(lastSha, latestSha) : '~30'
45
+ const fromRef = lastSha || '$(git log --since="4 weeks ago" --format="%H" | tail -1)'
46
+ const commitCount = lastSha ? getCommitCount(lastSha, latestSha) : '~30'
52
47
 
53
- if (commitCount === 0) {
54
- console.info('no new commits since last update')
55
- process.exit(0)
56
- }
48
+ if (commitCount === 0) {
49
+ console.info('no new commits since last update')
50
+ process.exit(0)
51
+ }
57
52
 
58
- console.info(`
53
+ console.info(`
59
54
  Update the changelog at: ${CHANGELOG_PATH}
60
55
 
61
56
  Commit range: ${fromRef}..${latestSha} (${commitCount} commits)
@@ -77,3 +72,4 @@ Archiving old entries:
77
72
  - when over 10 weeks, move oldest entries to changelog-YYYY.mdx (by year, e.g. changelog-2025.mdx)
78
73
  - add a link at the bottom of changelog.mdx: "See [2025 changes](/docs/changelog-2025)" etc (use absolute path)
79
74
  `)
75
+ })
@@ -1,183 +1,164 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- /**
4
- * @description Bootstrap project dependencies and workspace packages
5
- *
6
- * This script runs automatically during `bun install` via the prepare lifecycle.
7
- * It manages the .env file configuration with the following responsibilities:
8
- *
9
- * 1. Creates .env from .env.template if it doesn't exist
10
- * 2. Maintains an auto-generated section in .env with package metadata
11
- * 3. Currently syncs ZERO_VERSION from package.json dependencies
12
- * 4. Preserves all user-defined environment variables
13
- * 5. Creates backups before modifications for safety
14
- *
15
- * The auto-generated section is clearly marked and should not be edited manually.
16
- * All operations are defensive and will not fail the install process.
17
- */
18
-
19
- import {
20
- existsSync,
21
- readFileSync,
22
- writeFileSync,
23
- copyFileSync,
24
- renameSync,
25
- unlinkSync,
26
- } from 'node:fs'
27
- import { join } from 'node:path'
28
-
29
- import { getZeroVersion } from '@take-out/scripts/helpers/zero-get-version'
30
-
31
- const ENV_PATH = join(process.cwd(), '.env')
32
- const ENV_TEMPLATE_PATH = join(process.cwd(), '.env.template')
33
- const ENV_BACKUP_PATH = join(process.cwd(), '.env.backup')
34
- const ENV_TEMP_PATH = join(process.cwd(), '.env.tmp')
35
-
36
- // auto-generated section markers
37
- const BEGIN_MARKER = '# ---- BEGIN AUTO-GENERATED (DO NOT EDIT) ----'
38
- const END_MARKER = '# ---- END AUTO-GENERATED ----'
39
-
40
- function createEnvFromTemplate(): boolean {
41
- if (!existsSync(ENV_TEMPLATE_PATH)) {
42
- console.info('No .env.template found, skipping .env creation')
43
- return false
3
+ import { cmd } from './cmd'
4
+
5
+ await cmd`sync auto-generated env vars to local .env file`.run(async ({ path }) => {
6
+ const {
7
+ existsSync,
8
+ readFileSync,
9
+ writeFileSync,
10
+ copyFileSync,
11
+ renameSync,
12
+ unlinkSync,
13
+ } = await import('node:fs')
14
+ const { getZeroVersion } = await import('./helpers/zero-get-version')
15
+
16
+ // skip in CI environments
17
+ if (process.env.CI === 'true') {
18
+ console.info('Skipping bootstrap in CI environment')
19
+ process.exit(0)
44
20
  }
45
21
 
46
- try {
47
- copyFileSync(ENV_TEMPLATE_PATH, ENV_PATH)
48
- console.info('Created .env from .env.template')
49
- return true
50
- } catch (error) {
51
- console.error('Failed to create .env from .env.template:', error)
52
- return false
53
- }
54
- }
22
+ const ENV_PATH = path.join(process.cwd(), '.env')
23
+ const ENV_TEMPLATE_PATH = path.join(process.cwd(), '.env.template')
24
+ const ENV_BACKUP_PATH = path.join(process.cwd(), '.env.backup')
25
+ const ENV_TEMP_PATH = path.join(process.cwd(), '.env.tmp')
55
26
 
56
- function getAutoGeneratedContent(): string {
57
- const zeroVersion = getZeroVersion()
58
- if (!zeroVersion) {
59
- console.warn('Could not determine Zero version')
60
- return ''
61
- }
27
+ // auto-generated section markers
28
+ const BEGIN_MARKER = '# ---- BEGIN AUTO-GENERATED (DO NOT EDIT) ----'
29
+ const END_MARKER = '# ---- END AUTO-GENERATED ----'
62
30
 
63
- // build the auto-generated content
64
- const lines = [
65
- BEGIN_MARKER,
66
- `# Generated at: ${new Date().toISOString()}`,
67
- `ZERO_VERSION=${zeroVersion}`,
68
- END_MARKER,
69
- ]
70
-
71
- return lines.join('\n')
72
- }
73
-
74
- function updateEnvFile(): void {
75
- // ensure .env exists
76
- if (!existsSync(ENV_PATH)) {
77
- const created = createEnvFromTemplate()
78
- if (!created && !existsSync(ENV_PATH)) {
79
- // create empty .env if no template exists
80
- writeFileSync(ENV_PATH, '')
81
- console.info('Created empty .env file')
31
+ function createEnvFromTemplate(): boolean {
32
+ if (!existsSync(ENV_TEMPLATE_PATH)) {
33
+ console.info('No .env.template found, skipping .env creation')
34
+ return false
82
35
  }
83
- }
84
36
 
85
- try {
86
- // create backup
87
- if (existsSync(ENV_PATH)) {
88
- copyFileSync(ENV_PATH, ENV_BACKUP_PATH)
37
+ try {
38
+ copyFileSync(ENV_TEMPLATE_PATH, ENV_PATH)
39
+ console.info('Created .env from .env.template')
40
+ return true
41
+ } catch (error) {
42
+ console.error('Failed to create .env from .env.template:', error)
43
+ return false
89
44
  }
45
+ }
90
46
 
91
- // read current content
92
- const currentContent = readFileSync(ENV_PATH, 'utf-8')
93
-
94
- // find existing auto-generated section
95
- const beginIndex = currentContent.indexOf(BEGIN_MARKER)
96
- const endIndex = currentContent.indexOf(END_MARKER)
97
-
98
- let newContent: string
99
-
100
- if (beginIndex !== -1 && endIndex !== -1 && endIndex > beginIndex) {
101
- // replace existing auto-generated section
102
- const beforeSection = currentContent.substring(0, beginIndex).trimEnd()
103
- const afterSection = currentContent
104
- .substring(endIndex + END_MARKER.length)
105
- .trimStart()
106
-
107
- newContent = [beforeSection, getAutoGeneratedContent(), afterSection]
108
- .filter(Boolean)
109
- .join('\n\n')
110
- } else if (beginIndex !== -1 || endIndex !== -1) {
111
- // malformed markers - preserve content and append new section
112
- console.warn('Found malformed auto-generated section, appending new section')
113
- newContent = currentContent.trimEnd() + '\n\n' + getAutoGeneratedContent()
114
- } else {
115
- // no existing section - append to end
116
- const trimmedContent = currentContent.trimEnd()
117
- newContent = trimmedContent
118
- ? trimmedContent + '\n\n' + getAutoGeneratedContent()
119
- : getAutoGeneratedContent()
47
+ function getAutoGeneratedContent(): string {
48
+ const zeroVersion = getZeroVersion()
49
+ if (!zeroVersion) {
50
+ console.warn('Could not determine Zero version')
51
+ return ''
120
52
  }
121
53
 
122
- // write to temp file first (atomic operation)
123
- writeFileSync(ENV_TEMP_PATH, newContent)
54
+ const lines = [
55
+ BEGIN_MARKER,
56
+ `# Generated at: ${new Date().toISOString()}`,
57
+ `ZERO_VERSION=${zeroVersion}`,
58
+ END_MARKER,
59
+ ]
60
+
61
+ return lines.join('\n')
62
+ }
124
63
 
125
- // validate temp file
126
- const tempContent = readFileSync(ENV_TEMP_PATH, 'utf-8')
127
- if (!tempContent.includes(BEGIN_MARKER) || !tempContent.includes(END_MARKER)) {
128
- throw new Error('Generated content validation failed')
64
+ function updateEnvFile(): void {
65
+ // ensure .env exists
66
+ if (!existsSync(ENV_PATH)) {
67
+ const created = createEnvFromTemplate()
68
+ if (!created && !existsSync(ENV_PATH)) {
69
+ writeFileSync(ENV_PATH, '')
70
+ console.info('Created empty .env file')
71
+ }
129
72
  }
130
73
 
131
- // atomic replace
132
- renameSync(ENV_TEMP_PATH, ENV_PATH)
74
+ try {
75
+ // create backup
76
+ if (existsSync(ENV_PATH)) {
77
+ copyFileSync(ENV_PATH, ENV_BACKUP_PATH)
78
+ }
133
79
 
134
- if (existsSync(ENV_BACKUP_PATH)) {
135
- try {
136
- unlinkSync(ENV_BACKUP_PATH)
137
- } catch {
138
- // ignore cleanup errors
80
+ const currentContent = readFileSync(ENV_PATH, 'utf-8')
81
+
82
+ const beginIndex = currentContent.indexOf(BEGIN_MARKER)
83
+ const endIndex = currentContent.indexOf(END_MARKER)
84
+
85
+ let newContent: string
86
+
87
+ if (beginIndex !== -1 && endIndex !== -1 && endIndex > beginIndex) {
88
+ // replace existing auto-generated section
89
+ const beforeSection = currentContent.substring(0, beginIndex).trimEnd()
90
+ const afterSection = currentContent
91
+ .substring(endIndex + END_MARKER.length)
92
+ .trimStart()
93
+
94
+ newContent = [beforeSection, getAutoGeneratedContent(), afterSection]
95
+ .filter(Boolean)
96
+ .join('\n\n')
97
+ } else if (beginIndex !== -1 || endIndex !== -1) {
98
+ // malformed markers - preserve content and append new section
99
+ console.warn('Found malformed auto-generated section, appending new section')
100
+ newContent = currentContent.trimEnd() + '\n\n' + getAutoGeneratedContent()
101
+ } else {
102
+ // no existing section - append to end
103
+ const trimmedContent = currentContent.trimEnd()
104
+ newContent = trimmedContent
105
+ ? trimmedContent + '\n\n' + getAutoGeneratedContent()
106
+ : getAutoGeneratedContent()
139
107
  }
140
- }
141
108
 
142
- console.info('Updated .env auto-generated section')
143
- } catch (error) {
144
- console.error('Failed to update .env file:', error)
145
-
146
- // attempt to restore backup
147
- if (existsSync(ENV_BACKUP_PATH)) {
148
- try {
149
- copyFileSync(ENV_BACKUP_PATH, ENV_PATH)
150
- console.info('Restored .env from backup')
151
- } catch (restoreError) {
152
- console.error('Failed to restore backup:', restoreError)
109
+ // write to temp file first (atomic operation)
110
+ writeFileSync(ENV_TEMP_PATH, newContent)
111
+
112
+ // validate temp file
113
+ const tempContent = readFileSync(ENV_TEMP_PATH, 'utf-8')
114
+ if (!tempContent.includes(BEGIN_MARKER) || !tempContent.includes(END_MARKER)) {
115
+ throw new Error('Generated content validation failed')
116
+ }
117
+
118
+ // atomic replace
119
+ renameSync(ENV_TEMP_PATH, ENV_PATH)
120
+
121
+ if (existsSync(ENV_BACKUP_PATH)) {
122
+ try {
123
+ unlinkSync(ENV_BACKUP_PATH)
124
+ } catch {
125
+ // ignore cleanup errors
126
+ }
153
127
  }
154
- }
155
128
 
156
- // clean up temp file
157
- if (existsSync(ENV_TEMP_PATH)) {
158
- try {
159
- unlinkSync(ENV_TEMP_PATH)
160
- } catch {
161
- // ignore cleanup errors
129
+ console.info('Updated .env auto-generated section')
130
+ } catch (error) {
131
+ console.error('Failed to update .env file:', error)
132
+
133
+ // attempt to restore backup
134
+ if (existsSync(ENV_BACKUP_PATH)) {
135
+ try {
136
+ copyFileSync(ENV_BACKUP_PATH, ENV_PATH)
137
+ console.info('Restored .env from backup')
138
+ } catch (restoreError) {
139
+ console.error('Failed to restore backup:', restoreError)
140
+ }
162
141
  }
142
+
143
+ // clean up temp file
144
+ if (existsSync(ENV_TEMP_PATH)) {
145
+ try {
146
+ unlinkSync(ENV_TEMP_PATH)
147
+ } catch {
148
+ // ignore cleanup errors
149
+ }
150
+ }
151
+
152
+ // don't fail the install process
153
+ process.exit(0)
163
154
  }
155
+ }
164
156
 
165
- // don't fail the install process
157
+ try {
158
+ updateEnvFile()
159
+ } catch (error) {
160
+ // catch any unexpected errors and exit gracefully
161
+ console.error('Bootstrap script error:', error)
166
162
  process.exit(0)
167
163
  }
168
- }
169
-
170
- // main execution
171
- // skip bootstrap in CI environments
172
- if (process.env.CI === 'true') {
173
- console.info('Skipping bootstrap in CI environment')
174
- process.exit(0)
175
- }
176
-
177
- try {
178
- updateEnvFile()
179
- } catch (error) {
180
- // catch any unexpected errors and exit gracefully
181
- console.error('Bootstrap script error:', error)
182
- process.exit(0)
183
- }
164
+ })
@@ -1,24 +1,26 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- import { sleep } from '@take-out/helpers'
4
-
5
- const ONE_SERVER_URL = process.env.ONE_SERVER_URL || 'http://localhost:8081'
6
- const CHECK_INTERVAL = 2000
7
-
8
- async function checkServer(): Promise<boolean> {
9
- try {
10
- await fetch(ONE_SERVER_URL, {
11
- signal: AbortSignal.timeout(5000),
12
- }).then((res) => res.text())
13
- // give it a couple seconds to build initial route
14
- await sleep(2000)
15
- return true
16
- } catch (error) {
17
- return false
3
+ import { cmd } from './cmd'
4
+
5
+ await cmd`wait for dev server to be available`.run(async () => {
6
+ const { sleep } = await import('@take-out/helpers')
7
+
8
+ const ONE_SERVER_URL = process.env.ONE_SERVER_URL || 'http://localhost:8081'
9
+ const CHECK_INTERVAL = 2000
10
+
11
+ async function checkServer(): Promise<boolean> {
12
+ try {
13
+ await fetch(ONE_SERVER_URL, {
14
+ signal: AbortSignal.timeout(5000),
15
+ }).then((res) => res.text())
16
+ // give it a couple seconds to build initial route
17
+ await sleep(2000)
18
+ return true
19
+ } catch (error) {
20
+ return false
21
+ }
18
22
  }
19
- }
20
23
 
21
- async function waitForServer(): Promise<void> {
22
24
  process.stdout.write(`Waiting for server at ${ONE_SERVER_URL}...\n`)
23
25
 
24
26
  while (true) {
@@ -34,7 +36,6 @@ async function waitForServer(): Promise<void> {
34
36
  `Waiting to start dev watch until after dev server (wait ${CHECK_INTERVAL / 1000}s)...\n`
35
37
  )
36
38
  }
37
- }
38
39
 
39
- await waitForServer()
40
- process.exit(0)
40
+ process.exit(0)
41
+ })