@wix/agent-skills 1.24.0 → 1.26.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 +1 -0
- package/package.json +2 -1
- package/skills/wix-app/SKILL.md +16 -14
- package/skills/wix-app/references/BUSINESS_MANAGER_THEME.md +107 -0
- package/skills/wix-app/references/BUSINESS_MANAGER_TOKENS.md +81 -0
- package/skills/wix-app/references/DASHBOARD_MODAL.md +41 -0
- package/skills/wix-app/references/DASHBOARD_PAGE.md +13 -11
- package/skills/wix-app/references/DASHBOARD_PLUGIN.md +19 -4
- package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +3 -2
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +66 -68
- package/skills/wix-app/references/dashboard-page/DYNAMIC_PARAMETERS.md +21 -38
- package/skills/wix-app/references/data-collection/LIFECYCLE.md +6 -4
- package/skills/wix-headless/SKILL.md +0 -1
- package/skills/wix-headless/references/CAPABILITIES.md +3 -3
- package/skills/wix-headless/references/DISCOVERY.md +1 -1
- package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
- package/skills/wix-headless/references/SEED.md +1 -1
- package/skills/wix-headless/references/SETUP.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +1 -1
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +2 -2
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +3 -14
- package/skills/wix-headless/scripts/bootstrap.mjs +156 -0
- package/skills/wix-headless-kit/SKILL.md +4 -4
- package/skills/wix-headless-kit/install/AGENTS.md +2 -2
- package/skills/wix-headless-kit/install/bootstrap.mjs +156 -0
- package/skills/wix-headless-kit/install/check.mjs +1 -1
- package/skills/wix-manage/SKILL.md +2 -8
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +250 -18
- package/skills/wix-manage/references/cms/cms-schema-management.md +52 -1
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +0 -184
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +0 -203
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +0 -44
- package/skills/wix-manage/references/cms/cms-data-operations-extended.md +0 -263
- package/skills/wix-manage/references/cms/cms-references-and-relationships.md +0 -162
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
3
|
+
import { existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
|
|
7
|
+
// ── tiny event protocol (one JSON object per line) ───────────────────────────
|
|
8
|
+
const emit = (event, extra = {}) =>
|
|
9
|
+
process.stdout.write(JSON.stringify({ event, ...extra }) + '\n');
|
|
10
|
+
const fail = (event, extra = {}) => {
|
|
11
|
+
emit(event, { ok: false, ...extra });
|
|
12
|
+
process.exit(1);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// ── platform-safe binary names (npm/npx are .cmd on Windows) ─────────────────
|
|
16
|
+
const isWin = process.platform === 'win32';
|
|
17
|
+
const bin = (name) => (isWin ? `${name}.cmd` : name);
|
|
18
|
+
const WIX = [bin('npx'), '-y', '@wix/cli@latest']; // run the CLI via npx — no global install/mutation
|
|
19
|
+
|
|
20
|
+
// Force the CLI into non-interactive "agent" mode. Without an agent signal in
|
|
21
|
+
// the env, `wix login` renders an interactive Ink TUI (device code + keypress)
|
|
22
|
+
// that needs a raw TTY and crashes in an agent sandbox — and it never emits the
|
|
23
|
+
// JSON login events this script forwards. The CLI uses @vercel/detect-agent,
|
|
24
|
+
// whose first check is the AI_AGENT env var, so setting it guarantees agent mode
|
|
25
|
+
// (and the awaiting_user/success/logged_in events) for every child we spawn.
|
|
26
|
+
// Respect an existing value so a known runner (claude, cursor, …) keeps its name.
|
|
27
|
+
const AGENT_ENV = { ...process.env, AI_AGENT: process.env.AI_AGENT || 'wix-headless-skill' };
|
|
28
|
+
|
|
29
|
+
// Where the detached login parks its output between runs. It has to outlive this
|
|
30
|
+
// process, so it can't be a pipe and can't live in the project.
|
|
31
|
+
const STATE_DIR = join(tmpdir(), 'wix-headless-login');
|
|
32
|
+
const LOG = join(STATE_DIR, 'login.log');
|
|
33
|
+
const PIDFILE = join(STATE_DIR, 'login.pid');
|
|
34
|
+
|
|
35
|
+
// run a command, capture stdout+stderr (combined), return {status, out}
|
|
36
|
+
function capture(cmd, args, opts = {}) {
|
|
37
|
+
const r = spawnSync(cmd, args, { encoding: 'utf8', shell: isWin, env: AGENT_ENV, ...opts });
|
|
38
|
+
return { status: r.status ?? 1, out: `${r.stdout || ''}${r.stderr || ''}`, error: r.error };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ── 1. CLI reachable (via npx — no install) ──────────────────────────────────
|
|
42
|
+
function checkCli() {
|
|
43
|
+
const r = capture(WIX[0], [...WIX.slice(1), '--version']);
|
|
44
|
+
if (r.status !== 0) fail('cli_unreachable', { detail: r.out.trim().slice(0, 400) });
|
|
45
|
+
// npx interleaves "npm notice …" lines with the version, so don't just take the
|
|
46
|
+
// last line — pick the first semver-looking token, falling back to the last line.
|
|
47
|
+
const version = (r.out.match(/\d+\.\d+\.\d+[^\s]*/) || [])[0] || r.out.trim().split('\n').pop();
|
|
48
|
+
emit('cli_ok', { version });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ── 2. Reuse an existing session, or start device login ──────────────────────
|
|
52
|
+
const hasExistingSession = () => capture(WIX[0], [...WIX.slice(1), 'whoami']).status === 0;
|
|
53
|
+
|
|
54
|
+
function loginEvents() {
|
|
55
|
+
if (!existsSync(LOG)) return [];
|
|
56
|
+
return readFileSync(LOG, 'utf8')
|
|
57
|
+
.split('\n')
|
|
58
|
+
.map((l) => l.trim())
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.map((l) => {
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(l);
|
|
63
|
+
} catch {
|
|
64
|
+
return null; // non-JSON CLI chatter
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
.filter((e) => e && e.event);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const alive = (pid) => {
|
|
71
|
+
try {
|
|
72
|
+
process.kill(pid, 0);
|
|
73
|
+
return true;
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// A login this machine started earlier may still be waiting on the browser. Reuse
|
|
80
|
+
// its code instead of minting a second one — a new login invalidates nothing, but
|
|
81
|
+
// it hands the user a different code than the one already on their screen.
|
|
82
|
+
function pendingLogin() {
|
|
83
|
+
if (!existsSync(PIDFILE)) return null;
|
|
84
|
+
let state;
|
|
85
|
+
try {
|
|
86
|
+
state = JSON.parse(readFileSync(PIDFILE, 'utf8'));
|
|
87
|
+
} catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
if (!state.pid || !alive(state.pid)) return null;
|
|
91
|
+
const ev = loginEvents().find((e) => e.event === 'awaiting_user');
|
|
92
|
+
if (!ev) return null;
|
|
93
|
+
// Don't hand back a code that's about to expire mid-typing.
|
|
94
|
+
const ageSeconds = Math.round((Date.now() - state.startedAt) / 1000);
|
|
95
|
+
if (ageSeconds > (ev.expiresInSeconds ?? 600) - 60) return null;
|
|
96
|
+
return ev;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Detach so the login keeps polling after this process exits. stdio goes to a
|
|
100
|
+
// file, not a pipe: a pipe dies with the parent, and the CLI would get EPIPE.
|
|
101
|
+
function startLogin() {
|
|
102
|
+
mkdirSync(STATE_DIR, { recursive: true });
|
|
103
|
+
writeFileSync(LOG, '');
|
|
104
|
+
const out = openSync(LOG, 'a');
|
|
105
|
+
const child = spawn(WIX[0], [...WIX.slice(1), 'login'], {
|
|
106
|
+
detached: true,
|
|
107
|
+
stdio: ['ignore', out, out],
|
|
108
|
+
env: AGENT_ENV,
|
|
109
|
+
shell: isWin,
|
|
110
|
+
});
|
|
111
|
+
child.on('error', (e) => fail('login_failed', { detail: String(e) }));
|
|
112
|
+
writeFileSync(PIDFILE, JSON.stringify({ pid: child.pid, startedAt: Date.now() }));
|
|
113
|
+
child.unref();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function waitForCode(timeoutMs = 60000) {
|
|
117
|
+
const deadline = Date.now() + timeoutMs;
|
|
118
|
+
while (Date.now() < deadline) {
|
|
119
|
+
const events = loginEvents();
|
|
120
|
+
const ev = events.find((e) => e.event === 'awaiting_user');
|
|
121
|
+
if (ev) return ev;
|
|
122
|
+
const bad = events.find((e) => e.event === 'login_failed');
|
|
123
|
+
if (bad) fail('login_failed', bad);
|
|
124
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
125
|
+
}
|
|
126
|
+
const detail = existsSync(LOG) ? readFileSync(LOG, 'utf8').trim().slice(-1500) : '';
|
|
127
|
+
fail('login_failed', {
|
|
128
|
+
detail: detail || `wix login produced no device code within ${timeoutMs / 1000}s.`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// The next move is the user's, so hand the code back and exit rather than holding
|
|
133
|
+
// the caller open for a browser round-trip. `message` is the sentence to relay.
|
|
134
|
+
function surrenderTo(ev) {
|
|
135
|
+
emit('awaiting_user', {
|
|
136
|
+
...ev,
|
|
137
|
+
message:
|
|
138
|
+
`To connect your Wix account, open ${ev.verificationUri} and enter the code ` +
|
|
139
|
+
`${ev.userCode}. Tell me once you're done and I'll continue.`,
|
|
140
|
+
});
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── main ────────────────────────────────────────────────────────────────────
|
|
145
|
+
checkCli();
|
|
146
|
+
|
|
147
|
+
if (hasExistingSession()) {
|
|
148
|
+
emit('logged_in');
|
|
149
|
+
process.exit(0);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const pending = pendingLogin();
|
|
153
|
+
if (pending) surrenderTo(pending);
|
|
154
|
+
|
|
155
|
+
startLogin();
|
|
156
|
+
surrenderTo(await waitForCode());
|
|
@@ -86,10 +86,10 @@ doesn't express — or once the site exists and the work turns to managing or ex
|
|
|
86
86
|
|
|
87
87
|
Needed throughout: Node ≥ 20.11, git, a logged-in Wix CLI (`npx @wix/cli@latest whoami`;
|
|
88
88
|
`npx @wix/cli@latest login` is a device-code flow: surface the URL and code to the user, never
|
|
89
|
-
read tokens into context), and the two companion skills beside this one, `wix-docs`
|
|
90
|
-
`wix-manage`
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
read tokens into context), and the two companion skills installed beside this one, `wix-docs`
|
|
90
|
+
and `wix-manage`. `node <SKILL_ROOT>/install/bootstrap.mjs` checks the CLI and runs the login
|
|
91
|
+
when there is none; the cold-start page, `https://www.wix.com/skills/headless-cold-start/headless-kit.md`,
|
|
92
|
+
gets a machine with none of this, the skills included, to that point. In a folder that
|
|
93
93
|
already holds a `wix.config.json`, `node <SKILL_ROOT>/install/context.mjs` first: it runs
|
|
94
94
|
`wix env pull` when `.env.local` is missing and prints the folder's **shape** (`folder.shape`, the
|
|
95
95
|
cases of step 3, with the `next` for each) and the two identities a project has — the deploy site
|
|
@@ -17,8 +17,8 @@ call is memory, and an empty or error reply to it says nothing about the site.
|
|
|
17
17
|
|
|
18
18
|
## Skills
|
|
19
19
|
|
|
20
|
-
Installed at `.agents/skills
|
|
21
|
-
`
|
|
20
|
+
Installed at `.agents/skills/` (by the Wix plugin, or by
|
|
21
|
+
`npx skills add wix/skills --skill {{SKILL}} --skill wix-docs --skill wix-manage`).
|
|
22
22
|
|
|
23
23
|
- `{{SKILL}}` — the code in this app and how to extend it. The shipped code sits in
|
|
24
24
|
`.agents/skills/{{SKILL}}/templates/`, fetched once from the skill's repository and kept with this
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
3
|
+
import { existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
|
|
7
|
+
// ── tiny event protocol (one JSON object per line) ───────────────────────────
|
|
8
|
+
const emit = (event, extra = {}) =>
|
|
9
|
+
process.stdout.write(JSON.stringify({ event, ...extra }) + '\n');
|
|
10
|
+
const fail = (event, extra = {}) => {
|
|
11
|
+
emit(event, { ok: false, ...extra });
|
|
12
|
+
process.exit(1);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// ── platform-safe binary names (npm/npx are .cmd on Windows) ─────────────────
|
|
16
|
+
const isWin = process.platform === 'win32';
|
|
17
|
+
const bin = (name) => (isWin ? `${name}.cmd` : name);
|
|
18
|
+
const WIX = [bin('npx'), '-y', '@wix/cli@latest']; // run the CLI via npx — no global install/mutation
|
|
19
|
+
|
|
20
|
+
// Force the CLI into non-interactive "agent" mode. Without an agent signal in
|
|
21
|
+
// the env, `wix login` renders an interactive Ink TUI (device code + keypress)
|
|
22
|
+
// that needs a raw TTY and crashes in an agent sandbox — and it never emits the
|
|
23
|
+
// JSON login events this script forwards. The CLI uses @vercel/detect-agent,
|
|
24
|
+
// whose first check is the AI_AGENT env var, so setting it guarantees agent mode
|
|
25
|
+
// (and the awaiting_user/success/logged_in events) for every child we spawn.
|
|
26
|
+
// Respect an existing value so a known runner (claude, cursor, …) keeps its name.
|
|
27
|
+
const AGENT_ENV = { ...process.env, AI_AGENT: process.env.AI_AGENT || 'wix-headless-kit-skill' };
|
|
28
|
+
|
|
29
|
+
// Where the detached login parks its output between runs. It has to outlive this
|
|
30
|
+
// process, so it can't be a pipe and can't live in the project.
|
|
31
|
+
const STATE_DIR = join(tmpdir(), 'wix-headless-kit-login');
|
|
32
|
+
const LOG = join(STATE_DIR, 'login.log');
|
|
33
|
+
const PIDFILE = join(STATE_DIR, 'login.pid');
|
|
34
|
+
|
|
35
|
+
// run a command, capture stdout+stderr (combined), return {status, out}
|
|
36
|
+
function capture(cmd, args, opts = {}) {
|
|
37
|
+
const r = spawnSync(cmd, args, { encoding: 'utf8', shell: isWin, env: AGENT_ENV, ...opts });
|
|
38
|
+
return { status: r.status ?? 1, out: `${r.stdout || ''}${r.stderr || ''}`, error: r.error };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ── 1. CLI reachable (via npx — no install) ──────────────────────────────────
|
|
42
|
+
function checkCli() {
|
|
43
|
+
const r = capture(WIX[0], [...WIX.slice(1), '--version']);
|
|
44
|
+
if (r.status !== 0) fail('cli_unreachable', { detail: r.out.trim().slice(0, 400) });
|
|
45
|
+
// npx interleaves "npm notice …" lines with the version, so don't just take the
|
|
46
|
+
// last line — pick the first semver-looking token, falling back to the last line.
|
|
47
|
+
const version = (r.out.match(/\d+\.\d+\.\d+[^\s]*/) || [])[0] || r.out.trim().split('\n').pop();
|
|
48
|
+
emit('cli_ok', { version });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ── 2. Reuse an existing session, or start device login ──────────────────────
|
|
52
|
+
const hasExistingSession = () => capture(WIX[0], [...WIX.slice(1), 'whoami']).status === 0;
|
|
53
|
+
|
|
54
|
+
function loginEvents() {
|
|
55
|
+
if (!existsSync(LOG)) return [];
|
|
56
|
+
return readFileSync(LOG, 'utf8')
|
|
57
|
+
.split('\n')
|
|
58
|
+
.map((l) => l.trim())
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.map((l) => {
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(l);
|
|
63
|
+
} catch {
|
|
64
|
+
return null; // non-JSON CLI chatter
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
.filter((e) => e && e.event);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const alive = (pid) => {
|
|
71
|
+
try {
|
|
72
|
+
process.kill(pid, 0);
|
|
73
|
+
return true;
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// A login this machine started earlier may still be waiting on the browser. Reuse
|
|
80
|
+
// its code instead of minting a second one — a new login invalidates nothing, but
|
|
81
|
+
// it hands the user a different code than the one already on their screen.
|
|
82
|
+
function pendingLogin() {
|
|
83
|
+
if (!existsSync(PIDFILE)) return null;
|
|
84
|
+
let state;
|
|
85
|
+
try {
|
|
86
|
+
state = JSON.parse(readFileSync(PIDFILE, 'utf8'));
|
|
87
|
+
} catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
if (!state.pid || !alive(state.pid)) return null;
|
|
91
|
+
const ev = loginEvents().find((e) => e.event === 'awaiting_user');
|
|
92
|
+
if (!ev) return null;
|
|
93
|
+
// Don't hand back a code that's about to expire mid-typing.
|
|
94
|
+
const ageSeconds = Math.round((Date.now() - state.startedAt) / 1000);
|
|
95
|
+
if (ageSeconds > (ev.expiresInSeconds ?? 600) - 60) return null;
|
|
96
|
+
return ev;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Detach so the login keeps polling after this process exits. stdio goes to a
|
|
100
|
+
// file, not a pipe: a pipe dies with the parent, and the CLI would get EPIPE.
|
|
101
|
+
function startLogin() {
|
|
102
|
+
mkdirSync(STATE_DIR, { recursive: true });
|
|
103
|
+
writeFileSync(LOG, '');
|
|
104
|
+
const out = openSync(LOG, 'a');
|
|
105
|
+
const child = spawn(WIX[0], [...WIX.slice(1), 'login'], {
|
|
106
|
+
detached: true,
|
|
107
|
+
stdio: ['ignore', out, out],
|
|
108
|
+
env: AGENT_ENV,
|
|
109
|
+
shell: isWin,
|
|
110
|
+
});
|
|
111
|
+
child.on('error', (e) => fail('login_failed', { detail: String(e) }));
|
|
112
|
+
writeFileSync(PIDFILE, JSON.stringify({ pid: child.pid, startedAt: Date.now() }));
|
|
113
|
+
child.unref();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function waitForCode(timeoutMs = 60000) {
|
|
117
|
+
const deadline = Date.now() + timeoutMs;
|
|
118
|
+
while (Date.now() < deadline) {
|
|
119
|
+
const events = loginEvents();
|
|
120
|
+
const ev = events.find((e) => e.event === 'awaiting_user');
|
|
121
|
+
if (ev) return ev;
|
|
122
|
+
const bad = events.find((e) => e.event === 'login_failed');
|
|
123
|
+
if (bad) fail('login_failed', bad);
|
|
124
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
125
|
+
}
|
|
126
|
+
const detail = existsSync(LOG) ? readFileSync(LOG, 'utf8').trim().slice(-1500) : '';
|
|
127
|
+
fail('login_failed', {
|
|
128
|
+
detail: detail || `wix login produced no device code within ${timeoutMs / 1000}s.`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// The next move is the user's, so hand the code back and exit rather than holding
|
|
133
|
+
// the caller open for a browser round-trip. `message` is the sentence to relay.
|
|
134
|
+
function surrenderTo(ev) {
|
|
135
|
+
emit('awaiting_user', {
|
|
136
|
+
...ev,
|
|
137
|
+
message:
|
|
138
|
+
`To connect your Wix account, open ${ev.verificationUri} and enter the code ` +
|
|
139
|
+
`${ev.userCode}. Tell me once you're done and I'll continue.`,
|
|
140
|
+
});
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── main ────────────────────────────────────────────────────────────────────
|
|
145
|
+
checkCli();
|
|
146
|
+
|
|
147
|
+
if (hasExistingSession()) {
|
|
148
|
+
emit('logged_in');
|
|
149
|
+
process.exit(0);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const pending = pendingLogin();
|
|
153
|
+
if (pending) surrenderTo(pending);
|
|
154
|
+
|
|
155
|
+
startLogin();
|
|
156
|
+
surrenderTo(await waitForCode());
|
|
@@ -80,7 +80,7 @@ rmSync(tmp, { recursive: true, force: true });
|
|
|
80
80
|
// ---- what would act on each ------------------------------------------------------------------
|
|
81
81
|
const rel = relative(process.cwd(), SKILL_ROOT) || ".";
|
|
82
82
|
out.update = {
|
|
83
|
-
skill: `
|
|
83
|
+
skill: `update ${skillName} the way it was installed (the plugin's update, or the skills CLI's)`,
|
|
84
84
|
templates: `node ${rel}/install/templates.mjs --refresh (then commit the changed files under ${rel}/templates)`,
|
|
85
85
|
note: "neither touches src/; a shipped fix reaches the project by comparing its copy with the template",
|
|
86
86
|
};
|
|
@@ -135,19 +135,13 @@ Uses Calendar Events API to create WORKING_HOURS events on the business schedule
|
|
|
135
135
|
## CMS
|
|
136
136
|
|
|
137
137
|
### [CMS Data Items CRUD](references/cms/cms-data-items-crud.md)
|
|
138
|
-
"Add, query, update, and delete items in CMS collections
|
|
139
|
-
|
|
140
|
-
### [CMS Data Operations Extended](references/cms/cms-data-operations-extended.md)
|
|
141
|
-
Additional CMS data operations including count, upsert (bulk save), and update by filter patterns.
|
|
138
|
+
"Add, query, update, and delete items in CMS collections, one at a time or in bulk. Also covers counting items, upserting with bulk save, truncating a collection, aggregating data with a pipeline, linking items through single- and multi-reference fields, and reading items with their referenced items expanded."
|
|
142
139
|
|
|
143
140
|
### [CMS eCommerce Catalog Integration](references/cms/cms-ecommerce-catalog-integration.md)
|
|
144
141
|
The recommended way to sell existing CMS collection items (tickets, bookings, memberships) through Wix checkout. Add the CATALOG plugin to convert any CMS collection into purchasable products with cart and payment integration.
|
|
145
142
|
|
|
146
|
-
### [CMS References And Relationships](references/cms/cms-references-and-relationships.md)
|
|
147
|
-
"Add, replace, or remove items from MULTI_REFERENCE fields. Use insert-references, replace-references, remove-references endpoints. Required for managing multi-reference relationships - these CANNOT be set via regular insert/update/patch operations. Also covers single references and querying with expanded references."
|
|
148
|
-
|
|
149
143
|
### [CMS Schema Management](references/cms/cms-schema-management.md)
|
|
150
|
-
Create and modify CMS collection structures. Covers listing collections, creating collections with fields, adding/removing fields, and updating collection settings.
|
|
144
|
+
Create and modify CMS collection structures. Covers listing collections, creating collections with fields, adding/removing fields (including single- and multi-reference fields that link two collections), and updating collection settings.
|
|
151
145
|
|
|
152
146
|
### [CMS Draft & Publish Workflow (Draft Items plugin)](references/cms/cms-publishing-flow.md)
|
|
153
147
|
"Interact with CMS collections that gate their items behind a draft/publish workflow via the Draft Items plugin. Covers detecting the plugin, locating the paired drafts collection, reading published vs draft items, authoring/editing drafts, and publishing, unpublishing, reverting, and deleting items. Key endpoints: /wix-data/v2/items/publish-draft, /wix-data/v2/items/unpublish, /wix-data/v2/collections/add-draft-items-plugin, and the paired drafts collection referenced by draftItemsPluginOptions.draftsCollectionId."
|