@bendyline/gilde 0.2.2 → 0.2.4
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/authoring/chat-models/btl4-35b-q4.json +1 -0
- package/authoring/chat-models/glm-5.3-flash-320b-q2.json +5 -4
- package/authoring/chat-models/minicpm-v4.7-35b-a3b-q4.json +3 -1
- package/authoring/chat-models/nemotron3.5-bolt-74b-iq2.json +145 -0
- package/authoring/chat-models/nemotron3.5-super-vl-120b-nvfp4.json +143 -0
- package/data/chat-models/bt/btl4-35b-q4/manifest.json +1 -0
- package/data/chat-models/gl/glm-5.3-flash-320b-q2/manifest.json +5 -4
- package/data/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.2/manifest.json +27 -0
- package/data/chat-models/index.json +1 -1
- package/data/chat-models/mi/minicpm-v4.7-35b-a3b-q4/manifest.json +2 -1
- package/data/chat-models/mi/minicpm-v4.7-35b-a3b-q4/versions/1.0.0/manifest.json +1 -0
- package/data/chat-models/ne/nemotron3.5-bolt-74b-iq2/manifest.json +157 -0
- package/data/chat-models/ne/nemotron3.5-bolt-74b-iq2/versions/1.0.0/manifest.json +30 -0
- package/data/chat-models/ne/nemotron3.5-super-vl-120b-nvfp4/manifest.json +156 -0
- package/data/chat-models/ne/nemotron3.5-super-vl-120b-nvfp4/versions/1.0.0/manifest.json +28 -0
- package/data/chat-models/raw-index.json +1 -1
- package/data/craftbook-templates/index.json +1 -1
- package/data/craftbook-templates/raw-index.json +1 -1
- package/data/craftbook-templates/st/status-report/versions/1.0.4/craftbook.json +314 -0
- package/data/craftbook-templates/st/status-report/versions/1.0.4/test.json +110 -0
- package/data/project-types/index.json +1 -1
- package/data/project-types/raw-index.json +1 -1
- package/data/project-types/so/social-feed/versions/1.0.2/about.md +19 -0
- package/data/project-types/so/social-feed/versions/1.0.2/manifest.json +348 -0
- package/data/project-types/so/social-feed/versions/1.0.2/mission.md +10 -0
- package/data/project-types/so/social-feed/versions/1.0.2/pages/dashboard/index.html +754 -0
- package/data/project-types/so/social-feed/versions/1.0.2/posts/index.json +4 -0
- package/data/project-types/so/social-feed/versions/1.0.2/voice-guide.md +22 -0
- package/data/project-types/wo/word-clues/versions/1.0.1/about.md +7 -0
- package/data/project-types/wo/word-clues/versions/1.0.1/game.json +14 -0
- package/data/project-types/wo/word-clues/versions/1.0.1/manifest.json +205 -0
- package/data/project-types/wo/word-clues/versions/1.0.1/mission.md +3 -0
- package/data/project-types/wo/word-clues/versions/1.0.1/pages/board/index.html +399 -0
- package/data/project-types/wo/word-clues/versions/1.0.1/words.json +216 -0
- package/package.json +2 -1
- package/schemas/chat-model-version.schema.json +23 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Voice guide
|
|
2
|
+
|
|
3
|
+
{{voice}}
|
|
4
|
+
|
|
5
|
+
## How {{brand}} sounds
|
|
6
|
+
|
|
7
|
+
- Short sentences. Concrete nouns. No filler.
|
|
8
|
+
- Warm, not chummy; confident, never salesy.
|
|
9
|
+
- Write like one person talking to one person.
|
|
10
|
+
|
|
11
|
+
## Per platform
|
|
12
|
+
|
|
13
|
+
- **Bluesky** — conversational and link-friendly; 300 characters.
|
|
14
|
+
- **X** — tighter; 280 characters, and the first line does the work.
|
|
15
|
+
- **Instagram** — the image leads; the caption adds one honest thought.
|
|
16
|
+
|
|
17
|
+
## Never
|
|
18
|
+
|
|
19
|
+
- Hashtag pile-ups, engagement bait, manufactured urgency.
|
|
20
|
+
- Claims we cannot back, punching down, posting angry.
|
|
21
|
+
|
|
22
|
+
Edit this file freely — the crew treats it as law.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
A word-association game on the **Output** tab. The board holds sixteen words: six are
|
|
2
|
+
yours to find, nine are bystanders, and one is the trap.
|
|
3
|
+
|
|
4
|
+
Your clue-givers take turns. Each gives one word and a number, such as **OCEAN, 2**,
|
|
5
|
+
meaning two of your words go with "ocean". Tap the words you think they mean. You may
|
|
6
|
+
pick one more than the number. A bystander ends your turn, the trap ends the game, and
|
|
7
|
+
finding all six wins it.
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"releasedAt": "2026-10-14T00:00:00Z",
|
|
5
|
+
"minGezelVersion": "1.26280",
|
|
6
|
+
"meesterManaged": false,
|
|
7
|
+
"indexingEnabled": false,
|
|
8
|
+
"leanProfile": true,
|
|
9
|
+
"tabVisibility": {
|
|
10
|
+
"overview": false,
|
|
11
|
+
"tasks": false,
|
|
12
|
+
"approvals": false,
|
|
13
|
+
"workspace": false,
|
|
14
|
+
"artifacts": false,
|
|
15
|
+
"map": false
|
|
16
|
+
},
|
|
17
|
+
"nameTemplate": "Word Clues",
|
|
18
|
+
"aboutTemplate": "about.md",
|
|
19
|
+
"missionTemplate": "mission.md",
|
|
20
|
+
"gezels": [
|
|
21
|
+
{
|
|
22
|
+
"templateId": "woordsmid",
|
|
23
|
+
"voorman": true
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"templateId": "puzzelaar"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"clue-store": "import { type InferredInput, defineScript, gezel } from '@bendyline/gezel-sdk';\n\nexport const meta = defineScript({\n name: 'clue-store',\n description:\n \"The word-clue game's engine (game.json). action:'board' reads the game; 'give_clue' records a clue; 'guess' reveals a word the player picked; 'pass' ends the player's guessing; 'new_game' deals a fresh board.\",\n inputs: {\n action: {\n type: 'string',\n description: \"One of 'board', 'give_clue', 'guess', 'pass', 'new_game'.\",\n required: true,\n },\n clue: { type: 'string', description: 'For give_clue: one word, not on the board.' },\n count: { type: 'number', description: 'For give_clue: how many of the player’s words it points at.' },\n say: { type: 'string', description: 'For give_clue: one short line of table talk.' },\n word: { type: 'string', description: 'For guess: the board word the player picked.' },\n },\n outputs: {\n status: {\n type: 'string',\n description: \"'clue_needed', 'guessing', 'won', 'lost' or 'new'.\",\n },\n giver: { type: 'string', description: \"Whose clue is next: 'a' (Woordsmid) or 'b' (Puzzelaar).\" },\n result: { type: 'string', description: \"For guess: 'target', 'neutral', 'trap', or ''.\" },\n display: { type: 'string', description: 'For give_clue: the clue as shown to the player.' },\n modelState: { type: 'json', description: 'What the clue-giver sees: its words, the trap, the rest.' },\n summary: { type: 'string', description: 'A short summary of the game.' },\n },\n requires: ['workspace.read', 'workspace.write'],\n} as const);\n\nconst input = gezel.input as InferredInput<typeof meta>;\n\n// ── clue-rules-start ──\n// The board is sixteen words: six are the player's, nine are neutral, one\n// is the trap. A clue-giver who knows the board gives one word and a count;\n// the player then picks up to count + 1 words. A neutral word ends their\n// turn, the trap ends the game, and finding all six wins it. Kept\n// self-contained between these sentinels so unit tests execute the shipped\n// bytes.\nvar BOARD_SIZE = 16;\nvar TARGETS = 6;\n\nfunction shuffle(list, random) {\n var out = list.slice();\n for (var i = out.length - 1; i > 0; i -= 1) {\n var j = Math.floor(random() * (i + 1));\n var t = out[i];\n out[i] = out[j];\n out[j] = t;\n }\n return out;\n}\n\nfunction deal(bank, random) {\n var picked = shuffle(bank, random).slice(0, BOARD_SIZE);\n var cells = picked.map(function (word, i) {\n return { word: word, kind: i < TARGETS ? 'target' : i === TARGETS ? 'trap' : 'neutral', revealed: false };\n });\n return shuffle(cells, random);\n}\n\nfunction remaining(words, kind) {\n return words.filter(function (w) { return w.kind === kind && !w.revealed; }).map(function (w) { return w.word; });\n}\n\n// Why a clue is not allowed on this board, or '' when it is.\nfunction clueProblem(words, clue, count) {\n var c = String(clue || '').trim().toLowerCase();\n if (!/^[a-zÀ-ɏ'-]{2,24}$/.test(c)) return 'A clue is one word of letters, like \"ocean\".';\n for (var i = 0; i < words.length; i += 1) {\n var w = words[i].word.toLowerCase();\n if (w === c) return '\"' + c + '\" is on the board.';\n // Forms of a board word (plurals, compounds that start with it) give the\n // answer away; a word that merely contains one (\"planet\", \"net\") does not.\n var shorter = c.length < w.length ? c : w;\n var longer = c.length < w.length ? w : c;\n if (shorter.length >= 3 && longer.indexOf(shorter) === 0)\n return '\"' + c + '\" is a form of the board word \"' + w + '\".';\n }\n var left = remaining(words, 'target').length;\n if (!(count >= 1 && count <= left && Math.floor(count) === count))\n return 'The count must be a whole number from 1 to ' + left + '.';\n return '';\n}\n\nfunction applyGuess(game, word) {\n var pick = String(word || '').trim().toLowerCase();\n var cell = game.words.find(function (w) { return w.word.toLowerCase() === pick; });\n if (!cell) return { error: '\"' + word + '\" is not on the board.' };\n if (cell.revealed) return { error: '\"' + cell.word + '\" is already revealed.' };\n cell.revealed = true;\n var result = cell.kind;\n if (result === 'trap') {\n game.status = 'lost';\n } else if (remaining(game.words, 'target').length === 0) {\n game.status = 'won';\n } else if (result === 'neutral') {\n endGuessing(game);\n } else {\n game.clue.guessesLeft -= 1;\n if (game.clue.guessesLeft <= 0) endGuessing(game);\n }\n return { result: result };\n}\n\nfunction endGuessing(game) {\n game.status = 'clue_needed';\n game.giver = game.giver === 'a' ? 'b' : 'a';\n}\n// ── clue-rules-end ──\n\ninterface Cell {\n word: string;\n kind: 'target' | 'neutral' | 'trap';\n revealed: boolean;\n}\n\ninterface Game {\n version: number;\n status: 'new' | 'clue_needed' | 'guessing' | 'won' | 'lost';\n giver: 'a' | 'b';\n words: Cell[];\n clue: { word: string; count: number; guessesLeft: number; giver: 'a' | 'b' } | null;\n round: number;\n history: Array<{ round: number; clue: string; count: number; found: string[] }>;\n stats: { played: number; won: number; lost: number };\n}\n\nconst GAME_FILE = 'game.json';\n\nasync function load(): Promise<Game> {\n let parsed: Partial<Game> = {};\n try {\n parsed = JSON.parse(await gezel.fs.read(GAME_FILE)) as Partial<Game>;\n } catch {\n // A missing game is a new one.\n }\n return {\n version: 1,\n status: parsed.status ?? 'new',\n giver: parsed.giver === 'b' ? 'b' : 'a',\n words: Array.isArray(parsed.words) ? parsed.words : [],\n clue: parsed.clue ?? null,\n round: parsed.round ?? 0,\n history: Array.isArray(parsed.history) ? parsed.history : [],\n stats: parsed.stats ?? { played: 0, won: 0, lost: 0 },\n };\n}\n\nasync function save(game: Game): Promise<void> {\n await gezel.fs.write(GAME_FILE, `${JSON.stringify(game, null, 2)}\\n`);\n}\n\n// A table nobody has dealt yet gets its first board from the first look at\n// it, so a clue-giver asked to start a game can (new_game is the page's).\nasync function dealInto(game: Game): Promise<void> {\n let bank: string[] = [];\n try {\n bank = (JSON.parse(await gezel.fs.read('words.json')) as { words?: string[] }).words ?? [];\n } catch {\n bank = [];\n }\n if (bank.length < BOARD_SIZE) throw new Error('words.json needs at least 16 words.');\n game.words = deal(bank, Math.random);\n game.status = 'clue_needed';\n game.giver = game.stats.played % 2 === 0 ? 'a' : 'b';\n game.clue = null;\n game.round = 0;\n game.history = [];\n}\n\nconst game = await load();\nlet result = '';\nlet display = '';\nlet changed = false;\n\nswitch (input.action) {\n case 'new_game': {\n await dealInto(game);\n changed = true;\n break;\n }\n case 'give_clue': {\n if (game.status !== 'clue_needed')\n throw new Error(\n game.status === 'guessing'\n ? 'The player is still guessing; no clue is needed yet.'\n : game.status === 'new'\n ? 'No board is dealt yet. Call board first; it deals one.'\n : 'The game is over. Offer a new game instead of a clue.',\n );\n const count = Number(input.count);\n const problem = clueProblem(game.words, input.clue, count);\n if (problem) {\n // Point a struggling clue-giver at one word to hint at: a small model\n // given the whole board tends to offer a board word back.\n const left = remaining(game.words, 'target');\n const hint = left[Math.floor(Math.random() * left.length)];\n throw new Error(\n `${problem} Your clue must be a new word that is not on the board. Think of a word linked to \"${hint}\", and give it with count 1.`,\n );\n }\n const word = String(input.clue).trim().toUpperCase();\n game.clue = { word, count, guessesLeft: count + 1, giver: game.giver };\n game.status = 'guessing';\n game.round += 1;\n game.history = [...game.history, { round: game.round, clue: word, count, found: [] }];\n const say = String(input.say ?? '').replace(/\\s+/g, ' ').trim().slice(0, 160);\n display = `Clue: ${word}, ${count}.${say ? ` ${say}` : ''}`;\n changed = true;\n break;\n }\n case 'guess': {\n if (game.status !== 'guessing') throw new Error('Wait for a clue before guessing.');\n const outcome = applyGuess(game, input.word);\n if (outcome.error) throw new Error(outcome.error);\n result = outcome.result;\n if (result === 'target') game.history[game.history.length - 1]?.found.push(String(input.word));\n if (game.status === 'won' || game.status === 'lost') {\n game.stats.played += 1;\n if (game.status === 'won') game.stats.won += 1;\n else game.stats.lost += 1;\n }\n changed = true;\n break;\n }\n case 'pass': {\n if (game.status !== 'guessing') throw new Error('There is no guessing turn to end.');\n endGuessing(game);\n changed = true;\n break;\n }\n case 'board': {\n if (game.status === 'new' && game.words.length === 0) {\n await dealInto(game);\n changed = true;\n }\n break;\n }\n default:\n throw new Error(`Unknown action '${input.action}'.`);\n}\n\nif (changed) await save(game);\n\nconst over = game.status === 'won' || game.status === 'lost';\ngezel.output({\n status: game.status,\n giver: game.giver,\n result,\n display,\n modelState: {\n status: game.status,\n yourWords: remaining(game.words, 'target'),\n trap: game.words.find((w) => w.kind === 'trap')?.word ?? '',\n otherWords: remaining(game.words, 'neutral'),\n rule: 'Your clue must be a word that is NOT in yourWords, otherWords or trap.',\n found: game.words.filter((w) => w.kind === 'target' && w.revealed).map((w) => w.word),\n round: game.round,\n ...(game.clue && game.status === 'guessing' ? { currentClue: `${game.clue.word} ${game.clue.count}` } : {}),\n },\n summary: over\n ? `The player ${game.status === 'won' ? 'found all six words' : 'hit the trap'} in ${game.round} round(s). Games: ${game.stats.won} won, ${game.stats.lost} lost.`\n : `Round ${game.round}: ${remaining(game.words, 'target').length} of 6 words still to find.`,\n});\n"
|
|
31
|
+
},
|
|
32
|
+
"tools": [
|
|
33
|
+
{
|
|
34
|
+
"name": "board",
|
|
35
|
+
"description": "Read the game: your words still to find, the trap, the other words, and whether a clue is needed. Deals the first board when none is on the table.",
|
|
36
|
+
"script": "clue-store",
|
|
37
|
+
"inputs": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"properties": {}
|
|
40
|
+
},
|
|
41
|
+
"bind": {
|
|
42
|
+
"action": "board"
|
|
43
|
+
},
|
|
44
|
+
"state": true,
|
|
45
|
+
"answer": {
|
|
46
|
+
"tool": "give_clue",
|
|
47
|
+
"when": {
|
|
48
|
+
"op": "equals",
|
|
49
|
+
"field": "status",
|
|
50
|
+
"value": "clue_needed"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "give_clue",
|
|
56
|
+
"description": "Give the player's next clue: one word that is not on the board, the number of their words it points at, and one short line of table talk.",
|
|
57
|
+
"script": "clue-store",
|
|
58
|
+
"inputs": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"properties": {
|
|
61
|
+
"clue": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"description": "One word, not on the board."
|
|
64
|
+
},
|
|
65
|
+
"count": {
|
|
66
|
+
"type": "number",
|
|
67
|
+
"description": "How many of the player's words it points at."
|
|
68
|
+
},
|
|
69
|
+
"say": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"description": "One short line of table talk (max 160 characters)."
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"required": [
|
|
75
|
+
"clue",
|
|
76
|
+
"count"
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
"bind": {
|
|
80
|
+
"action": "give_clue"
|
|
81
|
+
},
|
|
82
|
+
"turn": {
|
|
83
|
+
"say": "say",
|
|
84
|
+
"show": "display",
|
|
85
|
+
"fallback": "Your clue is on the board."
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"name": "new_game",
|
|
90
|
+
"description": "Deal a fresh board.",
|
|
91
|
+
"script": "clue-store",
|
|
92
|
+
"inputs": {
|
|
93
|
+
"type": "object",
|
|
94
|
+
"properties": {}
|
|
95
|
+
},
|
|
96
|
+
"bind": {
|
|
97
|
+
"action": "new_game"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "guess",
|
|
102
|
+
"description": "The player picks a word on the board.",
|
|
103
|
+
"script": "clue-store",
|
|
104
|
+
"inputs": {
|
|
105
|
+
"type": "object",
|
|
106
|
+
"properties": {
|
|
107
|
+
"word": {
|
|
108
|
+
"type": "string"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"required": [
|
|
112
|
+
"word"
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
"bind": {
|
|
116
|
+
"action": "guess"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"name": "pass",
|
|
121
|
+
"description": "The player stops guessing this turn.",
|
|
122
|
+
"script": "clue-store",
|
|
123
|
+
"inputs": {
|
|
124
|
+
"type": "object",
|
|
125
|
+
"properties": {}
|
|
126
|
+
},
|
|
127
|
+
"bind": {
|
|
128
|
+
"action": "pass"
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"name": "ask_clue_a",
|
|
133
|
+
"description": "The board asks for the next clue.",
|
|
134
|
+
"script": "clue-store",
|
|
135
|
+
"inputs": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"properties": {}
|
|
138
|
+
},
|
|
139
|
+
"bind": {
|
|
140
|
+
"action": "board"
|
|
141
|
+
},
|
|
142
|
+
"reaction": {
|
|
143
|
+
"gezel": "woordsmid",
|
|
144
|
+
"hideSeed": true,
|
|
145
|
+
"standalone": true,
|
|
146
|
+
"prompt": "It is your turn in Word Clues. The game engine returned this state:\n```json\n{{output.modelState}}\n```\nIf `status` is `clue_needed`, call give_clue once: `clue` is one NEW word, not on the board, that links some of `yourWords`, `count` is how many it points at, and `say` is one short line of table talk. Never pick a clue that also fits `trap`, and avoid ones that fit `otherWords`. If the game is over, give no clue: say one warm line about how it went and offer another game.",
|
|
147
|
+
"turn": {
|
|
148
|
+
"tool": "give_clue",
|
|
149
|
+
"when": {
|
|
150
|
+
"op": "equals",
|
|
151
|
+
"field": "status",
|
|
152
|
+
"value": "clue_needed"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "ask_clue_b",
|
|
159
|
+
"description": "The board asks for the next clue.",
|
|
160
|
+
"script": "clue-store",
|
|
161
|
+
"inputs": {
|
|
162
|
+
"type": "object",
|
|
163
|
+
"properties": {}
|
|
164
|
+
},
|
|
165
|
+
"bind": {
|
|
166
|
+
"action": "board"
|
|
167
|
+
},
|
|
168
|
+
"reaction": {
|
|
169
|
+
"gezel": "puzzelaar",
|
|
170
|
+
"hideSeed": true,
|
|
171
|
+
"standalone": true,
|
|
172
|
+
"prompt": "It is your turn in Word Clues. The game engine returned this state:\n```json\n{{output.modelState}}\n```\nIf `status` is `clue_needed`, call give_clue once: `clue` is one NEW word, not on the board, that links some of `yourWords`, `count` is how many it points at, and `say` is one short line of table talk. Never pick a clue that also fits `trap`, and avoid ones that fit `otherWords`. If the game is over, give no clue: say one warm line about how it went and offer another game.",
|
|
173
|
+
"turn": {
|
|
174
|
+
"tool": "give_clue",
|
|
175
|
+
"when": {
|
|
176
|
+
"op": "equals",
|
|
177
|
+
"field": "status",
|
|
178
|
+
"value": "clue_needed"
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
],
|
|
184
|
+
"pages": {
|
|
185
|
+
"entry": "board/index.html",
|
|
186
|
+
"api": 1,
|
|
187
|
+
"reads": [
|
|
188
|
+
{
|
|
189
|
+
"source": "workspace",
|
|
190
|
+
"path": "game.json"
|
|
191
|
+
}
|
|
192
|
+
],
|
|
193
|
+
"tools": [
|
|
194
|
+
"new_game",
|
|
195
|
+
"guess",
|
|
196
|
+
"pass",
|
|
197
|
+
"ask_clue_a",
|
|
198
|
+
"ask_clue_b"
|
|
199
|
+
]
|
|
200
|
+
},
|
|
201
|
+
"workspaceSeed": [
|
|
202
|
+
"game.json",
|
|
203
|
+
"words.json"
|
|
204
|
+
]
|
|
205
|
+
}
|