@mc1global/opencode-jarvis 0.9.0 → 0.11.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.
Files changed (91) hide show
  1. package/QUICK-GUIDE.md +42 -28
  2. package/README.md +288 -165
  3. package/dist/application/azure-sync/push-use-cases.d.ts +6 -1
  4. package/dist/application/azure-sync/push-use-cases.d.ts.map +1 -1
  5. package/dist/application/azure-sync/push-use-cases.js +31 -5
  6. package/dist/application/azure-sync/push-use-cases.js.map +1 -1
  7. package/dist/application/config/config-write-service.d.ts +86 -0
  8. package/dist/application/config/config-write-service.d.ts.map +1 -0
  9. package/dist/application/config/config-write-service.js +237 -0
  10. package/dist/application/config/config-write-service.js.map +1 -0
  11. package/dist/application/config/index.d.ts +2 -0
  12. package/dist/application/config/index.d.ts.map +1 -1
  13. package/dist/application/config/index.js +1 -0
  14. package/dist/application/config/index.js.map +1 -1
  15. package/dist/application/context-memory/execution-journal-use-cases.d.ts +69 -0
  16. package/dist/application/context-memory/execution-journal-use-cases.d.ts.map +1 -0
  17. package/dist/application/context-memory/execution-journal-use-cases.js +89 -0
  18. package/dist/application/context-memory/execution-journal-use-cases.js.map +1 -0
  19. package/dist/cli/config-wizard.d.ts +14 -0
  20. package/dist/cli/config-wizard.d.ts.map +1 -0
  21. package/dist/cli/config-wizard.js +120 -0
  22. package/dist/cli/config-wizard.js.map +1 -0
  23. package/dist/cli/section-editors.d.ts +33 -0
  24. package/dist/cli/section-editors.d.ts.map +1 -0
  25. package/dist/cli/section-editors.js +286 -0
  26. package/dist/cli/section-editors.js.map +1 -0
  27. package/dist/cli/wizard-prompts.d.ts +76 -0
  28. package/dist/cli/wizard-prompts.d.ts.map +1 -0
  29. package/dist/cli/wizard-prompts.js +98 -0
  30. package/dist/cli/wizard-prompts.js.map +1 -0
  31. package/dist/domain/azure-sync/value-objects.d.ts +10 -0
  32. package/dist/domain/azure-sync/value-objects.d.ts.map +1 -1
  33. package/dist/domain/azure-sync/value-objects.js +24 -0
  34. package/dist/domain/azure-sync/value-objects.js.map +1 -1
  35. package/dist/domain/config/index.d.ts +1 -1
  36. package/dist/domain/config/index.d.ts.map +1 -1
  37. package/dist/domain/config/repositories.d.ts +26 -6
  38. package/dist/domain/config/repositories.d.ts.map +1 -1
  39. package/dist/domain/config/repositories.js +6 -6
  40. package/dist/domain/context-memory/entities.d.ts +50 -2
  41. package/dist/domain/context-memory/entities.d.ts.map +1 -1
  42. package/dist/domain/context-memory/entities.js +92 -2
  43. package/dist/domain/context-memory/entities.js.map +1 -1
  44. package/dist/domain/context-memory/repositories.d.ts +15 -2
  45. package/dist/domain/context-memory/repositories.d.ts.map +1 -1
  46. package/dist/domain/context-memory/value-objects.d.ts +18 -1
  47. package/dist/domain/context-memory/value-objects.d.ts.map +1 -1
  48. package/dist/domain/context-memory/value-objects.js +39 -1
  49. package/dist/domain/context-memory/value-objects.js.map +1 -1
  50. package/dist/hooks/config-command.d.ts +37 -0
  51. package/dist/hooks/config-command.d.ts.map +1 -0
  52. package/dist/hooks/config-command.js +68 -0
  53. package/dist/hooks/config-command.js.map +1 -0
  54. package/dist/hooks/execution-journal.d.ts +40 -0
  55. package/dist/hooks/execution-journal.d.ts.map +1 -0
  56. package/dist/hooks/execution-journal.js +102 -0
  57. package/dist/hooks/execution-journal.js.map +1 -0
  58. package/dist/hooks/first-run-guide.d.ts +2 -0
  59. package/dist/hooks/first-run-guide.d.ts.map +1 -1
  60. package/dist/hooks/first-run-guide.js +44 -2
  61. package/dist/hooks/first-run-guide.js.map +1 -1
  62. package/dist/hooks/slash-commands.d.ts +36 -0
  63. package/dist/hooks/slash-commands.d.ts.map +1 -0
  64. package/dist/hooks/slash-commands.js +121 -0
  65. package/dist/hooks/slash-commands.js.map +1 -0
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +71 -3
  68. package/dist/index.js.map +1 -1
  69. package/dist/infrastructure/azure-sync/azure-devops-client.d.ts.map +1 -1
  70. package/dist/infrastructure/azure-sync/azure-devops-client.js +9 -10
  71. package/dist/infrastructure/azure-sync/azure-devops-client.js.map +1 -1
  72. package/dist/infrastructure/config/index.d.ts +1 -0
  73. package/dist/infrastructure/config/index.d.ts.map +1 -1
  74. package/dist/infrastructure/config/index.js +1 -0
  75. package/dist/infrastructure/config/index.js.map +1 -1
  76. package/dist/infrastructure/config/yaml-config-writer.d.ts +16 -0
  77. package/dist/infrastructure/config/yaml-config-writer.d.ts.map +1 -0
  78. package/dist/infrastructure/config/yaml-config-writer.js +49 -0
  79. package/dist/infrastructure/config/yaml-config-writer.js.map +1 -0
  80. package/dist/infrastructure/context-memory/execution-journal-repository.d.ts +26 -0
  81. package/dist/infrastructure/context-memory/execution-journal-repository.d.ts.map +1 -0
  82. package/dist/infrastructure/context-memory/execution-journal-repository.js +110 -0
  83. package/dist/infrastructure/context-memory/execution-journal-repository.js.map +1 -0
  84. package/dist/tools/config-tools.d.ts +12 -0
  85. package/dist/tools/config-tools.d.ts.map +1 -0
  86. package/dist/tools/config-tools.js +136 -0
  87. package/dist/tools/config-tools.js.map +1 -0
  88. package/package.json +5 -2
  89. package/scripts/setup/setup-linux.sh +124 -0
  90. package/scripts/setup/setup-macos.sh +137 -0
  91. package/scripts/setup/setup-wsl.sh +175 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * SQLite Execution Journal Repository
3
+ *
4
+ * Implements ExecutionJournalRepository interface from domain layer.
5
+ * Maps ExecutionEntry entities to/from SQLite rows.
6
+ * Entry IDs are auto-increment integers assigned by SQLite.
7
+ *
8
+ * SOLID: SRP - persistence for ExecutionEntry only
9
+ * SOLID: DIP - implements domain interface
10
+ */
11
+ import type { SqliteAdapter } from "../database/sqlite-adapter.js";
12
+ import type { ExecutionJournalRepository } from "../../domain/context-memory/repositories.js";
13
+ import { ExecutionEntry } from "../../domain/context-memory/entities.js";
14
+ import { ExecutionEntryId } from "../../domain/context-memory/value-objects.js";
15
+ import { WorkspaceId } from "../../domain/shared/value-objects.js";
16
+ export declare class SqliteExecutionJournalRepository implements ExecutionJournalRepository {
17
+ private readonly db;
18
+ constructor(db: SqliteAdapter);
19
+ save(entry: ExecutionEntry): Promise<ExecutionEntry>;
20
+ findById(id: ExecutionEntryId): Promise<ExecutionEntry | null>;
21
+ update(entry: ExecutionEntry): Promise<void>;
22
+ findRunning(workspace: WorkspaceId): Promise<readonly ExecutionEntry[]>;
23
+ pruneOlderThan(workspace: WorkspaceId, before: Date): Promise<number>;
24
+ private toDomain;
25
+ }
26
+ //# sourceMappingURL=execution-journal-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-journal-repository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/context-memory/execution-journal-repository.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,6CAA6C,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EACL,gBAAgB,EAGjB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,WAAW,EAAa,MAAM,sCAAsC,CAAC;AAmC9E,qBAAa,gCAAiC,YAAW,0BAA0B;IACrE,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,aAAa;IAIxC,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;IA8BpD,QAAQ,CAAC,EAAE,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAQ9D,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5C,WAAW,CAAC,SAAS,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC;IAQvE,cAAc,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAa3E,OAAO,CAAC,QAAQ;CAoBjB"}
@@ -0,0 +1,110 @@
1
+ import { ExecutionEntry } from "../../domain/context-memory/entities.js";
2
+ import { ExecutionEntryId, ExecutionState, SessionId, } from "../../domain/context-memory/value-objects.js";
3
+ import { WorkspaceId, Timestamp } from "../../domain/shared/value-objects.js";
4
+ const SCHEMA_KEY = "context_memory_execution_journal";
5
+ const DDL = `
6
+ CREATE TABLE IF NOT EXISTS execution_journal (
7
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
8
+ tool_name TEXT NOT NULL,
9
+ args_summary TEXT NOT NULL DEFAULT '',
10
+ state TEXT NOT NULL DEFAULT 'running',
11
+ workspace TEXT NOT NULL,
12
+ session_id TEXT,
13
+ started_at TEXT NOT NULL,
14
+ finished_at TEXT,
15
+ error_message TEXT,
16
+ FOREIGN KEY (session_id) REFERENCES sessions(id)
17
+ );
18
+ CREATE INDEX IF NOT EXISTS idx_execjournal_workspace ON execution_journal(workspace);
19
+ CREATE INDEX IF NOT EXISTS idx_execjournal_state ON execution_journal(state);
20
+ CREATE INDEX IF NOT EXISTS idx_execjournal_started_at ON execution_journal(started_at);
21
+ `;
22
+ export class SqliteExecutionJournalRepository {
23
+ db;
24
+ constructor(db) {
25
+ this.db = db;
26
+ this.db.ensureSchema(SCHEMA_KEY, DDL);
27
+ }
28
+ async save(entry) {
29
+ const sql = `
30
+ INSERT INTO execution_journal (tool_name, args_summary, state, workspace, session_id, started_at, finished_at, error_message)
31
+ VALUES (@tool_name, @args_summary, @state, @workspace, @session_id, @started_at, @finished_at, @error_message)
32
+ `;
33
+ const result = this.db.execute(sql, {
34
+ tool_name: entry.toolName,
35
+ args_summary: entry.argsSummary,
36
+ state: entry.state,
37
+ workspace: entry.workspace.value,
38
+ session_id: entry.sessionId?.value ?? null,
39
+ started_at: entry.startedAt.toISO(),
40
+ finished_at: entry.finishedAt?.toISO() ?? null,
41
+ error_message: entry.errorMessage ?? null,
42
+ });
43
+ const realId = Number(result.lastInsertRowid);
44
+ return ExecutionEntry.reconstitute({
45
+ id: ExecutionEntryId.create(realId),
46
+ toolName: entry.toolName,
47
+ argsSummary: entry.argsSummary,
48
+ state: entry.state,
49
+ workspace: entry.workspace,
50
+ ...(entry.sessionId !== undefined ? { sessionId: entry.sessionId } : {}),
51
+ startedAt: entry.startedAt,
52
+ ...(entry.finishedAt !== undefined ? { finishedAt: entry.finishedAt } : {}),
53
+ ...(entry.errorMessage !== undefined ? { errorMessage: entry.errorMessage } : {}),
54
+ });
55
+ }
56
+ async findById(id) {
57
+ const row = this.db.queryOne("SELECT * FROM execution_journal WHERE id = @id", { id: id.numericValue });
58
+ return row != null ? this.toDomain(row) : null;
59
+ }
60
+ async update(entry) {
61
+ const sql = `
62
+ UPDATE execution_journal
63
+ SET state = @state, finished_at = @finished_at, error_message = @error_message
64
+ WHERE id = @id
65
+ `;
66
+ this.db.execute(sql, {
67
+ id: entry.id.numericValue,
68
+ state: entry.state,
69
+ finished_at: entry.finishedAt?.toISO() ?? null,
70
+ error_message: entry.errorMessage ?? null,
71
+ });
72
+ }
73
+ async findRunning(workspace) {
74
+ const rows = this.db.queryAll("SELECT * FROM execution_journal WHERE workspace = @workspace AND state = @state ORDER BY started_at DESC", { workspace: workspace.value, state: ExecutionState.Running });
75
+ return rows.map((row) => this.toDomain(row));
76
+ }
77
+ async pruneOlderThan(workspace, before) {
78
+ const sql = `
79
+ DELETE FROM execution_journal
80
+ WHERE workspace = @workspace AND state != @running AND started_at < @before
81
+ `;
82
+ const result = this.db.execute(sql, {
83
+ workspace: workspace.value,
84
+ running: ExecutionState.Running,
85
+ before: before.toISOString(),
86
+ });
87
+ return result.changes;
88
+ }
89
+ toDomain(row) {
90
+ const props = {
91
+ id: ExecutionEntryId.create(row.id),
92
+ toolName: row.tool_name,
93
+ argsSummary: row.args_summary,
94
+ state: row.state,
95
+ workspace: WorkspaceId.from(row.workspace),
96
+ ...(row.session_id !== null
97
+ ? { sessionId: SessionId.from(row.session_id) }
98
+ : {}),
99
+ startedAt: Timestamp.fromISO(row.started_at),
100
+ ...(row.finished_at !== null
101
+ ? { finishedAt: Timestamp.fromISO(row.finished_at) }
102
+ : {}),
103
+ ...(row.error_message !== null
104
+ ? { errorMessage: row.error_message }
105
+ : {}),
106
+ };
107
+ return ExecutionEntry.reconstitute(props);
108
+ }
109
+ }
110
+ //# sourceMappingURL=execution-journal-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-journal-repository.js","sourceRoot":"","sources":["../../../src/infrastructure/context-memory/execution-journal-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ToolDefinition } from "@opencode-ai/plugin";
2
+ import type { ConfigService } from "../application/config/config-service.js";
3
+ import type { ConfigWriteService } from "../application/config/config-write-service.js";
4
+ export interface ConfigToolsDeps {
5
+ readonly configService: ConfigService;
6
+ readonly configWriteService: ConfigWriteService;
7
+ }
8
+ /**
9
+ * Creates config read/write tools for agent-guided configuration.
10
+ */
11
+ export declare function createConfigTools(deps: ConfigToolsDeps): Record<string, ToolDefinition>;
12
+ //# sourceMappingURL=config-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-tools.d.ts","sourceRoot":"","sources":["../../src/tools/config-tools.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AAOxF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;CACjD;AAID;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,eAAe,GACpB,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAyGhC"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Config Tools
3
+ *
4
+ * OpenCode tool definitions for reading and writing JARVIS configuration.
5
+ * Provides agent-accessible tools for the /config slash command and
6
+ * general config management within OpenCode sessions.
7
+ *
8
+ * Tools defined (2):
9
+ * config-read — Read current effective config for a section or all sections
10
+ * config-write — Update config values for a specific section
11
+ *
12
+ * SOLID: SRP — config tool exposure only
13
+ * SOLID: DIP — depends on use case abstractions
14
+ */
15
+ import { tool } from "@opencode-ai/plugin";
16
+ const z = tool.schema;
17
+ // ── Tool Factory ──────────────────────────────────────────────────────
18
+ /**
19
+ * Creates config read/write tools for agent-guided configuration.
20
+ */
21
+ export function createConfigTools(deps) {
22
+ const { configService, configWriteService } = deps;
23
+ // ── config-read ──────────────────────────────────────────────────
24
+ const configRead = tool({
25
+ description: "Read current effective JARVIS configuration. Without a section argument, " +
26
+ "returns all writable sections with their current effective values (defaults merged " +
27
+ "with user overrides). With a section argument, returns that section's full config. " +
28
+ "Shows which values are overridden vs defaults.",
29
+ args: {
30
+ section: z
31
+ .string()
32
+ .optional()
33
+ .describe("Config section to read (e.g., 'rag', 'azure-sync', 'pipeline', " +
34
+ "'agent-registry', 'mcp-server', 'kanban', 'token-metrics'). " +
35
+ "Omit to read all sections."),
36
+ },
37
+ async execute(args) {
38
+ const writableContexts = configWriteService.getWritableContexts();
39
+ if (args.section !== undefined) {
40
+ if (!writableContexts.includes(args.section)) {
41
+ return `Unknown or non-writable section: "${args.section}"\n\nWritable sections: ${writableContexts.join(", ")}`;
42
+ }
43
+ const effective = configService.getConfig(args.section);
44
+ return formatConfigSection(args.section, effective);
45
+ }
46
+ // All sections
47
+ const lines = [
48
+ "JARVIS Configuration — All Sections",
49
+ `External config file: ${configService.isExternalConfigAvailable() ? "found" : "not found (using defaults only)"}`,
50
+ "",
51
+ ];
52
+ for (const ctx of writableContexts) {
53
+ const effective = configService.getConfig(ctx);
54
+ lines.push(formatConfigSection(ctx, effective));
55
+ lines.push("");
56
+ }
57
+ return lines.join("\n");
58
+ },
59
+ });
60
+ // ── config-write ─────────────────────────────────────────────────
61
+ const configWrite = tool({
62
+ description: "Update JARVIS configuration values for a specific section. " +
63
+ "Accepts a JSON object with the values to change. Only values that " +
64
+ "differ from defaults are persisted to config/jarvis.yaml. " +
65
+ "Validates input before writing (e.g., pollEnabled requires org+project).",
66
+ args: {
67
+ section: z
68
+ .string()
69
+ .describe("Config section to update (e.g., 'azure-sync', 'rag', 'pipeline', " +
70
+ "'agent-registry', 'mcp-server', 'kanban', 'token-metrics')."),
71
+ values: z
72
+ .string()
73
+ .describe("JSON string of the partial values to update. " +
74
+ 'Example: \'{"organization": "MyOrg", "project": "MyProject"}\' for azure-sync. ' +
75
+ "Only include the keys you want to change."),
76
+ },
77
+ async execute(args) {
78
+ let parsed;
79
+ try {
80
+ parsed = JSON.parse(args.values);
81
+ }
82
+ catch {
83
+ return `Error: Invalid JSON in values parameter: ${args.values}`;
84
+ }
85
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
86
+ return "Error: values must be a JSON object (not array or primitive)";
87
+ }
88
+ try {
89
+ const effective = configWriteService.updateContext(args.section, parsed);
90
+ return (`Configuration updated for "${args.section}".\n\n` +
91
+ `New effective values:\n${formatConfigSection(args.section, effective)}`);
92
+ }
93
+ catch (err) {
94
+ const msg = err instanceof Error ? err.message : String(err);
95
+ return `Error updating "${args.section}": ${msg}`;
96
+ }
97
+ },
98
+ });
99
+ return {
100
+ "config-read": configRead,
101
+ "config-write": configWrite,
102
+ };
103
+ }
104
+ // ── Formatting Helpers ────────────────────────────────────────────────
105
+ function formatConfigSection(name, config) {
106
+ const lines = [`[${name}]`];
107
+ if (config === null || config === undefined) {
108
+ lines.push(" (no configuration)");
109
+ return lines.join("\n");
110
+ }
111
+ if (typeof config !== "object") {
112
+ lines.push(` ${String(config)}`);
113
+ return lines.join("\n");
114
+ }
115
+ formatObject(config, lines, 1);
116
+ return lines.join("\n");
117
+ }
118
+ function formatObject(obj, lines, depth) {
119
+ const indent = " ".repeat(depth);
120
+ for (const [key, value] of Object.entries(obj)) {
121
+ if (value === null) {
122
+ lines.push(`${indent}${key}: null`);
123
+ }
124
+ else if (typeof value === "object" && !Array.isArray(value)) {
125
+ lines.push(`${indent}${key}:`);
126
+ formatObject(value, lines, depth + 1);
127
+ }
128
+ else if (Array.isArray(value)) {
129
+ lines.push(`${indent}${key}: [${value.map((v) => JSON.stringify(v)).join(", ")}]`);
130
+ }
131
+ else {
132
+ lines.push(`${indent}${key}: ${String(value)}`);
133
+ }
134
+ }
135
+ }
136
+ //# sourceMappingURL=config-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-tools.js","sourceRoot":"","sources":["../../src/tools/config-tools.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mc1global/opencode-jarvis",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "JARVIS Framework - OpenCode native plugin for multi-agent development with DDD architecture",
5
5
  "author": "Julio Fabio de O. Chagas <julio.fabio@mc1global.com>",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -15,11 +15,13 @@
15
15
  }
16
16
  },
17
17
  "bin": {
18
- "jarvis-mcp": "dist/mcp-server.js"
18
+ "jarvis-mcp": "dist/mcp-server.js",
19
+ "jarvis": "dist/cli/config-wizard.js"
19
20
  },
20
21
  "files": [
21
22
  "dist/",
22
23
  "templates/",
24
+ "scripts/setup/",
23
25
  "LICENSE",
24
26
  "README.md",
25
27
  "QUICK-GUIDE.md"
@@ -46,6 +48,7 @@
46
48
  "@opencode-ai/plugin": ">=1.1.0"
47
49
  },
48
50
  "dependencies": {
51
+ "@clack/prompts": "^1.0.1",
49
52
  "@langchain/textsplitters": "^1.0.1",
50
53
  "@modelcontextprotocol/sdk": "^1.26.0",
51
54
  "js-yaml": "^4.1.1",
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env bash
2
+ # ──────────────────────────────────────────────────────────────────────────────
3
+ # JARVIS Plugin — Linux Prerequisites Setup
4
+ #
5
+ # Installs non-npm dependencies required by @mc1global/opencode-jarvis:
6
+ # - Bun (required) — SQLite runtime for the plugin
7
+ # - Ollama (required) — Local embedding generation for RAG semantic search
8
+ # - embeddinggemma model — Default embedding model (768 dimensions)
9
+ # - Azure CLI (optional) — Azure DevOps board sync
10
+ # - Dagger CLI (optional) — Container-based CI/CD gate execution
11
+ #
12
+ # Usage:
13
+ # curl -fsSL <repo-raw-url>/scripts/setup/setup-linux.sh | bash
14
+ # # or
15
+ # chmod +x setup-linux.sh && ./setup-linux.sh
16
+ #
17
+ # Tested on: Ubuntu 22.04+, Debian 12+, Fedora 38+, Arch Linux
18
+ # ──────────────────────────────────────────────────────────────────────────────
19
+ set -euo pipefail
20
+
21
+ BOLD="\033[1m"
22
+ GREEN="\033[0;32m"
23
+ YELLOW="\033[0;33m"
24
+ RED="\033[0;31m"
25
+ RESET="\033[0m"
26
+
27
+ info() { echo -e "${BOLD}[INFO]${RESET} $1"; }
28
+ ok() { echo -e "${GREEN}[OK]${RESET} $1"; }
29
+ warn() { echo -e "${YELLOW}[WARN]${RESET} $1"; }
30
+ fail() { echo -e "${RED}[FAIL]${RESET} $1"; }
31
+
32
+ # ── Bun (required) ───────────────────────────────────────────────────────────
33
+
34
+ if ! command -v bun &>/dev/null; then
35
+ info "Installing Bun..."
36
+ curl -fsSL https://bun.sh/install | bash
37
+ export BUN_INSTALL="$HOME/.bun"
38
+ export PATH="$BUN_INSTALL/bin:$PATH"
39
+ ok "Bun installed ($(bun --version))"
40
+ else
41
+ ok "Bun already installed ($(bun --version))"
42
+ fi
43
+
44
+ # ── Ollama (required) ────────────────────────────────────────────────────────
45
+
46
+ if ! command -v ollama &>/dev/null; then
47
+ info "Installing Ollama..."
48
+ curl -fsSL https://ollama.ai/install.sh | sh
49
+ ok "Ollama installed"
50
+ else
51
+ ok "Ollama already installed"
52
+ fi
53
+
54
+ # Start Ollama if not already running
55
+ if ! curl -sf http://localhost:11434/api/tags &>/dev/null; then
56
+ info "Starting Ollama server..."
57
+ ollama serve &>/dev/null &
58
+ sleep 3
59
+ ok "Ollama server started"
60
+ else
61
+ ok "Ollama server already running"
62
+ fi
63
+
64
+ # ── Embedding Model (required for RAG) ───────────────────────────────────────
65
+
66
+ if ollama list 2>/dev/null | grep -q "embeddinggemma"; then
67
+ ok "embeddinggemma model already pulled"
68
+ else
69
+ info "Pulling embeddinggemma embedding model (this may take a minute)..."
70
+ ollama pull embeddinggemma
71
+ ok "embeddinggemma model ready"
72
+ fi
73
+
74
+ # ── Optional: Azure CLI ──────────────────────────────────────────────────────
75
+
76
+ echo ""
77
+ read -rp "Install Azure CLI for Azure DevOps sync? (y/N): " INSTALL_AZ
78
+ if [[ "${INSTALL_AZ:-N}" =~ ^[Yy]$ ]]; then
79
+ if ! command -v az &>/dev/null; then
80
+ info "Installing Azure CLI..."
81
+ curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
82
+ ok "Azure CLI installed — run 'az login' to authenticate"
83
+ else
84
+ ok "Azure CLI already installed"
85
+ fi
86
+ else
87
+ warn "Skipped Azure CLI (optional — needed only for Azure DevOps sync)"
88
+ fi
89
+
90
+ # ── Optional: Dagger CLI ─────────────────────────────────────────────────────
91
+
92
+ read -rp "Install Dagger CLI for CI/CD pipelines? (y/N): " INSTALL_DAGGER
93
+ if [[ "${INSTALL_DAGGER:-N}" =~ ^[Yy]$ ]]; then
94
+ if ! command -v dagger &>/dev/null; then
95
+ info "Installing Dagger CLI..."
96
+ curl -fsSL https://dl.dagger.io/dagger/install.sh | sh
97
+ sudo mv ./bin/dagger /usr/local/bin/dagger 2>/dev/null || true
98
+ ok "Dagger CLI installed"
99
+ else
100
+ ok "Dagger CLI already installed"
101
+ fi
102
+ else
103
+ warn "Skipped Dagger CLI (optional — needed only for CI/CD pipeline gates)"
104
+ fi
105
+
106
+ # ── Summary ──────────────────────────────────────────────────────────────────
107
+
108
+ echo ""
109
+ echo -e "${BOLD}──────────────────────────────────────────${RESET}"
110
+ echo -e "${GREEN}${BOLD}JARVIS prerequisites installed!${RESET}"
111
+ echo ""
112
+ echo "Next steps:"
113
+ echo " 1. Add the plugin to your project:"
114
+ echo ""
115
+ echo " # In your project root:"
116
+ echo ' echo '"'"'{ "plugin": ["@mc1global/opencode-jarvis"] }'"'"' > opencode.json'
117
+ echo ""
118
+ echo " 2. Launch OpenCode:"
119
+ echo ""
120
+ echo " cd /path/to/your/project"
121
+ echo " opencode"
122
+ echo ""
123
+ echo " 3. JARVIS will auto-bootstrap on first launch."
124
+ echo -e "${BOLD}──────────────────────────────────────────${RESET}"
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env bash
2
+ # ──────────────────────────────────────────────────────────────────────────────
3
+ # JARVIS Plugin — macOS Prerequisites Setup
4
+ #
5
+ # Installs non-npm dependencies required by @mc1global/opencode-jarvis:
6
+ # - Bun (required) — SQLite runtime for the plugin
7
+ # - Ollama (required) — Local embedding generation for RAG semantic search
8
+ # - embeddinggemma model — Default embedding model (768 dimensions)
9
+ # - Azure CLI (optional) — Azure DevOps board sync
10
+ # - Dagger CLI (optional) — Container-based CI/CD gate execution
11
+ #
12
+ # Usage:
13
+ # curl -fsSL <repo-raw-url>/scripts/setup/setup-macos.sh | bash
14
+ # # or
15
+ # chmod +x setup-macos.sh && ./setup-macos.sh
16
+ #
17
+ # Requires: macOS 12+ with Homebrew (installs Homebrew if missing)
18
+ # ──────────────────────────────────────────────────────────────────────────────
19
+ set -euo pipefail
20
+
21
+ BOLD="\033[1m"
22
+ GREEN="\033[0;32m"
23
+ YELLOW="\033[0;33m"
24
+ RED="\033[0;31m"
25
+ RESET="\033[0m"
26
+
27
+ info() { echo -e "${BOLD}[INFO]${RESET} $1"; }
28
+ ok() { echo -e "${GREEN}[OK]${RESET} $1"; }
29
+ warn() { echo -e "${YELLOW}[WARN]${RESET} $1"; }
30
+ fail() { echo -e "${RED}[FAIL]${RESET} $1"; }
31
+
32
+ # ── Homebrew ──────────────────────────────────────────────────────────────────
33
+
34
+ if ! command -v brew &>/dev/null; then
35
+ info "Homebrew not found — installing..."
36
+ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
37
+ # shellcheck disable=SC2016
38
+ echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> "$HOME/.zprofile"
39
+ eval "$(/opt/homebrew/bin/brew shellenv)"
40
+ ok "Homebrew installed"
41
+ else
42
+ ok "Homebrew already installed"
43
+ fi
44
+
45
+ # ── Bun (required) ───────────────────────────────────────────────────────────
46
+
47
+ if ! command -v bun &>/dev/null; then
48
+ info "Installing Bun..."
49
+ curl -fsSL https://bun.sh/install | bash
50
+ # Source the updated profile so bun is available in this session
51
+ export BUN_INSTALL="$HOME/.bun"
52
+ export PATH="$BUN_INSTALL/bin:$PATH"
53
+ ok "Bun installed ($(bun --version))"
54
+ else
55
+ ok "Bun already installed ($(bun --version))"
56
+ fi
57
+
58
+ # ── Ollama (required) ────────────────────────────────────────────────────────
59
+
60
+ if ! command -v ollama &>/dev/null; then
61
+ info "Installing Ollama..."
62
+ brew install ollama
63
+ ok "Ollama installed"
64
+ else
65
+ ok "Ollama already installed"
66
+ fi
67
+
68
+ # Start Ollama if not already running
69
+ if ! curl -sf http://localhost:11434/api/tags &>/dev/null; then
70
+ info "Starting Ollama server..."
71
+ ollama serve &>/dev/null &
72
+ sleep 3
73
+ ok "Ollama server started"
74
+ else
75
+ ok "Ollama server already running"
76
+ fi
77
+
78
+ # ── Embedding Model (required for RAG) ───────────────────────────────────────
79
+
80
+ if ollama list 2>/dev/null | grep -q "embeddinggemma"; then
81
+ ok "embeddinggemma model already pulled"
82
+ else
83
+ info "Pulling embeddinggemma embedding model (this may take a minute)..."
84
+ ollama pull embeddinggemma
85
+ ok "embeddinggemma model ready"
86
+ fi
87
+
88
+ # ── Optional: Azure CLI ──────────────────────────────────────────────────────
89
+
90
+ echo ""
91
+ read -rp "Install Azure CLI for Azure DevOps sync? (y/N): " INSTALL_AZ
92
+ if [[ "${INSTALL_AZ:-N}" =~ ^[Yy]$ ]]; then
93
+ if ! command -v az &>/dev/null; then
94
+ info "Installing Azure CLI..."
95
+ brew install azure-cli
96
+ ok "Azure CLI installed — run 'az login' to authenticate"
97
+ else
98
+ ok "Azure CLI already installed"
99
+ fi
100
+ else
101
+ warn "Skipped Azure CLI (optional — needed only for Azure DevOps sync)"
102
+ fi
103
+
104
+ # ── Optional: Dagger CLI ─────────────────────────────────────────────────────
105
+
106
+ read -rp "Install Dagger CLI for CI/CD pipelines? (y/N): " INSTALL_DAGGER
107
+ if [[ "${INSTALL_DAGGER:-N}" =~ ^[Yy]$ ]]; then
108
+ if ! command -v dagger &>/dev/null; then
109
+ info "Installing Dagger CLI..."
110
+ brew install dagger/tap/dagger
111
+ ok "Dagger CLI installed"
112
+ else
113
+ ok "Dagger CLI already installed"
114
+ fi
115
+ else
116
+ warn "Skipped Dagger CLI (optional — needed only for CI/CD pipeline gates)"
117
+ fi
118
+
119
+ # ── Summary ──────────────────────────────────────────────────────────────────
120
+
121
+ echo ""
122
+ echo -e "${BOLD}──────────────────────────────────────────${RESET}"
123
+ echo -e "${GREEN}${BOLD}JARVIS prerequisites installed!${RESET}"
124
+ echo ""
125
+ echo "Next steps:"
126
+ echo " 1. Add the plugin to your project:"
127
+ echo ""
128
+ echo " # In your project root:"
129
+ echo ' echo '"'"'{ "plugin": ["@mc1global/opencode-jarvis"] }'"'"' > opencode.json'
130
+ echo ""
131
+ echo " 2. Launch OpenCode:"
132
+ echo ""
133
+ echo " cd /path/to/your/project"
134
+ echo " opencode"
135
+ echo ""
136
+ echo " 3. JARVIS will auto-bootstrap on first launch."
137
+ echo -e "${BOLD}──────────────────────────────────────────${RESET}"