kamakiri 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +28 -0
- package/bin/kamakiri.js +167 -0
- package/package.json +27 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alexis Tabary
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# kamakiri
|
|
2
|
+
|
|
3
|
+
`kamakiri` is the command-line client for Kamakiri Pages, a static-site hosting
|
|
4
|
+
service. You build your site locally, deploy the output directory, and it goes
|
|
5
|
+
live over HTTPS on a `kamakiri-pages.jp` subdomain or on a domain of your own.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install -g kamakiri
|
|
9
|
+
kamakiri --help
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`npx kamakiri@latest` runs it without installing anything, and
|
|
13
|
+
`npm install -g kamakiri@latest` is how an installed copy is updated.
|
|
14
|
+
|
|
15
|
+
This package is a small launcher. The CLI itself is a single static Go binary,
|
|
16
|
+
published one per platform as `@kamakiri-labs/cli-<platform>-<arch>`; installing
|
|
17
|
+
`kamakiri` brings in the one package that matches your machine, as an optional
|
|
18
|
+
dependency npm skips everywhere else. The `kamakiri` command resolves that
|
|
19
|
+
binary and runs it, passing your arguments, the standard streams and the exit
|
|
20
|
+
code straight through.
|
|
21
|
+
|
|
22
|
+
Kamakiri Pages is an invitation-only private beta today, so `kamakiri login`
|
|
23
|
+
only succeeds for an email that has been invited. To request an invitation,
|
|
24
|
+
email beta@kamakiri-labs.jp.
|
|
25
|
+
|
|
26
|
+
The full documentation, the other ways to install the CLI, and the source are
|
|
27
|
+
at [github.com/kamakiri-labs/kamakiri](https://github.com/kamakiri-labs/kamakiri).
|
|
28
|
+
The CLI is MIT licensed.
|
package/bin/kamakiri.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The command npm installs as `kamakiri`. It resolves the platform package
|
|
3
|
+
// carrying this machine's binary and runs it, passing everything through: the
|
|
4
|
+
// arguments as given, the three standard streams, the exit code, and the
|
|
5
|
+
// signal a run died of. An interrupt is the binary's to answer, so this sits
|
|
6
|
+
// out SIGINT, SIGTERM and SIGHUP for as long as the binary is running.
|
|
7
|
+
//
|
|
8
|
+
// The shebang is what runs this on macOS and Linux, where npm links the file
|
|
9
|
+
// itself. Windows gets generated .cmd and .ps1 shims that invoke node
|
|
10
|
+
// explicitly and never read the line.
|
|
11
|
+
//
|
|
12
|
+
// It downloads nothing and runs no install script. The binary is already on
|
|
13
|
+
// disk when this runs, because npm installed the platform package as an
|
|
14
|
+
// optional dependency whose os/cpu fields matched this machine.
|
|
15
|
+
"use strict";
|
|
16
|
+
|
|
17
|
+
const { spawnSync } = require("child_process");
|
|
18
|
+
|
|
19
|
+
// The six platforms a release publishes a binary for, spelled the way
|
|
20
|
+
// process.platform and process.arch spell them. The packaging side writes the
|
|
21
|
+
// same six names on the packages themselves, so this list and that one are the
|
|
22
|
+
// two halves of one string and have to agree.
|
|
23
|
+
const SUPPORTED = [
|
|
24
|
+
"darwin-arm64",
|
|
25
|
+
"darwin-x64",
|
|
26
|
+
"linux-arm64",
|
|
27
|
+
"linux-x64",
|
|
28
|
+
"win32-arm64",
|
|
29
|
+
"win32-x64",
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const RELEASES_URL = "https://github.com/kamakiri-labs/kamakiri/releases";
|
|
33
|
+
const INSTALL_SCRIPT_URL = "https://get.kamakiri-labs.jp/install.sh";
|
|
34
|
+
|
|
35
|
+
// The three signals this stands aside for while the binary runs. A Ctrl-C and
|
|
36
|
+
// a hangup are aimed at the whole foreground job, so each reaches this process
|
|
37
|
+
// alongside the binary it started. SIGTERM is here because the CLI answers that
|
|
38
|
+
// one itself and prints how to pick an interrupted run back up, and this
|
|
39
|
+
// process dying on it first is what would cut that short.
|
|
40
|
+
//
|
|
41
|
+
// The set stops there on purpose. SIGQUIT stays the way out of a binary that
|
|
42
|
+
// traps the others and will not stop, and a listener on SIGTSTP that does
|
|
43
|
+
// nothing would swallow a Ctrl-Z instead of suspending the job.
|
|
44
|
+
const JOB_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
45
|
+
|
|
46
|
+
// Where this machine's binary lives, or null for a platform no release covers.
|
|
47
|
+
// A pure function of the pair rather than a read of process, so the two win32
|
|
48
|
+
// answers can be checked from any machine: every end-to-end run of this file
|
|
49
|
+
// happens on the host's own platform, and the .exe half of the split would
|
|
50
|
+
// otherwise first be exercised on a user's Windows box.
|
|
51
|
+
function platformTarget(platform, arch) {
|
|
52
|
+
const pair = platform + "-" + arch;
|
|
53
|
+
if (SUPPORTED.indexOf(pair) === -1) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
packageName: "@kamakiri-labs/cli-" + pair,
|
|
58
|
+
// The packaging side appends the same .exe to the two win32 packages. A
|
|
59
|
+
// shim that forgot it would report a package that is present and correct
|
|
60
|
+
// as missing, and only on Windows.
|
|
61
|
+
binarySubpath: platform === "win32" ? "bin/kamakiri.exe" : "bin/kamakiri",
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function say(lines) {
|
|
66
|
+
process.stderr.write(lines.join("\n") + "\n");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function main(args) {
|
|
70
|
+
const target = platformTarget(process.platform, process.arch);
|
|
71
|
+
if (target === null) {
|
|
72
|
+
say([
|
|
73
|
+
"kamakiri: there is no kamakiri binary for " + process.platform + "-" + process.arch + ".",
|
|
74
|
+
"The platforms a release covers are listed on the releases page, " + RELEASES_URL + ".",
|
|
75
|
+
"The install script at " + INSTALL_SCRIPT_URL + " installs from that same set, so it",
|
|
76
|
+
"has nothing for this machine either.",
|
|
77
|
+
]);
|
|
78
|
+
return 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const request = target.packageName + "/" + target.binarySubpath;
|
|
82
|
+
let binary;
|
|
83
|
+
try {
|
|
84
|
+
// The subpath is resolved rather than joined onto a guessed directory, so
|
|
85
|
+
// the binary is found wherever the install put the platform package: under
|
|
86
|
+
// the launcher, hoisted to the top of a project's node_modules, or in a
|
|
87
|
+
// store a package manager links from.
|
|
88
|
+
binary = require.resolve(request);
|
|
89
|
+
} catch {
|
|
90
|
+
say([
|
|
91
|
+
"kamakiri: the platform package " + target.packageName + " is not installed,",
|
|
92
|
+
"so there is no binary to run. Optional dependencies are the likely reason: an install",
|
|
93
|
+
"run with --no-optional, or with optional dependencies omitted in an npm configuration,",
|
|
94
|
+
"skips it. Installing again with them enabled brings it in, with",
|
|
95
|
+
"npm install -g kamakiri@latest for a global install, or npm install in the project that",
|
|
96
|
+
"depends on kamakiri.",
|
|
97
|
+
]);
|
|
98
|
+
return 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Ignored for as long as the binary is running, so the interrupt is the
|
|
102
|
+
// binary's to answer. Node kills a process outright on any of these when
|
|
103
|
+
// nothing is listening, and a Ctrl-C reaches this process at the same moment
|
|
104
|
+
// it reaches the binary, so without this the shim would die first and hand
|
|
105
|
+
// the shell its prompt back over whatever the CLI was still printing about
|
|
106
|
+
// the run it was interrupted in the middle of. The listener does nothing on
|
|
107
|
+
// purpose: it exists to displace that default, not to act.
|
|
108
|
+
const ignoreWhileRunning = () => {};
|
|
109
|
+
for (const signal of JOB_SIGNALS) {
|
|
110
|
+
process.on(signal, ignoreWhileRunning);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const result = spawnSync(binary, args, { stdio: "inherit" });
|
|
114
|
+
|
|
115
|
+
// Dropped again the moment the binary is gone, which puts the default back.
|
|
116
|
+
// The re-raise below counts on that: with the listener still registered it
|
|
117
|
+
// would run the listener instead, and this process would survive a death it
|
|
118
|
+
// is supposed to be passing on.
|
|
119
|
+
for (const signal of JOB_SIGNALS) {
|
|
120
|
+
process.removeListener(signal, ignoreWhileRunning);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// spawnSync answers in one of three ways, and each one means something
|
|
124
|
+
// different to whoever ran the command.
|
|
125
|
+
if (result.error) {
|
|
126
|
+
// The binary was never started, so there is no exit code to pass on and
|
|
127
|
+
// reporting one would say the CLI ran and failed.
|
|
128
|
+
say([
|
|
129
|
+
"kamakiri: the binary at " + binary + " could not be started (" +
|
|
130
|
+
(result.error.code || result.error.message) + ").",
|
|
131
|
+
"Installing the package again replaces it, with npm install -g kamakiri@latest for a",
|
|
132
|
+
"global install, or npm install in the project that depends on kamakiri.",
|
|
133
|
+
]);
|
|
134
|
+
return 1;
|
|
135
|
+
}
|
|
136
|
+
if (result.signal) {
|
|
137
|
+
// Re-raised on this process rather than turned into a number, so a caller
|
|
138
|
+
// sees the same death the binary died of: a command killed by a signal has
|
|
139
|
+
// to look killed to the shell above it, and a number in that position
|
|
140
|
+
// would read as a run that finished and failed. Windows reports no signal
|
|
141
|
+
// at all, so nothing there reaches this and the status below is what a
|
|
142
|
+
// killed child comes back as.
|
|
143
|
+
process.kill(process.pid, result.signal);
|
|
144
|
+
}
|
|
145
|
+
if (typeof result.status === "number") {
|
|
146
|
+
return result.status;
|
|
147
|
+
}
|
|
148
|
+
// Reached only if the re-raised signal did not end this process, or if
|
|
149
|
+
// spawnSync answered in none of its three ways. Neither is a run that
|
|
150
|
+
// finished, so neither reports success.
|
|
151
|
+
return 1;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Guarded so that requiring this file yields its functions without running a
|
|
155
|
+
// command, which is what lets the platform-pair choice be checked directly.
|
|
156
|
+
//
|
|
157
|
+
// The code is set rather than exited on. A write to stderr that lands on a pipe
|
|
158
|
+
// is asynchronous, and process.exit ends the process with whatever is still
|
|
159
|
+
// queued unwritten; these messages are short enough to fit the pipe buffer and
|
|
160
|
+
// would come through either way, so setting the code is the spelling that does
|
|
161
|
+
// not rest on their length. Nothing else is pending once spawnSync has
|
|
162
|
+
// returned, so the process ends on this line regardless.
|
|
163
|
+
if (require.main === module) {
|
|
164
|
+
process.exitCode = main(process.argv.slice(2));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = { platformTarget };
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kamakiri",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The kamakiri CLI, the command-line client for Kamakiri Pages",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/kamakiri-labs/kamakiri.git"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=18"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"kamakiri": "bin/kamakiri.js"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"optionalDependencies": {
|
|
20
|
+
"@kamakiri-labs/cli-darwin-x64": "0.1.0",
|
|
21
|
+
"@kamakiri-labs/cli-darwin-arm64": "0.1.0",
|
|
22
|
+
"@kamakiri-labs/cli-linux-x64": "0.1.0",
|
|
23
|
+
"@kamakiri-labs/cli-linux-arm64": "0.1.0",
|
|
24
|
+
"@kamakiri-labs/cli-win32-x64": "0.1.0",
|
|
25
|
+
"@kamakiri-labs/cli-win32-arm64": "0.1.0"
|
|
26
|
+
}
|
|
27
|
+
}
|