shopq 0.3.4 → 0.3.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # shopq
2
2
 
3
- [![CI](https://github.com/c-99-e/shopq/actions/workflows/ci.yml/badge.svg)](https://github.com/c-99-e/shopq/actions/workflows/ci.yml)
3
+ [![CI](https://github.com/c99e/shopq/actions/workflows/ci.yml/badge.svg)](https://github.com/c99e/shopq/actions/workflows/ci.yml)
4
4
  [![npm](https://img.shields.io/npm/v/shopq)](https://www.npmjs.com/package/shopq)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
6
  [![Bun](https://img.shields.io/badge/Bun-%3E%3D1.3-black?logo=bun)](https://bun.sh)
@@ -11,10 +11,20 @@ Built with AI agents as the primary user — structured JSON output, predictable
11
11
 
12
12
  ## Install
13
13
 
14
+ ### CLI
15
+
14
16
  ```bash
15
17
  bun install -g shopq
16
18
  ```
17
19
 
20
+ ### Pi coding agent
21
+
22
+ Install as a [pi package](https://shittycodingagent.ai/packages) to give your agent Shopify skills:
23
+
24
+ ```bash
25
+ pi install npm:shopq
26
+ ```
27
+
18
28
  ## Prerequisites
19
29
 
20
30
  - [Bun](https://bun.sh) v1.3+ (also works with Node.js v22+)
@@ -46,7 +56,7 @@ Bun loads `.env` automatically — no extra setup needed. shopq handles the OAut
46
56
  ### Development
47
57
 
48
58
  ```bash
49
- git clone https://github.com/c-99-e/shopq.git
59
+ git clone https://github.com/c99e/shopq.git
50
60
  cd shopq
51
61
  bun install
52
62
 
package/dist/cli.js ADDED
@@ -0,0 +1,247 @@
1
+ // @bun
2
+ // src/cli.ts
3
+ import { readFileSync } from "fs";
4
+
5
+ // src/registry.ts
6
+ var resources = new Map;
7
+ function getResource(name) {
8
+ return resources.get(name);
9
+ }
10
+ function getAllResources() {
11
+ return resources;
12
+ }
13
+
14
+ // src/help.ts
15
+ function topLevelHelp() {
16
+ const lines = [
17
+ "Usage: shopq <resource> <verb> [args] [flags]",
18
+ "",
19
+ "Global Flags:",
20
+ " --json, -j Output as JSON",
21
+ " --help, -h Show help",
22
+ " --version, -v Print version",
23
+ " --store <url> Store override",
24
+ " --no-color Disable colored output (also respects NO_COLOR env)",
25
+ ""
26
+ ];
27
+ const resources2 = getAllResources();
28
+ if (resources2.size > 0) {
29
+ lines.push("Resources:");
30
+ for (const [name, res] of resources2) {
31
+ lines.push(` ${name.padEnd(16)} ${res.description}`);
32
+ }
33
+ lines.push("");
34
+ }
35
+ return lines.join(`
36
+ `);
37
+ }
38
+ function resourceHelp(resourceName) {
39
+ const resource = getResource(resourceName);
40
+ if (!resource)
41
+ return;
42
+ const lines = [
43
+ `Usage: shopq ${resourceName} <verb> [args] [flags]`,
44
+ "",
45
+ `${resource.description}`,
46
+ "",
47
+ "Verbs:"
48
+ ];
49
+ for (const [verb, cmd] of resource.verbs) {
50
+ lines.push(` ${verb.padEnd(16)} ${cmd.description}`);
51
+ }
52
+ lines.push("");
53
+ return lines.join(`
54
+ `);
55
+ }
56
+
57
+ // src/parse.ts
58
+ function parseArgs(argv) {
59
+ const flags = {
60
+ json: false,
61
+ help: false,
62
+ version: false,
63
+ noColor: "NO_COLOR" in process.env
64
+ };
65
+ const positional = [];
66
+ let i = 0;
67
+ while (i < argv.length) {
68
+ const arg = argv[i];
69
+ if (arg === "--version" || arg === "-v") {
70
+ flags.version = true;
71
+ } else if (arg === "--help" || arg === "-h") {
72
+ flags.help = true;
73
+ } else if (arg === "--json" || arg === "-j") {
74
+ flags.json = true;
75
+ } else if (arg === "--no-color") {
76
+ flags.noColor = true;
77
+ } else if (arg === "--store") {
78
+ i++;
79
+ flags.store = argv[i];
80
+ } else if (arg?.startsWith("--store=")) {
81
+ flags.store = arg.slice("--store=".length);
82
+ } else if (arg === "--vars") {
83
+ i++;
84
+ flags.vars = argv[i];
85
+ } else if (arg?.startsWith("--vars=")) {
86
+ flags.vars = arg.slice("--vars=".length);
87
+ } else if (arg === "--file") {
88
+ i++;
89
+ flags.file = argv[i];
90
+ } else if (arg?.startsWith("--file=")) {
91
+ flags.file = arg.slice("--file=".length);
92
+ } else if (arg === "--status") {
93
+ i++;
94
+ flags.status = argv[i];
95
+ } else if (arg?.startsWith("--status=")) {
96
+ flags.status = arg.slice("--status=".length);
97
+ } else if (arg === "--type") {
98
+ i++;
99
+ flags.type = argv[i];
100
+ } else if (arg?.startsWith("--type=")) {
101
+ flags.type = arg.slice("--type=".length);
102
+ } else if (arg === "--vendor") {
103
+ i++;
104
+ flags.vendor = argv[i];
105
+ } else if (arg?.startsWith("--vendor=")) {
106
+ flags.vendor = arg.slice("--vendor=".length);
107
+ } else if (arg === "--limit") {
108
+ i++;
109
+ flags.limit = argv[i];
110
+ } else if (arg?.startsWith("--limit=")) {
111
+ flags.limit = arg.slice("--limit=".length);
112
+ } else if (arg === "--cursor") {
113
+ i++;
114
+ flags.cursor = argv[i];
115
+ } else if (arg?.startsWith("--cursor=")) {
116
+ flags.cursor = arg.slice("--cursor=".length);
117
+ } else if (arg === "--title") {
118
+ i++;
119
+ flags.title = argv[i];
120
+ } else if (arg?.startsWith("--title=")) {
121
+ flags.title = arg.slice("--title=".length);
122
+ } else if (arg === "--handle") {
123
+ i++;
124
+ flags.handle = argv[i];
125
+ } else if (arg?.startsWith("--handle=")) {
126
+ flags.handle = arg.slice("--handle=".length);
127
+ } else if (arg === "--tags") {
128
+ i++;
129
+ flags.tags = argv[i];
130
+ } else if (arg?.startsWith("--tags=")) {
131
+ flags.tags = arg.slice("--tags=".length);
132
+ } else if (arg === "--description") {
133
+ i++;
134
+ flags.description = argv[i];
135
+ } else if (arg?.startsWith("--description=")) {
136
+ flags.description = arg.slice("--description=".length);
137
+ } else if (arg === "--variants") {
138
+ i++;
139
+ flags.variants = argv[i];
140
+ } else if (arg?.startsWith("--variants=")) {
141
+ flags.variants = arg.slice("--variants=".length);
142
+ } else if (arg === "--options") {
143
+ i++;
144
+ flags.options = argv[i];
145
+ } else if (arg?.startsWith("--options=")) {
146
+ flags.options = arg.slice("--options=".length);
147
+ } else if (arg === "--body") {
148
+ i++;
149
+ flags.body = argv[i];
150
+ } else if (arg?.startsWith("--body=")) {
151
+ flags.body = arg.slice("--body=".length);
152
+ } else if (arg === "--body-file") {
153
+ i++;
154
+ flags["body-file"] = argv[i];
155
+ } else if (arg?.startsWith("--body-file=")) {
156
+ flags["body-file"] = arg.slice("--body-file=".length);
157
+ } else if (arg === "--published") {
158
+ i++;
159
+ flags.published = argv[i];
160
+ } else if (arg?.startsWith("--published=")) {
161
+ flags.published = arg.slice("--published=".length);
162
+ } else if (arg === "--seo-title") {
163
+ i++;
164
+ flags["seo-title"] = argv[i];
165
+ } else if (arg?.startsWith("--seo-title=")) {
166
+ flags["seo-title"] = arg.slice("--seo-title=".length);
167
+ } else if (arg === "--seo-desc") {
168
+ i++;
169
+ flags["seo-desc"] = argv[i];
170
+ } else if (arg?.startsWith("--seo-desc=")) {
171
+ flags["seo-desc"] = arg.slice("--seo-desc=".length);
172
+ } else if (arg === "--yes" || arg === "-y") {
173
+ flags.yes = true;
174
+ } else if (arg) {
175
+ positional.push(arg);
176
+ }
177
+ i++;
178
+ }
179
+ return {
180
+ resource: positional[0],
181
+ verb: positional[1],
182
+ args: positional.slice(2),
183
+ flags
184
+ };
185
+ }
186
+
187
+ // src/cli.ts
188
+ var pkgPath = new URL("../package.json", import.meta.url).pathname;
189
+ var pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
190
+ async function run(argv) {
191
+ const parsed = parseArgs(argv);
192
+ if (parsed.flags.version) {
193
+ console.log(pkg.version);
194
+ return;
195
+ }
196
+ if (!parsed.resource || parsed.flags.help && !parsed.resource) {
197
+ console.log(topLevelHelp());
198
+ return;
199
+ }
200
+ const resource = getResource(parsed.resource);
201
+ if (parsed.flags.help && parsed.resource) {
202
+ const help = resourceHelp(parsed.resource);
203
+ if (help) {
204
+ console.log(help);
205
+ return;
206
+ }
207
+ process.stderr.write(`Error: unknown resource "${parsed.resource}"
208
+ `);
209
+ process.exitCode = 2;
210
+ return;
211
+ }
212
+ if (!resource) {
213
+ process.stderr.write(`Error: unknown resource "${parsed.resource}"
214
+ `);
215
+ process.exitCode = 2;
216
+ return;
217
+ }
218
+ if (!parsed.verb) {
219
+ const defaultCommand2 = resource.verbs.get("_default");
220
+ if (defaultCommand2) {
221
+ await defaultCommand2.handler(parsed);
222
+ return;
223
+ }
224
+ const help = resourceHelp(parsed.resource);
225
+ if (help)
226
+ console.log(help);
227
+ return;
228
+ }
229
+ const defaultCommand = resource.verbs.get("_default");
230
+ if (defaultCommand) {
231
+ parsed.args = [parsed.verb, ...parsed.args];
232
+ parsed.verb = undefined;
233
+ await defaultCommand.handler(parsed);
234
+ return;
235
+ }
236
+ const command = resource.verbs.get(parsed.verb);
237
+ if (!command) {
238
+ process.stderr.write(`Error: unknown verb "${parsed.verb}" for resource "${parsed.resource}"
239
+ `);
240
+ process.exitCode = 2;
241
+ return;
242
+ }
243
+ await command.handler(parsed);
244
+ }
245
+ export {
246
+ run
247
+ };
package/dist/shopq.js CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
3
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
2
4
 
3
5
  // src/graphql.ts
4
6
  var API_VERSION = "2026-01";
@@ -26,11 +28,34 @@ class HttpError extends Error {
26
28
  class ConfigError extends Error {
27
29
  missing;
28
30
  constructor(missing) {
29
- super(`Missing required environment variables: ${missing.join(", ")}`);
31
+ super(`Missing required environment variables: ${missing.join(", ")}
32
+ ` + `Set them in ~/.config/shopq/.env, a local .env file, or as environment variables.`);
30
33
  this.missing = missing;
31
34
  this.name = "ConfigError";
32
35
  }
33
36
  }
37
+ function loadConfigEnv() {
38
+ const xdgConfig = process.env.XDG_CONFIG_HOME || `${process.env.HOME || __require("os").homedir()}/.config`;
39
+ const configPath = `${xdgConfig}/shopq/.env`;
40
+ try {
41
+ const content = __require("fs").readFileSync(configPath, "utf-8");
42
+ for (const line of content.split(`
43
+ `)) {
44
+ const trimmed = line.trim();
45
+ if (!trimmed || trimmed.startsWith("#"))
46
+ continue;
47
+ const eqIdx = trimmed.indexOf("=");
48
+ if (eqIdx === -1)
49
+ continue;
50
+ const key = trimmed.slice(0, eqIdx).trim();
51
+ const value = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, "");
52
+ if (!process.env[key]) {
53
+ process.env[key] = value;
54
+ }
55
+ }
56
+ } catch {}
57
+ }
58
+ loadConfigEnv();
34
59
  function resolveConfig(storeFlag) {
35
60
  const missing = [];
36
61
  const store = storeFlag || process.env.SHOPIFY_STORE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shopq",
3
- "version": "0.3.4",
3
+ "version": "0.3.8",
4
4
  "description": "A zero-dependency Shopify Admin CLI built on Bun",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,11 +20,11 @@
20
20
  },
21
21
  "repository": {
22
22
  "type": "git",
23
- "url": "git+https://github.com/c-99-e/shopq.git"
23
+ "url": "git+https://github.com/c99e/shopq.git"
24
24
  },
25
- "homepage": "https://github.com/c-99-e/shopq",
25
+ "homepage": "https://github.com/c99e/shopq",
26
26
  "bugs": {
27
- "url": "https://github.com/c-99-e/shopq/issues"
27
+ "url": "https://github.com/c99e/shopq/issues"
28
28
  },
29
29
  "keywords": [
30
30
  "shopify",