@witchpot/gmc 0.2.1 → 0.3.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/CHANGELOG.md +22 -0
- package/README.md +2 -0
- package/package.json +4 -1
- package/src/args.js +1 -0
- package/src/constants.js +4 -9
- package/src/help.js +15 -0
- package/src/requests.js +14 -15
- package/src/requests.test.js +35 -0
- package/src/workflows.js +23 -1589
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to the Game Market Copilot CLI will be recorded here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.3.0 - 2026-07-05
|
|
8
|
+
|
|
9
|
+
- Added `gmc tags` for tag taxonomy discovery: `gmc tags` lists the full
|
|
10
|
+
slug/name dictionary and `gmc tags --q <term> [--limit <number>]` searches
|
|
11
|
+
it. The endpoint is anonymous and unmetered, so agents can resolve a genre
|
|
12
|
+
or keyword to valid tag slugs before spending quota on `--tags` filters.
|
|
13
|
+
- Split shared, pure composition and analytics helpers (resolve/cohort/
|
|
14
|
+
showcase composers, deadline filtering) out of the CLI workflow layer and
|
|
15
|
+
into the new `@witchpot/gmc-core` package, now a published dependency of
|
|
16
|
+
this CLI. No command-facing behavior change.
|
|
17
|
+
- This release rides on server-side additions already live in the API:
|
|
18
|
+
- Tag filters on games search/count/aggregate/benchmark, review patterns,
|
|
19
|
+
and the marketing/creators/cohort/showcases workflows now validate and
|
|
20
|
+
canonicalize `--tags` slugs, rejecting unknown ones with a 400
|
|
21
|
+
`INVALID_TAG` error carrying `details.unknown_tags` and
|
|
22
|
+
`details.suggestions`. `gmc tags` is the recommended preflight for
|
|
23
|
+
resolving valid slugs before hitting these filters.
|
|
24
|
+
- The `market_aggregate` MCP tool gained `segment_filter`, which narrows
|
|
25
|
+
the base filter (AND) and reports `segment.matched`/`segment.ratio`
|
|
26
|
+
against the base cohort at no extra credit cost (not yet combinable
|
|
27
|
+
with `group_by`).
|
|
28
|
+
|
|
7
29
|
## 0.2.1 - 2026-07-04
|
|
8
30
|
|
|
9
31
|
- Updated `gmc update` to recommend the public `latest` npm dist-tag instead
|
package/README.md
CHANGED
|
@@ -91,6 +91,7 @@ Re-run install/print after `npm update` to pick up newer skill versions.
|
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
93
|
gmc schema --json
|
|
94
|
+
gmc tags --q roguelike --json
|
|
94
95
|
gmc update --json
|
|
95
96
|
gmc games search --source steam --release-year 2025 --reviews-min 1000 --fields title,appid,rating,reviews --json
|
|
96
97
|
gmc games aggregate --source steam --release-year 2025 --metric count,median_reviews --group-by release_year --reviews-min 1000 --json
|
|
@@ -107,6 +108,7 @@ when using output in agent answers.
|
|
|
107
108
|
- `gmc status`
|
|
108
109
|
- `gmc auth status`
|
|
109
110
|
- `gmc schema`
|
|
111
|
+
- `gmc tags`
|
|
110
112
|
- `gmc games search`
|
|
111
113
|
- `gmc games count`
|
|
112
114
|
- `gmc games aggregate`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@witchpot/gmc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Command line tools for Game Market Copilot market research.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
"engines": {
|
|
28
28
|
"node": ">=20.9.0"
|
|
29
29
|
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@witchpot/gmc-core": "^0.1.0"
|
|
32
|
+
},
|
|
30
33
|
"files": [
|
|
31
34
|
"bin",
|
|
32
35
|
"src",
|
package/src/args.js
CHANGED
package/src/constants.js
CHANGED
|
@@ -7,7 +7,7 @@ export const EXIT_CONFIG = 3;
|
|
|
7
7
|
export const EXIT_API = 4;
|
|
8
8
|
|
|
9
9
|
export const CLI_PACKAGE_NAME = "@witchpot/gmc";
|
|
10
|
-
export const CLI_VERSION = "0.
|
|
10
|
+
export const CLI_VERSION = "0.3.0";
|
|
11
11
|
|
|
12
12
|
export const DEFAULT_API_BASE_URL = "https://gamemarketcopilot.com";
|
|
13
13
|
export const DEFAULT_CONFIG_PATH = path.join(homedir(), ".config", "gmc", "config.json");
|
|
@@ -16,6 +16,8 @@ export const SUPPORTED_BETA_COMMANDS = [
|
|
|
16
16
|
"gmc status --json",
|
|
17
17
|
"gmc auth status --json",
|
|
18
18
|
"gmc schema --json",
|
|
19
|
+
"gmc tags --json",
|
|
20
|
+
"gmc tags --q <term> --json",
|
|
19
21
|
"gmc --version",
|
|
20
22
|
"gmc update --json",
|
|
21
23
|
"gmc skill install --json",
|
|
@@ -53,14 +55,7 @@ export const PROVISIONAL_BETA_COMMANDS = [
|
|
|
53
55
|
];
|
|
54
56
|
|
|
55
57
|
export const COMPARE_FOCUSES = ["overview", "market", "reviews", "marketing", "audience", "showcases"];
|
|
56
|
-
export
|
|
57
|
-
overview: [],
|
|
58
|
-
market: [],
|
|
59
|
-
reviews: ["reviews"],
|
|
60
|
-
marketing: ["marketing", "creators", "media"],
|
|
61
|
-
audience: ["reviews", "coverage", "creators"],
|
|
62
|
-
showcases: ["showcases"]
|
|
63
|
-
};
|
|
58
|
+
export { COMPARE_FOCUS_SECTIONS } from "@witchpot/gmc-core";
|
|
64
59
|
|
|
65
60
|
export const DEFAULT_BENCHMARK_LIMIT = "20";
|
|
66
61
|
export const DEFAULT_CAMPAIGN_SIGNALS_LIMIT = "30";
|
package/src/help.js
CHANGED
|
@@ -25,6 +25,8 @@ Usage:
|
|
|
25
25
|
gmc skill print --format agents-md
|
|
26
26
|
gmc skill status --json
|
|
27
27
|
gmc schema --json
|
|
28
|
+
gmc tags --json
|
|
29
|
+
gmc tags --q <term> --limit <number> --json
|
|
28
30
|
gmc lists --json
|
|
29
31
|
gmc lists create --name <name> --kind manual --json
|
|
30
32
|
gmc lists games <id> --json
|
|
@@ -56,6 +58,19 @@ Usage:
|
|
|
56
58
|
gmc showcases fit --source steam <externalId> --deadline-before <YYYY-MM-DD> --json
|
|
57
59
|
gmc showcases patterns --source steam --tags <tag_slug[,tag_slug...]> --json
|
|
58
60
|
|
|
61
|
+
Tag taxonomy:
|
|
62
|
+
gmc tags --json List the full tag dictionary (slug, name).
|
|
63
|
+
gmc tags --q <term> --json Search tags by free-text term.
|
|
64
|
+
gmc tags --q <term> --limit <number> --json
|
|
65
|
+
Cap the number of matches, 1-500 (default 50).
|
|
66
|
+
|
|
67
|
+
Commands that filter by --tags (games search/count/aggregate/benchmark,
|
|
68
|
+
reviews patterns, marketing/creators/cohort/showcases workflows) reject
|
|
69
|
+
unknown tag slugs with a 400 INVALID_TAG error and a
|
|
70
|
+
details.unknown_tags / details.suggestions payload. Run gmc tags --q
|
|
71
|
+
<term> first to resolve a genre or keyword to valid slugs before
|
|
72
|
+
building a --tags filter.
|
|
73
|
+
|
|
59
74
|
Binary aliases:
|
|
60
75
|
gmcp and game-market-copilot run the same CLI. Use them when a shell
|
|
61
76
|
alias shadows gmc (Oh My Zsh's git plugin defines gmc as
|
package/src/requests.js
CHANGED
|
@@ -14,6 +14,9 @@ import {
|
|
|
14
14
|
} from "./constants.js";
|
|
15
15
|
import { matches } from "./args.js";
|
|
16
16
|
import { writeJsonError } from "./output.js";
|
|
17
|
+
import { filterShowcasesByDeadline } from "@witchpot/gmc-core";
|
|
18
|
+
|
|
19
|
+
export { filterShowcasesByDeadline };
|
|
17
20
|
|
|
18
21
|
export function buildRequest(command, options, positional) {
|
|
19
22
|
if (matches(command, ["status"])) {
|
|
@@ -37,6 +40,17 @@ export function buildRequest(command, options, positional) {
|
|
|
37
40
|
};
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
if (matches(command, ["tags"])) {
|
|
44
|
+
const q = options.q ?? options.query;
|
|
45
|
+
return {
|
|
46
|
+
path: "/api/v1/tags",
|
|
47
|
+
query: {
|
|
48
|
+
...(q != null ? { q } : {}),
|
|
49
|
+
...pickQuery(options, { limit: "limit" })
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
40
54
|
if (matches(command, ["lists"])) {
|
|
41
55
|
return {
|
|
42
56
|
path: "/api/v1/lists",
|
|
@@ -886,18 +900,3 @@ function normalizeTagSlugCsv(value) {
|
|
|
886
900
|
.filter(Boolean)
|
|
887
901
|
.join(",");
|
|
888
902
|
}
|
|
889
|
-
|
|
890
|
-
export function filterShowcasesByDeadline(payload, deadlineBefore) {
|
|
891
|
-
if (!payload || !Array.isArray(payload.data)) return payload;
|
|
892
|
-
return {
|
|
893
|
-
...payload,
|
|
894
|
-
data: payload.data.filter((showcase) => {
|
|
895
|
-
if (!showcase || typeof showcase !== "object" || !showcase.deadline) return false;
|
|
896
|
-
return String(showcase.deadline) <= deadlineBefore;
|
|
897
|
-
}),
|
|
898
|
-
warnings: [
|
|
899
|
-
...(payload.warnings ?? []),
|
|
900
|
-
"deadline-before was applied client-side by the gmc CLI"
|
|
901
|
-
]
|
|
902
|
-
};
|
|
903
|
-
}
|
package/src/requests.test.js
CHANGED
|
@@ -39,6 +39,41 @@ test("games success-report forwards locale", () => {
|
|
|
39
39
|
assert.deepEqual(request.query, { locale: "ja" });
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
+
test("tags builds the full-dictionary request plan", () => {
|
|
43
|
+
const request = buildRequestFromArgv(["tags", "--json"]);
|
|
44
|
+
|
|
45
|
+
assert.equal(request.path, "/api/v1/tags");
|
|
46
|
+
assert.deepEqual(request.query, {});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("tags forwards --q as the q query param", () => {
|
|
50
|
+
const request = buildRequestFromArgv(["tags", "--q", "roguelike", "--json"]);
|
|
51
|
+
|
|
52
|
+
assert.equal(request.path, "/api/v1/tags");
|
|
53
|
+
assert.deepEqual(request.query, { q: "roguelike" });
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("tags accepts --query as an alias for --q", () => {
|
|
57
|
+
const request = buildRequestFromArgv(["tags", "--query", "roguelike", "--json"]);
|
|
58
|
+
|
|
59
|
+
assert.equal(request.path, "/api/v1/tags");
|
|
60
|
+
assert.deepEqual(request.query, { q: "roguelike" });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("tags forwards --limit alongside --q", () => {
|
|
64
|
+
const request = buildRequestFromArgv([
|
|
65
|
+
"tags",
|
|
66
|
+
"--q",
|
|
67
|
+
"deck",
|
|
68
|
+
"--limit",
|
|
69
|
+
"10",
|
|
70
|
+
"--json"
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
assert.equal(request.path, "/api/v1/tags");
|
|
74
|
+
assert.deepEqual(request.query, { q: "deck", limit: "10" });
|
|
75
|
+
});
|
|
76
|
+
|
|
42
77
|
test("games detail request plan stays unchanged", () => {
|
|
43
78
|
const request = buildRequestFromArgv([
|
|
44
79
|
"games",
|