@glie/mcp-polaris 0.7.0 → 0.9.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 +39 -5
- package/dist/index.js +313 -48
- package/package.json +4 -15
package/README.md
CHANGED
|
@@ -47,15 +47,49 @@ it. The same token authenticates this server and the `polaris` CLI as you.
|
|
|
47
47
|
|
|
48
48
|
## Tools
|
|
49
49
|
|
|
50
|
-
`polaris.me`, `polaris.project.*`, `polaris.milestone.*` (incl.
|
|
51
|
-
refine a spec
|
|
52
|
-
`polaris.
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
**Roadmap.** `polaris.me`, `polaris.project.*`, `polaris.milestone.*` (incl.
|
|
51
|
+
`update` to refine a spec, `attachment_*` to list/attach/remove the visual
|
|
52
|
+
references anchored in its body), `polaris.task.*` (incl. `update`,
|
|
53
|
+
`transition`, `approve`, `schedule`, `attachment_*` — same as the milestone's,
|
|
54
|
+
plus how a milestone reference gets forwarded here via
|
|
55
|
+
`source_attachment_id`), `polaris.stack.*` (`list` / `get` / `release` for the
|
|
56
|
+
approval Release Candidate flow), `polaris.agent.*`, `polaris.team.*`,
|
|
57
|
+
`polaris.claude_md.get`, `polaris.framework.list`.
|
|
58
|
+
|
|
59
|
+
**Helpdesk.** `polaris.ticket.*` (the customer conversation: `reply`, `pass`,
|
|
60
|
+
`frame_issue`, `link_issue`) and `polaris.issue.*` (the problem: `open`,
|
|
61
|
+
`transition`, `add_task`). N tickets can dedup onto one issue, and one issue
|
|
62
|
+
fans out into N tasks.
|
|
63
|
+
|
|
64
|
+
**Context, read-only.** `polaris.activity.list` (what happened) and
|
|
55
65
|
`polaris.chat.get` / `polaris.chat.messages` (comments agents left on a scope).
|
|
56
66
|
|
|
57
67
|
Run `tools/list` against the server for the full, current set.
|
|
58
68
|
|
|
69
|
+
## Marketing creatives
|
|
70
|
+
|
|
71
|
+
A task inside an mkt campaign is a creative, and `polaris.task.create` takes the
|
|
72
|
+
four axes that describe one:
|
|
73
|
+
|
|
74
|
+
| Field | What it says | Values |
|
|
75
|
+
| --------- | --------------------------- | ----------------------------------------------- |
|
|
76
|
+
| `medium` | what the piece is | `image` / `video` / `text` |
|
|
77
|
+
| `surface` | where it publishes | `feed` / `stories` / `reels` / `shorts` / `article` / `newsletter` |
|
|
78
|
+
| `slides` | how many images it carries | 2 to 10, images only. A carousel is an image with plural |
|
|
79
|
+
| `aspect` | how it is framed | `1:1` / `4:5` / `9:16` / `16:9` / `2:3` |
|
|
80
|
+
|
|
81
|
+
Plus `channel` (Instagram, TikTok, LinkedIn, ...) and `scheduled_date`, the day
|
|
82
|
+
it publishes.
|
|
83
|
+
|
|
84
|
+
The pairs are checked at creation, not patched over at generation time: a
|
|
85
|
+
carousel with no `slides` is refused (it would ship a single image under a name
|
|
86
|
+
that promises several), `slides` on a non-image piece is refused, and an
|
|
87
|
+
`aspect` that the surface does not accept is refused. Omit `aspect` to take the
|
|
88
|
+
channel's usual one.
|
|
89
|
+
|
|
90
|
+
`format` is still written and read, as the label the board and the agents use,
|
|
91
|
+
but it is derived from the axes rather than defining them.
|
|
92
|
+
|
|
59
93
|
## License
|
|
60
94
|
|
|
61
95
|
Apache-2.0
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
|
|
4
4
|
// ../../src/mcp/index.ts
|
|
5
5
|
import { createInterface } from "readline";
|
|
6
|
+
|
|
7
|
+
// ../../src/lib/media-types.ts
|
|
8
|
+
var MEDIA_TYPES = [
|
|
9
|
+
{ mime: "image/png", kind: "image", ext: ".png", aliases: [] },
|
|
10
|
+
{ mime: "image/jpeg", kind: "image", ext: ".jpg", aliases: [".jpeg"] },
|
|
11
|
+
{ mime: "image/webp", kind: "image", ext: ".webp", aliases: [] },
|
|
12
|
+
{ mime: "video/mp4", kind: "video", ext: ".mp4", aliases: [] },
|
|
13
|
+
{ mime: "video/quicktime", kind: "video", ext: ".mov", aliases: [] },
|
|
14
|
+
{ mime: "video/webm", kind: "video", ext: ".webm", aliases: [] }
|
|
15
|
+
];
|
|
16
|
+
function allMimes() {
|
|
17
|
+
return MEDIA_TYPES.map((t) => t.mime);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ../../src/mcp/index.ts
|
|
6
21
|
var BASE = process.env.POLARIS_URL ?? "http://127.0.0.1:7843";
|
|
7
22
|
var TOKEN = process.env.POLARIS_TOKEN ?? "";
|
|
8
23
|
var PROJECT = process.env.POLARIS_PROJECT ?? "";
|
|
@@ -53,9 +68,11 @@ var INSTRUCTIONS = [
|
|
|
53
68
|
"\u2022 polaris.claude_md.get(project_key) \u2014 read the project's conventions BEFORE you touch its tasks.",
|
|
54
69
|
"",
|
|
55
70
|
"STATE MACHINES \u2014 transitions are enforced; only legal moves succeed:",
|
|
56
|
-
"\u2022 Task: draft \u2192 backlog \u2192 dev \u2192 test \u2192 approval \u2192 release \u2192 done (any \u2192 canceled
|
|
71
|
+
"\u2022 Task: draft \u2192 backlog \u2192 dev \u2192 test \u2192 approval \u2192 release \u2192 done (any \u2192 canceled;",
|
|
72
|
+
" canceled \u2192 draft and done \u2192 approval undo the last step)",
|
|
57
73
|
" dev = an agent implements it & opens a PR \xB7 test = QA \xB7 approval = a human reviews \xB7 release = merged to dev/shipped.",
|
|
58
|
-
"\u2022 Milestone: draft \u2192 discovery \u2192 loop \u2192 release \u2192 done (any \u2192 canceled
|
|
74
|
+
"\u2022 Milestone: draft \u2192 discovery \u2192 loop \u2192 release \u2192 done (any \u2192 canceled;",
|
|
75
|
+
" canceled \u2192 discovery brings back a milestone closed by mistake)",
|
|
59
76
|
" discovery = answer the framework Q&A to split it into tasks \xB7 loop = build/test/approve \xB7 release = ship.",
|
|
60
77
|
"\u2022 Stack (Release Candidate): 2+ approval tasks of ONE milestone on an rc branch, tested & shipped together \u2014",
|
|
61
78
|
" liquid (assembling) \u2192 blocked (a member conflicts) | frozen (human-resolved) \u2192 released (any \u2192 canceled).",
|
|
@@ -80,8 +97,8 @@ var INSTRUCTIONS = [
|
|
|
80
97
|
'\u2022 "Break a milestone into tasks" \u2192 polaris.milestone.qa_list / qa_answer (while in discovery)',
|
|
81
98
|
`\u2022 "Triage support / what's waiting?" \u2192 polaris.ticket.list (status, project_key) \u2014 P1 first`,
|
|
82
99
|
'\u2022 "Reply to a customer / hand off" \u2192 polaris.ticket.reply then polaris.ticket.pass(to)',
|
|
83
|
-
'\u2022 "Turn a report into work" \u2192 polaris.ticket.frame_issue \u2192 polaris.issue.add_task \xD7N',
|
|
84
|
-
'\u2022 "Same bug reported again" \u2192 polaris.ticket.link_issue (dedup onto the open issue)',
|
|
100
|
+
'\u2022 "Turn a report into work" \u2192 polaris.ticket.frame_issue \u2192 polaris.issue.add_task \xD7N (framing is HUMAN-only; the helpdesker proposes it)',
|
|
101
|
+
'\u2022 "Same bug reported again" \u2192 polaris.ticket.link_issue (dedup onto the open issue; HUMAN-only) \u2192 say we already have it \u2192 close the duplicate ticket',
|
|
85
102
|
"",
|
|
86
103
|
"Identifiers: projects by `key` (string, e.g. saasA); milestones/tasks/agents/stacks by numeric `id`. Writes need a token; reads work anonymously."
|
|
87
104
|
].join(`
|
|
@@ -121,13 +138,32 @@ var TOOLS = [
|
|
|
121
138
|
},
|
|
122
139
|
{
|
|
123
140
|
name: "polaris.project.create",
|
|
124
|
-
description: "Create a project (human-only).",
|
|
125
|
-
inputSchema: objSchema({
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
141
|
+
description: "Create a project (human-only). With GitHub connected a repository is required \u2014 pick one from polaris.github.repositories. One repository holds one project.",
|
|
142
|
+
inputSchema: objSchema({
|
|
143
|
+
key: strSchema(),
|
|
144
|
+
name: strSchema(),
|
|
145
|
+
repo_url: strSchema("https://github.com/owner/repo \u2014 required when GitHub is connected")
|
|
146
|
+
}, ["key", "name"]),
|
|
129
147
|
call: async (args) => (await apiCall("POST", "/api/projects", args)).body
|
|
130
148
|
},
|
|
149
|
+
{
|
|
150
|
+
name: "polaris.github.repositories",
|
|
151
|
+
description: "Repositories a project may live in (human-only): whether GitHub is connected, and every repository the GitHub App reaches \u2014 available, or why not (already another project's, or archived).",
|
|
152
|
+
inputSchema: objSchema({}),
|
|
153
|
+
call: async () => (await apiCall("GET", "/api/github/repositories")).body
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: "polaris.project.arm",
|
|
157
|
+
description: "Arm a project for auto-approval (human-only): while armed, dev work that reaches `approval` CLEAN is approved on your behalf \u2014 no per-task click \u2014 and follows the normal path to release. Escalated tasks, mkt creatives, and support work still wait for a person; a merge that fails leaves the task in `approval`. Idempotent.",
|
|
158
|
+
inputSchema: objSchema({ key: strSchema("project key (e.g. saasA)") }, ["key"]),
|
|
159
|
+
call: async (args) => (await apiCall("POST", `/api/projects/${args.key}/arm`)).body
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: "polaris.project.disarm",
|
|
163
|
+
description: "Disarm a project (human-only). Immediate effect: the next task to reach `approval` waits for a person again. Work already parked in `approval` is untouched. Idempotent.",
|
|
164
|
+
inputSchema: objSchema({ key: strSchema("project key (e.g. saasA)") }, ["key"]),
|
|
165
|
+
call: async (args) => (await apiCall("POST", `/api/projects/${args.key}/disarm`)).body
|
|
166
|
+
},
|
|
131
167
|
{
|
|
132
168
|
name: "polaris.milestone.list",
|
|
133
169
|
description: "List milestones in a project.",
|
|
@@ -142,11 +178,16 @@ var TOOLS = [
|
|
|
142
178
|
},
|
|
143
179
|
{
|
|
144
180
|
name: "polaris.milestone.update",
|
|
145
|
-
description: "Correct or refine a milestone's spec \u2014 PATCH its description_md (and optionally name), same idea as polaris.task.update.
|
|
181
|
+
description: "Correct or refine a milestone's spec \u2014 PATCH its description_md (and optionally name), same idea as polaris.task.update. On a mkt campaign the market can also be corrected, while it is still in draft or discovery: after that the creatives are already bound to accounts. The campaign's rhythm, budget and channels live in the description \u2014 write them there and the briefer reads them. Needs a token.",
|
|
146
182
|
inputSchema: objSchema({
|
|
147
183
|
id: intSchema(),
|
|
148
184
|
name: strSchema(),
|
|
149
|
-
description_md: strSchema("full markdown brief; replaces the current description")
|
|
185
|
+
description_md: strSchema("full markdown brief; replaces the current description"),
|
|
186
|
+
market: {
|
|
187
|
+
type: "array",
|
|
188
|
+
items: { type: "string", enum: ["BR", "US", "EU"] },
|
|
189
|
+
description: "mkt: target markets; replaces the current list"
|
|
190
|
+
}
|
|
150
191
|
}, ["id"]),
|
|
151
192
|
call: async (args) => {
|
|
152
193
|
const body = {};
|
|
@@ -154,6 +195,8 @@ var TOOLS = [
|
|
|
154
195
|
body.name = args.name;
|
|
155
196
|
if (typeof args.description_md === "string")
|
|
156
197
|
body.description_md = args.description_md;
|
|
198
|
+
if ("market" in args)
|
|
199
|
+
body.market = args.market;
|
|
157
200
|
return (await apiCall("PATCH", `/api/milestones/${args.id}`, body)).body;
|
|
158
201
|
}
|
|
159
202
|
},
|
|
@@ -181,6 +224,60 @@ var TOOLS = [
|
|
|
181
224
|
answer_md: args.answer_md
|
|
182
225
|
})).body
|
|
183
226
|
},
|
|
227
|
+
{
|
|
228
|
+
name: "polaris.milestone.attachment_list",
|
|
229
|
+
description: "List this milestone's IMAGE attachments \u2014 anchored in its description_md by a `ref:N` marker, or attached but not yet placed in the text. A link is not here: it's plain `[text](url)` markdown written straight into description_md, no row, no marker \u2014 read it off the text like any other prose. Each image carries a `marker` ready to paste into description_md, an `attachment_id` (the underlying file \u2014 pass it to attachment_create elsewhere to attach the SAME image with no re-upload), and an `alt` (a plain description of what it shows, often blank) \u2014 intent (what to do with it) always lives in the description_md text around the marker, never in `alt`.",
|
|
230
|
+
inputSchema: objSchema({ id: intSchema("milestone id") }, ["id"]),
|
|
231
|
+
call: async (args) => (await apiCall("GET", `/api/milestones/${args.id}/attachments`)).body
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: "polaris.milestone.attachment_presign",
|
|
235
|
+
description: "Step 1 of attaching an image to a milestone: reserve an upload key. Returns file_key + upload_url \u2014 PUT the raw image bytes to upload_url YOURSELF (curl/fetch from your shell; this call does not carry bytes), then call polaris.milestone.attachment_create with the same file_key. A link isn't an attachment at all \u2014 just write `[text](url)` straight into the milestone's description_md.",
|
|
236
|
+
inputSchema: objSchema({
|
|
237
|
+
id: intSchema("milestone id"),
|
|
238
|
+
mime: strSchema(allMimes().join(" | ")),
|
|
239
|
+
size_bytes: intSchema()
|
|
240
|
+
}, ["id", "mime", "size_bytes"]),
|
|
241
|
+
call: async (args) => (await apiCall("POST", `/api/milestones/${args.id}/attachments/presign`, {
|
|
242
|
+
mime: args.mime,
|
|
243
|
+
size_bytes: args.size_bytes
|
|
244
|
+
})).body
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: "polaris.milestone.attachment_create",
|
|
248
|
+
description: "Attach an IMAGE to a milestone. Two shapes: a fresh upload (file_key from attachment_presign + mime + size_bytes + filename, alt optional); or attaching an EXISTING file already uploaded elsewhere (attachment_id \u2014 from another attachment's `attachment_id` field \u2014 alt optional) which is how a milestone reference gets forwarded onto a task without re-uploading its bytes. The same file can be attached to any number of milestones/tasks this way (N:N) \u2014 each attachment gets its own `alt` here, independent of what it says anywhere else it's attached. A link is NOT this call \u2014 write `[text](url)` straight into the milestone's description_md, no attachment row at all. `alt` only describes what the image shows \u2014 it is never an instruction; what to DO with it lives in the body prose around the marker this call returns, which you paste into description_md yourself (an attachment nobody placed in the text is as good as absent). Read that prose to decide: the default, when it just describes what the reference IS, is to pass it along as-is; only when it explicitly asks for something derived (a description, a summary) should you use it as input instead and write that into the task's own text.",
|
|
249
|
+
inputSchema: objSchema({
|
|
250
|
+
id: intSchema("milestone id"),
|
|
251
|
+
alt: strSchema("what the image shows, plainly \u2014 never an instruction"),
|
|
252
|
+
filename: strSchema("required for a fresh upload \u2014 the file's own name"),
|
|
253
|
+
file_key: strSchema("from attachment_presign"),
|
|
254
|
+
mime: strSchema(),
|
|
255
|
+
size_bytes: intSchema(),
|
|
256
|
+
attachment_id: intSchema("attach an EXISTING file (its attachment_id) instead of file_key/mime/size_bytes/filename \u2014 no re-upload")
|
|
257
|
+
}, ["id"]),
|
|
258
|
+
call: async (args) => {
|
|
259
|
+
const { id, ...body } = args;
|
|
260
|
+
return (await apiCall("POST", `/api/milestones/${id}/attachments`, body)).body;
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: "polaris.milestone.attachment_update",
|
|
265
|
+
description: "Edit the alt text on a milestone attachment \u2014 the only field worth changing after upload; the image itself and its filename stay what was actually uploaded. Only THIS attachment (this milestone) changes \u2014 the same file attached elsewhere keeps its own alt.",
|
|
266
|
+
inputSchema: objSchema({ id: intSchema("milestone id"), seq: intSchema(), alt: strSchema() }, [
|
|
267
|
+
"id",
|
|
268
|
+
"seq",
|
|
269
|
+
"alt"
|
|
270
|
+
]),
|
|
271
|
+
call: async (args) => (await apiCall("PATCH", `/api/milestones/${args.id}/attachments/${args.seq}`, {
|
|
272
|
+
alt: args.alt
|
|
273
|
+
})).body
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
name: "polaris.milestone.attachment_delete",
|
|
277
|
+
description: "Remove an attachment from a milestone by its seq. Only removes it from THIS milestone \u2014 the underlying file, and any other milestone/task it's attached to, are untouched.",
|
|
278
|
+
inputSchema: objSchema({ id: intSchema("milestone id"), seq: intSchema() }, ["id", "seq"]),
|
|
279
|
+
call: async (args) => (await apiCall("DELETE", `/api/milestones/${args.id}/attachments/${args.seq}`)).body
|
|
280
|
+
},
|
|
184
281
|
{
|
|
185
282
|
name: "polaris.task.list",
|
|
186
283
|
description: `Find tasks \u2014 the agent's entry point. Pass assignee_agent_id="self" (or assignee_human_id="self" for a human) to get what is YOURS; add status=dev (etc.) to see only active work. Other filters: milestone_id, product_key, team.`,
|
|
@@ -225,7 +322,7 @@ var TOOLS = [
|
|
|
225
322
|
milestone_id: intSchema(),
|
|
226
323
|
name: strSchema(),
|
|
227
324
|
description_md: strSchema(),
|
|
228
|
-
status: strSchema("draft
|
|
325
|
+
status: strSchema("draft \u2014 the only status a task can be created in; it reaches the rest by being moved, one legal step at a time (polaris.task.transition)"),
|
|
229
326
|
channel: strSchema("mkt: Instagram, TikTok, LinkedIn, \u2026"),
|
|
230
327
|
format: strSchema("mkt: post, carrossel, reel, story, artigo, \u2026"),
|
|
231
328
|
slides: intSchema("mkt: REQUIRED when format is a carousel \u2014 how many images the piece has (2..10). " + "It is a contract: the generator delivers exactly this many. Omit for every other format."),
|
|
@@ -239,6 +336,60 @@ var TOOLS = [
|
|
|
239
336
|
}, ["milestone_id", "name"]),
|
|
240
337
|
call: async (args) => (await apiCall("POST", "/api/tasks", args)).body
|
|
241
338
|
},
|
|
339
|
+
{
|
|
340
|
+
name: "polaris.task.attachment_list",
|
|
341
|
+
description: "List this task's IMAGE attachments, including ones a milestone reference forwarded here (attached by attachment_id, no re-upload) plus anything attached directly to this task. A link is not here: it's plain `[text](url)` markdown written straight into the task's description_md, no row, no marker. Each image carries a `marker` ready to paste into description_md, an `attachment_id` (the underlying file \u2014 pass it to attachment_create elsewhere to attach the SAME image with no re-upload), and an `alt` (a plain description of what it shows, often blank) \u2014 intent (what to do with it) always lives in the description_md text around the marker, never in `alt`.",
|
|
342
|
+
inputSchema: objSchema({ id: intSchema("task id") }, ["id"]),
|
|
343
|
+
call: async (args) => (await apiCall("GET", `/api/tasks/${args.id}/attachments`)).body
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
name: "polaris.task.attachment_presign",
|
|
347
|
+
description: "Step 1 of attaching an image to a task: reserve an upload key. Returns file_key + upload_url \u2014 PUT the raw image bytes to upload_url YOURSELF (curl/fetch from your shell; this call does not carry bytes), then call polaris.task.attachment_create with the same file_key. A link isn't an attachment at all \u2014 just write `[text](url)` straight into the task's description_md.",
|
|
348
|
+
inputSchema: objSchema({
|
|
349
|
+
id: intSchema("task id"),
|
|
350
|
+
mime: strSchema(allMimes().join(" | ")),
|
|
351
|
+
size_bytes: intSchema()
|
|
352
|
+
}, ["id", "mime", "size_bytes"]),
|
|
353
|
+
call: async (args) => (await apiCall("POST", `/api/tasks/${args.id}/attachments/presign`, {
|
|
354
|
+
mime: args.mime,
|
|
355
|
+
size_bytes: args.size_bytes
|
|
356
|
+
})).body
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
name: "polaris.task.attachment_create",
|
|
360
|
+
description: "Attach an IMAGE to a task. Two shapes: a fresh upload (file_key from attachment_presign + mime + size_bytes + filename, alt optional); or attaching an EXISTING file already uploaded elsewhere (attachment_id \u2014 from another attachment's `attachment_id` field \u2014 alt optional, no re-upload). This is how the BRIEF forwards a milestone's image onto a task it's planning. The same file can be attached to any number of milestones/tasks (N:N) \u2014 each attachment gets its own `alt` here, independent of what it says anywhere else it's attached. A link is NOT this call: write `[text](url)` straight into the task's description_md \u2014 for a milestone link, just copy the markdown across, there's nothing to attach. `alt` only describes what the image shows \u2014 never an instruction. Read the milestone's OWN body prose around its marker for intent (alt never carries it), and once attached here, paste the `marker` this call returns into the task's description_md yourself, with that instruction right after it \u2014 an attachment nobody placed in the text is as good as absent. Default: forward as-is; only when that prose explicitly asks for something derived (a description, a summary) should you use it as input instead and write that into this task's own description_md.",
|
|
361
|
+
inputSchema: objSchema({
|
|
362
|
+
id: intSchema("task id"),
|
|
363
|
+
alt: strSchema("what the image shows, plainly \u2014 never an instruction"),
|
|
364
|
+
filename: strSchema("required for a fresh upload \u2014 the file's own name"),
|
|
365
|
+
file_key: strSchema("from attachment_presign"),
|
|
366
|
+
mime: strSchema(),
|
|
367
|
+
size_bytes: intSchema(),
|
|
368
|
+
attachment_id: intSchema("attach an EXISTING file (its attachment_id) instead of file_key/mime/size_bytes/filename \u2014 no re-upload")
|
|
369
|
+
}, ["id"]),
|
|
370
|
+
call: async (args) => {
|
|
371
|
+
const { id, ...body } = args;
|
|
372
|
+
return (await apiCall("POST", `/api/tasks/${id}/attachments`, body)).body;
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
name: "polaris.task.attachment_update",
|
|
377
|
+
description: "Edit the alt text on a task attachment \u2014 the only field worth changing after upload; the image itself and its filename stay what was actually uploaded. Only THIS attachment (this task) changes \u2014 the same file attached elsewhere keeps its own alt.",
|
|
378
|
+
inputSchema: objSchema({ id: intSchema("task id"), seq: intSchema(), alt: strSchema() }, [
|
|
379
|
+
"id",
|
|
380
|
+
"seq",
|
|
381
|
+
"alt"
|
|
382
|
+
]),
|
|
383
|
+
call: async (args) => (await apiCall("PATCH", `/api/tasks/${args.id}/attachments/${args.seq}`, {
|
|
384
|
+
alt: args.alt
|
|
385
|
+
})).body
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
name: "polaris.task.attachment_delete",
|
|
389
|
+
description: "Remove an attachment from a task by its seq. Only removes it from THIS task \u2014 the underlying file, and any other milestone/task it's attached to, are untouched.",
|
|
390
|
+
inputSchema: objSchema({ id: intSchema("task id"), seq: intSchema() }, ["id", "seq"]),
|
|
391
|
+
call: async (args) => (await apiCall("DELETE", `/api/tasks/${args.id}/attachments/${args.seq}`)).body
|
|
392
|
+
},
|
|
242
393
|
{
|
|
243
394
|
name: "polaris.task.update",
|
|
244
395
|
description: "Correct or refine a task's spec \u2014 PATCH its description_md (and optionally name). For a marketing creative, set asset_url to the produced asset (image/video) so the reviewer can download and review it. It is NOT a log of what was done (leave that as a comment). Needs a token.",
|
|
@@ -264,19 +415,26 @@ var TOOLS = [
|
|
|
264
415
|
},
|
|
265
416
|
{
|
|
266
417
|
name: "polaris.task.transition",
|
|
267
|
-
description:
|
|
268
|
-
inputSchema: objSchema({ id: intSchema(), status: strSchema() }, ["id", "status"]),
|
|
269
|
-
call: async (args) =>
|
|
418
|
+
description: 'Move a task to its next status when you finish a stage (e.g. dev\u2192test once your PR is up). Enforced flow: draft\u2192backlog\u2192dev\u2192test\u2192approval\u2192release\u2192done (any\u2192canceled). Illegal jumps are rejected. Neither terminal state is a dead end: canceled\u2192draft and done\u2192approval undo the last step, so a mistaken close is recoverable without touching the database. The approval\u2192release gate is polaris.task.approve (human-only).\n\nThree of these moves hand the work to someone else, and `note` is REQUIRED on them \u2014 it is the message that travels with it, and it lands in the task chat as a handover: `dev\u2192test` (what you did and what to look at first), `test\u2192dev` (why it comes back \u2014 it is what the next attempt is made from), and `test\u2192approval`, which also requires `verdict` ("approved" or "rejected": a person is about to decide, and they need to know whether this passed or ran out of rounds). Every other move takes no note.',
|
|
419
|
+
inputSchema: objSchema({ id: intSchema(), status: strSchema(), note: strSchema(), verdict: strSchema() }, ["id", "status"]),
|
|
420
|
+
call: async (args) => {
|
|
421
|
+
const body = { status: args.status };
|
|
422
|
+
if (typeof args.note === "string")
|
|
423
|
+
body.note = args.note;
|
|
424
|
+
if (typeof args.verdict === "string")
|
|
425
|
+
body.verdict = args.verdict;
|
|
426
|
+
return (await apiCall("POST", `/api/tasks/${args.id}/state`, body)).body;
|
|
427
|
+
}
|
|
270
428
|
},
|
|
271
429
|
{
|
|
272
430
|
name: "polaris.task.approve",
|
|
273
|
-
description: "The human review gate:
|
|
431
|
+
description: "The human review gate: a task in `approval` advances to `release` \u2014 cleared to go out, not gone out. Human-only, and valid for everything: a mkt creative approves the same way, and is then either scheduled (auto-publish at its time) or marked published once it has gone out. To ship several approval tasks together, group them into a stack and use polaris.stack.release.",
|
|
274
432
|
inputSchema: objSchema({ id: intSchema() }, ["id"]),
|
|
275
433
|
call: async (args) => (await apiCall("POST", `/api/tasks/${args.id}/approve`)).body
|
|
276
434
|
},
|
|
277
435
|
{
|
|
278
436
|
name: "polaris.task.schedule",
|
|
279
|
-
description: "Schedule a mkt creative for publication: approval \u2192 agendado. The creative must be bound to an active social account (resolved from its market + channel) and have a publish_at in the future. Its copy is frozen while scheduled \u2014 editing it requires unscheduling first.",
|
|
437
|
+
description: "Schedule a mkt creative for publication: approval \u2192 agendado, and the publisher takes it to `done` when its time arrives. The creative must be bound to an active social account (resolved from its market + channel) and have a publish_at in the future. Its copy is frozen while scheduled \u2014 editing it requires unscheduling first.",
|
|
280
438
|
inputSchema: objSchema({ id: intSchema() }, ["id"]),
|
|
281
439
|
call: async (args) => (await apiCall("POST", `/api/tasks/${args.id}/schedule`)).body
|
|
282
440
|
},
|
|
@@ -288,7 +446,7 @@ var TOOLS = [
|
|
|
288
446
|
},
|
|
289
447
|
{
|
|
290
448
|
name: "polaris.task.mark_published",
|
|
291
|
-
description: "
|
|
449
|
+
description: "The creative has gone out: `release` \u2192 `done`, optionally with the permalink of the post. This is the LAST transition, not a shortcut \u2014 approve it into `release` first (cleared to go out), then mark it published once it actually has. Recorded as a manual human action; use it when the post went out outside the scheduler.",
|
|
292
450
|
inputSchema: objSchema({ id: intSchema() }, ["id"]),
|
|
293
451
|
call: async (args) => (await apiCall("POST", `/api/tasks/${args.id}/mark-published`)).body
|
|
294
452
|
},
|
|
@@ -366,13 +524,13 @@ var TOOLS = [
|
|
|
366
524
|
},
|
|
367
525
|
{
|
|
368
526
|
name: "polaris.ticket.frame_issue",
|
|
369
|
-
description: "Frame a NEW issue (the problem) from this ticket's conversation \u2014 the helpdesk twin of a milestone. A note is added to the thread. Then decompose it via polaris.issue.add_task.",
|
|
527
|
+
description: "Frame a NEW issue (the problem) from this ticket's conversation \u2014 the helpdesk twin of a milestone. A note is added to the thread. Then decompose it via polaris.issue.add_task. HUMAN ONLY: an agent token gets 403 (agent_cannot_admin) \u2014 the helpdesker proposes the issue during triage and a human validates it with a button.",
|
|
370
528
|
inputSchema: objSchema({ id: intSchema(), title: strSchema() }, ["id", "title"]),
|
|
371
529
|
call: async (args) => (await apiCall("POST", `/api/tickets/${args.id}/issues`, { title: args.title })).body
|
|
372
530
|
},
|
|
373
531
|
{
|
|
374
532
|
name: "polaris.ticket.link_issue",
|
|
375
|
-
description: "Link this ticket to an EXISTING issue (dedup \u2014 it's a duplicate report of a problem already being worked).",
|
|
533
|
+
description: "Link this ticket to an EXISTING issue (dedup \u2014 it's a duplicate report of a problem already being worked). Then tell the customer we already have the problem, point them to follow it in the product, and close this ticket after sending. HUMAN ONLY: an agent token gets 403 (agent_cannot_admin) \u2014 the helpdesker proposes the link, a human accepts it.",
|
|
376
534
|
inputSchema: objSchema({ id: intSchema(), issue_id: intSchema() }, ["id", "issue_id"]),
|
|
377
535
|
call: async (args) => (await apiCall("POST", `/api/tickets/${args.id}/issues/link`, { issue_id: args.issue_id })).body
|
|
378
536
|
},
|
|
@@ -527,6 +685,30 @@ var TOOLS = [
|
|
|
527
685
|
return r.body;
|
|
528
686
|
}
|
|
529
687
|
},
|
|
688
|
+
{
|
|
689
|
+
name: "polaris.revision.list",
|
|
690
|
+
description: "History of an object's markdown field, newest first \u2014 what the text was BEFORE and AFTER each change, who changed it and how (human, descriptioner, revert). Use it to answer \"what did the descriptioner actually change in this milestone?\", which the activity feed cannot tell you. Scopes: milestone|task|issue|agent use `id`; agent_function uses `key` (e.g. 'planner').",
|
|
691
|
+
inputSchema: objSchema({
|
|
692
|
+
scope: strSchema("milestone|task|issue|agent|agent_function"),
|
|
693
|
+
id: intSchema("object id \u2014 every scope except agent_function"),
|
|
694
|
+
key: strSchema("text key \u2014 agent_function only, e.g. 'planner'")
|
|
695
|
+
}, ["scope"]),
|
|
696
|
+
call: async (args) => {
|
|
697
|
+
const qs = new URLSearchParams;
|
|
698
|
+
qs.set("scope", String(args.scope));
|
|
699
|
+
if (args.id !== undefined && args.id !== null)
|
|
700
|
+
qs.set("id", String(args.id));
|
|
701
|
+
if (args.key !== undefined && args.key !== null)
|
|
702
|
+
qs.set("key", String(args.key));
|
|
703
|
+
return (await apiCall("GET", `/api/revisions?${qs}`)).body;
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
name: "polaris.revision.revert",
|
|
708
|
+
description: "Restore a markdown field to its value BEFORE the given revision. Not a rollback \u2014 it writes normally, so it records its own revision with source='revert' and can itself be reverted. Needs a token.",
|
|
709
|
+
inputSchema: objSchema({ id: intSchema("revision id") }, ["id"]),
|
|
710
|
+
call: async (args) => (await apiCall("POST", `/api/revisions/${args.id}/revert`)).body
|
|
711
|
+
},
|
|
530
712
|
{
|
|
531
713
|
name: "polaris.chat.get",
|
|
532
714
|
description: "Resolve the chat thread for a scope (e.g. task 42) and return its id. Idempotent (get-or-create). You rarely need this directly \u2014 polaris.chat.messages takes the scope and resolves the id for you.",
|
|
@@ -574,6 +756,88 @@ var TOOLS = [
|
|
|
574
756
|
inputSchema: objSchema({ key: strSchema("project key"), content: strSchema("full CLAUDE.md markdown") }, ["key", "content"]),
|
|
575
757
|
call: async (args) => (await apiCall("PUT", `/api/projects/${args.key}/claude-md`, { content: args.content })).body
|
|
576
758
|
},
|
|
759
|
+
{
|
|
760
|
+
name: "polaris.presence.list",
|
|
761
|
+
description: "Where a product exists in the world: the channels it publishes on and the directories it is listed in, each with its state (missing \u2192 exists \u2192 connected). Read this before writing a campaign \u2014 a channel that is not connected cannot be published to. Each row carries what the catalogue knows in `place`: read `place.actor` before planning work there \u2014 `agent` means there is a publishing tool, `human` means a person does it and records where, and `place.final_state` says how far this particular place can ever get.",
|
|
762
|
+
inputSchema: objSchema({ key: strSchema("project key") }, ["key"]),
|
|
763
|
+
call: async (args) => (await apiCall("GET", `/api/projects/${args.key}/presences`)).body
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
name: "polaris.place.list",
|
|
767
|
+
description: "The catalogue of places a product can exist in \u2014 every social network, paid surface, syndication platform, app store and software directory the studio knows about. The world's list, not ours: read it to decide WHERE a product should be. Each entry says what the place is, who acts there (`actor`: agent = there is a publishing tool; human = a person does it and records where), how far it can get (`final_state`), WHY it is worth being there (`note`), and the URL that was verified (`source`). Whether we are actually there is a PRESENCE \u2014 polaris.presence.list.",
|
|
768
|
+
inputSchema: objSchema({}),
|
|
769
|
+
call: async () => (await apiCall("GET", "/api/places")).body
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
name: "polaris.org_credential.list",
|
|
773
|
+
description: "The accounts that serve MANY products at once \u2014 Google Play Console, App Store Connect, a vendor login that covers several listings. Read it to know whether an entry can be opened at all, and by whom: the row names the owner, and the password never leaves the server. A presence points at one of these when the credential is the org's rather than the product's.",
|
|
774
|
+
inputSchema: objSchema({}),
|
|
775
|
+
call: async () => (await apiCall("GET", "/api/org-credentials")).body
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
name: "polaris.org_credential.add",
|
|
779
|
+
description: "Register an org-wide credential (human-only). Idempotent on slug + login: the same Play Console twice is the same Play Console, and a DIFFERENT login on the same site is a different credential. A place reached by OAuth is refused \u2014 that credential already lives in social accounts. Never send a password you were not given.",
|
|
780
|
+
inputSchema: objSchema({
|
|
781
|
+
slug: strSchema("play-store \xB7 app-store \xB7 capterra \u2026"),
|
|
782
|
+
label: strSchema("human name; defaults to the catalogue's"),
|
|
783
|
+
url: strSchema("where you log in"),
|
|
784
|
+
login_email: strSchema(),
|
|
785
|
+
notes: strSchema("who holds the second factor, and anything the next person needs")
|
|
786
|
+
}, ["slug"]),
|
|
787
|
+
call: async (args) => (await apiCall("POST", "/api/org-credentials", args)).body
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
name: "polaris.org_credential.verify",
|
|
791
|
+
description: "Stamp an org credential as CHECKED \u2014 it still opens the door (human-only). A credential does not announce that it expired: that is discovered on the day it is needed, which is always the worst day.",
|
|
792
|
+
inputSchema: objSchema({ id: intSchema("credential id") }, ["id"]),
|
|
793
|
+
call: async (args) => (await apiCall("POST", `/api/org-credentials/${args.id}/verify`, {})).body
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
name: "polaris.presence.add",
|
|
797
|
+
description: "Add a place to a project (human-only). kind: channel (we publish there) | listing (we keep an entry there). Idempotent on slug + MARKET: adding Instagram BR twice is the same Instagram BR, and Instagram US is a different presence. Never send a password you were not given.",
|
|
798
|
+
inputSchema: objSchema({
|
|
799
|
+
key: strSchema("project key"),
|
|
800
|
+
kind: strSchema("channel | listing"),
|
|
801
|
+
slug: strSchema("instagram \xB7 linkedin \xB7 reddit \xB7 g2 \xB7 capterra \u2026"),
|
|
802
|
+
label: strSchema("human name, e.g. Instagram"),
|
|
803
|
+
market: strSchema("the market this one serves (BR \xB7 US \xB7 \u2026) \u2014 it is half the identity, so a product with an account per market gets one presence per market. Omit where the place has no market (a blog, a store entry)."),
|
|
804
|
+
url: strSchema("public profile or listing URL"),
|
|
805
|
+
handle: strSchema("@handle or account name"),
|
|
806
|
+
state: strSchema("missing | exists | connected \u2014 connected means there IS a link"),
|
|
807
|
+
login_email: strSchema(),
|
|
808
|
+
org_credential_id: intSchema("the org-wide account that opens this entry, when there is one"),
|
|
809
|
+
notes: strSchema()
|
|
810
|
+
}, ["key", "kind", "slug", "label"]),
|
|
811
|
+
call: async (args) => {
|
|
812
|
+
const { key, ...body } = args;
|
|
813
|
+
return (await apiCall("POST", `/api/projects/${key}/presences`, body)).body;
|
|
814
|
+
}
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
name: "polaris.presence.update",
|
|
818
|
+
description: "Edit one presence \u2014 its URL, handle, owner, notes or state (human-only).",
|
|
819
|
+
inputSchema: objSchema({
|
|
820
|
+
key: strSchema("project key"),
|
|
821
|
+
id: intSchema("presence id"),
|
|
822
|
+
label: strSchema(),
|
|
823
|
+
url: strSchema(),
|
|
824
|
+
handle: strSchema(),
|
|
825
|
+
state: strSchema("missing | exists | connected"),
|
|
826
|
+
login_email: strSchema(),
|
|
827
|
+
org_credential_id: intSchema("the org-wide account that opens this entry; null unlinks"),
|
|
828
|
+
notes: strSchema()
|
|
829
|
+
}, ["key", "id"]),
|
|
830
|
+
call: async (args) => {
|
|
831
|
+
const { key, id, ...body } = args;
|
|
832
|
+
return (await apiCall("PATCH", `/api/projects/${key}/presences/${id}`, body)).body;
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
name: "polaris.presence.verify",
|
|
837
|
+
description: "Stamp a presence as CHECKED AGAINST THE TRUTH of the product (human-only). Use it after actually looking: on a directory listing the risk is not staleness, it is the feature checklist claiming something the product does not do.",
|
|
838
|
+
inputSchema: objSchema({ key: strSchema("project key"), id: intSchema() }, ["key", "id"]),
|
|
839
|
+
call: async (args) => (await apiCall("POST", `/api/projects/${args.key}/presences/${args.id}/verify`, {})).body
|
|
840
|
+
},
|
|
577
841
|
{
|
|
578
842
|
name: "polaris.agent.create",
|
|
579
843
|
description: "Create an agent/employee (human-only). function: developer|tester|planner|helpdesker; product = project key; team = dev|mkt; domain optional (roadmap|helpdesk|both).",
|
|
@@ -589,12 +853,22 @@ var TOOLS = [
|
|
|
589
853
|
},
|
|
590
854
|
{
|
|
591
855
|
name: "polaris.agent.update",
|
|
592
|
-
description: "Update an agent (human-only): name (rename), domain (roadmap|helpdesk|both), or
|
|
856
|
+
description: "Update an agent (human-only): name (rename), domain (roadmap|helpdesk|both), mantra_md, or resource_limits. The stable agent_id_slug never changes. resource_limits (CPU/RAM/disk, enforced via the agent's systemd unit) is null-or-object: null clears every field back to the default; an object states ALL fields (memory_max_mb, cpu_quota_pct, disk_quota_mb \u2014 each an integer, or null for that field's default). Takes effect on the agent's next re-provision, not instantly.",
|
|
593
857
|
inputSchema: objSchema({
|
|
594
858
|
id: intSchema(),
|
|
595
859
|
name: strSchema(),
|
|
596
860
|
domain: strSchema("roadmap|helpdesk|both"),
|
|
597
|
-
mantra_md: strSchema()
|
|
861
|
+
mantra_md: strSchema(),
|
|
862
|
+
resource_limits: {
|
|
863
|
+
type: ["object", "null"],
|
|
864
|
+
description: "CPU/RAM/disk caps. null = defaults for all fields. Object must state every field (int or null): memory_max_mb, cpu_quota_pct, disk_quota_mb.",
|
|
865
|
+
properties: {
|
|
866
|
+
memory_max_mb: { type: ["integer", "null"] },
|
|
867
|
+
cpu_quota_pct: { type: ["integer", "null"] },
|
|
868
|
+
disk_quota_mb: { type: ["integer", "null"] }
|
|
869
|
+
},
|
|
870
|
+
additionalProperties: false
|
|
871
|
+
}
|
|
598
872
|
}, ["id"]),
|
|
599
873
|
call: async (args) => {
|
|
600
874
|
const { id, ...patch } = args;
|
|
@@ -654,7 +928,7 @@ var TOOLS = [
|
|
|
654
928
|
},
|
|
655
929
|
{
|
|
656
930
|
name: "polaris.milestone.create",
|
|
657
|
-
description: "Create a milestone. team=dev|mkt; end_date = deadline (ISO date, required). For a marketing CAMPAIGN (team=mkt)
|
|
931
|
+
description: "Create a milestone. team=dev|mkt; end_date = deadline (ISO date, required). For a marketing CAMPAIGN (team=mkt), `market` says which markets it serves \u2014 that is what routes each creative to an account. Everything else about the campaign (rhythm, channels, budget, angle) goes in `description_md`: the briefer reads it and cuts the creatives, each with its own day.",
|
|
658
932
|
inputSchema: objSchema({
|
|
659
933
|
project_key: strSchema(),
|
|
660
934
|
name: strSchema(),
|
|
@@ -667,28 +941,7 @@ var TOOLS = [
|
|
|
667
941
|
type: "array",
|
|
668
942
|
items: { type: "string" },
|
|
669
943
|
description: "mkt: target markets \u2014 any of BR, US, EU"
|
|
670
|
-
}
|
|
671
|
-
cadence: {
|
|
672
|
-
type: "array",
|
|
673
|
-
description: "mkt: per-channel cadence rules Discovery expands into dated creatives",
|
|
674
|
-
items: {
|
|
675
|
-
type: "object",
|
|
676
|
-
properties: {
|
|
677
|
-
channel: { type: "string", description: "Instagram, TikTok, LinkedIn, \u2026" },
|
|
678
|
-
format: { type: "string", description: "post, reel, story, artigo, \u2026" },
|
|
679
|
-
n: { type: "integer", description: "count per period" },
|
|
680
|
-
per: { type: "string", description: "day | week" }
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
},
|
|
684
|
-
max_creatives: intSchema("mkt: cap on how many creatives Discovery/cadence may generate"),
|
|
685
|
-
paid: { type: "boolean", description: "mkt: is the whole campaign paid?" },
|
|
686
|
-
platforms: {
|
|
687
|
-
type: "array",
|
|
688
|
-
items: { type: "string" },
|
|
689
|
-
description: "mkt paid: any of Meta, Google, Reddit, LinkedIn, TikTok, YouTube"
|
|
690
|
-
},
|
|
691
|
-
budget: { type: "number", description: "mkt: campaign ad-spend budget (\u20AC)" }
|
|
944
|
+
}
|
|
692
945
|
}, ["project_key", "name", "team", "end_date"]),
|
|
693
946
|
call: async (args) => (await apiCall("POST", "/api/milestones", args)).body
|
|
694
947
|
},
|
|
@@ -716,11 +969,23 @@ var TOOLS = [
|
|
|
716
969
|
inputSchema: objSchema({ id: intSchema("stack id"), task_id: intSchema() }, ["id", "task_id"]),
|
|
717
970
|
call: async (args) => (await apiCall("DELETE", `/api/stacks/${args.id}/tasks`, { task_id: args.task_id })).body
|
|
718
971
|
},
|
|
972
|
+
{
|
|
973
|
+
name: "polaris.task.escalate",
|
|
974
|
+
description: "You are making a piece and something needs a HUMAN DECISION before it can be made \u2014 a premise in the brief that turned out false, two ways forward and no ground to choose between them, a collision with something already live. Stops the piece and puts it in front of a person, in `approval`, with your question attached.\n\nNot for a piece you could not finish: that is what ending the run does. This is for one you are not going to decide alone.\n\nThe `note` is the whole point \u2014 what you found, what the options are, and what you are not choosing on your own. Without it this is an abandoned piece with a flag on it.",
|
|
975
|
+
inputSchema: objSchema({
|
|
976
|
+
id: intSchema(),
|
|
977
|
+
note: strSchema("the question \u2014 what was found, the options, and what you will not decide")
|
|
978
|
+
}, ["id", "note"]),
|
|
979
|
+
call: async (args) => (await apiCall("POST", `/api/tasks/${args.id}/escalate`, { note: args.note })).body
|
|
980
|
+
},
|
|
719
981
|
{
|
|
720
982
|
name: "polaris.task.return_to_backlog",
|
|
721
|
-
description: "Send an approval task back for rework (human-only) \u2014 to its sticky developer (dev) or backlog. Clears escalation.",
|
|
722
|
-
inputSchema: objSchema({
|
|
723
|
-
|
|
983
|
+
description: "Send an approval task back for rework (human-only) \u2014 to its sticky developer (dev) or backlog. Clears escalation.\n\n**Write the `note`.** On a rework the agent does NOT re-read the brief: the request it gets says *you already have the brief*, and the note is the only thing that reaches it. Sending a piece back without one asks for the same piece again \u2014 and an agent that finds the field empty concludes the worker restarted and changes nothing, which is what it should do.",
|
|
984
|
+
inputSchema: objSchema({
|
|
985
|
+
id: intSchema(),
|
|
986
|
+
note: strSchema("why it is coming back \u2014 this is the brief for the next attempt")
|
|
987
|
+
}, ["id"]),
|
|
988
|
+
call: async (args) => (await apiCall("POST", `/api/tasks/${args.id}/return-to-backlog`, args.note ? { note: args.note } : undefined)).body
|
|
724
989
|
},
|
|
725
990
|
{
|
|
726
991
|
name: "polaris.chat.post",
|
package/package.json
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glie/mcp-polaris",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Model Context Protocol (stdio) server exposing Polaris
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Model Context Protocol (stdio) server exposing Polaris, glie's ops platform, as native tools in Claude Code and any MCP client.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "glie <carlos@glie.ai>",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"bin": {
|
|
9
9
|
"mcp-polaris": "dist/index.js"
|
|
10
10
|
},
|
|
11
|
-
"files": [
|
|
12
|
-
"dist",
|
|
13
|
-
"README.md",
|
|
14
|
-
"LICENSE"
|
|
15
|
-
],
|
|
11
|
+
"files": ["dist", "README.md", "LICENSE"],
|
|
16
12
|
"engines": {
|
|
17
13
|
"node": ">=18"
|
|
18
14
|
},
|
|
@@ -25,14 +21,7 @@
|
|
|
25
21
|
"directory": "packages/mcp-polaris"
|
|
26
22
|
},
|
|
27
23
|
"homepage": "https://polaris.glie.ai",
|
|
28
|
-
"keywords": [
|
|
29
|
-
"mcp",
|
|
30
|
-
"model-context-protocol",
|
|
31
|
-
"claude",
|
|
32
|
-
"claude-code",
|
|
33
|
-
"polaris",
|
|
34
|
-
"glie"
|
|
35
|
-
],
|
|
24
|
+
"keywords": ["mcp", "model-context-protocol", "claude", "claude-code", "polaris", "glie"],
|
|
36
25
|
"scripts": {
|
|
37
26
|
"build": "bun run build.ts",
|
|
38
27
|
"prepublishOnly": "bun run build.ts"
|