@pikaa-ai/pikaa 0.3.10 → 0.3.12
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/dist/cli.js +453 -12
- package/package.json +1 -1
- package/templates/base/groupy_prompt.md +4 -0
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
// src/cli/index.ts
|
|
5
5
|
import { resolve as resolve21 } from "path";
|
|
6
|
-
import { existsSync as
|
|
6
|
+
import { existsSync as existsSync21 } from "fs";
|
|
7
7
|
import { createInterface } from "readline";
|
|
8
8
|
|
|
9
9
|
// src/auth/store.ts
|
|
@@ -6043,7 +6043,7 @@ function parsePatch(oldSrc, newSrc, contextLines = 3) {
|
|
|
6043
6043
|
// package.json
|
|
6044
6044
|
var package_default = {
|
|
6045
6045
|
name: "@pikaa-ai/pikaa",
|
|
6046
|
-
version: "0.3.
|
|
6046
|
+
version: "0.3.12",
|
|
6047
6047
|
description: "PIKAA CLI - AI coding agent that runs locally in your terminal.",
|
|
6048
6048
|
main: "./dist/index.js",
|
|
6049
6049
|
module: "./dist/index.js",
|
|
@@ -7766,9 +7766,441 @@ if (false) {}
|
|
|
7766
7766
|
var __dirname = "/home/runner/work/agent-cli/agent-cli/src/mcp/servers/sqlite";
|
|
7767
7767
|
var SQLITE_MCP_SERVER_PATH = resolve20(__dirname, "server.ts");
|
|
7768
7768
|
|
|
7769
|
+
// src/init/project-analyzer.ts
|
|
7770
|
+
import { existsSync as existsSync18, readFileSync as readFileSync13, readdirSync as readdirSync6 } from "fs";
|
|
7771
|
+
import { join as join9, basename as basename2 } from "path";
|
|
7772
|
+
|
|
7773
|
+
class ProjectAnalyzer {
|
|
7774
|
+
cwd;
|
|
7775
|
+
constructor(cwd = process.cwd()) {
|
|
7776
|
+
this.cwd = cwd;
|
|
7777
|
+
}
|
|
7778
|
+
analyze() {
|
|
7779
|
+
const readmeInfo = this.extractReadmeMetadata();
|
|
7780
|
+
const projectName = readmeInfo.title || this.detectProjectName();
|
|
7781
|
+
const languages = this.detectLanguages();
|
|
7782
|
+
const packageManager = this.detectPackageManager();
|
|
7783
|
+
const frameworks = [];
|
|
7784
|
+
const infrastructure = [];
|
|
7785
|
+
const commands = {};
|
|
7786
|
+
const architectureNotes = [];
|
|
7787
|
+
const codeConventions = [];
|
|
7788
|
+
let description = readmeInfo.description;
|
|
7789
|
+
const pkgPath = join9(this.cwd, "package.json");
|
|
7790
|
+
if (existsSync18(pkgPath)) {
|
|
7791
|
+
try {
|
|
7792
|
+
const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
|
|
7793
|
+
if (!description && pkg.description)
|
|
7794
|
+
description = pkg.description;
|
|
7795
|
+
const pm = packageManager || "npm";
|
|
7796
|
+
const runPrefix = pm === "bun" || pm === "yarn" || pm === "pnpm" ? `${pm} run` : "npm run";
|
|
7797
|
+
const testPrefix = pm === "bun" ? "bun test" : pm === "pnpm" ? "pnpm test" : pm === "yarn" ? "yarn test" : "npm test";
|
|
7798
|
+
if (pkg.scripts) {
|
|
7799
|
+
if (pkg.scripts.dev)
|
|
7800
|
+
commands.dev = `${runPrefix} dev`;
|
|
7801
|
+
else if (pkg.scripts.start)
|
|
7802
|
+
commands.dev = `${runPrefix} start`;
|
|
7803
|
+
if (pkg.scripts.build)
|
|
7804
|
+
commands.build = `${runPrefix} build`;
|
|
7805
|
+
if (pkg.scripts.test)
|
|
7806
|
+
commands.test = pkg.scripts.test === "bun test" ? "bun test" : testPrefix;
|
|
7807
|
+
if (pkg.scripts.typecheck)
|
|
7808
|
+
commands.typecheck = `${runPrefix} typecheck`;
|
|
7809
|
+
else if (pkg.scripts.check)
|
|
7810
|
+
commands.typecheck = `${runPrefix} check`;
|
|
7811
|
+
if (pkg.scripts.lint)
|
|
7812
|
+
commands.lint = `${runPrefix} lint`;
|
|
7813
|
+
if (pkg.scripts.format)
|
|
7814
|
+
commands.format = `${runPrefix} format`;
|
|
7815
|
+
}
|
|
7816
|
+
const allDeps = {
|
|
7817
|
+
...pkg.dependencies || {},
|
|
7818
|
+
...pkg.devDependencies || {}
|
|
7819
|
+
};
|
|
7820
|
+
if (allDeps.next)
|
|
7821
|
+
frameworks.push("Next.js");
|
|
7822
|
+
if (allDeps.react)
|
|
7823
|
+
frameworks.push("React");
|
|
7824
|
+
if (allDeps.vue)
|
|
7825
|
+
frameworks.push("Vue.js");
|
|
7826
|
+
if (allDeps.svelte || allDeps["@sveltejs/kit"])
|
|
7827
|
+
frameworks.push("Svelte");
|
|
7828
|
+
if (allDeps.astro)
|
|
7829
|
+
frameworks.push("Astro");
|
|
7830
|
+
if (allDeps.vite)
|
|
7831
|
+
frameworks.push("Vite");
|
|
7832
|
+
if (allDeps.express)
|
|
7833
|
+
frameworks.push("Express");
|
|
7834
|
+
if (allDeps.hono)
|
|
7835
|
+
frameworks.push("Hono");
|
|
7836
|
+
if (allDeps.fastify)
|
|
7837
|
+
frameworks.push("Fastify");
|
|
7838
|
+
if (allDeps["@nestjs/core"])
|
|
7839
|
+
frameworks.push("NestJS");
|
|
7840
|
+
if (allDeps.tailwindcss)
|
|
7841
|
+
frameworks.push("TailwindCSS");
|
|
7842
|
+
if (allDeps["lucide-react"] || allDeps.lucide)
|
|
7843
|
+
frameworks.push("Lucide Icons");
|
|
7844
|
+
if (allDeps.zustand)
|
|
7845
|
+
frameworks.push("Zustand");
|
|
7846
|
+
if (allDeps["@tanstack/react-query"])
|
|
7847
|
+
frameworks.push("TanStack Query");
|
|
7848
|
+
if (allDeps.oxlint)
|
|
7849
|
+
frameworks.push("Oxlint");
|
|
7850
|
+
if (allDeps.eslint)
|
|
7851
|
+
frameworks.push("ESLint");
|
|
7852
|
+
if (allDeps.vitest)
|
|
7853
|
+
frameworks.push("Vitest");
|
|
7854
|
+
if (allDeps.jest)
|
|
7855
|
+
frameworks.push("Jest");
|
|
7856
|
+
if (allDeps.playwright || allDeps["@playwright/test"])
|
|
7857
|
+
frameworks.push("Playwright");
|
|
7858
|
+
if (pkg.type === "module") {
|
|
7859
|
+
codeConventions.push("Use ES modules (`import/export`), not CommonJS (`require`).");
|
|
7860
|
+
}
|
|
7861
|
+
} catch {}
|
|
7862
|
+
}
|
|
7863
|
+
const tsconfigPath = join9(this.cwd, "tsconfig.json");
|
|
7864
|
+
if (existsSync18(tsconfigPath)) {
|
|
7865
|
+
try {
|
|
7866
|
+
const tsconfig = JSON.parse(readFileSync13(tsconfigPath, "utf8"));
|
|
7867
|
+
if (tsconfig.compilerOptions?.strict) {
|
|
7868
|
+
codeConventions.push("TypeScript strict mode enabled.");
|
|
7869
|
+
}
|
|
7870
|
+
if (!commands.typecheck) {
|
|
7871
|
+
commands.typecheck = "tsc --noEmit";
|
|
7872
|
+
}
|
|
7873
|
+
} catch {}
|
|
7874
|
+
}
|
|
7875
|
+
const cargoPath = join9(this.cwd, "Cargo.toml");
|
|
7876
|
+
if (existsSync18(cargoPath)) {
|
|
7877
|
+
try {
|
|
7878
|
+
commands.dev = commands.dev || "cargo run";
|
|
7879
|
+
commands.build = commands.build || "cargo build";
|
|
7880
|
+
commands.test = commands.test || "cargo test";
|
|
7881
|
+
commands.lint = commands.lint || "cargo clippy";
|
|
7882
|
+
frameworks.push("Rust Cargo");
|
|
7883
|
+
} catch {}
|
|
7884
|
+
}
|
|
7885
|
+
const goModPath = join9(this.cwd, "go.mod");
|
|
7886
|
+
if (existsSync18(goModPath)) {
|
|
7887
|
+
try {
|
|
7888
|
+
commands.dev = commands.dev || "go run .";
|
|
7889
|
+
commands.build = commands.build || "go build ./...";
|
|
7890
|
+
commands.test = commands.test || "go test ./...";
|
|
7891
|
+
commands.lint = commands.lint || "golangci-lint run";
|
|
7892
|
+
frameworks.push("Go Modules");
|
|
7893
|
+
} catch {}
|
|
7894
|
+
}
|
|
7895
|
+
const pyprojectPath = join9(this.cwd, "pyproject.toml");
|
|
7896
|
+
const requirementsPath = join9(this.cwd, "requirements.txt");
|
|
7897
|
+
if (existsSync18(pyprojectPath) || existsSync18(requirementsPath)) {
|
|
7898
|
+
commands.test = commands.test || "pytest";
|
|
7899
|
+
commands.lint = commands.lint || "ruff check .";
|
|
7900
|
+
if (existsSync18(join9(this.cwd, "uv.lock"))) {
|
|
7901
|
+
frameworks.push("uv");
|
|
7902
|
+
commands.test = "uv run pytest";
|
|
7903
|
+
} else if (existsSync18(join9(this.cwd, "poetry.lock"))) {
|
|
7904
|
+
frameworks.push("Poetry");
|
|
7905
|
+
commands.test = "poetry run pytest";
|
|
7906
|
+
}
|
|
7907
|
+
}
|
|
7908
|
+
if (existsSync18(join9(this.cwd, "Dockerfile"))) {
|
|
7909
|
+
infrastructure.push("Docker");
|
|
7910
|
+
const sanitizedName = projectName.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/^-+|-+$/g, "");
|
|
7911
|
+
commands.dockerBuild = `docker build -t ${sanitizedName || "app"} .`;
|
|
7912
|
+
}
|
|
7913
|
+
if (existsSync18(join9(this.cwd, "nginx.conf"))) {
|
|
7914
|
+
infrastructure.push("Nginx");
|
|
7915
|
+
}
|
|
7916
|
+
if (existsSync18(join9(this.cwd, "src/api.ts")) || existsSync18(join9(this.cwd, "src/api"))) {
|
|
7917
|
+
architectureNotes.push("Backend API endpoints and network client logic are centralized in `src/api`.");
|
|
7918
|
+
}
|
|
7919
|
+
if (existsSync18(join9(this.cwd, "src/components"))) {
|
|
7920
|
+
architectureNotes.push("Reusable UI presentation components live in `src/components/`.");
|
|
7921
|
+
}
|
|
7922
|
+
if (existsSync18(join9(this.cwd, "src/types.ts")) || existsSync18(join9(this.cwd, "src/types"))) {
|
|
7923
|
+
architectureNotes.push("Shared TypeScript data models and interfaces are defined in `src/types`.");
|
|
7924
|
+
}
|
|
7925
|
+
if (existsSync18(join9(this.cwd, ".env.example"))) {
|
|
7926
|
+
architectureNotes.push("Environment configuration template is in `.env.example`.");
|
|
7927
|
+
}
|
|
7928
|
+
if (commands.typecheck || commands.lint || commands.test) {
|
|
7929
|
+
const checks = [];
|
|
7930
|
+
if (commands.typecheck)
|
|
7931
|
+
checks.push(`typecheck (\`${commands.typecheck}\`)`);
|
|
7932
|
+
if (commands.lint)
|
|
7933
|
+
checks.push(`lint (\`${commands.lint}\`)`);
|
|
7934
|
+
if (commands.test)
|
|
7935
|
+
checks.push(`tests (\`${commands.test}\`)`);
|
|
7936
|
+
codeConventions.push(`Run ${checks.join(" and ")} before concluding any major code edits.`);
|
|
7937
|
+
}
|
|
7938
|
+
const instructionFiles = ["AGENTS.md", "CLAUDE.md", ".agents.md", "AGENTS.override.md"];
|
|
7939
|
+
let hasExistingInstructions = false;
|
|
7940
|
+
let existingInstructionFile;
|
|
7941
|
+
for (const f of instructionFiles) {
|
|
7942
|
+
if (existsSync18(join9(this.cwd, f))) {
|
|
7943
|
+
hasExistingInstructions = true;
|
|
7944
|
+
existingInstructionFile = f;
|
|
7945
|
+
break;
|
|
7946
|
+
}
|
|
7947
|
+
}
|
|
7948
|
+
return {
|
|
7949
|
+
projectName,
|
|
7950
|
+
description,
|
|
7951
|
+
languages,
|
|
7952
|
+
packageManager,
|
|
7953
|
+
frameworks,
|
|
7954
|
+
infrastructure,
|
|
7955
|
+
commands,
|
|
7956
|
+
architectureNotes,
|
|
7957
|
+
codeConventions,
|
|
7958
|
+
hasExistingInstructions,
|
|
7959
|
+
existingInstructionFile
|
|
7960
|
+
};
|
|
7961
|
+
}
|
|
7962
|
+
generateAgentsMarkdown(analysis) {
|
|
7963
|
+
const lines = [];
|
|
7964
|
+
lines.push(`# ${analysis.projectName}`);
|
|
7965
|
+
lines.push("");
|
|
7966
|
+
if (analysis.description) {
|
|
7967
|
+
lines.push(`> ${analysis.description}`);
|
|
7968
|
+
lines.push("");
|
|
7969
|
+
}
|
|
7970
|
+
lines.push("## Commands");
|
|
7971
|
+
lines.push("");
|
|
7972
|
+
if (Object.keys(analysis.commands).length > 0) {
|
|
7973
|
+
if (analysis.commands.dev)
|
|
7974
|
+
lines.push(`- **Dev Server**: \`${analysis.commands.dev}\``);
|
|
7975
|
+
if (analysis.commands.build)
|
|
7976
|
+
lines.push(`- **Build**: \`${analysis.commands.build}\``);
|
|
7977
|
+
if (analysis.commands.test)
|
|
7978
|
+
lines.push(`- **Test**: \`${analysis.commands.test}\``);
|
|
7979
|
+
if (analysis.commands.typecheck)
|
|
7980
|
+
lines.push(`- **Typecheck**: \`${analysis.commands.typecheck}\``);
|
|
7981
|
+
if (analysis.commands.lint)
|
|
7982
|
+
lines.push(`- **Lint**: \`${analysis.commands.lint}\``);
|
|
7983
|
+
if (analysis.commands.format)
|
|
7984
|
+
lines.push(`- **Format**: \`${analysis.commands.format}\``);
|
|
7985
|
+
if (analysis.commands.dockerBuild)
|
|
7986
|
+
lines.push(`- **Docker Build**: \`${analysis.commands.dockerBuild}\``);
|
|
7987
|
+
} else {
|
|
7988
|
+
lines.push("- *No standard build/test commands detected.*");
|
|
7989
|
+
}
|
|
7990
|
+
lines.push("");
|
|
7991
|
+
lines.push("## Architecture & Stack");
|
|
7992
|
+
lines.push("");
|
|
7993
|
+
const stackItems = [];
|
|
7994
|
+
if (analysis.languages.length > 0)
|
|
7995
|
+
stackItems.push(analysis.languages.join(", "));
|
|
7996
|
+
if (analysis.frameworks.length > 0)
|
|
7997
|
+
stackItems.push(analysis.frameworks.join(", "));
|
|
7998
|
+
if (analysis.infrastructure.length > 0)
|
|
7999
|
+
stackItems.push(analysis.infrastructure.join(", "));
|
|
8000
|
+
if (stackItems.length > 0) {
|
|
8001
|
+
lines.push(`- **Core Stack**: ${stackItems.join(" \u2022 ")}`);
|
|
8002
|
+
}
|
|
8003
|
+
for (const note of analysis.architectureNotes) {
|
|
8004
|
+
lines.push(`- ${note}`);
|
|
8005
|
+
}
|
|
8006
|
+
lines.push("");
|
|
8007
|
+
lines.push("## Workflow & Code Guidelines");
|
|
8008
|
+
lines.push("");
|
|
8009
|
+
if (analysis.codeConventions.length > 0) {
|
|
8010
|
+
for (const conv of analysis.codeConventions) {
|
|
8011
|
+
lines.push(`- ${conv}`);
|
|
8012
|
+
}
|
|
8013
|
+
}
|
|
8014
|
+
lines.push("- Prefer targeted edits over whole-file rewrites.");
|
|
8015
|
+
lines.push("- When fixing errors, address the root cause rather than suppressing compiler warnings.");
|
|
8016
|
+
lines.push("");
|
|
8017
|
+
return lines.join(`
|
|
8018
|
+
`);
|
|
8019
|
+
}
|
|
8020
|
+
extractReadmeMetadata() {
|
|
8021
|
+
const readmeFiles = ["README.md", "readme.md", "README.MD"];
|
|
8022
|
+
for (const file of readmeFiles) {
|
|
8023
|
+
const fullPath = join9(this.cwd, file);
|
|
8024
|
+
if (existsSync18(fullPath)) {
|
|
8025
|
+
try {
|
|
8026
|
+
const content = readFileSync13(fullPath, "utf8");
|
|
8027
|
+
const lines = content.split(`
|
|
8028
|
+
`);
|
|
8029
|
+
let title;
|
|
8030
|
+
let description;
|
|
8031
|
+
for (const line of lines) {
|
|
8032
|
+
const trimmed = line.trim();
|
|
8033
|
+
if (!title && trimmed.startsWith("# ")) {
|
|
8034
|
+
title = trimmed.replace(/^#\s+/, "").trim();
|
|
8035
|
+
continue;
|
|
8036
|
+
}
|
|
8037
|
+
if (title && !description && trimmed.length > 0 && !trimmed.startsWith("#") && !trimmed.startsWith("```") && !trimmed.startsWith("[")) {
|
|
8038
|
+
description = trimmed;
|
|
8039
|
+
break;
|
|
8040
|
+
}
|
|
8041
|
+
}
|
|
8042
|
+
return { title, description };
|
|
8043
|
+
} catch {}
|
|
8044
|
+
}
|
|
8045
|
+
}
|
|
8046
|
+
return {};
|
|
8047
|
+
}
|
|
8048
|
+
detectProjectName() {
|
|
8049
|
+
const pkgPath = join9(this.cwd, "package.json");
|
|
8050
|
+
if (existsSync18(pkgPath)) {
|
|
8051
|
+
try {
|
|
8052
|
+
const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
|
|
8053
|
+
if (pkg.name && pkg.name !== "frontend" && pkg.name !== "backend" && pkg.name !== "app") {
|
|
8054
|
+
return pkg.name.startsWith("@") ? pkg.name.split("/")[1] || pkg.name : pkg.name;
|
|
8055
|
+
}
|
|
8056
|
+
} catch {}
|
|
8057
|
+
}
|
|
8058
|
+
const cargoPath = join9(this.cwd, "Cargo.toml");
|
|
8059
|
+
if (existsSync18(cargoPath)) {
|
|
8060
|
+
try {
|
|
8061
|
+
const match = readFileSync13(cargoPath, "utf8").match(/name\s*=\s*"([^"]+)"/);
|
|
8062
|
+
if (match?.[1])
|
|
8063
|
+
return match[1];
|
|
8064
|
+
} catch {}
|
|
8065
|
+
}
|
|
8066
|
+
const goModPath = join9(this.cwd, "go.mod");
|
|
8067
|
+
if (existsSync18(goModPath)) {
|
|
8068
|
+
try {
|
|
8069
|
+
const match = readFileSync13(goModPath, "utf8").match(/module\s+([^\s]+)/);
|
|
8070
|
+
if (match?.[1])
|
|
8071
|
+
return basename2(match[1]);
|
|
8072
|
+
} catch {}
|
|
8073
|
+
}
|
|
8074
|
+
return basename2(this.cwd);
|
|
8075
|
+
}
|
|
8076
|
+
detectLanguages() {
|
|
8077
|
+
const langs = new Set;
|
|
8078
|
+
if (existsSync18(join9(this.cwd, "tsconfig.json")) || this.hasFileWithExtension(".ts", ".tsx")) {
|
|
8079
|
+
langs.add("TypeScript");
|
|
8080
|
+
}
|
|
8081
|
+
if (existsSync18(join9(this.cwd, "package.json")) || this.hasFileWithExtension(".js", ".jsx", ".mjs")) {
|
|
8082
|
+
langs.add("JavaScript");
|
|
8083
|
+
}
|
|
8084
|
+
if (existsSync18(join9(this.cwd, "Cargo.toml")) || this.hasFileWithExtension(".rs")) {
|
|
8085
|
+
langs.add("Rust");
|
|
8086
|
+
}
|
|
8087
|
+
if (existsSync18(join9(this.cwd, "go.mod")) || this.hasFileWithExtension(".go")) {
|
|
8088
|
+
langs.add("Go");
|
|
8089
|
+
}
|
|
8090
|
+
if (existsSync18(join9(this.cwd, "pyproject.toml")) || existsSync18(join9(this.cwd, "requirements.txt")) || this.hasFileWithExtension(".py")) {
|
|
8091
|
+
langs.add("Python");
|
|
8092
|
+
}
|
|
8093
|
+
if (existsSync18(join9(this.cwd, "pom.xml")) || existsSync18(join9(this.cwd, "build.gradle")) || this.hasFileWithExtension(".java")) {
|
|
8094
|
+
langs.add("Java");
|
|
8095
|
+
}
|
|
8096
|
+
if (existsSync18(join9(this.cwd, "CMakeLists.txt")) || this.hasFileWithExtension(".cpp", ".c", ".h", ".hpp")) {
|
|
8097
|
+
langs.add("C/C++");
|
|
8098
|
+
}
|
|
8099
|
+
return Array.from(langs);
|
|
8100
|
+
}
|
|
8101
|
+
detectPackageManager() {
|
|
8102
|
+
if (existsSync18(join9(this.cwd, "bun.lockb")) || existsSync18(join9(this.cwd, "bun.lock")))
|
|
8103
|
+
return "bun";
|
|
8104
|
+
if (existsSync18(join9(this.cwd, "pnpm-lock.yaml")))
|
|
8105
|
+
return "pnpm";
|
|
8106
|
+
if (existsSync18(join9(this.cwd, "yarn.lock")))
|
|
8107
|
+
return "yarn";
|
|
8108
|
+
if (existsSync18(join9(this.cwd, "package-lock.json")))
|
|
8109
|
+
return "npm";
|
|
8110
|
+
if (existsSync18(join9(this.cwd, "Cargo.lock")) || existsSync18(join9(this.cwd, "Cargo.toml")))
|
|
8111
|
+
return "cargo";
|
|
8112
|
+
if (existsSync18(join9(this.cwd, "uv.lock")))
|
|
8113
|
+
return "uv";
|
|
8114
|
+
if (existsSync18(join9(this.cwd, "poetry.lock")))
|
|
8115
|
+
return "poetry";
|
|
8116
|
+
if (existsSync18(join9(this.cwd, "go.sum")) || existsSync18(join9(this.cwd, "go.mod")))
|
|
8117
|
+
return "go";
|
|
8118
|
+
if (existsSync18(join9(this.cwd, "package.json")))
|
|
8119
|
+
return "npm";
|
|
8120
|
+
return;
|
|
8121
|
+
}
|
|
8122
|
+
hasFileWithExtension(...exts) {
|
|
8123
|
+
try {
|
|
8124
|
+
const entries = readdirSync6(this.cwd);
|
|
8125
|
+
return entries.some((e) => exts.some((ext) => e.endsWith(ext)));
|
|
8126
|
+
} catch {
|
|
8127
|
+
return false;
|
|
8128
|
+
}
|
|
8129
|
+
}
|
|
8130
|
+
}
|
|
8131
|
+
// src/init/init-command.ts
|
|
8132
|
+
import { existsSync as existsSync19, writeFileSync as writeFileSync7 } from "fs";
|
|
8133
|
+
import { join as join10 } from "path";
|
|
8134
|
+
function runProjectInit(options = {}) {
|
|
8135
|
+
const cwd = options.cwd || process.cwd();
|
|
8136
|
+
const filename = options.filename || "AGENTS.md";
|
|
8137
|
+
const targetPath = join10(cwd, filename);
|
|
8138
|
+
const analyzer = new ProjectAnalyzer(cwd);
|
|
8139
|
+
const analysis = analyzer.analyze();
|
|
8140
|
+
const content = analyzer.generateAgentsMarkdown(analysis);
|
|
8141
|
+
const alreadyExists = existsSync19(targetPath);
|
|
8142
|
+
writeFileSync7(targetPath, content, "utf8");
|
|
8143
|
+
return {
|
|
8144
|
+
success: true,
|
|
8145
|
+
filePath: targetPath,
|
|
8146
|
+
analysis,
|
|
8147
|
+
content,
|
|
8148
|
+
overwritten: alreadyExists
|
|
8149
|
+
};
|
|
8150
|
+
}
|
|
8151
|
+
function printInitSummary(result) {
|
|
8152
|
+
const BOLD2 = "\x1B[1m";
|
|
8153
|
+
const GREEN = "\x1B[38;2;120;220;140m";
|
|
8154
|
+
const BRAND = "\x1B[38;2;217;119;87m";
|
|
8155
|
+
const CYAN = "\x1B[38;2;125;207;255m";
|
|
8156
|
+
const GRAY2 = "\x1B[38;2;148;148;148m";
|
|
8157
|
+
const WHITE2 = "\x1B[38;2;240;240;245m";
|
|
8158
|
+
const RESET2 = "\x1B[0m";
|
|
8159
|
+
const { analysis, filePath, overwritten } = result;
|
|
8160
|
+
console.log("");
|
|
8161
|
+
console.log(` ${GREEN}\u2713${RESET2} ${BOLD2}${WHITE2}${overwritten ? "Updated" : "Created"} Project Instructions Document${RESET2}`);
|
|
8162
|
+
console.log(` ${GRAY2}Path: ${CYAN}${filePath}${RESET2}`);
|
|
8163
|
+
console.log("");
|
|
8164
|
+
console.log(` ${BRAND}\u250C\u2500 ${BOLD2}Project Overview${RESET2} ${BRAND}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510${RESET2}`);
|
|
8165
|
+
console.log(` ${BRAND}\u2502${RESET2} ${BOLD2}Project:${RESET2} ${WHITE2}${analysis.projectName}${RESET2}`);
|
|
8166
|
+
if (analysis.languages.length > 0) {
|
|
8167
|
+
console.log(` ${BRAND}\u2502${RESET2} ${BOLD2}Languages:${RESET2} ${analysis.languages.join(", ")}`);
|
|
8168
|
+
}
|
|
8169
|
+
if (analysis.packageManager) {
|
|
8170
|
+
console.log(` ${BRAND}\u2502${RESET2} ${BOLD2}Package Manager:${RESET2} ${analysis.packageManager}`);
|
|
8171
|
+
}
|
|
8172
|
+
if (analysis.frameworks.length > 0) {
|
|
8173
|
+
console.log(` ${BRAND}\u2502${RESET2} ${BOLD2}Frameworks:${RESET2} ${analysis.frameworks.join(", ")}`);
|
|
8174
|
+
}
|
|
8175
|
+
console.log(` ${BRAND}\u2502${RESET2}`);
|
|
8176
|
+
console.log(` ${BRAND}\u2502${RESET2} ${BOLD2}Detected Commands:${RESET2}`);
|
|
8177
|
+
if (analysis.commands.build) {
|
|
8178
|
+
console.log(` ${BRAND}\u2502${RESET2} \u2022 Build: ${CYAN}${analysis.commands.build}${RESET2}`);
|
|
8179
|
+
}
|
|
8180
|
+
if (analysis.commands.test) {
|
|
8181
|
+
console.log(` ${BRAND}\u2502${RESET2} \u2022 Test: ${GREEN}${analysis.commands.test}${RESET2}`);
|
|
8182
|
+
}
|
|
8183
|
+
if (analysis.commands.typecheck) {
|
|
8184
|
+
console.log(` ${BRAND}\u2502${RESET2} \u2022 Typecheck: ${CYAN}${analysis.commands.typecheck}${RESET2}`);
|
|
8185
|
+
}
|
|
8186
|
+
if (analysis.commands.lint) {
|
|
8187
|
+
console.log(` ${BRAND}\u2502${RESET2} \u2022 Lint: ${CYAN}${analysis.commands.lint}${RESET2}`);
|
|
8188
|
+
}
|
|
8189
|
+
if (analysis.commands.dev) {
|
|
8190
|
+
console.log(` ${BRAND}\u2502${RESET2} \u2022 Dev: ${CYAN}${analysis.commands.dev}${RESET2}`);
|
|
8191
|
+
}
|
|
8192
|
+
if (Object.keys(analysis.commands).length === 0) {
|
|
8193
|
+
console.log(` ${BRAND}\u2502${RESET2} \u2022 ${GRAY2}(No standard commands detected)${RESET2}`);
|
|
8194
|
+
}
|
|
8195
|
+
console.log(` ${BRAND}\u2502${RESET2}`);
|
|
8196
|
+
console.log(` ${BRAND}\u2502${RESET2} ${GRAY2}AI agents will now automatically load AGENTS.md on every session.${RESET2}`);
|
|
8197
|
+
console.log(` ${BRAND}\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518${RESET2}`);
|
|
8198
|
+
console.log("");
|
|
8199
|
+
}
|
|
7769
8200
|
// src/cli/commands.ts
|
|
7770
8201
|
var AVAILABLE_SLASH_COMMANDS = [
|
|
7771
8202
|
{ name: "/help", description: "Show command list and help menu" },
|
|
8203
|
+
{ name: "/init", description: "Initialize or update AGENTS.md project instructions" },
|
|
7772
8204
|
{ name: "/stats", description: "Display session runtime, turn stats & sub-agent status" },
|
|
7773
8205
|
{ name: "/model", description: "Select or switch active AI model" },
|
|
7774
8206
|
{ name: "/reasoning", description: "Toggle internal reasoning chain visibility" },
|
|
@@ -7861,6 +8293,10 @@ async function handleSlashCommand(input, ctx) {
|
|
|
7861
8293
|
\x1B[38;2;95;175;175m\u23F8 Switched to Plan Mode (read-only planning, mutations blocked)\x1B[0m
|
|
7862
8294
|
`);
|
|
7863
8295
|
return true;
|
|
8296
|
+
case "/init":
|
|
8297
|
+
const initResult = runProjectInit({ cwd: ctx.session.cwd });
|
|
8298
|
+
printInitSummary(initResult);
|
|
8299
|
+
return true;
|
|
7864
8300
|
case "/agents":
|
|
7865
8301
|
printAgents(ctx);
|
|
7866
8302
|
return true;
|
|
@@ -9126,9 +9562,9 @@ class MarkdownHighlighter {
|
|
|
9126
9562
|
}
|
|
9127
9563
|
|
|
9128
9564
|
// src/cli/update-checker.ts
|
|
9129
|
-
import { existsSync as
|
|
9565
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync10, readFileSync as readFileSync14, writeFileSync as writeFileSync8 } from "fs";
|
|
9130
9566
|
import { homedir as homedir9 } from "os";
|
|
9131
|
-
import { join as
|
|
9567
|
+
import { join as join11 } from "path";
|
|
9132
9568
|
var CHECK_INTERVAL_MS = 12 * 60 * 60 * 1000;
|
|
9133
9569
|
function parseSemver(v) {
|
|
9134
9570
|
const clean = v.replace(/^v/, "").trim();
|
|
@@ -9149,8 +9585,8 @@ function isNewerVersion(current, remote) {
|
|
|
9149
9585
|
return remPatch > curPatch;
|
|
9150
9586
|
}
|
|
9151
9587
|
function getUpdateCachePath() {
|
|
9152
|
-
const baseDir = process.env.PIKAA_HOME || process.env.GROUPY_HOME ||
|
|
9153
|
-
return
|
|
9588
|
+
const baseDir = process.env.PIKAA_HOME || process.env.GROUPY_HOME || join11(homedir9(), ".pikaa");
|
|
9589
|
+
return join11(baseDir, "update-cache.json");
|
|
9154
9590
|
}
|
|
9155
9591
|
async function fetchLatestNpmVersion(packageName, timeoutMs = 1500) {
|
|
9156
9592
|
const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`;
|
|
@@ -9183,9 +9619,9 @@ async function checkForUpdates(options = {}) {
|
|
|
9183
9619
|
const cachePath = options.cachePath || getUpdateCachePath();
|
|
9184
9620
|
const now = Date.now();
|
|
9185
9621
|
let cached = null;
|
|
9186
|
-
if (!options.force &&
|
|
9622
|
+
if (!options.force && existsSync20(cachePath)) {
|
|
9187
9623
|
try {
|
|
9188
|
-
const raw = JSON.parse(
|
|
9624
|
+
const raw = JSON.parse(readFileSync14(cachePath, "utf8"));
|
|
9189
9625
|
if (raw && typeof raw.lastChecked === "number" && typeof raw.latestVersion === "string") {
|
|
9190
9626
|
cached = raw;
|
|
9191
9627
|
if (now - cached.lastChecked < CHECK_INTERVAL_MS) {
|
|
@@ -9213,8 +9649,8 @@ async function checkForUpdates(options = {}) {
|
|
|
9213
9649
|
return null;
|
|
9214
9650
|
}
|
|
9215
9651
|
try {
|
|
9216
|
-
const parentDir =
|
|
9217
|
-
if (!
|
|
9652
|
+
const parentDir = join11(cachePath, "..");
|
|
9653
|
+
if (!existsSync20(parentDir)) {
|
|
9218
9654
|
mkdirSync10(parentDir, { recursive: true });
|
|
9219
9655
|
}
|
|
9220
9656
|
const cacheData = {
|
|
@@ -9222,7 +9658,7 @@ async function checkForUpdates(options = {}) {
|
|
|
9222
9658
|
latestVersion,
|
|
9223
9659
|
packageName
|
|
9224
9660
|
};
|
|
9225
|
-
|
|
9661
|
+
writeFileSync8(cachePath, JSON.stringify(cacheData, null, 2), "utf8");
|
|
9226
9662
|
} catch {}
|
|
9227
9663
|
const updateAvailable = isNewerVersion(currentVersion, latestVersion);
|
|
9228
9664
|
return updateAvailable ? {
|
|
@@ -9589,6 +10025,10 @@ async function main() {
|
|
|
9589
10025
|
} else if (arg === "worktrees" || arg === "worktree") {
|
|
9590
10026
|
await printWorktreesList(worktreeManager, cwd);
|
|
9591
10027
|
process.exit(0);
|
|
10028
|
+
} else if (arg === "init") {
|
|
10029
|
+
const initResult = runProjectInit({ cwd });
|
|
10030
|
+
printInitSummary(initResult);
|
|
10031
|
+
process.exit(0);
|
|
9592
10032
|
} else if (arg === "--resume" || arg === "-R" || arg === "resume") {
|
|
9593
10033
|
resumeThreadId = args[++i];
|
|
9594
10034
|
} else if (arg === "--model" || arg === "-m") {
|
|
@@ -9630,7 +10070,7 @@ async function main() {
|
|
|
9630
10070
|
resolve21(cwd, "mcp_config.json")
|
|
9631
10071
|
].filter(Boolean);
|
|
9632
10072
|
for (const cfg of candidateConfigs) {
|
|
9633
|
-
if (
|
|
10073
|
+
if (existsSync21(cfg)) {
|
|
9634
10074
|
try {
|
|
9635
10075
|
await mcpManager.loadConfigFile(cfg);
|
|
9636
10076
|
mcpManager.registerToolsIntoRouter(tools4);
|
|
@@ -9888,6 +10328,7 @@ ${style.bold("USAGE:")}
|
|
|
9888
10328
|
groupy skills # List available domain skills
|
|
9889
10329
|
groupy memories # View learned user preferences
|
|
9890
10330
|
groupy worktrees # List active isolated Git Worktrees
|
|
10331
|
+
groupy init # Initialize or update AGENTS.md project instructions
|
|
9891
10332
|
|
|
9892
10333
|
${style.bold("OPTIONS:")}
|
|
9893
10334
|
-R, --resume <id> Resume an existing session from SQLite storage
|
package/package.json
CHANGED
|
@@ -47,6 +47,10 @@ You are Groupy, an expert autonomous AI coding assistant. You are running as a c
|
|
|
47
47
|
|
|
48
48
|
## Codebase Discovery & Execution Strategy
|
|
49
49
|
|
|
50
|
+
0. **Project Instructions Precedence (`AGENTS.md` / `CLAUDE.md`)**:
|
|
51
|
+
- If `AGENTS.md`, `CLAUDE.md`, or `.agents.md` is present in the workspace, its instructions take immediate precedence.
|
|
52
|
+
- Always prioritize and follow the development commands (build, test, lint), architectural constraints, and code conventions defined in `AGENTS.md` before executing any commands.
|
|
53
|
+
|
|
50
54
|
1. **Broad Exploration ("pelajari project ini / repo ini tentang apa")**:
|
|
51
55
|
- Inspect ONLY root configs (`package.json`, `Cargo.toml`, `go.mod`, `pyproject.toml`, etc.), `README.md`, and top-level directory tree.
|
|
52
56
|
- Deliver a concise Architecture Overview (Tech stack, folder hierarchy, main entry points).
|