@mawaru/sdk 0.27.0 → 0.29.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.
@@ -1,5 +1,10 @@
1
1
  import { describe, expect, it } from "vitest"
2
- import { AI_MODELS, aiManifestSchema } from "./ai-manifest.js"
2
+ import {
3
+ AI_MODEL_GROUPS,
4
+ AI_MODELS,
5
+ agentOfModel,
6
+ aiManifestSchema,
7
+ } from "./ai-manifest.js"
3
8
  import { instructionSchema } from "./port-spec.js"
4
9
 
5
10
  const textOutput = { type: "string" }
@@ -56,6 +61,25 @@ describe("aiManifestSchema", () => {
56
61
  ).toThrow()
57
62
  })
58
63
 
64
+ it("Codex のモデルも選べる(実行主体は model の接頭辞で決まる)", () => {
65
+ expect(
66
+ aiManifestSchema.parse({ ...valid, model: "gpt-6-astra" }).model,
67
+ ).toBe("gpt-6-astra")
68
+ for (const model of AI_MODEL_GROUPS.claude.models) {
69
+ expect(agentOfModel(model)).toBe("claude")
70
+ }
71
+ for (const model of AI_MODEL_GROUPS.codex.models) {
72
+ expect(agentOfModel(model)).toBe("codex")
73
+ }
74
+ // 各グループの既定はそのグループの選択肢に含まれる
75
+ expect(AI_MODEL_GROUPS.claude.models).toContain(
76
+ AI_MODEL_GROUPS.claude.default,
77
+ )
78
+ expect(AI_MODEL_GROUPS.codex.models).toContain(
79
+ AI_MODEL_GROUPS.codex.default,
80
+ )
81
+ })
82
+
59
83
  it("inputs は key 自由・1件以上(in / instruction の固定構成は廃止)", () => {
60
84
  // 0件は拒否
61
85
  expect(() => aiManifestSchema.parse({ ...valid, inputs: {} })).toThrow()
@@ -1,18 +1,54 @@
1
1
  import { z } from "zod"
2
2
  import { jsonSchemaSchema, PORT_KEY_PATTERN } from "./node.js"
3
3
 
4
- // AI ノードのモデル選択肢(既定は Opus:下書き品質が価値の中心。費用はユーザー持ち)。
5
- // エイリアス("opus" 等)は採らずバージョンを固定する:実行のたびに黙って別モデルへ
6
- // 乗り換わると品質も費用も再現しないため。新モデルが出たらこの配列を足して SDK を publish する
4
+ // AI ノードの実行主体(エージェント CLI)は Claude Code と Codex の2つ。Claude Code は Claude の
5
+ // モデルだけ、Codex は OpenAI のモデルだけを走らせるので、モデル ID と実行主体は 1:1。
6
+ // config.json に agent のようなフィールドは持たず、model の接頭辞(claude-* / gpt-*)で決まる
7
+ // (runner の _agents/index.ts と同じ規則。AI実行エージェントの抽象化(Claude CodeとCodex).md)。
8
+ //
9
+ // モデルはエイリアス("opus" 等)を採らずバージョンを固定する:実行のたびに黙って別モデルへ
10
+ // 乗り換わると品質も費用も再現しないため。新モデルが出たらこの配列を足して SDK を publish する。
11
+ // 既定は Opus:下書き品質が価値の中心。費用はユーザー持ち
12
+ export const AI_MODEL_GROUPS = {
13
+ claude: {
14
+ name: "Claude Code",
15
+ models: [
16
+ "claude-fable-5-1",
17
+ "claude-fable-5",
18
+ "claude-opus-5",
19
+ "claude-opus-4-8",
20
+ "claude-sonnet-5",
21
+ "claude-haiku-4-5",
22
+ ],
23
+ default: "claude-opus-5",
24
+ },
25
+ codex: {
26
+ name: "Codex",
27
+ models: [
28
+ "gpt-6-astra",
29
+ "gpt-5.6-sol",
30
+ "gpt-5.6-terra",
31
+ "gpt-5.6-luna",
32
+ "gpt-5.5",
33
+ ],
34
+ default: "gpt-6-astra",
35
+ },
36
+ } as const
37
+ export const AI_AGENT_IDS = ["claude", "codex"] as const
38
+ export const aiAgentIdSchema = z.enum(AI_AGENT_IDS)
39
+ export type AiAgentId = z.infer<typeof aiAgentIdSchema>
40
+
7
41
  export const AI_MODELS = [
8
- "claude-opus-5",
9
- "claude-opus-4-8",
10
- "claude-sonnet-5",
11
- "claude-haiku-4-5",
42
+ ...AI_MODEL_GROUPS.claude.models,
43
+ ...AI_MODEL_GROUPS.codex.models,
12
44
  ] as const
13
45
  export const aiModelSchema = z.enum(AI_MODELS)
14
46
  export type AiModel = z.infer<typeof aiModelSchema>
15
- export const DEFAULT_AI_MODEL = "claude-opus-5" satisfies AiModel
47
+ export const DEFAULT_AI_MODEL = AI_MODEL_GROUPS.claude.default satisfies AiModel
48
+
49
+ // モデル ID → 実行主体
50
+ export const agentOfModel = (model: AiModel): AiAgentId =>
51
+ model.startsWith("claude-") ? "claude" : "codex"
16
52
 
17
53
  // 入力口の宣言:スキーマ+実行属性。resume: true の口から入力が届いた実行は
18
54
  // 同じノードの直近セッションを復元して再開する(backend が ports.resume へ同期して
@@ -13,10 +13,16 @@ export declare const workspaceRepoName: (cwds: string[]) => string | null;
13
13
  export declare const findProjectDir: (cwd: string) => string | null;
14
14
  export type TranscriptRef = {
15
15
  url: string;
16
+ agent: "claude" | "codex";
16
17
  session_id: string;
18
+ local_path: string;
17
19
  redacted?: number;
18
20
  };
19
21
  export declare const fetchTranscriptRef: (credentials: Credentials, ref: StepRef) => Promise<TranscriptRef>;
20
22
  export declare const downloadTranscript: (url: string) => Promise<string>;
21
- export declare const placeTranscript: (cwd: string, sessionId: string, transcript: string) => string;
22
- export declare const spawnClaudeResume: (sessionId: string) => Promise<number>;
23
+ export declare const placeTranscript: (cwd: string, ref: Pick<TranscriptRef, "agent" | "session_id" | "local_path">, transcript: string) => string;
24
+ export declare const resumeCommand: (agent: TranscriptRef["agent"], sessionId: string) => {
25
+ bin: string;
26
+ args: string[];
27
+ };
28
+ export declare const spawnResume: (agent: TranscriptRef["agent"], sessionId: string) => Promise<number>;
@@ -1,7 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, } from "node:fs";
3
3
  import { homedir } from "node:os";
4
- import { join } from "node:path";
4
+ import { dirname, join } from "node:path";
5
5
  import { accessTokenFrom } from "./credentials.js";
6
6
  // UI がコピーさせる web の URL から tenant / run / step を取り出す。
7
7
  // 3つを1つの貼れる文字列で運ぶために URL の形にしている
@@ -28,6 +28,7 @@ export const parseStepUrl = (raw) => {
28
28
  return { tenantId, runId, stepId };
29
29
  };
30
30
  // transcript に記録された作業ディレクトリ(重複は畳み、最後に居た場所も返す)。
31
+ // Claude Code は各行のトップレベル `cwd`、Codex は先頭行 session_meta の `payload.cwd`。
31
32
  // **現在地がそこと違っていても resume 自体は通ってしまう**ので、人間に見せて確認を取る
32
33
  export const recordedCwds = (transcript) => {
33
34
  const all = [];
@@ -37,7 +38,8 @@ export const recordedCwds = (transcript) => {
37
38
  continue;
38
39
  let cwd;
39
40
  try {
40
- cwd = JSON.parse(line).cwd;
41
+ const parsed = JSON.parse(line);
42
+ cwd = parsed.cwd ?? parsed.payload?.cwd;
41
43
  }
42
44
  catch {
43
45
  continue;
@@ -64,6 +66,8 @@ export const workspaceRepoName = (cwds) => {
64
66
  return null;
65
67
  };
66
68
  const projectsRoot = () => join(process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), ".claude"), "projects");
69
+ // Codex の設定ルート(CLI 自身が CODEX_HOME を見るのでそれに合わせる)
70
+ const codexHome = () => process.env.CODEX_HOME ?? join(homedir(), ".codex");
67
71
  // 置き先のディレクトリを **規則を再実装せず観測で決める**(agent-runner の
68
72
  // _helpers/session.ts と同じ方針)。~/.claude/projects/*/*.jsonl の cwd を読み、
69
73
  // いま居るディレクトリと一致するものを選ぶ
@@ -113,25 +117,38 @@ export const downloadTranscript = async (url) => {
113
117
  }
114
118
  return await res.text();
115
119
  };
116
- // 置き先へ書き込む。ディレクトリが見つからないのは「この repo でまだ claude を
117
- // 起動していない」ケースなので、観測できるようにしてから再実行してもらう
118
- export const placeTranscript = (cwd, sessionId, transcript) => {
119
- const dir = findProjectDir(cwd);
120
- if (!dir) {
121
- throw new Error("このディレクトリの Claude Code プロジェクトが見つかりません。" +
122
- "ここで一度 `claude` を起動してから、もう一度実行してください。");
120
+ // 置き先へ書き込む。
121
+ // Claude Code は cwd から導出したディレクトリしか見ないので、現在地に対応する project dir を
122
+ // 観測で引き当てて置く。見つからないのは「この repo でまだ claude を起動していない」ケースなので、
123
+ // 観測できるようにしてから再実行してもらう。
124
+ // Codex は cwd に依らず sessions/ 配下を id で探すので、退避時の相対パスにそのまま置く
125
+ export const placeTranscript = (cwd, ref, transcript) => {
126
+ let file;
127
+ if (ref.agent === "codex") {
128
+ file = join(codexHome(), ref.local_path);
123
129
  }
124
- mkdirSync(dir, { recursive: true });
125
- const file = join(dir, `${sessionId}.jsonl`);
130
+ else {
131
+ const dir = findProjectDir(cwd);
132
+ if (!dir) {
133
+ throw new Error("このディレクトリの Claude Code プロジェクトが見つかりません。" +
134
+ "ここで一度 `claude` を起動してから、もう一度実行してください。");
135
+ }
136
+ file = join(dir, `${ref.session_id}.jsonl`);
137
+ }
138
+ mkdirSync(dirname(file), { recursive: true });
126
139
  writeFileSync(file, transcript);
127
140
  return file;
128
141
  };
129
- // stdio を引き継いで claude を起動する(そのまま対話に入る)
130
- export const spawnClaudeResume = (sessionId) => new Promise((resolve) => {
131
- const child = spawn("claude", ["--resume", sessionId], { stdio: "inherit" });
142
+ // エージェントごとの対話 resume コマンド
143
+ export const resumeCommand = (agent, sessionId) => agent === "codex"
144
+ ? { bin: "codex", args: ["resume", sessionId] }
145
+ : { bin: "claude", args: ["--resume", sessionId] };
146
+ // stdio を引き継いで CLI を起動する(そのまま対話に入る)
147
+ export const spawnResume = (agent, sessionId) => new Promise((resolve) => {
148
+ const { bin, args } = resumeCommand(agent, sessionId);
149
+ const child = spawn(bin, args, { stdio: "inherit" });
132
150
  child.on("error", () => {
133
- console.error("claude を起動できませんでした。Claude Code をインストールしてから `claude --resume " +
134
- `${sessionId}\` を実行してください。`);
151
+ console.error(`${bin} を起動できませんでした。インストールしてから \`${bin} ${args.join(" ")}\` を実行してください。`);
135
152
  resolve(1);
136
153
  });
137
154
  child.on("close", (code) => resolve(code ?? 0));
@@ -1,7 +1,7 @@
1
1
  import { homedir } from "node:os";
2
2
  import { dirname } from "node:path";
3
3
  import { requireCredentials } from "./credentials.js";
4
- import { downloadTranscript, fetchTranscriptRef, parseStepUrl, placeTranscript, recordedCwds, spawnClaudeResume, workspaceRepoName, } from "./resumeSession.js";
4
+ import { downloadTranscript, fetchTranscriptRef, parseStepUrl, placeTranscript, recordedCwds, spawnResume, workspaceRepoName, } from "./resumeSession.js";
5
5
  // ホーム配下は ~ に畳む(置き先は必ずホーム配下なので実質いつも効く)
6
6
  const tilde = (path) => {
7
7
  const home = homedir();
@@ -9,8 +9,9 @@ const tilde = (path) => {
9
9
  };
10
10
  // `mawaru session resume <step URL>`
11
11
  //
12
- // **確認は取らない。** 書くのは ~/.claude/projects/<現在地>/<sessionId>.jsonl の新規1ファイルだけで
13
- // repo には触れないので、場所を間違えても別プロジェクトの履歴に混ざるだけ=やり直せる。
12
+ // **確認は取らない。** 書くのはエージェントの設定ディレクトリ(~/.claude/projects/<現在地>/ か
13
+ // ~/.codex/sessions/<日付>/)への新規1ファイルだけで repo には触れないので、場所を間違えても
14
+ // 別プロジェクトの履歴に混ざるだけ=やり直せる。
14
15
  // **どこに cd すべきかは mawaru には分からない**(AI ノードの実行 repo と、エージェントが実際に
15
16
  // 触った repo は別物で、後者は setup.sh が workspace/ 配下に clone した対象 repo)ので推定して
16
17
  // 移動もしない。手がかりとして対象 repo 名だけ見せ、現在地と食い違うときに警告する
@@ -25,7 +26,7 @@ export const runSessionResume = async (stepUrl) => {
25
26
  const credentials = requireCredentials();
26
27
  const transcriptRef = await fetchTranscriptRef(credentials, ref);
27
28
  const transcript = await downloadTranscript(transcriptRef.url);
28
- console.log(`取得: セッション ${transcriptRef.session_id.slice(0, 8)}`);
29
+ console.log(`取得: セッション ${transcriptRef.session_id.slice(0, 8)}(${transcriptRef.agent})`);
29
30
  if (transcriptRef.redacted) {
30
31
  console.log(`(退避時に secret を ${transcriptRef.redacted} 箇所マスクしています)`);
31
32
  }
@@ -37,7 +38,7 @@ export const runSessionResume = async (stepUrl) => {
37
38
  console.log(`⚠ 現在地に ${repo} が含まれません。別 repo で再開しようとしているかもしれません(このまま続けます)`);
38
39
  }
39
40
  }
40
- const file = placeTranscript(cwd, transcriptRef.session_id, transcript);
41
+ const file = placeTranscript(cwd, transcriptRef, transcript);
41
42
  console.log(`復元先: ${tilde(dirname(file))}\n再開します…`);
42
- return await spawnClaudeResume(transcriptRef.session_id);
43
+ return await spawnResume(transcriptRef.agent, transcriptRef.session_id);
43
44
  };
@@ -1,13 +1,39 @@
1
1
  import { z } from "zod";
2
- export declare const AI_MODELS: readonly ["claude-opus-5", "claude-opus-4-8", "claude-sonnet-5", "claude-haiku-4-5"];
2
+ export declare const AI_MODEL_GROUPS: {
3
+ readonly claude: {
4
+ readonly name: "Claude Code";
5
+ readonly models: readonly ["claude-fable-5-1", "claude-fable-5", "claude-opus-5", "claude-opus-4-8", "claude-sonnet-5", "claude-haiku-4-5"];
6
+ readonly default: "claude-opus-5";
7
+ };
8
+ readonly codex: {
9
+ readonly name: "Codex";
10
+ readonly models: readonly ["gpt-6-astra", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.5"];
11
+ readonly default: "gpt-6-astra";
12
+ };
13
+ };
14
+ export declare const AI_AGENT_IDS: readonly ["claude", "codex"];
15
+ export declare const aiAgentIdSchema: z.ZodEnum<{
16
+ claude: "claude";
17
+ codex: "codex";
18
+ }>;
19
+ export type AiAgentId = z.infer<typeof aiAgentIdSchema>;
20
+ export declare const AI_MODELS: readonly ["claude-fable-5-1", "claude-fable-5", "claude-opus-5", "claude-opus-4-8", "claude-sonnet-5", "claude-haiku-4-5", "gpt-6-astra", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.5"];
3
21
  export declare const aiModelSchema: z.ZodEnum<{
22
+ "claude-fable-5-1": "claude-fable-5-1";
23
+ "claude-fable-5": "claude-fable-5";
4
24
  "claude-opus-5": "claude-opus-5";
5
25
  "claude-opus-4-8": "claude-opus-4-8";
6
26
  "claude-sonnet-5": "claude-sonnet-5";
7
27
  "claude-haiku-4-5": "claude-haiku-4-5";
28
+ "gpt-6-astra": "gpt-6-astra";
29
+ "gpt-5.6-sol": "gpt-5.6-sol";
30
+ "gpt-5.6-terra": "gpt-5.6-terra";
31
+ "gpt-5.6-luna": "gpt-5.6-luna";
32
+ "gpt-5.5": "gpt-5.5";
8
33
  }>;
9
34
  export type AiModel = z.infer<typeof aiModelSchema>;
10
- export declare const DEFAULT_AI_MODEL = "claude-opus-5";
35
+ export declare const DEFAULT_AI_MODEL: "claude-opus-5";
36
+ export declare const agentOfModel: (model: AiModel) => AiAgentId;
11
37
  export declare const aiInputDeclSchema: z.ZodObject<{
12
38
  schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
13
39
  resume: z.ZodOptional<z.ZodBoolean>;
@@ -18,10 +44,17 @@ export declare const aiManifestSchema: z.ZodObject<{
18
44
  description: z.ZodOptional<z.ZodString>;
19
45
  prompt: z.ZodString;
20
46
  model: z.ZodDefault<z.ZodEnum<{
47
+ "claude-fable-5-1": "claude-fable-5-1";
48
+ "claude-fable-5": "claude-fable-5";
21
49
  "claude-opus-5": "claude-opus-5";
22
50
  "claude-opus-4-8": "claude-opus-4-8";
23
51
  "claude-sonnet-5": "claude-sonnet-5";
24
52
  "claude-haiku-4-5": "claude-haiku-4-5";
53
+ "gpt-6-astra": "gpt-6-astra";
54
+ "gpt-5.6-sol": "gpt-5.6-sol";
55
+ "gpt-5.6-terra": "gpt-5.6-terra";
56
+ "gpt-5.6-luna": "gpt-5.6-luna";
57
+ "gpt-5.5": "gpt-5.5";
25
58
  }>>;
26
59
  skills: z.ZodDefault<z.ZodArray<z.ZodString>>;
27
60
  env: z.ZodDefault<z.ZodArray<z.ZodString>>;
@@ -1,16 +1,48 @@
1
1
  import { z } from "zod";
2
2
  import { jsonSchemaSchema, PORT_KEY_PATTERN } from "./node.js";
3
- // AI ノードのモデル選択肢(既定は Opus:下書き品質が価値の中心。費用はユーザー持ち)。
4
- // エイリアス("opus" 等)は採らずバージョンを固定する:実行のたびに黙って別モデルへ
5
- // 乗り換わると品質も費用も再現しないため。新モデルが出たらこの配列を足して SDK を publish する
3
+ // AI ノードの実行主体(エージェント CLI)は Claude Code と Codex の2つ。Claude Code は Claude の
4
+ // モデルだけ、Codex は OpenAI のモデルだけを走らせるので、モデル ID と実行主体は 1:1。
5
+ // config.json に agent のようなフィールドは持たず、model の接頭辞(claude-* / gpt-*)で決まる
6
+ // (runner の _agents/index.ts と同じ規則。AI実行エージェントの抽象化(Claude CodeとCodex).md)。
7
+ //
8
+ // モデルはエイリアス("opus" 等)を採らずバージョンを固定する:実行のたびに黙って別モデルへ
9
+ // 乗り換わると品質も費用も再現しないため。新モデルが出たらこの配列を足して SDK を publish する。
10
+ // 既定は Opus:下書き品質が価値の中心。費用はユーザー持ち
11
+ export const AI_MODEL_GROUPS = {
12
+ claude: {
13
+ name: "Claude Code",
14
+ models: [
15
+ "claude-fable-5-1",
16
+ "claude-fable-5",
17
+ "claude-opus-5",
18
+ "claude-opus-4-8",
19
+ "claude-sonnet-5",
20
+ "claude-haiku-4-5",
21
+ ],
22
+ default: "claude-opus-5",
23
+ },
24
+ codex: {
25
+ name: "Codex",
26
+ models: [
27
+ "gpt-6-astra",
28
+ "gpt-5.6-sol",
29
+ "gpt-5.6-terra",
30
+ "gpt-5.6-luna",
31
+ "gpt-5.5",
32
+ ],
33
+ default: "gpt-6-astra",
34
+ },
35
+ };
36
+ export const AI_AGENT_IDS = ["claude", "codex"];
37
+ export const aiAgentIdSchema = z.enum(AI_AGENT_IDS);
6
38
  export const AI_MODELS = [
7
- "claude-opus-5",
8
- "claude-opus-4-8",
9
- "claude-sonnet-5",
10
- "claude-haiku-4-5",
39
+ ...AI_MODEL_GROUPS.claude.models,
40
+ ...AI_MODEL_GROUPS.codex.models,
11
41
  ];
12
42
  export const aiModelSchema = z.enum(AI_MODELS);
13
- export const DEFAULT_AI_MODEL = "claude-opus-5";
43
+ export const DEFAULT_AI_MODEL = AI_MODEL_GROUPS.claude.default;
44
+ // モデル ID → 実行主体
45
+ export const agentOfModel = (model) => model.startsWith("claude-") ? "claude" : "codex";
14
46
  // 入力口の宣言:スキーマ+実行属性。resume: true の口から入力が届いた実行は
15
47
  // 同じノードの直近セッションを復元して再開する(backend が ports.resume へ同期して
16
48
  // payload 発行時に参照する。ポート型固定の撤去とセッション再開のポート属性化.md)
package/dist/cli.js CHANGED
@@ -16,7 +16,7 @@ const USAGE = `使い方: mawaru <command> [引数]
16
16
  login ブラウザで承認して mawaru にログインする(~/.mawaru/credentials.json)
17
17
  logout 保存した資格情報を消す
18
18
  session resume <step URL>
19
- AI ノードのセッションを手元に復元して claude --resume で再開する`;
19
+ AI ノードのセッションを手元に復元して CLI(claude / codex)の resume で再開する`;
20
20
  const [command, ...rest] = process.argv.slice(2);
21
21
  // init / typegen / validate は repo ルートを任意で受ける(省略時はカレント)
22
22
  const root = rest[0] ?? process.cwd();
@@ -46,12 +46,16 @@ skills/<dir>/ # AI ノードが参照する skill(SKILL.md)
46
46
 
47
47
  - `config.json` — 正は `_schemas/ai-manifest.ts`。`prompt`(必須)・`model`・
48
48
  `skills`(トップレベル `skills/` 配下のディレクトリ名)・`env`・`inputs` / `outputs`
49
+ - `model` が実行主体を決める:`claude-*` は Claude Code、`gpt-*` は Codex で走る
50
+ (選択肢は `AI_MODEL_GROUPS`)。認証は repo の Actions secrets に置く:Claude Code は
51
+ `ANTHROPIC_API_KEY`(または `CLAUDE_CODE_OAUTH_TOKEN`)、Codex は `OPENAI_API_KEY`
52
+ (`env` に宣言しなくても渡される)
49
53
  - `inputs` は1件以上・key 自由。値は `{ "schema": <JSON Schema>, "resume": true }` の形
50
54
  (`resume` は省略可。true の口から入力が届いた実行は、同じノードの直近セッションを
51
55
  復元して再開する——差し戻し→修正の続き実行に使う)。旧形式(値が素の JSON Schema)も
52
56
  読める
53
- - 実行時はラッパーが Claude Code(headless)を起動し、`outputs` のスキーマに適合する
54
- output を検証して報告する。出口が複数あれば AI が1つ選ぶ(複数出口=分岐)
57
+ - 実行時はラッパーがエージェント CLI(Claude Code / Codex、非対話)を起動し、`outputs` の
58
+ スキーマに適合する output を検証して報告する。出口が複数あれば AI が1つ選ぶ(複数出口=分岐)
55
59
  - **文体の既定は「短く」**:出力の文章は承認画面・Slack・顧客への回答としてそのまま人が読むため、
56
60
  ラッパーが枠組みプロンプトで「結論から・前置きや言い換えや締め文句を書かない・1文は短く」を
57
61
  常に指示している。長い文章(詳細なレポート等)が要るノードだけ `prompt` に長さ・文体を明示する
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mawaru/sdk",
3
- "version": "0.27.0",
3
+ "version": "0.29.0",
4
4
  "description": "mawaru 実行 repo の開発 SDK。契約スキーマ(config.json 規約・ループ graph API)の正 + typegen / validate CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -110,7 +110,7 @@ AI ノードの出力の文章は、承認画面・Slack・顧客への回答と
110
110
  「どこに何が置いてあるか」と、そこから先の判断だけを書く。
111
111
 
112
112
  理由:LLM にやらせるとトークンを食い flaky で、失敗が「セットアップの失敗」として明瞭に出ない。
113
- skill の配置は Claude Code 起動前に完了している必要もある。
113
+ skill の配置はエージェント CLI(Claude Code / Codex)の起動前に完了している必要もある。
114
114
 
115
115
  規約(実行 repo 側。config.json への宣言は不要、ファイルの存在が正):
116
116
 
@@ -122,7 +122,7 @@ cp -r workspace/repo/.claude/skills/some-skill skills/ # copySkills の前に
122
122
  printf '%s' "$SOME_SA_KEY" > workspace/key.json
123
123
  ```
124
124
 
125
- - 実行順は `env 注入 → input.json 書き出し → setup.sh → copySkills → 本体(Claude Code)`。
125
+ - 実行順は `env 注入 → input.json 書き出し → setup.sh → copySkills → 本体(エージェント CLI)`。
126
126
  `bash nodes/ai/<dir>/setup.sh "$INPUT_JSON"`(実行ビット不要)、cwd は checkout ルート。
127
127
  - **入力は `$1`(JSON 文字列)か `input.json`** で参照できる(`jq` はランナー同梱)。
128
128
  - **環境変数は config.json の `env` 宣言分だけ**が注入される。必要な secret は `env` に宣言し、
@@ -48,7 +48,7 @@ jobs:
48
48
 
49
49
  - name: write payload.json
50
50
  run: echo '${{ toJSON(github.event.client_payload) }}' > payload.json
51
- # SECRETS_JSON は全 repo secrets を注入するが、子プロセス(handler / Claude Code)には
51
+ # SECRETS_JSON は全 repo secrets を注入するが、子プロセス(handler / エージェント CLI)には
52
52
  # ラッパーが config.json の env 宣言分だけを展開して渡す(最小権限)
53
53
  # 実行時間の上限はラッパーが config.json の timeout_minutes(既定:program 30分 /
54
54
  # ai 360分)で締めて理由付きの failed を報告する。ここでは縛らず、暴走の最終