hirmos 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,27 +5,30 @@ Product-facing HIRMOS CLI.
5
5
  Implemented command:
6
6
 
7
7
  ```bash
8
- hirmos init [project-path] [--integration <ids>] [--source <path>]
8
+ hirmos init [project-path] [--integration <ids>] [--source <path>] [--version <version>] [--offline]
9
9
  ```
10
10
 
11
11
  The CLI makes an installed HIRMOS project discoverable to selected agent-native tools by generating thin bootstrap integration files from `_hirmos/integrations/agent-tools/`.
12
12
 
13
- It does not invoke agents, run HIRMOS workflows, install extensions, download remote packages, or generate slash-command packs.
13
+ It does not invoke agents, run HIRMOS workflows, install extensions, or generate slash-command packs.
14
14
 
15
15
  ## Usage
16
16
 
17
- From a project that already contains `_hirmos/`:
17
+ From a project root:
18
18
 
19
19
  ```bash
20
20
  hirmos init
21
21
  ```
22
22
 
23
+ If `_hirmos/` is not present, the CLI downloads the latest HIRMOS framework release package and installs `_hirmos/` before generating integrations.
24
+
23
25
  This defaults to:
24
26
 
25
27
  ```text
26
28
  project-path = .
27
29
  integration = agents
28
- source = existing _hirmos/ in the project
30
+ source = existing _hirmos/ in the project, otherwise latest GitHub release
31
+ version = latest
29
32
  ```
30
33
 
31
34
  Generate specific integrations:
@@ -40,12 +43,24 @@ Initialize another project path:
40
43
  hirmos init /path/to/project --integration agents,claude
41
44
  ```
42
45
 
43
- Install `_hirmos/` from a local source folder or release zip when the target project does not already contain `_hirmos/`:
46
+ Install a specific HIRMOS release:
47
+
48
+ ```bash
49
+ hirmos init --version 1.3.1
50
+ ```
51
+
52
+ Install `_hirmos/` from a local source folder or release zip instead of downloading:
44
53
 
45
54
  ```bash
46
55
  hirmos init /path/to/project --source /path/to/hirmos-framework.zip --integration agents
47
56
  ```
48
57
 
58
+ Disable remote download and require an existing `_hirmos/` or local `--source`:
59
+
60
+ ```bash
61
+ hirmos init --offline
62
+ ```
63
+
49
64
  ## Supported integrations
50
65
 
51
66
  ```text
@@ -104,4 +119,4 @@ hirmos system-design
104
119
  hirmos implementation
105
120
  ```
106
121
 
107
- The CLI currently implements only `hirmos init`.
122
+ The CLI implements `hirmos init`.
@@ -15,7 +15,11 @@ const validation_1 = require("../lib/validation");
15
15
  function runInit(options) {
16
16
  const projectRoot = path_1.default.resolve(options.projectPath);
17
17
  (0, validation_1.validateProjectRoot)(projectRoot);
18
- (0, source_install_1.ensureHirmosInstalled)(projectRoot, options.source);
18
+ const installResult = (0, source_install_1.ensureHirmosInstalled)(projectRoot, {
19
+ source: options.source,
20
+ version: options.version,
21
+ offline: options.offline
22
+ });
19
23
  (0, validation_1.validateHirmosFramework)(projectRoot);
20
24
  const hirmosDir = path_1.default.join(projectRoot, "_hirmos");
21
25
  const registry = (0, integration_registry_1.loadRegistry)(hirmosDir);
@@ -38,12 +42,15 @@ function runInit(options) {
38
42
  (0, filesystem_1.writeText)(write.path, write.content);
39
43
  }
40
44
  (0, project_config_1.writeProjectConfig)(projectRoot, mergeResult.config);
41
- return formatInitSummary(mergeResult.wasFirstInitialization, selected, mergeResult.added, mergeResult.alreadyInstalled, renderedWrites.map((item) => item.relative));
45
+ return formatInitSummary(mergeResult.wasFirstInitialization, selected, mergeResult.added, mergeResult.alreadyInstalled, renderedWrites.map((item) => item.relative), installResult);
42
46
  }
43
- function formatInitSummary(first, selected, added, alreadyInstalled, targets) {
47
+ function formatInitSummary(first, selected, added, alreadyInstalled, targets, installResult) {
44
48
  const lines = [];
45
49
  if (first) {
46
50
  lines.push("HIRMOS initialized.", "");
51
+ if (installResult.installed && installResult.sourceDescription) {
52
+ lines.push(`Installed framework from ${installResult.sourceDescription}.`, "");
53
+ }
47
54
  lines.push("Installed integrations:");
48
55
  for (const id of selected)
49
56
  lines.push(`- ${id}`);
package/dist/index.js CHANGED
@@ -15,7 +15,9 @@ function main() {
15
15
  const summary = (0, init_1.runInit)({
16
16
  projectPath: parsed.projectPath,
17
17
  integrations: parsed.integrations,
18
- source: parsed.source
18
+ source: parsed.source,
19
+ version: parsed.version,
20
+ offline: parsed.offline
19
21
  });
20
22
  process.stdout.write(summary);
21
23
  return;
package/dist/lib/args.js CHANGED
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.parseArgs = parseArgs;
7
+ exports.normalizeVersionOption = normalizeVersionOption;
7
8
  exports.parseIntegrationList = parseIntegrationList;
8
9
  exports.helpText = helpText;
9
10
  const path_1 = __importDefault(require("path"));
@@ -14,12 +15,14 @@ function parseArgs(argv) {
14
15
  }
15
16
  const command = argv[0];
16
17
  if (command !== "init") {
17
- (0, errors_1.fail)(`Unsupported command: ${command}. DP-3B implements only: hirmos init`);
18
+ (0, errors_1.fail)(`Unsupported command: ${command}. This CLI currently supports: hirmos init`);
18
19
  }
19
20
  let projectPath = ".";
20
21
  let projectPathSet = false;
21
22
  let integrationValue;
22
23
  let source;
24
+ let version = "latest";
25
+ let offline = false;
23
26
  for (let i = 1; i < argv.length; i += 1) {
24
27
  const arg = argv[i];
25
28
  if (arg === "--integration") {
@@ -44,6 +47,21 @@ function parseArgs(argv) {
44
47
  source = arg.slice("--source=".length);
45
48
  continue;
46
49
  }
50
+ if (arg === "--version") {
51
+ const value = argv[++i];
52
+ if (!value)
53
+ (0, errors_1.fail)("Missing value for --version");
54
+ version = value;
55
+ continue;
56
+ }
57
+ if (arg.startsWith("--version=")) {
58
+ version = arg.slice("--version=".length);
59
+ continue;
60
+ }
61
+ if (arg === "--offline") {
62
+ offline = true;
63
+ continue;
64
+ }
47
65
  if (arg === "--help" || arg === "-h") {
48
66
  return { command: "help" };
49
67
  }
@@ -61,9 +79,17 @@ function parseArgs(argv) {
61
79
  command: "init",
62
80
  projectPath: path_1.default.resolve(projectPath),
63
81
  integrations,
64
- source: source ? path_1.default.resolve(source) : undefined
82
+ source: source ? path_1.default.resolve(source) : undefined,
83
+ version: normalizeVersionOption(version),
84
+ offline
65
85
  };
66
86
  }
87
+ function normalizeVersionOption(value) {
88
+ const normalized = value.trim();
89
+ if (!normalized)
90
+ (0, errors_1.fail)("--version must not be empty");
91
+ return normalized;
92
+ }
67
93
  function parseIntegrationList(value) {
68
94
  const ids = value
69
95
  .split(",")
@@ -75,5 +101,5 @@ function parseIntegrationList(value) {
75
101
  return ids;
76
102
  }
77
103
  function helpText() {
78
- return `HIRMOS CLI\n\nUsage:\n hirmos init [project-path] [--integration <ids>] [--source <path>]\n\nDefaults:\n project-path: .\n integration: agents\n source: existing _hirmos/ in the project\n\nDP-3B implements only hirmos init. Workflow commands such as hirmos requirements are interpreted by an agent after HIRMOS Core is loaded.\n`;
104
+ return `HIRMOS CLI\n\nUsage:\n hirmos init [project-path] [--integration <ids>] [--source <path>] [--version <version>] [--offline]\n\nDefaults:\n project-path: .\n integration: agents\n source: existing _hirmos/ in the project, otherwise the latest GitHub release\n version: latest\n\nNotes:\n --source installs from a local _hirmos folder, framework folder, or hirmos-framework.zip.\n --version selects a GitHub release when _hirmos/ is missing and --source is not provided.\n --offline disables remote release download and requires an existing _hirmos/ or --source.\n\nThis CLI implements hirmos init. Workflow commands such as hirmos requirements are interpreted by an agent after HIRMOS Core is loaded.\n`;
79
105
  }
@@ -4,20 +4,61 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ensureHirmosInstalled = ensureHirmosInstalled;
7
+ exports.buildReleaseDownloadUrl = buildReleaseDownloadUrl;
8
+ exports.normalizeReleaseVersion = normalizeReleaseVersion;
7
9
  const fs_1 = __importDefault(require("fs"));
8
10
  const os_1 = __importDefault(require("os"));
9
11
  const path_1 = __importDefault(require("path"));
10
12
  const child_process_1 = require("child_process");
11
13
  const errors_1 = require("./errors");
12
14
  const filesystem_1 = require("./filesystem");
13
- function ensureHirmosInstalled(projectRoot, source) {
15
+ const RELEASE_OWNER = "ymarrerot";
16
+ const RELEASE_REPO = "HIRMOS";
17
+ const RELEASE_ASSET = "hirmos-framework.zip";
18
+ function ensureHirmosInstalled(projectRoot, options) {
14
19
  const hirmosDir = path_1.default.join(projectRoot, "_hirmos");
15
20
  if ((0, filesystem_1.pathExists)(hirmosDir)) {
16
- return;
21
+ return { installed: false, sourceDescription: null };
22
+ }
23
+ if (options.source) {
24
+ installFromSource(projectRoot, options.source);
25
+ return { installed: true, sourceDescription: options.source };
26
+ }
27
+ if (options.offline) {
28
+ (0, errors_1.fail)(`Missing _hirmos/ in ${projectRoot}. Offline mode requires an existing _hirmos/ or --source <path-to-hirmos-framework.zip-or-folder>.`);
17
29
  }
18
- if (!source) {
19
- (0, errors_1.fail)(`Missing _hirmos/ in ${projectRoot}. Provide --source <path-to-hirmos-framework.zip-or-folder>.`);
30
+ const version = normalizeReleaseVersion(options.version);
31
+ const url = buildReleaseDownloadUrl(version);
32
+ const tmp = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), "hirmos-release-"));
33
+ const zipPath = path_1.default.join(tmp, RELEASE_ASSET);
34
+ try {
35
+ downloadFile(url, zipPath);
36
+ installFromZip(projectRoot, zipPath);
37
+ return { installed: true, sourceDescription: version === "latest" ? "latest GitHub release" : `GitHub release ${version}` };
20
38
  }
39
+ finally {
40
+ fs_1.default.rmSync(tmp, { recursive: true, force: true });
41
+ }
42
+ }
43
+ function buildReleaseDownloadUrl(version) {
44
+ const normalized = normalizeReleaseVersion(version);
45
+ const overrideBase = process.env.HIRMOS_CLI_RELEASE_BASE_URL;
46
+ if (overrideBase) {
47
+ const trimmed = overrideBase.replace(/\/+$/u, "");
48
+ return `${trimmed}/${normalized}/${RELEASE_ASSET}`;
49
+ }
50
+ if (normalized === "latest") {
51
+ return `https://github.com/${RELEASE_OWNER}/${RELEASE_REPO}/releases/latest/download/${RELEASE_ASSET}`;
52
+ }
53
+ return `https://github.com/${RELEASE_OWNER}/${RELEASE_REPO}/releases/download/${normalized}/${RELEASE_ASSET}`;
54
+ }
55
+ function normalizeReleaseVersion(version) {
56
+ const trimmed = version.trim();
57
+ if (!trimmed || trimmed === "latest")
58
+ return "latest";
59
+ return trimmed.startsWith("v") ? trimmed : `v${trimmed}`;
60
+ }
61
+ function installFromSource(projectRoot, source) {
21
62
  if (!(0, filesystem_1.pathExists)(source)) {
22
63
  (0, errors_1.fail)(`Source path does not exist: ${source}`);
23
64
  }
@@ -46,11 +87,11 @@ function installFromZip(projectRoot, zipPath) {
46
87
  extractZip(zipPath, tmp);
47
88
  }
48
89
  catch (error) {
49
- (0, errors_1.fail)(`Unable to extract --source zip. Ensure the zip is valid and an extraction command is available: ${error.message}`);
90
+ (0, errors_1.fail)(`Unable to extract framework zip. Ensure the zip is valid and an extraction command is available: ${error.message}`);
50
91
  }
51
92
  const sourceHirmos = findHirmosDir(tmp);
52
93
  if (!sourceHirmos) {
53
- (0, errors_1.fail)(`Source zip does not contain an _hirmos/ folder: ${zipPath}`);
94
+ (0, errors_1.fail)(`Framework zip does not contain an _hirmos/ folder: ${zipPath}`);
54
95
  }
55
96
  copyHirmos(projectRoot, sourceHirmos);
56
97
  }
@@ -79,6 +120,16 @@ function copyHirmos(projectRoot, sourceHirmos) {
79
120
  }
80
121
  (0, filesystem_1.ensureDir)(projectRoot);
81
122
  fs_1.default.cpSync(sourceHirmos, target, { recursive: true, errorOnExist: true });
123
+ validateCopiedHirmos(projectRoot);
124
+ }
125
+ function validateCopiedHirmos(projectRoot) {
126
+ const required = ["_hirmos/HIRMOS_CORE.md", "_hirmos/VERSION", "_hirmos/project.json"];
127
+ for (const relative of required) {
128
+ if (!(0, filesystem_1.pathExists)(path_1.default.join(projectRoot, relative))) {
129
+ fs_1.default.rmSync(path_1.default.join(projectRoot, "_hirmos"), { recursive: true, force: true });
130
+ (0, errors_1.fail)(`Installed framework is incomplete; missing ${relative}. Removed partial _hirmos/ install.`);
131
+ }
132
+ }
82
133
  }
83
134
  function extractZip(zipPath, destination) {
84
135
  if (process.platform === "win32") {
@@ -87,3 +138,26 @@ function extractZip(zipPath, destination) {
87
138
  }
88
139
  (0, child_process_1.execFileSync)("unzip", ["-q", zipPath, "-d", destination], { stdio: "ignore" });
89
140
  }
141
+ function downloadFile(url, destination) {
142
+ (0, filesystem_1.ensureDir)(path_1.default.dirname(destination));
143
+ try {
144
+ if (process.platform === "win32") {
145
+ (0, child_process_1.execFileSync)("powershell", [
146
+ "-NoProfile",
147
+ "-Command",
148
+ "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest -Uri $args[0] -OutFile $args[1]",
149
+ url,
150
+ destination
151
+ ], { stdio: "ignore" });
152
+ }
153
+ else {
154
+ (0, child_process_1.execFileSync)("curl", ["-fL", "--retry", "2", "--connect-timeout", "20", "--max-time", "120", "-o", destination, url], { stdio: "ignore" });
155
+ }
156
+ }
157
+ catch (error) {
158
+ (0, errors_1.fail)(`Unable to download HIRMOS release from ${url}. Use --source for a local release package or --offline to disable downloads. ${error.message}`);
159
+ }
160
+ if (!(0, filesystem_1.pathExists)(destination) || fs_1.default.statSync(destination).size === 0) {
161
+ (0, errors_1.fail)(`Downloaded HIRMOS release is empty or missing: ${destination}`);
162
+ }
163
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hirmos",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "HIRMOS product-facing CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "commonjs",