@minus-ai/create-skill 0.1.0-beta.13 → 0.1.0-beta.15

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
@@ -520,7 +520,11 @@ async function main() {
520
520
  const vars = { skillId: skillResult.id, folder, className, displayName, description, namespace, port, nodeVersion, nodeMajor: String(NODE_MAJOR_FLOOR) }
521
521
 
522
522
  // Backend files (pipeline.py from input-type subdir)
523
- writeOut(join(targetDir, 'pipeline.py'), render(readTemplate('pipeline.py.tpl', inputType), vars))
523
+ // 末尾统一追加 SDK 参考速查(纯注释单源模板),各场景模板不各自复制
524
+ writeOut(
525
+ join(targetDir, 'pipeline.py'),
526
+ render(readTemplate('pipeline.py.tpl', inputType), vars) + readTemplate('pipeline-reference.py.tpl')
527
+ )
524
528
  writeOut(join(targetDir, 'server.py'), render(readTemplate('server.py.tpl'), vars))
525
529
  writeOut(join(targetDir, 'pyproject.toml'), render(readTemplate('pyproject.toml.tpl'), vars))
526
530
  writeOut(join(targetDir, '.env.example'), render(readTemplate('env.example.tpl'), vars))
@@ -597,9 +601,11 @@ ${templateDocs[inputType] || templateDocs.custom}
597
601
 
598
602
  写代码前必须先了解 SDK 提供的能力,优先使用 SDK 已有的组件和方法,不要手写。
599
603
 
604
+ ⛔ 下面凡是 \`${platformUrl}/runtime/...\` 的远程文档,**一律用 \`curl -sSL '<url>'\` 抓取,不要用 WebFetch**:平台文档是 http + 非标准端口地址,WebFetch 连不上(TCP 层 ECONNREFUSED,与 http/https 无关),会把可达的文档误判成"读不到"而停止写代码。\`curl -sSL\` 走系统网络栈并自动跟随重定向,是唯一可靠取法;只有 \`curl\` 真的失败(连不上 / 非 2xx)才说明文档不可达。
605
+
600
606
  ### 开发手册
601
- 写前端代码前,读以下开发手册:
602
- - \`${platformUrl}/runtime/frontend-guide/doc.md\`
607
+ 写前端代码前,用 curl 抓取以下开发手册:
608
+ - \`curl -sSL '${platformUrl}/runtime/frontend-guide/doc.md'\`
603
609
  - 手册包含:前后端数据契约(StepOutcome → StepRenderCtx)、Widget 选型与用法(defineWidgetStep、内置 Interactive/Display Widget)、自定义 Widget 开发、多语言接入。
604
610
 
605
611
  ### 后端 SDK 参考
@@ -608,9 +614,9 @@ ${templateDocs[inputType] || templateDocs.custom}
608
614
  - \`PipelineContext\`:读 \`.venv/**/minus_ai_sdk/pipeline/context.py\`
609
615
 
610
616
  ### 前端 SDK 参考
611
- @minus/* 包通过平台 CDN 加载,本地无源码。写前端代码前,读以下文档了解可用 API:
612
- - Widget 框架:读 \`${platformUrl}/runtime/widget-framework/docs.md\`
613
- - 平台组件:读 \`${platformUrl}/runtime/platform-widgets/docs.md\`
617
+ @minus/* 包通过平台 CDN 加载,本地无源码。写前端代码前,用 curl 抓取以下文档了解可用 API:
618
+ - Widget 框架:\`curl -sSL '${platformUrl}/runtime/widget-framework/docs.md'\`
619
+ - 平台组件:\`curl -sSL '${platformUrl}/runtime/platform-widgets/docs.md'\`
614
620
 
615
621
  修改前端代码后,同步更新 \`frontend/src/locales/\` 下的多语言文件。
616
622
 
@@ -624,9 +630,10 @@ ${templateDocs[inputType] || templateDocs.custom}
624
630
  // README.md
625
631
  writeOut(join(targetDir, 'README.md'), render(readTemplate('README.md.tpl'), vars))
626
632
 
627
- // frontend/assets/ 和 tests/ 目录
633
+ // frontend/assets/ 和 tests/ 目录(pytest 骨架:新 skill 天生带测试)
628
634
  writeOut(join(targetDir, 'frontend', 'assets', '.gitkeep'), '')
629
- writeOut(join(targetDir, 'tests', '.gitkeep'), '')
635
+ writeOut(join(targetDir, 'tests', 'conftest.py'), render(readTemplate('conftest.py.tpl'), vars))
636
+ writeOut(join(targetDir, 'tests', 'test_pipeline.py'), render(readTemplate('test_pipeline.py.tpl'), vars))
630
637
 
631
638
  const rootPkgContent = render(readTemplate('root-package.json.tpl'), vars)
632
639
  const fePkgContent = render(readTemplate('frontend-package.json.tpl'), vars)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minus-ai/create-skill",
3
- "version": "0.1.0-beta.13",
3
+ "version": "0.1.0-beta.15",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "create-skill": "index.mjs"
@@ -0,0 +1,5 @@
1
+ import sys
2
+ from pathlib import Path
3
+
4
+ # 项目根加进 sys.path,使 `import pipeline` 与运行时(server.py 同目录启动)一致
5
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
@@ -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.12",
14
+ "@minus-ai/dev-vite-plugin": "^0.1.0-beta.14",
15
15
  "@types/node": "^{{nodeMajor}}.0.0",
16
16
  "@types/react": "^18.3.3",
17
17
  "@types/react-dom": "^18.3.0",
@@ -0,0 +1,14 @@
1
+
2
+
3
+ # ──────────────────────────────────────────────────────────────────────────────
4
+ # SDK 参考(纯注释,读懂后可整段删除)
5
+ #
6
+ # StepOutcome 三态与 ctx 能力(entry_params / previous_outputs / last_user_input /
7
+ # sif / llm / upload_file)的权威定义和用法,读已安装 SDK 的模块头注释与 docstring:
8
+ # .venv/**/minus_ai_sdk/pipeline/context.py
9
+ # .venv/**/minus_ai_sdk/pipeline/outcome.py
10
+ # 不要凭记忆写签名——以上述源码为准(SDK 会原地更新,文档随包发布永不过期)。
11
+ #
12
+ # 唯一容易写反的语义:StepOutcome.input_required 暂停后,用户提交的内容
13
+ # 挂在「下一步」的 ctx.last_user_input,而不是重跑本步。
14
+ # ──────────────────────────────────────────────────────────────────────────────
@@ -9,9 +9,16 @@ dependencies = [
9
9
  "uvicorn[standard]",
10
10
  ]
11
11
 
12
+ [project.optional-dependencies]
13
+ dev = ["pytest", "pytest-asyncio"]
14
+
12
15
  [tool.setuptools]
13
16
  py-modules = ["pipeline", "server"]
14
17
 
15
18
  [tool.uv]
16
19
  # SDK wheel 可能在同一版本号下更新过,安装时绕过本地缓存强制重新下载
17
20
  reinstall-package = ["minus-ai-sdk-python"]
21
+
22
+ [tool.pytest.ini_options]
23
+ asyncio_mode = "auto"
24
+ testpaths = ["tests"]
@@ -12,14 +12,12 @@
12
12
  },
13
13
  "workspaces": ["frontend"],
14
14
  "scripts": {
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
- "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",
19
- "build": "cd frontend && pnpm run build"
15
+ "dev": "minus-dev --port {{port}}",
16
+ "dev:backend": "minus-dev --port {{port}} --backend-only",
17
+ "build": "cd frontend && pnpm run build",
18
+ "test": ".venv/bin/pytest tests"
20
19
  },
21
20
  "devDependencies": {
22
- "@minus-ai/dev-vite-plugin": "^0.1.0-beta.12",
23
- "concurrently": "^9.1.2"
21
+ "@minus-ai/dev-vite-plugin": "^0.1.0-beta.14"
24
22
  }
25
23
  }
@@ -0,0 +1,35 @@
1
+ """pipeline step 函数的 payload 结构测试骨架。
2
+
3
+ 约定(与平台测试体系一致):
4
+ - 直接调用 step 函数,不起 HTTP/SSE;外部 API 用 monkeypatch mock。
5
+ - 断言 payload 的关键字段 + 类型,不断言会漂移的具体数据值。
6
+ 运行:.venv/bin/pytest(需先 .venv/bin/pip install pytest pytest-asyncio)
7
+ """
8
+ from types import SimpleNamespace
9
+
10
+ import pipeline as pl
11
+ from minus_ai_sdk import StepOutcome
12
+
13
+
14
+ class FakeContext:
15
+ """鸭子类型 PipelineContext:step 函数常用的成员。"""
16
+
17
+ def __init__(self, entry_params=None, last_user_input=None, previous_outputs=None):
18
+ self.entry_params = entry_params or {}
19
+ self.last_user_input = last_user_input or {}
20
+ self.previous_outputs = previous_outputs or {}
21
+ self.sif = SimpleNamespace() # 外部 API 客户端按需 monkeypatch
22
+ self.emitted = []
23
+
24
+ async def emit(self, message_type, payload=None):
25
+ self.emitted.append((message_type, payload))
26
+
27
+
28
+ async def test_step_1_returns_valid_outcome():
29
+ ctx = FakeContext(entry_params={})
30
+ outcome = await pl.{{className}}.step_1(SimpleNamespace(), ctx)
31
+ assert isinstance(outcome, StepOutcome)
32
+ assert isinstance(outcome.payload, dict)
33
+ # TODO: 按你的 step payload 契约补充关键字段断言,例如:
34
+ # assert outcome.kind.value == "input_required"
35
+ # assert isinstance(outcome.payload["rows"], list)