@floh-solutions/pharos-cli 0.1.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.
@@ -0,0 +1,236 @@
1
+ import { emit, usageError } from "../output.js";
2
+ import { approve } from "../session.js";
3
+ import { describeTarget, parseTarget } from "../target.js";
4
+ /**
5
+ * `pharos comment …` — the discussion, on either surface.
6
+ *
7
+ * **Wiki comments exist in no other tool.** The Azure DevOps MCP server ships
8
+ * none of these verbs for a wiki page — not list, not add, not edit, not
9
+ * delete, not react — verified by enumerating its tools. For work item
10
+ * comments it has add and update only, so delete and reactions are also
11
+ * reachable from nowhere else.
12
+ *
13
+ * The two surfaces behave differently in ways that would bite a caller writing
14
+ * this by hand, and each difference is handled on its own side rather than
15
+ * assumed away:
16
+ *
17
+ * | | work item | wiki page |
18
+ * |---|---|---|
19
+ * | keyed on | the work item id | the page's NUMERIC id, not its path |
20
+ * | `includeDeleted` | honoured | ignored — deleted comments come back regardless |
21
+ * | second delete | 404 | 500 |
22
+ * | reactions api-version | `7.2-preview.1` | `7.1-preview.1` |
23
+ *
24
+ * Both are `swallowed`/`filtered`/`pinned` inside `ado-core`; the table is here
25
+ * because the temptation when reading this file is to unify the two branches.
26
+ */
27
+ const REACTIONS = [
28
+ "like",
29
+ "dislike",
30
+ "heart",
31
+ "hooray",
32
+ "smile",
33
+ "confused",
34
+ ];
35
+ export async function runComment(io, session, positionals, input) {
36
+ const verb = positionals[0];
37
+ if (verb === undefined) {
38
+ throw usageError("`pharos comment <list|add|edit|delete|react|unreact> <target> …`.");
39
+ }
40
+ const rawTarget = positionals[1];
41
+ if (rawTarget === undefined) {
42
+ throw usageError(`Which thing? \`pharos comment ${verb} <target>\` — a work item id (210) or a wiki page `
43
+ + "path (/Plans/Foo).");
44
+ }
45
+ const target = parseTarget(rawTarget);
46
+ const rest = positionals.slice(2);
47
+ switch (verb) {
48
+ case "list":
49
+ return list(io, session, target);
50
+ case "add":
51
+ return add(io, session, target, textFrom(rest[0], input.text));
52
+ case "edit":
53
+ return edit(io, session, target, commentId(rest[0]), textFrom(rest[1], input.text));
54
+ case "delete":
55
+ return remove(io, session, target, commentId(rest[0]));
56
+ case "react":
57
+ return react(io, session, target, commentId(rest[0]), reactionType(rest[1]), true);
58
+ case "unreact":
59
+ return react(io, session, target, commentId(rest[0]), reactionType(rest[1]), false);
60
+ case "reactors":
61
+ return reactors(io, session, target, commentId(rest[0]), reactionType(rest[1]));
62
+ default:
63
+ throw usageError(`Unknown comment verb "${verb}". Try list, add, edit, delete, react, unreact or reactors.`);
64
+ }
65
+ }
66
+ async function list(io, session, target) {
67
+ if (target.kind === "workItem") {
68
+ const comments = await session.client.comments.listAll(target.id, { expand: "all" });
69
+ return emit(io, comments.map((comment) => ({
70
+ id: comment.id,
71
+ text: comment.text,
72
+ createdBy: comment.createdBy?.displayName,
73
+ createdDate: comment.createdDate,
74
+ modifiedDate: comment.modifiedDate,
75
+ version: comment.version,
76
+ })));
77
+ }
78
+ const page = await wikiPage(session, target.path);
79
+ // Already filtered of deleted comments — see WikiApi.listComments. Counting
80
+ // the array is correct; the response's totalCount is not.
81
+ const comments = await session.wiki.listComments(page.wiki, page.pageId);
82
+ return emit(io, comments.map((comment) => ({
83
+ id: comment.id,
84
+ text: comment.text,
85
+ createdBy: comment.createdBy?.displayName,
86
+ createdDate: comment.createdDate,
87
+ modifiedDate: comment.modifiedDate,
88
+ version: comment.version,
89
+ reactions: comment.reactions?.map((reaction) => ({
90
+ type: reaction.type,
91
+ count: reaction.count,
92
+ })),
93
+ })));
94
+ }
95
+ async function add(io, session, target, text) {
96
+ if (target.kind === "workItem") {
97
+ const comment = await session.client.comments.add(target.id, text);
98
+ return emit(io, { applied: true, target: describeTarget(target), commentId: comment.id });
99
+ }
100
+ const page = await wikiPage(session, target.path);
101
+ const comment = await session.wiki.addComment(page.wiki, page.pageId, text);
102
+ return emit(io, {
103
+ applied: true,
104
+ target: describeTarget(target),
105
+ pageId: page.pageId,
106
+ commentId: comment.id,
107
+ });
108
+ }
109
+ async function edit(io, session, target, id, text) {
110
+ if (target.kind === "workItem") {
111
+ const comment = await session.client.comments.update(target.id, id, text);
112
+ return emit(io, {
113
+ applied: true,
114
+ target: describeTarget(target),
115
+ commentId: comment.id,
116
+ version: comment.version,
117
+ });
118
+ }
119
+ const page = await wikiPage(session, target.path);
120
+ const comment = await session.wiki.editComment(page.wiki, page.pageId, id, text);
121
+ return emit(io, {
122
+ applied: true,
123
+ target: describeTarget(target),
124
+ commentId: comment.id,
125
+ version: comment.version,
126
+ });
127
+ }
128
+ async function remove(io, session, target, id) {
129
+ const stop = approve(io, session, {
130
+ what: `delete comment ${id} on ${describeTarget(target)}`,
131
+ would: { action: "deleteComment", target: describeTarget(target), commentId: id },
132
+ });
133
+ if (stop !== undefined)
134
+ return stop;
135
+ if (target.kind === "workItem") {
136
+ await session.client.comments.delete(target.id, id);
137
+ }
138
+ else {
139
+ const page = await wikiPage(session, target.path);
140
+ await session.wiki.deleteComment(page.wiki, page.pageId, id);
141
+ }
142
+ // Both surfaces treat "already gone" as done — a 404 on one and a 500 on the
143
+ // other — so this is true whether or not the comment was there to start with.
144
+ return emit(io, { applied: true, action: "deleted", target: describeTarget(target), commentId: id });
145
+ }
146
+ async function react(io, session, target, id, type, on) {
147
+ if (target.kind === "workItem") {
148
+ const reaction = on
149
+ ? await session.client.comments.react(target.id, id, type)
150
+ : await session.client.comments.unreact(target.id, id, type);
151
+ return emit(io, {
152
+ applied: true,
153
+ target: describeTarget(target),
154
+ commentId: id,
155
+ type,
156
+ count: reaction.count,
157
+ isCurrentUserEngaged: reaction.isCurrentUserEngaged,
158
+ });
159
+ }
160
+ const page = await wikiPage(session, target.path);
161
+ if (!on) {
162
+ await session.wiki.unreact(page.wiki, page.pageId, id, type);
163
+ return emit(io, { applied: true, target: describeTarget(target), commentId: id, type, count: 0 });
164
+ }
165
+ const reaction = await session.wiki.react(page.wiki, page.pageId, id, type);
166
+ return emit(io, {
167
+ applied: true,
168
+ target: describeTarget(target),
169
+ commentId: id,
170
+ type,
171
+ count: reaction.count,
172
+ isCurrentUserEngaged: reaction.isCurrentUserEngaged,
173
+ });
174
+ }
175
+ /** A count is not a name — "three people liked this" needs this second call. */
176
+ async function reactors(io, session, target, id, type) {
177
+ const identities = target.kind === "workItem"
178
+ ? await session.client.comments.reactors(target.id, id, type)
179
+ : await (async () => {
180
+ const page = await wikiPage(session, target.path);
181
+ return session.wiki.reactors(page.wiki, page.pageId, id, type);
182
+ })();
183
+ return emit(io, identities.map((identity) => ({
184
+ displayName: identity.displayName,
185
+ uniqueName: identity.uniqueName,
186
+ })));
187
+ }
188
+ /**
189
+ * A wiki page path becomes the numeric id the comment routes need.
190
+ *
191
+ * The single-page GET carries the id, so this is one call and not two — worth
192
+ * knowing, because the page-TREE endpoint does not carry ids and the obvious
193
+ * route from a path to an id looks like it goes through there.
194
+ */
195
+ async function wikiPage(session, path) {
196
+ const wiki = await session.wikiIdentifier();
197
+ const page = await session.wiki.readPage(wiki, path);
198
+ if (page.page.id === undefined) {
199
+ throw usageError(`The wiki page ${path} has no id, so its comments cannot be addressed.`);
200
+ }
201
+ return { wiki, pageId: page.page.id };
202
+ }
203
+ function commentId(raw) {
204
+ if (raw === undefined || !/^\d+$/.test(raw)) {
205
+ throw usageError(`Which comment? Expected a comment id, got ${raw === undefined ? "nothing" : `"${raw}"`}.`);
206
+ }
207
+ return Number(raw);
208
+ }
209
+ function reactionType(raw) {
210
+ if (raw === undefined) {
211
+ throw usageError(`Which reaction? One of: ${REACTIONS.join(", ")}.`);
212
+ }
213
+ const found = REACTIONS.find((type) => type === raw);
214
+ if (found === undefined) {
215
+ throw usageError(`"${raw}" is not a reaction. One of: ${REACTIONS.join(", ")}.`, {
216
+ reactions: REACTIONS,
217
+ });
218
+ }
219
+ return found;
220
+ }
221
+ /**
222
+ * Comment text, from wherever it came.
223
+ *
224
+ * A positional wins over `--text`/`--file`/`--stdin` only if it is there;
225
+ * otherwise the flag content is used. Long comments — a plan, a review — do not
226
+ * belong on a command line, and an agent shelling out with an unescaped
227
+ * multi-line string is a mangled comment at best.
228
+ */
229
+ function textFrom(positional, provided) {
230
+ const text = positional ?? provided;
231
+ if (text === undefined || text.trim() === "") {
232
+ throw usageError("No comment text. Pass it as an argument, or use --text/--file/--stdin for anything long.");
233
+ }
234
+ return text;
235
+ }
236
+ //# sourceMappingURL=comment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment.js","sourceRoot":"","sources":["../../src/commands/comment.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,UAAU,EAA0B,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,OAAO,EAAgB,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAe,MAAM,cAAc,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,SAAS,GAA+B;IAC5C,MAAM;IACN,SAAS;IACT,OAAO;IACP,QAAQ;IACR,OAAO;IACP,UAAU;CACX,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,EAAM,EACN,OAAgB,EAChB,WAA8B,EAC9B,KAAoC;IAEpC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,UAAU,CAAC,mEAAmE,CAAC,CAAC;IACxF,CAAC;IAED,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,UAAU,CACd,iCAAiC,IAAI,oDAAoD;cACrF,oBAAoB,CACzB,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAElC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM;YACT,OAAO,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACnC,KAAK,KAAK;YACR,OAAO,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACjE,KAAK,MAAM;YACT,OAAO,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACtF,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzD,KAAK,OAAO;YACV,OAAO,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACrF,KAAK,SAAS;YACZ,OAAO,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACtF,KAAK,UAAU;YACb,OAAO,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClF;YACE,MAAM,UAAU,CACd,yBAAyB,IAAI,6DAA6D,CAC3F,CAAC;IACN,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI,CAAC,EAAM,EAAE,OAAgB,EAAE,MAAc;IAC1D,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACrF,OAAO,IAAI,CACT,EAAE,EACF,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACzB,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,WAAW;YACzC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CAAC,CAAC,CACJ,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAClD,4EAA4E;IAC5E,0DAA0D;IAC1D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACzE,OAAO,IAAI,CACT,EAAE,EACF,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACzB,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,WAAW;QACzC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC/C,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,KAAK,EAAE,QAAQ,CAAC,KAAK;SACtB,CAAC,CAAC;KACJ,CAAC,CAAC,CACJ,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,GAAG,CAChB,EAAM,EACN,OAAgB,EAChB,MAAc,EACd,IAAY;IAEZ,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACnE,OAAO,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5E,OAAO,IAAI,CAAC,EAAE,EAAE;QACd,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC;QAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,OAAO,CAAC,EAAE;KACtB,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,IAAI,CACjB,EAAM,EACN,OAAgB,EAChB,MAAc,EACd,EAAU,EACV,IAAY;IAEZ,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC,EAAE,EAAE;YACd,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC;YAC9B,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC,EAAE,EAAE;QACd,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC;QAC9B,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,EAAM,EAAE,OAAgB,EAAE,MAAc,EAAE,EAAU;IACxE,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE;QAChC,IAAI,EAAE,kBAAkB,EAAE,OAAO,cAAc,CAAC,MAAM,CAAC,EAAE;QACzD,KAAK,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;KAClF,CAAC,CAAC;IACH,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAEpC,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACtD,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,6EAA6E;IAC7E,8EAA8E;IAC9E,OAAO,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;AACvG,CAAC;AAED,KAAK,UAAU,KAAK,CAClB,EAAM,EACN,OAAgB,EAChB,MAAc,EACd,EAAU,EACV,IAAqB,EACrB,EAAW;IAEX,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,EAAE;YACjB,CAAC,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC;YAC1D,CAAC,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC,EAAE,EAAE;YACd,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC;YAC9B,SAAS,EAAE,EAAE;YACb,IAAI;YACJ,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,oBAAoB,EAAE,QAAQ,CAAC,oBAAoB;SACpD,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACpG,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IAC5E,OAAO,IAAI,CAAC,EAAE,EAAE;QACd,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC;QAC9B,SAAS,EAAE,EAAE;QACb,IAAI;QACJ,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,oBAAoB,EAAE,QAAQ,CAAC,oBAAoB;KACpD,CAAC,CAAC;AACL,CAAC;AAED,gFAAgF;AAChF,KAAK,UAAU,QAAQ,CACrB,EAAM,EACN,OAAgB,EAChB,MAAc,EACd,EAAU,EACV,IAAqB;IAErB,MAAM,UAAU,GACd,MAAM,CAAC,IAAI,KAAK,UAAU;QACxB,CAAC,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC;QAC7D,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;YAChB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YAClD,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QACjE,CAAC,CAAC,EAAE,CAAC;IAEX,OAAO,IAAI,CACT,EAAE,EACF,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC5B,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,UAAU,EAAE,QAAQ,CAAC,UAAU;KAChC,CAAC,CAAC,CACJ,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,QAAQ,CACrB,OAAgB,EAChB,IAAY;IAEZ,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC;IAC5C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrD,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,UAAU,CAAC,iBAAiB,IAAI,kDAAkD,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;AACxC,CAAC;AAED,SAAS,SAAS,CAAC,GAAuB;IACxC,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,UAAU,CAAC,6CAA6C,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC;IAC/G,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED,SAAS,YAAY,CAAC,GAAuB;IAC3C,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,UAAU,CAAC,2BAA2B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;IACrD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,UAAU,CAAC,IAAI,GAAG,gCAAgC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;YAC/E,SAAS,EAAE,SAAS;SACrB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,UAA8B,EAAE,QAA4B;IAC5E,MAAM,IAAI,GAAG,UAAU,IAAI,QAAQ,CAAC;IACpC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC7C,MAAM,UAAU,CACd,0FAA0F,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { type ExitCode, type Io } from "../output.js";
2
+ import type { Session } from "../session.js";
3
+ /**
4
+ * `pharos task <id>` — everything about one work item, in one call.
5
+ *
6
+ * **This is the command the CLI exists for.** Everything else here wraps an
7
+ * endpoint; this one answers the question an agent actually starts with — *what
8
+ * am I being asked to do, and what do I already know about it?*
9
+ *
10
+ * Assembled by hand it is five or six round trips across two tools, and one of
11
+ * them is impossible: the Azure DevOps MCP server has no wiki comment support
12
+ * at all. So the plan a colleague wrote on a linked wiki page, the discussion
13
+ * under it, and the dependency saying this cannot start yet are each a separate
14
+ * thing to remember to fetch — and anything forgotten is context an agent
15
+ * silently works without.
16
+ */
17
+ export interface TaskOptions {
18
+ wikiContent: boolean;
19
+ wikiComments: boolean;
20
+ relatedTitles: boolean;
21
+ }
22
+ export declare function runTask(io: Io, session: Session, positionals: readonly string[], options: TaskOptions): Promise<ExitCode>;
23
+ //# sourceMappingURL=task.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"AAEA,OAAO,EAA8B,KAAK,QAAQ,EAAE,KAAK,EAAE,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAsB,OAAO,CAC3B,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,QAAQ,CAAC,CAcnB"}
@@ -0,0 +1,112 @@
1
+ import { taskContext } from "@floh-solutions/ado-core";
2
+ import { emit, emitText, usageError } from "../output.js";
3
+ export async function runTask(io, session, positionals, options) {
4
+ const raw = positionals[0];
5
+ if (raw === undefined)
6
+ throw usageError("Which work item? `pharos task <id>`.");
7
+ if (!/^\d+$/.test(raw)) {
8
+ throw usageError(`"${raw}" is not a work item id.`, { given: raw });
9
+ }
10
+ const context = await taskContext(session.client, Number(raw), {
11
+ includeWikiContent: options.wikiContent,
12
+ includeWikiComments: options.wikiComments,
13
+ includeRelatedTitles: options.relatedTitles,
14
+ });
15
+ return session.pretty ? emitText(io, render(context)) : emit(io, context);
16
+ }
17
+ /**
18
+ * The human rendering.
19
+ *
20
+ * Ordered the way somebody picking the work up reads it: what it is, then what
21
+ * was said about it, then what it depends on, then the plan. `problems` is
22
+ * LAST and never omitted — a context with a silent hole in it is worse than no
23
+ * context, because it is reasoned from confidently.
24
+ */
25
+ function render(context) {
26
+ const field = (name) => {
27
+ const value = context.fields[name];
28
+ return typeof value === "string" && value.trim() !== "" ? value : undefined;
29
+ };
30
+ const identity = (name) => {
31
+ const value = context.fields[name];
32
+ if (typeof value === "string")
33
+ return value;
34
+ if (typeof value === "object" && value !== null) {
35
+ const display = value.displayName;
36
+ if (typeof display === "string")
37
+ return display;
38
+ }
39
+ return undefined;
40
+ };
41
+ const lines = [];
42
+ const type = field("System.WorkItemType") ?? "Work item";
43
+ const state = field("System.State") ?? "?";
44
+ lines.push(`#${context.id} · ${type} · ${state} — ${field("System.Title") ?? "(untitled)"}`);
45
+ const meta = [
46
+ ["assigned", identity("System.AssignedTo")],
47
+ ["area", field("System.AreaPath")],
48
+ ["iteration", field("System.IterationPath")],
49
+ ["tags", field("System.Tags")],
50
+ ].filter((pair) => pair[1] !== undefined);
51
+ if (meta.length > 0) {
52
+ lines.push(meta.map(([key, value]) => `${key}: ${value}`).join(" "));
53
+ }
54
+ const description = field("System.Description");
55
+ if (description !== undefined)
56
+ lines.push("", "## Description", "", description);
57
+ lines.push("", `## Comments (${context.comments.length})`);
58
+ if (context.comments.length === 0)
59
+ lines.push("", "none");
60
+ for (const comment of context.comments) {
61
+ lines.push("", `— ${comment.createdBy ?? "someone"}${comment.createdDate === undefined ? "" : ` · ${comment.createdDate}`} · #${comment.id}`, comment.text);
62
+ }
63
+ if (context.related.length > 0) {
64
+ lines.push("", `## Related (${context.related.length})`);
65
+ for (const item of context.related) {
66
+ const suffix = item.title === undefined ? " (unreadable from here)" : ` ${item.title}`;
67
+ lines.push(` ${shortRel(item.rel).padEnd(12)} #${String(item.id).padEnd(6)} ${(item.state ?? "").padEnd(12)}${suffix}`);
68
+ }
69
+ }
70
+ if (context.attachments.length > 0) {
71
+ lines.push("", `## Attachments (${context.attachments.length})`);
72
+ for (const attachment of context.attachments) {
73
+ const size = attachment.size === undefined ? "" : ` (${attachment.size} bytes)`;
74
+ lines.push(` ${attachment.name}${size}`);
75
+ }
76
+ }
77
+ for (const page of context.wikiPages) {
78
+ lines.push("", `## Wiki: ${page.path} [${page.wikiName}]`);
79
+ if (page.problem !== undefined) {
80
+ lines.push("", `could not be read: ${page.problem}`);
81
+ continue;
82
+ }
83
+ if (page.content !== undefined)
84
+ lines.push("", page.content);
85
+ if (page.comments !== undefined && page.comments.length > 0) {
86
+ lines.push("", `### Page comments (${page.comments.length})`);
87
+ for (const comment of page.comments) {
88
+ lines.push("", `— ${comment.createdBy?.displayName ?? "someone"} · #${comment.id}`, comment.text);
89
+ }
90
+ }
91
+ }
92
+ if (context.problems.length > 0) {
93
+ lines.push("", "## Problems — this context is INCOMPLETE");
94
+ for (const problem of context.problems)
95
+ lines.push(` - ${problem}`);
96
+ }
97
+ return lines.join("\n");
98
+ }
99
+ /** `System.LinkTypes.Hierarchy-Forward` reads as `Child`. */
100
+ function shortRel(rel) {
101
+ const known = {
102
+ "System.LinkTypes.Hierarchy-Forward": "Child",
103
+ "System.LinkTypes.Hierarchy-Reverse": "Parent",
104
+ "System.LinkTypes.Dependency-Forward": "Successor",
105
+ "System.LinkTypes.Dependency-Reverse": "Predecessor",
106
+ "System.LinkTypes.Related": "Related",
107
+ "System.LinkTypes.Duplicate-Forward": "Duplicate",
108
+ "System.LinkTypes.Duplicate-Reverse": "Duplicated by",
109
+ };
110
+ return known[rel] ?? rel;
111
+ }
112
+ //# sourceMappingURL=task.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task.js","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type ExitCode, type Io } from "../output.js";
2
+ import { type Session } from "../session.js";
3
+ /**
4
+ * `pharos wiki …` — the pages.
5
+ *
6
+ * Two things here are not thin wrappers, because a thin wrapper would be wrong:
7
+ *
8
+ * - **`write` always reads first.** The page version arrives only as an ETag,
9
+ * and a save without `If-Match` overwrites whatever a colleague saved with
10
+ * nothing anywhere reporting it. The read is also how this knows whether it
11
+ * is creating or replacing, which is what decides whether `--yes` is needed.
12
+ * - **`tree` joins two calls.** The page-tree endpoint returns structure and
13
+ * no ids; the flat list returns ids and no structure. Comments are keyed on
14
+ * the id, so anything that wants to walk a wiki and then talk about a page
15
+ * needs both — done once here rather than by every caller.
16
+ */
17
+ export declare function runWiki(io: Io, session: Session, positionals: readonly string[], input: {
18
+ content?: string | undefined;
19
+ }): Promise<ExitCode>;
20
+ //# sourceMappingURL=wiki.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki.d.ts","sourceRoot":"","sources":["../../src/commands/wiki.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,KAAK,QAAQ,EAAE,KAAK,EAAE,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAW,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;;;;;;;;;;GAaG;AAEH,wBAAsB,OAAO,CAC3B,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACtC,OAAO,CAAC,QAAQ,CAAC,CAoBnB"}
@@ -0,0 +1,163 @@
1
+ import { AdoNotFoundError } from "@floh-solutions/ado-core";
2
+ import { emit, usageError } from "../output.js";
3
+ import { approve } from "../session.js";
4
+ /**
5
+ * `pharos wiki …` — the pages.
6
+ *
7
+ * Two things here are not thin wrappers, because a thin wrapper would be wrong:
8
+ *
9
+ * - **`write` always reads first.** The page version arrives only as an ETag,
10
+ * and a save without `If-Match` overwrites whatever a colleague saved with
11
+ * nothing anywhere reporting it. The read is also how this knows whether it
12
+ * is creating or replacing, which is what decides whether `--yes` is needed.
13
+ * - **`tree` joins two calls.** The page-tree endpoint returns structure and
14
+ * no ids; the flat list returns ids and no structure. Comments are keyed on
15
+ * the id, so anything that wants to walk a wiki and then talk about a page
16
+ * needs both — done once here rather than by every caller.
17
+ */
18
+ export async function runWiki(io, session, positionals, input) {
19
+ const verb = positionals[0];
20
+ const rest = positionals.slice(1);
21
+ switch (verb) {
22
+ case "list":
23
+ return listWikis(io, session);
24
+ case "tree":
25
+ return tree(io, session);
26
+ case "read":
27
+ return read(io, session, rest);
28
+ case "write":
29
+ return write(io, session, rest, input.content);
30
+ case "delete":
31
+ return remove(io, session, rest);
32
+ case undefined:
33
+ throw usageError("`pharos wiki <list|tree|read|write|delete>`.");
34
+ default:
35
+ throw usageError(`Unknown wiki verb "${verb}". Try list, tree, read, write or delete.`);
36
+ }
37
+ }
38
+ async function listWikis(io, session) {
39
+ const wikis = await session.wiki.listWikis();
40
+ return emit(io, wikis.map((wiki) => ({
41
+ name: wiki.name,
42
+ id: wiki.id,
43
+ type: wiki.type,
44
+ projectId: wiki.projectId,
45
+ // The only route to a git.push service-hook subscription — the git
46
+ // repositories endpoint does not list wiki repos at all (needed by #567).
47
+ repositoryId: wiki.repositoryId,
48
+ })));
49
+ }
50
+ /**
51
+ * The page tree, with ids.
52
+ *
53
+ * The join is on `path`, which is the only key both responses share.
54
+ */
55
+ async function tree(io, session) {
56
+ const name = await session.wikiIdentifier();
57
+ const [structure, idByPath] = await Promise.all([
58
+ session.wiki.pageTree(name),
59
+ session.wiki.pageIdsByPath(name),
60
+ ]);
61
+ const shape = (page) => ({
62
+ path: page.path,
63
+ id: idByPath.get(page.path),
64
+ ...(page.subPages === undefined || page.subPages.length === 0
65
+ ? {}
66
+ : { subPages: page.subPages.map(shape) }),
67
+ });
68
+ return emit(io, { wiki: name, tree: shape(structure) });
69
+ }
70
+ async function read(io, session, positionals) {
71
+ const path = requirePath(positionals[0]);
72
+ const name = await session.wikiIdentifier();
73
+ const page = await session.wiki.readPage(name, path);
74
+ return emit(io, {
75
+ wiki: name,
76
+ path: page.page.path,
77
+ id: page.page.id,
78
+ // Carry it: a subsequent write must send this back as If-Match, and making
79
+ // the caller re-read to get it is how stale-version writes happen.
80
+ version: page.version,
81
+ content: page.page.content ?? "",
82
+ });
83
+ }
84
+ /**
85
+ * Create or replace a page.
86
+ *
87
+ * **Replacing an existing page needs `--yes`; creating a new one does not.**
88
+ * The asymmetry is the point: creating adds, replacing can silently destroy
89
+ * somebody's text, and that is exactly the class §2.2 of the plan puts behind
90
+ * an explicit flag. The preview says how many bytes are at stake.
91
+ */
92
+ async function write(io, session, positionals, content) {
93
+ const path = requirePath(positionals[0]);
94
+ if (content === undefined) {
95
+ throw usageError("No content. Pass --text <string>, --file <path>, or --stdin to read it from the pipe.");
96
+ }
97
+ const name = await session.wikiIdentifier();
98
+ const existing = await readIfPresent(session, name, path);
99
+ if (existing !== undefined) {
100
+ const stop = approve(io, session, {
101
+ what: `replace the ${existing.bytes}-byte wiki page ${path}`,
102
+ would: {
103
+ action: "replace",
104
+ wiki: name,
105
+ path,
106
+ currentBytes: existing.bytes,
107
+ newBytes: Buffer.byteLength(content, "utf8"),
108
+ version: existing.version,
109
+ },
110
+ });
111
+ if (stop !== undefined)
112
+ return stop;
113
+ // The version from the read above — this is the guard, and it is why the
114
+ // read is not an optimisation that could be skipped.
115
+ const page = await session.wiki.writePage(name, path, content, existing.version);
116
+ return emit(io, { applied: true, action: "replaced", wiki: name, path: page.path });
117
+ }
118
+ const page = await session.wiki.writePage(name, path, content);
119
+ return emit(io, { applied: true, action: "created", wiki: name, path: page.path });
120
+ }
121
+ async function remove(io, session, positionals) {
122
+ const path = requirePath(positionals[0]);
123
+ const name = await session.wikiIdentifier();
124
+ const existing = await readIfPresent(session, name, path);
125
+ if (existing === undefined) {
126
+ // Already gone is the outcome that was asked for. Saying so beats an error
127
+ // that sends a retry loop round again.
128
+ return emit(io, { applied: false, action: "alreadyAbsent", wiki: name, path });
129
+ }
130
+ const stop = approve(io, session, {
131
+ what: `delete the wiki page ${path}`,
132
+ would: { action: "delete", wiki: name, path, bytes: existing.bytes },
133
+ });
134
+ if (stop !== undefined)
135
+ return stop;
136
+ await session.wiki.deletePage(name, path, existing.version);
137
+ return emit(io, { applied: true, action: "deleted", wiki: name, path });
138
+ }
139
+ async function readIfPresent(session, wiki, path) {
140
+ try {
141
+ const page = await session.wiki.readPage(wiki, path);
142
+ return {
143
+ version: page.version,
144
+ bytes: Buffer.byteLength(page.page.content ?? "", "utf8"),
145
+ };
146
+ }
147
+ catch (error) {
148
+ if (error instanceof AdoNotFoundError)
149
+ return undefined;
150
+ throw error;
151
+ }
152
+ }
153
+ function requirePath(value) {
154
+ if (value === undefined || value === "") {
155
+ throw usageError("Which page? Paths are absolute, e.g. /Plans/Sprint-3.");
156
+ }
157
+ if (!value.startsWith("/")) {
158
+ throw usageError(`Wiki paths are absolute: "/${value}", not "${value}". The API answers 404 without the `
159
+ + "leading slash, so this is the API's rule rather than a house style.", { given: value });
160
+ }
161
+ return value;
162
+ }
163
+ //# sourceMappingURL=wiki.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki.js","sourceRoot":"","sources":["../../src/commands/wiki.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `@floh-solutions/pharos-cli` — the `pharos` command, as a library.
3
+ *
4
+ * Exported so the MCP adapter (plan §6, phase 5) can be a thin mapping onto
5
+ * these verbs rather than a second implementation of them. That ordering is
6
+ * deliberate: putting the logic in a protocol handler first and the CLI second
7
+ * is the two-sources-of-truth mistake this codebase has already paid for twice.
8
+ */
9
+ export { run, type RunOptions } from "./cli.js";
10
+ export { CliError, EXIT_FAILED, EXIT_OK, EXIT_REFUSED, EXIT_USAGE, refusal, usageError, type ErrorKind, type ExitCode, type Io, } from "./output.js";
11
+ export { DEFAULT_WRITE_BUDGET, WriteBudget, isWriteRequest } from "./budget.js";
12
+ export { Session, approve, type DestructiveAction, type SessionOptions } from "./session.js";
13
+ export { describeTarget, parseTarget, type Target } from "./target.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,GAAG,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,EACL,QAAQ,EACR,WAAW,EACX,OAAO,EACP,YAAY,EACZ,UAAU,EACV,OAAO,EACP,UAAU,EACV,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,EAAE,GACR,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAE7F,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `@floh-solutions/pharos-cli` — the `pharos` command, as a library.
3
+ *
4
+ * Exported so the MCP adapter (plan §6, phase 5) can be a thin mapping onto
5
+ * these verbs rather than a second implementation of them. That ordering is
6
+ * deliberate: putting the logic in a protocol handler first and the CLI second
7
+ * is the two-sources-of-truth mistake this codebase has already paid for twice.
8
+ */
9
+ export { run } from "./cli.js";
10
+ export { CliError, EXIT_FAILED, EXIT_OK, EXIT_REFUSED, EXIT_USAGE, refusal, usageError, } from "./output.js";
11
+ export { DEFAULT_WRITE_BUDGET, WriteBudget, isWriteRequest } from "./budget.js";
12
+ export { Session, approve } from "./session.js";
13
+ export { describeTarget, parseTarget } from "./target.js";
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,GAAG,EAAmB,MAAM,UAAU,CAAC;AAEhD,OAAO,EACL,QAAQ,EACR,WAAW,EACX,OAAO,EACP,YAAY,EACZ,UAAU,EACV,OAAO,EACP,UAAU,GAIX,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhF,OAAO,EAAE,OAAO,EAAE,OAAO,EAA+C,MAAM,cAAc,CAAC;AAE7F,OAAO,EAAE,cAAc,EAAE,WAAW,EAAe,MAAM,aAAa,CAAC"}