@aistastudio/myc 0.3.3 → 0.3.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/README.md CHANGED
@@ -31,9 +31,11 @@ Installation is one command:
31
31
 
32
32
  ```bash
33
33
  bun install -g @aistastudio/myc # 3.20 MB, 10 files, no models pulled at install
34
- myc --version # myc 0.3.3 (schema 1)
34
+ myc --version # myc 0.3.5 (schema 1)
35
35
  ```
36
36
 
37
+ It runs on macOS and Linux; on Windows, use WSL.
38
+
37
39
  The embedding model is **not** downloaded during install. Semantic search is
38
40
  opt-in and explicit: `myc models fetch` (129 MB, ~7 s). Until then search is
39
41
  lexical and says so.
@@ -56,6 +58,7 @@ writing a config that silently won't start.
56
58
  ```bash
57
59
  ./dist/myc init # .myc/ + SQLite + migrations in this repo
58
60
  ./dist/myc wire # hooks for Claude Code / Codex / opencode / Kimi
61
+ ./dist/myc wire --scope user # the same for agents in git worktrees (Claude Code's user layer)
59
62
  ./dist/myc ready # what can be picked up right now
60
63
  ./dist/myc remember "why X, not Y" # record a fact or decision
61
64
  ./dist/myc recall "how retrieval works"
@@ -65,6 +68,25 @@ writing a config that silently won't start.
65
68
 
66
69
  Full command list: `./dist/myc --help`.
67
70
 
71
+ **Agents in git worktrees.** `myc wire` writes into the project:
72
+ `.claude/settings.json`, `.mcp.json`. An agent that orca starts in a git
73
+ worktree of a nested repository (`~/orca/workspaces/<repo>/<branch>`) lives in
74
+ the team's tree, where those files are not, even though `myc` itself finds the
75
+ main copy's workspace from there. `myc wire --scope user` puts the same into
76
+ Claude Code's user layer, which every session reads:
77
+ `~/.claude/helpers/myc-hooks.mjs`, SessionStart/PreCompact/PostToolUse hooks and
78
+ `Bash(myc <command>:*)` rules in `~/.claude/settings.json` (merged node by node;
79
+ the hooks of orca, herdr and other tools stay byte for byte), the skill in
80
+ `~/.claude/skills/myc`, and the MCP server through `claude mcp add --scope user`.
81
+ Before anything else the helper checks, without starting myc, whether there is
82
+ a workspace here (a git worktree is resolved through its main copy), and stays
83
+ silent when there is none or the project wires myc itself: in a project without
84
+ myc the hook costs one node start, and prime never arrives twice. Outside a
85
+ workspace the MCP server offers zero tools and no instructions. The user's
86
+ `statusLine` is never touched (it belongs to orca), and `--hook-mode replace`
87
+ is refused here. The journal is `~/.myc/wire-user.json`; `myc unwire --scope
88
+ user` restores the settings node by node and removes the MCP server.
89
+
68
90
  ## Heavy commands take turns
69
91
 
70
92
  Several agents on one machine — in one tree or in neighbouring projects — each
@@ -97,7 +119,8 @@ myc run: waiting for a 'heavy' slot (1/1 busy, 1 waiting ahead), waited 0.0s of
97
119
 
98
120
  A holder that dies — even by `SIGKILL` — frees its slot; a `myc run` nested
99
121
  inside another one runs at once, in its parent's slot. One slot per lane by
100
- default, `MYC_HEAVY_SLOTS=2` for two.
122
+ default, `MYC_HEAVY_SLOTS=2` for two. myc does not load the project's `.env` or
123
+ `bunfig.toml`: the command gets the caller's environment as is.
101
124
 
102
125
  **Agents don't have to remember it.** `myc wire --queue-hook` installs a Claude
103
126
  Code `PreToolUse` hook that rewrites a heavy Bash command into
@@ -266,6 +289,34 @@ myc code grep "<lit>" exhaustive, every occurrence; --in <path> narrows it
266
289
  myc skeleton <file> the file's API — 26× cheaper than reading it
267
290
  ```
268
291
 
292
+ The file list is git's own (`git ls-files`, so `.gitignore` applies; a tree
293
+ without git is walked, and the command says so). On top of any list,
294
+ secret-named files are never indexed, whatever `.gitignore` says: `.env` and
295
+ `.env.*` (templates like `.env.example` are indexed), `*.pem`, `*.key`,
296
+ keystores, private SSH keys, `.npmrc`, `.netrc` and other credential files —
297
+ `code index` counts them without naming them, and `code grep` refuses to read one.
298
+
299
+ **Nested repositories and git worktrees.** A workspace can be an ecosystem: a
300
+ root that is a git repository with independent repositories inside it (not
301
+ submodules). It has one code index, built from the root — one row per file,
302
+ paths like `messaging-server/server/src/x.ts`. From inside a nested
303
+ repository every code command answers from that repository's part of the
304
+ root index, with paths relative to the repository you are in; from the root
305
+ the answers do not change. `myc code index` run inside a nested repository
306
+ refreshes its part of the root index instead of building a second copy of the
307
+ same files, and so does the background refresh. A git worktree — even one
308
+ outside the workspace tree — is answered from the index of the main checkout:
309
+ there is no index per branch. When the worktree is on another commit, or has
310
+ uncommitted changes to tracked files, every answer carries
311
+ `WARN code_index.worktree_divergent` naming both branches, because lines and
312
+ spans may not match your files. `code grep` reads the worktree's files (the
313
+ line numbers are yours, the owning symbols come from the index); `skeleton`
314
+ shows the main copy's declarations when your copy differs from what the index
315
+ saw, and says so. When nothing covers the repository, the hint is the command
316
+ for the workspace root (`myc -C <root> code index`), not one that would build a
317
+ duplicate. Anchors set from the root and from inside a repository are stored
318
+ under different keys; `code symbol` reads both.
319
+
269
320
  Anchors tie knowledge to a span and follow the code as it moves; that half is
270
321
  language-agnostic and was verified on Python as well as TypeScript.
271
322
 
package/bin/myc.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env -S bun --no-env-file --config=/dev/null
2
2
  /**
3
3
  * Точка входа npm-пакета @aistastudio/myc.
4
4
  *
@@ -10,6 +10,27 @@
10
10
  * Порядок важен: сначала проверка рантайма, и только потом ДИНАМИЧЕСКИЙ
11
11
  * импорт бандла. Статический импорт Node разрешил бы до первой строки тела
12
12
  * модуля — и мы бы снова упали на `bun:sqlite`, не успев ничего сказать.
13
+ *
14
+ * SHEBANG. Оба флага — про ЧУЖОЙ каталог: myc зовут хуки и MCP в каждом
15
+ * проекте пользователя, и cwd — это его проект. Без них Bun ДО первой строки
16
+ * этого файла грузит .env, .env.local, .env.<NODE_ENV> каталога в process.env
17
+ * (а `myc run` отдавал их команде: 2026-09-11 в cherry `bun test` получил
18
+ * 20 переменных EXPO_PUBLIC_* из .env worktree, которых в оболочке агента не
19
+ * было) и исполняет preload из ./bunfig.toml — happy-dom и моки тестов
20
+ * проекта внутри myc.
21
+ * --no-env-file .env* не грузятся;
22
+ * --config=/dev/null пустой конфиг вместо ./bunfig.toml. «Без конфига» у
23
+ * Bun нет: `--config=` (пусто) молча возвращает
24
+ * ./bunfig.toml, несуществующий путь — фатальная ошибка
25
+ * до старта, а /dev/null есть на любой POSIX. Глобальный
26
+ * ~/.bunfig.toml Bun читает по-прежнему: он не проектный.
27
+ * `env -S` нужен, чтобы флаги дошли до bun раздельно: ядро Linux отдаёт всё
28
+ * после интерпретатора ОДНИМ аргументом. -S есть в GNU coreutils ≥ 8.30 и в
29
+ * env macOS/BSD. На Windows такой shebang не исполним: шим `bun add -g` берёт
30
+ * `-S` за программу, а cmd-shim npm -S понимает, но Bun на Windows не
31
+ * открывает /dev/null — myc там только через WSL (говорит preflight.js).
32
+ * Запуск МИМО shebang (`bun …/myc.js`) флагов не получает; второй рубеж для
33
+ * `myc run` — callerEnv в src/commands/run.ts.
13
34
  */
14
35
 
15
36
  import { spawnSync } from "node:child_process";
package/bin/preflight.js CHANGED
@@ -3,43 +3,66 @@
3
3
  * postinstall-проверка. Запускается тем рантаймом, который ставил пакет —
4
4
  * обычно это node, поэтому здесь снова голый JS без `bun:`.
5
5
  *
6
- * Зачем: shebang у bin/myc.js — `#!/usr/bin/env bun`, и если Bun в системе
7
- * нет вовсе, первая же попытка запустить `myc` даст `env: bun: No such file
8
- * or directory` (код 127) сообщение, по которому нельзя понять ни причину,
9
- * ни что делать. Наша заглушка до этого не доживает: её просто некому
6
+ * Зачем: shebang у bin/myc.js — `#!/usr/bin/env -S bun --no-env-file
7
+ * --config=/dev/null` (зачем флаги в шапке самого bin/myc.js), и если Bun в
8
+ * системе нет вовсе, первая же попытка запустить `myc` даст `env: bun: No such
9
+ * file or directory` (код 127) сообщение, по которому нельзя понять ни
10
+ * причину, ни что делать. Наша заглушка до этого не доживает: её просто некому
10
11
  * выполнить. Значит сказать надо здесь, на установке.
11
12
  *
12
13
  * Установку НЕ роняем: пакет разложен правильно, не хватает только рантайма,
13
14
  * и это чинится `curl … | bash` без переустановки.
15
+ *
16
+ * WINDOWS — та же беда другим путём: там этот shebang не исполним вовсе, даже
17
+ * при установленном Bun. Шим `bun add -g` берёт `-S` за программу
18
+ * (`interpreter executable "-S" not found`), cmd-shim npm передаёт
19
+ * `--config=/dev/null`, а Bun на Windows такого файла не находит (`ENOENT …
20
+ * while reading config`). Оба отказа — до первой строки myc, и сказать
21
+ * человеку, что делать, можно только здесь. Установку тоже не роняем.
22
+ * Предел: `bun add -g` postinstall недоверенного пакета не запускает
23
+ * («Blocked 1 postinstall»), и эту рамку увидит только ставящий через npm —
24
+ * остальным о WSL говорит README.
14
25
  */
15
26
 
16
27
  import { spawnSync } from "node:child_process";
17
28
 
18
- if (typeof process.versions.bun !== "string" && !bunOnPath()) {
29
+ if (process.platform === "win32") {
19
30
  process.stderr.write(
20
- // Рамка собирается по ширине самой длинной строки, а не подгоняется
21
- // руками: после переименования пакета `@myc/cli` -> `@aistastudio/myc`
22
- // верхняя граница разъехалась, и это первое, что видит человек без Bun.
23
- (() => {
24
- const title = "@aistastudio/myc установлен, но запускаться пока не будет";
25
- const body = [
26
- "myc работает только на Bun (хранилище на bun:sqlite).",
27
- "Bun в системе не найден.",
28
- "",
29
- " curl -fsSL https://bun.sh/install | bash",
30
- "",
31
- "После этого: myc --version",
32
- ];
33
- const w = Math.max(title.length + 3, ...body.map((l) => l.length)) + 1;
34
- const top = ` ┌─ ${title} ${"".repeat(Math.max(0, w - title.length - 2))}┐`;
35
- const mid = body.map((l) => ` │ ${l.padEnd(w)}│`);
36
- const bot = ` └${"".repeat(w + 1)}┘`;
37
- return ["", top, ...mid, bot, ""].join("\n");
38
- })(),
39
-
31
+ frame("@aistastudio/myc: Windows is not supported", [
32
+ "myc runs on macOS and Linux; on Windows use WSL.",
33
+ "The `myc` launcher will not start in cmd or PowerShell.",
34
+ "",
35
+ " wsl --install",
36
+ "",
37
+ "Then, inside WSL: install Bun and @aistastudio/myc there.",
38
+ ]),
39
+ );
40
+ } else if (typeof process.versions.bun !== "string" && !bunOnPath()) {
41
+ process.stderr.write(
42
+ frame("@aistastudio/myc установлен, но запускаться пока не будет", [
43
+ "myc работает только на Bun (хранилище на bun:sqlite).",
44
+ "Bun в системе не найден.",
45
+ "",
46
+ " curl -fsSL https://bun.sh/install | bash",
47
+ "",
48
+ "После этого: myc --version",
49
+ ]),
40
50
  );
41
51
  }
42
52
 
53
+ /**
54
+ * Рамка собирается по ширине самой длинной строки, а не подгоняется руками:
55
+ * после переименования пакета `@myc/cli` -> `@aistastudio/myc` верхняя граница
56
+ * разъехалась, и это первое, что видит человек без Bun.
57
+ */
58
+ function frame(title, body) {
59
+ const w = Math.max(title.length + 3, ...body.map((l) => l.length)) + 1;
60
+ const top = ` ┌─ ${title} ${"─".repeat(Math.max(0, w - title.length - 2))}┐`;
61
+ const mid = body.map((l) => ` │ ${l.padEnd(w)}│`);
62
+ const bot = ` └${"─".repeat(w + 1)}┘`;
63
+ return ["", top, ...mid, bot, ""].join("\n");
64
+ }
65
+
43
66
  function bunOnPath() {
44
67
  try {
45
68
  return spawnSync("bun", ["--version"], { stdio: "ignore" }).status === 0;