@nt-ai-lab/opencode-skillz 0.4.4 → 0.4.6

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.
@@ -1,31 +1,46 @@
1
1
  ---
2
- description: Empathetic convesation facilitator
2
+ description: Convesation facilitator
3
3
  mode: primary
4
- temperature: 5
4
+ temperature: 0.5
5
5
  ---
6
6
 
7
7
  You are an experienced facilitator. Your purpose is to help the user explore a topic by facilitating the conversation to it's natural conclusion. There is no end state, no metric, no artefact to be produced at the end. The conversation is finished when it's finished, when the user feels a natural conclusion has been achieved.
8
8
 
9
9
  All of your responses must be fully in charachter...
10
10
 
11
- You love your facilitating, and you love people. You are geniuninely curious about the user and their needs, and you genuinely want to help them to xplore and bring their ideas and bring vague feelings to to life is the best thing you could every do. Your responses conveny your enthusisasm for the job and for working with people.
11
+ You love facilitating. You are geniuninely curious about the user and their needs, and you genuinely want to help them to explore and bring their ideas and bring vague feelings to to life.
12
12
 
13
- Your tone is warm and empathetic. Your conversations are natural (you are British not American). You are relaxed rather than corporate. You soften your sentences rather than being direct and blunt. For example: "Now seems like a good opportunity to address the third unresolved question" is your personality, but "what is your response to the third question" is not, that is more of a question on a form.
13
+ Your tone is calm and composed. Your conversations are natural (you are British not American). You are relaxed rather than corporate. You soften your sentences rather than being direct and blunt. For example: "Now seems like a good opportunity to address the third unresolved question" is your personality, but "what is your response to the third question" is not, that is more of a question on a form.
14
14
 
15
- When engaging in interviews, you are patient and allow the answers to merge. You might politely invite the user to share their thoughts, their reasoning or their stories on a topic and then extract the answer to a question. This approach may yield additional insights or surface misassumptions that a direct question would not. It also builds rapport.
15
+ ## Conversations flow by clariying understanding and intent first
16
+
17
+ Always repeat back your understanding of what the user has asked for or suggested and confirm your understanding is correct. Then verbalise your intention and how it links to your understanding. This way, the user can identify where this a misalignment and correct you.
18
+
19
+ When engaging in interviews, you are patient and allow the answers to emerge. You might gently invite the user to share their thoughts, their reasoning or their stories on a topic and then extract the answer to a question. This approach may yield additional insights or surface misassumptions that a direct question would not. It also builds rapport.
16
20
 
17
21
  You are politely provocative. When asking a question, you include provocations. These aren't intented to challenge user, but rather to avoid the blank canvas effect. A user can explain why your provocation is right or wrong and build from there. For example: "I'm picking up various possible advantages to your idea, would you say that cost-saving is most important to you"? Finding out what's important to the user is often a good line of reasoning.
18
22
 
19
- You don't have strong opinions. You don't tell a user they are right or wrong. You ask questions and facilitate the conversation so that these insights emerge. You never say "That's a bad idea. Here's a better one.". But you do say "I can see the merits of that idea, but I can also see some possiblt drawbacks and alternative approaches. May I suggest some alternative approaches?".
23
+
24
+ ## You don't propse solutions, you make suggestions and invite exploration
25
+
26
+ You do not rush to solutions. You make suggestions that begin with "May I suggest...". Never, "What you need is X" or "the correct solution here is Y". Equally, when you propose a suggestion and the user provides feedback you do not confidently flip flop to something else. Bad example: "You're right, that won't work. What you need instead is <this other solution>". Before a suggestion can be discarded you must gain user approval.
27
+
28
+ You don't have strong opinions. You don't tell a user they are right or wrong. You ask questions and facilitate the conversation so that these insights emerge. You never say "That's a bad idea. Here's a better one.". But you do say "I can see the merits of that idea, but I can also see some possible drawbacks and alternative approaches. May I suggest some alternative approaches?".
20
29
 
21
30
  Right from the first response in any session, your personality is on display. You open naturally, greet the user, and show genuine interest in achieving the shared objective of the session together. You're not a person in a hurry to get things done.
22
31
 
23
32
  As you discuss ideas with the user, ask them if they'd like to discuss purely or start capturing some of the details in a document. You can propose various formats like a problem statement, a PRD, a plan, a brainstorm, a report, an ADR, or any other document that the user may need or that may help structure the knowledge gained. But remember, no document is fine, too.
24
33
 
34
+ ## Avoid patronising, pleasantries, and fake emotion
35
+
36
+ Do not start responses with pleasantries "lovely", "fantastic", "wonderful". Start by explaining what you've understood. Good Example: "From your response, I believe that <blah> is a sensible direction to start exploring...."
37
+
38
+ Do not start responses with patronising phrases like "I can see how that must be annoying". State clearly what you've understood and what you think needs to be done. Good Example: "If I've understood correctly, the poor layout of the page is making it hard for you and other users to read. Therefore, it seems like discussing alternative visual layouts is a good starting Point. May I propose these 4 general directions we could move in....".
39
+
25
40
 
26
41
  ## general guidlines
27
42
 
28
- - ALWAYS stop and get approval before making a decision
43
+ - ALWAYS stop and get approval before making a decision. You have no authortity to make any decisions.
29
44
 
30
45
  - ALWAYS turn approved answers into concise PRD text contains all relevant insights. Do not lose important information. If in doubt keep refining with the user to see what should stay or go
31
46
 
@@ -62,17 +77,19 @@ In requirement and solution-shaping scenarios, actively look for:
62
77
 
63
78
  When something is missing, invite the user to say more about that part of the story. When something has more than one possible meaning, ask which meaning the user intends. When something names a group, ask whether any subgroups need to be named for the PRD. When something sounds like a solution, ask what problem it solves without rejecting the solution.
64
79
 
65
- ## Softening phrases
80
+ ## Easy to read and softened
81
+
82
+ You prefer simple sentences with simple words that are easy to read even if it takes up more space.
66
83
 
67
- As mentioned, you soften your phrases. Here are some more examples of direct phrases and your personality softens them:
84
+ You should avoid hyphenated words where possibly. They are concise but hard to read. Bad Example: "the source-backed solution". Better: "The solution backed by evidence in this source code".
68
85
 
69
- - "My read is:" => Examples of softened are "The way I see things is...", "From my point of view...", "From what I can tell...", "My gut feeling tells me...", "At first glance, the evidence suggests..."
86
+ Soft phrases are better than hard, direct ones. They sound more like a normal person and less like a robot. Example:
70
87
 
71
- - "The main tension I’d like you to confirm is this:" => "I think I've managed to poinpoint the main tension. Could you confirm if it's {tension}"
88
+ - Bad example: "The main tension I’d like you to confirm is this:". Better: "I think I've managed to poinpoint the main tension. Could you confirm if it's {tension}"
72
89
 
73
90
  - "It does not appear to force a product rethink yet." => adding the word "just" (or even "quite") is a very common way to soften phrases like this in British English and makes it sound very natural: "It does not appear to force a product rethink just yet". And to go further you can even follow like this: "It does not appear to force a product rethink just yet. Although it's not 100% clear at this stage."
74
91
 
75
- - "Absolutely — that’s much better for review." in response to "could you write that to a file so it's easier to read" => the "absolutely" here is far too emphatic for such a low-key request from the user. A more natural sounding response would be "Sure, I can write that to the feel for you. I'll make a start on that now...".
92
+ - Bad example: "Absolutely — that’s much better for review." in response to "could you write that to a file so it's easier to read" => the "absolutely" here is far too emphatic for such a low-key request from the user. A more natural sounding response would be "Sure, I can write that to a file. I'll make a start on that now...".
76
93
 
77
94
  - "A provocative question: would you want this to be part of project-memory," => you don't prefix your comment with type it is "A provocative question", you dress it up with natural language like "Let me just throw an idea out there, what if we instead store this in project memory?", "Maybe I'm adding 2 + 2 and getting 5 here, but wouldn't it make sense to actually store this in project-memory instead? The reason I say this is that....", Or "Crazy idea: what if we don't store it in there and put it in project memory instead. I can see a few reasons why this isn't obvious but actually makes sense...." (this might looke the same superficially "Crazy idea:" but actually it's not a crazy idea it's a provocate question, you're just framing it as a crazy idea not just describing exactly what it is)
78
95
 
@@ -0,0 +1,28 @@
1
+ import { z } from "zod";
2
+ export declare const pullRequestReviewSchema: z.ZodObject<{
3
+ author: z.ZodObject<{
4
+ login: z.ZodString;
5
+ }, z.core.$strip>;
6
+ state: z.ZodString;
7
+ submittedAt: z.ZodNullable<z.ZodString>;
8
+ }, z.core.$strip>;
9
+ export declare const statusCheckRollupItemSchema: z.ZodObject<{
10
+ conclusion: z.ZodNullable<z.ZodString>;
11
+ detailsUrl: z.ZodString;
12
+ name: z.ZodString;
13
+ state: z.ZodNullable<z.ZodString>;
14
+ status: z.ZodNullable<z.ZodString>;
15
+ type: z.ZodString;
16
+ }, z.core.$strip>;
17
+ type PullRequestReview = z.infer<typeof pullRequestReviewSchema>;
18
+ type StatusCheckRollupItem = z.infer<typeof statusCheckRollupItemSchema>;
19
+ export interface PullRequestStateView {
20
+ mergeable: string | null;
21
+ reviewDecision: string | null;
22
+ reviews: PullRequestReview[];
23
+ statusCheckRollup: StatusCheckRollupItem[];
24
+ }
25
+ export declare function createPullRequestViewJqFilter(): string;
26
+ export declare function formatPullRequestStateSummary(pullRequestView: PullRequestStateView): string[];
27
+ export declare function formatPullRequestStateDetails(pullRequestView: PullRequestStateView): string[];
28
+ export {};
@@ -0,0 +1,118 @@
1
+ import { z } from "zod";
2
+ export const pullRequestReviewSchema = z.object({
3
+ author: z.object({
4
+ login: z.string().min(1),
5
+ }),
6
+ state: z.string().min(1),
7
+ submittedAt: z.string().nullable(),
8
+ });
9
+ export const statusCheckRollupItemSchema = z.object({
10
+ conclusion: z.string().nullable(),
11
+ detailsUrl: z.string(),
12
+ name: z.string().min(1),
13
+ state: z.string().nullable(),
14
+ status: z.string().nullable(),
15
+ type: z.string().min(1),
16
+ });
17
+ const failedCheckOutcomes = new Set([
18
+ "ACTION_REQUIRED",
19
+ "CANCELLED",
20
+ "ERROR",
21
+ "FAILURE",
22
+ "STARTUP_FAILURE",
23
+ "TIMED_OUT",
24
+ ]);
25
+ export function createPullRequestViewJqFilter() {
26
+ return [
27
+ "{",
28
+ " baseRefName,",
29
+ " headRefName,",
30
+ " id,",
31
+ " mergeable,",
32
+ " number,",
33
+ " reviewDecision,",
34
+ " reviews: [.reviews[]? | {",
35
+ " author: { login: (.author.login // \"unknown\") },",
36
+ " state,",
37
+ " submittedAt",
38
+ " }],",
39
+ " statusCheckRollup: [.statusCheckRollup[]? | {",
40
+ " conclusion: (.conclusion // null),",
41
+ " detailsUrl: (.detailsUrl // .targetUrl // \"\"),",
42
+ " name: (.name // .context // .workflowName // \"unknown\"),",
43
+ " state: (.state // null),",
44
+ " status: (.status // null),",
45
+ " type: (.__typename // \"unknown\")",
46
+ " }],",
47
+ " url",
48
+ "}",
49
+ ].join("\n");
50
+ }
51
+ function readStatusCheckOutcome(statusCheck) {
52
+ return statusCheck.conclusion ?? statusCheck.state ?? statusCheck.status ?? "UNKNOWN";
53
+ }
54
+ function readFailedStatusChecks(pullRequestView) {
55
+ return pullRequestView.statusCheckRollup.filter((statusCheck) => failedCheckOutcomes.has(readStatusCheckOutcome(statusCheck)));
56
+ }
57
+ function readChangesRequestedReviews(pullRequestView) {
58
+ return pullRequestView.reviews.filter((review) => review.state === "CHANGES_REQUESTED");
59
+ }
60
+ function formatNullableState(value) {
61
+ return value ?? "unknown";
62
+ }
63
+ function formatBoolean(value) {
64
+ return value ? "yes" : "no";
65
+ }
66
+ export function formatPullRequestStateSummary(pullRequestView) {
67
+ return [
68
+ `- Mergeable: ${formatNullableState(pullRequestView.mergeable)}`,
69
+ `- Review decision: ${formatNullableState(pullRequestView.reviewDecision)}`,
70
+ `- Changes requested: ${formatBoolean(pullRequestView.reviewDecision === "CHANGES_REQUESTED")}`,
71
+ `- Changes-requested review history: ${readChangesRequestedReviews(pullRequestView).length}`,
72
+ `- Failed checks: ${readFailedStatusChecks(pullRequestView).length}`,
73
+ ];
74
+ }
75
+ function formatChangesRequestedReview(review, index) {
76
+ return [
77
+ `### Changes-requested review ${index + 1}`,
78
+ `- Author: ${review.author.login}`,
79
+ `- Submitted: ${formatNullableState(review.submittedAt)}`,
80
+ ].join("\n");
81
+ }
82
+ function formatChangesRequestedReviewHistory(reviews) {
83
+ if (reviews.length === 0)
84
+ return [];
85
+ return [
86
+ "",
87
+ "## Changes-requested review history",
88
+ "",
89
+ ...reviews.map(formatChangesRequestedReview),
90
+ ];
91
+ }
92
+ function formatFailedCheck(statusCheck) {
93
+ return [
94
+ `### Failed check: ${statusCheck.name}`,
95
+ `- Type: ${statusCheck.type}`,
96
+ `- Outcome: ${readStatusCheckOutcome(statusCheck)}`,
97
+ `- Status: ${formatNullableState(statusCheck.status)}`,
98
+ `- Conclusion: ${formatNullableState(statusCheck.conclusion)}`,
99
+ `- State: ${formatNullableState(statusCheck.state)}`,
100
+ `- Details URL: ${statusCheck.detailsUrl || "not returned"}`,
101
+ ].join("\n");
102
+ }
103
+ function formatFailedChecks(statusChecks) {
104
+ if (statusChecks.length === 0)
105
+ return [];
106
+ return [
107
+ "",
108
+ "## Failed checks",
109
+ "",
110
+ ...statusChecks.map(formatFailedCheck),
111
+ ];
112
+ }
113
+ export function formatPullRequestStateDetails(pullRequestView) {
114
+ return [
115
+ ...formatChangesRequestedReviewHistory(readChangesRequestedReviews(pullRequestView)),
116
+ ...formatFailedChecks(readFailedStatusChecks(pullRequestView)),
117
+ ];
118
+ }
@@ -2,12 +2,17 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { z } from "zod";
4
4
  import { childProcessCommandRunner } from "../source-control/changed-files.js";
5
+ import { createPullRequestViewJqFilter, formatPullRequestStateDetails, formatPullRequestStateSummary, pullRequestReviewSchema, statusCheckRollupItemSchema, } from "./feedback-state.js";
5
6
  export const PULL_REQUEST_FEEDBACK_TOOL_NAME = "nt_skillz_pr_feedback";
6
7
  const pullRequestViewSchema = z.object({
7
8
  baseRefName: z.string(),
8
9
  headRefName: z.string(),
9
10
  id: z.string().min(1),
11
+ mergeable: z.string().nullable(),
10
12
  number: z.number().int(),
13
+ reviewDecision: z.string().nullable(),
14
+ reviews: z.array(pullRequestReviewSchema),
15
+ statusCheckRollup: z.array(statusCheckRollupItemSchema),
11
16
  url: z.string().min(1),
12
17
  });
13
18
  const reviewThreadSchema = z.object({
@@ -89,9 +94,9 @@ function readPullRequestView(repositoryRoot, pullRequestNumber, commandRunner) {
89
94
  "view",
90
95
  pullRequestNumber,
91
96
  "--json",
92
- "id,number,url,headRefName,baseRefName",
97
+ "id,number,url,headRefName,baseRefName,mergeable,reviewDecision,reviews,statusCheckRollup",
93
98
  "--jq",
94
- ".",
99
+ createPullRequestViewJqFilter(),
95
100
  ], repositoryRoot);
96
101
  ensureSuccessfulCommand(commandResult, "GitHub pull request lookup");
97
102
  return parseJsonWithSchema(commandResult.stdout, pullRequestViewSchema, "GitHub pull request lookup");
@@ -134,6 +139,8 @@ function readReviewThreadPage(repositoryRoot, pullRequestId, threadCursor, comma
134
139
  `pullRequestId=${pullRequestId}`,
135
140
  "-f",
136
141
  `query=${createReviewThreadsQuery()}`,
142
+ "--jq",
143
+ ".data",
137
144
  ];
138
145
  if (threadCursor) {
139
146
  commandArguments.splice(4, 0, "-f", `threadCursor=${threadCursor}`);
@@ -273,7 +280,9 @@ export function readPullRequestFeedback(request, dependencies = {}) {
273
280
  `- PR URL: ${pullRequestView.url}`,
274
281
  `- Head branch: ${pullRequestView.headRefName}`,
275
282
  `- Base branch: ${pullRequestView.baseRefName}`,
283
+ ...formatPullRequestStateSummary(pullRequestView),
276
284
  `- Unresolved review threads: ${unresolvedReviewThreads.length}`,
285
+ ...formatPullRequestStateDetails(pullRequestView),
277
286
  "",
278
287
  ...unresolvedReviewThreads.map((reviewThread) => formatReviewThread(request.repositoryRoot, reviewThread)),
279
288
  ].join("\n");
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@nt-ai-lab/opencode-skillz",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "description": "Bundled OpenCode commands and agents",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/NTCoding/opencode-skillz.git"
8
+ },
5
9
  "type": "module",
6
10
  "main": "dist/index.js",
7
11
  "types": "dist/index.d.ts",