jarvis-ai-framework 1.0.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/AGENTS.md +416 -0
- package/LICENSE +21 -0
- package/README.md +190 -0
- package/agents/AGENTS.md +234 -0
- package/agents/README.md +309 -0
- package/agents/engineering/data/eng.data-engineer.agent.md +309 -0
- package/agents/engineering/eng.agent.md +303 -0
- package/agents/engineering/eng.bug-hunter.md +386 -0
- package/agents/engineering/eng.cybersecurity.agent.md +503 -0
- package/agents/engineering/eng.dev-code-reviewer.md +148 -0
- package/agents/engineering/eng.docs-writer.md +152 -0
- package/agents/engineering/eng.frontend.agent.md +117 -0
- package/agents/engineering/eng.rpa.agent.md +215 -0
- package/agents/engineering/eng.tech-analyst.agent.md +102 -0
- package/agents/engineering/eng.ux-designer.agent.md +193 -0
- package/agents/engineering/qa/eng.qa.cypress-specialist.md +109 -0
- package/agents/engineering/qa/eng.qa.quality-champion-task-agent.md +85 -0
- package/agents/engineering/qa/eng.qa.quality-strategist.md +111 -0
- package/agents/engineering/qa/eng.qa.test-architect.md +400 -0
- package/agents/engineering/qa/eng.qa.test-planner.md +477 -0
- package/agents/engineering/qa/eng.qa.testing-engineer.md +339 -0
- package/agents/product/prod.pm-checker.md +52 -0
- package/bin/commands/docs-publish.js +184 -0
- package/bin/commands/docs-sync.js +139 -0
- package/bin/commands/info.js +87 -0
- package/bin/commands/init.js +237 -0
- package/bin/commands/install-rtk.js +90 -0
- package/bin/commands/list.js +48 -0
- package/bin/commands/qa-signoff.js +112 -0
- package/bin/commands/whoami.js +43 -0
- package/bin/jarvis.js +159 -0
- package/bin/lib/auth/session.js +56 -0
- package/bin/lib/config/constants.js +123 -0
- package/bin/lib/config/ide-config.js +233 -0
- package/bin/lib/core/scanner.js +124 -0
- package/bin/lib/core/sync-engine.js +551 -0
- package/bin/lib/docs/fetch-file.sh +41 -0
- package/bin/lib/docs/publish-file.sh +284 -0
- package/bin/lib/docs/validate-frontmatter.js +157 -0
- package/bin/lib/env-loader.js +198 -0
- package/bin/lib/tasks/comment.js +131 -0
- package/bin/lib/utils/git-parser.js +145 -0
- package/bin/lib/utils/logger.js +104 -0
- package/bin/lib/utils/npmrc-parser.js +106 -0
- package/bin/lib/utils/paths.js +55 -0
- package/bin/lib/utils/ui.js +59 -0
- package/bin/lib/vcs/api.js +312 -0
- package/bin/lib/vcs/create-issue.js +43 -0
- package/bin/lib/vcs/create-merge.js +43 -0
- package/bin/lib/vcs/fetch-raw.js +30 -0
- package/bin/postinstall.js +41 -0
- package/members.md +25 -0
- package/package.json +55 -0
- package/rules/AGENTS.md +205 -0
- package/rules/engineering/data/data-rules.md +200 -0
- package/rules/engineering/eng-rules.md +243 -0
- package/rules/engineering/eng-security-rules.md +186 -0
- package/rules/engineering/eng.breakdown-subtasks-rules.md +585 -0
- package/rules/engineering/eng.bump-rules.md +27 -0
- package/rules/engineering/eng.docs-scraping-rules.md +64 -0
- package/rules/engineering/eng.downstream-flow-rules.md +297 -0
- package/rules/engineering/eng.integrations-rules.md +73 -0
- package/rules/engineering/eng.plan-rules.md +333 -0
- package/rules/engineering/eng.pr-rules.md +359 -0
- package/rules/engineering/eng.pre-pr-rules.md +103 -0
- package/rules/engineering/eng.start-rules.md +246 -0
- package/rules/engineering/eng.tech-spec-rules.md +968 -0
- package/rules/engineering/eng.work-rules.md +312 -0
- package/rules/engineering/frontend/eng.frontend-rules.md +147 -0
- package/rules/engineering/qa/eng.qa.cypress-standards-rules.md +259 -0
- package/rules/engineering/qa/eng.qa.exploratory-session-rules.md +137 -0
- package/rules/engineering/qa/eng.qa.quality-gate-scoring-rules.md +181 -0
- package/rules/engineering/qa/eng.qa.tech-spec-validation-criteria-rules.md +120 -0
- package/rules/engineering/rpa/eng.rpa-rules.md +230 -0
- package/rules/product/README.md +24 -0
- package/rules/product/prod-rules.md +151 -0
- package/rules/rtk-rules.md +68 -0
- package/skills/AGENTS.md +290 -0
- package/skills/SKILLS-ROADMAP.md +333 -0
- package/skills/churn-audit/SKILL.md +385 -0
- package/skills/context-detect/SKILL.md +399 -0
- package/skills/context-detect/assets/context-profile-template.md +127 -0
- package/skills/docs-central/README.md +310 -0
- package/skills/docs-central/SKILL.md +423 -0
- package/skills/docs-index/SKILL.md +377 -0
- package/skills/eng-ai-engineer/SKILL.md +296 -0
- package/skills/eng-arch-c4/SKILL.md +358 -0
- package/skills/eng-arch-c4/assets/example-code.md +189 -0
- package/skills/eng-arch-c4/assets/example-component.md +105 -0
- package/skills/eng-arch-c4/assets/example-container.md +104 -0
- package/skills/eng-arch-c4/assets/example-context.md +81 -0
- package/skills/eng-backend/SKILL.md +776 -0
- package/skills/eng-browser-extension-builder/SKILL.md +385 -0
- package/skills/eng-cybersecurity/SKILL.md +645 -0
- package/skills/eng-data-bi/SKILL.md +199 -0
- package/skills/eng-data-debug/SKILL.md +307 -0
- package/skills/eng-data-engineer/SKILL.md +256 -0
- package/skills/eng-data-onboard/SKILL.md +310 -0
- package/skills/eng-data-orchestrator/SKILL.md +426 -0
- package/skills/eng-design-system/SKILL.md +619 -0
- package/skills/eng-docs-write/SKILL.md +312 -0
- package/skills/eng-frontend/SKILL.md +913 -0
- package/skills/eng-jira-comment/SKILL.md +17 -0
- package/skills/eng-microfrontend/SKILL.md +602 -0
- package/skills/eng-ms-trace/SKILL.md +469 -0
- package/skills/eng-nestjs/SKILL.md +791 -0
- package/skills/eng-performance-engineer/SKILL.md +312 -0
- package/skills/eng-pr/SKILL.md +339 -0
- package/skills/eng-qa-a11y-audit/SKILL.md +269 -0
- package/skills/eng-qa-bug-report/SKILL.md +1088 -0
- package/skills/eng-qa-bug-report/TASK_MANAGERS.md +138 -0
- package/skills/eng-qa-cypress-e2e/SKILL.md +177 -0
- package/skills/eng-qa-dev-guide/SKILL.md +164 -0
- package/skills/eng-qa-e2e/SKILL.md +400 -0
- package/skills/eng-qa-e2e-spec-writer/SKILL.md +322 -0
- package/skills/eng-qa-exploratory/SKILL.md +188 -0
- package/skills/eng-qa-gate/SKILL.md +370 -0
- package/skills/eng-qa-gate/assets/checklist-validacao.md +291 -0
- package/skills/eng-qa-graphql-contract/SKILL.md +256 -0
- package/skills/eng-qa-quality-report/SKILL.md +412 -0
- package/skills/eng-qa-test-plan/SKILL.md +466 -0
- package/skills/eng-qa-test-plan/assets/test-coverage-template.md +92 -0
- package/skills/eng-qa-test-plan/assets/test-patterns.md +178 -0
- package/skills/eng-qa-testsprite/SKILL.md +325 -0
- package/skills/eng-qa-testsprite/references/testsprite-mcp.md +224 -0
- package/skills/eng-qa-unit-test/SKILL.md +471 -0
- package/skills/eng-rabbitmq/SKILL.md +661 -0
- package/skills/eng-scraper/SKILL.md +683 -0
- package/skills/eng-scraper-robot-builder/SKILL.md +370 -0
- package/skills/eng-security-patch/SKILL.md +378 -0
- package/skills/eng-security-triage/SKILL.md +266 -0
- package/skills/eng-task-comment/SKILL.md +60 -0
- package/skills/eng-tech-analyst/SKILL.md +529 -0
- package/skills/eng-threat-model/SKILL.md +161 -0
- package/skills/init-jarvis/SKILL.md +1304 -0
- package/skills/init-jarvis/assets/mcp-configs.md +389 -0
- package/skills/init-jarvis/assets/onboarding-checklist.md +104 -0
- package/skills/init-jarvis/assets/setup-guide.md +360 -0
- package/skills/lovable-prompt-generator/SKILL.md +304 -0
- package/skills/prod-roadmap-report/README.md +303 -0
- package/skills/prod-roadmap-report/SKILL.md +198 -0
- package/skills/prod-roadmap-report/commands/status.compiled.single.team.md +23 -0
- package/skills/prod-roadmap-report/commands/status.list.projects.md +17 -0
- package/skills/prod-roadmap-report/commands/status.memory.md +192 -0
- package/skills/prod-roadmap-report/commands/status.roadmap.preview.md +94 -0
- package/skills/prod-roadmap-report/references/detailed-guide.md +236 -0
- package/skills/prod-roadmap-report/rules/detailed-guide.md +237 -0
- package/skills/prod-roadmap-report/rules/status-report-rules.md +44 -0
- package/skills/prod-roadmap-report/templates/template-multiple-teams-compiled-status.md +53 -0
- package/skills/prod-roadmap-report/templates/template-projects-list.md +23 -0
- package/skills/prod-roadmap-report/templates/template-single-team-compiled-status.md +60 -0
- package/skills/prod-roadmap-report/templates/template-single-team-status.md +49 -0
- package/skills/prod-specs/SKILL.md +108 -0
- package/skills/prod-specs/references/prod.spec.clarify.md +176 -0
- package/skills/prod-specs/references/prod.spec.epic.md +107 -0
- package/skills/prod-specs/references/prod.spec.frd.md +135 -0
- package/skills/prod-specs/references/prod.spec.issue.md +145 -0
- package/skills/prod-specs/references/prod.spec.prd.md +118 -0
- package/skills/prod-specs/rules/prod-spec-rules.md +186 -0
- package/skills/prod-specs/templates/prod-breakdown-template.md +136 -0
- package/skills/prod-specs/templates/prod-epic-template.md +76 -0
- package/skills/prod-specs/templates/prod-frd-template.md +172 -0
- package/skills/prod-specs/templates/prod-issue-template.md +68 -0
- package/skills/prod-specs/templates/prod-prd-full-template.md +159 -0
- package/skills/prod-specs/templates/prod-prd-template.md +173 -0
- package/skills/prod-specs-update/SKILL.md +272 -0
- package/skills/report-issue/SKILL.md +156 -0
- package/taxonomy.md +270 -0
- package/templates/AGENTS.md +189 -0
- package/templates/CDD aplicado a Prompts.md +182 -0
- package/templates/ENV-template.md +187 -0
- package/templates/engineering/AGENTS-template.md +71 -0
- package/templates/engineering/ARD-template.md +193 -0
- package/templates/engineering/CONTACTS-template.md +135 -0
- package/templates/engineering/PR-template.md +40 -0
- package/templates/engineering/RFC-Playbook.md +325 -0
- package/templates/engineering/RFC-template.md +199 -0
- package/templates/engineering/architecture-template.md +277 -0
- package/templates/engineering/breakdown-subtasks-template.md +582 -0
- package/templates/engineering/c4-model-template.md +516 -0
- package/templates/engineering/data-contract-template.md +135 -0
- package/templates/engineering/data-pipeline-template.md +163 -0
- package/templates/engineering/plan-template.md +255 -0
- package/templates/engineering/qa/eng.qa.quality-gate-examples-template.md +311 -0
- package/templates/engineering/qa/eng.qa.quality-gate-report-template.md +249 -0
- package/templates/engineering/qa/qa.cypress-test-template.md +172 -0
- package/templates/engineering/qa/qa.exploratory-session-template.md +148 -0
- package/templates/engineering/qa/qa.quality-report-template.md +130 -0
- package/templates/engineering/qa/qa.release-signoff-template.md +54 -0
- package/templates/engineering/qa/qa.sprint-plan-template.md +49 -0
- package/templates/engineering/swagger-template.md +145 -0
- package/templates/engineering/tech-spec-template.md +497 -0
- package/templates/engineering/work-progress-template.md +155 -0
- package/workflows/AGENTS.md +240 -0
- package/workflows/README.md +160 -0
- package/workflows/all-tools.md +11 -0
- package/workflows/engineering/data/data.contract.md +202 -0
- package/workflows/engineering/data/data.new-pipeline.md +234 -0
- package/workflows/engineering/eng.breakdown-subtasks.md +420 -0
- package/workflows/engineering/eng.bug-audit.md +591 -0
- package/workflows/engineering/eng.build-tech-spec.md +1116 -0
- package/workflows/engineering/eng.create-ard-from-code.md +259 -0
- package/workflows/engineering/eng.create-ard.md +382 -0
- package/workflows/engineering/eng.create-rfc.md +245 -0
- package/workflows/engineering/eng.debug.md +479 -0
- package/workflows/engineering/eng.docs.md +40 -0
- package/workflows/engineering/eng.light-arch.md +84 -0
- package/workflows/engineering/eng.plan.md +213 -0
- package/workflows/engineering/eng.pr.md +466 -0
- package/workflows/engineering/eng.pre-pr.md +167 -0
- package/workflows/engineering/eng.review.md +185 -0
- package/workflows/engineering/eng.rpa.robot.md +342 -0
- package/workflows/engineering/eng.security-audit.md +312 -0
- package/workflows/engineering/eng.security-incident.md +275 -0
- package/workflows/engineering/eng.security-pipeline.md +210 -0
- package/workflows/engineering/eng.security-review.md +235 -0
- package/workflows/engineering/eng.start.md +494 -0
- package/workflows/engineering/eng.work.md +558 -0
- package/workflows/engineering/frontend/eng.frontend-component.md +190 -0
- package/workflows/engineering/frontend/eng.frontend-perf-audit.md +375 -0
- package/workflows/engineering/frontend/eng.frontend-review.md +185 -0
- package/workflows/engineering/qa/eng.qa-dev-quality-guide.md +51 -0
- package/workflows/engineering/qa/eng.qa-e2e-test-generation.md +51 -0
- package/workflows/engineering/qa/eng.qa-exploratory-session.md +60 -0
- package/workflows/engineering/qa/eng.qa-quality-gate-validation.md +202 -0
- package/workflows/engineering/qa/eng.qa-quality-report.md +83 -0
- package/workflows/engineering/qa/eng.qa-refinement-entry.md +83 -0
- package/workflows/engineering/qa/eng.qa-release-signoff.md +170 -0
- package/workflows/engineering/qa/eng.qa-sprint-planning.md +100 -0
- package/workflows/engineering/ta/eng.ta.atendimento.md +93 -0
- package/workflows/product/prod.roadmap.preview.md +110 -0
- package/workflows/product/prod.spec.breakdown.md +163 -0
- package/workflows/product/prod.spec.clarify.md +178 -0
- package/workflows/product/prod.spec.epic.md +154 -0
- package/workflows/product/prod.spec.frd.md +96 -0
- package/workflows/product/prod.spec.issue.md +145 -0
- package/workflows/product/prod.spec.md +60 -0
- package/workflows/product/prod.spec.prd.md +100 -0
- package/workflows/taxonomy.md +92 -0
- package/workflows/warm-up.md +574 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { cardUrl } from "../vcs/api.js";
|
|
2
|
+
|
|
3
|
+
function env(name) {
|
|
4
|
+
return String(process.env[name] || "").trim();
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function taskManager() {
|
|
8
|
+
return env("TASK_MANAGER").toLowerCase() || "jira";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function commentJira(cardKey, message) {
|
|
12
|
+
const base = env("TASK_MANAGER_URL_BASE").replace(/\/$/, "");
|
|
13
|
+
const token = env("TOKEN_TASK_MANAGER");
|
|
14
|
+
const email = env("USER");
|
|
15
|
+
if (!base || !token) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
"Jira: preencha TASK_MANAGER_URL_BASE e TOKEN_TASK_MANAGER no ENV.md",
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
const auth = email
|
|
21
|
+
? `Basic ${Buffer.from(`${email}:${token}`).toString("base64")}`
|
|
22
|
+
: `Bearer ${token}`;
|
|
23
|
+
const res = await fetch(`${base}/rest/api/3/issue/${cardKey}/comment`, {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: auth,
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
Accept: "application/json",
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify({
|
|
31
|
+
body: {
|
|
32
|
+
version: 1,
|
|
33
|
+
type: "doc",
|
|
34
|
+
content: [
|
|
35
|
+
{
|
|
36
|
+
type: "paragraph",
|
|
37
|
+
content: [{ type: "text", text: message }],
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
});
|
|
43
|
+
if (!res.ok) {
|
|
44
|
+
throw new Error(`Jira ${res.status}: ${await res.text()}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function commentLinear(cardKey, message) {
|
|
49
|
+
const token = env("TOKEN_TASK_MANAGER");
|
|
50
|
+
if (!token) throw new Error("Linear: preencha TOKEN_TASK_MANAGER no ENV.md");
|
|
51
|
+
const res = await fetch("https://api.linear.app/graphql", {
|
|
52
|
+
method: "POST",
|
|
53
|
+
headers: {
|
|
54
|
+
Authorization: token,
|
|
55
|
+
"Content-Type": "application/json",
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
query: `mutation($id: String!, $body: String!) {
|
|
59
|
+
commentCreate(input: { issueId: $id, body: $body }) { success }
|
|
60
|
+
}`,
|
|
61
|
+
variables: { id: cardKey, body: message },
|
|
62
|
+
}),
|
|
63
|
+
});
|
|
64
|
+
const json = await res.json();
|
|
65
|
+
if (!res.ok || json.errors) {
|
|
66
|
+
throw new Error(`Linear: ${JSON.stringify(json.errors || json)}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function commentGithub(cardKey, message) {
|
|
71
|
+
const token =
|
|
72
|
+
env("TOKEN_TASK_MANAGER") || env("GITHUB_TOKEN") || env("GH_TOKEN");
|
|
73
|
+
const base = env("TASK_MANAGER_URL_BASE").replace(/\/$/, "");
|
|
74
|
+
if (!token || !base) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
"GitHub Issues: TASK_MANAGER_URL_BASE (https://github.com/org/repo) e TOKEN_TASK_MANAGER/GITHUB_TOKEN",
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
const path = new URL(base).pathname.replace(/^\/+|\/+$/g, "");
|
|
80
|
+
const number = String(cardKey).replace(/^#/, "");
|
|
81
|
+
const res = await fetch(
|
|
82
|
+
`https://api.github.com/repos/${path}/issues/${number}/comments`,
|
|
83
|
+
{
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: {
|
|
86
|
+
Authorization: `Bearer ${token}`,
|
|
87
|
+
Accept: "application/vnd.github+json",
|
|
88
|
+
"Content-Type": "application/json",
|
|
89
|
+
},
|
|
90
|
+
body: JSON.stringify({ body: message }),
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
if (!res.ok) throw new Error(`GitHub ${res.status}: ${await res.text()}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function commentAsana(cardKey, message) {
|
|
97
|
+
const token = env("TOKEN_TASK_MANAGER");
|
|
98
|
+
if (!token) throw new Error("Asana: preencha TOKEN_TASK_MANAGER no ENV.md");
|
|
99
|
+
const res = await fetch(`https://app.asana.com/api/1.0/tasks/${cardKey}/stories`, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: {
|
|
102
|
+
Authorization: `Bearer ${token}`,
|
|
103
|
+
"Content-Type": "application/json",
|
|
104
|
+
},
|
|
105
|
+
body: JSON.stringify({ data: { text: message } }),
|
|
106
|
+
});
|
|
107
|
+
if (!res.ok) throw new Error(`Asana ${res.status}: ${await res.text()}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const cardKey = process.argv[2];
|
|
111
|
+
const message = process.argv.slice(3).join(" ");
|
|
112
|
+
|
|
113
|
+
if (!cardKey || !message) {
|
|
114
|
+
console.error("Uso: comment.js <TASK_MANAGER_KEY> <mensagem>");
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const tm = taskManager();
|
|
119
|
+
try {
|
|
120
|
+
if (tm === "linear") await commentLinear(cardKey, message);
|
|
121
|
+
else if (tm === "github") await commentGithub(cardKey, message);
|
|
122
|
+
else if (tm === "asana") await commentAsana(cardKey, message);
|
|
123
|
+
else await commentJira(cardKey, message);
|
|
124
|
+
|
|
125
|
+
const url = cardUrl(tm, env("TASK_MANAGER_URL_BASE"), cardKey);
|
|
126
|
+
console.log(`💬 Comentário adicionado em ${cardKey} (${tm})`);
|
|
127
|
+
if (url !== cardKey) console.log(` ${url}`);
|
|
128
|
+
} catch (err) {
|
|
129
|
+
console.error(`⚠️ Não foi possível comentar no card ${cardKey}: ${err.message}`);
|
|
130
|
+
process.exit(2);
|
|
131
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parseia URL de repositório Git (GitLab, GitHub, Bitbucket, self-hosted).
|
|
3
|
+
* Vendor: hostname, senão VERSION_CONTROL do ENV.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const VENDORS = {
|
|
7
|
+
gitlab: {
|
|
8
|
+
detect: (host) => host.includes("gitlab"),
|
|
9
|
+
apiBase: (origin, host) =>
|
|
10
|
+
host === "gitlab.com" ? "https://gitlab.com/api/v4" : `${origin}/api/v4`,
|
|
11
|
+
},
|
|
12
|
+
github: {
|
|
13
|
+
detect: (host) => host.includes("github"),
|
|
14
|
+
apiBase: (origin, host) =>
|
|
15
|
+
host === "github.com" ? "https://api.github.com" : `${origin}/api/v3`,
|
|
16
|
+
},
|
|
17
|
+
bitbucket: {
|
|
18
|
+
detect: (host) => host.includes("bitbucket"),
|
|
19
|
+
apiBase: () => "https://api.bitbucket.org/2.0",
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function normalizeGitUrl(url) {
|
|
24
|
+
let raw = String(url).trim();
|
|
25
|
+
const ssh = raw.match(/^git@([^:]+):(.+?)(\.git)?$/);
|
|
26
|
+
if (ssh) {
|
|
27
|
+
raw = `https://${ssh[1]}/${ssh[2].replace(/\.git$/, "")}`;
|
|
28
|
+
}
|
|
29
|
+
raw = raw.replace(/\.git$/, "");
|
|
30
|
+
return raw;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function detectVendor(host) {
|
|
34
|
+
const fromEnv = String(process.env.VERSION_CONTROL || "")
|
|
35
|
+
.trim()
|
|
36
|
+
.toLowerCase();
|
|
37
|
+
for (const [vendor, spec] of Object.entries(VENDORS)) {
|
|
38
|
+
if (spec.detect(host)) return vendor;
|
|
39
|
+
}
|
|
40
|
+
if (VENDORS[fromEnv]) return fromEnv;
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {string} url
|
|
46
|
+
* @returns {{
|
|
47
|
+
* vendor: 'gitlab'|'github'|'bitbucket',
|
|
48
|
+
* host: string,
|
|
49
|
+
* origin: string,
|
|
50
|
+
* projectPath: string,
|
|
51
|
+
* projectPathEncoded: string,
|
|
52
|
+
* owner: string,
|
|
53
|
+
* repo: string,
|
|
54
|
+
* apiBase: string,
|
|
55
|
+
* webBase: string,
|
|
56
|
+
* }}
|
|
57
|
+
*/
|
|
58
|
+
export function parseRepoUrl(url) {
|
|
59
|
+
if (!url || typeof url !== "string") {
|
|
60
|
+
throw new Error("URL do repositório vazia ou inválida");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const normalized = normalizeGitUrl(url);
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = new URL(normalized);
|
|
67
|
+
} catch {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`URL inválida: ${url}\n` +
|
|
70
|
+
"Formatos: https://github.com/org/repo.git | https://gitlab.com/grupo/repo.git | https://bitbucket.org/ws/repo.git",
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const host = parsed.hostname;
|
|
75
|
+
const origin = parsed.origin;
|
|
76
|
+
const projectPath = parsed.pathname.replace(/^\/+|\/+$/g, "");
|
|
77
|
+
if (!projectPath) {
|
|
78
|
+
throw new Error(`Project path vazio na URL: ${url}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const vendor = detectVendor(host);
|
|
82
|
+
if (!vendor) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Não foi possível detectar o vendor de ${host}.\n` +
|
|
85
|
+
"Defina VERSION_CONTROL=gitlab|github|bitbucket no ENV.md.",
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const parts = projectPath.split("/");
|
|
90
|
+
const repo = parts[parts.length - 1];
|
|
91
|
+
const owner = parts.slice(0, -1).join("/");
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
vendor,
|
|
95
|
+
host,
|
|
96
|
+
origin,
|
|
97
|
+
projectPath,
|
|
98
|
+
projectPathEncoded: encodeURIComponent(projectPath),
|
|
99
|
+
owner,
|
|
100
|
+
repo,
|
|
101
|
+
apiBase: VENDORS[vendor].apiBase(origin, host),
|
|
102
|
+
webBase: origin,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** @deprecated use parseRepoUrl */
|
|
107
|
+
export function parseGitLabUrl(url) {
|
|
108
|
+
const parsed = parseRepoUrl(url);
|
|
109
|
+
if (parsed.vendor !== "gitlab") {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`URL não é GitLab (${parsed.vendor}): ${url}\n` +
|
|
112
|
+
"Use parseRepoUrl() para GitHub/Bitbucket.",
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
return parsed;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function buildApiUrl(repoUrl, endpoint) {
|
|
119
|
+
const { vendor, apiBase, projectPathEncoded, owner, repo } =
|
|
120
|
+
parseRepoUrl(repoUrl);
|
|
121
|
+
if (vendor === "gitlab") {
|
|
122
|
+
return `${apiBase}/projects/${projectPathEncoded}/${endpoint}`;
|
|
123
|
+
}
|
|
124
|
+
if (vendor === "github") {
|
|
125
|
+
return `${apiBase}/repos/${owner}/${repo}/${endpoint}`;
|
|
126
|
+
}
|
|
127
|
+
return `${apiBase}/repositories/${owner}/${repo}/${endpoint}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function buildWebUrl(repoUrl, path) {
|
|
131
|
+
const { webBase, projectPath, vendor } = parseRepoUrl(repoUrl);
|
|
132
|
+
if (vendor === "gitlab") {
|
|
133
|
+
return `${webBase}/${projectPath}/${path}`;
|
|
134
|
+
}
|
|
135
|
+
if (vendor === "github") {
|
|
136
|
+
return `${webBase}/${projectPath}/${path}`;
|
|
137
|
+
}
|
|
138
|
+
return `${webBase}/${projectPath}/${path}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function mergeRequestPath(vendor, iid) {
|
|
142
|
+
if (vendor === "gitlab") return `-/merge_requests/${iid}`;
|
|
143
|
+
if (vendor === "github") return `pull/${iid}`;
|
|
144
|
+
return `pull-requests/${iid}`;
|
|
145
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Sistema de logging centralizado
|
|
3
|
+
* @module utils/logger
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {'debug' | 'info' | 'warn' | 'error' | 'silent'} LogLevel
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const LOG_LEVELS = {
|
|
11
|
+
debug: 0,
|
|
12
|
+
info: 1,
|
|
13
|
+
warn: 2,
|
|
14
|
+
error: 3,
|
|
15
|
+
silent: 99,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
let currentLevel = LOG_LEVELS.info;
|
|
19
|
+
let isTestMode = false;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Define o nível mínimo de log
|
|
23
|
+
* @param {LogLevel} level
|
|
24
|
+
*/
|
|
25
|
+
export function setLogLevel(level) {
|
|
26
|
+
currentLevel = LOG_LEVELS[level] ?? LOG_LEVELS.info;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Ativa modo de teste (silencia todos os logs)
|
|
31
|
+
* @param {boolean} enabled
|
|
32
|
+
*/
|
|
33
|
+
export function setTestMode(enabled) {
|
|
34
|
+
isTestMode = enabled;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Verifica se deve logar baseado no nível
|
|
39
|
+
* @private
|
|
40
|
+
* @param {number} level
|
|
41
|
+
* @returns {boolean}
|
|
42
|
+
*/
|
|
43
|
+
function shouldLog(level) {
|
|
44
|
+
return !isTestMode && level >= currentLevel;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Logger principal
|
|
49
|
+
*/
|
|
50
|
+
export const logger = {
|
|
51
|
+
/**
|
|
52
|
+
* Log de debug (desenvolvimento)
|
|
53
|
+
* @param {...any} args
|
|
54
|
+
*/
|
|
55
|
+
debug(...args) {
|
|
56
|
+
if (shouldLog(LOG_LEVELS.debug)) {
|
|
57
|
+
console.log(...args);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Log informativo
|
|
63
|
+
* @param {...any} args
|
|
64
|
+
*/
|
|
65
|
+
info(...args) {
|
|
66
|
+
if (shouldLog(LOG_LEVELS.info)) {
|
|
67
|
+
console.log(...args);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Log de aviso
|
|
73
|
+
* @param {...any} args
|
|
74
|
+
*/
|
|
75
|
+
warn(...args) {
|
|
76
|
+
if (shouldLog(LOG_LEVELS.warn)) {
|
|
77
|
+
console.warn(...args);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Log de erro
|
|
83
|
+
* @param {...any} args
|
|
84
|
+
*/
|
|
85
|
+
error(...args) {
|
|
86
|
+
if (shouldLog(LOG_LEVELS.error)) {
|
|
87
|
+
console.error(...args);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Detecta flags de verbosidade e configura logger
|
|
94
|
+
* @param {Object} flags - Flags do CLI
|
|
95
|
+
*/
|
|
96
|
+
export function configureFromFlags(flags) {
|
|
97
|
+
if (flags.quiet || flags.q) {
|
|
98
|
+
setLogLevel("error");
|
|
99
|
+
} else if (flags.verbose || flags.v) {
|
|
100
|
+
setLogLevel("debug");
|
|
101
|
+
} else if (flags.silent) {
|
|
102
|
+
setLogLevel("silent");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
|
|
6
|
+
function readNpmrcToken(hostFragment, cwd = process.cwd()) {
|
|
7
|
+
const paths = [join(cwd, ".npmrc"), join(homedir(), ".npmrc")];
|
|
8
|
+
const re = new RegExp(
|
|
9
|
+
`//[^\\s]*${hostFragment.replace(".", "\\.")}[^\\s]*:_authToken=([^\\s]+)`,
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
for (const path of paths) {
|
|
13
|
+
if (!existsSync(path)) continue;
|
|
14
|
+
try {
|
|
15
|
+
const content = readFileSync(path, "utf-8");
|
|
16
|
+
const match = content.match(re);
|
|
17
|
+
if (match?.[1]) return match[1];
|
|
18
|
+
} catch {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function ghCliToken() {
|
|
26
|
+
try {
|
|
27
|
+
const token = execSync("gh auth token", {
|
|
28
|
+
encoding: "utf-8",
|
|
29
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
30
|
+
}).trim();
|
|
31
|
+
return token || null;
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Token do vendor de Git (ENV / .npmrc / CLI).
|
|
39
|
+
* @param {'gitlab'|'github'|'bitbucket'|string} vendor
|
|
40
|
+
* @param {string} [cwd]
|
|
41
|
+
*/
|
|
42
|
+
export function getVcsToken(vendor, cwd = process.cwd()) {
|
|
43
|
+
const v = String(vendor || process.env.VERSION_CONTROL || "")
|
|
44
|
+
.trim()
|
|
45
|
+
.toLowerCase();
|
|
46
|
+
|
|
47
|
+
if (v === "github") {
|
|
48
|
+
const token =
|
|
49
|
+
process.env.GITHUB_TOKEN ||
|
|
50
|
+
process.env.GH_TOKEN ||
|
|
51
|
+
readNpmrcToken("npm.pkg.github.com", cwd) ||
|
|
52
|
+
readNpmrcToken("github.com", cwd) ||
|
|
53
|
+
ghCliToken();
|
|
54
|
+
if (token) return token;
|
|
55
|
+
throw new Error(
|
|
56
|
+
"Token GitHub não encontrado.\n" +
|
|
57
|
+
"Use `gh auth login`, ou defina GITHUB_TOKEN, ou //npm.pkg.github.com/:_authToken= no .npmrc.",
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (v === "bitbucket") {
|
|
62
|
+
const token =
|
|
63
|
+
process.env.BITBUCKET_TOKEN ||
|
|
64
|
+
readNpmrcToken("bitbucket.org", cwd);
|
|
65
|
+
if (token) return token;
|
|
66
|
+
throw new Error(
|
|
67
|
+
"Token Bitbucket não encontrado.\n" +
|
|
68
|
+
"Defina BITBUCKET_TOKEN (App Password) no ambiente.",
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const token =
|
|
73
|
+
process.env.GITLAB_TOKEN ||
|
|
74
|
+
readNpmrcToken("gitlab.com", cwd) ||
|
|
75
|
+
readNpmrcToken("gitlab", cwd);
|
|
76
|
+
if (token) return token;
|
|
77
|
+
throw new Error(
|
|
78
|
+
"Token GitLab não encontrado no .npmrc\n" +
|
|
79
|
+
"Configure:\n" +
|
|
80
|
+
" //gitlab.com/api/v4/packages/npm/:_authToken=seu-token\n" +
|
|
81
|
+
"Ou GITLAB_TOKEN no ambiente.",
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** @deprecated use getVcsToken('gitlab') */
|
|
86
|
+
export function getGitLabToken(cwd = process.cwd()) {
|
|
87
|
+
return getVcsToken("gitlab", cwd);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function hasGitLabToken(cwd = process.cwd()) {
|
|
91
|
+
try {
|
|
92
|
+
getVcsToken("gitlab", cwd);
|
|
93
|
+
return true;
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function hasVcsToken(vendor, cwd = process.cwd()) {
|
|
100
|
+
try {
|
|
101
|
+
getVcsToken(vendor, cwd);
|
|
102
|
+
return true;
|
|
103
|
+
} catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join, dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { IDES } from "../config/ide-config.js";
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
// From bin/lib/utils -> go up 3 levels to reach project root (both dev and production)
|
|
9
|
+
export const FRAMEWORK_ROOT = join(__dirname, "..", "..", "..");
|
|
10
|
+
|
|
11
|
+
export function getFrameworkRoot() {
|
|
12
|
+
if (process.env.JARVIS_ROOT && existsSync(process.env.JARVIS_ROOT)) {
|
|
13
|
+
return process.env.JARVIS_ROOT;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (existsSync(join(FRAMEWORK_ROOT, "agents"))) {
|
|
17
|
+
return FRAMEWORK_ROOT;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
throw new Error(
|
|
21
|
+
"Could not locate framework assets.\n" +
|
|
22
|
+
"Run: npm install jarvis-framework --save-dev",
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** @returns {{ name: string, version: string, root: string }} */
|
|
27
|
+
export function getPackageInfo() {
|
|
28
|
+
const root = getFrameworkRoot();
|
|
29
|
+
const pkgPath = join(root, "package.json");
|
|
30
|
+
if (!existsSync(pkgPath)) {
|
|
31
|
+
return { name: "jarvis-framework", version: "0.0.0", root };
|
|
32
|
+
}
|
|
33
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
34
|
+
return {
|
|
35
|
+
name: pkg.name || "jarvis-framework",
|
|
36
|
+
version: pkg.version || "0.0.0",
|
|
37
|
+
root,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function detectIDE(cwd) {
|
|
42
|
+
for (const ide of IDES) {
|
|
43
|
+
if (!ide.supported) continue;
|
|
44
|
+
const folder = ide.folderName || ide.value;
|
|
45
|
+
if (existsSync(join(cwd, `.${folder}`))) return ide.value;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function detectAllIDEs(cwd) {
|
|
51
|
+
return IDES
|
|
52
|
+
.filter((ide) => ide.supported)
|
|
53
|
+
.filter((ide) => existsSync(join(cwd, `.${ide.folderName || ide.value}`)))
|
|
54
|
+
.map((ide) => ide.value);
|
|
55
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { getPackageInfo } from "./paths.js";
|
|
2
|
+
|
|
3
|
+
export const RED = "\x1b[0;31m";
|
|
4
|
+
export const GREEN = "\x1b[0;32m";
|
|
5
|
+
export const BLUE = "\x1b[0;34m";
|
|
6
|
+
export const YELLOW = "\x1b[1;33m";
|
|
7
|
+
export const CYAN = "\x1b[0;36m";
|
|
8
|
+
export const DIM = "\x1b[2m";
|
|
9
|
+
export const BOLD = "\x1b[1m";
|
|
10
|
+
export const NC = "\x1b[0m";
|
|
11
|
+
|
|
12
|
+
export function showBanner() {
|
|
13
|
+
console.log(CYAN);
|
|
14
|
+
console.log("");
|
|
15
|
+
console.log(" ╔════════════════════════════════╗");
|
|
16
|
+
console.log(" ╔══╝ ╚══╗");
|
|
17
|
+
console.log(" ╔═╝ ┌────────────────────┐ ╚═╗");
|
|
18
|
+
console.log(" ╔═╝ │ J.A.R.V.I.S │ ╚═╗");
|
|
19
|
+
console.log(" ║ └────────────────────┘ ║");
|
|
20
|
+
console.log(" ║ ║");
|
|
21
|
+
console.log(" ║ ╭──────────────╮ ║");
|
|
22
|
+
console.log(" ║ ╭──╯ ╰──╮ ║");
|
|
23
|
+
console.log(" ║ ╭─╯ ◉ ◉ ╰─╮ ║");
|
|
24
|
+
console.log(" ║ │ │ ║");
|
|
25
|
+
console.log(" ║ │ ╲____╱ │ ║");
|
|
26
|
+
console.log(" ║ │ ──────────── │ ║");
|
|
27
|
+
console.log(" ║ ╰─╮ ╭─╯ ║");
|
|
28
|
+
console.log(" ║ ╰──╮ ╭──╯ ║");
|
|
29
|
+
console.log(" ║ ╰──────────────╯ ║");
|
|
30
|
+
console.log(" ║ ║");
|
|
31
|
+
console.log(" ╚═╗ ◇ STARK INDUSTRIES ◇ ╔═╝");
|
|
32
|
+
console.log(" ╚═╗ ╔═╝");
|
|
33
|
+
console.log(" ╚══╗ [ SYSTEM ONLINE ] ╔══╝");
|
|
34
|
+
console.log(" ╚════════════════════════════════╝");
|
|
35
|
+
console.log("");
|
|
36
|
+
console.log(" ──────── J . A . R . V . I . S ────────");
|
|
37
|
+
console.log(NC);
|
|
38
|
+
console.log(
|
|
39
|
+
`${DIM}Framework Jarvis para desenvolvimento assistido por IA${NC}`,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const pkg = getPackageInfo();
|
|
44
|
+
console.log("");
|
|
45
|
+
console.log(
|
|
46
|
+
`${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}`,
|
|
47
|
+
);
|
|
48
|
+
console.log(`${BOLD}${CYAN} ${pkg.name} v${pkg.version}${NC}`);
|
|
49
|
+
console.log(`${DIM} origem: ${pkg.root}${NC}`);
|
|
50
|
+
console.log(
|
|
51
|
+
`${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}`,
|
|
52
|
+
);
|
|
53
|
+
} catch {
|
|
54
|
+
// banner sem versão se assets não forem encontrados
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log("");
|
|
58
|
+
console.log("");
|
|
59
|
+
}
|