Skip to content
Open
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* `pos-cli mcp-config` — display and inspect the MCP server tool configuration (which tools are enabled/disabled). Supports `--json` for raw output. Configurable via `MCP_TOOLS_CONFIG` env var.
* `pos-cli lsp` — start the platformOS Language Server Protocol server for Liquid, GraphQL, and JSON files. Provides autocompletion, diagnostics, hover docs, and go-to-definition in LSP-compatible editors.
* `pos-cli check init [path]` — generate a `.platformos-check.yml` configuration file for the Liquid code quality checker.
* `pos-cli check run [path]` — run the platformos-check Node.js linter on Liquid/JSON files. Supports `-a` (auto-fix), `-f json` (JSON output), `-s` (silent). No Ruby required.
* `pos-cli check run [path]` — run the platformos-check Node.js linter on Liquid/JSON files. Supports `-a` (auto-fix), `-c, --check <name>` (filter by check name, repeatable), `-f json` (JSON output), `-s` (silent). No Ruby required.
* `pos-cli check update-docs` — download the latest platformOS Liquid documentation used by the linter, keeping checks like `UndefinedObject` and `UndefinedFilter` up to date.
* `pos-cli fetch-logs [environment]` — fetch recent logs as NDJSON (newline-delimited JSON), designed for machine consumption and used internally by the MCP server. Supports `--last-log-id` for incremental polling.
* `pos-cli exec liquid` — execute Liquid code directly on an instance (supports `-f` flag to load from file, requires confirmation on production)
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ The output includes:
#### Options

- `-a` - Enable automatic fixing of issues where possible
- `-c, --check <name>` - Only show offenses from the named check (repeatable, e.g. `-c UndefinedObject -c UnusedAssign`)
- `-f <format>` - Output format: `text` (default) or `json`
- `-s, --silent` - Only show errors, no success messages

Expand All @@ -162,6 +163,14 @@ Silent mode (no success message):

pos-cli check run -s

Filter by specific check:

pos-cli check run --check UndefinedObject

Filter by multiple checks:

pos-cli check run -c UndefinedObject -c UnusedAssign

Combined options:

pos-cli check run -a -f json
Expand Down
6 changes: 6 additions & 0 deletions bin/pos-cli-check-run.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ program
.description('check Liquid code quality with platformos-check linter')
.argument('[path]', 'path to check (defaults to current directory)', process.cwd())
.option('-a', 'enable automatic fixing')
.option('-c, --check <name>', 'only show offenses from the named check (repeatable)', collect, [])
.option('-f <format>', 'output format: text or json', 'text')
.option('-s, --silent', 'only show errors, no success messages')
.action(async (checkPath, options) => {
Expand All @@ -16,9 +17,14 @@ program
await run({
path: absolutePath,
autoFix: options.a || false,
checks: options.check.length > 0 ? options.check : undefined,
format: options.f || 'text',
silent: options.silent || false
});
});

function collect(value, previous) {
return previous.concat([value]);
}

program.parse(process.argv);
19 changes: 17 additions & 2 deletions lib/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,12 +350,25 @@ const initConfig = async (rootPath) => {
};

const run = async (opts) => {
const { path: checkPath, autoFix, format, silent } = opts;
const { path: checkPath, autoFix, checks, format, silent } = opts;

await validatePath(checkPath);

const platformosCheck = await loadPlatformosCheck();

if (checks && checks.length > 0) {
const validNames = new Set(platformosCheck.allChecks.map((c) => c.meta.code));
const unknown = checks.filter((name) => !validNames.has(name));
if (unknown.length > 0) {
const available = Array.from(validNames).sort().join(', ');
await logger.Error(
`Unknown check${unknown.length > 1 ? 's' : ''}: ${unknown.join(', ')}\n` +
`Available checks: ${available}`
);
return;
}
}

let offenses = [];
let spinner;
let app;
Expand All @@ -374,7 +387,9 @@ const run = async (opts) => {
}
});

offenses = result.offenses;
offenses = checks
? result.offenses.filter((o) => checks.includes(o.check))
: result.offenses;
app = result.app;

// Update spinner with completion info if it's still running
Expand Down
43 changes: 43 additions & 0 deletions test/integration/check.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,47 @@ describe('pos-cli check run', () => {
expect(json.files[0].offenses[0].severity).toEqual('warning');
});

test('Filter by check name with --check', async () => {
const { stdout, code } = await run('with-issues', '--check UndefinedObject');

expect(code).toEqual(1);
expect(stdout).toMatch('3 offenses found in 1 file');
expect(stdout).toMatch('UndefinedObject');
});

test('Errors on unknown check name', async () => {
const { stderr, code } = await run('with-issues', '--check NonExistentCheck');

expect(code).toEqual(1);
expect(stderr).toMatch('Unknown check: NonExistentCheck');
expect(stderr).toMatch('Available checks:');
});

test('Filter by check name with -c shorthand', async () => {
const { stdout, code } = await run('with-issues', '-c UndefinedObject');

expect(code).toEqual(1);
expect(stdout).toMatch('3 offenses found in 1 file');
expect(stdout).toMatch('UndefinedObject');
});

test('JSON output with --check filter', async () => {
const { stdout, code } = await run('with-issues', '-f json --check UndefinedObject');

expect(code).toEqual(1);

const json = JSON.parse(stdout);
expect(json.offenseCount).toEqual(3);
expect(json.files[0].offenses.every(o => o.check === 'UndefinedObject')).toBe(true);
});

test('JSON output errors on unknown check name', async () => {
const { stderr, code } = await run('with-issues', '-f json --check NonExistentCheck');

expect(code).toEqual(1);
expect(stderr).toMatch('Unknown check: NonExistentCheck');
});

test('Specific path argument', async () => {
const cwdPath = cwd('with-issues');
const specificPath = path.join(cwdPath, 'app/views/pages');
Expand Down Expand Up @@ -199,6 +240,8 @@ describe('pos-cli check run', () => {
expect(stdout).toMatch('Usage: pos-cli check run');
expect(stdout).toMatch('-a');
expect(stdout).toMatch('enable automatic fixing');
expect(stdout).toMatch('-c, --check <name>');
expect(stdout).toMatch('only show offenses from the named check');
expect(stdout).toMatch('-f <format>');
expect(stdout).toMatch('output format');
expect(stdout).toMatch('-s, --silent');
Expand Down
Loading