@minus-ai/create-skill 0.1.0-beta.10 → 0.1.0-beta.12

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/index.mjs CHANGED
@@ -640,7 +640,6 @@ ${templateDocs[inputType] || templateDocs.custom}
640
640
  writeOut(join(targetDir, 'frontend/tsconfig.json'), render(readTemplate('tsconfig.json.tpl'), vars))
641
641
  writeOut(join(targetDir, 'frontend/src/main.tsx'), render(readTemplate('main.tsx.tpl', inputType), vars))
642
642
  writeOut(join(targetDir, 'frontend/src/locales/zh-CN.json'), render(readTemplate('zh-CN.json.tpl', inputType), vars))
643
- writeOut(join(targetDir, 'frontend/src/locales/en-US.json'), render(readTemplate('en-US.json.tpl', inputType), vars))
644
643
 
645
644
  // 类型声明文件(让 tsc build 能识别 @minus/* 模块)
646
645
  writeOut(join(targetDir, 'frontend/src/minus-runtime.d.ts'), `declare module '@minus/*';\n`)
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@minus-ai/create-skill",
3
- "version": "0.1.0-beta.10",
3
+ "version": "0.1.0-beta.12",
4
4
  "type": "module",
5
5
  "bin": {
6
- "create-skill": "./index.mjs"
6
+ "create-skill": "index.mjs"
7
7
  },
8
8
  "files": [
9
9
  "index.mjs",
@@ -0,0 +1 @@
1
+ 3
@@ -107,10 +107,12 @@ pnpm run build
107
107
 
108
108
  | 命令 | 说明 |
109
109
  |---|---|
110
- | `pnpm run dev` | 启动开发环境(前后端) |
110
+ | `pnpm run dev` | 启动开发环境(mac/Linux,前后端) |
111
+ | `pnpm run dev:backend` | 仅启动后端(mac/Linux) |
112
+ | `pnpm run dev:win` | 启动开发环境(Windows,前后端) |
113
+ | `pnpm run dev:win:backend` | 仅启动后端(Windows) |
111
114
  | `pnpm run build` | 构建前端产物 |
112
115
  | `cd frontend && pnpm exec vite` | 仅启动前端 |
113
- | `.venv/bin/uvicorn server:app --port {{port}} --reload --env-file .env.local` | 仅启动后端 |
114
116
 
115
117
  ## 进入开发模式(Claude Code)
116
118
 
@@ -4,7 +4,6 @@ import { FlowApp, I18nProvider, mergeMessages, useT, type StepConfig } from '@mi
4
4
  import { AmazonSearchBar, CountrySelect, SearchSubmitButton, validateAsins, platformWidgetMessages } from '@minus/platform-widgets';
5
5
  import { Toaster } from 'sonner';
6
6
  import zhCN from './locales/zh-CN.json';
7
- import enUS from './locales/en-US.json';
8
7
 
9
8
  /*
10
9
  * 防御性编码提示(适用于所有 step render 函数):
@@ -15,12 +14,12 @@ import enUS from './locales/en-US.json';
15
14
  * - 嵌套:(data.obj as Record<string, unknown> | undefined)?.field ?? fallback
16
15
  * 框架已有 Error Boundary 兜底,但不应依赖——优先在数据层做防御。
17
16
  */
18
- function buildSteps(t: (k: string, fb?: string) => string): StepConfig[] {
17
+ function buildSteps(t: (k: string) => string): StepConfig[] {
19
18
  return [
20
19
  {
21
20
  render: ({ data }) => (
22
21
  <div className="minus-default-step-done">
23
- {(data.text as string | undefined) ?? t('{{namespace}}.step.empty', '(空)')}
22
+ {(data.text as string | undefined) ?? t('{{namespace}}.step.empty')}
24
23
  </div>
25
24
  ),
26
25
  },
@@ -37,7 +36,7 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
37
36
  async function handleSubmit() {
38
37
  if (loading) return;
39
38
  const { asins, error: asinError } = validateAsins(value);
40
- if (asinError) { setError(t(asinError.key, asinError.fallback, asinError.vars)); return; }
39
+ if (asinError) { setError(t(asinError.key, undefined, asinError.vars)); return; }
41
40
  setError(null);
42
41
  setLoading(true);
43
42
  try { await onStart({ asins: asins.join(','), country }); } finally { setLoading(false); }
@@ -60,7 +59,7 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
60
59
  <AmazonSearchBar
61
60
  onSubmit={handleSubmit}
62
61
  country={<CountrySelect onChange={setCountry} />}
63
- input={<input type="text" value={value} onChange={(e) => { setValue(e.target.value); if (error) setError(null); }} placeholder={t('{{namespace}}.home.placeholder', '输入一个或多个ASIN')} spellCheck={false} disabled={loading} />}
62
+ input={<input type="text" value={value} onChange={(e) => { setValue(e.target.value); if (error) setError(null); }} placeholder={t('{{namespace}}.home.placeholder')} spellCheck={false} disabled={loading} />}
64
63
  submit={<SearchSubmitButton />}
65
64
  error={error}
66
65
  />
@@ -71,7 +70,7 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
71
70
  const rootEl = document.getElementById('root');
72
71
  if (!rootEl) throw new Error('#root not found');
73
72
 
74
- const skillMessages = mergeMessages(platformWidgetMessages, { 'zh-CN': zhCN as Record<string, string>, 'en-US': enUS as Record<string, string> });
73
+ const skillMessages = mergeMessages(platformWidgetMessages, { 'zh-CN': zhCN as Record<string, string> });
75
74
 
76
75
  function SkillRoot() {
77
76
  const t = useT();
@@ -4,7 +4,6 @@ import { FlowApp, I18nProvider, mergeMessages, useT, type StepConfig } from '@mi
4
4
  import { platformWidgetMessages } from '@minus/platform-widgets';
5
5
  import { Toaster } from 'sonner';
6
6
  import zhCN from './locales/zh-CN.json';
7
- import enUS from './locales/en-US.json';
8
7
 
9
8
  /*
10
9
  * 防御性编码提示(适用于所有 step render 函数):
@@ -15,12 +14,12 @@ import enUS from './locales/en-US.json';
15
14
  * - 嵌套:(data.obj as Record<string, unknown> | undefined)?.field ?? fallback
16
15
  * 框架已有 Error Boundary 兜底,但不应依赖——优先在数据层做防御。
17
16
  */
18
- function buildSteps(t: (k: string, fb?: string) => string): StepConfig[] {
17
+ function buildSteps(t: (k: string) => string): StepConfig[] {
19
18
  return [
20
19
  {
21
20
  render: ({ data }) => (
22
21
  <div className="minus-default-step-done">
23
- {(data.text as string) ?? t('{{namespace}}.step.empty', '(空)')}
22
+ {(data.text as string) ?? t('{{namespace}}.step.empty')}
24
23
  </div>
25
24
  ),
26
25
  },
@@ -54,11 +53,11 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
54
53
  )}
55
54
  <div style={{ background: '#fff', border: '1px solid #e5e7eb', borderRadius: 8, padding: 20, display: 'flex', flexDirection: 'column', gap: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.04)' }}>
56
55
  <label className="minus-field">
57
- <span>{t('{{namespace}}.home.fieldLabel', '输入')}</span>
58
- <input type="text" value={value} onChange={(e) => setValue(e.target.value)} placeholder={t('{{namespace}}.home.placeholder', '请输入...')} onKeyDown={(e) => e.key === 'Enter' && handleSubmit()} />
56
+ <span>{t('{{namespace}}.home.fieldLabel')}</span>
57
+ <input type="text" value={value} onChange={(e) => setValue(e.target.value)} placeholder={t('{{namespace}}.home.placeholder')} onKeyDown={(e) => e.key === 'Enter' && handleSubmit()} />
59
58
  </label>
60
59
  <button className="minus-btn minus-btn-primary" onClick={handleSubmit} disabled={!value.trim() || loading}>
61
- {loading ? t('{{namespace}}.home.processing', '处理中…') : t('{{namespace}}.home.send', '开始')}
60
+ {loading ? t('{{namespace}}.home.processing') : t('{{namespace}}.home.send')}
62
61
  </button>
63
62
  </div>
64
63
  </div>
@@ -68,7 +67,7 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
68
67
  const rootEl = document.getElementById('root');
69
68
  if (!rootEl) throw new Error('#root not found');
70
69
 
71
- const skillMessages = mergeMessages(platformWidgetMessages, { 'zh-CN': zhCN as Record<string, string>, 'en-US': enUS as Record<string, string> });
70
+ const skillMessages = mergeMessages(platformWidgetMessages, { 'zh-CN': zhCN as Record<string, string> });
72
71
 
73
72
  function SkillRoot() {
74
73
  const t = useT();
@@ -4,7 +4,6 @@ import { FlowApp, I18nProvider, mergeMessages, useT, type StepConfig } from '@mi
4
4
  import { CompletionPanel, platformWidgetMessages } from '@minus/platform-widgets';
5
5
  import { Toaster } from 'sonner';
6
6
  import zhCN from './locales/zh-CN.json';
7
- import enUS from './locales/en-US.json';
8
7
 
9
8
  /*
10
9
  * 防御性编码提示(适用于所有 step render 函数):
@@ -15,12 +14,12 @@ import enUS from './locales/en-US.json';
15
14
  * - 嵌套:(data.obj as Record<string, unknown> | undefined)?.field ?? fallback
16
15
  * 框架已有 Error Boundary 兜底,但不应依赖——优先在数据层做防御。
17
16
  */
18
- function buildSteps(t: (k: string, fb?: string) => string): StepConfig[] {
17
+ function buildSteps(t: (k: string) => string): StepConfig[] {
19
18
  return [
20
19
  {
21
20
  render: ({ data }) => (
22
21
  <div className="minus-default-step-done">
23
- {(data.text as string | undefined) ?? t('{{namespace}}.step.empty', '(空)')}
22
+ {(data.text as string | undefined) ?? t('{{namespace}}.step.empty')}
24
23
  </div>
25
24
  ),
26
25
  },
@@ -61,7 +60,7 @@ if (!rootEl) throw new Error('#root not found');
61
60
 
62
61
  const skillMessages = mergeMessages(
63
62
  platformWidgetMessages,
64
- { 'zh-CN': zhCN as Record<string, string>, 'en-US': enUS as Record<string, string> },
63
+ { 'zh-CN': zhCN as Record<string, string> },
65
64
  );
66
65
 
67
66
  function SkillRoot() {
@@ -4,7 +4,6 @@ import { FlowApp, I18nProvider, mergeMessages, useT, type StepConfig } from '@mi
4
4
  import { FilePicker, uploadFile, platformWidgetMessages } from '@minus/platform-widgets';
5
5
  import { Toaster } from 'sonner';
6
6
  import zhCN from './locales/zh-CN.json';
7
- import enUS from './locales/en-US.json';
8
7
 
9
8
  /*
10
9
  * 防御性编码提示(适用于所有 step render 函数):
@@ -15,12 +14,12 @@ import enUS from './locales/en-US.json';
15
14
  * - 嵌套:(data.obj as Record<string, unknown> | undefined)?.field ?? fallback
16
15
  * 框架已有 Error Boundary 兜底,但不应依赖——优先在数据层做防御。
17
16
  */
18
- function buildSteps(t: (k: string, fb?: string) => string): StepConfig[] {
17
+ function buildSteps(t: (k: string) => string): StepConfig[] {
19
18
  return [
20
19
  {
21
20
  render: ({ data }) => (
22
21
  <div className="minus-default-step-done">
23
- {(data.text as string) ?? t('{{namespace}}.step.empty', '(空)')}
22
+ {(data.text as string) ?? t('{{namespace}}.step.empty')}
24
23
  </div>
25
24
  ),
26
25
  },
@@ -35,14 +34,14 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
35
34
 
36
35
  async function handleSubmit() {
37
36
  if (loading) return;
38
- if (!file) { setError(t('{{namespace}}.home.fileEmpty', '请选择一个文件')); return; }
37
+ if (!file) { setError(t('{{namespace}}.home.fileEmpty')); return; }
39
38
  setError(null);
40
39
  setLoading(true);
41
40
  try {
42
41
  const { fileId } = await uploadFile(file);
43
42
  await onStart({ fileId, fileName: file.name });
44
43
  } catch (e: any) {
45
- setError(e?.message ?? t('{{namespace}}.home.uploadFailed', '文件上传失败'));
44
+ setError(e?.message ?? t('{{namespace}}.home.uploadFailed'));
46
45
  } finally {
47
46
  setLoading(false);
48
47
  }
@@ -64,12 +63,12 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
64
63
  )}
65
64
  <div style={{ background: '#fff', border: '1px solid #e5e7eb', borderRadius: 8, padding: 20, display: 'flex', flexDirection: 'column', gap: 16, boxShadow: '0 1px 2px rgba(0,0,0,0.04)' }}>
66
65
  <label className="minus-field">
67
- <span>{t('{{namespace}}.home.fieldLabel', '文件')}</span>
66
+ <span>{t('{{namespace}}.home.fieldLabel')}</span>
68
67
  <FilePicker value={file} onChange={(f) => { setFile(f); if (error) setError(null); }} disabled={loading} />
69
68
  </label>
70
69
  {error && <p style={{ margin: 0, fontSize: 13, color: 'var(--minus-color-danger, #ef4444)' }}>{error}</p>}
71
70
  <button className="minus-btn minus-btn-primary" onClick={handleSubmit} disabled={!file || loading}>
72
- {loading ? t('{{namespace}}.home.processing', '上传中…') : t('{{namespace}}.home.send', '开始')}
71
+ {loading ? t('{{namespace}}.home.processing') : t('{{namespace}}.home.send')}
73
72
  </button>
74
73
  </div>
75
74
  </div>
@@ -79,7 +78,7 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
79
78
  const rootEl = document.getElementById('root');
80
79
  if (!rootEl) throw new Error('#root not found');
81
80
 
82
- const skillMessages = mergeMessages(platformWidgetMessages, { 'zh-CN': zhCN as Record<string, string>, 'en-US': enUS as Record<string, string> });
81
+ const skillMessages = mergeMessages(platformWidgetMessages, { 'zh-CN': zhCN as Record<string, string> });
83
82
 
84
83
  function SkillRoot() {
85
84
  const t = useT();
@@ -11,7 +11,7 @@
11
11
  "sonner": "^2.0.7"
12
12
  },
13
13
  "devDependencies": {
14
- "@minus-ai/dev-vite-plugin": "^0.1.0-beta.8",
14
+ "@minus-ai/dev-vite-plugin": "^0.1.0-beta.12",
15
15
  "@types/node": "^{{nodeMajor}}.0.0",
16
16
  "@types/react": "^18.3.3",
17
17
  "@types/react-dom": "^18.3.0",
@@ -4,7 +4,6 @@ import { FlowApp, I18nProvider, mergeMessages, useT, type StepConfig } from '@mi
4
4
  import { AmazonSearchBar, CountrySelect, SearchSubmitButton, validateKeywords, platformWidgetMessages } from '@minus/platform-widgets';
5
5
  import { Toaster } from 'sonner';
6
6
  import zhCN from './locales/zh-CN.json';
7
- import enUS from './locales/en-US.json';
8
7
 
9
8
  /*
10
9
  * 防御性编码提示(适用于所有 step render 函数):
@@ -15,12 +14,12 @@ import enUS from './locales/en-US.json';
15
14
  * - 嵌套:(data.obj as Record<string, unknown> | undefined)?.field ?? fallback
16
15
  * 框架已有 Error Boundary 兜底,但不应依赖——优先在数据层做防御。
17
16
  */
18
- function buildSteps(t: (k: string, fb?: string) => string): StepConfig[] {
17
+ function buildSteps(t: (k: string) => string): StepConfig[] {
19
18
  return [
20
19
  {
21
20
  render: ({ data }) => (
22
21
  <div className="minus-default-step-done">
23
- {(data.text as string) ?? t('{{namespace}}.step.empty', '(空)')}
22
+ {(data.text as string) ?? t('{{namespace}}.step.empty')}
24
23
  </div>
25
24
  ),
26
25
  },
@@ -37,7 +36,7 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
37
36
  async function handleSubmit() {
38
37
  if (loading) return;
39
38
  const { keywords, error: kwError } = validateKeywords(value);
40
- if (kwError) { setError(t(kwError.key, kwError.fallback, kwError.vars)); return; }
39
+ if (kwError) { setError(t(kwError.key, undefined, kwError.vars)); return; }
41
40
  setError(null);
42
41
  setLoading(true);
43
42
  try { await onStart({ keywords: keywords.join(','), country }); } finally { setLoading(false); }
@@ -60,7 +59,7 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
60
59
  <AmazonSearchBar
61
60
  onSubmit={handleSubmit}
62
61
  country={<CountrySelect onChange={setCountry} />}
63
- input={<textarea value={value} onChange={(e) => { setValue(e.target.value); if (error) setError(null); }} onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSubmit(); } }} placeholder={t('{{namespace}}.home.placeholder', '输入关键词,多个关键词用逗号或换行分隔')} spellCheck={false} disabled={loading} rows={1} />}
62
+ input={<textarea value={value} onChange={(e) => { setValue(e.target.value); if (error) setError(null); }} onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSubmit(); } }} placeholder={t('{{namespace}}.home.placeholder')} spellCheck={false} disabled={loading} rows={1} />}
64
63
  submit={<SearchSubmitButton />}
65
64
  error={error}
66
65
  />
@@ -71,7 +70,7 @@ function Home({ title, description, useCases, tags, onStart }: { title: string;
71
70
  const rootEl = document.getElementById('root');
72
71
  if (!rootEl) throw new Error('#root not found');
73
72
 
74
- const skillMessages = mergeMessages(platformWidgetMessages, { 'zh-CN': zhCN as Record<string, string>, 'en-US': enUS as Record<string, string> });
73
+ const skillMessages = mergeMessages(platformWidgetMessages, { 'zh-CN': zhCN as Record<string, string> });
75
74
 
76
75
  function SkillRoot() {
77
76
  const t = useT();
@@ -4,7 +4,6 @@ import { FlowApp, I18nProvider, mergeMessages, useT, type StepConfig, type StepR
4
4
  import { AmazonSearchBar, CompletionPanel, CountrySelect, SearchSubmitButton, validateAsins, validateKeywords, platformWidgetMessages } from '@minus/platform-widgets';
5
5
  import { Toaster } from 'sonner';
6
6
  import zhCN from './locales/zh-CN.json';
7
- import enUS from './locales/en-US.json';
8
7
 
9
8
  type InputType = 'keyword' | 'asin';
10
9
 
@@ -17,12 +16,12 @@ type InputType = 'keyword' | 'asin';
17
16
  * - 嵌套:(data.obj as Record<string, unknown> | undefined)?.field ?? fallback
18
17
  * 框架已有 Error Boundary 兜底,但不应依赖——优先在数据层做防御。
19
18
  */
20
- function buildSteps(t: (k: string, fb?: string) => string): StepConfig[] {
19
+ function buildSteps(t: (k: string) => string): StepConfig[] {
21
20
  return [
22
21
  {
23
22
  render: ({ data }) => (
24
23
  <div className="minus-default-step-done">
25
- {(data.text as string) ?? t('{{namespace}}.step.empty', '(空)')}
24
+ {(data.text as string) ?? t('{{namespace}}.step.empty')}
26
25
  </div>
27
26
  ),
28
27
  },
@@ -55,7 +54,7 @@ function Home({
55
54
  if (inputType === 'asin') {
56
55
  const { asins, error: asinError } = validateAsins(value);
57
56
  if (asinError) {
58
- setError(t(asinError.key, asinError.fallback, asinError.vars));
57
+ setError(t(asinError.key, undefined, asinError.vars));
59
58
  return;
60
59
  }
61
60
  setError(null);
@@ -68,7 +67,7 @@ function Home({
68
67
  } else {
69
68
  const { keywords, error: kwError } = validateKeywords(value);
70
69
  if (kwError) {
71
- setError(t(kwError.key, kwError.fallback, kwError.vars));
70
+ setError(t(kwError.key, undefined, kwError.vars));
72
71
  return;
73
72
  }
74
73
  setError(null);
@@ -82,8 +81,8 @@ function Home({
82
81
  }
83
82
 
84
83
  const placeholder = inputType === 'keyword'
85
- ? t('{{namespace}}.home.placeholderKeyword', '输入关键词,如 bluetooth earbuds')
86
- : t('{{namespace}}.home.placeholderAsin', '输入一个或多个ASIN');
84
+ ? t('{{namespace}}.home.placeholderKeyword')
85
+ : t('{{namespace}}.home.placeholderAsin');
87
86
 
88
87
  return (
89
88
  <>
@@ -116,7 +115,7 @@ function Home({
116
115
  marginLeft: type === 'asin' ? -1 : 0,
117
116
  }}
118
117
  >
119
- {t(`{{namespace}}.home.tab.${type}`, type === 'keyword' ? '关键词' : 'ASIN')}
118
+ {t(`{{namespace}}.home.tab.${type}`)}
120
119
  </button>
121
120
  ))}
122
121
  </div>
@@ -146,7 +145,7 @@ if (!rootEl) throw new Error('#root not found');
146
145
 
147
146
  const skillMessages = mergeMessages(
148
147
  platformWidgetMessages,
149
- { 'zh-CN': zhCN as Record<string, string>, 'en-US': enUS as Record<string, string> },
148
+ { 'zh-CN': zhCN as Record<string, string> },
150
149
  );
151
150
 
152
151
  function SkillRoot() {
@@ -14,10 +14,12 @@
14
14
  "scripts": {
15
15
  "dev": "minus-dev-cleanup && mkdir -p .minus && echo $$ > .minus/dev.pid && concurrently -n skill,fe \".venv/bin/uvicorn server:app --port {{port}} --reload --reload-include '*.py' --reload-include '.env.local' --env-file .env.local\" \"cd frontend && pnpm exec vite\"",
16
16
  "dev:backend": "minus-dev-cleanup && mkdir -p .minus && echo $$ > .minus/backend.pid && .venv/bin/uvicorn server:app --port {{port}} --reload --reload-include '*.py' --reload-include '.env.local' --env-file .env.local",
17
+ "dev:win": "minus-dev --port {{port}}",
18
+ "dev:win:backend": "minus-dev --port {{port}} --backend-only",
17
19
  "build": "cd frontend && pnpm run build"
18
20
  },
19
21
  "devDependencies": {
20
- "@minus-ai/dev-vite-plugin": "^0.1.0-beta.8",
22
+ "@minus-ai/dev-vite-plugin": "^0.1.0-beta.12",
21
23
  "concurrently": "^9.1.2"
22
24
  }
23
25
  }