@go-labs-sg/gosh 1.4.0 → 1.5.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/README.md CHANGED
@@ -157,6 +157,42 @@ Deploy prerequisite: apply the additive GOSH database schema changes for both
157
157
  to `[]`, before deploying the updated server. Older event snapshots restore an
158
158
  empty list. Client generation alone does not apply these database changes.
159
159
 
160
+ ### Number range answers
161
+
162
+ Fill-in-the-blank missions can accept any number in an inclusive range instead
163
+ of text answers. Set `config.numberRange` with `min` and `max` (`min` must be
164
+ less than or equal to `max`). Players must answer with a number such as `55`,
165
+ `55.5`, `-3` or `1,000`; anything that is not a number is marked incorrect.
166
+ Ranges cannot be combined with `acceptedAnswers` and are only available for
167
+ fill-in-the-blank missions.
168
+
169
+ ```bash
170
+ gosh mission create --input '{"stationId":"station-id","name":"Guess the height","type":"FILL_IN_THE_BLANK","config":{"numberRange":{"min":50,"max":60}}}'
171
+ gosh mission update --input '{"missionId":"mission-id","name":"Guess the height","type":"FILL_IN_THE_BLANK","config":null,"correctAnswer":"55"}'
172
+ ```
173
+
174
+ When updating, omit `config` to keep the saved range or pass `null` to switch
175
+ back to text answers. Players see a number input but never the range itself.
176
+
177
+ Rollout gate: the stored `correctAnswer` (`"50-60"`) is a display key, not a
178
+ safe fallback. A server without number-range support grades it as plain text,
179
+ so it accepts the literal `50-60` and rejects an in-range `55`, and its
180
+ template, clone and version writers drop `config`. Apply the additive
181
+ `Mission.config` and `GoshTemplateMission.config` columns, finish rolling out
182
+ the server everywhere, then create range missions.
183
+
184
+ Rollback: a range mission that has submissions cannot be switched back to text.
185
+ The answer-key lock in `mission update` rejects that edit on purpose, so stored
186
+ answers and points stay consistent. Do not loosen or bypass it. Instead:
187
+
188
+ - Unused range missions (no submissions) and templates can be switched back to
189
+ text answers or removed before a rollback.
190
+ - Used range missions: do not roll the server back past number-range support
191
+ while those events are live. Fix forward on a compatible build (any build
192
+ with number-range grading), or keep the previous image ready only for
193
+ events with no range missions. A lossless rollback for used range missions
194
+ needs its own approved plan; a normal edit cannot do it.
195
+
160
196
  ### Templates and organization scope
161
197
 
162
198
  Template commands use the selected organization as their scope. Provide its ID in
@@ -264,11 +300,15 @@ gosh team create \
264
300
  ```
265
301
 
266
302
  Configure gameplay, then manage the event's routing groups and their complete
267
- station lists:
303
+ station lists. `requireLocationOnSubmit` (default false) makes players at a
304
+ location-locked station check in again within the last two minutes before each
305
+ answer or upload is accepted, not only once at check-in. A fresh QR scan counts
306
+ at stations that also accept QR. It stays editable during live play; omit it,
307
+ or `allowStationSkipping`, to keep the event's current value.
268
308
 
269
309
  ```bash
270
310
  gosh event set-gameplay \
271
- --input '{"eventId":"event-id","progression":"SEQUENTIAL","groupRoutingEnabled":true,"allowMissionSkipping":true,"allowStationSkipping":false}' \
311
+ --input '{"eventId":"event-id","progression":"SEQUENTIAL","groupRoutingEnabled":true,"allowMissionSkipping":true,"allowStationSkipping":false,"requireLocationOnSubmit":true}' \
272
312
  --target event-id \
273
313
  --allow-state-change
274
314
 
@@ -791,7 +791,7 @@
791
791
  "path": ["mission", "create"],
792
792
  "procedure": "event.createMission",
793
793
  "requiresAuth": true,
794
- "summary": "Create a mission in a station. Fill-in-the-blank inputs support correctAnswer and acceptedAnswers (up to 50 alternatives). Optional revealMessage (up to 2,000 characters) is shown only after submitting.",
794
+ "summary": "Create a mission in a station. Fill-in-the-blank inputs support correctAnswer and acceptedAnswers (up to 50 alternatives), or config.numberRange {min,max} to accept any number in that inclusive range instead. Optional revealMessage (up to 2,000 characters) is shown only after submitting.",
795
795
  "targetKeys": [
796
796
  "id",
797
797
  "memberId",
@@ -823,7 +823,7 @@
823
823
  "path": ["mission", "update"],
824
824
  "procedure": "event.updateMission",
825
825
  "requiresAuth": true,
826
- "summary": "Update a mission. Fill-in-the-blank inputs support acceptedAnswers; omit to preserve or pass [] to clear. Existing submissions are not re-graded. Edit revealMessage during live play; omit it to preserve or use an empty string to clear.",
826
+ "summary": "Update a mission. Fill-in-the-blank inputs support acceptedAnswers; omit to preserve or pass [] to clear. Set config.numberRange {min,max} for a numeric range answer; omit config to preserve or pass null to return to text answers. Existing submissions are not re-graded. Edit revealMessage during live play; omit it to preserve or use an empty string to clear.",
827
827
  "targetKeys": [
828
828
  "id",
829
829
  "memberId",
@@ -1170,7 +1170,7 @@
1170
1170
  "path": ["event", "set-gameplay"],
1171
1171
  "procedure": "team.setGameplaySettings",
1172
1172
  "requiresAuth": true,
1173
- "summary": "Set open or sequential progression, group routing, and per-mission skipping before play starts.",
1173
+ "summary": "Set open or sequential progression, group routing, and per-mission skipping before play starts. Station skipping and requireLocationOnSubmit stay editable live.",
1174
1174
  "targetKeys": ["eventId"]
1175
1175
  },
1176
1176
  {
@@ -2200,6 +2200,15 @@
2200
2200
  "requiresAuth": true,
2201
2201
  "summary": "Get a playable station."
2202
2202
  },
2203
+ {
2204
+ "effects": [],
2205
+ "input": "json",
2206
+ "operation": "query",
2207
+ "path": ["player", "station", "presence"],
2208
+ "procedure": "event.getPlayerStationPresence",
2209
+ "requiresAuth": true,
2210
+ "summary": "Check whether a location is within a station's submit range when the event asks players to stay at the station to submit. Returns a state and rounded distance, never coordinates."
2211
+ },
2203
2212
  {
2204
2213
  "effects": [],
2205
2214
  "input": "none",
@@ -332,7 +332,7 @@ Reorder shared stations, or a selected team's station route when scopeTeamId is
332
332
 
333
333
  ## `gosh mission create`
334
334
 
335
- Create a mission in a station. Fill-in-the-blank inputs support correctAnswer and acceptedAnswers (up to 50 alternatives). Optional revealMessage (up to 2,000 characters) is shown only after submitting.
335
+ Create a mission in a station. Fill-in-the-blank inputs support correctAnswer and acceptedAnswers (up to 50 alternatives), or config.numberRange {min,max} to accept any number in that inclusive range instead. Optional revealMessage (up to 2,000 characters) is shown only after submitting.
336
336
 
337
337
  - Authentication: browser-authenticated CLI session required
338
338
  - Input: `--input '<json>'` required
@@ -340,7 +340,7 @@ Create a mission in a station. Fill-in-the-blank inputs support correctAnswer an
340
340
 
341
341
  ## `gosh mission update`
342
342
 
343
- Update a mission. Fill-in-the-blank inputs support acceptedAnswers; omit to preserve or pass [] to clear. Existing submissions are not re-graded. Edit revealMessage during live play; omit it to preserve or use an empty string to clear.
343
+ Update a mission. Fill-in-the-blank inputs support acceptedAnswers; omit to preserve or pass [] to clear. Set config.numberRange {min,max} for a numeric range answer; omit config to preserve or pass null to return to text answers. Existing submissions are not re-graded. Edit revealMessage during live play; omit it to preserve or use an empty string to clear.
344
344
 
345
345
  - Authentication: browser-authenticated CLI session required
346
346
  - Input: `--input '<json>'` required
@@ -444,7 +444,7 @@ Replace a team's linked station route and set its order.
444
444
 
445
445
  ## `gosh event set-gameplay`
446
446
 
447
- Set open or sequential progression, group routing, and per-mission skipping before play starts.
447
+ Set open or sequential progression, group routing, and per-mission skipping before play starts. Station skipping and requireLocationOnSubmit stay editable live.
448
448
 
449
449
  - Authentication: browser-authenticated CLI session required
450
450
  - Input: `--input '<json>'` required
@@ -922,6 +922,14 @@ Get a playable station.
922
922
  - Input: `--input '<json>'` required
923
923
  - Effects: read-only
924
924
 
925
+ ## `gosh player station presence`
926
+
927
+ Check whether a location is within a station's submit range when the event asks players to stay at the station to submit. Returns a state and rounded distance, never coordinates.
928
+
929
+ - Authentication: browser-authenticated CLI session required
930
+ - Input: `--input '<json>'` required
931
+ - Effects: read-only
932
+
925
933
  ## `gosh player events`
926
934
 
927
935
  List events joined by the current user.
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ var __toESM = (mod, isNodeMode, target) => {
35
35
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
36
36
  var __require = import.meta.require;
37
37
 
38
- // ../../../node_modules/.bun/dotenv@18.0.8/node_modules/dotenv/dist/index.cjs
38
+ // ../../../node_modules/.bun/dotenv@18.0.9/node_modules/dotenv/dist/index.cjs
39
39
  var require_dist = __commonJS(function(exports, module) {
40
40
  var j = (e, n) => () => {
41
41
  try {
@@ -367,7 +367,7 @@ var require_dist = __commonJS(function(exports, module) {
367
367
  }
368
368
  function Ee(e) {
369
369
  let n = J(), t = { encoding: n.encoding || "utf8", quiet: n.quiet, debug: n.debug === true, override: n.override === true, fast: n.fast === true, paths: [".env"], defaultPath: true };
370
- return n.path != null && (t.paths = [n.path], t.defaultPath = false), e.pathSet && (t.paths = e.paths, t.defaultPath = false), e.quiet != null && (t.quiet = e.quiet), e.debug != null && (t.debug = e.debug), e.override != null && (t.override = e.override), e.fast != null && (t.fast = e.fast), t;
370
+ return n.path && (t.paths = [n.path], t.defaultPath = false), e.pathSet && (t.paths = e.paths, t.defaultPath = false), e.quiet != null && (t.quiet = e.quiet), e.debug != null && (t.debug = e.debug), e.override != null && (t.override = e.override), e.fast != null && (t.fast = e.fast), t;
371
371
  }
372
372
  function be(e) {
373
373
  let n = {}, t = [], o = { override: e.override, debug: e.debug };
@@ -7728,6 +7728,10 @@ var typedOperations = {
7728
7728
  kind: "query",
7729
7729
  invoke: (client, input) => client.event.getPlayerStation.query(input)
7730
7730
  },
7731
+ "event.getPlayerStationPresence": {
7732
+ kind: "query",
7733
+ invoke: (client, input) => client.event.getPlayerStationPresence.query(input)
7734
+ },
7731
7735
  "event.listJoined": {
7732
7736
  kind: "query",
7733
7737
  invoke: (client, input) => client.event.listJoined.query(input)
@@ -8091,8 +8095,8 @@ var commands = [
8091
8095
  mutation(["station", "clone"], "event.cloneStation", "Clone a station and its missions.", ["state-change"]),
8092
8096
  mutation(["station", "archive"], "event.archiveStation", "Archive a station.", ["state-change", "delete"]),
8093
8097
  mutation(["station", "reorder"], "event.reorderStations", "Reorder shared stations, or a selected team's station route when scopeTeamId is supplied.", ["state-change"]),
8094
- mutation(["mission", "create"], "event.createMission", "Create a mission in a station. Fill-in-the-blank inputs support correctAnswer and acceptedAnswers (up to 50 alternatives). Optional revealMessage (up to 2,000 characters) is shown only after submitting.", ["state-change"]),
8095
- mutation(["mission", "update"], "event.updateMission", "Update a mission. Fill-in-the-blank inputs support acceptedAnswers; omit to preserve or pass [] to clear. Existing submissions are not re-graded. Edit revealMessage during live play; omit it to preserve or use an empty string to clear.", ["state-change"]),
8098
+ mutation(["mission", "create"], "event.createMission", "Create a mission in a station. Fill-in-the-blank inputs support correctAnswer and acceptedAnswers (up to 50 alternatives), or config.numberRange {min,max} to accept any number in that inclusive range instead. Optional revealMessage (up to 2,000 characters) is shown only after submitting.", ["state-change"]),
8099
+ mutation(["mission", "update"], "event.updateMission", "Update a mission. Fill-in-the-blank inputs support acceptedAnswers; omit to preserve or pass [] to clear. Set config.numberRange {min,max} for a numeric range answer; omit config to preserve or pass null to return to text answers. Existing submissions are not re-graded. Edit revealMessage during live play; omit it to preserve or use an empty string to clear.", ["state-change"]),
8096
8100
  mutation(["mission", "archive"], "event.archiveMission", "Archive a mission.", ["state-change", "delete"]),
8097
8101
  mutation(["mission", "reorder"], "event.reorderMissions", "Reorder missions within a station.", ["state-change"]),
8098
8102
  query(["team", "list"], "team.list", "List teams and their current members."),
@@ -8109,7 +8113,7 @@ var commands = [
8109
8113
  mutation(["team", "set-play-mode"], "team.setPlayMode", "Change an event between individual and team play.", ["state-change"]),
8110
8114
  mutation(["team", "set-submission-access"], "team.setSubmissionAccess", "Change who can submit missions in team play.", ["state-change"]),
8111
8115
  mutation(["team", "set-station-routes"], "team.setStationRoutes", "Replace a team's linked station route and set its order.", ["state-change"]),
8112
- mutation(["event", "set-gameplay"], "team.setGameplaySettings", "Set open or sequential progression, group routing, and per-mission skipping before play starts.", ["state-change"]),
8116
+ mutation(["event", "set-gameplay"], "team.setGameplaySettings", "Set open or sequential progression, group routing, and per-mission skipping before play starts. Station skipping and requireLocationOnSubmit stay editable live.", ["state-change"]),
8113
8117
  query(["routing-group", "list"], "team.listRoutingGroups", "List an event's routing groups, ordered stations, and assigned teams."),
8114
8118
  query(["routing-group", "release-history"], "team.listRoutingGroupReleaseHistory", "Show a routing group's five most recent release changes with actor, action and before/after UTC values."),
8115
8119
  mutation(["routing-group", "release"], "team.updateRoutingGroupRelease", "Schedule (future releaseAt ISO timestamp with offset), CLEAR schedule, HOLD, RELEASE_SCHEDULED_HOLD (keep schedule), or RELEASE_NOW for a routing group. After a group starts, only HOLD and RELEASE_SCHEDULED_HOLD are accepted. Requires launchEvent permission.", ["state-change"]),
@@ -8172,6 +8176,7 @@ var commands = [
8172
8176
  query(["player", "map"], "event.getPlayerMap", "Get the player event map."),
8173
8177
  query(["player", "shell"], "event.getPlayerShell", "Get the player application shell."),
8174
8178
  query(["player", "station"], "event.getPlayerStation", "Get a playable station."),
8179
+ query(["player", "station", "presence"], "event.getPlayerStationPresence", "Check whether a location is within a station's submit range when the event asks players to stay at the station to submit. Returns a state and rounded distance, never coordinates."),
8175
8180
  query(["player", "events"], "event.listJoined", "List events joined by the current user.", { input: "none" }),
8176
8181
  query(["player", "broadcasts"], "event.listPlayerBroadcasts", "List broadcasts visible to the current player."),
8177
8182
  query(["player", "broadcast"], "event.getPlayerBroadcast", "Get one broadcast visible to the current player."),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@go-labs-sg/gosh",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "GOSH CLI for organizers and AI agents — manage organizations, events, teams, stations, missions, templates, and live operations through the GOSH API.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "dependencies": {
21
21
  "@trpc/client": "^11.19.0",
22
- "dotenv": "^18.0.8",
22
+ "dotenv": "^18.0.9",
23
23
  "superjson": "^2.2.6"
24
24
  },
25
25
  "engines": {