grix-connector 4.2.3 → 4.2.5

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 (31) hide show
  1. package/dist/adapter/claude/claude-adapter.js +18 -17
  2. package/dist/assets/dsh-bridge/grix-dsh-bridge-4.2.5.tgz +0 -0
  3. package/dist/assets/dsh-bridge/manifest.json +6 -6
  4. package/dist/core/mcp/tools.js +1 -1
  5. package/dist/default-skills/grix-access-control/SKILL.md +1 -1
  6. package/dist/default-skills/grix-admin/SKILL.md +115 -155
  7. package/dist/default-skills/grix-admin/references/api-contract.md +23 -12
  8. package/dist/default-skills/grix-agent-dispatch/SKILL.md +152 -188
  9. package/dist/default-skills/grix-audit-data/SKILL.md +1 -1
  10. package/dist/default-skills/grix-chat-state/SKILL.md +26 -43
  11. package/dist/default-skills/grix-egg/SKILL.md +94 -50
  12. package/dist/default-skills/grix-group/SKILL.md +1 -1
  13. package/dist/default-skills/grix-owner-relay/SKILL.md +30 -64
  14. package/dist/default-skills/grix-query/SKILL.md +1 -1
  15. package/dist/default-skills/grix-skill-library/SKILL.md +52 -0
  16. package/dist/default-skills/grix-widget-visitor-ban/SKILL.md +1 -1
  17. package/dist/default-skills/message-send/SKILL.md +1 -1
  18. package/dist/default-skills/message-unsend/SKILL.md +1 -1
  19. package/dist/default-skills/tailnet-file-share/SKILL.md +38 -72
  20. package/dist/default-skills/tailnet-file-share/references/certificate-trust.md +64 -0
  21. package/dist/mcp/stream-http/security.js +1 -1
  22. package/openclaw-plugin/index.js +120 -3
  23. package/openclaw-plugin/skills/grix-admin/SKILL.md +127 -156
  24. package/openclaw-plugin/skills/grix-egg/SKILL.md +27 -1
  25. package/openclaw-plugin/skills/grix-group/SKILL.md +52 -159
  26. package/openclaw-plugin/skills/grix-query/SKILL.md +54 -248
  27. package/openclaw-plugin/skills/grix-update/SKILL.md +70 -304
  28. package/openclaw-plugin/skills/message-send/SKILL.md +41 -172
  29. package/openclaw-plugin/skills/message-unsend/SKILL.md +29 -170
  30. package/package.json +1 -1
  31. package/dist/assets/dsh-bridge/grix-dsh-bridge-4.2.3.tgz +0 -0
@@ -1,39 +1,93 @@
1
1
  ---
2
2
  name: grix-egg
3
- description: 'Install a Grix egg skill package into your own skill directory. Use when you receive an instruction containing a line like "技能包: <URL>" and are asked to install / incubate it as a skill for yourself.'
4
- trigger: "当收到含「技能包: <URL>」的安装指令、要求把虾蛋技能包装进自己的技能目录时"
3
+ description: "Grix egg market — the FIRST entry when the user wants a new agent or assistant for some purpose: search published eggs (skill and persona packages) by the business description with `grix_egg_search` / `grix_egg_get`, present matches, then install the chosen egg yourself from the download URL `grix_egg_get` returns (skill package into your own skill directory, or persona package into a new agent via grix-admin); only when nothing fits do you fall back to grix-admin to create a bare agent. Also handles the platform install instruction (a line like \"技能包: <URL>\")."
4
+ trigger: 'When the user wants to create a new agent / assistant for a role or business need, asks what ready-made eggs (skills, personas) exist, or when you receive an install instruction containing a "技能包: <URL>" line'
5
5
  ---
6
6
 
7
- # Grix Egg — Skill Package Self-Install
7
+ # Grix Egg
8
8
 
9
- For an agent like you, incubating an egg means exactly one thing: **installing a
10
- skill package into your own skill directory** so you can use it from then on.
9
+ Two jobs, in the order they happen:
11
10
 
12
- When you receive an install instruction containing a `技能包: <URL>` line, use
13
- this skill to install it, self-check, and send back an install-status card. The
14
- whole job is done by you on this machine no other agent installs it for you,
15
- and the main agent cannot touch your skill directory.
11
+ 1. [Discovery](#part-1--discovery-find-an-egg-before-creating-an-agent) the
12
+ user wants a new agent: find a ready-made egg first.
13
+ 2. [Self-install](#part-2--self-install-技能包-url)install a skill package
14
+ into your own skill directory, from a URL you got via `grix_egg_get` or
15
+ from the platform's `技能包: <URL>` instruction.
16
16
 
17
- ## What the instruction gives you
17
+ ## Part 1 Discovery: find an egg before creating an agent
18
18
 
19
- - `技能包: <URL>` download URL of the skill package to install (always present).
20
- - `install_id: <ID>` the ID of this install; echo it verbatim in the status card (always present).
21
- - `grix agent id: <ID>` your own grix agent id; use it as `target_agent_id` in the status card (may be present).
19
+ When the user describes an agent they want ("帮我建一个跟进外贸询盘的助手",
20
+ "I need a bot that reviews PRs"), **do not** go to `grix-admin` yet. Search the
21
+ egg market first; a published egg gives them a tested skill set or persona in
22
+ one tap.
22
23
 
23
- ## What you must do
24
+ ### Search strategy
24
25
 
25
- 1. Extract the download URL after `技能包:`.
26
- 2. Determine your own skill directory: it is **the parent of the directory this grix-egg skill lives in**. E.g. if this skill is at `~/.codex/skills/grix-egg/`, the skill directory is `~/.codex/skills/`; at `~/.claude/skills/grix-egg/` it is `~/.claude/skills/`, and so on.
27
- 3. Download and unpack the skill package.
28
- 4. Copy every unpacked skill (any directory containing a `SKILL.md`) into your skill directory, whole directory at a time.
29
- 5. Confirm the new skill's `SKILL.md` now exists in your skill directory.
30
- 6. **Send back the install-status card** (see below) so the platform can close out this install as success/failure.
31
- 7. Then tell the user, in one natural-language sentence, which skill(s) were installed.
26
+ The backend matches keywords term-by-term (AND) against name + description +
27
+ category, so a whole sentence returns nothing. Instead:
32
28
 
33
- ## Steps 2–5: install (run in shell)
29
+ 1. Distill the description into **2–4 short keywords**: the role noun, the
30
+ domain, the core action (e.g. `外贸`, `询盘`, `报价`; `code review`, `PR`).
31
+ 2. Call `grix_egg_search` **once per keyword** (`pageSize` 10), in the user's
32
+ language and `locale`. Merge the results, rank by number of keyword hits
33
+ then `install_count`.
34
+ 3. If keywords return nothing, browse by category: search with no keyword
35
+ and a likely `categoryId` (categories come back in `category_id` /
36
+ `category_name` of any result, or run a broad search first).
37
+ 4. Optionally `grix_egg_get` the top candidates for the full description and
38
+ `version_desc`.
34
39
 
35
- Replace the two angle-bracket placeholders with real values, then run.
36
- `SKILLS_DIR` is the parent of the directory this skill lives in.
40
+ ### Present candidates
41
+
42
+ Show at most 3–5 eggs, each with: name (+ emoji), one-line description,
43
+ category, `install_count`, and what it can do for the user:
44
+
45
+ - `can_create_agent: true` — hatches into a **new agent** (persona + skills).
46
+ - `existing_agent_client_types` non-empty — installs as a **skill into an
47
+ existing agent** of those client types.
48
+
49
+ Ask the user which one to hatch. Do not invent capabilities that are not in
50
+ the egg description.
51
+
52
+ ### Install the chosen egg
53
+
54
+ `grix_egg_get` returns the package URLs: `skill_zip_url` (+ `skill_zip_sha256`)
55
+ and `persona_zip_url` (+ `persona_zip_sha256`). No App round-trip is needed.
56
+
57
+ - **Skill into yourself** (`existing_agent_client_types` includes your client
58
+ type): download `skill_zip_url`, verify the sha256 when present, then run the
59
+ Part 2 script with that URL. There is no `install_id` in this path, so skip
60
+ the status card and just report the installed skill(s).
61
+ - **New agent** (`can_create_agent: true`): create and bind the agent with
62
+ `grix-admin` (`create-and-connector-bind`), then apply `persona_zip_url` to
63
+ it the same way the platform's `人格包: <URL>` instruction would.
64
+ - No egg fits, or the user explicitly wants a blank agent → hand over to
65
+ `grix-admin` (`create-and-connector-bind`) and say clearly that no
66
+ ready-made egg matched.
67
+
68
+ If the platform itself sends a `技能包: <URL>` instruction (the owner hatched
69
+ from the App), run Part 2 — that path carries an `install_id` and needs the
70
+ status card.
71
+
72
+ ## Part 2 — Self-install (`技能包: <URL>`)
73
+
74
+ Incubating an egg means exactly one thing for you: **installing a skill
75
+ package into your own skill directory**. The whole job runs on this machine;
76
+ no other agent installs it for you.
77
+
78
+ The instruction gives you:
79
+
80
+ - `技能包: <URL>` — download URL of the package (always present).
81
+ - `install_id: <ID>` — echo it verbatim in the status card (always present).
82
+ - `grix agent id: <ID>` — your own agent id; use as `target_agent_id` in the
83
+ status card (may be present).
84
+
85
+ Steps: (1) extract the URL; (2) your skill directory is **the parent of the
86
+ directory this skill lives in** (e.g. `~/.claude/skills/grix-egg/` →
87
+ `~/.claude/skills/`); (3) download, unpack, copy every directory containing a
88
+ `SKILL.md` into it, overwriting a same-name skill; (4) confirm the new
89
+ `SKILL.md` exists; (5) send the status card; (6) tell the user in one sentence
90
+ which skill(s) were installed.
37
91
 
38
92
  ```bash
39
93
  set -e
@@ -45,7 +99,6 @@ curl -fsSL "$URL" -o "$TMP/skill.zip"
45
99
  mkdir -p "$TMP/unpacked"
46
100
  unzip -o -q "$TMP/skill.zip" -d "$TMP/unpacked"
47
101
 
48
- # Copy every skill directory containing a SKILL.md into the skill directory
49
102
  found=0
50
103
  while IFS= read -r -d '' f; do
51
104
  d="$(dirname "$f")"
@@ -53,7 +106,7 @@ while IFS= read -r -d '' f; do
53
106
  found=1
54
107
  done < <(find "$TMP/unpacked" -name SKILL.md -print0)
55
108
 
56
- # Fallback: SKILL.md sits loose at the unpack root — create a skill directory named after its `name` and move everything in
109
+ # Fallback: SKILL.md sits loose at the unpack root
57
110
  if [ "$found" -eq 0 ] && [ -f "$TMP/unpacked/SKILL.md" ]; then
58
111
  name="$(grep -m1 '^name:' "$TMP/unpacked/SKILL.md" | sed 's/^name:[[:space:]]*//')"
59
112
  [ -z "$name" ] && name="egg-skill"
@@ -61,38 +114,29 @@ if [ "$found" -eq 0 ] && [ -f "$TMP/unpacked/SKILL.md" ]; then
61
114
  cp -R "$TMP/unpacked/." "$SKILLS_DIR/$name/"
62
115
  fi
63
116
 
64
- # Self-check: list the skill directory and confirm the new skill is in place
65
117
  ls -1 "$SKILLS_DIR"
66
118
  rm -rf "$TMP"
67
119
  ```
68
120
 
69
- ## Step 6: send back the install-status card
121
+ ### Status card
70
122
 
71
- After installing and self-checking, **send a separate, standalone message**
72
- whose content is exactly the single card-link line below (the message contains
73
- only this line — no other text):
123
+ After the self-check, send a **separate, standalone message** containing only
124
+ this one line (the platform uses it to close the install record):
74
125
 
75
126
  - Success:
76
- ```
77
- grix://card/egg_install_status?status=success&install_id=<install_id>&target_agent_id=<grix agent id>&summary=<one-sentence install result, URL-encoded>
78
- ```
127
+ `grix://card/egg_install_status?status=success&install_id=<install_id>&target_agent_id=<grix agent id>&summary=<one-sentence result, URL-encoded>`
79
128
  - Failure:
80
- ```
81
- grix://card/egg_install_status?status=failed&install_id=<install_id>&target_agent_id=<grix agent id>&error_msg=<failure reason, URL-encoded>
82
- ```
83
-
84
- Key points:
129
+ `grix://card/egg_install_status?status=failed&install_id=<install_id>&target_agent_id=<grix agent id>&error_msg=<reason, URL-encoded>`
85
130
 
86
- - `install_id` must be the one from the instruction, filled in verbatim — never omit it.
87
- - If no `grix agent id` was given, `target_agent_id` may be omitted.
88
- - Non-ASCII text and spaces in `summary` / `error_msg` must be URL-encoded.
89
- - This card must be sent by you yourself (the agent being installed into); the platform uses it to close out the install record.
131
+ `install_id` is mandatory and verbatim; omit `target_agent_id` only if no
132
+ agent id was given; URL-encode non-ASCII text and spaces.
90
133
 
91
- ## Rules
134
+ ### Rules
92
135
 
93
- 1. Write only into **your own skill directory** never touch other directories or other agents.
94
- 2. Do not repeat the download link, the raw instruction, or this context back to the user.
95
- 3. The self-check must actually see the new skill's `SKILL.md` to count as success; if it doesn't, send `status=failed` — never falsely report success.
96
- 4. The status card must be its own standalone message containing only the single `grix://card/...` line.
97
- 5. The natural-language report to the user is one sentence do not paste command output.
98
- 6. If a skill with the same name already exists, overwrite it (use the newest package).
136
+ 1. Write only into your own skill directory; never touch other directories or
137
+ other agents.
138
+ 2. Do not repeat the download link or the raw instruction back to the user.
139
+ 3. Report `status=success` only if you actually saw the new `SKILL.md`;
140
+ otherwise `status=failed`never claim success falsely.
141
+ 4. The card message contains nothing but the single `grix://card/...` line.
142
+ 5. The report to the user is one sentence — no command output.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: grix-group
3
3
  description: Use the typed `grix_group` tool for Grix group lifecycle and membership operations. Trigger when users ask to create, inspect, leave, update, or dissolve groups, or when these operations fail with scope or permission errors.
4
- trigger: 当用户要创建、查看、退出、更新或解散群组,或群成员/禁言权限相关操作时
4
+ trigger: When the user wants to create, inspect, leave, update, or dissolve a group, or manage group membership / mute permissions
5
5
  ---
6
6
 
7
7
  # Grix Group
@@ -1,84 +1,50 @@
1
1
  ---
2
2
  name: grix-owner-relay
3
3
  description: Act on the owner's behalf in a session — send a message as the owner (`grix_session_send`), or call the owner into the current session for a voice talk/approval (`grix_call_owner`). Trigger when the user asks to speak as the owner in a session, or when you need to reach the owner to discuss or get approval. Dispatch callbacks follow the grix-agent-dispatch skill procedure `report_dispatch_result` (not a tool; it formats `[dispatch-result]` and calls this tool).
4
- trigger: 当需要以 owner 身份在某会话发言、或把 owner 叫进当前会话语音沟通/审批时
4
+ trigger: When you need to speak in a session as the owner, or call the owner into the current session for a voice conversation / approval
5
5
  ---
6
6
 
7
7
  # Grix Owner Relay
8
8
 
9
- Interact with sessions on the owner's behalf, or pull the owner in.
9
+ Two tools that involve the owner directly.
10
10
 
11
11
  ## Speak as the owner — `grix_session_send`
12
12
 
13
- Send a message into a session **as the owner** — it shows up as if the owner
14
- themselves sent it, **not** as you (the agent).
13
+ Sends a message into a session **as the owner** — it appears as the owner's
14
+ own words, **not** as you (the agent).
15
15
 
16
- - `session_id` (required) — target session ID.
17
- - `content` (required) message text to send as the owner (max 10000 chars).
18
- - `quoted_message_id` (optional) — message ID in the **same** target session to
19
- quote/reply to. Required for dispatch callbacks so the dispatcher is
20
- quote-woken.
16
+ - `session_id` (required) — target session ID. The owner must be a member of
17
+ it; otherwise the send is rejected with an owner-not-member error.
18
+ - `content` (required) — message text (max 10000 chars).
19
+ - `quoted_message_id` (optional) ID of a message in the **same** target
20
+ session to quote/reply to.
21
21
 
22
- ### When to use it
22
+ Requires the **Send as Owner** permission scope. If the call is rejected for a
23
+ missing permission or non-membership, surface the error as-is so the owner can
24
+ fix it; never work around it with `grix_message_send`. Your own membership in
25
+ the target session is not checked and is irrelevant.
23
26
 
24
- To relay on the owner's behalf into a session where the message must appear as
25
- the owner's own words. Typical case: you were dispatched to work somewhere and
26
- need to drop a note to the owner (or to others) in a session of theirs.
27
+ ### Use it only when the message must appear as the owner's
27
28
 
28
- **First-class use case: dispatch callback.** When you were dispatched via
29
- `grix-agent-dispatch`, follow the skill procedure `report_dispatch_result` in
30
- that skill (exactly 6 parameters; **not** a tool name). It formats `content`
31
- as **only** the `[dispatch-result]` wire block (no `@` line), and calls this
32
- tool with `session_id` = `callback_session_id` and
33
- `quoted_message_id` = the dispatcher anchor from the task pointer. Do not
34
- hand-roll the wire template in the task text; if you must call this tool
35
- directly for a dispatch callback, still send **only** that block plus the
36
- quote id no extra instructions, explanations, or requests outside the
37
- block.
38
-
39
- **Dispatch callbacks always go through this tool, even when you are a member
40
- of the callback session.** A message sent as yourself cannot quote-wake the
41
- dispatcher agent, so membership is irrelevant — never fall back to
42
- `grix_message_send` for a callback. If the call is rejected for missing
43
- permission, surface the error as-is so the owner can grant the scope; do not
44
- work around it.
45
-
46
- ### Before you call it, make sure
47
-
48
- 1. You genuinely want to **impersonate the owner**, not speak as yourself
49
- (dispatch callbacks are exactly such a case).
50
- 2. The owner is a member of the target session (otherwise the send is
51
- rejected with an owner-not-member error — surface it, don't retry blindly).
52
-
53
- ### Never use it for
54
-
55
- - ❌ **Sending your own ordinary reply in a conversation.** Reply normally
56
- instead (or use `grix_message_send` to send as yourself). Using
57
- `grix_session_send` for ordinary chatter makes *your* answer appear as the
58
- *owner's* words. The one exception is the structured dispatch callback
59
- (`report_dispatch_result`), which must always go through this tool.
60
- - ❌ As a generic substitute for sending a message as yourself — use
61
- `grix_message_send` for that.
62
-
63
- To send as yourself (the agent), use the `message-send` skill
64
- (`grix_message_send`).
29
+ - Dispatch callbacks: the `report_dispatch_result` procedure in
30
+ `grix-agent-dispatch` (a skill procedure with exactly 6 parameters, **not** a
31
+ tool name) builds a `[dispatch-result]` block and sends it through this
32
+ tool with `quoted_message_id` set and no `@` line. That skill owns the
33
+ format; follow it there.
34
+ - Relaying a note the owner asked you to send under their name.
35
+ - Your own ordinary replies reply normally, or use `grix_message_send`
36
+ (skill `message-send`) to send as yourself. Using this tool for ordinary
37
+ chatter makes *your* answer appear as the *owner's* words.
65
38
 
66
39
  ## Call the owner in — `grix_call_owner`
67
40
 
68
- Bring the owner into a session for a voice conversation — use this when you need
69
- to discuss something or get an approval/review during your work. It sends the
70
- owner an offline notification; tapping it lands them in the conversation and
71
- auto-starts a voice-brain call.
41
+ Brings the owner into a session for a voice conversation — use it when you
42
+ need to discuss something or get an approval/review during your work. The
43
+ owner receives an offline notification; tapping it lands them in the
44
+ conversation and auto-starts a voice-brain call.
72
45
 
73
46
  - `session_id` (required) — the session to call the owner into.
74
47
 
75
- ## Rules
76
-
77
- 1. `grix_session_send` requires the owner to be a member of the target session,
78
- plus the **Send as Owner** permission scope. Your own membership in the
79
- target session is irrelevant and is not checked. If the call is rejected for
80
- missing permission, surface the error as-is — the owner can grant the scope;
81
- never work around it with `grix_message_send`.
82
- 2. `grix_call_owner` requires the owner to have configured a voice brain and is
83
- rate-limited per session. Use it only when you genuinely need the owner, not
84
- as a routine notification.
48
+ Requires the owner to have configured a voice brain, and is rate-limited per
49
+ session. Use it only when you genuinely need the owner, not as a routine
50
+ notification.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: grix-query
3
3
  description: Use the typed `grix_query` tool for Grix contact lookup, keyword search, session search, favorited-session search, and session message history lookup. Trigger when users ask to find contacts, search conversations, list visible or favorited sessions, or inspect recent messages in a known session.
4
- trigger: 当用户要查找联系人、搜索会话、列出可见会话或收藏会话、或查看某个已知会话的历史消息时
4
+ trigger: When the user wants to find contacts, search sessions, list visible or favorited sessions, or read message history of a known session
5
5
  ---
6
6
 
7
7
  # Grix Query
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: grix-skill-library
3
+ description: Manage the owner's custom skill library on the Grix platform with `grix_skill_get` (list or read a skill's SKILL.md) and `grix_skill_set` (create, overwrite, or delete a skill by name). The library syncs to every machine the owner runs an agent on. Trigger when the user asks to save something as a reusable skill, list or show their skills, edit an existing skill, or delete one.
4
+ trigger: When the user wants to list, read, create, update, or delete one of their custom Grix skills, or turn a procedure into a reusable skill
5
+ ---
6
+
7
+ # Grix Skill Library
8
+
9
+ The owner's custom skills live in the Grix platform and auto-sync to a
10
+ per-machine `grix/skills` directory on every host where the owner runs an
11
+ agent. These two tools manage that library only; whether and when an agent
12
+ loads a synced skill is up to the owner (system prompt or conversation).
13
+
14
+ ## Tools
15
+
16
+ - `grix_skill_get` — `name` (optional). With a name: returns that skill's full
17
+ `SKILL.md` text. Without: lists the library (names + versions).
18
+ - `grix_skill_set` — `name` (required, max 100 chars, unique per owner; also
19
+ the synced directory name) and `content` (required, full `SKILL.md` text,
20
+ max 256 KB). An existing name is overwritten. An empty `content` string
21
+ **deletes** the skill.
22
+
23
+ ## Skill format
24
+
25
+ `content` is a standard `SKILL.md`: YAML frontmatter with `name` (matching
26
+ the `name` argument) and a one-line `description` that says what the skill
27
+ does and when to use it, then a Markdown body with the procedure — inputs,
28
+ steps, rules, and how to report. Write it for an agent that has no other
29
+ context. Keep it focused on one job; do not embed secrets, machine-specific
30
+ paths, or credentials.
31
+
32
+ ## Workflow
33
+
34
+ 1. **Create**: confirm the name and what the skill should do; draft the
35
+ `SKILL.md`; call `grix_skill_set`. Before overwriting, call
36
+ `grix_skill_get` with the name to check whether it already exists and
37
+ tell the user if it does.
38
+ 2. **Edit**: `grix_skill_get` the current content first, apply the change to
39
+ that text, then `grix_skill_set` the full revised text — never send a
40
+ partial body.
41
+ 3. **Delete**: confirm with the user, then `grix_skill_set` with the name and
42
+ `content: ""`.
43
+ 4. **List / show**: `grix_skill_get` without a name, or with the name.
44
+
45
+ ## Rules
46
+
47
+ 1. Never guess a skill name — list first if unsure.
48
+ 2. Overwrite and delete are irreversible; confirm before either when the
49
+ user did not explicitly ask for it.
50
+ 3. After a successful set, tell the user the skill is saved and will sync to
51
+ their machines; do not paste the whole content back unless asked.
52
+ 4. On a permission or scope error, report it as-is; do not retry.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: grix-widget-visitor-ban
3
3
  description: Ban a widget visitor session with the typed `grix_widget_visitor_ban` tool — blocks the visitor's chat session and automatically adds the session's most recent init IP to the owner's global IP ban list (7-day expiry by default). Trigger when the owner asks to ban, block, or kick an abusive/spamming widget visitor.
4
- trigger: 当用户要封禁、拉黑或踢掉某个骚扰/滥用的 widget 访客会话时
4
+ trigger: When the owner wants to ban, block, or kick an abusive or spamming widget visitor session
5
5
  ---
6
6
 
7
7
  # Grix Widget Visitor Ban
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: message-send
3
3
  description: "Send a message into a specific Grix session by session ID, including cross-session and proactive sends. For replying to the current event use the reply/complete tools instead. Trigger words: send DM, DM, send message, notify, message another session."
4
- trigger: 当用户要主动给某个指定会话发消息、跨会话发送、或通知另一个会话时
4
+ trigger: When the user wants to proactively message a specific session, send across sessions, or notify another session
5
5
  ---
6
6
 
7
7
  # Message Send
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: message-unsend
3
3
  description: "Silently recall/unsend an already-sent message in a Grix session. After execution, end immediately without replying any confirmation text. Trigger words: recall, unsend, delete message, withdraw message."
4
- trigger: 当用户要撤回、收回、删除一条已经发出的消息时
4
+ trigger: When the user wants to recall, retract, or delete a message that was already sent
5
5
  ---
6
6
 
7
7
  # Message Unsend
@@ -1,88 +1,54 @@
1
1
  ---
2
2
  name: tailnet-file-share
3
- description: Turn a local file into a tailnet link images render as inline previews, everything else gets a download link. Trigger when the user asks to view, send, share, download, or export any file on this machine.
4
- trigger: 当用户要求查看、发送、分享、下载、导出本机上的任何文件时
3
+ description: Deliver a local file to the useras a native chat attachment (`grix_file_upload`) or as a tailnet download/preview link (`grix_file_link`). Trigger when the user asks to view, send, share, download, or export any file on this machine.
4
+ trigger: When the user asks to view, send, share, download, or export any file on this machine
5
5
  ---
6
6
 
7
7
  # Tailnet File Share
8
8
 
9
- When the user wants to view or obtain a file on this machine (images, logs, reports, build artifacts, exported data, etc.), you must:
9
+ When the user wants a file that lives on this machine (image, log, report,
10
+ build artifact, exported data, …), never paste its path or contents. Pick one
11
+ of two tools and hand over the result.
10
12
 
11
- 1. Call the `grix_file_link` tool with the file's absolute path.
12
- 2. Copy the tool's `markdown` field into your reply verbatim — do not modify it.
13
- - Image files (jpg/png/gif/webp/svg, etc.): the tool returns `![filename](url)`, which renders as an inline image preview in chat.
14
- - Other files: the tool returns `[filename](url)`, which the user clicks to download.
15
- 3. Do not print the raw file path, and do not paste or paraphrase the file contents.
16
- 4. The link is bound to this machine's tailnet-internal address and is unreachable from the public internet. The user can reopen it any time, so under normal circumstances there is no expiry to worry about and none to mention — just send the link.
13
+ ## 1. Choose the tool
17
14
 
18
- ## When to use `grix_file_upload` (native attachment) instead
15
+ | Scenario | Tool |
16
+ |---|---|
17
+ | The file should appear as a proper attachment in the chat — especially images or videos the user will look at inline; ≤ 50 MB | `grix_file_upload` |
18
+ | File > 50 MB, a clickable download link is enough, or it is an arbitrary local artifact | `grix_file_link` |
19
19
 
20
- Besides `grix_file_link` there is a `grix_file_upload` tool: it uploads a local
21
- file to the Grix platform, where it appears in the target session as a **native
22
- attachment message** (images/videos display inline in chat no tailnet, no
23
- certificate install needed). It supports images, videos, documents, and
24
- archives, up to 50 MB per file. Choose by scenario:
20
+ `grix_file_upload` uploads to the Grix platform; the attachment renders
21
+ natively (images/videos inline) with no tailnet or certificate involved.
22
+ Supports images, videos, documents, archives up to 50 MB per file.
25
23
 
26
- - The file should be a proper attachment in the chat (especially sending images or videos for the user to look at) → use `grix_file_upload`.
27
- - The file is large (>50 MB), a clickable download link is all that's needed, or it's an arbitrary local-path artifact → use `grix_file_link`.
24
+ `grix_file_link` serves the file over HTTPS from this machine's tailnet
25
+ address. The link is unreachable from the public internet, stays valid
26
+ indefinitely, and the user can reopen it any time — do not mention expiry.
28
27
 
29
- ## HTTPS and the one-time trust-certificate install
28
+ ## 2. Call it and relay the result
30
29
 
31
- Download links are HTTPS (`https://…`), signed on the fly by a self-signed CA
32
- built into this machine with a 10-year validity. The tool result also returns
33
- `ca_install_url` the install link for the root CA certificate.
30
+ - `grix_file_upload`: `file_path` (absolute) and `session_id` (the current
31
+ chat's session unless the user names another); optional `caption` and
32
+ `reply_to_message_id`. The tool delivers the attachment do not also send
33
+ a link.
34
+ - `grix_file_link`: `file_path` (absolute); leave `ttl_ms` unset. Copy the
35
+ tool's `markdown` field into your reply **verbatim**:
36
+ - images (jpg/png/gif/webp/svg …) come back as `![filename](url)` and
37
+ render as an inline preview;
38
+ - everything else comes back as `[filename](url)` for download.
34
39
 
35
- - **The first time you send a file link to a given user** (or whenever they report "the link won't open / certificate not trusted / not secure"), send them `ca_install_url` as the "install trust certificate" link along with the steps below.
36
- - Each device only needs this **once**; afterwards, for 10 years, every download link from this machine is warning-free, and no reinstall is needed even if the tailnet IP changes.
40
+ Do not print the raw file path and do not paraphrase the file contents.
37
41
 
38
- Install guidance to send the user (pick the one matching their device):
42
+ If `grix_file_link` fails (e.g. Tailscale is not connected), tell the user the
43
+ local file path so they can retrieve it themselves.
39
44
 
40
- - **iPhone / iPad**: open `ca_install_url` in Safari — it prompts "This website is trying to download a configuration profile" → Allow → a "Profile Downloaded" entry appears at the top of Settings; tap it to install → then go to Settings → General → About → Certificate Trust Settings and turn the switch on for that certificate (enable full trust). This step is mandatory, otherwise the system still won't trust it. (iOS must use Safari; other browsers won't trigger profile installation. The server already returns a `.mobileconfig` based on the device, so no manual parameters are needed.)
41
- - **Mac**: click the link to download the `.crt` → double-click to open it in Keychain Access → find the certificate → double-click → expand "Trust" → set "When using this certificate" to "Always Trust".
42
- - **Android**: tap `ca_install_url` to download the `.crt` → Settings → Security → Encryption & credentials → Install a certificate → CA certificate, and pick the downloaded file (recent Android versions do not support one-tap install from the browser; the Settings route is required).
43
- - **Windows**: double-click the `.crt` → "Install Certificate" → choose the store location → "Place all certificates in the following store" → select "Trusted Root Certification Authorities".
45
+ ## 3. If the link does not open (`grix_file_link` only)
44
46
 
45
- If the `grix_file_link` call fails (e.g. Tailscale is not connected), tell the
46
- user the local file path and let them retrieve it themselves.
47
-
48
- ## Scope (important): this CA only covers `grix_file_link`'s own service
49
-
50
- The built-in CA above and the certificates it issues **only make the download
51
- service started by `grix_file_link` (this machine's tailnet address) trusted by
52
- the device**. It does not cover — and cannot fix — other services the user
53
- starts themselves.
54
-
55
- When the user has **started their own HTTPS service on the tailnet** (a
56
- self-hosted site / API / media server, etc.) and the browser reports a
57
- certificate error, be clear that this is a separate matter:
58
-
59
- - A device only trusts "certificates issued by a CA it has personally installed". A self-hosted service uses its own CA (e.g. mkcert), which the device never installed, so it reports `not trusted / impersonation / NET::ERR_CERT_AUTHORITY_INVALID` — this has nothing to do with whether the Grix CA is installed.
60
- - There are only two ways to make a self-hosted service trusted:
61
- 1. Have that service sign its certificate with a CA the device already trusts, and keep the leaf certificate's validity **≤ 398 days** (otherwise, even with the CA trusted, it reports `NET::ERR_CERT_VALIDITY_TOO_LONG`);
62
- 2. Or simply don't have the user run their own HTTPS — share the files via `grix_file_link` instead, served by the built-in service, automatically trusted and with compliant validity.
63
- - Note: the Grix built-in CA's **private key stays only on the machine running the connector and is never handed out** (`ca_install_url` serves the public certificate only, not the private key). So only services **on the same machine as the connector** can borrow this CA for signing; services on other machines must bring their own CA and install it once per device.
64
-
65
- In short: if it can be sent via `grix_file_link`, send it that way — it's the
66
- least trouble. Certificate trust for self-hosted services is outside this
67
- skill's responsibility and must be solved on that service's side.
68
-
69
- ## Two trust paths: inside the Grix app vs. the system browser (diagnose this first)
70
-
71
- The same link opened **in the Grix app** and **in a system browser (Safari /
72
- Chrome)** goes through two entirely independent certificate-trust mechanisms,
73
- with different errors and different fixes. When a user reports "won't open /
74
- certificate error", first find out which path they were on.
75
-
76
- - **Inside the Grix app** (image previews, in-app downloads, etc. use the app's own network stack): the app has a built-in trust rule — if the link is a tailnet address (`100.64.0.0/10` range) and the certificate's issuer name contains `Grix Tailnet Local CA`, it is allowed through, and **the user does not need to install any certificate on the device**. So `grix_file_link` links generally work out of the box in the app with zero install. If it still won't open in the app, it's most likely not a tailnet IP, or the issuer name doesn't match — not a "certificate not installed" problem.
77
- - **System browser (Safari / Chrome)**: this goes through the phone's / computer's system trust store, which has nothing to do with the app's rule. The root CA must be installed as described in *HTTPS and the one-time trust-certificate install* above (on iOS, install the `.mobileconfig` and enable full trust; on Android, go through Settings; and so on). `NET::ERR_CERT_AUTHORITY_INVALID`, "impersonation", and `NET::ERR_CERT_VALIDITY_TOO_LONG` in the user's screenshots are almost always this path — guide them to install the CA.
78
-
79
- The same distinction applies to **self-hosted services**, decided by where the user wants to view it:
80
-
81
- - Only needs to display **inside the Grix app**: the self-hosted service does not have to distribute a private key to the user, and no certificate install is needed — it only needs to ① be served on a tailnet IP, and ② have its CA's issuer name carry `Grix Tailnet Local CA`, and the app will trust it.
82
- - Needs to open in a **system browser**: the app's rule does not apply; that service's own CA must still be installed on each device (see *Scope* above).
83
-
84
- Note: the in-app rule is **a string match on the issuer name**, not a binding to
85
- a specific CA's public-key fingerprint. It is a convenience trade-off within a
86
- private tailnet only and **is not a hard security boundary** — anyone on the
87
- same tailnet can have the app trust them simply by naming their CA with the same
88
- prefix. Do not treat it as a trust root that stands up to an attacker.
47
+ Links open inside the Grix app with no setup. In a system browser
48
+ (Safari/Chrome) the device must trust this machine's root CA once: the tool
49
+ result includes `ca_install_url`. The first time you send a link to a user, or
50
+ whenever they report "won't open / certificate not trusted / not secure", send
51
+ `ca_install_url` with the per-device steps in
52
+ [references/certificate-trust.md](references/certificate-trust.md). That file
53
+ also explains why the CA does not cover the user's own self-hosted HTTPS
54
+ services.
@@ -0,0 +1,64 @@
1
+ # Certificate trust for `grix_file_link` links
2
+
3
+ Download links are HTTPS, signed on the fly by a self-signed root CA built
4
+ into this machine (10-year validity). The tool result returns
5
+ `ca_install_url`, the install link for that root CA's **public** certificate.
6
+
7
+ ## Two independent trust paths — diagnose this first
8
+
9
+ - **Inside the Grix app** (image previews, in-app downloads): the app has a
10
+ built-in rule — a link on a tailnet address (`100.64.0.0/10`) whose
11
+ certificate issuer name contains `Grix Tailnet Local CA` is allowed through.
12
+ No certificate install is needed. If a link still fails in the app, the
13
+ cause is a non-tailnet IP or a mismatched issuer name, not a missing
14
+ certificate.
15
+ - **System browser (Safari / Chrome)**: uses the device's system trust store,
16
+ which knows nothing about the app rule. The root CA must be installed once
17
+ per device. `NET::ERR_CERT_AUTHORITY_INVALID`, "impersonation", and
18
+ `NET::ERR_CERT_VALIDITY_TOO_LONG` in a user's screenshot are almost always
19
+ this path.
20
+
21
+ Note: the in-app rule is a string match on the issuer name, not a pin on a
22
+ specific CA key. It is a convenience inside a private tailnet, not a security
23
+ boundary.
24
+
25
+ ## One-time install per device (system browser path)
26
+
27
+ Each device needs this once; afterwards every link from this machine is
28
+ warning-free for 10 years, even if the tailnet IP changes. Send the step
29
+ matching the user's device:
30
+
31
+ - **iPhone / iPad**: open `ca_install_url` in **Safari** (other browsers do
32
+ not trigger profile install) → "This website is trying to download a
33
+ configuration profile" → Allow → Settings shows "Profile Downloaded" at the
34
+ top; tap it to install → then Settings → General → About → Certificate
35
+ Trust Settings → enable full trust for the certificate. The last step is
36
+ mandatory. The server returns a `.mobileconfig` automatically.
37
+ - **Mac**: download the `.crt` → double-click to open in Keychain Access →
38
+ find the certificate → double-click → expand "Trust" → set "When using this
39
+ certificate" to "Always Trust".
40
+ - **Android**: download the `.crt` → Settings → Security → Encryption &
41
+ credentials → Install a certificate → CA certificate → pick the file
42
+ (recent Android versions require the Settings route).
43
+ - **Windows**: double-click the `.crt` → "Install Certificate" → "Place all
44
+ certificates in the following store" → "Trusted Root Certification
45
+ Authorities".
46
+
47
+ ## Self-hosted HTTPS services are out of scope
48
+
49
+ The built-in CA only makes `grix_file_link`'s own download service trusted. A
50
+ service the user runs themselves (site / API / media server on the tailnet)
51
+ uses its own CA that the device never installed, so the browser reports
52
+ `not trusted / NET::ERR_CERT_AUTHORITY_INVALID` regardless of the Grix CA.
53
+
54
+ Ways to make such a service trusted:
55
+
56
+ 1. Sign its certificate with a CA the device already trusts, keeping the leaf
57
+ validity ≤ 398 days (longer triggers `NET::ERR_CERT_VALIDITY_TOO_LONG`).
58
+ The Grix CA's private key never leaves the machine running the connector
59
+ (`ca_install_url` serves only the public certificate), so only services on
60
+ that same machine could borrow it.
61
+ 2. For in-app viewing only: serve on a tailnet IP with an issuer name
62
+ containing `Grix Tailnet Local CA` — the app rule then applies, but system
63
+ browsers still need that service's CA installed.
64
+ 3. Simplest: share files through `grix_file_link` instead.
@@ -1 +1 @@
1
- function a(o){const e=new Set([`http://127.0.0.1:${o.serverPort}`,`http://localhost:${o.serverPort}`,...o.allowedOrigins]),t=new Set([`127.0.0.1:${o.serverPort}`,`localhost:${o.serverPort}`,...o.allowedHosts]);return{validateRequest(s){const r=i(s,e);if(!r.ok)return r;const n=l(s,t);return n.ok?{ok:!0}:n}}}function i(o,e){const t=o.headers.origin;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${t}`}:{ok:!0}}function l(o,e){const t=o.headers.host;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${t}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
1
+ function a(e){const t=new Set([`http://127.0.0.1:${e.serverPort}`,`http://localhost:${e.serverPort}`,...e.allowedOrigins]),o=new Set([`127.0.0.1:${e.serverPort}`,`localhost:${e.serverPort}`,...e.allowedHosts]);return{validateRequest(s){const r=i(s,t);if(!r.ok)return r;const n=l(s,o);return n.ok?{ok:!0}:n}}}function i(e,t){const o=e.headers.origin;return o?t.has(o)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${o}`}:{ok:!0}}function l(e,t){const o=e.headers.host;return o?t.has(o)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${o}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};