Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .claude/rules/repo-wide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Repo-wide review rules (Claude loader)

Loads the same repo-wide review rules Copilot uses, so Claude applies them during implementation. Edit `.github/copilot-instructions.md` — not this file.

@../../.github/copilot-instructions.md
11 changes: 11 additions & 0 deletions .claude/rules/tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
paths:
- "src/**/__tests__/**"
- "features/**"
---

# Test review rules (Claude loader)

Loads the same test review rules Copilot applies to vitest unit tests under `src/**/__tests__/**` and Cucumber E2E under `features/**`. Edit `.github/instructions/tests.instructions.md` — not this file.

@../../.github/instructions/tests.instructions.md
10 changes: 10 additions & 0 deletions .claude/rules/typescript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
paths:
- "src/**/*.ts"
---

# TypeScript review rules (Claude loader)

Loads the same TypeScript review rules Copilot applies to `src/**/*.ts`. Edit `.github/instructions/typescript.instructions.md` — not this file.

@../../.github/instructions/typescript.instructions.md
47 changes: 47 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copilot review instructions — cli-kintone

cli-kintone is the official kintone CLI (TypeScript, Node `>=20`, pnpm), **public OSS** under `kintone/`. Review PRs in this priority order. TS-specific and test-specific rules live in `.github/instructions/*.instructions.md`.

## Correctness

- Flag missing handling for rate-limit responses (HTTP 429). Surface a typed error and exit non-zero; do not swallow-and-retry forever.
- Flag generic "request failed" error messages that don't tell the user what to do. Map auth, not-found, and validation failures to actionable messages.
- Flag boundary / off-by-one bugs in pagination, batching, CSV / JSON row handling.

## Security

- Flag code that logs, prints, or returns API tokens, passwords, `Authorization` headers, basic-auth credentials, or session cookies. Redact before stdout / stderr / logs / error messages / thrown errors.
- Flag credentials, hostnames, customer data, or internal information committed to source, tests, fixtures, snapshots, or `features/`. Repo is public.
- Flag `child_process.exec` / shell concatenation from user input. Use `spawn` with argv.
- Flag path traversal: user-supplied paths must be normalized within the expected base.
- Flag disabled TLS (`rejectUnauthorized: false`, `NODE_TLS_REJECT_UNAUTHORIZED=0`) without an explicit user-facing flag.

## Code quality

- Flag hard-coded `/` in user-facing paths; use `path.join` / `path.resolve` (Windows is supported).
- Flag unused exports, dead code, `console.log` in non-CLI paths.
- Flag a new runtime dependency without justification in the PR description (`pkg` is sensitive to bundle size / native modules).

## Tests

- Behavior changes in `src/{record,customize,plugin,kintone}/` need a vitest test in the colocated `__tests__/`.
- User-visible CLI behavior needs a Cucumber feature / step update under `features/`.
- Flag tests that mock the unit under test, mock pure functions, or assert on mock-internal calls instead of observable behavior.
- Flag committed credentials or real kintone hostnames in fixtures.

## PRs

- PRs must fill in `.github/PULL_REQUEST_TEMPLATE.md` (Why / What / How to test / Checklist).

## Review style

- Concrete: cite file and line, name the risk, suggest the change. Avoid vague "consider improving readability".
- State **observed** impact ("breaks CSV import on BOM"), not a hypothetical edge case.
- Scope to the diff. Refactor ideas on surrounding code go in `suggestion:` only.
- Comment in English. Do not block on issues already enforced by ESLint / Prettier in CI.
- Use one of these prefixes (default = no prefix = blocking):
- **(no prefix)** — blocking. Bugs, security, type or test failures, public-OSS hygiene breaks. Must be addressed before merge.
- **`nit:`** — non-blocking polish (style, typo, naming). Author can ignore.
- **`question:`** — clarification of intent. May become blocking depending on the answer.
- **`suggestion:`** — non-blocking improvement, alternative, or refactor idea on surrounding code.
- Provide a GitHub-flavored `suggestion` code block when a concrete fix exists; `question:` needs none.
45 changes: 45 additions & 0 deletions .github/instructions/tests.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
applyTo: "src/**/__tests__/**,features/**"
---
Comment on lines +1 to +3

# Test review rules — vitest unit tests & Cucumber E2E

Apply in addition to `.github/copilot-instructions.md`.

## Layering

- vitest — colocated as `src/**/__tests__/*.test.ts`. Use for unit / integration of pure logic, parsers, formatters, and feature modules in `src/{record,customize,plugin,kintone}/`.
- Cucumber — `features/`. Use for user-visible CLI behavior: option parsing, exit codes, stdout / stderr format, file I/O against a real kintone environment.
- A behavior change that affects what the user sees on the command line needs a `features/` update, not only a vitest test.

## What to flag in vitest

- Mocking the unit under test, mocking pure functions, or asserting on mock call counts when the public output already encodes the behavior.

```ts
// ✗ over-mocked: asserts on the mock, not the behavior
const fn = vi.fn();
myCommand({ logger: fn });
expect(fn).toHaveBeenCalledWith("done");

// ✓ assert on the observable result
const result = await myCommand({ ... });
expect(result.status).toBe("ok");
```

- Wide `vi.mock("module")` calls when a narrow stub on the dependency would do.
- Snapshots of large objects without a clear reason — prefer field-level assertions.
- Tests that pass by mocking the kintone API to return exactly what the code expects without exercising any branch.
- Skipped (`.skip`) or focused (`.only`) tests left in the diff.

## What to flag in Cucumber (`features/`)

- New scenarios that hard-code credentials, real kintone subdomains, or app IDs. Use the env-driven setup in `features/supports/` (credentials loaded via env vars per `e2e-credentials-schema.json`).
- Step definitions that reach into internal modules in `src/`. Steps should drive the CLI as a black box (spawn the binary, assert stdout / stderr / exit code / file outputs).
- Background steps duplicated across scenarios that could be lifted to `Background:` blocks.

## Common to both

- Tests must not write outside their tmp dir, leak network calls in unit tests, or depend on test ordering.
- Failure messages should identify what was being verified, not just `expected true to be false`.
- New domain logic in `src/{record,customize,plugin}/` needs at least one vitest test; new CLI-visible behavior needs a `features/` scenario. Flag missing coverage.
56 changes: 56 additions & 0 deletions .github/instructions/typescript.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
applyTo: "src/**/*.ts"
---

# TypeScript review rules — `src/**`

Apply in addition to `.github/copilot-instructions.md`.

## Types

- Prefer types from `@kintone/rest-api-client` for kintone records, fields, app schemas, and API responses. Do not re-declare equivalent shapes locally — re-declaration drifts from the SDK on every update. Import from the top-level package; do not reach into internal subpaths.

```ts
// ✗ ad-hoc shape that drifts from the SDK
type Record = { $id: { value: string }; [k: string]: { value: unknown } };

// ✓ reuse SDK types via the public entry point
import type { KintoneRestAPIClient } from "@kintone/rest-api-client";
import { KintoneRestAPIError } from "@kintone/rest-api-client";
```

- Flag new `any`, `as any`, `as unknown as`, `@ts-ignore`, `@ts-expect-error` without an inline justification.
- Prefer `unknown` over `any` at boundaries (parsed JSON, file content), then narrow with a type guard.
- Use discriminated unions for command results instead of optional fields that are "always set together".

## Errors

- Command handlers in `src/cli/**` must not throw raw `Error`. Wrap with a typed error class (see `src/record/error/`) so the CLI can emit a useful exit code and message.
- `catch (e)` must narrow before use:

```ts
// ✓
} catch (e) {
if (e instanceof KintoneRestAPIError) { ... }
throw e;
}
```

- Error messages must not contain API tokens, passwords, or `Authorization` headers, even when re-throwing.

## Async & I/O

- All new I/O should be `async` with `node:fs/promises`. Flag `*Sync` calls outside of startup / scripts.
- Prefer `Promise.all` for independent calls. Flag accidental sequential `await` in loops over independent items.

## CLI options (`src/cli/**`)

- Option names are kebab-case (`--api-token`, `--app-id`, `--base-url`). Camel-case option names are wrong.
- Reuse shared builders from `src/cli/authOptions/`, `src/cli/connectionOptions.ts`, `src/cli/logOption.ts` instead of redeclaring `--base-url`, `--username`, `--password`, `--api-token`, `--basic-auth-*`, `--proxy`.
- New flags need a description suitable for `--help` and corresponding docs in `website/docs/reference/`.

## Imports & boundaries

- Use `import type { ... }` for type-only imports.
- No deep imports across feature boundaries (e.g. files under `src/record/` should not import private submodules of `src/customize/`). Use the feature's public entry (`src/<feature>/index.ts` style) or lift the shared code into `src/utils/` / `src/kintone/`.
- Domain logic does not live in `src/cli/**`. That layer wires yargs and delegates; logic lives in `src/{record,customize,plugin,kintone}/`.
77 changes: 77 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# cli-kintone

Official CLI for kintone. Bundles record / customize / plugin subcommands and ships as a Node.js package plus standalone executables (Linux x64, macOS arm64, Windows x64) produced via `ncc` + Node SEA (`pkg`).

For the documentation site (Docusaurus), see [`website/CLAUDE.md`](./website/CLAUDE.md).

## Repository layout

```
src/
├── cli/ # Entry points and yargs command wiring (main.ts is the entry)
│ ├── record/ # `cli-kintone record ...`
│ ├── customize/ # `cli-kintone customize ...`
│ ├── plugin/ # `cli-kintone plugin ...`
│ ├── authOptions/ # Shared --base-url / --username / --password / --api-token / --basic-auth-... flags
│ └── connectionOptions.ts, logOption.ts, stability.ts
├── record/ # Record import/export/delete domain logic
├── customize/ # JS customize apply/export/init logic
├── plugin/ # Plugin pack / upload / keygen / info logic
├── kintone/ # kintone API client wrappers (built on @kintone/rest-api-client)
└── utils/

features/ # Cucumber E2E (step_definitions/, supports/, plugin/, customize/, record/)
scripts/ # Build helpers (compress-to-zip-file.ts, update-contributors.ts)
plugin-templates/ # Scaffolding emitted by `cli-kintone plugin init`
website/ # Docusaurus docs (see website/CLAUDE.md)
.github/ # Workflows, PR template, Copilot review instructions
```

Unit tests live next to source as `__tests__/` directories using vitest.

## Toolchain

- Node `>=20` (`mise.toml` pins Node 24 for development)
- Package manager: **pnpm** — version pinned by `packageManager` in `package.json` (`mise.toml` also pins a pnpm version for development)
- Bundler: `@vercel/ncc` for single-file build, `pkg` (Node SEA) for native executables
- Linter / formatter: ESLint (`eslint.config.mjs`) + Prettier (`*.{json,md,yml,yaml}`)
- Tests: vitest (unit) + Cucumber (E2E, `features/`)
- Release: release-please with **Conventional Commits** (see `release-please-config.json`)

## Commands

| Command | Purpose |
| --- | --- |
| `pnpm build` | Clean `lib/` then `tsc --build tsconfig.build.json` |
| `pnpm start` | `build` in watch mode |
| `pnpm build:all` | Build + native executables + license analysis + zip |
| `pnpm typecheck` | `tsc --noEmit` against `tsconfig.typecheck.json` |
| `pnpm test` | vitest (unit) |
| `pnpm test:ci` | vitest with CI config |
| `pnpm test:e2e` | Cucumber E2E. Requires kintone credentials via env (see `features/supports/`) |
| `pnpm test:e2e:dev` | `test:e2e --fail-fast` |
| `pnpm lint` | `lint:eslint` + `lint:prettier` in parallel |
| `pnpm fix` | Auto-fix eslint + prettier |
| `pnpm doc:*` | Delegate to `website/` workspace |
| `./cli.js` | Run the locally built CLI |

Before submitting a change, run: `pnpm lint && pnpm typecheck && pnpm test`.

## Testing policy

- **Unit (vitest)**: colocated in `src/**/__tests__/`. Default to real implementations; mock only at external boundaries (HTTP, fs, kintone API).
- **E2E (Cucumber)**: lives in `features/`. Step definitions in `features/step_definitions/`. Each subcommand has its own subfolder. E2E runs against a real kintone environment using credentials from `e2e-credentials-schema.json`-shaped env vars; do not commit credentials.
- Add a vitest test when changing domain logic in `src/{record,customize,plugin,kintone}/`. Add or update a feature file when changing user-visible CLI behavior.

## Cross-repo dependencies

- Depends on `@kintone/rest-api-client` from `kintone/js-sdk`. When the SDK ships a breaking change, bump here and verify against `pnpm test:e2e`.
- Public docs live in `website/` and at <https://cli.kintone.dev/>.

## AI agent files

- `CLAUDE.md` (this file): implementation context for Claude.
- `website/CLAUDE.md`: Docusaurus-specific guidance for the docs workspace.
- `.github/copilot-instructions.md`: repo-wide review rules for GitHub Copilot. Single source of truth for review-time rules.
- `.github/instructions/*.instructions.md`: path-scoped Copilot review rules (`applyTo` frontmatter).
- `.claude/rules/*.md`: Claude-side path-scoped rule loaders. Each file declares `paths:` frontmatter and `@import`s the matching Copilot file so Claude follows the same rules without duplicating content. The Copilot files under `.github/` are the canonical source — edit them, not the loaders.
Loading