@globalfishingwatch/skills 0.0.1

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.
Files changed (47) hide show
  1. package/README.md +89 -0
  2. package/dist/decode-url/SKILL.md +51 -0
  3. package/dist/decode-url/index.js +20339 -0
  4. package/dist/decode-url/scripts/decode-url.mjs +18 -0
  5. package/dist/decode-url/scripts/register-gfw-resolver.mjs +24 -0
  6. package/dist/encode-url/MAINTENANCE.md +53 -0
  7. package/dist/encode-url/SKILL.md +135 -0
  8. package/dist/encode-url/index.js +20211 -0
  9. package/dist/encode-url/references/areas.json +1401 -0
  10. package/dist/encode-url/references/examples-conversations.md +113 -0
  11. package/dist/encode-url/references/examples.md +234 -0
  12. package/dist/encode-url/references/filters.md +67 -0
  13. package/dist/encode-url/references/highlighted-workspaces.md +65 -0
  14. package/dist/encode-url/references/layers.md +96 -0
  15. package/dist/encode-url/references/ports.json +27507 -0
  16. package/dist/encode-url/references/query-params.md +114 -0
  17. package/dist/encode-url/references/routes.md +24 -0
  18. package/dist/encode-url/scripts/encode-url.mjs +26 -0
  19. package/dist/encode-url/scripts/register-gfw-resolver.mjs +24 -0
  20. package/dist/index.js +20514 -0
  21. package/dist/package.json +35 -0
  22. package/package.json +35 -0
  23. package/src/decode-url/SKILL.md +51 -0
  24. package/src/decode-url/decode.ts +87 -0
  25. package/src/decode-url/index.ts +4 -0
  26. package/src/decode-url/scripts/decode-url.mjs +18 -0
  27. package/src/decode-url/scripts/register-gfw-resolver.mjs +24 -0
  28. package/src/decode-url/workspaces.ts +34 -0
  29. package/src/encode-url/MAINTENANCE.md +53 -0
  30. package/src/encode-url/SKILL.md +135 -0
  31. package/src/encode-url/config.ts +8 -0
  32. package/src/encode-url/dictionary.ts +305 -0
  33. package/src/encode-url/encode.ts +79 -0
  34. package/src/encode-url/index.ts +4 -0
  35. package/src/encode-url/references/areas.json +1401 -0
  36. package/src/encode-url/references/examples-conversations.md +113 -0
  37. package/src/encode-url/references/examples.md +234 -0
  38. package/src/encode-url/references/filters.md +67 -0
  39. package/src/encode-url/references/highlighted-workspaces.md +65 -0
  40. package/src/encode-url/references/layers.md +96 -0
  41. package/src/encode-url/references/ports.json +27507 -0
  42. package/src/encode-url/references/query-params.md +114 -0
  43. package/src/encode-url/references/routes.md +24 -0
  44. package/src/encode-url/routes.ts +166 -0
  45. package/src/encode-url/scripts/encode-url.mjs +26 -0
  46. package/src/encode-url/scripts/register-gfw-resolver.mjs +24 -0
  47. package/src/index.ts +6 -0
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # @globalfishingwatch/skills
2
+
3
+ Agent skills for GFW applications, shareable across repos. Each skill lives in `src/<skill-name>/`: a `SKILL.md` (instructions for the agent), runnable scripts, reference docs, and its own code — built into its own self-contained bundle so the whole `src/<skill-name>/` (or `dist/<skill-name>/`) folder can be copied anywhere and just works.
4
+
5
+ ## Skills
6
+
7
+ - [encode-url](src/encode-url/SKILL.md) — build a fishing-map URL + TanStack Router navigation config from a navigation intent (route, layers, filters, time range, viewport).
8
+ - [decode-url](src/decode-url/SKILL.md) — decode a fishing-map URL into structured context of what the user is seeing.
9
+
10
+ Both use the real `parseWorkspace`/`stringifyWorkspace` from `@globalfishingwatch/dataviews-client`, so URLs match the app byte-for-byte. `encode-url` owns the shared logic (layer dictionary, route matching) and `decode-url` imports it from there.
11
+
12
+ ## Programmatic use
13
+
14
+ ```ts
15
+ import { decodeMapUrl } from '@globalfishingwatch/skills/decode-url'
16
+ import { encodeMapUrl } from '@globalfishingwatch/skills/encode-url'
17
+
18
+ const context = decodeMapUrl(currentUrl)
19
+ const { navigation, path } = encodeMapUrl({ route: { type: 'workspace' }, state: context.raw })
20
+ ```
21
+
22
+ `@globalfishingwatch/skills` (no subpath) also re-exports both, for convenience.
23
+
24
+ ## Development
25
+
26
+ ```bash
27
+ pnpm nx dist skills # build (also builds dataviews-client deps)
28
+ ```
29
+
30
+ This produces `libs/skills/dist/`: a combined `index.js`, plus one self-contained folder per skill (`encode-url/`, `decode-url/`) — each with its own `index.js` bundle alongside its `SKILL.md`, `scripts/`, and `references/`.
31
+
32
+ Skill scripts run with plain `node` (>= 23) and import their own skill's bundle as `@globalfishingwatch/skills/<skill-name>`, resolved by `scripts/register-gfw-resolver.mjs` from (in order): a sibling `index.js` (dist output), a `../../dist/<skill-name>/index.js` in this monorepo (unbuilt source layout), or — once installed as an npm package — normal `node_modules` resolution via the package's `exports` map.
33
+
34
+ ## Installing a skill into Claude Code (or another agent)
35
+
36
+ Each skill folder is self-contained (own bundle + `SKILL.md` + `scripts/` + `references/`), so installing one is just copying its folder into the target skills directory.
37
+
38
+ ### From this monorepo
39
+
40
+ ```bash
41
+ pnpm nx dist skills
42
+
43
+ # Claude Code, this project only
44
+ cp -r libs/skills/dist/encode-url .claude/skills/
45
+
46
+ # Claude Code, all your projects
47
+ cp -r libs/skills/dist/decode-url ~/.claude/skills/
48
+
49
+ # any other agent that reads SKILL.md folders — same idea, just point at its skills dir
50
+ cp -r libs/skills/dist/encode-url /path/to/agent/skills/
51
+ ```
52
+
53
+ Or, for your own `~/.claude/skills/`, one command per skill — builds, wipes the old copy, reinstalls:
54
+
55
+ ```bash
56
+ pnpm nx run skills:claude:encode-url
57
+ pnpm nx run skills:claude:decode-url
58
+ ```
59
+
60
+ ### From the published npm package
61
+
62
+ ```bash
63
+ pnpm add @globalfishingwatch/skills
64
+ cp -r node_modules/@globalfishingwatch/skills/dist/encode-url ~/.claude/skills/
65
+ cp -r node_modules/@globalfishingwatch/skills/dist/decode-url ~/.claude/skills/
66
+ ```
67
+
68
+ ### Into [gfw-agent](https://github.com/GlobalFishingWatch/gfw-agent)
69
+
70
+ Its skills live at repo root `skills/<skill-name>/` (not `.claude/skills/`), and each agent profile (`agents/<name>.json`) opts in via a `skills` array:
71
+
72
+ ```bash
73
+ pnpm add @globalfishingwatch/skills
74
+ cp -r node_modules/@globalfishingwatch/skills/dist/encode-url skills/
75
+ cp -r node_modules/@globalfishingwatch/skills/dist/decode-url skills/
76
+ ```
77
+
78
+ Then add the skill name(s) to the profile, e.g. `agents/default.json`:
79
+
80
+ ```json
81
+ "skills": ["encode-url", "decode-url"]
82
+ ```
83
+
84
+ ## Adding a new skill
85
+
86
+ Create `libs/skills/src/<skill-name>/` with `SKILL.md` (+ optional `scripts/`, `references/`, and code). If it needs logic another skill already has (e.g. the layer dictionary or route matching in `encode-url/`), import it from there rather than duplicating it. Export the skill's public API from an `index.ts`, add its path to `src/index.ts`, and:
87
+
88
+ - add it as an `additionalEntryPoints` entry + `exports["./<skill-name>"]` in `package.json`, so it gets its own bundle
89
+ - add its `assets` globs (`SKILL.md`, `scripts/**/*`, `references/**/*`, …) to the `dist` target in `project.json`
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: decode-url
3
+ description: Decode a GFW map URL into structured context of what the user is currently seeing — route (map/report/vessel/search), visible layers with filters, time range and viewport. Use whenever you receive the user's current URL and need to understand or describe their view, or to modify it (decode, edit the raw state, re-encode with the encode-url skill).
4
+ ---
5
+
6
+ # Decode GFW map URL
7
+
8
+ ```bash
9
+ node scripts/decode-url.mjs '<url or path>'
10
+ ```
11
+
12
+ Accepts a full URL (`https://globalfishingwatch.org/map/...`) or just the path. Output:
13
+
14
+ ```json
15
+ {
16
+ "route": {
17
+ "type": "report",
18
+ "category": "fishing-activity",
19
+ "workspaceId": "default-public",
20
+ "datasetId": "public-eez-areas",
21
+ "areaId": "5682"
22
+ },
23
+ "workspaceName": "Default public workspace",
24
+ "timeRange": { "start": "2025-08-01T00:00:00.000Z", "end": "2026-08-01T00:00:00.000Z" },
25
+ "viewport": { "latitude": 40.7, "longitude": 12.4, "zoom": 4.7 },
26
+ "timebarVisualisation": "events",
27
+ "layers": [
28
+ {
29
+ "id": "ais",
30
+ "name": "Apparent fishing effort (AIS)",
31
+ "category": "activity",
32
+ "visible": true,
33
+ "filters": { "geartype": ["trawlers"] }
34
+ }
35
+ ],
36
+ "report": { "reportBufferValue": 50 },
37
+ "vessel": { "vesselSelfReportedId": "..." },
38
+ "search": { "query": "lake aurora" },
39
+ "raw": {}
40
+ }
41
+ ```
42
+
43
+ How to narrate it:
44
+
45
+ - `route.type` says where the user is: `workspace` (map browsing), `report` (area report — `areaId` within `datasetId`, e.g. `public-eez-areas`; no `datasetId`/`areaId` = global report), `ports-report`, `vessel` (vessel profile), `vessel-search`, `vessel-group-report`, `user`, `workspaces-list`.
46
+ - `workspaceName` (when present) names a curated workspace: Marine Manager MPAs (`category: "marine-manager"`, e.g. Palau, Galapagos and Hermandad) or global curated reports (`activity-report`, `detections-report`, `events-report`, Deep Sea Mining Watch). Lead with it — "you're looking at the Palau Marine Manager workspace" beats reciting layers.
47
+ - Describe only `visible: true` layers; mention hidden ones only if relevant. Layer `filters` use API values: `flag` is ISO3 (translate to country names), `matched: ["false"]` on detections means dark vessels (no AIS match), `geartype`/`vessel_type` are fleet filters.
48
+ - `timeRange` is the analyzed period; no `timeRange` means the app default (roughly the last year).
49
+ - `raw` is the full parsed workspace state — edit it and feed it back to the encode-url skill (`{"route": <route>, "state": <raw>}`) to produce a modified view that keeps everything else identical.
50
+
51
+ Requires node >= 23 (uses `module.registerHooks`). In the monorepo run `pnpm nx dist skills` once so `dist/` exists.