taskin 4.1.4 → 4.3.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 +46 -23
- package/dist/index.js +1135 -611
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -278,8 +278,8 @@ ${body}` : subject;
|
|
|
278
278
|
}
|
|
279
279
|
const lines = output.split("\n").filter((l) => l.trim());
|
|
280
280
|
for (const line of lines) {
|
|
281
|
-
const [added, removed,
|
|
282
|
-
if (added === void 0 || removed === void 0 ||
|
|
281
|
+
const [added, removed, path16] = line.split(" ");
|
|
282
|
+
if (added === void 0 || removed === void 0 || path16 === void 0) continue;
|
|
283
283
|
if (added === "-" || removed === "-") {
|
|
284
284
|
continue;
|
|
285
285
|
}
|
|
@@ -288,7 +288,7 @@ ${body}` : subject;
|
|
|
288
288
|
totalLinesAdded += linesAdded;
|
|
289
289
|
totalLinesRemoved += linesRemoved;
|
|
290
290
|
files.push({
|
|
291
|
-
path:
|
|
291
|
+
path: path16,
|
|
292
292
|
linesAdded,
|
|
293
293
|
linesRemoved,
|
|
294
294
|
changeType: "modified"
|
|
@@ -314,15 +314,15 @@ ${body}` : subject;
|
|
|
314
314
|
if (!output) {
|
|
315
315
|
return null;
|
|
316
316
|
}
|
|
317
|
-
const [added, removed,
|
|
318
|
-
if (added === void 0 || removed === void 0 ||
|
|
317
|
+
const [added, removed, path16] = output.split(" ");
|
|
318
|
+
if (added === void 0 || removed === void 0 || path16 === void 0) {
|
|
319
319
|
return null;
|
|
320
320
|
}
|
|
321
321
|
if (added === "-" || removed === "-") {
|
|
322
322
|
return null;
|
|
323
323
|
}
|
|
324
324
|
return {
|
|
325
|
-
path:
|
|
325
|
+
path: path16,
|
|
326
326
|
linesAdded: parseInt(added, 10),
|
|
327
327
|
linesRemoved: parseInt(removed, 10),
|
|
328
328
|
changeType: "modified"
|
|
@@ -493,8 +493,8 @@ var init_git_service = __esm({
|
|
|
493
493
|
}).trim();
|
|
494
494
|
if (files) {
|
|
495
495
|
taskFilePath = files.split("\n")[0] ?? null;
|
|
496
|
-
const { readFileSync:
|
|
497
|
-
taskFileContent =
|
|
496
|
+
const { readFileSync: readFileSync7 } = await import("fs");
|
|
497
|
+
taskFileContent = readFileSync7(`${this.cwd}/${taskFilePath}`, "utf-8");
|
|
498
498
|
}
|
|
499
499
|
} catch {
|
|
500
500
|
}
|
|
@@ -514,8 +514,8 @@ var init_git_service = __esm({
|
|
|
514
514
|
});
|
|
515
515
|
let committed = false;
|
|
516
516
|
if (taskFileContent && taskFilePath) {
|
|
517
|
-
const { writeFileSync:
|
|
518
|
-
|
|
517
|
+
const { writeFileSync: writeFileSync4 } = await import("fs");
|
|
518
|
+
writeFileSync4(`${this.cwd}/${taskFilePath}`, taskFileContent, "utf-8");
|
|
519
519
|
const message = buildTaskStatusCommitMessage({ taskId, status, ciSkipTag: this.ciSkipTag });
|
|
520
520
|
committed = await this.addAndCommit(taskPattern, message);
|
|
521
521
|
} else {
|
|
@@ -2737,6 +2737,610 @@ var init_src3 = __esm({
|
|
|
2737
2737
|
}
|
|
2738
2738
|
});
|
|
2739
2739
|
|
|
2740
|
+
// node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/filter-tasks/filter-tasks.js
|
|
2741
|
+
function casaResponsavel2(task, procurado) {
|
|
2742
|
+
const alvo = procurado.toLowerCase();
|
|
2743
|
+
return contem2(task.assignee?.id, alvo) || contem2(task.assignee?.name, alvo);
|
|
2744
|
+
}
|
|
2745
|
+
function filterTasks2(tasks, criteria) {
|
|
2746
|
+
return tasks.filter((task) => {
|
|
2747
|
+
if (criteria.status !== void 0) {
|
|
2748
|
+
if (task.status !== criteria.status)
|
|
2749
|
+
return false;
|
|
2750
|
+
} else if (criteria.open && !EM_ABERTO2.includes(task.status)) {
|
|
2751
|
+
return false;
|
|
2752
|
+
} else if (criteria.closed && !ENCERRADOS2.includes(task.status)) {
|
|
2753
|
+
return false;
|
|
2754
|
+
}
|
|
2755
|
+
if (criteria.type !== void 0 && task.type !== criteria.type)
|
|
2756
|
+
return false;
|
|
2757
|
+
if (criteria.assignee !== void 0 && !casaResponsavel2(task, criteria.assignee))
|
|
2758
|
+
return false;
|
|
2759
|
+
if (criteria.text !== void 0) {
|
|
2760
|
+
const procurado = criteria.text.toLowerCase();
|
|
2761
|
+
const casa = task.id.toLowerCase().includes(procurado) || contem2(task.title, procurado) || contem2(task.status, procurado) || casaResponsavel2(task, procurado);
|
|
2762
|
+
if (!casa)
|
|
2763
|
+
return false;
|
|
2764
|
+
}
|
|
2765
|
+
return true;
|
|
2766
|
+
});
|
|
2767
|
+
}
|
|
2768
|
+
function summarizeTask2(task) {
|
|
2769
|
+
return {
|
|
2770
|
+
id: task.id,
|
|
2771
|
+
title: task.title,
|
|
2772
|
+
status: task.status,
|
|
2773
|
+
type: task.type,
|
|
2774
|
+
...task.assignee && { assignee: { id: task.assignee.id, name: task.assignee.name } },
|
|
2775
|
+
...task.order !== void 0 && { priority: task.order },
|
|
2776
|
+
...task.groupId && { groupId: task.groupId },
|
|
2777
|
+
...task.groupName && { groupName: task.groupName },
|
|
2778
|
+
...task.difficulty !== void 0 && { difficulty: task.difficulty }
|
|
2779
|
+
};
|
|
2780
|
+
}
|
|
2781
|
+
var EM_ABERTO2, ENCERRADOS2, contem2;
|
|
2782
|
+
var init_filter_tasks = __esm({
|
|
2783
|
+
"node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/filter-tasks/filter-tasks.js"() {
|
|
2784
|
+
"use strict";
|
|
2785
|
+
init_esm_shims();
|
|
2786
|
+
EM_ABERTO2 = ["pending", "in-progress", "paused", "in-review", "blocked"];
|
|
2787
|
+
ENCERRADOS2 = ["done", "canceled"];
|
|
2788
|
+
contem2 = (valor, procurado) => valor?.toLowerCase().includes(procurado) ?? false;
|
|
2789
|
+
}
|
|
2790
|
+
});
|
|
2791
|
+
|
|
2792
|
+
// node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/filter-tasks/index.js
|
|
2793
|
+
var init_filter_tasks2 = __esm({
|
|
2794
|
+
"node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/filter-tasks/index.js"() {
|
|
2795
|
+
"use strict";
|
|
2796
|
+
init_esm_shims();
|
|
2797
|
+
init_filter_tasks();
|
|
2798
|
+
}
|
|
2799
|
+
});
|
|
2800
|
+
|
|
2801
|
+
// node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/metrics.types.js
|
|
2802
|
+
var init_metrics_types = __esm({
|
|
2803
|
+
"node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/metrics.types.js"() {
|
|
2804
|
+
"use strict";
|
|
2805
|
+
init_esm_shims();
|
|
2806
|
+
}
|
|
2807
|
+
});
|
|
2808
|
+
|
|
2809
|
+
// node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/task-manager.js
|
|
2810
|
+
var init_task_manager = __esm({
|
|
2811
|
+
"node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/task-manager.js"() {
|
|
2812
|
+
"use strict";
|
|
2813
|
+
init_esm_shims();
|
|
2814
|
+
}
|
|
2815
|
+
});
|
|
2816
|
+
|
|
2817
|
+
// node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/task-manager.types.js
|
|
2818
|
+
var init_task_manager_types = __esm({
|
|
2819
|
+
"node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/task-manager.types.js"() {
|
|
2820
|
+
"use strict";
|
|
2821
|
+
init_esm_shims();
|
|
2822
|
+
}
|
|
2823
|
+
});
|
|
2824
|
+
|
|
2825
|
+
// node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/user-registry.types.js
|
|
2826
|
+
var init_user_registry_types = __esm({
|
|
2827
|
+
"node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/user-registry.types.js"() {
|
|
2828
|
+
"use strict";
|
|
2829
|
+
init_esm_shims();
|
|
2830
|
+
}
|
|
2831
|
+
});
|
|
2832
|
+
|
|
2833
|
+
// node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/index.js
|
|
2834
|
+
var init_dist = __esm({
|
|
2835
|
+
"node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/index.js"() {
|
|
2836
|
+
"use strict";
|
|
2837
|
+
init_esm_shims();
|
|
2838
|
+
init_filter_tasks2();
|
|
2839
|
+
init_metrics_types();
|
|
2840
|
+
init_task_manager();
|
|
2841
|
+
init_task_manager_types();
|
|
2842
|
+
init_user_registry_types();
|
|
2843
|
+
}
|
|
2844
|
+
});
|
|
2845
|
+
|
|
2846
|
+
// node_modules/@opentask/taskin-task-server-mcp/dist/task-server-mcp.js
|
|
2847
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2848
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2849
|
+
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
2850
|
+
import { TaskIdSchema as TaskIdSchema4 } from "@opentask/taskin-types";
|
|
2851
|
+
function readTaskId(raw) {
|
|
2852
|
+
if (typeof raw !== "string")
|
|
2853
|
+
return void 0;
|
|
2854
|
+
const parsed = TaskIdSchema4.safeParse(raw);
|
|
2855
|
+
return parsed.success ? parsed.data : void 0;
|
|
2856
|
+
}
|
|
2857
|
+
function invalidTaskId(raw) {
|
|
2858
|
+
return {
|
|
2859
|
+
content: [
|
|
2860
|
+
{
|
|
2861
|
+
type: "text",
|
|
2862
|
+
text: `Invalid task id: ${JSON.stringify(raw)}. Expected the numeric id of a task, e.g. "020".`
|
|
2863
|
+
}
|
|
2864
|
+
],
|
|
2865
|
+
isError: true
|
|
2866
|
+
};
|
|
2867
|
+
}
|
|
2868
|
+
async function createTaskMCPServer(taskManager, options) {
|
|
2869
|
+
const server = new TaskMCPServer({
|
|
2870
|
+
taskManager,
|
|
2871
|
+
...options
|
|
2872
|
+
});
|
|
2873
|
+
await server.connect({ transport: "stdio" });
|
|
2874
|
+
return server;
|
|
2875
|
+
}
|
|
2876
|
+
var TaskMCPServer;
|
|
2877
|
+
var init_task_server_mcp = __esm({
|
|
2878
|
+
"node_modules/@opentask/taskin-task-server-mcp/dist/task-server-mcp.js"() {
|
|
2879
|
+
"use strict";
|
|
2880
|
+
init_esm_shims();
|
|
2881
|
+
init_dist();
|
|
2882
|
+
TaskMCPServer = class _TaskMCPServer {
|
|
2883
|
+
server;
|
|
2884
|
+
taskManager;
|
|
2885
|
+
config;
|
|
2886
|
+
constructor(config) {
|
|
2887
|
+
this.taskManager = config.taskManager;
|
|
2888
|
+
this.config = {
|
|
2889
|
+
name: "taskin-mcp-server",
|
|
2890
|
+
version: "1.0.0",
|
|
2891
|
+
debug: false,
|
|
2892
|
+
...config,
|
|
2893
|
+
taskManager: config.taskManager
|
|
2894
|
+
};
|
|
2895
|
+
this.server = new Server({
|
|
2896
|
+
name: this.config.name,
|
|
2897
|
+
version: this.config.version
|
|
2898
|
+
}, {
|
|
2899
|
+
capabilities: {
|
|
2900
|
+
tools: {},
|
|
2901
|
+
prompts: {},
|
|
2902
|
+
resources: {}
|
|
2903
|
+
}
|
|
2904
|
+
});
|
|
2905
|
+
this.setupHandlers();
|
|
2906
|
+
}
|
|
2907
|
+
/**
|
|
2908
|
+
* Setup MCP request handlers
|
|
2909
|
+
*/
|
|
2910
|
+
setupHandlers() {
|
|
2911
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
2912
|
+
const { tools } = this.listTools();
|
|
2913
|
+
return { tools };
|
|
2914
|
+
});
|
|
2915
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
2916
|
+
const result = await this.callTool({
|
|
2917
|
+
name: request.params.name,
|
|
2918
|
+
arguments: request.params.arguments
|
|
2919
|
+
});
|
|
2920
|
+
return {
|
|
2921
|
+
content: result.content,
|
|
2922
|
+
isError: result.isError
|
|
2923
|
+
};
|
|
2924
|
+
});
|
|
2925
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
2926
|
+
const { prompts } = this.listPrompts();
|
|
2927
|
+
return { prompts };
|
|
2928
|
+
});
|
|
2929
|
+
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
2930
|
+
const result = await this.getPrompt({
|
|
2931
|
+
name: request.params.name,
|
|
2932
|
+
arguments: request.params.arguments
|
|
2933
|
+
});
|
|
2934
|
+
return {
|
|
2935
|
+
messages: result.messages.map((msg) => ({
|
|
2936
|
+
role: msg.role,
|
|
2937
|
+
content: {
|
|
2938
|
+
type: "text",
|
|
2939
|
+
text: msg.content
|
|
2940
|
+
}
|
|
2941
|
+
}))
|
|
2942
|
+
};
|
|
2943
|
+
});
|
|
2944
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
2945
|
+
const result = await this.listResources();
|
|
2946
|
+
return { resources: result.resources };
|
|
2947
|
+
});
|
|
2948
|
+
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
2949
|
+
const result = await this.readResource({
|
|
2950
|
+
uri: request.params.uri
|
|
2951
|
+
});
|
|
2952
|
+
return result;
|
|
2953
|
+
});
|
|
2954
|
+
}
|
|
2955
|
+
/**
|
|
2956
|
+
* Connect to MCP transport
|
|
2957
|
+
*
|
|
2958
|
+
* `MCPTransportType` tem um valor so, entao nao ha o que despachar. O ramo
|
|
2959
|
+
* que existia aqui aceitava `'sse'` pelo tipo e recusava em tempo de
|
|
2960
|
+
* execucao, ja com o provider inicializado.
|
|
2961
|
+
*/
|
|
2962
|
+
async connect(_options) {
|
|
2963
|
+
await this.server.connect(new StdioServerTransport());
|
|
2964
|
+
this.log("MCP Server connected via stdio");
|
|
2965
|
+
}
|
|
2966
|
+
/**
|
|
2967
|
+
* Get server information
|
|
2968
|
+
*/
|
|
2969
|
+
getServerInfo() {
|
|
2970
|
+
return {
|
|
2971
|
+
name: this.config.name,
|
|
2972
|
+
version: this.config.version,
|
|
2973
|
+
protocolVersion: "2024-11-05",
|
|
2974
|
+
capabilities: {
|
|
2975
|
+
tools: {},
|
|
2976
|
+
prompts: {},
|
|
2977
|
+
resources: {}
|
|
2978
|
+
}
|
|
2979
|
+
};
|
|
2980
|
+
}
|
|
2981
|
+
/**
|
|
2982
|
+
* List available tools
|
|
2983
|
+
*/
|
|
2984
|
+
listTools() {
|
|
2985
|
+
const tools = [
|
|
2986
|
+
{
|
|
2987
|
+
name: "list_tasks",
|
|
2988
|
+
description: "List the tasks in the project. Returns a JSON array with what identifies each task \u2014 id, title, status, type, assignee \u2014 without the markdown body. Fetch a task body by id after choosing one.",
|
|
2989
|
+
inputSchema: {
|
|
2990
|
+
type: "object",
|
|
2991
|
+
properties: {
|
|
2992
|
+
status: { type: "string", description: "Exact status (pending, in-progress, done, ...)" },
|
|
2993
|
+
type: { type: "string", description: "Exact type (feat, fix, chore, ...)" },
|
|
2994
|
+
assignee: { type: "string", description: "Assignee id or name, whole or in part" },
|
|
2995
|
+
open: { type: "boolean", description: "Only tasks still open" },
|
|
2996
|
+
closed: { type: "boolean", description: "Only tasks already closed" },
|
|
2997
|
+
text: { type: "string", description: "Free text over id, title, status and assignee" }
|
|
2998
|
+
},
|
|
2999
|
+
required: []
|
|
3000
|
+
}
|
|
3001
|
+
},
|
|
3002
|
+
{
|
|
3003
|
+
name: "start_task",
|
|
3004
|
+
description: "Start working on a task by changing its status to in-progress",
|
|
3005
|
+
inputSchema: {
|
|
3006
|
+
type: "object",
|
|
3007
|
+
properties: {
|
|
3008
|
+
taskId: {
|
|
3009
|
+
type: "string",
|
|
3010
|
+
description: "The unique identifier of the task (UUID)"
|
|
3011
|
+
}
|
|
3012
|
+
},
|
|
3013
|
+
required: ["taskId"]
|
|
3014
|
+
}
|
|
3015
|
+
},
|
|
3016
|
+
{
|
|
3017
|
+
name: "finish_task",
|
|
3018
|
+
description: "Mark a task as completed by changing its status to done",
|
|
3019
|
+
inputSchema: {
|
|
3020
|
+
type: "object",
|
|
3021
|
+
properties: {
|
|
3022
|
+
taskId: {
|
|
3023
|
+
type: "string",
|
|
3024
|
+
description: "The unique identifier of the task (UUID)"
|
|
3025
|
+
}
|
|
3026
|
+
},
|
|
3027
|
+
required: ["taskId"]
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
];
|
|
3031
|
+
return { tools };
|
|
3032
|
+
}
|
|
3033
|
+
/**
|
|
3034
|
+
* Call a tool
|
|
3035
|
+
*/
|
|
3036
|
+
async callTool(params) {
|
|
3037
|
+
try {
|
|
3038
|
+
this.log(`Calling tool: ${params.name}`, params.arguments);
|
|
3039
|
+
switch (params.name) {
|
|
3040
|
+
case "list_tasks":
|
|
3041
|
+
return await this.handleListTasks(params.arguments ?? {});
|
|
3042
|
+
case "start_task": {
|
|
3043
|
+
const taskId = readTaskId(params.arguments?.taskId);
|
|
3044
|
+
return taskId ? await this.handleStartTask(taskId) : invalidTaskId(params.arguments?.taskId);
|
|
3045
|
+
}
|
|
3046
|
+
case "finish_task": {
|
|
3047
|
+
const taskId = readTaskId(params.arguments?.taskId);
|
|
3048
|
+
return taskId ? await this.handleFinishTask(taskId) : invalidTaskId(params.arguments?.taskId);
|
|
3049
|
+
}
|
|
3050
|
+
default:
|
|
3051
|
+
return {
|
|
3052
|
+
content: [
|
|
3053
|
+
{
|
|
3054
|
+
type: "text",
|
|
3055
|
+
text: `Unknown tool: ${params.name}`
|
|
3056
|
+
}
|
|
3057
|
+
],
|
|
3058
|
+
isError: true
|
|
3059
|
+
};
|
|
3060
|
+
}
|
|
3061
|
+
} catch (error2) {
|
|
3062
|
+
this.log("Tool call error:", error2);
|
|
3063
|
+
return {
|
|
3064
|
+
content: [
|
|
3065
|
+
{
|
|
3066
|
+
type: "text",
|
|
3067
|
+
text: error2 instanceof Error ? error2.message : String(error2)
|
|
3068
|
+
}
|
|
3069
|
+
],
|
|
3070
|
+
isError: true
|
|
3071
|
+
};
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
/**
|
|
3075
|
+
* Handle start_task tool
|
|
3076
|
+
*/
|
|
3077
|
+
async handleStartTask(taskId) {
|
|
3078
|
+
const task = await this.taskManager.startTask(taskId);
|
|
3079
|
+
return {
|
|
3080
|
+
content: [
|
|
3081
|
+
{
|
|
3082
|
+
type: "text",
|
|
3083
|
+
text: JSON.stringify({
|
|
3084
|
+
success: true,
|
|
3085
|
+
message: `Task ${taskId} started successfully`,
|
|
3086
|
+
task: {
|
|
3087
|
+
id: task.id,
|
|
3088
|
+
title: task.title,
|
|
3089
|
+
status: task.status,
|
|
3090
|
+
type: task.type
|
|
3091
|
+
}
|
|
3092
|
+
}, null, 2)
|
|
3093
|
+
}
|
|
3094
|
+
]
|
|
3095
|
+
};
|
|
3096
|
+
}
|
|
3097
|
+
/**
|
|
3098
|
+
* Handle finish_task tool
|
|
3099
|
+
*/
|
|
3100
|
+
async handleFinishTask(taskId) {
|
|
3101
|
+
const task = await this.taskManager.finishTask(taskId);
|
|
3102
|
+
return {
|
|
3103
|
+
content: [
|
|
3104
|
+
{
|
|
3105
|
+
type: "text",
|
|
3106
|
+
text: JSON.stringify({
|
|
3107
|
+
success: true,
|
|
3108
|
+
message: `Task ${taskId} finished successfully`,
|
|
3109
|
+
task: {
|
|
3110
|
+
id: task.id,
|
|
3111
|
+
title: task.title,
|
|
3112
|
+
status: task.status,
|
|
3113
|
+
type: task.type
|
|
3114
|
+
}
|
|
3115
|
+
}, null, 2)
|
|
3116
|
+
}
|
|
3117
|
+
]
|
|
3118
|
+
};
|
|
3119
|
+
}
|
|
3120
|
+
/**
|
|
3121
|
+
* List available prompts
|
|
3122
|
+
*/
|
|
3123
|
+
listPrompts() {
|
|
3124
|
+
const prompts = [
|
|
3125
|
+
{
|
|
3126
|
+
name: "start-task-workflow",
|
|
3127
|
+
description: "Guide the user through starting work on a task with git branch creation",
|
|
3128
|
+
arguments: [
|
|
3129
|
+
{
|
|
3130
|
+
name: "taskId",
|
|
3131
|
+
description: "The task ID to start",
|
|
3132
|
+
required: true
|
|
3133
|
+
}
|
|
3134
|
+
]
|
|
3135
|
+
},
|
|
3136
|
+
{
|
|
3137
|
+
name: "finish-task-workflow",
|
|
3138
|
+
description: "Guide the user through completing a task with commit and PR creation",
|
|
3139
|
+
arguments: [
|
|
3140
|
+
{
|
|
3141
|
+
name: "taskId",
|
|
3142
|
+
description: "The task ID to finish",
|
|
3143
|
+
required: true
|
|
3144
|
+
}
|
|
3145
|
+
]
|
|
3146
|
+
},
|
|
3147
|
+
{
|
|
3148
|
+
name: "task-summary",
|
|
3149
|
+
description: "Generate a summary of a task for documentation or reports",
|
|
3150
|
+
arguments: [
|
|
3151
|
+
{
|
|
3152
|
+
name: "taskId",
|
|
3153
|
+
description: "The task ID to summarize",
|
|
3154
|
+
required: true
|
|
3155
|
+
}
|
|
3156
|
+
]
|
|
3157
|
+
}
|
|
3158
|
+
];
|
|
3159
|
+
return { prompts };
|
|
3160
|
+
}
|
|
3161
|
+
/**
|
|
3162
|
+
* Get a prompt
|
|
3163
|
+
*/
|
|
3164
|
+
async getPrompt(params) {
|
|
3165
|
+
this.log(`Getting prompt: ${params.name}`, params.arguments);
|
|
3166
|
+
switch (params.name) {
|
|
3167
|
+
case "start-task-workflow":
|
|
3168
|
+
return {
|
|
3169
|
+
description: "Workflow for starting a task",
|
|
3170
|
+
messages: [
|
|
3171
|
+
{
|
|
3172
|
+
role: "user",
|
|
3173
|
+
content: {
|
|
3174
|
+
type: "text",
|
|
3175
|
+
text: `I want to start working on task ${params.arguments?.taskId}. Can you help me set everything up?`
|
|
3176
|
+
}
|
|
3177
|
+
},
|
|
3178
|
+
{
|
|
3179
|
+
role: "assistant",
|
|
3180
|
+
content: {
|
|
3181
|
+
type: "text",
|
|
3182
|
+
text: `I'll help you start working on task ${params.arguments?.taskId}. Here's what I'll do:
|
|
3183
|
+
|
|
3184
|
+
1. Mark the task as "in-progress"
|
|
3185
|
+
2. Create a git branch based on the task type and ID
|
|
3186
|
+
3. Ensure your working directory is clean
|
|
3187
|
+
4. Switch to the new branch
|
|
3188
|
+
|
|
3189
|
+
Let me start by marking the task as in-progress using the start_task tool.`
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
]
|
|
3193
|
+
};
|
|
3194
|
+
case "finish-task-workflow":
|
|
3195
|
+
return {
|
|
3196
|
+
description: "Workflow for finishing a task",
|
|
3197
|
+
messages: [
|
|
3198
|
+
{
|
|
3199
|
+
role: "user",
|
|
3200
|
+
content: {
|
|
3201
|
+
type: "text",
|
|
3202
|
+
text: `I've completed task ${params.arguments?.taskId}. What should I do next?`
|
|
3203
|
+
}
|
|
3204
|
+
},
|
|
3205
|
+
{
|
|
3206
|
+
role: "assistant",
|
|
3207
|
+
content: {
|
|
3208
|
+
type: "text",
|
|
3209
|
+
text: `Great! Let me help you finish task ${params.arguments?.taskId}. Here's the workflow:
|
|
3210
|
+
|
|
3211
|
+
1. Mark the task as "done"
|
|
3212
|
+
2. Ensure all changes are committed
|
|
3213
|
+
3. Push your branch to remote
|
|
3214
|
+
4. Create a pull request
|
|
3215
|
+
|
|
3216
|
+
Let me start by marking the task as done using the finish_task tool.`
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
]
|
|
3220
|
+
};
|
|
3221
|
+
case "task-summary":
|
|
3222
|
+
return {
|
|
3223
|
+
description: "Generate task summary",
|
|
3224
|
+
messages: [
|
|
3225
|
+
{
|
|
3226
|
+
role: "user",
|
|
3227
|
+
content: {
|
|
3228
|
+
type: "text",
|
|
3229
|
+
text: `Can you provide a summary of task ${params.arguments?.taskId}?`
|
|
3230
|
+
}
|
|
3231
|
+
},
|
|
3232
|
+
{
|
|
3233
|
+
role: "assistant",
|
|
3234
|
+
content: {
|
|
3235
|
+
type: "text",
|
|
3236
|
+
text: `I'll generate a comprehensive summary of task ${params.arguments?.taskId} including its current status, description, and any relevant metadata.`
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
]
|
|
3240
|
+
};
|
|
3241
|
+
default:
|
|
3242
|
+
throw new Error(`Unknown prompt: ${params.name}`);
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
/**
|
|
3246
|
+
* Le e seleciona as tarefas, pela mesma seam que o CLI usa.
|
|
3247
|
+
*
|
|
3248
|
+
* `filterTasks` e `summarizeTask` vivem no pacote agnostico justamente para
|
|
3249
|
+
* que a resposta aqui e a de `taskin list --json` nao possam divergir — ja
|
|
3250
|
+
* houve duas filtragens discordando no repositorio.
|
|
3251
|
+
*/
|
|
3252
|
+
async selecionarTarefas(criteria) {
|
|
3253
|
+
const tasks = await this.taskManager.getAllTasks();
|
|
3254
|
+
return filterTasks2(tasks, criteria).map(summarizeTask2);
|
|
3255
|
+
}
|
|
3256
|
+
/** Converte os argumentos crus da chamada MCP no criterio tipado. */
|
|
3257
|
+
static criterioDe(args) {
|
|
3258
|
+
return {
|
|
3259
|
+
...typeof args.status === "string" && { status: args.status },
|
|
3260
|
+
...typeof args.type === "string" && { type: args.type },
|
|
3261
|
+
...typeof args.assignee === "string" && { assignee: args.assignee },
|
|
3262
|
+
...args.open === true && { open: true },
|
|
3263
|
+
...args.closed === true && { closed: true },
|
|
3264
|
+
...typeof args.text === "string" && { text: args.text }
|
|
3265
|
+
};
|
|
3266
|
+
}
|
|
3267
|
+
async handleListTasks(args) {
|
|
3268
|
+
const tarefas = await this.selecionarTarefas(_TaskMCPServer.criterioDe(args));
|
|
3269
|
+
return {
|
|
3270
|
+
content: [{ type: "text", text: JSON.stringify(tarefas, null, 2) }],
|
|
3271
|
+
isError: false
|
|
3272
|
+
};
|
|
3273
|
+
}
|
|
3274
|
+
/**
|
|
3275
|
+
* List available resources
|
|
3276
|
+
*/
|
|
3277
|
+
async listResources() {
|
|
3278
|
+
return {
|
|
3279
|
+
resources: [
|
|
3280
|
+
{
|
|
3281
|
+
uri: "taskin://tasks",
|
|
3282
|
+
name: "All Tasks",
|
|
3283
|
+
description: "Access to all tasks in the system",
|
|
3284
|
+
mimeType: "application/json"
|
|
3285
|
+
}
|
|
3286
|
+
]
|
|
3287
|
+
};
|
|
3288
|
+
}
|
|
3289
|
+
/**
|
|
3290
|
+
* Read a resource
|
|
3291
|
+
*/
|
|
3292
|
+
async readResource(params) {
|
|
3293
|
+
this.log(`Reading resource: ${params.uri}`);
|
|
3294
|
+
const uri = params.uri;
|
|
3295
|
+
if (uri === "taskin://tasks") {
|
|
3296
|
+
const tarefas = await this.selecionarTarefas({});
|
|
3297
|
+
return {
|
|
3298
|
+
contents: [
|
|
3299
|
+
{
|
|
3300
|
+
uri,
|
|
3301
|
+
mimeType: "application/json",
|
|
3302
|
+
text: JSON.stringify(tarefas, null, 2)
|
|
3303
|
+
}
|
|
3304
|
+
]
|
|
3305
|
+
};
|
|
3306
|
+
}
|
|
3307
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
3308
|
+
}
|
|
3309
|
+
/**
|
|
3310
|
+
* Debug logging
|
|
3311
|
+
*/
|
|
3312
|
+
log(...args) {
|
|
3313
|
+
if (this.config.debug) {
|
|
3314
|
+
console.error("[TaskMCPServer]", ...args);
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
};
|
|
3318
|
+
}
|
|
3319
|
+
});
|
|
3320
|
+
|
|
3321
|
+
// node_modules/@opentask/taskin-task-server-mcp/dist/task-server-mcp.types.js
|
|
3322
|
+
var init_task_server_mcp_types = __esm({
|
|
3323
|
+
"node_modules/@opentask/taskin-task-server-mcp/dist/task-server-mcp.types.js"() {
|
|
3324
|
+
"use strict";
|
|
3325
|
+
init_esm_shims();
|
|
3326
|
+
}
|
|
3327
|
+
});
|
|
3328
|
+
|
|
3329
|
+
// node_modules/@opentask/taskin-task-server-mcp/dist/index.js
|
|
3330
|
+
var dist_exports = {};
|
|
3331
|
+
__export(dist_exports, {
|
|
3332
|
+
TaskMCPServer: () => TaskMCPServer,
|
|
3333
|
+
createTaskMCPServer: () => createTaskMCPServer
|
|
3334
|
+
});
|
|
3335
|
+
var init_dist2 = __esm({
|
|
3336
|
+
"node_modules/@opentask/taskin-task-server-mcp/dist/index.js"() {
|
|
3337
|
+
"use strict";
|
|
3338
|
+
init_esm_shims();
|
|
3339
|
+
init_task_server_mcp();
|
|
3340
|
+
init_task_server_mcp_types();
|
|
3341
|
+
}
|
|
3342
|
+
});
|
|
3343
|
+
|
|
2740
3344
|
// src/index.ts
|
|
2741
3345
|
init_esm_shims();
|
|
2742
3346
|
import { Command } from "commander";
|
|
@@ -3456,6 +4060,51 @@ init_esm_shims();
|
|
|
3456
4060
|
// ../task-manager/src/index.ts
|
|
3457
4061
|
init_esm_shims();
|
|
3458
4062
|
|
|
4063
|
+
// ../task-manager/src/filter-tasks/index.ts
|
|
4064
|
+
init_esm_shims();
|
|
4065
|
+
|
|
4066
|
+
// ../task-manager/src/filter-tasks/filter-tasks.ts
|
|
4067
|
+
init_esm_shims();
|
|
4068
|
+
var EM_ABERTO = ["pending", "in-progress", "paused", "in-review", "blocked"];
|
|
4069
|
+
var ENCERRADOS = ["done", "canceled"];
|
|
4070
|
+
var contem = (valor, procurado) => valor?.toLowerCase().includes(procurado) ?? false;
|
|
4071
|
+
function casaResponsavel(task, procurado) {
|
|
4072
|
+
const alvo = procurado.toLowerCase();
|
|
4073
|
+
return contem(task.assignee?.id, alvo) || contem(task.assignee?.name, alvo);
|
|
4074
|
+
}
|
|
4075
|
+
function filterTasks(tasks, criteria) {
|
|
4076
|
+
return tasks.filter((task) => {
|
|
4077
|
+
if (criteria.status !== void 0) {
|
|
4078
|
+
if (task.status !== criteria.status) return false;
|
|
4079
|
+
} else if (criteria.open && !EM_ABERTO.includes(task.status)) {
|
|
4080
|
+
return false;
|
|
4081
|
+
} else if (criteria.closed && !ENCERRADOS.includes(task.status)) {
|
|
4082
|
+
return false;
|
|
4083
|
+
}
|
|
4084
|
+
if (criteria.type !== void 0 && task.type !== criteria.type) return false;
|
|
4085
|
+
if (criteria.assignee !== void 0 && !casaResponsavel(task, criteria.assignee)) return false;
|
|
4086
|
+
if (criteria.text !== void 0) {
|
|
4087
|
+
const procurado = criteria.text.toLowerCase();
|
|
4088
|
+
const casa = task.id.toLowerCase().includes(procurado) || contem(task.title, procurado) || contem(task.status, procurado) || casaResponsavel(task, procurado);
|
|
4089
|
+
if (!casa) return false;
|
|
4090
|
+
}
|
|
4091
|
+
return true;
|
|
4092
|
+
});
|
|
4093
|
+
}
|
|
4094
|
+
function summarizeTask(task) {
|
|
4095
|
+
return {
|
|
4096
|
+
id: task.id,
|
|
4097
|
+
title: task.title,
|
|
4098
|
+
status: task.status,
|
|
4099
|
+
type: task.type,
|
|
4100
|
+
...task.assignee && { assignee: { id: task.assignee.id, name: task.assignee.name } },
|
|
4101
|
+
...task.order !== void 0 && { priority: task.order },
|
|
4102
|
+
...task.groupId && { groupId: task.groupId },
|
|
4103
|
+
...task.groupName && { groupName: task.groupName },
|
|
4104
|
+
...task.difficulty !== void 0 && { difficulty: task.difficulty }
|
|
4105
|
+
};
|
|
4106
|
+
}
|
|
4107
|
+
|
|
3459
4108
|
// ../task-manager/src/metrics.types.ts
|
|
3460
4109
|
init_esm_shims();
|
|
3461
4110
|
|
|
@@ -3502,6 +4151,16 @@ var TaskManager = class {
|
|
|
3502
4151
|
await this.taskProvider.updateTask(updatedTask);
|
|
3503
4152
|
return updatedTask;
|
|
3504
4153
|
}
|
|
4154
|
+
/**
|
|
4155
|
+
* Every task the configured provider knows about.
|
|
4156
|
+
*
|
|
4157
|
+
* Pass-through on purpose: the manager owns the state transitions, not the
|
|
4158
|
+
* storage. Having it here is what lets a consumer holding only the manager —
|
|
4159
|
+
* the MCP server — answer "what work exists?".
|
|
4160
|
+
*/
|
|
4161
|
+
async getAllTasks() {
|
|
4162
|
+
return await this.taskProvider.getAllTasks();
|
|
4163
|
+
}
|
|
3505
4164
|
async finishTask(taskId) {
|
|
3506
4165
|
const task = await this.taskProvider.findTask(taskId);
|
|
3507
4166
|
if (!task) {
|
|
@@ -4313,7 +4972,7 @@ async function startDashboard(options) {
|
|
|
4313
4972
|
}
|
|
4314
4973
|
});
|
|
4315
4974
|
await wsServer.start();
|
|
4316
|
-
success(
|
|
4975
|
+
success(`WebSocket server running on ws://${host}:${wsPort}`);
|
|
4317
4976
|
info(`Starting dashboard server on http://${host}:${port}...`);
|
|
4318
4977
|
const isDev = __dirname2.includes("/src/");
|
|
4319
4978
|
const dashboardDist = isDev ? path8.join(__dirname2, "..", "..", "dashboard-dist") : path8.join(__dirname2, "..", "dashboard-dist");
|
|
@@ -4364,7 +5023,7 @@ async function startDashboard(options) {
|
|
|
4364
5023
|
if (actualPort !== port) {
|
|
4365
5024
|
warning(`Port ${port} was in use. Dashboard started on port ${actualPort}.`);
|
|
4366
5025
|
}
|
|
4367
|
-
success(
|
|
5026
|
+
success(`Dashboard available at http://${host}:${actualPort}`);
|
|
4368
5027
|
const filterParams = new URLSearchParams();
|
|
4369
5028
|
if (options.open) {
|
|
4370
5029
|
filterParams.set("filter", "open");
|
|
@@ -4396,7 +5055,7 @@ async function startDashboard(options) {
|
|
|
4396
5055
|
httpServer.close(() => resolve());
|
|
4397
5056
|
});
|
|
4398
5057
|
await wsServer.stop();
|
|
4399
|
-
success("
|
|
5058
|
+
success("Servers stopped");
|
|
4400
5059
|
process.exit(0);
|
|
4401
5060
|
};
|
|
4402
5061
|
process.on("SIGINT", cleanup);
|
|
@@ -4495,9 +5154,18 @@ init_src3();
|
|
|
4495
5154
|
init_src();
|
|
4496
5155
|
import { execSync as execSync5 } from "child_process";
|
|
4497
5156
|
|
|
4498
|
-
// src/lib/
|
|
5157
|
+
// src/lib/ci-skip-tag/index.ts
|
|
4499
5158
|
init_esm_shims();
|
|
4500
|
-
|
|
5159
|
+
|
|
5160
|
+
// src/lib/ci-skip-tag/resolve-ci-skip-tag.ts
|
|
5161
|
+
init_esm_shims();
|
|
5162
|
+
function resolveCiSkipTag(configurada, skipCi) {
|
|
5163
|
+
return skipCi === false ? "" : configurada;
|
|
5164
|
+
}
|
|
5165
|
+
|
|
5166
|
+
// src/lib/notification/notify-helper.ts
|
|
5167
|
+
init_esm_shims();
|
|
5168
|
+
import { execSync as execSync4 } from "child_process";
|
|
4501
5169
|
|
|
4502
5170
|
// src/lib/debug.ts
|
|
4503
5171
|
init_esm_shims();
|
|
@@ -4891,6 +5559,10 @@ var finishCommand = defineCommand({
|
|
|
4891
5559
|
{
|
|
4892
5560
|
flags: "--dry-run",
|
|
4893
5561
|
description: "Show what would be executed without running"
|
|
5562
|
+
},
|
|
5563
|
+
{
|
|
5564
|
+
flags: "--no-skip-ci",
|
|
5565
|
+
description: "Write the status commit without the CI-skip tag"
|
|
4894
5566
|
}
|
|
4895
5567
|
],
|
|
4896
5568
|
handler: async (taskId, options) => {
|
|
@@ -4916,11 +5588,12 @@ async function finishTask(taskId, options, gitService) {
|
|
|
4916
5588
|
info(`Current status: ${task.status}`);
|
|
4917
5589
|
const configManager = new ConfigManager(monorepoRoot);
|
|
4918
5590
|
const behavior = configManager.getAutomationBehavior();
|
|
5591
|
+
const ciSkipTag = resolveCiSkipTag(behavior.ciSkipTag, options.skipCi);
|
|
4919
5592
|
const autoSyncActive = behavior.autoSync && !!behavior.defaultBranch;
|
|
4920
5593
|
const statusCommitMessage = buildTaskStatusCommitMessage({
|
|
4921
5594
|
taskId: normalizedId,
|
|
4922
5595
|
status: "done",
|
|
4923
|
-
ciSkipTag
|
|
5596
|
+
ciSkipTag
|
|
4924
5597
|
});
|
|
4925
5598
|
if (options.dryRun) {
|
|
4926
5599
|
console.log();
|
|
@@ -4943,7 +5616,7 @@ async function finishTask(taskId, options, gitService) {
|
|
|
4943
5616
|
);
|
|
4944
5617
|
console.log(colors.secondary(` - Push: git push`));
|
|
4945
5618
|
console.log();
|
|
4946
|
-
info("
|
|
5619
|
+
info("Dry run complete");
|
|
4947
5620
|
return;
|
|
4948
5621
|
}
|
|
4949
5622
|
if (task.status === "done") {
|
|
@@ -4953,7 +5626,7 @@ async function finishTask(taskId, options, gitService) {
|
|
|
4953
5626
|
if (behavior.autoSync && !behavior.defaultBranch) {
|
|
4954
5627
|
warning("autoSync is enabled but no defaultBranch is configured. Nothing will be synced.");
|
|
4955
5628
|
}
|
|
4956
|
-
const git = gitService ?? new GitService(process.cwd(), { ciSkipTag
|
|
5629
|
+
const git = gitService ?? new GitService(process.cwd(), { ciSkipTag });
|
|
4957
5630
|
if (!options.skipUpdate) {
|
|
4958
5631
|
info("Marking task as done...");
|
|
4959
5632
|
const updatedTask = await taskManager.finishTask(task.id);
|
|
@@ -4962,7 +5635,7 @@ async function finishTask(taskId, options, gitService) {
|
|
|
4962
5635
|
if (behavior.autoCommitStatusChange) {
|
|
4963
5636
|
const committed = await git.commitTaskStatusChangeOnBranch(normalizedId, "done", behavior.defaultBranch);
|
|
4964
5637
|
if (committed) {
|
|
4965
|
-
success("
|
|
5638
|
+
success("Auto-committed status change");
|
|
4966
5639
|
}
|
|
4967
5640
|
}
|
|
4968
5641
|
if (behavior.autoSync && behavior.originBranch && behavior.defaultBranch) {
|
|
@@ -4971,10 +5644,10 @@ async function finishTask(taskId, options, gitService) {
|
|
|
4971
5644
|
taskId: normalizedId,
|
|
4972
5645
|
defaultBranch: behavior.defaultBranch,
|
|
4973
5646
|
originBranch: behavior.originBranch,
|
|
4974
|
-
ciSkipTag
|
|
5647
|
+
ciSkipTag
|
|
4975
5648
|
});
|
|
4976
5649
|
if (squashed) {
|
|
4977
|
-
success(
|
|
5650
|
+
success(`Squash commit pushed to ${behavior.originBranch}`);
|
|
4978
5651
|
}
|
|
4979
5652
|
} catch (squashError) {
|
|
4980
5653
|
error(
|
|
@@ -4990,7 +5663,7 @@ async function finishTask(taskId, options, gitService) {
|
|
|
4990
5663
|
cwd: process.cwd(),
|
|
4991
5664
|
stdio: "ignore"
|
|
4992
5665
|
});
|
|
4993
|
-
success("
|
|
5666
|
+
success("Auto-committed completed work");
|
|
4994
5667
|
} catch {
|
|
4995
5668
|
}
|
|
4996
5669
|
}
|
|
@@ -5212,7 +5885,7 @@ async function initializeTaskin(options) {
|
|
|
5212
5885
|
await ensureProviderInstalled(selectedProvider);
|
|
5213
5886
|
}
|
|
5214
5887
|
const providerConfig = await setupProviderConfig(selectedProvider, cwd);
|
|
5215
|
-
const ciSkipTag = await
|
|
5888
|
+
const ciSkipTag = await resolveCiSkipTag2(options.ciSkipTag);
|
|
5216
5889
|
const config = {
|
|
5217
5890
|
version: "1.0.3",
|
|
5218
5891
|
automation: {
|
|
@@ -5227,7 +5900,7 @@ async function initializeTaskin(options) {
|
|
|
5227
5900
|
};
|
|
5228
5901
|
info("Creating configuration file...");
|
|
5229
5902
|
writeFileSync2(configFile, JSON.stringify(config, null, 2), "utf-8");
|
|
5230
|
-
success(
|
|
5903
|
+
success(`Created ${colors.highlight(".taskin.json")}`);
|
|
5231
5904
|
if (process.env.CI !== "true" && selectedProvider.id === "fs") {
|
|
5232
5905
|
await promptCreateFirstUser(cwd);
|
|
5233
5906
|
}
|
|
@@ -5246,7 +5919,7 @@ async function initializeTaskin(options) {
|
|
|
5246
5919
|
info("For more information, run: taskin --help");
|
|
5247
5920
|
console.log();
|
|
5248
5921
|
}
|
|
5249
|
-
async function
|
|
5922
|
+
async function resolveCiSkipTag2(fromFlag) {
|
|
5250
5923
|
if (fromFlag !== void 0) {
|
|
5251
5924
|
return normalizeCiSkipTag(fromFlag);
|
|
5252
5925
|
}
|
|
@@ -5310,7 +5983,7 @@ async function setupProviderConfig(provider, cwd) {
|
|
|
5310
5983
|
}));
|
|
5311
5984
|
const answers = await inquirer2.prompt(questions);
|
|
5312
5985
|
console.log();
|
|
5313
|
-
success(
|
|
5986
|
+
success(`${provider.name} configuration saved`);
|
|
5314
5987
|
return answers;
|
|
5315
5988
|
}
|
|
5316
5989
|
async function setupFileSystemProvider(cwd) {
|
|
@@ -5352,7 +6025,7 @@ This is a sample task created during Taskin initialization.
|
|
|
5352
6025
|
You can edit or delete this file. Use \`taskin list\` to see all tasks.
|
|
5353
6026
|
`;
|
|
5354
6027
|
writeFileSync2(sampleTaskFile, sampleTask, "utf-8");
|
|
5355
|
-
success(
|
|
6028
|
+
success(`Created sample task ${colors.highlight("task-001-setup-project.md")}`);
|
|
5356
6029
|
}
|
|
5357
6030
|
return {
|
|
5358
6031
|
tasksDir: "TASKS",
|
|
@@ -5397,7 +6070,7 @@ async function promptCreateFirstUser(cwd) {
|
|
|
5397
6070
|
email: answers.email
|
|
5398
6071
|
};
|
|
5399
6072
|
await userRegistry.saveUser(user);
|
|
5400
|
-
success(
|
|
6073
|
+
success(`User "${user.name}" (${user.email}) created successfully!`);
|
|
5401
6074
|
}
|
|
5402
6075
|
|
|
5403
6076
|
// src/commands/lint.ts
|
|
@@ -5518,6 +6191,10 @@ var listCommand = defineCommand({
|
|
|
5518
6191
|
{
|
|
5519
6192
|
flags: "--closed",
|
|
5520
6193
|
description: "Show only closed tasks (done, canceled)"
|
|
6194
|
+
},
|
|
6195
|
+
{
|
|
6196
|
+
flags: "--json",
|
|
6197
|
+
description: "Print the tasks as JSON, for other tools to consume"
|
|
5521
6198
|
}
|
|
5522
6199
|
],
|
|
5523
6200
|
handler: async (filter, options) => {
|
|
@@ -5526,36 +6203,28 @@ var listCommand = defineCommand({
|
|
|
5526
6203
|
});
|
|
5527
6204
|
async function listTasks(filter, options) {
|
|
5528
6205
|
requireTaskinProject();
|
|
5529
|
-
|
|
6206
|
+
const comoJson = options.json === true;
|
|
6207
|
+
if (!comoJson) {
|
|
6208
|
+
printHeader("Task List", "\u{1F4CA}");
|
|
6209
|
+
}
|
|
5530
6210
|
const { provider: taskProvider } = await resolveTaskProvider();
|
|
5531
6211
|
const tasks = await taskProvider.getAllTasks();
|
|
5532
|
-
if (tasks.length === 0) {
|
|
6212
|
+
if (tasks.length === 0 && !comoJson) {
|
|
5533
6213
|
console.log(colors.warning("No tasks found in TASKS/ directory"));
|
|
5534
6214
|
return;
|
|
5535
6215
|
}
|
|
5536
|
-
const
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
}
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
}
|
|
5549
|
-
if (options.assignee) {
|
|
5550
|
-
filteredTasks = filteredTasks.filter(
|
|
5551
|
-
(t) => t.assignee?.name.toLowerCase().includes(options.assignee.toLowerCase()) || t.assignee?.id.toLowerCase().includes(options.assignee.toLowerCase())
|
|
5552
|
-
);
|
|
5553
|
-
}
|
|
5554
|
-
if (filter) {
|
|
5555
|
-
const lowerFilter = filter.toLowerCase();
|
|
5556
|
-
filteredTasks = filteredTasks.filter(
|
|
5557
|
-
(t) => t.id.includes(lowerFilter) || t.title.toLowerCase().includes(lowerFilter) || t.status.toLowerCase().includes(lowerFilter) || t.assignee?.name.toLowerCase().includes(lowerFilter) || t.assignee?.id.toLowerCase().includes(lowerFilter)
|
|
5558
|
-
);
|
|
6216
|
+
const criteria = {
|
|
6217
|
+
...options.status && { status: options.status },
|
|
6218
|
+
...options.type && { type: options.type },
|
|
6219
|
+
...options.assignee && { assignee: options.assignee },
|
|
6220
|
+
...options.open && { open: true },
|
|
6221
|
+
...options.closed && { closed: true },
|
|
6222
|
+
...filter && { text: filter }
|
|
6223
|
+
};
|
|
6224
|
+
const filteredTasks = filterTasks(tasks, criteria);
|
|
6225
|
+
if (comoJson) {
|
|
6226
|
+
console.log(JSON.stringify(filteredTasks.map(summarizeTask), null, 2));
|
|
6227
|
+
return;
|
|
5559
6228
|
}
|
|
5560
6229
|
if (filteredTasks.length === 0) {
|
|
5561
6230
|
console.log(colors.warning("No tasks match the filters"));
|
|
@@ -5623,448 +6292,324 @@ function getTypeColor(type) {
|
|
|
5623
6292
|
}
|
|
5624
6293
|
}
|
|
5625
6294
|
|
|
5626
|
-
// src/commands/mcp-
|
|
6295
|
+
// src/commands/mcp-install.ts
|
|
5627
6296
|
init_esm_shims();
|
|
6297
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
6298
|
+
import path14 from "path";
|
|
5628
6299
|
|
|
5629
|
-
//
|
|
6300
|
+
// src/lib/mcp-install/index.ts
|
|
5630
6301
|
init_esm_shims();
|
|
5631
6302
|
|
|
5632
|
-
//
|
|
6303
|
+
// src/lib/mcp-install/merge-mcp-config.ts
|
|
5633
6304
|
init_esm_shims();
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
6305
|
+
var NOME_DO_SERVIDOR = "taskin";
|
|
6306
|
+
var ehObjeto = (valor) => typeof valor === "object" && valor !== null && !Array.isArray(valor);
|
|
6307
|
+
var mesmaEntrada = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
6308
|
+
function mergeMcpConfig(existente, entrada, options = {}) {
|
|
6309
|
+
if (existente === void 0) {
|
|
6310
|
+
return { outcome: "created", config: { mcpServers: { [NOME_DO_SERVIDOR]: entrada } } };
|
|
6311
|
+
}
|
|
6312
|
+
let lido;
|
|
6313
|
+
try {
|
|
6314
|
+
lido = JSON.parse(existente);
|
|
6315
|
+
} catch {
|
|
6316
|
+
return { outcome: "unreadable", reason: "o arquivo n\xE3o \xE9 JSON v\xE1lido" };
|
|
6317
|
+
}
|
|
6318
|
+
if (!ehObjeto(lido)) {
|
|
6319
|
+
return { outcome: "unreadable", reason: "o conte\xFAdo n\xE3o \xE9 um objeto" };
|
|
6320
|
+
}
|
|
6321
|
+
const servidores = lido.mcpServers;
|
|
6322
|
+
if (servidores !== void 0 && !ehObjeto(servidores)) {
|
|
6323
|
+
return { outcome: "unreadable", reason: "`mcpServers` n\xE3o \xE9 um objeto" };
|
|
6324
|
+
}
|
|
6325
|
+
const atuais = ehObjeto(servidores) ? servidores : {};
|
|
6326
|
+
const atual = atuais[NOME_DO_SERVIDOR];
|
|
6327
|
+
if (atual !== void 0) {
|
|
6328
|
+
if (mesmaEntrada(atual, entrada)) {
|
|
6329
|
+
return { outcome: "unchanged" };
|
|
6330
|
+
}
|
|
6331
|
+
if (!options.overwrite) {
|
|
6332
|
+
return { outcome: "conflict", current: atual };
|
|
6333
|
+
}
|
|
6334
|
+
}
|
|
6335
|
+
const config = {
|
|
6336
|
+
...lido,
|
|
6337
|
+
mcpServers: { ...atuais, [NOME_DO_SERVIDOR]: entrada }
|
|
5653
6338
|
};
|
|
6339
|
+
return atual === void 0 ? { outcome: "added", config } : { outcome: "replaced", config };
|
|
5654
6340
|
}
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
prompts: {},
|
|
5675
|
-
resources: {}
|
|
5676
|
-
}
|
|
5677
|
-
});
|
|
5678
|
-
this.setupHandlers();
|
|
6341
|
+
|
|
6342
|
+
// src/lib/mcp-install/package-manager.ts
|
|
6343
|
+
init_esm_shims();
|
|
6344
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
|
|
6345
|
+
import path11 from "path";
|
|
6346
|
+
var POR_LOCKFILE = [
|
|
6347
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
6348
|
+
["yarn.lock", "yarn"],
|
|
6349
|
+
["bun.lockb", "bun"],
|
|
6350
|
+
["package-lock.json", "npm"]
|
|
6351
|
+
];
|
|
6352
|
+
function declarado(raiz) {
|
|
6353
|
+
try {
|
|
6354
|
+
const { packageManager } = JSON.parse(readFileSync3(path11.join(raiz, "package.json"), "utf-8"));
|
|
6355
|
+
if (typeof packageManager !== "string") return void 0;
|
|
6356
|
+
const nome = packageManager.split("@")[0];
|
|
6357
|
+
return POR_LOCKFILE.some(([, gerenciador]) => gerenciador === nome) ? nome : void 0;
|
|
6358
|
+
} catch {
|
|
6359
|
+
return void 0;
|
|
5679
6360
|
}
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
return { tools };
|
|
5687
|
-
});
|
|
5688
|
-
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
5689
|
-
const result = await this.callTool({
|
|
5690
|
-
name: request.params.name,
|
|
5691
|
-
arguments: request.params.arguments
|
|
5692
|
-
});
|
|
5693
|
-
return {
|
|
5694
|
-
content: [
|
|
5695
|
-
{
|
|
5696
|
-
type: "text",
|
|
5697
|
-
text: result.content
|
|
5698
|
-
}
|
|
5699
|
-
],
|
|
5700
|
-
isError: result.isError
|
|
5701
|
-
};
|
|
5702
|
-
});
|
|
5703
|
-
this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
5704
|
-
const { prompts } = this.listPrompts();
|
|
5705
|
-
return { prompts };
|
|
5706
|
-
});
|
|
5707
|
-
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
5708
|
-
const result = await this.getPrompt({
|
|
5709
|
-
name: request.params.name,
|
|
5710
|
-
arguments: request.params.arguments
|
|
5711
|
-
});
|
|
5712
|
-
return {
|
|
5713
|
-
messages: result.messages.map((msg) => ({
|
|
5714
|
-
role: msg.role,
|
|
5715
|
-
content: {
|
|
5716
|
-
type: "text",
|
|
5717
|
-
text: msg.content
|
|
5718
|
-
}
|
|
5719
|
-
}))
|
|
5720
|
-
};
|
|
5721
|
-
});
|
|
5722
|
-
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
5723
|
-
const result = await this.listResources();
|
|
5724
|
-
return { resources: result.resources };
|
|
5725
|
-
});
|
|
5726
|
-
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
5727
|
-
const result = await this.readResource({
|
|
5728
|
-
uri: request.params.uri
|
|
5729
|
-
});
|
|
5730
|
-
return result;
|
|
5731
|
-
});
|
|
6361
|
+
}
|
|
6362
|
+
function detectPackageManager2(raiz) {
|
|
6363
|
+
const explicito = declarado(raiz);
|
|
6364
|
+
if (explicito) return explicito;
|
|
6365
|
+
for (const [lockfile, gerenciador] of POR_LOCKFILE) {
|
|
6366
|
+
if (existsSync6(path11.join(raiz, lockfile))) return gerenciador;
|
|
5732
6367
|
}
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
6368
|
+
return "npm";
|
|
6369
|
+
}
|
|
6370
|
+
function mcpCommandFor(manager) {
|
|
6371
|
+
switch (manager) {
|
|
6372
|
+
case "pnpm":
|
|
6373
|
+
return { command: "pnpm", args: ["exec", "taskin", "mcp-server"] };
|
|
6374
|
+
case "yarn":
|
|
6375
|
+
return { command: "yarn", args: ["taskin", "mcp-server"] };
|
|
6376
|
+
case "bun":
|
|
6377
|
+
return { command: "bunx", args: ["taskin", "mcp-server"] };
|
|
6378
|
+
case "npm":
|
|
6379
|
+
return { command: "npx", args: ["taskin", "mcp-server"] };
|
|
5744
6380
|
}
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
6381
|
+
}
|
|
6382
|
+
|
|
6383
|
+
// src/lib/mcp-install/probe-server.ts
|
|
6384
|
+
init_esm_shims();
|
|
6385
|
+
import { spawn } from "child_process";
|
|
6386
|
+
var LIMITE_MS = 3e4;
|
|
6387
|
+
var requisicao = (id, method, params) => `${JSON.stringify({ jsonrpc: "2.0", id, method, ...params !== void 0 && { params } })}
|
|
6388
|
+
`;
|
|
6389
|
+
function probeMcpServer(entrada, cwd, esperadas = []) {
|
|
6390
|
+
return new Promise((resolve) => {
|
|
6391
|
+
const filho = spawn(entrada.command, [...entrada.args], {
|
|
6392
|
+
cwd,
|
|
6393
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
6394
|
+
env: { ...process.env }
|
|
6395
|
+
});
|
|
6396
|
+
let saida = "";
|
|
6397
|
+
let erro = "";
|
|
6398
|
+
let respondido = false;
|
|
6399
|
+
const encerrar = (resultado) => {
|
|
6400
|
+
if (respondido) return;
|
|
6401
|
+
respondido = true;
|
|
6402
|
+
clearTimeout(cronometro);
|
|
6403
|
+
filho.kill();
|
|
6404
|
+
resolve(resultado);
|
|
5758
6405
|
};
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
required: ["taskId"]
|
|
5777
|
-
}
|
|
5778
|
-
},
|
|
5779
|
-
{
|
|
5780
|
-
name: "finish_task",
|
|
5781
|
-
description: "Mark a task as completed by changing its status to done",
|
|
5782
|
-
inputSchema: {
|
|
5783
|
-
type: "object",
|
|
5784
|
-
properties: {
|
|
5785
|
-
taskId: {
|
|
5786
|
-
type: "string",
|
|
5787
|
-
description: "The unique identifier of the task (UUID)"
|
|
5788
|
-
}
|
|
5789
|
-
},
|
|
5790
|
-
required: ["taskId"]
|
|
6406
|
+
const cronometro = setTimeout(
|
|
6407
|
+
() => encerrar({ ok: false, reason: `o servidor n\xE3o respondeu em ${LIMITE_MS / 1e3}s`, stderr: erro.trim() }),
|
|
6408
|
+
LIMITE_MS
|
|
6409
|
+
);
|
|
6410
|
+
filho.on("error", (e) => encerrar({ ok: false, reason: e.message, stderr: erro.trim() }));
|
|
6411
|
+
filho.stderr.on("data", (pedaco) => {
|
|
6412
|
+
erro += pedaco.toString();
|
|
6413
|
+
});
|
|
6414
|
+
filho.stdout.on("data", (pedaco) => {
|
|
6415
|
+
saida += pedaco.toString();
|
|
6416
|
+
for (const linha2 of saida.split("\n")) {
|
|
6417
|
+
if (!linha2.trim()) continue;
|
|
6418
|
+
let mensagem;
|
|
6419
|
+
try {
|
|
6420
|
+
mensagem = JSON.parse(linha2);
|
|
6421
|
+
} catch {
|
|
6422
|
+
continue;
|
|
5791
6423
|
}
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
/**
|
|
5797
|
-
* Call a tool
|
|
5798
|
-
*/
|
|
5799
|
-
async callTool(params) {
|
|
5800
|
-
try {
|
|
5801
|
-
this.log(`Calling tool: ${params.name}`, params.arguments);
|
|
5802
|
-
switch (params.name) {
|
|
5803
|
-
case "start_task": {
|
|
5804
|
-
const taskId = readTaskId(params.arguments?.taskId);
|
|
5805
|
-
return taskId ? await this.handleStartTask(taskId) : invalidTaskId(params.arguments?.taskId);
|
|
6424
|
+
if (mensagem.id !== 2) continue;
|
|
6425
|
+
if (mensagem.error) {
|
|
6426
|
+
encerrar({ ok: false, reason: `recusou tools/list: ${mensagem.error.message}`, stderr: erro.trim() });
|
|
6427
|
+
return;
|
|
5806
6428
|
}
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
6429
|
+
const ferramentas = (mensagem.result?.tools ?? []).map((t) => t.name);
|
|
6430
|
+
if (ferramentas.length === 0) {
|
|
6431
|
+
encerrar({ ok: false, reason: "subiu, mas n\xE3o anuncia ferramenta nenhuma", stderr: erro.trim() });
|
|
6432
|
+
return;
|
|
5810
6433
|
}
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
}
|
|
5818
|
-
],
|
|
5819
|
-
isError: true
|
|
5820
|
-
};
|
|
5821
|
-
}
|
|
5822
|
-
} catch (error2) {
|
|
5823
|
-
this.log("Tool call error:", error2);
|
|
5824
|
-
return {
|
|
5825
|
-
content: [
|
|
5826
|
-
{
|
|
5827
|
-
type: "text",
|
|
5828
|
-
text: error2 instanceof Error ? error2.message : String(error2)
|
|
6434
|
+
const faltando = esperadas.filter((nome) => !ferramentas.includes(nome));
|
|
6435
|
+
encerrar(
|
|
6436
|
+
faltando.length === 0 ? { ok: true, tools: ferramentas } : {
|
|
6437
|
+
ok: false,
|
|
6438
|
+
reason: `respondeu, mas sem ${faltando.join(", ")} \u2014 o comando provavelmente alcan\xE7a outra instala\xE7\xE3o do taskin (anunciou: ${ferramentas.join(", ")})`,
|
|
6439
|
+
stderr: erro.trim()
|
|
5829
6440
|
}
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
}
|
|
5833
|
-
}
|
|
6441
|
+
);
|
|
6442
|
+
return;
|
|
6443
|
+
}
|
|
6444
|
+
});
|
|
6445
|
+
filho.on(
|
|
6446
|
+
"close",
|
|
6447
|
+
(code) => encerrar({ ok: false, reason: `encerrou com c\xF3digo ${code} sem responder`, stderr: erro.trim() })
|
|
6448
|
+
);
|
|
6449
|
+
filho.stdin.write(
|
|
6450
|
+
requisicao(1, "initialize", {
|
|
6451
|
+
protocolVersion: "2024-11-05",
|
|
6452
|
+
capabilities: {},
|
|
6453
|
+
clientInfo: { name: "taskin-install", version: "1" }
|
|
6454
|
+
})
|
|
6455
|
+
);
|
|
6456
|
+
filho.stdin.write(requisicao(2, "tools/list"));
|
|
6457
|
+
});
|
|
6458
|
+
}
|
|
6459
|
+
|
|
6460
|
+
// src/lib/mcp-install/resolve-invocation.ts
|
|
6461
|
+
init_esm_shims();
|
|
6462
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
6463
|
+
import path12 from "path";
|
|
6464
|
+
function viaScript(manager) {
|
|
6465
|
+
if (manager === "npm") {
|
|
6466
|
+
return { command: "npm", args: ["run", "taskin", "--", "mcp-server"] };
|
|
5834
6467
|
}
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
const
|
|
5840
|
-
return
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
type: "text",
|
|
5844
|
-
text: JSON.stringify({
|
|
5845
|
-
success: true,
|
|
5846
|
-
message: `Task ${taskId} started successfully`,
|
|
5847
|
-
task: {
|
|
5848
|
-
id: task.id,
|
|
5849
|
-
title: task.title,
|
|
5850
|
-
status: task.status,
|
|
5851
|
-
type: task.type
|
|
5852
|
-
}
|
|
5853
|
-
}, null, 2)
|
|
5854
|
-
}
|
|
5855
|
-
]
|
|
5856
|
-
};
|
|
6468
|
+
return { command: manager, args: ["taskin", "mcp-server"] };
|
|
6469
|
+
}
|
|
6470
|
+
function temScriptTaskin(raiz) {
|
|
6471
|
+
try {
|
|
6472
|
+
const { scripts } = JSON.parse(readFileSync4(path12.join(raiz, "package.json"), "utf-8"));
|
|
6473
|
+
return typeof scripts?.taskin === "string";
|
|
6474
|
+
} catch {
|
|
6475
|
+
return false;
|
|
5857
6476
|
}
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
const task = await this.taskManager.finishTask(taskId);
|
|
5863
|
-
return {
|
|
5864
|
-
content: [
|
|
5865
|
-
{
|
|
5866
|
-
type: "text",
|
|
5867
|
-
text: JSON.stringify({
|
|
5868
|
-
success: true,
|
|
5869
|
-
message: `Task ${taskId} finished successfully`,
|
|
5870
|
-
task: {
|
|
5871
|
-
id: task.id,
|
|
5872
|
-
title: task.title,
|
|
5873
|
-
status: task.status,
|
|
5874
|
-
type: task.type
|
|
5875
|
-
}
|
|
5876
|
-
}, null, 2)
|
|
5877
|
-
}
|
|
5878
|
-
]
|
|
5879
|
-
};
|
|
6477
|
+
}
|
|
6478
|
+
function resolveInvocation(raiz, manager) {
|
|
6479
|
+
if (existsSync7(path12.join(raiz, "node_modules", ".bin", "taskin"))) {
|
|
6480
|
+
return mcpCommandFor(manager);
|
|
5880
6481
|
}
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
*/
|
|
5884
|
-
listPrompts() {
|
|
5885
|
-
const prompts = [
|
|
5886
|
-
{
|
|
5887
|
-
name: "start-task-workflow",
|
|
5888
|
-
description: "Guide the user through starting work on a task with git branch creation",
|
|
5889
|
-
arguments: [
|
|
5890
|
-
{
|
|
5891
|
-
name: "taskId",
|
|
5892
|
-
description: "The task ID to start",
|
|
5893
|
-
required: true
|
|
5894
|
-
}
|
|
5895
|
-
]
|
|
5896
|
-
},
|
|
5897
|
-
{
|
|
5898
|
-
name: "finish-task-workflow",
|
|
5899
|
-
description: "Guide the user through completing a task with commit and PR creation",
|
|
5900
|
-
arguments: [
|
|
5901
|
-
{
|
|
5902
|
-
name: "taskId",
|
|
5903
|
-
description: "The task ID to finish",
|
|
5904
|
-
required: true
|
|
5905
|
-
}
|
|
5906
|
-
]
|
|
5907
|
-
},
|
|
5908
|
-
{
|
|
5909
|
-
name: "task-summary",
|
|
5910
|
-
description: "Generate a summary of a task for documentation or reports",
|
|
5911
|
-
arguments: [
|
|
5912
|
-
{
|
|
5913
|
-
name: "taskId",
|
|
5914
|
-
description: "The task ID to summarize",
|
|
5915
|
-
required: true
|
|
5916
|
-
}
|
|
5917
|
-
]
|
|
5918
|
-
}
|
|
5919
|
-
];
|
|
5920
|
-
return { prompts };
|
|
6482
|
+
if (temScriptTaskin(raiz)) {
|
|
6483
|
+
return viaScript(manager);
|
|
5921
6484
|
}
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
*/
|
|
5925
|
-
async getPrompt(params) {
|
|
5926
|
-
this.log(`Getting prompt: ${params.name}`, params.arguments);
|
|
5927
|
-
switch (params.name) {
|
|
5928
|
-
case "start-task-workflow":
|
|
5929
|
-
return {
|
|
5930
|
-
description: "Workflow for starting a task",
|
|
5931
|
-
messages: [
|
|
5932
|
-
{
|
|
5933
|
-
role: "user",
|
|
5934
|
-
content: {
|
|
5935
|
-
type: "text",
|
|
5936
|
-
text: `I want to start working on task ${params.arguments?.taskId}. Can you help me set everything up?`
|
|
5937
|
-
}
|
|
5938
|
-
},
|
|
5939
|
-
{
|
|
5940
|
-
role: "assistant",
|
|
5941
|
-
content: {
|
|
5942
|
-
type: "text",
|
|
5943
|
-
text: `I'll help you start working on task ${params.arguments?.taskId}. Here's what I'll do:
|
|
5944
|
-
|
|
5945
|
-
1. Mark the task as "in-progress"
|
|
5946
|
-
2. Create a git branch based on the task type and ID
|
|
5947
|
-
3. Ensure your working directory is clean
|
|
5948
|
-
4. Switch to the new branch
|
|
6485
|
+
return mcpCommandFor(manager);
|
|
6486
|
+
}
|
|
5949
6487
|
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
}
|
|
5953
|
-
]
|
|
5954
|
-
};
|
|
5955
|
-
case "finish-task-workflow":
|
|
5956
|
-
return {
|
|
5957
|
-
description: "Workflow for finishing a task",
|
|
5958
|
-
messages: [
|
|
5959
|
-
{
|
|
5960
|
-
role: "user",
|
|
5961
|
-
content: {
|
|
5962
|
-
type: "text",
|
|
5963
|
-
text: `I've completed task ${params.arguments?.taskId}. What should I do next?`
|
|
5964
|
-
}
|
|
5965
|
-
},
|
|
5966
|
-
{
|
|
5967
|
-
role: "assistant",
|
|
5968
|
-
content: {
|
|
5969
|
-
type: "text",
|
|
5970
|
-
text: `Great! Let me help you finish task ${params.arguments?.taskId}. Here's the workflow:
|
|
6488
|
+
// src/lib/project-root/index.ts
|
|
6489
|
+
init_esm_shims();
|
|
5971
6490
|
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
6491
|
+
// src/lib/project-root/project-root.ts
|
|
6492
|
+
init_esm_shims();
|
|
6493
|
+
import { statSync } from "fs";
|
|
6494
|
+
import path13 from "path";
|
|
6495
|
+
var MARCADOR = ".taskin.json";
|
|
6496
|
+
function temMarcador(diretorio) {
|
|
6497
|
+
try {
|
|
6498
|
+
return statSync(path13.join(diretorio, MARCADOR)).isFile();
|
|
6499
|
+
} catch {
|
|
6500
|
+
return false;
|
|
6501
|
+
}
|
|
6502
|
+
}
|
|
6503
|
+
function findProjectRoot(startDir = process.cwd()) {
|
|
6504
|
+
let atual = path13.resolve(startDir);
|
|
6505
|
+
while (true) {
|
|
6506
|
+
if (temMarcador(atual)) return atual;
|
|
6507
|
+
const acima = path13.dirname(atual);
|
|
6508
|
+
if (acima === atual) return void 0;
|
|
6509
|
+
atual = acima;
|
|
6510
|
+
}
|
|
6511
|
+
}
|
|
5976
6512
|
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
text: `I'll generate a comprehensive summary of task ${params.arguments?.taskId} including its current status, description, and any relevant metadata.`
|
|
5998
|
-
}
|
|
5999
|
-
}
|
|
6000
|
-
]
|
|
6001
|
-
};
|
|
6002
|
-
default:
|
|
6003
|
-
throw new Error(`Unknown prompt: ${params.name}`);
|
|
6513
|
+
// src/commands/mcp-install.ts
|
|
6514
|
+
var ARQUIVO = ".mcp.json";
|
|
6515
|
+
function lerSeExistir(caminho) {
|
|
6516
|
+
try {
|
|
6517
|
+
return readFileSync5(caminho, "utf-8");
|
|
6518
|
+
} catch {
|
|
6519
|
+
return void 0;
|
|
6520
|
+
}
|
|
6521
|
+
}
|
|
6522
|
+
var mcpInstallCommand = defineCommand({
|
|
6523
|
+
name: "mcp-install",
|
|
6524
|
+
description: "\u{1F50C} Register the Taskin MCP server in this project's .mcp.json",
|
|
6525
|
+
options: [
|
|
6526
|
+
{
|
|
6527
|
+
flags: "-f, --force",
|
|
6528
|
+
description: "Replace an existing taskin entry that differs"
|
|
6529
|
+
},
|
|
6530
|
+
{
|
|
6531
|
+
flags: "--no-probe",
|
|
6532
|
+
description: "Skip starting the server to verify the entry works"
|
|
6004
6533
|
}
|
|
6534
|
+
],
|
|
6535
|
+
handler: async (options) => {
|
|
6536
|
+
await instalar(options);
|
|
6005
6537
|
}
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
{
|
|
6013
|
-
uri: "taskin://tasks",
|
|
6014
|
-
name: "All Tasks",
|
|
6015
|
-
description: "Access to all tasks in the system",
|
|
6016
|
-
mimeType: "application/json"
|
|
6017
|
-
}
|
|
6018
|
-
]
|
|
6019
|
-
};
|
|
6538
|
+
});
|
|
6539
|
+
async function instalar(options) {
|
|
6540
|
+
const raiz = findProjectRoot();
|
|
6541
|
+
if (!raiz) {
|
|
6542
|
+
error('No .taskin.json found here or in any parent directory. Run "taskin init" first.');
|
|
6543
|
+
process.exit(1);
|
|
6020
6544
|
}
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6545
|
+
const caminho = path14.join(raiz, ARQUIVO);
|
|
6546
|
+
const manager = detectPackageManager2(raiz);
|
|
6547
|
+
const entrada = resolveInvocation(raiz, manager);
|
|
6548
|
+
info(`Project root: ${raiz}`);
|
|
6549
|
+
info(`Package manager: ${manager} \u2014 the entry will run \`${[entrada.command, ...entrada.args].join(" ")}\``);
|
|
6550
|
+
const resultado = mergeMcpConfig(lerSeExistir(caminho), entrada, { overwrite: options.force === true });
|
|
6551
|
+
switch (resultado.outcome) {
|
|
6552
|
+
case "unreadable":
|
|
6553
|
+
error(`${ARQUIVO} exists but ${resultado.reason}. Nothing was written \u2014 fix or remove it first.`);
|
|
6554
|
+
process.exit(1);
|
|
6555
|
+
return;
|
|
6556
|
+
case "conflict":
|
|
6557
|
+
warning(`${ARQUIVO} already has a "${NOME_DO_SERVIDOR}" entry that differs:`);
|
|
6558
|
+
console.log(` current: ${JSON.stringify(resultado.current)}`);
|
|
6559
|
+
console.log(` new: ${JSON.stringify(entrada)}`);
|
|
6560
|
+
info("Run again with --force to replace it.");
|
|
6561
|
+
process.exit(1);
|
|
6562
|
+
return;
|
|
6563
|
+
case "unchanged":
|
|
6564
|
+
success(`${ARQUIVO} already registers the Taskin MCP server. Nothing to do.`);
|
|
6565
|
+
break;
|
|
6566
|
+
default:
|
|
6567
|
+
writeFileSync3(caminho, `${JSON.stringify(resultado.config, null, 2)}
|
|
6568
|
+
`, "utf-8");
|
|
6569
|
+
success(
|
|
6570
|
+
resultado.outcome === "created" ? `Created ${ARQUIVO}` : `${resultado.outcome === "added" ? "Added" : "Replaced"} the "${NOME_DO_SERVIDOR}" entry in ${ARQUIVO}`
|
|
6571
|
+
);
|
|
6042
6572
|
}
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6573
|
+
if (options.probe === false) {
|
|
6574
|
+
info("Skipped the check. Run without --no-probe to verify the server actually starts.");
|
|
6575
|
+
return;
|
|
6576
|
+
}
|
|
6577
|
+
info("Starting the server to check the entry actually works...");
|
|
6578
|
+
const { TaskMCPServer: TaskMCPServer2 } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
|
|
6579
|
+
const esperadas = new TaskMCPServer2({ taskManager: {} }).listTools().tools.map((t) => t.name);
|
|
6580
|
+
const sonda = await probeMcpServer(entrada, raiz, esperadas);
|
|
6581
|
+
if (!sonda.ok) {
|
|
6582
|
+
error(`The entry was written, but the server did not answer: ${sonda.reason}`);
|
|
6583
|
+
if (sonda.stderr) {
|
|
6584
|
+
console.log(sonda.stderr);
|
|
6049
6585
|
}
|
|
6586
|
+
process.exit(1);
|
|
6587
|
+
return;
|
|
6050
6588
|
}
|
|
6051
|
-
};
|
|
6052
|
-
|
|
6053
|
-
// node_modules/@opentask/taskin-task-server-mcp/dist/task-server-mcp.types.js
|
|
6054
|
-
init_esm_shims();
|
|
6589
|
+
success(`The server answered with ${sonda.tools.length} tool(s): ${sonda.tools.join(", ")}`);
|
|
6590
|
+
}
|
|
6055
6591
|
|
|
6056
6592
|
// src/commands/mcp-server.ts
|
|
6593
|
+
init_esm_shims();
|
|
6594
|
+
init_dist2();
|
|
6057
6595
|
import chalk6 from "chalk";
|
|
6596
|
+
var linha = (texto = "") => process.stderr.write(`${texto}
|
|
6597
|
+
`);
|
|
6598
|
+
var aviso = (mensagem) => linha(colors.info(`\u2139 ${mensagem}`));
|
|
6599
|
+
var feito = (mensagem) => linha(colors.success(`\u2713 ${mensagem}`));
|
|
6600
|
+
var falha = (mensagem) => linha(colors.error(`\u2717 ${mensagem}`));
|
|
6601
|
+
function cabecalho(titulo, icone) {
|
|
6602
|
+
linha();
|
|
6603
|
+
linha(colors.highlight("=".repeat(60)));
|
|
6604
|
+
linha(colors.highlight(`${icone} ${titulo}`));
|
|
6605
|
+
linha(colors.highlight("=".repeat(60)));
|
|
6606
|
+
linha();
|
|
6607
|
+
}
|
|
6058
6608
|
var mcpServerCommand = defineCommand({
|
|
6059
6609
|
name: "mcp-server",
|
|
6060
6610
|
description: "\u{1F916} Start Model Context Protocol server for LLM integration",
|
|
6061
6611
|
alias: "mcp",
|
|
6062
6612
|
options: [
|
|
6063
|
-
{
|
|
6064
|
-
flags: "-t, --transport <type>",
|
|
6065
|
-
description: "Transport type (stdio or sse)",
|
|
6066
|
-
defaultValue: "stdio"
|
|
6067
|
-
},
|
|
6068
6613
|
{
|
|
6069
6614
|
flags: "-d, --debug",
|
|
6070
6615
|
description: "Enable debug logging"
|
|
@@ -6076,45 +6621,40 @@ var mcpServerCommand = defineCommand({
|
|
|
6076
6621
|
});
|
|
6077
6622
|
async function startMCPServer(options) {
|
|
6078
6623
|
requireTaskinProject();
|
|
6079
|
-
const transport = options.transport || "stdio";
|
|
6080
6624
|
const debug = options.debug || false;
|
|
6081
|
-
|
|
6625
|
+
cabecalho("Starting MCP Server", "\u{1F916}");
|
|
6082
6626
|
try {
|
|
6083
|
-
|
|
6627
|
+
aviso("Initializing task manager...");
|
|
6084
6628
|
const { provider } = await resolveTaskProvider();
|
|
6085
6629
|
const manager = new TaskManager(provider);
|
|
6086
|
-
info(`Creating MCP server with ${transport} transport...`);
|
|
6087
6630
|
const mcpServer = new TaskMCPServer({
|
|
6088
6631
|
taskManager: manager,
|
|
6089
6632
|
name: "taskin-mcp-server",
|
|
6090
6633
|
version: "1.0.0",
|
|
6091
6634
|
debug
|
|
6092
6635
|
});
|
|
6093
|
-
|
|
6094
|
-
await mcpServer.connect({ transport });
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
const cleanup = async () => {
|
|
6116
|
-
info("\nShutting down MCP server...");
|
|
6117
|
-
success("\u2713 Server stopped");
|
|
6636
|
+
aviso("Starting MCP server over stdio...");
|
|
6637
|
+
await mcpServer.connect({ transport: "stdio" });
|
|
6638
|
+
feito("MCP server started successfully");
|
|
6639
|
+
linha();
|
|
6640
|
+
aviso(` ${chalk6.bold("Debug")}: ${chalk6.cyan(debug ? "enabled" : "disabled")}`);
|
|
6641
|
+
linha();
|
|
6642
|
+
aviso(chalk6.bold("Available Tools:"));
|
|
6643
|
+
for (const ferramenta of mcpServer.listTools().tools) {
|
|
6644
|
+
aviso(` \u2022 ${chalk6.green(ferramenta.name)} - ${ferramenta.description}`);
|
|
6645
|
+
}
|
|
6646
|
+
linha();
|
|
6647
|
+
aviso(chalk6.bold("Available Prompts:"));
|
|
6648
|
+
for (const prompt of mcpServer.listPrompts().prompts) {
|
|
6649
|
+
aviso(` \u2022 ${chalk6.green(prompt.name)} - ${prompt.description}`);
|
|
6650
|
+
}
|
|
6651
|
+
linha();
|
|
6652
|
+
aviso(`Press ${chalk6.bold("Ctrl+C")} to stop the server`);
|
|
6653
|
+
linha();
|
|
6654
|
+
const cleanup = () => {
|
|
6655
|
+
linha();
|
|
6656
|
+
aviso("Shutting down MCP server...");
|
|
6657
|
+
feito("Server stopped");
|
|
6118
6658
|
process.exit(0);
|
|
6119
6659
|
};
|
|
6120
6660
|
process.on("SIGINT", cleanup);
|
|
@@ -6122,9 +6662,9 @@ async function startMCPServer(options) {
|
|
|
6122
6662
|
await new Promise(() => {
|
|
6123
6663
|
});
|
|
6124
6664
|
} catch (err) {
|
|
6125
|
-
|
|
6665
|
+
falha("Failed to start MCP server");
|
|
6126
6666
|
if (err instanceof Error) {
|
|
6127
|
-
|
|
6667
|
+
falha(err.message);
|
|
6128
6668
|
if (debug) {
|
|
6129
6669
|
console.error(err.stack);
|
|
6130
6670
|
}
|
|
@@ -6159,6 +6699,10 @@ var createCommand = defineCommand({
|
|
|
6159
6699
|
{
|
|
6160
6700
|
flags: "-u, --user <user>",
|
|
6161
6701
|
description: "Assignee user"
|
|
6702
|
+
},
|
|
6703
|
+
{
|
|
6704
|
+
flags: "--no-skip-ci",
|
|
6705
|
+
description: "Write the status commit without the CI-skip tag"
|
|
6162
6706
|
}
|
|
6163
6707
|
],
|
|
6164
6708
|
handler: async (options) => {
|
|
@@ -6234,11 +6778,12 @@ async function createTask(options, gitService) {
|
|
|
6234
6778
|
await userRegistry.ensureCurrentUser();
|
|
6235
6779
|
const configManager = new ConfigManager(monorepoRoot);
|
|
6236
6780
|
const behavior = configManager.getAutomationBehavior();
|
|
6781
|
+
const ciSkipTag = resolveCiSkipTag(behavior.ciSkipTag, options.skipCi);
|
|
6237
6782
|
const autoSyncActive = behavior.autoSync && !!behavior.defaultBranch;
|
|
6238
6783
|
if (behavior.autoSync && !behavior.defaultBranch) {
|
|
6239
6784
|
warning("autoSync is enabled but no defaultBranch is configured. Nothing will be synced.");
|
|
6240
6785
|
}
|
|
6241
|
-
const git = gitService ?? new GitService(process.cwd(), { ciSkipTag
|
|
6786
|
+
const git = gitService ?? new GitService(process.cwd(), { ciSkipTag });
|
|
6242
6787
|
if (autoSyncActive) {
|
|
6243
6788
|
try {
|
|
6244
6789
|
await syncBeforeCreate(git, {
|
|
@@ -6271,7 +6816,7 @@ async function createTask(options, gitService) {
|
|
|
6271
6816
|
taskId,
|
|
6272
6817
|
title: options.title,
|
|
6273
6818
|
defaultBranch: behavior.defaultBranch,
|
|
6274
|
-
ciSkipTag
|
|
6819
|
+
ciSkipTag
|
|
6275
6820
|
});
|
|
6276
6821
|
} catch (pushError) {
|
|
6277
6822
|
error(
|
|
@@ -6287,7 +6832,7 @@ async function createTask(options, gitService) {
|
|
|
6287
6832
|
console.log(colors.secondary(`\u{1F4C1} Path: ${createdPath}`));
|
|
6288
6833
|
}
|
|
6289
6834
|
if (autoSyncActive) {
|
|
6290
|
-
success("
|
|
6835
|
+
success("Task committed and pushed to remote");
|
|
6291
6836
|
}
|
|
6292
6837
|
console.log();
|
|
6293
6838
|
console.log(colors.info("Next steps:"));
|
|
@@ -6442,7 +6987,7 @@ async function pauseTask(taskId, options) {
|
|
|
6442
6987
|
console.log(colors.secondary(` - Add all changes: git add -A`));
|
|
6443
6988
|
console.log(colors.secondary(` - Commit: git commit -m "${commitMessage2}"`));
|
|
6444
6989
|
console.log();
|
|
6445
|
-
info("
|
|
6990
|
+
info("Dry run complete");
|
|
6446
6991
|
return;
|
|
6447
6992
|
}
|
|
6448
6993
|
if (task.status !== "in-progress") {
|
|
@@ -6476,7 +7021,7 @@ async function pauseTask(taskId, options) {
|
|
|
6476
7021
|
}
|
|
6477
7022
|
await taskManager.pauseTask(normalizedId);
|
|
6478
7023
|
success("Task paused successfully!");
|
|
6479
|
-
success("
|
|
7024
|
+
success("Auto-committed work in progress");
|
|
6480
7025
|
info("Status updated to paused");
|
|
6481
7026
|
console.log();
|
|
6482
7027
|
info("Next steps:");
|
|
@@ -6593,6 +7138,10 @@ var reviewCommand = defineCommand({
|
|
|
6593
7138
|
{
|
|
6594
7139
|
flags: "--no-sound",
|
|
6595
7140
|
description: "Disable review sound"
|
|
7141
|
+
},
|
|
7142
|
+
{
|
|
7143
|
+
flags: "--no-skip-ci",
|
|
7144
|
+
description: "Write the status commit without the CI-skip tag"
|
|
6596
7145
|
}
|
|
6597
7146
|
],
|
|
6598
7147
|
handler: async (taskId, options) => {
|
|
@@ -6624,6 +7173,7 @@ async function reviewTask(taskId, options) {
|
|
|
6624
7173
|
const hookSettings = configManager.getHookSettings();
|
|
6625
7174
|
const reviewHooks = configManager.getCommandHooks("review");
|
|
6626
7175
|
const behavior = configManager.getAutomationBehavior();
|
|
7176
|
+
const ciSkipTag = resolveCiSkipTag(behavior.ciSkipTag, options.skipCi);
|
|
6627
7177
|
const hookRunner = new HookRunner();
|
|
6628
7178
|
const hookContext = {
|
|
6629
7179
|
taskId: normalizedId,
|
|
@@ -6663,7 +7213,7 @@ async function reviewTask(taskId, options) {
|
|
|
6663
7213
|
});
|
|
6664
7214
|
console.log();
|
|
6665
7215
|
}
|
|
6666
|
-
info("
|
|
7216
|
+
info("Dry run complete");
|
|
6667
7217
|
return;
|
|
6668
7218
|
}
|
|
6669
7219
|
if (reviewHooks.pre && reviewHooks.pre.length > 0 && !options.skipMerge) {
|
|
@@ -6682,7 +7232,7 @@ async function reviewTask(taskId, options) {
|
|
|
6682
7232
|
const failedPre = preResults.find((r) => !r.success);
|
|
6683
7233
|
if (failedPre && !hookSettings.continueOnError) {
|
|
6684
7234
|
console.log();
|
|
6685
|
-
error("
|
|
7235
|
+
error("Pre-review hooks failed!");
|
|
6686
7236
|
error("Fix the errors above and try again.");
|
|
6687
7237
|
process.exit(1);
|
|
6688
7238
|
}
|
|
@@ -6704,7 +7254,7 @@ async function reviewTask(taskId, options) {
|
|
|
6704
7254
|
const failedCheck = duringResults.find((r) => !r.success);
|
|
6705
7255
|
if (failedCheck && !hookSettings.continueOnError) {
|
|
6706
7256
|
console.log();
|
|
6707
|
-
error("
|
|
7257
|
+
error("Review checks failed!");
|
|
6708
7258
|
error("Fix the errors above and try again.");
|
|
6709
7259
|
console.log();
|
|
6710
7260
|
info("Tip: Run individual checks to see full error details");
|
|
@@ -6714,18 +7264,15 @@ async function reviewTask(taskId, options) {
|
|
|
6714
7264
|
}
|
|
6715
7265
|
info("Marking task as ready for review...");
|
|
6716
7266
|
const updatedTask = await taskManager.reviewTask(task.id);
|
|
6717
|
-
success(
|
|
7267
|
+
success(`Task ${updatedTask.id} status changed to: ${updatedTask.status}`);
|
|
6718
7268
|
if (behavior.autoCommitStatusChange) {
|
|
6719
7269
|
try {
|
|
6720
|
-
const message = appendCiSkipTag(
|
|
6721
|
-
`docs(TASKS): task-${normalizedId} - mark as ready for review`,
|
|
6722
|
-
behavior.ciSkipTag
|
|
6723
|
-
);
|
|
7270
|
+
const message = appendCiSkipTag(`docs(TASKS): task-${normalizedId} - mark as ready for review`, ciSkipTag);
|
|
6724
7271
|
execSync9(`git add TASKS/task-${normalizedId}-*.md && git commit -m "${message}"`, {
|
|
6725
7272
|
cwd: monorepoRoot,
|
|
6726
7273
|
stdio: "ignore"
|
|
6727
7274
|
});
|
|
6728
|
-
success("
|
|
7275
|
+
success("Auto-committed status change");
|
|
6729
7276
|
} catch {
|
|
6730
7277
|
}
|
|
6731
7278
|
}
|
|
@@ -6746,7 +7293,7 @@ async function reviewTask(taskId, options) {
|
|
|
6746
7293
|
console.log();
|
|
6747
7294
|
}
|
|
6748
7295
|
const totalDuration = [...reviewHooks.pre ?? [], ...reviewHooks.during ?? [], ...reviewHooks.post ?? []].length > 0 ? "with hooks" : "";
|
|
6749
|
-
success(
|
|
7296
|
+
success(`Task ready for review! ${totalDuration}`);
|
|
6750
7297
|
await sendTaskNotification(configManager, "task:review", normalizedId, task.title);
|
|
6751
7298
|
if (options.sound !== false) {
|
|
6752
7299
|
await playSound("review");
|
|
@@ -6793,13 +7340,17 @@ var startCommand = defineCommand({
|
|
|
6793
7340
|
{
|
|
6794
7341
|
flags: "--dry-run",
|
|
6795
7342
|
description: "Show what would be executed without running"
|
|
7343
|
+
},
|
|
7344
|
+
{
|
|
7345
|
+
flags: "--no-skip-ci",
|
|
7346
|
+
description: "Write the status commit without the CI-skip tag"
|
|
6796
7347
|
}
|
|
6797
7348
|
],
|
|
6798
7349
|
handler: async (taskId, options) => {
|
|
6799
7350
|
await startTask(taskId, options);
|
|
6800
7351
|
}
|
|
6801
7352
|
});
|
|
6802
|
-
async function startTask(taskId,
|
|
7353
|
+
async function startTask(taskId, options, gitService) {
|
|
6803
7354
|
requireTaskinProject();
|
|
6804
7355
|
printHeader(`Starting Task ${taskId}`, "\u{1F680}");
|
|
6805
7356
|
const normalizedId = normalizeTaskId(taskId);
|
|
@@ -6819,12 +7370,13 @@ async function startTask(taskId, _options, gitService) {
|
|
|
6819
7370
|
info(`Current status: ${task.status}`);
|
|
6820
7371
|
const configManager = new ConfigManager(monorepoRoot);
|
|
6821
7372
|
const behavior = configManager.getAutomationBehavior();
|
|
7373
|
+
const ciSkipTag = resolveCiSkipTag(behavior.ciSkipTag, options.skipCi);
|
|
6822
7374
|
const statusCommitMessage = buildTaskStatusCommitMessage({
|
|
6823
7375
|
taskId: normalizedId,
|
|
6824
7376
|
status: "in-progress",
|
|
6825
|
-
ciSkipTag
|
|
7377
|
+
ciSkipTag
|
|
6826
7378
|
});
|
|
6827
|
-
if (
|
|
7379
|
+
if (options.dryRun) {
|
|
6828
7380
|
console.log();
|
|
6829
7381
|
info("\u{1F50D} Dry run mode - showing what would be executed:");
|
|
6830
7382
|
console.log();
|
|
@@ -6839,7 +7391,7 @@ async function startTask(taskId, _options, gitService) {
|
|
|
6839
7391
|
)
|
|
6840
7392
|
);
|
|
6841
7393
|
console.log();
|
|
6842
|
-
info("
|
|
7394
|
+
info("Dry run complete");
|
|
6843
7395
|
return;
|
|
6844
7396
|
}
|
|
6845
7397
|
if (task.status === "in-progress") {
|
|
@@ -6854,11 +7406,11 @@ async function startTask(taskId, _options, gitService) {
|
|
|
6854
7406
|
const updatedTask = await taskManager.startTask(task.id);
|
|
6855
7407
|
success(`Task ${updatedTask.id} started successfully!`);
|
|
6856
7408
|
success(`Status changed to: ${updatedTask.status}`);
|
|
6857
|
-
const git = gitService ?? new GitService(process.cwd(), { ciSkipTag
|
|
7409
|
+
const git = gitService ?? new GitService(process.cwd(), { ciSkipTag });
|
|
6858
7410
|
if (behavior.autoCommitStatusChange) {
|
|
6859
7411
|
const committed = await git.commitTaskStatusChangeOnBranch(normalizedId, "in-progress", behavior.defaultBranch);
|
|
6860
7412
|
if (committed) {
|
|
6861
|
-
success("
|
|
7413
|
+
success("Auto-committed status change");
|
|
6862
7414
|
}
|
|
6863
7415
|
}
|
|
6864
7416
|
console.log();
|
|
@@ -6880,7 +7432,7 @@ async function startTask(taskId, _options, gitService) {
|
|
|
6880
7432
|
}
|
|
6881
7433
|
console.log();
|
|
6882
7434
|
await sendTaskNotification(configManager, "task:start", normalizedId, task.title);
|
|
6883
|
-
if (
|
|
7435
|
+
if (options.sound !== false) {
|
|
6884
7436
|
playSound("start");
|
|
6885
7437
|
}
|
|
6886
7438
|
}
|
|
@@ -6890,7 +7442,7 @@ init_esm_shims();
|
|
|
6890
7442
|
init_src3();
|
|
6891
7443
|
init_src();
|
|
6892
7444
|
import chalk7 from "chalk";
|
|
6893
|
-
import
|
|
7445
|
+
import path15 from "path";
|
|
6894
7446
|
var statsCommand = defineCommand({
|
|
6895
7447
|
name: "stats",
|
|
6896
7448
|
description: "\u{1F4CA} Show user/team metrics and statistics",
|
|
@@ -6922,7 +7474,7 @@ var statsCommand = defineCommand({
|
|
|
6922
7474
|
});
|
|
6923
7475
|
async function showStats(options) {
|
|
6924
7476
|
requireTaskinProject();
|
|
6925
|
-
const tasksDir =
|
|
7477
|
+
const tasksDir = path15.join(process.cwd(), "TASKS");
|
|
6926
7478
|
const { userRegistry } = await resolveTaskProvider();
|
|
6927
7479
|
const gitAnalyzer = new GitAnalyzer(process.cwd());
|
|
6928
7480
|
const metricsAdapter = new FileSystemMetricsAdapter(tasksDir, userRegistry, gitAnalyzer);
|
|
@@ -7077,102 +7629,73 @@ function getStatusEmoji(status) {
|
|
|
7077
7629
|
|
|
7078
7630
|
// src/lib/help.ts
|
|
7079
7631
|
init_esm_shims();
|
|
7080
|
-
|
|
7632
|
+
var EXEMPLOS = {
|
|
7633
|
+
init: ["taskin init", "taskin setup"],
|
|
7634
|
+
list: ["taskin list", "taskin list pending", "taskin list --status in-progress", "taskin list --type feat"],
|
|
7635
|
+
new: [
|
|
7636
|
+
'taskin new -t feat -T "Add login" -d "Implement user authentication"',
|
|
7637
|
+
'taskin new --type fix --title "Fix bug" --user "John"',
|
|
7638
|
+
'taskin create -t docs -T "Update README"'
|
|
7639
|
+
],
|
|
7640
|
+
start: ["taskin start 001", "taskin start task-001", "taskin start 001 --force"],
|
|
7641
|
+
pause: ["taskin pause 001", 'taskin pause 001 -m "saving progress"'],
|
|
7642
|
+
review: ["taskin review 001", "taskin review 001 --dry-run"],
|
|
7643
|
+
finish: ["taskin finish 001", "taskin done task-001"],
|
|
7644
|
+
stats: ["taskin stats", "taskin stats --team", "taskin stats --period month"],
|
|
7645
|
+
config: ["taskin config", "taskin config --level assisted", "taskin config --show"],
|
|
7646
|
+
export: ["taskin export", "taskin export --format json"],
|
|
7647
|
+
lint: ["taskin lint", "taskin lint --fix", "taskin lint --fix --metadata-style=list"],
|
|
7648
|
+
dashboard: ["taskin dashboard", "taskin dashboard --port 3000", "taskin dashboard --filter-open"],
|
|
7649
|
+
"mcp-install": ["taskin mcp-install", "taskin mcp-install --force", "taskin mcp-install --no-probe"],
|
|
7650
|
+
"mcp-server": ["taskin mcp-server", "taskin mcp"],
|
|
7651
|
+
notify: ["taskin notify --event task:done --task 001"]
|
|
7652
|
+
};
|
|
7653
|
+
var ICONE_PADRAO = "\u2022";
|
|
7654
|
+
function separarIcone(descricao) {
|
|
7655
|
+
const match = descricao.match(new RegExp("^(\\p{Extended_Pictographic}\\uFE0F?)\\s+(.*)$", "su"));
|
|
7656
|
+
return match?.[1] && match[2] !== void 0 ? { icone: match[1], texto: match[2] } : { icone: ICONE_PADRAO, texto: descricao };
|
|
7657
|
+
}
|
|
7658
|
+
var OCULTOS = ["help"];
|
|
7659
|
+
function assinatura(cmd) {
|
|
7660
|
+
const argumentos = cmd.usage().replace("[options]", "").trim();
|
|
7661
|
+
const nome = colors.highlight(`taskin ${cmd.name()}`);
|
|
7662
|
+
return argumentos ? nome + colors.normal(` ${argumentos}`) : nome;
|
|
7663
|
+
}
|
|
7664
|
+
function detalhes(cmd) {
|
|
7665
|
+
const partes = [];
|
|
7666
|
+
const aliases = cmd.aliases();
|
|
7667
|
+
if (aliases.length > 0) {
|
|
7668
|
+
partes.push(`Alias: ${aliases.join(", ")}`);
|
|
7669
|
+
}
|
|
7670
|
+
const flags = cmd.options.map((opcao) => opcao.flags.split(",")[0]?.trim()).filter(Boolean);
|
|
7671
|
+
if (flags.length > 0) {
|
|
7672
|
+
partes.push(`Options: ${flags.join(", ")}`);
|
|
7673
|
+
}
|
|
7674
|
+
return partes.length > 0 ? partes.join(" \xB7 ") : void 0;
|
|
7675
|
+
}
|
|
7676
|
+
function showCustomHelp(program2) {
|
|
7081
7677
|
printHeader("Taskin - Task Management System", icons.rocket);
|
|
7082
7678
|
console.log(colors.info("\u{1F4CB} AVAILABLE COMMANDS"));
|
|
7083
7679
|
console.log(colors.highlight("\u2550".repeat(60)));
|
|
7084
7680
|
console.log();
|
|
7085
|
-
const
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
name: colors.highlight("taskin new"),
|
|
7102
|
-
alias: colors.secondary("Alias: create"),
|
|
7103
|
-
description: "Create a new task",
|
|
7104
|
-
examples: [
|
|
7105
|
-
'taskin new -t feat -T "Add login" -d "Implement user authentication"',
|
|
7106
|
-
'taskin new --type fix --title "Fix bug" --user "John"',
|
|
7107
|
-
'taskin create -t docs -T "Update README"'
|
|
7108
|
-
],
|
|
7109
|
-
icon: "\u{1F4DD}"
|
|
7110
|
-
},
|
|
7111
|
-
{
|
|
7112
|
-
name: colors.highlight("taskin start") + colors.normal(" <task-id>"),
|
|
7113
|
-
alias: colors.secondary("Alias: begin"),
|
|
7114
|
-
description: "Start working on a task (suggests commits)",
|
|
7115
|
-
examples: ["taskin start 001", "taskin start task-001", "taskin start 001 --force"],
|
|
7116
|
-
icon: "\u{1F680}"
|
|
7117
|
-
},
|
|
7118
|
-
{
|
|
7119
|
-
name: colors.highlight("taskin pause") + colors.normal(" <task-id>"),
|
|
7120
|
-
alias: colors.secondary("Alias: stop"),
|
|
7121
|
-
description: "Pause a task (auto-commits work in progress)",
|
|
7122
|
-
examples: ["taskin pause 001", 'taskin pause 001 -m "saving progress"'],
|
|
7123
|
-
icon: "\u23F8\uFE0F"
|
|
7124
|
-
},
|
|
7125
|
-
{
|
|
7126
|
-
name: colors.highlight("taskin finish") + colors.normal(" <task-id>"),
|
|
7127
|
-
alias: colors.secondary("Alias: done"),
|
|
7128
|
-
description: "Finish a task (suggests commits)",
|
|
7129
|
-
examples: ["taskin finish 001", "taskin done task-001"],
|
|
7130
|
-
icon: "\u2705"
|
|
7131
|
-
},
|
|
7132
|
-
{
|
|
7133
|
-
name: colors.highlight("taskin config") + colors.normal(" [options]"),
|
|
7134
|
-
alias: colors.secondary("Options: --level <manual|assisted|autopilot>"),
|
|
7135
|
-
description: "Configure automation level",
|
|
7136
|
-
examples: ["taskin config", "taskin config --level assisted", "taskin config --level autopilot"],
|
|
7137
|
-
icon: "\u2699\uFE0F"
|
|
7138
|
-
},
|
|
7139
|
-
{
|
|
7140
|
-
name: colors.highlight("taskin lint") + colors.normal(" [options]"),
|
|
7141
|
-
alias: colors.secondary("Options: -p, --path <directory>"),
|
|
7142
|
-
description: "Validate task markdown files",
|
|
7143
|
-
examples: ["taskin lint", "taskin lint --path ./TASKS", "taskin lint -p /path/to/tasks"],
|
|
7144
|
-
icon: "\u{1F50D}"
|
|
7145
|
-
},
|
|
7146
|
-
{
|
|
7147
|
-
name: colors.highlight("taskin dashboard") + colors.normal(" [options]"),
|
|
7148
|
-
alias: colors.secondary("Options: --host, --port, --filter-open, --filter-closed"),
|
|
7149
|
-
description: "Start the web dashboard",
|
|
7150
|
-
examples: [
|
|
7151
|
-
"taskin dashboard",
|
|
7152
|
-
"taskin dashboard --port 3000",
|
|
7153
|
-
"taskin dashboard --filter-open",
|
|
7154
|
-
"taskin dashboard --filter-closed -o"
|
|
7155
|
-
],
|
|
7156
|
-
icon: "\u{1F4CA}"
|
|
7157
|
-
},
|
|
7158
|
-
{
|
|
7159
|
-
name: colors.highlight("taskin mcp-server"),
|
|
7160
|
-
alias: colors.secondary("Alias: mcp"),
|
|
7161
|
-
description: "Start MCP server for Claude Desktop integration",
|
|
7162
|
-
examples: ["taskin mcp-server", "taskin mcp"],
|
|
7163
|
-
icon: "\u{1F916}"
|
|
7681
|
+
const comandos = program2.commands.filter((cmd) => !OCULTOS.includes(cmd.name()));
|
|
7682
|
+
comandos.forEach((cmd, index) => {
|
|
7683
|
+
const exemplos = EXEMPLOS[cmd.name()] ?? [];
|
|
7684
|
+
const { icone, texto } = separarIcone(cmd.description());
|
|
7685
|
+
console.log(colors.warning(`${icone} ${assinatura(cmd)}`));
|
|
7686
|
+
const linhaDeDetalhes = detalhes(cmd);
|
|
7687
|
+
if (linhaDeDetalhes) {
|
|
7688
|
+
console.log(colors.normal(` ${colors.secondary(linhaDeDetalhes)}`));
|
|
7689
|
+
}
|
|
7690
|
+
console.log(colors.info(` ${texto}`));
|
|
7691
|
+
if (exemplos.length > 0) {
|
|
7692
|
+
console.log();
|
|
7693
|
+
console.log(colors.normal(` ${colors.info("\u{1F4DD} Examples:")}`));
|
|
7694
|
+
for (const exemplo of exemplos) {
|
|
7695
|
+
console.log(colors.secondary(` ${exemplo}`));
|
|
7696
|
+
}
|
|
7164
7697
|
}
|
|
7165
|
-
|
|
7166
|
-
commands.forEach((cmd, index) => {
|
|
7167
|
-
console.log(colors.warning(`${cmd.icon} ${cmd.name}`));
|
|
7168
|
-
console.log(colors.normal(` ${cmd.alias}`));
|
|
7169
|
-
console.log(colors.info(` ${cmd.description}`));
|
|
7170
|
-
console.log();
|
|
7171
|
-
console.log(colors.normal(` ${colors.info("\u{1F4DD} Examples:")}`));
|
|
7172
|
-
cmd.examples.forEach((example) => {
|
|
7173
|
-
console.log(colors.secondary(` ${example}`));
|
|
7174
|
-
});
|
|
7175
|
-
if (index < commands.length - 1) {
|
|
7698
|
+
if (index < comandos.length - 1) {
|
|
7176
7699
|
console.log();
|
|
7177
7700
|
console.log(colors.normal(` ${colors.secondary("\u2500".repeat(50))}`));
|
|
7178
7701
|
console.log();
|
|
@@ -7207,7 +7730,7 @@ function showCustomHelp() {
|
|
|
7207
7730
|
|
|
7208
7731
|
// src/version.ts
|
|
7209
7732
|
init_esm_shims();
|
|
7210
|
-
import { readFileSync as
|
|
7733
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
7211
7734
|
import { dirname, join as join4 } from "path";
|
|
7212
7735
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7213
7736
|
var __filename3 = fileURLToPath3(import.meta.url);
|
|
@@ -7215,7 +7738,7 @@ var __dirname3 = dirname(__filename3);
|
|
|
7215
7738
|
function getVersion() {
|
|
7216
7739
|
try {
|
|
7217
7740
|
const packageJsonPath = join4(__dirname3, "../package.json");
|
|
7218
|
-
const packageJson = JSON.parse(
|
|
7741
|
+
const packageJson = JSON.parse(readFileSync6(packageJsonPath, "utf-8"));
|
|
7219
7742
|
return packageJson.version;
|
|
7220
7743
|
} catch {
|
|
7221
7744
|
return "0.0.0";
|
|
@@ -7574,7 +8097,7 @@ var program = new Command();
|
|
|
7574
8097
|
program.name("taskin").description("\u{1F680} Task Management System").version(getVersion());
|
|
7575
8098
|
program.helpOption("-h, --help", "Display help information");
|
|
7576
8099
|
program.command("help").description("Show help information").action(() => {
|
|
7577
|
-
showCustomHelp();
|
|
8100
|
+
showCustomHelp(program);
|
|
7578
8101
|
});
|
|
7579
8102
|
initCommand(program);
|
|
7580
8103
|
listCommand(program);
|
|
@@ -7588,18 +8111,19 @@ configCommand(program);
|
|
|
7588
8111
|
registerExportCommand(program);
|
|
7589
8112
|
lintCommand(program);
|
|
7590
8113
|
dashboardCommand(program);
|
|
8114
|
+
mcpInstallCommand(program);
|
|
7591
8115
|
mcpServerCommand(program);
|
|
7592
8116
|
notifyCommand(program);
|
|
7593
8117
|
program.on("option:help", () => {
|
|
7594
|
-
showCustomHelp();
|
|
8118
|
+
showCustomHelp(program);
|
|
7595
8119
|
process.exit(0);
|
|
7596
8120
|
});
|
|
7597
8121
|
if (process.argv.length <= 2) {
|
|
7598
|
-
showCustomHelp();
|
|
8122
|
+
showCustomHelp(program);
|
|
7599
8123
|
process.exit(0);
|
|
7600
8124
|
}
|
|
7601
8125
|
if (process.argv.length === 3 && (process.argv[2] === "--help" || process.argv[2] === "-h")) {
|
|
7602
|
-
showCustomHelp();
|
|
8126
|
+
showCustomHelp(program);
|
|
7603
8127
|
process.exit(0);
|
|
7604
8128
|
}
|
|
7605
8129
|
program.parse();
|