@o/cli 0.16.19 → 0.16.20-canary.1791839822276

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.
package/dist/cmd.d.ts CHANGED
@@ -14,18 +14,20 @@ type Args<S extends string> = import('./args.js').Args<S>;
14
14
  type RunFn<S extends string> = (fn: (ctx: Prettify<{
15
15
  args: Args<S>;
16
16
  } & CmdContext>) => Promise<void> | void) => Promise<void>;
17
+ type Chainable<S extends string> = {
18
+ env(vars: Record<string, string>): Chainable<S>;
19
+ run: RunFn<S>;
20
+ };
21
+ type Command = {
22
+ env(vars: Record<string, string>): Command;
23
+ args<const S extends string>(spec: S): Chainable<S>;
24
+ run: RunFn<''>;
25
+ };
17
26
  export declare function setInterceptCmd(fn: ((info: {
18
27
  description: string;
19
28
  args?: string;
20
29
  }) => void) | undefined): void;
21
- declare function createCmd(description: string): {
22
- env(vars: Record<string, string>): /*elided*/ any;
23
- args<const S extends string>(spec: S): {
24
- env(vars: Record<string, string>): /*elided*/ any;
25
- run: RunFn<S>;
26
- };
27
- run: RunFn<"">;
28
- };
30
+ declare function createCmd(description: string): Command;
29
31
  export declare function cmd(description: string): ReturnType<typeof createCmd>;
30
32
  export declare function cmd(strings: TemplateStringsArray): ReturnType<typeof createCmd>;
31
33
  export {};
package/dist/cmd.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cmd.d.ts","sourceRoot":"","sources":["../src/cmd.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAA;AAEhD,KAAK,UAAU,GAAG;IAChB,CAAC,EAAE,cAAc,KAAK,EAAE,CAAC,CAAA;IACzB,MAAM,EAAE,cAAc,YAAY,CAAC,CAAA;IACnC,MAAM,EAAE,cAAc,gBAAgB,CAAC,CAAA;IACvC,GAAG,EAAE,cAAc,UAAU,EAAE,GAAG,CAAA;IAClC,EAAE,EAAE,cAAc,SAAS,CAAC,CAAA;IAC5B,IAAI,EAAE,cAAc,WAAW,CAAC,CAAA;IAChC,EAAE,EAAE,cAAc,SAAS,CAAC,CAAA;CAC7B,CAAA;AAED,KAAK,IAAI,CAAC,CAAC,SAAS,MAAM,IAAI,OAAO,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;AAEzD,KAAK,KAAK,CAAC,CAAC,SAAS,MAAM,IAAI,CAC7B,EAAE,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;CAAE,GAAG,UAAU,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,KACxE,OAAO,CAAC,IAAI,CAAC,CAAA;AAIlB,wBAAgB,eAAe,CAC7B,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAAC,GAAG,SAAS,QAGzE;AAED,iBAAS,SAAS,CAAC,WAAW,EAAE,MAAM;cA6DxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;eAIrB,CAAC,SAAS,MAAM,QAAQ,CAAC;kBAbxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;;;;EAmBrC;AAED,wBAAgB,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAA;AACtE,wBAAgB,GAAG,CAAC,OAAO,EAAE,oBAAoB,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAA"}
1
+ {"version":3,"file":"cmd.d.ts","sourceRoot":"","sources":["../src/cmd.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAA;AAEhD,KAAK,UAAU,GAAG;IAChB,CAAC,EAAE,cAAc,KAAK,EAAE,CAAC,CAAA;IACzB,MAAM,EAAE,cAAc,YAAY,CAAC,CAAA;IACnC,MAAM,EAAE,cAAc,gBAAgB,CAAC,CAAA;IACvC,GAAG,EAAE,cAAc,UAAU,EAAE,GAAG,CAAA;IAClC,EAAE,EAAE,cAAc,SAAS,CAAC,CAAA;IAC5B,IAAI,EAAE,cAAc,WAAW,CAAC,CAAA;IAChC,EAAE,EAAE,cAAc,SAAS,CAAC,CAAA;CAC7B,CAAA;AAED,KAAK,IAAI,CAAC,CAAC,SAAS,MAAM,IAAI,OAAO,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;AAEzD,KAAK,KAAK,CAAC,CAAC,SAAS,MAAM,IAAI,CAC7B,EAAE,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;CAAE,GAAG,UAAU,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,KACxE,OAAO,CAAC,IAAI,CAAC,CAAA;AAElB,KAAK,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI;IACjC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;IAC/C,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;CACd,CAAA;AAED,KAAK,OAAO,GAAG;IACb,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAA;IAC1C,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;IACnD,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAA;CACf,CAAA;AAID,wBAAgB,eAAe,CAC7B,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAAC,GAAG,SAAS,QAGzE;AAED,iBAAS,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAuE/C;AAED,wBAAgB,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAA;AACtE,wBAAgB,GAAG,CAAC,OAAO,EAAE,oBAAoB,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAA"}
package/dist/cmd.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cmd.js","sourceRoot":"","sources":["../src/cmd.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cmd.js","sourceRoot":"","sources":["../src/cmd.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@o/cli",
3
- "version": "0.16.19",
3
+ "version": "0.16.20-canary.1791839822276",
4
4
  "description": "Typed command and subprocess helpers for Orez consumers.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -14,7 +14,9 @@
14
14
  "module": "dist/index.js",
15
15
  "types": "./dist/index.d.ts",
16
16
  "bin": {
17
- "o": "./dist/cli.js"
17
+ "o": "./dist/cli.js",
18
+ "tko": "./src/tko/cli.ts",
19
+ "takeout": "./src/tko/cli.ts"
18
20
  },
19
21
  "exports": {
20
22
  "./package.json": "./package.json",
@@ -22,12 +24,23 @@
22
24
  "types": "./dist/index.d.ts",
23
25
  "import": "./dist/index.js",
24
26
  "default": "./dist/index.js"
25
- }
27
+ },
28
+ "./utils/*": {
29
+ "types": "./src/tko/utils/*.ts",
30
+ "default": "./src/tko/utils/*.ts"
31
+ },
32
+ "./constants/*": {
33
+ "types": "./src/tko/constants/*.ts",
34
+ "default": "./src/tko/constants/*.ts"
35
+ },
36
+ "./withOpSqliteStatic": "./src/tko/withOpSqliteStatic.cjs",
37
+ "./withExpoModulesCoreSwift6Fix": "./src/tko/withExpoModulesCoreSwift6Fix.cjs"
26
38
  },
27
39
  "files": [
28
40
  "dist",
29
41
  "LICENSE",
30
- "README.md"
42
+ "README.md",
43
+ "src/tko"
31
44
  ],
32
45
  "scripts": {
33
46
  "build": "rm -rf dist && tsc -p tsconfig.build.json && cp src/run-pty.mjs dist/run-pty.mjs && chmod +x dist/cli.js dist/run-pty.mjs",
@@ -40,7 +53,10 @@
40
53
  "dependencies": {
41
54
  "@clack/prompts": "^0.8.2",
42
55
  "@lydell/node-pty": "^1.2.0-beta.3",
43
- "picocolors": "^1.1.1"
56
+ "picocolors": "^1.1.1",
57
+ "@o/run": "0.16.20-canary.1791839822276",
58
+ "@o/scripts": "0.16.20-canary.1791839822276",
59
+ "citty": "^0.1.6"
44
60
  },
45
61
  "devDependencies": {
46
62
  "@types/bun": "1.3.14",
@@ -50,5 +66,14 @@
50
66
  },
51
67
  "publishConfig": {
52
68
  "access": "public"
53
- }
69
+ },
70
+ "peerDependencies": {
71
+ "@expo/config-plugins": "*"
72
+ },
73
+ "peerDependenciesMeta": {
74
+ "@expo/config-plugins": {
75
+ "optional": true
76
+ }
77
+ },
78
+ "releaseSourceCommit": "e7c02e302d6227ce686b136dcb361e5823d58d33"
54
79
  }
package/src/tko/cli.ts ADDED
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env bun
2
+
3
+ /**
4
+ * Takeout CLI
5
+ * Interactive tools for Takeout starter kit setup and management
6
+ */
7
+
8
+ import { spawnSync } from 'node:child_process'
9
+ import { existsSync, statSync } from 'node:fs'
10
+ import { join } from 'node:path'
11
+
12
+ import { defineCommand, runMain } from 'citty'
13
+
14
+ // check if a directory exists in scripts folder (lazy check)
15
+ function isScriptCategory(name: string): boolean {
16
+ const scriptsDir = join(process.cwd(), 'scripts')
17
+ const categoryPath = join(scriptsDir, name)
18
+
19
+ try {
20
+ return existsSync(categoryPath) && statSync(categoryPath).isDirectory()
21
+ } catch {
22
+ return false
23
+ }
24
+ }
25
+
26
+ // find a local script in ./scripts/, returns path or null
27
+ function findLocalScript(name: string): string | null {
28
+ const scriptsDir = join(process.cwd(), 'scripts')
29
+ const normalizedName = name.replace(/:/g, '/')
30
+
31
+ for (const ext of ['.ts', '.js', '']) {
32
+ const scriptPath = join(scriptsDir, `${normalizedName}${ext}`)
33
+ if (existsSync(scriptPath)) {
34
+ return scriptPath
35
+ }
36
+ }
37
+
38
+ return null
39
+ }
40
+
41
+ function isLocalScript(name: string): boolean {
42
+ return findLocalScript(name) !== null
43
+ }
44
+
45
+ // find a built-in script in @o/scripts, returns path or null
46
+ function findBuiltInScript(name: string): string | null {
47
+ try {
48
+ const resolved = import.meta.resolve('@o/scripts/package.json')
49
+ const packageJsonPath = new URL(resolved).pathname
50
+ const packageRoot = join(packageJsonPath, '..')
51
+ const srcPath = join(packageRoot, 'src')
52
+
53
+ // normalize name: convert colons to slashes
54
+ const normalizedName = name.replace(/:/g, '/')
55
+
56
+ // check if the script file exists
57
+ for (const ext of ['.ts', '.js', '']) {
58
+ const scriptPath = join(srcPath, `${normalizedName}${ext}`)
59
+ if (existsSync(scriptPath)) {
60
+ return scriptPath
61
+ }
62
+ }
63
+ } catch {
64
+ // package not found or error resolving
65
+ }
66
+
67
+ return null
68
+ }
69
+
70
+ function isBuiltInScript(name: string): boolean {
71
+ return findBuiltInScript(name) !== null
72
+ }
73
+
74
+ // always enable shorthand mode — both tko and takeout resolve to this file
75
+ const isShorthand = true
76
+
77
+ if (isShorthand) {
78
+ // in shorthand mode, treat first arg as potential script command
79
+ const firstArg = process.argv[2]
80
+ const builtInCommands = [
81
+ 'docs',
82
+ 'onboard',
83
+ 'run',
84
+ 'run-all',
85
+ 'script',
86
+ 'skills',
87
+ 'env:setup',
88
+ 'sync',
89
+ 'changed',
90
+ '--help',
91
+ '-h',
92
+ '--version',
93
+ '-v',
94
+ ]
95
+
96
+ if (firstArg && !builtInCommands.includes(firstArg)) {
97
+ // resolve the script name for category/script patterns
98
+ let resolvedScriptName: string | undefined
99
+
100
+ // check if it's a script category or has a slash (category/script format)
101
+ // Do a lazy check only on the specific arg, not scanning all directories
102
+ if (isScriptCategory(firstArg)) {
103
+ // find first non-flag arg as sub-script name
104
+ // e.g., "tko check types" or "tko check --default-all types"
105
+ const restArgs = process.argv.slice(3)
106
+ const subScriptIdx = restArgs.findIndex((a) => !a.startsWith('-'))
107
+ if (subScriptIdx !== -1) {
108
+ const subScript = restArgs[subScriptIdx]
109
+ resolvedScriptName = `${firstArg}/${subScript}`
110
+ // remove the sub-script from its position and replace category with combined path
111
+ process.argv.splice(3 + subScriptIdx, 1)
112
+ process.argv[2] = resolvedScriptName
113
+ }
114
+ // inject "run" into args to use the run command directly
115
+ process.argv.splice(2, 0, 'run')
116
+ } else if (firstArg?.includes('/')) {
117
+ resolvedScriptName = firstArg
118
+ // inject "run" into args to use the run command directly
119
+ process.argv.splice(2, 0, 'run')
120
+ } else if (isLocalScript(firstArg) || isBuiltInScript(firstArg)) {
121
+ resolvedScriptName = firstArg
122
+ // check if it's a local or built-in script (like update-deps, clean, etc.)
123
+ // use "run" to avoid citty parsing issues with hyphens
124
+ process.argv.splice(2, 0, 'run')
125
+ } else {
126
+ // assume it's a script command, inject "script" into args
127
+ process.argv.splice(2, 0, 'script')
128
+ }
129
+
130
+ // bypass citty for --help on scripts so the script handles it itself
131
+ const hasHelp = process.argv.includes('--help') || process.argv.includes('-h')
132
+ if (resolvedScriptName && hasHelp) {
133
+ const scriptPath =
134
+ findLocalScript(resolvedScriptName) || findBuiltInScript(resolvedScriptName)
135
+ if (scriptPath) {
136
+ const flagArgs = process.argv.slice(3).filter((a) => a !== resolvedScriptName)
137
+ const result = spawnSync('bun', [scriptPath, ...flagArgs], {
138
+ stdio: 'inherit',
139
+ shell: false,
140
+ })
141
+ process.exit(result.status || 0)
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ const main = defineCommand({
148
+ meta: {
149
+ name: isShorthand ? 'tko' : 'takeout',
150
+ version: '0.0.2',
151
+ description: 'CLI tools for Takeout starter kit',
152
+ },
153
+ subCommands: {
154
+ onboard: () => import('./commands/onboard').then((m) => m.onboardCommand),
155
+ docs: () => import('./commands/docs').then((m) => m.docsCommand),
156
+ 'env:setup': () => import('./commands/env-setup').then((m) => m.envSetupCommand),
157
+ run: () => import('./commands/run').then((m) => m.runCommand),
158
+ 'run-all': () => import('./commands/run-all').then((m) => m.runAllCommand),
159
+ script: () => import('./commands/script').then((m) => m.scriptCommand),
160
+ skills: () => import('./commands/skills').then((m) => m.skillsCommand),
161
+ sync: () => import('./commands/sync').then((m) => m.syncCommand),
162
+ changed: () => import('./commands/changed').then((m) => m.changedCommand),
163
+ },
164
+ async run() {
165
+ const hasArgs = process.argv.length > 2
166
+ if (!hasArgs) {
167
+ const { listAllScripts } = await import('./utils/script-listing')
168
+ await listAllScripts()
169
+ }
170
+ },
171
+ })
172
+
173
+ runMain(main)
@@ -0,0 +1,313 @@
1
+ /**
2
+ * Changed command - show what's changed in upstream Takeout since last sync
3
+ */
4
+
5
+ import { execSync } from 'node:child_process'
6
+ import { existsSync, readFileSync } from 'node:fs'
7
+ import { join } from 'node:path'
8
+
9
+ import { defineCommand } from 'citty'
10
+ import pc from 'picocolors'
11
+
12
+ const UPSTREAM_REPO = 'tamagui/takeout2'
13
+ const UPSTREAM_REMOTE = 'takeout-upstream'
14
+ const TAKEOUT_FILE = '.takeout'
15
+
16
+ const COMMIT_TYPE_ORDER = [
17
+ 'feat',
18
+ 'fix',
19
+ 'perf',
20
+ 'refactor',
21
+ 'docs',
22
+ 'chore',
23
+ 'test',
24
+ 'ci',
25
+ ]
26
+
27
+ interface CommitInfo {
28
+ hash: string
29
+ type: string
30
+ scope?: string
31
+ message: string
32
+ breaking: boolean
33
+ date: string
34
+ }
35
+
36
+ interface TakeoutConfig {
37
+ sha?: string
38
+ date?: string
39
+ }
40
+
41
+ function readTakeoutConfig(): TakeoutConfig | null {
42
+ const configPath = join(process.cwd(), TAKEOUT_FILE)
43
+
44
+ if (!existsSync(configPath)) {
45
+ return null
46
+ }
47
+
48
+ try {
49
+ const content = readFileSync(configPath, 'utf-8')
50
+ const config: TakeoutConfig = {}
51
+
52
+ for (const line of content.split('\n')) {
53
+ const trimmed = line.trim()
54
+ if (trimmed.startsWith('#') || !trimmed) continue
55
+
56
+ const [key, ...valueParts] = trimmed.split('=')
57
+ const value = valueParts.join('=').trim()
58
+
59
+ if (key === 'sha') config.sha = value
60
+ if (key === 'date') config.date = value
61
+ }
62
+
63
+ return config
64
+ } catch {
65
+ return null
66
+ }
67
+ }
68
+
69
+ function parseConventionalCommit(
70
+ message: string
71
+ ): { type: string; scope?: string; message: string; breaking: boolean } | null {
72
+ // match conventional commit format: type(scope)!: message or type!: message
73
+ const match = message.match(/^(\w+)(?:\(([^)]+)\))?(!)?: (.+)$/)
74
+ if (!match) return null
75
+
76
+ const [, type, scope, breaking, msg] = match
77
+
78
+ // include all commit types for takeout
79
+ const validTypes = [
80
+ 'feat',
81
+ 'fix',
82
+ 'perf',
83
+ 'refactor',
84
+ 'docs',
85
+ 'chore',
86
+ 'test',
87
+ 'ci',
88
+ 'build',
89
+ 'style',
90
+ ]
91
+ if (!type || !validTypes.includes(type)) return null
92
+
93
+ return {
94
+ type,
95
+ scope,
96
+ message: msg || message,
97
+ breaking: !!breaking || message.toLowerCase().includes('breaking'),
98
+ }
99
+ }
100
+
101
+ function ensureUpstreamRemote(): boolean {
102
+ try {
103
+ // check if remote exists
104
+ const remotes = execSync('git remote', { encoding: 'utf-8' })
105
+ if (!remotes.includes(UPSTREAM_REMOTE)) {
106
+ console.info(pc.dim(` adding ${UPSTREAM_REMOTE} remote...`))
107
+ execSync(`git remote add ${UPSTREAM_REMOTE} git@github.com:${UPSTREAM_REPO}.git`, {
108
+ stdio: 'pipe',
109
+ })
110
+ }
111
+
112
+ // fetch latest
113
+ console.info(pc.dim(` fetching from ${UPSTREAM_REMOTE}...`))
114
+ execSync(`git fetch ${UPSTREAM_REMOTE} --quiet`, { stdio: 'pipe' })
115
+ return true
116
+ } catch (err) {
117
+ console.error(pc.red(`failed to setup upstream remote: ${err}`))
118
+ return false
119
+ }
120
+ }
121
+
122
+ function getCommitsBetween(fromSha: string, toRef: string): CommitInfo[] {
123
+ const commits: CommitInfo[] = []
124
+
125
+ try {
126
+ // format: hash|date|message
127
+ const result = execSync(
128
+ `git log ${fromSha}..${toRef} --pretty=format:"%H|%ad|%s" --date=short 2>/dev/null`,
129
+ { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 }
130
+ )
131
+
132
+ const lines = result.trim().split('\n').filter(Boolean)
133
+
134
+ for (const line of lines) {
135
+ const [hash = '', date = '', ...messageParts] = line.split('|')
136
+ const message = messageParts.join('|')
137
+
138
+ const parsed = parseConventionalCommit(message)
139
+
140
+ // include non-conventional commits too, just categorize them as "other"
141
+ commits.push({
142
+ hash: hash.slice(0, 7),
143
+ type: parsed?.type || 'other',
144
+ scope: parsed?.scope,
145
+ message: parsed?.message || message,
146
+ breaking: parsed?.breaking || false,
147
+ date,
148
+ })
149
+ }
150
+ } catch {
151
+ // no commits or error
152
+ }
153
+
154
+ return commits
155
+ }
156
+
157
+ function formatChangelog(commits: CommitInfo[]): void {
158
+ if (commits.length === 0) {
159
+ console.info(pc.dim(' no changes found'))
160
+ return
161
+ }
162
+
163
+ // group by type
164
+ const grouped = new Map<string, CommitInfo[]>()
165
+ for (const commit of commits) {
166
+ const existing = grouped.get(commit.type) || []
167
+ existing.push(commit)
168
+ grouped.set(commit.type, existing)
169
+ }
170
+
171
+ // sort by type order
172
+ const sortedTypes = Array.from(grouped.keys()).sort((a, b) => {
173
+ const aIdx = COMMIT_TYPE_ORDER.indexOf(a)
174
+ const bIdx = COMMIT_TYPE_ORDER.indexOf(b)
175
+ return (aIdx === -1 ? 999 : aIdx) - (bIdx === -1 ? 999 : bIdx)
176
+ })
177
+
178
+ // show breaking changes first
179
+ const breakingChanges = commits.filter((c) => c.breaking)
180
+ if (breakingChanges.length > 0) {
181
+ console.info()
182
+ console.info(pc.red(pc.bold(' BREAKING CHANGES')))
183
+ for (const commit of breakingChanges) {
184
+ const scope = commit.scope ? pc.cyan(`(${commit.scope})`) : ''
185
+ console.info(
186
+ ` ${pc.red('!')} ${scope} ${commit.message} ${pc.dim(`(${commit.hash})`)}`
187
+ )
188
+ }
189
+ }
190
+
191
+ const typeLabels: Record<string, string> = {
192
+ feat: 'Features',
193
+ fix: 'Bug Fixes',
194
+ perf: 'Performance',
195
+ refactor: 'Refactoring',
196
+ docs: 'Documentation',
197
+ chore: 'Maintenance',
198
+ test: 'Tests',
199
+ ci: 'CI',
200
+ build: 'Build',
201
+ style: 'Style',
202
+ other: 'Other',
203
+ }
204
+
205
+ const typeColors: Record<string, (s: string) => string> = {
206
+ feat: pc.green,
207
+ fix: pc.yellow,
208
+ perf: pc.magenta,
209
+ refactor: pc.blue,
210
+ docs: pc.dim,
211
+ chore: pc.dim,
212
+ test: pc.dim,
213
+ ci: pc.dim,
214
+ build: pc.dim,
215
+ style: pc.dim,
216
+ other: pc.white,
217
+ }
218
+
219
+ for (const type of sortedTypes) {
220
+ const typeCommits = grouped.get(type)!.filter((c) => !c.breaking)
221
+ if (typeCommits.length === 0) continue
222
+
223
+ const label = typeLabels[type] || type
224
+ const color = typeColors[type] || pc.white
225
+
226
+ console.info()
227
+ console.info(color(pc.bold(` ${label}`)))
228
+
229
+ for (const commit of typeCommits) {
230
+ const scope = commit.scope ? pc.cyan(`(${commit.scope}) `) : ''
231
+ console.info(
232
+ ` ${pc.dim('-')} ${scope}${commit.message} ${pc.dim(`(${commit.hash})`)}`
233
+ )
234
+ }
235
+ }
236
+ }
237
+
238
+ export const changedCommand = defineCommand({
239
+ meta: {
240
+ name: 'changed',
241
+ description: 'Show changes in upstream Takeout since last sync',
242
+ },
243
+ args: {
244
+ from: {
245
+ type: 'string',
246
+ description: 'Starting commit SHA (defaults to .takeout file)',
247
+ },
248
+ to: {
249
+ type: 'string',
250
+ description: 'Ending commit ref (defaults to upstream main)',
251
+ },
252
+ },
253
+ async run({ args }) {
254
+ console.info()
255
+ console.info(pc.bold(pc.cyan('Takeout Changes')))
256
+ console.info()
257
+
258
+ // determine from SHA
259
+ let fromSha = args.from
260
+ const config = readTakeoutConfig()
261
+
262
+ if (!fromSha) {
263
+ if (!config?.sha) {
264
+ console.info(pc.yellow('No .takeout file found with last sync SHA.'))
265
+ console.info()
266
+ console.info(pc.dim('Either:'))
267
+ console.info(pc.dim(' 1. Create a .takeout file with: sha=<commit-sha>'))
268
+ console.info(pc.dim(' 2. Run with --from <sha> to specify starting point'))
269
+ console.info(pc.dim(' 3. Run `tko sync` to sync and create the file'))
270
+ console.info()
271
+ return
272
+ }
273
+ fromSha = config.sha
274
+ }
275
+
276
+ // setup upstream remote and fetch
277
+ if (!ensureUpstreamRemote()) {
278
+ return
279
+ }
280
+
281
+ const toRef = args.to || `${UPSTREAM_REMOTE}/main`
282
+
283
+ console.info(pc.dim(` from: ${fromSha.slice(0, 7)}`))
284
+ console.info(pc.dim(` to: ${toRef}`))
285
+
286
+ if (config?.date) {
287
+ console.info(pc.dim(` last sync: ${config.date}`))
288
+ }
289
+
290
+ // get commits
291
+ const commits = getCommitsBetween(fromSha, toRef)
292
+
293
+ if (commits.length === 0) {
294
+ console.info()
295
+ console.info(pc.green('✓ Already up to date with upstream!'))
296
+ console.info()
297
+ return
298
+ }
299
+
300
+ console.info()
301
+ console.info(
302
+ pc.bold(
303
+ `${commits.length} commit${commits.length === 1 ? '' : 's'} since last sync:`
304
+ )
305
+ )
306
+
307
+ formatChangelog(commits)
308
+
309
+ console.info()
310
+ console.info(pc.dim('Run `tko sync` to sync these changes into your fork.'))
311
+ console.info()
312
+ },
313
+ })