@glie/mcp-polaris 0.14.0 → 0.18.2
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 +20 -8
- package/dist/index.js +145 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,8 +48,10 @@ it. The same token authenticates this server and the `polaris` CLI as you.
|
|
|
48
48
|
## Tools
|
|
49
49
|
|
|
50
50
|
**Roadmap.** `polaris.me`, `polaris.project.*`, `polaris.milestone.*` (incl.
|
|
51
|
-
`update` to refine a spec, `
|
|
52
|
-
|
|
51
|
+
`update` to refine a spec or move its dates, `demote` to send one with no tasks back to the
|
|
52
|
+
idea list, `attachment_*` to list/attach/remove the visual
|
|
53
|
+
references anchored in its body), `polaris.idea.*` (incl. `promote` into a milestone and
|
|
54
|
+
`promote_task` into a standalone task with no milestone), `polaris.task.*` (incl. `update`,
|
|
53
55
|
`transition`, `approve`, `schedule`, `attachment_*` — same as the milestone's,
|
|
54
56
|
plus how a milestone reference gets forwarded here via
|
|
55
57
|
`source_attachment_id`), `polaris.stack.*` (`list` / `get` / `release` for the
|
|
@@ -57,12 +59,22 @@ approval Release Candidate flow), `polaris.agent.*`, `polaris.team.*`,
|
|
|
57
59
|
`polaris.claude_md.get`, `polaris.framework.list`.
|
|
58
60
|
|
|
59
61
|
**Helpdesk.** `polaris.ticket.*` (the customer conversation: `reply`, `pass`,
|
|
60
|
-
`frame_issue`, `link_issue`) and `polaris.issue.*` (the problem:
|
|
61
|
-
`transition`, `add_task`). N tickets can dedup onto one issue, and one issue
|
|
62
|
-
fans out into N tasks.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
`frame_issue`, `link_issue`, `attachment_list`) and `polaris.issue.*` (the problem:
|
|
63
|
+
`open`, `transition`, `add_task`). N tickets can dedup onto one issue, and one issue
|
|
64
|
+
fans out into N tasks. A reply carries files through `attachment_ids`: upload each
|
|
65
|
+
one to `POST /api/tickets/:id/attachments` first (this server does not carry bytes),
|
|
66
|
+
then paste its `marker` into `body_md` to draw it inside the message.
|
|
67
|
+
|
|
68
|
+
**Context, read-only.** `polaris.activity.list` (what happened),
|
|
69
|
+
`polaris.chat.get` / `polaris.chat.messages` (comments agents left on a scope),
|
|
70
|
+
and `polaris.task.run_lines` (the thread of an agent's run on a task: what it was
|
|
71
|
+
asked, said, ran and got back; human tokens only).
|
|
72
|
+
|
|
73
|
+
**What a creative delivered.** `polaris.task.creatives` lists every version of a
|
|
74
|
+
creative task with its files and the words that go out beside them (caption,
|
|
75
|
+
title, copy). `polaris.task.creative_download` saves one version to this machine
|
|
76
|
+
as a zip of its slides, so a video can be opened, its frames pulled and its
|
|
77
|
+
sound measured.
|
|
66
78
|
|
|
67
79
|
Run `tools/list` against the server for the full, current set.
|
|
68
80
|
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// ../../src/mcp/index.ts
|
|
5
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
6
|
+
import { tmpdir } from "os";
|
|
7
|
+
import { join, resolve } from "path";
|
|
5
8
|
import { createInterface } from "readline";
|
|
6
9
|
|
|
7
10
|
// ../../src/lib/media-types.ts
|
|
@@ -13,11 +16,22 @@ var MEDIA_TYPES = [
|
|
|
13
16
|
{ mime: "video/quicktime", kind: "video", ext: ".mov", aliases: [] },
|
|
14
17
|
{ mime: "video/webm", kind: "video", ext: ".webm", aliases: [] }
|
|
15
18
|
];
|
|
19
|
+
function mimesOfKind(kind) {
|
|
20
|
+
return MEDIA_TYPES.filter((t) => t.kind === kind).map((t) => t.mime);
|
|
21
|
+
}
|
|
16
22
|
function allMimes() {
|
|
17
23
|
return MEDIA_TYPES.map((t) => t.mime);
|
|
18
24
|
}
|
|
25
|
+
var RECEIVED_IMAGE_MIMES = ["image/gif"];
|
|
26
|
+
var INLINE_MIMES = new Set([
|
|
27
|
+
...mimesOfKind("image"),
|
|
28
|
+
...mimesOfKind("video"),
|
|
29
|
+
...RECEIVED_IMAGE_MIMES
|
|
30
|
+
]);
|
|
19
31
|
|
|
20
32
|
// ../../src/mcp/index.ts
|
|
33
|
+
var VERSION = "0.18.2";
|
|
34
|
+
var FRAMEWORK_KEY_DOC = "optional \u2014 a key from polaris.framework.list. Leave it out when none applies: a framework is for founding a large domain, and most milestones take none. An unknown key is refused (400) with the keys that exist.";
|
|
21
35
|
var BASE = process.env.POLARIS_URL ?? "http://127.0.0.1:7843";
|
|
22
36
|
var TOKEN = process.env.POLARIS_TOKEN ?? "";
|
|
23
37
|
var PROJECT = process.env.POLARIS_PROJECT ?? "";
|
|
@@ -84,13 +98,15 @@ var INSTRUCTIONS = [
|
|
|
84
98
|
"\u2022 N tickets \u2192 1 issue (duplicates dedup onto one problem) \xB7 1 ticket \u2192 N issues \xB7 1 issue \u2192 N tasks (iterative fix).",
|
|
85
99
|
"\u2022 Flow: ticket.create \u2192 ticket.reply / ticket.pass (communicate) \u2192 ticket.frame_issue (or issue.open standalone; ticket.link_issue to dedup)",
|
|
86
100
|
" \u2192 issue.add_task \xD7N (a planner decomposes) \u2192 task.transition the tasks through dev\u2192test\u2192approval\u2192release.",
|
|
87
|
-
"\u2022 The ball: ticket.pass sets whose move it is (customer|team)
|
|
101
|
+
"\u2022 The ball: ticket.pass sets whose move it is (customer|team). A team message never moves it; a customer reply brings it back to the team and auto-reopens a resolved/closed ticket.",
|
|
88
102
|
"",
|
|
89
103
|
"WHICH TOOL WHEN:",
|
|
90
104
|
`\u2022 "What's mine / what next?" \u2192 polaris.task.list (assignee \u2026="self", status=\u2026)`,
|
|
91
105
|
'\u2022 "Read X in full" \u2192 polaris.task.get \xB7 milestone.get \xB7 project.get \xB7 stack.get',
|
|
92
106
|
'\u2022 "Fix an unclear brief" \u2192 polaris.task.update / milestone.update (PATCH description_md)',
|
|
93
107
|
'\u2022 "Catch up \u2014 what happened/said?"\u2192 polaris.activity.list (events) \xB7 polaris.chat.messages (comments left by agents)',
|
|
108
|
+
`\u2022 "What is the agent doing / why?" \u2192 polaris.task.run_lines (the run's thread: prompt, reasoning, commands, results; human-only)`,
|
|
109
|
+
'\u2022 "What did this creative deliver?" \u2192 polaris.task.creatives (versions, files, caption) \xB7 polaris.task.creative_download (the file, saved locally)',
|
|
94
110
|
'\u2022 "Move my task forward" \u2192 polaris.task.transition(id, status)',
|
|
95
111
|
`\u2022 "It's reviewed, ship it" \u2192 polaris.task.approve (human-only); ship several together via polaris.stack.* \u2192 stack.release`,
|
|
96
112
|
`\u2022 "My task is stuck in a blocked stack" \u2192 fix the conflict on YOUR branch (rebase agent/task-N onto dev, push) \u2014 the rc PR flips to ready automatically. A stacked task can't advance individually; never merge the rc PR by hand.`,
|
|
@@ -98,6 +114,8 @@ var INSTRUCTIONS = [
|
|
|
98
114
|
'\u2022 "Jot something down for later" \u2192 polaris.idea.create (a title is enough). NO dates: an idea is not a milestone.',
|
|
99
115
|
'\u2022 "What have we already thought of?" \u2192 polaris.idea.list \u2014 read it before proposing work; it also holds what was turned down',
|
|
100
116
|
'\u2022 "This idea is now real" \u2192 polaris.idea.promote (needs end_date + team) \u2014 the one door from the idea list to the timeline',
|
|
117
|
+
'\u2022 "This idea is one small piece of dev work" \u2192 polaris.idea.promote_task \u2014 a standalone task, no milestone, straight into the dev backlog (human-only)',
|
|
118
|
+
'\u2022 "This milestone was only a hunch" \u2192 polaris.milestone.demote \u2014 back to the idea list, only while it has no tasks (human-only)',
|
|
101
119
|
`\u2022 "Triage support / what's waiting?" \u2192 polaris.ticket.list (status, project_key) \u2014 P1 first`,
|
|
102
120
|
'\u2022 "Reply to a customer / hand off" \u2192 polaris.ticket.reply then polaris.ticket.pass(to)',
|
|
103
121
|
'\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)',
|
|
@@ -227,13 +245,27 @@ var TOOLS = [
|
|
|
227
245
|
start_date: strSchema("YYYY-MM-DD, optional"),
|
|
228
246
|
name: strSchema("optional: overrides the idea's title"),
|
|
229
247
|
description_md: strSchema("optional: overrides the idea's note"),
|
|
230
|
-
framework_key: strSchema(
|
|
248
|
+
framework_key: strSchema(FRAMEWORK_KEY_DOC)
|
|
231
249
|
}, ["project_key", "id", "end_date"]),
|
|
232
250
|
call: async (args) => {
|
|
233
251
|
const { project_key, id, ...body } = args;
|
|
234
252
|
return (await apiCall("POST", `/api/projects/${project_key}/ideas/${id}/promote`, body)).body;
|
|
235
253
|
}
|
|
236
254
|
},
|
|
255
|
+
{
|
|
256
|
+
name: "polaris.idea.promote_task",
|
|
257
|
+
description: "Promote a dev idea into a STANDALONE task \u2014 one piece of work with no milestone and no deadline, born in the idea's project and straight into the dev backlog, where the project's developer agents pick it up. For work that is a goal with several tasks, use polaris.idea.promote (a milestone). A mkt idea is refused: a creative needs a campaign. Promoting twice returns the first task and writes nothing. Human-only.",
|
|
258
|
+
inputSchema: objSchema({
|
|
259
|
+
project_key: strSchema(),
|
|
260
|
+
id: intSchema("idea id"),
|
|
261
|
+
name: strSchema("optional: overrides the idea's title"),
|
|
262
|
+
description_md: strSchema("optional: overrides the idea's note (the developer's brief)")
|
|
263
|
+
}, ["project_key", "id"]),
|
|
264
|
+
call: async (args) => {
|
|
265
|
+
const { project_key, id, ...body } = args;
|
|
266
|
+
return (await apiCall("POST", `/api/projects/${project_key}/ideas/${id}/promote-task`, body)).body;
|
|
267
|
+
}
|
|
268
|
+
},
|
|
237
269
|
{
|
|
238
270
|
name: "polaris.idea.drop",
|
|
239
271
|
description: "Drop an idea, with the reason it was dropped. Reversible (polaris.idea.reopen) \u2014 dropping is not a one-way door, because almost every good idea looks bad at first. Idempotent: dropping twice keeps the first reason. Needs a token.",
|
|
@@ -275,9 +307,21 @@ var TOOLS = [
|
|
|
275
307
|
},
|
|
276
308
|
{
|
|
277
309
|
name: "polaris.milestone.list",
|
|
278
|
-
description: "List milestones in a project.",
|
|
279
|
-
inputSchema: objSchema({
|
|
280
|
-
|
|
310
|
+
description: "List milestones in a project. Each one comes with its whole description, so a project with a long history answers with a lot: narrow it with `status` (e.g. loop for the campaigns running now) and `team` (dev|mkt).",
|
|
311
|
+
inputSchema: objSchema({
|
|
312
|
+
project_key: strSchema(),
|
|
313
|
+
status: strSchema("draft|discovery|loop|release|done|canceled"),
|
|
314
|
+
team: strSchema("dev|mkt")
|
|
315
|
+
}, ["project_key"]),
|
|
316
|
+
call: async (args) => {
|
|
317
|
+
const qs = new URLSearchParams({ limit: "200" });
|
|
318
|
+
for (const k of ["status", "team"]) {
|
|
319
|
+
const v = args[k];
|
|
320
|
+
if (v !== undefined && v !== null)
|
|
321
|
+
qs.set(k, String(v));
|
|
322
|
+
}
|
|
323
|
+
return (await apiCall("GET", `/api/projects/${args.project_key}/milestones?${qs}`)).body;
|
|
324
|
+
}
|
|
281
325
|
},
|
|
282
326
|
{
|
|
283
327
|
name: "polaris.milestone.get",
|
|
@@ -287,11 +331,13 @@ var TOOLS = [
|
|
|
287
331
|
},
|
|
288
332
|
{
|
|
289
333
|
name: "polaris.milestone.update",
|
|
290
|
-
description: "Correct or refine a milestone
|
|
334
|
+
description: "Correct or refine a milestone \u2014 PATCH its description_md, name, or dates (start_date / end_date move it on the timeline; send only the one that changes, start can never fall after end), 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.",
|
|
291
335
|
inputSchema: objSchema({
|
|
292
336
|
id: intSchema(),
|
|
293
337
|
name: strSchema(),
|
|
294
338
|
description_md: strSchema("full markdown brief; replaces the current description"),
|
|
339
|
+
start_date: strSchema("ISO date, e.g. 2026-06-01"),
|
|
340
|
+
end_date: strSchema("ISO date, the deadline, e.g. 2026-06-30"),
|
|
295
341
|
market: {
|
|
296
342
|
type: "array",
|
|
297
343
|
items: { type: "string", enum: ["BR", "US", "EU"] },
|
|
@@ -304,6 +350,10 @@ var TOOLS = [
|
|
|
304
350
|
body.name = args.name;
|
|
305
351
|
if (typeof args.description_md === "string")
|
|
306
352
|
body.description_md = args.description_md;
|
|
353
|
+
if (typeof args.start_date === "string")
|
|
354
|
+
body.start_date = args.start_date;
|
|
355
|
+
if (typeof args.end_date === "string")
|
|
356
|
+
body.end_date = args.end_date;
|
|
307
357
|
if ("market" in args)
|
|
308
358
|
body.market = args.market;
|
|
309
359
|
return (await apiCall("PATCH", `/api/milestones/${args.id}`, body)).body;
|
|
@@ -315,6 +365,12 @@ var TOOLS = [
|
|
|
315
365
|
inputSchema: objSchema({ id: intSchema(), status: strSchema() }, ["id", "status"]),
|
|
316
366
|
call: async (args) => (await apiCall("POST", `/api/milestones/${args.id}/state`, { status: args.status })).body
|
|
317
367
|
},
|
|
368
|
+
{
|
|
369
|
+
name: "polaris.milestone.demote",
|
|
370
|
+
description: "Send a milestone back to the idea list. Only a milestone with NO tasks (not even canceled ones), still in draft, discovery or loop, and not while a planner is breaking it into tasks. The idea it was promoted from reopens (or a new idea is captured from it) carrying the milestone's name and context; the milestone is canceled and cannot be reopened \u2014 promote the idea again instead. Demoting twice returns the first idea. Human-only.",
|
|
371
|
+
inputSchema: objSchema({ id: intSchema("milestone id") }, ["id"]),
|
|
372
|
+
call: async (args) => (await apiCall("POST", `/api/milestones/${args.id}/demote`, {})).body
|
|
373
|
+
},
|
|
318
374
|
{
|
|
319
375
|
name: "polaris.milestone.qa_list",
|
|
320
376
|
description: "List framework Q&A rows for a milestone.",
|
|
@@ -389,10 +445,10 @@ var TOOLS = [
|
|
|
389
445
|
},
|
|
390
446
|
{
|
|
391
447
|
name: "polaris.task.list",
|
|
392
|
-
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.`,
|
|
448
|
+
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 (or "none" for the standalone tasks, which have no milestone), product_key, team.`,
|
|
393
449
|
inputSchema: objSchema({
|
|
394
450
|
status: strSchema("comma-separated subset of: draft,backlog,dev,test,approval,release,done,canceled"),
|
|
395
|
-
milestone_id:
|
|
451
|
+
milestone_id: strSchema('a milestone id, or "none" for the standalone tasks (no milestone)'),
|
|
396
452
|
product_key: strSchema("project key, e.g. saasA"),
|
|
397
453
|
team: strSchema("dev|mkt"),
|
|
398
454
|
assignee_agent_id: strSchema('agent id, or "self" for the calling agent'),
|
|
@@ -426,9 +482,10 @@ var TOOLS = [
|
|
|
426
482
|
},
|
|
427
483
|
{
|
|
428
484
|
name: "polaris.task.create",
|
|
429
|
-
description: "Create a task within a milestone. A marketing CREATIVE (a task in an mkt campaign) carries WHERE IT GOES: `presence_id`, one of the destinations from polaris.destination.list. The channel and the market are read from that destination, and sending them here is refused. It also takes format + scheduled_date (the publish day / calendar slot) + platform (if this creative is individually paid). A CAROUSEL (format=carrossel) also requires `slides` (2..10) \u2014 without it the call is refused, because a carousel with no declared size ships one image.",
|
|
485
|
+
description: "Create a task within a milestone \u2014 or, for one small piece of DEV work with no milestone, a STANDALONE task in a project: send project_key instead of milestone_id (human-only, team dev, no creative fields). A marketing CREATIVE (a task in an mkt campaign) carries WHERE IT GOES: `presence_id`, one of the destinations from polaris.destination.list. The channel and the market are read from that destination, and sending them here is refused. It also takes format + scheduled_date (the publish day / calendar slot) + platform (if this creative is individually paid). A CAROUSEL (format=carrossel) also requires `slides` (2..10) \u2014 without it the call is refused, because a carousel with no declared size ships one image.",
|
|
430
486
|
inputSchema: objSchema({
|
|
431
|
-
milestone_id: intSchema(),
|
|
487
|
+
milestone_id: intSchema("the milestone it belongs to \u2014 or omit it and send project_key"),
|
|
488
|
+
project_key: strSchema("instead of milestone_id: a standalone dev task in this project, with no milestone (human-only)"),
|
|
432
489
|
name: strSchema(),
|
|
433
490
|
description_md: strSchema(),
|
|
434
491
|
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)"),
|
|
@@ -443,7 +500,7 @@ var TOOLS = [
|
|
|
443
500
|
scheduled_date: strSchema("mkt: publish day (ISO date) \u2014 the calendar slot"),
|
|
444
501
|
platform: strSchema("mkt: ad platform if this creative is individually paid"),
|
|
445
502
|
asset_url: strSchema("mkt: URL of the produced creative asset (image/video) for the reviewer")
|
|
446
|
-
}, ["
|
|
503
|
+
}, ["name"]),
|
|
447
504
|
call: async (args) => (await apiCall("POST", "/api/tasks", args)).body
|
|
448
505
|
},
|
|
449
506
|
{
|
|
@@ -619,13 +676,29 @@ var TOOLS = [
|
|
|
619
676
|
},
|
|
620
677
|
{
|
|
621
678
|
name: "polaris.ticket.reply",
|
|
622
|
-
description: "Add a message to a ticket's conversation. Default side=team (you replying); an adapter relaying a customer message passes side=customer. Sending a message does NOT pass the ball.",
|
|
623
|
-
inputSchema: objSchema({
|
|
679
|
+
description: "Add a message to a ticket's conversation. Default side=team (you replying); an adapter relaying a customer message passes side=customer. Sending a message does NOT pass the ball. To send FILES with the reply (a screenshot, a screencast of the thing you are describing): upload each one first \u2014 `curl -sS -H \"Authorization: Bearer $POLARIS_TOKEN\" -F file=@clip.mp4 $POLARIS_URL/api/tickets/<id>/attachments` \u2014 then pass the ids it returns as attachment_ids. Paste each one's `marker` into body_md where it belongs and the image or video is drawn THERE, between your paragraphs; an attachment whose marker you never placed falls to a strip at the foot of the message, which for a screencast is the wrong place. Up to 15MB per file.",
|
|
680
|
+
inputSchema: objSchema({
|
|
681
|
+
id: intSchema(),
|
|
682
|
+
body_md: strSchema(),
|
|
683
|
+
side: strSchema("customer|team"),
|
|
684
|
+
attachment_ids: {
|
|
685
|
+
type: "array",
|
|
686
|
+
items: { type: "integer" },
|
|
687
|
+
description: "Ids from the attachment upload above (or from ticket.attachment_list, where sent=false). They ride on THIS message and become visible with it."
|
|
688
|
+
}
|
|
689
|
+
}, ["id", "body_md"]),
|
|
624
690
|
call: async (args) => (await apiCall("POST", `/api/tickets/${args.id}/messages`, {
|
|
625
691
|
body_md: args.body_md,
|
|
626
|
-
side: args.side
|
|
692
|
+
side: args.side,
|
|
693
|
+
attachment_ids: args.attachment_ids
|
|
627
694
|
})).body
|
|
628
695
|
},
|
|
696
|
+
{
|
|
697
|
+
name: "polaris.ticket.attachment_list",
|
|
698
|
+
description: 'Every file on this ticket \u2014 what the customer sent and what we have attached. Each row carries a `marker` (`` for an image, `[name](ref:N)` for a video) to paste into a reply\'s body_md so the file is drawn inside the message instead of in a list under it, and `sent` (false while it has been uploaded and no message names it yet \u2014 nobody sees it until a reply does). A file (PDF, log) has no marker: there is nothing to draw, and it rides as a download chip. Upload with `curl -sS -H "Authorization: Bearer $POLARIS_TOKEN" -F file=@shot.png $POLARIS_URL/api/tickets/<id>/attachments` \u2014 this call does not carry bytes.',
|
|
699
|
+
inputSchema: objSchema({ id: intSchema() }, ["id"]),
|
|
700
|
+
call: async (args) => (await apiCall("GET", `/api/tickets/${args.id}/attachments`)).body
|
|
701
|
+
},
|
|
629
702
|
{
|
|
630
703
|
name: "polaris.ticket.pass",
|
|
631
704
|
description: "Pass the ball \u2014 whose move it is. to=customer after you reply; to=team to pull it back. Manual + idempotent.",
|
|
@@ -836,7 +909,7 @@ var TOOLS = [
|
|
|
836
909
|
},
|
|
837
910
|
{
|
|
838
911
|
name: "polaris.chat.messages",
|
|
839
|
-
description: "Read the comments/context agents and humans left on a scope (e.g. task 42) \u2014 free-text notes, decisions, @mentions. Pass the scope; the chat id is resolved for you.
|
|
912
|
+
description: "Read the comments/context agents and humans left on a scope (e.g. task 42) \u2014 free-text notes, decisions, @mentions, and the handover notes that travel with a task's moves (what the maker delivered, why a reviewer sent it back). Pass the scope; the chat id is resolved for you. To write one, polaris.chat.post.",
|
|
840
913
|
inputSchema: objSchema({
|
|
841
914
|
scope_type: strSchema("task|milestone|project|agent_dm|human_dm|general"),
|
|
842
915
|
scope_id: intSchema(),
|
|
@@ -851,6 +924,58 @@ var TOOLS = [
|
|
|
851
924
|
return (await apiCall("GET", `/api/chats/${chatId}/messages${qs}`)).body;
|
|
852
925
|
}
|
|
853
926
|
},
|
|
927
|
+
{
|
|
928
|
+
name: "polaris.task.run_lines",
|
|
929
|
+
description: "Watch an agent work: the THREAD of one run on a task \u2014 what it was asked (`prompt`), what it said (`said`), what it ran (`ran`, tool + full input), what came back (`back`), and the rest (`other`). This is the backstage of a run; for the comments left on the task use polaris.chat.messages. HUMAN ONLY: an agent token gets 403 (one agent reading another's reasoning changes what it can judge). A task has one run per agent session (the brief, whoever made the piece, the reviewer); the response's `runs` lists them, newest first, and without `session` you get the newest. Bodies are whole, never truncated, and the first line is the entire prompt \u2014 page with `limit`, then pass the response's `next_after` as `after` to read on or to follow a live run.",
|
|
930
|
+
inputSchema: objSchema({
|
|
931
|
+
id: intSchema("task id"),
|
|
932
|
+
session: strSchema("a session_id from `runs` \u2014 which run to read; omit for the newest"),
|
|
933
|
+
after: intSchema("return only lines with seq greater than this (the previous `next_after`)"),
|
|
934
|
+
limit: intSchema("how many lines (default 500, max 2000)")
|
|
935
|
+
}, ["id"]),
|
|
936
|
+
call: async (args) => {
|
|
937
|
+
const qs = new URLSearchParams;
|
|
938
|
+
for (const k of ["session", "after", "limit"]) {
|
|
939
|
+
const v = args[k];
|
|
940
|
+
if (v !== undefined && v !== null)
|
|
941
|
+
qs.set(k, String(v));
|
|
942
|
+
}
|
|
943
|
+
const r = await apiCall("GET", `/api/tasks/${args.id}/run-lines${qs.toString() ? `?${qs}` : ""}`);
|
|
944
|
+
return r.body;
|
|
945
|
+
}
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
name: "polaris.task.creatives",
|
|
949
|
+
description: "What a creative task has actually delivered: every version, newest first, each slot with its file (`mime`, `url`, `status`) and the words that go out beside it (`caption`, `title`, `copy`, `description`). Read this to judge a piece; the maker's handover note is in polaris.chat.messages on the task. The files sit behind the same login as the API, so to look at one, polaris.task.creative_download.",
|
|
950
|
+
inputSchema: objSchema({ id: intSchema("task id") }, ["id"]),
|
|
951
|
+
call: async (args) => (await apiCall("GET", `/api/tasks/${args.id}/creatives`)).body
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
name: "polaris.task.creative_download",
|
|
955
|
+
description: "Save one version of a creative to THIS machine, as a zip of its slides in slot order (slide-01.mp4, slide-02.png, ...), so its frames can be pulled and its sound measured. Newest version unless `version` is given; only a version whose slides are all ready exists to download (404 otherwise). Writes into `dir` (default: the system temp folder) and returns the file's absolute path and size; unzip it to look inside.",
|
|
956
|
+
inputSchema: objSchema({
|
|
957
|
+
id: intSchema("task id"),
|
|
958
|
+
version: intSchema("which version (polaris.task.creatives lists them); omit for the newest"),
|
|
959
|
+
dir: strSchema("folder to save into; created if missing. Default: the system temp folder")
|
|
960
|
+
}, ["id"]),
|
|
961
|
+
call: async (args) => {
|
|
962
|
+
const qs = typeof args.version === "number" ? `?version=${args.version}` : "";
|
|
963
|
+
const headers = {};
|
|
964
|
+
if (TOKEN)
|
|
965
|
+
headers.Authorization = `Bearer ${TOKEN}`;
|
|
966
|
+
const res = await fetch(`${BASE}/api/tasks/${args.id}/creative.zip${qs}`, { headers });
|
|
967
|
+
if (!res.ok) {
|
|
968
|
+
return { status: res.status, body: await res.text() };
|
|
969
|
+
}
|
|
970
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
971
|
+
const dir = resolve(typeof args.dir === "string" && args.dir ? args.dir : tmpdir());
|
|
972
|
+
mkdirSync(dir, { recursive: true });
|
|
973
|
+
const name = `task-${args.id}-${typeof args.version === "number" ? `v${args.version}` : "latest"}.zip`;
|
|
974
|
+
const path = join(dir, name);
|
|
975
|
+
writeFileSync(path, bytes);
|
|
976
|
+
return { data: { path, bytes: bytes.length } };
|
|
977
|
+
}
|
|
978
|
+
},
|
|
854
979
|
{
|
|
855
980
|
name: "polaris.project.update",
|
|
856
981
|
description: "Update a project (human-only): repo_url, name, status (active|paused|archived), owner_human_id. Brand/context live in the CLAUDE.md \u2014 use polaris.project.claude_md_set.",
|
|
@@ -1071,7 +1196,7 @@ var TOOLS = [
|
|
|
1071
1196
|
team: strSchema("dev|mkt"),
|
|
1072
1197
|
end_date: strSchema("ISO date, e.g. 2026-06-30"),
|
|
1073
1198
|
start_date: strSchema("ISO date (optional)"),
|
|
1074
|
-
framework_key: strSchema(),
|
|
1199
|
+
framework_key: strSchema(FRAMEWORK_KEY_DOC),
|
|
1075
1200
|
description_md: strSchema(),
|
|
1076
1201
|
market: {
|
|
1077
1202
|
type: "array",
|
|
@@ -1178,7 +1303,7 @@ var TOOLS = [
|
|
|
1178
1303
|
items: { type: "string" },
|
|
1179
1304
|
description: "developer|tester|planner|helpdesker"
|
|
1180
1305
|
},
|
|
1181
|
-
framework_key: strSchema()
|
|
1306
|
+
framework_key: strSchema("optional \u2014 the team's default framework: a key from polaris.framework.list")
|
|
1182
1307
|
}, ["key", "name"]),
|
|
1183
1308
|
call: async (args) => (await apiCall("POST", "/api/teams", args)).body
|
|
1184
1309
|
},
|
|
@@ -1190,7 +1315,7 @@ var TOOLS = [
|
|
|
1190
1315
|
name: strSchema(),
|
|
1191
1316
|
requires: { type: "array", items: { type: "string" } },
|
|
1192
1317
|
functions: { type: "array", items: { type: "string" } },
|
|
1193
|
-
framework_key: strSchema()
|
|
1318
|
+
framework_key: strSchema("the team's default framework: a key from polaris.framework.list")
|
|
1194
1319
|
}, ["key"]),
|
|
1195
1320
|
call: async (args) => {
|
|
1196
1321
|
const { key, ...patch } = args;
|
|
@@ -1216,7 +1341,7 @@ async function handle(req) {
|
|
|
1216
1341
|
return ok(id, {
|
|
1217
1342
|
protocolVersion: "2024-11-05",
|
|
1218
1343
|
capabilities: { tools: {} },
|
|
1219
|
-
serverInfo: { name: "mcp-polaris", version:
|
|
1344
|
+
serverInfo: { name: "mcp-polaris", version: VERSION },
|
|
1220
1345
|
instructions: INSTRUCTIONS
|
|
1221
1346
|
});
|
|
1222
1347
|
case "initialized":
|
|
@@ -1276,5 +1401,6 @@ if (true) {
|
|
|
1276
1401
|
rl.on("close", () => log("stdin closed, exiting"));
|
|
1277
1402
|
}
|
|
1278
1403
|
export {
|
|
1404
|
+
VERSION,
|
|
1279
1405
|
TOOLS
|
|
1280
1406
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glie/mcp-polaris",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.2",
|
|
4
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>",
|