@tonycasey/lisa 2.2.0 ā 2.5.5
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/lib/application/handlers/PromptSubmitHandler.d.ts +22 -12
- package/dist/lib/application/handlers/PromptSubmitHandler.d.ts.map +1 -1
- package/dist/lib/application/handlers/PromptSubmitHandler.js +36 -13
- package/dist/lib/application/handlers/PromptSubmitHandler.js.map +1 -1
- package/dist/lib/application/handlers/SessionStartHandler.d.ts +47 -5
- package/dist/lib/application/handlers/SessionStartHandler.d.ts.map +1 -1
- package/dist/lib/application/handlers/SessionStartHandler.js +164 -37
- package/dist/lib/application/handlers/SessionStartHandler.js.map +1 -1
- package/dist/lib/application/handlers/SessionStopHandler.d.ts +29 -5
- package/dist/lib/application/handlers/SessionStopHandler.d.ts.map +1 -1
- package/dist/lib/application/handlers/SessionStopHandler.js +83 -11
- package/dist/lib/application/handlers/SessionStopHandler.js.map +1 -1
- package/dist/lib/application/interfaces/index.d.ts +1 -0
- package/dist/lib/application/interfaces/index.d.ts.map +1 -1
- package/dist/lib/application/mediator/IMediator.d.ts +73 -0
- package/dist/lib/application/mediator/IMediator.d.ts.map +1 -0
- package/dist/lib/application/mediator/IMediator.js +12 -0
- package/dist/lib/application/mediator/IMediator.js.map +1 -0
- package/dist/lib/application/mediator/Mediator.d.ts +29 -0
- package/dist/lib/application/mediator/Mediator.d.ts.map +1 -0
- package/dist/lib/application/mediator/Mediator.js +53 -0
- package/dist/lib/application/mediator/Mediator.js.map +1 -0
- package/dist/lib/application/mediator/index.d.ts +10 -0
- package/dist/lib/application/mediator/index.d.ts.map +1 -0
- package/dist/lib/application/mediator/index.js +18 -0
- package/dist/lib/application/mediator/index.js.map +1 -0
- package/dist/lib/application/mediator/requests/PromptSubmitRequest.d.ts +60 -0
- package/dist/lib/application/mediator/requests/PromptSubmitRequest.d.ts.map +1 -0
- package/dist/lib/application/mediator/requests/PromptSubmitRequest.js +35 -0
- package/dist/lib/application/mediator/requests/PromptSubmitRequest.js.map +1 -0
- package/dist/lib/application/mediator/requests/SessionStartRequest.d.ts +36 -0
- package/dist/lib/application/mediator/requests/SessionStartRequest.d.ts.map +1 -0
- package/dist/lib/application/mediator/requests/SessionStartRequest.js +32 -0
- package/dist/lib/application/mediator/requests/SessionStartRequest.js.map +1 -0
- package/dist/lib/application/mediator/requests/SessionStopRequest.d.ts +67 -0
- package/dist/lib/application/mediator/requests/SessionStopRequest.d.ts.map +1 -0
- package/dist/lib/application/mediator/requests/SessionStopRequest.js +35 -0
- package/dist/lib/application/mediator/requests/SessionStopRequest.js.map +1 -0
- package/dist/lib/application/mediator/requests/index.d.ts +9 -0
- package/dist/lib/application/mediator/requests/index.d.ts.map +1 -0
- package/dist/lib/application/mediator/requests/index.js +13 -0
- package/dist/lib/application/mediator/requests/index.js.map +1 -0
- package/dist/lib/cli.d.ts +2 -44
- package/dist/lib/cli.d.ts.map +1 -1
- package/dist/lib/cli.js +351 -606
- package/dist/lib/cli.js.map +1 -1
- package/dist/lib/commands/docker.d.ts +20 -0
- package/dist/lib/commands/docker.d.ts.map +1 -0
- package/dist/lib/commands/docker.js +27 -0
- package/dist/lib/commands/docker.js.map +1 -0
- package/dist/lib/commands/doctor.d.ts +94 -0
- package/dist/lib/commands/doctor.d.ts.map +1 -0
- package/dist/lib/commands/doctor.js +716 -0
- package/dist/lib/commands/doctor.js.map +1 -0
- package/dist/lib/commands/index.d.ts +10 -0
- package/dist/lib/commands/index.d.ts.map +1 -0
- package/dist/lib/commands/index.js +31 -0
- package/dist/lib/commands/index.js.map +1 -0
- package/dist/lib/commands/init.d.ts +31 -0
- package/dist/lib/commands/init.d.ts.map +1 -0
- package/dist/lib/commands/init.js +497 -0
- package/dist/lib/commands/init.js.map +1 -0
- package/dist/lib/commands/shared/constants.d.ts +27 -0
- package/dist/lib/commands/shared/constants.d.ts.map +1 -0
- package/dist/lib/commands/shared/constants.js +46 -0
- package/dist/lib/commands/shared/constants.js.map +1 -0
- package/dist/lib/commands/shared/index.d.ts +5 -0
- package/dist/lib/commands/shared/index.d.ts.map +1 -0
- package/dist/lib/commands/shared/index.js +15 -0
- package/dist/lib/commands/shared/index.js.map +1 -0
- package/dist/lib/domain/index.d.ts +4 -2
- package/dist/lib/domain/index.d.ts.map +1 -1
- package/dist/lib/domain/index.js +5 -2
- package/dist/lib/domain/index.js.map +1 -1
- package/dist/lib/domain/interfaces/ILabelInference.d.ts +62 -0
- package/dist/lib/domain/interfaces/ILabelInference.d.ts.map +1 -0
- package/dist/lib/domain/interfaces/ILabelInference.js +11 -0
- package/dist/lib/domain/interfaces/ILabelInference.js.map +1 -0
- package/dist/lib/domain/interfaces/ILisaServices.d.ts +6 -0
- package/dist/lib/domain/interfaces/ILisaServices.d.ts.map +1 -1
- package/dist/lib/domain/interfaces/IMcpClient.d.ts +15 -2
- package/dist/lib/domain/interfaces/IMcpClient.d.ts.map +1 -1
- package/dist/lib/domain/interfaces/ISessionCaptureService.d.ts +2 -1
- package/dist/lib/domain/interfaces/ISessionCaptureService.d.ts.map +1 -1
- package/dist/lib/domain/interfaces/IStructuredLog.d.ts +162 -0
- package/dist/lib/domain/interfaces/IStructuredLog.d.ts.map +1 -0
- package/dist/lib/domain/interfaces/IStructuredLog.js +85 -0
- package/dist/lib/domain/interfaces/IStructuredLog.js.map +1 -0
- package/dist/lib/domain/interfaces/index.d.ts +2 -0
- package/dist/lib/domain/interfaces/index.d.ts.map +1 -1
- package/dist/lib/domain/interfaces/index.js +6 -0
- package/dist/lib/domain/interfaces/index.js.map +1 -1
- package/dist/lib/domain/interfaces/types/ITask.d.ts +16 -0
- package/dist/lib/domain/interfaces/types/ITask.d.ts.map +1 -1
- package/dist/lib/domain/interfaces/types/ITask.js.map +1 -1
- package/dist/lib/domain/utils/cancellation.d.ts +111 -0
- package/dist/lib/domain/utils/cancellation.d.ts.map +1 -0
- package/dist/lib/domain/utils/cancellation.js +168 -0
- package/dist/lib/domain/utils/cancellation.js.map +1 -0
- package/dist/lib/domain/utils/index.d.ts +8 -0
- package/dist/lib/domain/utils/index.d.ts.map +1 -0
- package/dist/lib/domain/utils/index.js +16 -0
- package/dist/lib/domain/utils/index.js.map +1 -0
- package/dist/lib/infrastructure/adapters/claude/session-start.d.ts +1 -1
- package/dist/lib/infrastructure/adapters/claude/session-start.js +9 -11
- package/dist/lib/infrastructure/adapters/claude/session-start.js.map +1 -1
- package/dist/lib/infrastructure/adapters/claude/session-stop.d.ts +1 -5
- package/dist/lib/infrastructure/adapters/claude/session-stop.d.ts.map +1 -1
- package/dist/lib/infrastructure/adapters/claude/session-stop.js +12 -15
- package/dist/lib/infrastructure/adapters/claude/session-stop.js.map +1 -1
- package/dist/lib/infrastructure/adapters/claude/user-prompt-submit.d.ts +1 -1
- package/dist/lib/infrastructure/adapters/claude/user-prompt-submit.js +9 -11
- package/dist/lib/infrastructure/adapters/claude/user-prompt-submit.js.map +1 -1
- package/dist/lib/infrastructure/adapters/opencode/plugin.d.ts +2 -2
- package/dist/lib/infrastructure/adapters/opencode/plugin.d.ts.map +1 -1
- package/dist/lib/infrastructure/adapters/opencode/plugin.js +16 -21
- package/dist/lib/infrastructure/adapters/opencode/plugin.js.map +1 -1
- package/dist/lib/infrastructure/cli/index.d.ts +8 -0
- package/dist/lib/infrastructure/cli/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/cli/index.js +15 -0
- package/dist/lib/infrastructure/cli/index.js.map +1 -0
- package/dist/lib/infrastructure/cli/io.d.ts +91 -0
- package/dist/lib/infrastructure/cli/io.d.ts.map +1 -0
- package/dist/lib/infrastructure/cli/io.js +128 -0
- package/dist/lib/infrastructure/cli/io.js.map +1 -0
- package/dist/lib/infrastructure/dal/connections/McpConnectionManager.js +1 -1
- package/dist/lib/infrastructure/dal/connections/McpConnectionManager.js.map +1 -1
- package/dist/lib/infrastructure/dal/repositories/mcp/McpTaskRepository.d.ts.map +1 -1
- package/dist/lib/infrastructure/dal/repositories/mcp/McpTaskRepository.js +6 -2
- package/dist/lib/infrastructure/dal/repositories/mcp/McpTaskRepository.js.map +1 -1
- package/dist/lib/infrastructure/dal/repositories/neo4j/Neo4jTaskRepository.d.ts +5 -2
- package/dist/lib/infrastructure/dal/repositories/neo4j/Neo4jTaskRepository.d.ts.map +1 -1
- package/dist/lib/infrastructure/dal/repositories/neo4j/Neo4jTaskRepository.js +78 -45
- package/dist/lib/infrastructure/dal/repositories/neo4j/Neo4jTaskRepository.js.map +1 -1
- package/dist/lib/infrastructure/dal/repositories/zep/ZepTaskRepository.d.ts.map +1 -1
- package/dist/lib/infrastructure/dal/repositories/zep/ZepTaskRepository.js +6 -2
- package/dist/lib/infrastructure/dal/repositories/zep/ZepTaskRepository.js.map +1 -1
- package/dist/lib/infrastructure/di/Container.d.ts +72 -0
- package/dist/lib/infrastructure/di/Container.d.ts.map +1 -0
- package/dist/lib/infrastructure/di/Container.js +182 -0
- package/dist/lib/infrastructure/di/Container.js.map +1 -0
- package/dist/lib/infrastructure/di/IContainer.d.ts +87 -0
- package/dist/lib/infrastructure/di/IContainer.d.ts.map +1 -0
- package/dist/lib/infrastructure/di/IContainer.js +11 -0
- package/dist/lib/infrastructure/di/IContainer.js.map +1 -0
- package/dist/lib/infrastructure/di/ServiceFactory.d.ts +6 -0
- package/dist/lib/infrastructure/di/ServiceFactory.d.ts.map +1 -1
- package/dist/lib/infrastructure/di/ServiceFactory.js +66 -0
- package/dist/lib/infrastructure/di/ServiceFactory.js.map +1 -1
- package/dist/lib/infrastructure/di/bootstrap.d.ts +43 -0
- package/dist/lib/infrastructure/di/bootstrap.d.ts.map +1 -0
- package/dist/lib/infrastructure/di/bootstrap.js +272 -0
- package/dist/lib/infrastructure/di/bootstrap.js.map +1 -0
- package/dist/lib/infrastructure/di/index.d.ts +6 -0
- package/dist/lib/infrastructure/di/index.d.ts.map +1 -1
- package/dist/lib/infrastructure/di/index.js +15 -1
- package/dist/lib/infrastructure/di/index.js.map +1 -1
- package/dist/lib/infrastructure/di/tokens.d.ts +70 -0
- package/dist/lib/infrastructure/di/tokens.d.ts.map +1 -0
- package/dist/lib/infrastructure/di/tokens.js +58 -0
- package/dist/lib/infrastructure/di/tokens.js.map +1 -0
- package/dist/lib/infrastructure/index.d.ts +1 -0
- package/dist/lib/infrastructure/index.d.ts.map +1 -1
- package/dist/lib/infrastructure/index.js +2 -0
- package/dist/lib/infrastructure/index.js.map +1 -1
- package/dist/lib/infrastructure/logging/Logger.d.ts +51 -4
- package/dist/lib/infrastructure/logging/Logger.d.ts.map +1 -1
- package/dist/lib/infrastructure/logging/Logger.js +127 -2
- package/dist/lib/infrastructure/logging/Logger.js.map +1 -1
- package/dist/lib/infrastructure/mcp/McpClient.d.ts +36 -1
- package/dist/lib/infrastructure/mcp/McpClient.d.ts.map +1 -1
- package/dist/lib/infrastructure/mcp/McpClient.js +68 -2
- package/dist/lib/infrastructure/mcp/McpClient.js.map +1 -1
- package/dist/lib/infrastructure/services/LabelInferenceService.d.ts +33 -0
- package/dist/lib/infrastructure/services/LabelInferenceService.d.ts.map +1 -0
- package/dist/lib/infrastructure/services/LabelInferenceService.js +225 -0
- package/dist/lib/infrastructure/services/LabelInferenceService.js.map +1 -0
- package/dist/lib/infrastructure/services/MemoryService.d.ts +18 -1
- package/dist/lib/infrastructure/services/MemoryService.d.ts.map +1 -1
- package/dist/lib/infrastructure/services/MemoryService.js +117 -52
- package/dist/lib/infrastructure/services/MemoryService.js.map +1 -1
- package/dist/lib/infrastructure/services/SessionCaptureService.d.ts +74 -20
- package/dist/lib/infrastructure/services/SessionCaptureService.d.ts.map +1 -1
- package/dist/lib/infrastructure/services/SessionCaptureService.js +331 -22
- package/dist/lib/infrastructure/services/SessionCaptureService.js.map +1 -1
- package/dist/lib/infrastructure/services/index.d.ts +1 -0
- package/dist/lib/infrastructure/services/index.d.ts.map +1 -1
- package/dist/lib/infrastructure/services/index.js +4 -1
- package/dist/lib/infrastructure/services/index.js.map +1 -1
- package/dist/lib/infrastructure/utils/index.d.ts +10 -0
- package/dist/lib/infrastructure/utils/index.d.ts.map +1 -0
- package/dist/lib/infrastructure/utils/index.js +26 -0
- package/dist/lib/infrastructure/utils/index.js.map +1 -0
- package/dist/lib/skills/github/github.d.ts +27 -0
- package/dist/lib/skills/github/github.d.ts.map +1 -0
- package/dist/lib/skills/github/github.js +408 -0
- package/dist/lib/skills/github/github.js.map +1 -0
- package/dist/lib/skills/shared/clients/GhCliClient.d.ts +17 -0
- package/dist/lib/skills/shared/clients/GhCliClient.d.ts.map +1 -0
- package/dist/lib/skills/shared/clients/GhCliClient.js +244 -0
- package/dist/lib/skills/shared/clients/GhCliClient.js.map +1 -0
- package/dist/lib/skills/shared/clients/McpClient.d.ts +12 -0
- package/dist/lib/skills/shared/clients/McpClient.d.ts.map +1 -1
- package/dist/lib/skills/shared/clients/McpClient.js +121 -76
- package/dist/lib/skills/shared/clients/McpClient.js.map +1 -1
- package/dist/lib/skills/shared/clients/index.d.ts +1 -0
- package/dist/lib/skills/shared/clients/index.d.ts.map +1 -1
- package/dist/lib/skills/shared/clients/index.js +4 -1
- package/dist/lib/skills/shared/clients/index.js.map +1 -1
- package/dist/lib/skills/shared/clients/interfaces/IGhCliClient.d.ts +56 -0
- package/dist/lib/skills/shared/clients/interfaces/IGhCliClient.d.ts.map +1 -0
- package/dist/lib/skills/shared/clients/interfaces/IGhCliClient.js +7 -0
- package/dist/lib/skills/shared/clients/interfaces/IGhCliClient.js.map +1 -0
- package/dist/lib/skills/shared/clients/interfaces/IZepClient.d.ts +7 -1
- package/dist/lib/skills/shared/clients/interfaces/IZepClient.d.ts.map +1 -1
- package/dist/lib/skills/shared/clients/interfaces/index.d.ts +1 -0
- package/dist/lib/skills/shared/clients/interfaces/index.d.ts.map +1 -1
- package/dist/lib/skills/shared/clients/interfaces/index.js +1 -0
- package/dist/lib/skills/shared/clients/interfaces/index.js.map +1 -1
- package/dist/lib/skills/shared/services/GitHubService.d.ts +169 -0
- package/dist/lib/skills/shared/services/GitHubService.d.ts.map +1 -0
- package/dist/lib/skills/shared/services/GitHubService.js +493 -0
- package/dist/lib/skills/shared/services/GitHubService.js.map +1 -0
- package/dist/lib/skills/shared/services/GitHubSyncService.d.ts +124 -0
- package/dist/lib/skills/shared/services/GitHubSyncService.d.ts.map +1 -0
- package/dist/lib/skills/shared/services/GitHubSyncService.js +412 -0
- package/dist/lib/skills/shared/services/GitHubSyncService.js.map +1 -0
- package/dist/lib/skills/shared/services/TaskCliService.d.ts +4 -2
- package/dist/lib/skills/shared/services/TaskCliService.d.ts.map +1 -1
- package/dist/lib/skills/shared/services/TaskCliService.js +90 -6
- package/dist/lib/skills/shared/services/TaskCliService.js.map +1 -1
- package/dist/lib/skills/shared/services/TaskService.d.ts.map +1 -1
- package/dist/lib/skills/shared/services/TaskService.js +199 -21
- package/dist/lib/skills/shared/services/TaskService.js.map +1 -1
- package/dist/lib/skills/shared/services/index.d.ts +2 -0
- package/dist/lib/skills/shared/services/index.d.ts.map +1 -1
- package/dist/lib/skills/shared/services/index.js +7 -1
- package/dist/lib/skills/shared/services/index.js.map +1 -1
- package/dist/lib/skills/shared/services/interfaces/ITaskService.d.ts +56 -1
- package/dist/lib/skills/shared/services/interfaces/ITaskService.d.ts.map +1 -1
- package/dist/lib/skills/shared/utils/index.d.ts +1 -0
- package/dist/lib/skills/shared/utils/index.d.ts.map +1 -1
- package/dist/lib/skills/shared/utils/index.js +9 -1
- package/dist/lib/skills/shared/utils/index.js.map +1 -1
- package/dist/lib/skills/shared/utils/issue-refs.d.ts +127 -0
- package/dist/lib/skills/shared/utils/issue-refs.d.ts.map +1 -0
- package/dist/lib/skills/shared/utils/issue-refs.js +179 -0
- package/dist/lib/skills/shared/utils/issue-refs.js.map +1 -0
- package/dist/lib/skills/tasks/tasks.d.ts +5 -2
- package/dist/lib/skills/tasks/tasks.d.ts.map +1 -1
- package/dist/lib/skills/tasks/tasks.js +8 -3
- package/dist/lib/skills/tasks/tasks.js.map +1 -1
- package/dist/opencode/lisa.js +5886 -1310
- package/dist/package.json +1 -1
- package/dist/project/.lisa/skills/github/SKILL.md +415 -0
- package/dist/project/.lisa/skills/lisa/SKILL.md +22 -0
- package/dist/project/.lisa/skills/memory/SKILL.md +3 -2
- package/package.json +6 -5
- package/dist/hooks/session-start.js +0 -5763
- package/dist/hooks/session-stop.js +0 -5348
- package/dist/hooks/user-prompt-submit.js +0 -5406
- package/dist/project/.claude/config.js +0 -40
package/dist/lib/cli.js
CHANGED
|
@@ -1,623 +1,81 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
3
36
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
37
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
38
|
};
|
|
6
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.runScan = exports.TEMPLATE_ROOT = exports.DEFAULT_GROUP = exports.DEFAULT_ENDPOINT = exports.createDefaultServices = void 0;
|
|
8
|
-
exports.initCommand = initCommand;
|
|
9
|
-
exports.doctorCommand = doctorCommand;
|
|
10
|
-
exports.upCommand = upCommand;
|
|
11
|
-
exports.downCommand = downCommand;
|
|
12
|
-
exports.cleanupPreviousInstall = cleanupPreviousInstall;
|
|
40
|
+
exports.runScan = exports.TEMPLATE_ROOT = exports.DEFAULT_GROUP = exports.DEFAULT_ENDPOINT = exports.cleanupPreviousInstall = exports.createDefaultServices = exports.downCommand = exports.upCommand = exports.doctorCommand = exports.initCommand = void 0;
|
|
13
41
|
const commander_1 = require("commander");
|
|
14
42
|
const child_process_1 = require("child_process");
|
|
15
43
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
16
44
|
const path_1 = __importDefault(require("path"));
|
|
17
45
|
const chalk_1 = __importDefault(require("chalk"));
|
|
18
|
-
const prompts_1 = require("@inquirer/prompts");
|
|
19
46
|
const services_1 = require("./services");
|
|
20
47
|
Object.defineProperty(exports, "createDefaultServices", { enumerable: true, get: function () { return services_1.createDefaultServices; } });
|
|
21
48
|
const scanner_1 = require("./scanner");
|
|
22
49
|
Object.defineProperty(exports, "runScan", { enumerable: true, get: function () { return scanner_1.runScan; } });
|
|
23
50
|
const infrastructure_1 = require("./infrastructure");
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
exports
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Get project name from package.json or directory name.
|
|
40
|
-
* Used as the default group ID for memory storage.
|
|
41
|
-
*/
|
|
42
|
-
function getProjectName() {
|
|
43
|
-
try {
|
|
44
|
-
const pkgPath = path_1.default.join(process.cwd(), 'package.json');
|
|
45
|
-
if (fs_extra_1.default.existsSync(pkgPath)) {
|
|
46
|
-
const pkg = fs_extra_1.default.readJsonSync(pkgPath);
|
|
47
|
-
if (pkg.name) {
|
|
48
|
-
// Remove scope prefix if present (e.g., @tonycasey/lisa -> lisa)
|
|
49
|
-
return pkg.name.replace(/^@[^/]+\//, '');
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
// Ignore errors reading package.json
|
|
55
|
-
}
|
|
56
|
-
// Fall back to directory name
|
|
57
|
-
return path_1.default.basename(process.cwd());
|
|
58
|
-
}
|
|
59
|
-
const DEFAULT_GROUP = getProjectName();
|
|
60
|
-
exports.DEFAULT_GROUP = DEFAULT_GROUP;
|
|
51
|
+
const di_1 = require("./infrastructure/di");
|
|
52
|
+
const requests_1 = require("./application/mediator/requests");
|
|
53
|
+
const cli_1 = require("./infrastructure/cli");
|
|
54
|
+
const domain_1 = require("./domain");
|
|
55
|
+
const services_2 = require("./infrastructure/services");
|
|
56
|
+
const commands_1 = require("./commands");
|
|
57
|
+
Object.defineProperty(exports, "doctorCommand", { enumerable: true, get: function () { return commands_1.doctorCommand; } });
|
|
58
|
+
Object.defineProperty(exports, "initCommand", { enumerable: true, get: function () { return commands_1.initCommand; } });
|
|
59
|
+
Object.defineProperty(exports, "cleanupPreviousInstall", { enumerable: true, get: function () { return commands_1.cleanupPreviousInstall; } });
|
|
60
|
+
Object.defineProperty(exports, "upCommand", { enumerable: true, get: function () { return commands_1.upCommand; } });
|
|
61
|
+
Object.defineProperty(exports, "downCommand", { enumerable: true, get: function () { return commands_1.downCommand; } });
|
|
62
|
+
Object.defineProperty(exports, "TEMPLATE_ROOT", { enumerable: true, get: function () { return commands_1.TEMPLATE_ROOT; } });
|
|
63
|
+
Object.defineProperty(exports, "DEFAULT_ENDPOINT", { enumerable: true, get: function () { return commands_1.DEFAULT_ENDPOINT; } });
|
|
64
|
+
Object.defineProperty(exports, "DEFAULT_GROUP", { enumerable: true, get: function () { return commands_1.DEFAULT_GROUP; } });
|
|
61
65
|
// Create CLI logger (console disabled by default to avoid interfering with CLI output)
|
|
62
66
|
const cliLogger = (0, infrastructure_1.createLogger)({
|
|
63
67
|
enableConsole: process.env.LOG_CONSOLE === 'true',
|
|
64
68
|
enableFile: process.env.LOG_FILE !== 'false',
|
|
65
69
|
});
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
*/
|
|
71
|
-
async function createSymlink(target, link, cwd) {
|
|
72
|
-
const isWindows = process.platform === 'win32';
|
|
73
|
-
const projectRoot = cwd || process.cwd();
|
|
74
|
-
// Skip if link already exists (use lstat to detect symlinks even if target doesn't exist)
|
|
75
|
-
try {
|
|
76
|
-
await fs_extra_1.default.lstat(link);
|
|
77
|
-
return; // Link exists (symlink, junction, or regular file/dir)
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
// Link doesn't exist, proceed with creation
|
|
81
|
-
}
|
|
82
|
-
// Calculate relative path from link to target (for Unix symlinks)
|
|
83
|
-
const linkDir = path_1.default.dirname(link);
|
|
84
|
-
const relativeTarget = path_1.default.relative(linkDir, target);
|
|
85
|
-
try {
|
|
86
|
-
if (isWindows) {
|
|
87
|
-
// Windows junctions require absolute paths
|
|
88
|
-
const absoluteTarget = path_1.default.resolve(target);
|
|
89
|
-
// Try junction first (doesn't require admin rights)
|
|
90
|
-
await fs_extra_1.default.symlink(absoluteTarget, link, 'junction');
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
// Unix: standard symlink with relative path
|
|
94
|
-
await fs_extra_1.default.symlink(relativeTarget, link, 'dir');
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
catch (err) {
|
|
98
|
-
const error = err;
|
|
99
|
-
if (isWindows && (error.code === 'EPERM' || error.code === 'ENOENT' || error.code === 'EINVAL')) {
|
|
100
|
-
// Junction failed, fall back to copy
|
|
101
|
-
console.warn(chalk_1.default.yellow(` Symlink failed, copying directory instead: ${path_1.default.basename(link)}`));
|
|
102
|
-
await fs_extra_1.default.copy(target, link);
|
|
103
|
-
// Record that we used copy (for future sync)
|
|
104
|
-
await recordCopyFallback(projectRoot, link, target);
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
throw err;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Track directories that were copied instead of linked.
|
|
113
|
-
* Used by `lisa sync` to keep copies up to date.
|
|
114
|
-
*/
|
|
115
|
-
async function recordCopyFallback(projectRoot, link, target) {
|
|
116
|
-
const fallbackFile = path_1.default.join(projectRoot, '.lisa', '.copy-fallbacks.json');
|
|
117
|
-
let existing = { copies: [] };
|
|
118
|
-
try {
|
|
119
|
-
existing = await fs_extra_1.default.readJson(fallbackFile);
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
// File doesn't exist yet, use default
|
|
123
|
-
}
|
|
124
|
-
// Store relative paths
|
|
125
|
-
const relLink = path_1.default.relative(projectRoot, link);
|
|
126
|
-
const relTarget = path_1.default.relative(projectRoot, target);
|
|
127
|
-
// Check if already recorded
|
|
128
|
-
if (!existing.copies.some(c => c.link === relLink)) {
|
|
129
|
-
existing.copies.push({ link: relLink, target: relTarget, createdAt: new Date().toISOString() });
|
|
130
|
-
await fs_extra_1.default.ensureDir(path_1.default.dirname(fallbackFile));
|
|
131
|
-
await fs_extra_1.default.writeJson(fallbackFile, existing, { spaces: 2 });
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Clean up previous Lisa installation before upgrade.
|
|
136
|
-
* - Removes scripts/** JS files from skill directories (old format)
|
|
137
|
-
* - Backs up existing SKILL.md files to SKILL.md.backup
|
|
138
|
-
* - Removes common/ and shared/ directories (now bundled)
|
|
139
|
-
*
|
|
140
|
-
* @param skillsDir - Path to skills directory
|
|
141
|
-
* @param verbose - If true, logs detailed information about each operation
|
|
142
|
-
*/
|
|
143
|
-
async function cleanupPreviousInstall(skillsDir, verbose = false) {
|
|
144
|
-
const backedUp = [];
|
|
145
|
-
const removed = [];
|
|
146
|
-
if (!await fs_extra_1.default.pathExists(skillsDir)) {
|
|
147
|
-
if (verbose) {
|
|
148
|
-
console.log(chalk_1.default.gray(` [cleanup] Skills directory does not exist: ${skillsDir}`));
|
|
149
|
-
}
|
|
150
|
-
return { backedUp, removed };
|
|
151
|
-
}
|
|
152
|
-
if (verbose) {
|
|
153
|
-
console.log(chalk_1.default.cyan(` [cleanup] Scanning skills directory: ${skillsDir}`));
|
|
154
|
-
}
|
|
155
|
-
const skillDirs = await fs_extra_1.default.readdir(skillsDir);
|
|
156
|
-
for (const skillName of skillDirs) {
|
|
157
|
-
const skillPath = path_1.default.join(skillsDir, skillName);
|
|
158
|
-
const stat = await fs_extra_1.default.stat(skillPath);
|
|
159
|
-
if (!stat.isDirectory())
|
|
160
|
-
continue;
|
|
161
|
-
// Remove common/ and shared/ directories (now bundled into CLI)
|
|
162
|
-
if (skillName === 'common' || skillName === 'shared') {
|
|
163
|
-
if (verbose) {
|
|
164
|
-
console.log(chalk_1.default.yellow(` [cleanup] Removing bundled directory: ${skillName}/`));
|
|
165
|
-
}
|
|
166
|
-
await fs_extra_1.default.remove(skillPath);
|
|
167
|
-
removed.push(skillPath);
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
// Backup existing SKILL.md files
|
|
171
|
-
const skillMdPath = path_1.default.join(skillPath, 'SKILL.md');
|
|
172
|
-
if (await fs_extra_1.default.pathExists(skillMdPath)) {
|
|
173
|
-
const backupPath = path_1.default.join(skillPath, 'SKILL.md.backup');
|
|
174
|
-
if (verbose) {
|
|
175
|
-
console.log(chalk_1.default.gray(` [cleanup] Backing up: ${skillName}/SKILL.md -> SKILL.md.backup`));
|
|
176
|
-
}
|
|
177
|
-
await fs_extra_1.default.copy(skillMdPath, backupPath, { overwrite: true });
|
|
178
|
-
backedUp.push(skillMdPath);
|
|
179
|
-
}
|
|
180
|
-
// Remove scripts/ directory with all JS files
|
|
181
|
-
const scriptsDir = path_1.default.join(skillPath, 'scripts');
|
|
182
|
-
if (await fs_extra_1.default.pathExists(scriptsDir)) {
|
|
183
|
-
// Find and remove all .js files in scripts/
|
|
184
|
-
const scriptFiles = await fs_extra_1.default.readdir(scriptsDir);
|
|
185
|
-
for (const file of scriptFiles) {
|
|
186
|
-
if (file.endsWith('.js')) {
|
|
187
|
-
const filePath = path_1.default.join(scriptsDir, file);
|
|
188
|
-
if (verbose) {
|
|
189
|
-
console.log(chalk_1.default.yellow(` [cleanup] Removing old script: ${skillName}/scripts/${file}`));
|
|
190
|
-
}
|
|
191
|
-
await fs_extra_1.default.remove(filePath);
|
|
192
|
-
removed.push(filePath);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
// Remove scripts/ directory if empty
|
|
196
|
-
const remainingFiles = await fs_extra_1.default.readdir(scriptsDir);
|
|
197
|
-
if (remainingFiles.length === 0) {
|
|
198
|
-
if (verbose) {
|
|
199
|
-
console.log(chalk_1.default.gray(` [cleanup] Removing empty directory: ${skillName}/scripts/`));
|
|
200
|
-
}
|
|
201
|
-
await fs_extra_1.default.remove(scriptsDir);
|
|
202
|
-
removed.push(scriptsDir);
|
|
203
|
-
}
|
|
204
|
-
else if (verbose) {
|
|
205
|
-
console.log(chalk_1.default.gray(` [cleanup] Keeping ${skillName}/scripts/ (contains ${remainingFiles.length} non-JS files)`));
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return { backedUp, removed };
|
|
210
|
-
}
|
|
211
|
-
// Interactive prompt functions
|
|
212
|
-
async function promptDeploymentMode() {
|
|
213
|
-
return await (0, prompts_1.select)({
|
|
214
|
-
message: 'How would you like to configure storage?',
|
|
215
|
-
choices: [
|
|
216
|
-
{
|
|
217
|
-
name: 'Set up later (scaffold project, configure storage later)',
|
|
218
|
-
value: 'skip',
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
name: 'Local Docker (runs Neo4j + MCP server locally)',
|
|
222
|
-
value: 'local',
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
name: 'Zep Cloud (managed storage service)',
|
|
226
|
-
value: 'zep-cloud',
|
|
227
|
-
},
|
|
228
|
-
],
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
async function promptZepCloudConfig() {
|
|
232
|
-
const zepApiKey = await (0, prompts_1.password)({
|
|
233
|
-
message: 'Zep API Key:',
|
|
234
|
-
validate: (val) => val.length > 0 || 'API key is required',
|
|
235
|
-
});
|
|
236
|
-
const zepProjectId = await (0, prompts_1.input)({
|
|
237
|
-
message: 'Zep Project ID:',
|
|
238
|
-
validate: (val) => val.length > 0 || 'Project ID is required',
|
|
239
|
-
});
|
|
240
|
-
return {
|
|
241
|
-
zepApiKey,
|
|
242
|
-
zepProjectId,
|
|
243
|
-
endpoint: ZEP_CLOUD_ENDPOINT,
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
async function promptGroupId() {
|
|
247
|
-
const projectName = path_1.default.basename(process.cwd());
|
|
248
|
-
return await (0, prompts_1.input)({
|
|
249
|
-
message: 'Group ID:',
|
|
250
|
-
default: projectName,
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
async function promptCliSupport() {
|
|
254
|
-
const choices = await (0, prompts_1.checkbox)({
|
|
255
|
-
message: 'Which CLI tools do you want to support?',
|
|
256
|
-
choices: [
|
|
257
|
-
{
|
|
258
|
-
name: 'Claude Code (Anthropic)',
|
|
259
|
-
value: 'claude-code',
|
|
260
|
-
checked: true,
|
|
261
|
-
},
|
|
262
|
-
{
|
|
263
|
-
name: 'OpenCode (open source)',
|
|
264
|
-
value: 'opencode',
|
|
265
|
-
checked: true,
|
|
266
|
-
},
|
|
267
|
-
],
|
|
268
|
-
});
|
|
269
|
-
// Default to both if none selected
|
|
270
|
-
if (choices.length === 0) {
|
|
271
|
-
return ['claude-code', 'opencode'];
|
|
272
|
-
}
|
|
273
|
-
return choices;
|
|
274
|
-
}
|
|
275
|
-
async function initCommand(opts, services) {
|
|
276
|
-
const force = Boolean(opts.force);
|
|
277
|
-
const verbose = opts.verbose !== false; // Default to true
|
|
278
|
-
const cwd = opts.cwd;
|
|
279
|
-
let config;
|
|
280
|
-
let cliSupport;
|
|
281
|
-
// Determine if we need interactive prompts
|
|
282
|
-
const hasExplicitMode = opts.mode !== undefined;
|
|
283
|
-
const skipPrompts = opts.yes || hasExplicitMode;
|
|
284
|
-
if (skipPrompts) {
|
|
285
|
-
// Non-interactive mode - use provided options or defaults
|
|
286
|
-
const mode = opts.mode || 'local';
|
|
287
|
-
config = {
|
|
288
|
-
mode,
|
|
289
|
-
endpoint: opts.endpoint || (mode === 'zep-cloud' ? ZEP_CLOUD_ENDPOINT : DEFAULT_ENDPOINT),
|
|
290
|
-
groupId: opts.group || process.env.GRAPHITI_GROUP_ID || DEFAULT_GROUP,
|
|
291
|
-
zepApiKey: opts.zepApiKey,
|
|
292
|
-
zepProjectId: opts.zepProjectId,
|
|
293
|
-
};
|
|
294
|
-
// Default to both CLIs if not specified
|
|
295
|
-
cliSupport = opts.cliSupport || ['claude-code', 'opencode'];
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
// Interactive mode - prompt user
|
|
299
|
-
const mode = await promptDeploymentMode();
|
|
300
|
-
let modeConfig;
|
|
301
|
-
if (mode === 'zep-cloud') {
|
|
302
|
-
modeConfig = await promptZepCloudConfig();
|
|
303
|
-
}
|
|
304
|
-
else {
|
|
305
|
-
modeConfig = { endpoint: DEFAULT_ENDPOINT };
|
|
306
|
-
}
|
|
307
|
-
const groupId = await promptGroupId();
|
|
308
|
-
// Prompt for CLI support
|
|
309
|
-
cliSupport = await promptCliSupport();
|
|
310
|
-
config = {
|
|
311
|
-
mode,
|
|
312
|
-
endpoint: modeConfig.endpoint || DEFAULT_ENDPOINT,
|
|
313
|
-
groupId,
|
|
314
|
-
...modeConfig,
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
const includeDocker = opts.includeDocker !== false && config.mode !== 'zep-cloud' && config.mode !== 'skip';
|
|
318
|
-
const supportClaudeCode = cliSupport.includes('claude-code');
|
|
319
|
-
const supportOpenCode = cliSupport.includes('opencode');
|
|
320
|
-
const replacements = {
|
|
321
|
-
GRAPHITI_ENDPOINT: config.endpoint,
|
|
322
|
-
GRAPHITI_GROUP: config.groupId,
|
|
323
|
-
GRAPHITI_GROUP_ID: config.groupId,
|
|
324
|
-
PROJECT_NAME: config.groupId,
|
|
325
|
-
};
|
|
326
|
-
const lisaDir = path_1.default.join(cwd, '.lisa');
|
|
327
|
-
const skillsDir = path_1.default.join(lisaDir, 'skills');
|
|
328
|
-
const rulesDir = path_1.default.join(lisaDir, 'rules');
|
|
329
|
-
const claudeDir = path_1.default.join(cwd, '.claude');
|
|
330
|
-
const composeDest = path_1.default.join(cwd, 'docker-compose.graphiti.yml');
|
|
331
|
-
const copies = [];
|
|
332
|
-
// Create .env from template on first install only (preserve user customizations)
|
|
333
|
-
const envDest = path_1.default.join(lisaDir, '.env');
|
|
334
|
-
if (!await fs_extra_1.default.pathExists(envDest)) {
|
|
335
|
-
await fs_extra_1.default.ensureDir(lisaDir);
|
|
336
|
-
copies.push(services.templateCopier.copy('.lisa/.env.template', envDest, replacements, false // Never force overwrite - preserves user customizations
|
|
337
|
-
));
|
|
338
|
-
}
|
|
339
|
-
// Clean up previous installation if upgrading
|
|
340
|
-
// This removes old scripts/** JS files and backs up existing SKILL.md files
|
|
341
|
-
if (await fs_extra_1.default.pathExists(skillsDir)) {
|
|
342
|
-
if (verbose) {
|
|
343
|
-
console.log(chalk_1.default.cyan('\nUpgrade cleanup:'));
|
|
344
|
-
}
|
|
345
|
-
const cleanup = await cleanupPreviousInstall(skillsDir, verbose);
|
|
346
|
-
if (cleanup.backedUp.length > 0) {
|
|
347
|
-
console.log(chalk_1.default.cyan(` Backed up ${cleanup.backedUp.length} existing SKILL.md file(s)`));
|
|
348
|
-
}
|
|
349
|
-
if (cleanup.removed.length > 0) {
|
|
350
|
-
console.log(chalk_1.default.cyan(` Removed ${cleanup.removed.length} old script file(s)/director(ies)`));
|
|
351
|
-
}
|
|
352
|
-
if (verbose && cleanup.backedUp.length === 0 && cleanup.removed.length === 0) {
|
|
353
|
-
console.log(chalk_1.default.gray(' No cleanup needed (fresh install or already upgraded)'));
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
// Skill scaffolding (model-neutral) - copy only SKILL.md files and cache dirs
|
|
357
|
-
// Scripts are accessed via subcommands (lisa memory, lisa tasks, etc.)
|
|
358
|
-
// SKILL.md files are always overwritten (we back them up above), other files respect force flag
|
|
359
|
-
const skillsSrc = path_1.default.join(TEMPLATE_ROOT, '.lisa', 'skills');
|
|
360
|
-
await fs_extra_1.default.ensureDir(skillsDir);
|
|
361
|
-
copies.push(fs_extra_1.default.copy(skillsSrc, skillsDir, {
|
|
362
|
-
overwrite: true, // Always overwrite SKILL.md files (they're backed up above)
|
|
363
|
-
filter: (src) => {
|
|
364
|
-
const basename = path_1.default.basename(src);
|
|
365
|
-
const relativePath = path_1.default.relative(skillsSrc, src);
|
|
366
|
-
// Always include the root skills directory
|
|
367
|
-
if (relativePath === '')
|
|
368
|
-
return true;
|
|
369
|
-
// Include skill directories (memory, tasks, jira, git, lisa, prompt, init-review)
|
|
370
|
-
// but exclude shared/, common/, scripts/
|
|
371
|
-
if (relativePath.includes('shared') || relativePath.includes('common'))
|
|
372
|
-
return false;
|
|
373
|
-
if (relativePath.includes('scripts'))
|
|
374
|
-
return false;
|
|
375
|
-
// Include SKILL.md files and cache directories
|
|
376
|
-
if (basename === 'SKILL.md' || basename === 'SKILL.local.md')
|
|
377
|
-
return true;
|
|
378
|
-
if (basename === 'cache' || basename === '.gitkeep')
|
|
379
|
-
return true;
|
|
380
|
-
// Include directories that might contain the above
|
|
381
|
-
return fs_extra_1.default.statSync(src).isDirectory();
|
|
382
|
-
}
|
|
383
|
-
}));
|
|
384
|
-
// Rules scaffolding (shared)
|
|
385
|
-
copies.push(services.templateCopier.copy('.lisa/rules/shared/clean-architecture.md', path_1.default.join(rulesDir, 'shared', 'clean-architecture.md'), replacements, force));
|
|
386
|
-
copies.push(services.templateCopier.copy('.lisa/rules/shared/code-quality-rules.md', path_1.default.join(rulesDir, 'shared', 'code-quality-rules.md'), replacements, force));
|
|
387
|
-
copies.push(services.templateCopier.copy('.lisa/rules/shared/testing-principles.md', path_1.default.join(rulesDir, 'shared', 'testing-principles.md'), replacements, force));
|
|
388
|
-
// Rules scaffolding (typescript)
|
|
389
|
-
copies.push(services.templateCopier.copy('.lisa/rules/typescript/coding-standards.md', path_1.default.join(rulesDir, 'typescript', 'coding-standards.md'), replacements, force));
|
|
390
|
-
copies.push(services.templateCopier.copy('.lisa/rules/typescript/testing.md', path_1.default.join(rulesDir, 'typescript', 'testing.md'), replacements, force));
|
|
391
|
-
copies.push(services.templateCopier.copy('.lisa/rules/typescript/typescript-config-guide.md', path_1.default.join(rulesDir, 'typescript', 'typescript-config-guide.md'), replacements, force));
|
|
392
|
-
// Claude Code scaffolding (hooks and settings) - only if Claude Code is selected
|
|
393
|
-
if (supportClaudeCode) {
|
|
394
|
-
copies.push(services.templateCopier.copy('.claude/config.js', path_1.default.join(claudeDir, 'config.js'), replacements, force));
|
|
395
|
-
// Copy bundled hooks (these are pre-bundled with all dependencies)
|
|
396
|
-
const hooksDir = path_1.default.join(claudeDir, 'hooks');
|
|
397
|
-
await fs_extra_1.default.ensureDir(hooksDir);
|
|
398
|
-
const bundledHooks = ['session-start.js', 'session-stop.js', 'user-prompt-submit.js'];
|
|
399
|
-
for (const hook of bundledHooks) {
|
|
400
|
-
const src = path_1.default.join(BUNDLED_HOOKS_ROOT, hook);
|
|
401
|
-
const dest = path_1.default.join(hooksDir, hook);
|
|
402
|
-
if (await fs_extra_1.default.pathExists(src)) {
|
|
403
|
-
copies.push(fs_extra_1.default.copy(src, dest, { overwrite: force }));
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
// Create symlinks for .claude/skills and .claude/rules
|
|
407
|
-
// If these are real directories (not symlinks), clean them up first
|
|
408
|
-
const claudeSkillsLink = path_1.default.join(claudeDir, 'skills');
|
|
409
|
-
const claudeRulesLink = path_1.default.join(claudeDir, 'rules');
|
|
410
|
-
// Check if .claude/skills exists as a real directory (not symlink)
|
|
411
|
-
try {
|
|
412
|
-
const skillsStat = await fs_extra_1.default.lstat(claudeSkillsLink);
|
|
413
|
-
if (skillsStat.isDirectory() && !skillsStat.isSymbolicLink()) {
|
|
414
|
-
// Clean up old scripts in .claude/skills before removing
|
|
415
|
-
if (verbose) {
|
|
416
|
-
console.log(chalk_1.default.cyan('\nConverting .claude/skills from directory to symlink:'));
|
|
417
|
-
}
|
|
418
|
-
await cleanupPreviousInstall(claudeSkillsLink, verbose);
|
|
419
|
-
await fs_extra_1.default.remove(claudeSkillsLink);
|
|
420
|
-
console.log(chalk_1.default.cyan(' Converted .claude/skills to symlink -> .lisa/skills'));
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
catch {
|
|
424
|
-
// Doesn't exist, will be created as symlink
|
|
425
|
-
}
|
|
426
|
-
try {
|
|
427
|
-
const rulesStat = await fs_extra_1.default.lstat(claudeRulesLink);
|
|
428
|
-
if (rulesStat.isDirectory() && !rulesStat.isSymbolicLink()) {
|
|
429
|
-
await fs_extra_1.default.remove(claudeRulesLink);
|
|
430
|
-
console.log(chalk_1.default.cyan(' Converted .claude/rules to symlink -> .lisa/rules'));
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
catch {
|
|
434
|
-
// Doesn't exist, will be created as symlink
|
|
435
|
-
}
|
|
436
|
-
await createSymlink(skillsDir, claudeSkillsLink, cwd);
|
|
437
|
-
await createSymlink(rulesDir, claudeRulesLink, cwd);
|
|
438
|
-
}
|
|
439
|
-
// OpenCode scaffolding - only if OpenCode is selected
|
|
440
|
-
if (supportOpenCode) {
|
|
441
|
-
const opencodeDir = path_1.default.join(cwd, '.opencode');
|
|
442
|
-
const pluginDir = path_1.default.join(opencodeDir, 'plugin');
|
|
443
|
-
await fs_extra_1.default.ensureDir(pluginDir);
|
|
444
|
-
// Copy bundled OpenCode plugin
|
|
445
|
-
const pluginSrc = path_1.default.join(BUNDLED_OPENCODE_ROOT, 'lisa.js');
|
|
446
|
-
const pluginDest = path_1.default.join(pluginDir, 'lisa.js');
|
|
447
|
-
if (await fs_extra_1.default.pathExists(pluginSrc)) {
|
|
448
|
-
copies.push(fs_extra_1.default.copy(pluginSrc, pluginDest, { overwrite: force }));
|
|
449
|
-
}
|
|
450
|
-
// Create symlink for .opencode/skills
|
|
451
|
-
await createSymlink(skillsDir, path_1.default.join(opencodeDir, 'skills'), cwd);
|
|
452
|
-
}
|
|
453
|
-
if (includeDocker) {
|
|
454
|
-
// Choose compose file based on mode
|
|
455
|
-
const composeTemplate = '.lisa/docker/docker-compose.graphiti.yml';
|
|
456
|
-
copies.push(services.templateCopier.copy(composeTemplate, composeDest, replacements, force));
|
|
457
|
-
}
|
|
458
|
-
await Promise.all(copies);
|
|
459
|
-
// Build scaffolded directories list
|
|
460
|
-
const scaffoldedDirs = ['.lisa'];
|
|
461
|
-
if (supportClaudeCode)
|
|
462
|
-
scaffoldedDirs.push('.claude');
|
|
463
|
-
if (supportOpenCode)
|
|
464
|
-
scaffoldedDirs.push('.opencode');
|
|
465
|
-
if (includeDocker)
|
|
466
|
-
scaffoldedDirs.push('Docker assets');
|
|
467
|
-
console.log(chalk_1.default.green(`Scaffolded ${scaffoldedDirs.join(', ')} into ${cwd}`));
|
|
468
|
-
console.log(`Mode: ${config.mode}`);
|
|
469
|
-
console.log(`Endpoint: ${config.endpoint}`);
|
|
470
|
-
console.log(`Group ID: ${config.groupId}`);
|
|
471
|
-
console.log(`CLI Support: ${cliSupport.join(', ')}`);
|
|
472
|
-
// Show skip mode instructions
|
|
473
|
-
if (config.mode === 'skip') {
|
|
474
|
-
console.log('');
|
|
475
|
-
console.log(chalk_1.default.cyan('To configure storage later:'));
|
|
476
|
-
console.log(chalk_1.default.cyan(' 1. Read .lisa/docs/STORAGE_SETUP.md'));
|
|
477
|
-
console.log(chalk_1.default.cyan(' 2. Edit .lisa/.env with your configuration'));
|
|
478
|
-
console.log(chalk_1.default.cyan(' 3. Start a new terminal session'));
|
|
479
|
-
console.log(chalk_1.default.cyan(' 4. Run `lisa doctor` to verify connection'));
|
|
480
|
-
}
|
|
481
|
-
// Isolated mode: create .claude/lib structure for non-npm projects
|
|
482
|
-
if (opts.isolated) {
|
|
483
|
-
const libDir = path_1.default.join(claudeDir, 'lib');
|
|
484
|
-
await fs_extra_1.default.ensureDir(libDir);
|
|
485
|
-
// Create minimal package.json in .claude/lib
|
|
486
|
-
const libPackageJson = {
|
|
487
|
-
name: 'claude-lib',
|
|
488
|
-
version: '1.0.0',
|
|
489
|
-
private: true,
|
|
490
|
-
description: 'Lisa support files for Claude Code',
|
|
491
|
-
};
|
|
492
|
-
const libPackagePath = path_1.default.join(libDir, 'package.json');
|
|
493
|
-
if (!await fs_extra_1.default.pathExists(libPackagePath) || force) {
|
|
494
|
-
await fs_extra_1.default.writeJson(libPackagePath, libPackageJson, { spaces: 2 });
|
|
495
|
-
console.log(chalk_1.default.green('Created .claude/lib/package.json'));
|
|
496
|
-
}
|
|
497
|
-
// Add .claude/lib to .gitignore if not already there
|
|
498
|
-
const gitignorePath = path_1.default.join(cwd, '.gitignore');
|
|
499
|
-
if (await fs_extra_1.default.pathExists(gitignorePath)) {
|
|
500
|
-
let gitignore = await fs_extra_1.default.readFile(gitignorePath, 'utf8');
|
|
501
|
-
if (!gitignore.includes('.claude/lib/node_modules')) {
|
|
502
|
-
gitignore += '\n# Lisa support files\n.claude/lib/node_modules/\n';
|
|
503
|
-
await fs_extra_1.default.writeFile(gitignorePath, gitignore);
|
|
504
|
-
console.log(chalk_1.default.green('Added .claude/lib/node_modules to .gitignore'));
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
console.log('');
|
|
508
|
-
console.log(chalk_1.default.cyan('Isolated mode: Lisa installed to .claude/lib/'));
|
|
509
|
-
console.log(chalk_1.default.cyan('Your project root stays clean (no package.json or node_modules).'));
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
async function loadConfig(cwd) {
|
|
513
|
-
// Read from .env file (legacy/runtime config)
|
|
514
|
-
const lisaEnv = path_1.default.join(cwd, '.lisa', '.env');
|
|
515
|
-
const map = {};
|
|
516
|
-
if (await fs_extra_1.default.pathExists(lisaEnv)) {
|
|
517
|
-
const raw = await fs_extra_1.default.readFile(lisaEnv, 'utf8');
|
|
518
|
-
raw.split(/\r?\n/).forEach((line) => {
|
|
519
|
-
if (!line || line.startsWith('#'))
|
|
520
|
-
return;
|
|
521
|
-
const idx = line.indexOf('=');
|
|
522
|
-
if (idx === -1)
|
|
523
|
-
return;
|
|
524
|
-
const key = line.slice(0, idx).trim();
|
|
525
|
-
map[key] = line.slice(idx + 1).trim();
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
// If no .env exists, return null
|
|
529
|
-
if (Object.keys(map).length === 0) {
|
|
530
|
-
return null;
|
|
531
|
-
}
|
|
532
|
-
return {
|
|
533
|
-
endpoint: map.GRAPHITI_ENDPOINT || DEFAULT_ENDPOINT,
|
|
534
|
-
group: map.GRAPHITI_GROUP_ID || DEFAULT_GROUP,
|
|
535
|
-
mode: map.STORAGE_MODE || 'local',
|
|
536
|
-
zepApiKey: map.ZEP_API_KEY,
|
|
537
|
-
};
|
|
538
|
-
}
|
|
539
|
-
async function doctorCommand(opts, services) {
|
|
540
|
-
const cwd = opts.cwd;
|
|
541
|
-
// Default compose file location is at project root (deployed by init command)
|
|
542
|
-
const composeFile = opts.compose || path_1.default.join(cwd, 'docker-compose.graphiti.yml');
|
|
543
|
-
const config = (await loadConfig(cwd)) ?? { endpoint: undefined, group: undefined, mode: 'local' };
|
|
544
|
-
const endpoint = opts.endpoint || config.endpoint || DEFAULT_ENDPOINT;
|
|
545
|
-
const mode = config.mode || 'local';
|
|
546
|
-
const results = [];
|
|
547
|
-
// Show current mode
|
|
548
|
-
results.push(chalk_1.default.cyan(`Mode: ${mode}`));
|
|
549
|
-
results.push(chalk_1.default.cyan(`Group: ${config.group || DEFAULT_GROUP}`));
|
|
550
|
-
results.push('');
|
|
551
|
-
// Mode-specific checks
|
|
552
|
-
if (mode === 'zep-cloud') {
|
|
553
|
-
// Zep Cloud mode - no local Docker needed
|
|
554
|
-
results.push(chalk_1.default.yellow('Zep Cloud mode - no local Docker required'));
|
|
555
|
-
results.push('');
|
|
556
|
-
// Get API key from config or environment for Zep Cloud authentication
|
|
557
|
-
const zepApiKey = config.zepApiKey || process.env.ZEP_API_KEY;
|
|
558
|
-
if (!zepApiKey) {
|
|
559
|
-
results.push(chalk_1.default.yellow('Warning: ZEP_API_KEY not configured (required for Zep Cloud)'));
|
|
560
|
-
}
|
|
561
|
-
try {
|
|
562
|
-
await services.mcp.ping(endpoint, { apiKey: zepApiKey });
|
|
563
|
-
results.push(chalk_1.default.green(`Zep MCP reachable at ${endpoint}`));
|
|
564
|
-
}
|
|
565
|
-
catch (err) {
|
|
566
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
567
|
-
results.push(chalk_1.default.red(`Zep MCP check failed at ${endpoint}: ${message}`));
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
else if (mode === 'skip') {
|
|
571
|
-
// Skip mode - memory/tasks not configured
|
|
572
|
-
results.push(chalk_1.default.yellow('Skip mode - memory/tasks not configured'));
|
|
573
|
-
results.push(chalk_1.default.yellow('Run "lisa init" again to configure storage backend'));
|
|
574
|
-
}
|
|
575
|
-
else {
|
|
576
|
-
// Local mode - Docker is needed
|
|
577
|
-
try {
|
|
578
|
-
const stdout = await services.docker.version();
|
|
579
|
-
results.push(chalk_1.default.green(`Docker OK: ${stdout}`));
|
|
580
|
-
}
|
|
581
|
-
catch (err) {
|
|
582
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
583
|
-
results.push(chalk_1.default.red(`Docker missing or not running: ${message}`));
|
|
584
|
-
}
|
|
585
|
-
try {
|
|
586
|
-
const stdout = await services.docker.composeVersion();
|
|
587
|
-
results.push(chalk_1.default.green(`Docker Compose OK: ${stdout}`));
|
|
588
|
-
}
|
|
589
|
-
catch (err) {
|
|
590
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
591
|
-
results.push(chalk_1.default.red(`Docker Compose missing: ${message}`));
|
|
592
|
-
}
|
|
593
|
-
if (await fs_extra_1.default.pathExists(composeFile)) {
|
|
594
|
-
results.push(chalk_1.default.green(`Compose file found: ${composeFile}`));
|
|
595
|
-
}
|
|
596
|
-
else {
|
|
597
|
-
results.push(chalk_1.default.red(`Compose file not found: ${composeFile}`));
|
|
598
|
-
}
|
|
599
|
-
try {
|
|
600
|
-
await services.mcp.ping(endpoint);
|
|
601
|
-
results.push(chalk_1.default.green(`MCP reachable at ${endpoint}`));
|
|
602
|
-
}
|
|
603
|
-
catch (err) {
|
|
604
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
605
|
-
results.push(chalk_1.default.red(`MCP check failed at ${endpoint}: ${message}`));
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
console.log(results.join('\n'));
|
|
609
|
-
}
|
|
610
|
-
async function upCommand(opts, services) {
|
|
611
|
-
await services.docker.compose(opts.composeFile, ['up', '-d']);
|
|
612
|
-
}
|
|
613
|
-
async function downCommand(opts, services) {
|
|
614
|
-
await services.docker.compose(opts.composeFile, ['down']);
|
|
615
|
-
}
|
|
70
|
+
// Command implementations moved to src/lib/commands/
|
|
71
|
+
// - initCommand, cleanupPreviousInstall -> init.ts
|
|
72
|
+
// - doctorCommand -> doctor.ts
|
|
73
|
+
// - upCommand, downCommand -> docker.ts
|
|
616
74
|
const program = new commander_1.Command();
|
|
617
75
|
program
|
|
618
76
|
.name('lisa')
|
|
619
77
|
.description('Lisa remembers everything. Memory for Claude Code and AI assistants.')
|
|
620
|
-
.version(VERSION);
|
|
78
|
+
.version(commands_1.VERSION);
|
|
621
79
|
program
|
|
622
80
|
.command('init')
|
|
623
81
|
.description('Scaffold .lisa, .claude/.opencode, and Docker assets')
|
|
@@ -643,7 +101,7 @@ program
|
|
|
643
101
|
opencodeOnly: cmd.opencodeOnly,
|
|
644
102
|
verbose,
|
|
645
103
|
});
|
|
646
|
-
const services = (0, services_1.createDefaultServices)(TEMPLATE_ROOT);
|
|
104
|
+
const services = (0, services_1.createDefaultServices)(commands_1.TEMPLATE_ROOT);
|
|
647
105
|
// Determine CLI support from flags
|
|
648
106
|
let cliSupport;
|
|
649
107
|
if (cmd.claudeOnly && !cmd.opencodeOnly) {
|
|
@@ -656,7 +114,7 @@ program
|
|
|
656
114
|
cliSupport = ['claude-code', 'opencode'];
|
|
657
115
|
}
|
|
658
116
|
// If neither flag is set, cliSupport remains undefined and prompts will be shown
|
|
659
|
-
await initCommand({
|
|
117
|
+
await (0, commands_1.initCommand)({
|
|
660
118
|
endpoint: cmd.endpoint,
|
|
661
119
|
group: cmd.group,
|
|
662
120
|
force: cmd.force,
|
|
@@ -689,7 +147,7 @@ program
|
|
|
689
147
|
.option('-v, --verbose', 'Show detailed logging (default: true)', true)
|
|
690
148
|
.option('-q, --quiet', 'Suppress detailed logging')
|
|
691
149
|
.action(async (cmd) => {
|
|
692
|
-
const services = (0, services_1.createDefaultServices)(TEMPLATE_ROOT);
|
|
150
|
+
const services = (0, services_1.createDefaultServices)(commands_1.TEMPLATE_ROOT);
|
|
693
151
|
const verbose = cmd.verbose && !cmd.quiet;
|
|
694
152
|
// Determine CLI support from flags
|
|
695
153
|
let cliSupport;
|
|
@@ -702,7 +160,7 @@ program
|
|
|
702
160
|
else if (cmd.claudeOnly && cmd.opencodeOnly) {
|
|
703
161
|
cliSupport = ['claude-code', 'opencode'];
|
|
704
162
|
}
|
|
705
|
-
await initCommand({
|
|
163
|
+
await (0, commands_1.initCommand)({
|
|
706
164
|
endpoint: cmd.endpoint,
|
|
707
165
|
group: cmd.group,
|
|
708
166
|
force: cmd.force,
|
|
@@ -723,8 +181,8 @@ program
|
|
|
723
181
|
.option('-c, --compose <file>', 'Compose file', 'docker-compose.graphiti.yml')
|
|
724
182
|
.action(async (cmd) => {
|
|
725
183
|
const composeFile = path_1.default.resolve(process.cwd(), cmd.compose);
|
|
726
|
-
const services = (0, services_1.createDefaultServices)(TEMPLATE_ROOT);
|
|
727
|
-
await upCommand({ composeFile }, services);
|
|
184
|
+
const services = (0, services_1.createDefaultServices)(commands_1.TEMPLATE_ROOT);
|
|
185
|
+
await (0, commands_1.upCommand)({ composeFile }, services);
|
|
728
186
|
});
|
|
729
187
|
program
|
|
730
188
|
.command('down')
|
|
@@ -732,17 +190,25 @@ program
|
|
|
732
190
|
.option('-c, --compose <file>', 'Compose file', 'docker-compose.graphiti.yml')
|
|
733
191
|
.action(async (cmd) => {
|
|
734
192
|
const composeFile = path_1.default.resolve(process.cwd(), cmd.compose);
|
|
735
|
-
const services = (0, services_1.createDefaultServices)(TEMPLATE_ROOT);
|
|
736
|
-
await downCommand({ composeFile }, services);
|
|
193
|
+
const services = (0, services_1.createDefaultServices)(commands_1.TEMPLATE_ROOT);
|
|
194
|
+
await (0, commands_1.downCommand)({ composeFile }, services);
|
|
737
195
|
});
|
|
738
196
|
program
|
|
739
197
|
.command('doctor')
|
|
740
|
-
.description('Validate
|
|
198
|
+
.description('Validate Lisa configuration and backend connectivity')
|
|
741
199
|
.option('-c, --compose <file>', 'Compose file', 'docker-compose.graphiti.yml')
|
|
742
200
|
.option('-e, --endpoint <url>', 'MCP endpoint override')
|
|
201
|
+
.option('-v, --verbose', 'Show detailed diagnostics')
|
|
202
|
+
.option('--json', 'Output results as JSON')
|
|
743
203
|
.action(async (cmd) => {
|
|
744
|
-
const services = (0, services_1.createDefaultServices)(TEMPLATE_ROOT);
|
|
745
|
-
await
|
|
204
|
+
const services = (0, services_1.createDefaultServices)(commands_1.TEMPLATE_ROOT);
|
|
205
|
+
await (0, commands_1.doctorCommand)({
|
|
206
|
+
cwd: process.cwd(),
|
|
207
|
+
compose: cmd.compose,
|
|
208
|
+
endpoint: cmd.endpoint,
|
|
209
|
+
verbose: cmd.verbose,
|
|
210
|
+
json: cmd.json,
|
|
211
|
+
}, services);
|
|
746
212
|
});
|
|
747
213
|
program
|
|
748
214
|
.command('scan [path]')
|
|
@@ -993,6 +459,17 @@ program
|
|
|
993
459
|
const scriptPath = path_1.default.join(__dirname, 'skills', 'jira', 'jira.js');
|
|
994
460
|
await spawnAndWait(scriptPath, args);
|
|
995
461
|
});
|
|
462
|
+
// Subcommand: lisa github
|
|
463
|
+
program
|
|
464
|
+
.command('github')
|
|
465
|
+
.description('GitHub Issues and Projects operations')
|
|
466
|
+
.allowUnknownOption()
|
|
467
|
+
.action(async (_opts, cmd) => {
|
|
468
|
+
// Pass all arguments after the command to the script
|
|
469
|
+
const args = cmd.args || [];
|
|
470
|
+
const scriptPath = path_1.default.join(__dirname, 'skills', 'github', 'github.js');
|
|
471
|
+
await spawnAndWait(scriptPath, args);
|
|
472
|
+
});
|
|
996
473
|
// Subcommand: lisa prompt
|
|
997
474
|
program
|
|
998
475
|
.command('prompt')
|
|
@@ -1033,6 +510,274 @@ program
|
|
|
1033
510
|
const scriptPath = path_1.default.join(__dirname, 'skills', 'lisa', 'compile-skills.js');
|
|
1034
511
|
await spawnAndWait(scriptPath, args);
|
|
1035
512
|
});
|
|
513
|
+
// Subcommand: lisa issue
|
|
514
|
+
// Wraps gh CLI with auto-labeling capabilities
|
|
515
|
+
const issueCmd = program
|
|
516
|
+
.command('issue')
|
|
517
|
+
.description('GitHub issue management with auto-labeling');
|
|
518
|
+
issueCmd
|
|
519
|
+
.command('create')
|
|
520
|
+
.description('Create a GitHub issue with automatic label inference')
|
|
521
|
+
.requiredOption('-t, --title <title>', 'Issue title')
|
|
522
|
+
.option('-b, --body <body>', 'Issue body')
|
|
523
|
+
.option('-l, --label <labels...>', 'Explicit labels (skips auto-labeling for type)')
|
|
524
|
+
.option('--no-auto-label', 'Disable automatic label inference')
|
|
525
|
+
.option('-y, --yes', 'Skip confirmation, apply inferred labels automatically')
|
|
526
|
+
.option('--dry-run', 'Show what would be created without creating')
|
|
527
|
+
.action(async (opts) => {
|
|
528
|
+
const title = opts.title;
|
|
529
|
+
const body = opts.body || '';
|
|
530
|
+
const explicitLabels = opts.label || [];
|
|
531
|
+
const autoLabel = opts.autoLabel !== false;
|
|
532
|
+
const skipConfirm = opts.yes || false;
|
|
533
|
+
const dryRun = opts.dryRun || false;
|
|
534
|
+
// Collect all labels
|
|
535
|
+
const allLabels = [...explicitLabels];
|
|
536
|
+
let inferredLabels = [];
|
|
537
|
+
let reasons = {};
|
|
538
|
+
// Auto-label if enabled and no explicit type labels provided
|
|
539
|
+
if (autoLabel) {
|
|
540
|
+
const service = (0, services_2.createLabelInferenceService)();
|
|
541
|
+
const result = service.inferLabels(title, body);
|
|
542
|
+
inferredLabels = result.labels;
|
|
543
|
+
reasons = result.reasons;
|
|
544
|
+
// Filter out labels that conflict with explicit labels
|
|
545
|
+
const explicitTypes = explicitLabels.filter(l => ['bug', 'enhancement', 'documentation', 'refactor', 'testing'].includes(l));
|
|
546
|
+
if (explicitTypes.length > 0) {
|
|
547
|
+
// User specified a type label, don't override it
|
|
548
|
+
inferredLabels = inferredLabels.filter(l => !['bug', 'enhancement', 'documentation', 'refactor', 'testing'].includes(l));
|
|
549
|
+
}
|
|
550
|
+
// Add non-duplicate inferred labels
|
|
551
|
+
for (const label of inferredLabels) {
|
|
552
|
+
if (!allLabels.includes(label)) {
|
|
553
|
+
allLabels.push(label);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// Show what will be created
|
|
558
|
+
console.log(chalk_1.default.bold('Issue to create:'));
|
|
559
|
+
console.log(` Title: ${chalk_1.default.cyan(title)}`);
|
|
560
|
+
if (body) {
|
|
561
|
+
const bodyPreview = body.length > 100 ? body.slice(0, 100) + '...' : body;
|
|
562
|
+
console.log(` Body: ${chalk_1.default.dim(bodyPreview)}`);
|
|
563
|
+
}
|
|
564
|
+
console.log('');
|
|
565
|
+
if (explicitLabels.length > 0) {
|
|
566
|
+
console.log(chalk_1.default.bold('Explicit labels:'));
|
|
567
|
+
for (const label of explicitLabels) {
|
|
568
|
+
console.log(` ${chalk_1.default.green('+')} ${label}`);
|
|
569
|
+
}
|
|
570
|
+
console.log('');
|
|
571
|
+
}
|
|
572
|
+
if (inferredLabels.length > 0) {
|
|
573
|
+
console.log(chalk_1.default.bold('Inferred labels:'));
|
|
574
|
+
for (const label of inferredLabels) {
|
|
575
|
+
const reason = reasons[label] || 'Pattern match';
|
|
576
|
+
console.log(` ${chalk_1.default.yellow('~')} ${label} ${chalk_1.default.dim(`(${reason})`)}`);
|
|
577
|
+
}
|
|
578
|
+
console.log('');
|
|
579
|
+
}
|
|
580
|
+
if (allLabels.length > 0) {
|
|
581
|
+
console.log(chalk_1.default.bold('Final labels:'));
|
|
582
|
+
console.log(` ${allLabels.join(', ')}`);
|
|
583
|
+
console.log('');
|
|
584
|
+
}
|
|
585
|
+
if (dryRun) {
|
|
586
|
+
console.log(chalk_1.default.yellow('Dry run - no issue created'));
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
// Confirm if not skipping
|
|
590
|
+
if (!skipConfirm && inferredLabels.length > 0) {
|
|
591
|
+
const { confirm } = await Promise.resolve().then(() => __importStar(require('@inquirer/prompts')));
|
|
592
|
+
const confirmed = await confirm({
|
|
593
|
+
message: 'Create issue with these labels?',
|
|
594
|
+
default: true,
|
|
595
|
+
});
|
|
596
|
+
if (!confirmed) {
|
|
597
|
+
console.log(chalk_1.default.yellow('Cancelled'));
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
// Build gh command
|
|
602
|
+
const ghArgs = ['issue', 'create', '--title', title];
|
|
603
|
+
if (body) {
|
|
604
|
+
ghArgs.push('--body', body);
|
|
605
|
+
}
|
|
606
|
+
for (const label of allLabels) {
|
|
607
|
+
ghArgs.push('--label', label);
|
|
608
|
+
}
|
|
609
|
+
// Execute gh command using spawnSync to avoid shell injection
|
|
610
|
+
try {
|
|
611
|
+
const { spawnSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
612
|
+
const result = spawnSync('gh', ghArgs, {
|
|
613
|
+
encoding: 'utf8',
|
|
614
|
+
stdio: ['inherit', 'pipe', 'inherit'],
|
|
615
|
+
shell: false,
|
|
616
|
+
});
|
|
617
|
+
if (result.error) {
|
|
618
|
+
throw result.error;
|
|
619
|
+
}
|
|
620
|
+
if (result.status !== 0) {
|
|
621
|
+
throw new Error(`gh exited with code ${result.status}`);
|
|
622
|
+
}
|
|
623
|
+
console.log(chalk_1.default.green('Issue created:'), (result.stdout || '').trim());
|
|
624
|
+
}
|
|
625
|
+
catch (error) {
|
|
626
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
627
|
+
console.error(chalk_1.default.red('Failed to create issue:'), message);
|
|
628
|
+
process.exit(1);
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
issueCmd
|
|
632
|
+
.command('labels')
|
|
633
|
+
.description('Infer labels for content without creating an issue')
|
|
634
|
+
.requiredOption('-t, --title <title>', 'Issue title to analyze')
|
|
635
|
+
.option('-b, --body <body>', 'Issue body to analyze')
|
|
636
|
+
.option('--json', 'Output as JSON')
|
|
637
|
+
.action((opts) => {
|
|
638
|
+
const service = (0, services_2.createLabelInferenceService)();
|
|
639
|
+
const result = service.inferLabels(opts.title, opts.body || '');
|
|
640
|
+
if (opts.json) {
|
|
641
|
+
console.log(JSON.stringify(result, null, 2));
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
if (result.labels.length === 0) {
|
|
645
|
+
console.log(chalk_1.default.yellow('No labels inferred'));
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
console.log(chalk_1.default.bold('Inferred labels:'));
|
|
649
|
+
for (const label of result.labels) {
|
|
650
|
+
const reason = result.reasons[label] || 'Pattern match';
|
|
651
|
+
console.log(` ${chalk_1.default.green('+')} ${label}`);
|
|
652
|
+
console.log(` ${chalk_1.default.dim(reason)}`);
|
|
653
|
+
}
|
|
654
|
+
console.log('');
|
|
655
|
+
console.log(`Confidence: ${(result.confidence * 100).toFixed(0)}%`);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
// Subcommand: lisa hook
|
|
660
|
+
// These commands are called by Claude Code via settings.json hooks
|
|
661
|
+
const hookCmd = program
|
|
662
|
+
.command('hook')
|
|
663
|
+
.description('Hook commands for Claude Code integration');
|
|
664
|
+
hookCmd
|
|
665
|
+
.command('session-start')
|
|
666
|
+
.description('Handle session start event (called by Claude Code)')
|
|
667
|
+
.action(async () => {
|
|
668
|
+
let dispose;
|
|
669
|
+
try {
|
|
670
|
+
// Read input from Claude Code
|
|
671
|
+
const input = await (0, cli_1.readJsonFromStdin)();
|
|
672
|
+
const trigger = (0, cli_1.parseTrigger)(input.source, input.session_type, input.trigger);
|
|
673
|
+
// Bootstrap container and resolve mediator
|
|
674
|
+
const bootstrap = await (0, di_1.bootstrapContainer)({
|
|
675
|
+
projectRoot: input.cwd || process.cwd(),
|
|
676
|
+
disableLogging: true,
|
|
677
|
+
});
|
|
678
|
+
dispose = bootstrap.dispose;
|
|
679
|
+
const mediator = await bootstrap.container.resolve(di_1.TOKENS.Mediator);
|
|
680
|
+
// Create and send request
|
|
681
|
+
const request = new requests_1.SessionStartRequest(trigger, (0, domain_1.toISOTimestamp)(), input.session_id);
|
|
682
|
+
const result = await mediator.send(request);
|
|
683
|
+
// Output context to stdout (goes to Claude)
|
|
684
|
+
const output = {
|
|
685
|
+
hookSpecificOutput: {
|
|
686
|
+
hookEventName: 'SessionStart',
|
|
687
|
+
additionalContext: result.contextContent,
|
|
688
|
+
},
|
|
689
|
+
};
|
|
690
|
+
await (0, cli_1.writeJsonToStdout)(output);
|
|
691
|
+
// Status message to stderr (shown to user)
|
|
692
|
+
await (0, cli_1.writeStatus)(result.message);
|
|
693
|
+
}
|
|
694
|
+
catch (error) {
|
|
695
|
+
// On error, still output something to not block session
|
|
696
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
697
|
+
const output = {
|
|
698
|
+
hookSpecificOutput: {
|
|
699
|
+
hookEventName: 'SessionStart',
|
|
700
|
+
additionalContext: `Memory load skipped: ${errorMessage}`,
|
|
701
|
+
},
|
|
702
|
+
};
|
|
703
|
+
await (0, cli_1.writeJsonToStdout)(output);
|
|
704
|
+
await (0, cli_1.writeStatus)(`Memory load failed: ${errorMessage}`);
|
|
705
|
+
}
|
|
706
|
+
finally {
|
|
707
|
+
if (dispose)
|
|
708
|
+
await dispose();
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
hookCmd
|
|
712
|
+
.command('session-stop')
|
|
713
|
+
.description('Handle session stop event (called by Claude Code)')
|
|
714
|
+
.action(async () => {
|
|
715
|
+
let dispose;
|
|
716
|
+
try {
|
|
717
|
+
// Read input from Claude Code
|
|
718
|
+
const input = await (0, cli_1.readJsonFromStdin)();
|
|
719
|
+
// Bootstrap container and resolve mediator
|
|
720
|
+
const bootstrap = await (0, di_1.bootstrapContainer)({
|
|
721
|
+
projectRoot: input.cwd || process.cwd(),
|
|
722
|
+
disableLogging: true,
|
|
723
|
+
});
|
|
724
|
+
dispose = bootstrap.dispose;
|
|
725
|
+
const mediator = await bootstrap.container.resolve(di_1.TOKENS.Mediator);
|
|
726
|
+
// Create and send request
|
|
727
|
+
const request = new requests_1.SessionStopRequest('idle', (0, domain_1.toISOTimestamp)(), input.session_id, input.transcript_path);
|
|
728
|
+
const result = await mediator.send(request);
|
|
729
|
+
// Status message to stderr
|
|
730
|
+
await (0, cli_1.writeStatus)(result.message);
|
|
731
|
+
}
|
|
732
|
+
catch (error) {
|
|
733
|
+
// Silent failure - don't block user
|
|
734
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
735
|
+
await (0, cli_1.writeStatus)(`Session capture failed: ${errorMessage}`);
|
|
736
|
+
}
|
|
737
|
+
finally {
|
|
738
|
+
if (dispose)
|
|
739
|
+
await dispose();
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
hookCmd
|
|
743
|
+
.command('user-prompt-submit')
|
|
744
|
+
.description('Handle user prompt submit event (called by Claude Code)')
|
|
745
|
+
.action(async () => {
|
|
746
|
+
let dispose;
|
|
747
|
+
try {
|
|
748
|
+
// Read input from Claude Code
|
|
749
|
+
const input = await (0, cli_1.readJsonFromStdin)();
|
|
750
|
+
const content = input.prompt || input.content || '';
|
|
751
|
+
const permissionMode = (input.permission_mode || input.permissionMode || 'default');
|
|
752
|
+
if (!content) {
|
|
753
|
+
// No content to process
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
// Bootstrap container and resolve mediator
|
|
757
|
+
const bootstrap = await (0, di_1.bootstrapContainer)({
|
|
758
|
+
projectRoot: process.cwd(),
|
|
759
|
+
disableLogging: true,
|
|
760
|
+
});
|
|
761
|
+
dispose = bootstrap.dispose;
|
|
762
|
+
const mediator = await bootstrap.container.resolve(di_1.TOKENS.Mediator);
|
|
763
|
+
// Create and send request
|
|
764
|
+
const request = new requests_1.PromptSubmitRequest(content, (0, domain_1.toISOTimestamp)(), input.session_id, permissionMode);
|
|
765
|
+
const result = await mediator.send(request);
|
|
766
|
+
// Output recursion results if in plan mode
|
|
767
|
+
if (result.recursion?.hasContext) {
|
|
768
|
+
console.log('\nš Related Context from Memory:\n');
|
|
769
|
+
console.log(result.recursion.summary);
|
|
770
|
+
console.log('');
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
catch {
|
|
774
|
+
// Silent failure - don't block user
|
|
775
|
+
}
|
|
776
|
+
finally {
|
|
777
|
+
if (dispose)
|
|
778
|
+
await dispose();
|
|
779
|
+
}
|
|
780
|
+
});
|
|
1036
781
|
if (require.main === module) {
|
|
1037
782
|
program.parseAsync(process.argv).catch((err) => {
|
|
1038
783
|
console.error(chalk_1.default.red(err.message));
|