Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .Knowledge/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
| f2s-req-tech | `.Knowledge/topics/f2s-req-tech.md` | 生成技术方案文档(全端通用,含后端/前端/全栈等) | 模板:[技术方案模版](template/技术方案模版.md);技能:`skills/f2s-req-tech/SKILL.md` |
| f2s-dev-workflow-constraints | `.Knowledge/topics/f2s-dev-workflow-constraints.md` | 开发工作流约束(仅 Flow2Spec 本仓自身,不给下游):只改 templates / 不改配置根 / 用户驱动分发 | 长文:`rules/repo-dev-workflow-constraints.*`;自查技能:`skills/repo-dev-check/SKILL.md` |
| f2s-kb-distill | `.Knowledge/topics/f2s-kb-distill.md` | Q&A 驱动知识提取;自动判断创建新 topic 或追加现有 topic | 技能:skills/f2s-kb-distill/SKILL.mdc |
| flow2spec-init-defaults | `.Knowledge/topics/f2s-init-defaults.md` | `flow2spec init` 字段默认值、四处落点一致性、老项目缺字段补写、`init` 不动 stock/req/topics/matchers、manifest 两个版本字段(`projectRev` / `pkgRev`)对照 | 包源码:`lib/flow2specConfig.js` `DEFAULTS` / `CONFIG_FIELDS`;模板:`templates/{locale}/flow2spec.config.json` |
| flow2spec-init-defaults | `.Knowledge/topics/f2s-init-defaults.md` | `flow2spec init` 字段默认值、四处落点一致性、老项目缺字段补写、init 目标与插件模式(`init plugin`)、`init` 不动 stock/req/topics/matchers、manifest 两个版本字段(`projectRev` / `pkgRev`)对照 | 包源码:`lib/flow2specConfig.js` `DEFAULTS` / `CONFIG_FIELDS`;模板:`templates/{locale}/flow2spec.config.json` |
| flow2spec-doctor | `.Knowledge/topics/flow2spec-doctor.md` | `flow2spec doctor` 只读检查环境、项目初始化、协作上下文与知识库健康 | stock:[Doctor 诊断命令](stock-docs/Flow2Spec-doctor诊断命令.md);中英文命令文档:`docs/命令说明.md` / `docs/en/commands-reference.md` |
| flow2spec-dsh-adapter | `.Knowledge/topics/flow2spec-dsh-adapter.md` | `flow2spec init dsh`、DeepSeek Harness 项目技能发现与 `.dsh/` 目录适配 | 用户文档:`docs/使用说明.md` / `docs/en/usage-guide.md`;实现:`lib/dshAgentsAdapter.js` |
| flow2spec-core-package | `.Knowledge/topics/flow2spec-core-package.md` | `@double-coding/flow2spec-core` 职责边界:核心实现、发包模板真源、原生插件 API 与 CLI/legacy shim 消费关系 | 开发者文档:`packages/core/README.md`;入口:`packages/core/index.js` |
Expand Down
4 changes: 3 additions & 1 deletion .Knowledge/matchers/m-flow2spec-init-defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"codexAgentsAdapter",
"renderProjectConfigBlock",
"init 默认翻面",
"AGENTS init 默认列"
"AGENTS init 默认列",
"init plugin",
"插件模式初始化"
],
"id": "m-flow2spec-init-defaults",
"version": "1.0.0",
Expand Down
12 changes: 11 additions & 1 deletion .Knowledge/topics/f2s-init-defaults.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
id: flow2spec-init-defaults
revision: 1
revision: 2
summary: "flow2spec-init-defaults(路由摘要)"
primary: config
confidence: inferred
Expand Down Expand Up @@ -46,6 +46,16 @@ tags: [policy]

「当前默认值」一栏以包模板 `packages/core/templates/zh-CN/flow2spec.config.json` 为锚,作变更前先核对该文件。

## init 目标与插件模式(plugin)

`AGENTS` 注册表(`packages/core/lib/agents.js`)含五个 init 目标:`cursor` / `claude` / `codex` / `dsh` / `plugin`。

- **`plugin` 是 `root: null` 的虚拟目标**:面向能力由客户端插件提供的场景(如 Qoder 插件市场用户),skills/rules/hooks 随插件安装在用户级,项目侧无需镜像。
- **`flow2spec init plugin` 行为**:仅落 `.Knowledge/` 模板 + 路由骨架 + `pkgRev`、`flow2spec.config.json` 缺失字段问答与 `.gitignore` 补齐;不创建任何配置根目录,不生成根 `AGENTS.md`,不写 hooks。
- **实现形态**:`init.js` 主循环对 `root: null` 的 id 直接跳过 agent 专属动作;未来新的插件化客户端复用同一路径,不需新增专属目标。
- **doctor 配套判定**:无任何配置根时,缺根 `AGENTS.md` 与缺配置根均为 **warning**(提示插件模式属正常);存在 `.codex` / `.dsh` 时缺根 `AGENTS.md` 仍为 error。
- 回归:`scripts/test-plugin-init.js`。

### 默认值变更记录

- **2026-06**:`subAgent` / `switchAgentVerification` / `intentRecognition` 三项默认值由 `false` 翻面为 `true`。新项目 init 默认即开启子 agent 编排、交叉校验与意图识别自动分流。老项目(已写过这三项)不受影响;仅在升级时**仍缺该字段**的老项目会按新默认 `true` 补齐。`changeTracking.fix` 维持 `false`(显式排除翻面)。
Expand Down
4 changes: 2 additions & 2 deletions .Knowledge/topics/flow2spec-qoder-plugin.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
id: flow2spec-qoder-plugin
revision: 1
revision: 2
summary: "Qoder 原生插件构建:从 Core 全量生成 skills/rules/hooks 并打包 zip"
primary: feature
confidence: inferred
Expand All @@ -25,7 +25,7 @@ tags: [module]
- 构建脚本:`scripts/build-qoder-plugin.js`(npm script `build:qoder-plugin`)
- 内容事实源:`packages/core/index.js` 的 `resources` API 与 `packages/core/templates/`(包边界与版本契约见 `flow2spec-core-package` 主题)
- 产物目录:`output/qoder-plugin/`(已 gitignore;每次构建先清空重建)
- 插件使用前提:目标项目须先 `npx @double-coding/flow2spec init` 生成 `.Knowledge/` 与 `flow2spec.config.json`
- 插件使用前提:目标项目须先 `npx @double-coding/flow2spec init plugin`(插件模式:仅生成 `.Knowledge/` 与 `flow2spec.config.json`,不写客户端配置根;目标语义见 `flow2spec-init-defaults` 主题)

## 禁止项

Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"node": ">=16"
},
"scripts": {
"test": "node cli.js --help && node cli.js kb check && node scripts/sync-package-readme.js --check && node scripts/test-workspace-version.js && node scripts/test-cli-update.js && node scripts/test-knowledge-engine.js && node scripts/test-developer-id.js && node scripts/test-template-knowledge.js && node scripts/test-init-gitignore.js && node scripts/test-dsh-init.js && node scripts/test-doctor.js && node scripts/test-core-api.js && node scripts/test-package-install.js",
"test": "node cli.js --help && node cli.js kb check && node scripts/sync-package-readme.js --check && node scripts/test-workspace-version.js && node scripts/test-cli-update.js && node scripts/test-knowledge-engine.js && node scripts/test-developer-id.js && node scripts/test-template-knowledge.js && node scripts/test-init-gitignore.js && node scripts/test-dsh-init.js && node scripts/test-plugin-init.js && node scripts/test-doctor.js && node scripts/test-core-api.js && node scripts/test-package-install.js",
"test:core": "node scripts/test-core-api.js",
"test:cli": "node cli.js --help && node cli.js doctor --json",
"sync:agents": "node cli.js init cursor claude codex",
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ agent(可多个,空格分隔;省略时交互选择):
flow2spec init <agent> <agent> # 同时初始化多个客户端
flow2spec init <agent> --locale en-US # 使用英文模板初始化指定客户端
flow2spec init dsh # 初始化 DeepSeek Harness 项目技能
flow2spec init plugin # 插件模式客户端(如 Qoder 插件):仅初始化知识库与配置
flow2spec init --yes # 跳过所有问答,使用默认值(适合 CI)
flow2spec init --reset-knowledge # 强制用模板覆盖 .Knowledge(谨慎)

Expand Down Expand Up @@ -888,6 +889,8 @@ if (sub === "init") {
.then(({ ids, knowledgeResult, routingUpgrade, indexSnapshot, gitignoreResult, projectConfig, locale, claudeHooksResult }) => {
const lines = ids.map((id) => {
const { root, label } = AGENTS[id];
if (!root)
return ` - ${label}:仅 .Knowledge/ 与 ${CONFIG_FILENAME}(skills/rules/hooks 由客户端插件提供)`;
if (id === "codex")
return ` - ${root}/:(${label})skills/、topics/、hooks/、hooks.json、AGENTS.md(指针);仓库根 AGENTS.md(完整)`;
if (id === "dsh")
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@double-coding/flow2spec",
"version": "3.5.0",
"version": "3.6.0",
"description": "在业务仓库初始化文档驱动、可写回知识库的 AI 协作骨架",
"homepage": "https://github.com/double-coding-lab/Flow2Spec#readme",
"repository": {
Expand All @@ -19,7 +19,7 @@
"README.md"
],
"dependencies": {
"@double-coding/flow2spec-core": "^3.5.0"
"@double-coding/flow2spec-core": "^3.6.0"
},
"publishConfig": {
"access": "public",
Expand Down
4 changes: 4 additions & 0 deletions packages/core/lib/agents.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
/**
* flow2spec init 支持的 AI 工具配置目录。
* 知识库统一写入项目根 `.Knowledge/`(含 template),rules/skills 保留在各配置根。
* `root: null` 表示虚拟目标(如 plugin 插件模式):不写任何配置根,
* skills/rules/hooks 由客户端插件提供,项目侧仅落 .Knowledge 与 flow2spec.config.json。
*/
const AGENTS = {
cursor: { root: ".cursor", label: "Cursor" },
claude: { root: ".claude", label: "Claude" },
codex: { root: ".codex", label: "Codex" },
dsh: { root: ".dsh", label: "DeepSeek Harness" },
plugin: { root: null, label: "插件模式(仅知识库,能力由客户端插件提供)" },
};

const KNOWLEDGE_ROOT = ".Knowledge";
Expand All @@ -16,6 +19,7 @@ const AGENT_SUBDIRS = {
claude: ["rules", "skills"],
codex: ["skills"],
dsh: ["skills", "topics"],
plugin: [],
};

/**
Expand Down
19 changes: 12 additions & 7 deletions packages/core/lib/doctor.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,20 @@ function runDoctor(cwd = process.cwd(), options = {}) {
}

const agentsPath = path.join(cwd, "AGENTS.md");
const needsAgentsEntry = [".codex", ".dsh"].some((root) =>
fs.existsSync(path.join(cwd, root)),
);
checks.push(
fs.existsSync(agentsPath)
? makeCheck("agents-entry", "项目入口", STATUS.pass, "根 AGENTS.md 已就绪。")
: makeCheck(
"agents-entry",
"项目入口",
STATUS.error,
"缺少根 AGENTS.md。",
"运行 flow2spec init codex 或 flow2spec init dsh,或重新初始化所需 Agent。",
needsAgentsEntry ? STATUS.error : STATUS.warning,
needsAgentsEntry
? "缺少根 AGENTS.md。"
: "未检测到根 AGENTS.md(插件模式项目属正常)。",
"Codex/DSH 用户运行 flow2spec init codex 或 flow2spec init dsh;插件模式(flow2spec init plugin)无需此文件。",
),
);

Expand Down Expand Up @@ -211,17 +216,17 @@ function runDoctor(cwd = process.cwd(), options = {}) {
claude: ["settings.json"],
cursor: ["hooks.json"],
};
const initializedAgents = Object.entries(AGENTS).filter(([, agent]) =>
fs.existsSync(path.join(cwd, agent.root)),
const initializedAgents = Object.entries(AGENTS).filter(
([, agent]) => agent.root && fs.existsSync(path.join(cwd, agent.root)),
);
if (initializedAgents.length === 0) {
checks.push(
makeCheck(
"agent-roots",
"Agent 配置",
STATUS.warning,
"未检测到 .codex、.claude、.cursor 或 .dsh 配置根。",
"运行 flow2spec init <agent> 初始化实际使用的 Agent。",
"未检测到 .codex、.claude、.cursor 或 .dsh 配置根(插件模式项目属正常)。",
"使用本地客户端时运行 flow2spec init <agent>;插件模式(flow2spec init plugin)无需配置根。",
),
);
} else {
Expand Down
2 changes: 2 additions & 0 deletions packages/core/lib/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,8 @@ async function run(cwd, agentIds, options = {}) {

const claudeHooksResult = {};
for (const id of ids) {
// 虚拟目标(root: null,如 plugin 插件模式):能力由客户端插件提供,不写配置根。
if (!AGENTS[id].root) continue;
ensureAgentDirs(cwd, id);
writeAgentArtifacts(cwd, id, templatesDir, projectConfig);
if (id === "claude") {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@double-coding/flow2spec-core",
"version": "3.5.0",
"version": "3.6.0",
"templateVersion": "3.5.0",
"description": "Flow2Spec Core APIs, knowledge engine, project initialization and shared resources",
"homepage": "https://github.com/double-coding-lab/Flow2Spec#readme",
Expand Down
2 changes: 1 addition & 1 deletion scripts/build-qoder-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ ${hookList}

## 使用前提(重要)

1. **目标项目须先初始化 Flow2Spec**:项目根执行 \`npx @double-coding/flow2spec init\`,生成 \`.Knowledge/\`(知识路由)与 \`flow2spec.config.json\`(编排开关);未初始化时技能会提示先执行 init。
1. **目标项目须先初始化 Flow2Spec**:项目根执行 \`npx @double-coding/flow2spec init plugin\`(插件模式:仅生成 \`.Knowledge/\` 知识路由与 \`flow2spec.config.json\` 编排开关,不写任何客户端配置根);未初始化时技能会提示先执行 init。
2. **Hooks 依赖 Node.js**(>=16)在 PATH 中可用;hooks 仅做提醒/检测,不替代技能正文的 \`Read("flow2spec.config.json")\` 门禁。

## 来源与说明
Expand Down
14 changes: 7 additions & 7 deletions scripts/test-cli-update.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ if (process.platform === "win32") {
fs.writeFileSync(path.join(tempDir, "npm.cmd"), [
"@echo off",
"if \"%2\"==\"@double-coding/flow2spec-core\" (",
" echo {\"version\":\"3.6.0\",\"templateVersion\":\"3.5.0\"}",
" echo {\"version\":\"3.6.1\",\"templateVersion\":\"3.5.0\"}",
") else (",
" echo 3.5.1",
" echo 3.6.1",
")",
"",
].join("\r\n"), "utf8");
Expand All @@ -24,9 +24,9 @@ if (process.platform === "win32") {
fs.writeFileSync(npmPath, [
"#!/usr/bin/env sh",
"if [ \"$2\" = \"@double-coding/flow2spec-core\" ]; then",
" echo '{\"version\":\"3.6.0\",\"templateVersion\":\"3.5.0\"}'",
" echo '{\"version\":\"3.6.1\",\"templateVersion\":\"3.5.0\"}'",
"else",
" echo '3.5.1'",
" echo '3.6.1'",
"fi",
"",
].join("\n"), { encoding: "utf8", mode: 0o755 });
Expand All @@ -43,10 +43,10 @@ const check = spawnSync(process.execPath, [cliPath, "update", "--check"], {
encoding: "utf8",
});
assert.strictEqual(check.status, 0, check.stderr);
assert.match(check.stdout, /CLI:\s+3\.5\.0 -> 3\.5\.1/);
assert.match(check.stdout, /Core:\s+3\.5\.0 -> 3\.6\.0/);
assert.match(check.stdout, /CLI:\s+3\.6\.0 -> 3\.6\.1/);
assert.match(check.stdout, /Core:\s+3\.6\.0 -> 3\.6\.1/);
assert.match(check.stdout, /Template:\s+3\.5\.0 -> 3\.5\.0/);
assert.match(check.stdout, /\^3\.5\.0 \(compatible\)/);
assert.match(check.stdout, /\^3\.6\.0 \(compatible\)/);

const invalid = spawnSync(process.execPath, [cliPath, "update", "--unknown"], {
cwd: path.resolve(__dirname, ".."),
Expand Down
11 changes: 7 additions & 4 deletions scripts/test-core-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const fs = require("fs");
const os = require("os");
const path = require("path");
const core = require("@double-coding/flow2spec-core");
const corePkg = require("../packages/core/package.json");

async function main() {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "flow2spec-core-"));
Expand All @@ -15,14 +16,14 @@ async function main() {
});

assert.strictEqual(typeof api.project.init, "function");
assert.deepStrictEqual(Object.keys(api.project.agents()), ["cursor", "claude", "codex", "dsh"]);
assert.deepStrictEqual(Object.keys(api.project.agents()), ["cursor", "claude", "codex", "dsh", "plugin"]);
assert.deepStrictEqual(api.config.supportedLocales(), ["zh-CN", "en-US"]);
assert.strictEqual(typeof api.knowledge.check, "function");
assert.strictEqual(core.getCapabilities().schema, "flow2spec.capabilities.v1");
assert.strictEqual(core.getCapabilities().protocolVersion, 2);
assert.deepStrictEqual(core.getVersions(), {
coreVersion: "3.5.0",
templateVersion: "3.5.0",
coreVersion: corePkg.version,
templateVersion: corePkg.templateVersion,
protocolVersion: 2,
});
assert.deepStrictEqual(
Expand Down Expand Up @@ -113,10 +114,12 @@ async function main() {
assert.strictEqual(update.templateUpdateAvailable, true);
assert.ok(update.notice.includes("f2s-kb-upgrade"));

// 模拟「Core-only 更新」:最新 Core 比当前高一个补丁号,模板不变
const [coreMajor, coreMinor, corePatch] = corePkg.version.split(".").map(Number);
fs.writeFileSync(
cachePath,
`${JSON.stringify({
latestCoreVersion: "3.6.0",
latestCoreVersion: `${coreMajor}.${coreMinor}.${corePatch + 1}`,
latestTemplateVersion: "1.0.0",
checkedAt: Date.now(),
})}\n`,
Expand Down
5 changes: 3 additions & 2 deletions scripts/test-init-gitignore.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const os = require("os");
const path = require("path");

const runInit = require("../packages/core/lib/init");
const corePkg = require("../packages/core/package.json");

(async () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "flow2spec-init-"));
Expand Down Expand Up @@ -32,8 +33,8 @@ const runInit = require("../packages/core/lib/init");
path.join(tmpRoot, agentRoot, "hooks", "f2s-update-check.js"),
"utf8",
);
assert(hook.includes("const GENERATED_CORE_VERSION = '3.5.0';"));
assert(hook.includes("const GENERATED_TEMPLATE_VERSION = '3.5.0';"));
assert(hook.includes(`const GENERATED_CORE_VERSION = '${corePkg.version}';`));
assert(hook.includes(`const GENERATED_TEMPLATE_VERSION = '${corePkg.templateVersion}';`));
assert(!hook.includes("__FLOW2SPEC_PACKAGE_NAME__"));
assert(!hook.includes("__FLOW2SPEC_CORE_VERSION__"));
assert(!hook.includes("__FLOW2SPEC_TEMPLATE_VERSION__"));
Expand Down
Loading
Loading