foundruu 0.1.0 → 0.2.0
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/README.md +27 -3
- package/dist/cli.js +21 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/plugins.d.ts +38 -0
- package/dist/core/plugins.js +58 -0
- package/dist/core/plugins.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,9 +9,13 @@ AI開発を標準化するためのプラットフォーム **FoundRuu** の CLI
|
|
|
9
9
|
## インストール
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npm install
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
npm install -g foundruu # または npx foundruu <command>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
ソースから使う場合:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install && npm run build && npm link
|
|
15
19
|
```
|
|
16
20
|
|
|
17
21
|
## コマンド
|
|
@@ -25,6 +29,7 @@ npm link # foundruu コマンドとして使えるようにする
|
|
|
25
29
|
| `foundruu update [--force]` | Workflow / Prompt / Rules を最新へ更新 |
|
|
26
30
|
| `foundruu session start <name>` / `session list` | AI開発セッションの作成 / 一覧 |
|
|
27
31
|
| `foundruu templates` | 利用可能なテンプレート一覧 |
|
|
32
|
+
| `foundruu plugins` | 読み込まれているプラグイン一覧 |
|
|
28
33
|
| `foundruu --help` / `--version` | ヘルプ / バージョン |
|
|
29
34
|
|
|
30
35
|
## 利用フロー
|
|
@@ -82,6 +87,25 @@ Docker / GitHub Actions / AI Rules / Workflow / Prompt / foundruu.json
|
|
|
82
87
|
`foundruu doctor --deep` は DevDoctor 由来の品質診断で、docs/(および最新の `.ai/sessions/`)の
|
|
83
88
|
要件・設計・テスト・AI指示ドキュメントをスコア化し、不足観点と改善案を提示します。
|
|
84
89
|
|
|
90
|
+
## プラグイン
|
|
91
|
+
|
|
92
|
+
`foundruu-plugin-*` という名前の npm パッケージを入れる(または `foundruu.json` の `plugins` にパスを書く)と自動で読み込まれ、コマンドと doctor チェックを拡張できます:
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
// foundruu-plugin-security/index.js
|
|
96
|
+
module.exports = {
|
|
97
|
+
name: "security",
|
|
98
|
+
register({ program, addDoctorCheck, log }) {
|
|
99
|
+
addDoctorCheck({
|
|
100
|
+
id: "security-md", label: "SECURITY.md", category: "セキュリティ",
|
|
101
|
+
severity: "warn", hint: "SECURITY.md を追加してください",
|
|
102
|
+
check: (ctx) => ctx.exists("SECURITY.md"),
|
|
103
|
+
});
|
|
104
|
+
program.command("audit").action(() => log.success("audit 実行"));
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
85
109
|
## GitHub Actions として使う
|
|
86
110
|
|
|
87
111
|
他リポジトリの PR チェックとして doctor を実行できます:
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,8 @@ const session_1 = require("./commands/session");
|
|
|
10
10
|
const config_1 = require("./core/config");
|
|
11
11
|
const logger_1 = require("./core/logger");
|
|
12
12
|
const templates_1 = require("./registry/templates");
|
|
13
|
+
const plugins_1 = require("./core/plugins");
|
|
14
|
+
const checks_1 = require("./doctor/checks");
|
|
13
15
|
const program = new commander_1.Command();
|
|
14
16
|
program
|
|
15
17
|
.name("foundruu")
|
|
@@ -85,5 +87,24 @@ program
|
|
|
85
87
|
logger_1.log.info(` ${t.id.padEnd(16)} ${t.label}${t.status === "planned" ? "(準備中)" : ""}`);
|
|
86
88
|
}
|
|
87
89
|
});
|
|
90
|
+
// プラグイン読み込み(コマンド・doctor チェックの拡張)
|
|
91
|
+
const loadedPlugins = (0, plugins_1.loadPlugins)(process.cwd(), {
|
|
92
|
+
program,
|
|
93
|
+
addDoctorCheck: (check) => checks_1.checks.push(check),
|
|
94
|
+
log: logger_1.log,
|
|
95
|
+
});
|
|
96
|
+
program
|
|
97
|
+
.command("plugins")
|
|
98
|
+
.description("読み込まれているプラグインを一覧表示する")
|
|
99
|
+
.action(() => {
|
|
100
|
+
if (loadedPlugins.length === 0) {
|
|
101
|
+
logger_1.log.info("プラグインは読み込まれていません。");
|
|
102
|
+
logger_1.log.info(" node_modules の foundruu-plugin-* または foundruu.json の plugins で追加できます。");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
for (const p of loadedPlugins) {
|
|
106
|
+
logger_1.log.info(` ${p.name.padEnd(24)} ${p.source}`);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
88
109
|
program.parse();
|
|
89
110
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AACA,yCAAoC;AACpC,0CAA0C;AAC1C,kDAAsD;AACtD,8CAAqD;AACrD,8CAA8C;AAC9C,gDAAgE;AAChE,0CAA2C;AAC3C,0CAAoC;AACpC,oDAAiD;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { DoctorCheck } from "../doctor/types";
|
|
3
|
+
import { log } from "./logger";
|
|
4
|
+
/**
|
|
5
|
+
* プラグインシステム。
|
|
6
|
+
*
|
|
7
|
+
* 読み込み対象:
|
|
8
|
+
* 1. プロジェクトの node_modules にある `foundruu-plugin-*` / `@scope/foundruu-plugin-*`
|
|
9
|
+
* 2. foundruu.json の `plugins` 配列(モジュール名 or 相対パス)
|
|
10
|
+
*
|
|
11
|
+
* プラグインは register(ctx) でコマンド追加・doctor チェック追加ができる:
|
|
12
|
+
*
|
|
13
|
+
* module.exports = {
|
|
14
|
+
* name: "my-plugin",
|
|
15
|
+
* register({ program, addDoctorCheck }) {
|
|
16
|
+
* program.command("hello").action(() => console.log("hi"));
|
|
17
|
+
* addDoctorCheck({ id: "...", label: "...", category: "...",
|
|
18
|
+
* severity: "warn", hint: "...", check: (ctx) => true });
|
|
19
|
+
* },
|
|
20
|
+
* };
|
|
21
|
+
*/
|
|
22
|
+
export interface PluginContext {
|
|
23
|
+
program: Command;
|
|
24
|
+
addDoctorCheck(check: DoctorCheck): void;
|
|
25
|
+
log: typeof log;
|
|
26
|
+
}
|
|
27
|
+
export interface FoundruuPlugin {
|
|
28
|
+
name: string;
|
|
29
|
+
register(ctx: PluginContext): void;
|
|
30
|
+
}
|
|
31
|
+
export interface LoadedPlugin {
|
|
32
|
+
name: string;
|
|
33
|
+
source: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* プラグインを発見して register を呼ぶ。壊れたプラグインは警告してスキップする。
|
|
37
|
+
*/
|
|
38
|
+
export declare function loadPlugins(cwd: string, ctx: PluginContext): LoadedPlugin[];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loadPlugins = loadPlugins;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const config_1 = require("./config");
|
|
10
|
+
const logger_1 = require("./logger");
|
|
11
|
+
const PLUGIN_PREFIX = "foundruu-plugin-";
|
|
12
|
+
function discoverNodeModules(cwd) {
|
|
13
|
+
const nm = path_1.default.join(cwd, "node_modules");
|
|
14
|
+
if (!fs_1.default.existsSync(nm))
|
|
15
|
+
return [];
|
|
16
|
+
const found = [];
|
|
17
|
+
for (const entry of fs_1.default.readdirSync(nm, { withFileTypes: true })) {
|
|
18
|
+
if (entry.name.startsWith(PLUGIN_PREFIX)) {
|
|
19
|
+
found.push(path_1.default.join(nm, entry.name));
|
|
20
|
+
}
|
|
21
|
+
else if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
22
|
+
for (const scoped of fs_1.default.readdirSync(path_1.default.join(nm, entry.name))) {
|
|
23
|
+
if (scoped.startsWith(PLUGIN_PREFIX))
|
|
24
|
+
found.push(path_1.default.join(nm, entry.name, scoped));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return found;
|
|
29
|
+
}
|
|
30
|
+
function configuredPlugins(cwd) {
|
|
31
|
+
const config = (0, config_1.readConfig)(cwd);
|
|
32
|
+
return (config?.plugins ?? []).map((p) => p.startsWith(".") || p.startsWith("/") ? path_1.default.resolve(cwd, p) : path_1.default.join(cwd, "node_modules", p));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* プラグインを発見して register を呼ぶ。壊れたプラグインは警告してスキップする。
|
|
36
|
+
*/
|
|
37
|
+
function loadPlugins(cwd, ctx) {
|
|
38
|
+
const specs = [...new Set([...discoverNodeModules(cwd), ...configuredPlugins(cwd)])];
|
|
39
|
+
const loaded = [];
|
|
40
|
+
for (const spec of specs) {
|
|
41
|
+
try {
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
43
|
+
const mod = require(spec);
|
|
44
|
+
const plugin = ("default" in mod ? mod.default : mod);
|
|
45
|
+
if (!plugin?.name || typeof plugin.register !== "function") {
|
|
46
|
+
logger_1.log.warn(`プラグインの形式が不正です(name / register が必要): ${spec}`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
plugin.register(ctx);
|
|
50
|
+
loaded.push({ name: plugin.name, source: spec });
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
logger_1.log.warn(`プラグインの読み込みに失敗しました: ${spec} (${err.message})`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return loaded;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=plugins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../src/core/plugins.ts"],"names":[],"mappings":"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"}
|