factorio-mod-workshop 0.1.0__py3-none-any.whl

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.
fmw/help.py ADDED
@@ -0,0 +1,387 @@
1
+ """Prose help, shipped with the package.
2
+
3
+ Kept here rather than in the repository's docs/ so that someone who installed
4
+ via `uv tool install` - or an agent with no checkout - can read it. Each entry
5
+ becomes a subcommand's argparse `description`, so `fmw <cmd> --help` is the
6
+ single place this text appears; there is no parallel `help <cmd>` topic to
7
+ drift out of step with it.
8
+ """
9
+
10
+ OVERVIEW = """\
11
+ fmw - Factorio Mod Workshop
12
+
13
+ Turns mod portal activity into structured data you can triage, decide about and
14
+ act on, across many mods at once.
15
+
16
+ Three layers, deliberately separate:
17
+
18
+ cache/ what users actually said. Disposable, refetched in minutes.
19
+ threads/<mod>.yaml what you decided about a conversation.
20
+ tracker/<mod>/ what you are doing about a problem. Code changes only.
21
+
22
+ A typical session:
23
+
24
+ fmw sync fetch what is new
25
+ fmw inbox see what needs a decision
26
+ fmw thread <id> read one discussion in full
27
+ fmw mark <id> ... record a judgement, or
28
+ fmw track new <id> open a ticket when code must change
29
+ fmw testplan batch verified-pending fixes into one game session
30
+
31
+ Setup, once:
32
+
33
+ fmw init <path> create a workspace
34
+ then set FMW_WORKSPACE in your shell profile, or:
35
+ fmw launcher put `fmw` on PATH, pinned to that workspace
36
+ fmw repo add <path> register a directory holding your mods
37
+ fmw discover find them, and read their portal metadata
38
+
39
+ Every command takes --json for machine-readable output.
40
+
41
+ fmw never writes to the mod portal: there is no write API, and replying to
42
+ users is the maintainer's job. Only sync, discover and `thread --refresh` touch
43
+ the network; everything else reads the local cache, so exploring costs nothing.
44
+
45
+ Read any command's prose with `fmw <command> --help`. Two wider topics:
46
+ `fmw help workspace` (file formats and every field value) and
47
+ `fmw help workflow` (the loop, and the mistakes it prevents).
48
+ `fmw help --all` prints everything at once.
49
+ """
50
+
51
+ COMMANDS = {
52
+ "init": """\
53
+ Create a workspace: the directory holding your registry, tickets, thread
54
+ judgements and cache. Nothing is created implicitly, and the path is required -
55
+ guessing which workspace was meant is worse than refusing.
56
+
57
+ Copies a scaffold of documentation and examples. Existing files are never
58
+ overwritten, so re-running it on an old workspace adds newly shipped files
59
+ without touching your data. `fmw upgrade` refreshes the ones the tool owns.
60
+
61
+ Afterwards: `fmw repo add <path>` for each directory holding your mods, then
62
+ `fmw discover`.
63
+ """,
64
+ "launcher": """\
65
+ Install a small wrapper on your PATH that pins one workspace, so `fmw` works
66
+ from any directory - typically from inside a mod repository - without exporting
67
+ FMW_WORKSPACE by hand.
68
+
69
+ Writes a POSIX `sh` script on Linux and macOS, a `.cmd` on Windows. Goes to the
70
+ first conventional per-user bin directory already on your PATH - ~/.local/bin
71
+ or ~/bin, or %APPDATA%\\uv\\bin on Windows - and prints the right command for
72
+ your shell if none of them is.
73
+
74
+ An FMW_WORKSPACE set in the environment still overrides it. Use --name for a
75
+ second workspace, and re-run with --force after moving either directory, since
76
+ the wrapper holds absolute paths.
77
+
78
+ Refuses to run from an ephemeral `uvx` environment, whose path `uv cache prune`
79
+ deletes. With `uv tool install`, `fmw` is already on PATH and you only need to
80
+ export FMW_WORKSPACE.
81
+ """,
82
+ "repo": """\
83
+ Manage the directories `fmw discover` scans for mods. These are your mod
84
+ checkouts - a monorepo, one repository per mod, or a mix.
85
+
86
+ fmw repo add ~/code/my-mods register a directory and report what is in it
87
+ fmw repo list show them, with the mods found in each
88
+ fmw repo remove ~/code/old stop scanning one
89
+
90
+ Edits config.yaml in place, preserving its comments. Removing a repository does
91
+ not remove mods already in the registry - delete those from mods.yaml if you
92
+ want them gone.
93
+
94
+ `fmw discover --scan DIR` scans a directory once without registering it.
95
+ """,
96
+ "discover": """\
97
+ Build the mod registry from two sources: your local checkouts and the portal.
98
+
99
+ It does not read discussions - that is `fmw sync`. Here the portal is queried
100
+ only through its metadata API, for published versions and download counts.
101
+
102
+ Locally, walks each registered repository (see `fmw repo`) for info.json files -
103
+ the manifest the game requires. Anything with a name and a version is a mod, so
104
+ repo layout does not matter: a monorepo, one repo per mod, or a mix. Depth is 3
105
+ levels by default; node_modules, .git, .venv and __pycache__ are skipped.
106
+
107
+ Skips that you might not expect - unreadable JSON, a manifest without
108
+ name/version, one mod name found twice - are reported rather than passed over
109
+ silently. Only the depth limit and ignored directories are quiet.
110
+
111
+ From the portal, adds published version, Factorio version, downloads and
112
+ category. Mods you have locally but never published are marked and reported.
113
+ --no-portal stays offline.
114
+
115
+ Re-running merges: fields you own (maintained, notes, priority) are preserved,
116
+ local facts refresh from the scan, and portal facts refresh only when a lookup
117
+ happened - so --no-portal does not blank previously fetched data.
118
+ """,
119
+ "mods": """\
120
+ List the registry.
121
+
122
+ Columns abbreviate: v = mod version, F = Factorio version, loc = your local
123
+ checkout, mp = the mod portal, dl = downloads. Portal columns stay empty until
124
+ `fmw discover` runs without --no-portal, and the command says so when they are.
125
+
126
+ A `~` marks a mod whose local and published versions differ. It is a flag, not
127
+ a diagnosis: unreleased work, an out-of-date checkout and a deliberate local
128
+ edit are indistinguishable from the numbers. Ask the maintainer before changing
129
+ such a checkout.
130
+
131
+ `maintained` is yours to set: active, frozen or unknown. Frozen mods are
132
+ skipped by sync, inbox and testplan unless --all.
133
+ """,
134
+ "sync": """\
135
+ Fetch discussions and report exactly what changed since the last run.
136
+
137
+ The only command that hits the network, besides `discover` and
138
+ `thread --refresh`. Idempotent: run it again and it prints nothing new. The
139
+ first run fetches every thread and takes a few minutes for ~20 mods.
140
+
141
+ Differences are appended to an append-only log, so `fmw changes --since` can
142
+ replay them offline later.
143
+
144
+ Also warns when a thread's title and its ticket disagree about being resolved -
145
+ each direction means different unfinished work.
146
+
147
+ Writes only to the cache. Your judgements and tickets are never touched by a
148
+ network operation.
149
+ """,
150
+ "changes": """\
151
+ Replay changes recorded by earlier syncs, without touching the network.
152
+
153
+ Two dates are shown per entry: `seen` is when fmw detected the change, `posted`
154
+ is when the message was written. --since filters on `seen`, so after a first
155
+ sync backfills months of history, everything carries today's detection date.
156
+ """,
157
+ "inbox": """\
158
+ Everything awaiting a decision, in one view: replies you owe, fixes awaiting
159
+ your testing, open tickets, and threads nobody has triaged.
160
+
161
+ Thread flags: T has a ticket, R you owe a reply, ! the maintainer judged the
162
+ report mistaken.
163
+
164
+ A thread leaves the inbox when a ticket cites it AND its conversation is
165
+ settled, or when you record a judgement with `fmw mark`. Threads whose portal
166
+ title already carries a resolution marker are hidden and counted separately;
167
+ --all-threads shows them.
168
+
169
+ Tickets stay listed while their thread is unsettled, because a ticket tracks
170
+ the code change, not the conversation.
171
+ """,
172
+ "mark": """\
173
+ Record your judgement about a conversation - the alternative to opening a
174
+ ticket. Most threads deserve one: a question you answered, a duplicate, a
175
+ mistaken report, plain thanks. Tickets are for code changes.
176
+
177
+ --triage pending | handled | ignored
178
+ --class what the thread really is, regardless of its portal tag
179
+ --needs-response / --responded
180
+
181
+ The portal's tag is a hint only. Reporters mislabel constantly: shy users file
182
+ bugs as questions, careless ones file expected behaviour as errors.
183
+
184
+ `--responded` is the only thing that clears a reply obligation - nothing infers
185
+ it from you having read the thread.
186
+
187
+ Bulk form: `--before YYYY-MM-DD [mods]` applies one judgement to every
188
+ still-pending thread last active before that date, never overwriting a decision
189
+ already recorded. Long-dormant threads accumulate faster than they can be read
190
+ one at a time.
191
+ """,
192
+ "threads": """\
193
+ List a mod's threads with, under each, its id and author, your recorded
194
+ judgement in brackets, and one line per ticket citing it with that ticket's
195
+ kind and status.
196
+
197
+ Tags are abbreviated bug, gen, idea, ann; --tag accepts either form.
198
+ Resolution markers are not flagged separately because they are part of the
199
+ title text.
200
+ """,
201
+ "thread": """\
202
+ Print one discussion as plain Markdown: title, tag, then every message with its
203
+ author and exact timestamp.
204
+
205
+ Reads from the cache, so it costs nothing; --refresh re-fetches first. A bare
206
+ thread id is resolved against the cache to find its mod.
207
+
208
+ Read the whole thread before concluding anything - the answer is often in a
209
+ later reply, sometimes from the maintainer.
210
+ """,
211
+ "search": """\
212
+ Find threads and tickets mentioning a phrase, and answer "has anyone reported
213
+ this before".
214
+
215
+ Searches cached thread titles and message bodies, plus ticket titles and
216
+ bodies. Prints the id, mod, title and the matching line with who wrote it, so
217
+ results feed straight into `fmw thread <id>`.
218
+
219
+ Grouping several reports of one problem into a single ticket is the workflow
220
+ this exists for: add each thread to that ticket's sources rather than opening a
221
+ second ticket.
222
+ """,
223
+ "track": """\
224
+ Tickets: things requiring a code change, `error` or `feature`. A thread needing
225
+ an answer never becomes one - use `fmw mark`.
226
+
227
+ `track new <thread-id>` takes the title from the thread, minus its resolution
228
+ marker, and records the portal's tag. `--also <mod>` covers several mods, since
229
+ some of these share code.
230
+
231
+ Ids are random 6-hex, unique across mods, and never change, so retitling a
232
+ ticket breaks no references. Edit the Markdown body directly to fill in
233
+ Summary, Analysis, Resolution and Test plan.
234
+
235
+ Statuses run new, needs-info, confirmed, in-progress, needs-testing, fixed,
236
+ released - plus wontfix and duplicate. `needs-testing` means written but not
237
+ verified in game, which is as far as an agent can take a fix on its own.
238
+ """,
239
+ "testplan": """\
240
+ Collect every ticket in `needs-testing` into one document, grouped by mod, with
241
+ each ticket's Test plan section, the threads that reported it, and the checkout
242
+ path.
243
+
244
+ Each Factorio run costs real time, so fixes are batched and verified in a
245
+ single session rather than one at a time. Tickets with no test plan written say
246
+ so rather than appearing ready.
247
+
248
+ After verifying, set each to `fixed`, then `released` once published - which
249
+ raises a reply obligation on every thread the ticket cites.
250
+ """,
251
+ "status": """\
252
+ Workspace overview.
253
+
254
+ `mods_in_default_scope` is what sync, inbox and testplan act on: everything not
255
+ marked frozen. `mods_marked_active` counts only those you explicitly classified
256
+ - the two differ, and both are useful.
257
+
258
+ `awaiting_triage` uses exactly the definition `fmw inbox` lists, so the number
259
+ here always matches the list you work from. Threads hidden because their portal
260
+ title is already marked resolved are counted separately.
261
+
262
+ Also warns when the workspace documentation predates the current schema, or
263
+ when the workspace is not a git repository.
264
+ """,
265
+ "upgrade": """\
266
+ Bring a workspace to the current schema: refresh the documentation files the
267
+ tool owns, rewrite `maintained` values onto the current vocabulary, and migrate
268
+ tickets written by older versions.
269
+
270
+ Your registry entries, tickets, thread judgements, cache and config.yaml keep
271
+ their content. --dry-run reports what would change.
272
+
273
+ Worth running after updating fmw: workspace docs are copied once at init and
274
+ otherwise never change, so they can end up teaching a schema that no longer
275
+ exists.
276
+ """,
277
+ }
278
+
279
+
280
+ # Topics larger than one command. Same rule as COMMANDS: user-facing material
281
+ # ships with the package, so it is readable without the repository. Anything
282
+ # needed to *change* fmw rather than use it belongs in docs/ instead.
283
+ TOPICS = {
284
+ "workspace": """\
285
+ The workspace holds everything fmw knows. It lives outside the tool's own
286
+ repository, at --workspace or $FMW_WORKSPACE; there is no implicit default,
287
+ because guessing which one was meant is worse than refusing.
288
+
289
+ config.yaml which directories to scan, Discord details (you)
290
+ paths.yaml where each mod is checked out on this machine
291
+ mods.yaml the mod registry
292
+ threads/<mod>.yaml your judgement about each conversation
293
+ tracker/<mod>/*.md tickets
294
+ cache/<mod>/... mirrored portal data - never hand-edit, sync overwrites it
295
+ notes/ anything else
296
+
297
+ Only config.yaml and paths.yaml are machine-specific, and `fmw init` writes a
298
+ .gitignore excluding them. Everything else is portable, so a workspace can be a
299
+ git repository several maintainers share: each copies config.example.yaml and
300
+ runs `fmw discover` to generate their own paths.yaml.
301
+
302
+ mods.yaml
303
+ maintained active | frozen | unknown. Yours to set. Frozen mods are skipped
304
+ by sync, inbox and testplan unless --all; active and unknown are
305
+ in scope, so an unclassified mod is never silently ignored.
306
+ These words are chosen because YAML 1.1 turns bare yes/no into
307
+ booleans, which silently broke every comparison against them.
308
+ on_portal true, false (a confirmed 404), or absent when never checked.
309
+ notes, priority, aliases yours; preserved across discover runs.
310
+ Everything else is refreshed by `fmw discover`.
311
+
312
+ tracker/<mod>/<id>-<slug>.md - YAML frontmatter, then Markdown
313
+ id random 6-hex, unique across mods, never changes. References use it
314
+ alone, so retitling or renaming the file breaks nothing.
315
+ mods list; the first is primary and decides the directory.
316
+ kind error | feature. Tickets are code changes only.
317
+ status new | needs-info | confirmed | in-progress | needs-testing |
318
+ fixed | released | wontfix | duplicate.
319
+ Open: the first five. needs-testing means written but unverified -
320
+ as far as an agent can take a fix. released raises a reply
321
+ obligation on every thread the ticket cites.
322
+ sources portal:<24-hex-id> | discord:<url> | github:<url> | self.
323
+ Only portal: entries affect behaviour; they are how a thread is
324
+ known to be handled and how duplicates group into one ticket.
325
+ severity, affects, fixed_in, related, duplicate_of - convention, not enforced.
326
+ Body sections: Summary, Analysis, Resolution, Test plan.
327
+
328
+ threads/<mod>.yaml - keyed by thread id
329
+ triage pending | handled | ignored
330
+ needs_response you owe the reporter a reply. Only `fmw mark --responded`
331
+ clears it; nothing infers it from you having read anything.
332
+ class error | feature | question | wrong | duplicate | chatter.
333
+ Your reading, which the portal's tag is only a hint toward.
334
+ note, duplicate_of, announced (releases already told to the reporter)
335
+
336
+ Only --kind and --status are validated, and only when set through the CLI.
337
+ Nothing validates a file you edit by hand.
338
+ """,
339
+ "workflow": """\
340
+ The loop, and where each command fits.
341
+
342
+ 1. `fmw sync` - the only command that reaches the network besides discover and
343
+ `thread --refresh`. Prints exactly what changed; prints nothing when nothing
344
+ did. Safe to re-run.
345
+
346
+ 2. `fmw inbox` - everything awaiting a decision. Also `fmw status` for counts,
347
+ which use the same definition, so the dashboard matches the list.
348
+
349
+ 3. Read before deciding. `fmw thread <id>` prints a whole discussion; the
350
+ answer is often in a later reply, sometimes from the maintainer.
351
+ `fmw search <phrase>` finds every thread and ticket mentioning something -
352
+ run it before opening a ticket, so repeat reports join the existing one.
353
+
354
+ 4. Decide. Most threads need a judgement, not a ticket:
355
+
356
+ fmw mark <id> --triage handled --class question --note "answered inline"
357
+ fmw mark <id> --duplicate-of <other-thread-id>
358
+ fmw mark --before 2025-01-01 <mod> --triage handled # bulk, never
359
+ # overwrites a
360
+ # recorded decision
361
+ Open a ticket only when code must change. Several reports of one problem
362
+ belong in one ticket with several sources, not several tickets.
363
+
364
+ 5. Fix, but do not claim it works. An agent cannot launch Factorio. Set
365
+ `status: needs-testing`, fill in the ticket's Test plan section, and leave
366
+ it. `fmw testplan` gathers every such ticket into one document so a batch is
367
+ verified in a single play session.
368
+
369
+ 6. After the maintainer confirms: `fixed`, then `released` once published.
370
+ Setting released makes every thread the ticket cites reappear under "You owe
371
+ a reply". Reply, then `fmw mark <id> --responded`.
372
+
373
+ Notes that save mistakes:
374
+
375
+ - The portal's thread tag is a hint, not a signal. Reporters mislabel
376
+ constantly: shy users file bugs as questions, careless ones file expected
377
+ behaviour as errors. Read the thread and set --class yourself.
378
+ - Title markers are the opposite: [FIXED], (fixed), (Wrong) are written by the
379
+ maintainer and can be trusted. fmw reads them back automatically.
380
+ - A `~` in `fmw mods` means local and published versions differ. Do not infer
381
+ why and do not "fix" it - unreleased work, an out-of-date checkout and a
382
+ deliberate local edit look identical. Ask.
383
+ - Correlate a reported version against the mod's changelog before assuming a
384
+ bug still exists. Many reports are against old versions.
385
+ - Never hand-edit cache/. The next sync overwrites it.
386
+ """,
387
+ }